Merge from Chromium at DEPS revision r210036

This commit was generated by merge_to_master.py.

Change-Id: Ib0e33a83ad5dfa541481e83d7acfc6970e68f471
diff --git a/chrome/browser/DEPS b/chrome/browser/DEPS
index b9c6a71..632d192 100644
--- a/chrome/browser/DEPS
+++ b/chrome/browser/DEPS
@@ -5,12 +5,12 @@
   "+chrome/installer",
   "+chrome/tools/profiles",  # For history unit tests.
   "+chromeos",
-  "+components/autofill/browser",
   "+components/autofill/content/browser",
+  "+components/autofill/core/browser",
   "+components/autofill/core/common",
   "+components/auto_login_parser",
-  "+components/breakpad",
   "+components/browser_context_keyed_service",
+  "+components/nacl/common",
   "+components/navigation_interception",
   "+components/user_prefs",
   "+components/visitedlink/browser",
@@ -52,9 +52,6 @@
   # TODO(stuartmorgan): Remove these by refactoring necessary code out of
   # webkit/. See crbug.com/146251
   # DO NOT ADD ANY MORE ITEMS TO THE LIST BELOW!
-  "+webkit/base/origin_url_conversions.h",
-  "+webkit/common/cursors/webcursor.h",
-  "+webkit/dom_storage/dom_storage_types.h",
   "+webkit/plugins",  # Defines some types that are marshalled over IPC.
 
   # TODO(kinuko): Remove all other webkit/* dependencies after we cleaned
@@ -62,12 +59,14 @@
   "+webkit/browser",
   "+webkit/common",
 
+  # TODO(ananta): remove me when
+  # bug https://code.google.com/p/chromium/issues/detail?id=237249 is fixed.
+  "!content/public/child/image_decoder_utils.h",
+
   # webkit/glue files are listed individually since they aren't conceptually
   # grouped like the other webkit/ files, and can therefore be tackled one at
   # a time.
-  "+webkit/glue/image_decoder.h",
   "+webkit/glue/resource_type.h",
-  "+webkit/glue/webkit_glue.h",
   # DO NOT ADD ANY MORE ITEMS TO THE ABOVE LIST!
 
   "-chrome/browser/ui/views",
@@ -89,4 +88,32 @@
   "+third_party/re2",
   "+third_party/sqlite",
   "+third_party/undoview",
+
+  # No inclusion of WebKit from the browser, other than strictly enum/POD,
+  # header-only types, and some selected common code.
+  "-third_party/WebKit",
+  "+third_party/WebKit/public/platform/WebCString.h",
+  "+third_party/WebKit/public/platform/WebRect.h",
+  "+third_party/WebKit/public/platform/WebReferrerPolicy.h",
+  "+third_party/WebKit/public/platform/WebScreenInfo.h",
+  "+third_party/WebKit/public/platform/WebString.h",
+  "+third_party/WebKit/public/platform/WebURL.h",
+  "+third_party/WebKit/public/web/WebAutofillClient.h",
+  "+third_party/WebKit/public/web/WebCache.h",
+  "+third_party/WebKit/public/web/WebContextMenuData.h",
+  "+third_party/WebKit/public/web/WebCursorInfo.h",
+  "+third_party/WebKit/public/web/WebDevToolsAgent.h",
+  "+third_party/WebKit/public/web/WebFindOptions.h",
+  "+third_party/WebKit/public/web/WebInputEvent.h",
+  "+third_party/WebKit/public/web/WebMediaPlayerAction.h",
+  "+third_party/WebKit/public/web/WebNotificationPresenter.h",
+  "+third_party/WebKit/public/web/WebPluginAction.h",
+  "+third_party/WebKit/public/web/WebScreenInfo.h",
+  "+third_party/WebKit/public/web/WebTextDirection.h",
+
+  # These should be burned down. http://crbug.com/237267
+  "!third_party/WebKit/public/web/WebKit.h",
+  "!third_party/WebKit/public/web/WebSecurityOrigin.h",
+  "!third_party/WebKit/public/web/WebSecurityPolicy.h",
+  "!third_party/WebKit/public/web/WebView.h",
 ]
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 1479406..7099dbd 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -19,6 +19,7 @@
 #include "chrome/browser/flags_storage.h"
 #include "chrome/common/chrome_content_client.h"
 #include "chrome/common/chrome_switches.h"
+#include "components/nacl/common/nacl_switches.h"
 #include "content/public/browser/user_metrics.h"
 #include "grit/chromium_strings.h"
 #include "grit/generated_resources.h"
@@ -540,6 +541,13 @@
     SINGLE_VALUE_TYPE(switches::kExtensionsOnChromeURLs)
   },
   {
+    "enable-fast-unload",
+    IDS_FLAGS_ENABLE_FAST_UNLOAD_NAME,
+    IDS_FLAGS_ENABLE_FAST_UNLOAD_DESCRIPTION,
+    kOsAll,
+    SINGLE_VALUE_TYPE(switches::kEnableFastUnload)
+  },
+  {
     "enable-adview",
     IDS_FLAGS_ENABLE_ADVIEW_NAME,
     IDS_FLAGS_ENABLE_ADVIEW_DESCRIPTION,
@@ -554,6 +562,13 @@
     SINGLE_VALUE_TYPE(switches::kEnableAdviewSrcAttribute)
   },
   {
+    "enable-app-window-controls",
+    IDS_FLAGS_ENABLE_APP_WINDOW_CONTROLS_NAME,
+    IDS_FLAGS_ENABLE_APP_WINDOW_CONTROLS_DESCRIPTION,
+    kOsDesktop,
+    SINGLE_VALUE_TYPE(switches::kEnableAppWindowControls)
+  },
+  {
     "action-box",
     IDS_FLAGS_ACTION_BOX_NAME,
     IDS_FLAGS_ACTION_BOX_DESCRIPTION,
@@ -621,14 +636,6 @@
                               switches::kDisableLocalFirstLoadNTP)
   },
   {
-    "enable-local-only-instant-extended-api",
-    IDS_FLAGS_ENABLE_LOCAL_ONLY_INSTANT_EXTENDED_API,
-    IDS_FLAGS_ENABLE_LOCAL_ONLY_INSTANT_EXTENDED_API_DESCRIPTION,
-    kOsMac | kOsWin | kOsCrOS,
-    ENABLE_DISABLE_VALUE_TYPE(switches::kEnableLocalOnlyInstantExtendedAPI,
-                              switches::kDisableLocalOnlyInstantExtendedAPI)
-  },
-  {
     "static-ip-config",
     IDS_FLAGS_STATIC_IP_CONFIG_NAME,
     IDS_FLAGS_STATIC_IP_CONFIG_DESCRIPTION,
@@ -655,13 +662,6 @@
     SINGLE_VALUE_TYPE(switches::kEnableSyncFavicons)
   },
   {
-    "sync-keystore-encryption",
-    IDS_FLAGS_SYNC_KEYSTORE_ENCRYPTION_NAME,
-    IDS_FLAGS_SYNC_KEYSTORE_ENCRYPTION_DESCRIPTION,
-    kOsAll,
-    SINGLE_VALUE_TYPE(switches::kSyncKeystoreEncryption)
-  },
-  {
     "enable-gesture-tap-highlight",
     IDS_FLAGS_ENABLE_GESTURE_TAP_HIGHLIGHTING_NAME,
     IDS_FLAGS_ENABLE_GESTURE_TAP_HIGHLIGHTING_DESCRIPTION,
@@ -723,6 +723,13 @@
                               switches::kDisableQuic)
   },
   {
+    "enable-spdy4a2",
+    IDS_FLAGS_ENABLE_SPDY4A2_NAME,
+    IDS_FLAGS_ENABLE_SPDY4A2_DESCRIPTION,
+    kOsAll,
+    SINGLE_VALUE_TYPE(switches::kEnableSpdy4a2)
+  },
+  {
     "enable-async-dns",
     IDS_FLAGS_ENABLE_ASYNC_DNS_NAME,
     IDS_FLAGS_ENABLE_ASYNC_DNS_DESCRIPTION,
@@ -762,6 +769,13 @@
     SINGLE_VALUE_TYPE(switches::kDisableLegacyEncryptedMedia)
   },
   {
+    "override-encrypted-media-canplaytype",
+    IDS_FLAGS_ENCRYPTED_MEDIA_CANPLAYTYPE_OVERRIDE_NAME,
+    IDS_FLAGS_ENCRYPTED_MEDIA_CANPLAYTYPE_OVERRIDE_DESCRIPTION,
+    kOsMac | kOsWin,
+    SINGLE_VALUE_TYPE(switches::kOverrideEncryptedMediaCanPlayType)
+  },
+  {
     "enable-opus-playback",
     IDS_FLAGS_ENABLE_OPUS_PLAYBACK_NAME,
     IDS_FLAGS_ENABLE_OPUS_PLAYBACK_DESCRIPTION,
@@ -779,7 +793,7 @@
     "enable-managed-users",
     IDS_FLAGS_ENABLE_LOCALLY_MANAGED_USERS_NAME,
     IDS_FLAGS_ENABLE_LOCALLY_MANAGED_USERS_DESCRIPTION,
-    kOsMac | kOsWin | kOsLinux | kOsAndroid | kOsCrOSOwnerOnly,
+    kOsMac | kOsWin | kOsLinux | kOsCrOSOwnerOnly,
     SINGLE_VALUE_TYPE(switches::kEnableManagedUsers)
   },
 #if defined(USE_ASH)
@@ -903,6 +917,13 @@
     SINGLE_VALUE_TYPE(switches::kEnableSpellingAutoCorrect)
   },
   {
+    "enable-scroll-prediction",
+    IDS_FLAGS_ENABLE_SCROLL_PREDICTION_NAME,
+    IDS_FLAGS_ENABLE_SCROLL_PREDICTION_DESCRIPTION,
+    kOsDesktop,
+    SINGLE_VALUE_TYPE(switches::kEnableScrollPrediction)
+  },
+  {
     "touch-events",
     IDS_TOUCH_EVENTS_NAME,
     IDS_TOUCH_EVENTS_DESCRIPTION,
@@ -933,7 +954,7 @@
   },
 #if defined(OS_CHROMEOS)
   {
-      "ash-use-alt-shelf",
+      "ash-use-alternate-shelf",
       IDS_FLAGS_ALTERNATE_SHELF_LAYOUT_NAME,
       IDS_FLAGS_ALTERNATE_SHELF_LAYOUT_DESCRIPTION,
       kOsCrOS,
@@ -1079,11 +1100,18 @@
     SINGLE_VALUE_TYPE(ash::switches::kAshDisableNewLockAnimations),
   },
   {
-    "file-manager-no-checkboxes",
-    IDS_FLAGS_FILE_MANAGER_NO_CHECKBOXES_NAME,
-    IDS_FLAGS_FILE_MANAGER_NO_CHECKBOXES_DESCRIPTION,
+    "file-manager-show-checkboxes",
+    IDS_FLAGS_FILE_MANAGER_SHOW_CHECKBOXES_NAME,
+    IDS_FLAGS_FILE_MANAGER_SHOW_CHECKBOXES_DESCRIPTION,
     kOsCrOS,
-    SINGLE_VALUE_TYPE(chromeos::switches::kFileManagerNoCheckboxes)
+    SINGLE_VALUE_TYPE(chromeos::switches::kFileManagerShowCheckboxes)
+  },
+  {
+    "file-manager-enable-sharing",
+    IDS_FLAGS_FILE_MANAGER_ENABLE_SHARING_NAME,
+    IDS_FLAGS_FILE_MANAGER_ENABLE_SHARING_DESCRIPTION,
+    kOsCrOS,
+    SINGLE_VALUE_TYPE(chromeos::switches::kFileManagerEnableSharing)
   },
   {
     "disable-app-mode",
@@ -1243,6 +1271,14 @@
     SINGLE_VALUE_TYPE(switches::kEnablePasswordGeneration)
   },
   {
+    "enable-password-autofill-public-suffix-domain-matching",
+    IDS_FLAGS_ENABLE_PASSWORD_AUTOFILL_PUBLIC_SUFFIX_DOMAIN_MATCHING_NAME,
+    IDS_FLAGS_ENABLE_PASSWORD_AUTOFILL_PUBLIC_SUFFIX_DOMAIN_MATCHING_DESCRIPTION,
+    kOsAndroid,
+    SINGLE_VALUE_TYPE(
+        switches::kEnablePasswordAutofillPublicSuffixDomainMatching)
+  },
+  {
     "enable-deferred-image-decoding",
     IDS_FLAGS_ENABLE_DEFERRED_IMAGE_DECODING_NAME,
     IDS_FLAGS_ENABLE_DEFERRED_IMAGE_DECODING_DESCRIPTION,
@@ -1257,13 +1293,6 @@
     SINGLE_VALUE_TYPE(switches::kPerformanceMonitorGathering)
   },
   {
-    "disable-native-autofill-ui",
-    IDS_FLAGS_DISABLE_NATIVE_AUTOFILL_UI_NAME,
-    IDS_FLAGS_DISABLE_NATIVE_AUTOFILL_UI_DESCRIPTION,
-    kOsDesktop,
-    SINGLE_VALUE_TYPE(switches::kDisableNativeAutofillUi)
-  },
-  {
     "enable-experimental-form-filling",
     IDS_FLAGS_ENABLE_EXPERIMENTAL_FORM_FILLING_NAME,
     IDS_FLAGS_ENABLE_EXPERIMENTAL_FORM_FILLING_DESCRIPTION,
@@ -1317,7 +1346,7 @@
     "enable-rich-notifications",
     IDS_FLAGS_ENABLE_RICH_NOTIFICATIONS_NAME,
     IDS_FLAGS_ENABLE_RICH_NOTIFICATIONS_DESCRIPTION,
-    kOsWin | kOsCrOS | kOsMac,
+    kOsWin | kOsMac,
     ENABLE_DISABLE_VALUE_TYPE(
         message_center::switches::kEnableRichNotifications,
         message_center::switches::kDisableRichNotifications)
@@ -1445,13 +1474,6 @@
     SINGLE_VALUE_TYPE(switches::kEnableTcpFastOpen)
   },
   {
-    "enable-webp-in-accept-header",
-    IDS_FLAGS_ENABLE_WEBP_IN_ACCEPT_HEADER_NAME,
-    IDS_FLAGS_ENABLE_WEBP_IN_ACCEPT_HEADER_DESCRIPTION,
-    kOsAll,
-    SINGLE_VALUE_TYPE(switches::kEnableWebPInAcceptHeader)
-  },
-  {
     "apps-use-native-frame",
     IDS_FLAGS_ENABLE_NATIVE_FRAMES_FOR_APPS_NAME,
     IDS_FLAGS_ENABLE_NATIVE_FRAMES_FOR_APPS_DESCRIPTION,
@@ -1466,26 +1488,12 @@
     SINGLE_VALUE_TYPE(switches::kSyncfsEnableDirectoryOperation),
   },
   {
-    "enable-draggable-menu-button",
-    IDS_FLAGS_ENABLE_DRAGGABLE_MENU_BUTTON_NAME,
-    IDS_FLAGS_ENABLE_DRAGGABLE_MENU_BUTTON_DESCRIPTION,
-    kOsAndroid,
-    SINGLE_VALUE_TYPE(switches::kEnableDraggableMenuButton)
-  },
-  {
     "enable-reset-profile-settings",
     IDS_FLAGS_ENABLE_RESET_PROFILE_SETTINGS_NAME,
     IDS_FLAGS_ENABLE_RESET_PROFILE_SETTINGS_DESCRIPTION,
     kOsAll,
     SINGLE_VALUE_TYPE(switches::kEnableResetProfileSettings)
   },
-  {
-    "enable-device-discovery",
-    IDS_FLAGS_ENABLE_DEVICE_DISCOVERY_NAME,
-    IDS_FLAGS_ENABLE_DEVICE_DISCOVERY_DESCRIPTION,
-    kOsDesktop,
-    SINGLE_VALUE_TYPE(switches::kEnableDeviceDiscovery)
-  },
 #if defined(OS_MACOSX)
   {
     "enable-app-list-shim",
@@ -1572,6 +1580,36 @@
     kOsAll,
     SINGLE_VALUE_TYPE(switches::kEnableTranslateSettings)
   },
+  {
+    "enable-web-midi",
+    IDS_FLAGS_ENABLE_WEB_MIDI_NAME,
+    IDS_FLAGS_ENABLE_WEB_MIDI_DESCRIPTION,
+    kOsMac,
+    SINGLE_VALUE_TYPE(switches::kEnableWebMIDI)
+  },
+  {
+    "enable-new-profile-management",
+    IDS_FLAGS_ENABLE_NEW_PROFILE_MANAGEMENT_NAME,
+    IDS_FLAGS_ENABLE_NEW_PROFILE_MANAGEMENT_DESCRIPTION,
+    kOsWin,
+    SINGLE_VALUE_TYPE(switches::kNewProfileManagement)
+  },
+  {
+    "enable-gaia-profile-info",
+    IDS_FLAGS_ENABLE_GAIA_PROFILE_INFO_NAME,
+    IDS_FLAGS_ENABLE_GAIA_PROFILE_INFO_DESCRIPTION,
+    kOsMac | kOsWin,
+    SINGLE_VALUE_TYPE(switches::kGaiaProfileInfo)
+  },
+#if defined(OS_WIN)
+  {
+    "disable-app-launcher",
+    IDS_FLAGS_DISABLE_APP_LIST_NAME,
+    IDS_FLAGS_DISABLE_APP_LIST_DESCRIPTION,
+    kOsAll,
+    SINGLE_VALUE_TYPE(switches::kDisableAppList)
+  },
+#endif
 };
 
 const Experiment* experiments = kExperiments;
diff --git a/chrome/browser/android/OWNERS b/chrome/browser/android/OWNERS
index ac80525..29d0acf 100644
--- a/chrome/browser/android/OWNERS
+++ b/chrome/browser/android/OWNERS
@@ -1,5 +1,3 @@
 bulach@chromium.org
-jcivelli@chromium.org
-nileshagrawal@chromium.org
 tedchoc@chromium.org
 yfriedman@chromium.org
diff --git a/chrome/browser/android/chrome_jni_registrar.cc b/chrome/browser/android/chrome_jni_registrar.cc
index b388f5a..379c23d 100644
--- a/chrome/browser/android/chrome_jni_registrar.cc
+++ b/chrome/browser/android/chrome_jni_registrar.cc
@@ -10,7 +10,9 @@
 #include "chrome/browser/android/chrome_web_contents_delegate_android.h"
 #include "chrome/browser/android/content_view_util.h"
 #include "chrome/browser/android/dev_tools_server.h"
+#include "chrome/browser/android/favicon_helper.h"
 #include "chrome/browser/android/intent_helper.h"
+#include "chrome/browser/android/most_visited_sites.h"
 #include "chrome/browser/android/provider/chrome_browser_provider.h"
 #include "chrome/browser/android/tab_android.h"
 #include "chrome/browser/autofill/android/personal_data_manager_android.h"
@@ -28,7 +30,7 @@
 #include "chrome/browser/ui/android/ssl_client_certificate_request.h"
 #include "chrome/browser/ui/android/validation_message_bubble_android.h"
 #include "chrome/browser/ui/android/website_settings_popup_android.h"
-#include "components/autofill/browser/android/component_jni_registrar.h"
+#include "components/autofill/core/browser/android/component_jni_registrar.h"
 #include "components/navigation_interception/component_jni_registrar.h"
 #include "components/web_contents_delegate_android/component_jni_registrar.h"
 
@@ -59,9 +61,11 @@
     RegisterChromeWebContentsDelegateAndroid },
   { "ContentViewUtil", RegisterContentViewUtil },
   { "DevToolsServer", RegisterDevToolsServer },
+  { "FaviconHelper", FaviconHelper::RegisterFaviconHelper },
   { "IntentHelper", RegisterIntentHelper },
   { "JavascriptAppModalDialog",
     JavascriptAppModalDialogAndroid::RegisterJavascriptAppModalDialog },
+  { "MostVisitedSites", RegisterMostVisitedSites },
   { "NavigationPopup", NavigationPopup::RegisterNavigationPopup },
   { "PersonalDataManagerAndroid",
     autofill::PersonalDataManagerAndroid::Register },
@@ -84,5 +88,5 @@
                                arraysize(kChromeRegisteredMethods));
 }
 
-} // namespace android
-} // namespace chrome
+}  // namespace android
+}  // namespace chrome
diff --git a/chrome/browser/android/chrome_web_contents_delegate_android.h b/chrome/browser/android/chrome_web_contents_delegate_android.h
index dbfb535..d86c89f 100644
--- a/chrome/browser/android/chrome_web_contents_delegate_android.h
+++ b/chrome/browser/android/chrome_web_contents_delegate_android.h
@@ -8,7 +8,7 @@
 #include <jni.h>
 
 #include "base/files/file_path.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "components/web_contents_delegate_android/web_contents_delegate_android.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
diff --git a/chrome/browser/android/crash_dump_manager.cc b/chrome/browser/android/crash_dump_manager.cc
index 07e0881..6ee4e04 100644
--- a/chrome/browser/android/crash_dump_manager.cc
+++ b/chrome/browser/android/crash_dump_manager.cc
@@ -14,8 +14,8 @@
 #include "base/rand_util.h"
 #include "base/stl_util.h"
 #include "base/strings/stringprintf.h"
+#include "chrome/common/chrome_paths.h"
 #include "chrome/common/descriptors_android.h"
-#include "components/breakpad/common/breakpad_paths.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/child_process_data.h"
 #include "content/public/browser/file_descriptor_info.h"
@@ -91,7 +91,7 @@
 
   if (file_size == 0) {
     // Empty minidump, this process did not crash. Just remove the file.
-    r = file_util::Delete(minidump_path, false);
+    r = base::Delete(minidump_path, false);
     DCHECK(r) << "Failed to delete temporary minidump file "
               << minidump_path.value();
     return;
@@ -100,7 +100,7 @@
   // We are dealing with a valid minidump. Copy it to the crash report
   // directory from where Java code will upload it later on.
   base::FilePath crash_dump_dir;
-  r = PathService::Get(breakpad::DIR_CRASH_DUMPS, &crash_dump_dir);
+  r = PathService::Get(chrome::DIR_CRASH_DUMPS, &crash_dump_dir);
   if (!r) {
     NOTREACHED() << "Failed to retrieve the crash dump directory.";
     return;
@@ -111,11 +111,11 @@
       base::StringPrintf("chromium-renderer-minidump-%016" PRIx64 ".dmp%d",
                          rand, pid);
   base::FilePath dest_path = crash_dump_dir.Append(filename);
-  r = file_util::Move(minidump_path, dest_path);
+  r = base::Move(minidump_path, dest_path);
   if (!r) {
     LOG(ERROR) << "Failed to move crash dump from " << minidump_path.value()
                << " to " << dest_path.value();
-    file_util::Delete(minidump_path, false);
+    base::Delete(minidump_path, false);
     return;
   }
   LOG(INFO) << "Crash minidump successfully generated: " <<
diff --git a/chrome/browser/android/dev_tools_server.cc b/chrome/browser/android/dev_tools_server.cc
index 8602490..d7f9617 100644
--- a/chrome/browser/android/dev_tools_server.cc
+++ b/chrome/browser/android/dev_tools_server.cc
@@ -16,11 +16,11 @@
 #include "base/logging.h"
 #include "base/strings/stringprintf.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/devtools/devtools_adb_bridge.h"
 #include "chrome/browser/history/top_sites.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/android/tab_model/tab_model.h"
 #include "chrome/browser/ui/android/tab_model/tab_model_list.h"
-#include "chrome/common/chrome_version_info.h"
 #include "content/public/browser/android/devtools_auth.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/devtools_http_handler.h"
@@ -33,21 +33,21 @@
 #include "net/socket/unix_domain_socket_posix.h"
 #include "net/url_request/url_request_context_getter.h"
 #include "ui/base/resource/resource_bundle.h"
+#include "webkit/common/user_agent/user_agent_util.h"
 
 namespace {
 
 const char kFrontEndURL[] =
-    "http://chrome-devtools-frontend.appspot.com/static/%s/devtools.html";
-const char kDefaultSocketName[] = "chrome_devtools_remote";
+    "http://chrome-devtools-frontend.appspot.com/serve_rev/%s/devtools.html";
+const char kDefaultSocketNamePrefix[] = "chrome";
 const char kTetheringSocketName[] = "chrome_devtools_tethering_%d_%d";
 
 // Delegate implementation for the devtools http handler on android. A new
 // instance of this gets created each time devtools is enabled.
 class DevToolsServerDelegate : public content::DevToolsHttpHandlerDelegate {
  public:
-  explicit DevToolsServerDelegate(bool use_bundled_frontend_resources)
-      : use_bundled_frontend_resources_(use_bundled_frontend_resources),
-        last_tethering_socket_(0) {
+  DevToolsServerDelegate()
+      : last_tethering_socket_(0) {
   }
 
   virtual std::string GetDiscoveryPageHTML() OVERRIDE {
@@ -62,7 +62,7 @@
   }
 
   virtual bool BundlesFrontendResources() OVERRIDE {
-    return use_bundled_frontend_resources_;
+    return false;
   }
 
   virtual base::FilePath GetDebugFrontendDir() OVERRIDE {
@@ -124,7 +124,6 @@
       top_sites->SyncWithHistory();
   }
 
-  bool use_bundled_frontend_resources_;
   int last_tethering_socket_;
 
   DISALLOW_COPY_AND_ASSIGN(DevToolsServerDelegate);
@@ -133,8 +132,8 @@
 }  // namespace
 
 DevToolsServer::DevToolsServer()
-    : use_bundled_frontend_resources_(false),
-      socket_name_(kDefaultSocketName),
+    : socket_name_(base::StringPrintf(kDevToolsChannelNameFormat,
+                                      kDefaultSocketNamePrefix)),
       protocol_handler_(NULL) {
   // Override the default socket name if one is specified on the command line.
   const CommandLine& command_line = *CommandLine::ForCurrentProcess();
@@ -144,10 +143,9 @@
   }
 }
 
-DevToolsServer::DevToolsServer(bool use_bundled_frontend_resources,
-                               const std::string& socket_name)
-    : use_bundled_frontend_resources_(use_bundled_frontend_resources),
-      socket_name_(socket_name),
+DevToolsServer::DevToolsServer(const std::string& socket_name_prefix)
+    : socket_name_(base::StringPrintf(kDevToolsChannelNameFormat,
+                                      socket_name_prefix.c_str())),
       protocol_handler_(NULL) {
 }
 
@@ -159,17 +157,14 @@
   if (protocol_handler_)
     return;
 
-  chrome::VersionInfo version_info;
-
   protocol_handler_ = content::DevToolsHttpHandler::Start(
       new net::UnixDomainSocketWithAbstractNamespaceFactory(
           socket_name_,
           base::StringPrintf("%s_%d", socket_name_.c_str(), getpid()),
           base::Bind(&content::CanUserConnectToDevTools)),
-      use_bundled_frontend_resources_ ?
-          "" :
-          base::StringPrintf(kFrontEndURL, version_info.Version().c_str()),
-      new DevToolsServerDelegate(use_bundled_frontend_resources_));
+      base::StringPrintf(kFrontEndURL,
+                         webkit_glue::GetWebKitRevision().c_str()),
+      new DevToolsServerDelegate());
 }
 
 void DevToolsServer::Stop() {
@@ -191,11 +186,9 @@
 
 static jint InitRemoteDebugging(JNIEnv* env,
                                 jobject obj,
-                                jboolean use_bundled_frontend_resources,
-                                jstring socketName) {
+                                jstring socket_name_prefix) {
   DevToolsServer* server = new DevToolsServer(
-      use_bundled_frontend_resources,
-      base::android::ConvertJavaStringToUTF8(env, socketName));
+      base::android::ConvertJavaStringToUTF8(env, socket_name_prefix));
   return reinterpret_cast<jint>(server);
 }
 
diff --git a/chrome/browser/android/dev_tools_server.h b/chrome/browser/android/dev_tools_server.h
index 775f0c0..72ddc89 100644
--- a/chrome/browser/android/dev_tools_server.h
+++ b/chrome/browser/android/dev_tools_server.h
@@ -17,8 +17,7 @@
 class DevToolsServer {
  public:
   DevToolsServer();
-  DevToolsServer(bool use_bundled_frontend_resources,
-                 const std::string& socket_name);
+  explicit DevToolsServer(const std::string& socket_name_prefix);
   ~DevToolsServer();
 
   // Opens linux abstract socket to be ready for remote debugging.
@@ -30,7 +29,6 @@
   bool IsStarted() const;
 
  private:
-  bool use_bundled_frontend_resources_;
   std::string socket_name_;
   content::DevToolsHttpHandler* protocol_handler_;
 
diff --git a/chrome/browser/android/favicon_helper.cc b/chrome/browser/android/favicon_helper.cc
new file mode 100644
index 0000000..03dc5d0
--- /dev/null
+++ b/chrome/browser/android/favicon_helper.cc
@@ -0,0 +1,101 @@
+// 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/android/favicon_helper.h"
+
+#include <jni.h>
+
+#include "base/android/jni_android.h"
+#include "base/android/jni_string.h"
+#include "base/android/scoped_java_ref.h"
+#include "base/bind.h"
+#include "chrome/browser/favicon/favicon_service.h"
+#include "chrome/browser/favicon/favicon_service_factory.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_android.h"
+#include "jni/FaviconHelper_jni.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/gfx/android/java_bitmap.h"
+
+using base::android::ScopedJavaGlobalRef;
+using base::android::ScopedJavaLocalRef;
+using base::android::AttachCurrentThread;
+using base::android::ConvertJavaStringToUTF16;
+using base::android::ConvertUTF8ToJavaString;
+using base::android::MethodID;
+
+namespace {
+
+void FaviconImageCallback(
+    ScopedJavaGlobalRef<jobject>* java_favicon_image_callback,
+    const chrome::FaviconImageResult& favicon_image_result) {
+  JNIEnv* env = AttachCurrentThread();
+
+  // Convert favicon_image_result to java objects.
+  ScopedJavaLocalRef<jstring> java_icon_url = ConvertUTF8ToJavaString(
+      env, favicon_image_result.icon_url.spec());
+  SkBitmap favicon_bitmap = favicon_image_result.image.AsBitmap();
+  ScopedJavaLocalRef<jobject> java_favicon_bitmap = gfx::ConvertToJavaBitmap(
+      &favicon_bitmap);
+
+  // Call java side FaviconImageCallback method.
+  Java_FaviconImageCallback_onFaviconAvailable(
+      env, java_favicon_image_callback->obj(), java_favicon_bitmap.obj(),
+      java_icon_url.obj());
+}
+
+}  // namespace
+
+static jint Init(JNIEnv* env, jclass clazz) {
+  return reinterpret_cast<jint>(new FaviconHelper());
+}
+
+FaviconHelper::FaviconHelper() {
+  cancelable_task_tracker_.reset(new CancelableTaskTracker());
+}
+
+void FaviconHelper::Destroy(JNIEnv* env, jobject obj) {
+  delete this;
+}
+
+jboolean FaviconHelper::GetFaviconImageForURL(
+    JNIEnv* env, jobject obj, jobject jprofile, jstring page_url,
+    jint icon_types, jint desired_size_in_dip,
+    jobject java_favicon_image_callback) {
+  Profile* profile = ProfileAndroid::FromProfileAndroid(jprofile);
+  DCHECK(profile);
+  if (!profile)
+    return false;
+
+  FaviconService* favicon_service = FaviconServiceFactory::GetForProfile(
+      profile, Profile::EXPLICIT_ACCESS);
+  DCHECK(favicon_service);
+  if (!favicon_service)
+    return false;
+
+  FaviconService::FaviconForURLParams params(
+      profile, GURL(ConvertJavaStringToUTF16(env, page_url)),
+      static_cast<int>(icon_types), static_cast<int>(desired_size_in_dip));
+
+  ScopedJavaGlobalRef<jobject>* j_scoped_favicon_callback =
+      new ScopedJavaGlobalRef<jobject>();
+  j_scoped_favicon_callback->Reset(env, java_favicon_image_callback);
+
+  FaviconService::FaviconImageCallback callback_runner = base::Bind(
+      &FaviconImageCallback, base::Owned(j_scoped_favicon_callback));
+
+  favicon_service->GetFaviconImageForURL(
+      params, callback_runner,
+      cancelable_task_tracker_.get());
+
+  return true;
+}
+
+FaviconHelper::~FaviconHelper() {
+}
+
+// static
+bool FaviconHelper::RegisterFaviconHelper(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
diff --git a/chrome/browser/android/favicon_helper.h b/chrome/browser/android/favicon_helper.h
new file mode 100644
index 0000000..a360995
--- /dev/null
+++ b/chrome/browser/android/favicon_helper.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 CHROME_BROWSER_ANDROID_FAVICON_HELPER_H_
+#define CHROME_BROWSER_ANDROID_FAVICON_HELPER_H_
+
+#include <jni.h>
+
+#include "base/memory/scoped_ptr.h"
+#include "chrome/common/cancelable_task_tracker.h"
+
+class FaviconHelper {
+ public:
+  FaviconHelper();
+  void Destroy(JNIEnv* env, jobject obj);
+  jboolean GetFaviconImageForURL(JNIEnv* env, jobject obj, jobject jprofile,
+                                 jstring page_url, jint icon_types,
+                                 jint desired_size_in_dip,
+                                 jobject java_favicon_image_callback);
+  static bool RegisterFaviconHelper(JNIEnv* env);
+ private:
+  scoped_ptr<CancelableTaskTracker> cancelable_task_tracker_;
+
+  virtual ~FaviconHelper();
+
+  DISALLOW_COPY_AND_ASSIGN(FaviconHelper);
+};
+
+#endif  // CHROME_BROWSER_ANDROID_FAVICON_HELPER_H_
diff --git a/chrome/browser/android/infobar_stubs.cc b/chrome/browser/android/infobar_stubs.cc
deleted file mode 100644
index 9316a7b..0000000
--- a/chrome/browser/android/infobar_stubs.cc
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/infobars/confirm_infobar_delegate.h"
-#include "chrome/browser/translate/translate_infobar_delegate.h"
-
-// Clank implementations of cross-platform API, never used
-// since infobars are created using the InfoBarFactory but we need
-// them implemented so the binary links both upstream and downstream.
-InfoBar* ConfirmInfoBarDelegate::CreateInfoBar(InfoBarService* owner) {
-  NOTREACHED() << "ConfirmInfoBar: InfoBarFactory should be used on Android";
-  return NULL;
-}
-
-InfoBar* TranslateInfoBarDelegate::CreateInfoBar(InfoBarService* owner) {
-  return NULL;
-}
diff --git a/chrome/browser/android/most_visited_sites.cc b/chrome/browser/android/most_visited_sites.cc
new file mode 100644
index 0000000..779fb55
--- /dev/null
+++ b/chrome/browser/android/most_visited_sites.cc
@@ -0,0 +1,183 @@
+// 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/android/most_visited_sites.h"
+
+#include "base/android/jni_android.h"
+#include "base/android/jni_array.h"
+#include "base/android/jni_string.h"
+#include "base/android/scoped_java_ref.h"
+#include "chrome/browser/history/history_types.h"
+#include "chrome/browser/history/top_sites.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_android.h"
+#include "content/public/browser/browser_thread.h"
+#include "jni/MostVisitedSites_jni.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/gfx/android/java_bitmap.h"
+#include "ui/gfx/codec/jpeg_codec.h"
+
+using base::android::AttachCurrentThread;
+using base::android::ConvertUTF8ToJavaString;
+using base::android::ConvertJavaStringToUTF8;
+using base::android::ScopedJavaGlobalRef;
+using base::android::ToJavaArrayOfStrings;
+using base::android::CheckException;
+using content::BrowserThread;
+using history::TopSites;
+
+namespace chrome {
+namespace android {
+
+bool RegisterMostVisitedSites(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
+}  // namespace android
+}  // namespace chrome
+
+namespace {
+
+class NativeCallback : public base::RefCounted<NativeCallback> {
+ public:
+  NativeCallback(jobject j_callback_obj, int num_results)
+      : num_results_(num_results) {
+    JNIEnv* env = AttachCurrentThread();
+    j_callback_obj_.Reset(env, j_callback_obj);
+  }
+
+  void OnMostVisitedURLsAvailable(
+      const history::MostVisitedURLList& visited_list) {
+    std::vector<string16> titles;
+    std::vector<std::string> urls;
+    ExtractMostVisitedTitlesAndURLs(visited_list, &titles, &urls);
+
+    JNIEnv* env = AttachCurrentThread();
+    Java_MostVisitedURLsCallback_onMostVisitedURLsAvailable(
+        env,
+        j_callback_obj_.obj(),
+        ToJavaArrayOfStrings(env, titles).obj(),
+        ToJavaArrayOfStrings(env, urls).obj());
+  }
+
+ private:
+  friend class base::RefCounted<NativeCallback>;
+  ~NativeCallback() {}
+
+  void ExtractMostVisitedTitlesAndURLs(
+      const history::MostVisitedURLList& visited_list,
+      std::vector<string16>* titles,
+      std::vector<std::string>* urls) {
+    for (size_t i = 0; i < visited_list.size() && i < num_results_; ++i) {
+      const history::MostVisitedURL& visited = visited_list[i];
+
+      if (visited.url.is_empty())
+        break;  // This is the signal that there are no more real visited sites.
+
+      titles->push_back(visited.title);
+      urls->push_back(visited.url.spec());
+    }
+  }
+
+  ScopedJavaGlobalRef<jobject> j_callback_obj_;
+  size_t num_results_;
+};
+
+SkBitmap ExtractThumbnail(const base::RefCountedMemory& image_data) {
+  scoped_ptr<SkBitmap> image(gfx::JPEGCodec::Decode(
+      image_data.front(),
+      image_data.size()));
+  return image.get() ? *image : SkBitmap();
+}
+
+void OnObtainedThumbnail(
+    ScopedJavaGlobalRef<jobject>* bitmap,
+    ScopedJavaGlobalRef<jobject>* j_callback_ref) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  JNIEnv* env = AttachCurrentThread();
+  Java_ThumbnailCallback_onMostVisitedURLsThumbnailAvailable(
+      env, j_callback_ref->obj(), bitmap->obj());
+}
+
+void GetUrlThumbnailTask(
+    std::string url_string,
+    scoped_refptr<TopSites> top_sites,
+    ScopedJavaGlobalRef<jobject>* j_callback_ref) {
+  JNIEnv* env = AttachCurrentThread();
+
+  ScopedJavaGlobalRef<jobject>* j_bitmap_ref =
+      new ScopedJavaGlobalRef<jobject>();
+
+  GURL gurl(url_string);
+
+  scoped_refptr<base::RefCountedMemory> data;
+  if (top_sites->GetPageThumbnail(gurl, &data)) {
+    SkBitmap thumbnail_bitmap = ExtractThumbnail(*data.get());
+    if (!thumbnail_bitmap.empty()) {
+      j_bitmap_ref->Reset(
+          env,
+          gfx::ConvertToJavaBitmap(&thumbnail_bitmap).obj());
+    }
+  }
+
+  // Since j_callback_ref is owned by this callback,
+  // when the callback falls out of scope it will be deleted.
+  // We need to pass ownership to the next callback.
+  ScopedJavaGlobalRef<jobject>* j_callback_ref_pass =
+      new ScopedJavaGlobalRef<jobject>(*j_callback_ref);
+  BrowserThread::PostTask(
+      BrowserThread::UI, FROM_HERE,
+      base::Bind(
+          &OnObtainedThumbnail,
+          base::Owned(j_bitmap_ref),base::Owned(j_callback_ref_pass)));
+}
+
+}  // namespace
+
+void GetMostVisitedURLs(
+    JNIEnv* env,
+    jclass clazz,
+    jobject j_profile,
+    jobject j_callback_obj,
+    jint num_results) {
+  Profile* profile = ProfileAndroid::FromProfileAndroid(j_profile);
+
+  DCHECK(profile);
+  if (!profile)
+    return;
+
+  TopSites* top_sites = profile->GetTopSites();
+
+  scoped_refptr<NativeCallback> native_callback =
+      new NativeCallback(j_callback_obj, static_cast<int>(num_results));
+  top_sites->GetMostVisitedURLs(
+      base::Bind(&NativeCallback::OnMostVisitedURLsAvailable,
+                 native_callback));
+}
+
+// May be called from any thread
+void GetURLThumbnail(
+    JNIEnv* env,
+    jclass clazz,
+    jobject j_profile,
+    jstring url,
+    jobject j_callback_obj) {
+  Profile* profile = ProfileAndroid::FromProfileAndroid(j_profile);
+
+  DCHECK(profile);
+  if (!profile)
+    return;
+
+  ScopedJavaGlobalRef<jobject>* j_callback_ref =
+      new ScopedJavaGlobalRef<jobject>();
+  j_callback_ref->Reset(env, j_callback_obj);
+
+  std::string url_string = ConvertJavaStringToUTF8(env, url);
+  scoped_refptr<TopSites> top_sites(profile->GetTopSites());
+  BrowserThread::PostTask(
+      BrowserThread::DB, FROM_HERE, base::Bind(
+          &GetUrlThumbnailTask,
+          url_string,
+          top_sites, base::Owned(j_callback_ref)));
+}
diff --git a/chrome/browser/android/most_visited_sites.h b/chrome/browser/android/most_visited_sites.h
new file mode 100644
index 0000000..6b1c85d
--- /dev/null
+++ b/chrome/browser/android/most_visited_sites.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 CHROME_BROWSER_ANDROID_MOST_VISITED_SITES_H_
+#define CHROME_BROWSER_ANDROID_MOST_VISITED_SITES_H_
+
+#include <jni.h>
+
+namespace chrome {
+namespace android {
+
+bool RegisterMostVisitedSites(JNIEnv* env);
+
+}  // namespace android
+}  // namespace chrome
+
+#endif  // CHROME_BROWSER_ANDROID_MOST_VISITED_SITES_H_
diff --git a/chrome/browser/android/provider/chrome_browser_provider.cc b/chrome/browser/android/provider/chrome_browser_provider.cc
index 6353f44..71764ef 100644
--- a/chrome/browser/android/provider/chrome_browser_provider.cc
+++ b/chrome/browser/android/provider/chrome_browser_provider.cc
@@ -13,7 +13,7 @@
 #include "base/logging.h"
 #include "base/memory/ref_counted_memory.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/android/provider/blocking_ui_thread_async_request.h"
 #include "chrome/browser/android/provider/bookmark_model_observer_task.h"
 #include "chrome/browser/android/provider/run_on_ui_thread_blocking.h"
@@ -894,8 +894,9 @@
         template_service->GetDefaultSearchProvider();
     if (search_engine) {
       const TemplateURLRef* search_url = &search_engine->url_ref();
-      std::string url = search_url->ReplaceSearchTerms(
-                     TemplateURLRef::SearchTermsArgs(row->search_term()));
+      TemplateURLRef::SearchTermsArgs search_terms_args(row->search_term());
+      search_terms_args.append_extra_query_params = true;
+      std::string url = search_url->ReplaceSearchTerms(search_terms_args);
       if (!url.empty()) {
         row->set_url(GURL(url));
         row->set_template_url_id(search_engine->id());
diff --git a/chrome/browser/android/resource_id.h b/chrome/browser/android/resource_id.h
index 459754c..3393724 100644
--- a/chrome/browser/android/resource_id.h
+++ b/chrome/browser/android/resource_id.h
@@ -31,7 +31,7 @@
 DEFINE_RESOURCE_ID(IDR_INFOBAR_PLUGIN_INSTALL, R.drawable.infobar_plugin)
 DEFINE_RESOURCE_ID(IDR_INFOBAR_RESTORE_SESSION, R.drawable.infobar_restore)
 DEFINE_RESOURCE_ID(IDR_INFOBAR_SAVE_PASSWORD, R.drawable.infobar_savepassword)
-DEFINE_RESOURCE_ID(IDR_INFOBAR_SSL_WARNING, R.drawable.infobar_insecure)
+DEFINE_RESOURCE_ID(IDR_INFOBAR_WARNING, R.drawable.infobar_warning)
 DEFINE_RESOURCE_ID(IDR_INFOBAR_THEME, R.drawable.infobar_theme)
 DEFINE_RESOURCE_ID(IDR_INFOBAR_TRANSLATE, R.drawable.infobar_translate)
 
diff --git a/chrome/browser/android/tab_android.cc b/chrome/browser/android/tab_android.cc
index 010b376..3b5b2b1 100644
--- a/chrome/browser/android/tab_android.cc
+++ b/chrome/browser/android/tab_android.cc
@@ -65,8 +65,7 @@
       contents,
       autofill::TabAutofillManagerDelegate::FromWebContents(contents),
       g_browser_process->GetApplicationLocale(),
-      autofill::AutofillManager::ENABLE_AUTOFILL_DOWNLOAD_MANAGER,
-      true);
+      autofill::AutofillManager::ENABLE_AUTOFILL_DOWNLOAD_MANAGER);
   BlockedContentTabHelper::CreateForWebContents(contents);
   BookmarkTabHelper::CreateForWebContents(contents);
   CoreTabHelper::CreateForWebContents(contents);
diff --git a/chrome/browser/android/tab_android_test_stubs.cc b/chrome/browser/android/tab_android_test_stubs.cc
index edfd4cd..b26ae5f 100644
--- a/chrome/browser/android/tab_android_test_stubs.cc
+++ b/chrome/browser/android/tab_android_test_stubs.cc
@@ -6,6 +6,10 @@
 // needed to compile some tests.
 
 #include "chrome/browser/android/tab_android.h"
+#include "chrome/browser/infobars/confirm_infobar_delegate.h"
+#include "chrome/browser/translate/translate_infobar_delegate.h"
+#include "chrome/browser/ui/auto_login_infobar_delegate.h"
+#include "chrome/browser/ui/auto_login_infobar_delegate_android.h"
 
 // static
 TabAndroid* TabAndroid::FromWebContents(content::WebContents* web_contents) {
@@ -16,3 +20,40 @@
 TabAndroid* TabAndroid::GetNativeTab(JNIEnv* env, jobject obj) {
   return NULL;
 }
+
+// AutoLoginInfoBarDelegatAndroid empty implementation for test_shell.
+// TODO(miguelg) remove once the AutoLoginInfoBar is upstreamed.
+AutoLoginInfoBarDelegateAndroid::AutoLoginInfoBarDelegateAndroid(
+    InfoBarService* owner,
+    const AutoLoginInfoBarDelegate::Params& params)
+    : AutoLoginInfoBarDelegate(owner, params) {}
+
+AutoLoginInfoBarDelegateAndroid::~AutoLoginInfoBarDelegateAndroid() {}
+
+bool AutoLoginInfoBarDelegateAndroid::Accept() {
+  return false;
+}
+
+bool AutoLoginInfoBarDelegateAndroid::Cancel() {
+  return false;
+}
+
+base::string16 AutoLoginInfoBarDelegateAndroid::GetMessageText() const {
+  return base::string16();
+}
+
+// static
+bool AutoLoginInfoBarDelegateAndroid::Register(JNIEnv* env) {
+  return false;
+}
+
+// static
+InfoBar* ConfirmInfoBarDelegate::CreateInfoBar(InfoBarService* owner) {
+  NOTREACHED() << "ConfirmInfoBar: InfoBarFactory should be used on Android";
+  return NULL;
+}
+
+// static
+InfoBar* TranslateInfoBarDelegate::CreateInfoBar(InfoBarService* owner) {
+  return NULL;
+}
diff --git a/chrome/browser/app_controller_mac.h b/chrome/browser/app_controller_mac.h
index cea9bfd..46d8a05 100644
--- a/chrome/browser/app_controller_mac.h
+++ b/chrome/browser/app_controller_mac.h
@@ -10,12 +10,13 @@
 #import <Cocoa/Cocoa.h>
 #include <vector>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/observer_list.h"
 #include "base/prefs/pref_change_registrar.h"
 #include "ui/base/work_area_watcher_observer.h"
 
+class AppControllerProfileObserver;
 class BookmarkMenuBridge;
 class CommandUpdater;
 class GURL;
@@ -39,6 +40,10 @@
   // build the user-data specific main menu items.
   Profile* lastProfile_;
 
+  // The ProfileObserver observes the ProfileInfoCache and gets notified
+  // when a profile has been deleted.
+  scoped_ptr<AppControllerProfileObserver> profileInfoCacheObserver_;
+
   // Management of the bookmark menu which spans across all windows
   // (and Browser*s).
   scoped_ptr<BookmarkMenuBridge> bookmarkMenuBridge_;
@@ -46,7 +51,7 @@
 
   // The profile menu, which appears right before the Help menu. It is only
   // available when multiple profiles is enabled.
-  scoped_nsobject<ProfileMenuController> profileMenuController_;
+  base::scoped_nsobject<ProfileMenuController> profileMenuController_;
 
   // If we're told to open URLs (in particular, via |-application:openFiles:| by
   // Launch Services) before we've launched the browser, we queue them up in
@@ -101,7 +106,7 @@
 - (IBAction)showPreferences:(id)sender;
 
 // Redirect in the menu item from the expected target of "File's
-// Owner" (NSAppliation) for a Branded About Box
+// Owner" (NSApplication) for a Branded About Box
 - (IBAction)orderFrontStandardAboutPanel:(id)sender;
 
 // Toggles the "Confirm to Quit" preference.
diff --git a/chrome/browser/app_controller_mac.mm b/chrome/browser/app_controller_mac.mm
index 4aae313..3944238 100644
--- a/chrome/browser/app_controller_mac.mm
+++ b/chrome/browser/app_controller_mac.mm
@@ -28,6 +28,7 @@
 #include "chrome/browser/first_run/first_run.h"
 #include "chrome/browser/lifetime/application_lifetime.h"
 #include "chrome/browser/printing/print_dialog_cloud.h"
+#include "chrome/browser/profiles/profile_info_cache_observer.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/service/service_process_control.h"
 #include "chrome/browser/sessions/session_restore.h"
@@ -190,8 +191,57 @@
 - (BOOL)userWillWaitForInProgressDownloads:(int)downloadCount;
 - (BOOL)shouldQuitWithInProgressDownloads;
 - (void)executeApplication:(id)sender;
+- (void)profileWasRemoved:(const base::FilePath&)profilePath;
 @end
 
+class AppControllerProfileObserver : public ProfileInfoCacheObserver {
+ public:
+  AppControllerProfileObserver(
+      ProfileManager* profile_manager, AppController* app_controller)
+      : profile_manager_(profile_manager),
+        app_controller_(app_controller) {
+    DCHECK(profile_manager_);
+    DCHECK(app_controller_);
+    profile_manager_->GetProfileInfoCache().AddObserver(this);
+  }
+
+  virtual ~AppControllerProfileObserver() {
+    DCHECK(profile_manager_);
+    profile_manager_->GetProfileInfoCache().RemoveObserver(this);
+  }
+
+ private:
+  // ProfileInfoCacheObserver implementation:
+
+  virtual void OnProfileAdded(const base::FilePath& profile_path) OVERRIDE {
+  }
+
+  virtual void OnProfileWasRemoved(const base::FilePath& profile_path,
+                                   const string16& profile_name) OVERRIDE {
+    // When a profile is deleted we need to notify the AppController,
+    // so it can correctly update its pointer to the last used profile.
+    [app_controller_ profileWasRemoved:profile_path];
+  }
+
+  virtual void OnProfileWillBeRemoved(
+      const base::FilePath& profile_path) OVERRIDE {
+  }
+
+  virtual void OnProfileNameChanged(const base::FilePath& profile_path,
+                                    const string16& old_profile_name) OVERRIDE {
+  }
+
+  virtual void OnProfileAvatarChanged(
+      const base::FilePath& profile_path) OVERRIDE {
+  }
+
+  ProfileManager* profile_manager_;
+
+  AppController* app_controller_;  // Weak; owns us.
+
+  DISALLOW_COPY_AND_ASSIGN(AppControllerProfileObserver);
+};
+
 @implementation AppController
 
 @synthesize startupComplete = startupComplete_;
@@ -585,6 +635,11 @@
   EncodingMenuControllerDelegate::BuildEncodingMenu([self lastProfile],
                                                     encodingMenu);
 
+  // Instantiate the ProfileInfoCache observer so that we can get
+  // notified when a profile is deleted.
+  profileInfoCacheObserver_.reset(new AppControllerProfileObserver(
+      g_browser_process->profile_manager(), self));
+
   // Since Chrome is localized to more languages than the OS, tell Cocoa which
   // menu is the Help so it can add the search item to it.
   [NSApp setHelpMenu:helpMenu_];
@@ -659,8 +714,8 @@
       IDS_DOWNLOAD_REMOVE_CONFIRM_CANCEL_BUTTON_LABEL);
 
   // 'waitButton' is the default choice.
-  int choice = NSRunAlertPanel(titleText, explanationText,
-                               waitTitle, exitTitle, nil);
+  int choice = NSRunAlertPanel(titleText, @"%@",
+                               waitTitle, exitTitle, nil, explanationText);
   return choice == NSAlertDefaultReturn ? YES : NO;
 }
 
@@ -714,6 +769,18 @@
   return service && !service->entries().empty();
 }
 
+// Called from the AppControllerProfileObserver every time a profile is deleted.
+- (void)profileWasRemoved:(const base::FilePath&)profilePath {
+  Profile* lastProfile = [self lastProfile];
+
+  // If the lastProfile has been deleted, the profile manager has
+  // already loaded a new one, so the pointer needs to be updated;
+  // otherwise we will try to start up a browser window with a pointer
+  // to the old profile.
+  if (profilePath == lastProfile->GetPath())
+    lastProfile_ = g_browser_process->profile_manager()->GetLastUsedProfile();
+}
+
 // Returns true if there is a modal window (either window- or application-
 // modal) blocking the active browser. Note that tab modal dialogs (HTTP auth
 // sheets) will not count as blocking the browser. But things like open/save
@@ -928,7 +995,7 @@
       break;
     case IDC_TASK_MANAGER:
       content::RecordAction(UserMetricsAction("TaskManager"));
-      TaskManagerMac::Show(false);
+      TaskManagerMac::Show();
       break;
     case IDC_OPTIONS:
       [self showPreferences:sender];
@@ -1226,7 +1293,7 @@
     [dockMenu addItem:[NSMenuItem separatorItem]];
 
   NSString* titleStr = l10n_util::GetNSStringWithFixup(IDS_NEW_WINDOW_MAC);
-  scoped_nsobject<NSMenuItem> item(
+  base::scoped_nsobject<NSMenuItem> item(
       [[NSMenuItem alloc] initWithTitle:titleStr
                                  action:@selector(commandFromDock:)
                           keyEquivalent:@""]);
@@ -1255,31 +1322,23 @@
       int position = 0;
       NSString* menuStr =
           l10n_util::GetNSStringWithFixup(IDS_BACKGROUND_APPS_MAC);
-      scoped_nsobject<NSMenu> appMenu([[NSMenu alloc] initWithTitle:menuStr]);
+      base::scoped_nsobject<NSMenu> appMenu(
+          [[NSMenu alloc] initWithTitle:menuStr]);
       for (extensions::ExtensionList::const_iterator cursor =
                applications.begin();
            cursor != applications.end();
            ++cursor, ++position) {
-        DCHECK_EQ(applications.GetPosition(*cursor), position);
+        DCHECK_EQ(applications.GetPosition(cursor->get()), position);
         NSString* itemStr =
             base::SysUTF16ToNSString(UTF8ToUTF16((*cursor)->name()));
-        scoped_nsobject<NSMenuItem> appItem([[NSMenuItem alloc]
-            initWithTitle:itemStr
-                   action:@selector(executeApplication:)
-            keyEquivalent:@""]);
+        base::scoped_nsobject<NSMenuItem> appItem(
+            [[NSMenuItem alloc] initWithTitle:itemStr
+                                       action:@selector(executeApplication:)
+                                keyEquivalent:@""]);
         [appItem setTarget:self];
         [appItem setTag:position];
         [appMenu addItem:appItem];
       }
-
-      scoped_nsobject<NSMenuItem> appMenuItem([[NSMenuItem alloc]
-          initWithTitle:menuStr
-                 action:@selector(executeApplication:)
-          keyEquivalent:@""]);
-      [appMenuItem setTarget:self];
-      [appMenuItem setTag:IDC_VIEW_BACKGROUND_PAGES];
-      [appMenuItem setSubmenu:appMenu];
-      [dockMenu addItem:appMenuItem];
     }
   }
 
diff --git a/chrome/browser/app_controller_mac_browsertest.mm b/chrome/browser/app_controller_mac_browsertest.mm
index 62d2680..11f2c98 100644
--- a/chrome/browser/app_controller_mac_browsertest.mm
+++ b/chrome/browser/app_controller_mac_browsertest.mm
@@ -5,7 +5,7 @@
 #import <Cocoa/Cocoa.h>
 
 #include "base/command_line.h"
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "chrome/app/chrome_command_ids.h"
 #import "chrome/browser/app_controller_mac.h"
 #include "chrome/browser/ui/browser.h"
@@ -22,8 +22,8 @@
 class AppControllerPlatformAppBrowserTest : public InProcessBrowserTest {
  protected:
   AppControllerPlatformAppBrowserTest()
-      : native_browser_list(BrowserList::GetInstance(
-                                chrome::HOST_DESKTOP_TYPE_NATIVE)) {
+      : active_browser_list_(BrowserList::GetInstance(
+                                chrome::GetActiveDesktop())) {
   }
 
   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
@@ -31,29 +31,28 @@
                                     "1234");
   }
 
-  // Mac only has the native desktop.
-  const BrowserList* native_browser_list;
+  const BrowserList* active_browser_list_;
 };
 
 // Test that if only a platform app window is open and no browser windows are
 // open then a reopen event does nothing.
 IN_PROC_BROWSER_TEST_F(AppControllerPlatformAppBrowserTest,
                        PlatformAppReopenWithWindows) {
-  scoped_nsobject<AppController> ac([[AppController alloc] init]);
+  base::scoped_nsobject<AppController> ac([[AppController alloc] init]);
   NSUInteger old_window_count = [[NSApp windows] count];
-  EXPECT_EQ(1u, native_browser_list->size());
+  EXPECT_EQ(1u, active_browser_list_->size());
   BOOL result = [ac applicationShouldHandleReopen:NSApp hasVisibleWindows:YES];
 
   EXPECT_TRUE(result);
   EXPECT_EQ(old_window_count, [[NSApp windows] count]);
-  EXPECT_EQ(1u, native_browser_list->size());
+  EXPECT_EQ(1u, active_browser_list_->size());
 }
 
 class AppControllerWebAppBrowserTest : public InProcessBrowserTest {
  protected:
   AppControllerWebAppBrowserTest()
-      : native_browser_list(BrowserList::GetInstance(
-                                chrome::HOST_DESKTOP_TYPE_NATIVE)) {
+      : active_browser_list_(BrowserList::GetInstance(
+                                chrome::GetActiveDesktop())) {
   }
 
   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
@@ -64,21 +63,20 @@
     return "http://example.com/";
   }
 
-  // Mac only has the native desktop.
-  const BrowserList* native_browser_list;
+  const BrowserList* active_browser_list_;
 };
 
 // Test that in web app mode a reopen event opens the app URL.
 IN_PROC_BROWSER_TEST_F(AppControllerWebAppBrowserTest,
                        WebAppReopenWithNoWindows) {
-  scoped_nsobject<AppController> ac([[AppController alloc] init]);
-  EXPECT_EQ(1u, native_browser_list->size());
+  base::scoped_nsobject<AppController> ac([[AppController alloc] init]);
+  EXPECT_EQ(1u, active_browser_list_->size());
   BOOL result = [ac applicationShouldHandleReopen:NSApp hasVisibleWindows:NO];
 
   EXPECT_FALSE(result);
-  EXPECT_EQ(2u, native_browser_list->size());
+  EXPECT_EQ(2u, active_browser_list_->size());
 
-  Browser* browser = native_browser_list->get(0);
+  Browser* browser = active_browser_list_->get(0);
   GURL current_url =
       browser->tab_strip_model()->GetActiveWebContents()->GetURL();
   EXPECT_EQ(GetAppURL(), current_url.spec());
diff --git a/chrome/browser/app_controller_mac_unittest.mm b/chrome/browser/app_controller_mac_unittest.mm
index b391fd7..ed9c813 100644
--- a/chrome/browser/app_controller_mac_unittest.mm
+++ b/chrome/browser/app_controller_mac_unittest.mm
@@ -4,16 +4,39 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/files/file_path.h"
+#include "base/mac/scoped_nsobject.h"
 #include "chrome/app/chrome_command_ids.h"
 #import "chrome/browser/app_controller_mac.h"
+#include "chrome/browser/ui/cocoa/cocoa_profile_test.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/common/chrome_constants.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/test/base/testing_profile_manager.h"
+#include "chrome/test/base/ui_test_utils.h"
 #include "testing/platform_test.h"
 
 class AppControllerTest : public PlatformTest {
+ protected:
+  AppControllerTest()
+      : ui_thread_(content::BrowserThread::UI, &message_loop_),
+        db_thread_(content::BrowserThread::DB, &message_loop_),
+        file_thread_(content::BrowserThread::FILE, &message_loop_) {
+  }
+
+  virtual void TearDown() {
+    TestingBrowserProcess::GetGlobal()->SetProfileManager(NULL);
+    message_loop_.RunUntilIdle();
+  }
+
+  base::MessageLoopForUI message_loop_;
+  content::TestBrowserThread ui_thread_;
+  content::TestBrowserThread db_thread_;
+  content::TestBrowserThread file_thread_;
 };
 
 TEST_F(AppControllerTest, DockMenu) {
-  scoped_nsobject<AppController> ac([[AppController alloc] init]);
+  base::scoped_nsobject<AppController> ac([[AppController alloc] init]);
   NSMenu* menu = [ac applicationDockMenu:NSApp];
   NSMenuItem* item;
 
@@ -25,3 +48,30 @@
     EXPECT_EQ(@selector(commandFromDock:), [item action]);
   }
 }
+
+TEST_F(AppControllerTest, LastProfile) {
+  TestingProfileManager manager(TestingBrowserProcess::GetGlobal());
+  ASSERT_TRUE(manager.SetUp());
+
+  // Create two profiles.
+  base::FilePath dest_path1 =
+      manager.CreateTestingProfile("New Profile 1")->GetPath();
+  base::FilePath dest_path2 =
+      manager.CreateTestingProfile("New Profile 2")->GetPath();
+  ASSERT_EQ(2U, manager.profile_manager()->GetNumberOfProfiles());
+  ASSERT_EQ(2U, manager.profile_manager()->GetLoadedProfiles().size());
+
+  PrefService* local_state = g_browser_process->local_state();
+  local_state->SetString(prefs::kProfileLastUsed,
+                         dest_path1.BaseName().MaybeAsASCII());
+
+  base::scoped_nsobject<AppController> ac([[AppController alloc] init]);
+
+  // Delete the active profile.
+  manager.profile_manager()->ScheduleProfileForDeletion(
+      dest_path1, ProfileManager::CreateCallback());
+
+  message_loop_.RunUntilIdle();
+
+  EXPECT_EQ(dest_path2, [ac lastProfile]->GetPath());
+}
diff --git a/chrome/browser/autocomplete/autocomplete_browsertest.cc b/chrome/browser/autocomplete/autocomplete_browsertest.cc
index 510d82b..8161ce37 100644
--- a/chrome/browser/autocomplete/autocomplete_browsertest.cc
+++ b/chrome/browser/autocomplete/autocomplete_browsertest.cc
@@ -120,12 +120,12 @@
   AutocompleteController* autocomplete_controller = GetAutocompleteController();
 
   {
+    OmniboxView* location_entry = location_bar->GetLocationEntry();
+    location_entry->model()->SetInputInProgress(true);
     autocomplete_controller->Start(AutocompleteInput(
         ASCIIToUTF16("chrome"), string16::npos, string16(), GURL(), true, false,
         true, AutocompleteInput::SYNCHRONOUS_MATCHES));
 
-    OmniboxView* location_entry = location_bar->GetLocationEntry();
-
     EXPECT_TRUE(autocomplete_controller->done());
     EXPECT_TRUE(location_bar->GetInputString().empty());
     EXPECT_TRUE(location_entry->GetText().empty());
diff --git a/chrome/browser/autocomplete/autocomplete_classifier.cc b/chrome/browser/autocomplete/autocomplete_classifier.cc
index ed7d8ab..4eff86a 100644
--- a/chrome/browser/autocomplete/autocomplete_classifier.cc
+++ b/chrome/browser/autocomplete/autocomplete_classifier.cc
@@ -9,7 +9,7 @@
 #include "chrome/browser/autocomplete/autocomplete_input.h"
 #include "chrome/browser/autocomplete/autocomplete_match.h"
 #include "chrome/browser/autocomplete/autocomplete_provider.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 // static
 const int AutocompleteClassifier::kDefaultOmniboxProviders =
@@ -32,6 +32,7 @@
     // TODO: remove TYPE_SEARCH once it's no longer needed to pass
     // the Instant suggestion through via FinalizeInstantQuery.
     AutocompleteProvider::TYPE_SEARCH |
+    AutocompleteProvider::TYPE_SHORTCUTS |
     AutocompleteProvider::TYPE_ZERO_SUGGEST;
 
 AutocompleteClassifier::AutocompleteClassifier(Profile* profile)
diff --git a/chrome/browser/autocomplete/autocomplete_controller.cc b/chrome/browser/autocomplete/autocomplete_controller.cc
index 81921bf..3cc8a68 100644
--- a/chrome/browser/autocomplete/autocomplete_controller.cc
+++ b/chrome/browser/autocomplete/autocomplete_controller.cc
@@ -13,7 +13,7 @@
 #include "base/metrics/histogram.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/autocomplete/autocomplete_controller_delegate.h"
 #include "chrome/browser/autocomplete/bookmark_provider.h"
 #include "chrome/browser/autocomplete/builtin_provider.h"
@@ -310,12 +310,11 @@
 }
 
 void AutocompleteController::StartZeroSuggest(const GURL& url,
-                                              const string16& user_text,
                                               const string16& permanent_text) {
   if (zero_suggest_provider_ != NULL) {
     DCHECK(!in_start_);  // We should not be already running a query.
     in_zero_suggest_ = true;
-    zero_suggest_provider_->StartZeroSuggest(url, user_text, permanent_text);
+    zero_suggest_provider_->StartZeroSuggest(url, permanent_text);
   }
 }
 
@@ -377,6 +376,7 @@
   for (ACProviders::const_iterator i(providers_.begin()); i != providers_.end();
        ++i)
     (*i)->ResetSession();
+  in_zero_suggest_ = false;
 }
 
 void AutocompleteController::UpdateResult(
@@ -464,23 +464,23 @@
     string16 keyword(match->GetSubstitutingExplicitlyInvokedKeyword(profile_));
     if (!keyword.empty()) {
       keywords.insert(keyword);
+      continue;
+    }
+
+    // Only add the keyword if the match does not have a duplicate keyword with
+    // a more relevant match.
+    keyword = match->associated_keyword.get() ?
+        match->associated_keyword->keyword :
+        keyword_provider_->GetKeywordForText(match->fill_into_edit);
+    if (!keyword.empty() && !keywords.count(keyword)) {
+      keywords.insert(keyword);
+
+      if (!match->associated_keyword.get())
+        match->associated_keyword.reset(new AutocompleteMatch(
+            keyword_provider_->CreateAutocompleteMatch(match->fill_into_edit,
+                                                       keyword, input_)));
     } else {
-      string16 keyword = match->associated_keyword.get() ?
-          match->associated_keyword->keyword :
-          keyword_provider_->GetKeywordForText(match->fill_into_edit);
-
-      // Only add the keyword if the match does not have a duplicate keyword
-      // with a more relevant match.
-      if (!keyword.empty() && !keywords.count(keyword)) {
-        keywords.insert(keyword);
-
-        if (!match->associated_keyword.get())
-          match->associated_keyword.reset(new AutocompleteMatch(
-              keyword_provider_->CreateAutocompleteMatch(match->fill_into_edit,
-                  keyword, input_)));
-      } else {
-        match->associated_keyword.reset();
-      }
+      match->associated_keyword.reset();
     }
   }
 }
diff --git a/chrome/browser/autocomplete/autocomplete_controller.h b/chrome/browser/autocomplete/autocomplete_controller.h
index 38a658d..5b06749 100644
--- a/chrome/browser/autocomplete/autocomplete_controller.h
+++ b/chrome/browser/autocomplete/autocomplete_controller.h
@@ -9,8 +9,8 @@
 #include "base/compiler_specific.h"
 #include "base/gtest_prod_util.h"
 #include "base/strings/string16.h"
-#include "base/time.h"
-#include "base/timer.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
 #include "chrome/browser/autocomplete/autocomplete_input.h"
 #include "chrome/browser/autocomplete/autocomplete_provider.h"
 #include "chrome/browser/autocomplete/autocomplete_provider_listener.h"
@@ -80,11 +80,10 @@
   // Begin asynchronously fetching zero-suggest suggestions for |url|.
   // |user_text| is the text entered in the omnibox, which may be non-empty if
   // the user previously focused in the omnibox during this interaction.
-  // |permanent_text| is the text version of |url| displayed in the omnibox.
+  // |permanent_text| is the omnibox text for the current page.
   // TODO(jered): Rip out |user_text| once the first match is decoupled from
   // the current typing in the omnibox.
   void StartZeroSuggest(const GURL& url,
-                        const string16& user_text,
                         const string16& permanent_text);
 
   // Cancels any pending zero-suggest fetch.
diff --git a/chrome/browser/autocomplete/autocomplete_input.cc b/chrome/browser/autocomplete/autocomplete_input.cc
index cf2af6a..349e611 100644
--- a/chrome/browser/autocomplete/autocomplete_input.cc
+++ b/chrome/browser/autocomplete/autocomplete_input.cc
@@ -10,9 +10,9 @@
 #include "chrome/browser/net/url_fixer_upper.h"
 #include "chrome/browser/profiles/profile_io_data.h"
 #include "content/public/common/url_constants.h"
-#include "googleurl/src/url_canon_ip.h"
 #include "net/base/net_util.h"
 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
+#include "url/url_canon_ip.h"
 
 namespace {
 
diff --git a/chrome/browser/autocomplete/autocomplete_input.h b/chrome/browser/autocomplete/autocomplete_input.h
index 839d73f..d70a3af 100644
--- a/chrome/browser/autocomplete/autocomplete_input.h
+++ b/chrome/browser/autocomplete/autocomplete_input.h
@@ -9,8 +9,8 @@
 
 #include "base/basictypes.h"
 #include "base/strings/string16.h"
-#include "googleurl/src/gurl.h"
-#include "googleurl/src/url_parse.h"
+#include "url/gurl.h"
+#include "url/url_parse.h"
 
 // The user input for an autocomplete query.  Allows copying.
 class AutocompleteInput {
diff --git a/chrome/browser/autocomplete/autocomplete_input_unittest.cc b/chrome/browser/autocomplete/autocomplete_input_unittest.cc
index 1cdcc02..db7a1dd 100644
--- a/chrome/browser/autocomplete/autocomplete_input_unittest.cc
+++ b/chrome/browser/autocomplete/autocomplete_input_unittest.cc
@@ -8,8 +8,8 @@
 #include "base/strings/string16.h"
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
-#include "googleurl/src/url_parse.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "url/url_parse.h"
 
 TEST(AutocompleteInputTest, InputType) {
   struct test_data {
diff --git a/chrome/browser/autocomplete/autocomplete_match.cc b/chrome/browser/autocomplete/autocomplete_match.cc
index 5eccdb7..fc6774c 100644
--- a/chrome/browser/autocomplete/autocomplete_match.cc
+++ b/chrome/browser/autocomplete/autocomplete_match.cc
@@ -9,9 +9,8 @@
 #include "base/strings/string16.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/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/autocomplete/autocomplete_provider.h"
 #include "chrome/browser/search_engines/template_url.h"
 #include "chrome/browser/search_engines/template_url_service.h"
@@ -421,14 +420,14 @@
 
 void AutocompleteMatch::RecordAdditionalInfo(const std::string& property,
                                              const std::string& value) {
-  DCHECK(property.size());
-  DCHECK(value.size());
+  DCHECK(!property.empty());
+  DCHECK(!value.empty());
   additional_info[property] = value;
 }
 
 void AutocompleteMatch::RecordAdditionalInfo(const std::string& property,
                                              int value) {
-  RecordAdditionalInfo(property, base::StringPrintf("%d", value));
+  RecordAdditionalInfo(property, base::IntToString(value));
 }
 
 void AutocompleteMatch::RecordAdditionalInfo(const std::string& property,
@@ -437,6 +436,12 @@
                        UTF16ToUTF8(base::TimeFormatShortDateAndTime(value)));
 }
 
+std::string AutocompleteMatch::GetAdditionalInfo(
+    const std::string& property) const {
+  AdditionalInfo::const_iterator i(additional_info.find(property));
+  return (i == additional_info.end()) ? std::string() : i->second;
+}
+
 #ifndef NDEBUG
 void AutocompleteMatch::Validate() const {
   ValidateClassifications(contents, contents_class);
diff --git a/chrome/browser/autocomplete/autocomplete_match.h b/chrome/browser/autocomplete/autocomplete_match.h
index 146586e..4d4ca47 100644
--- a/chrome/browser/autocomplete/autocomplete_match.h
+++ b/chrome/browser/autocomplete/autocomplete_match.h
@@ -13,7 +13,7 @@
 #include "chrome/browser/search_engines/template_url.h"
 #include "chrome/common/autocomplete_match_type.h"
 #include "content/public/common/page_transition_types.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 class AutocompleteProvider;
 class Profile;
@@ -214,6 +214,10 @@
   void RecordAdditionalInfo(const std::string& property,
                             const base::Time& value);
 
+  // Returns the value recorded for |property| in the |additional_info|
+  // dictionary.  Returns the empty string if no such value exists.
+  std::string GetAdditionalInfo(const std::string& property) const;
+
   // The provider of this match, used to remember which provider the user had
   // selected when the input changes. This may be NULL, in which case there is
   // no provider (or memory of the user's selection).
diff --git a/chrome/browser/autocomplete/autocomplete_provider.cc b/chrome/browser/autocomplete/autocomplete_provider.cc
index d71e075..873bbac 100644
--- a/chrome/browser/autocomplete/autocomplete_provider.cc
+++ b/chrome/browser/autocomplete/autocomplete_provider.cc
@@ -14,9 +14,9 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/pref_names.h"
 #include "content/public/common/url_constants.h"
-#include "googleurl/src/gurl.h"
-#include "googleurl/src/url_util.h"
 #include "net/base/net_util.h"
+#include "url/gurl.h"
+#include "url/url_util.h"
 
 // static
 const size_t AutocompleteProvider::kMaxMatches = 3;
diff --git a/chrome/browser/autocomplete/autocomplete_provider_unittest.cc b/chrome/browser/autocomplete/autocomplete_provider_unittest.cc
index fea4c84..d7342f5 100644
--- a/chrome/browser/autocomplete/autocomplete_provider_unittest.cc
+++ b/chrome/browser/autocomplete/autocomplete_provider_unittest.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/autocomplete/autocomplete_provider.h"
 
 #include "base/bind.h"
+#include "base/command_line.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/message_loop.h"
 #include "base/strings/string16.h"
@@ -21,6 +22,7 @@
 #include "chrome/browser/search_engines/template_url_service.h"
 #include "chrome/browser/search_engines/template_url_service_factory.h"
 #include "chrome/common/chrome_notification_types.h"
+#include "chrome/common/chrome_switches.h"
 #include "chrome/test/base/testing_browser_process.h"
 #include "chrome/test/base/testing_profile.h"
 #include "content/public/browser/notification_observer.h"
@@ -185,11 +187,13 @@
   void ResetControllerWithKeywordProvider();
   void RunExactKeymatchTest(bool allow_exact_keyword_match);
 
+  void CopyResults();
+
   AutocompleteResult result_;
   scoped_ptr<AutocompleteController> controller_;
 
  private:
-  // content::NotificationObserver
+  // content::NotificationObserver:
   virtual void Observe(int type,
                        const content::NotificationSource& source,
                        const content::NotificationDetails& details) OVERRIDE;
@@ -416,12 +420,16 @@
       controller_->result().default_match()->type);
 }
 
+void AutocompleteProviderTest::CopyResults() {
+  result_.CopyFrom(controller_->result());
+}
+
 void AutocompleteProviderTest::Observe(
     int type,
     const content::NotificationSource& source,
     const content::NotificationDetails& details) {
   if (controller_->done()) {
-    result_.CopyFrom(controller_->result());
+    CopyResults();
     base::MessageLoop::current()->Quit();
   }
 }
@@ -435,7 +443,7 @@
 
   // Make sure the default match gets set to the highest relevance match.  The
   // highest relevance matches should come from the second provider.
-  EXPECT_EQ(kResultsPerProvider * 2, result_.size());  // two providers
+  EXPECT_EQ(kResultsPerProvider * 2, result_.size());
   ASSERT_NE(result_.end(), result_.default_match());
   EXPECT_EQ(provider2, result_.default_match()->provider);
 }
@@ -445,7 +453,7 @@
   ResetControllerWithTestProviders(false, NULL, NULL);
   RunTest();
 
-  EXPECT_EQ(kResultsPerProvider * 2, result_.size());  // two providers
+  ASSERT_EQ(kResultsPerProvider * 2, result_.size());
 
   // Now, check the results from the second provider, as they should not have
   // assisted query stats set.
@@ -480,6 +488,21 @@
   RunExactKeymatchTest(false);
 }
 
+// Ensures matches from (only) the default search provider respect any extra
+// query params set on the command line.
+TEST_F(AutocompleteProviderTest, ExtraQueryParams) {
+  ResetControllerWithKeywordAndSearchProviders();
+  CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+      switches::kExtraSearchQueryParams, "a=b");
+  RunExactKeymatchTest(true);
+  CopyResults();
+  ASSERT_EQ(2U, result_.size());
+  EXPECT_EQ("http://keyword/test",
+            result_.match_at(0)->destination_url.possibly_invalid_spec());
+  EXPECT_EQ("http://defaultturl/k%20test?a=b",
+            result_.match_at(1)->destination_url.possibly_invalid_spec());
+}
+
 // Test that redundant associated keywords are removed.
 TEST_F(AutocompleteProviderTest, RedundantKeywordsIgnoredInResult) {
   ResetControllerWithKeywordProvider();
diff --git a/chrome/browser/autocomplete/autocomplete_result.cc b/chrome/browser/autocomplete/autocomplete_result.cc
index c723d3f..38a0edf 100644
--- a/chrome/browser/autocomplete/autocomplete_result.cc
+++ b/chrome/browser/autocomplete/autocomplete_result.cc
@@ -134,8 +134,8 @@
   default_match_ = begin();
 
   // Set the alternate nav URL.
-  alternate_nav_url_ = default_match_ == end() ? GURL() :
-      ComputeAlternateNavUrl(input, *default_match_);
+  alternate_nav_url_ = (default_match_ == end()) ?
+      GURL() : ComputeAlternateNavUrl(input, *default_match_);
 }
 
 bool AutocompleteResult::HasCopiedMatches() const {
@@ -207,10 +207,10 @@
 GURL AutocompleteResult::ComputeAlternateNavUrl(
     const AutocompleteInput& input,
     const AutocompleteMatch& match) {
-  return (input.type() == AutocompleteInput::UNKNOWN &&
-          AutocompleteMatch::IsSearchType(match.type) &&
-          match.transition != content::PAGE_TRANSITION_KEYWORD &&
-          input.canonicalized_url() != match.destination_url) ?
+  return ((input.type() == AutocompleteInput::UNKNOWN) &&
+          (AutocompleteMatch::IsSearchType(match.type)) &&
+          (match.transition != content::PAGE_TRANSITION_KEYWORD) &&
+          (input.canonicalized_url() != match.destination_url)) ?
       input.canonicalized_url() : GURL();
 }
 
diff --git a/chrome/browser/autocomplete/autocomplete_result.h b/chrome/browser/autocomplete/autocomplete_result.h
index 2da5320..57660f4 100644
--- a/chrome/browser/autocomplete/autocomplete_result.h
+++ b/chrome/browser/autocomplete/autocomplete_result.h
@@ -11,7 +11,7 @@
 
 #include "base/basictypes.h"
 #include "chrome/browser/autocomplete/autocomplete_match.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 class AutocompleteInput;
 class AutocompleteProvider;
@@ -120,7 +120,8 @@
 #endif
 
   // Compute the "alternate navigation URL" for a given match. This is obtained
-  // by interpreting the user input directly as a URL.
+  // by interpreting the user input directly as a URL. See comments on
+  // |alternate_nav_url_|.
   static GURL ComputeAlternateNavUrl(const AutocompleteInput& input,
                                      const AutocompleteMatch& match);
 
diff --git a/chrome/browser/autocomplete/bookmark_provider.cc b/chrome/browser/autocomplete/bookmark_provider.cc
index bee5367..3e8443f 100644
--- a/chrome/browser/autocomplete/bookmark_provider.cc
+++ b/chrome/browser/autocomplete/bookmark_provider.cc
@@ -10,7 +10,7 @@
 
 #include "base/metrics/histogram.h"
 #include "base/prefs/pref_service.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/autocomplete/autocomplete_result.h"
 #include "chrome/browser/bookmarks/bookmark_model.h"
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
@@ -188,7 +188,7 @@
   // use the sum to figure out a value between the base score and the maximum
   // score.
   //
-  // The factor for each term is calculated based on:
+  // The factor for each term is the product of:
   //
   //  1) how much of the bookmark's title has been matched by the term:
   //       (term length / title length).
@@ -209,8 +209,13 @@
   //     a partial factor of (14-6)/14 = 0.571 ).
   //
   // Once all term factors have been calculated they are summed. The resulting
-  // sum will never be greater than 1.0. This sum is then multiplied against
-  // the scoring range available, which is 299. The 299 is calculated by
+  // sum will never be greater than 1.0 because of the way the bookmark model
+  // matches and removes overlaps. (In particular, the bookmark model only
+  // matches terms to the beginning of words and it removes all overlapping
+  // matches, keeping only the longest. Together these mean that each
+  // character is included in at most one match. This property ensures the
+  // sum of factors is at most 1.) This sum is then multiplied against the
+  // scoring range available, which is 299. The 299 is calculated by
   // subtracting the minimum possible score, 900, from the maximum possible
   // score, 1199. This product, ranging from 0 to 299, is added to the minimum
   // possible score, 900, giving the preliminary score.
diff --git a/chrome/browser/autocomplete/builtin_provider_unittest.cc b/chrome/browser/autocomplete/builtin_provider_unittest.cc
index df80f56..bc524b5 100644
--- a/chrome/browser/autocomplete/builtin_provider_unittest.cc
+++ b/chrome/browser/autocomplete/builtin_provider_unittest.cc
@@ -11,8 +11,8 @@
 #include "chrome/browser/autocomplete/autocomplete_provider.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/test/base/testing_browser_process.h"
-#include "googleurl/src/gurl.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
 
 class BuiltinProviderTest : public testing::Test {
  protected:
diff --git a/chrome/browser/autocomplete/history_provider.cc b/chrome/browser/autocomplete/history_provider.cc
index 6aa2fb1..d09b794 100644
--- a/chrome/browser/autocomplete/history_provider.cc
+++ b/chrome/browser/autocomplete/history_provider.cc
@@ -16,7 +16,7 @@
 #include "chrome/browser/net/url_fixer_upper.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/url_constants.h"
-#include "googleurl/src/url_util.h"
+#include "url/url_util.h"
 
 HistoryProvider::HistoryProvider(AutocompleteProviderListener* listener,
                                  Profile* profile,
diff --git a/chrome/browser/autocomplete/history_quick_provider.cc b/chrome/browser/autocomplete/history_quick_provider.cc
index 7be9e6a..1a5eb67 100644
--- a/chrome/browser/autocomplete/history_quick_provider.cc
+++ b/chrome/browser/autocomplete/history_quick_provider.cc
@@ -16,7 +16,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/autocomplete/autocomplete_result.h"
 #include "chrome/browser/autocomplete/history_url_provider.h"
 #include "chrome/browser/history/history_database.h"
@@ -39,11 +39,11 @@
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/notification_source.h"
 #include "content/public/browser/notification_types.h"
-#include "googleurl/src/url_parse.h"
-#include "googleurl/src/url_util.h"
 #include "net/base/escape.h"
 #include "net/base/net_util.h"
 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
+#include "url/url_parse.h"
+#include "url/url_util.h"
 
 using history::InMemoryURLIndex;
 using history::ScoredHistoryMatch;
diff --git a/chrome/browser/autocomplete/history_url_provider.cc b/chrome/browser/autocomplete/history_url_provider.cc
index fa9066f..e831193 100644
--- a/chrome/browser/autocomplete/history_url_provider.cc
+++ b/chrome/browser/autocomplete/history_url_provider.cc
@@ -29,11 +29,11 @@
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/url_constants.h"
-#include "googleurl/src/gurl.h"
-#include "googleurl/src/url_parse.h"
-#include "googleurl/src/url_util.h"
 #include "net/base/net_util.h"
 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
+#include "url/gurl.h"
+#include "url/url_parse.h"
+#include "url/url_util.h"
 
 namespace {
 
diff --git a/chrome/browser/autocomplete/history_url_provider_unittest.cc b/chrome/browser/autocomplete/history_url_provider_unittest.cc
index 049bd7c..893402c 100644
--- a/chrome/browser/autocomplete/history_url_provider_unittest.cc
+++ b/chrome/browser/autocomplete/history_url_provider_unittest.cc
@@ -10,7 +10,7 @@
 #include "base/path_service.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/autocomplete/autocomplete_match.h"
 #include "chrome/browser/autocomplete/autocomplete_provider.h"
 #include "chrome/browser/autocomplete/autocomplete_provider_listener.h"
@@ -855,9 +855,8 @@
     AutocompleteInput input(ASCIIToUTF16(test_cases[i].input), string16::npos,
                             string16(), GURL("about:blank"),
                             false, false, true, AutocompleteInput::ALL_MATCHES);
-    AutocompleteMatch match =
-        HistoryURLProvider::SuggestExactInput(autocomplete_, input,
-                                              test_cases[i].trim_http);
+    AutocompleteMatch match = HistoryURLProvider::SuggestExactInput(
+        autocomplete_.get(), input, test_cases[i].trim_http);
     EXPECT_EQ(ASCIIToUTF16(test_cases[i].contents), match.contents);
     for (size_t match_index = 0; match_index < match.contents_class.size();
          ++match_index) {
diff --git a/chrome/browser/autocomplete/keyword_provider.cc b/chrome/browser/autocomplete/keyword_provider.cc
index 3726f8f..c2759dd 100644
--- a/chrome/browser/autocomplete/keyword_provider.cc
+++ b/chrome/browser/autocomplete/keyword_provider.cc
@@ -86,9 +86,8 @@
   // probably better rankings than the fraction of the keyword typed.  We should
   // always put any exact matches first no matter what, since the code in
   // Start() assumes this (and it makes sense).
-  bool operator()(const string16& keyword1,
-                  const string16& keyword2) const {
-    return keyword1.length() < keyword2.length();
+  bool operator()(const TemplateURL* t_url1, const TemplateURL* t_url2) const {
+    return t_url1->keyword().length() < t_url2->keyword().length();
   }
 };
 
@@ -216,8 +215,9 @@
     const string16& text,
     const string16& keyword,
     const AutocompleteInput& input) {
-  return CreateAutocompleteMatch(GetTemplateURLService(), keyword, input,
-      keyword.size(), SplitReplacementStringFromInput(text, true), 0);
+  return CreateAutocompleteMatch(
+      GetTemplateURLService()->GetTemplateURLForKeyword(keyword), input,
+      keyword.length(), SplitReplacementStringFromInput(text, true), 0);
 }
 
 void KeywordProvider::Start(const AutocompleteInput& input,
@@ -253,8 +253,6 @@
   if (!ExtractKeywordFromInput(input, &keyword, &remaining_input))
     return;
 
-  TemplateURLService* model = GetTemplateURLService();
-
   // Get the best matches for this keyword.
   //
   // NOTE: We could cache the previous keywords and reuse them here in the
@@ -265,27 +263,26 @@
   // TODO(pkasting): http://b/893701 We should remember the user's use of a
   // search query both from the autocomplete popup and from web pages
   // themselves.
-  std::vector<string16> keyword_matches;
-  model->FindMatchingKeywords(keyword,
-                              !remaining_input.empty(),
-                              &keyword_matches);
+  TemplateURLService::TemplateURLVector matches;
+  GetTemplateURLService()->FindMatchingKeywords(
+      keyword, !remaining_input.empty(), &matches);
 
-  for (std::vector<string16>::iterator i(keyword_matches.begin());
-       i != keyword_matches.end(); ) {
-    const TemplateURL* template_url = model->GetTemplateURLForKeyword(*i);
+  for (TemplateURLService::TemplateURLVector::iterator i(matches.begin());
+       i != matches.end(); ) {
+    const TemplateURL* template_url = *i;
 
     // Prune any extension keywords that are disallowed in incognito mode (if
     // we're incognito), or disabled.
     if (profile_ && template_url->IsExtensionKeyword()) {
       ExtensionService* service = extensions::ExtensionSystem::Get(profile_)->
           extension_service();
-      const extensions::Extension* extension = service->GetExtensionById(
-          template_url->GetExtensionId(), false);
+      const extensions::Extension* extension =
+          service->GetExtensionById(template_url->GetExtensionId(), false);
       bool enabled =
           extension && (!profile_->IsOffTheRecord() ||
                         service->IsIncognitoEnabled(extension->id()));
       if (!enabled) {
-        i = keyword_matches.erase(i);
+        i = matches.erase(i);
         continue;
       }
     }
@@ -293,22 +290,22 @@
     // Prune any substituting keywords if there is no substitution.
     if (template_url->SupportsReplacement() && remaining_input.empty() &&
         !input.allow_exact_keyword_match()) {
-      i = keyword_matches.erase(i);
+      i = matches.erase(i);
       continue;
     }
 
     ++i;
   }
-  if (keyword_matches.empty())
+  if (matches.empty())
     return;
-  std::sort(keyword_matches.begin(), keyword_matches.end(), CompareQuality());
+  std::sort(matches.begin(), matches.end(), CompareQuality());
 
   // Limit to one exact or three inexact matches, and mark them up for display
   // in the autocomplete popup.
   // Any exact match is going to be the highest quality match, and thus at the
   // front of our vector.
-  if (keyword_matches.front() == keyword) {
-    const TemplateURL* template_url = model->GetTemplateURLForKeyword(keyword);
+  if (matches.front()->keyword() == keyword) {
+    const TemplateURL* template_url = matches.front();
     const bool is_extension_keyword = template_url->IsExtensionKeyword();
 
     // Only create an exact match if |remaining_input| is empty or if
@@ -321,9 +318,8 @@
 
     // TODO(pkasting): We should probably check that if the user explicitly
     // typed a scheme, that scheme matches the one in |template_url|.
-    matches_.push_back(CreateAutocompleteMatch(model, keyword, input,
-                                               keyword.length(),
-                                               remaining_input, -1));
+    matches_.push_back(CreateAutocompleteMatch(
+        template_url, input, keyword.length(), remaining_input, -1));
 
     if (profile_ && is_extension_keyword) {
       if (input.matches_requested() == AutocompleteInput::ALL_MATCHES) {
@@ -364,15 +360,12 @@
       }
     }
   } else {
-    if (keyword_matches.size() > kMaxMatches) {
-      keyword_matches.erase(keyword_matches.begin() + kMaxMatches,
-                            keyword_matches.end());
-    }
-    for (std::vector<string16>::const_iterator i(keyword_matches.begin());
-         i != keyword_matches.end(); ++i) {
-      matches_.push_back(CreateAutocompleteMatch(model, *i,
-                                                 input, keyword.length(),
-                                                 remaining_input, -1));
+    if (matches.size() > kMaxMatches)
+      matches.erase(matches.begin() + kMaxMatches, matches.end());
+    for (TemplateURLService::TemplateURLVector::const_iterator i(
+         matches.begin()); i != matches.end(); ++i) {
+      matches_.push_back(CreateAutocompleteMatch(
+          *i, input, keyword.length(), remaining_input, -1));
     }
   }
 }
@@ -400,10 +393,79 @@
 }
 
 // static
-void KeywordProvider::FillInURLAndContents(
+int KeywordProvider::CalculateRelevance(AutocompleteInput::Type type,
+                                        bool complete,
+                                        bool supports_replacement,
+                                        bool prefer_keyword,
+                                        bool allow_exact_keyword_match) {
+  // This function is responsible for scoring suggestions of keywords
+  // themselves and the suggestion of the verbatim query on an
+  // extension keyword.  SearchProvider::CalculateRelevanceForKeywordVerbatim()
+  // scores verbatim query suggestions for non-extension keywords.
+  // These two functions are currently in sync, but there's no reason
+  // we couldn't decide in the future to score verbatim matches
+  // differently for extension and non-extension keywords.  If you
+  // make such a change, however, you should update this comment to
+  // describe it, so it's clear why the functions diverge.
+  if (!complete)
+    return (type == AutocompleteInput::URL) ? 700 : 450;
+  if (!supports_replacement || (allow_exact_keyword_match && prefer_keyword))
+    return 1500;
+  return (allow_exact_keyword_match && (type == AutocompleteInput::QUERY)) ?
+      1450 : 1100;
+}
+
+AutocompleteMatch KeywordProvider::CreateAutocompleteMatch(
+    const TemplateURL* template_url,
+    const AutocompleteInput& input,
+    size_t prefix_length,
     const string16& remaining_input,
-    const TemplateURL* element,
-    AutocompleteMatch* match) {
+    int relevance) {
+  DCHECK(template_url);
+  const bool supports_replacement =
+      template_url->url_ref().SupportsReplacement();
+
+  // Create an edit entry of "[keyword] [remaining input]".  This is helpful
+  // even when [remaining input] is empty, as the user can select the popup
+  // choice and immediately begin typing in query input.
+  const string16& keyword = template_url->keyword();
+  const bool keyword_complete = (prefix_length == keyword.length());
+  if (relevance < 0) {
+    relevance =
+        CalculateRelevance(input.type(), keyword_complete,
+                           // When the user wants keyword matches to take
+                           // preference, score them highly regardless of
+                           // whether the input provides query text.
+                           supports_replacement, input.prefer_keyword(),
+                           input.allow_exact_keyword_match());
+  }
+  AutocompleteMatch match(this, relevance, false,
+      supports_replacement ? AutocompleteMatchType::SEARCH_OTHER_ENGINE :
+                             AutocompleteMatchType::HISTORY_KEYWORD);
+  match.fill_into_edit = keyword;
+  if (!remaining_input.empty() || !keyword_complete || supports_replacement)
+    match.fill_into_edit.push_back(L' ');
+  match.fill_into_edit.append(remaining_input);
+  // If we wanted to set |result.inline_autocomplete_offset| correctly, we'd
+  // need CleanUserInputKeyword() to return the amount of adjustment it's made
+  // to the user's input.  Because right now inexact keyword matches can't score
+  // more highly than a "what you typed" match from one of the other providers,
+  // we just don't bother to do this, and leave inline autocompletion off.
+  match.inline_autocomplete_offset = string16::npos;
+
+  // Create destination URL and popup entry content by substituting user input
+  // into keyword templates.
+  FillInURLAndContents(remaining_input, template_url, &match);
+
+  match.keyword = keyword;
+  match.transition = content::PAGE_TRANSITION_KEYWORD;
+
+  return match;
+}
+
+void KeywordProvider::FillInURLAndContents(const string16& remaining_input,
+                                           const TemplateURL* element,
+                                           AutocompleteMatch* match) const {
   DCHECK(!element->short_name().empty());
   const TemplateURLRef& element_ref = element->url_ref();
   DCHECK(element_ref.IsValid());
@@ -435,97 +497,23 @@
     // input, but we rely on later canonicalization functions to do more
     // fixup to make the URL valid if necessary.
     DCHECK(element_ref.SupportsReplacement());
-    match->destination_url = GURL(element_ref.ReplaceSearchTerms(
-        TemplateURLRef::SearchTermsArgs(remaining_input)));
+    TemplateURLRef::SearchTermsArgs search_terms_args(remaining_input);
+    search_terms_args.append_extra_query_params =
+        element == GetTemplateURLService()->GetDefaultSearchProvider();
+    match->destination_url =
+        GURL(element_ref.ReplaceSearchTerms(search_terms_args));
     std::vector<size_t> content_param_offsets;
     match->contents.assign(l10n_util::GetStringFUTF16(message_id,
                                                       element->short_name(),
                                                       remaining_input,
                                                       &content_param_offsets));
-    if (content_param_offsets.size() == 2) {
-      AutocompleteMatch::ClassifyLocationInString(content_param_offsets[1],
-          remaining_input.length(), match->contents.length(),
-          ACMatchClassification::NONE, &match->contents_class);
-    } else {
-      // See comments on an identical NOTREACHED() in search_provider.cc.
-      NOTREACHED();
-    }
+    DCHECK_EQ(2U, content_param_offsets.size());
+    AutocompleteMatch::ClassifyLocationInString(content_param_offsets[1],
+        remaining_input.length(), match->contents.length(),
+        ACMatchClassification::NONE, &match->contents_class);
   }
 }
 
-// static
-int KeywordProvider::CalculateRelevance(AutocompleteInput::Type type,
-                                        bool complete,
-                                        bool supports_replacement,
-                                        bool prefer_keyword,
-                                        bool allow_exact_keyword_match) {
-  // This function is responsible for scoring suggestions of keywords
-  // themselves and the suggestion of the verbatim query on an
-  // extension keyword.  SearchProvider::CalculateRelevanceForKeywordVerbatim()
-  // scores verbatim query suggestions for non-extension keywords.
-  // These two functions are currently in sync, but there's no reason
-  // we couldn't decide in the future to score verbatim matches
-  // differently for extension and non-extension keywords.  If you
-  // make such a change, however, you should update this comment to
-  // describe it, so it's clear why the functions diverge.
-  if (!complete)
-    return (type == AutocompleteInput::URL) ? 700 : 450;
-  if (!supports_replacement || (allow_exact_keyword_match && prefer_keyword))
-    return 1500;
-  return (allow_exact_keyword_match && (type == AutocompleteInput::QUERY)) ?
-      1450 : 1100;
-}
-
-AutocompleteMatch KeywordProvider::CreateAutocompleteMatch(
-    TemplateURLService* model,
-    const string16& keyword,
-    const AutocompleteInput& input,
-    size_t prefix_length,
-    const string16& remaining_input,
-    int relevance) {
-  DCHECK(model);
-  // Get keyword data from data store.
-  TemplateURL* element = model->GetTemplateURLForKeyword(keyword);
-  DCHECK(element);
-  const bool supports_replacement = element->url_ref().SupportsReplacement();
-
-  // Create an edit entry of "[keyword] [remaining input]".  This is helpful
-  // even when [remaining input] is empty, as the user can select the popup
-  // choice and immediately begin typing in query input.
-  const bool keyword_complete = (prefix_length == keyword.length());
-  if (relevance < 0) {
-    relevance =
-        CalculateRelevance(input.type(), keyword_complete,
-                           // When the user wants keyword matches to take
-                           // preference, score them highly regardless of
-                           // whether the input provides query text.
-                           supports_replacement, input.prefer_keyword(),
-                           input.allow_exact_keyword_match());
-  }
-  AutocompleteMatch match(this, relevance, false,
-      supports_replacement ? AutocompleteMatchType::SEARCH_OTHER_ENGINE :
-                             AutocompleteMatchType::HISTORY_KEYWORD);
-  match.fill_into_edit.assign(keyword);
-  if (!remaining_input.empty() || !keyword_complete || supports_replacement)
-    match.fill_into_edit.push_back(L' ');
-  match.fill_into_edit.append(remaining_input);
-  // If we wanted to set |result.inline_autocomplete_offset| correctly, we'd
-  // need CleanUserInputKeyword() to return the amount of adjustment it's made
-  // to the user's input.  Because right now inexact keyword matches can't score
-  // more highly than a "what you typed" match from one of the other providers,
-  // we just don't bother to do this, and leave inline autocompletion off.
-  match.inline_autocomplete_offset = string16::npos;
-
-  // Create destination URL and popup entry content by substituting user input
-  // into keyword templates.
-  FillInURLAndContents(remaining_input, element, &match);
-
-  match.keyword = keyword;
-  match.transition = content::PAGE_TRANSITION_KEYWORD;
-
-  return match;
-}
-
 void KeywordProvider::Observe(int type,
                               const content::NotificationSource& source,
                               const content::NotificationDetails& details) {
@@ -567,10 +555,10 @@
         return;  // This is an old result. Just ignore.
 
       string16 keyword, remaining_input;
-      if (!ExtractKeywordFromInput(input, &keyword, &remaining_input)) {
-        NOTREACHED();
-        return;
-      }
+      bool result = ExtractKeywordFromInput(input, &keyword, &remaining_input);
+      DCHECK(result);
+      const TemplateURL* template_url =
+          model->GetTemplateURLForKeyword(keyword);
 
       // TODO(mpcomplete): consider clamping the number of suggestions to
       // AutocompleteProvider::kMaxMatches.
@@ -585,7 +573,7 @@
         int first_relevance = CalculateRelevance(input.type(), true, true,
             input.prefer_keyword(), input.allow_exact_keyword_match());
         extension_suggest_matches_.push_back(CreateAutocompleteMatch(
-            model, keyword, input, keyword.length(),
+            template_url, input, keyword.length(),
             UTF8ToUTF16(suggestion.content), first_relevance - (i + 1)));
 
         AutocompleteMatch* match = &extension_suggest_matches_.back();
diff --git a/chrome/browser/autocomplete/keyword_provider.h b/chrome/browser/autocomplete/keyword_provider.h
index c9caba1..7e582b4 100644
--- a/chrome/browser/autocomplete/keyword_provider.h
+++ b/chrome/browser/autocomplete/keyword_provider.h
@@ -110,12 +110,6 @@
                                       string16* keyword,
                                       string16* remaining_input);
 
-  // Fills in the "destination_url" and "contents" fields of |match| with the
-  // provided user input and keyword data.
-  static void FillInURLAndContents(const string16& remaining_input,
-                                   const TemplateURL* element,
-                                   AutocompleteMatch* match);
-
   // Determines the relevance for some input, given its type, whether the user
   // typed the complete keyword, and whether the user is in "prefer keyword
   // matches" mode, and whether the keyword supports replacement.
@@ -129,13 +123,18 @@
 
   // Creates a fully marked-up AutocompleteMatch from the user's input.
   // If |relevance| is negative, calculate a relevance based on heuristics.
-  AutocompleteMatch CreateAutocompleteMatch(TemplateURLService* model,
-                                            const string16& keyword,
+  AutocompleteMatch CreateAutocompleteMatch(const TemplateURL* template_url,
                                             const AutocompleteInput& input,
                                             size_t prefix_length,
                                             const string16& remaining_input,
                                             int relevance);
 
+  // Fills in the "destination_url" and "contents" fields of |match| with the
+  // provided user input and keyword data.
+  void FillInURLAndContents(const string16& remaining_input,
+                            const TemplateURL* element,
+                            AutocompleteMatch* match) const;
+
   void EnterExtensionKeywordMode(const std::string& extension_id);
   void MaybeEndExtensionKeywordMode();
 
diff --git a/chrome/browser/autocomplete/keyword_provider_unittest.cc b/chrome/browser/autocomplete/keyword_provider_unittest.cc
index 5dec594..45b5ac9 100644
--- a/chrome/browser/autocomplete/keyword_provider_unittest.cc
+++ b/chrome/browser/autocomplete/keyword_provider_unittest.cc
@@ -2,15 +2,17 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/command_line.h"
 #include "base/message_loop.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/autocomplete/autocomplete_match.h"
 #include "chrome/browser/autocomplete/keyword_provider.h"
 #include "chrome/browser/search_engines/template_url.h"
 #include "chrome/browser/search_engines/template_url_service.h"
+#include "chrome/common/chrome_switches.h"
 #include "chrome/test/base/testing_browser_process.h"
-#include "googleurl/src/gurl.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
 
 class KeywordProviderTest : public testing::Test {
  protected:
@@ -33,23 +35,25 @@
                ResultType AutocompleteMatch::* member);
 
  protected:
+  static const TemplateURLService::Initializer kTestData[];
+
   scoped_refptr<KeywordProvider> kw_provider_;
   scoped_ptr<TemplateURLService> model_;
 };
 
-void KeywordProviderTest::SetUp() {
-  static const TemplateURLService::Initializer kTestKeywordData[] = {
-    { "aa", "aa.com?foo=%s", "aa" },
-    { "aaaa", "http://aaaa/?aaaa=1&b=%s&c", "aaaa" },
-    { "aaaaa", "%s", "aaaaa" },
-    { "ab", "bogus URL %s", "ab" },
-    { "weasel", "weasel%sweasel", "weasel" },
-    { "www", " +%2B?=%sfoo ", "www" },
-    { "z", "%s=z", "z" },
-  };
+// static
+const TemplateURLService::Initializer KeywordProviderTest::kTestData[] = {
+  { "aa", "aa.com?foo=%s", "aa" },
+  { "aaaa", "http://aaaa/?aaaa=1&b=%s&c", "aaaa" },
+  { "aaaaa", "%s", "aaaaa" },
+  { "ab", "bogus URL %s", "ab" },
+  { "weasel", "weasel%sweasel", "weasel" },
+  { "www", " +%2B?=%sfoo ", "www" },
+  { "z", "%s=z", "z" },
+};
 
-  model_.reset(new TemplateURLService(kTestKeywordData,
-                                    arraysize(kTestKeywordData)));
+void KeywordProviderTest::SetUp() {
+  model_.reset(new TemplateURLService(kTestData, arraysize(kTestData)));
   kw_provider_ = new KeywordProvider(NULL, model_.get());
 }
 
@@ -134,22 +138,22 @@
 TEST_F(KeywordProviderTest, URL) {
   test_data<GURL> url_cases[] = {
     // No query input -> empty destination URL.
-    {ASCIIToUTF16("z"),               1, {GURL()}},
-    {ASCIIToUTF16("z    \t"),         1, {GURL()}},
+    {ASCIIToUTF16("z"),           1, {GURL()}},
+    {ASCIIToUTF16("z    \t"),     1, {GURL()}},
 
     // Check that tokenization only collapses whitespace between first tokens
     // and query input, but not rest of URL, is escaped.
-    {ASCIIToUTF16("w  bar +baz"),     2, {GURL(" +%2B?=bar+%2Bbazfoo "),
-                                          GURL("bar+%2Bbaz=z")}},
+    {ASCIIToUTF16("w  bar +baz"), 2, {GURL(" +%2B?=bar+%2Bbazfoo "),
+                                      GURL("bar+%2Bbaz=z")}},
 
     // Substitution should work with various locations of the "%s".
-    {ASCIIToUTF16("aaa 1a2b"),        2, {GURL("http://aaaa/?aaaa=1&b=1a2b&c"),
-                                          GURL("1a2b")}},
-    {ASCIIToUTF16("a 1 2 3"),         3, {GURL("aa.com?foo=1+2+3"),
-                                          GURL("bogus URL 1+2+3"),
-                                        GURL("http://aaaa/?aaaa=1&b=1+2+3&c")}},
-    {ASCIIToUTF16("www.w w"),         2, {GURL(" +%2B?=wfoo "),
-                                          GURL("weaselwweasel")}},
+    {ASCIIToUTF16("aaa 1a2b"),    2, {GURL("http://aaaa/?aaaa=1&b=1a2b&c"),
+                                      GURL("1a2b")}},
+    {ASCIIToUTF16("a 1 2 3"),     3, {GURL("aa.com?foo=1+2+3"),
+                                      GURL("bogus URL 1+2+3"),
+                                      GURL("http://aaaa/?aaaa=1&b=1+2+3&c")}},
+    {ASCIIToUTF16("www.w w"),     2, {GURL(" +%2B?=wfoo "),
+                                      GURL("weaselwweasel")}},
   };
 
   RunTest<GURL>(url_cases, arraysize(url_cases),
@@ -189,27 +193,7 @@
   };
 
   RunTest<string16>(contents_cases, arraysize(contents_cases),
-                        &AutocompleteMatch::contents);
-}
-
-TEST_F(KeywordProviderTest, DISABLED_Description) {
-  test_data<string16> description_cases[] = {
-    // Whole keyword should be returned for both exact and inexact matches.
-    {ASCIIToUTF16("z foo"),           1, {ASCIIToUTF16("(Keyword: z)")}},
-    {ASCIIToUTF16("a foo"),           3, {ASCIIToUTF16("(Keyword: aa)"),
-                                          ASCIIToUTF16("(Keyword: ab)"),
-                                          ASCIIToUTF16("(Keyword: aaaa)")}},
-    {ASCIIToUTF16("ftp://www.www w"), 0, {}},
-    {ASCIIToUTF16("http://www.ab w"), 1, {ASCIIToUTF16("(Keyword: ab)")}},
-
-    // Keyword should be returned regardless of query input.
-    {ASCIIToUTF16("z"),               1, {ASCIIToUTF16("(Keyword: z)")}},
-    {ASCIIToUTF16("z    \t"),         1, {ASCIIToUTF16("(Keyword: z)")}},
-    {ASCIIToUTF16("z   a   b   c++"), 1, {ASCIIToUTF16("(Keyword: z)")}},
-  };
-
-  RunTest<string16>(description_cases, arraysize(description_cases),
-                        &AutocompleteMatch::description);
+                    &AutocompleteMatch::contents);
 }
 
 TEST_F(KeywordProviderTest, AddKeyword) {
@@ -294,3 +278,19 @@
     EXPECT_EQ(cases[i].updated_cursor_position, input.cursor_position());
   }
 }
+
+// If extra query params are specified on the command line, they should be
+// reflected (only) in the default search provider's destination URL.
+TEST_F(KeywordProviderTest, ExtraQueryParams) {
+  CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+      switches::kExtraSearchQueryParams, "a=b");
+
+  test_data<GURL> url_cases[] = {
+    {ASCIIToUTF16("a 1 2 3"), 3, {GURL("aa.com?a=b&foo=1+2+3"),
+                                  GURL("bogus URL 1+2+3"),
+                                  GURL("http://aaaa/?aaaa=1&b=1+2+3&c")}},
+  };
+
+  RunTest<GURL>(url_cases, arraysize(url_cases),
+                &AutocompleteMatch::destination_url);
+}
diff --git a/chrome/browser/autocomplete/search_provider.cc b/chrome/browser/autocomplete/search_provider.cc
index 93f68ff..c5861c4 100644
--- a/chrome/browser/autocomplete/search_provider.cc
+++ b/chrome/browser/autocomplete/search_provider.cc
@@ -7,7 +7,6 @@
 #include <algorithm>
 #include <cmath>
 
-#include "base/auto_reset.h"
 #include "base/callback.h"
 #include "base/i18n/break_iterator.h"
 #include "base/i18n/case_conversion.h"
@@ -40,7 +39,6 @@
 #include "chrome/browser/search_engines/template_url_service_factory.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/url_constants.h"
-#include "googleurl/src/url_util.h"
 #include "grit/generated_resources.h"
 #include "net/base/escape.h"
 #include "net/base/load_flags.h"
@@ -50,9 +48,10 @@
 #include "net/url_request/url_fetcher.h"
 #include "net/url_request/url_request_status.h"
 #include "ui/base/l10n/l10n_util.h"
+#include "url/url_util.h"
 
-using base::Time;
-using base::TimeDelta;
+
+// Helpers --------------------------------------------------------------------
 
 namespace {
 
@@ -115,35 +114,164 @@
 }
 
 
+// SearchProvider::Result -----------------------------------------------------
+
+SearchProvider::Result::Result(bool from_keyword_provider,
+                               int relevance,
+                               bool relevance_from_server)
+    : from_keyword_provider_(from_keyword_provider),
+      relevance_(relevance),
+      relevance_from_server_(relevance_from_server) {
+}
+
+SearchProvider::Result::~Result() {
+}
+
+
+// SearchProvider::SuggestResult ----------------------------------------------
+
+SearchProvider::SuggestResult::SuggestResult(const string16& suggestion,
+                                             bool from_keyword_provider,
+                                             int relevance,
+                                             bool relevance_from_server)
+    : Result(from_keyword_provider, relevance, relevance_from_server),
+      suggestion_(suggestion) {
+}
+
+SearchProvider::SuggestResult::~SuggestResult() {
+}
+
+bool SearchProvider::SuggestResult::IsInlineable(const string16& input) const {
+  return StartsWith(suggestion_, input, false);
+}
+
+int SearchProvider::SuggestResult::CalculateRelevance(
+    const AutocompleteInput& input,
+    bool keyword_provider_requested) const {
+  if (!from_keyword_provider_ && keyword_provider_requested)
+    return 100;
+  return ((input.type() == AutocompleteInput::URL) ? 300 : 600);
+}
+
+
+// SearchProvider::NavigationResult -------------------------------------------
+
+SearchProvider::NavigationResult::NavigationResult(
+    const AutocompleteProvider& provider,
+    const GURL& url,
+    const string16& description,
+    bool from_keyword_provider,
+    int relevance,
+    bool relevance_from_server)
+    : Result(from_keyword_provider, relevance, relevance_from_server),
+      url_(url),
+      formatted_url_(AutocompleteInput::FormattedStringWithEquivalentMeaning(
+          url, provider.StringForURLDisplay(url, true, false))),
+      description_(description) {
+  DCHECK(url_.is_valid());
+}
+
+SearchProvider::NavigationResult::~NavigationResult() {
+}
+
+bool SearchProvider::NavigationResult::IsInlineable(
+    const string16& input) const {
+  return URLPrefix::BestURLPrefix(formatted_url_, input) != NULL;
+}
+
+int SearchProvider::NavigationResult::CalculateRelevance(
+    const AutocompleteInput& input,
+    bool keyword_provider_requested) const {
+  return (from_keyword_provider_ || !keyword_provider_requested) ? 800 : 150;
+}
+
+
+// SearchProvider::CompareScoredResults ---------------------------------------
+
+class SearchProvider::CompareScoredResults {
+ public:
+  bool operator()(const Result& a, const Result& b) {
+    // Sort in descending relevance order.
+    return a.relevance() > b.relevance();
+  }
+};
+
+
+// SearchProvider::Results ----------------------------------------------------
+
+SearchProvider::Results::Results() : verbatim_relevance(-1) {
+}
+
+SearchProvider::Results::~Results() {
+}
+
+void SearchProvider::Results::Clear() {
+  suggest_results.clear();
+  navigation_results.clear();
+  verbatim_relevance = -1;
+}
+
+bool SearchProvider::Results::HasServerProvidedScores() const {
+  if (verbatim_relevance >= 0)
+    return true;
+
+  // Right now either all results of one type will be server-scored or they will
+  // all be locally scored, but in case we change this later, we'll just check
+  // them all.
+  for (SuggestResults::const_iterator i(suggest_results.begin());
+       i != suggest_results.end(); ++i) {
+    if (i->relevance_from_server())
+      return true;
+  }
+  for (NavigationResults::const_iterator i(navigation_results.begin());
+       i != navigation_results.end(); ++i) {
+    if (i->relevance_from_server())
+      return true;
+  }
+
+  return false;
+}
+
+
 // SearchProvider -------------------------------------------------------------
 
 // static
 const int SearchProvider::kDefaultProviderURLFetcherID = 1;
-// static
 const int SearchProvider::kKeywordProviderURLFetcherID = 2;
-// static
 int SearchProvider::kMinimumTimeBetweenSuggestQueriesMs = 100;
+const char SearchProvider::kRelevanceFromServerKey[] = "relevance_from_server";
+const char SearchProvider::kTrue[] = "true";
+const char SearchProvider::kFalse[] = "false";
+
+SearchProvider::SearchProvider(AutocompleteProviderListener* listener,
+                               Profile* profile)
+    : AutocompleteProvider(listener, profile,
+          AutocompleteProvider::TYPE_SEARCH),
+      providers_(TemplateURLServiceFactory::GetForProfile(profile)),
+      suggest_results_pending_(0),
+      field_trial_triggered_(false),
+      field_trial_triggered_in_session_(false),
+      omnibox_start_margin_(-1) {
+}
 
 // static
 AutocompleteMatch SearchProvider::CreateSearchSuggestion(
-    Profile* profile,
     AutocompleteProvider* autocomplete_provider,
-    const AutocompleteInput& input,
-    const string16& query_string,
-    const string16& input_text,
     int relevance,
     AutocompleteMatch::Type type,
-    int accepted_suggestion,
+    const TemplateURL* template_url,
+    const string16& query_string,
+    const string16& input_text,
+    const AutocompleteInput& input,
     bool is_keyword,
-    const string16& keyword,
-    int omnibox_start_margin) {
+    int accepted_suggestion,
+    int omnibox_start_margin,
+    bool append_extra_query_params) {
   AutocompleteMatch match(autocomplete_provider, relevance, false, type);
 
-  // Bail out now if we don't actually have a valid provider.
-  match.keyword = keyword;
-  const TemplateURL* provider_url = match.GetTemplateURL(profile, false);
-  if (provider_url == NULL)
+  if (!template_url)
     return match;
+  match.keyword = template_url->keyword();
 
   match.contents.assign(query_string);
   // We do intra-string highlighting for suggestions - the suggested segment
@@ -199,13 +327,15 @@
   }
   match.fill_into_edit.append(query_string);
 
-  const TemplateURLRef& search_url = provider_url->url_ref();
+  const TemplateURLRef& search_url = template_url->url_ref();
   DCHECK(search_url.SupportsReplacement());
   match.search_terms_args.reset(
       new TemplateURLRef::SearchTermsArgs(query_string));
   match.search_terms_args->original_query = input_text;
   match.search_terms_args->accepted_suggestion = accepted_suggestion;
   match.search_terms_args->omnibox_start_margin = omnibox_start_margin;
+  match.search_terms_args->append_extra_query_params =
+      append_extra_query_params;
   // This is the destination URL sans assisted query stats.  This must be set
   // so the AutocompleteController can properly de-dupe; the controller will
   // eventually overwrite it before it reaches the user.
@@ -219,113 +349,108 @@
   return match;
 }
 
-SearchProvider::SearchProvider(AutocompleteProviderListener* listener,
-                               Profile* profile)
-    : AutocompleteProvider(listener, profile,
-          AutocompleteProvider::TYPE_SEARCH),
-      providers_(TemplateURLServiceFactory::GetForProfile(profile)),
-      suggest_results_pending_(0),
-      instant_finalized_(false),
-      field_trial_triggered_(false),
-      field_trial_triggered_in_session_(false),
-      suppress_search_suggestions_(false),
-      omnibox_start_margin_(-1) {
-}
-
-void SearchProvider::FinalizeInstantQuery(const string16& input_text,
-                                          const InstantSuggestion& suggestion) {
-  if (done_ || instant_finalized_)
-    return;
-
-  instant_finalized_ = true;
-  UpdateDone();
-
-  if (input_text.empty()) {
-    // We only need to update the listener if we're actually done.
-    if (done_)
-      listener_->OnProviderUpdate(false);
-    return;
-  }
-
-  default_provider_suggestion_ = suggestion;
-
-  string16 adjusted_input_text(input_text);
-  AutocompleteInput::RemoveForcedQueryStringIfNecessary(input_.type(),
-                                                        &adjusted_input_text);
-
-  const string16 text = adjusted_input_text + suggestion.text;
-  bool results_updated = false;
-  // Remove any matches that are identical to |text|. We don't use the
-  // destination_url for comparison as it varies depending upon the index passed
-  // to TemplateURL::ReplaceSearchTerms.
-  for (ACMatches::iterator i = matches_.begin(); i != matches_.end();) {
-    if (((i->type == AutocompleteMatchType::SEARCH_HISTORY) ||
-         (i->type == AutocompleteMatchType::SEARCH_SUGGEST)) &&
-        (i->fill_into_edit == text)) {
-      i = matches_.erase(i);
-      results_updated = true;
-    } else {
-      ++i;
+void SearchProvider::AddProviderInfo(ProvidersInfo* provider_info) const {
+  provider_info->push_back(metrics::OmniboxEventProto_ProviderInfo());
+  metrics::OmniboxEventProto_ProviderInfo& new_entry = provider_info->back();
+  new_entry.set_provider(AsOmniboxEventProviderType());
+  new_entry.set_provider_done(done_);
+  std::vector<uint32> field_trial_hashes;
+  OmniboxFieldTrial::GetActiveSuggestFieldTrialHashes(&field_trial_hashes);
+  for (size_t i = 0; i < field_trial_hashes.size(); ++i) {
+    if (field_trial_triggered_)
+      new_entry.mutable_field_trial_triggered()->Add(field_trial_hashes[i]);
+    if (field_trial_triggered_in_session_) {
+      new_entry.mutable_field_trial_triggered_in_session()->Add(
+          field_trial_hashes[i]);
     }
   }
-
-  // Add the new Instant suggest result.
-  if (suggestion.type == INSTANT_SUGGESTION_SEARCH) {
-    // Instant has a query suggestion. Rank it higher than SEARCH_WHAT_YOU_TYPED
-    // so that it gets autocompleted.
-    const int verbatim_relevance = GetVerbatimRelevance();
-    int did_not_accept_default_suggestion =
-        default_results_.suggest_results.empty() ?
-        TemplateURLRef::NO_SUGGESTIONS_AVAILABLE :
-        TemplateURLRef::NO_SUGGESTION_CHOSEN;
-    MatchMap match_map;
-    AddMatchToMap(text, adjusted_input_text, verbatim_relevance + 1,
-                  AutocompleteMatchType::SEARCH_SUGGEST,
-                  did_not_accept_default_suggestion, false, &match_map);
-    if (!match_map.empty()) {
-      matches_.push_back(match_map.begin()->second);
-      results_updated = true;
-    }
-  } else {
-    // Instant has a URL suggestion. Rank it higher than URL_WHAT_YOU_TYPED so
-    // it gets autocompleted; use kNonURLVerbatimRelevance rather than
-    // verbatim_relevance so that the score does not change if the user keeps
-    // typing and the input changes from type UNKNOWN to URL.
-    matches_.push_back(NavigationToMatch(
-        NavigationResult(*this,
-                         GURL(UTF16ToUTF8(suggestion.text)),
-                         string16(),
-                         false,
-                         kNonURLVerbatimRelevance + 1)));
-    results_updated = true;
-  }
-
-  if (results_updated || done_)
-    listener_->OnProviderUpdate(results_updated);
 }
 
-void SearchProvider::ClearInstantSuggestion() {
-  default_provider_suggestion_ = InstantSuggestion();
-  if (done_ || instant_finalized_)
-    return;
-  instant_finalized_ = true;
-  UpdateMatches();
-  listener_->OnProviderUpdate(true);
-}
-
-void SearchProvider::SuppressSearchSuggestions() {
-  suppress_search_suggestions_ = true;
+void SearchProvider::ResetSession() {
+  field_trial_triggered_in_session_ = false;
 }
 
 void SearchProvider::SetOmniboxStartMargin(int omnibox_start_margin) {
   omnibox_start_margin_ = omnibox_start_margin;
 }
 
+SearchProvider::~SearchProvider() {
+}
+
+// static
+void SearchProvider::RemoveStaleResults(const string16& input,
+                                        int verbatim_relevance,
+                                        SuggestResults* suggest_results,
+                                        NavigationResults* navigation_results) {
+  DCHECK_GE(verbatim_relevance, 0);
+  // Keep pointers to the head of (the highest scoring elements of)
+  // |suggest_results| and |navigation_results|.  Iterate down the lists
+  // removing non-inlineable results in order of decreasing relevance
+  // scores.  Stop when the highest scoring element among those remaining
+  // is inlineable or the element is less than |verbatim_relevance|.
+  // This allows non-inlineable lower-scoring results to remain
+  // because (i) they are guaranteed to not be inlined and (ii)
+  // letting them remain reduces visual jank.  For instance, as the
+  // user types the mis-spelled query "fpobar" (for foobar), the
+  // suggestion "foobar" will be suggested on every keystroke.  If the
+  // SearchProvider always removes all non-inlineable results, the user will
+  // see visual jitter/jank as the result disappears and re-appears moments
+  // later as the suggest server returns results.
+  SuggestResults::iterator sug_it = suggest_results->begin();
+  NavigationResults::iterator nav_it = navigation_results->begin();
+  while ((sug_it != suggest_results->end()) ||
+         (nav_it != navigation_results->end())) {
+    const int sug_rel =
+        (sug_it != suggest_results->end()) ? sug_it->relevance() : -1;
+    const int nav_rel =
+        (nav_it != navigation_results->end()) ? nav_it->relevance() : -1;
+    if (std::max(sug_rel, nav_rel) < verbatim_relevance)
+      break;
+    if (sug_rel > nav_rel) {
+      // The current top result is a search suggestion.
+      if (sug_it->IsInlineable(input))
+        break;
+      sug_it = suggest_results->erase(sug_it);
+    } else if (sug_rel == nav_rel) {
+      // Have both results and they're tied.
+      const bool sug_inlineable = sug_it->IsInlineable(input);
+      const bool nav_inlineable = nav_it->IsInlineable(input);
+      if (!sug_inlineable)
+        sug_it = suggest_results->erase(sug_it);
+      if (!nav_inlineable)
+        nav_it = navigation_results->erase(nav_it);
+      if (sug_inlineable || nav_inlineable)
+        break;
+    } else {
+      // The current top result is a navigational suggestion.
+      if (nav_it->IsInlineable(input))
+        break;
+      nav_it = navigation_results->erase(nav_it);
+    }
+  }
+}
+
+// static
+int SearchProvider::CalculateRelevanceForKeywordVerbatim(
+    AutocompleteInput::Type type,
+    bool prefer_keyword) {
+  // This function is responsible for scoring verbatim query matches
+  // for non-extension keywords.  KeywordProvider::CalculateRelevance()
+  // scores verbatim query matches for extension keywords, as well as
+  // for keyword matches (i.e., suggestions of a keyword itself, not a
+  // suggestion of a query on a keyword search engine).  These two
+  // functions are currently in sync, but there's no reason we
+  // couldn't decide in the future to score verbatim matches
+  // differently for extension and non-extension keywords.  If you
+  // make such a change, however, you should update this comment to
+  // describe it, so it's clear why the functions diverge.
+  if (prefer_keyword)
+    return 1500;
+  return (type == AutocompleteInput::QUERY) ? 1450 : 1100;
+}
+
 void SearchProvider::Start(const AutocompleteInput& input,
                            bool minimal_changes) {
-  const bool suppress_search_suggestions = suppress_search_suggestions_;
-  suppress_search_suggestions_ = false;
-
   // Do our best to load the model as early as possible.  This will reduce
   // odds of having the model not ready when really needed (a non-empty input).
   TemplateURLService* model = providers_.template_url_service();
@@ -335,9 +460,6 @@
   matches_.clear();
   field_trial_triggered_ = false;
 
-  instant_finalized_ =
-      (input.matches_requested() != AutocompleteInput::ALL_MATCHES);
-
   // Can't return search/suggest results for bogus input or without a profile.
   if (!profile_ || (input.type() == AutocompleteInput::INVALID)) {
     Stop(false);
@@ -374,23 +496,9 @@
       keyword_provider->keyword() : string16());
   if (!minimal_changes ||
       !providers_.equal(default_provider_keyword, keyword_provider_keyword)) {
-    // If Instant has not come back with a suggestion, adjust the previous
-    // suggestion if possible. If |instant_finalized| is true, we are looking
-    // for synchronous matches only, so the suggestion is cleared.
-    if (instant_finalized_)
-      default_provider_suggestion_ = InstantSuggestion();
-    else
-      AdjustDefaultProviderSuggestion(input_.text(), input.text());
-
     // Cancel any in-flight suggest requests.
-    if (!done_) {
-      // The Stop(false) call below clears |default_provider_suggestion_|, but
-      // in this instance we do not want to clear cached results, so we
-      // restore it.
-      base::AutoReset<InstantSuggestion> reset(&default_provider_suggestion_,
-                                               InstantSuggestion());
+    if (!done_)
       Stop(false);
-    }
   }
 
   providers_.set(default_provider_keyword, keyword_provider_keyword);
@@ -413,141 +521,19 @@
 
   input_ = input;
 
-  if (!suppress_search_suggestions) {
-    DoHistoryQuery(minimal_changes);
-    StartOrStopSuggestQuery(minimal_changes);
-  }
+  DoHistoryQuery(minimal_changes);
+  StartOrStopSuggestQuery(minimal_changes);
   UpdateMatches();
 }
 
-SearchProvider::Result::Result(bool from_keyword_provider, int relevance)
-    : from_keyword_provider_(from_keyword_provider),
-      relevance_(relevance) {
-}
-
-SearchProvider::Result::~Result() {}
-
-SearchProvider::SuggestResult::SuggestResult(const string16& suggestion,
-                                             bool from_keyword_provider,
-                                             int relevance)
-    : Result(from_keyword_provider, relevance),
-      suggestion_(suggestion) {
-}
-
-SearchProvider::SuggestResult::~SuggestResult() {}
-
-bool SearchProvider::SuggestResult::IsInlineable(const string16& input) const {
-  return StartsWith(suggestion_, input, false);
-}
-
-int SearchProvider::SuggestResult::CalculateRelevance(
-    const AutocompleteInput& input,
-    bool keyword_provider_requested) const {
-  if (!from_keyword_provider_ && keyword_provider_requested)
-    return 100;
-  return ((input.type() == AutocompleteInput::URL) ? 300 : 600);
-}
-
-SearchProvider::NavigationResult::NavigationResult(
-    const AutocompleteProvider& provider,
-    const GURL& url,
-    const string16& description,
-    bool from_keyword_provider,
-    int relevance)
-    : Result(from_keyword_provider, relevance),
-      url_(url),
-      formatted_url_(AutocompleteInput::FormattedStringWithEquivalentMeaning(
-          url, provider.StringForURLDisplay(url, true, false))),
-      description_(description) {
-  DCHECK(url_.is_valid());
-}
-
-SearchProvider::NavigationResult::~NavigationResult() {}
-
-bool SearchProvider::NavigationResult::IsInlineable(
-    const string16& input) const {
-  return URLPrefix::BestURLPrefix(formatted_url_, input) != NULL;
-}
-
-int SearchProvider::NavigationResult::CalculateRelevance(
-    const AutocompleteInput& input,
-    bool keyword_provider_requested) const {
-  return (from_keyword_provider_ || !keyword_provider_requested) ? 800 : 150;
-}
-
-SearchProvider::Results::Results()
-    : has_suggested_relevance(false),
-      verbatim_relevance(-1) {
-}
-
-SearchProvider::Results::~Results() {
-}
-
-void SearchProvider::Results::Clear() {
-  suggest_results.clear();
-  navigation_results.clear();
-  has_suggested_relevance = false;
-  verbatim_relevance = -1;
-}
-
-class SearchProvider::CompareScoredResults {
- public:
-  bool operator()(const Result& a, const Result& b) {
-    // Sort in descending relevance order.
-    return a.relevance() > b.relevance();
-  }
-};
-
-void SearchProvider::Run() {
-  // Start a new request with the current input.
-  suggest_results_pending_ = 0;
-  time_suggest_request_sent_ = base::TimeTicks::Now();
-
-  default_fetcher_.reset(CreateSuggestFetcher(kDefaultProviderURLFetcherID,
-      providers_.GetDefaultProviderURL(), input_));
-  keyword_fetcher_.reset(CreateSuggestFetcher(kKeywordProviderURLFetcherID,
-      providers_.GetKeywordProviderURL(), keyword_input_));
-
-  // Both the above can fail if the providers have been modified or deleted
-  // since the query began.
-  if (suggest_results_pending_ == 0) {
-    UpdateDone();
-    // We only need to update the listener if we're actually done.
-    if (done_)
-      listener_->OnProviderUpdate(false);
-  }
-}
-
 void SearchProvider::Stop(bool clear_cached_results) {
   StopSuggest();
   done_ = true;
-  default_provider_suggestion_ = InstantSuggestion();
 
   if (clear_cached_results)
     ClearAllResults();
 }
 
-void SearchProvider::AddProviderInfo(ProvidersInfo* provider_info) const {
-  provider_info->push_back(metrics::OmniboxEventProto_ProviderInfo());
-  metrics::OmniboxEventProto_ProviderInfo& new_entry = provider_info->back();
-  new_entry.set_provider(AsOmniboxEventProviderType());
-  new_entry.set_provider_done(done_);
-  std::vector<uint32> field_trial_hashes;
-  OmniboxFieldTrial::GetActiveSuggestFieldTrialHashes(&field_trial_hashes);
-  for (size_t i = 0; i < field_trial_hashes.size(); ++i) {
-    if (field_trial_triggered_)
-      new_entry.mutable_field_trial_triggered()->Add(field_trial_hashes[i]);
-    if (field_trial_triggered_in_session_) {
-      new_entry.mutable_field_trial_triggered_in_session()->Add(
-          field_trial_hashes[i]);
-    }
-  }
-}
-
-void SearchProvider::ResetSession() {
-  field_trial_triggered_in_session_ = false;
-}
-
 void SearchProvider::OnURLFetchComplete(const net::URLFetcher* source) {
   DCHECK(!done_);
   suggest_results_pending_--;
@@ -576,9 +562,10 @@
   // Ensure the request succeeded and that the provider used is still available.
   // A verbatim match cannot be generated without this provider, causing errors.
   const bool request_succeeded =
-      source->GetStatus().is_success() && source->GetResponseCode() == 200 &&
-      ((is_keyword && providers_.GetKeywordProviderURL()) ||
-       (!is_keyword && providers_.GetDefaultProviderURL()));
+      source->GetStatus().is_success() && (source->GetResponseCode() == 200) &&
+      (is_keyword ?
+          providers_.GetKeywordProviderURL() :
+          providers_.GetDefaultProviderURL());
 
   // Record response time for suggest requests sent to Google.  We care
   // only about the common case: the Google default provider used in
@@ -587,7 +574,7 @@
   if (!is_keyword && default_url &&
       (TemplateURLPrepopulateData::GetEngineType(default_url->url()) ==
        SEARCH_ENGINE_GOOGLE)) {
-    const TimeDelta elapsed_time =
+    const base::TimeDelta elapsed_time =
         base::TimeTicks::Now() - time_suggest_request_sent_;
     if (request_succeeded) {
       UMA_HISTOGRAM_TIMES("Omnibox.SuggestRequest.Success.GoogleResponseTime",
@@ -611,11 +598,24 @@
     listener_->OnProviderUpdate(results_updated);
 }
 
-bool SearchProvider::IsNonInstantSearchDone() const {
-  return !timer_.IsRunning() && (suggest_results_pending_ == 0);
-}
+void SearchProvider::Run() {
+  // Start a new request with the current input.
+  suggest_results_pending_ = 0;
+  time_suggest_request_sent_ = base::TimeTicks::Now();
 
-SearchProvider::~SearchProvider() {
+  default_fetcher_.reset(CreateSuggestFetcher(kDefaultProviderURLFetcherID,
+      providers_.GetDefaultProviderURL(), input_));
+  keyword_fetcher_.reset(CreateSuggestFetcher(kKeywordProviderURLFetcherID,
+      providers_.GetKeywordProviderURL(), keyword_input_));
+
+  // Both the above can fail if the providers have been modified or deleted
+  // since the query began.
+  if (suggest_results_pending_ == 0) {
+    UpdateDone();
+    // We only need to update the listener if we're actually done.
+    if (done_)
+      listener_->OnProviderUpdate(false);
+  }
 }
 
 void SearchProvider::DoHistoryQuery(bool minimal_changes) {
@@ -688,7 +688,7 @@
   // To avoid flooding the suggest server, don't send a query until at
   // least 100 ms since the last query.
   base::TimeTicks next_suggest_time(time_suggest_request_sent_ +
-      TimeDelta::FromMilliseconds(kMinimumTimeBetweenSuggestQueriesMs));
+      base::TimeDelta::FromMilliseconds(kMinimumTimeBetweenSuggestQueriesMs));
   base::TimeTicks now(base::TimeTicks::Now());
   if (now >= next_suggest_time) {
     Run();
@@ -777,11 +777,11 @@
   // and ease in reasoning about the invariants involved, this code
   // removes stales results from the keyword provider and default
   // provider independently.
-  RemoveStaleResults(input_.text(), GetVerbatimRelevance(),
+  RemoveStaleResults(input_.text(), GetVerbatimRelevance(NULL),
                      &default_results_.suggest_results,
                      &default_results_.navigation_results);
   if (!keyword_input_.text().empty()) {
-    RemoveStaleResults(keyword_input_.text(), GetKeywordVerbatimRelevance(),
+    RemoveStaleResults(keyword_input_.text(), GetKeywordVerbatimRelevance(NULL),
                        &keyword_results_.suggest_results,
                        &keyword_results_.navigation_results);
   } else {
@@ -791,102 +791,11 @@
   }
 }
 
-// static
-void SearchProvider::RemoveStaleResults(const string16& input,
-                                        int verbatim_relevance,
-                                        SuggestResults* suggest_results,
-                                        NavigationResults* navigation_results) {
-  DCHECK_GE(verbatim_relevance, 0);
-  // Keep pointers to the head of (the highest scoring elements of)
-  // |suggest_results| and |navigation_results|.  Iterate down the lists
-  // removing non-inlineable results in order of decreasing relevance
-  // scores.  Stop when the highest scoring element among those remaining
-  // is inlineable or the element is less than |verbatim_relevance|.
-  // This allows non-inlineable lower-scoring results to remain
-  // because (i) they are guaranteed to not be inlined and (ii)
-  // letting them remain reduces visual jank.  For instance, as the
-  // user types the mis-spelled query "fpobar" (for foobar), the
-  // suggestion "foobar" will be suggested on every keystroke.  If the
-  // SearchProvider always removes all non-inlineable results, the user will
-  // see visual jitter/jank as the result disappears and re-appears moments
-  // later as the suggest server returns results.
-  SuggestResults::iterator sug_it = suggest_results->begin();
-  NavigationResults::iterator nav_it = navigation_results->begin();
-  while ((sug_it != suggest_results->end()) ||
-         (nav_it != navigation_results->end())) {
-    const int sug_rel =
-        (sug_it != suggest_results->end()) ? sug_it->relevance() : -1;
-    const int nav_rel =
-        (nav_it != navigation_results->end()) ? nav_it->relevance() : -1;
-    if (std::max(sug_rel, nav_rel) < verbatim_relevance)
-      break;
-    if (sug_rel > nav_rel) {
-      // The current top result is a search suggestion.
-      if (sug_it->IsInlineable(input))
-        break;
-      sug_it = suggest_results->erase(sug_it);
-    } else if (sug_rel == nav_rel) {
-      // Have both results and they're tied.
-      const bool sug_inlineable = sug_it->IsInlineable(input);
-      const bool nav_inlineable = nav_it->IsInlineable(input);
-      if (!sug_inlineable)
-        sug_it = suggest_results->erase(sug_it);
-      if (!nav_inlineable)
-        nav_it = navigation_results->erase(nav_it);
-      if (sug_inlineable || nav_inlineable)
-        break;
-    } else {
-      // The current top result is a navigational suggestion.
-      if (nav_it->IsInlineable(input))
-        break;
-      nav_it = navigation_results->erase(nav_it);
-    }
-  }
-}
-
-void SearchProvider::AdjustDefaultProviderSuggestion(
-    const string16& previous_input,
-    const string16& current_input) {
-  if (default_provider_suggestion_.type == INSTANT_SUGGESTION_URL) {
-    // Description and relevance do not matter in the check for staleness.
-    NavigationResult result(*this,
-                            GURL(default_provider_suggestion_.text),
-                            string16(),
-                            false,
-                            100);
-    // If navigation suggestion is stale, clear |default_provider_suggestion_|.
-    if (!result.IsInlineable(current_input))
-      default_provider_suggestion_ = InstantSuggestion();
-  } else {
-    DCHECK(default_provider_suggestion_.type == INSTANT_SUGGESTION_SEARCH);
-    // InstantSuggestion of type SEARCH contain only the suggested text, and not
-    // the full text of the query. This looks at the current and previous input
-    // to determine if the user is typing forward, and if the new input is
-    // contained in |default_provider_suggestion_|. If so, the suggestion is
-    // adjusted and can be kept. Otherwise, it is reset.
-    if (!previous_input.empty() &&
-        StartsWith(current_input, previous_input, false)) {
-      // User is typing forward; verify if new input is part of the suggestion.
-      const string16 new_text = string16(current_input, previous_input.size());
-      if (StartsWith(default_provider_suggestion_.text, new_text, false)) {
-        // New input is a prefix to the previous suggestion, adjust the
-        // suggestion to strip the prefix.
-        default_provider_suggestion_.text.erase(0, new_text.size());
-        return;
-      }
-    }
-    // If we are here, the search suggestion is stale; reset it.
-    default_provider_suggestion_ = InstantSuggestion();
-  }
-}
-
 void SearchProvider::ApplyCalculatedRelevance() {
   ApplyCalculatedSuggestRelevance(&keyword_results_.suggest_results);
   ApplyCalculatedSuggestRelevance(&default_results_.suggest_results);
   ApplyCalculatedNavigationRelevance(&keyword_results_.navigation_results);
   ApplyCalculatedNavigationRelevance(&default_results_.navigation_results);
-  default_results_.has_suggested_relevance = false;
-  keyword_results_.has_suggested_relevance = false;
   default_results_.verbatim_relevance = -1;
   keyword_results_.verbatim_relevance = -1;
 }
@@ -897,6 +806,7 @@
     result.set_relevance(
         result.CalculateRelevance(input_, providers_.has_keyword_provider()) +
         (list->size() - i - 1));
+    result.set_relevance_from_server(false);
   }
 }
 
@@ -907,6 +817,7 @@
     result.set_relevance(
         result.CalculateRelevance(input_, providers_.has_keyword_provider()) +
         (list->size() - i - 1));
+    result.set_relevance_from_server(false);
   }
 }
 
@@ -959,7 +870,6 @@
 
   // Reset suggested relevance information from the default provider.
   Results* results = is_keyword ? &keyword_results_ : &default_results_;
-  results->has_suggested_relevance = false;
   results->verbatim_relevance = -1;
 
   // 5th element: Optional key-value pairs from the Suggest server.
@@ -1006,13 +916,13 @@
       if (url.is_valid()) {
         if (descriptions != NULL)
           descriptions->GetString(index, &title);
-        results->navigation_results.push_back(
-            NavigationResult(*this, url, title, is_keyword, relevance));
+        results->navigation_results.push_back(NavigationResult(
+            *this, url, title, is_keyword, relevance, true));
       }
     } else {
       // TODO(kochi): Improve calculator result presentation.
       results->suggest_results.push_back(
-          SuggestResult(result, is_keyword, relevance));
+          SuggestResult(result, is_keyword, relevance, true));
     }
   }
 
@@ -1020,8 +930,6 @@
   if (relevances == NULL) {
     ApplyCalculatedSuggestRelevance(&results->suggest_results);
     ApplyCalculatedNavigationRelevance(&results->navigation_results);
-  } else {
-    results->has_suggested_relevance = true;
   }
   // Keep the result lists sorted.
   const CompareScoredResults comparator = CompareScoredResults();
@@ -1038,19 +946,21 @@
   // Convert all the results to matches and add them to a map, so we can keep
   // the most relevant match for each result.
   MatchMap map;
-  const Time no_time;
+  const base::Time no_time;
   int did_not_accept_keyword_suggestion =
       keyword_results_.suggest_results.empty() ?
       TemplateURLRef::NO_SUGGESTIONS_AVAILABLE :
       TemplateURLRef::NO_SUGGESTION_CHOSEN;
 
-  int verbatim_relevance = GetVerbatimRelevance();
+  bool relevance_from_server;
+  int verbatim_relevance = GetVerbatimRelevance(&relevance_from_server);
   int did_not_accept_default_suggestion =
       default_results_.suggest_results.empty() ?
       TemplateURLRef::NO_SUGGESTIONS_AVAILABLE :
       TemplateURLRef::NO_SUGGESTION_CHOSEN;
   if (verbatim_relevance > 0) {
     AddMatchToMap(input_.text(), input_.text(), verbatim_relevance,
+                  relevance_from_server,
                   AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
                   did_not_accept_default_suggestion, false, &map);
   }
@@ -1063,24 +973,17 @@
     // to the keyword verbatim search query.  Do not create other matches
     // of type SEARCH_OTHER_ENGINE.
     if (keyword_url && !keyword_url->IsExtensionKeyword()) {
-      const int keyword_verbatim_relevance = GetKeywordVerbatimRelevance();
+      bool keyword_relevance_from_server;
+      const int keyword_verbatim_relevance =
+          GetKeywordVerbatimRelevance(&keyword_relevance_from_server);
       if (keyword_verbatim_relevance > 0) {
         AddMatchToMap(keyword_input_.text(), keyword_input_.text(),
-                      keyword_verbatim_relevance,
+                      keyword_verbatim_relevance, keyword_relevance_from_server,
                       AutocompleteMatchType::SEARCH_OTHER_ENGINE,
                       did_not_accept_keyword_suggestion, true, &map);
       }
     }
   }
-  const size_t verbatim_matches_size = map.size();
-  if (!default_provider_suggestion_.text.empty() &&
-      default_provider_suggestion_.type == INSTANT_SUGGESTION_SEARCH &&
-      !input_.prevent_inline_autocomplete())
-    AddMatchToMap(input_.text() + default_provider_suggestion_.text,
-                  input_.text(), verbatim_relevance + 1,
-                  AutocompleteMatchType::SEARCH_SUGGEST,
-                  did_not_accept_default_suggestion, false, &map);
-
   AddHistoryResultsToMap(keyword_history_results_, true,
                          did_not_accept_keyword_suggestion, &map);
   AddHistoryResultsToMap(default_history_results_, false,
@@ -1089,34 +992,49 @@
   AddSuggestResultsToMap(keyword_results_.suggest_results, &map);
   AddSuggestResultsToMap(default_results_.suggest_results, &map);
 
-  // Now add the most relevant matches from the map to |matches_|.
-  matches_.clear();
+  ACMatches matches;
   for (MatchMap::const_iterator i(map.begin()); i != map.end(); ++i)
-    matches_.push_back(i->second);
+    matches.push_back(i->second);
 
-  if (!default_provider_suggestion_.text.empty() &&
-      default_provider_suggestion_.type == INSTANT_SUGGESTION_URL &&
-      !input_.prevent_inline_autocomplete()) {
-    // See comment in FinalizeInstantQuery() for why we don't use
-    // |verbatim_relevance| here.
-    matches_.push_back(NavigationToMatch(
-        NavigationResult(*this,
-                         GURL(UTF16ToUTF8(default_provider_suggestion_.text)),
-                         string16(),
-                         false,
-                         kNonURLVerbatimRelevance + 1)));
+  AddNavigationResultsToMatches(keyword_results_.navigation_results, &matches);
+  AddNavigationResultsToMatches(default_results_.navigation_results, &matches);
+
+  // Now add the most relevant matches to |matches_|.  We take up to kMaxMatches
+  // suggest/navsuggest matches, regardless of origin.  If Instant Extended is
+  // enabled and we have server-provided (and thus hopefully more accurate)
+  // scores for some suggestions, we allow more of those, until we reach
+  // AutocompleteResult::kMaxMatches total matches (that is, enough to fill the
+  // whole popup).
+  //
+  // We will always return any verbatim matches, no matter how we obtained their
+  // scores, unless we have already accepted AutocompleteResult::kMaxMatches
+  // higher-scoring matches under the conditions above.
+  std::sort(matches.begin(), matches.end(), &AutocompleteMatch::MoreRelevant);
+  matches_.clear();
+
+  size_t num_suggestions = 0;
+  for (ACMatches::const_iterator i(matches.begin());
+       (i != matches.end()) &&
+           (matches_.size() < AutocompleteResult::kMaxMatches);
+       ++i) {
+    // SEARCH_OTHER_ENGINE is only used in the SearchProvider for the keyword
+    // verbatim result, so this condition basically means "if this match is a
+    // suggestion of some sort".
+    if ((i->type != AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED) &&
+        (i->type != AutocompleteMatchType::SEARCH_OTHER_ENGINE)) {
+      // If we've already hit the limit on non-server-scored suggestions, and
+      // this isn't a server-scored suggestion we can add, skip it.
+      if ((num_suggestions >= kMaxMatches) &&
+          (!chrome::IsInstantExtendedAPIEnabled() ||
+           (i->GetAdditionalInfo(kRelevanceFromServerKey) != kTrue))) {
+        continue;
+      }
+
+      ++num_suggestions;
+    }
+
+    matches_.push_back(*i);
   }
-  AddNavigationResultsToMatches(keyword_results_.navigation_results, true);
-  AddNavigationResultsToMatches(default_results_.navigation_results, false);
-
-  // Allow additional match(es) for verbatim results if present.
-  const size_t max_total_matches = kMaxMatches + verbatim_matches_size;
-  std::partial_sort(matches_.begin(),
-      matches_.begin() + std::min(max_total_matches, matches_.size()),
-      matches_.end(), &AutocompleteMatch::MoreRelevant);
-
-  if (matches_.size() > max_total_matches)
-    matches_.resize(max_total_matches);
 }
 
 bool SearchProvider::IsTopMatchNavigationInKeywordMode() const {
@@ -1153,7 +1071,6 @@
   // not create any other match of type SEARCH_OTHER_ENGINE.
   return
       matches_.front().type != AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED &&
-      matches_.front().type != AutocompleteMatchType::URL_WHAT_YOU_TYPED &&
       matches_.front().type != AutocompleteMatchType::SEARCH_OTHER_ENGINE &&
       matches_.front().inline_autocomplete_offset == string16::npos &&
       matches_.front().fill_into_edit != input_.text();
@@ -1164,10 +1081,8 @@
 
   // Check constraints that may be violated by suggested relevances.
   if (!matches_.empty() &&
-      (default_results_.has_suggested_relevance ||
-       default_results_.verbatim_relevance >= 0 ||
-       keyword_results_.has_suggested_relevance ||
-       keyword_results_.verbatim_relevance >= 0)) {
+      (default_results_.HasServerProvidedScores() ||
+       keyword_results_.HasServerProvidedScores())) {
     // These blocks attempt to repair undesirable behavior by suggested
     // relevances with minimal impact, preserving other suggested relevances.
     if (IsTopMatchNavigationInKeywordMode()) {
@@ -1204,11 +1119,10 @@
       ConvertResultsToAutocompleteMatches();
     }
     if (IsTopMatchNotInlinable()) {
-      // Disregard suggested relevances if the top match is not a verbatim
-      // match, inlinable, or URL_WHAT_YOU_TYPED (which may be top match
-      // regardless of inlining).  For example, input "foo" should not
-      // invoke a search for "bar", which would happen if the "bar" search
-      // match outranked all other matches.
+      // Disregard suggested relevances if the top match is not a verbatim match
+      // or inlinable.  For example, input "foo" should not invoke a search for
+      // "bar", which would happen if the "bar" search match outranked all other
+      // matches.
       ApplyCalculatedRelevance();
       ConvertResultsToAutocompleteMatches();
     }
@@ -1224,22 +1138,14 @@
 
 void SearchProvider::AddNavigationResultsToMatches(
     const NavigationResults& navigation_results,
-    bool is_keyword) {
-  if (navigation_results.empty())
-    return;
-
-  if (is_keyword ?
-          keyword_results_.has_suggested_relevance :
-          default_results_.has_suggested_relevance) {
-    for (NavigationResults::const_iterator it = navigation_results.begin();
-         it != navigation_results.end(); ++it)
-      matches_.push_back(NavigationToMatch(*it));
-  } else {
-    // Pick the highest-scoring element only in absence of the
-    // suggested relevance scores.  (The results are already sorted.)
-    // TODO(kochi|msw): Add more navigational results if they get more
-    //                  meaningful relevance values; see http://b/1170574.
-    matches_.push_back(NavigationToMatch(navigation_results.front()));
+    ACMatches* matches) {
+  for (NavigationResults::const_iterator it = navigation_results.begin();
+        it != navigation_results.end(); ++it) {
+    matches->push_back(NavigationToMatch(*it));
+    // In the absence of suggested relevance scores, use only the single
+    // highest-scoring result.  (The results are already sorted by relevance.)
+    if (!it->relevance_from_server())
+      return;
   }
 }
 
@@ -1278,7 +1184,7 @@
                                          is_keyword);
   for (SuggestResults::const_iterator i(scored_results.begin());
        i != scored_results.end(); ++i) {
-    AddMatchToMap(i->suggestion(), input_text, i->relevance(),
+    AddMatchToMap(i->suggestion(), input_text, i->relevance(), false,
                   AutocompleteMatchType::SEARCH_HISTORY,
                   did_not_accept_suggestion,
                   is_keyword, map);
@@ -1323,7 +1229,8 @@
 
     int relevance = CalculateRelevanceForHistory(i->time, is_keyword,
                                                  prevent_inline_autocomplete);
-    scored_results.push_back(SuggestResult(i->term, is_keyword, relevance));
+    scored_results.push_back(
+        SuggestResult(i->term, is_keyword, relevance, false));
   }
 
   // History returns results sorted for us.  However, we may have docked some
@@ -1350,11 +1257,12 @@
     const bool is_keyword = results[i].from_keyword_provider();
     const string16& input = is_keyword ? keyword_input_.text() : input_.text();
     AddMatchToMap(results[i].suggestion(), input, results[i].relevance(),
+                  results[i].relevance_from_server(),
                   AutocompleteMatchType::SEARCH_SUGGEST, i, is_keyword, map);
   }
 }
 
-int SearchProvider::GetVerbatimRelevance() const {
+int SearchProvider::GetVerbatimRelevance(bool* relevance_from_server) const {
   // Use the suggested verbatim relevance score if it is non-negative (valid),
   // if inline autocomplete isn't prevented (always show verbatim on backspace),
   // and if it won't suppress verbatim, leaving no default provider matches.
@@ -1363,14 +1271,16 @@
   // left unable to search using their default provider from the omnibox.
   // Check for results on each verbatim calculation, as results from older
   // queries (on previous input) may be trimmed for failing to inline new input.
-  if (default_results_.verbatim_relevance >= 0 &&
+  bool use_server_relevance =
+      (default_results_.verbatim_relevance >= 0) &&
       !input_.prevent_inline_autocomplete() &&
-      (default_results_.verbatim_relevance > 0 ||
+      ((default_results_.verbatim_relevance > 0) ||
        !default_results_.suggest_results.empty() ||
-       !default_results_.navigation_results.empty())) {
-    return default_results_.verbatim_relevance;
-  }
-  return CalculateRelevanceForVerbatim();
+       !default_results_.navigation_results.empty());
+  if (relevance_from_server)
+    *relevance_from_server = use_server_relevance;
+  return use_server_relevance ?
+      default_results_.verbatim_relevance : CalculateRelevanceForVerbatim();
 }
 
 int SearchProvider::CalculateRelevanceForVerbatim() const {
@@ -1396,7 +1306,8 @@
   }
 }
 
-int SearchProvider::GetKeywordVerbatimRelevance() const {
+int SearchProvider::GetKeywordVerbatimRelevance(
+    bool* relevance_from_server) const {
   // Use the suggested verbatim relevance score if it is non-negative (valid),
   // if inline autocomplete isn't prevented (always show verbatim on backspace),
   // and if it won't suppress verbatim, leaving no keyword provider matches.
@@ -1405,38 +1316,22 @@
   // left unable to search using their keyword provider from the omnibox.
   // Check for results on each verbatim calculation, as results from older
   // queries (on previous input) may be trimmed for failing to inline new input.
-  if (keyword_results_.verbatim_relevance >= 0 &&
+  bool use_server_relevance =
+      (keyword_results_.verbatim_relevance >= 0) &&
       !input_.prevent_inline_autocomplete() &&
-      (keyword_results_.verbatim_relevance > 0 ||
+      ((keyword_results_.verbatim_relevance > 0) ||
        !keyword_results_.suggest_results.empty() ||
-       !keyword_results_.navigation_results.empty())) {
-    return keyword_results_.verbatim_relevance;
-  }
-  return CalculateRelevanceForKeywordVerbatim(
-      keyword_input_.type(), keyword_input_.prefer_keyword());
-}
-
-// static
-int SearchProvider::CalculateRelevanceForKeywordVerbatim(
-    AutocompleteInput::Type type,
-    bool prefer_keyword) {
-  // This function is responsible for scoring verbatim query matches
-  // for non-extension keywords.  KeywordProvider::CalculateRelevance()
-  // scores verbatim query matches for extension keywords, as well as
-  // for keyword matches (i.e., suggestions of a keyword itself, not a
-  // suggestion of a query on a keyword search engine).  These two
-  // functions are currently in sync, but there's no reason we
-  // couldn't decide in the future to score verbatim matches
-  // differently for extension and non-extension keywords.  If you
-  // make such a change, however, you should update this comment to
-  // describe it, so it's clear why the functions diverge.
-  if (prefer_keyword)
-    return 1500;
-  return (type == AutocompleteInput::QUERY) ? 1450 : 1100;
+       !keyword_results_.navigation_results.empty());
+  if (relevance_from_server)
+    *relevance_from_server = use_server_relevance;
+  return use_server_relevance ?
+      keyword_results_.verbatim_relevance :
+      CalculateRelevanceForKeywordVerbatim(keyword_input_.type(),
+                                           keyword_input_.prefer_keyword());
 }
 
 int SearchProvider::CalculateRelevanceForHistory(
-    const Time& time,
+    const base::Time& time,
     bool is_keyword,
     bool prevent_inline_autocomplete) const {
   // The relevance of past searches falls off over time. There are two distinct
@@ -1445,7 +1340,7 @@
   // falls to 1300. If the second equation is used the relevance of a search 15
   // minutes ago is discounted 50 points, while the relevance of a search two
   // weeks ago is discounted 450 points.
-  double elapsed_time = std::max((Time::Now() - time).InSecondsF(), 0.);
+  double elapsed_time = std::max((base::Time::Now() - time).InSecondsF(), 0.0);
   bool is_primary_provider = is_keyword || !providers_.has_keyword_provider();
   if (is_primary_provider && !prevent_inline_autocomplete) {
     // Searches with the past two days get a different curve.
@@ -1473,34 +1368,27 @@
 void SearchProvider::AddMatchToMap(const string16& query_string,
                                    const string16& input_text,
                                    int relevance,
+                                   bool relevance_from_server,
                                    AutocompleteMatch::Type type,
                                    int accepted_suggestion,
                                    bool is_keyword,
                                    MatchMap* map) {
-  // With Instant Extended, we never want to inline autocomplete search queries
-  // -- they should always use grey text if they are to autocomplete at all. So
-  // we clamp non-verbatim results to just below the verbatim score to ensure
-  // that none of them are inline autocompleted.
-  if (type != AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED &&
-      type != AutocompleteMatchType::SEARCH_OTHER_ENGINE &&
-      chrome::IsInstantExtendedAPIEnabled()) {
-    relevance = std::min(kNonURLVerbatimRelevance - 1, relevance);
-  }
-
-  const string16& keyword = is_keyword ?
-      providers_.keyword_provider() : providers_.default_provider();
-  AutocompleteMatch match = CreateSearchSuggestion(profile_, this, input_,
-      query_string, input_text, relevance, type, accepted_suggestion,
-      is_keyword, keyword, omnibox_start_margin_);
+  const TemplateURL* template_url = is_keyword ?
+      providers_.GetKeywordProviderURL() : providers_.GetDefaultProviderURL();
+  AutocompleteMatch match = CreateSearchSuggestion(this, relevance, type,
+      template_url, query_string, input_text, input_, is_keyword,
+      accepted_suggestion, omnibox_start_margin_,
+      !is_keyword || providers_.default_provider().empty());
   if (!match.destination_url.is_valid())
     return;
+  match.RecordAdditionalInfo(kRelevanceFromServerKey,
+                             relevance_from_server ? kTrue : kFalse);
 
   // Try to add |match| to |map|.  If a match for |query_string| is already in
   // |map|, replace it if |match| is more relevant.
   // NOTE: Keep this ToLower() call in sync with url_database.cc.
-  const std::pair<MatchMap::iterator, bool> i = map->insert(
-      std::pair<string16, AutocompleteMatch>(
-          base::i18n::ToLower(query_string), match));
+  const std::pair<MatchMap::iterator, bool> i(
+      map->insert(std::make_pair(base::i18n::ToLower(query_string), match)));
   // NOTE: We purposefully do a direct relevance comparison here instead of
   // using AutocompleteMatch::MoreRelevant(), so that we'll prefer "items added
   // first" rather than "items alphabetically first" when the scores are equal.
@@ -1570,17 +1458,28 @@
   match.description = navigation.description();
   AutocompleteMatch::ClassifyMatchInString(input, match.description,
       ACMatchClassification::NONE, &match.description_class);
+
+  match.RecordAdditionalInfo(
+      kRelevanceFromServerKey,
+      navigation.relevance_from_server() ? kTrue : kFalse);
+
   return match;
 }
 
 void SearchProvider::DemoteKeywordNavigationMatchesPastTopQuery() {
   // First, determine the maximum score of any keyword query match (verbatim or
   // query suggestion).
-  int max_query_relevance = GetKeywordVerbatimRelevance();
+  bool relevance_from_server;
+  int max_query_relevance = GetKeywordVerbatimRelevance(&relevance_from_server);
   if (!keyword_results_.suggest_results.empty()) {
-    max_query_relevance =
-        std::max(keyword_results_.suggest_results.front().relevance(),
-                 max_query_relevance);
+    const SuggestResult& top_keyword = keyword_results_.suggest_results.front();
+    const int suggest_relevance = top_keyword.relevance();
+    if (suggest_relevance > max_query_relevance) {
+      max_query_relevance = suggest_relevance;
+      relevance_from_server = top_keyword.relevance_from_server();
+    } else if (suggest_relevance == max_query_relevance) {
+      relevance_from_server |= top_keyword.relevance_from_server();
+    }
   }
   // If no query is supposed to appear, then navigational matches cannot
   // be demoted past it.  Get rid of suggested relevance scores for
@@ -1604,12 +1503,12 @@
       return;
     max_query_relevance = std::max(max_query_relevance - 1, 0);
     it->set_relevance(max_query_relevance);
+    it->set_relevance_from_server(relevance_from_server);
   }
 }
 
 void SearchProvider::UpdateDone() {
   // We're done when the timer isn't running, there are no suggest queries
   // pending, and we're not waiting on Instant.
-  done_ = IsNonInstantSearchDone() &&
-      (instant_finalized_ || !chrome::IsInstantEnabled(profile_));
+  done_ = !timer_.IsRunning() && (suggest_results_pending_ == 0);
 }
diff --git a/chrome/browser/autocomplete/search_provider.h b/chrome/browser/autocomplete/search_provider.h
index 1251402..531825d 100644
--- a/chrome/browser/autocomplete/search_provider.h
+++ b/chrome/browser/autocomplete/search_provider.h
@@ -18,14 +18,13 @@
 #include "base/basictypes.h"
 #include "base/compiler_specific.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/time.h"
-#include "base/timer.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
 #include "chrome/browser/autocomplete/autocomplete_input.h"
 #include "chrome/browser/autocomplete/autocomplete_match.h"
 #include "chrome/browser/autocomplete/autocomplete_provider.h"
 #include "chrome/browser/history/history_types.h"
 #include "chrome/browser/search_engines/template_url.h"
-#include "chrome/common/instant_types.h"
 #include "net/url_request/url_fetcher_delegate.h"
 
 class Profile;
@@ -59,69 +58,45 @@
   // ID used in creating URLFetcher for keyword provider's suggest results.
   static const int kKeywordProviderURLFetcherID;
 
-  // Returns an AutocompleteMatch representing a search for |query_string|
-  // using the provider identified by |keyword|. |is_keyword| should be true if
-  // |input| represents a keyword search (even if it's for the default search
-  // provider). |input_text| (the original input text) and |accepted_suggestion|
-  // are used to generate Assisted Query Stats.
-  // Returns a match with an invalid destination_url in case of any errors.
-  static AutocompleteMatch CreateSearchSuggestion(
-      Profile* profile,
-      AutocompleteProvider* autocomplete_provider,
-      const AutocompleteInput& input,
-      const string16& query_string,
-      const string16& input_text,
-      int relevance,
-      AutocompleteMatch::Type type,
-      int accepted_suggestion,
-      bool is_keyword,
-      const string16& keyword,
-      int omnibox_start_margin);
-
   SearchProvider(AutocompleteProviderListener* listener, Profile* profile);
 
-  // Marks the instant query as done. If |input_text| is non-empty this changes
-  // the 'search what you typed' results text to |input_text| +
-  // |suggestion.text|. |input_text| is the text the user input into the edit.
-  // |input_text| differs from |input_.text()| if the input contained
-  // whitespace.
+  // Returns an AutocompleteMatch with the given |autocomplete_provider|,
+  // |relevance|, and |type|, which represents a search via |template_url| for
+  // |query_string|.  If |template_url| is NULL, returns a match with an invalid
+  // destination URL.
   //
-  // This method also marks the search provider as no longer needing to wait for
-  // the instant result.
-  void FinalizeInstantQuery(const string16& input_text,
-                            const InstantSuggestion& suggestion);
-  void ClearInstantSuggestion();
+  // |input_text| is the original user input, which may differ from
+  // |query_string|; e.g. the user typed "foo" and got a search suggestion of
+  // "food", which we're now marking up.  This is used to highlight portions of
+  // the match contents to distinguish locally-typed text from suggested text.
+  //
+  // |input| and |is_keyword| are necessary for various other details, like
+  // whether we should allow inline autocompletion and what the transition type
+  // should be.  |accepted_suggestion| and |omnibox_start_margin| are used along
+  // with |input_text| to generate Assisted Query Stats.
+  // |append_extra_query_params| should be set if |template_url| is the default
+  // search engine, so the destination URL will contain any
+  // command-line-specified query params.
+  static AutocompleteMatch CreateSearchSuggestion(
+      AutocompleteProvider* autocomplete_provider,
+      int relevance,
+      AutocompleteMatch::Type type,
+      const TemplateURL* template_url,
+      const string16& query_string,
+      const string16& input_text,
+      const AutocompleteInput& input,
+      bool is_keyword,
+      int accepted_suggestion,
+      int omnibox_start_margin,
+      bool append_extra_query_params);
 
-  // If called, SearchProvider will not fetch any search suggestions for the
-  // next call to Start(). Used with InstantExtended where Instant fetches its
-  // own search suggestions.
-  //
-  // Note that this only applies to the next call to Start() and so this must be
-  // called repeatedly before Start() if you wish to continually suppress search
-  // suggestions.
-  void SuppressSearchSuggestions();
+  // AutocompleteProvider:
+  virtual void AddProviderInfo(ProvidersInfo* provider_info) const OVERRIDE;
+  virtual void ResetSession() OVERRIDE;
 
   // Update the omnibox start margin used to generate search suggestion URLs.
   void SetOmniboxStartMargin(int omnibox_start_margin);
 
-  // AutocompleteProvider:
-  virtual void Start(const AutocompleteInput& input,
-                     bool minimal_changes) OVERRIDE;
-  virtual void Stop(bool clear_cached_results) OVERRIDE;
-
-  // Adds search-provider-specific information to omnibox event logs.
-  virtual void AddProviderInfo(ProvidersInfo* provider_info) const OVERRIDE;
-
-  // Sets |field_trial_triggered_in_session_| to false.
-  virtual void ResetSession() OVERRIDE;
-
-  // net::URLFetcherDelegate
-  virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE;
-
-  // Returns whether the provider is done processing the query with the
-  // exception of waiting for Instant to finish.
-  bool IsNonInstantSearchDone() const;
-
   bool field_trial_triggered_in_session() const {
     return field_trial_triggered_in_session_;
   }
@@ -138,12 +113,6 @@
   FRIEND_TEST_ALL_PREFIXES(SearchProviderTest, SuggestRelevanceExperiment);
   FRIEND_TEST_ALL_PREFIXES(AutocompleteProviderTest, GetDestinationURL);
 
-  // The amount of time to wait before sending a new suggest request after
-  // the previous one.
-  static int kMinimumTimeBetweenSuggestQueriesMs;
-
-  virtual ~SearchProvider();
-
   // Manages the providers (TemplateURLs) used by SearchProvider. Two providers
   // may be used:
   // . The default provider. This corresponds to the user's default search
@@ -200,9 +169,9 @@
   //           highly fragmented SearchProvider logic for each Result type.
   class Result {
    public:
-    // Takes whether the result is from the keyword provider and its
-    // assigned relevance score.
-    explicit Result(bool from_keyword_provider, int relevance);
+    Result(bool from_keyword_provider,
+           int relevance,
+           bool relevance_from_server);
     virtual ~Result();
 
     bool from_keyword_provider() const { return from_keyword_provider_; }
@@ -210,6 +179,11 @@
     int relevance() const { return relevance_; }
     void set_relevance(int relevance) { relevance_ = relevance; }
 
+    bool relevance_from_server() const { return relevance_from_server_; }
+    void set_relevance_from_server(bool relevance_from_server) {
+      relevance_from_server_ = relevance_from_server;
+    }
+
     // Returns if this result is inlineable against the current input |input|.
     // Non-inlineable results are stale.
     virtual bool IsInlineable(const string16& input) const = 0;
@@ -227,13 +201,22 @@
 
     // The relevance score.
     int relevance_;
+
+   private:
+    // Whether this result's relevance score was fully or partly calculated
+    // based on server information, and thus is assumed to be more accurate.
+    // This is ultimately used in
+    // SearchProvider::ConvertResultsToAutocompleteMatches(), see comments
+    // there.
+    bool relevance_from_server_;
   };
 
   class SuggestResult : public Result {
    public:
     SuggestResult(const string16& suggestion,
                   bool from_keyword_provider,
-                  int relevance);
+                  int relevance,
+                  bool relevance_from_server);
     virtual ~SuggestResult();
 
     const string16& suggestion() const { return suggestion_; }
@@ -257,14 +240,13 @@
                      const GURL& url,
                      const string16& description,
                      bool from_keyword_provider,
-                     int relevance);
+                     int relevance,
+                     bool relevance_from_server);
     virtual ~NavigationResult();
 
     const GURL& url() const { return url_; }
     const string16& description() const { return description_; }
-    const string16& formatted_url() const {
-      return formatted_url_;
-    }
+    const string16& formatted_url() const { return formatted_url_; }
 
     // Result:
     virtual bool IsInlineable(const string16& input) const OVERRIDE;
@@ -284,30 +266,36 @@
     string16 description_;
   };
 
+  class CompareScoredResults;
+
   typedef std::vector<SuggestResult> SuggestResults;
   typedef std::vector<NavigationResult> NavigationResults;
+  typedef std::vector<history::KeywordSearchTermVisit> HistoryResults;
+  typedef std::map<string16, AutocompleteMatch> MatchMap;
 
   // A simple structure bundling most of the information (including
   // both SuggestResults and NavigationResults) returned by a call to
   // the suggest server.
+  //
+  // This has to be declared after the typedefs since it relies on some of them.
   struct Results {
     Results();
     ~Results();
 
     // Clears |suggest_results| and |navigation_results| and resets
-    // |has_suggested_relevance| and |verbatim_relevance| to default
-    // values (false and -1 (implies unset), respectively).
+    // |verbatim_relevance| to -1 (implies unset).
     void Clear();
 
+    // Returns whether any of the results (including verbatim) have
+    // server-provided scores.
+    bool HasServerProvidedScores() const;
+
     // Query suggestions sorted by relevance score.
     SuggestResults suggest_results;
 
     // Navigational suggestions sorted by relevance score.
     NavigationResults navigation_results;
 
-    // Flag indicating server supplied relevance score.
-    bool has_suggested_relevance;
-
     // The server supplied verbatim relevance scores. Negative values
     // indicate that there is no suggested score; a value of 0
     // suppresses the verbatim result.
@@ -317,10 +305,27 @@
     DISALLOW_COPY_AND_ASSIGN(Results);
   };
 
-  typedef std::vector<history::KeywordSearchTermVisit> HistoryResults;
-  typedef std::map<string16, AutocompleteMatch> MatchMap;
+  virtual ~SearchProvider();
 
-  class CompareScoredResults;
+  // Removes non-inlineable results until either the top result can inline
+  // autocomplete the current input or verbatim outscores the top result.
+  static void RemoveStaleResults(const string16& input,
+                                 int verbatim_relevance,
+                                 SuggestResults* suggest_results,
+                                 NavigationResults* navigation_results);
+
+  // Calculates the relevance score for the keyword verbatim result (if the
+  // input matches one of the profile's keyword).
+  static int CalculateRelevanceForKeywordVerbatim(AutocompleteInput::Type type,
+                                                  bool prefer_keyword);
+
+  // AutocompleteProvider:
+  virtual void Start(const AutocompleteInput& input,
+                     bool minimal_changes) OVERRIDE;
+  virtual void Stop(bool clear_cached_results) OVERRIDE;
+
+  // net::URLFetcherDelegate:
+  virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE;
 
   // Called when timer_ expires.
   void Run();
@@ -346,19 +351,9 @@
   // Clears the current results.
   void ClearAllResults();
 
-  // Removes non-inlineable results until either the top result can inline
-  // autocomplete the current input or verbatim outscores the top result.
+  // Removes stale results for both default and keyword providers.  See comments
+  // on RemoveStaleResults().
   void RemoveAllStaleResults();
-  static void RemoveStaleResults(const string16& input,
-                                 int verbatim_relevance,
-                                 SuggestResults* suggest_results,
-                                 NavigationResults* navigation_results);
-
-  // If |default_provider_suggestion_| (which was suggested for
-  // |previous_input|) is still applicable given the |current_input|, adjusts it
-  // so it can be reused. Otherwise, clears it.
-  void AdjustDefaultProviderSuggestion(const string16& previous_input,
-                                       const string16& current_input);
 
   // Apply calculated relevance scores to the current results.
   void ApplyCalculatedRelevance();
@@ -390,12 +385,11 @@
   // if suggested relevances cause undesriable behavior. Updates |done_|.
   void UpdateMatches();
 
-  // Converts the top navigation result in |navigation_results| to an
-  // AutocompleteMatch and adds it to |matches_|. |is_keyword| must be true if
-  // the results come from the keyword provider.
+  // Converts an appropriate number of navigation results in
+  // |navigation_results| to matches and adds them to |matches|.
   void AddNavigationResultsToMatches(
       const NavigationResults& navigation_results,
-      bool is_keyword);
+      ACMatches* matches);
 
   // Adds a match for each result in |results| to |map|. |is_keyword| indicates
   // whether the results correspond to the keyword provider or default provider.
@@ -414,30 +408,31 @@
   // Adds matches for |results| to |map|.
   void AddSuggestResultsToMap(const SuggestResults& results, MatchMap* map);
 
-  // Gets the relevance score for the verbatim result; this value may be
-  // provided by the suggest server; otherwise it is calculated locally.
-  int GetVerbatimRelevance() const;
+  // Gets the relevance score for the verbatim result.  This value may be
+  // provided by the suggest server or calculated locally; if
+  // |relevance_from_server| is non-NULL, it will be set to indicate which of
+  // those is true.
+  int GetVerbatimRelevance(bool* relevance_from_server) const;
+
   // Calculates the relevance score for the verbatim result from the
   // default search engine.  This version takes into account context:
   // i.e., whether the user has entered a keyword-based search or not.
   int CalculateRelevanceForVerbatim() const;
+
   // Calculates the relevance score for the verbatim result from the default
   // search engine *ignoring* whether the input is a keyword-based search
   // or not.  This function should only be used to determine the minimum
   // relevance score that the best result from this provider should have.
   // For normal use, prefer the above function.
   int CalculateRelevanceForVerbatimIgnoringKeywordModeState() const;
-  // Gets the relevance score for the keyword verbatim result; this
-  // value may be provided by the suggest server; otherwise it is
-  // calculated locally.
+
+  // Gets the relevance score for the keyword verbatim result.
+  // |relevance_from_server| is handled as in GetVerbatimRelevance().
   // TODO(mpearson): Refactor so this duplication isn't necesary or
   // restructure so one static function takes all the parameters it needs
   // (rather than looking at internal state).
-  int GetKeywordVerbatimRelevance() const;
-  // Calculates the relevance score for the keyword verbatim result (if the
-  // input matches one of the profile's keyword).
-  static int CalculateRelevanceForKeywordVerbatim(AutocompleteInput::Type type,
-                                                  bool prefer_keyword);
+  int GetKeywordVerbatimRelevance(bool* relevance_from_server) const;
+
   // |time| is the time at which this query was last seen.  |is_keyword|
   // indicates whether the results correspond to the keyword provider or default
   // provider. |prevent_inline_autocomplete| is true if we should not inline
@@ -452,6 +447,7 @@
   void AddMatchToMap(const string16& query_string,
                      const string16& input_text,
                      int relevance,
+                     bool relevance_from_server,
                      AutocompleteMatch::Type type,
                      int accepted_suggestion,
                      bool is_keyword,
@@ -473,6 +469,17 @@
   // Updates the value of |done_| from the internal state.
   void UpdateDone();
 
+  // The amount of time to wait before sending a new suggest request after the
+  // previous one.  Non-const because some unittests modify this value.
+  static int kMinimumTimeBetweenSuggestQueriesMs;
+
+  // We annotate our AutocompleteMatches with whether their relevance scores
+  // were server-provided using this key in the |additional_info| field.
+  static const char kRelevanceFromServerKey[];
+  // These are the values we record with the above key.
+  static const char kTrue[];
+  static const char kFalse[];
+
   // Maintains the TemplateURLs used.
   Providers providers_;
 
@@ -505,12 +512,6 @@
   Results default_results_;
   Results keyword_results_;
 
-  // Has FinalizeInstantQuery been invoked since the last |Start|?
-  bool instant_finalized_;
-
-  // The |suggestion| parameter passed to FinalizeInstantQuery.
-  InstantSuggestion default_provider_suggestion_;
-
   // Whether a field trial, if any, has triggered in the most recent
   // autocomplete query.  This field is set to false in Start() and may be set
   // to true if either the default provider or keyword provider has completed
@@ -523,10 +524,6 @@
   // session.
   bool field_trial_triggered_in_session_;
 
-  // If true, suppress search suggestions. Reset to false in Start().
-  // See comments for SuppressSearchSuggestions().
-  bool suppress_search_suggestions_;
-
   // Start margin of the omnibox. Used to construct search URLs.
   int omnibox_start_margin_;
 
diff --git a/chrome/browser/autocomplete/search_provider_unittest.cc b/chrome/browser/autocomplete/search_provider_unittest.cc
index 88edef6..2551ca2 100644
--- a/chrome/browser/autocomplete/search_provider_unittest.cc
+++ b/chrome/browser/autocomplete/search_provider_unittest.cc
@@ -4,12 +4,13 @@
 
 #include "chrome/browser/autocomplete/search_provider.h"
 
+#include "base/command_line.h"
 #include "base/metrics/field_trial.h"
 #include "base/prefs/pref_service.h"
 #include "base/run_loop.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "build/build_config.h"
 #include "chrome/browser/autocomplete/autocomplete_classifier_factory.h"
 #include "chrome/browser/autocomplete/autocomplete_controller.h"
@@ -25,7 +26,7 @@
 #include "chrome/browser/search_engines/template_url.h"
 #include "chrome/browser/search_engines/template_url_service.h"
 #include "chrome/browser/search_engines/template_url_service_factory.h"
-#include "chrome/common/instant_types.h"
+#include "chrome/common/chrome_switches.h"
 #include "chrome/common/metrics/entropy_provider.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/testing_browser_process.h"
@@ -35,7 +36,8 @@
 #include "net/url_request/url_request_status.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-using content::BrowserThread;
+
+// SearchProviderTest ---------------------------------------------------------
 
 // The following environment is configured for these tests:
 // . The TemplateURL default_t_url_ is set as the default provider.
@@ -49,26 +51,6 @@
 class SearchProviderTest : public testing::Test,
                            public AutocompleteProviderListener {
  public:
-  SearchProviderTest()
-      : default_t_url_(NULL),
-        term1_(UTF8ToUTF16("term1")),
-        keyword_t_url_(NULL),
-        keyword_term_(UTF8ToUTF16("keyword")),
-        ui_thread_(BrowserThread::UI, &message_loop_),
-        io_thread_(BrowserThread::IO),
-        quit_when_done_(false) {
-    io_thread_.Start();
-  }
-
-  static void SetUpTestCase();
-
-  static void TearDownTestCase();
-
-  // See description above class for what this registers.
-  virtual void SetUp();
-
-  virtual void TearDown();
-
   struct ResultInfo {
     ResultInfo() : result_type(AutocompleteMatchType::NUM_TYPES) {
     }
@@ -79,16 +61,36 @@
         result_type(result_type),
         fill_into_edit(fill_into_edit) {
     }
+
     const GURL gurl;
     const AutocompleteMatch::Type result_type;
     const string16 fill_into_edit;
   };
+
   struct TestData {
     const string16 input;
     const size_t num_results;
     const ResultInfo output[3];
   };
 
+  SearchProviderTest()
+      : default_t_url_(NULL),
+        term1_(ASCIIToUTF16("term1")),
+        keyword_t_url_(NULL),
+        keyword_term_(ASCIIToUTF16("keyword")),
+        ui_thread_(content::BrowserThread::UI, &message_loop_),
+        io_thread_(content::BrowserThread::IO),
+        quit_when_done_(false) {
+    io_thread_.Start();
+  }
+
+  static void SetUpTestCase();
+  static void TearDownTestCase();
+
+  // See description above class for what this registers.
+  virtual void SetUp() OVERRIDE;
+  virtual void TearDown() OVERRIDE;
+
   void RunTest(TestData* cases, int num_cases, bool prefer_keyword);
 
  protected:
@@ -166,8 +168,6 @@
 
 // static
 base::FieldTrialList* SearchProviderTest::field_trial_list_ = NULL;
-
-// static
 const std::string SearchProviderTest::kNotApplicable = "Not Applicable";
 
 // static
@@ -237,6 +237,41 @@
   provider_->kMinimumTimeBetweenSuggestQueriesMs = 0;
 }
 
+void SearchProviderTest::TearDown() {
+  message_loop_.RunUntilIdle();
+
+  // Shutdown the provider before the profile.
+  provider_ = NULL;
+}
+
+void SearchProviderTest::RunTest(TestData* cases,
+                                 int num_cases,
+                                 bool prefer_keyword) {
+  ACMatches matches;
+  for (int i = 0; i < num_cases; ++i) {
+    AutocompleteInput input(cases[i].input, string16::npos, string16(), GURL(),
+                            false, prefer_keyword, true,
+                            AutocompleteInput::ALL_MATCHES);
+    provider_->Start(input, false);
+    matches = provider_->matches();
+    string16 diagnostic_details = ASCIIToUTF16("Input was: ") + cases[i].input +
+        ASCIIToUTF16("; prefer_keyword was: ") +
+        (prefer_keyword ? ASCIIToUTF16("true") : ASCIIToUTF16("false"));
+    EXPECT_EQ(cases[i].num_results, matches.size()) << diagnostic_details;
+    if (matches.size() == cases[i].num_results) {
+      for (size_t j = 0; j < cases[i].num_results; ++j) {
+        EXPECT_EQ(cases[i].output[j].gurl, matches[j].destination_url) <<
+            diagnostic_details;
+        EXPECT_EQ(cases[i].output[j].result_type, matches[j].type) <<
+            diagnostic_details;
+        EXPECT_EQ(cases[i].output[j].fill_into_edit,
+                  matches[j].fill_into_edit) <<
+            diagnostic_details;
+      }
+    }
+  }
+}
+
 void SearchProviderTest::OnProviderUpdate(bool updated_matches) {
   if (quit_when_done_ && provider_->done()) {
     quit_when_done_ = false;
@@ -286,7 +321,6 @@
   QueryForInput(text, false, false);
   profile_.BlockUntilHistoryProcessesPendingRequests();
   ASSERT_NO_FATAL_FAILURE(FinishDefaultSuggestQuery());
-  EXPECT_NE(chrome::IsInstantExtendedAPIEnabled(), provider_->done());
   if (!wyt_match)
     return;
   ASSERT_GE(provider_->matches().size(), 1u);
@@ -296,41 +330,6 @@
       wyt_match));
 }
 
-void SearchProviderTest::TearDown() {
-  message_loop_.RunUntilIdle();
-
-  // Shutdown the provider before the profile.
-  provider_ = NULL;
-}
-
-void SearchProviderTest::RunTest(TestData* cases,
-                                 int num_cases,
-                                 bool prefer_keyword) {
-  ACMatches matches;
-  for (int i = 0; i < num_cases; ++i) {
-    AutocompleteInput input(cases[i].input, string16::npos, string16(), GURL(),
-                            false, prefer_keyword, true,
-                            AutocompleteInput::ALL_MATCHES);
-    provider_->Start(input, false);
-    matches = provider_->matches();
-    string16 diagnostic_details = ASCIIToUTF16("Input was: ") + cases[i].input +
-        ASCIIToUTF16("; prefer_keyword was: ") +
-        (prefer_keyword ? ASCIIToUTF16("true") : ASCIIToUTF16("false"));
-    EXPECT_EQ(cases[i].num_results, matches.size()) << diagnostic_details;
-    if (matches.size() == cases[i].num_results) {
-      for (size_t j = 0; j < cases[i].num_results; ++j) {
-        EXPECT_EQ(cases[i].output[j].gurl, matches[j].destination_url) <<
-            diagnostic_details;
-        EXPECT_EQ(cases[i].output[j].result_type, matches[j].type) <<
-            diagnostic_details;
-        EXPECT_EQ(cases[i].output[j].fill_into_edit,
-                  matches[j].fill_into_edit) <<
-            diagnostic_details;
-      }
-    }
-  }
-}
-
 GURL SearchProviderTest::AddSearchToHistory(TemplateURL* t_url,
                                             string16 term,
                                             int visit_count) {
@@ -382,7 +381,8 @@
   default_fetcher->delegate()->OnURLFetchComplete(default_fetcher);
 }
 
-// Tests -----------------------------------------------------------------------
+
+// Actual Tests ---------------------------------------------------------------
 
 // Make sure we query history for the default provider and a URLFetcher is
 // created for the default provider suggest results.
@@ -438,7 +438,7 @@
 // is queried as well as URLFetchers getting created.
 TEST_F(SearchProviderTest, QueryKeywordProvider) {
   string16 term = keyword_term_.substr(0, keyword_term_.length() - 1);
-  QueryForInput(keyword_t_url_->keyword() + UTF8ToUTF16(" ") + term,
+  QueryForInput(keyword_t_url_->keyword() + ASCIIToUTF16(" ") + term,
                 false,
                 false);
 
@@ -510,191 +510,6 @@
   }
 }
 
-// Make sure FinalizeInstantQuery works.
-TEST_F(SearchProviderTest, FinalizeInstantQuery) {
-  chrome::EnableInstantExtendedAPIForTesting();
-
-  ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("foo"),
-                                                      NULL));
-
-  // Tell the provider Instant is done.
-  provider_->FinalizeInstantQuery(ASCIIToUTF16("foo"),
-                                  InstantSuggestion(ASCIIToUTF16("bar"),
-                                                    INSTANT_COMPLETE_NOW,
-                                                    INSTANT_SUGGESTION_SEARCH,
-                                                    string16(),
-                                                    kNoMatchIndex));
-
-  // The provider should now be done.
-  EXPECT_TRUE(provider_->done());
-
-  // There should be two matches, one for what you typed, the other for
-  // 'foobar'.
-  EXPECT_EQ(2u, provider_->matches().size());
-  GURL instant_url(default_t_url_->url_ref().ReplaceSearchTerms(
-      TemplateURLRef::SearchTermsArgs(ASCIIToUTF16("foobar"))));
-  AutocompleteMatch instant_match;
-  EXPECT_TRUE(FindMatchWithDestination(instant_url, &instant_match));
-
-  // And the 'foobar' match should not have a description, it'll be set later.
-  EXPECT_TRUE(instant_match.description.empty());
-
-  // Make sure the what you typed match has no description.
-  AutocompleteMatch wyt_match;
-  EXPECT_TRUE(FindMatchWithDestination(
-      GURL(default_t_url_->url_ref().ReplaceSearchTerms(
-          TemplateURLRef::SearchTermsArgs(ASCIIToUTF16("foo")))),
-          &wyt_match));
-  EXPECT_TRUE(wyt_match.description.empty());
-
-  // Instant search suggestions are never inline autocompleted, so they should
-  // score less than the WYT match.
-  EXPECT_LT(instant_match.relevance, wyt_match.relevance);
-}
-
-// Make sure FinalizeInstantQuery works with URL suggestions.
-TEST_F(SearchProviderTest, FinalizeInstantURL) {
-  chrome::EnableInstantExtendedAPIForTesting();
-
-  ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("ex"),
-                                                      NULL));
-
-  // Tell the provider Instant is done.
-  provider_->FinalizeInstantQuery(ASCIIToUTF16("ex"),
-                                  InstantSuggestion(
-                                      ASCIIToUTF16("http://example.com/"),
-                                      INSTANT_COMPLETE_NOW,
-                                      INSTANT_SUGGESTION_URL,
-                                      string16(),
-                                      kNoMatchIndex));
-
-  // The provider should now be done.
-  EXPECT_TRUE(provider_->done());
-
-  // There should be two matches, one for what you typed, the other for
-  // "http://example.com/".
-  EXPECT_EQ(2u, provider_->matches().size());
-  GURL instant_url("http://example.com");
-  AutocompleteMatch instant_match;
-  EXPECT_TRUE(FindMatchWithDestination(instant_url, &instant_match));
-
-  // The Instant match should not have a description, it'll be set later.
-  EXPECT_TRUE(instant_match.description.empty());
-
-  // Make sure the what you typed match has no description.
-  AutocompleteMatch wyt_match;
-  EXPECT_TRUE(FindMatchWithDestination(
-      GURL(default_t_url_->url_ref().ReplaceSearchTerms(
-          TemplateURLRef::SearchTermsArgs(ASCIIToUTF16("ex")))),
-          &wyt_match));
-  EXPECT_TRUE(wyt_match.description.empty());
-
-  // The Instant URL should be more relevant.
-  EXPECT_GT(instant_match.relevance, wyt_match.relevance);
-}
-
-// An Instant URL suggestion should behave the same way whether the input text
-// is classified as UNKNOWN or as an URL. Otherwise if the user types
-// "example.co" url-what-you-typed will displace the Instant suggestion for
-// "example.com".
-TEST_F(SearchProviderTest, FinalizeInstantURLWithURLText) {
-  chrome::EnableInstantExtendedAPIForTesting();
-
-  ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(
-      ASCIIToUTF16("example.co"), NULL));
-
-  // Tell the provider Instant is done.
-  provider_->FinalizeInstantQuery(ASCIIToUTF16("example.co"),
-                                  InstantSuggestion(
-                                      ASCIIToUTF16("http://example.com/"),
-                                      INSTANT_COMPLETE_NOW,
-                                      INSTANT_SUGGESTION_URL,
-                                      string16(),
-                                      kNoMatchIndex));
-
-  // The provider should now be done.
-  EXPECT_TRUE(provider_->done());
-
-  // There should be two matches, one for what you typed, the other for
-  // "http://example.com/".
-  EXPECT_EQ(2u, provider_->matches().size());
-  GURL instant_url("http://example.com");
-  AutocompleteMatch instant_match;
-  EXPECT_TRUE(FindMatchWithDestination(instant_url, &instant_match));
-
-  // The Instant match should not have a description, it'll be set later.
-  EXPECT_TRUE(instant_match.description.empty());
-
-  // The Instant URL should be more relevant than a URL_WHAT_YOU_TYPED match.
-  EXPECT_GT(instant_match.relevance,
-            HistoryURLProvider::kScoreForWhatYouTypedResult);
-}
-
-// Make sure that if FinalizeInstantQuery is invoked before suggest results
-// return, the suggest text from FinalizeInstantQuery is remembered.
-TEST_F(SearchProviderTest, RememberInstantQuery) {
-  chrome::EnableInstantExtendedAPIForTesting();
-
-  QueryForInput(ASCIIToUTF16("foo"), false, false);
-
-  // Finalize the Instant query immediately.
-  provider_->FinalizeInstantQuery(ASCIIToUTF16("foo"),
-                                  InstantSuggestion(ASCIIToUTF16("bar"),
-                                                    INSTANT_COMPLETE_NOW,
-                                                    INSTANT_SUGGESTION_SEARCH,
-                                                    string16(),
-                                                    kNoMatchIndex));
-
-  // There should be two matches, one for what you typed, the other for
-  // 'foobar'.
-  EXPECT_EQ(2u, provider_->matches().size());
-  GURL instant_url(default_t_url_->url_ref().ReplaceSearchTerms(
-      TemplateURLRef::SearchTermsArgs(ASCIIToUTF16("foobar"))));
-  AutocompleteMatch instant_match;
-  EXPECT_TRUE(FindMatchWithDestination(instant_url, &instant_match));
-
-  // Wait until history and the suggest query complete.
-  profile_.BlockUntilHistoryProcessesPendingRequests();
-  ASSERT_NO_FATAL_FAILURE(FinishDefaultSuggestQuery());
-
-  // Provider should be done.
-  EXPECT_TRUE(provider_->done());
-
-  // There should be two matches, one for what you typed, the other for
-  // 'foobar'.
-  EXPECT_EQ(2u, provider_->matches().size());
-  EXPECT_TRUE(FindMatchWithDestination(instant_url, &instant_match));
-
-  // And the 'foobar' match should not have a description, it'll be set later.
-  EXPECT_TRUE(instant_match.description.empty());
-}
-
-// Make sure that if trailing whitespace is added to the text supplied to
-// AutocompleteInput the default suggest text is cleared.
-TEST_F(SearchProviderTest, DifferingText) {
-  chrome::EnableInstantExtendedAPIForTesting();
-
-  ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("foo"),
-                                                      NULL));
-
-  // Finalize the Instant query immediately.
-  provider_->FinalizeInstantQuery(ASCIIToUTF16("foo"),
-                                  InstantSuggestion(ASCIIToUTF16("bar"),
-                                                    INSTANT_COMPLETE_NOW,
-                                                    INSTANT_SUGGESTION_SEARCH,
-                                                    string16(),
-                                                    kNoMatchIndex));
-
-  // Query with the same input text, but trailing whitespace.
-  AutocompleteMatch instant_match;
-  ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("foo "),
-                                                      &instant_match));
-
-  // There should only one match, for what you typed.
-  EXPECT_EQ(1u, provider_->matches().size());
-  EXPECT_FALSE(instant_match.destination_url.is_empty());
-}
-
 TEST_F(SearchProviderTest, DontAutocompleteURLLikeTerms) {
   AutocompleteClassifierFactory::GetInstance()->SetTestingFactoryAndUse(
       &profile_, &AutocompleteClassifierFactory::BuildInstanceFor);
@@ -981,6 +796,38 @@
   RunTest(cases, arraysize(cases), true);
 }
 
+// Ensures command-line flags are reflected in the URLs the search provider
+// generates.
+TEST_F(SearchProviderTest, CommandLineOverrides) {
+  TemplateURLService* turl_model =
+      TemplateURLServiceFactory::GetForProfile(&profile_);
+
+  TemplateURLData data;
+  data.short_name = ASCIIToUTF16("default");
+  data.SetKeyword(data.short_name);
+  data.SetURL("{google:baseURL}{searchTerms}");
+  default_t_url_ = new TemplateURL(&profile_, data);
+  turl_model->Add(default_t_url_);
+  turl_model->SetDefaultSearchProvider(default_t_url_);
+
+  CommandLine::ForCurrentProcess()->AppendSwitchASCII(switches::kGoogleBaseURL,
+                                                      "http://www.bar.com/");
+  CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+      switches::kExtraSearchQueryParams, "a=b");
+
+  TestData cases[] = {
+    { ASCIIToUTF16("k a"), 2,
+      { ResultInfo(GURL("http://keyword/a"),
+                   AutocompleteMatchType::SEARCH_OTHER_ENGINE,
+                   ASCIIToUTF16("k a")),
+        ResultInfo(GURL("http://www.bar.com/k%20a?a=b"),
+                   AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
+                   ASCIIToUTF16("k a")) } },
+  };
+
+  RunTest(cases, arraysize(cases), false);
+}
+
 // Verifies Navsuggest results don't set a TemplateURL, which Instant relies on.
 // Also verifies that just the *first* navigational result is listed as a match
 // if suggested relevance scores were not sent.
@@ -1201,9 +1048,10 @@
     fetcher->delegate()->OnURLFetchComplete(fetcher);
     RunTillProviderDone();
 
-   const std::string description = "for input with json=" + cases[i].json;
+    const std::string description = "for input with json=" + cases[i].json;
     const ACMatches& matches = provider_->matches();
     // The top match must inline and score as highly as calculated verbatim.
+    ASSERT_FALSE(matches.empty());
     EXPECT_NE(string16::npos, matches[0].inline_autocomplete_offset) <<
         description;
     EXPECT_GE(matches[0].relevance, 1300) << description;
@@ -1567,21 +1415,20 @@
         { "k a", false },
         { kNotApplicable, false } } },
     // Check when there is neither verbatim nor a query suggestion that,
-    // because we can demote navsuggestions below a query suggestion,
+    // because we can't demote navsuggestions below a query suggestion,
     // we abandon suggested relevance scores entirely.  One consequence is
     // that this means we restore the keyword verbatim match.  Note
     // that in this case of abandoning suggested relevance scores, we still
-    // keep the navsuggestions in order by their original scores (just
-    // not at their original scores), and continue to allow multiple
-    // navsuggestions to appear.
+    // keep the navsuggestions in the same order, but we revert to only allowing
+    // one navigation to appear because the scores are completely local.
     { "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
        "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
         "\"google:verbatimrelevance\":0,"
         "\"google:suggestrelevance\":[9998, 9999]}]",
       { { "a", true },
         { "a2.com", false },
-        { "a1.com", false },
         { "k a", false },
+        { kNotApplicable, false },
         { kNotApplicable, false } } },
     { "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
        "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
@@ -1589,8 +1436,8 @@
         "\"google:suggestrelevance\":[9999, 9998]}]",
       { { "a", true },
         { "a1.com", false },
-        { "a2.com", false },
         { "k a", false },
+        { kNotApplicable, false },
         { kNotApplicable, false } } },
     // More checks that everything works when it's not necessary to demote.
     { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
@@ -1637,6 +1484,7 @@
     const std::string description = "for input with json=" + cases[i].json;
     const ACMatches& matches = provider_->matches();
     // The top match must inline and score as highly as calculated verbatim.
+    ASSERT_FALSE(matches.empty());
     EXPECT_NE(string16::npos, matches[0].inline_autocomplete_offset) <<
         description;
     EXPECT_GE(matches[0].relevance, 1300) << description;
@@ -1656,6 +1504,112 @@
   }
 }
 
+TEST_F(SearchProviderTest, LocalAndRemoteRelevances) {
+  // Enable Instant Extended in order to allow an increased number of
+  // suggestions.
+  chrome::EnableInstantExtendedAPIForTesting();
+
+  // We hardcode the string "term1" below, so ensure that the search term that
+  // got added to history already is that string.
+  ASSERT_EQ(ASCIIToUTF16("term1"), term1_);
+  string16 term = term1_.substr(0, term1_.length() - 1);
+
+  AddSearchToHistory(default_t_url_, term + ASCIIToUTF16("2"), 2);
+  profile_.BlockUntilHistoryProcessesPendingRequests();
+
+  struct {
+    const string16 input;
+    const std::string json;
+    const std::string matches[6];
+  } cases[] = {
+    // The history results outscore the default verbatim score.  term2 has more
+    // visits so it outscores term1.  The suggestions are still returned since
+    // they're server-scored.
+    { term,
+      "[\"term\",[\"a1\", \"a2\", \"a3\"],[],[],"
+       "{\"google:suggesttype\":[\"QUERY\", \"QUERY\", \"QUERY\"],"
+        "\"google:suggestrelevance\":[1, 2, 3]}]",
+      { "term2", "term1", "term", "a3", "a2", "a1" } },
+    // Because we already have three suggestions by the time we see the history
+    // results, they don't get returned.
+    { term,
+      "[\"term\",[\"a1\", \"a2\", \"a3\"],[],[],"
+       "{\"google:suggesttype\":[\"QUERY\", \"QUERY\", \"QUERY\"],"
+        "\"google:verbatimrelevance\":1450,"
+        "\"google:suggestrelevance\":[1440, 1430, 1420]}]",
+      { "term", "a1", "a2", "a3", kNotApplicable, kNotApplicable } },
+    // If we only have two suggestions, we have room for a history result.
+    { term,
+      "[\"term\",[\"a1\", \"a2\"],[],[],"
+       "{\"google:suggesttype\":[\"QUERY\", \"QUERY\"],"
+        "\"google:verbatimrelevance\":1450,"
+        "\"google:suggestrelevance\":[1430, 1410]}]",
+      { "term", "a1", "a2", "term2", kNotApplicable, kNotApplicable } },
+    // If we have more than three suggestions, they should all be returned as
+    // long as we have enough total space for them.
+    { term,
+      "[\"term\",[\"a1\", \"a2\", \"a3\", \"a4\"],[],[],"
+       "{\"google:suggesttype\":[\"QUERY\", \"QUERY\", \"QUERY\", \"QUERY\"],"
+        "\"google:verbatimrelevance\":1450,"
+        "\"google:suggestrelevance\":[1440, 1430, 1420, 1410]}]",
+      { "term", "a1", "a2", "a3", "a4", kNotApplicable } },
+    { term,
+      "[\"term\",[\"a1\", \"a2\", \"a3\", \"a4\", \"a5\", \"a6\"],[],[],"
+       "{\"google:suggesttype\":[\"QUERY\", \"QUERY\", \"QUERY\", \"QUERY\","
+                                "\"QUERY\", \"QUERY\"],"
+        "\"google:verbatimrelevance\":1450,"
+        "\"google:suggestrelevance\":[1440, 1430, 1420, 1410, 1400, 1390]}]",
+      { "term", "a1", "a2", "a3", "a4", "a5" } },
+    { term,
+      "[\"term\",[\"a1\", \"a2\", \"a3\", \"a4\"],[],[],"
+       "{\"google:suggesttype\":[\"QUERY\", \"QUERY\", \"QUERY\", \"QUERY\"],"
+        "\"google:verbatimrelevance\":1450,"
+        "\"google:suggestrelevance\":[1430, 1410, 1390, 1370]}]",
+      { "term", "a1", "a2", "term2", "a3", "a4" } },
+    // When the input looks like a URL, we disallow having a query as the
+    // highest-ranking result.  If the query was provided by a suggestion, we
+    // reset the suggest scores to enforce this (see
+    // SearchProvider::UpdateMatches()).  Even if we reset the suggest scores,
+    // however, we should still allow navsuggestions to be treated as
+    // server-provided.
+    { ASCIIToUTF16("a.com"),
+      "[\"a.com\",[\"a1\", \"a2\", \"a.com/1\", \"a.com/2\"],[],[],"
+       "{\"google:suggesttype\":[\"QUERY\", \"QUERY\", \"NAVIGATION\","
+                                "\"NAVIGATION\"],"
+        // A verbatim query for URL-like input scores 850, so the navigation
+        // scores here should bracket it.
+        "\"google:suggestrelevance\":[9999, 9998, 900, 800]}]",
+      { "a.com/1", "a.com", "a.com/2", "a1", kNotApplicable, kNotApplicable } },
+  };
+
+  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); i++) {
+    QueryForInput(cases[i].input, false, false);
+    net::TestURLFetcher* fetcher = WaitUntilURLFetcherIsReady(
+        SearchProvider::kDefaultProviderURLFetcherID);
+    ASSERT_TRUE(fetcher);
+    fetcher->set_response_code(200);
+    fetcher->SetResponseString(cases[i].json);
+    fetcher->delegate()->OnURLFetchComplete(fetcher);
+    RunTillProviderDone();
+
+    const std::string description = "for input with json=" + cases[i].json;
+    const ACMatches& matches = provider_->matches();
+
+    // Ensure no extra matches are present.
+    ASSERT_LE(matches.size(), 6U);
+
+    size_t j = 0;
+    // Ensure that the returned matches equal the expectations.
+    for (; j < matches.size(); ++j)
+      EXPECT_EQ(ASCIIToUTF16(cases[i].matches[j]),
+                matches[j].contents) << description;
+    // Ensure that no expected matches are missing.
+    for (; j < ARRAYSIZE_UNSAFE(cases[i].matches); ++j)
+      EXPECT_EQ(kNotApplicable, cases[i].matches[j]) <<
+          "Case # " << i << " " << description;
+  }
+}
+
 // Verifies suggest relevance behavior for URL input.
 TEST_F(SearchProviderTest, DefaultProviderSuggestRelevanceScoringUrlInput) {
   struct {
@@ -1928,9 +1882,10 @@
 
   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); i++) {
     QueryForInput(ASCIIToUTF16(cases[i].input), false, false);
-    SearchProvider::NavigationResult result(
-        *provider_.get(), GURL(cases[i].url), string16(), false, 0);
-    AutocompleteMatch match(provider_->NavigationToMatch(result));
+    AutocompleteMatch match(
+        provider_->NavigationToMatch(SearchProvider::NavigationResult(
+            *provider_.get(), GURL(cases[i].url), string16(), false, 0,
+            false)));
     EXPECT_EQ(cases[i].inline_offset, match.inline_autocomplete_offset);
     EXPECT_EQ(ASCIIToUTF16(cases[i].fill_into_edit), match.fill_into_edit);
   }
@@ -1941,7 +1896,7 @@
   const string16 input(ASCIIToUTF16("ht"));
   const string16 url(ASCIIToUTF16("http://a.com"));
   const SearchProvider::NavigationResult result(
-      *provider_.get(), GURL(url), string16(), false, 0);
+      *provider_.get(), GURL(url), string16(), false, 0, false);
 
   // Check the offset and strings when inline autocompletion is allowed.
   QueryForInput(input, false, false);
@@ -1961,10 +1916,10 @@
 // Verifies that input "w" marks a more significant domain label than "www.".
 TEST_F(SearchProviderTest, NavigationInlineDomainClassify) {
   QueryForInput(ASCIIToUTF16("w"), false, false);
-  const GURL url("http://www.wow.com");
-  const SearchProvider::NavigationResult result(
-      *provider_.get(), url, string16(), false, 0);
-  AutocompleteMatch match(provider_->NavigationToMatch(result));
+  AutocompleteMatch match(
+      provider_->NavigationToMatch(SearchProvider::NavigationResult(
+          *provider_.get(), GURL("http://www.wow.com"), string16(), false, 0,
+          false)));
   EXPECT_EQ(5U, match.inline_autocomplete_offset);
   EXPECT_EQ(ASCIIToUTF16("www.wow.com"), match.fill_into_edit);
   EXPECT_EQ(ASCIIToUTF16("www.wow.com"), match.contents);
@@ -2124,15 +2079,14 @@
         break;
       if (cases[i].results[j].is_navigation_result) {
         provider_->default_results_.navigation_results.push_back(
-            SearchProvider::NavigationResult(*provider_.get(),
-                                             GURL(suggestion),
-                                             string16(),
-                                             false,
-                                             cases[i].results[j].relevance));
+            SearchProvider::NavigationResult(
+                *provider_.get(), GURL(suggestion), string16(), false,
+                cases[i].results[j].relevance, false));
       } else {
         provider_->default_results_.suggest_results.push_back(
             SearchProvider::SuggestResult(ASCIIToUTF16(suggestion), false,
-                                          cases[i].results[j].relevance));
+                                          cases[i].results[j].relevance,
+                                          false));
       }
     }
 
diff --git a/chrome/browser/autocomplete/shortcuts_provider.cc b/chrome/browser/autocomplete/shortcuts_provider.cc
index ae59d8e..cf121be 100644
--- a/chrome/browser/autocomplete/shortcuts_provider.cc
+++ b/chrome/browser/autocomplete/shortcuts_provider.cc
@@ -17,7 +17,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/autocomplete/autocomplete_input.h"
 #include "chrome/browser/autocomplete/autocomplete_provider_listener.h"
 #include "chrome/browser/autocomplete/autocomplete_result.h"
@@ -25,10 +25,11 @@
 #include "chrome/browser/history/history_service.h"
 #include "chrome/browser/history/history_service_factory.h"
 #include "chrome/browser/history/shortcuts_backend_factory.h"
+#include "chrome/browser/omnibox/omnibox_field_trial.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/url_constants.h"
-#include "googleurl/src/url_parse.h"
+#include "url/url_parse.h"
 
 namespace {
 
@@ -53,7 +54,8 @@
     : AutocompleteProvider(listener, profile,
           AutocompleteProvider::TYPE_SHORTCUTS),
       languages_(profile_->GetPrefs()->GetString(prefs::kAcceptLanguages)),
-      initialized_(false) {
+      initialized_(false),
+      max_relevance_(AutocompleteResult::kLowestDefaultScore - 1) {
   scoped_refptr<history::ShortcutsBackend> backend =
       ShortcutsBackendFactory::GetForProfile(profile_);
   if (backend.get()) {
@@ -61,6 +63,9 @@
     if (backend->initialized())
       initialized_ = true;
   }
+  int max_relevance;
+  if (OmniboxFieldTrial::ShortcutsScoringMaxRelevance(&max_relevance))
+    max_relevance_ = max_relevance;
 }
 
 void ShortcutsProvider::Start(const AutocompleteInput& input,
@@ -169,6 +174,16 @@
     matches_.erase(matches_.begin() + AutocompleteProvider::kMaxMatches,
                    matches_.end());
   }
+  // Reset relevance scores to guarantee no results are given an
+  // inlineable score and all scores are decreasing (but not do assign
+  // any scores below 1).
+  int max_relevance = AutocompleteResult::kLowestDefaultScore - 1;
+  for (ACMatches::iterator it = matches_.begin(); it != matches_.end(); ++it) {
+    max_relevance = std::min(max_relevance, it->relevance);
+    it->relevance = max_relevance;
+    if (max_relevance > 1)
+      --max_relevance;
+  }
 }
 
 AutocompleteMatch ShortcutsProvider::ShortcutToACMatch(
@@ -185,6 +200,9 @@
   match.contents_class = shortcut.contents_class;
   match.description = shortcut.description;
   match.description_class = shortcut.description_class;
+  match.RecordAdditionalInfo("number of hits", shortcut.number_of_hits);
+  match.RecordAdditionalInfo("last access time", shortcut.last_access_time);
+  match.RecordAdditionalInfo("original input text", UTF16ToUTF8(shortcut.text));
 
   // Try to mark pieces of the contents and description as matches if they
   // appear in |term_string|.
@@ -318,7 +336,6 @@
     backend->shortcuts_map().end();
 }
 
-// static
 int ShortcutsProvider::CalculateScore(
     const string16& terms,
     const history::ShortcutsBackend::Shortcut& shortcut) {
@@ -331,7 +348,7 @@
   // directly. This makes sense since the first characters typed are much more
   // important for determining how likely it is a user wants a particular
   // shortcut than are the remaining continued characters.
-  double base_score = (AutocompleteResult::kLowestDefaultScore - 1) *
+  double base_score = max_relevance_ *
       sqrt(static_cast<double>(terms.length()) / shortcut.text.length());
 
   // Then we decay this by half each week.
diff --git a/chrome/browser/autocomplete/shortcuts_provider.h b/chrome/browser/autocomplete/shortcuts_provider.h
index b4b0fc9..11f0b0a 100644
--- a/chrome/browser/autocomplete/shortcuts_provider.h
+++ b/chrome/browser/autocomplete/shortcuts_provider.h
@@ -94,12 +94,19 @@
       const string16& keyword,
       history::ShortcutsBackend* backend);
 
-  static int CalculateScore(
+  int CalculateScore(
       const string16& terms,
       const history::ShortcutsBackend::Shortcut& shortcut);
 
   std::string languages_;
   bool initialized_;
+
+  // The maximum relevance that can be assigned in CalculateScore().
+  // Note that if the final assigned relevance is at least
+  // AutocompleteResult::kLowestDefaultScore, the relevance will be
+  // demoted to less than that number because ShortcutsProvider isn't
+  // allowed to inline.
+  int max_relevance_;
 };
 
 #endif  // CHROME_BROWSER_AUTOCOMPLETE_SHORTCUTS_PROVIDER_H_
diff --git a/chrome/browser/autocomplete/shortcuts_provider_unittest.cc b/chrome/browser/autocomplete/shortcuts_provider_unittest.cc
index bc1034c..9b2b4e4 100644
--- a/chrome/browser/autocomplete/shortcuts_provider_unittest.cc
+++ b/chrome/browser/autocomplete/shortcuts_provider_unittest.cc
@@ -573,37 +573,37 @@
       spans_description, base::Time::Now(), 1);
 
   // Maximal score.
-  const int kMaxScore = ShortcutsProvider::CalculateScore(
+  const int kMaxScore = provider_->CalculateScore(
       ASCIIToUTF16("test"), shortcut);
 
   // Score decreases as percent of the match is decreased.
   int score_three_quarters =
-      ShortcutsProvider::CalculateScore(ASCIIToUTF16("tes"), shortcut);
+      provider_->CalculateScore(ASCIIToUTF16("tes"), shortcut);
   EXPECT_LT(score_three_quarters, kMaxScore);
   int score_one_half =
-      ShortcutsProvider::CalculateScore(ASCIIToUTF16("te"), shortcut);
+      provider_->CalculateScore(ASCIIToUTF16("te"), shortcut);
   EXPECT_LT(score_one_half, score_three_quarters);
   int score_one_quarter =
-      ShortcutsProvider::CalculateScore(ASCIIToUTF16("t"), shortcut);
+      provider_->CalculateScore(ASCIIToUTF16("t"), shortcut);
   EXPECT_LT(score_one_quarter, score_one_half);
 
   // Should decay with time - one week.
   shortcut.last_access_time = base::Time::Now() - base::TimeDelta::FromDays(7);
   int score_week_old =
-      ShortcutsProvider::CalculateScore(ASCIIToUTF16("test"), shortcut);
+      provider_->CalculateScore(ASCIIToUTF16("test"), shortcut);
   EXPECT_LT(score_week_old, kMaxScore);
 
   // Should decay more in two weeks.
   shortcut.last_access_time = base::Time::Now() - base::TimeDelta::FromDays(14);
   int score_two_weeks_old =
-      ShortcutsProvider::CalculateScore(ASCIIToUTF16("test"), shortcut);
+      provider_->CalculateScore(ASCIIToUTF16("test"), shortcut);
   EXPECT_LT(score_two_weeks_old, score_week_old);
 
   // But not if it was activly clicked on. 2 hits slow decaying power.
   shortcut.number_of_hits = 2;
   shortcut.last_access_time = base::Time::Now() - base::TimeDelta::FromDays(14);
   int score_popular_two_weeks_old =
-      ShortcutsProvider::CalculateScore(ASCIIToUTF16("test"), shortcut);
+      provider_->CalculateScore(ASCIIToUTF16("test"), shortcut);
   EXPECT_LT(score_two_weeks_old, score_popular_two_weeks_old);
   // But still decayed.
   EXPECT_LT(score_popular_two_weeks_old, kMaxScore);
@@ -612,7 +612,7 @@
   shortcut.number_of_hits = 3;
   shortcut.last_access_time = base::Time::Now() - base::TimeDelta::FromDays(14);
   int score_more_popular_two_weeks_old =
-      ShortcutsProvider::CalculateScore(ASCIIToUTF16("test"), shortcut);
+      provider_->CalculateScore(ASCIIToUTF16("test"), shortcut);
   EXPECT_LT(score_two_weeks_old, score_more_popular_two_weeks_old);
   EXPECT_LT(score_popular_two_weeks_old, score_more_popular_two_weeks_old);
   // But still decayed.
diff --git a/chrome/browser/autocomplete/zero_suggest_provider.cc b/chrome/browser/autocomplete/zero_suggest_provider.cc
index b210f5a..77c0e1f 100644
--- a/chrome/browser/autocomplete/zero_suggest_provider.cc
+++ b/chrome/browser/autocomplete/zero_suggest_provider.cc
@@ -12,7 +12,7 @@
 #include "base/strings/string16.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/autocomplete/autocomplete_input.h"
 #include "chrome/browser/autocomplete/autocomplete_match.h"
 #include "chrome/browser/autocomplete/autocomplete_provider_listener.h"
@@ -30,7 +30,6 @@
 #include "chrome/browser/sync/profile_sync_service_factory.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/url_constants.h"
-#include "googleurl/src/gurl.h"
 #include "net/base/escape.h"
 #include "net/base/load_flags.h"
 #include "net/base/net_util.h"
@@ -38,6 +37,7 @@
 #include "net/http/http_response_headers.h"
 #include "net/url_request/url_fetcher.h"
 #include "net/url_request/url_request_status.h"
+#include "url/gurl.h"
 
 namespace {
 
@@ -80,13 +80,6 @@
 
 void ZeroSuggestProvider::Start(const AutocompleteInput& input,
                                 bool /*minimal_changes*/) {
-  CheckIfTextModfied(input.text());
-  // Clear results only if the user text was modified.
-  Stop(user_text_modified_);
-  ConvertResultsToAutocompleteMatches(input.text(), false);
-  // listener_->OnProviderUpdate() does not need to be called because this
-  // function is only called in the synchronous pass when a user has performed
-  // an action (such as typing a character in the omnobox).
 }
 
 void ZeroSuggestProvider::Stop(bool clear_cached_results) {
@@ -125,6 +118,7 @@
   // |field_trial_triggered_in_session_| unchanged and set
   // |field_trial_triggered_| to false since zero suggest is inactive now.
   field_trial_triggered_ = false;
+  Stop(true);
 }
 
 void ZeroSuggestProvider::OnURLFetchComplete(const net::URLFetcher* source) {
@@ -150,13 +144,12 @@
   done_ = true;
 
   if (have_results) {
-    ConvertResultsToAutocompleteMatches(original_user_text_, true);
+    ConvertResultsToAutocompleteMatches();
     listener_->OnProviderUpdate(true);
   }
 }
 
 void ZeroSuggestProvider::StartZeroSuggest(const GURL& url,
-                                           const string16& user_text,
                                            const string16& permanent_text) {
   Stop(true);
   field_trial_triggered_ = false;
@@ -165,11 +158,9 @@
     return;
   verbatim_relevance_ = kDefaultVerbatimZeroSuggestRelevance;
   done_ = false;
-  original_user_text_ = user_text;
   permanent_text_ = permanent_text;
   current_query_ = url.spec();
   current_url_match_ = MatchForCurrentURL();
-  user_text_modified_ = false;
   // TODO(jered): Consider adding locally-sourced zero-suggestions here too.
   // These may be useful on the NTP or more relevant to the user than server
   // suggestions, if based on local browsing history.
@@ -182,7 +173,6 @@
     : AutocompleteProvider(listener, profile,
           AutocompleteProvider::TYPE_ZERO_SUGGEST),
       template_url_service_(TemplateURLServiceFactory::GetForProfile(profile)),
-      user_text_modified_(false),
       have_pending_request_(false),
       verbatim_relevance_(kDefaultVerbatimZeroSuggestRelevance),
       field_trial_triggered_(false),
@@ -295,49 +285,45 @@
         if (descriptions != NULL)
           descriptions->GetString(index, &title);
         navigation_results->push_back(SearchProvider::NavigationResult(
-            *this, url, title, false, relevance));
+            *this, url, title, false, relevance, relevances != NULL));
       }
     } else {
       suggest_results->push_back(SearchProvider::SuggestResult(
-          result, false, relevance));
+          result, false, relevance, relevances != NULL));
     }
   }
 }
 
 void ZeroSuggestProvider::AddSuggestResultsToMap(
     const SearchProvider::SuggestResults& results,
-    const string16& provider_keyword,
+    const TemplateURL* template_url,
     SearchProvider::MatchMap* map) {
   for (size_t i = 0; i < results.size(); ++i) {
-    AddMatchToMap(results[i].suggestion(),
-                  provider_keyword,
-                  results[i].relevance(),
-                  AutocompleteMatchType::SEARCH_SUGGEST, i, map);
+    AddMatchToMap(results[i].relevance(), AutocompleteMatchType::SEARCH_SUGGEST,
+                  template_url, results[i].suggestion(), i, map);
   }
 }
 
-void ZeroSuggestProvider::AddMatchToMap(const string16& query_string,
-                                        const string16& provider_keyword,
-                                        int relevance,
+void ZeroSuggestProvider::AddMatchToMap(int relevance,
                                         AutocompleteMatch::Type type,
+                                        const TemplateURL* template_url,
+                                        const string16& query_string,
                                         int accepted_suggestion,
                                         SearchProvider::MatchMap* map) {
   // Pass in query_string as the input_text since we don't want any bolding.
   // TODO(samarth|melevin): use the actual omnibox margin here as well instead
   // of passing in -1.
   AutocompleteMatch match = SearchProvider::CreateSearchSuggestion(
-      profile_, this, AutocompleteInput(),
-      query_string, query_string, relevance, type, accepted_suggestion,
-      false, provider_keyword, -1);
+      this, relevance, type, template_url, query_string, query_string,
+      AutocompleteInput(), false, accepted_suggestion, -1, true);
   if (!match.destination_url.is_valid())
     return;
 
   // Try to add |match| to |map|.  If a match for |query_string| is already in
   // |map|, replace it if |match| is more relevant.
   // NOTE: Keep this ToLower() call in sync with url_database.cc.
-  const std::pair<SearchProvider::MatchMap::iterator, bool> i = map->insert(
-      std::pair<string16, AutocompleteMatch>(
-          base::i18n::ToLower(query_string), match));
+  const std::pair<SearchProvider::MatchMap::iterator, bool> i(map->insert(
+      std::make_pair(base::i18n::ToLower(query_string), match)));
   // NOTE: We purposefully do a direct relevance comparison here instead of
   // using AutocompleteMatch::MoreRelevant(), so that we'll prefer "items added
   // first" rather than "items alphabetically first" when the scores are equal.
@@ -368,7 +354,12 @@
   AutocompleteMatch::ClassifyLocationInString(string16::npos, 0,
       match.contents.length(), ACMatchClassification::URL,
       &match.contents_class);
-  match.description = navigation.description();
+
+  match.description =
+      AutocompleteMatch::SanitizeString(navigation.description());
+  AutocompleteMatch::ClassifyLocationInString(string16::npos, 0,
+      match.description.length(), ACMatchClassification::NONE,
+      &match.description_class);
   return match;
 }
 
@@ -415,25 +406,18 @@
   LogOmniboxZeroSuggestRequest(ZERO_SUGGEST_REQUEST_SENT);
 }
 
-void ZeroSuggestProvider::CheckIfTextModfied(const string16& user_text) {
-  if (!user_text.empty() && user_text != permanent_text_)
-    user_text_modified_ = true;
-}
-
 void ZeroSuggestProvider::ParseSuggestResults(const Value& root_val) {
   SearchProvider::SuggestResults suggest_results;
   FillResults(root_val, &verbatim_relevance_,
               &suggest_results, &navigation_results_);
 
   query_matches_map_.clear();
-  const TemplateURL* default_provider =
-     template_url_service_->GetDefaultSearchProvider();
-  AddSuggestResultsToMap(suggest_results, default_provider->keyword(),
+  AddSuggestResultsToMap(suggest_results,
+                         template_url_service_->GetDefaultSearchProvider(),
                          &query_matches_map_);
 }
 
-void ZeroSuggestProvider::ConvertResultsToAutocompleteMatches(
-    string16 user_text, bool update_histograms) {
+void ZeroSuggestProvider::ConvertResultsToAutocompleteMatches() {
   matches_.clear();
 
   const TemplateURL* default_provider =
@@ -445,33 +429,24 @@
   const int num_query_results = query_matches_map_.size();
   const int num_nav_results = navigation_results_.size();
   const int num_results = num_query_results + num_nav_results;
-  if (update_histograms) {
-    UMA_HISTOGRAM_COUNTS("ZeroSuggest.QueryResults", num_query_results);
-    UMA_HISTOGRAM_COUNTS("ZeroSuggest.URLResults",  num_nav_results);
-    UMA_HISTOGRAM_COUNTS("ZeroSuggest.AllResults", num_results);
-  }
+  UMA_HISTOGRAM_COUNTS("ZeroSuggest.QueryResults", num_query_results);
+  UMA_HISTOGRAM_COUNTS("ZeroSuggest.URLResults",  num_nav_results);
+  UMA_HISTOGRAM_COUNTS("ZeroSuggest.AllResults", num_results);
 
-  if (num_results == 0 || user_text_modified_)
+  if (num_results == 0)
     return;
 
   // TODO(jered): Rip this out once the first match is decoupled from the
   // current typing in the omnibox.
-  // If the user text is empty, we can autocomplete to the URL.  Otherwise,
-  // don't modify the omnibox text.
-  current_url_match_.inline_autocomplete_offset = user_text.empty() ?
-      0 : string16::npos;
   matches_.push_back(current_url_match_);
 
-  for (SearchProvider::MatchMap::const_iterator it = query_matches_map_.begin();
-       it != query_matches_map_.end(); ++it) {
+  for (SearchProvider::MatchMap::const_iterator it(query_matches_map_.begin());
+       it != query_matches_map_.end(); ++it)
     matches_.push_back(it->second);
-  }
 
-  for (SearchProvider::NavigationResults::const_iterator it =
-           navigation_results_.begin();
-       it != navigation_results_.end(); ++it) {
+  for (SearchProvider::NavigationResults::const_iterator it(
+       navigation_results_.begin()); it != navigation_results_.end(); ++it)
     matches_.push_back(NavigationToMatch(*it));
-  }
 }
 
 AutocompleteMatch ZeroSuggestProvider::MatchForCurrentURL() {
@@ -483,6 +458,7 @@
       HistoryURLProvider::SuggestExactInput(this, input,
                                             !HasHTTPScheme(input.text())));
   match.is_history_what_you_typed_match = false;
+  match.inline_autocomplete_offset = string16::npos;
 
   // The placeholder suggestion for the current URL has high relevance so
   // that it is in the first suggestion slot and inline autocompleted. It
diff --git a/chrome/browser/autocomplete/zero_suggest_provider.h b/chrome/browser/autocomplete/zero_suggest_provider.h
index 155f0af..3d83a35 100644
--- a/chrome/browser/autocomplete/zero_suggest_provider.h
+++ b/chrome/browser/autocomplete/zero_suggest_provider.h
@@ -70,14 +70,13 @@
   // net::URLFetcherDelegate
   virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE;
 
-  // Initiates a new fetch for the given |url|, limiting suggestions to those
-  // matching |user_text|. |user_text| may be non-empty if the user previously
-  // interacted with zero-suggest suggestions and then unfocused the omnibox.
-  // |permanent_text| is the text version of |url| displayed in the omnibox.
+  // Initiates a new fetch for the given |url|. |user_text| is the user input
+  // and may be non-empty if the user previously interacted with
+  // zero-suggest suggestions and then unfocused the omnibox. |permanent_text|
+  // is the omnibox text for the current page.
   // TODO(jered): Rip out |user_text| once the first match is decoupled from
   // the current typing in the omnibox.
   void StartZeroSuggest(const GURL& url,
-                        const string16& user_text,
                         const string16& permanent_text);
 
  private:
@@ -102,21 +101,22 @@
                    SearchProvider::SuggestResults* suggest_results,
                    SearchProvider::NavigationResults* navigation_results);
 
-  // Creates AutocompleteMatches for "Search |provider_keyword| for
-  // <suggestion>" for all suggestions in |results|, and adds them to |map|.
+  // Creates AutocompleteMatches to search |template_url| for "<suggestion>" for
+  // all suggestions in |results|, and adds them to |map|.
   void AddSuggestResultsToMap(const SearchProvider::SuggestResults& results,
-                              const string16& provider_keyword,
+                              const TemplateURL* template_url,
                               SearchProvider::MatchMap* map);
 
-  // Creates an AutocompleteMatch for "Search |provider_keyword| for
-  // |query_string|".  The supplied |relevance| and |type| and
-  // |accepted_suggestion| will also be used to create the AutocompleteMatch.
+  // Creates an AutocompleteMatch with the provided |relevance| and |type| to
+  // search |template_url| for |query_string|.  |accepted_suggestion| will be
+  // used to generate Assisted Query Stats.
+  //
   // Adds this match to |map|; if such a match already exists, whichever one
   // has lower relevance is eliminated.
-  void AddMatchToMap(const string16& query_string,
-                     const string16& provider_keyword,
-                     int relevance,
+  void AddMatchToMap(int relevance,
                      AutocompleteMatch::Type type,
+                     const TemplateURL* template_url,
+                     const string16& query_string,
                      int accepted_suggestion,
                      SearchProvider::MatchMap* map);
 
@@ -124,21 +124,16 @@
   AutocompleteMatch NavigationToMatch(
       const SearchProvider::NavigationResult& navigation);
 
-  // Sets |user_text_modified_| if the user has modified the omnibox text, based
-  // on the user input |user_text|.
-  void CheckIfTextModfied(const string16& user_text);
-
   // Fetches zero-suggest suggestions for |current_query_|.
   void Run();
 
   // Parses results from the zero-suggest server and updates results.
   void ParseSuggestResults(const base::Value& root_val);
 
-  // Converts the parsed results to a set of AutocompleteMatches, based on user
-  // input |user_text|, and adds them to |matches_|.  If |update_histograms| is
-  // true, also update the histograms for how many results were received.
-  void ConvertResultsToAutocompleteMatches(string16 user_text,
-                                           bool update_histograms);
+  // Converts the parsed results to a set of AutocompleteMatches and adds them
+  // to |matches_|.  Also update the histograms for how many results were
+  // received.
+  void ConvertResultsToAutocompleteMatches();
 
   // Returns an AutocompleteMatch for the current URL. The match should be in
   // the top position so that pressing enter has the effect of reloading the
@@ -151,12 +146,8 @@
   // The URL for which a suggestion fetch is pending.
   std::string current_query_;
 
-  // What the user has typed.
-  string16 original_user_text_;
   // Copy of OmniboxEditModel::permanent_text_.
   string16 permanent_text_;
-  // Whether the user has modified the omnibox since the zero suggest request.
-  bool user_text_modified_;
 
   // Fetcher used to retrieve results.
   scoped_ptr<net::URLFetcher> fetcher_;
diff --git a/chrome/browser/autofill/android/personal_data_manager_android.cc b/chrome/browser/autofill/android/personal_data_manager_android.cc
index 802dc41..a853f92 100644
--- a/chrome/browser/autofill/android/personal_data_manager_android.cc
+++ b/chrome/browser/autofill/android/personal_data_manager_android.cc
@@ -11,8 +11,8 @@
 #include "chrome/browser/autofill/personal_data_manager_factory.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/profiles/profile_manager.h"
-#include "components/autofill/browser/field_types.h"
-#include "components/autofill/browser/personal_data_manager.h"
+#include "components/autofill/core/browser/field_types.h"
+#include "components/autofill/core/browser/personal_data_manager.h"
 #include "jni/PersonalDataManager_jni.h"
 
 using base::android::ConvertJavaStringToUTF8;
diff --git a/chrome/browser/autofill/android/personal_data_manager_android.h b/chrome/browser/autofill/android/personal_data_manager_android.h
index 1809b07..6221f8a 100644
--- a/chrome/browser/autofill/android/personal_data_manager_android.h
+++ b/chrome/browser/autofill/android/personal_data_manager_android.h
@@ -7,8 +7,8 @@
 
 #include "base/android/jni_helper.h"
 #include "base/android/scoped_java_ref.h"
-#include "components/autofill/browser/personal_data_manager.h"
-#include "components/autofill/browser/personal_data_manager_observer.h"
+#include "components/autofill/core/browser/personal_data_manager.h"
+#include "components/autofill/core/browser/personal_data_manager_observer.h"
 
 namespace autofill {
 
diff --git a/chrome/browser/autofill/autofill_browsertest.cc b/chrome/browser/autofill/autofill_browsertest.cc
index d2d213f..213e79d 100644
--- a/chrome/browser/autofill/autofill_browsertest.cc
+++ b/chrome/browser/autofill/autofill_browsertest.cc
@@ -13,7 +13,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/autofill/personal_data_manager_factory.h"
 #include "chrome/browser/infobars/confirm_infobar_delegate.h"
 #include "chrome/browser/infobars/infobar_service.h"
@@ -27,16 +27,16 @@
 #include "chrome/common/render_messages.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
-#include "components/autofill/browser/autofill_common_test.h"
-#include "components/autofill/browser/autofill_external_delegate.h"
-#include "components/autofill/browser/autofill_manager.h"
-#include "components/autofill/browser/autofill_manager_test_delegate.h"
-#include "components/autofill/browser/autofill_profile.h"
-#include "components/autofill/browser/credit_card.h"
-#include "components/autofill/browser/personal_data_manager.h"
-#include "components/autofill/browser/personal_data_manager_observer.h"
-#include "components/autofill/browser/validation.h"
 #include "components/autofill/content/browser/autofill_driver_impl.h"
+#include "components/autofill/core/browser/autofill_common_test.h"
+#include "components/autofill/core/browser/autofill_external_delegate.h"
+#include "components/autofill/core/browser/autofill_manager.h"
+#include "components/autofill/core/browser/autofill_manager_test_delegate.h"
+#include "components/autofill/core/browser/autofill_profile.h"
+#include "components/autofill/core/browser/credit_card.h"
+#include "components/autofill/core/browser/personal_data_manager.h"
+#include "components/autofill/core/browser/personal_data_manager_observer.h"
+#include "components/autofill/core/browser/validation.h"
 #include "content/public/browser/navigation_controller.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
@@ -232,11 +232,9 @@
     AutofillDriverImpl* autofill_driver =
         AutofillDriverImpl::FromWebContents(web_contents);
     AutofillManager* autofill_manager = autofill_driver->autofill_manager();
-    if (autofill_manager->IsNativeUiEnabled()) {
-      scoped_ptr<AutofillExternalDelegate> external_delegate(
-          new TestAutofillExternalDelegate(web_contents, autofill_manager));
-      autofill_driver->SetAutofillExternalDelegate(external_delegate.Pass());
-    }
+    scoped_ptr<AutofillExternalDelegate> external_delegate(
+        new TestAutofillExternalDelegate(web_contents, autofill_manager));
+    autofill_driver->SetAutofillExternalDelegate(external_delegate.Pass());
     autofill_manager->SetTestDelegate(&test_delegate_);
   }
 
@@ -471,14 +469,6 @@
   }
 
   void SendKeyToPopupAndWait(ui::KeyboardCode key) {
-    // TODO(isherman): Remove this condition once the WebKit popup UI code is
-    // removed.
-    if (!external_delegate()) {
-      // When testing the WebKit-based UI, route all keys to the page.
-      SendKeyToPageAndWait(key);
-      return;
-    }
-
     // When testing the native UI, route popup-targeted key presses via the
     // external delegate.
     content::NativeWebKeyboardEvent event;
diff --git a/chrome/browser/autofill/autofill_cc_infobar_delegate.cc b/chrome/browser/autofill/autofill_cc_infobar_delegate.cc
index 185b283..a55a4d0 100644
--- a/chrome/browser/autofill/autofill_cc_infobar_delegate.cc
+++ b/chrome/browser/autofill/autofill_cc_infobar_delegate.cc
@@ -6,8 +6,8 @@
 
 #include "base/logging.h"
 #include "chrome/browser/infobars/infobar_service.h"
-#include "components/autofill/browser/credit_card.h"
-#include "components/autofill/browser/personal_data_manager.h"
+#include "components/autofill/core/browser/credit_card.h"
+#include "components/autofill/core/browser/personal_data_manager.h"
 #include "components/autofill/core/common/autofill_constants.h"
 #include "content/public/browser/page_navigator.h"
 #include "content/public/browser/web_contents.h"
diff --git a/chrome/browser/autofill/autofill_cc_infobar_delegate.h b/chrome/browser/autofill/autofill_cc_infobar_delegate.h
index 14c959a..4941864 100644
--- a/chrome/browser/autofill/autofill_cc_infobar_delegate.h
+++ b/chrome/browser/autofill/autofill_cc_infobar_delegate.h
@@ -11,7 +11,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/strings/string16.h"
 #include "chrome/browser/infobars/confirm_infobar_delegate.h"
-#include "components/autofill/browser/autofill_metrics.h"
+#include "components/autofill/core/browser/autofill_metrics.h"
 #include "ui/base/window_open_disposition.h"
 
 class CreditCard;
diff --git a/chrome/browser/autofill/autofill_driver_impl_browsertest.cc b/chrome/browser/autofill/autofill_driver_impl_browsertest.cc
new file mode 100644
index 0000000..fb3e6a7
--- /dev/null
+++ b/chrome/browser/autofill/autofill_driver_impl_browsertest.cc
@@ -0,0 +1,145 @@
+// 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/scoped_ptr.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_tabstrip.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/common/url_constants.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "chrome/test/base/testing_pref_service_syncable.h"
+#include "components/autofill/content/browser/autofill_driver_impl.h"
+#include "components/autofill/core/browser/autofill_manager.h"
+#include "components/autofill/core/browser/test_autofill_manager_delegate.h"
+#include "content/public/browser/navigation_controller.h"
+#include "content/public/browser/notification_service.h"
+#include "content/public/browser/notification_types.h"
+#include "content/public/browser/page_navigator.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_observer.h"
+#include "content/public/common/url_constants.h"
+#include "content/public/test/test_utils.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/rect.h"
+
+namespace autofill {
+namespace {
+
+class MockAutofillManagerDelegate
+    : public autofill::TestAutofillManagerDelegate {
+ public:
+  MockAutofillManagerDelegate() {}
+  virtual ~MockAutofillManagerDelegate() {}
+
+  virtual PrefService* GetPrefs() { return &prefs_; }
+
+  user_prefs::PrefRegistrySyncable* GetPrefRegistry() {
+    return prefs_.registry();
+  }
+
+  MOCK_METHOD7(ShowAutofillPopup,
+               void(const gfx::RectF& element_bounds,
+                    base::i18n::TextDirection text_direction,
+                    const std::vector<string16>& values,
+                    const std::vector<string16>& labels,
+                    const std::vector<string16>& icons,
+                    const std::vector<int>& identifiers,
+                    base::WeakPtr<AutofillPopupDelegate> delegate));
+
+  MOCK_METHOD0(HideAutofillPopup, void());
+
+ private:
+  TestingPrefServiceSyncable prefs_;
+
+  DISALLOW_COPY_AND_ASSIGN(MockAutofillManagerDelegate);
+};
+
+// Subclass AutofillDriverImpl so we can create an AutofillDriverImpl instance.
+class TestAutofillDriverImpl : public AutofillDriverImpl {
+ public:
+  TestAutofillDriverImpl(content::WebContents* web_contents,
+                         AutofillManagerDelegate* delegate)
+      : AutofillDriverImpl(
+          web_contents,
+          delegate,
+          g_browser_process->GetApplicationLocale(),
+          AutofillManager::ENABLE_AUTOFILL_DOWNLOAD_MANAGER) {}
+  virtual ~TestAutofillDriverImpl() {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TestAutofillDriverImpl);
+};
+
+}  // namespace
+
+class AutofillDriverImplBrowserTest
+    : public InProcessBrowserTest,
+      public content::WebContentsObserver {
+ public:
+  AutofillDriverImplBrowserTest() {}
+  virtual ~AutofillDriverImplBrowserTest() {}
+
+  virtual void SetUpOnMainThread() OVERRIDE {
+    web_contents_ = browser()->tab_strip_model()->GetActiveWebContents();
+    ASSERT_TRUE(web_contents_ != NULL);
+    Observe(web_contents_);
+    AutofillManager::RegisterUserPrefs(manager_delegate_.GetPrefRegistry());
+
+    autofill_driver_.reset(new TestAutofillDriverImpl(web_contents_,
+                                                      &manager_delegate_));
+  }
+
+  // Normally the WebContents will automatically delete the driver, but here
+  // the driver is owned by this test, so we have to manually destroy.
+  virtual void WebContentsDestroyed(content::WebContents* web_contents)
+      OVERRIDE {
+    DCHECK_EQ(web_contents_, web_contents);
+    autofill_driver_.reset();
+  }
+
+ protected:
+  content::WebContents* web_contents_;
+
+  testing::NiceMock<MockAutofillManagerDelegate> manager_delegate_;
+  scoped_ptr<TestAutofillDriverImpl> autofill_driver_;
+};
+
+IN_PROC_BROWSER_TEST_F(AutofillDriverImplBrowserTest,
+                       SwitchTabAndHideAutofillPopup) {
+  // Notification is different on platforms. On linux this will be called twice,
+  // while on windows only once.
+  EXPECT_CALL(manager_delegate_, HideAutofillPopup())
+      .Times(testing::AtLeast(1));
+
+  content::WindowedNotificationObserver observer(
+      content::NOTIFICATION_WEB_CONTENTS_VISIBILITY_CHANGED,
+      content::Source<content::WebContents>(web_contents_));
+  chrome::AddSelectedTabWithURL(browser(), GURL(content::kAboutBlankURL),
+                                content::PAGE_TRANSITION_AUTO_TOPLEVEL);
+  observer.Wait();
+}
+
+IN_PROC_BROWSER_TEST_F(AutofillDriverImplBrowserTest,
+                       TestPageNavigationHidingAutofillPopup) {
+  // Notification is different on platforms. On linux this will be called twice,
+  // while on windows only once.
+  EXPECT_CALL(manager_delegate_, HideAutofillPopup())
+      .Times(testing::AtLeast(1));
+
+  content::WindowedNotificationObserver observer(
+      content::NOTIFICATION_NAV_ENTRY_COMMITTED,
+      content::Source<content::NavigationController>(
+          &(web_contents_->GetController())));
+  browser()->OpenURL(content::OpenURLParams(
+      GURL(chrome::kChromeUIBookmarksURL), content::Referrer(),
+      CURRENT_TAB, content::PAGE_TRANSITION_TYPED, false));
+  browser()->OpenURL(content::OpenURLParams(
+      GURL(chrome::kChromeUIAboutURL), content::Referrer(),
+      CURRENT_TAB, content::PAGE_TRANSITION_TYPED, false));
+  observer.Wait();
+}
+
+}  // namespace autofill
diff --git a/chrome/browser/autofill/autofill_external_delegate_browsertest.cc b/chrome/browser/autofill/autofill_external_delegate_browsertest.cc
deleted file mode 100644
index 16e7611..0000000
--- a/chrome/browser/autofill/autofill_external_delegate_browsertest.cc
+++ /dev/null
@@ -1,168 +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 "base/memory/scoped_ptr.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/browser_tabstrip.h"
-#include "chrome/browser/ui/tabs/tab_strip_model.h"
-#include "chrome/common/url_constants.h"
-#include "chrome/test/base/in_process_browser_test.h"
-#include "chrome/test/base/testing_pref_service_syncable.h"
-#include "components/autofill/browser/autofill_manager.h"
-#include "components/autofill/browser/test_autofill_driver.h"
-#include "components/autofill/browser/test_autofill_external_delegate.h"
-#include "components/autofill/browser/test_autofill_manager_delegate.h"
-#include "content/public/browser/navigation_controller.h"
-#include "content/public/browser/notification_service.h"
-#include "content/public/browser/notification_types.h"
-#include "content/public/browser/page_navigator.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/browser/web_contents_observer.h"
-#include "content/public/common/url_constants.h"
-#include "content/public/test/test_utils.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/gfx/rect.h"
-
-namespace autofill {
-namespace {
-
-class MockAutofillManagerDelegate
-    : public autofill::TestAutofillManagerDelegate {
- public:
-  MockAutofillManagerDelegate() {}
-  virtual ~MockAutofillManagerDelegate() {}
-
-  virtual PrefService* GetPrefs() { return &prefs_; }
-
-  user_prefs::PrefRegistrySyncable* GetPrefRegistry() {
-    return prefs_.registry();
-  }
-
-  MOCK_METHOD7(ShowAutofillPopup,
-               void(const gfx::RectF& element_bounds,
-                    base::i18n::TextDirection text_direction,
-                    const std::vector<string16>& values,
-                    const std::vector<string16>& labels,
-                    const std::vector<string16>& icons,
-                    const std::vector<int>& identifiers,
-                    base::WeakPtr<AutofillPopupDelegate> delegate));
-
-  MOCK_METHOD0(HideAutofillPopup, void());
-
- private:
-  TestingPrefServiceSyncable prefs_;
-
-  DISALLOW_COPY_AND_ASSIGN(MockAutofillManagerDelegate);
-};
-
-// Subclass AutofillManager so we can create AutofillManager instance.
-class TestAutofillManager : public AutofillManager {
- public:
-  TestAutofillManager(AutofillDriver* driver,
-                      autofill::AutofillManagerDelegate* delegate)
-      : AutofillManager(driver,
-                        delegate,
-                        g_browser_process->GetApplicationLocale(),
-                        AutofillManager::ENABLE_AUTOFILL_DOWNLOAD_MANAGER) {}
-  virtual ~TestAutofillManager() {}
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(TestAutofillManager);
-};
-
-// Subclass AutofillExternalDelegate so we can create an
-// AutofillExternalDelegate instance.
-class TestAutofillExternalDelegate : public AutofillExternalDelegate {
- public:
-  TestAutofillExternalDelegate(content::WebContents* web_contents,
-                               AutofillManager* autofill_manager)
-      : AutofillExternalDelegate(web_contents, autofill_manager) {}
-  virtual ~TestAutofillExternalDelegate() {}
-};
-
-}  // namespace
-
-class AutofillExternalDelegateBrowserTest
-    : public InProcessBrowserTest,
-      public content::WebContentsObserver {
- public:
-  AutofillExternalDelegateBrowserTest() {}
-  virtual ~AutofillExternalDelegateBrowserTest() {}
-
-  virtual void SetUpOnMainThread() OVERRIDE {
-    web_contents_ = browser()->tab_strip_model()->GetActiveWebContents();
-    ASSERT_TRUE(web_contents_ != NULL);
-    Observe(web_contents_);
-
-    AutofillManager::RegisterUserPrefs(manager_delegate_.GetPrefRegistry());
-
-    autofill_driver_.reset(new TestAutofillDriver(web_contents_));
-    autofill_manager_.reset(
-        new TestAutofillManager(autofill_driver_.get(), &manager_delegate_));
-    autofill_external_delegate_.reset(
-        new TestAutofillExternalDelegate(web_contents_,
-                                         autofill_manager_.get()));
-  }
-
-  // Normally the WebContents will automatically delete the delegate, but here
-  // the delegate is owned by this test, so we have to manually destroy.
-  virtual void WebContentsDestroyed(content::WebContents* web_contents)
-      OVERRIDE {
-    DCHECK_EQ(web_contents_, web_contents);
-    autofill_external_delegate_.reset();
-    autofill_manager_.reset();
-    autofill_driver_.reset();
-  }
-
- protected:
-  content::WebContents* web_contents_;
-
-  testing::NiceMock<MockAutofillManagerDelegate> manager_delegate_;
-  scoped_ptr<TestAutofillDriver> autofill_driver_;
-  scoped_ptr<TestAutofillManager> autofill_manager_;
-  scoped_ptr<TestAutofillExternalDelegate> autofill_external_delegate_;
-};
-
-IN_PROC_BROWSER_TEST_F(AutofillExternalDelegateBrowserTest,
-                       SwitchTabAndHideAutofillPopup) {
-  autofill::GenerateTestAutofillPopup(autofill_external_delegate_.get());
-
-  // Notification is different on platforms. On linux this will be called twice,
-  // while on windows only once.
-  EXPECT_CALL(manager_delegate_, HideAutofillPopup())
-      .Times(testing::AtLeast(1));
-
-  content::WindowedNotificationObserver observer(
-      content::NOTIFICATION_WEB_CONTENTS_VISIBILITY_CHANGED,
-      content::Source<content::WebContents>(web_contents_));
-  chrome::AddSelectedTabWithURL(browser(), GURL(content::kAboutBlankURL),
-                                content::PAGE_TRANSITION_AUTO_TOPLEVEL);
-  observer.Wait();
-}
-
-IN_PROC_BROWSER_TEST_F(AutofillExternalDelegateBrowserTest,
-                       TestPageNavigationHidingAutofillPopup) {
-  autofill::GenerateTestAutofillPopup(autofill_external_delegate_.get());
-
-  // Notification is different on platforms. On linux this will be called twice,
-  // while on windows only once.
-  EXPECT_CALL(manager_delegate_, HideAutofillPopup())
-      .Times(testing::AtLeast(1));
-
-  content::WindowedNotificationObserver observer(
-      content::NOTIFICATION_NAV_ENTRY_COMMITTED,
-      content::Source<content::NavigationController>(
-          &(web_contents_->GetController())));
-  browser()->OpenURL(content::OpenURLParams(
-      GURL(chrome::kChromeUIBookmarksURL), content::Referrer(),
-      CURRENT_TAB, content::PAGE_TRANSITION_TYPED, false));
-  browser()->OpenURL(content::OpenURLParams(
-      GURL(chrome::kChromeUIAboutURL), content::Referrer(),
-      CURRENT_TAB, content::PAGE_TRANSITION_TYPED, false));
-  observer.Wait();
-}
-
-}  // namespace autofill
diff --git a/chrome/browser/autofill/autofill_interactive_uitest.cc b/chrome/browser/autofill/autofill_interactive_uitest.cc
index 2199cb5..c040136 100644
--- a/chrome/browser/autofill/autofill_interactive_uitest.cc
+++ b/chrome/browser/autofill/autofill_interactive_uitest.cc
@@ -6,19 +6,20 @@
 #include "base/memory/scoped_ptr.h"
 #include "chrome/browser/autofill/personal_data_manager_factory.h"
 #include "chrome/browser/infobars/confirm_infobar_delegate.h"
+#include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/common/chrome_notification_types.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
-#include "components/autofill/browser/autofill_common_test.h"
-#include "components/autofill/browser/autofill_external_delegate.h"
-#include "components/autofill/browser/autofill_manager.h"
-#include "components/autofill/browser/autofill_manager_test_delegate.h"
-#include "components/autofill/browser/autofill_profile.h"
-#include "components/autofill/browser/personal_data_manager.h"
-#include "components/autofill/browser/personal_data_manager_observer.h"
 #include "components/autofill/content/browser/autofill_driver_impl.h"
+#include "components/autofill/core/browser/autofill_common_test.h"
+#include "components/autofill/core/browser/autofill_external_delegate.h"
+#include "components/autofill/core/browser/autofill_manager.h"
+#include "components/autofill/core/browser/autofill_manager_test_delegate.h"
+#include "components/autofill/core/browser/autofill_profile.h"
+#include "components/autofill/core/browser/personal_data_manager.h"
+#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/notification_service.h"
@@ -209,11 +210,9 @@
     AutofillDriverImpl* autofill_driver =
         AutofillDriverImpl::FromWebContents(web_contents);
     AutofillManager* autofill_manager = autofill_driver->autofill_manager();
-    if (autofill_manager->IsNativeUiEnabled()) {
-      scoped_ptr<AutofillExternalDelegate> external_delegate(
-          new TestAutofillExternalDelegate(web_contents, autofill_manager));
-      autofill_driver->SetAutofillExternalDelegate(external_delegate.Pass());
-    }
+    scoped_ptr<AutofillExternalDelegate> external_delegate(
+        new TestAutofillExternalDelegate(web_contents, autofill_manager));
+    autofill_driver->SetAutofillExternalDelegate(external_delegate.Pass());
     autofill_manager->SetTestDelegate(&test_delegate_);
   }
 
diff --git a/chrome/browser/autofill/form_structure_browsertest.cc b/chrome/browser/autofill/form_structure_browsertest.cc
index e4491ab..e6babac 100644
--- a/chrome/browser/autofill/form_structure_browsertest.cc
+++ b/chrome/browser/autofill/form_structure_browsertest.cc
@@ -11,11 +11,11 @@
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
-#include "components/autofill/browser/autofill_manager.h"
-#include "components/autofill/browser/data_driven_test.h"
-#include "components/autofill/browser/form_structure.h"
 #include "components/autofill/content/browser/autofill_driver_impl.h"
-#include "googleurl/src/gurl.h"
+#include "components/autofill/core/browser/autofill_manager.h"
+#include "components/autofill/core/browser/data_driven_test.h"
+#include "components/autofill/core/browser/form_structure.h"
+#include "url/gurl.h"
 
 namespace autofill {
 namespace {
diff --git a/chrome/browser/autofill/personal_data_manager_factory.cc b/chrome/browser/autofill/personal_data_manager_factory.cc
index 5157fe2..17b234e 100644
--- a/chrome/browser/autofill/personal_data_manager_factory.cc
+++ b/chrome/browser/autofill/personal_data_manager_factory.cc
@@ -10,7 +10,7 @@
 #include "chrome/browser/profiles/incognito_helpers.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/webdata/web_data_service_factory.h"
-#include "components/autofill/browser/personal_data_manager.h"
+#include "components/autofill/core/browser/personal_data_manager.h"
 #include "components/browser_context_keyed_service/browser_context_dependency_manager.h"
 
 namespace autofill {
diff --git a/chrome/browser/autofill/risk/fingerprint_browsertest.cc b/chrome/browser/autofill/risk/fingerprint_browsertest.cc
index 1a1a3f0..ec028a5 100644
--- a/chrome/browser/autofill/risk/fingerprint_browsertest.cc
+++ b/chrome/browser/autofill/risk/fingerprint_browsertest.cc
@@ -169,14 +169,8 @@
   base::MessageLoop message_loop_;
 };
 
-// This test is flaky on Windows. See http://crbug.com/178356.
-#if defined(OS_WIN)
-#define MAYBE_GetFingerprint DISABLED_GetFingerprint
-#else
-#define MAYBE_GetFingerprint GetFingerprint
-#endif
 // Test that getting a fingerprint works on some basic level.
-IN_PROC_BROWSER_TEST_F(AutofillRiskFingerprintTest, MAYBE_GetFingerprint) {
+IN_PROC_BROWSER_TEST_F(AutofillRiskFingerprintTest, GetFingerprint) {
   content::Geoposition position;
   position.latitude = kLatitude;
   position.longitude = kLongitude;
diff --git a/chrome/browser/automation/automation_provider.h b/chrome/browser/automation/automation_provider.h
index cd98c08..ac7ad28 100644
--- a/chrome/browser/automation/automation_provider.h
+++ b/chrome/browser/automation/automation_provider.h
@@ -26,7 +26,7 @@
 #include "chrome/browser/common/cancelable_request.h"
 #include "chrome/common/automation_constants.h"
 #include "chrome/common/content_settings.h"
-#include "components/autofill/browser/field_types.h"
+#include "components/autofill/core/browser/field_types.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/trace_subscriber.h"
diff --git a/chrome/browser/automation/automation_provider_observers.cc b/chrome/browser/automation/automation_provider_observers.cc
index 7a7823d..bd66049 100644
--- a/chrome/browser/automation/automation_provider_observers.cc
+++ b/chrome/browser/automation/automation_provider_observers.cc
@@ -79,9 +79,9 @@
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/process_type.h"
 #include "extensions/common/view_type.h"
-#include "googleurl/src/gurl.h"
 #include "ui/gfx/codec/png_codec.h"
 #include "ui/gfx/rect.h"
+#include "url/gurl.h"
 
 using content::BrowserThread;
 using content::DomOperationNotificationDetails;
diff --git a/chrome/browser/automation/automation_provider_observers.h b/chrome/browser/automation/automation_provider_observers.h
index 9d7406d..a92bd5d 100644
--- a/chrome/browser/automation/automation_provider_observers.h
+++ b/chrome/browser/automation/automation_provider_observers.h
@@ -20,8 +20,8 @@
 #include "base/values.h"
 #include "chrome/browser/automation/automation_provider_json.h"
 #include "chrome/browser/bookmarks/bookmark_model_observer.h"
-#include "components/autofill/browser/personal_data_manager.h"
-#include "components/autofill/browser/personal_data_manager_observer.h"
+#include "components/autofill/core/browser/personal_data_manager.h"
+#include "components/autofill/core/browser/personal_data_manager_observer.h"
 #if defined(OS_CHROMEOS)
 #include "chrome/browser/chromeos/cros/network_library.h"
 #include "chrome/browser/chromeos/login/enrollment/enrollment_screen.h"
@@ -33,7 +33,6 @@
 #include "chrome/browser/download/all_download_item_notifier.h"
 #include "chrome/browser/history/history_service.h"
 #include "chrome/browser/history/history_types.h"
-#include "chrome/browser/importer/importer_data_types.h"
 #include "chrome/browser/importer/importer_progress_observer.h"
 #include "chrome/browser/memory_details.h"
 #include "chrome/browser/password_manager/password_store_change.h"
@@ -42,6 +41,7 @@
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/common/automation_constants.h"
 #include "chrome/common/extensions/extension_constants.h"
+#include "chrome/common/importer/importer_data_types.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/download_item.h"
 #include "content/public/browser/download_manager.h"
@@ -936,28 +936,6 @@
   DISALLOW_COPY_AND_ASSIGN(VirtualConnectObserver);
 };
 
-// Waits for enterprise device enrollment to complete and returns the status to
-// the automation provider.
-class EnrollmentObserver
-    : public chromeos::EnrollmentScreen::TestingObserver {
- public:
-  EnrollmentObserver(AutomationProvider* automation,
-                     IPC::Message* reply_message,
-                     chromeos::EnrollmentScreen* enrollment_screen);
-
-  virtual ~EnrollmentObserver();
-
-  // chromeos::EnrollmentScreen::Observer implementation.
-  virtual void OnEnrollmentComplete(bool succeeded);
-
- private:
-  base::WeakPtr<AutomationProvider> automation_;
-  scoped_ptr<IPC::Message> reply_message_;
-  chromeos::EnrollmentScreen* enrollment_screen_;
-
-  DISALLOW_COPY_AND_ASSIGN(EnrollmentObserver);
-};
-
 #endif  // defined(OS_CHROMEOS)
 
 // Waits for the bookmark model to load.
diff --git a/chrome/browser/automation/automation_provider_observers_chromeos.cc b/chrome/browser/automation/automation_provider_observers_chromeos.cc
index adb3dcd..621a9ba 100644
--- a/chrome/browser/automation/automation_provider_observers_chromeos.cc
+++ b/chrome/browser/automation/automation_provider_observers_chromeos.cc
@@ -425,30 +425,3 @@
   }
   return virt;
 }
-
-EnrollmentObserver::EnrollmentObserver(AutomationProvider* automation,
-    IPC::Message* reply_message,
-    chromeos::EnrollmentScreen* enrollment_screen)
-    : automation_(automation->AsWeakPtr()),
-      reply_message_(reply_message),
-      enrollment_screen_(enrollment_screen) {
-  enrollment_screen_->AddTestingObserver(this);
-}
-
-EnrollmentObserver::~EnrollmentObserver() {}
-
-void EnrollmentObserver::OnEnrollmentComplete(bool succeeded) {
-  enrollment_screen_->RemoveTestingObserver(this);
-  if (automation_) {
-    if (succeeded) {
-      AutomationJSONReply(automation_.get(), reply_message_.release())
-          .SendSuccess(NULL);
-    } else {
-      scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
-      return_value->SetString("error_string", "Enrollment failed.");
-      AutomationJSONReply(automation_.get(), reply_message_.release())
-          .SendSuccess(return_value.get());
-    }
-  }
-  delete this;
-}
diff --git a/chrome/browser/automation/automation_resource_message_filter.cc b/chrome/browser/automation/automation_resource_message_filter.cc
index fafded1..05ccab5 100644
--- a/chrome/browser/automation/automation_resource_message_filter.cc
+++ b/chrome/browser/automation/automation_resource_message_filter.cc
@@ -16,10 +16,10 @@
 #include "chrome/common/render_messages.h"
 #include "content/public/browser/browser_message_filter.h"
 #include "content/public/browser/browser_thread.h"
-#include "googleurl/src/gurl.h"
 #include "net/base/net_errors.h"
 #include "net/url_request/url_request_context.h"
 #include "net/url_request/url_request_filter.h"
+#include "url/gurl.h"
 
 using content::BrowserMessageFilter;
 using content::BrowserThread;
diff --git a/chrome/browser/automation/automation_util.cc b/chrome/browser/automation/automation_util.cc
index ccfb056..f482544 100644
--- a/chrome/browser/automation/automation_util.cc
+++ b/chrome/browser/automation/automation_util.cc
@@ -13,7 +13,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
 #include "base/synchronization/waitable_event.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "base/values.h"
 #include "chrome/browser/automation/automation_provider.h"
 #include "chrome/browser/automation/automation_provider_json.h"
diff --git a/chrome/browser/automation/testing_automation_provider.cc b/chrome/browser/automation/testing_automation_provider.cc
index d59502f..b37e935 100644
--- a/chrome/browser/automation/testing_automation_provider.cc
+++ b/chrome/browser/automation/testing_automation_provider.cc
@@ -24,7 +24,7 @@
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/thread_restrictions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/autocomplete/autocomplete_controller.h"
 #include "chrome/browser/autocomplete/autocomplete_match.h"
@@ -61,8 +61,6 @@
 #include "chrome/browser/extensions/updater/extension_updater.h"
 #include "chrome/browser/history/history_service_factory.h"
 #include "chrome/browser/history/top_sites.h"
-#include "chrome/browser/importer/importer_host.h"
-#include "chrome/browser/importer/importer_list.h"
 #include "chrome/browser/infobars/confirm_infobar_delegate.h"
 #include "chrome/browser/infobars/infobar_service.h"
 #include "chrome/browser/lifetime/application_lifetime.h"
@@ -112,6 +110,7 @@
 #include "chrome/common/automation_messages.h"
 #include "chrome/common/chrome_constants.h"
 #include "chrome/common/chrome_notification_types.h"
+#include "chrome/common/chrome_paths.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/extensions/background_info.h"
 #include "chrome/common/extensions/extension.h"
@@ -120,7 +119,6 @@
 #include "chrome/common/extensions/permissions/permissions_data.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/render_messages.h"
-#include "components/breakpad/common/breakpad_paths.h"
 #include "content/public/browser/browser_child_process_host_iterator.h"
 #include "content/public/browser/child_process_data.h"
 #include "content/public/browser/favicon_status.h"
@@ -136,6 +134,7 @@
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/child_process_host.h"
 #include "content/public/common/common_param_traits.h"
+#include "content/public/common/drop_data.h"
 #include "content/public/common/geoposition.h"
 #include "content/public/common/ssl_status.h"
 #include "extensions/browser/view_type_utils.h"
@@ -146,7 +145,6 @@
 #include "ui/base/events/event_constants.h"
 #include "ui/base/keycodes/keyboard_codes.h"
 #include "ui/base/ui_base_types.h"
-#include "webkit/common/webdropdata.h"
 #include "webkit/plugins/webplugininfo.h"
 
 #if defined(ENABLE_CONFIGURATION_POLICY)
@@ -249,11 +247,7 @@
 };
 
 TestingAutomationProvider::TestingAutomationProvider(Profile* profile)
-    : AutomationProvider(profile)
-#if defined(OS_CHROMEOS)
-      , power_manager_observer_(NULL)
-#endif
-      {
+    : AutomationProvider(profile) {
   BrowserList::AddObserver(this);
   registrar_.Add(this, chrome::NOTIFICATION_SESSION_END,
                  content::NotificationService::AllSources());
@@ -302,40 +296,6 @@
 #endif  // !defined(OS_CHROMEOS) && !defined(OS_MACOSX)
 }
 
-void TestingAutomationProvider::OnSourceProfilesLoaded() {
-  DCHECK_NE(static_cast<ImporterList*>(NULL), importer_list_.get());
-
-  // Get the correct profile based on the browser that the user provided.
-  importer::SourceProfile source_profile;
-  size_t i = 0;
-  size_t importers_count = importer_list_->count();
-  for ( ; i < importers_count; ++i) {
-    importer::SourceProfile profile = importer_list_->GetSourceProfileAt(i);
-    if (profile.importer_name == import_settings_data_.browser_name) {
-      source_profile = profile;
-      break;
-    }
-  }
-  // If we made it to the end of the loop, then the input was bad.
-  if (i == importers_count) {
-    AutomationJSONReply(this, import_settings_data_.reply_message)
-        .SendError("Invalid browser name string found.");
-    return;
-  }
-
-  // Deletes itself.
-  ImporterHost* importer_host = new ImporterHost;
-  importer_host->SetObserver(
-      new AutomationProviderImportSettingsObserver(
-          this, import_settings_data_.reply_message));
-
-  Profile* target_profile = import_settings_data_.browser->profile();
-  importer_host->StartImportSettings(source_profile,
-                                     target_profile,
-                                     import_settings_data_.import_items,
-                                     new ProfileWriter(target_profile));
-}
-
 void TestingAutomationProvider::Observe(
     int type,
     const content::NotificationSource& source,
@@ -943,7 +903,7 @@
   }
 
   // Emulate drag and drop to set the file paths to the file upload control.
-  WebDropData drop_data;
+  content::DropData drop_data;
   for (size_t path_index = 0; path_index < paths->GetSize(); ++path_index) {
     string16 path;
     if (!paths->GetString(path_index, &path)) {
@@ -953,7 +913,7 @@
     }
 
     drop_data.filenames.push_back(
-        WebDropData::FileInfo(path, string16()));
+        content::DropData::FileInfo(path, string16()));
   }
 
   const gfx::Point client(x, y);
@@ -1897,9 +1857,6 @@
   browser_handler_map_["SaveTabContents"] =
       &TestingAutomationProvider::SaveTabContents;
 
-  browser_handler_map_["ImportSettings"] =
-      &TestingAutomationProvider::ImportSettings;
-
   browser_handler_map_["AddSavedPassword"] =
       &TestingAutomationProvider::AddSavedPassword;
   browser_handler_map_["RemoveSavedPassword"] =
@@ -2238,7 +2195,7 @@
   properties->SetString("command_line_string",
       CommandLine::ForCurrentProcess()->GetCommandLineString());
   base::FilePath dumps_path;
-  PathService::Get(breakpad::DIR_CRASH_DUMPS, &dumps_path);
+  PathService::Get(chrome::DIR_CRASH_DUMPS, &dumps_path);
   properties->SetString("DIR_CRASH_DUMPS", dumps_path.value());
 #if defined(USE_AURA)
   properties->SetBoolean("aura", true);
@@ -3237,51 +3194,6 @@
       this, reply_message);
 }
 
-// Refer to ImportSettings() in chrome/test/pyautolib/pyauto.py for sample
-// json input.
-// Sample json output: "{}"
-void TestingAutomationProvider::ImportSettings(Browser* browser,
-                                               DictionaryValue* args,
-                                               IPC::Message* reply_message) {
-  // Map from the json string passed over to the import item masks.
-  std::map<std::string, importer::ImportItem> string_to_import_item;
-  string_to_import_item["HISTORY"] = importer::HISTORY;
-  string_to_import_item["FAVORITES"] = importer::FAVORITES;
-  string_to_import_item["COOKIES"] = importer::COOKIES;
-  string_to_import_item["PASSWORDS"] = importer::PASSWORDS;
-  string_to_import_item["SEARCH_ENGINES"] = importer::SEARCH_ENGINES;
-  string_to_import_item["HOME_PAGE"] = importer::HOME_PAGE;
-  string_to_import_item["ALL"] = importer::ALL;
-
-  ListValue* import_items_list = NULL;
-  if (!args->GetString("import_from", &import_settings_data_.browser_name) ||
-      !args->GetList("import_items", &import_items_list)) {
-    AutomationJSONReply(this, reply_message)
-        .SendError("Incorrect type for one or more of the arguments.");
-    return;
-  }
-
-  import_settings_data_.import_items = 0;
-  int num_items = import_items_list->GetSize();
-  for (int i = 0; i < num_items; i++) {
-    std::string item;
-    // If the provided string is not part of the map, error out.
-    if (!import_items_list->GetString(i, &item) ||
-        !ContainsKey(string_to_import_item, item)) {
-      AutomationJSONReply(this, reply_message)
-          .SendError("Invalid item string found in import_items.");
-      return;
-    }
-    import_settings_data_.import_items |= string_to_import_item[item];
-  }
-
-  import_settings_data_.browser = browser;
-  import_settings_data_.reply_message = reply_message;
-
-  importer_list_ = new ImporterList(NULL);
-  importer_list_->DetectSourceProfiles(this);
-}
-
 namespace {
 
 // Translates a dictionary password to a PasswordForm struct.
diff --git a/chrome/browser/automation/testing_automation_provider.h b/chrome/browser/automation/testing_automation_provider.h
index 7298c1d..df1fadb 100644
--- a/chrome/browser/automation/testing_automation_provider.h
+++ b/chrome/browser/automation/testing_automation_provider.h
@@ -17,7 +17,6 @@
 #include "chrome/browser/automation/automation_provider.h"
 #include "chrome/browser/automation/automation_provider_json.h"
 #include "chrome/browser/history/history_service.h"
-#include "chrome/browser/importer/importer_list_observer.h"
 #include "chrome/browser/ui/browser_list_observer.h"
 #include "content/public/browser/notification_registrar.h"
 #include "content/public/common/page_type.h"
@@ -26,12 +25,11 @@
 #include "third_party/WebKit/public/web/WebInputEvent.h"
 
 #if defined(OS_CHROMEOS)
-// TODO(sque): move to a ChromeOS-specific class. See crosbug.com/22081.
-class PowerManagerClientObserverForTesting;
-#endif  // defined(OS_CHROMEOS)
+#include "chromeos/dbus/power_manager/power_supply_properties.pb.h"
+#include "chromeos/dbus/power_manager_client.h"
+#endif
 
 class CreditCard;
-class ImporterList;
 
 namespace base {
 class DictionaryValue;
@@ -53,7 +51,9 @@
 // This is an automation provider containing testing calls.
 class TestingAutomationProvider : public AutomationProvider,
                                   public chrome::BrowserListObserver,
-                                  public importer::ImporterListObserver,
+#if defined(OS_CHROMEOS)
+                                  public chromeos::PowerManagerClient::Observer,
+#endif
                                   public content::NotificationObserver {
  public:
   explicit TestingAutomationProvider(Profile* profile);
@@ -65,28 +65,22 @@
   virtual void OnChannelError() OVERRIDE;
 
  private:
-  // Storage for ImportSettings() to resume operations after a callback.
-  struct ImportSettingsData {
-    string16 browser_name;
-    int import_items;
-    Browser* browser;
-    IPC::Message* reply_message;
-  };
-
   virtual ~TestingAutomationProvider();
 
   // chrome::BrowserListObserver:
   virtual void OnBrowserAdded(Browser* browser) OVERRIDE;
   virtual void OnBrowserRemoved(Browser* browser) OVERRIDE;
 
-  // importer::ImporterListObserver:
-  virtual void OnSourceProfilesLoaded() OVERRIDE;
-
   // content::NotificationObserver:
   virtual void Observe(int type,
                        const content::NotificationSource& source,
                        const content::NotificationDetails& details) OVERRIDE;
 
+#if defined(OS_CHROMEOS)
+  // chromeos::PowerManagerClient::Observer:
+  virtual void PowerChanged(const power_manager::PowerSupplyProperties& proto);
+#endif
+
   // IPC Message callbacks.
   void CloseBrowser(int handle, IPC::Message* reply_message);
   void ActivateTab(int handle, int at_index, int* status);
@@ -456,12 +450,6 @@
                        base::DictionaryValue* args,
                        IPC::Message* reply_message);
 
-  // Import the given settings from the given browser.
-  // Uses the JSON interface for input/output.
-  void ImportSettings(Browser* browser,
-                      base::DictionaryValue* args,
-                      IPC::Message* reply_message);
-
   // Add a new entry to the password store based on the password information
   // provided. This method can also be used to add a blacklisted site (which
   // will never fill in the password).
@@ -1443,9 +1431,7 @@
   void EnsureTabSelected(Browser* browser, content::WebContents* tab);
 
 #if defined(OS_CHROMEOS)
-  // Avoid scoped ptr here to avoid having to define it completely in the
-  // non-ChromeOS code.
-  PowerManagerClientObserverForTesting* power_manager_observer_;
+  power_manager::PowerSupplyProperties power_supply_properties_;
 #endif  // defined(OS_CHROMEOS)
 
   std::map<std::string, JsonHandler> handler_map_;
@@ -1453,12 +1439,6 @@
 
   content::NotificationRegistrar registrar_;
 
-  // Used to enumerate browser profiles.
-  scoped_refptr<ImporterList> importer_list_;
-
-  // The stored data for the ImportSettings operation.
-  ImportSettingsData import_settings_data_;
-
   // The automation event observer queue. It is lazily created when an observer
   // is added to avoid overhead when not needed.
   scoped_ptr<AutomationEventQueue> automation_event_queue_;
diff --git a/chrome/browser/automation/testing_automation_provider_chromeos.cc b/chrome/browser/automation/testing_automation_provider_chromeos.cc
index f14f594..0406ea6 100644
--- a/chrome/browser/automation/testing_automation_provider_chromeos.cc
+++ b/chrome/browser/automation/testing_automation_provider_chromeos.cc
@@ -12,7 +12,7 @@
 #include "base/prefs/pref_service.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/automation/automation_provider_json.h"
 #include "chrome/browser/automation/automation_provider_observers.h"
 #include "chrome/browser/automation/automation_util.h"
@@ -44,7 +44,6 @@
 #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
 #include "chrome/common/pref_names.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
-#include "chromeos/dbus/power_manager_client.h"
 #include "chromeos/dbus/session_manager_client.h"
 #include "chromeos/dbus/update_engine_client.h"
 #include "chromeos/network/network_state_handler.h"
@@ -156,21 +155,14 @@
   }
 }
 
-// Last reported power status.
-chromeos::PowerSupplyStatus global_power_status;
-
 }  // namespace
 
-class PowerManagerClientObserverForTesting
-    : public chromeos::PowerManagerClient::Observer {
- public:
-  virtual ~PowerManagerClientObserverForTesting() {}
-
-  virtual void PowerChanged(const chromeos::PowerSupplyStatus& status)
-      OVERRIDE {
-    global_power_status = status;
-  }
-};
+#if defined(OS_CHROMEOS)
+void TestingAutomationProvider::PowerChanged(
+    const power_manager::PowerSupplyProperties& proto) {
+  power_supply_properties_ = proto;
+}
+#endif
 
 void TestingAutomationProvider::AcceptOOBENetworkScreen(
     DictionaryValue* args,
@@ -502,20 +494,26 @@
                                                IPC::Message* reply_message) {
   scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
 
-  return_value->SetBoolean("battery_is_present",
-                           global_power_status.battery_is_present);
-  return_value->SetBoolean("line_power_on", global_power_status.line_power_on);
-  if (global_power_status.battery_is_present) {
-    return_value->SetBoolean("battery_fully_charged",
-                             global_power_status.battery_is_full);
+  const bool battery_is_present = power_supply_properties_.battery_state() !=
+      power_manager::PowerSupplyProperties_BatteryState_NOT_PRESENT;
+  const bool line_power_on = power_supply_properties_.external_power() !=
+      power_manager::PowerSupplyProperties_ExternalPower_DISCONNECTED;
+
+  return_value->SetBoolean("battery_is_present", battery_is_present);
+  return_value->SetBoolean("line_power_on", line_power_on);
+
+  if (battery_is_present) {
+    const bool battery_is_full = power_supply_properties_.battery_state() ==
+        power_manager::PowerSupplyProperties_BatteryState_FULL;
+    return_value->SetBoolean("battery_fully_charged", battery_is_full);
     return_value->SetDouble("battery_percentage",
-                            global_power_status.battery_percentage);
-    if (global_power_status.line_power_on) {
-      int64 time = global_power_status.battery_seconds_to_full;
-      if (time > 0 || global_power_status.battery_is_full)
+                            power_supply_properties_.battery_percent());
+    if (line_power_on) {
+      int64 time = power_supply_properties_.battery_time_to_full_sec();
+      if (time > 0 || battery_is_full)
         return_value->SetInteger("battery_seconds_to_full", time);
     } else {
-      int64 time = global_power_status.battery_seconds_to_empty;
+      int64 time = power_supply_properties_.battery_time_to_empty_sec();
       if (time > 0)
         return_value->SetInteger("battery_seconds_to_empty", time);
     }
@@ -1245,14 +1243,11 @@
 }
 
 void TestingAutomationProvider::AddChromeosObservers() {
-  power_manager_observer_ = new PowerManagerClientObserverForTesting;
   chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->
-      AddObserver(power_manager_observer_);
+      AddObserver(this);
 }
 
 void TestingAutomationProvider::RemoveChromeosObservers() {
   chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->
-      RemoveObserver(power_manager_observer_);
-  delete power_manager_observer_;
-  power_manager_observer_ = NULL;
+      RemoveObserver(this);
 }
diff --git a/chrome/browser/automation/url_request_automation_job.cc b/chrome/browser/automation/url_request_automation_job.cc
index bf3ed52..a815718 100644
--- a/chrome/browser/automation/url_request_automation_job.cc
+++ b/chrome/browser/automation/url_request_automation_job.cc
@@ -7,7 +7,7 @@
 #include "base/bind.h"
 #include "base/compiler_specific.h"
 #include "base/message_loop.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/automation/automation_resource_message_filter.h"
 #include "chrome/common/automation_messages.h"
 #include "content/public/browser/browser_thread.h"
diff --git a/chrome/browser/background/background_application_list_model.cc b/chrome/browser/background/background_application_list_model.cc
index f16a3a6..c5d2538 100644
--- a/chrome/browser/background/background_application_list_model.cc
+++ b/chrome/browser/background/background_application_list_model.cc
@@ -43,7 +43,8 @@
 class ExtensionNameComparator {
  public:
   explicit ExtensionNameComparator(icu::Collator* collator);
-  bool operator()(const Extension* x, const Extension* y);
+  bool operator()(const scoped_refptr<const Extension>& x,
+                  const scoped_refptr<const Extension>& y);
 
  private:
   icu::Collator* collator_;
@@ -53,11 +54,11 @@
   : collator_(collator) {
 }
 
-bool ExtensionNameComparator::operator()(const Extension* x,
-                                         const Extension* y) {
+bool ExtensionNameComparator::operator()(
+    const scoped_refptr<const Extension>& x,
+    const scoped_refptr<const Extension>& y) {
   return l10n_util::StringComparator<string16>(collator_)(
-    UTF8ToUTF16(x->name()),
-    UTF8ToUTF16(y->name()));
+      UTF8ToUTF16(x->name()), UTF8ToUTF16(y->name()));
 }
 
 // Background application representation, private to the
diff --git a/chrome/browser/background/background_application_list_model_unittest.cc b/chrome/browser/background/background_application_list_model_unittest.cc
index de09c28..0ae8476 100644
--- a/chrome/browser/background/background_application_list_model_unittest.cc
+++ b/chrome/browser/background/background_application_list_model_unittest.cc
@@ -355,7 +355,7 @@
       new BackgroundApplicationListModel(profile_.get()));
   ASSERT_EQ(0U, model->size());
 
-  static const int kIterations = 500;
+  static const int kIterations = 20;
   ExtensionCollection extensions;
   size_t count = 0;
   size_t expected = 0;
diff --git a/chrome/browser/background/background_contents_service.h b/chrome/browser/background/background_contents_service.h
index 3cddb7d..50057cf 100644
--- a/chrome/browser/background/background_contents_service.h
+++ b/chrome/browser/background/background_contents_service.h
@@ -16,8 +16,8 @@
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
 #include "content/public/common/window_container_type.h"
-#include "googleurl/src/gurl.h"
 #include "ui/base/window_open_disposition.h"
+#include "url/gurl.h"
 
 class CommandLine;
 class PrefService;
diff --git a/chrome/browser/background/background_contents_service_unittest.cc b/chrome/browser/background/background_contents_service_unittest.cc
index 8d7d40a..6d3bb26 100644
--- a/chrome/browser/background/background_contents_service_unittest.cc
+++ b/chrome/browser/background/background_contents_service_unittest.cc
@@ -19,9 +19,9 @@
 #include "chrome/test/base/testing_browser_process.h"
 #include "chrome/test/base/testing_profile.h"
 #include "content/public/browser/notification_service.h"
-#include "googleurl/src/gurl.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/platform_test.h"
+#include "url/gurl.h"
 
 class BackgroundContentsServiceTest : public testing::Test {
  public:
diff --git a/chrome/browser/background/background_mode_manager.cc b/chrome/browser/background/background_mode_manager.cc
index e6a0b96..8bb5d71 100644
--- a/chrome/browser/background/background_mode_manager.cc
+++ b/chrome/browser/background/background_mode_manager.cc
@@ -309,7 +309,12 @@
           // treated as new installs.
           if (extensions::ExtensionSystem::Get(profile)->extension_service()->
                   is_ready()) {
-            OnBackgroundAppInstalled(extension);
+            bool is_being_reloaded = false;
+            CheckReloadStatus(extension, &is_being_reloaded);
+            // No need to show the notification if we showed to the user
+            // previously for this app.
+            if (!is_being_reloaded)
+              OnBackgroundAppInstalled(extension);
           }
         }
       }
@@ -487,7 +492,7 @@
       chrome::ShowAboutChrome(bmd->GetBrowserWindow());
       break;
     case IDC_TASK_MANAGER:
-      chrome::OpenTaskManager(bmd->GetBrowserWindow(), true);
+      chrome::OpenTaskManager(bmd->GetBrowserWindow());
       break;
     case IDC_EXIT:
       content::RecordAction(UserMetricsAction("Exit"));
@@ -623,8 +628,25 @@
   CreateStatusTrayIcon();
 
   // Notify the user that a background app has been installed.
-  if (extension)  // NULL when called by unit tests.
+  if (extension) {  // NULL when called by unit tests.
     DisplayAppInstalledNotification(extension);
+  }
+}
+
+void BackgroundModeManager::CheckReloadStatus(
+    const Extension* extension,
+    bool* is_being_reloaded) {
+    // Walk the BackgroundModeData for all profiles to see if one of their
+    // extensions is being reloaded.
+    for (BackgroundModeInfoMap::const_iterator it =
+             background_mode_data_.begin();
+         it != background_mode_data_.end();
+         ++it) {
+      Profile* profile = it->first;
+      // If the extension is being reloaded, no need to show a notification.
+      if (profile->GetExtensionService()->IsBeingReloaded(extension->id()))
+        *is_being_reloaded = true;
+    }
 }
 
 void BackgroundModeManager::CreateStatusTrayIcon() {
diff --git a/chrome/browser/background/background_mode_manager.h b/chrome/browser/background/background_mode_manager.h
index 1600cd1..e1c8051 100644
--- a/chrome/browser/background/background_mode_manager.h
+++ b/chrome/browser/background/background_mode_manager.h
@@ -85,6 +85,9 @@
                            ProfileInfoCacheStorage);
   FRIEND_TEST_ALL_PREFIXES(BackgroundModeManagerTest,
                            ProfileInfoCacheObserver);
+  FRIEND_TEST_ALL_PREFIXES(BackgroundAppBrowserTest,
+                           ReloadBackgroundApp);
+
   class BackgroundModeData : public ui::SimpleMenuModel::Delegate {
    public:
     explicit BackgroundModeData(
@@ -183,7 +186,15 @@
   // Invoked when an extension is installed so we can ensure that
   // launch-on-startup is enabled if appropriate. |extension| can be NULL when
   // called from unit tests.
-  void OnBackgroundAppInstalled(const extensions::Extension* extension);
+  void OnBackgroundAppInstalled(
+      const extensions::Extension* extension);
+
+  // Walk the list of profiles and see if an extension or app is being
+  // currently upgraded or reloaded by any profile.  If so, update the
+  // output variables appropriately.
+  void CheckReloadStatus(
+      const extensions::Extension* extension,
+      bool* is_being_reloaded);
 
   // Called to make sure that our launch-on-startup mode is properly set.
   // (virtual so we can override for tests).
@@ -191,7 +202,8 @@
 
   // Invoked when a background app is installed so we can display a
   // platform-specific notification to the user.
-  void DisplayAppInstalledNotification(const extensions::Extension* extension);
+  virtual void DisplayAppInstalledNotification(
+      const extensions::Extension* extension);
 
   // Invoked to put Chrome in KeepAlive mode - chrome runs in the background
   // and has a status bar icon.
diff --git a/chrome/browser/bookmarks/bookmark_codec.cc b/chrome/browser/bookmarks/bookmark_codec.cc
index c4d0c30..54116bf 100644
--- a/chrome/browser/bookmarks/bookmark_codec.cc
+++ b/chrome/browser/bookmarks/bookmark_codec.cc
@@ -10,9 +10,9 @@
 #include "base/strings/string_util.h"
 #include "base/values.h"
 #include "chrome/browser/bookmarks/bookmark_model.h"
-#include "googleurl/src/gurl.h"
 #include "grit/generated_resources.h"
 #include "ui/base/l10n/l10n_util.h"
+#include "url/gurl.h"
 
 using base::Time;
 
diff --git a/chrome/browser/bookmarks/bookmark_editor.cc b/chrome/browser/bookmarks/bookmark_editor.cc
deleted file mode 100644
index 0cdb1af..0000000
--- a/chrome/browser/bookmarks/bookmark_editor.cc
+++ /dev/null
@@ -1,84 +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/bookmarks/bookmark_editor.h"
-
-#include "grit/generated_resources.h"
-
-BookmarkEditor::EditDetails::EditDetails(Type node_type)
-    : type(node_type), existing_node(NULL), parent_node(NULL), index(-1) {
-}
-
-BookmarkNode::Type BookmarkEditor::EditDetails::GetNodeType() const {
-  BookmarkNode::Type node_type = BookmarkNode::URL;
-  switch (type) {
-    case EXISTING_NODE:
-      node_type = existing_node->type();
-      break;
-    case NEW_URL:
-      node_type = BookmarkNode::URL;
-      break;
-    case NEW_FOLDER:
-      node_type = BookmarkNode::FOLDER;
-      break;
-    default:
-      NOTREACHED();
-  }
-  return node_type;
-}
-
-int BookmarkEditor::EditDetails::GetWindowTitleId() const {
-  int dialog_title = IDS_BOOKMARK_EDITOR_TITLE;
-  switch (type) {
-    case EditDetails::EXISTING_NODE:
-    case EditDetails::NEW_URL:
-      dialog_title = (type == EditDetails::EXISTING_NODE &&
-                      existing_node->type() == BookmarkNode::FOLDER) ?
-          IDS_BOOKMARK_FOLDER_EDITOR_WINDOW_TITLE :
-          IDS_BOOKMARK_EDITOR_TITLE;
-      break;
-    case EditDetails::NEW_FOLDER:
-      dialog_title = urls.empty() ?
-          IDS_BOOKMARK_FOLDER_EDITOR_WINDOW_TITLE_NEW :
-          IDS_BOOKMARK_ALL_TABS_DIALOG_TITLE;
-      break;
-    default:
-      NOTREACHED();
-  }
-  return dialog_title;
-}
-
-BookmarkEditor::EditDetails BookmarkEditor::EditDetails::EditNode(
-    const BookmarkNode* node) {
-  EditDetails details(EXISTING_NODE);
-  details.existing_node = node;
-  if (node)
-    details.parent_node = node->parent();
-  return details;
-}
-
-BookmarkEditor::EditDetails BookmarkEditor::EditDetails::AddNodeInFolder(
-    const BookmarkNode* parent_node,
-    int index,
-    const GURL& url,
-    const string16& title) {
-  EditDetails details(NEW_URL);
-  details.parent_node = parent_node;
-  details.index = index;
-  details.url = url;
-  details.title = title;
-  return details;
-}
-
-BookmarkEditor::EditDetails BookmarkEditor::EditDetails::AddFolder(
-    const BookmarkNode* parent_node,
-    int index) {
-  EditDetails details(NEW_FOLDER);
-  details.parent_node = parent_node;
-  details.index = index;
-  return details;
-}
-
-BookmarkEditor::EditDetails::~EditDetails() {
-}
diff --git a/chrome/browser/bookmarks/bookmark_editor.h b/chrome/browser/bookmarks/bookmark_editor.h
deleted file mode 100644
index b398028..0000000
--- a/chrome/browser/bookmarks/bookmark_editor.h
+++ /dev/null
@@ -1,110 +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_BOOKMARKS_BOOKMARK_EDITOR_H_
-#define CHROME_BROWSER_BOOKMARKS_BOOKMARK_EDITOR_H_
-
-#include <utility>
-#include <vector>
-
-#include "base/strings/string16.h"
-#include "chrome/browser/bookmarks/bookmark_model.h"
-#include "ui/gfx/native_widget_types.h"
-
-class Browser;
-class GURL;
-class Profile;
-
-// Small, cross platform interface that shows the correct platform specific
-// bookmark editor dialog.
-class BookmarkEditor {
- public:
-  // An enumeration of the possible configurations offered.
-  enum Configuration {
-    SHOW_TREE,
-    NO_TREE
-  };
-
-  // Describes what the user is editing.
-  class EditDetails {
-   public:
-    // Returns the type of the existing or new node.
-    BookmarkNode::Type GetNodeType() const;
-
-    // Returns the resource id for the string resource to use on the window
-    // title for this edit operation.
-    int GetWindowTitleId() const;
-
-    // Returns an EditDetails instance for the user editing the given bookmark.
-    static EditDetails EditNode(const BookmarkNode* node);
-
-    // Returns an EditDetails instance for the user adding a bookmark within
-    // a given parent node with a specified index.
-    static EditDetails AddNodeInFolder(const BookmarkNode* parent_node,
-                                       int index,
-                                       const GURL& url,
-                                       const string16& title);
-
-    // Returns an EditDetails instance for the user adding a folder within a
-    // given parent node with a specified index.
-    static EditDetails AddFolder(const BookmarkNode* parent_node,
-                                 int index);
-
-    enum Type {
-      // The user is editing an existing node in the model. The node the user
-      // is editing is set in |existing_node|.
-      EXISTING_NODE,
-
-      // A new bookmark should be created if the user accepts the edit.
-      // |existing_node| is null in this case.
-      NEW_URL,
-
-      // A new folder bookmark should be created if the user accepts the edit.
-      // The contents of the folder should be that of |urls|.
-      // |existing_node| is null in this case.
-      NEW_FOLDER
-    };
-
-    ~EditDetails();
-
-    // See description of enum value for details.
-    const Type type;
-
-    // If type == EXISTING_NODE this gives the existing node.
-    const BookmarkNode* existing_node;
-
-    // If type == NEW_URL or type == NEW_FOLDER this gives the parent node
-    // to place the new node in.
-    const BookmarkNode* parent_node;
-
-    // If type == NEW_URL or type == NEW_FOLDER this gives the index to insert
-    // the new node at.
-    int index;
-
-    // If type == NEW_URL this gives the URL/title.
-    GURL url;
-    string16 title;
-
-    // If type == NEW_FOLDER, this is the urls/title pairs to add to the
-    // folder.
-    std::vector<std::pair<GURL, string16> > urls;
-
-   private:
-    explicit EditDetails(Type node_type);
-  };
-
-  // Shows the bookmark editor. If --use-more-webui is enabled use the bookmark
-  // manager to add or edit bookmarks. The bookmark editor allows editing an
-  // existing node or creating a new bookmark node (as determined by
-  // |details.type|). If |configuration| is SHOW_TREE, a tree is shown allowing
-  // the user to choose the parent of the node.
-  // |parent| gives the initial parent to select in the tree for the node.
-  // |parent| is only used if |details.existing_node| is null.
-  static void Show(gfx::NativeWindow parent_window,
-                   Profile* profile,
-                   const EditDetails& details,
-                   Configuration configuration);
-};
-
-#endif  // CHROME_BROWSER_BOOKMARKS_BOOKMARK_EDITOR_H_
diff --git a/chrome/browser/bookmarks/bookmark_expanded_state_tracker_unittest.cc b/chrome/browser/bookmarks/bookmark_expanded_state_tracker_unittest.cc
index 17ac4a1..4957290 100644
--- a/chrome/browser/bookmarks/bookmark_expanded_state_tracker_unittest.cc
+++ b/chrome/browser/bookmarks/bookmark_expanded_state_tracker_unittest.cc
@@ -9,11 +9,9 @@
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
 #include "chrome/test/base/testing_profile.h"
 #include "chrome/test/base/ui_test_utils.h"
-#include "content/public/test/test_browser_thread.h"
+#include "content/public/test/test_browser_thread_bundle.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-using content::BrowserThread;
-
 class BookmarkExpandedStateTrackerTest : public testing::Test {
  public:
   BookmarkExpandedStateTrackerTest();
@@ -26,17 +24,12 @@
 
  private:
   scoped_ptr<TestingProfile> profile_;
-  base::MessageLoopForUI message_loop_;
-  content::TestBrowserThread ui_thread_;
-  content::TestBrowserThread file_thread_;
+  content::TestBrowserThreadBundle thread_bundle_;
 
   DISALLOW_COPY_AND_ASSIGN(BookmarkExpandedStateTrackerTest);
 };
 
-BookmarkExpandedStateTrackerTest::BookmarkExpandedStateTrackerTest()
-    : ui_thread_(BrowserThread::UI, &message_loop_),
-      file_thread_(BrowserThread::FILE, &message_loop_) {
-}
+BookmarkExpandedStateTrackerTest::BookmarkExpandedStateTrackerTest() {}
 
 void BookmarkExpandedStateTrackerTest::SetUp() {
   profile_.reset(new TestingProfile);
diff --git a/chrome/browser/bookmarks/bookmark_html_reader.cc b/chrome/browser/bookmarks/bookmark_html_reader.cc
deleted file mode 100644
index 8b2dcca..0000000
--- a/chrome/browser/bookmarks/bookmark_html_reader.cc
+++ /dev/null
@@ -1,432 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/bookmarks/bookmark_html_reader.h"
-
-#include "base/callback.h"
-#include "base/file_util.h"
-#include "base/i18n/icu_string_conversions.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_split.h"
-#include "base/strings/string_util.h"
-#include "base/time.h"
-#include "chrome/browser/bookmarks/imported_bookmark_entry.h"
-#include "chrome/browser/favicon/favicon_util.h"
-#include "chrome/browser/favicon/imported_favicon_usage.h"
-#include "content/public/common/url_constants.h"
-#include "googleurl/src/gurl.h"
-#include "net/base/data_url.h"
-#include "net/base/escape.h"
-
-namespace {
-
-// Fetches the given |attribute| value from the |attribute_list|. Returns true
-// if successful, and |value| will contain the value.
-bool GetAttribute(const std::string& attribute_list,
-                  const std::string& attribute,
-                  std::string* value) {
-  const char kQuote[] = "\"";
-
-  size_t begin = attribute_list.find(attribute + "=" + kQuote);
-  if (begin == std::string::npos)
-    return false;  // Can't find the attribute.
-
-  begin += attribute.size() + 2;
-  size_t end = begin + 1;
-
-  while (end < attribute_list.size()) {
-    if (attribute_list[end] == '"' &&
-        attribute_list[end - 1] != '\\') {
-      break;
-    }
-    end++;
-  }
-
-  if (end == attribute_list.size())
-    return false;  // The value is not quoted.
-
-  *value = attribute_list.substr(begin, end - begin);
-  return true;
-}
-
-// Given the URL of a page and a favicon data URL, adds an appropriate record
-// to the given favicon usage vector.
-void DataURLToFaviconUsage(
-    const GURL& link_url,
-    const GURL& favicon_data,
-    std::vector<ImportedFaviconUsage>* favicons) {
-  if (!link_url.is_valid() || !favicon_data.is_valid() ||
-      !favicon_data.SchemeIs(chrome::kDataScheme))
-    return;
-
-  // Parse the data URL.
-  std::string mime_type, char_set, data;
-  if (!net::DataURL::Parse(favicon_data, &mime_type, &char_set, &data) ||
-      data.empty())
-    return;
-
-  ImportedFaviconUsage usage;
-  if (!FaviconUtil::ReencodeFavicon(
-          reinterpret_cast<const unsigned char*>(&data[0]),
-          data.size(), &usage.png_data))
-    return;  // Unable to decode.
-
-  // We need to make up a URL for the favicon. We use a version of the page's
-  // URL so that we can be sure it will not collide.
-  usage.favicon_url = GURL(std::string("made-up-favicon:") + link_url.spec());
-
-  // We only have one URL per favicon for Firefox 2 bookmarks.
-  usage.urls.insert(link_url);
-
-  favicons->push_back(usage);
-}
-
-}  // namespace
-
-namespace bookmark_html_reader {
-
-void ImportBookmarksFile(
-      const base::Callback<bool(void)>& cancellation_callback,
-      const base::Callback<bool(const GURL&)>& valid_url_callback,
-      const base::FilePath& file_path,
-      std::vector<ImportedBookmarkEntry>* bookmarks,
-      std::vector<ImportedFaviconUsage>* favicons) {
-  std::string content;
-  file_util::ReadFileToString(file_path, &content);
-  std::vector<std::string> lines;
-  base::SplitString(content, '\n', &lines);
-
-  base::string16 last_folder;
-  bool last_folder_on_toolbar = false;
-  bool last_folder_is_empty = true;
-  bool has_subfolder = false;
-  base::Time last_folder_add_date;
-  std::vector<base::string16> path;
-  size_t toolbar_folder_index = 0;
-  std::string charset;
-  for (size_t i = 0;
-       i < lines.size() &&
-           (cancellation_callback.is_null() || !cancellation_callback.Run());
-       ++i) {
-    std::string line;
-    TrimString(lines[i], " ", &line);
-
-    // Get the encoding of the bookmark file.
-    if (internal::ParseCharsetFromLine(line, &charset))
-      continue;
-
-    // Get the folder name.
-    if (internal::ParseFolderNameFromLine(line,
-                                          charset,
-                                          &last_folder,
-                                          &last_folder_on_toolbar,
-                                          &last_folder_add_date)) {
-      continue;
-    }
-
-    // Get the bookmark entry.
-    base::string16 title;
-    base::string16 shortcut;
-    GURL url, favicon;
-    base::Time add_date;
-    base::string16 post_data;
-    bool is_bookmark;
-    // TODO(jcampan): http://b/issue?id=1196285 we do not support POST based
-    //                keywords yet.
-    is_bookmark =
-        internal::ParseBookmarkFromLine(line, charset, &title,
-                                        &url, &favicon, &shortcut,
-                                        &add_date, &post_data) ||
-        internal::ParseMinimumBookmarkFromLine(line, charset, &title, &url);
-
-    if (is_bookmark)
-      last_folder_is_empty = false;
-
-    if (is_bookmark &&
-        post_data.empty() &&
-        (valid_url_callback.is_null() || valid_url_callback.Run(url))) {
-      if (toolbar_folder_index > path.size() && !path.empty()) {
-        NOTREACHED();  // error in parsing.
-        break;
-      }
-
-      ImportedBookmarkEntry entry;
-      entry.creation_time = add_date;
-      entry.url = url;
-      entry.title = title;
-
-      if (toolbar_folder_index) {
-        // The toolbar folder should be at the top level.
-        entry.in_toolbar = true;
-        entry.path.assign(path.begin() + toolbar_folder_index - 1, path.end());
-      } else {
-        // Add this bookmark to the list of |bookmarks|.
-        if (!has_subfolder && !last_folder.empty()) {
-          path.push_back(last_folder);
-          last_folder.clear();
-        }
-        entry.path.assign(path.begin(), path.end());
-      }
-      bookmarks->push_back(entry);
-
-      // Save the favicon. DataURLToFaviconUsage will handle the case where
-      // there is no favicon.
-      if (favicons)
-        DataURLToFaviconUsage(url, favicon, favicons);
-
-      continue;
-    }
-
-    // Bookmarks in sub-folder are encapsulated with <DL> tag.
-    if (StartsWithASCII(line, "<DL>", false)) {
-      has_subfolder = true;
-      if (!last_folder.empty()) {
-        path.push_back(last_folder);
-        last_folder.clear();
-      }
-      if (last_folder_on_toolbar && !toolbar_folder_index)
-        toolbar_folder_index = path.size();
-
-      // Mark next folder empty as initial state.
-      last_folder_is_empty = true;
-    } else if (StartsWithASCII(line, "</DL>", false)) {
-      if (path.empty())
-        break;  // Mismatch <DL>.
-
-      base::string16 folder_title = path.back();
-      path.pop_back();
-
-      if (last_folder_is_empty) {
-        // Empty folder should be added explicitly.
-        ImportedBookmarkEntry entry;
-        entry.is_folder = true;
-        entry.creation_time = last_folder_add_date;
-        entry.title = folder_title;
-        if (toolbar_folder_index) {
-          // The toolbar folder should be at the top level.
-          // Make sure we don't add the toolbar folder itself if it is empty.
-          if (toolbar_folder_index <= path.size()) {
-            entry.in_toolbar = true;
-            entry.path.assign(path.begin() + toolbar_folder_index - 1,
-                              path.end());
-            bookmarks->push_back(entry);
-          }
-        } else {
-          // Add this folder to the list of |bookmarks|.
-          entry.path.assign(path.begin(), path.end());
-          bookmarks->push_back(entry);
-        }
-
-        // Parent folder include current one, so it's not empty.
-        last_folder_is_empty = false;
-      }
-
-      if (toolbar_folder_index > path.size())
-        toolbar_folder_index = 0;
-    }
-  }
-}
-
-namespace internal {
-
-bool ParseCharsetFromLine(const std::string& line, std::string* charset) {
-  const char kCharset[] = "charset=";
-  if (StartsWithASCII(line, "<META", false) &&
-      (line.find("CONTENT=\"") != std::string::npos ||
-          line.find("content=\"") != std::string::npos)) {
-    size_t begin = line.find(kCharset);
-    if (begin == std::string::npos)
-      return false;
-    begin += std::string(kCharset).size();
-    size_t end = line.find_first_of('\"', begin);
-    *charset = line.substr(begin, end - begin);
-    return true;
-  }
-  return false;
-}
-
-bool ParseFolderNameFromLine(const std::string& line,
-                             const std::string& charset,
-                             base::string16* folder_name,
-                             bool* is_toolbar_folder,
-                             base::Time* add_date) {
-  const char kFolderOpen[] = "<DT><H3";
-  const char kFolderClose[] = "</H3>";
-  const char kToolbarFolderAttribute[] = "PERSONAL_TOOLBAR_FOLDER";
-  const char kAddDateAttribute[] = "ADD_DATE";
-
-  if (!StartsWithASCII(line, kFolderOpen, true))
-    return false;
-
-  size_t end = line.find(kFolderClose);
-  size_t tag_end = line.rfind('>', end) + 1;
-  // If no end tag or start tag is broken, we skip to find the folder name.
-  if (end == std::string::npos || tag_end < arraysize(kFolderOpen))
-    return false;
-
-  base::CodepageToUTF16(line.substr(tag_end, end - tag_end), charset.c_str(),
-                        base::OnStringConversionError::SKIP, folder_name);
-  *folder_name = net::UnescapeForHTML(*folder_name);
-
-  std::string attribute_list = line.substr(arraysize(kFolderOpen),
-      tag_end - arraysize(kFolderOpen) - 1);
-  std::string value;
-
-  // Add date
-  if (GetAttribute(attribute_list, kAddDateAttribute, &value)) {
-    int64 time;
-    base::StringToInt64(value, &time);
-    // Upper bound it at 32 bits.
-    if (0 < time && time < (1LL << 32))
-      *add_date = base::Time::FromTimeT(time);
-  }
-
-  if (GetAttribute(attribute_list, kToolbarFolderAttribute, &value) &&
-      LowerCaseEqualsASCII(value, "true"))
-    *is_toolbar_folder = true;
-  else
-    *is_toolbar_folder = false;
-
-  return true;
-}
-
-bool ParseBookmarkFromLine(const std::string& line,
-                           const std::string& charset,
-                           base::string16* title,
-                           GURL* url,
-                           GURL* favicon,
-                           base::string16* shortcut,
-                           base::Time* add_date,
-                           base::string16* post_data) {
-  const char kItemOpen[] = "<DT><A";
-  const char kItemClose[] = "</A>";
-  const char kFeedURLAttribute[] = "FEEDURL";
-  const char kHrefAttribute[] = "HREF";
-  const char kIconAttribute[] = "ICON";
-  const char kShortcutURLAttribute[] = "SHORTCUTURL";
-  const char kAddDateAttribute[] = "ADD_DATE";
-  const char kPostDataAttribute[] = "POST_DATA";
-
-  title->clear();
-  *url = GURL();
-  *favicon = GURL();
-  shortcut->clear();
-  post_data->clear();
-  *add_date = base::Time();
-
-  if (!StartsWithASCII(line, kItemOpen, true))
-    return false;
-
-  size_t end = line.find(kItemClose);
-  size_t tag_end = line.rfind('>', end) + 1;
-  if (end == std::string::npos || tag_end < arraysize(kItemOpen))
-    return false;  // No end tag or start tag is broken.
-
-  std::string attribute_list = line.substr(arraysize(kItemOpen),
-      tag_end - arraysize(kItemOpen) - 1);
-
-  // We don't import Live Bookmark folders, which is Firefox's RSS reading
-  // feature, since the user never necessarily bookmarked them and we don't
-  // have this feature to update their contents.
-  std::string value;
-  if (GetAttribute(attribute_list, kFeedURLAttribute, &value))
-    return false;
-
-  // Title
-  base::CodepageToUTF16(line.substr(tag_end, end - tag_end), charset.c_str(),
-                        base::OnStringConversionError::SKIP, title);
-  *title = net::UnescapeForHTML(*title);
-
-  // URL
-  if (GetAttribute(attribute_list, kHrefAttribute, &value)) {
-    base::string16 url16;
-    base::CodepageToUTF16(value, charset.c_str(),
-                          base::OnStringConversionError::SKIP, &url16);
-    url16 = net::UnescapeForHTML(url16);
-
-    *url = GURL(url16);
-  }
-
-  // Favicon
-  if (GetAttribute(attribute_list, kIconAttribute, &value))
-    *favicon = GURL(value);
-
-  // Keyword
-  if (GetAttribute(attribute_list, kShortcutURLAttribute, &value)) {
-    base::CodepageToUTF16(value, charset.c_str(),
-                          base::OnStringConversionError::SKIP, shortcut);
-    *shortcut = net::UnescapeForHTML(*shortcut);
-  }
-
-  // Add date
-  if (GetAttribute(attribute_list, kAddDateAttribute, &value)) {
-    int64 time;
-    base::StringToInt64(value, &time);
-    // Upper bound it at 32 bits.
-    if (0 < time && time < (1LL << 32))
-      *add_date = base::Time::FromTimeT(time);
-  }
-
-  // Post data.
-  if (GetAttribute(attribute_list, kPostDataAttribute, &value)) {
-    base::CodepageToUTF16(value, charset.c_str(),
-                          base::OnStringConversionError::SKIP, post_data);
-    *post_data = net::UnescapeForHTML(*post_data);
-  }
-
-  return true;
-}
-
-bool ParseMinimumBookmarkFromLine(const std::string& line,
-                                  const std::string& charset,
-                                  base::string16* title,
-                                  GURL* url) {
-  const char kItemOpen[] = "<DT><A";
-  const char kItemClose[] = "</";
-  const char kHrefAttributeUpper[] = "HREF";
-  const char kHrefAttributeLower[] = "href";
-
-  title->clear();
-  *url = GURL();
-
-  // Case-insensitive check of open tag.
-  if (!StartsWithASCII(line, kItemOpen, false))
-    return false;
-
-  // Find any close tag.
-  size_t end = line.find(kItemClose);
-  size_t tag_end = line.rfind('>', end) + 1;
-  if (end == std::string::npos || tag_end < arraysize(kItemOpen))
-    return false;  // No end tag or start tag is broken.
-
-  std::string attribute_list = line.substr(arraysize(kItemOpen),
-      tag_end - arraysize(kItemOpen) - 1);
-
-  // Title
-  base::CodepageToUTF16(line.substr(tag_end, end - tag_end), charset.c_str(),
-                        base::OnStringConversionError::SKIP, title);
-  *title = net::UnescapeForHTML(*title);
-
-  // URL
-  std::string value;
-  if (GetAttribute(attribute_list, kHrefAttributeUpper, &value) ||
-      GetAttribute(attribute_list, kHrefAttributeLower, &value)) {
-    if (charset.length() != 0) {
-      base::string16 url16;
-      base::CodepageToUTF16(value, charset.c_str(),
-                            base::OnStringConversionError::SKIP, &url16);
-      url16 = net::UnescapeForHTML(url16);
-
-      *url = GURL(url16);
-    } else {
-      *url = GURL(value);
-    }
-  }
-
-  return true;
-}
-
-}  // namespace internal
-
-}  // namespace bookmark_html_reader
diff --git a/chrome/browser/bookmarks/bookmark_html_reader.h b/chrome/browser/bookmarks/bookmark_html_reader.h
deleted file mode 100644
index 3fec412..0000000
--- a/chrome/browser/bookmarks/bookmark_html_reader.h
+++ /dev/null
@@ -1,97 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_BOOKMARKS_BOOKMARK_HTML_READER_H_
-#define CHROME_BROWSER_BOOKMARKS_BOOKMARK_HTML_READER_H_
-
-#include <string>
-#include <vector>
-
-#include "base/callback_forward.h"
-#include "base/strings/string16.h"
-
-class GURL;
-struct ImportedBookmarkEntry;
-struct ImportedFaviconUsage;
-
-namespace base {
-class FilePath;
-class Time;
-}
-
-namespace bookmark_html_reader {
-
-// Imports the bookmarks from the specified file.
-//
-// |cancellation_callback| is polled to query if the import should be cancelled;
-// if it returns |true| at any time the import will be cancelled. If
-// |cancellation_callback| is a null callback the import will run to completion.
-//
-// |valid_url_callback| is called to determine if a specified URL is valid for
-// import; it returns |true| if it is. If |valid_url_callback| is a null
-// callback, all URLs are considered to be valid.
-//
-// |file_path| is the path of the file on disk to import.
-//
-// |bookmarks| is a pointer to a vector, which is filled with the imported
-// bookmarks. It may not be NULL.
-//
-// |favicons| is a pointer to a vector, which is filled with the favicons of
-// imported bookmarks. It may be NULL, in which case favicons are not imported.
-void ImportBookmarksFile(
-    const base::Callback<bool(void)>& cancellation_callback,
-    const base::Callback<bool(const GURL&)>& valid_url_callback,
-    const base::FilePath& file_path,
-    std::vector<ImportedBookmarkEntry>* bookmarks,
-    std::vector<ImportedFaviconUsage>* favicons);
-
-namespace internal {
-
-// The file format that BookmarkHTMLReader parses starts with a heading
-// tag, which contains its title. All bookmarks and sub-folders follow,
-// bracketed by a <DL> tag:
-//   <DT><H3 PERSONAL_TOOLBAR_FOLDER="true" ...>title</H3>
-//   <DL><p>
-//      ... container ...
-//   </DL><p>
-// And a bookmark is presented by a <A> tag:
-//   <DT><A HREF="url" SHORTCUTURL="shortcut" ADD_DATE="11213014"...>name</A>
-// Reference: http://kb.mozillazine.org/Bookmarks.html
-
-bool ParseCharsetFromLine(const std::string& line,
-                          std::string* charset);
-bool ParseFolderNameFromLine(const std::string& line,
-                             const std::string& charset,
-                             base::string16* folder_name,
-                             bool* is_toolbar_folder,
-                             base::Time* add_date);
-// See above, this will also put the data: URL of the favicon into |*favicon|
-// if there is a favicon given. |post_data| is set for POST base keywords to
-// the contents of the actual POST (with %s for the search term).
-bool ParseBookmarkFromLine(const std::string& line,
-                           const std::string& charset,
-                           base::string16* title,
-                           GURL* url,
-                           GURL* favicon,
-                           base::string16* shortcut,
-                           base::Time* add_date,
-                           base::string16* post_data);
-// Save bookmarks imported from browsers with Firefox 2 compatible bookmark
-// systems such as Epiphany. This bookmark format is the same as that of the
-// basic Firefox 2 bookmark, but it misses additional properties and uses
-// lower-case tag:
-//   ...<h1>Bookmarks</h1><dl>
-//   <dt><a href="url">name</a></dt>
-//   <dt><a href="url">name</a></dt>
-//   </dl>
-bool ParseMinimumBookmarkFromLine(const std::string& line,
-                                  const std::string& charset,
-                                  base::string16* title,
-                                  GURL* url);
-
-}  // namespace internal
-
-}  // namespace bookmark_html_reader
-
-#endif  // CHROME_BROWSER_BOOKMARKS_BOOKMARK_HTML_READER_H_
diff --git a/chrome/browser/bookmarks/bookmark_html_reader_unittest.cc b/chrome/browser/bookmarks/bookmark_html_reader_unittest.cc
deleted file mode 100644
index 5d5462a..0000000
--- a/chrome/browser/bookmarks/bookmark_html_reader_unittest.cc
+++ /dev/null
@@ -1,275 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/bookmarks/bookmark_html_reader.h"
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/callback.h"
-#include "base/files/file_path.h"
-#include "base/path_service.h"
-#include "base/strings/string16.h"
-#include "base/strings/string_util.h"
-#include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/bookmarks/imported_bookmark_entry.h"
-#include "chrome/common/chrome_paths.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace bookmark_html_reader {
-
-TEST(BookmarkHTMLReaderTest, ParseTests) {
-  bool result;
-
-  // Tests charset.
-  std::string charset;
-  result = internal::ParseCharsetFromLine(
-      "<META HTTP-EQUIV=\"Content-Type\" "
-      "CONTENT=\"text/html; charset=UTF-8\">",
-      &charset);
-  EXPECT_TRUE(result);
-  EXPECT_EQ("UTF-8", charset);
-
-  // Escaped characters in name.
-  base::string16 folder_name;
-  bool is_toolbar_folder;
-  base::Time folder_add_date;
-  result = internal::ParseFolderNameFromLine(
-      "<DT><H3 ADD_DATE=\"1207558707\" >&lt; &gt;"
-      " &amp; &quot; &#39; \\ /</H3>",
-      charset, &folder_name, &is_toolbar_folder, &folder_add_date);
-  EXPECT_TRUE(result);
-  EXPECT_EQ(ASCIIToUTF16("< > & \" ' \\ /"), folder_name);
-  EXPECT_FALSE(is_toolbar_folder);
-  EXPECT_TRUE(base::Time::FromTimeT(1207558707) == folder_add_date);
-
-  // Empty name and toolbar folder attribute.
-  result = internal::ParseFolderNameFromLine(
-      "<DT><H3 PERSONAL_TOOLBAR_FOLDER=\"true\"></H3>",
-      charset, &folder_name, &is_toolbar_folder, &folder_add_date);
-  EXPECT_TRUE(result);
-  EXPECT_EQ(base::string16(), folder_name);
-  EXPECT_TRUE(is_toolbar_folder);
-
-  // Unicode characters in title and shortcut.
-  base::string16 title;
-  GURL url, favicon;
-  base::string16 shortcut;
-  base::string16 post_data;
-  base::Time add_date;
-  result = internal::ParseBookmarkFromLine(
-      "<DT><A HREF=\"http://chinese.site.cn/path?query=1#ref\" "
-      "SHORTCUTURL=\"\xE4\xB8\xAD\">\xE4\xB8\xAD\xE6\x96\x87</A>",
-      charset, &title, &url, &favicon, &shortcut, &add_date, &post_data);
-  EXPECT_TRUE(result);
-  EXPECT_EQ(L"\x4E2D\x6587", UTF16ToWide(title));
-  EXPECT_EQ("http://chinese.site.cn/path?query=1#ref", url.spec());
-  EXPECT_EQ(L"\x4E2D", UTF16ToWide(shortcut));
-  EXPECT_EQ(base::string16(), post_data);
-  EXPECT_TRUE(base::Time() == add_date);
-
-  // No shortcut, and url contains %22 ('"' character).
-  result = internal::ParseBookmarkFromLine(
-      "<DT><A HREF=\"http://domain.com/?q=%22<>%22\">name</A>",
-      charset, &title, &url, &favicon, &shortcut, &add_date, &post_data);
-  EXPECT_TRUE(result);
-  EXPECT_EQ(ASCIIToUTF16("name"), title);
-  EXPECT_EQ("http://domain.com/?q=%22%3C%3E%22", url.spec());
-  EXPECT_EQ(base::string16(), shortcut);
-  EXPECT_EQ(base::string16(), post_data);
-  EXPECT_TRUE(base::Time() == add_date);
-
-  result = internal::ParseBookmarkFromLine(
-      "<DT><A HREF=\"http://domain.com/?g=&quot;\"\">name</A>",
-      charset, &title, &url, &favicon, &shortcut, &add_date, &post_data);
-  EXPECT_TRUE(result);
-  EXPECT_EQ(ASCIIToUTF16("name"), title);
-  EXPECT_EQ("http://domain.com/?g=%22", url.spec());
-  EXPECT_EQ(base::string16(), shortcut);
-  EXPECT_EQ(base::string16(), post_data);
-  EXPECT_TRUE(base::Time() == add_date);
-
-  // Creation date.
-  result = internal::ParseBookmarkFromLine(
-      "<DT><A HREF=\"http://site/\" ADD_DATE=\"1121301154\">name</A>",
-      charset, &title, &url, &favicon, &shortcut, &add_date, &post_data);
-  EXPECT_TRUE(result);
-  EXPECT_EQ(ASCIIToUTF16("name"), title);
-  EXPECT_EQ(GURL("http://site/"), url);
-  EXPECT_EQ(base::string16(), shortcut);
-  EXPECT_EQ(base::string16(), post_data);
-  EXPECT_TRUE(base::Time::FromTimeT(1121301154) == add_date);
-
-  // Post-data
-  result = internal::ParseBookmarkFromLine(
-      "<DT><A HREF=\"http://localhost:8080/test/hello.html\" ADD_DATE=\""
-      "1212447159\" LAST_VISIT=\"1212447251\" LAST_MODIFIED=\"1212447248\""
-      "SHORTCUTURL=\"post\" ICON=\"data:\" POST_DATA=\"lname%3D%25s\""
-      "LAST_CHARSET=\"UTF-8\" ID=\"rdf:#$weKaR3\">Test Post keyword</A>",
-      charset, &title, &url, &favicon, &shortcut, &add_date, &post_data);
-  EXPECT_TRUE(result);
-  EXPECT_EQ(ASCIIToUTF16("Test Post keyword"), title);
-  EXPECT_EQ("http://localhost:8080/test/hello.html", url.spec());
-  EXPECT_EQ(ASCIIToUTF16("post"), shortcut);
-  EXPECT_EQ(ASCIIToUTF16("lname%3D%25s"), post_data);
-  EXPECT_TRUE(base::Time::FromTimeT(1212447159) == add_date);
-
-  // Invalid case.
-  result = internal::ParseBookmarkFromLine(
-      "<DT><A HREF=\"http://domain.com/?q=%22",
-      charset, &title, &url, &favicon, &shortcut, &add_date, &post_data);
-  EXPECT_FALSE(result);
-  EXPECT_EQ(base::string16(), title);
-  EXPECT_EQ("", url.spec());
-  EXPECT_EQ(base::string16(), shortcut);
-  EXPECT_EQ(base::string16(), post_data);
-  EXPECT_TRUE(base::Time() == add_date);
-
-  // Epiphany format.
-  result = internal::ParseMinimumBookmarkFromLine(
-      "<dt><a href=\"http://www.google.com/\">Google</a></dt>",
-      charset, &title, &url);
-  EXPECT_TRUE(result);
-  EXPECT_EQ(ASCIIToUTF16("Google"), title);
-  EXPECT_EQ("http://www.google.com/", url.spec());
-}
-
-namespace {
-
-void ExpectFirstFirefox2Bookmark(const ImportedBookmarkEntry& entry) {
-  EXPECT_EQ(ASCIIToUTF16("Empty"), entry.title);
-  EXPECT_TRUE(entry.is_folder);
-  EXPECT_EQ(base::Time::FromTimeT(1295938143), entry.creation_time);
-  EXPECT_EQ(1U, entry.path.size());
-  if (entry.path.size() == 1)
-    EXPECT_EQ(ASCIIToUTF16("Empty's Parent"), entry.path.front());
-}
-
-void ExpectSecondFirefox2Bookmark(const ImportedBookmarkEntry& entry) {
-  EXPECT_EQ(ASCIIToUTF16("[Tamura Yukari.com]"), entry.title);
-  EXPECT_FALSE(entry.is_folder);
-  EXPECT_EQ(base::Time::FromTimeT(1234567890), entry.creation_time);
-  EXPECT_EQ(1U, entry.path.size());
-  if (entry.path.size() == 1)
-    EXPECT_EQ(ASCIIToUTF16("Not Empty"), entry.path.front());
-  EXPECT_EQ("http://www.tamurayukari.com/", entry.url.spec());
-}
-
-void ExpectThirdFirefox2Bookmark(const ImportedBookmarkEntry& entry) {
-  EXPECT_EQ(ASCIIToUTF16("Google"), entry.title);
-  EXPECT_FALSE(entry.is_folder);
-  EXPECT_EQ(base::Time::FromTimeT(0000000000), entry.creation_time);
-  EXPECT_EQ(1U, entry.path.size());
-  if (entry.path.size() == 1)
-    EXPECT_EQ(ASCIIToUTF16("Not Empty But Default"), entry.path.front());
-  EXPECT_EQ("http://www.google.com/", entry.url.spec());
-}
-
-void ExpectFirstEpiphanyBookmark(const ImportedBookmarkEntry& entry) {
-  EXPECT_EQ(ASCIIToUTF16("[Tamura Yukari.com]"), entry.title);
-  EXPECT_EQ("http://www.tamurayukari.com/", entry.url.spec());
-  EXPECT_EQ(0U, entry.path.size());
-}
-
-void ExpectSecondEpiphanyBookmark(const ImportedBookmarkEntry& entry) {
-  EXPECT_EQ(ASCIIToUTF16("Google"), entry.title);
-  EXPECT_EQ("http://www.google.com/", entry.url.spec());
-  EXPECT_EQ(0U, entry.path.size());
-}
-
-}  // namespace
-
-TEST(BookmarkHTMLReaderTest, Firefox2BookmarkFileImport) {
-  base::FilePath path;
-  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &path));
-  path = path.AppendASCII("bookmark_html_reader");
-  path = path.AppendASCII("firefox2.html");
-
-  std::vector<ImportedBookmarkEntry> bookmarks;
-  ImportBookmarksFile(base::Callback<bool(void)>(),
-                      base::Callback<bool(const GURL&)>(),
-                      path, &bookmarks, NULL);
-
-  ASSERT_EQ(3U, bookmarks.size());
-  ExpectFirstFirefox2Bookmark(bookmarks[0]);
-  ExpectSecondFirefox2Bookmark(bookmarks[1]);
-  ExpectThirdFirefox2Bookmark(bookmarks[2]);
-}
-
-TEST(BookmarkHTMLReaderTest, EpiphanyBookmarkFileImport) {
-  base::FilePath path;
-  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &path));
-  path = path.AppendASCII("bookmark_html_reader");
-  path = path.AppendASCII("epiphany.html");
-
-  std::vector<ImportedBookmarkEntry> bookmarks;
-  ImportBookmarksFile(base::Callback<bool(void)>(),
-                      base::Callback<bool(const GURL&)>(),
-                      path, &bookmarks, NULL);
-
-  ASSERT_EQ(2U, bookmarks.size());
-  ExpectFirstEpiphanyBookmark(bookmarks[0]);
-  ExpectSecondEpiphanyBookmark(bookmarks[1]);
-}
-
-namespace {
-
-class CancelAfterFifteenCalls {
-  int count;
- public:
-  CancelAfterFifteenCalls() : count(0) { }
-  bool ShouldCancel() {
-    return ++count > 16;
-  }
-};
-
-}  // namespace
-
-TEST(BookmarkHTMLReaderTest, CancellationCallback) {
-  base::FilePath path;
-  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &path));
-  path = path.AppendASCII("bookmark_html_reader");
-  // Use a file for testing that has multiple bookmarks.
-  path = path.AppendASCII("firefox2.html");
-
-  std::vector<ImportedBookmarkEntry> bookmarks;
-  CancelAfterFifteenCalls cancel_fifteen;
-  ImportBookmarksFile(base::Bind(&CancelAfterFifteenCalls::ShouldCancel,
-                                 base::Unretained(&cancel_fifteen)),
-                      base::Callback<bool(const GURL&)>(),
-                      path, &bookmarks, NULL);
-
-  // The cancellation callback is checked before each line is read, so fifteen
-  // lines are imported. The first fifteen lines of firefox2.html include only
-  // one bookmark.
-  ASSERT_EQ(1U, bookmarks.size());
-  ExpectFirstFirefox2Bookmark(bookmarks[0]);
-}
-
-namespace {
-
-bool IsURLValid(const GURL& url) {
-  // No offense to whomever owns this domain...
-  return !url.DomainIs("tamurayukari.com");
-}
-
-}  // namespace
-
-TEST(BookmarkHTMLReaderTest, ValidURLCallback) {
-  base::FilePath path;
-  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &path));
-  path = path.AppendASCII("bookmark_html_reader");
-  // Use a file for testing that has multiple bookmarks.
-  path = path.AppendASCII("firefox2.html");
-
-  std::vector<ImportedBookmarkEntry> bookmarks;
-  ImportBookmarksFile(base::Callback<bool(void)>(),
-                      base::Bind(&IsURLValid),
-                      path, &bookmarks, NULL);
-
-  ASSERT_EQ(2U, bookmarks.size());
-  ExpectFirstFirefox2Bookmark(bookmarks[0]);
-  ExpectThirdFirefox2Bookmark(bookmarks[1]);
-}
-
-}  // namespace bookmark_html_reader
diff --git a/chrome/browser/bookmarks/bookmark_html_writer.cc b/chrome/browser/bookmarks/bookmark_html_writer.cc
index 620628a..47eee0a 100644
--- a/chrome/browser/bookmarks/bookmark_html_writer.cc
+++ b/chrome/browser/bookmarks/bookmark_html_writer.cc
@@ -12,7 +12,7 @@
 #include "base/message_loop.h"
 #include "base/platform_file.h"
 #include "base/strings/string_number_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "base/values.h"
 #include "chrome/browser/bookmarks/bookmark_codec.h"
 #include "chrome/browser/bookmarks/bookmark_model.h"
diff --git a/chrome/browser/bookmarks/bookmark_html_writer_unittest.cc b/chrome/browser/bookmarks/bookmark_html_writer_unittest.cc
deleted file mode 100644
index e735369..0000000
--- a/chrome/browser/bookmarks/bookmark_html_writer_unittest.cc
+++ /dev/null
@@ -1,285 +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/bookmarks/bookmark_html_writer.h"
-
-#include "base/files/scoped_temp_dir.h"
-#include "base/i18n/time_formatting.h"
-#include "base/message_loop.h"
-#include "base/path_service.h"
-#include "base/strings/string16.h"
-#include "base/strings/string_util.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
-#include "chrome/browser/bookmarks/bookmark_html_reader.h"
-#include "chrome/browser/bookmarks/bookmark_model.h"
-#include "chrome/browser/bookmarks/bookmark_model_factory.h"
-#include "chrome/browser/bookmarks/imported_bookmark_entry.h"
-#include "chrome/browser/favicon/favicon_service.h"
-#include "chrome/browser/favicon/favicon_service_factory.h"
-#include "chrome/browser/favicon/imported_favicon_usage.h"
-#include "chrome/browser/history/history_service.h"
-#include "chrome/browser/history/history_service_factory.h"
-#include "chrome/test/base/testing_profile.h"
-#include "chrome/test/base/ui_test_utils.h"
-#include "content/public/test/test_browser_thread.h"
-#include "grit/generated_resources.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "ui/gfx/codec/png_codec.h"
-
-using content::BrowserThread;
-
-namespace {
-
-const int kIconWidth = 16;
-const int kIconHeight = 16;
-
-void MakeTestSkBitmap(int w, int h, SkBitmap* bmp) {
-  bmp->setConfig(SkBitmap::kARGB_8888_Config, w, h);
-  bmp->allocPixels();
-
-  uint32_t* src_data = bmp->getAddr32(0, 0);
-  for (int i = 0; i < w * h; i++) {
-    src_data[i] = SkPreMultiplyARGB(i % 255, i % 250, i % 245, i % 240);
-  }
-}
-
-}  // namespace
-
-class BookmarkHTMLWriterTest : public testing::Test {
- protected:
-  virtual void SetUp() {
-    testing::Test::SetUp();
-    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
-    path_ = temp_dir_.path().AppendASCII("bookmarks.html");
-  }
-
-  // Converts an ImportedBookmarkEntry to a string suitable for assertion
-  // testing.
-  string16 BookmarkEntryToString(const ImportedBookmarkEntry& entry) {
-    string16 result;
-    result.append(ASCIIToUTF16("on_toolbar="));
-    if (entry.in_toolbar)
-      result.append(ASCIIToUTF16("true"));
-    else
-      result.append(ASCIIToUTF16("false"));
-
-    result.append(ASCIIToUTF16(" url=") + UTF8ToUTF16(entry.url.spec()));
-
-    result.append(ASCIIToUTF16(" path="));
-    for (size_t i = 0; i < entry.path.size(); ++i) {
-      if (i != 0)
-        result.append(ASCIIToUTF16("/"));
-      result.append(entry.path[i]);
-    }
-
-    result.append(ASCIIToUTF16(" title="));
-    result.append(entry.title);
-
-    result.append(ASCIIToUTF16(" time="));
-    result.append(base::TimeFormatFriendlyDateAndTime(entry.creation_time));
-    return result;
-  }
-
-  // Creates a set of bookmark values to a string for assertion testing.
-  string16 BookmarkValuesToString(bool on_toolbar,
-                                  const GURL& url,
-                                  const string16& title,
-                                  base::Time creation_time,
-                                  const string16& f1,
-                                  const string16& f2,
-                                  const string16& f3) {
-    ImportedBookmarkEntry entry;
-    entry.in_toolbar = on_toolbar;
-    entry.url = url;
-    if (!f1.empty()) {
-      entry.path.push_back(f1);
-      if (!f2.empty()) {
-        entry.path.push_back(f2);
-        if (!f3.empty())
-          entry.path.push_back(f3);
-      }
-    }
-    entry.title = title;
-    entry.creation_time = creation_time;
-    return BookmarkEntryToString(entry);
-  }
-
-  void AssertBookmarkEntryEquals(const ImportedBookmarkEntry& entry,
-                                 bool on_toolbar,
-                                 const GURL& url,
-                                 const string16& title,
-                                 base::Time creation_time,
-                                 const string16& f1,
-                                 const string16& f2,
-                                 const string16& f3) {
-    EXPECT_EQ(BookmarkValuesToString(on_toolbar, url, title, creation_time,
-                                     f1, f2, f3),
-              BookmarkEntryToString(entry));
-  }
-
-  base::ScopedTempDir temp_dir_;
-  base::FilePath path_;
-};
-
-// Class that will notify message loop when file is written.
-class BookmarksObserver : public BookmarksExportObserver {
- public:
-  explicit BookmarksObserver(base::MessageLoop* loop) : loop_(loop) {
-    DCHECK(loop);
-  }
-
-  virtual void OnExportFinished() OVERRIDE {
-    loop_->Quit();
-  }
-
- private:
-  base::MessageLoop* loop_;
-  DISALLOW_COPY_AND_ASSIGN(BookmarksObserver);
-};
-
-// Tests bookmark_html_writer by populating a BookmarkModel, writing it out by
-// way of bookmark_html_writer, then using the importer to read it back in.
-TEST_F(BookmarkHTMLWriterTest, Test) {
-  base::MessageLoop message_loop;
-  content::TestBrowserThread fake_ui_thread(BrowserThread::UI, &message_loop);
-  content::TestBrowserThread fake_file_thread(BrowserThread::FILE,
-                                              &message_loop);
-
-  TestingProfile profile;
-  profile.CreateHistoryService(true, false);
-  profile.BlockUntilHistoryProcessesPendingRequests();
-  profile.CreateFaviconService();
-  profile.CreateBookmarkModel(true);
-
-  BookmarkModel* model = BookmarkModelFactory::GetForProfile(&profile);
-  ui_test_utils::WaitForBookmarkModelToLoad(model);
-
-  // Create test PNG representing favicon for url1.
-  SkBitmap bitmap;
-  MakeTestSkBitmap(kIconWidth, kIconHeight, &bitmap);
-  std::vector<unsigned char> icon_data;
-  gfx::PNGCodec::EncodeBGRASkBitmap(bitmap, false, &icon_data);
-
-  // Populate the BookmarkModel. This creates the following bookmark structure:
-  // Bookmarks bar
-  //   F1
-  //     url1
-  //     F2
-  //       url2
-  //   url3
-  //   url4
-  // Other
-  //   url1
-  //   url2
-  //   F3
-  //     F4
-  //       url1
-  // Mobile
-  //   url1
-  //   <bookmark without a title.>
-  string16 f1_title = ASCIIToUTF16("F\"&;<1\"");
-  string16 f2_title = ASCIIToUTF16("F2");
-  string16 f3_title = ASCIIToUTF16("F 3");
-  string16 f4_title = ASCIIToUTF16("F4");
-  string16 url1_title = ASCIIToUTF16("url 1");
-  string16 url2_title = ASCIIToUTF16("url&2");
-  string16 url3_title = ASCIIToUTF16("url\"3");
-  string16 url4_title = ASCIIToUTF16("url\"&;");
-  string16 unnamed_bookmark_title = ASCIIToUTF16("");
-  GURL url1("http://url1");
-  GURL url1_favicon("http://url1/icon.ico");
-  GURL url2("http://url2");
-  GURL url3("http://url3");
-  GURL url4("javascript:alert(\"Hello!\");");
-  GURL unnamed_bookmark_url("about:blank");
-  base::Time t1(base::Time::Now());
-  base::Time t2(t1 + base::TimeDelta::FromHours(1));
-  base::Time t3(t1 + base::TimeDelta::FromHours(1));
-  base::Time t4(t1 + base::TimeDelta::FromHours(1));
-  const BookmarkNode* f1 = model->AddFolder(
-      model->bookmark_bar_node(), 0, f1_title);
-  model->AddURLWithCreationTime(f1, 0, url1_title, url1, t1);
-  HistoryServiceFactory::GetForProfile(&profile, Profile::EXPLICIT_ACCESS)->
-      AddPage(url1, base::Time::Now(), history::SOURCE_BROWSED);
-  FaviconServiceFactory::GetForProfile(
-      &profile, Profile::EXPLICIT_ACCESS)->SetFavicons(
-          url1, url1_favicon, chrome::FAVICON,
-          gfx::Image::CreateFrom1xBitmap(bitmap));
-  message_loop.RunUntilIdle();
-  const BookmarkNode* f2 = model->AddFolder(f1, 1, f2_title);
-  model->AddURLWithCreationTime(f2, 0, url2_title, url2, t2);
-  model->AddURLWithCreationTime(model->bookmark_bar_node(),
-                                1, url3_title, url3, t3);
-
-  model->AddURLWithCreationTime(model->other_node(), 0, url1_title, url1, t1);
-  model->AddURLWithCreationTime(model->other_node(), 1, url2_title, url2, t2);
-  const BookmarkNode* f3 = model->AddFolder(model->other_node(), 2, f3_title);
-  const BookmarkNode* f4 = model->AddFolder(f3, 0, f4_title);
-  model->AddURLWithCreationTime(f4, 0, url1_title, url1, t1);
-  model->AddURLWithCreationTime(model->bookmark_bar_node(), 2, url4_title,
-                                url4, t4);
-  model->AddURLWithCreationTime(model->mobile_node(), 0, url1_title, url1, t1);
-  model->AddURLWithCreationTime(model->mobile_node(), 1, unnamed_bookmark_title,
-                                unnamed_bookmark_url, t2);
-
-  // Write to a temp file.
-  BookmarksObserver observer(&message_loop);
-  bookmark_html_writer::WriteBookmarks(&profile, path_, &observer);
-  message_loop.Run();
-
-  // Clear favicon so that it would be read from file.
-  FaviconServiceFactory::GetForProfile(
-      &profile, Profile::EXPLICIT_ACCESS)->SetFavicons(
-          url1, url1_favicon, chrome::FAVICON, gfx::Image());
-  message_loop.RunUntilIdle();
-
-  // Read the bookmarks back in.
-  std::vector<ImportedBookmarkEntry> parsed_bookmarks;
-  std::vector<ImportedFaviconUsage> favicons;
-  bookmark_html_reader::ImportBookmarksFile(base::Callback<bool(void)>(),
-                                            base::Callback<bool(const GURL&)>(),
-                                            path_,
-                                            &parsed_bookmarks,
-                                            &favicons);
-
-  // Check loaded favicon (url1 is represented by 4 separate bookmarks).
-  EXPECT_EQ(4U, favicons.size());
-  for (size_t i = 0; i < favicons.size(); i++) {
-    if (url1_favicon == favicons[i].favicon_url) {
-      EXPECT_EQ(1U, favicons[i].urls.size());
-      std::set<GURL>::const_iterator iter = favicons[i].urls.find(url1);
-      ASSERT_TRUE(iter != favicons[i].urls.end());
-      ASSERT_TRUE(*iter == url1);
-      ASSERT_TRUE(favicons[i].png_data == icon_data);
-    }
-  }
-
-  // Verify we got back what we wrote.
-  ASSERT_EQ(9U, parsed_bookmarks.size());
-  // Windows and ChromeOS builds use Sentence case.
-  string16 bookmark_folder_name =
-      l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_FOLDER_NAME);
-  AssertBookmarkEntryEquals(parsed_bookmarks[0], true, url1, url1_title, t1,
-                            bookmark_folder_name, f1_title, string16());
-  AssertBookmarkEntryEquals(parsed_bookmarks[1], true, url2, url2_title, t2,
-                            bookmark_folder_name, f1_title, f2_title);
-  AssertBookmarkEntryEquals(parsed_bookmarks[2], true, url3, url3_title, t3,
-                            bookmark_folder_name, string16(), string16());
-  AssertBookmarkEntryEquals(parsed_bookmarks[3], true, url4, url4_title, t4,
-                            bookmark_folder_name, string16(), string16());
-  AssertBookmarkEntryEquals(parsed_bookmarks[4], false, url1, url1_title, t1,
-                            string16(), string16(), string16());
-  AssertBookmarkEntryEquals(parsed_bookmarks[5], false, url2, url2_title, t2,
-                            string16(), string16(), string16());
-  AssertBookmarkEntryEquals(parsed_bookmarks[6], false, url1, url1_title, t1,
-                            f3_title, f4_title, string16());
-  AssertBookmarkEntryEquals(parsed_bookmarks[7], false, url1, url1_title, t1,
-                            string16(), string16(), string16());
-  AssertBookmarkEntryEquals(parsed_bookmarks[8], false, unnamed_bookmark_url,
-                            unnamed_bookmark_title, t2,
-                            string16(), string16(), string16());
-}
diff --git a/chrome/browser/bookmarks/bookmark_index.cc b/chrome/browser/bookmarks/bookmark_index.cc
index bc5150b..3af121e 100644
--- a/chrome/browser/bookmarks/bookmark_index.cc
+++ b/chrome/browser/bookmarks/bookmark_index.cc
@@ -258,11 +258,6 @@
 
 void BookmarkIndex::RegisterNode(const string16& term,
                                  const BookmarkNode* node) {
-  if (std::find(index_[term].begin(), index_[term].end(), node) !=
-      index_[term].end()) {
-    // We've already added node for term.
-    return;
-  }
   index_[term].insert(node);
 }
 
diff --git a/chrome/browser/bookmarks/bookmark_index_unittest.cc b/chrome/browser/bookmarks/bookmark_index_unittest.cc
index 48d1fd2..f2e4469 100644
--- a/chrome/browser/bookmarks/bookmark_index_unittest.cc
+++ b/chrome/browser/bookmarks/bookmark_index_unittest.cc
@@ -20,11 +20,9 @@
 #include "chrome/browser/history/url_database.h"
 #include "chrome/test/base/testing_profile.h"
 #include "chrome/test/base/ui_test_utils.h"
-#include "content/public/test/test_browser_thread.h"
+#include "content/public/test/test_browser_thread_bundle.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-using content::BrowserThread;
-
 class BookmarkIndexTest : public testing::Test {
  public:
   BookmarkIndexTest() : model_(new BookmarkModel(NULL)) {}
@@ -235,9 +233,7 @@
 TEST_F(BookmarkIndexTest, GetResultsSortedByTypedCount) {
   // This ensures MessageLoop::current() will exist, which is needed by
   // TestingProfile::BlockUntilHistoryProcessesPendingRequests().
-  base::MessageLoop loop(base::MessageLoop::TYPE_DEFAULT);
-  content::TestBrowserThread ui_thread(BrowserThread::UI, &loop);
-  content::TestBrowserThread file_thread(BrowserThread::FILE, &loop);
+  content::TestBrowserThreadBundle thread_bundle;
 
   TestingProfile profile;
   profile.CreateHistoryService(true, false);
diff --git a/chrome/browser/bookmarks/bookmark_model.cc b/chrome/browser/bookmarks/bookmark_model.cc
index df4ce6b..eff176e 100644
--- a/chrome/browser/bookmarks/bookmark_model.cc
+++ b/chrome/browser/bookmarks/bookmark_model.cc
@@ -46,6 +46,25 @@
   return const_cast<BookmarkNode*>(node);
 }
 
+// Helper to recursively determine if a Dictionary has any valid values.
+bool HasValues(const base::DictionaryValue& root) {
+  if (root.empty())
+    return false;
+  for (base::DictionaryValue::Iterator iter(root); !iter.IsAtEnd();
+       iter.Advance()) {
+    const base::Value& value = iter.value();
+    if (value.IsType(base::Value::TYPE_DICTIONARY)) {
+      const base::DictionaryValue* dict_value = NULL;
+      if (value.GetAsDictionary(&dict_value) && HasValues(*dict_value))
+        return true;
+    } else {
+      // A non dictionary type was encountered, assume it's a valid value.
+      return true;
+    }
+  }
+  return false;
+}
+
 // Whitespace characters to strip from bookmark titles.
 const char16 kInvalidChars[] = {
   '\n', '\r', '\t',
@@ -123,9 +142,8 @@
   JSONStringValueSerializer serializer(&meta_info_str_);
   scoped_ptr<DictionaryValue> meta_dict(
       static_cast<DictionaryValue*>(serializer.Deserialize(NULL, NULL)));
-  if (meta_dict.get() && meta_dict->HasKey(key)) {
-    meta_dict->Remove(key, NULL);
-    if (meta_dict->empty()) {
+  if (meta_dict.get() && meta_dict->Remove(key, NULL)) {
+    if (!HasValues(*meta_dict)) {
       meta_info_str_.clear();
     } else {
       serializer.Serialize(*meta_dict);
diff --git a/chrome/browser/bookmarks/bookmark_model.h b/chrome/browser/bookmarks/bookmark_model.h
index cfa1475..cc90532 100644
--- a/chrome/browser/bookmarks/bookmark_model.h
+++ b/chrome/browser/bookmarks/bookmark_model.h
@@ -21,9 +21,9 @@
 #include "components/browser_context_keyed_service/browser_context_keyed_service.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
-#include "googleurl/src/gurl.h"
 #include "ui/base/models/tree_node_model.h"
 #include "ui/gfx/image/image.h"
+#include "url/gurl.h"
 
 class BookmarkExpandedStateTracker;
 class BookmarkIndex;
diff --git a/chrome/browser/bookmarks/bookmark_model_test_utils.cc b/chrome/browser/bookmarks/bookmark_model_test_utils.cc
index 15370d4..f04a6b5 100644
--- a/chrome/browser/bookmarks/bookmark_model_test_utils.cc
+++ b/chrome/browser/bookmarks/bookmark_model_test_utils.cc
@@ -4,13 +4,18 @@
 
 #include "chrome/browser/bookmarks/bookmark_model_test_utils.h"
 
+#include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/bookmarks/bookmark_model.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
 
-// static
-void BookmarkModelTestUtils::AssertNodesEqual(const BookmarkNode* expected,
-                                              const BookmarkNode* actual,
-                                              bool check_ids) {
+namespace {
+
+// Helper to verify the two given bookmark nodes.
+// The IDs of the bookmark nodes are compared only if check_ids is true.
+void AssertNodesEqual(const BookmarkNode* expected,
+                      const BookmarkNode* actual,
+                      bool check_ids) {
   ASSERT_TRUE(expected);
   ASSERT_TRUE(actual);
   if (check_ids)
@@ -29,6 +34,51 @@
   }
 }
 
+// Helper function which does the actual work of creating the nodes for
+// a particular level in the hierarchy.
+std::string::size_type AddNodesFromString(BookmarkModel* model,
+                                          const BookmarkNode* node,
+                                          const std::string& model_string,
+                                          std::string::size_type start_pos) {
+  DCHECK(node);
+  int index = node->child_count();
+  static const std::string folder_tell(":[");
+  std::string::size_type end_pos = model_string.find(' ', start_pos);
+  while (end_pos != std::string::npos) {
+    std::string::size_type part_length = end_pos - start_pos;
+    std::string node_name = model_string.substr(start_pos, part_length);
+    // Are we at the end of a folder group?
+    if (node_name != "]") {
+      // No, is it a folder?
+      std::string tell;
+      if (part_length > 2)
+        tell = node_name.substr(part_length - 2, 2);
+      if (tell == folder_tell) {
+        node_name = node_name.substr(0, part_length - 2);
+        const BookmarkNode* new_node =
+            model->AddFolder(node, index, UTF8ToUTF16(node_name));
+        end_pos = AddNodesFromString(model, new_node, model_string,
+                                     end_pos + 1);
+      } else {
+        std::string url_string("http://");
+        url_string += std::string(node_name.begin(), node_name.end());
+        url_string += ".com";
+        model->AddURL(node, index, UTF8ToUTF16(node_name), GURL(url_string));
+        ++end_pos;
+      }
+      ++index;
+      start_pos = end_pos;
+      end_pos = model_string.find(' ', start_pos);
+    } else {
+      ++end_pos;
+      break;
+    }
+  }
+  return end_pos;
+}
+
+}  // namespace
+
 // static
 void BookmarkModelTestUtils::AssertModelsEqual(BookmarkModel* expected,
                                                BookmarkModel* actual,
@@ -36,10 +86,38 @@
   AssertNodesEqual(expected->bookmark_bar_node(),
                    actual->bookmark_bar_node(),
                    check_ids);
-  AssertNodesEqual(expected->other_node(),
-                   actual->other_node(),
-                   check_ids);
-  AssertNodesEqual(expected->mobile_node(),
-                   actual->mobile_node(),
-                   check_ids);
+  AssertNodesEqual(expected->other_node(), actual->other_node(), check_ids);
+  AssertNodesEqual(expected->mobile_node(), actual->mobile_node(), check_ids);
+}
+
+// static
+std::string BookmarkModelTestUtils::ModelStringFromNode(
+    const BookmarkNode* node) {
+  // Since the children of the node are not available as a vector,
+  // we'll just have to do it the hard way.
+  int child_count = node->child_count();
+  std::string child_string;
+  for (int i = 0; i < child_count; ++i) {
+    const BookmarkNode* child = node->GetChild(i);
+    if (child->is_folder()) {
+      child_string += UTF16ToUTF8(child->GetTitle()) + ":[ " +
+          ModelStringFromNode(child) + "] ";
+    } else {
+      child_string += UTF16ToUTF8(child->GetTitle()) + " ";
+    }
+  }
+  return child_string;
+}
+
+// static
+void BookmarkModelTestUtils::AddNodesFromModelString(
+    BookmarkModel* model,
+    const BookmarkNode* node,
+    const std::string& model_string) {
+  DCHECK(node);
+  const std::string folder_tell(":[");
+  std::string::size_type start_pos = 0;
+  std::string::size_type end_pos =
+      AddNodesFromString(model, node, model_string, start_pos);
+  DCHECK(end_pos == std::string::npos);
 }
diff --git a/chrome/browser/bookmarks/bookmark_model_test_utils.h b/chrome/browser/bookmarks/bookmark_model_test_utils.h
index e942bd6..fab44dc 100644
--- a/chrome/browser/bookmarks/bookmark_model_test_utils.h
+++ b/chrome/browser/bookmarks/bookmark_model_test_utils.h
@@ -5,6 +5,10 @@
 #ifndef CHROME_BROWSER_BOOKMARKS_BOOKMARK_MODEL_TEST_UTILS_H_
 #define CHROME_BROWSER_BOOKMARKS_BOOKMARK_MODEL_TEST_UTILS_H_
 
+#include <string>
+
+#include "base/basictypes.h"
+
 class BookmarkModel;
 class BookmarkNode;
 
@@ -16,12 +20,35 @@
   static void AssertModelsEqual(BookmarkModel* expected,
                                 BookmarkModel* actual,
                                 bool check_ids);
+
+  // Return the descendants of |node| as a string useful for verifying node
+  // modifications. The format of the resulting string is:
+  //
+  //           result = node " " , { node " " }
+  //             node = bookmark title | folder
+  //           folder = folder title ":[ " { node " " } "]"
+  //   bookmark title = (* string with no spaces *)
+  //     folder title = (* string with no spaces *)
+  //
+  // Example: "a f1:[ b d c ] d f2:[ e f g ] h "
+  //
+  // (Logically, we should use |string16|s, but it's more convenient for test
+  // purposes to use (UTF-8) |std::string|s.)
+  static std::string ModelStringFromNode(const BookmarkNode* node);
+
+  // Create and add the node hierarchy specified by |nodeString| to the
+  // bookmark node given by |node|. The string has the same format as
+  // specified for ModelStringFromNode. The new nodes added to |node|
+  // are appended to the end of node's existing subnodes, if any.
+  // |model| must be the model of which |node| is a member.
+  // NOTE: The string format is very rigid and easily broken if not followed
+  //       exactly (since we're using a very simple parser).
+  static void AddNodesFromModelString(BookmarkModel* model,
+                                      const BookmarkNode* node,
+                                      const std::string& model_string);
+
  private:
-  // Helper to verify the two given bookmark nodes.
-  // The IDs of the bookmark nodes are compared only if check_ids is true.
-  static void AssertNodesEqual(const BookmarkNode* expected,
-                               const BookmarkNode* actual,
-                               bool check_ids);
+  DISALLOW_IMPLICIT_CONSTRUCTORS(BookmarkModelTestUtils);
 };
 
 #endif  // CHROME_BROWSER_BOOKMARKS_BOOKMARK_MODEL_TEST_UTILS_H_
diff --git a/chrome/browser/bookmarks/bookmark_model_unittest.cc b/chrome/browser/bookmarks/bookmark_model_unittest.cc
index 2f8551c..06610d7 100644
--- a/chrome/browser/bookmarks/bookmark_model_unittest.cc
+++ b/chrome/browser/bookmarks/bookmark_model_unittest.cc
@@ -18,18 +18,18 @@
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
 #include "chrome/browser/bookmarks/bookmark_model_observer.h"
+#include "chrome/browser/bookmarks/bookmark_model_test_utils.h"
 #include "chrome/browser/bookmarks/bookmark_utils.h"
-#include "chrome/test/base/model_test_utils.h"
 #include "chrome/test/base/testing_profile.h"
 #include "chrome/test/base/ui_test_utils.h"
-#include "content/public/test/test_browser_thread.h"
-#include "googleurl/src/gurl.h"
+#include "content/public/test/test_browser_thread_bundle.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/models/tree_node_iterator.h"
 #include "ui/base/models/tree_node_model.h"
+#include "url/gurl.h"
 
 using base::Time;
 using base::TimeDelta;
@@ -596,53 +596,54 @@
 TEST_F(BookmarkModelTest, Copy) {
   const BookmarkNode* root = model_.bookmark_bar_node();
   static const std::string model_string("a 1:[ b c ] d 2:[ e f g ] h ");
-  model_test_utils::AddNodesFromModelString(&model_, root, model_string);
+  BookmarkModelTestUtils::AddNodesFromModelString(&model_, root, model_string);
 
   // Validate initial model.
-  std::string actual_model_string = model_test_utils::ModelStringFromNode(root);
+  std::string actual_model_string =
+      BookmarkModelTestUtils::ModelStringFromNode(root);
   EXPECT_EQ(model_string, actual_model_string);
 
   // Copy 'd' to be after '1:b': URL item from bar to folder.
-  const BookmarkNode* nodeToCopy = root->GetChild(2);
+  const BookmarkNode* node_to_copy = root->GetChild(2);
   const BookmarkNode* destination = root->GetChild(1);
-  model_.Copy(nodeToCopy, destination, 1);
-  actual_model_string = model_test_utils::ModelStringFromNode(root);
+  model_.Copy(node_to_copy, destination, 1);
+  actual_model_string = BookmarkModelTestUtils::ModelStringFromNode(root);
   EXPECT_EQ("a 1:[ b d c ] d 2:[ e f g ] h ", actual_model_string);
 
   // Copy '1:d' to be after 'a': URL item from folder to bar.
   const BookmarkNode* folder = root->GetChild(1);
-  nodeToCopy = folder->GetChild(1);
-  model_.Copy(nodeToCopy, root, 1);
-  actual_model_string = model_test_utils::ModelStringFromNode(root);
+  node_to_copy = folder->GetChild(1);
+  model_.Copy(node_to_copy, root, 1);
+  actual_model_string = BookmarkModelTestUtils::ModelStringFromNode(root);
   EXPECT_EQ("a d 1:[ b d c ] d 2:[ e f g ] h ", actual_model_string);
 
   // Copy '1' to be after '2:e': Folder from bar to folder.
-  nodeToCopy = root->GetChild(2);
+  node_to_copy = root->GetChild(2);
   destination = root->GetChild(4);
-  model_.Copy(nodeToCopy, destination, 1);
-  actual_model_string = model_test_utils::ModelStringFromNode(root);
+  model_.Copy(node_to_copy, destination, 1);
+  actual_model_string = BookmarkModelTestUtils::ModelStringFromNode(root);
   EXPECT_EQ("a d 1:[ b d c ] d 2:[ e 1:[ b d c ] f g ] h ",
             actual_model_string);
 
   // Copy '2:1' to be after '2:f': Folder within same folder.
   folder = root->GetChild(4);
-  nodeToCopy = folder->GetChild(1);
-  model_.Copy(nodeToCopy, folder, 3);
-  actual_model_string = model_test_utils::ModelStringFromNode(root);
+  node_to_copy = folder->GetChild(1);
+  model_.Copy(node_to_copy, folder, 3);
+  actual_model_string = BookmarkModelTestUtils::ModelStringFromNode(root);
   EXPECT_EQ("a d 1:[ b d c ] d 2:[ e 1:[ b d c ] f 1:[ b d c ] g ] h ",
             actual_model_string);
 
   // Copy first 'd' to be after 'h': URL item within the bar.
-  nodeToCopy = root->GetChild(1);
-  model_.Copy(nodeToCopy, root, 6);
-  actual_model_string = model_test_utils::ModelStringFromNode(root);
+  node_to_copy = root->GetChild(1);
+  model_.Copy(node_to_copy, root, 6);
+  actual_model_string = BookmarkModelTestUtils::ModelStringFromNode(root);
   EXPECT_EQ("a d 1:[ b d c ] d 2:[ e 1:[ b d c ] f 1:[ b d c ] g ] h d ",
             actual_model_string);
 
   // Copy '2' to be after 'a': Folder within the bar.
-  nodeToCopy = root->GetChild(4);
-  model_.Copy(nodeToCopy, root, 1);
-  actual_model_string = model_test_utils::ModelStringFromNode(root);
+  node_to_copy = root->GetChild(4);
+  model_.Copy(node_to_copy, root, 1);
+  actual_model_string = BookmarkModelTestUtils::ModelStringFromNode(root);
   EXPECT_EQ("a 2:[ e 1:[ b d c ] f 1:[ b d c ] g ] d 1:[ b d c ] "
             "d 2:[ e 1:[ b d c ] f 1:[ b d c ] g ] h d ",
             actual_model_string);
@@ -868,9 +869,7 @@
 class BookmarkModelTestWithProfile : public testing::Test {
  public:
   BookmarkModelTestWithProfile()
-      : bb_model_(NULL),
-        ui_thread_(BrowserThread::UI, &message_loop_),
-        file_thread_(BrowserThread::FILE, &message_loop_) {}
+      : bb_model_(NULL) {}
 
   // testing::Test:
   virtual void TearDown() OVERRIDE {
@@ -925,9 +924,7 @@
   BookmarkModel* bb_model_;
 
  private:
-  base::MessageLoopForUI message_loop_;
-  content::TestBrowserThread ui_thread_;
-  content::TestBrowserThread file_thread_;
+  content::TestBrowserThreadBundle thread_bundle_;
 };
 
 // Creates a set of nodes in the bookmark bar model, then recreates the
@@ -1114,16 +1111,24 @@
   EXPECT_EQ("value1", out_value);
   EXPECT_FALSE(node.SetMetaInfo("key1", "value1"));
 
-  EXPECT_FALSE(node.GetMetaInfo("key2", &out_value));
-  EXPECT_TRUE(node.SetMetaInfo("key2", "value2"));
-  EXPECT_TRUE(node.GetMetaInfo("key2", &out_value));
+  EXPECT_FALSE(node.GetMetaInfo("key2.subkey1", &out_value));
+  EXPECT_TRUE(node.SetMetaInfo("key2.subkey1", "value2"));
+  EXPECT_TRUE(node.GetMetaInfo("key2.subkey1", &out_value));
   EXPECT_EQ("value2", out_value);
 
+  EXPECT_FALSE(node.GetMetaInfo("key2.subkey2.leaf", &out_value));
+  EXPECT_TRUE(node.SetMetaInfo("key2.subkey2.leaf", ""));
+  EXPECT_TRUE(node.GetMetaInfo("key2.subkey2.leaf", &out_value));
+  EXPECT_EQ("", out_value);
+
   EXPECT_TRUE(node.DeleteMetaInfo("key1"));
-  EXPECT_TRUE(node.DeleteMetaInfo("key2"));
+  EXPECT_TRUE(node.DeleteMetaInfo("key2.subkey1"));
+  EXPECT_TRUE(node.DeleteMetaInfo("key2.subkey2.leaf"));
   EXPECT_FALSE(node.DeleteMetaInfo("key3"));
   EXPECT_FALSE(node.GetMetaInfo("key1", &out_value));
-  EXPECT_FALSE(node.GetMetaInfo("key2", &out_value));
+  EXPECT_FALSE(node.GetMetaInfo("key2.subkey1", &out_value));
+  EXPECT_FALSE(node.GetMetaInfo("key2.subkey2", &out_value));
+  EXPECT_FALSE(node.GetMetaInfo("key2.subkey2.leaf", &out_value));
   EXPECT_TRUE(node.meta_info_str().empty());
 }
 
diff --git a/chrome/browser/bookmarks/bookmark_node_data.h b/chrome/browser/bookmarks/bookmark_node_data.h
index 80e55f6..1401e70 100644
--- a/chrome/browser/bookmarks/bookmark_node_data.h
+++ b/chrome/browser/bookmarks/bookmark_node_data.h
@@ -9,7 +9,7 @@
 
 #include "base/files/file_path.h"
 #include "base/strings/string16.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 #if defined(TOOLKIT_VIEWS)
 #include "ui/base/dragdrop/os_exchange_data.h"
diff --git a/chrome/browser/bookmarks/bookmark_node_data_unittest.cc b/chrome/browser/bookmarks/bookmark_node_data_unittest.cc
index dff83cc..8e5c0e2 100644
--- a/chrome/browser/bookmarks/bookmark_node_data_unittest.cc
+++ b/chrome/browser/bookmarks/bookmark_node_data_unittest.cc
@@ -11,25 +11,18 @@
 #include "chrome/browser/bookmarks/bookmark_node_data.h"
 #include "chrome/test/base/testing_profile.h"
 #include "chrome/test/base/ui_test_utils.h"
-#include "content/public/test/test_browser_thread.h"
-#include "googleurl/src/gurl.h"
+#include "content/public/test/test_browser_thread_bundle.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/dragdrop/os_exchange_data.h"
 #include "ui/base/dragdrop/os_exchange_data_provider_win.h"
-
-using content::BrowserThread;
+#include "url/gurl.h"
 
 class BookmarkNodeDataTest : public testing::Test {
  public:
-  BookmarkNodeDataTest()
-      : ui_thread_(BrowserThread::UI, &loop_),
-        file_thread_(BrowserThread::FILE, &loop_) {
-  }
+  BookmarkNodeDataTest() {}
 
  private:
-  base::MessageLoop loop_;
-  content::TestBrowserThread ui_thread_;
-  content::TestBrowserThread file_thread_;
+  content::TestBrowserThreadBundle thread_bundle_;
 };
 
 namespace {
diff --git a/chrome/browser/bookmarks/bookmark_service.h b/chrome/browser/bookmarks/bookmark_service.h
index 284fe4c..8233565 100644
--- a/chrome/browser/bookmarks/bookmark_service.h
+++ b/chrome/browser/bookmarks/bookmark_service.h
@@ -8,7 +8,7 @@
 #include <vector>
 
 #include "base/strings/string16.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 namespace content {
 class BrowserContext;
diff --git a/chrome/browser/bookmarks/bookmark_storage.cc b/chrome/browser/bookmarks/bookmark_storage.cc
index 431a6d1..b7b2ce1 100644
--- a/chrome/browser/bookmarks/bookmark_storage.cc
+++ b/chrome/browser/bookmarks/bookmark_storage.cc
@@ -11,7 +11,7 @@
 #include "base/json/json_file_value_serializer.h"
 #include "base/json/json_string_value_serializer.h"
 #include "base/metrics/histogram.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/bookmarks/bookmark_codec.h"
 #include "chrome/browser/bookmarks/bookmark_index.h"
 #include "chrome/browser/bookmarks/bookmark_model.h"
diff --git a/chrome/browser/bookmarks/bookmark_utils.cc b/chrome/browser/bookmarks/bookmark_utils.cc
index b72b22f..ea04f7f 100644
--- a/chrome/browser/bookmarks/bookmark_utils.cc
+++ b/chrome/browser/bookmarks/bookmark_utils.cc
@@ -14,7 +14,7 @@
 #include "base/prefs/pref_service.h"
 #include "base/strings/string16.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/bookmarks/bookmark_model.h"
 #include "chrome/browser/bookmarks/bookmark_node_data.h"
 #include "chrome/browser/history/query_parser.h"
@@ -76,38 +76,6 @@
           net::UnescapeRule::NORMAL, NULL, NULL, NULL), words);
 }
 
-const BookmarkNode* CreateNewNode(BookmarkModel* model,
-                                  const BookmarkNode* parent,
-                                  const BookmarkEditor::EditDetails& details,
-                                  const string16& new_title,
-                                  const GURL& new_url) {
-  const BookmarkNode* node;
-  // When create the new one to right-clicked folder, add it to the next to the
-  // folder's position. Because |details.index| has a index of the folder when
-  // it was right-clicked, it might cause out of range exception when another
-  // bookmark manager edits contents of the folder.
-  // So we must check the range.
-  int child_count = parent->child_count();
-  int insert_index = (parent == details.parent_node && details.index >= 0 &&
-                      details.index <= child_count) ?
-                      details.index : child_count;
-  if (details.type == BookmarkEditor::EditDetails::NEW_URL) {
-    node = model->AddURL(parent, insert_index, new_title, new_url);
-  } else if (details.type == BookmarkEditor::EditDetails::NEW_FOLDER) {
-    node = model->AddFolder(parent, insert_index, new_title);
-    for (size_t i = 0; i < details.urls.size(); ++i) {
-      model->AddURL(node, node->child_count(), details.urls[i].second,
-                    details.urls[i].first);
-    }
-    model->SetDateFolderModified(parent, Time::Now());
-  } else {
-    NOTREACHED();
-    return NULL;
-  }
-
-  return node;
-}
-
 }  // namespace
 
 namespace bookmark_utils {
@@ -270,50 +238,6 @@
   return (node->is_url() && DoesBookmarkContainWords(node, words, languages));
 }
 
-const BookmarkNode* ApplyEditsWithNoFolderChange(
-    BookmarkModel* model,
-    const BookmarkNode* parent,
-    const BookmarkEditor::EditDetails& details,
-    const string16& new_title,
-    const GURL& new_url) {
-  if (details.type == BookmarkEditor::EditDetails::NEW_URL ||
-      details.type == BookmarkEditor::EditDetails::NEW_FOLDER) {
-    return CreateNewNode(model, parent, details, new_title, new_url);
-  }
-
-  const BookmarkNode* node = details.existing_node;
-  DCHECK(node);
-
-  if (node->is_url())
-    model->SetURL(node, new_url);
-  model->SetTitle(node, new_title);
-
-  return node;
-}
-
-const BookmarkNode* ApplyEditsWithPossibleFolderChange(
-    BookmarkModel* model,
-    const BookmarkNode* new_parent,
-    const BookmarkEditor::EditDetails& details,
-    const string16& new_title,
-    const GURL& new_url) {
-  if (details.type == BookmarkEditor::EditDetails::NEW_URL ||
-      details.type == BookmarkEditor::EditDetails::NEW_FOLDER) {
-    return CreateNewNode(model, new_parent, details, new_title, new_url);
-  }
-
-  const BookmarkNode* node = details.existing_node;
-  DCHECK(node);
-
-  if (new_parent != node->parent())
-    model->Move(node, new_parent, new_parent->child_count());
-  if (node->is_url())
-    model->SetURL(node, new_url);
-  model->SetTitle(node, new_title);
-
-  return node;
-}
-
 void RegisterUserPrefs(user_prefs::PrefRegistrySyncable* registry) {
   registry->RegisterBooleanPref(
       prefs::kShowBookmarkBar,
diff --git a/chrome/browser/bookmarks/bookmark_utils.h b/chrome/browser/bookmarks/bookmark_utils.h
index 1524f3f..a72e6d8 100644
--- a/chrome/browser/bookmarks/bookmark_utils.h
+++ b/chrome/browser/bookmarks/bookmark_utils.h
@@ -9,7 +9,6 @@
 #include <vector>
 
 #include "base/strings/string16.h"
-#include "chrome/browser/bookmarks/bookmark_editor.h"
 #include "chrome/browser/bookmarks/bookmark_node_data.h"
 
 class BookmarkModel;
@@ -76,28 +75,6 @@
                              const string16& text,
                              const std::string& languages);
 
-// Modifies a bookmark node (assuming that there's no magic that needs to be
-// done regarding moving from one folder to another).  If a new node is
-// explicitly being added, returns a pointer to the new node that was created.
-// Otherwise the return value is identically |node|.
-const BookmarkNode* ApplyEditsWithNoFolderChange(
-    BookmarkModel* model,
-    const BookmarkNode* parent,
-    const BookmarkEditor::EditDetails& details,
-    const string16& new_title,
-    const GURL& new_url);
-
-// Modifies a bookmark node assuming that the parent of the node may have
-// changed and the node will need to be removed and reinserted.  If a new node
-// is explicitly being added, returns a pointer to the new node that was
-// created.  Otherwise the return value is identically |node|.
-const BookmarkNode* ApplyEditsWithPossibleFolderChange(
-    BookmarkModel* model,
-    const BookmarkNode* new_parent,
-    const BookmarkEditor::EditDetails& details,
-    const string16& new_title,
-    const GURL& new_url);
-
 // Register user preferences for Bookmarks Bar.
 void RegisterUserPrefs(user_prefs::PrefRegistrySyncable* registry);
 
diff --git a/chrome/browser/bookmarks/bookmark_utils_unittest.cc b/chrome/browser/bookmarks/bookmark_utils_unittest.cc
index f3bd727..e96f3f7 100644
--- a/chrome/browser/bookmarks/bookmark_utils_unittest.cc
+++ b/chrome/browser/bookmarks/bookmark_utils_unittest.cc
@@ -6,7 +6,6 @@
 
 #include "base/message_loop.h"
 #include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/bookmarks/bookmark_editor.h"
 #include "chrome/browser/bookmarks/bookmark_model.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/clipboard/clipboard.h"
@@ -157,44 +156,6 @@
   EXPECT_FALSE(CanPasteFromClipboard(model.bookmark_bar_node()));
 }
 
-TEST_F(BookmarkUtilsTest, ApplyEditsWithNoFolderChange) {
-  BookmarkModel model(NULL);
-  const BookmarkNode* bookmarkbar = model.bookmark_bar_node();
-  model.AddURL(bookmarkbar, 0, ASCIIToUTF16("url0"), GURL("chrome://newtab"));
-  model.AddURL(bookmarkbar, 1, ASCIIToUTF16("url1"), GURL("chrome://newtab"));
-
-  {
-    BookmarkEditor::EditDetails detail(
-        BookmarkEditor::EditDetails::AddFolder(bookmarkbar, 1));
-    ApplyEditsWithNoFolderChange(&model,
-                                 bookmarkbar,
-                                 detail,
-                                 ASCIIToUTF16("folder0"),
-                                 GURL(std::string()));
-    EXPECT_EQ(ASCIIToUTF16("folder0"), bookmarkbar->GetChild(1)->GetTitle());
-  }
-  {
-    BookmarkEditor::EditDetails detail(
-        BookmarkEditor::EditDetails::AddFolder(bookmarkbar, -1));
-    ApplyEditsWithNoFolderChange(&model,
-                                 bookmarkbar,
-                                 detail,
-                                 ASCIIToUTF16("folder1"),
-                                 GURL(std::string()));
-    EXPECT_EQ(ASCIIToUTF16("folder1"), bookmarkbar->GetChild(3)->GetTitle());
-  }
-  {
-    BookmarkEditor::EditDetails detail(
-        BookmarkEditor::EditDetails::AddFolder(bookmarkbar, 10));
-    ApplyEditsWithNoFolderChange(&model,
-                                 bookmarkbar,
-                                 detail,
-                                 ASCIIToUTF16("folder2"),
-                                 GURL(std::string()));
-    EXPECT_EQ(ASCIIToUTF16("folder2"), bookmarkbar->GetChild(4)->GetTitle());
-  }
-}
-
 TEST_F(BookmarkUtilsTest, GetParentForNewNodes) {
   BookmarkModel model(NULL);
   // This tests the case where selection contains one item and that item is a
diff --git a/chrome/browser/bookmarks/imported_bookmark_entry.cc b/chrome/browser/bookmarks/imported_bookmark_entry.cc
deleted file mode 100644
index f6a30a8..0000000
--- a/chrome/browser/bookmarks/imported_bookmark_entry.cc
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/bookmarks/imported_bookmark_entry.h"
-
-ImportedBookmarkEntry::ImportedBookmarkEntry()
-    : in_toolbar(false),
-      is_folder(false) {}
-
-ImportedBookmarkEntry::~ImportedBookmarkEntry() {}
-
-bool ImportedBookmarkEntry::operator==(
-    const ImportedBookmarkEntry& other) const {
-  return (in_toolbar == other.in_toolbar &&
-          is_folder == other.is_folder &&
-          url == other.url &&
-          path == other.path &&
-          title == other.title &&
-          creation_time == other.creation_time);
-}
diff --git a/chrome/browser/bookmarks/imported_bookmark_entry.h b/chrome/browser/bookmarks/imported_bookmark_entry.h
deleted file mode 100644
index 73bf0a9..0000000
--- a/chrome/browser/bookmarks/imported_bookmark_entry.h
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_BOOKMARKS_IMPORTED_BOOKMARK_ENTRY_H_
-#define CHROME_BROWSER_BOOKMARKS_IMPORTED_BOOKMARK_ENTRY_H_
-
-#include <vector>
-
-#include "base/strings/string16.h"
-#include "base/time.h"
-#include "googleurl/src/gurl.h"
-
-struct ImportedBookmarkEntry {
-  ImportedBookmarkEntry();
-  ~ImportedBookmarkEntry();
-
-  bool operator==(const ImportedBookmarkEntry& other) const;
-
-  bool in_toolbar;
-  bool is_folder;
-  GURL url;
-  std::vector<base::string16> path;
-  base::string16 title;
-  base::Time creation_time;
-};
-
-#endif  // CHROME_BROWSER_BOOKMARKS_IMPORTED_BOOKMARK_ENTRY_H_
diff --git a/chrome/browser/browser_about_handler.cc b/chrome/browser/browser_about_handler.cc
index 9dfcf1d..22c4f92 100644
--- a/chrome/browser/browser_about_handler.cc
+++ b/chrome/browser/browser_about_handler.cc
@@ -11,6 +11,7 @@
 #include "base/logging.h"
 #include "base/memory/singleton.h"
 #include "base/strings/string_util.h"
+#include "chrome/browser/lifetime/application_lifetime.h"
 #include "chrome/browser/net/url_fixer_upper.h"
 #include "chrome/browser/ui/browser_dialogs.h"
 #include "chrome/common/chrome_switches.h"
@@ -101,6 +102,9 @@
   content::kChromeUINetworkViewCacheHost,
   content::kChromeUITracingHost,
   content::kChromeUIWebRTCInternalsHost,
+#if defined(ENABLE_WEBRTC)
+  chrome::kChromeUIWebRtcLogsHost,
+#endif
 };
 
 }  // namespace
@@ -157,6 +161,11 @@
   } else if (host == chrome::kChromeUIHelpHost) {
     host = chrome::kChromeUIUberHost;
     path = chrome::kChromeUIHelpHost + url->path();
+  } else if (host == chrome::kChromeUIRestartHost) {
+    // Call AttemptRestart after chrome::Navigate() completes to avoid access of
+    // gtk objects after they are destoyed by BrowserWindowGtk::Close().
+    base::MessageLoop::current()->PostTask(FROM_HERE,
+        base::Bind(&chrome::AttemptRestart));
   }
   GURL::Replacements replacements;
   replacements.SetHostStr(host);
diff --git a/chrome/browser/browser_about_handler_unittest.cc b/chrome/browser/browser_about_handler_unittest.cc
index c21f2e4..0b6e9c4 100644
--- a/chrome/browser/browser_about_handler_unittest.cc
+++ b/chrome/browser/browser_about_handler_unittest.cc
@@ -9,8 +9,8 @@
 #include "chrome/common/url_constants.h"
 #include "chrome/test/base/testing_profile.h"
 #include "content/public/test/test_browser_thread.h"
-#include "googleurl/src/gurl.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
 
 using content::BrowserThread;
 
diff --git a/chrome/browser/browser_keyevents_browsertest.cc b/chrome/browser/browser_keyevents_browsertest.cc
index 781d009..f27f00f 100644
--- a/chrome/browser/browser_keyevents_browsertest.cc
+++ b/chrome/browser/browser_keyevents_browsertest.cc
@@ -25,7 +25,7 @@
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_view.h"
 #include "content/public/test/browser_test_utils.h"
-#include "net/test/spawned_test_server/spawned_test_server.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
 #include "ui/base/keycodes/keyboard_codes.h"
 #include "ui/views/controls/textfield/textfield.h"
 
@@ -40,7 +40,7 @@
 
 namespace {
 
-const char kTestingPage[] = "files/keyevents_test.html";
+const char kTestingPage[] = "/keyevents_test.html";
 const char kSuppressEventJS[] =
     "window.domAutomationController.send(setDefaultAction('%ls', %ls));";
 const char kGetResultJS[] =
@@ -368,10 +368,10 @@
         "U 65 0 false false false false" } },
   };
 
-  ASSERT_TRUE(test_server()->Start());
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
 
   ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
-  GURL url = test_server()->GetURL(kTestingPage);
+  GURL url = embedded_test_server()->GetURL(kTestingPage);
   ui_test_utils::NavigateToURL(browser(), url);
 
   ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER));
@@ -461,10 +461,10 @@
       "U 17 0 true false false false" }
   };
 
-  ASSERT_TRUE(test_server()->Start());
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
 
   ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
-  GURL url = test_server()->GetURL(kTestingPage);
+  GURL url = embedded_test_server()->GetURL(kTestingPage);
   ui_test_utils::NavigateToURL(browser(), url);
 
   ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER));
@@ -507,10 +507,10 @@
       "U 91 0 false false false true" }
   };
 
-  ASSERT_TRUE(test_server()->Start());
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
 
   ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
-  GURL url = test_server()->GetURL(kTestingPage);
+  GURL url = embedded_test_server()->GetURL(kTestingPage);
   ui_test_utils::NavigateToURL(browser(), url);
 
   ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER));
@@ -607,10 +607,10 @@
 #endif
 #endif
 
-  ASSERT_TRUE(test_server()->Start());
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
 
   ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
-  GURL url = test_server()->GetURL(kTestingPage);
+  GURL url = embedded_test_server()->GetURL(kTestingPage);
   ui_test_utils::NavigateToURL(browser(), url);
 
   content::RunAllPendingInMessageLoop();
@@ -681,10 +681,10 @@
 #define MAYBE_ReservedAccelerators ReservedAccelerators
 #endif
 IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, MAYBE_ReservedAccelerators) {
-  ASSERT_TRUE(test_server()->Start());
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
 
   ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
-  GURL url = test_server()->GetURL(kTestingPage);
+  GURL url = embedded_test_server()->GetURL(kTestingPage);
   ui_test_utils::NavigateToURL(browser(), url);
 
   ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER));
@@ -783,10 +783,10 @@
       "U 17 0 true false false false" }
   };
 
-  ASSERT_TRUE(test_server()->Start());
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
 
   ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
-  GURL url = test_server()->GetURL(kTestingPage);
+  GURL url = embedded_test_server()->GetURL(kTestingPage);
   ui_test_utils::NavigateToURL(browser(), url);
 
   ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER));
@@ -821,10 +821,10 @@
       "U 34 0 false false false false" }
   };
 
-  ASSERT_TRUE(test_server()->Start());
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
 
   ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
-  GURL url = test_server()->GetURL(kTestingPage);
+  GURL url = embedded_test_server()->GetURL(kTestingPage);
   ui_test_utils::NavigateToURL(browser(), url);
 
   ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER));
@@ -863,10 +863,10 @@
       "U 17 0 true false false false" }
   };
 
-  ASSERT_TRUE(test_server()->Start());
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
 
   ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
-  GURL url = test_server()->GetURL(kTestingPage);
+  GURL url = embedded_test_server()->GetURL(kTestingPage);
   ui_test_utils::NavigateToURL(browser(), url);
 
   ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER));
diff --git a/chrome/browser/browser_process.h b/chrome/browser/browser_process.h
index d6f8595..0824b1c 100644
--- a/chrome/browser/browser_process.h
+++ b/chrome/browser/browser_process.h
@@ -13,6 +13,7 @@
 #include <string>
 
 #include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
 #include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/ui/host_desktop.h"
 
@@ -175,6 +176,8 @@
 
   // Returns the object that manages background applications.
   virtual BackgroundModeManager* background_mode_manager() = 0;
+  virtual void set_background_mode_manager_for_test(
+      scoped_ptr<BackgroundModeManager> manager) = 0;
 
   // Returns the StatusTray, which provides an API for displaying status icons
   // in the system status tray. Returns NULL if status icons are not supported
diff --git a/chrome/browser/browser_process_impl.cc b/chrome/browser/browser_process_impl.cc
index 44bf2da..6673807 100644
--- a/chrome/browser/browser_process_impl.cc
+++ b/chrome/browser/browser_process_impl.cc
@@ -704,6 +704,11 @@
 #endif
 }
 
+void BrowserProcessImpl::set_background_mode_manager_for_test(
+    scoped_ptr<BackgroundModeManager> manager) {
+  background_mode_manager_ = manager.Pass();
+}
+
 StatusTray* BrowserProcessImpl::status_tray() {
   DCHECK(CalledOnValidThread());
   if (!status_tray_.get())
diff --git a/chrome/browser/browser_process_impl.h b/chrome/browser/browser_process_impl.h
index 201eb92..66191dc 100644
--- a/chrome/browser/browser_process_impl.h
+++ b/chrome/browser/browser_process_impl.h
@@ -18,7 +18,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/prefs/pref_change_registrar.h"
 #include "base/threading/non_thread_safe.h"
-#include "base/timer.h"
+#include "base/timer/timer.h"
 #include "chrome/browser/browser_process.h"
 
 class ChromeNetLog;
@@ -110,6 +110,8 @@
   virtual DownloadStatusUpdater* download_status_updater() OVERRIDE;
   virtual DownloadRequestLimiter* download_request_limiter() OVERRIDE;
   virtual BackgroundModeManager* background_mode_manager() OVERRIDE;
+  virtual void set_background_mode_manager_for_test(
+      scoped_ptr<BackgroundModeManager> manager) OVERRIDE;
   virtual StatusTray* status_tray() OVERRIDE;
   virtual SafeBrowsingService* safe_browsing_service() OVERRIDE;
   virtual safe_browsing::ClientSideDetectionService*
diff --git a/chrome/browser/browser_process_platform_part_aurawin.cc b/chrome/browser/browser_process_platform_part_aurawin.cc
index e6be06d..34813a6 100644
--- a/chrome/browser/browser_process_platform_part_aurawin.cc
+++ b/chrome/browser/browser_process_platform_part_aurawin.cc
@@ -24,13 +24,23 @@
 
 void BrowserProcessPlatformPart::PlatformSpecificCommandLineProcessing(
     const CommandLine& command_line) {
-  if (base::win::GetVersion() >= base::win::VERSION_WIN8 &&
-      command_line.HasSwitch(switches::kViewerConnection) &&
-      !metro_viewer_process_host_.get()) {
-    // Tell the metro viewer process host to connect to the given IPC channel.
-    metro_viewer_process_host_.reset(
-        new ChromeMetroViewerProcessHost(
-            command_line.GetSwitchValueASCII(switches::kViewerConnection)));
+  // Check for Windows 8 specific commandlines requesting that this process
+  // either connect to an existing viewer or launch a new viewer and
+  // synchronously wait for it to connect.
+  if (base::win::GetVersion() >= base::win::VERSION_WIN8) {
+    bool launch = command_line.HasSwitch(switches::kViewerLaunchViaAppId);
+    bool connect = (launch ||
+                    (command_line.HasSwitch(switches::kViewerConnect) &&
+                     !metro_viewer_process_host_.get()));
+    if (connect) {
+      // Create a host to connect to the Metro viewer process over IPC.
+      metro_viewer_process_host_.reset(new ChromeMetroViewerProcessHost());
+      if (launch) {
+        CHECK(metro_viewer_process_host_->LaunchViewerAndWaitForConnection(
+            command_line.GetSwitchValueNative(
+                switches::kViewerLaunchViaAppId)));
+      }
+    }
   }
 }
 
diff --git a/chrome/browser/browser_process_platform_part_chromeos.cc b/chrome/browser/browser_process_platform_part_chromeos.cc
index 11cacb3..1821785 100644
--- a/chrome/browser/browser_process_platform_part_chromeos.cc
+++ b/chrome/browser/browser_process_platform_part_chromeos.cc
@@ -4,8 +4,12 @@
 
 #include "chrome/browser/browser_process_platform_part_chromeos.h"
 
+#include "base/logging.h"
+#include "base/time/default_tick_clock.h"
+#include "base/time/tick_clock.h"
 #include "chrome/browser/chromeos/memory/oom_priority_manager.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
+#include "chrome/browser/chromeos/system/automatic_reboot_manager.h"
 
 BrowserProcessPlatformPart::BrowserProcessPlatformPart()
     : created_profile_helper_(false) {
@@ -14,6 +18,17 @@
 BrowserProcessPlatformPart::~BrowserProcessPlatformPart() {
 }
 
+void BrowserProcessPlatformPart::InitializeAutomaticRebootManager() {
+  DCHECK(!automatic_reboot_manager_);
+
+  automatic_reboot_manager_.reset(new chromeos::system::AutomaticRebootManager(
+      scoped_ptr<base::TickClock>(new base::DefaultTickClock)));
+}
+
+void BrowserProcessPlatformPart::ShutdownAutomaticRebootManager() {
+  automatic_reboot_manager_.reset();
+}
+
 chromeos::OomPriorityManager*
     BrowserProcessPlatformPart::oom_priority_manager() {
   DCHECK(CalledOnValidThread());
diff --git a/chrome/browser/browser_process_platform_part_chromeos.h b/chrome/browser/browser_process_platform_part_chromeos.h
index 3eb1236..08dc683 100644
--- a/chrome/browser/browser_process_platform_part_chromeos.h
+++ b/chrome/browser/browser_process_platform_part_chromeos.h
@@ -15,12 +15,21 @@
 class ProfileHelper;
 }
 
+namespace chromeos {
+namespace system {
+class AutomaticRebootManager;
+}
+}
+
 class BrowserProcessPlatformPart : public BrowserProcessPlatformPartBase,
                                    public base::NonThreadSafe {
  public:
   BrowserProcessPlatformPart();
   virtual ~BrowserProcessPlatformPart();
 
+  void InitializeAutomaticRebootManager();
+  void ShutdownAutomaticRebootManager();
+
   // Returns the out-of-memory priority manager.
   virtual chromeos::OomPriorityManager* oom_priority_manager();
 
@@ -31,6 +40,10 @@
   // Overridden from BrowserProcessPlatformPartBase:
   virtual void StartTearDown() OVERRIDE;
 
+  chromeos::system::AutomaticRebootManager* automatic_reboot_manager() {
+    return automatic_reboot_manager_.get();
+  }
+
  protected:
   virtual void CreateProfileHelper();
 
@@ -40,6 +53,9 @@
  private:
   scoped_ptr<chromeos::OomPriorityManager> oom_priority_manager_;
 
+  scoped_ptr<chromeos::system::AutomaticRebootManager>
+      automatic_reboot_manager_;
+
   DISALLOW_COPY_AND_ASSIGN(BrowserProcessPlatformPart);
 };
 
diff --git a/chrome/browser/browser_resources.grd b/chrome/browser/browser_resources.grd
index 24678bd..749ac3a 100644
--- a/chrome/browser/browser_resources.grd
+++ b/chrome/browser/browser_resources.grd
@@ -35,6 +35,8 @@
       <structure name="IDR_EXTENSIONS_HTML" file="resources\extensions\extensions.html" flattenhtml="true" type="chrome_html" />
       <structure name="IDR_HELP_CSS" file="resources\help\help.css" flattenhtml="true" type="chrome_html" />
       <structure name="IDR_HELP_HTML" file="resources\help\help.html" flattenhtml="true" type="chrome_html" />
+      <structure name="IDR_HELP_CHANNEL_CHANGE_PAGE_CSS" file="resources\help\channel_change_page.css" flattenhtml="true" type="chrome_html" />
+      <structure name="IDR_HELP_CHANNEL_CHANGE_PAGE_HTML" file="resources\help\channel_change_page.html" flattenhtml="true" type="chrome_html" />
       <structure name="IDR_INCOGNITO_TAB_HTML" file="resources\incognito_tab.html" flattenhtml="true" type="chrome_html" />
       <if expr="pp_ifdef('chromeos')">
         <structure name="IDR_LOGIN_HTML" file="resources\chromeos\login\login.html" flattenhtml="true" type="chrome_html" variables="OOBE=login" expand_variables="true"/>
@@ -93,9 +95,6 @@
       </if>
       <if expr="pp_ifdef('enable_printing')">
         <include name="IDR_CLOUDPRINT_MANIFEST" file="resources\cloud_print_app\manifest.json" type="BINDATA" />
-        <include name="IDR_CLOUD_PRINT_SETUP_DONE_HTML" file="resources\cloud_print\cloud_print_setup_done.html" flattenhtml="true" type="BINDATA" />
-        <include name="IDR_CLOUD_PRINT_SETUP_FLOW_HTML" file="resources\cloud_print\cloud_print_setup_flow.html" flattenhtml="true" type="BINDATA" />
-        <include name="IDR_CLOUD_PRINT_SETUP_LOGIN_HTML" file="resources\cloud_print\cloud_print_setup_login.html" flattenhtml="true" type="BINDATA" />
       </if>
       <include name="IDR_CRASHES_HTML" file="resources\crashes.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" />
       <include name="IDR_CRASHES_JS" file="resources\crashes.js" type="BINDATA" />
@@ -120,10 +119,8 @@
       </if>
       <include name="IDR_FLAGS_HTML" file="resources\flags.html" flattenhtml="true" type="BINDATA" />
       <include name="IDR_FLAGS_JS" file="resources\flags.js" type="BINDATA" />
-      <if expr="not is_android">
-        <include name="IDR_GAIA_LOGIN_HTML" file="sync\resources\gaia_login.html" flattenhtml="true" type="BINDATA" />
-      </if>
       <include name="IDR_HELP_JS" file="resources\help\help.js" flattenhtml="true" type="BINDATA" />
+      <include name="IDR_CHANNEL_CHANGE_PAGE_JS" file="resources\help\channel_change_page.js" flattenhtml="true" type="BINDATA" />
       <include name="IDR_HISTORY_HTML" file="resources\history\history.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" />
       <include name="IDR_HISTORY_JS" file="resources\history\history.js" flattenhtml="true" type="BINDATA" />
       <include name="IDR_OTHER_DEVICES_JS" file="resources\history\other_devices.js" flattenhtml="true" type="BINDATA" />
@@ -158,9 +155,7 @@
       <include name="IDR_LOCAL_NTP_HTML" file="resources\local_ntp\local_ntp.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" />
       <include name="IDR_LOCAL_NTP_CSS" file="resources\local_ntp\local_ntp.css" type="BINDATA" />
       <include name="IDR_LOCAL_NTP_JS" file="resources\local_ntp\local_ntp.js" flattenhtml="true" type="BINDATA" />
-      <include name="IDR_LOCAL_NTP_IMAGES_LOGO_PNG" file="resources\local_ntp\images\ntp_google_logo.png" type="BINDATA" />
       <include name="IDR_LOCAL_NTP_IMAGES_2X_LOGO_PNG" file="resources\local_ntp\images\2x\ntp_google_logo.png" type="BINDATA" />
-      <include name="IDR_LOCAL_NTP_IMAGES_WHITE_LOGO_PNG" file="resources\local_ntp\images\ntp_white_google_logo.png" type="BINDATA" />
       <include name="IDR_LOCAL_NTP_IMAGES_2X_WHITE_LOGO_PNG" file="resources\local_ntp\images\2x\ntp_white_google_logo.png" type="BINDATA" />
       <include name="IDR_LOCAL_OMNIBOX_POPUP_IMAGES_HISTORY_ICON_PNG" file="resources\local_omnibox_popup\images\history_icon.png" type="BINDATA" />
       <include name="IDR_LOCAL_OMNIBOX_POPUP_IMAGES_2X_HISTORY_ICON_PNG" file="resources\local_omnibox_popup\images\2x\history_icon.png" type="BINDATA" />
@@ -259,6 +254,10 @@
       <include name="IDR_USER_ACTIONS_HTML" file="resources\user_actions\user_actions.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" />
       <include name="IDR_USER_ACTIONS_CSS" file="resources\user_actions\user_actions.css" type="BINDATA" />
       <include name="IDR_USER_ACTIONS_JS" file="resources\user_actions\user_actions.js" type="BINDATA" />
+      <if expr="pp_ifdef('enable_webrtc')">
+        <include name="IDR_WEBRTC_LOGS_HTML" file="resources\media\webrtc_logs.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" />
+        <include name="IDR_WEBRTC_LOGS_JS" file="resources\media\webrtc_logs.js" type="BINDATA" />
+      </if>
       <include name="IDR_WEBSTORE_MANIFEST" file="resources\webstore_app\manifest.json" type="BINDATA" />
       <if expr="pp_ifdef('use_ash')">
         <include name="IDR_TASK_MANAGER_HTML" file="resources\task_manager\main.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" />
@@ -274,7 +273,6 @@
       </if>
       <include name="IDR_GAIA_AUTH_MANIFEST" file="resources\gaia_auth\manifest.json" type="BINDATA" />
       <include name="IDR_GAIA_AUTH_KEYBOARD_MANIFEST" file="resources\gaia_auth\manifest_keyboard.json" type="BINDATA" />
-      <include name="IDR_GAIA_TEST_AUTH_MANIFEST" file="resources\gaia_auth\manifest_test.json" type="BINDATA" />
       <if expr="pp_ifdef('chromeos')">
         <include name="IDR_ABOUT_SYS_HTML" file="resources\chromeos\about_sys.html" flattenhtml="true" type="BINDATA" />
         <include name="IDR_BACKLOADER_MANIFEST" file="resources\backloader\manifest.json" type="BINDATA" />
@@ -341,6 +339,11 @@
         <include name="IDR_QUICKOFFICE_EDITOR_MANIFEST"
         file="resources\quick_office\manifest_experimental.json" type="BINDATA" />
       </if>
+      <if expr="pp_ifdef('chromeos')">
+        <include name="IDR_SALSA_CSS" file="resources\chromeos\salsa.css" type="BINDATA" />
+        <include name="IDR_SALSA_HTML" file="resources\chromeos\salsa.html" type="BINDATA" />
+        <include name="IDR_SALSA_JS" file="resources\chromeos\salsa.js" type="BINDATA" />
+      </if>
       <if expr="pp_ifdef('use_ash')">
         <include name="IDR_GESTURE_CONFIG_CSS" file="resources\gesture_config.css" type="BINDATA" />
         <include name="IDR_GESTURE_CONFIG_HTML" file="resources\gesture_config.html" type="BINDATA" />
diff --git a/chrome/browser/browser_shutdown.cc b/chrome/browser/browser_shutdown.cc
index e9f7a8a..9cc661b 100644
--- a/chrome/browser/browser_shutdown.cc
+++ b/chrome/browser/browser_shutdown.cc
@@ -20,7 +20,7 @@
 #include "base/strings/stringprintf.h"
 #include "base/threading/thread.h"
 #include "base/threading/thread_restrictions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "build/build_config.h"
 #include "chrome/browser/about_flags.h"
 #include "chrome/browser/browser_process.h"
@@ -267,7 +267,7 @@
   int64 shutdown_ms = 0;
   if (file_util::ReadFileToString(shutdown_ms_file, &shutdown_ms_str))
     base::StringToInt64(shutdown_ms_str, &shutdown_ms);
-  file_util::Delete(shutdown_ms_file, false);
+  base::Delete(shutdown_ms_file, false);
 
   if (type == NOT_VALID || shutdown_ms == 0 || num_procs == 0)
     return;
diff --git a/chrome/browser/browsing_data/browsing_data_appcache_helper.h b/chrome/browser/browsing_data/browsing_data_appcache_helper.h
index 46ea34e..6f3ac7a 100644
--- a/chrome/browser/browsing_data/browsing_data_appcache_helper.h
+++ b/chrome/browser/browsing_data/browsing_data_appcache_helper.h
@@ -7,8 +7,8 @@
 
 #include "base/callback.h"
 #include "base/memory/ref_counted.h"
-#include "googleurl/src/gurl.h"
 #include "net/base/completion_callback.h"
+#include "url/gurl.h"
 #include "webkit/browser/appcache/appcache_service.h"
 
 class Profile;
diff --git a/chrome/browser/browsing_data/browsing_data_cookie_helper.cc b/chrome/browser/browsing_data/browsing_data_cookie_helper.cc
index f5819af..5551642 100644
--- a/chrome/browser/browsing_data/browsing_data_cookie_helper.cc
+++ b/chrome/browser/browsing_data/browsing_data_cookie_helper.cc
@@ -12,13 +12,13 @@
 #include "base/stl_util.h"
 #include "chrome/browser/profiles/profile.h"
 #include "content/public/browser/browser_thread.h"
-#include "googleurl/src/gurl.h"
 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
 #include "net/cookies/canonical_cookie.h"
 #include "net/cookies/cookie_util.h"
 #include "net/cookies/parsed_cookie.h"
 #include "net/url_request/url_request_context.h"
 #include "net/url_request/url_request_context_getter.h"
+#include "url/gurl.h"
 
 using content::BrowserThread;
 
diff --git a/chrome/browser/browsing_data/browsing_data_cookie_helper_unittest.cc b/chrome/browser/browsing_data/browsing_data_cookie_helper_unittest.cc
index a54b9bd..968a733 100644
--- a/chrome/browser/browsing_data/browsing_data_cookie_helper_unittest.cc
+++ b/chrome/browser/browsing_data/browsing_data_cookie_helper_unittest.cc
@@ -4,12 +4,11 @@
 
 #include "chrome/browser/browsing_data/browsing_data_cookie_helper.h"
 
-
 #include "base/bind.h"
 #include "base/message_loop.h"
-#include "base/synchronization/waitable_event.h"
 #include "chrome/test/base/testing_profile.h"
 #include "content/public/test/test_browser_thread.h"
+#include "content/public/test/test_browser_thread_bundle.h"
 #include "net/cookies/canonical_cookie.h"
 #include "net/cookies/parsed_cookie.h"
 #include "net/url_request/url_request_context_getter.h"
@@ -21,7 +20,7 @@
 
 class BrowsingDataCookieHelperTest : public testing::Test {
  public:
-  void SetUpOnIOThread(base::WaitableEvent* io_setup_complete) {
+  void SetUpOnIOThread() {
     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
     // This is a workaround for a bug in the TestingProfile.
     // The URLRequestContext will be created by GetCookieMonster on the UI
@@ -30,31 +29,21 @@
     // Force it to be created here.
     testing_profile_->CreateRequestContext();
     testing_profile_->GetRequestContext()->GetURLRequestContext();
-    io_setup_complete->Signal();
   }
 
   virtual void SetUp() {
-    ui_thread_.reset(new content::TestBrowserThread(BrowserThread::UI,
-                                                    &message_loop_));
-    // Note: we're starting a real IO thread because parts of the
-    // BrowsingDataCookieHelper expect to run on that thread.
-    io_thread_.reset(new content::TestBrowserThread(BrowserThread::IO));
-    ASSERT_TRUE(io_thread_->Start());
     testing_profile_.reset(new TestingProfile());
-    base::WaitableEvent io_setup_complete(true, false);
     BrowserThread::PostTask(
         BrowserThread::IO, FROM_HERE,
         base::Bind(&BrowsingDataCookieHelperTest::SetUpOnIOThread,
-                   base::Unretained(this), &io_setup_complete));
-    io_setup_complete.Wait();
+                   base::Unretained(this)));
+    base::MessageLoop::current()->RunUntilIdle();
   }
 
   virtual void TearDown() {
     // This must be reset before the IO thread stops, because the
     // URLRequestContextGetter forces its own deletion to occur on that thread.
     testing_profile_->ResetRequestContext();
-    io_thread_.reset();
-    ui_thread_.reset();
   }
 
   void CreateCookiesForTest() {
@@ -209,9 +198,7 @@
   }
 
  protected:
-  base::MessageLoop message_loop_;
-  scoped_ptr<content::TestBrowserThread> ui_thread_;
-  scoped_ptr<content::TestBrowserThread> io_thread_;
+  content::TestBrowserThreadBundle thread_bundle_;
   scoped_ptr<TestingProfile> testing_profile_;
 
   net::CookieList cookie_list_;
diff --git a/chrome/browser/browsing_data/browsing_data_database_helper.cc b/chrome/browser/browsing_data/browsing_data_database_helper.cc
index c010e10..f41705a 100644
--- a/chrome/browser/browsing_data/browsing_data_database_helper.cc
+++ b/chrome/browser/browsing_data/browsing_data_database_helper.cc
@@ -17,25 +17,21 @@
 #include "net/base/net_errors.h"
 #include "third_party/WebKit/public/platform/WebCString.h"
 #include "third_party/WebKit/public/platform/WebString.h"
-#include "third_party/WebKit/public/web/WebSecurityOrigin.h"
+#include "webkit/common/database/database_identifier.h"
 
 using content::BrowserContext;
 using content::BrowserThread;
-using WebKit::WebSecurityOrigin;
+using webkit_database::DatabaseIdentifier;
 
 BrowsingDataDatabaseHelper::DatabaseInfo::DatabaseInfo(
-    const std::string& host,
+    const DatabaseIdentifier& identifier,
     const std::string& database_name,
-    const std::string& origin_identifier,
     const std::string& description,
-    const std::string& origin,
     int64 size,
     base::Time last_modified)
-    : host(host),
+    : identifier(identifier),
       database_name(database_name),
-      origin_identifier(origin_identifier),
       description(description),
-      origin(origin),
       size(size),
       last_modified(last_modified) {
 }
@@ -81,11 +77,9 @@
   if (tracker_.get() && tracker_->GetAllOriginsInfo(&origins_info)) {
     for (std::vector<webkit_database::OriginInfo>::const_iterator ori =
          origins_info.begin(); ori != origins_info.end(); ++ori) {
-      WebSecurityOrigin web_security_origin =
-          WebSecurityOrigin::createFromDatabaseIdentifier(
-              WebKit::WebString::fromUTF8(ori->GetOriginIdentifier()));
-      GURL origin_url(web_security_origin.toString().utf8());
-      if (!BrowsingDataHelper::HasWebScheme(origin_url)) {
+      DatabaseIdentifier identifier =
+          DatabaseIdentifier::Parse(ori->GetOriginIdentifier());
+      if (!BrowsingDataHelper::HasWebScheme(identifier.ToOrigin())) {
         // Non-websafe state is not considered browsing data.
         continue;
       }
@@ -98,11 +92,9 @@
         base::PlatformFileInfo file_info;
         if (file_util::GetFileInfo(file_path, &file_info)) {
           database_info_.push_back(DatabaseInfo(
-                web_security_origin.host().utf8(),
+                identifier,
                 UTF16ToUTF8(*db),
-                ori->GetOriginIdentifier(),
                 UTF16ToUTF8(ori->GetDatabaseDescription(*db)),
-                origin_url.spec(),
                 file_info.size,
                 file_info.last_modified));
         }
@@ -163,7 +155,6 @@
   CannedBrowsingDataDatabaseHelper* clone =
       new CannedBrowsingDataDatabaseHelper(profile_);
 
-  base::AutoLock auto_lock(lock_);
   clone->pending_database_info_ = pending_database_info_;
   return clone;
 }
@@ -173,7 +164,6 @@
     const std::string& name,
     const std::string& description) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  base::AutoLock auto_lock(lock_);
   if (BrowsingDataHelper::HasWebScheme(origin)) {
     pending_database_info_.insert(PendingDatabaseInfo(
           origin, name, description));
@@ -181,17 +171,17 @@
 }
 
 void CannedBrowsingDataDatabaseHelper::Reset() {
-  base::AutoLock auto_lock(lock_);
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   pending_database_info_.clear();
 }
 
 bool CannedBrowsingDataDatabaseHelper::empty() const {
-  base::AutoLock auto_lock(lock_);
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   return pending_database_info_.empty();
 }
 
 size_t CannedBrowsingDataDatabaseHelper::GetDatabaseCount() const {
-  base::AutoLock auto_lock(lock_);
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   return pending_database_info_.size();
 }
 
@@ -208,32 +198,18 @@
 
   is_fetching_ = true;
   completion_callback_ = callback;
-  BrowserThread::PostTask(
-      BrowserThread::WEBKIT_DEPRECATED, FROM_HERE,
-      base::Bind(&CannedBrowsingDataDatabaseHelper::ConvertInfoInWebKitThread,
-                 this));
-}
 
-CannedBrowsingDataDatabaseHelper::~CannedBrowsingDataDatabaseHelper() {}
-
-void CannedBrowsingDataDatabaseHelper::ConvertInfoInWebKitThread() {
-  base::AutoLock auto_lock(lock_);
   database_info_.clear();
   for (std::set<PendingDatabaseInfo>::const_iterator
        info = pending_database_info_.begin();
        info != pending_database_info_.end(); ++info) {
-    WebSecurityOrigin web_security_origin =
-        WebSecurityOrigin::createFromString(
-            UTF8ToUTF16(info->origin.spec()));
-    std::string origin_identifier =
-        web_security_origin.databaseIdentifier().utf8();
+    DatabaseIdentifier identifier =
+        DatabaseIdentifier::CreateFromOrigin(info->origin);
 
     database_info_.push_back(DatabaseInfo(
-        web_security_origin.host().utf8(),
+        identifier,
         info->name,
-        origin_identifier,
         info->description,
-        web_security_origin.toString().utf8(),
         0,
         base::Time()));
   }
@@ -242,3 +218,5 @@
       BrowserThread::UI, FROM_HERE,
       base::Bind(&CannedBrowsingDataDatabaseHelper::NotifyInUIThread, this));
 }
+
+CannedBrowsingDataDatabaseHelper::~CannedBrowsingDataDatabaseHelper() {}
diff --git a/chrome/browser/browsing_data/browsing_data_database_helper.h b/chrome/browser/browsing_data/browsing_data_database_helper.h
index 155653a..963f178 100644
--- a/chrome/browser/browsing_data/browsing_data_database_helper.h
+++ b/chrome/browser/browsing_data/browsing_data_database_helper.h
@@ -14,8 +14,9 @@
 #include "base/memory/ref_counted.h"
 #include "base/synchronization/lock.h"
 #include "chrome/common/url_constants.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 #include "webkit/browser/database/database_tracker.h"
+#include "webkit/common/database/database_identifier.h"
 
 class Profile;
 
@@ -29,20 +30,16 @@
  public:
   // Contains detailed information about a web database.
   struct DatabaseInfo {
-    DatabaseInfo(const std::string& host,
+    DatabaseInfo(const webkit_database::DatabaseIdentifier& identifier,
                  const std::string& database_name,
-                 const std::string& origin_identifier,
                  const std::string& description,
-                 const std::string& origin,
                  int64 size,
                  base::Time last_modified);
     ~DatabaseInfo();
 
-    std::string host;
+    webkit_database::DatabaseIdentifier identifier;
     std::string database_name;
-    std::string origin_identifier;
     std::string description;
-    std::string origin;
     int64 size;
     base::Time last_modified;
   };
@@ -57,7 +54,7 @@
 
   // Requests a single database to be deleted in the FILE thread. This must be
   // called in the UI thread.
-  virtual void DeleteDatabase(const std::string& origin,
+  virtual void DeleteDatabase(const std::string& origin_identifier,
                               const std::string& name);
 
  protected:
@@ -149,14 +146,6 @@
  private:
   virtual ~CannedBrowsingDataDatabaseHelper();
 
-  // Converts the pending database info structs to database info structs.
-  void ConvertInfoInWebKitThread();
-
-  // Used to protect access to pending_database_info_.
-  mutable base::Lock lock_;
-
-  // Access to |pending_database_info_| is protected by |lock_| since it may
-  // be accessed on the UI or the WEBKIT thread.
   std::set<PendingDatabaseInfo> pending_database_info_;
 
   Profile* profile_;
diff --git a/chrome/browser/browsing_data/browsing_data_database_helper_browsertest.cc b/chrome/browser/browsing_data/browsing_data_database_helper_browsertest.cc
index d8a9642..ab1ea67 100644
--- a/chrome/browser/browsing_data/browsing_data_database_helper_browsertest.cc
+++ b/chrome/browser/browsing_data/browsing_data_database_helper_browsertest.cc
@@ -71,7 +71,7 @@
     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     ASSERT_EQ(1UL, database_info_list.size());
     EXPECT_EQ(std::string(kTestIdentifier1),
-              database_info_list.begin()->origin_identifier);
+              database_info_list.begin()->identifier.ToString());
     base::MessageLoop::current()->Quit();
   }
 
@@ -117,13 +117,13 @@
   ASSERT_EQ(3u, result.size());
   std::list<BrowsingDataDatabaseHelper::DatabaseInfo>::iterator info =
       result.begin();
-  EXPECT_STREQ(origin_str1, info->origin_identifier.c_str());
+  EXPECT_EQ(origin_str1, info->identifier.ToString());
   EXPECT_STREQ(db1, info->database_name.c_str());
   info++;
-  EXPECT_STREQ(origin_str1, info->origin_identifier.c_str());
+  EXPECT_EQ(origin_str1, info->identifier.ToString());
   EXPECT_STREQ(db2, info->database_name.c_str());
   info++;
-  EXPECT_STREQ(origin_str2, info->origin_identifier.c_str());
+  EXPECT_EQ(origin_str2, info->identifier.ToString());
   EXPECT_STREQ(db3, info->database_name.c_str());
 }
 
@@ -146,7 +146,7 @@
       callback.result();
 
   ASSERT_EQ(1u, result.size());
-  EXPECT_STREQ(origin_str, result.begin()->origin_identifier.c_str());
+  EXPECT_EQ(origin_str, result.begin()->identifier.ToString());
   EXPECT_STREQ(db, result.begin()->database_name.c_str());
 }
 }  // namespace
diff --git a/chrome/browser/browsing_data/browsing_data_file_system_helper.cc b/chrome/browser/browsing_data/browsing_data_file_system_helper.cc
index b86cc2f..70a7155 100644
--- a/chrome/browser/browsing_data/browsing_data_file_system_helper.cc
+++ b/chrome/browser/browsing_data/browsing_data_file_system_helper.cc
@@ -122,41 +122,40 @@
 
 void BrowsingDataFileSystemHelperImpl::FetchFileSystemInfoInFileThread() {
   DCHECK(file_task_runner()->RunsTasksOnCurrentThread());
-  scoped_ptr<fileapi::SandboxMountPointProvider::OriginEnumerator>
-      origin_enumerator(filesystem_context_->
-          sandbox_provider()->CreateOriginEnumerator());
 
-  // We don't own this pointer; it's a magic singleton generated by the
-  // profile's FileSystemContext. Deleting it would be a bad idea.
-  fileapi::FileSystemQuotaUtil* quota_util =
-     filesystem_context_->GetQuotaUtil(fileapi::kFileSystemTypeTemporary);
+  // We check usage for these filesystem types.
+  const fileapi::FileSystemType types[] = {
+    fileapi::kFileSystemTypeTemporary,
+    fileapi::kFileSystemTypePersistent,
+    fileapi::kFileSystemTypeSyncable,
+  };
 
-  GURL current;
+  typedef std::map<GURL, FileSystemInfo> OriginInfoMap;
+  OriginInfoMap file_system_info_map;
+  for (size_t i = 0; i < arraysize(types); ++i) {
+    fileapi::FileSystemType type = types[i];
+    fileapi::FileSystemQuotaUtil* quota_util =
+      filesystem_context_->GetQuotaUtil(type);
+    DCHECK(quota_util);
+    std::set<GURL> origins;
+    quota_util->GetOriginsForTypeOnFileThread(type, &origins);
+    for (std::set<GURL>::iterator iter = origins.begin();
+        iter != origins.end(); ++iter) {
+      const GURL& current = *iter;
+      if (!BrowsingDataHelper::HasWebScheme(current))
+        continue;  // Non-websafe state is not considered browsing data.
+      int64 usage = quota_util->GetOriginUsageOnFileThread(
+          filesystem_context_.get(), current, type);
+      OriginInfoMap::iterator inserted =
+          file_system_info_map.insert(
+              std::make_pair(current, FileSystemInfo(current))).first;
+      inserted->second.usage_map[type] = usage;
+    }
+  }
 
-  while (!(current = origin_enumerator->Next()).is_empty()) {
-    if (!BrowsingDataHelper::HasWebScheme(current))
-      continue;  // Non-websafe state is not considered browsing data.
-
-    // We can call these synchronous methods as we've already verified that
-    // we're running on the file task runner.
-    int64 persistent_usage = quota_util->GetOriginUsageOnFileThread(
-        filesystem_context_.get(), current, fileapi::kFileSystemTypePersistent);
-    int64 temporary_usage = quota_util->GetOriginUsageOnFileThread(
-        filesystem_context_.get(), current, fileapi::kFileSystemTypeTemporary);
-    int64 syncable_usage = quota_util->GetOriginUsageOnFileThread(
-        filesystem_context_.get(), current, fileapi::kFileSystemTypeSyncable);
-    file_system_info_.push_back(
-        FileSystemInfo(
-            current,
-            origin_enumerator->HasFileSystemType(
-                fileapi::kFileSystemTypePersistent),
-            origin_enumerator->HasFileSystemType(
-                fileapi::kFileSystemTypeTemporary),
-            origin_enumerator->HasFileSystemType(
-                fileapi::kFileSystemTypeSyncable),
-            persistent_usage,
-            temporary_usage,
-            syncable_usage));
+  for (OriginInfoMap::iterator iter = file_system_info_map.begin();
+       iter != file_system_info_map.end(); ++iter) {
+    file_system_info_.push_back(iter->second);
   }
 
   BrowserThread::PostTask(
@@ -181,21 +180,7 @@
 }  // namespace
 
 BrowsingDataFileSystemHelper::FileSystemInfo::FileSystemInfo(
-    const GURL& origin,
-    bool has_persistent,
-    bool has_temporary,
-    bool has_syncable,
-    int64 usage_persistent,
-    int64 usage_temporary,
-    int64 usage_syncable)
-    : origin(origin),
-      has_persistent(has_persistent),
-      has_temporary(has_temporary),
-      has_syncable(has_syncable),
-      usage_persistent(usage_persistent),
-      usage_temporary(usage_temporary),
-      usage_syncable(usage_syncable) {
-}
+    const GURL& origin) : origin(origin) {}
 
 BrowsingDataFileSystemHelper::FileSystemInfo::~FileSystemInfo() {}
 
@@ -240,16 +225,7 @@
        file_system != file_system_info_.end();
        ++file_system) {
     if (file_system->origin == origin) {
-      if (type == fileapi::kFileSystemTypePersistent) {
-        file_system->has_persistent = true;
-        file_system->usage_persistent = size;
-      } else if (type == fileapi::kFileSystemTypeTemporary) {
-        file_system->has_temporary = true;
-        file_system->usage_temporary = size;
-      } else {
-        file_system->has_syncable = true;
-        file_system->usage_syncable = size;
-      }
+      file_system->usage_map[type] = size;
       duplicate_origin = true;
       break;
     }
@@ -260,14 +236,9 @@
   if (!BrowsingDataHelper::HasWebScheme(origin))
     return;  // Non-websafe state is not considered browsing data.
 
-  file_system_info_.push_back(FileSystemInfo(
-      origin,
-      (type == fileapi::kFileSystemTypePersistent),
-      (type == fileapi::kFileSystemTypeTemporary),
-      (type == fileapi::kFileSystemTypeSyncable),
-      (type == fileapi::kFileSystemTypePersistent) ? size : 0,
-      (type == fileapi::kFileSystemTypeTemporary) ? size : 0,
-      (type == fileapi::kFileSystemTypeSyncable) ? size : 0));
+  FileSystemInfo info(origin);
+  info.usage_map[type] = size;
+  file_system_info_.push_back(info);
 }
 
 void CannedBrowsingDataFileSystemHelper::Reset() {
diff --git a/chrome/browser/browsing_data/browsing_data_file_system_helper.h b/chrome/browser/browsing_data/browsing_data_file_system_helper.h
index 6b5dc4a..d0c1b6f 100644
--- a/chrome/browser/browsing_data/browsing_data_file_system_helper.h
+++ b/chrome/browser/browsing_data/browsing_data_file_system_helper.h
@@ -6,6 +6,7 @@
 #define CHROME_BROWSER_BROWSING_DATA_BROWSING_DATA_FILE_SYSTEM_HELPER_H_
 
 #include <list>
+#include <map>
 #include <string>
 
 #include "base/callback.h"
@@ -14,7 +15,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/synchronization/lock.h"
 #include "chrome/common/url_constants.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 #include "webkit/common/fileapi/file_system_types.h"
 
 namespace fileapi {
@@ -43,33 +44,15 @@
     : public base::RefCountedThreadSafe<BrowsingDataFileSystemHelper> {
  public:
   // Detailed information about a file system, including it's origin GURL,
-  // the presence or absence of persistent and temporary storage, and the
-  // amount of data (in bytes) each contains.
+  // the amount of data (in bytes) for each sandboxed filesystem type.
   struct FileSystemInfo {
-    FileSystemInfo(
-        const GURL& origin,
-        bool has_persistent,
-        bool has_temporary,
-        bool has_syncable,
-        int64 usage_persistent,
-        int64 usage_temporary,
-        int64 usage_syncable);
+    FileSystemInfo(const GURL& origin);
     ~FileSystemInfo();
 
     // The origin for which the information is relevant.
     GURL origin;
-    // True if the origin has a persistent file system.
-    bool has_persistent;
-    // True if the origin has a temporary file system.
-    bool has_temporary;
-    // True if the origin has a syncable file system.
-    bool has_syncable;
-    // Persistent file system usage, in bytes.
-    int64 usage_persistent;
-    // Temporary file system usage, in bytes.
-    int64 usage_temporary;
-    // Syncable file system usage, in bytes.
-    int64 usage_syncable;
+    // FileSystemType to usage (in bytes) map.
+    std::map<fileapi::FileSystemType, int64> usage_map;
   };
 
   // Creates a BrowsingDataFileSystemHelper instance for the file systems
diff --git a/chrome/browser/browsing_data/browsing_data_file_system_helper_unittest.cc b/chrome/browser/browsing_data/browsing_data_file_system_helper_unittest.cc
index ad756e4..3ac40a5 100644
--- a/chrome/browser/browsing_data/browsing_data_file_system_helper_unittest.cc
+++ b/chrome/browser/browsing_data/browsing_data_file_system_helper_unittest.cc
@@ -9,15 +9,16 @@
 #include "base/file_util.h"
 #include "base/message_loop.h"
 #include "base/platform_file.h"
+#include "base/stl_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/browsing_data/browsing_data_file_system_helper.h"
 #include "chrome/test/base/testing_profile.h"
 #include "content/public/browser/storage_partition.h"
 #include "content/public/test/test_browser_thread.h"
+#include "content/public/test/test_browser_thread_bundle.h"
 #include "webkit/browser/fileapi/file_system_context.h"
 #include "webkit/browser/fileapi/file_system_url.h"
 #include "webkit/browser/fileapi/file_system_usage_cache.h"
-#include "webkit/browser/fileapi/sandbox_mount_point_provider.h"
 #include "webkit/common/fileapi/file_system_types.h"
 
 using content::BrowserContext;
@@ -62,26 +63,19 @@
 // point.
 class BrowsingDataFileSystemHelperTest : public testing::Test {
  public:
-  BrowsingDataFileSystemHelperTest()
-      : ui_thread_(BrowserThread::UI, &message_loop_),
-        db_thread_(BrowserThread::DB, &message_loop_),
-        webkit_thread_(BrowserThread::WEBKIT_DEPRECATED, &message_loop_),
-        file_thread_(BrowserThread::FILE, &message_loop_),
-        file_user_blocking_thread_(
-            BrowserThread::FILE_USER_BLOCKING, &message_loop_),
-        io_thread_(BrowserThread::IO, &message_loop_) {
+  BrowsingDataFileSystemHelperTest() {
     profile_.reset(new TestingProfile());
 
     helper_ = BrowsingDataFileSystemHelper::Create(
         BrowserContext::GetDefaultStoragePartition(profile_.get())->
             GetFileSystemContext());
-    message_loop_.RunUntilIdle();
+    base::MessageLoop::current()->RunUntilIdle();
     canned_helper_ = new CannedBrowsingDataFileSystemHelper(profile_.get());
   }
   virtual ~BrowsingDataFileSystemHelperTest() {
     // Avoid memory leaks.
     profile_.reset();
-    message_loop_.RunUntilIdle();
+    base::MessageLoop::current()->RunUntilIdle();
   }
 
   TestingProfile* GetProfile() {
@@ -100,26 +94,36 @@
   }
 
   // Callback that should be executed in response to
-  // fileapi::SandboxMountPointProvider::OpenFileSystem.
-  void OpenFileSystemCallback(base::PlatformFileError error) {
+  // fileapi::FileSystemContext::OpenFileSystem.
+  void OpenFileSystemCallback(base::PlatformFileError error,
+                              const std::string& name,
+                              const GURL& root) {
     open_file_system_result_ = error;
     Notify();
   }
 
-  // Calls fileapi::SandboxMountPointProvider::OpenFileSystem
+  bool OpenFileSystem(const GURL& origin,
+                      fileapi::FileSystemType type,
+                      fileapi::OpenFileSystemMode open_mode) {
+    BrowserContext::GetDefaultStoragePartition(profile_.get())->
+        GetFileSystemContext()->OpenFileSystem(
+            origin, type, open_mode,
+            base::Bind(
+                &BrowsingDataFileSystemHelperTest::OpenFileSystemCallback,
+                base::Unretained(this)));
+    BlockUntilNotified();
+    return open_file_system_result_ == base::PLATFORM_FILE_OK;
+  }
+
+  // Calls fileapi::FileSystemContext::OpenFileSystem with
+  // OPEN_FILE_SYSTEM_FAIL_IF_NONEXISTENT flag
   // to verify the existence of a file system for a specified type and origin,
   // blocks until a response is available, then returns the result
   // synchronously to it's caller.
   bool FileSystemContainsOriginAndType(const GURL& origin,
                                        fileapi::FileSystemType type) {
-    sandbox_->OpenFileSystem(
-        origin, type,
-        fileapi::OPEN_FILE_SYSTEM_FAIL_IF_NONEXISTENT,
-        base::Bind(
-            &BrowsingDataFileSystemHelperTest::OpenFileSystemCallback,
-            base::Unretained(this)));
-    BlockUntilNotified();
-    return open_file_system_result_ == base::PLATFORM_FILE_OK;
+    return OpenFileSystem(origin, type,
+                          fileapi::OPEN_FILE_SYSTEM_FAIL_IF_NONEXISTENT);
   }
 
   // Callback that should be executed in response to StartFetching(), and stores
@@ -154,9 +158,6 @@
   // Sets up kOrigin1 with a temporary file system, kOrigin2 with a persistent
   // file system, and kOrigin3 with both.
   virtual void PopulateTestFileSystemData() {
-    sandbox_ = BrowserContext::GetDefaultStoragePartition(profile_.get())->
-        GetFileSystemContext()->sandbox_provider();
-
     CreateDirectoryForOriginAndType(kOrigin1, kTemporary);
     CreateDirectoryForOriginAndType(kOrigin2, kPersistent);
     CreateDirectoryForOriginAndType(kOrigin3, kTemporary);
@@ -170,13 +171,13 @@
     EXPECT_TRUE(FileSystemContainsOriginAndType(kOrigin3, kTemporary));
   }
 
-  // Uses the fileapi methods to create a filesystem of a given type for a
-  // specified origin.
+  // Calls OpenFileSystem with OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT
+  // to create a filesystem of a given type for a specified origin.
   void CreateDirectoryForOriginAndType(const GURL& origin,
                                        fileapi::FileSystemType type) {
-    base::FilePath target = sandbox_->GetBaseDirectoryForOriginAndType(
-        origin, type, true /* create */);
-    EXPECT_TRUE(file_util::DirectoryExists(target));
+    OpenFileSystem(origin, type,
+                   fileapi::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT);
+    EXPECT_EQ(base::PLATFORM_FILE_OK, open_file_system_result_);
   }
 
   // Returns a list of the FileSystemInfo objects gathered in the most recent
@@ -186,16 +187,7 @@
   }
 
  protected:
-  // message_loop_, as well as all the threads associated with it must be
-  // defined before profile_ to prevent explosions. The threads also must be
-  // defined in the order they're listed here. Oh how I love C++.
-  base::MessageLoopForUI message_loop_;
-  content::TestBrowserThread ui_thread_;
-  content::TestBrowserThread db_thread_;
-  content::TestBrowserThread webkit_thread_;
-  content::TestBrowserThread file_thread_;
-  content::TestBrowserThread file_user_blocking_thread_;
-  content::TestBrowserThread io_thread_;
+  content::TestBrowserThreadBundle thread_bundle_;
   scoped_ptr<TestingProfile> profile_;
 
   // Temporary storage to pass information back from callbacks.
@@ -205,9 +197,6 @@
   scoped_refptr<BrowsingDataFileSystemHelper> helper_;
   scoped_refptr<CannedBrowsingDataFileSystemHelper> canned_helper_;
 
-  // We don't own this pointer: don't delete it.
-  fileapi::SandboxMountPointProvider* sandbox_;
-
   DISALLOW_COPY_AND_ASSIGN(BrowsingDataFileSystemHelperTest);
 };
 
@@ -226,28 +215,27 @@
        file_system_info_list_->begin(); info != file_system_info_list_->end();
        ++info) {
     if (info->origin == kOrigin1) {
-        EXPECT_FALSE(test_hosts_found[0]);
-        test_hosts_found[0] = true;
-        EXPECT_FALSE(info->has_persistent);
-        EXPECT_TRUE(info->has_temporary);
-        EXPECT_EQ(0, info->usage_persistent);
-        EXPECT_EQ(kEmptyFileSystemSize, info->usage_temporary);
+      EXPECT_FALSE(test_hosts_found[0]);
+      test_hosts_found[0] = true;
+      EXPECT_FALSE(ContainsKey(info->usage_map, kPersistent));
+      EXPECT_TRUE(ContainsKey(info->usage_map, kTemporary));
+      EXPECT_EQ(kEmptyFileSystemSize,
+                info->usage_map[fileapi::kFileSystemTypeTemporary]);
     } else if (info->origin == kOrigin2) {
-        EXPECT_FALSE(test_hosts_found[1]);
-        test_hosts_found[1] = true;
-        EXPECT_TRUE(info->has_persistent);
-        EXPECT_FALSE(info->has_temporary);
-        EXPECT_EQ(kEmptyFileSystemSize, info->usage_persistent);
-        EXPECT_EQ(0, info->usage_temporary);
+      EXPECT_FALSE(test_hosts_found[1]);
+      test_hosts_found[1] = true;
+      EXPECT_TRUE(ContainsKey(info->usage_map, kPersistent));
+      EXPECT_FALSE(ContainsKey(info->usage_map, kTemporary));
+      EXPECT_EQ(kEmptyFileSystemSize, info->usage_map[kPersistent]);
     } else if (info->origin == kOrigin3) {
-        EXPECT_FALSE(test_hosts_found[2]);
-        test_hosts_found[2] = true;
-        EXPECT_TRUE(info->has_persistent);
-        EXPECT_TRUE(info->has_temporary);
-        EXPECT_EQ(kEmptyFileSystemSize, info->usage_persistent);
-        EXPECT_EQ(kEmptyFileSystemSize, info->usage_temporary);
+      EXPECT_FALSE(test_hosts_found[2]);
+      test_hosts_found[2] = true;
+      EXPECT_TRUE(ContainsKey(info->usage_map, kPersistent));
+      EXPECT_TRUE(ContainsKey(info->usage_map, kTemporary));
+      EXPECT_EQ(kEmptyFileSystemSize, info->usage_map[kPersistent]);
+      EXPECT_EQ(kEmptyFileSystemSize, info->usage_map[kTemporary]);
     } else {
-        ADD_FAILURE() << info->origin.spec() << " isn't an origin we added.";
+      ADD_FAILURE() << info->origin.spec() << " isn't an origin we added.";
     }
   }
   for (size_t i = 0; i < arraysize(test_hosts_found); i++) {
@@ -269,10 +257,10 @@
   BrowsingDataFileSystemHelper::FileSystemInfo info =
       *(file_system_info_list_->begin());
   EXPECT_EQ(kOrigin3, info.origin);
-  EXPECT_TRUE(info.has_persistent);
-  EXPECT_TRUE(info.has_temporary);
-  EXPECT_EQ(kEmptyFileSystemSize, info.usage_persistent);
-  EXPECT_EQ(kEmptyFileSystemSize, info.usage_temporary);
+  EXPECT_TRUE(ContainsKey(info.usage_map, kPersistent));
+  EXPECT_TRUE(ContainsKey(info.usage_map, kTemporary));
+  EXPECT_EQ(kEmptyFileSystemSize, info.usage_map[kPersistent]);
+  EXPECT_EQ(kEmptyFileSystemSize, info.usage_map[kTemporary]);
 }
 
 // Verifies that the CannedBrowsingDataFileSystemHelper correctly reports
@@ -297,17 +285,15 @@
   std::list<BrowsingDataFileSystemHelper::FileSystemInfo>::iterator info =
       file_system_info_list_->begin();
   EXPECT_EQ(kOrigin1, info->origin);
-  EXPECT_TRUE(info->has_persistent);
-  EXPECT_FALSE(info->has_temporary);
-  EXPECT_EQ(200, info->usage_persistent);
-  EXPECT_EQ(0, info->usage_temporary);
+  EXPECT_TRUE(ContainsKey(info->usage_map, kPersistent));
+  EXPECT_FALSE(ContainsKey(info->usage_map, kTemporary));
+  EXPECT_EQ(200, info->usage_map[kPersistent]);
 
   info++;
   EXPECT_EQ(kOrigin2, info->origin);
-  EXPECT_FALSE(info->has_persistent);
-  EXPECT_TRUE(info->has_temporary);
-  EXPECT_EQ(0, info->usage_persistent);
-  EXPECT_EQ(100, info->usage_temporary);
+  EXPECT_FALSE(ContainsKey(info->usage_map, kPersistent));
+  EXPECT_TRUE(ContainsKey(info->usage_map, kTemporary));
+  EXPECT_EQ(100, info->usage_map[kTemporary]);
 }
 
 // Verifies that the CannedBrowsingDataFileSystemHelper correctly ignores
diff --git a/chrome/browser/browsing_data/browsing_data_helper.cc b/chrome/browser/browsing_data/browsing_data_helper.cc
index 5a50ff0..0faf856 100644
--- a/chrome/browser/browsing_data/browsing_data_helper.cc
+++ b/chrome/browser/browsing_data/browsing_data_helper.cc
@@ -11,8 +11,8 @@
 #include "chrome/common/url_constants.h"
 #include "content/public/browser/child_process_security_policy.h"
 #include "extensions/common/constants.h"
-#include "googleurl/src/gurl.h"
 #include "third_party/WebKit/public/platform/WebString.h"
+#include "url/gurl.h"
 
 // Static
 bool BrowsingDataHelper::IsWebScheme(const std::string& scheme) {
diff --git a/chrome/browser/browsing_data/browsing_data_helper_unittest.cc b/chrome/browser/browsing_data/browsing_data_helper_unittest.cc
index fe3b476..e19b81a 100644
--- a/chrome/browser/browsing_data/browsing_data_helper_unittest.cc
+++ b/chrome/browser/browsing_data/browsing_data_helper_unittest.cc
@@ -9,9 +9,9 @@
 #include "chrome/common/url_constants.h"
 #include "content/public/common/url_constants.h"
 #include "extensions/common/constants.h"
-#include "googleurl/src/gurl.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/WebKit/public/platform/WebString.h"
+#include "url/gurl.h"
 
 namespace {
 
diff --git a/chrome/browser/browsing_data/browsing_data_indexed_db_helper.cc b/chrome/browser/browsing_data/browsing_data_indexed_db_helper.cc
index b517ee6..59e3625 100644
--- a/chrome/browser/browsing_data/browsing_data_indexed_db_helper.cc
+++ b/chrome/browser/browsing_data/browsing_data_indexed_db_helper.cc
@@ -16,12 +16,10 @@
 #include "chrome/browser/browsing_data/browsing_data_helper.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/indexed_db_context.h"
-#include "webkit/browser/database/database_util.h"
 
 using content::BrowserThread;
 using content::IndexedDBContext;
 using content::IndexedDBInfo;
-using webkit_database::DatabaseUtil;
 
 namespace {
 
@@ -38,12 +36,12 @@
  private:
   virtual ~BrowsingDataIndexedDBHelperImpl();
 
-  // Enumerates all indexed database files in the WEBKIT thread.
-  void FetchIndexedDBInfoInWebKitThread();
+  // Enumerates all indexed database files in the IndexedDB thread.
+  void FetchIndexedDBInfoInIndexedDBThread();
   // Notifies the completion callback in the UI thread.
   void NotifyInUIThread();
-  // Delete a single indexed database in the WEBKIT thread.
-  void DeleteIndexedDBInWebKitThread(const GURL& origin);
+  // Delete a single indexed database in the IndexedDB thread.
+  void DeleteIndexedDBInIndexedDBThread(const GURL& origin);
 
   scoped_refptr<IndexedDBContext> indexed_db_context_;
 
@@ -52,7 +50,7 @@
   // while |is_fetching_| is true. The flag |is_fetching_| is only accessed on
   // the UI thread.
   // In the context of this class |indexed_db_info_| is only accessed on the
-  // WEBKIT thread.
+  // context's IndexedDB thread.
   std::list<IndexedDBInfo> indexed_db_info_;
 
   // This only mutates on the UI thread.
@@ -85,25 +83,26 @@
 
   is_fetching_ = true;
   completion_callback_ = callback;
-  BrowserThread::PostTask(
-      BrowserThread::WEBKIT_DEPRECATED, FROM_HERE,
+  indexed_db_context_->TaskRunner()->PostTask(
+      FROM_HERE,
       base::Bind(
-          &BrowsingDataIndexedDBHelperImpl::FetchIndexedDBInfoInWebKitThread,
+          &BrowsingDataIndexedDBHelperImpl::FetchIndexedDBInfoInIndexedDBThread,
           this));
 }
 
 void BrowsingDataIndexedDBHelperImpl::DeleteIndexedDB(
     const GURL& origin) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  BrowserThread::PostTask(
-      BrowserThread::WEBKIT_DEPRECATED, FROM_HERE,
+  indexed_db_context_->TaskRunner()->PostTask(
+      FROM_HERE,
       base::Bind(
-          &BrowsingDataIndexedDBHelperImpl::DeleteIndexedDBInWebKitThread, this,
+          &BrowsingDataIndexedDBHelperImpl::DeleteIndexedDBInIndexedDBThread,
+          this,
           origin));
 }
 
-void BrowsingDataIndexedDBHelperImpl::FetchIndexedDBInfoInWebKitThread() {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT_DEPRECATED));
+void BrowsingDataIndexedDBHelperImpl::FetchIndexedDBInfoInIndexedDBThread() {
+  DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
   std::vector<IndexedDBInfo> origins = indexed_db_context_->GetAllOriginsInfo();
   for (std::vector<IndexedDBInfo>::const_iterator iter = origins.begin();
        iter != origins.end(); ++iter) {
@@ -127,9 +126,9 @@
   is_fetching_ = false;
 }
 
-void BrowsingDataIndexedDBHelperImpl::DeleteIndexedDBInWebKitThread(
+void BrowsingDataIndexedDBHelperImpl::DeleteIndexedDBInIndexedDBThread(
     const GURL& origin) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT_DEPRECATED));
+  DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
   indexed_db_context_->DeleteForOrigin(origin);
 }
 
@@ -171,7 +170,6 @@
   CannedBrowsingDataIndexedDBHelper* clone =
       new CannedBrowsingDataIndexedDBHelper();
 
-  base::AutoLock auto_lock(lock_);
   clone->pending_indexed_db_info_ = pending_indexed_db_info_;
   clone->indexed_db_info_ = indexed_db_info_;
   return clone;
@@ -182,29 +180,24 @@
   if (!BrowsingDataHelper::HasWebScheme(origin))
     return;  // Non-websafe state is not considered browsing data.
 
-  base::AutoLock auto_lock(lock_);
   pending_indexed_db_info_.insert(PendingIndexedDBInfo(origin, name));
 }
 
 void CannedBrowsingDataIndexedDBHelper::Reset() {
-  base::AutoLock auto_lock(lock_);
   indexed_db_info_.clear();
   pending_indexed_db_info_.clear();
 }
 
 bool CannedBrowsingDataIndexedDBHelper::empty() const {
-  base::AutoLock auto_lock(lock_);
   return indexed_db_info_.empty() && pending_indexed_db_info_.empty();
 }
 
 size_t CannedBrowsingDataIndexedDBHelper::GetIndexedDBCount() const {
-  base::AutoLock auto_lock(lock_);
   return pending_indexed_db_info_.size();
 }
 
 const std::set<CannedBrowsingDataIndexedDBHelper::PendingIndexedDBInfo>&
 CannedBrowsingDataIndexedDBHelper::GetIndexedDBInfo() const  {
-  base::AutoLock auto_lock(lock_);
   return pending_indexed_db_info_;
 }
 
@@ -216,15 +209,17 @@
 
   is_fetching_ = true;
   completion_callback_ = callback;
-  BrowserThread::PostTask(
-      BrowserThread::WEBKIT_DEPRECATED, FROM_HERE,
-      base::Bind(
-          &CannedBrowsingDataIndexedDBHelper::ConvertPendingInfoInWebKitThread,
-          this));
+
+  // We post a task to emulate async fetching behavior.
+  base::MessageLoop::current()->PostTask(
+      FROM_HERE,
+      base::Bind(&CannedBrowsingDataIndexedDBHelper::
+                     ConvertPendingInfo,
+                 this));
 }
 
-void CannedBrowsingDataIndexedDBHelper::ConvertPendingInfoInWebKitThread() {
-  base::AutoLock auto_lock(lock_);
+void CannedBrowsingDataIndexedDBHelper::ConvertPendingInfo() {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   indexed_db_info_.clear();
   for (std::set<PendingIndexedDBInfo>::const_iterator
        pending_info = pending_indexed_db_info_.begin();
@@ -233,15 +228,6 @@
     indexed_db_info_.push_back(info);
   }
 
-  BrowserThread::PostTask(
-      BrowserThread::UI, FROM_HERE,
-      base::Bind(&CannedBrowsingDataIndexedDBHelper::NotifyInUIThread, this));
-}
-
-void CannedBrowsingDataIndexedDBHelper::NotifyInUIThread() {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  DCHECK(is_fetching_);
-
   completion_callback_.Run(indexed_db_info_);
   completion_callback_.Reset();
   is_fetching_ = false;
diff --git a/chrome/browser/browsing_data/browsing_data_indexed_db_helper.h b/chrome/browser/browsing_data/browsing_data_indexed_db_helper.h
index ee4e76f..bdcd036 100644
--- a/chrome/browser/browsing_data/browsing_data_indexed_db_helper.h
+++ b/chrome/browser/browsing_data/browsing_data_indexed_db_helper.h
@@ -14,9 +14,9 @@
 #include "base/files/file_path.h"
 #include "base/memory/ref_counted.h"
 #include "base/synchronization/lock.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "content/public/browser/indexed_db_context.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 class Profile;
 
@@ -39,7 +39,7 @@
   virtual void StartFetching(
       const base::Callback<void(const std::list<content::IndexedDBInfo>&)>&
           callback) = 0;
-  // Requests a single indexed database to be deleted in the WEBKIT thread.
+  // Requests a single indexed database to be deleted in the IndexedDB thread.
   virtual void DeleteIndexedDB(const GURL& origin) = 0;
 
  protected:
@@ -100,15 +100,8 @@
   virtual ~CannedBrowsingDataIndexedDBHelper();
 
   // Convert the pending indexed db info to indexed db info objects.
-  void ConvertPendingInfoInWebKitThread();
+  void ConvertPendingInfo();
 
-  void NotifyInUIThread();
-
-  // Lock to protect access to pending_indexed_db_info_;
-  mutable base::Lock lock_;
-
-  // Access to |pending_indexed_db_info_| is protected by |lock_| since it can
-  // be accessed on the UI and on the WEBKIT thread.
   std::set<PendingIndexedDBInfo> pending_indexed_db_info_;
 
   // Access to |indexed_db_info_| is triggered indirectly via the UI thread and
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 c41c7a7..80c55fd 100644
--- a/chrome/browser/browsing_data/browsing_data_local_storage_helper.h
+++ b/chrome/browser/browsing_data/browsing_data_local_storage_helper.h
@@ -14,10 +14,10 @@
 #include "base/files/file_path.h"
 #include "base/memory/ref_counted.h"
 #include "base/synchronization/lock.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/common/url_constants.h"
 #include "content/public/browser/dom_storage_context.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 class Profile;
 
diff --git a/chrome/browser/browsing_data/browsing_data_quota_helper_unittest.cc b/chrome/browser/browsing_data/browsing_data_quota_helper_unittest.cc
index ce0b511..095c631 100644
--- a/chrome/browser/browsing_data/browsing_data_quota_helper_unittest.cc
+++ b/chrome/browser/browsing_data/browsing_data_quota_helper_unittest.cc
@@ -8,10 +8,10 @@
 #include "base/files/scoped_temp_dir.h"
 #include "base/memory/weak_ptr.h"
 #include "base/message_loop.h"
-#include "base/message_loop.h"
 #include "base/message_loop/message_loop_proxy.h"
 #include "chrome/browser/browsing_data/browsing_data_quota_helper_impl.h"
 #include "content/public/test/test_browser_thread.h"
+#include "content/public/test/test_browser_thread_bundle.h"
 #include "webkit/browser/quota/mock_storage_client.h"
 #include "webkit/browser/quota/quota_manager.h"
 
@@ -23,10 +23,7 @@
   typedef BrowsingDataQuotaHelper::QuotaInfoArray QuotaInfoArray;
 
   BrowsingDataQuotaHelperTest()
-      : ui_thread_(BrowserThread::UI, &message_loop_),
-        db_thread_(BrowserThread::DB, &message_loop_),
-        io_thread_(BrowserThread::IO, &message_loop_),
-        fetching_completed_(true),
+      : fetching_completed_(true),
         quota_(-1),
         weak_factory_(this) {}
 
@@ -114,10 +111,7 @@
     fetching_completed_ = true;
   }
 
-  base::MessageLoop message_loop_;
-  content::TestBrowserThread ui_thread_;
-  content::TestBrowserThread db_thread_;
-  content::TestBrowserThread io_thread_;
+  content::TestBrowserThreadBundle thread_bundle_;
   scoped_refptr<quota::QuotaManager> quota_manager_;
 
   base::ScopedTempDir dir_;
diff --git a/chrome/browser/browsing_data/browsing_data_remover.cc b/chrome/browser/browsing_data/browsing_data_remover.cc
index e0799e1..27e6eed 100644
--- a/chrome/browser/browsing_data/browsing_data_remover.cc
+++ b/chrome/browser/browsing_data/browsing_data_remover.cc
@@ -45,8 +45,8 @@
 #include "chrome/common/chrome_notification_types.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/url_constants.h"
-#include "components/autofill/browser/personal_data_manager.h"
-#include "components/autofill/browser/webdata/autofill_webdata_service.h"
+#include "components/autofill/core/browser/personal_data_manager.h"
+#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/dom_storage_context.h"
 #include "content/public/browser/download_manager.h"
diff --git a/chrome/browser/browsing_data/browsing_data_remover.h b/chrome/browser/browsing_data/browsing_data_remover.h
index 9eb1597..e75735e 100644
--- a/chrome/browser/browsing_data/browsing_data_remover.h
+++ b/chrome/browser/browsing_data/browsing_data_remover.h
@@ -13,13 +13,13 @@
 #include "base/prefs/pref_member.h"
 #include "base/sequenced_task_runner_helpers.h"
 #include "base/synchronization/waitable_event_watcher.h"
-#include "base/time.h"
+#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 "googleurl/src/gurl.h"
+#include "url/gurl.h"
 #include "webkit/common/quota/quota_types.h"
 
 class ExtensionSpecialStoragePolicy;
diff --git a/chrome/browser/browsing_data/browsing_data_remover_unittest.cc b/chrome/browser/browsing_data/browsing_data_remover_unittest.cc
index 11021fc..43cce41 100644
--- a/chrome/browser/browsing_data/browsing_data_remover_unittest.cc
+++ b/chrome/browser/browsing_data/browsing_data_remover_unittest.cc
@@ -26,15 +26,16 @@
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/testing_browser_process.h"
 #include "chrome/test/base/testing_profile.h"
-#include "components/autofill/browser/autofill_common_test.h"
-#include "components/autofill/browser/autofill_profile.h"
-#include "components/autofill/browser/credit_card.h"
-#include "components/autofill/browser/personal_data_manager.h"
-#include "components/autofill/browser/personal_data_manager_observer.h"
+#include "components/autofill/core/browser/autofill_common_test.h"
+#include "components/autofill/core/browser/autofill_profile.h"
+#include "components/autofill/core/browser/credit_card.h"
+#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/notification_service.h"
 #include "content/public/browser/storage_partition.h"
 #include "content/public/test/test_browser_thread.h"
+#include "content/public/test/test_browser_thread_bundle.h"
 #include "net/cookies/cookie_monster.h"
 #include "net/ssl/server_bound_cert_service.h"
 #include "net/ssl/server_bound_cert_store.h"
@@ -542,14 +543,7 @@
                                 public content::NotificationObserver {
  public:
   BrowsingDataRemoverTest()
-      : ui_thread_(BrowserThread::UI, &message_loop_),
-        db_thread_(BrowserThread::DB, &message_loop_),
-        webkit_thread_(BrowserThread::WEBKIT_DEPRECATED, &message_loop_),
-        file_thread_(BrowserThread::FILE, &message_loop_),
-        file_user_blocking_thread_(
-            BrowserThread::FILE_USER_BLOCKING, &message_loop_),
-        io_thread_(BrowserThread::IO, &message_loop_),
-        profile_(new TestingProfile()) {
+      : profile_(new TestingProfile()) {
     registrar_.Add(this, chrome::NOTIFICATION_BROWSING_DATA_REMOVED,
                    content::Source<Profile>(profile_.get()));
   }
@@ -564,7 +558,7 @@
     // the message loop is cleared out, before destroying the threads and loop.
     // Otherwise we leak memory.
     profile_.reset();
-    message_loop_.RunUntilIdle();
+    base::MessageLoop::current()->RunUntilIdle();
   }
 
   void BlockUntilBrowsingDataRemoved(BrowsingDataRemover::TimePeriod period,
@@ -652,15 +646,7 @@
   scoped_ptr<BrowsingDataRemover::NotificationDetails> called_with_details_;
   content::NotificationRegistrar registrar_;
 
-  // message_loop_, as well as all the threads associated with it must be
-  // defined before profile_ to prevent explosions. Oh how I love C++.
-  base::MessageLoopForUI message_loop_;
-  content::TestBrowserThread ui_thread_;
-  content::TestBrowserThread db_thread_;
-  content::TestBrowserThread webkit_thread_;
-  content::TestBrowserThread file_thread_;
-  content::TestBrowserThread file_user_blocking_thread_;
-  content::TestBrowserThread io_thread_;
+  content::TestBrowserThreadBundle thread_bundle_;
   scoped_ptr<TestingProfile> profile_;
   scoped_refptr<quota::MockQuotaManager> quota_manager_;
 
diff --git a/chrome/browser/browsing_data/cookies_tree_model.cc b/chrome/browser/browsing_data/cookies_tree_model.cc
index dcb4b25..58abc27 100644
--- a/chrome/browser/browsing_data/cookies_tree_model.cc
+++ b/chrome/browser/browsing_data/cookies_tree_model.cc
@@ -189,7 +189,7 @@
     const BrowsingDataDatabaseHelper::DatabaseInfo* database_info) {
   Init(TYPE_DATABASE);
   this->database_info = database_info;
-  origin = GURL(database_info->origin);
+  origin = database_info->identifier.ToOrigin();
   return *this;
 }
 
@@ -342,7 +342,7 @@
 
   if (container) {
     container->database_helper_->DeleteDatabase(
-        database_info_->origin_identifier, database_info_->database_name);
+        database_info_->identifier.ToString(), database_info_->database_name);
     container->database_info_list_.erase(database_info_);
   }
 }
@@ -1113,7 +1113,7 @@
            container->database_info_list_.begin();
        database_info != container->database_info_list_.end();
        ++database_info) {
-    GURL origin(database_info->origin);
+    GURL origin(database_info->identifier.ToOrigin());
 
     if (!filter.size() ||
         (CookieTreeHostNode::TitleForUrl(origin).find(filter) !=
diff --git a/chrome/browser/browsing_data/cookies_tree_model_unittest.cc b/chrome/browser/browsing_data/cookies_tree_model_unittest.cc
index 07fd27b..531b540 100644
--- a/chrome/browser/browsing_data/cookies_tree_model_unittest.cc
+++ b/chrome/browser/browsing_data/cookies_tree_model_unittest.cc
@@ -24,7 +24,7 @@
 #include "chrome/test/base/testing_profile.h"
 #include "content/public/browser/notification_details.h"
 #include "content/public/browser/notification_types.h"
-#include "content/public/test/test_browser_thread.h"
+#include "content/public/test/test_browser_thread_bundle.h"
 #include "net/url_request/url_request_context.h"
 #include "net/url_request/url_request_context_getter.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -38,17 +38,11 @@
 
 class CookiesTreeModelTest : public testing::Test {
  public:
-  CookiesTreeModelTest()
-      : ui_thread_(BrowserThread::UI, &message_loop_),
-        file_user_blocking_(BrowserThread::FILE_USER_BLOCKING, &message_loop_),
-        io_thread_(BrowserThread::IO, &message_loop_) {
-  }
-
   virtual ~CookiesTreeModelTest() {
     // Avoid memory leaks.
     special_storage_policy_ = NULL;
     profile_.reset();
-    message_loop_.RunUntilIdle();
+    base::MessageLoop::current()->RunUntilIdle();
   }
 
   virtual void SetUp() OVERRIDE {
@@ -92,7 +86,7 @@
     mock_browsing_data_local_storage_helper_ = NULL;
     mock_browsing_data_database_helper_ = NULL;
     mock_browsing_data_flash_lso_helper_ = NULL;
-    message_loop_.RunUntilIdle();
+    base::MessageLoop::current()->RunUntilIdle();
   }
 
   scoped_ptr<CookiesTreeModel> CreateCookiesTreeModelWithInitialSample() {
@@ -339,11 +333,7 @@
   }
 
  protected:
-  base::MessageLoop message_loop_;
-  content::TestBrowserThread ui_thread_;
-  content::TestBrowserThread file_user_blocking_;
-  content::TestBrowserThread io_thread_;
-
+  content::TestBrowserThreadBundle thread_bundle_;
   scoped_ptr<TestingProfile> profile_;
   scoped_refptr<MockBrowsingDataCookieHelper>
       mock_browsing_data_cookie_helper_;
diff --git a/chrome/browser/browsing_data/mock_browsing_data_database_helper.cc b/chrome/browser/browsing_data/mock_browsing_data_database_helper.cc
index b6fbdb5..3db7ca9 100644
--- a/chrome/browser/browsing_data/mock_browsing_data_database_helper.cc
+++ b/chrome/browser/browsing_data/mock_browsing_data_database_helper.cc
@@ -30,13 +30,15 @@
 }
 
 void MockBrowsingDataDatabaseHelper::AddDatabaseSamples() {
+  webkit_database::DatabaseIdentifier id1 =
+      webkit_database::DatabaseIdentifier::Parse("http_gdbhost1_1");
   response_.push_back(BrowsingDataDatabaseHelper::DatabaseInfo(
-      "gdbhost1", "db1", "http_gdbhost1_1", "description 1",
-      "http://gdbhost1:1/", 1, base::Time()));
+      id1, "db1", "description 1", 1, base::Time()));
   databases_["http_gdbhost1_1:db1"] = true;
+  webkit_database::DatabaseIdentifier id2 =
+      webkit_database::DatabaseIdentifier::Parse("http_gdbhost2_2");
   response_.push_back(BrowsingDataDatabaseHelper::DatabaseInfo(
-      "gdbhost2", "db2", "http_gdbhost2_2", "description 2",
-      "http://gdbhost2:2/", 2, base::Time()));
+      id2, "db2", "description 2", 2, base::Time()));
   databases_["http_gdbhost2_2:db2"] = true;
 }
 
diff --git a/chrome/browser/browsing_data/mock_browsing_data_file_system_helper.cc b/chrome/browser/browsing_data/mock_browsing_data_file_system_helper.cc
index e650c48..26d8185 100644
--- a/chrome/browser/browsing_data/mock_browsing_data_file_system_helper.cc
+++ b/chrome/browser/browsing_data/mock_browsing_data_file_system_helper.cc
@@ -29,8 +29,14 @@
 void MockBrowsingDataFileSystemHelper::AddFileSystem(
     const GURL& origin, bool has_persistent, bool has_temporary,
     bool has_syncable) {
-  response_.push_back(BrowsingDataFileSystemHelper::FileSystemInfo(
-      origin, has_persistent, has_temporary, has_syncable, 0, 0, 0));
+  BrowsingDataFileSystemHelper::FileSystemInfo info(origin);
+  if (has_persistent)
+    info.usage_map[fileapi::kFileSystemTypePersistent] = 0;
+  if (has_temporary)
+    info.usage_map[fileapi::kFileSystemTypeTemporary] = 0;
+  if (has_syncable)
+    info.usage_map[fileapi::kFileSystemTypeSyncable] = 0;
+  response_.push_back(info);
   file_systems_[origin.spec()] = true;
 }
 
diff --git a/chrome/browser/captive_portal/captive_portal_detector.h b/chrome/browser/captive_portal/captive_portal_detector.h
index 7ecda27..162ae6e 100644
--- a/chrome/browser/captive_portal/captive_portal_detector.h
+++ b/chrome/browser/captive_portal/captive_portal_detector.h
@@ -11,7 +11,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/threading/non_thread_safe.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "net/url_request/url_fetcher.h"
 #include "net/url_request/url_fetcher_delegate.h"
 #include "net/url_request/url_request_context_getter.h"
diff --git a/chrome/browser/captive_portal/captive_portal_detector_unittest.cc b/chrome/browser/captive_portal/captive_portal_detector_unittest.cc
index c0c1806..44f4b3e 100644
--- a/chrome/browser/captive_portal/captive_portal_detector_unittest.cc
+++ b/chrome/browser/captive_portal/captive_portal_detector_unittest.cc
@@ -7,13 +7,13 @@
 #include "base/basictypes.h"
 #include "base/bind.h"
 #include "base/message_loop.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/captive_portal/testing_utils.h"
 #include "chrome/test/base/testing_profile.h"
-#include "googleurl/src/gurl.h"
 #include "net/base/net_errors.h"
 #include "net/url_request/url_fetcher.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
 
 namespace captive_portal {
 
diff --git a/chrome/browser/captive_portal/captive_portal_service.h b/chrome/browser/captive_portal/captive_portal_service.h
index f9c5b4a..c8b5970 100644
--- a/chrome/browser/captive_portal/captive_portal_service.h
+++ b/chrome/browser/captive_portal/captive_portal_service.h
@@ -9,12 +9,12 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/prefs/pref_member.h"
 #include "base/threading/non_thread_safe.h"
-#include "base/time.h"
-#include "base/timer.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
 #include "chrome/browser/captive_portal/captive_portal_detector.h"
 #include "components/browser_context_keyed_service/browser_context_keyed_service.h"
-#include "googleurl/src/gurl.h"
 #include "net/base/backoff_entry.h"
+#include "url/gurl.h"
 
 class Profile;
 
diff --git a/chrome/browser/captive_portal/captive_portal_tab_reloader.h b/chrome/browser/captive_portal/captive_portal_tab_reloader.h
index 212f520..83a7686 100644
--- a/chrome/browser/captive_portal/captive_portal_tab_reloader.h
+++ b/chrome/browser/captive_portal/captive_portal_tab_reloader.h
@@ -9,8 +9,8 @@
 #include "base/callback_forward.h"
 #include "base/compiler_specific.h"
 #include "base/memory/weak_ptr.h"
-#include "base/time.h"
-#include "base/timer.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
 #include "chrome/browser/captive_portal/captive_portal_service.h"
 
 class Profile;
diff --git a/chrome/browser/captive_portal/captive_portal_tab_reloader_unittest.cc b/chrome/browser/captive_portal/captive_portal_tab_reloader_unittest.cc
index 522adb8..feebe41 100644
--- a/chrome/browser/captive_portal/captive_portal_tab_reloader_unittest.cc
+++ b/chrome/browser/captive_portal/captive_portal_tab_reloader_unittest.cc
@@ -12,12 +12,12 @@
 #include "content/public/browser/interstitial_page.h"
 #include "content/public/browser/interstitial_page_delegate.h"
 #include "content/public/browser/web_contents.h"
-#include "googleurl/src/gurl.h"
 #include "net/base/net_errors.h"
 #include "net/cert/cert_status_flags.h"
 #include "net/ssl/ssl_info.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
 
 namespace captive_portal {
 
diff --git a/chrome/browser/chrome_browser_application_mac.h b/chrome/browser/chrome_browser_application_mac.h
index 5363942..136e448 100644
--- a/chrome/browser/chrome_browser_application_mac.h
+++ b/chrome/browser/chrome_browser_application_mac.h
@@ -12,7 +12,6 @@
 #include <vector>
 
 #import "base/mac/scoped_sending_event.h"
-#import "base/memory/scoped_nsobject.h"
 #import "base/message_loop/message_pump_mac.h"
 #include "base/synchronization/lock.h"
 
diff --git a/chrome/browser/chrome_browser_application_mac.mm b/chrome/browser/chrome_browser_application_mac.mm
index 74dd296..fba6506 100644
--- a/chrome/browser/chrome_browser_application_mac.mm
+++ b/chrome/browser/chrome_browser_application_mac.mm
@@ -9,7 +9,7 @@
 #include "base/debug/stack_trace.h"
 #import "base/logging.h"
 #import "base/mac/scoped_nsexception_enabler.h"
-#import "base/memory/scoped_nsobject.h"
+#import "base/mac/scoped_nsobject.h"
 #import "base/metrics/histogram.h"
 #include "base/strings/stringprintf.h"
 #import "base/strings/sys_string_conversions.h"
@@ -406,7 +406,7 @@
   }
 
   // Minimize the window by keeping this close to the super call.
-  scoped_ptr<base::mac::ScopedNSExceptionEnabler> enabler(NULL);
+  scoped_ptr<base::mac::ScopedNSExceptionEnabler> enabler;
   if (enableNSExceptions)
     enabler.reset(new base::mac::ScopedNSExceptionEnabler());
   return [super sendAction:anAction to:aTarget from:sender];
diff --git a/chrome/browser/chrome_browser_field_trials.cc b/chrome/browser/chrome_browser_field_trials.cc
index 5bab278..00256c7 100644
--- a/chrome/browser/chrome_browser_field_trials.cc
+++ b/chrome/browser/chrome_browser_field_trials.cc
@@ -10,7 +10,7 @@
 #include "base/metrics/field_trial.h"
 #include "base/prefs/pref_service.h"
 #include "base/strings/string_util.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/omnibox/omnibox_field_trial.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/chrome_version_info.h"
@@ -57,6 +57,9 @@
   base::FieldTrialList::FindValue("InstantDummy");
   base::FieldTrialList::FindValue("InstantChannel");
   base::FieldTrialList::FindValue("Test0PercentDefault");
+  // MouseEventPreconnect trial is used from renderer process.
+  // Mark here so it will be sync-ed.
+  base::FieldTrialList::FindValue("MouseEventPreconnect");
   // Activate the autocomplete dynamic field trials.
   OmniboxFieldTrial::ActivateDynamicTrials();
 }
diff --git a/chrome/browser/chrome_browser_field_trials_desktop.h b/chrome/browser/chrome_browser_field_trials_desktop.h
index 16358cd..2668e7e 100644
--- a/chrome/browser/chrome_browser_field_trials_desktop.h
+++ b/chrome/browser/chrome_browser_field_trials_desktop.h
@@ -6,7 +6,7 @@
 #define CHROME_BROWSER_CHROME_BROWSER_FIELD_TRIALS_DESKTOP_H_
 
 #include "base/basictypes.h"
-#include "base/time.h"
+#include "base/time/time.h"
 
 class CommandLine;
 class PrefService;
diff --git a/chrome/browser/chrome_browser_field_trials_mobile.h b/chrome/browser/chrome_browser_field_trials_mobile.h
index 4aca806..dac9603 100644
--- a/chrome/browser/chrome_browser_field_trials_mobile.h
+++ b/chrome/browser/chrome_browser_field_trials_mobile.h
@@ -6,7 +6,7 @@
 #define CHROME_BROWSER_CHROME_BROWSER_FIELD_TRIALS_MOBILE_H_
 
 #include "base/basictypes.h"
-#include "base/time.h"
+#include "base/time/time.h"
 
 class CommandLine;
 class PrefService;
diff --git a/chrome/browser/chrome_browser_main.cc b/chrome/browser/chrome_browser_main.cc
index 856e4f2..a959216 100644
--- a/chrome/browser/chrome_browser_main.cc
+++ b/chrome/browser/chrome_browser_main.cc
@@ -34,7 +34,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/sys_info.h"
 #include "base/threading/platform_thread.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "base/values.h"
 #include "build/build_config.h"
 #include "chrome/browser/about_flags.h"
@@ -427,9 +427,15 @@
         command_line.GetSwitchValueASCII(switches::kOriginalProcessStartTime);
     int64 remote_start_time;
     if (base::StringToInt64(start_time_string, &remote_start_time)) {
-      UMA_HISTOGRAM_LONG_TIMES(
-          "Startup.WarmStartTimeFromRemoteProcessStart",
-          base::Time::Now() - base::Time::FromInternalValue(remote_start_time));
+      base::TimeDelta elapsed =
+          base::Time::Now() - base::Time::FromInternalValue(remote_start_time);
+      if (command_line.HasSwitch(switches::kFastStart)) {
+        UMA_HISTOGRAM_LONG_TIMES(
+            "Startup.WarmStartTimeFromRemoteProcessStartFast", elapsed);
+      } else {
+        UMA_HISTOGRAM_LONG_TIMES(
+            "Startup.WarmStartTimeFromRemoteProcessStart", elapsed);
+      }
     }
   }
 
@@ -610,11 +616,13 @@
   // Ensure any field trials specified on the command line are initialized.
   // Also stop the metrics service so that we don't pollute UMA.
   if (command_line->HasSwitch(switches::kForceFieldTrials)) {
-    std::string persistent = command_line->GetSwitchValueASCII(
-        switches::kForceFieldTrials);
-    bool ret = base::FieldTrialList::CreateTrialsFromString(persistent);
-    CHECK(ret) << "Invalid --" << switches::kForceFieldTrials <<
-                  " list specified.";
+    // Create field trials without activating them, so that this behaves in a
+    // consistent manner with field trials created from the server.
+    bool result = base::FieldTrialList::CreateTrialsFromString(
+        command_line->GetSwitchValueASCII(switches::kForceFieldTrials),
+        base::FieldTrialList::DONT_ACTIVATE_TRIALS);
+    CHECK(result) << "Invalid --" << switches::kForceFieldTrials
+                  << " list specified.";
   }
 
   chrome_variations::VariationsService* variations_service =
@@ -834,10 +842,13 @@
   chrome::UMABrowsingActivityObserver::Init();
 #endif
 
+#if !defined(OS_CHROMEOS)
   // Convert active labs into switches. This needs to be done before
   // ResourceBundle::InitSharedInstanceWithLocale as some loaded resources are
   // affected by experiment flags (--touch-optimized-ui in particular). Not
   // needed on Android as there aren't experimental flags.
+  // On ChromeOS system level flags are applied from the device settings from
+  // the session manager.
   {
     TRACE_EVENT0("startup",
         "ChromeBrowserMainParts::PreCreateThreadsImpl:ConvertFlags");
@@ -846,6 +857,7 @@
     about_flags::ConvertFlagsToSwitches(&flags_storage_,
                                         CommandLine::ForCurrentProcess());
   }
+#endif
 
   local_state_->UpdateCommandLinePrefStore(
       new CommandLinePrefStore(CommandLine::ForCurrentProcess()));
@@ -1069,10 +1081,8 @@
 #if !defined(OS_ANDROID)
 void ChromeBrowserMainParts::RunPageCycler() {
   CommandLine* command_line = CommandLine::ForCurrentProcess();
-  // We assume a native desktop for tests, but we will need to find a way to
-  // get the proper host desktop type once we start running these tests in ASH.
-  Browser* browser = chrome::FindBrowserWithProfile(
-      profile_, chrome::HOST_DESKTOP_TYPE_NATIVE);
+  Browser* browser = chrome::FindBrowserWithProfile(profile_,
+                                                    chrome::GetActiveDesktop());
   DCHECK(browser);
   PageCycler* page_cycler = NULL;
   base::FilePath input_file =
@@ -1554,14 +1564,10 @@
 #endif
       }
 
-#if !defined(OS_CHROMEOS)
-      // TODO(mad): Move this call in a proper place on CrOS.
-      // http://crosbug.com/17687
       if (translate_manager_ != NULL) {
         translate_manager_->FetchLanguageListFromTranslateServer(
             profile_->GetPrefs());
       }
-#endif
     }
 
     run_message_loop_ = true;
diff --git a/chrome/browser/chrome_browser_main_android.cc b/chrome/browser/chrome_browser_main_android.cc
index f08ce27..b83a09e 100644
--- a/chrome/browser/chrome_browser_main_android.cc
+++ b/chrome/browser/chrome_browser_main_android.cc
@@ -84,21 +84,6 @@
   ChromeBrowserMainParts::PreEarlyInitialization();
 }
 
-int ChromeBrowserMainPartsAndroid::PreCreateThreads() {
-  TRACE_EVENT0("startup", "ChromeBrowserMainPartsAndroid::PreCreateThreads")
-  // PreCreateThreads initializes ResourceBundle instance.
-  const int result = ChromeBrowserMainParts::PreCreateThreads();
-
-  // Add devtools_resources.pak which is used in Chromium TestShell.
-  base::FilePath paks_path;
-  PathService::Get(ui::DIR_RESOURCE_PAKS_ANDROID, &paks_path);
-  ResourceBundle::GetSharedInstance().AddOptionalDataPackFromPath(
-      paks_path.Append(FILE_PATH_LITERAL("devtools_resources.pak")),
-      ui::SCALE_FACTOR_NONE);
-
-  return result;
-}
-
 void ChromeBrowserMainPartsAndroid::ShowMissingLocaleMessageBox() {
   NOTREACHED();
 }
diff --git a/chrome/browser/chrome_browser_main_android.h b/chrome/browser/chrome_browser_main_android.h
index 1439ac2..b498db5 100644
--- a/chrome/browser/chrome_browser_main_android.h
+++ b/chrome/browser/chrome_browser_main_android.h
@@ -18,7 +18,6 @@
   // content::BrowserMainParts overrides.
   virtual void PreProfileInit() OVERRIDE;
   virtual void PreEarlyInitialization() OVERRIDE;
-  virtual int PreCreateThreads() OVERRIDE;
 
   // ChromeBrowserMainParts overrides.
   virtual void ShowMissingLocaleMessageBox() OVERRIDE;
diff --git a/chrome/browser/chrome_browser_main_mac.mm b/chrome/browser/chrome_browser_main_mac.mm
index b1b4989..156146b 100644
--- a/chrome/browser/chrome_browser_main_mac.mm
+++ b/chrome/browser/chrome_browser_main_mac.mm
@@ -12,7 +12,7 @@
 #include "base/files/file_path.h"
 #include "base/mac/bundle_locations.h"
 #include "base/mac/mac_util.h"
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "base/metrics/histogram.h"
 #include "base/path_service.h"
 #include "chrome/app/breakpad_mac.h"
@@ -265,9 +265,9 @@
   }
 
   // Now load the nib (from the right bundle).
-  scoped_nsobject<NSNib>
-      nib([[NSNib alloc] initWithNibNamed:@"MainMenu"
-                                   bundle:base::mac::FrameworkBundle()]);
+  base::scoped_nsobject<NSNib> nib(
+      [[NSNib alloc] initWithNibNamed:@"MainMenu"
+                               bundle:base::mac::FrameworkBundle()]);
   // TODO(viettrungluu): crbug.com/20504 - This currently leaks, so if you
   // change this, you'll probably need to change the Valgrind suppression.
   [nib instantiateNibWithOwner:NSApp topLevelObjects:nil];
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index 6aba761..f2a6ab4 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -44,6 +44,9 @@
 #include "chrome/browser/extensions/suggest_permission_util.h"
 #include "chrome/browser/geolocation/chrome_access_token_store.h"
 #include "chrome/browser/google/google_util.h"
+#include "chrome/browser/guestview/adview/adview_guest.h"
+#include "chrome/browser/guestview/guestview_constants.h"
+#include "chrome/browser/guestview/webview/webview_guest.h"
 #include "chrome/browser/media/media_capture_devices_dispatcher.h"
 #include "chrome/browser/metrics/chrome_browser_main_extra_parts_metrics.h"
 #include "chrome/browser/nacl_host/nacl_host_message_filter.h"
@@ -78,13 +81,12 @@
 #include "chrome/browser/tab_contents/tab_util.h"
 #include "chrome/browser/toolkit_extra_parts.h"
 #include "chrome/browser/ui/chrome_select_file_policy.h"
+#include "chrome/browser/ui/sync/sync_promo_ui.h"
 #include "chrome/browser/ui/tab_contents/chrome_web_contents_view_delegate.h"
 #include "chrome/browser/ui/webui/chrome_web_ui_controller_factory.h"
-#include "chrome/browser/ui/webui/sync_promo/sync_promo_ui.h"
 #include "chrome/browser/user_style_sheet_watcher.h"
 #include "chrome/browser/user_style_sheet_watcher_factory.h"
 #include "chrome/browser/validation_message_message_filter.h"
-#include "chrome/browser/webview/webview_guest.h"
 #include "chrome/common/child_process_logging.h"
 #include "chrome/common/chrome_constants.h"
 #include "chrome/common/chrome_paths.h"
@@ -134,6 +136,7 @@
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/message_center/message_center_util.h"
+#include "webkit/browser/fileapi/external_mount_points.h"
 #include "webkit/common/webpreferences.h"
 #include "webkit/plugins/plugin_switches.h"
 
@@ -145,6 +148,7 @@
 #include "chrome/browser/spellchecker/spellcheck_message_filter_mac.h"
 #elif defined(OS_CHROMEOS)
 #include "chrome/browser/chromeos/chrome_browser_main_chromeos.h"
+#include "chrome/browser/chromeos/fileapi/cros_mount_point_provider.h"
 #include "chrome/browser/chromeos/login/startup_utils.h"
 #include "chrome/browser/chromeos/login/user_manager.h"
 #include "chrome/browser/chromeos/system/statistics_provider.h"
@@ -232,6 +236,7 @@
   "ghbfeebgmiidnnmeobbbaiamklmpbpii",  // see crbug.com/134099
   "jdfhpkjeckflbbleddjlpimecpbjdeep",  // see crbug.com/142514
   "iabmpiboiopbgfabjmgeedhcmjenhbla",  // see crbug.com/165080
+  "B7CF8A292249681AF81771650BA4CEEAF19A4560", // see crbug.com/165080
   "6EAED1924DB611B6EEF2A664BD077BE7EAD33B8F", // see crbug.com/234789
   "7525AF4F66763A70A883C4700529F647B470E4D2", // see crbug.com/238084
   "0B549507088E1564D672F7942EB87CA4DAD73972", // see crbug.com/238084
@@ -693,28 +698,79 @@
   return extensions::ActivityLog::IsLogEnabledOnAnyProfile();
 }
 
+void ChromeContentBrowserClient::GuestWebContentsCreated(
+    WebContents* guest_web_contents,
+    WebContents* opener_web_contents,
+    scoped_ptr<base::DictionaryValue> extra_params) {
+  if (opener_web_contents) {
+    GuestView* guest = GuestView::FromWebContents(opener_web_contents);
+    if (!guest) {
+      NOTREACHED();
+      return;
+    }
+
+    switch (guest->GetViewType()) {
+      case GuestView::WEBVIEW: {
+        new WebViewGuest(guest_web_contents);
+        break;
+      }
+      case GuestView::ADVIEW: {
+        new AdViewGuest(guest_web_contents);
+        break;
+      }
+      default:
+        NOTREACHED();
+        break;
+    }
+    return;
+  }
+
+  if (!extra_params) {
+    NOTREACHED();
+    return;
+  }
+  std::string api_type;
+  extra_params->GetString(guestview::kAttributeApi, &api_type);
+
+  if (api_type == "adview") {
+    new AdViewGuest(guest_web_contents);
+  } else if (api_type == "webview") {
+    new WebViewGuest(guest_web_contents);
+  } else {
+    NOTREACHED();
+  }
+}
+
 void ChromeContentBrowserClient::GuestWebContentsAttached(
     WebContents* guest_web_contents,
     WebContents* embedder_web_contents,
-    int browser_plugin_instance_id) {
+    int browser_plugin_instance_id,
+    const base::DictionaryValue& extra_params) {
   Profile* profile = Profile::FromBrowserContext(
       embedder_web_contents->GetBrowserContext());
   ExtensionService* service =
       extensions::ExtensionSystem::Get(profile)->extension_service();
-  if (!service)
+  if (!service) {
+    NOTREACHED();
     return;
+  }
   const GURL& url = embedder_web_contents->GetSiteInstance()->GetSiteURL();
   const Extension* extension = service->extensions()->
       GetExtensionOrAppByURL(ExtensionURLInfo(url));
-  if (!extension)
+  if (!extension) {
+    NOTREACHED();
     return;
-  std::vector<ExtensionMsg_Loaded_Params> extensions;
-  extensions.push_back(ExtensionMsg_Loaded_Params(extension));
-  guest_web_contents->Send(new ExtensionMsg_Loaded(extensions));
-  new WebViewGuest(guest_web_contents,
-                   embedder_web_contents,
-                   extension->id(),
-                   browser_plugin_instance_id);
+  }
+
+  GuestView* guest = GuestView::FromWebContents(guest_web_contents);
+  if (!guest) {
+    NOTREACHED();
+    return;
+  }
+  guest->Attach(embedder_web_contents,
+                extension->id(),
+                browser_plugin_instance_id,
+                extra_params);
 }
 
 void ChromeContentBrowserClient::RenderProcessHostCreated(
@@ -748,8 +804,12 @@
   host->GetChannel()->AddFilter(new WebRtcLoggingHandlerHost());
 #endif
 #if !defined(DISABLE_NACL)
-  host->GetChannel()->AddFilter(new NaClHostMessageFilter(id, profile,
-    context));
+  ExtensionInfoMap* extension_info_map =
+      extensions::ExtensionSystem::Get(profile)->info_map();
+  host->GetChannel()->AddFilter(new NaClHostMessageFilter(
+      id, profile->IsOffTheRecord(),
+      profile->GetPath(), extension_info_map,
+      context));
 #endif
 
   host->Send(new ChromeViewMsg_SetIsIncognitoProcess(
@@ -1307,6 +1367,7 @@
       switches::kDisableScriptedPrintThrottling,
       switches::kEnableAdview,
       switches::kEnableAdviewSrcAttribute,
+      switches::kEnableAppWindowControls,
       switches::kEnableBenchmarking,
       switches::kEnableExperimentalExtensionApis,
       switches::kEnableIPCFuzzing,
@@ -1987,7 +2048,7 @@
       !chromeos::StartupUtils::IsOobeCompleted()) {
     bool keyboard_driven_oobe = false;
     chromeos::system::StatisticsProvider::GetInstance()->GetMachineFlag(
-        chromeos::kOemKeyboardDrivenOobeKey, &keyboard_driven_oobe);
+        chromeos::system::kOemKeyboardDrivenOobeKey, &keyboard_driven_oobe);
     if (keyboard_driven_oobe)
        web_prefs->password_echo_enabled = true;
   }
@@ -2236,6 +2297,8 @@
 
 void ChromeContentBrowserClient::GetAdditionalFileSystemMountPointProviders(
     const base::FilePath& storage_partition_path,
+    quota::SpecialStoragePolicy* special_storage_policy,
+    fileapi::ExternalMountPoints* external_mount_points,
     ScopedVector<fileapi::FileSystemMountPointProvider>* additional_providers) {
 #if !defined(OS_ANDROID)
   base::SequencedWorkerPool* pool = content::BrowserThread::GetBlockingPool();
@@ -2244,6 +2307,17 @@
       pool->GetSequencedTaskRunner(pool->GetNamedSequenceToken(
           MediaFileSystemMountPointProvider::kMediaTaskRunnerName)).get()));
 #endif
+#if defined(OS_CHROMEOS)
+  DCHECK(external_mount_points);
+  chromeos::CrosMountPointProvider* cros_mount_provider =
+      new chromeos::CrosMountPointProvider(
+          special_storage_policy,
+          external_mount_points,
+          fileapi::ExternalMountPoints::GetSystemInstance());
+  cros_mount_provider->AddSystemMountPoints();
+  DCHECK(cros_mount_provider->CanHandleType(fileapi::kFileSystemTypeExternal));
+  additional_providers->push_back(cros_mount_provider);
+#endif
 }
 
 #if defined(OS_POSIX) && !defined(OS_MACOSX)
diff --git a/chrome/browser/chrome_content_browser_client.h b/chrome/browser/chrome_content_browser_client.h
index 9d2a5e7..0996c6e 100644
--- a/chrome/browser/chrome_content_browser_client.h
+++ b/chrome/browser/chrome_content_browser_client.h
@@ -59,10 +59,15 @@
       bool* in_memory) OVERRIDE;
   virtual content::WebContentsViewDelegate* GetWebContentsViewDelegate(
       content::WebContents* web_contents) OVERRIDE;
+  virtual void GuestWebContentsCreated(
+      content::WebContents* guest_web_contents,
+      content::WebContents* opener_web_contents,
+      scoped_ptr<base::DictionaryValue> extra_params) OVERRIDE;
   virtual void GuestWebContentsAttached(
       content::WebContents* guest_web_contents,
       content::WebContents* embedder_web_contents,
-      int browser_plugin_instance_id) OVERRIDE;
+      int browser_plugin_instance_id,
+      const base::DictionaryValue& extra_params) OVERRIDE;
   virtual void RenderProcessHostCreated(
       content::RenderProcessHost* host) OVERRIDE;
   virtual bool ShouldUseProcessPerSite(content::BrowserContext* browser_context,
@@ -237,6 +242,8 @@
       std::vector<std::string>* additional_schemes) OVERRIDE;
   virtual void GetAdditionalFileSystemMountPointProviders(
       const base::FilePath& storage_partition_path,
+      quota::SpecialStoragePolicy* special_storage_policy,
+      fileapi::ExternalMountPoints* external_mount_points,
       ScopedVector<fileapi::FileSystemMountPointProvider>*
           additional_providers) OVERRIDE;
 
diff --git a/chrome/browser/chrome_content_browser_client_browsertest.cc b/chrome/browser/chrome_content_browser_client_browsertest.cc
index a8b6bbb..de24691 100644
--- a/chrome/browser/chrome_content_browser_client_browsertest.cc
+++ b/chrome/browser/chrome_content_browser_client_browsertest.cc
@@ -11,7 +11,7 @@
 #include "content/public/browser/navigation_entry.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/content_switches.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 namespace content {
 
diff --git a/chrome/browser/chrome_process_finder_win.cc b/chrome/browser/chrome_process_finder_win.cc
index c7a4985..34f6761 100644
--- a/chrome/browser/chrome_process_finder_win.cc
+++ b/chrome/browser/chrome_process_finder_win.cc
@@ -93,7 +93,7 @@
 
 // END COPY from net/base/escape.cc
 
-}
+}  // namespace
 
 namespace chrome {
 
@@ -102,7 +102,8 @@
                       user_data_dir.value().c_str());
 }
 
-NotifyChromeResult AttemptToNotifyRunningChrome(HWND remote_window) {
+NotifyChromeResult AttemptToNotifyRunningChrome(HWND remote_window,
+                                                bool fast_start) {
   DCHECK(remote_window);
   static const char kSearchUrl[] =
       "http://www.google.com/search?q=%s&sourceid=chrome&ie=UTF-8";
@@ -150,6 +151,9 @@
       base::Int64ToString(
           base::CurrentProcessInfo::CreationTime()->ToInternalValue()));
 
+  if (fast_start)
+    command_line.AppendSwitch(switches::kFastStart);
+
   // Send the command line to the remote chrome window.
   // Format is "START\0<<<current directory>>>\0<<<commandline>>>".
   std::wstring to_send(L"START\0", 6);  // want the NULL in the string.
diff --git a/chrome/browser/chrome_process_finder_win.h b/chrome/browser/chrome_process_finder_win.h
index 46c49ed..bc5c81f 100644
--- a/chrome/browser/chrome_process_finder_win.h
+++ b/chrome/browser/chrome_process_finder_win.h
@@ -25,7 +25,9 @@
 // Attempts to send the current command line to an already running instance of
 // Chrome via a WM_COPYDATA message.
 // Returns true if a running Chrome is found and successfully notified.
-NotifyChromeResult AttemptToNotifyRunningChrome(HWND remote_window);
+// |fast_start| is true when this is being called on the window fast start path.
+NotifyChromeResult AttemptToNotifyRunningChrome(HWND remote_window,
+                                                bool fast_start);
 
 }  // namespace chrome
 
diff --git a/chrome/browser/chrome_quota_permission_context.cc b/chrome/browser/chrome_quota_permission_context.cc
index 5c42180..3e3907b 100644
--- a/chrome/browser/chrome_quota_permission_context.cc
+++ b/chrome/browser/chrome_quota_permission_context.cc
@@ -17,11 +17,11 @@
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/navigation_details.h"
 #include "content/public/browser/web_contents.h"
-#include "googleurl/src/gurl.h"
 #include "grit/generated_resources.h"
 #include "grit/locale_settings.h"
 #include "net/base/net_util.h"
 #include "ui/base/l10n/l10n_util.h"
+#include "url/gurl.h"
 #include "webkit/common/quota/quota_types.h"
 
 using content::BrowserThread;
diff --git a/chrome/browser/chrome_to_mobile_service.cc b/chrome/browser/chrome_to_mobile_service.cc
index 4233625..eebde18 100644
--- a/chrome/browser/chrome_to_mobile_service.cc
+++ b/chrome/browser/chrome_to_mobile_service.cc
@@ -15,12 +15,12 @@
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/chrome_to_mobile_service_factory.h"
+#include "chrome/browser/invalidation/invalidation_service.h"
+#include "chrome/browser/invalidation/invalidation_service_factory.h"
 #include "chrome/browser/printing/cloud_print/cloud_print_url.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/signin/token_service.h"
 #include "chrome/browser/signin/token_service_factory.h"
-#include "chrome/browser/sync/profile_sync_service.h"
-#include "chrome/browser/sync/profile_sync_service_factory.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_command_controller.h"
 #include "chrome/browser/ui/browser_finder.h"
@@ -205,7 +205,7 @@
 // Call this as a BlockingPoolSequencedTask [after posting SubmitSnapshotFile].
 void DeleteSnapshotFile(const base::FilePath& snapshot) {
   DCHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
-  bool success = file_util::Delete(snapshot, false);
+  bool success = base::Delete(snapshot, false);
   DCHECK(success);
 }
 
@@ -261,23 +261,24 @@
 ChromeToMobileService::ChromeToMobileService(Profile* profile)
     : weak_ptr_factory_(this),
       profile_(profile),
-      sync_invalidation_enabled_(false) {
+      invalidation_enabled_(false) {
   // TODO(msw): Unit tests do not provide profiles; see http://crbug.com/122183
-  ProfileSyncService* profile_sync_service =
-      profile_ ? ProfileSyncServiceFactory::GetForProfile(profile_) : NULL;
-  if (profile_sync_service) {
+
+  invalidation::InvalidationService* invalidation_service = profile_ ?
+      invalidation::InvalidationServiceFactory::GetForProfile(profile_) : NULL;
+  if (invalidation_service) {
     CloudPrintURL cloud_print_url(profile_);
     cloud_print_url_ = cloud_print_url.GetCloudPrintServiceURL();
-    sync_invalidation_enabled_ =
-        (profile_sync_service->GetInvalidatorState() ==
+    invalidation_enabled_ =
+        (invalidation_service->GetInvalidatorState() ==
          syncer::INVALIDATIONS_ENABLED);
     // Register for cloud print device list invalidation notifications.
-    profile_sync_service->RegisterInvalidationHandler(this);
+    invalidation_service->RegisterInvalidationHandler(this);
     syncer::ObjectIdSet ids;
     ids.insert(invalidation::ObjectId(
         ipc::invalidation::ObjectSource::CHROME_COMPONENTS,
         kSyncInvalidationObjectIdChromeToMobileDeviceList));
-    profile_sync_service->UpdateRegisteredInvalidationIds(this, ids);
+    invalidation_service->UpdateRegisteredInvalidationIds(this, ids);
   }
 }
 
@@ -292,7 +293,7 @@
 }
 
 const base::ListValue* ChromeToMobileService::GetMobiles() const {
-  return sync_invalidation_enabled_ ?
+  return invalidation_enabled_ ?
       profile_->GetPrefs()->GetList(prefs::kChromeToMobileDeviceList) : NULL;
 }
 
@@ -384,10 +385,10 @@
 void ChromeToMobileService::Shutdown() {
   // TODO(msw): Unit tests do not provide profiles; see http://crbug.com/122183
   // Unregister for cloud print device list invalidation notifications.
-  ProfileSyncService* profile_sync_service =
-      profile_ ? ProfileSyncServiceFactory::GetForProfile(profile_) : NULL;
-  if (profile_sync_service)
-    profile_sync_service->UnregisterInvalidationHandler(this);
+  invalidation::InvalidationService* invalidation_service = profile_ ?
+      invalidation::InvalidationServiceFactory::GetForProfile(profile_) : NULL;
+  if (invalidation_service)
+    invalidation_service->UnregisterInvalidationHandler(this);
 }
 
 void ChromeToMobileService::OnURLFetchComplete(const net::URLFetcher* source) {
@@ -472,7 +473,7 @@
 
 void ChromeToMobileService::OnInvalidatorStateChange(
     syncer::InvalidatorState state) {
-  sync_invalidation_enabled_ = (state == syncer::INVALIDATIONS_ENABLED);
+  invalidation_enabled_ = (state == syncer::INVALIDATIONS_ENABLED);
 }
 
 void ChromeToMobileService::OnIncomingInvalidation(
@@ -482,12 +483,12 @@
       ipc::invalidation::ObjectSource::CHROME_COMPONENTS,
       kSyncInvalidationObjectIdChromeToMobileDeviceList)));
   // TODO(msw): Unit tests do not provide profiles; see http://crbug.com/122183
-  ProfileSyncService* profile_sync_service =
-      profile_ ? ProfileSyncServiceFactory::GetForProfile(profile_) : NULL;
-  if (profile_sync_service) {
+  invalidation::InvalidationService* invalidation_service = profile_ ?
+      invalidation::InvalidationServiceFactory::GetForProfile(profile_) : NULL;
+  if (invalidation_service) {
     // TODO(dcheng): Only acknowledge the invalidation once the device search
     // has finished. http://crbug.com/156843.
-    profile_sync_service->AcknowledgeInvalidation(
+    invalidation_service->AcknowledgeInvalidation(
         invalidation_map.begin()->first,
         invalidation_map.begin()->second.ack_handle);
   }
diff --git a/chrome/browser/chrome_to_mobile_service.h b/chrome/browser/chrome_to_mobile_service.h
index 499d856..ee18dee 100644
--- a/chrome/browser/chrome_to_mobile_service.h
+++ b/chrome/browser/chrome_to_mobile_service.h
@@ -16,16 +16,16 @@
 #include "base/memory/scoped_vector.h"
 #include "base/memory/weak_ptr.h"
 #include "base/strings/string16.h"
-#include "base/timer.h"
+#include "base/timer/timer.h"
 #include "base/values.h"
 #include "chrome/browser/sessions/session_id.h"
 #include "components/browser_context_keyed_service/browser_context_keyed_service.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
 #include "google_apis/gaia/oauth2_access_token_consumer.h"
-#include "googleurl/src/gurl.h"
 #include "net/url_request/url_fetcher_delegate.h"
 #include "sync/notifier/invalidation_handler.h"
+#include "url/gurl.h"
 
 class OAuth2AccessTokenFetcher;
 class Browser;
@@ -201,9 +201,9 @@
 
   Profile* profile_;
 
-  // Sync invalidation service state. Chrome To Mobile requires this service to
-  // to keep the mobile device list up to date and prevent page send failures.
-  bool sync_invalidation_enabled_;
+  // Invalidation service state. Chrome To Mobile requires this service to keep
+  // the mobile device list up to date and prevent page send failures.
+  bool invalidation_enabled_;
 
   // Used to recieve TokenService notifications for GaiaOAuth2LoginRefreshToken.
   content::NotificationRegistrar registrar_;
diff --git a/chrome/browser/chrome_to_mobile_service_factory.cc b/chrome/browser/chrome_to_mobile_service_factory.cc
index 3c1150a..8b1c0c4 100644
--- a/chrome/browser/chrome_to_mobile_service_factory.cc
+++ b/chrome/browser/chrome_to_mobile_service_factory.cc
@@ -5,9 +5,9 @@
 #include "chrome/browser/chrome_to_mobile_service_factory.h"
 
 #include "chrome/browser/chrome_to_mobile_service.h"
+#include "chrome/browser/invalidation/invalidation_service_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/signin/token_service_factory.h"
-#include "chrome/browser/sync/profile_sync_service_factory.h"
 #include "components/browser_context_keyed_service/browser_context_dependency_manager.h"
 
 // static
@@ -36,7 +36,7 @@
     : BrowserContextKeyedServiceFactory(
         "ChromeToMobileService",
         BrowserContextDependencyManager::GetInstance()) {
-  DependsOn(ProfileSyncServiceFactory::GetInstance());
+  DependsOn(invalidation::InvalidationServiceFactory::GetInstance());
   DependsOn(TokenServiceFactory::GetInstance());
   // TODO(msw): Uncomment this once it exists.
   // DependsOn(PrefServiceFactory::GetInstance());
diff --git a/chrome/browser/chrome_to_mobile_service_unittest.cc b/chrome/browser/chrome_to_mobile_service_unittest.cc
index 79635c8..3cc210ca 100644
--- a/chrome/browser/chrome_to_mobile_service_unittest.cc
+++ b/chrome/browser/chrome_to_mobile_service_unittest.cc
@@ -85,6 +85,10 @@
 // Test that GetMobiles and HasMobiles require Sync Invalidations being enabled.
 TEST_F(ChromeToMobileServiceTest, GetMobiles) {
   ChromeToMobileService* service = GetService();
+
+  // Send a fake notification that Sync Invalidations are disabled.
+  service->OnInvalidatorStateChange(syncer::TRANSIENT_INVALIDATION_ERROR);
+
   EXPECT_EQ(NULL, service->GetMobiles());
   EXPECT_FALSE(service->HasMobiles());
 
@@ -117,6 +121,9 @@
 
 // Test fulfilling the requirements to enable the feature.
 TEST_F(ChromeToMobileServiceTest, RequirementsToEnable) {
+  // Send a fake notification that Sync Invalidations are disabled.
+  GetService()->OnInvalidatorStateChange(syncer::TRANSIENT_INVALIDATION_ERROR);
+
   // Navigate to a page with a URL that is valid to send.
   AddTab(browser(), GURL("http://foo"));
   EXPECT_FALSE(UpdateAndGetVerifiedCommandState());
diff --git a/chrome/browser/chromeos/DEPS b/chrome/browser/chromeos/DEPS
index 8e9c86e..52ada1a 100644
--- a/chrome/browser/chromeos/DEPS
+++ b/chrome/browser/chromeos/DEPS
@@ -3,5 +3,4 @@
   "+dbus",
   "+device/bluetooth",
   "+media/base/media_switches.h",  # For media command line switches.
-  "+webkit/chromeos/fileapi",
 ]
diff --git a/chrome/browser/chromeos/accessibility/accessibility_manager.cc b/chrome/browser/chromeos/accessibility/accessibility_manager.cc
index e578328..f0617f7 100644
--- a/chrome/browser/chromeos/accessibility/accessibility_manager.cc
+++ b/chrome/browser/chromeos/accessibility/accessibility_manager.cc
@@ -7,6 +7,7 @@
 #include "ash/high_contrast/high_contrast_controller.h"
 #include "ash/shell.h"
 #include "ash/system/tray/system_tray_notifier.h"
+#include "ash/wm/event_rewriter_event_filter.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/singleton.h"
 #include "base/metrics/histogram.h"
@@ -32,9 +33,9 @@
 #include "chrome/common/extensions/manifest_handlers/content_scripts_handler.h"
 #include "chrome/common/pref_names.h"
 #include "content/public/browser/browser_accessibility_state.h"
-#include "content/public/browser/notification_observer.h"
-#include "content/public/browser/notification_registrar.h"
+#include "content/public/browser/notification_details.h"
 #include "content/public/browser/notification_service.h"
+#include "content/public/browser/notification_source.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/web_contents.h"
@@ -161,6 +162,7 @@
 AccessibilityManager::AccessibilityManager()
     : profile_(NULL),
       large_cursor_enabled_(false),
+      sticky_keys_enabled_(false),
       spoken_feedback_enabled_(false),
       high_contrast_enabled_(false),
       spoken_feedback_notification_(ash::A11Y_NOTIFICATION_NONE) {
@@ -216,6 +218,35 @@
   return large_cursor_enabled_;
 }
 
+void AccessibilityManager::EnableStickyKeys(bool enabled) {
+  if (!profile_)
+    return;
+  PrefService* pref_service = profile_->GetPrefs();
+  pref_service->SetBoolean(prefs::kStickyKeysEnabled, enabled);
+  pref_service->CommitPendingWrite();
+}
+
+bool AccessibilityManager::IsStickyKeysEnabled() {
+  return sticky_keys_enabled_;
+}
+
+void AccessibilityManager::UpdateStickyKeysFromPref() {
+  if (!profile_)
+    return;
+
+  const bool enabled =
+      profile_->GetPrefs()->GetBoolean(prefs::kStickyKeysEnabled);
+
+  if (sticky_keys_enabled_ == enabled)
+    return;
+
+  sticky_keys_enabled_ = enabled;
+#if defined(USE_ASH)
+  // Sticky keys is implemented only in ash.
+  ash::Shell::GetInstance()->event_rewriter_filter()->EnableStickyKeys(enabled);
+#endif
+}
+
 void AccessibilityManager::EnableSpokenFeedback(
     bool enabled,
     ash::AccessibilityNotificationVisibility notify) {
@@ -418,6 +449,10 @@
         base::Bind(&AccessibilityManager::UpdateLargeCursorFromPref,
                    base::Unretained(this)));
     pref_change_registrar_->Add(
+        prefs::kStickyKeysEnabled,
+        base::Bind(&AccessibilityManager::UpdateStickyKeysFromPref,
+                   base::Unretained(this)));
+    pref_change_registrar_->Add(
         prefs::kSpokenFeedbackEnabled,
         base::Bind(&AccessibilityManager::UpdateSpokenFeedbackFromPref,
                    base::Unretained(this)));
@@ -441,6 +476,7 @@
 
   profile_ = profile;
   UpdateLargeCursorFromPref();
+  UpdateStickyKeysFromPref();
   UpdateSpokenFeedbackFromPref();
   UpdateHighContrastFromPref();
 }
@@ -479,10 +515,13 @@
     const content::NotificationSource& source,
     const content::NotificationDetails& details) {
   switch (type) {
-    case chrome::NOTIFICATION_LOGIN_WEBUI_VISIBLE:
+    case chrome::NOTIFICATION_LOGIN_WEBUI_VISIBLE: {
       // Update |profile_| when entering the login screen.
-      SetProfile(ProfileHelper::GetSigninProfile());
+      Profile* profile = ProfileManager::GetDefaultProfile();
+      if (ProfileHelper::IsSigninProfile(profile))
+        SetProfile(profile);
       break;
+    }
     case chrome::NOTIFICATION_SESSION_STARTED:
       // Update |profile_| when entering a session.
       SetProfile(ProfileManager::GetDefaultProfile());
diff --git a/chrome/browser/chromeos/accessibility/accessibility_manager.h b/chrome/browser/chromeos/accessibility/accessibility_manager.h
index 5f87098..d181f01 100644
--- a/chrome/browser/chromeos/accessibility/accessibility_manager.h
+++ b/chrome/browser/chromeos/accessibility/accessibility_manager.h
@@ -48,6 +48,12 @@
   // Returns true if the large cursor is enabled, or false if not.
   bool IsLargeCursorEnabled();
 
+  // Enables or disable Sticky Keys.
+  void EnableStickyKeys(bool enabled);
+
+  // Returns true if the Sticky Keys is enabled, or false if not.
+  bool IsStickyKeysEnabled();
+
   // Enables or disables spoken feedback. Enabling spoken feedback installs the
   // ChromeVox component extension.
   void EnableSpokenFeedback(bool enabled,
@@ -79,6 +85,7 @@
 
  private:
   void UpdateLargeCursorFromPref();
+  void UpdateStickyKeysFromPref();
   void UpdateSpokenFeedbackFromPref();
   void UpdateHighContrastFromPref();
   void LocalePrefChanged();
@@ -98,6 +105,7 @@
   scoped_ptr<PrefChangeRegistrar> local_state_pref_change_registrar_;
 
   bool large_cursor_enabled_;
+  bool sticky_keys_enabled_;
   bool spoken_feedback_enabled_;
   bool high_contrast_enabled_;
 
diff --git a/chrome/browser/chromeos/accessibility/magnification_manager.cc b/chrome/browser/chromeos/accessibility/magnification_manager.cc
index 875f12a..84cdc21 100644
--- a/chrome/browser/chromeos/accessibility/magnification_manager.cc
+++ b/chrome/browser/chromeos/accessibility/magnification_manager.cc
@@ -22,10 +22,11 @@
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/common/chrome_notification_types.h"
 #include "chrome/common/pref_names.h"
-#include "content/public/browser/notification_observer.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_service.h"
+#include "content/public/browser/notification_source.h"
 
 namespace chromeos {
 
@@ -102,9 +103,7 @@
 
  private:
   void SetProfile(Profile* profile) {
-    if (pref_change_registrar_) {
-      pref_change_registrar_.reset();
-    }
+    pref_change_registrar_.reset();
 
     if (profile) {
       pref_change_registrar_.reset(new PrefChangeRegistrar);
@@ -186,15 +185,18 @@
         content::Details<AccessibilityStatusEventDetails>(&details));
   }
 
-  // content::NotificationObserver implimentation:
+  // content::NotificationObserver implementation:
   virtual void Observe(int type,
                        const content::NotificationSource& source,
                        const content::NotificationDetails& details) OVERRIDE {
     switch (type) {
-      case chrome::NOTIFICATION_LOGIN_WEBUI_VISIBLE:
+      case chrome::NOTIFICATION_LOGIN_WEBUI_VISIBLE: {
         // Update |profile_| when entering the login screen.
-        SetProfile(ProfileHelper::GetSigninProfile());
+        Profile* profile = ProfileManager::GetDefaultProfile();
+        if (ProfileHelper::IsSigninProfile(profile))
+          SetProfile(profile);
         break;
+      }
       case chrome::NOTIFICATION_SESSION_STARTED:
         // Update |profile_| when entering a session.
         SetProfile(ProfileManager::GetDefaultProfile());
diff --git a/chrome/browser/chromeos/app_mode/app_session_lifetime.cc b/chrome/browser/chromeos/app_mode/app_session_lifetime.cc
index 3e4aadc..48514f0 100644
--- a/chrome/browser/chromeos/app_mode/app_session_lifetime.cc
+++ b/chrome/browser/chromeos/app_mode/app_session_lifetime.cc
@@ -36,9 +36,10 @@
 
  private:
   // extensions::ShellWindowRegistry::Observer overrides:
-  virtual void OnShellWindowAdded(ShellWindow* shell_window) OVERRIDE {}
-  virtual void OnShellWindowIconChanged(ShellWindow* shell_window) OVERRIDE {}
-  virtual void OnShellWindowRemoved(ShellWindow* shell_window) OVERRIDE {
+  virtual void OnShellWindowAdded(apps::ShellWindow* shell_window) OVERRIDE {}
+  virtual void OnShellWindowIconChanged(apps::ShellWindow* shell_window)
+    OVERRIDE {}
+  virtual void OnShellWindowRemoved(apps::ShellWindow* shell_window) OVERRIDE {
     if (window_registry_->shell_windows().empty()) {
       chrome::AttemptUserExit();
       window_registry_->RemoveObserver(this);
diff --git a/chrome/browser/chromeos/app_mode/kiosk_app_data.cc b/chrome/browser/chromeos/app_mode/kiosk_app_data.cc
index 680ccc8..639d07f 100644
--- a/chrome/browser/chromeos/app_mode/kiosk_app_data.cc
+++ b/chrome/browser/chromeos/app_mode/kiosk_app_data.cc
@@ -277,7 +277,7 @@
   if (!icon_path_.empty()) {
     BrowserThread::PostBlockingPoolTask(
         FROM_HERE,
-        base::Bind(base::IgnoreResult(&file_util::Delete), icon_path_, false));
+        base::Bind(base::IgnoreResult(&base::Delete), icon_path_, false));
   }
 }
 
diff --git a/chrome/browser/chromeos/app_mode/kiosk_app_update_service.cc b/chrome/browser/chromeos/app_mode/kiosk_app_update_service.cc
index 0b789f9..e9a0384 100644
--- a/chrome/browser/chromeos/app_mode/kiosk_app_update_service.cc
+++ b/chrome/browser/chromeos/app_mode/kiosk_app_update_service.cc
@@ -6,6 +6,10 @@
 
 #include "base/logging.h"
 #include "chrome/browser/app_mode/app_mode_utils.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part_chromeos.h"
+#include "chrome/browser/chromeos/system/automatic_reboot_manager.h"
+#include "chrome/browser/extensions/api/runtime/runtime_api.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/extension_system.h"
 #include "chrome/browser/extensions/extension_system_factory.h"
@@ -22,17 +26,39 @@
 
 }  // namespace
 
-KioskAppUpdateService::KioskAppUpdateService(Profile* profile)
-    : profile_(profile) {
+KioskAppUpdateService::KioskAppUpdateService(
+    Profile* profile,
+    system::AutomaticRebootManager* automatic_reboot_manager)
+    : profile_(profile),
+      automatic_reboot_manager_(automatic_reboot_manager) {
   ExtensionService* service =
       extensions::ExtensionSystem::Get(profile_)->extension_service();
   if (service)
     service->AddUpdateObserver(this);
+
+  if (automatic_reboot_manager_)
+    automatic_reboot_manager_->AddObserver(this);
 }
 
 KioskAppUpdateService::~KioskAppUpdateService() {
 }
 
+void KioskAppUpdateService::StartAppUpdateRestartTimer() {
+  if (restart_timer_.IsRunning())
+    return;
+
+  // Setup timer to force restart once the wait period expires.
+  restart_timer_.Start(
+      FROM_HERE, base::TimeDelta::FromMilliseconds(kForceRestartWaitTimeMs),
+      this, &KioskAppUpdateService::ForceAppUpdateRestart);
+}
+
+void KioskAppUpdateService::ForceAppUpdateRestart() {
+  // Force a chrome restart (not a logout or reboot) by closing all browsers.
+  LOG(WARNING) << "Force closing all browsers to update kiosk app.";
+  chrome::CloseAllBrowsers();
+}
+
 void KioskAppUpdateService::Shutdown() {
   ExtensionService* service = profile_->GetExtensionService();
   if (service)
@@ -44,23 +70,38 @@
   if (app_id != app_id_)
     return;
 
-  StartRestartTimer();
+  extensions::RuntimeEventRouter::DispatchOnRestartRequiredEvent(
+      profile_,
+      app_id_,
+      extensions::api::runtime::OnRestartRequired::REASON_APP_UPDATE);
+
+  StartAppUpdateRestartTimer();
 }
 
-void KioskAppUpdateService::StartRestartTimer() {
-  if (restart_timer_.IsRunning())
-    return;
+void KioskAppUpdateService::OnRebootScheduled(Reason reason) {
+  extensions::api::runtime::OnRestartRequired::Reason restart_reason =
+      extensions::api::runtime::OnRestartRequired::REASON_NONE;
+  switch (reason) {
+    case REBOOT_REASON_OS_UPDATE:
+      restart_reason =
+          extensions::api::runtime::OnRestartRequired::REASON_OS_UPDATE;
+      break;
+    case REBOOT_REASON_PERIODIC:
+      restart_reason =
+          extensions::api::runtime::OnRestartRequired::REASON_PERIODIC;
+      break;
+    default:
+      NOTREACHED() << "Unknown reboot reason=" << reason;
+      return;
+  }
 
-  // Setup timer to force restart once the wait period expires.
-  restart_timer_.Start(
-      FROM_HERE, base::TimeDelta::FromMilliseconds(kForceRestartWaitTimeMs),
-      this, &KioskAppUpdateService::ForceRestart);
+  extensions::RuntimeEventRouter::DispatchOnRestartRequiredEvent(
+      profile_, app_id_, restart_reason);
 }
 
-void KioskAppUpdateService::ForceRestart() {
-  // Force a chrome restart (not a logout or reboot) by closing all browsers.
-  LOG(WARNING) << "Force closing all browsers to update kiosk app.";
-  chrome::CloseAllBrowsers();
+void KioskAppUpdateService::WillDestroyAutomaticRebootManager() {
+  automatic_reboot_manager_->RemoveObserver(this);
+  automatic_reboot_manager_ = NULL;
 }
 
 KioskAppUpdateServiceFactory::KioskAppUpdateServiceFactory()
@@ -92,8 +133,10 @@
 
 BrowserContextKeyedService*
 KioskAppUpdateServiceFactory::BuildServiceInstanceFor(
-    content::BrowserContext* profile) const {
-  return new KioskAppUpdateService(static_cast<Profile*>(profile));
+    content::BrowserContext* context) const {
+  return new KioskAppUpdateService(
+      Profile::FromBrowserContext(context),
+      g_browser_process->platform_part()->automatic_reboot_manager());
 }
 
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/app_mode/kiosk_app_update_service.h b/chrome/browser/chromeos/app_mode/kiosk_app_update_service.h
index 7421a81..8de4589 100644
--- a/chrome/browser/chromeos/app_mode/kiosk_app_update_service.h
+++ b/chrome/browser/chromeos/app_mode/kiosk_app_update_service.h
@@ -10,7 +10,8 @@
 #include "base/basictypes.h"
 #include "base/compiler_specific.h"
 #include "base/memory/singleton.h"
-#include "base/timer.h"
+#include "base/timer/timer.h"
+#include "chrome/browser/chromeos/system/automatic_reboot_manager_observer.h"
 #include "chrome/browser/extensions/update_observer.h"
 #include "components/browser_context_keyed_service/browser_context_keyed_service.h"
 #include "components/browser_context_keyed_service/browser_context_keyed_service_factory.h"
@@ -19,34 +20,48 @@
 
 namespace chromeos {
 
+namespace system {
+class AutomaticRebootManager;
+}
+
 // This class enforces automatic restart on app and Chrome updates in app mode.
 class KioskAppUpdateService : public BrowserContextKeyedService,
-                              public extensions::UpdateObserver {
+                              public extensions::UpdateObserver,
+                              public system::AutomaticRebootManagerObserver {
  public:
-  explicit KioskAppUpdateService(Profile* profile);
+  KioskAppUpdateService(
+      Profile* profile,
+      system::AutomaticRebootManager* automatic_reboot_manager);
   virtual ~KioskAppUpdateService();
 
   void set_app_id(const std::string& app_id) { app_id_ = app_id; }
   std::string get_app_id() const { return app_id_; }
 
  private:
-  void StartRestartTimer();
-  void ForceRestart();
+  friend class KioskAppUpdateServiceTest;
+
+  void StartAppUpdateRestartTimer();
+  void ForceAppUpdateRestart();
+
+  // BrowserContextKeyedService overrides:
+  virtual void Shutdown() OVERRIDE;
 
   // extensions::UpdateObserver overrides:
   virtual void OnAppUpdateAvailable(const std::string& app_id) OVERRIDE;
   virtual void OnChromeUpdateAvailable() OVERRIDE {}
 
-  // BrowserContextKeyedService overrides:
-  virtual void Shutdown() OVERRIDE;
+  // system::AutomaticRebootManagerObserver overrides:
+  virtual void OnRebootScheduled(Reason reason) OVERRIDE;
+  virtual void WillDestroyAutomaticRebootManager() OVERRIDE;
 
- private:
   Profile* profile_;
   std::string app_id_;
 
   // After we detect an upgrade we start a one-short timer to force restart.
   base::OneShotTimer<KioskAppUpdateService> restart_timer_;
 
+  system::AutomaticRebootManager* automatic_reboot_manager_;  // Not owned.
+
   DISALLOW_COPY_AND_ASSIGN(KioskAppUpdateService);
 };
 
diff --git a/chrome/browser/chromeos/app_mode/kiosk_app_update_service_browsertest.cc b/chrome/browser/chromeos/app_mode/kiosk_app_update_service_browsertest.cc
new file mode 100644
index 0000000..f37386d
--- /dev/null
+++ b/chrome/browser/chromeos/app_mode/kiosk_app_update_service_browsertest.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 <string>
+
+#include "base/basictypes.h"
+#include "base/command_line.h"
+#include "base/compiler_specific.h"
+#include "base/file_util.h"
+#include "base/files/file_path.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/path_service.h"
+#include "base/prefs/pref_service.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/test/scoped_path_override.h"
+#include "base/threading/sequenced_worker_pool.h"
+#include "base/time/time.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
+#include "chrome/browser/chromeos/app_mode/kiosk_app_update_service.h"
+#include "chrome/browser/chromeos/system/automatic_reboot_manager.h"
+#include "chrome/browser/extensions/extension_test_message_listener.h"
+#include "chrome/browser/extensions/platform_app_browsertest_util.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/extensions/extension.h"
+#include "chrome/common/pref_names.h"
+#include "chromeos/chromeos_paths.h"
+#include "chromeos/dbus/update_engine_client.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/test/test_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace chromeos {
+
+class KioskAppUpdateServiceTest : public extensions::PlatformAppBrowserTest {
+ public:
+  KioskAppUpdateServiceTest() : app_(NULL), update_service_(NULL) {}
+  virtual ~KioskAppUpdateServiceTest() {}
+
+  // extensions::PlatformAppBrowserTest overrides:
+  virtual void SetUpOnMainThread() OVERRIDE {
+    extensions::PlatformAppBrowserTest::SetUpOnMainThread();
+
+    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+    const base::FilePath& temp_dir = temp_dir_.path();
+
+    const base::TimeDelta uptime = base::TimeDelta::FromHours(1);
+    const std::string uptime_seconds =
+        base::DoubleToString(uptime.InSecondsF());
+    const base::FilePath uptime_file = temp_dir.Append("uptime");
+    ASSERT_EQ(static_cast<int>(uptime_seconds.size()),
+              file_util::WriteFile(
+                  uptime_file, uptime_seconds.c_str(), uptime_seconds.size()));
+    uptime_file_override_.reset(
+        new base::ScopedPathOverride(chromeos::FILE_UPTIME, uptime_file));
+
+    app_ = LoadExtension(
+        test_data_dir_.AppendASCII("api_test/runtime/on_restart_required"));
+
+    // Fake app mode command line.
+    CommandLine* command = CommandLine::ForCurrentProcess();
+    command->AppendSwitch(switches::kForceAppMode);
+    command->AppendSwitchASCII(switches::kAppId, app_->id());
+
+    update_service_ = KioskAppUpdateServiceFactory::GetForProfile(profile());
+    update_service_->set_app_id(app_->id());
+
+    content::BrowserThread::GetBlockingPool()->FlushForTesting();
+    content::RunAllPendingInMessageLoop();
+  }
+
+  void FireAppUpdateAvailable() {
+    update_service_->OnAppUpdateAvailable(app_->id());
+  }
+
+  void FireUpdatedNeedReboot() {
+    UpdateEngineClient::Status status;
+    status.status = UpdateEngineClient::UPDATE_STATUS_UPDATED_NEED_REBOOT;
+    g_browser_process->platform_part()->automatic_reboot_manager()->
+        UpdateStatusChanged(status);
+  }
+
+ private:
+  base::ScopedTempDir temp_dir_;
+  scoped_ptr<base::ScopedPathOverride> uptime_file_override_;
+  const extensions::Extension* app_;  // Not owned.
+  KioskAppUpdateService* update_service_;  // Not owned.
+
+  DISALLOW_COPY_AND_ASSIGN(KioskAppUpdateServiceTest);
+};
+
+IN_PROC_BROWSER_TEST_F(KioskAppUpdateServiceTest, AppUpdate) {
+  FireAppUpdateAvailable();
+
+  ExtensionTestMessageListener listener("app_update", false);
+  listener.WaitUntilSatisfied();
+}
+
+IN_PROC_BROWSER_TEST_F(KioskAppUpdateServiceTest, OsUpdate) {
+  g_browser_process->local_state()->SetBoolean(prefs::kRebootAfterUpdate, true);
+  FireUpdatedNeedReboot();
+
+  ExtensionTestMessageListener listener("os_update", false);
+  listener.WaitUntilSatisfied();
+}
+
+IN_PROC_BROWSER_TEST_F(KioskAppUpdateServiceTest, Periodic) {
+  g_browser_process->local_state()->SetInteger(
+      prefs::kUptimeLimit, base::TimeDelta::FromMinutes(30).InSeconds());
+
+  ExtensionTestMessageListener listener("periodic", false);
+  listener.WaitUntilSatisfied();
+}
+
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/app_mode/startup_app_launcher.cc b/chrome/browser/chromeos/app_mode/startup_app_launcher.cc
index 0dd80fe..b1d38b4 100644
--- a/chrome/browser/chromeos/app_mode/startup_app_launcher.cc
+++ b/chrome/browser/chromeos/app_mode/startup_app_launcher.cc
@@ -9,7 +9,7 @@
 #include "base/files/file_path.h"
 #include "base/json/json_file_value_serializer.h"
 #include "base/path_service.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "base/values.h"
 #include "chrome/browser/chromeos/app_mode/app_session_lifetime.h"
 #include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h"
diff --git a/chrome/browser/chromeos/app_mode/startup_app_launcher.h b/chrome/browser/chromeos/app_mode/startup_app_launcher.h
index 8d63387..a4bc841 100644
--- a/chrome/browser/chromeos/app_mode/startup_app_launcher.h
+++ b/chrome/browser/chromeos/app_mode/startup_app_launcher.h
@@ -10,7 +10,7 @@
 #include "base/basictypes.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
-#include "base/timer.h"
+#include "base/timer/timer.h"
 #include "chrome/browser/chromeos/app_mode/kiosk_app_launch_error.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
diff --git a/chrome/browser/chromeos/attestation/attestation_policy_observer.cc b/chrome/browser/chromeos/attestation/attestation_policy_observer.cc
index 37a7a0b..7028f5c 100644
--- a/chrome/browser/chromeos/attestation/attestation_policy_observer.cc
+++ b/chrome/browser/chromeos/attestation/attestation_policy_observer.cc
@@ -9,7 +9,7 @@
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/location.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/chromeos/attestation/attestation_ca_client.h"
 #include "chrome/browser/chromeos/attestation/attestation_key_payload.pb.h"
 #include "chrome/browser/chromeos/settings/cros_settings.h"
@@ -35,6 +35,8 @@
 // been set large enough so that the majority of users will have gone through
 // a full sign-in during the period.
 const int kExpiryThresholdInDays = 30;
+const int kRetryDelay = 5;  // Seconds.
+const int kRetryLimit = 100;
 
 // A dbus callback which handles a boolean result.
 //
@@ -45,12 +47,15 @@
 //   value - The value returned by the dbus operation.
 void DBusBoolRedirectCallback(const base::Closure& on_true,
                               const base::Closure& on_false,
+                              const base::Closure& on_failure,
                               const tracked_objects::Location& from_here,
                               chromeos::DBusMethodCallStatus status,
                               bool value) {
   if (status != chromeos::DBUS_METHOD_CALL_SUCCESS) {
     LOG(ERROR) << "Cryptohome DBus method failed: " << from_here.ToString()
                << " - " << status;
+    if (!on_failure.is_null())
+      on_failure.Run();
     return;
   }
   const base::Closure& task = value ? on_true : on_false;
@@ -67,6 +72,7 @@
 //   data - The data returned by the dbus operation.
 void DBusStringCallback(
     const base::Callback<void(const std::string&)> on_success,
+    const base::Closure& on_failure,
     const tracked_objects::Location& from_here,
     chromeos::DBusMethodCallStatus status,
     bool result,
@@ -74,6 +80,8 @@
   if (status != chromeos::DBUS_METHOD_CALL_SUCCESS || !result) {
     LOG(ERROR) << "Cryptohome DBus method failed: " << from_here.ToString()
                << " - " << status << " - " << result;
+    if (!on_failure.is_null())
+      on_failure.Run();
     return;
   }
   on_success.Run(data);
@@ -90,6 +98,8 @@
       policy_client_(policy_client),
       cryptohome_client_(NULL),
       attestation_flow_(NULL),
+      num_retries_(0),
+      retry_delay_(kRetryDelay),
       weak_factory_(this) {
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
   cros_settings_->AddSettingsObserver(kDeviceAttestationEnabled, this);
@@ -104,6 +114,8 @@
       policy_client_(policy_client),
       cryptohome_client_(cryptohome_client),
       attestation_flow_(attestation_flow),
+      num_retries_(0),
+      retry_delay_(kRetryDelay),
       weak_factory_(this) {
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
   cros_settings_->AddSettingsObserver(kDeviceAttestationEnabled, this);
@@ -126,6 +138,7 @@
     LOG(WARNING) << "AttestationPolicyObserver: Unexpected event received.";
     return;
   }
+  num_retries_ = 0;
   Start();
 }
 
@@ -167,6 +180,8 @@
       base::Bind(DBusBoolRedirectCallback,
                  on_does_exist,
                  on_does_not_exist,
+                 base::Bind(&AttestationPolicyObserver::Reschedule,
+                            weak_factory_.GetWeakPtr()),
                  FROM_HERE));
 }
 
@@ -178,6 +193,8 @@
       base::Bind(DBusStringCallback,
                  base::Bind(&AttestationPolicyObserver::UploadCertificate,
                             weak_factory_.GetWeakPtr()),
+                 base::Bind(&AttestationPolicyObserver::Reschedule,
+                            weak_factory_.GetWeakPtr()),
                  FROM_HERE,
                  DBUS_METHOD_CALL_SUCCESS));
 }
@@ -189,6 +206,8 @@
       base::Bind(DBusStringCallback,
                  base::Bind(&AttestationPolicyObserver::CheckCertificateExpiry,
                             weak_factory_.GetWeakPtr()),
+                 base::Bind(&AttestationPolicyObserver::Reschedule,
+                            weak_factory_.GetWeakPtr()),
                  FROM_HERE));
 }
 
@@ -241,12 +260,17 @@
   cryptohome_client_->TpmAttestationGetKeyPayload(
       KEY_DEVICE,
       kEnterpriseMachineKey,
-      base::Bind(DBusStringCallback, callback, FROM_HERE));
+      base::Bind(DBusStringCallback,
+                 callback,
+                 base::Bind(&AttestationPolicyObserver::Reschedule,
+                            weak_factory_.GetWeakPtr()),
+                 FROM_HERE));
 }
 
 void AttestationPolicyObserver::OnUploadComplete(bool status) {
   if (!status)
     return;
+  LOG(INFO) << "Enterprise Machine Certificate uploaded to DMServer.";
   GetKeyPayload(base::Bind(&AttestationPolicyObserver::MarkAsUploaded,
                            weak_factory_.GetWeakPtr()));
 }
@@ -268,8 +292,21 @@
       base::Bind(DBusBoolRedirectCallback,
                  base::Closure(),
                  base::Closure(),
+                 base::Closure(),
                  FROM_HERE));
 }
 
+void AttestationPolicyObserver::Reschedule() {
+  if (++num_retries_ < kRetryLimit) {
+    content::BrowserThread::PostDelayedTask(
+        content::BrowserThread::UI, FROM_HERE,
+        base::Bind(&AttestationPolicyObserver::Start,
+                   weak_factory_.GetWeakPtr()),
+        base::TimeDelta::FromSeconds(retry_delay_));
+  } else {
+    LOG(WARNING) << "AttestationPolicyObserver: Retry limit exceeded.";
+  }
+}
+
 }  // namespace attestation
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/attestation/attestation_policy_observer.h b/chrome/browser/chromeos/attestation/attestation_policy_observer.h
index 1ae4e50..1f78971 100644
--- a/chrome/browser/chromeos/attestation/attestation_policy_observer.h
+++ b/chrome/browser/chromeos/attestation/attestation_policy_observer.h
@@ -50,6 +50,11 @@
                        const content::NotificationSource& source,
                        const content::NotificationDetails& details) OVERRIDE;
 
+  // Sets the retry delay in seconds; useful in testing.
+  void set_retry_delay(int retry_delay) {
+    retry_delay_ = retry_delay;
+  }
+
  private:
   // Checks attestation policy and starts any necessary work.
   void Start();
@@ -80,11 +85,18 @@
   // Marks a key as uploaded in the payload proto.
   void MarkAsUploaded(const std::string& key_payload);
 
+  // Reschedules a policy check (i.e. a call to Start) for a later time.
+  // TODO(dkrahn): A better solution would be to wait for a dbus signal which
+  // indicates the system is ready to process this task. See crbug.com/256845.
+  void Reschedule();
+
   CrosSettings* cros_settings_;
   policy::CloudPolicyClient* policy_client_;
   CryptohomeClient* cryptohome_client_;
   AttestationFlow* attestation_flow_;
   scoped_ptr<AttestationFlow> default_attestation_flow_;
+  int num_retries_;
+  int retry_delay_;
 
   // 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/attestation/attestation_policy_observer_unittest.cc b/chrome/browser/chromeos/attestation/attestation_policy_observer_unittest.cc
index 19ef480..dd0a070 100644
--- a/chrome/browser/chromeos/attestation/attestation_policy_observer_unittest.cc
+++ b/chrome/browser/chromeos/attestation/attestation_policy_observer_unittest.cc
@@ -19,7 +19,7 @@
 #include "content/public/test/test_browser_thread.h"
 #include "crypto/rsa_private_key.h"
 #include "net/cert/x509_certificate.h"
-#include "net/cert/x509_util_nss.h"
+#include "net/cert/x509_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 using testing::_;
@@ -75,6 +75,11 @@
       FROM_HERE, base::Bind(callback, DBUS_METHOD_CALL_SUCCESS, true));
 }
 
+void DBusCallbackError(const BoolDBusMethodCallback& callback) {
+  base::MessageLoop::current()->PostTask(
+      FROM_HERE, base::Bind(callback, DBUS_METHOD_CALL_FAILURE, false));
+}
+
 void CertCallbackSuccess(const AttestationFlow::CertificateCallback& callback) {
   base::MessageLoop::current()->PostTask(
       FROM_HERE, base::Bind(callback, true, "fake_cert"));
@@ -187,6 +192,7 @@
     AttestationPolicyObserver observer(&policy_client_,
                                        &cryptohome_client_,
                                        &attestation_flow_);
+    observer.set_retry_delay(0);
     base::RunLoop().RunUntilIdle();
   }
 
@@ -220,19 +226,12 @@
                                &kTestKeyData[arraysize(kTestKeyData)])));
     if (!test_key.get())
       return false;
-    net::X509Certificate::OSCertHandle handle =
-        net::x509_util::CreateSelfSignedCert(test_key->public_key(),
-                                             test_key->key(),
-                                             "CN=subject",
-                                             12345,
-                                             valid_start,
-                                             valid_expiry);
-
-    if (!handle)
-      return false;
-    bool result = net::X509Certificate::GetDEREncoded(handle, certificate);
-    net::X509Certificate::FreeOSCertHandle(handle);
-    return result;
+    return net::x509_util::CreateSelfSignedCert(test_key.get(),
+                                                "CN=subject",
+                                                12345,
+                                                valid_start,
+                                                valid_expiry,
+                                                certificate);
   }
 
   base::MessageLoop message_loop_;
@@ -295,5 +294,14 @@
   Run();
 }
 
+TEST_F(AttestationPolicyObserverTest, DBusFailureRetry) {
+  SetupMocks(MOCK_NEW_KEY, "");
+  // Simulate a DBus failure.
+  EXPECT_CALL(cryptohome_client_, TpmAttestationDoesKeyExist(_, _, _))
+      .WillOnce(WithArgs<2>(Invoke(DBusCallbackError)))
+      .WillRepeatedly(WithArgs<2>(Invoke(DBusCallbackFalse)));
+  Run();
+}
+
 }  // namespace attestation
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/audio/audio_devices_pref_handler_impl.cc b/chrome/browser/chromeos/audio/audio_devices_pref_handler_impl.cc
index 2fc83e3..b43afdb 100644
--- a/chrome/browser/chromeos/audio/audio_devices_pref_handler_impl.cc
+++ b/chrome/browser/chromeos/audio/audio_devices_pref_handler_impl.cc
@@ -15,15 +15,25 @@
 #include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/common/chrome_notification_types.h"
 #include "chrome/common/pref_names.h"
+#include "chromeos/audio/audio_device.h"
 #include "chromeos/audio/cras_audio_handler.h"
 
+namespace {
+
+std::string GetDeviceIdString(const chromeos::AudioDevice& device) {
+  return device.display_name + " : " +
+         base::Uint64ToString(device.id & static_cast<uint64>(0xffffffff));
+}
+
+}
+
 namespace chromeos {
 
 double AudioDevicesPrefHandlerImpl::GetVolumeGainValue(
-    uint64 device_id) {
+    const AudioDevice& device) {
   UpdateDevicesVolumePref();
 
-  std::string device_id_str = base::Uint64ToString(device_id);
+  std::string device_id_str = GetDeviceIdString(device);
   if (!device_volume_settings_->HasKey(device_id_str))
     MigrateDeviceVolumeSettings(device_id_str);
 
@@ -34,17 +44,17 @@
 }
 
 void AudioDevicesPrefHandlerImpl::SetVolumeGainValue(
-    uint64 device_id, double value) {
+    const AudioDevice& device, double value) {
   value = std::min(std::max(value, 0.0), 100.0);
-  device_volume_settings_->SetDouble(base::Uint64ToString(device_id), value);
+  device_volume_settings_->SetDouble(GetDeviceIdString(device), value);
 
   SaveDevicesVolumePref();
 }
 
-bool AudioDevicesPrefHandlerImpl::GetMuteValue(uint64 device_id) {
+bool AudioDevicesPrefHandlerImpl::GetMuteValue(const AudioDevice& device) {
   UpdateDevicesMutePref();
 
-  std::string device_id_str = base::Uint64ToString(device_id);
+  std::string device_id_str = GetDeviceIdString(device);
   if (!device_mute_settings_->HasKey(device_id_str))
     MigrateDeviceMuteSettings(device_id_str);
 
@@ -54,9 +64,9 @@
   return (mute == kPrefMuteOn);
 }
 
-void AudioDevicesPrefHandlerImpl::SetMuteValue(uint64 device_id,
+void AudioDevicesPrefHandlerImpl::SetMuteValue(const AudioDevice& device,
                                                bool mute) {
-  device_mute_settings_->SetInteger(base::Uint64ToString(device_id),
+  device_mute_settings_->SetInteger(GetDeviceIdString(device),
                                     mute ? kPrefMuteOn : kPrefMuteOff);
   SaveDevicesMutePref();
 }
diff --git a/chrome/browser/chromeos/audio/audio_devices_pref_handler_impl.h b/chrome/browser/chromeos/audio/audio_devices_pref_handler_impl.h
index e596a1f..1a46dcf 100644
--- a/chrome/browser/chromeos/audio/audio_devices_pref_handler_impl.h
+++ b/chrome/browser/chromeos/audio/audio_devices_pref_handler_impl.h
@@ -22,11 +22,12 @@
   explicit AudioDevicesPrefHandlerImpl(PrefService* local_state);
 
   // Overridden from AudioDevicesPrefHandler.
-  virtual double GetVolumeGainValue(uint64 device_id) OVERRIDE;
-  virtual void SetVolumeGainValue(uint64 device_id, double value) OVERRIDE;
+  virtual double GetVolumeGainValue(const AudioDevice& device) OVERRIDE;
+  virtual void SetVolumeGainValue(const AudioDevice& device,
+                                  double value) OVERRIDE;
 
-  virtual bool GetMuteValue(uint64 device_id) OVERRIDE;
-  virtual void SetMuteValue(uint64 device_id, bool mute_on) OVERRIDE;
+  virtual bool GetMuteValue(const AudioDevice& device) OVERRIDE;
+  virtual void SetMuteValue(const AudioDevice& device, bool mute_on) OVERRIDE;
 
   virtual bool GetAudioCaptureAllowedValue() OVERRIDE;
   virtual bool GetAudioOutputAllowedValue() OVERRIDE;
diff --git a/chrome/browser/chromeos/boot_times_loader.cc b/chrome/browser/chromeos/boot_times_loader.cc
index 7522d61..a9919ae 100644
--- a/chrome/browser/chromeos/boot_times_loader.cc
+++ b/chrome/browser/chromeos/boot_times_loader.cc
@@ -21,7 +21,7 @@
 #include "base/strings/stringprintf.h"
 #include "base/threading/thread.h"
 #include "base/threading/thread_restrictions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chromeos/login/authentication_notification_details.h"
 #include "chrome/browser/ui/browser.h"
diff --git a/chrome/browser/chromeos/boot_times_loader.h b/chrome/browser/chromeos/boot_times_loader.h
index dc420e8..2312a57 100644
--- a/chrome/browser/chromeos/boot_times_loader.h
+++ b/chrome/browser/chromeos/boot_times_loader.h
@@ -11,7 +11,7 @@
 #include "base/atomic_sequence_num.h"
 #include "base/callback_forward.h"
 #include "base/compiler_specific.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/common/cancelable_task_tracker.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
diff --git a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
index d34fd61..834916c 100644
--- a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
+++ b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
@@ -21,8 +21,6 @@
 #include "base/prefs/pref_service.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
-#include "base/time/default_tick_clock.h"
-#include "base/time/tick_clock.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/browser_process_platform_part_chromeos.h"
 #include "chrome/browser/chromeos/accessibility/accessibility_manager.h"
@@ -72,7 +70,7 @@
 #include "chrome/browser/chromeos/settings/device_oauth2_token_service_factory.h"
 #include "chrome/browser/chromeos/settings/device_settings_service.h"
 #include "chrome/browser/chromeos/settings/owner_key_util.h"
-#include "chrome/browser/chromeos/system/automatic_reboot_manager.h"
+#include "chrome/browser/chromeos/swap_metrics.h"
 #include "chrome/browser/chromeos/system/device_change_handler.h"
 #include "chrome/browser/chromeos/system/statistics_provider.h"
 #include "chrome/browser/chromeos/system_key_event_listener.h"
@@ -101,7 +99,6 @@
 #include "chromeos/cryptohome/async_method_caller.h"
 #include "chromeos/cryptohome/cryptohome_library.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
-#include "chromeos/dbus/power_manager_client.h"
 #include "chromeos/dbus/session_manager_client.h"
 #include "chromeos/disks/disk_mount_manager.h"
 #include "chromeos/ime/input_method_manager.h"
@@ -110,7 +107,6 @@
 #include "chromeos/network/network_change_notifier_chromeos.h"
 #include "chromeos/network/network_change_notifier_factory_chromeos.h"
 #include "chromeos/network/network_handler.h"
-#include "chromeos/power/power_manager_handler.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/power_save_blocker.h"
@@ -120,6 +116,11 @@
 #include "net/url_request/url_request.h"
 #include "net/url_request/url_request_context_getter.h"
 
+// Exclude X11 dependents for ozone
+#if defined(USE_X11)
+#include "chrome/browser/chromeos/device_uma.h"
+#endif
+
 namespace chromeos {
 
 namespace {
@@ -385,6 +386,8 @@
   if (KioskModeSettings::Get()->IsKioskModeEnabled())
     ShutdownKioskModeScreensaver();
 
+  dbus_services_.reset();
+
   // To be precise, logout (browser shutdown) is not yet done, but the
   // remaining work is negligible, hence we say LogoutDone here.
   BootTimesLoader::Get()->AddLogoutTimeMarker("LogoutDone", false);
@@ -460,11 +463,6 @@
 // Threads are initialized between MainMessageLoopStart and MainMessageLoopRun.
 // about_flags settings are applied in ChromeBrowserMainParts::PreCreateThreads.
 void ChromeBrowserMainPartsChromeos::PreMainMessageLoopRun() {
-  // Set the crypto thread after the IO thread has been created/started.
-  NetworkHandler::Get()->cert_loader()->SetCryptoTaskRunner(
-      content::BrowserThread::GetMessageLoopProxyForThread(
-          content::BrowserThread::IO));
-
   if (ash::switches::UseNewAudioHandler()) {
     CrasAudioHandler::Initialize(
         AudioDevicesPrefHandler::Create(g_browser_process->local_state()));
@@ -473,8 +471,6 @@
        AudioPrefHandler::Create(g_browser_process->local_state()));
   }
 
-  PowerManagerHandler::Initialize();
-
   if (!StartupUtils::IsOobeCompleted())
     system::StatisticsProvider::GetInstance()->LoadOemManifest();
 
@@ -542,18 +538,10 @@
   //   2) if passed alone, to signal that the indicated user has already
   //      logged in and we should behave accordingly.
   // This handles case 2.
-  if (parsed_command_line().HasSwitch(switches::kLoginUser) &&
-      !parsed_command_line().HasSwitch(switches::kLoginPassword)) {
-    std::string username =
-        parsed_command_line().GetSwitchValueASCII(switches::kLoginUser);
-    UserManager* user_manager = UserManager::Get();
-    // In case of multi-profiles --login-profile will contain user_id_hash.
-    std::string username_hash =
-        parsed_command_line().GetSwitchValueASCII(switches::kLoginProfile);
-    user_manager->UserLoggedIn(username, username_hash, true);
-    VLOG(1) << "Relaunching browser for user: " << username
-            << " with hash: " << username_hash;
-
+  bool immediate_login =
+      parsed_command_line().HasSwitch(switches::kLoginUser) &&
+      !parsed_command_line().HasSwitch(switches::kLoginPassword);
+  if (immediate_login){
     // Redirects Chrome logging to the user data dir.
     logging::RedirectChromeLogging(parsed_command_line());
 
@@ -594,6 +582,18 @@
 
   // In Aura builds this will initialize ash::Shell.
   ChromeBrowserMainPartsLinux::PreProfileInit();
+
+  if (immediate_login) {
+    std::string username =
+        parsed_command_line().GetSwitchValueASCII(switches::kLoginUser);
+    UserManager* user_manager = UserManager::Get();
+    // In case of multi-profiles --login-profile will contain user_id_hash.
+    std::string username_hash =
+        parsed_command_line().GetSwitchValueASCII(switches::kLoginProfile);
+    user_manager->UserLoggedIn(username, username_hash, true);
+    VLOG(1) << "Relaunching browser for user: " << username
+            << " with hash: " << username_hash;
+  }
 }
 
 void ChromeBrowserMainPartsChromeos::PostProfileInit() {
@@ -632,11 +632,6 @@
     UserManager::Get()->RestoreActiveSessions();
   }
 
-  // Make sure the NetworkConfigurationUpdater is ready so that it pushes ONC
-  // configuration before login.
-  g_browser_process->browser_policy_connector()->
-      GetNetworkConfigurationUpdater();
-
   // Start loading the machine statistics. Note: if we start loading machine
   // statistics early in PreEarlyInitialization() then the crossystem tool
   // sometimes hangs for unknown reasons, see http://crbug.com/167671.
@@ -697,8 +692,7 @@
   display_configuration_observer_.reset(
       new DisplayConfigurationObserver());
 
-  automatic_reboot_manager_.reset(new system::AutomaticRebootManager(
-      scoped_ptr<base::TickClock>(new base::DefaultTickClock)));
+  g_browser_process->platform_part()->InitializeAutomaticRebootManager();
 
   // This observer cannot be created earlier because it requires the shell to be
   // available.
@@ -721,9 +715,18 @@
   // reasons, see http://crosbug.com/24833.
   XInputHierarchyChangedEventListener::GetInstance();
 
+#if defined(USE_X11)
+  // Start the CrOS input device UMA watcher
+  DeviceUMA::GetInstance();
+#endif
+
   // -- This used to be in ChromeBrowserMainParts::PreMainMessageLoopRun()
   // -- immediately after ChildProcess::WaitForDebugger().
 
+  // Swap metrics watcher must be installed before browser is activated.
+  if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kNoSwapMetrics))
+    swap_metrics_.reset(new SwapMetrics);
+
   // Start the out-of-memory priority manager here so that we give the most
   // amount of time for the other services to start up before we start
   // adjusting the oom priority.
@@ -748,6 +751,8 @@
 
   g_browser_process->platform_part()->oom_priority_manager()->Stop();
 
+  swap_metrics_.reset();
+
   // Stops LoginUtils background fetchers. This is needed because IO thread is
   // going to stop soon after this function. The pending background jobs could
   // cause it to crash during shutdown.
@@ -791,6 +796,10 @@
   // Singletons are finally destroyed in AtExitManager.
   XInputHierarchyChangedEventListener::GetInstance()->Stop();
 
+#if defined(USE_X11)
+  DeviceUMA::GetInstance()->Stop();
+#endif
+
   // SystemKeyEventListener::Shutdown() is always safe to call,
   // even if Initialize() wasn't called.
   SystemKeyEventListener::Shutdown();
@@ -801,8 +810,6 @@
     AudioHandler::Shutdown();
   }
 
-  PowerManagerHandler::Shutdown();
-
   WebSocketProxyController::Shutdown();
 
   // Let classes unregister themselves as observers of the ash::Shell singleton
@@ -830,7 +837,7 @@
 
   // Let the AutomaticRebootManager unregister itself as an observer of several
   // subsystems.
-  automatic_reboot_manager_.reset();
+  g_browser_process->platform_part()->ShutdownAutomaticRebootManager();
 
   // Clean up dependency on CrosSettings and stop pending data fetches.
   KioskAppManager::Shutdown();
@@ -845,62 +852,13 @@
 }
 
 void ChromeBrowserMainPartsChromeos::PostDestroyThreads() {
-  // Destroy DBus services immediately after threads are stopped.
-  dbus_services_.reset();
-
   ChromeBrowserMainPartsLinux::PostDestroyThreads();
-
   // Destroy DeviceSettingsService after g_browser_process.
   DeviceSettingsService::Shutdown();
 }
 
 void ChromeBrowserMainPartsChromeos::SetupPlatformFieldTrials() {
-  SetupZramFieldTrial();
   default_pinned_apps_field_trial::SetupTrial();
 }
 
-void ChromeBrowserMainPartsChromeos::SetupZramFieldTrial() {
-  // The dice for this experiment have been thrown at boot.  The selected group
-  // number is stored in a file.
-  const base::FilePath kZramGroupPath("/home/chronos/.swap_exp_enrolled");
-  std::string zram_file_content;
-  // If the file does not exist, the experiment has not started.
-  if (!file_util::ReadFileToString(kZramGroupPath, &zram_file_content))
-    return;
-  // The file contains a single significant character, possibly followed by
-  // newline.  "x" means the user has opted out.  "0" through "8" are the valid
-  // group names.  (See src/platform/init/swap-exp.conf in chromiumos repo for
-  // group meanings.)
-  if (zram_file_content.empty()) {
-    LOG(WARNING) << "zram field trial: " << kZramGroupPath.value()
-                 << " is empty";
-    return;
-  }
-  char zram_group = zram_file_content[0];
-  if (zram_group == 'x')
-    return;
-  if (zram_group < '0' || zram_group > '8') {
-    LOG(WARNING) << "zram field trial: invalid group \"" << zram_group << "\"";
-    return;
-  }
-  LOG(WARNING) << "zram field trial: group " << zram_group;
-  const base::FieldTrial::Probability kDivisor = 1;  // on/off only
-  scoped_refptr<base::FieldTrial> trial =
-      base::FieldTrialList::FactoryGetFieldTrial(
-          "ZRAM", kDivisor, "default", 2013, 12, 31, NULL);
-  // Assign probability of 1 to the group Chrome OS has picked.  Assign 0 to
-  // all other choices.
-  trial->AppendGroup("2GB_RAM_no_swap", zram_group == '0' ? 1 : 0);
-  trial->AppendGroup("2GB_RAM_2GB_swap", zram_group == '1' ? 1 : 0);
-  trial->AppendGroup("2GB_RAM_3GB_swap", zram_group == '2' ? 1 : 0);
-  trial->AppendGroup("4GB_RAM_no_swap", zram_group == '3' ? 1 : 0);
-  trial->AppendGroup("4GB_RAM_4GB_swap", zram_group == '4' ? 1 : 0);
-  trial->AppendGroup("4GB_RAM_6GB_swap", zram_group == '5' ? 1 : 0);
-  trial->AppendGroup("snow_no_swap", zram_group == '6' ? 1 : 0);
-  trial->AppendGroup("snow_1GB_swap", zram_group == '7' ? 1 : 0);
-  trial->AppendGroup("snow_2GB_swap", zram_group == '8' ? 1 : 0);
-  // This is necessary to start the experiment as a side effect.
-  trial->group();
-}
-
 }  //  namespace chromeos
diff --git a/chrome/browser/chromeos/chrome_browser_main_chromeos.h b/chrome/browser/chromeos/chrome_browser_main_chromeos.h
index 8739e44..fbcba38 100644
--- a/chrome/browser/chromeos/chrome_browser_main_chromeos.h
+++ b/chrome/browser/chromeos/chrome_browser_main_chromeos.h
@@ -32,6 +32,7 @@
 class SessionManagerObserver;
 class StorageMonitorCros;
 class SuspendObserver;
+class SwapMetrics;
 class UserActivityNotifier;
 class VideoActivityNotifier;
 
@@ -44,7 +45,6 @@
 }
 
 namespace system {
-class AutomaticRebootManager;
 class DeviceChangeHandler;
 }
 
@@ -72,8 +72,6 @@
   virtual void SetupPlatformFieldTrials() OVERRIDE;
 
  private:
-  void SetupZramFieldTrial();
-
   scoped_ptr<contacts::ContactManager> contact_manager_;
   scoped_ptr<BrightnessObserver> brightness_observer_;
   scoped_ptr<DisplayConfigurationObserver> display_configuration_observer_;
@@ -88,9 +86,9 @@
   scoped_ptr<UserActivityNotifier> user_activity_notifier_;
   scoped_ptr<VideoActivityNotifier> video_activity_notifier_;
   scoped_ptr<StorageMonitorCros> storage_monitor_;
-  scoped_ptr<system::AutomaticRebootManager> automatic_reboot_manager_;
   scoped_ptr<IdleActionWarningObserver> idle_action_warning_observer_;
   scoped_ptr<system::DeviceChangeHandler> device_change_handler_;
+  scoped_ptr<SwapMetrics> swap_metrics_;
 
   scoped_ptr<internal::DBusServices> dbus_services_;
 
diff --git a/chrome/browser/chromeos/contacts/contact_database.cc b/chrome/browser/chromeos/contacts/contact_database.cc
index 0b1193f..cfff9b2 100644
--- a/chrome/browser/chromeos/contacts/contact_database.cc
+++ b/chrome/browser/chromeos/contacts/contact_database.cc
@@ -175,7 +175,7 @@
 
   VLOG(1) << "Opening " << database_dir.value();
   UMA_HISTOGRAM_MEMORY_KB("Contacts.DatabaseSizeBytes",
-                          file_util::ComputeDirectorySize(database_dir));
+                          base::ComputeDirectorySize(database_dir));
   *success = false;
   HistogramInitResult histogram_result = HISTOGRAM_INIT_RESULT_SUCCESS;
 
@@ -200,7 +200,7 @@
     // Delete the existing database and try again (just once, though).
     if (status.IsCorruption() && delete_and_retry_on_corruption) {
       LOG(WARNING) << "Deleting possibly-corrupt database";
-      file_util::Delete(database_dir, true);
+      base::Delete(database_dir, true);
       delete_and_retry_on_corruption = false;
       histogram_result = HISTOGRAM_INIT_RESULT_DELETED_CORRUPTED;
     } else {
diff --git a/chrome/browser/chromeos/contacts/contact_map.h b/chrome/browser/chromeos/contacts/contact_map.h
index 22de98e..66a8444 100644
--- a/chrome/browser/chromeos/contacts/contact_map.h
+++ b/chrome/browser/chromeos/contacts/contact_map.h
@@ -12,7 +12,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/scoped_vector.h"
 #include "base/stl_util.h"
-#include "base/time.h"
+#include "base/time/time.h"
 
 namespace contacts {
 
diff --git a/chrome/browser/chromeos/contacts/contact_map_unittest.cc b/chrome/browser/chromeos/contacts/contact_map_unittest.cc
index dc7bb96..ebd46e1 100644
--- a/chrome/browser/chromeos/contacts/contact_map_unittest.cc
+++ b/chrome/browser/chromeos/contacts/contact_map_unittest.cc
@@ -6,7 +6,7 @@
 
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/scoped_vector.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/chromeos/contacts/contact.pb.h"
 #include "chrome/browser/chromeos/contacts/contact_test_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/chrome/browser/chromeos/contacts/contact_test_util.cc b/chrome/browser/chromeos/contacts/contact_test_util.cc
index 6ef76dc..071083a 100644
--- a/chrome/browser/chromeos/contacts/contact_test_util.cc
+++ b/chrome/browser/chromeos/contacts/contact_test_util.cc
@@ -11,7 +11,7 @@
 #include "base/logging.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/chromeos/contacts/contact_map.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "third_party/skia/include/core/SkCanvas.h"
diff --git a/chrome/browser/chromeos/contacts/gdata_contacts_service.cc b/chrome/browser/chromeos/contacts/gdata_contacts_service.cc
index 0d614cb..12e4161 100644
--- a/chrome/browser/chromeos/contacts/gdata_contacts_service.cc
+++ b/chrome/browser/chromeos/contacts/gdata_contacts_service.cc
@@ -16,8 +16,8 @@
 #include "base/metrics/histogram.h"
 #include "base/stl_util.h"
 #include "base/strings/string_util.h"
-#include "base/time.h"
-#include "base/timer.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
 #include "base/values.h"
 #include "chrome/browser/chromeos/contacts/contact.pb.h"
 #include "chrome/browser/google_apis/gdata_contacts_requests.h"
@@ -436,14 +436,12 @@
  public:
   DownloadContactsRequest(
       GDataContactsService* service,
-      google_apis::RequestSender* runner,
-      net::URLRequestContextGetter* url_request_context_getter,
+      google_apis::RequestSender* sender,
       SuccessCallback success_callback,
       FailureCallback failure_callback,
       const base::Time& min_update_time)
       : service_(service),
-        sender_(runner),
-        url_request_context_getter_(url_request_context_getter),
+        sender_(sender),
         success_callback_(success_callback),
         failure_callback_(failure_callback),
         min_update_time_(min_update_time),
@@ -481,7 +479,6 @@
       google_apis::GetContactGroupsRequest* operation =
           new google_apis::GetContactGroupsRequest(
               sender_,
-              url_request_context_getter_,
               base::Bind(&DownloadContactsRequest::HandleGroupsFeedData,
                          weak_ptr_factory_.GetWeakPtr()));
       if (!service_->groups_feed_url_for_testing_.is_empty()) {
@@ -589,7 +586,6 @@
     google_apis::GetContactsRequest* operation =
         new google_apis::GetContactsRequest(
             sender_,
-            url_request_context_getter_,
             my_contacts_group_id_,
             min_update_time_,
             base::Bind(&DownloadContactsRequest::HandleContactsFeedData,
@@ -649,7 +645,7 @@
       return false;
     }
     const DictionaryValue* category_dict = NULL;
-    if (!category_list->GetSize() == 1 ||
+    if (category_list->GetSize() != 1 ||
         !category_list->GetDictionary(0, &category_dict)) {
       LOG(WARNING) << "Unable to get dictionary from category list of size "
                    << category_list->GetSize();
@@ -746,7 +742,6 @@
       sender_->StartRequestWithRetry(
           new google_apis::GetContactPhotoRequest(
               sender_,
-              url_request_context_getter_,
               GURL(url),
               base::Bind(&DownloadContactsRequest::HandlePhotoData,
                          weak_ptr_factory_.GetWeakPtr(),
@@ -803,7 +798,6 @@
 
   GDataContactsService* service_;  // not owned
   google_apis::RequestSender* sender_;  // not owned
-  net::URLRequestContextGetter* url_request_context_getter_;  // not owned
 
   SuccessCallback success_callback_;
   FailureCallback failure_callback_;
@@ -857,14 +851,13 @@
 GDataContactsService::GDataContactsService(
     net::URLRequestContextGetter* url_request_context_getter,
     Profile* profile)
-    : url_request_context_getter_(url_request_context_getter),
-      max_photo_downloads_per_second_(kMaxPhotoDownloadsPerSecond),
+    : max_photo_downloads_per_second_(kMaxPhotoDownloadsPerSecond),
       photo_download_timer_interval_(base::TimeDelta::FromSeconds(1)) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   std::vector<std::string> scopes;
   scopes.push_back(kContactsScope);
   sender_.reset(new google_apis::RequestSender(profile,
-                                               url_request_context_getter_,
+                                               url_request_context_getter,
                                                scopes,
                                                "" /* custom_user_agent */));
 }
@@ -891,7 +884,6 @@
   DownloadContactsRequest* request =
       new DownloadContactsRequest(this,
                                   sender_.get(),
-                                  url_request_context_getter_,
                                   success_callback,
                                   failure_callback,
                                   min_update_time);
diff --git a/chrome/browser/chromeos/contacts/gdata_contacts_service.h b/chrome/browser/chromeos/contacts/gdata_contacts_service.h
index 886f48a..47f30ef 100644
--- a/chrome/browser/chromeos/contacts/gdata_contacts_service.h
+++ b/chrome/browser/chromeos/contacts/gdata_contacts_service.h
@@ -13,7 +13,7 @@
 #include "base/compiler_specific.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/scoped_vector.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "googleurl/src/gurl.h"
 
 class Profile;
@@ -109,8 +109,6 @@
   // unsuccessfully).
   void OnRequestComplete(DownloadContactsRequest* request);
 
-  net::URLRequestContextGetter* url_request_context_getter_;  // not owned
-
   scoped_ptr<google_apis::RequestSender> sender_;
 
   // Group ID for the "My Contacts" system contacts group.
diff --git a/chrome/browser/chromeos/contacts/gdata_contacts_service_stub.h b/chrome/browser/chromeos/contacts/gdata_contacts_service_stub.h
index bc23a69..0be0213 100644
--- a/chrome/browser/chromeos/contacts/gdata_contacts_service_stub.h
+++ b/chrome/browser/chromeos/contacts/gdata_contacts_service_stub.h
@@ -9,7 +9,7 @@
 
 #include "base/basictypes.h"
 #include "base/compiler_specific.h"
-#include "base/time.h"
+#include "base/time/time.h"
 
 namespace contacts {
 typedef std::vector<const contacts::Contact*> ContactPointers;
diff --git a/chrome/browser/chromeos/contacts/gdata_contacts_service_unittest.cc b/chrome/browser/chromeos/contacts/gdata_contacts_service_unittest.cc
index 0ffe075..ac43ff8 100644
--- a/chrome/browser/chromeos/contacts/gdata_contacts_service_unittest.cc
+++ b/chrome/browser/chromeos/contacts/gdata_contacts_service_unittest.cc
@@ -8,7 +8,7 @@
 #include "base/files/file_path.h"
 #include "base/message_loop.h"
 #include "base/strings/stringprintf.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/chromeos/contacts/contact.pb.h"
 #include "chrome/browser/chromeos/contacts/contact_test_util.h"
 #include "chrome/browser/google_apis/auth_service.h"
diff --git a/chrome/browser/chromeos/contacts/google_contact_store.h b/chrome/browser/chromeos/contacts/google_contact_store.h
index b880ea4..8773722 100644
--- a/chrome/browser/chromeos/contacts/google_contact_store.h
+++ b/chrome/browser/chromeos/contacts/google_contact_store.h
@@ -17,8 +17,8 @@
 #include "base/memory/scoped_vector.h"
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
-#include "base/time.h"
-#include "base/timer.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
 #include "chrome/browser/chromeos/contacts/contact_map.h"
 #include "net/base/network_change_notifier.h"
 
diff --git a/chrome/browser/chromeos/contacts/google_contact_store_unittest.cc b/chrome/browser/chromeos/contacts/google_contact_store_unittest.cc
index 377ce35..de42453 100644
--- a/chrome/browser/chromeos/contacts/google_contact_store_unittest.cc
+++ b/chrome/browser/chromeos/contacts/google_contact_store_unittest.cc
@@ -7,7 +7,7 @@
 #include "base/bind.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/message_loop.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/chromeos/contacts/contact.pb.h"
 #include "chrome/browser/chromeos/contacts/contact_store_observer.h"
 #include "chrome/browser/chromeos/contacts/contact_test_util.h"
diff --git a/chrome/browser/chromeos/cros/cert_library.cc b/chrome/browser/chromeos/cros/cert_library.cc
index 736d6cb..952f14f 100644
--- a/chrome/browser/chromeos/cros/cert_library.cc
+++ b/chrome/browser/chromeos/cros/cert_library.cc
@@ -19,6 +19,7 @@
 #include "chromeos/dbus/cryptohome_client.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/login/login_state.h"
+#include "chromeos/network/onc/onc_utils.h"
 #include "content/public/browser/browser_thread.h"
 #include "crypto/nss_util.h"
 #include "grit/generated_resources.h"
@@ -61,6 +62,16 @@
   }
 }
 
+std::string CertToPEM(const net::X509Certificate& cert) {
+  std::string pem_encoded_cert;
+  if (!net::X509Certificate::GetPEMEncoded(cert.os_cert_handle(),
+                                           &pem_encoded_cert)) {
+    LOG(ERROR) << "Couldn't PEM-encode certificate";
+    return std::string();
+  }
+  return pem_encoded_cert;
+}
+
 }  // namespace
 
 class CertNameComparator {
@@ -148,9 +159,8 @@
   return GetDisplayString(cert, hardware_backed);
 }
 
-std::string CertLibrary::GetCertNicknameAt(CertType type, int index) const {
-  net::X509Certificate* cert = GetCertificateAt(type, index);
-  return x509_certificate_model::GetNickname(cert->os_cert_handle());
+std::string CertLibrary::GetCertPEMAt(CertType type, int index) const {
+  return CertToPEM(*GetCertificateAt(type, index));
 }
 
 std::string CertLibrary::GetCertPkcs11IdAt(CertType type, int index) const {
@@ -168,17 +178,16 @@
       NetworkHandler::Get()->cert_loader()->tpm_token_name();
 }
 
-int CertLibrary::GetCertIndexByNickname(CertType type,
-                                        const std::string& nickname) const {
+int CertLibrary::GetCertIndexByPEM(CertType type,
+                                   const std::string& pem_encoded) const {
   int num_certs = NumCertificates(type);
   for (int index = 0; index < num_certs; ++index) {
     net::X509Certificate* cert = GetCertificateAt(type, index);
-    net::X509Certificate::OSCertHandle cert_handle = cert->os_cert_handle();
-    std::string nick = x509_certificate_model::GetNickname(cert_handle);
-    if (nick == nickname)
-      return index;
+    if (CertToPEM(*cert) != pem_encoded)
+      continue;
+    return index;
   }
-  return -1;  // Not found.
+  return -1;
 }
 
 int CertLibrary::GetCertIndexByPkcs11Id(CertType type,
@@ -272,4 +281,4 @@
   return certs_;
 }
 
-}  // chromeos
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/cros/cert_library.h b/chrome/browser/chromeos/cros/cert_library.h
index 46890cf..8d595b9 100644
--- a/chrome/browser/chromeos/cros/cert_library.h
+++ b/chrome/browser/chromeos/cros/cert_library.h
@@ -68,12 +68,16 @@
 
   // Retreives the certificate property for |type| at |index|.
   string16 GetCertDisplayStringAt(CertType type, int index) const;
-  std::string GetCertNicknameAt(CertType type, int index) const;
+  std::string GetCertPEMAt(CertType type, int index) const;
   std::string GetCertPkcs11IdAt(CertType type, int index) const;
   bool IsCertHardwareBackedAt(CertType type, int index) const;
 
-  // Returns the index of a Certificate matching |nickname| or -1 if none found.
-  int GetCertIndexByNickname(CertType type, const std::string& nickname) const;
+  // Returns the index of a Certificate matching |pem_encoded| or -1 if none
+  // found. This function may be slow depending on the number of stored
+  // certificates.
+  // TOOD(pneubeck): Either make this more efficient, asynchronous or get rid of
+  // it.
+  int GetCertIndexByPEM(CertType type, const std::string& pem_encoded) const;
   // Same as above but for a PKCS#11 id. TODO(stevenjb): Replace this with a
   // better mechanism for uniquely idientifying certificates, crbug.com/236978.
   int GetCertIndexByPkcs11Id(CertType type, const std::string& pkcs11_id) const;
diff --git a/chrome/browser/chromeos/cros/cros_mock.cc b/chrome/browser/chromeos/cros/cros_mock.cc
index 5386e3f..7e7f71d 100644
--- a/chrome/browser/chromeos/cros/cros_mock.cc
+++ b/chrome/browser/chromeos/cros/cros_mock.cc
@@ -6,7 +6,7 @@
 
 #include "base/memory/ref_counted.h"
 #include "base/message_loop.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/chromeos/cros/mock_network_library.h"
 #include "chrome/browser/chromeos/login/screens/wizard_screen.h"
 #include "chrome/browser/chromeos/login/wizard_controller.h"
diff --git a/chrome/browser/chromeos/cros/mock_network_library.h b/chrome/browser/chromeos/cros/mock_network_library.h
index d2c5192..d9144c5 100644
--- a/chrome/browser/chromeos/cros/mock_network_library.h
+++ b/chrome/browser/chromeos/cros/mock_network_library.h
@@ -167,10 +167,6 @@
   MOCK_METHOD3(GetIPConfigs, void(const std::string&,
                                   HardwareAddressFormat,
                                   const NetworkGetIPConfigsCallback&));
-  MOCK_METHOD3(GetIPConfigsAndBlock,
-               NetworkIPConfigVector(const std::string&,
-                                     std::string*,
-                                     HardwareAddressFormat));
   MOCK_METHOD6(SetIPParameters, void(const std::string&,
                                      const std::string&,
                                      const std::string&,
diff --git a/chrome/browser/chromeos/cros/native_network_parser.cc b/chrome/browser/chromeos/cros/native_network_parser.cc
index 4a7637e..fc729d7 100644
--- a/chrome/browser/chromeos/cros/native_network_parser.cc
+++ b/chrome/browser/chromeos/cros/native_network_parser.cc
@@ -6,12 +6,14 @@
 
 #include <string>
 
+#include "base/logging.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/values.h"
 #include "chrome/browser/chromeos/cros/native_network_constants.h"
 #include "chrome/browser/chromeos/cros/network_library.h"
 #include "chrome/browser/chromeos/login/user_manager.h"
+#include "chromeos/network/onc/onc_utils.h"
 #include "third_party/cros_system_api/dbus/service_constants.h"
 
 namespace chromeos {
@@ -48,8 +50,7 @@
   { flimflam::kEapAnonymousIdentityProperty,
     PROPERTY_INDEX_EAP_ANONYMOUS_IDENTITY },
   { flimflam::kEapCaCertIdProperty, PROPERTY_INDEX_EAP_CA_CERT_ID },
-  { flimflam::kEapCaCertNssProperty, PROPERTY_INDEX_EAP_CA_CERT_NSS },
-  { flimflam::kEapCaCertProperty, PROPERTY_INDEX_EAP_CA_CERT },
+  { shill::kEapCaCertPemProperty, PROPERTY_INDEX_EAP_CA_CERT_PEM },
   { flimflam::kEapCertIdProperty, PROPERTY_INDEX_EAP_CERT_ID },
   { flimflam::kEapClientCertNssProperty, PROPERTY_INDEX_EAP_CLIENT_CERT_NSS },
   { flimflam::kEapClientCertProperty, PROPERTY_INDEX_EAP_CLIENT_CERT },
@@ -82,8 +83,8 @@
   { flimflam::kIsActiveProperty, PROPERTY_INDEX_IS_ACTIVE },
   { flimflam::kL2tpIpsecAuthenticationType,
     PROPERTY_INDEX_IPSEC_AUTHENTICATIONTYPE },
-  { flimflam::kL2tpIpsecCaCertNssProperty,
-    PROPERTY_INDEX_L2TPIPSEC_CA_CERT_NSS },
+  { shill::kL2tpIpsecCaCertPemProperty,
+    PROPERTY_INDEX_L2TPIPSEC_CA_CERT_PEM },
   { flimflam::kL2tpIpsecClientCertIdProperty,
     PROPERTY_INDEX_L2TPIPSEC_CLIENT_CERT_ID },
   { flimflam::kL2tpIpsecClientCertSlotProp,
@@ -153,7 +154,7 @@
     PROPERTY_INDEX_OPEN_VPN_AUTHNOCACHE },
   { flimflam::kOpenVPNAuthUserPassProperty,
     PROPERTY_INDEX_OPEN_VPN_AUTHUSERPASS },
-  { flimflam::kOpenVPNCaCertNSSProperty, PROPERTY_INDEX_OPEN_VPN_CACERT },
+  { shill::kOpenVPNCaCertPemProperty, PROPERTY_INDEX_OPEN_VPN_CA_CERT_PEM },
   { flimflam::kOpenVPNClientCertSlotProperty,
     PROPERTY_INDEX_OPEN_VPN_CLIENT_CERT_SLOT },
   { flimflam::kOpenVPNCipherProperty, PROPERTY_INDEX_OPEN_VPN_CIPHER },
@@ -1237,12 +1238,11 @@
       wifi_network->set_eap_client_cert_pkcs11_id(eap_client_cert_pkcs11_id);
       return true;
     }
-    case PROPERTY_INDEX_EAP_CA_CERT_NSS: {
-      std::string eap_server_ca_cert_nss_nickname;
-      if (!value.GetAsString(&eap_server_ca_cert_nss_nickname))
+    case PROPERTY_INDEX_EAP_CA_CERT_PEM: {
+      std::string ca_cert_pem;
+      if (!value.GetAsString(&ca_cert_pem))
         break;
-      wifi_network->set_eap_server_ca_cert_nss_nickname(
-          eap_server_ca_cert_nss_nickname);
+      wifi_network->set_eap_server_ca_cert_pem(ca_cert_pem);
       return true;
     }
     case PROPERTY_INDEX_EAP_USE_SYSTEM_CAS: {
@@ -1259,13 +1259,6 @@
       wifi_network->set_eap_passphrase(eap_passphrase);
       return true;
     }
-    case PROPERTY_INDEX_EAP_CA_CERT: {
-      std::string eap_cert_nickname;
-      if (!value.GetAsString(&eap_cert_nickname))
-        break;
-      wifi_network->set_eap_server_ca_cert_nss_nickname(eap_cert_nickname);
-      return true;
-    }
     case PROPERTY_INDEX_WIFI_AUTH_MODE:
     case PROPERTY_INDEX_WIFI_PHY_MODE:
     case PROPERTY_INDEX_EAP_CLIENT_CERT:
@@ -1379,12 +1372,12 @@
       network->set_provider_type(ParseProviderType(provider_type_string));
       return true;
     }
-    case PROPERTY_INDEX_L2TPIPSEC_CA_CERT_NSS:
-    case PROPERTY_INDEX_OPEN_VPN_CACERT: {
-      std::string ca_cert_nss;
-      if (!value.GetAsString(&ca_cert_nss))
+    case PROPERTY_INDEX_L2TPIPSEC_CA_CERT_PEM:
+    case PROPERTY_INDEX_OPEN_VPN_CA_CERT_PEM: {
+      std::string ca_cert_pem;
+      if (!value.GetAsString(&ca_cert_pem))
         break;
-      network->set_ca_cert_nss(ca_cert_nss);
+      network->set_ca_cert_pem(ca_cert_pem);
       return true;
     }
     case PROPERTY_INDEX_L2TPIPSEC_PSK: {
diff --git a/chrome/browser/chromeos/cros/network_constants.h b/chrome/browser/chromeos/cros/network_constants.h
index 187d7d9..35f6ce6 100644
--- a/chrome/browser/chromeos/cros/network_constants.h
+++ b/chrome/browser/chromeos/cros/network_constants.h
@@ -32,9 +32,8 @@
   PROPERTY_INDEX_DEVICES,
   PROPERTY_INDEX_EAP,
   PROPERTY_INDEX_EAP_ANONYMOUS_IDENTITY,
-  PROPERTY_INDEX_EAP_CA_CERT,
   PROPERTY_INDEX_EAP_CA_CERT_ID,
-  PROPERTY_INDEX_EAP_CA_CERT_NSS,
+  PROPERTY_INDEX_EAP_CA_CERT_PEM,
   PROPERTY_INDEX_EAP_CERT_ID,
   PROPERTY_INDEX_EAP_CLIENT_CERT,
   PROPERTY_INDEX_EAP_CLIENT_CERT_NSS,
@@ -70,7 +69,7 @@
   PROPERTY_INDEX_ISSUER_SUBJECT_PATTERN_ORGANIZATION,
   PROPERTY_INDEX_ISSUER_SUBJECT_PATTERN_ORGANIZATIONAL_UNIT,
   PROPERTY_INDEX_IS_ACTIVE,
-  PROPERTY_INDEX_L2TPIPSEC_CA_CERT_NSS,
+  PROPERTY_INDEX_L2TPIPSEC_CA_CERT_PEM,
   PROPERTY_INDEX_L2TPIPSEC_CLIENT_CERT_ID,
   PROPERTY_INDEX_L2TPIPSEC_CLIENT_CERT_SLOT,
   PROPERTY_INDEX_L2TPIPSEC_GROUP_NAME,
@@ -95,7 +94,7 @@
   PROPERTY_INDEX_OPEN_VPN_AUTHNOCACHE,
   PROPERTY_INDEX_OPEN_VPN_AUTHRETRY,
   PROPERTY_INDEX_OPEN_VPN_AUTHUSERPASS,
-  PROPERTY_INDEX_OPEN_VPN_CACERT,
+  PROPERTY_INDEX_OPEN_VPN_CA_CERT_PEM,
   PROPERTY_INDEX_OPEN_VPN_CERT,
   PROPERTY_INDEX_OPEN_VPN_CIPHER,
   PROPERTY_INDEX_OPEN_VPN_CLIENT_CERT_ID,
diff --git a/chrome/browser/chromeos/cros/network_library.cc b/chrome/browser/chromeos/cros/network_library.cc
index 5076cdc..8db027b 100644
--- a/chrome/browser/chromeos/cros/network_library.cc
+++ b/chrome/browser/chromeos/cros/network_library.cc
@@ -16,10 +16,12 @@
 #include "chrome/browser/chromeos/cros/network_library_impl_cros.h"
 #include "chrome/browser/chromeos/cros/network_library_impl_stub.h"
 #include "chrome/common/net/x509_certificate_model.h"
+#include "chromeos/network/cert_loader.h"
 #include "chromeos/network/certificate_pattern.h"
 #include "chromeos/network/certificate_pattern_matcher.h"
 #include "chromeos/network/cros_network_functions.h"
 #include "chromeos/network/network_state_handler.h"
+#include "chromeos/network/onc/onc_utils.h"
 #include "content/public/browser/browser_thread.h"
 #include "grit/ash_strings.h"
 #include "grit/generated_resources.h"
@@ -591,7 +593,7 @@
 VirtualNetwork::~VirtualNetwork() {}
 
 void VirtualNetwork::EraseCredentials() {
-  WipeString(&ca_cert_nss_);
+  WipeString(&ca_cert_pem_);
   WipeString(&psk_passphrase_);
   WipeString(&client_cert_id_);
   WipeString(&user_passphrase_);
@@ -619,8 +621,8 @@
   VirtualNetwork* remembered_vpn = static_cast<VirtualNetwork*>(remembered);
   VLOG(1) << "Copy VPN credentials: " << name()
           << " username: " << remembered_vpn->username();
-  if (ca_cert_nss_.empty())
-    ca_cert_nss_ = remembered_vpn->ca_cert_nss();
+  if (ca_cert_pem_.empty())
+    ca_cert_pem_ = remembered_vpn->ca_cert_pem();
   if (psk_passphrase_.empty())
     psk_passphrase_ = remembered_vpn->psk_passphrase();
   if (client_cert_id_.empty())
@@ -711,13 +713,16 @@
   return user_passphrase_required_ && user_passphrase_.empty();
 }
 
-void VirtualNetwork::SetCACertNSS(const std::string& ca_cert_nss) {
+void VirtualNetwork::SetCACertPEM(const std::string& ca_cert_pem) {
+  VLOG(1) << "SetCACertPEM " << ca_cert_pem;
   if (provider_type_ == PROVIDER_TYPE_OPEN_VPN) {
-    SetStringProperty(
-        flimflam::kOpenVPNCaCertNSSProperty, ca_cert_nss, &ca_cert_nss_);
+    ca_cert_pem_ = ca_cert_pem;
+    base::ListValue pem_list;
+    pem_list.AppendString(ca_cert_pem_);
+    SetValueProperty(shill::kOpenVPNCaCertPemProperty, pem_list);
   } else {
     SetStringProperty(
-        flimflam::kL2tpIpsecCaCertNssProperty, ca_cert_nss, &ca_cert_nss_);
+        shill::kL2tpIpsecCaCertPemProperty, ca_cert_pem, &ca_cert_pem_);
   }
 }
 
@@ -1109,6 +1114,7 @@
 void WifiNetwork::EraseCredentials() {
   WipeString(&passphrase_);
   WipeString(&user_passphrase_);
+  WipeString(&eap_server_ca_cert_pem_);
   WipeString(&eap_client_cert_pkcs11_id_);
   WipeString(&eap_identity_);
   WipeString(&eap_anonymous_identity_);
@@ -1182,11 +1188,13 @@
   }
 }
 
-void WifiNetwork::SetEAPServerCaCertNssNickname(
-    const std::string& nss_nickname) {
-  VLOG(1) << "SetEAPServerCaCertNssNickname " << nss_nickname;
-  SetOrClearStringProperty(flimflam::kEapCaCertNssProperty,
-                           nss_nickname, &eap_server_ca_cert_nss_nickname_);
+void WifiNetwork::SetEAPServerCaCertPEM(
+    const std::string& ca_cert_pem) {
+  VLOG(1) << "SetEAPServerCaCertPEM " << ca_cert_pem;
+  eap_server_ca_cert_pem_ = ca_cert_pem;
+  base::ListValue pem_list;
+  pem_list.AppendString(ca_cert_pem);
+  SetValueProperty(shill::kEapCaCertPemProperty, pem_list);
 }
 
 void WifiNetwork::SetEAPClientCertPkcs11Id(const std::string& pkcs11_id) {
diff --git a/chrome/browser/chromeos/cros/network_library.h b/chrome/browser/chromeos/cros/network_library.h
index 8b4e2ba..f5cee29 100644
--- a/chrome/browser/chromeos/cros/network_library.h
+++ b/chrome/browser/chromeos/cros/network_library.h
@@ -9,13 +9,15 @@
 #include <string>
 #include <vector>
 
+#include "base/callback.h"
 #include "base/compiler_specific.h"
 #include "base/gtest_prod_util.h"
+#include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/singleton.h"
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
-#include "base/timer.h"
+#include "base/timer/timer.h"
 #include "base/values.h"
 #include "chrome/browser/chromeos/cros/network_constants.h"
 #include "chromeos/network/network_ip_config.h"
@@ -656,7 +658,7 @@
 
   const std::string& server_hostname() const { return server_hostname_; }
   ProviderType provider_type() const { return provider_type_; }
-  const std::string& ca_cert_nss() const { return ca_cert_nss_; }
+  const std::string& ca_cert_pem() const { return ca_cert_pem_; }
   const std::string& psk_passphrase() const { return psk_passphrase_; }
   bool psk_passphrase_required() const { return psk_passphrase_required_; }
   const std::string& client_cert_id() const { return client_cert_id_; }
@@ -683,7 +685,7 @@
   bool IsUserPassphraseRequired() const;
 
   // Public setters.
-  void SetCACertNSS(const std::string& ca_cert_nss);
+  void SetCACertPEM(const std::string& ca_cert_pem);
   void SetL2TPIPsecPSKCredentials(const std::string& psk_passphrase,
                                   const std::string& username,
                                   const std::string& user_passphrase,
@@ -720,8 +722,8 @@
   void set_provider_type(ProviderType provider_type) {
     provider_type_ = provider_type;
   }
-  void set_ca_cert_nss(const std::string& ca_cert_nss) {
-    ca_cert_nss_ = ca_cert_nss;
+  void set_ca_cert_pem(const std::string& ca_cert_pem) {
+    ca_cert_pem_ = ca_cert_pem;
   }
   void set_psk_passphrase(const std::string& psk_passphrase) {
     psk_passphrase_ = psk_passphrase;
@@ -761,8 +763,7 @@
 
   std::string server_hostname_;
   ProviderType provider_type_;
-  // NSS nickname for server CA certificate.
-  std::string ca_cert_nss_;
+  std::string ca_cert_pem_;
   std::string psk_passphrase_;
   bool psk_passphrase_required_;
   // PKCS#11 ID for client certificate.
@@ -995,8 +996,8 @@
 
   EAPMethod eap_method() const { return eap_method_; }
   EAPPhase2Auth eap_phase_2_auth() const { return eap_phase_2_auth_; }
-  const std::string& eap_server_ca_cert_nss_nickname() const {
-    return eap_server_ca_cert_nss_nickname_; }
+  const std::string& eap_server_ca_cert_pem() const {
+    return eap_server_ca_cert_pem_; }
   const std::string& eap_client_cert_pkcs11_id() const {
     return eap_client_cert_pkcs11_id_; }
   const bool eap_use_system_cas() const { return eap_use_system_cas_; }
@@ -1018,7 +1019,7 @@
   // 802.1x properties
   void SetEAPMethod(EAPMethod method);
   void SetEAPPhase2Auth(EAPPhase2Auth auth);
-  void SetEAPServerCaCertNssNickname(const std::string& nss_nickname);
+  void SetEAPServerCaCertPEM(const std::string& ca_cert_pem);
   void SetEAPClientCertPkcs11Id(const std::string& pkcs11_id);
   void SetEAPUseSystemCAs(bool use_system_cas);
   void SetEAPIdentity(const std::string& identity);
@@ -1079,9 +1080,8 @@
   void set_eap_phase_2_auth(EAPPhase2Auth eap_phase_2_auth) {
     eap_phase_2_auth_ = eap_phase_2_auth;
   }
-  void set_eap_server_ca_cert_nss_nickname(
-      const std::string& eap_server_ca_cert_nss_nickname) {
-    eap_server_ca_cert_nss_nickname_ = eap_server_ca_cert_nss_nickname;
+  void set_eap_server_ca_cert_pem(const std::string& eap_server_ca_cert_pem) {
+    eap_server_ca_cert_pem_ = eap_server_ca_cert_pem;
   }
   void set_eap_client_cert_pkcs11_id(
       const std::string& eap_client_cert_pkcs11_id) {
@@ -1126,7 +1126,7 @@
 
   EAPMethod eap_method_;
   EAPPhase2Auth eap_phase_2_auth_;
-  std::string eap_server_ca_cert_nss_nickname_;
+  std::string eap_server_ca_cert_pem_;
   std::string eap_client_cert_pkcs11_id_;
   bool eap_use_system_cas_;
   std::string eap_identity_;
@@ -1564,7 +1564,7 @@
     ~EAPConfigData();
     EAPMethod method;
     EAPPhase2Auth auth;
-    std::string server_ca_cert_nss_nickname;
+    std::string server_ca_cert_pem;
     bool use_system_cas;
     std::string client_cert_pkcs11_id;
     std::string identity;
@@ -1584,7 +1584,7 @@
     VPNConfigData();
     ~VPNConfigData();
     std::string psk;
-    std::string server_ca_cert_nss_nickname;
+    std::string server_ca_cert_pem;
     std::string client_cert_pkcs11_id;
     std::string username;
     std::string user_passphrase;
@@ -1628,16 +1628,6 @@
                             HardwareAddressFormat format,
                             const NetworkGetIPConfigsCallback& callback) = 0;
 
-  // DEPRECATED: DO NOT USE. Instead, use the asynchronous GetIPConfigs above.
-  // Fetches IP configs and hardware address for a given device_path. The
-  // hardware address is usually a MAC address like "0011AA22BB33".
-  // |hardware_address| will be an empty string, if no hardware address is
-  // found.
-  virtual NetworkIPConfigVector GetIPConfigsAndBlock(
-      const std::string& device_path,
-      std::string* hardware_address,
-      HardwareAddressFormat) = 0;
-
   // Sets the configuration of the IP parameters. This is called when user
   // changes IP settings from dhcp to static or vice versa or when user changes
   // the ip config info. If nothing is changed, this method does nothing.
@@ -1665,7 +1655,7 @@
   // changes.
   virtual void SwitchToPreferredNetwork() = 0;
 
-  // Load networks from an NetworkConfigurations list of ONC.
+  // Load networks from a list of NetworkConfigurations of ONC.
   virtual void LoadOncNetworks(const base::ListValue& network_configs,
                                onc::ONCSource source) = 0;
 
diff --git a/chrome/browser/chromeos/cros/network_library_impl_base.cc b/chrome/browser/chromeos/cros/network_library_impl_base.cc
index ede3904..22ca01b 100644
--- a/chrome/browser/chromeos/cros/network_library_impl_base.cc
+++ b/chrome/browser/chromeos/cros/network_library_impl_base.cc
@@ -304,10 +304,11 @@
   return remembered_virtual_networks_;
 }
 
+namespace {
+
 // Use shill's ordering of the services to determine which type of
 // network to return (i.e. don't assume priority of network types).
 // Note: This does not include any virtual networks.
-namespace {
 const Network* highest_priority(const Network* a, const Network*b) {
   if (!a)
     return b;
@@ -317,7 +318,8 @@
     return b;
   return a;
 }
-}
+
+}  // namespace
 
 const Network* NetworkLibraryImplBase::active_network() const {
   const Network* result = active_nonvirtual_network();
@@ -806,8 +808,7 @@
     connect_data_.service_name = ssid;
     connect_data_.eap_method = eap_config->method;
     connect_data_.eap_auth = eap_config->auth;
-    connect_data_.server_ca_cert_nss_nickname =
-        eap_config->server_ca_cert_nss_nickname;
+    connect_data_.server_ca_cert_pem = eap_config->server_ca_cert_pem;
     connect_data_.eap_use_system_cas = eap_config->use_system_cas;
     connect_data_.client_cert_pkcs11_id =
         eap_config->client_cert_pkcs11_id;
@@ -828,8 +829,7 @@
   connect_data_.service_name = service_name;
   connect_data_.server_hostname = server_hostname;
   connect_data_.psk_key = config.psk;
-  connect_data_.server_ca_cert_nss_nickname =
-      config.server_ca_cert_nss_nickname;
+  connect_data_.server_ca_cert_pem = config.server_ca_cert_pem;
   connect_data_.client_cert_pkcs11_id = config.client_cert_pkcs11_id;
   connect_data_.username = config.username;
   connect_data_.passphrase = config.user_passphrase;
@@ -867,7 +867,7 @@
     // Enterprise 802.1X EAP network.
     wifi->SetEAPMethod(data.eap_method);
     wifi->SetEAPPhase2Auth(data.eap_auth);
-    wifi->SetEAPServerCaCertNssNickname(data.server_ca_cert_nss_nickname);
+    wifi->SetEAPServerCaCertPEM(data.server_ca_cert_pem);
     wifi->SetEAPUseSystemCAs(data.eap_use_system_cas);
     wifi->SetEAPClientCertPkcs11Id(data.client_cert_pkcs11_id);
     wifi->SetEAPIdentity(data.eap_identity);
@@ -913,7 +913,7 @@
   if (!data.server_hostname.empty())
     vpn->set_server_hostname(data.server_hostname);
 
-  vpn->SetCACertNSS(data.server_ca_cert_nss_nickname);
+  vpn->SetCACertPEM(data.server_ca_cert_pem);
   switch (vpn->provider_type()) {
     case PROVIDER_TYPE_L2TP_IPSEC_PSK:
       vpn->SetL2TPIPsecPSKCredentials(
diff --git a/chrome/browser/chromeos/cros/network_library_impl_base.h b/chrome/browser/chromeos/cros/network_library_impl_base.h
index 999c001..75e9fac 100644
--- a/chrome/browser/chromeos/cros/network_library_impl_base.h
+++ b/chrome/browser/chromeos/cros/network_library_impl_base.h
@@ -263,7 +263,7 @@
     std::string otp;
     std::string group_name;
     std::string server_hostname;
-    std::string server_ca_cert_nss_nickname;
+    std::string server_ca_cert_pem;
     std::string client_cert_pkcs11_id;
     EAPMethod eap_method;
     EAPPhase2Auth eap_auth;
diff --git a/chrome/browser/chromeos/cros/network_library_impl_cros.cc b/chrome/browser/chromeos/cros/network_library_impl_cros.cc
index 6683bba..6109aa7 100644
--- a/chrome/browser/chromeos/cros/network_library_impl_cros.cc
+++ b/chrome/browser/chromeos/cros/network_library_impl_cros.cc
@@ -544,34 +544,6 @@
                                format));
 }
 
-NetworkIPConfigVector NetworkLibraryImplCros::GetIPConfigsAndBlock(
-    const std::string& device_path,
-    std::string* hardware_address,
-    HardwareAddressFormat format) {
-  NetworkIPConfigVector ipconfig_vector;
-  CrosListIPConfigsAndBlock(device_path,
-                            &ipconfig_vector,
-                            NULL,
-                            hardware_address);
-
-  for (size_t i = 0; i < hardware_address->size(); ++i)
-    (*hardware_address)[i] = toupper((*hardware_address)[i]);
-  if (format == FORMAT_COLON_SEPARATED_HEX) {
-    if (hardware_address->size() % 2 == 0) {
-      std::string output;
-      for (size_t i = 0; i < hardware_address->size(); ++i) {
-        if ((i != 0) && (i % 2 == 0))
-          output.push_back(':');
-        output.push_back((*hardware_address)[i]);
-      }
-      *hardware_address = output;
-    }
-  } else {
-    DCHECK_EQ(format, FORMAT_RAW_HEX);
-  }
-  return ipconfig_vector;
-}
-
 void NetworkLibraryImplCros::SetIPParameters(const std::string& service_path,
                                              const std::string& address,
                                              const std::string& netmask,
diff --git a/chrome/browser/chromeos/cros/network_library_impl_cros.h b/chrome/browser/chromeos/cros/network_library_impl_cros.h
index fa001af..c81c1c9 100644
--- a/chrome/browser/chromeos/cros/network_library_impl_cros.h
+++ b/chrome/browser/chromeos/cros/network_library_impl_cros.h
@@ -5,7 +5,7 @@
 #ifndef CHROME_BROWSER_CHROMEOS_CROS_NETWORK_LIBRARY_IMPL_CROS_H_
 #define CHROME_BROWSER_CHROMEOS_CROS_NETWORK_LIBRARY_IMPL_CROS_H_
 
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/chromeos/cros/network_library_impl_base.h"
 
 namespace chromeos {
@@ -75,10 +75,6 @@
       const std::string& device_path,
       HardwareAddressFormat format,
       const NetworkGetIPConfigsCallback& callback) OVERRIDE;
-  virtual NetworkIPConfigVector GetIPConfigsAndBlock(
-      const std::string& device_path,
-      std::string* hardware_address,
-      HardwareAddressFormat format) OVERRIDE;
   virtual void SetIPParameters(const std::string& service_path,
                                const std::string& address,
                                const std::string& netmask,
diff --git a/chrome/browser/chromeos/cros/network_library_impl_stub.cc b/chrome/browser/chromeos/cros/network_library_impl_stub.cc
index bccfb1b..3df19fb 100644
--- a/chrome/browser/chromeos/cros/network_library_impl_stub.cc
+++ b/chrome/browser/chromeos/cros/network_library_impl_stub.cc
@@ -735,14 +735,6 @@
   callback.Run(ip_configs_, hardware_address_);
 }
 
-NetworkIPConfigVector NetworkLibraryImplStub::GetIPConfigsAndBlock(
-    const std::string& device_path,
-    std::string* hardware_address,
-    HardwareAddressFormat format) {
-  *hardware_address = hardware_address_;
-  return ip_configs_;
-}
-
 void NetworkLibraryImplStub::SetIPParameters(const std::string& service_path,
                                              const std::string& address,
                                              const std::string& netmask,
diff --git a/chrome/browser/chromeos/cros/network_library_impl_stub.h b/chrome/browser/chromeos/cros/network_library_impl_stub.h
index 2b456c9..3501a8b 100644
--- a/chrome/browser/chromeos/cros/network_library_impl_stub.h
+++ b/chrome/browser/chromeos/cros/network_library_impl_stub.h
@@ -75,10 +75,6 @@
       const std::string& device_path,
       HardwareAddressFormat format,
       const NetworkGetIPConfigsCallback& callback) OVERRIDE;
-  virtual NetworkIPConfigVector GetIPConfigsAndBlock(
-      const std::string& device_path,
-      std::string* hardware_address,
-      HardwareAddressFormat format) OVERRIDE;
   virtual void SetIPParameters(const std::string& service_path,
                                const std::string& address,
                                const std::string& netmask,
diff --git a/chrome/browser/chromeos/cros/network_library_unittest.cc b/chrome/browser/chromeos/cros/network_library_unittest.cc
index d601637..2ba7361 100644
--- a/chrome/browser/chromeos/cros/network_library_unittest.cc
+++ b/chrome/browser/chromeos/cros/network_library_unittest.cc
@@ -154,13 +154,15 @@
                                 std::string shill_json,
                                 onc::ONCSource source,
                                 bool expect_successful_import) {
-    MockUserManager* mock_user_manager = new MockUserManager;
+    MockUserManager* mock_user_manager =
+        new ::testing::StrictMock<MockUserManager>;
     // Takes ownership of |mock_user_manager|.
     ScopedUserManagerEnabler user_manager_enabler(mock_user_manager);
     mock_user_manager->SetActiveUser("madmax@my.domain.com");
     EXPECT_CALL(*mock_user_manager, IsUserLoggedIn())
         .Times(AnyNumber())
         .WillRepeatedly(Return(true));
+    EXPECT_CALL(*mock_user_manager, Shutdown());
 
     scoped_ptr<base::DictionaryValue> onc_blob =
         onc::test_utils::ReadTestDictionary(onc_file);
@@ -289,14 +291,14 @@
 
 TEST_F(NetworkLibraryStubTest, NetworkConnectWifiWithCertPattern) {
   scoped_ptr<base::DictionaryValue> onc_root =
-      onc::test_utils::ReadTestDictionary("toplevel_wifi_eap_clientcert.onc");
+      onc::test_utils::ReadTestDictionary("certificate-client.onc");
   base::ListValue* certificates;
   onc_root->GetListWithoutPathExpansion(onc::toplevel_config::kCertificates,
                                         &certificates);
 
   onc::CertificateImporter importer(true /* allow trust imports */);
   ASSERT_EQ(onc::CertificateImporter::IMPORT_OK,
-            importer.ParseAndStoreCertificates(*certificates, NULL));
+            importer.ParseAndStoreCertificates(*certificates, NULL, NULL));
 
   WifiNetwork* wifi = cros_->FindWifiNetworkByPath("wifi_cert_pattern");
 
@@ -318,14 +320,14 @@
 
 TEST_F(NetworkLibraryStubTest, NetworkConnectVPNWithCertPattern) {
   scoped_ptr<base::DictionaryValue> onc_root =
-      onc::test_utils::ReadTestDictionary("toplevel_openvpn_clientcert.onc");
+      onc::test_utils::ReadTestDictionary("certificate-client.onc");
   base::ListValue* certificates;
   onc_root->GetListWithoutPathExpansion(onc::toplevel_config::kCertificates,
                                         &certificates);
 
   onc::CertificateImporter importer(true /* allow trust imports */);
   ASSERT_EQ(onc::CertificateImporter::IMPORT_OK,
-            importer.ParseAndStoreCertificates(*certificates, NULL));
+            importer.ParseAndStoreCertificates(*certificates, NULL, NULL));
 
   VirtualNetwork* vpn = cros_->FindVirtualNetworkByPath("vpn_cert_pattern");
 
@@ -404,10 +406,10 @@
     LoadOncNetworksTest,
     LoadOncNetworksTest,
     ::testing::Values(
-         ImportParams("managed_toplevel1.onc",
+         ImportParams("managed_toplevel1_with_cert_pems.onc",
                       "chromeos/net/shill_for_managed_toplevel1.json",
                       onc::ONC_SOURCE_USER_POLICY),
-         ImportParams("managed_toplevel2.onc",
+         ImportParams("managed_toplevel2_with_cert_pems.onc",
                       "chromeos/net/shill_for_managed_toplevel2.json",
                       onc::ONC_SOURCE_USER_POLICY),
          ImportParams("managed_toplevel_l2tpipsec.onc",
@@ -429,10 +431,10 @@
                       "chromeos/net/shill_for_toplevel_wifi_leap.json",
                       onc::ONC_SOURCE_USER_POLICY),
          ImportParams(
-            "toplevel_wifi_eap_clientcert.onc",
+            "toplevel_wifi_eap_clientcert_with_cert_pems.onc",
             "chromeos/net/shill_for_toplevel_wifi_eap_clientcert.json",
             onc::ONC_SOURCE_USER_POLICY),
-         ImportParams("toplevel_openvpn_clientcert.onc",
+         ImportParams("toplevel_openvpn_clientcert_with_cert_pems.onc",
                       "chromeos/net/shill_for_toplevel_openvpn_clientcert.json",
                       onc::ONC_SOURCE_USER_POLICY),
          ImportParams("toplevel_wifi_remove.onc",
diff --git a/chrome/browser/chromeos/customization_document.cc b/chrome/browser/chromeos/customization_document.cc
index a5f551c..a625cd4 100644
--- a/chrome/browser/chromeos/customization_document.cc
+++ b/chrome/browser/chromeos/customization_document.cc
@@ -14,7 +14,7 @@
 #include "base/prefs/pref_service.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chromeos/login/wizard_controller.h"
 #include "chrome/browser/chromeos/system/statistics_provider.h"
@@ -47,8 +47,6 @@
 
 const char kAcceptedManifestVersion[] = "1.0";
 
-const char kHardwareClass[] = "hardware_class";
-
 // Path to OEM partner startup customization manifest.
 const char kStartupCustomizationManifestPath[] =
     "/opt/oem/etc/startup_manifest.json";
@@ -175,7 +173,8 @@
     root_->GetString(kRegistrationUrlAttr, &registration_url_);
 
     std::string hwid;
-    if (statistics_provider->GetMachineStatistic(kHardwareClass, &hwid)) {
+    if (statistics_provider->GetMachineStatistic(
+            chromeos::system::kHardwareClass, &hwid)) {
       ListValue* hwid_list = NULL;
       if (root_->GetList(kHwidMapAttr, &hwid_list)) {
         for (size_t i = 0; i < hwid_list->GetSize(); ++i) {
diff --git a/chrome/browser/chromeos/customization_document.h b/chrome/browser/chromeos/customization_document.h
index 81872e9..7f33edb 100644
--- a/chrome/browser/chromeos/customization_document.h
+++ b/chrome/browser/chromeos/customization_document.h
@@ -11,7 +11,7 @@
 #include "base/gtest_prod_util.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/singleton.h"
-#include "base/timer.h"
+#include "base/timer/timer.h"
 #include "base/values.h"
 #include "googleurl/src/gurl.h"
 #include "net/url_request/url_fetcher_delegate.h"
diff --git a/chrome/browser/chromeos/device_uma.cc b/chrome/browser/chromeos/device_uma.cc
new file mode 100644
index 0000000..2f852bb
--- /dev/null
+++ b/chrome/browser/chromeos/device_uma.cc
@@ -0,0 +1,111 @@
+// 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/device_uma.h"
+
+#include <X11/extensions/XInput.h>
+#include <X11/extensions/XInput2.h>
+
+#include "base/logging.h"
+#include "base/memory/singleton.h"
+#include "base/metrics/histogram.h"
+#include "ui/base/events/event_constants.h"
+#include "ui/base/events/event_utils.h"
+#include "ui/base/x/device_data_manager.h"
+
+// Enum type for CrOS gesture lib UMA
+enum UMACrosGestureMetricsType{
+  // To give an estimated number of all interested events.
+  UMA_CROS_GESTURE_METRICS_ALL_EVENTS,
+  UMA_CROS_GESTURE_METRICS_NOISY_GROUND,
+  // NOTE: Add states only immediately above this line. Make sure to
+  // update the enum list in tools/metrics/histograms/histograms.xml
+  // accordingly.
+  UMA_CROS_GESTURE_METRICS_COUNT
+};
+
+namespace chromeos {
+
+DeviceUMA* DeviceUMA::GetInstance() {
+  return Singleton<DeviceUMA>::get();
+}
+
+DeviceUMA::DeviceUMA()
+    :is_observing_(false) {
+  AddMessageLoopObserver();
+}
+
+DeviceUMA::~DeviceUMA() {
+  RemoveMessageLoopObserver();
+}
+
+void DeviceUMA::Stop() {
+  RemoveMessageLoopObserver();
+}
+
+void DeviceUMA::AddMessageLoopObserver() {
+  if (!is_observing_) {
+    base::MessageLoopForUI::current()->AddObserver(this);
+    is_observing_ = true;
+  }
+}
+
+void DeviceUMA::RemoveMessageLoopObserver() {
+  if (is_observing_) {
+    base::MessageLoopForUI::current()->RemoveObserver(this);
+    is_observing_ = false;
+  }
+}
+
+base::EventStatus DeviceUMA::WillProcessEvent(
+    const base::NativeEvent& event) {
+  CheckIncomingEvent(event);
+  return base::EVENT_CONTINUE;
+}
+
+void DeviceUMA::DidProcessEvent(
+    const base::NativeEvent& event) {
+}
+
+void DeviceUMA::CheckTouchpadEvent(const base::NativeEvent& native_event) {
+  XIDeviceEvent* xiev =
+      static_cast<XIDeviceEvent*>(native_event->xcookie.data);
+  // We take only the slave event since there is no need to count twice.
+  if (xiev->deviceid != xiev->sourceid)
+    return;
+  UMA_HISTOGRAM_ENUMERATION("Touchpad.Metrics",
+                            UMA_CROS_GESTURE_METRICS_ALL_EVENTS,
+                            UMA_CROS_GESTURE_METRICS_COUNT);
+
+  // Check for the CrOS touchpad metrics gesture
+  ui::DeviceDataManager *manager = ui::DeviceDataManager::GetInstance();
+  if (manager->IsCMTMetricsEvent(native_event)) {
+    ui::GestureMetricsType type;
+    float data1, data2;
+    manager->GetMetricsData(native_event, &type, &data1, &data2);
+
+    // We currently track only the noisy ground issue. Please see
+    // http://crbug.com/237683.
+    if (type == ui::kGestureMetricsTypeNoisyGround) {
+      UMA_HISTOGRAM_ENUMERATION("Touchpad.Metrics",
+                                UMA_CROS_GESTURE_METRICS_NOISY_GROUND,
+                                UMA_CROS_GESTURE_METRICS_COUNT);
+    }
+  }
+}
+
+void DeviceUMA::CheckIncomingEvent(const base::NativeEvent& event) {
+  switch (event->type) {
+    case GenericEvent: {
+      if (ui::IsTouchpadEvent(event))
+        CheckTouchpadEvent(event);
+      break;
+    }
+    default:
+      break;
+  }
+  return;
+}
+
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/device_uma.h b/chrome/browser/chromeos/device_uma.h
new file mode 100644
index 0000000..77f7543
--- /dev/null
+++ b/chrome/browser/chromeos/device_uma.h
@@ -0,0 +1,53 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_DEVICE_UMA_H_
+#define CHROME_BROWSER_CHROMEOS_DEVICE_UMA_H_
+
+#include "base/basictypes.h"
+#include "base/event_types.h"
+#include "base/message_loop.h"
+
+template <typename T> struct DefaultSingletonTraits;
+
+namespace chromeos {
+
+// A class to record devices' input event details via the UMA system
+class DeviceUMA : public base::MessageLoopForUI::Observer {
+ public:
+  // Getting instance starts the class automatically if it hasn't been
+  // started before.
+  static DeviceUMA* GetInstance();
+
+  void Stop();
+
+ private:
+  friend struct DefaultSingletonTraits<DeviceUMA>;
+
+  DeviceUMA();
+  virtual ~DeviceUMA();
+
+  // Start and stop observing events.
+  void AddMessageLoopObserver();
+  void RemoveMessageLoopObserver();
+
+  // MessageLoopForUI::Observer overrides.
+  virtual base::EventStatus WillProcessEvent(
+      const base::NativeEvent& event) OVERRIDE;
+  virtual void DidProcessEvent(const base::NativeEvent& event) OVERRIDE;
+
+  // Check CrOS touchpad events to see if the metrics gesture is present
+  void CheckTouchpadEvent(const base::NativeEvent& event);
+
+  // Check the incoming events for interesting patterns that we care about.
+  void CheckIncomingEvent(const base::NativeEvent& event);
+
+  bool is_observing_;
+
+  DISALLOW_COPY_AND_ASSIGN(DeviceUMA);
+};
+
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_CHROMEOS_DEVICE_UMA_H_
diff --git a/chrome/browser/chromeos/display/display_preferences.cc b/chrome/browser/chromeos/display/display_preferences.cc
index 707efcb..33c4581 100644
--- a/chrome/browser/chromeos/display/display_preferences.cc
+++ b/chrome/browser/chromeos/display/display_preferences.cc
@@ -84,12 +84,6 @@
   PrefService* local_state = g_browser_process->local_state();
   ash::DisplayController* display_controller = GetDisplayController();
 
-  ash::DisplayLayout default_layout = ash::DisplayLayout::FromInts(
-      local_state->GetInteger(prefs::kSecondaryDisplayLayout),
-      local_state->GetInteger(prefs::kSecondaryDisplayOffset));
-  default_layout.primary_id = local_state->GetInt64(prefs::kPrimaryDisplayID);
-  display_controller->SetDefaultDisplayLayout(default_layout);
-
   const base::DictionaryValue* layouts = local_state->GetDictionary(
       prefs::kSecondaryDisplays);
   for (DictionaryValue::Iterator it(*layouts); !it.IsAtEnd(); it.Advance()) {
@@ -111,13 +105,6 @@
         continue;
       }
       display_controller->RegisterLayoutForDisplayIdPair(id1, id2, layout);
-    } else {
-      int64 id = gfx::Display::kInvalidDisplayID;
-      if (!base::StringToInt64(it.key(), &id) ||
-          id == gfx::Display::kInvalidDisplayID) {
-        continue;
-      }
-      display_controller->RegisterLayoutForDisplayId(id, layout);
     }
   }
 }
@@ -202,7 +189,7 @@
     property_value->SetInteger("rotation", static_cast<int>(info.rotation()));
     property_value->SetInteger("ui-scale",
                                static_cast<int>(info.ui_scale() * 1000));
-    if (info.has_custom_overscan_insets())
+    if (!info.overscan_insets_in_dip().empty())
       InsetsToValue(info.overscan_insets_in_dip(), property_value.get());
     pref_data->Set(base::Int64ToString(id), property_value.release());
   }
@@ -246,20 +233,12 @@
 }  // namespace
 
 void RegisterDisplayLocalStatePrefs(PrefRegistrySimple* registry) {
-  // The default secondary display layout.
-  registry->RegisterIntegerPref(prefs::kSecondaryDisplayLayout,
-                                static_cast<int>(ash::DisplayLayout::RIGHT));
-  // The default offset of the secondary display position from the primary
-  // display.
-  registry->RegisterIntegerPref(prefs::kSecondaryDisplayOffset, 0);
   // Per-display preference.
   registry->RegisterDictionaryPref(prefs::kSecondaryDisplays);
   registry->RegisterDictionaryPref(prefs::kDisplayProperties);
   DisplayPowerStateToStringMap::const_iterator iter =
       GetDisplayPowerStateToStringMap()->find(chromeos::DISPLAY_POWER_ALL_ON);
   registry->RegisterStringPref(prefs::kDisplayPowerState, iter->second);
-  registry->RegisterInt64Pref(prefs::kPrimaryDisplayID,
-                              gfx::Display::kInvalidDisplayID);
 }
 
 void StoreDisplayPrefs() {
@@ -270,22 +249,9 @@
   StoreCurrentDisplayPowerState();
 }
 
-void SetCurrentAndDefaultDisplayLayout(const ash::DisplayLayout& layout) {
+void SetCurrentDisplayLayout(const ash::DisplayLayout& layout) {
   ash::DisplayController* display_controller = GetDisplayController();
   display_controller->SetLayoutForCurrentDisplays(layout);
-
-  if (IsValidUser()) {
-    PrefService* local_state = g_browser_process->local_state();
-    ash::DisplayIdPair pair = display_controller->GetCurrentDisplayIdPair();
-    // Use registered layout as the layout might have been inverted when
-    // the displays are swapped.
-    ash::DisplayLayout display_layout =
-        display_controller->GetRegisteredDisplayLayout(pair);
-    local_state->SetInteger(prefs::kSecondaryDisplayLayout,
-                            static_cast<int>(display_layout.position));
-    local_state->SetInteger(prefs::kSecondaryDisplayOffset,
-                            display_layout.offset);
-  }
 }
 
 void LoadDisplayPreferences(bool first_run_after_boot) {
diff --git a/chrome/browser/chromeos/display/display_preferences.h b/chrome/browser/chromeos/display/display_preferences.h
index 20058bd..c96e824 100644
--- a/chrome/browser/chromeos/display/display_preferences.h
+++ b/chrome/browser/chromeos/display/display_preferences.h
@@ -29,8 +29,8 @@
 // dispay layout).
 void StoreDisplayPrefs();
 
-// Sets the display layout for the current displays and default.
-void SetCurrentAndDefaultDisplayLayout(const ash::DisplayLayout& layout);
+// Sets the display layout for the current displays.
+void SetCurrentDisplayLayout(const ash::DisplayLayout& layout);
 
 // Load display preferences from Local Store. |first_run_after_boot| is used
 // determine if a certain preference should be applied at boot time or
diff --git a/chrome/browser/chromeos/display/display_preferences_unittest.cc b/chrome/browser/chromeos/display/display_preferences_unittest.cc
index 17136c9..a87a628 100644
--- a/chrome/browser/chromeos/display/display_preferences_unittest.cc
+++ b/chrome/browser/chromeos/display/display_preferences_unittest.cc
@@ -113,15 +113,6 @@
         base::Int64ToString(id), layout, offset, primary_id);
   }
 
-  void StoreDefaultLayoutPref(ash::DisplayLayout::Position layout,
-                              int offset,
-                              int64 primary_id) {
-    local_state_.SetInteger(prefs::kSecondaryDisplayLayout,
-                            static_cast<int>(layout));
-    local_state_.SetInteger(prefs::kSecondaryDisplayOffset, offset);
-    local_state_.SetInt64(prefs::kPrimaryDisplayID, primary_id);
-  }
-
   void StoreDisplayOverscan(int64 id, const gfx::Insets& insets) {
     DictionaryPrefUpdate update(&local_state_, prefs::kDisplayProperties);
     const std::string name = base::Int64ToString(id);
@@ -154,58 +145,6 @@
   DISALLOW_COPY_AND_ASSIGN(DisplayPreferencesTest);
 };
 
-TEST_F(DisplayPreferencesTest, DefaultLayout) {
-  ash::DisplayController* display_controller =
-      ash::Shell::GetInstance()->display_controller();
-
-  int64 id1 = gfx::Screen::GetNativeScreen()->GetPrimaryDisplay().id();
-  int64 id2 = id1 + 1;
-  StoreDefaultLayoutPref(ash::DisplayLayout::LEFT, 50, id2);
-  LoadDisplayPreferences(true);
-  EXPECT_EQ("left, 50",
-            display_controller->default_display_layout().ToString());
-
-  UpdateDisplay("100x100,200x200");
-  // Displays are swapped, so does the layout.
-  EXPECT_EQ("right, -50",
-            display_controller->GetCurrentDisplayLayout().ToString());
-  EXPECT_EQ(id2,
-            display_controller->GetCurrentDisplayLayout().primary_id);
-}
-
-TEST_F(DisplayPreferencesTest, OldInitialization) {
-  ash::DisplayController* display_controller =
-      ash::Shell::GetInstance()->display_controller();
-
-  int64 id1 = gfx::Screen::GetNativeScreen()->GetPrimaryDisplay().id();
-  int64 id2 = id1 + 1;
-  int64 dummy_id = id2 + 1;
-
-  StoreDisplayLayoutPrefForSecondary(id2, ash::DisplayLayout::BOTTOM, 20, id2);
-  StoreDisplayLayoutPrefForSecondary(
-      dummy_id, ash::DisplayLayout::TOP, -10, id1);
-  StoreDisplayOverscan(id1, gfx::Insets(10, 10, 10, 10));
-  StoreDisplayOverscan(id2, gfx::Insets(20, 20, 20, 20));
-
-  LoadDisplayPreferences(true);
-
-  UpdateDisplay("100x100,200x200");
-  EXPECT_EQ(id1, ash::ScreenAsh::GetSecondaryDisplay().id());
-
-  // Check if the layout settings are notified to the system properly.
-  gfx::Screen* screen = gfx::Screen::GetNativeScreen();
-  EXPECT_EQ(id2, screen->GetPrimaryDisplay().id());
-  // Display was swapped, so the layout was inverted.
-  EXPECT_EQ("top, -20",
-            display_controller->GetCurrentDisplayLayout().ToString());
-
-  EXPECT_EQ("bottom, 20", GetRegisteredDisplayLayoutStr(id1, id2));
-  EXPECT_EQ("top, -10", GetRegisteredDisplayLayoutStr(id1, dummy_id));
-  EXPECT_EQ("160x160", screen->GetPrimaryDisplay().bounds().size().ToString());
-  EXPECT_EQ("80x80",
-            ash::ScreenAsh::GetSecondaryDisplay().bounds().size().ToString());
-}
-
 TEST_F(DisplayPreferencesTest, PairedLayoutOverrides) {
   UpdateDisplay("100x100,200x200");
   int64 id1 = gfx::Screen::GetNativeScreen()->GetPrimaryDisplay().id();
@@ -215,7 +154,6 @@
 
   StoreDisplayLayoutPrefForPair(id1, id2, ash::DisplayLayout::TOP, 20);
   StoreDisplayLayoutPrefForPair(id1, dummy_id, ash::DisplayLayout::LEFT, 30);
-  StoreDefaultLayoutPref(ash::DisplayLayout::LEFT, 50, id2);
   StoreDisplayPowerStateForTest(
       chromeos::DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON);
 
@@ -253,7 +191,7 @@
 
   LoggedInAsUser();
   ash::DisplayLayout layout(ash::DisplayLayout::TOP, 10);
-  SetCurrentAndDefaultDisplayLayout(layout);
+  SetCurrentDisplayLayout(layout);
   StoreDisplayLayoutPrefForTest(
       id1, dummy_id, ash::DisplayLayout(ash::DisplayLayout::LEFT, 20));
   // Can't switch to a display that does not exist.
@@ -281,12 +219,6 @@
   EXPECT_TRUE(layout_value->GetBoolean(kMirroredKey, &mirrored));
   EXPECT_FALSE(mirrored);
 
-  // The default value is set for the last call of
-  // SetCurrentAndDefaultDisplayLayout
-  EXPECT_EQ(ash::DisplayLayout::TOP,
-            local_state()->GetInteger(prefs::kSecondaryDisplayLayout));
-  EXPECT_EQ(10, local_state()->GetInteger(prefs::kSecondaryDisplayOffset));
-
   const base::DictionaryValue* properties =
       local_state()->GetDictionary(prefs::kDisplayProperties);
   const base::DictionaryValue* property = NULL;
@@ -336,17 +268,8 @@
   EXPECT_TRUE(layout_value->GetString(kPrimaryIdKey, &primary_id_str));
   EXPECT_EQ(base::Int64ToString(id2), primary_id_str);
 
-  // Default value should changte.
-  EXPECT_EQ(ash::DisplayLayout::TOP,
-            local_state()->GetInteger(prefs::kSecondaryDisplayLayout));
-  EXPECT_EQ(10, local_state()->GetInteger(prefs::kSecondaryDisplayOffset));
-
-  SetCurrentAndDefaultDisplayLayout(
+  SetCurrentDisplayLayout(
       ash::DisplayLayout(ash::DisplayLayout::BOTTOM, 20));
-  // Displays are swapped, so does the default layout.
-  EXPECT_EQ(ash::DisplayLayout::TOP,
-            local_state()->GetInteger(prefs::kSecondaryDisplayLayout));
-  EXPECT_EQ(-20, local_state()->GetInteger(prefs::kSecondaryDisplayOffset));
 
   UpdateDisplay("200x200*2,1+0-200x200");
   // Mirrored.
@@ -391,7 +314,7 @@
 
   LoggedInAsUser();
   ash::DisplayLayout layout(ash::DisplayLayout::TOP, 10);
-  SetCurrentAndDefaultDisplayLayout(layout);
+  SetCurrentDisplayLayout(layout);
   layout = layout.Invert();
 
   const base::DictionaryValue* displays =
@@ -427,7 +350,7 @@
   gfx::Display::SetInternalDisplayId(id1);
   int64 id2 = ash::ScreenAsh::GetSecondaryDisplay().id();
   ash::DisplayLayout layout(ash::DisplayLayout::TOP, 10);
-  SetCurrentAndDefaultDisplayLayout(layout);
+  SetCurrentDisplayLayout(layout);
   display_manager->SetDisplayUIScale(id1, 1.25f);
   display_controller->SetPrimaryDisplayId(id2);
   int64 new_primary =
@@ -441,10 +364,6 @@
   EXPECT_FALSE(local_state()->FindPreference(
       prefs::kSecondaryDisplays)->HasUserSetting());
   EXPECT_FALSE(local_state()->FindPreference(
-      prefs::kSecondaryDisplayLayout)->HasUserSetting());
-  EXPECT_FALSE(local_state()->FindPreference(
-      prefs::kSecondaryDisplayOffset)->HasUserSetting());
-  EXPECT_FALSE(local_state()->FindPreference(
       prefs::kDisplayProperties)->HasUserSetting());
 
   // Settings are still notified to the system.
diff --git a/chrome/browser/chromeos/display/overscan_calibrator.cc b/chrome/browser/chromeos/display/overscan_calibrator.cc
index 6eedc1a..1e8f37a 100644
--- a/chrome/browser/chromeos/display/overscan_calibrator.cc
+++ b/chrome/browser/chromeos/display/overscan_calibrator.cc
@@ -75,11 +75,6 @@
 
   ash::internal::DisplayInfo info = ash::Shell::GetInstance()->
       display_manager()->GetDisplayInfo(display_.id());
-  if (info.has_overscan()) {
-    info.clear_has_custom_overscan_insets();
-    info.UpdateDisplaySize();
-    native_insets_ = info.overscan_insets_in_dip();
-  }
 
   aura::RootWindow* root = ash::Shell::GetInstance()->display_controller()->
       GetRootWindowForDisplayId(display_.id());
@@ -103,22 +98,13 @@
 }
 
 void OverscanCalibrator::Commit() {
-  if (insets_ == native_insets_) {
-    ash::Shell::GetInstance()->display_controller()->ClearCustomOverscanInsets(
-        display_.id());
-  } else {
-    ash::Shell::GetInstance()->display_controller()->SetOverscanInsets(
-        display_.id(), insets_);
-  }
+  ash::Shell::GetInstance()->display_controller()->SetOverscanInsets(
+      display_.id(), insets_);
   committed_ = true;
 }
 
 void OverscanCalibrator::Reset() {
-  if (!native_insets_.empty())
-    insets_ = native_insets_;
-  else
-    insets_ = initial_insets_;
-
+  insets_ = initial_insets_;
   calibration_layer_->SchedulePaint(calibration_layer_->bounds());
 }
 
diff --git a/chrome/browser/chromeos/display/overscan_calibrator.h b/chrome/browser/chromeos/display/overscan_calibrator.h
index 66f0b0e..691d13d 100644
--- a/chrome/browser/chromeos/display/overscan_calibrator.h
+++ b/chrome/browser/chromeos/display/overscan_calibrator.h
@@ -54,9 +54,6 @@
   // The insets initially given. Stored so we can undo the insets later.
   gfx::Insets initial_insets_;
 
-  // The insets claimed by the display.
-  gfx::Insets native_insets_;
-
   // Whether the current insets are committed to the system or not.
   bool committed_;
 
diff --git a/chrome/browser/chromeos/drive/change_list_loader.cc b/chrome/browser/chromeos/drive/change_list_loader.cc
index 23eb52e..99548da 100644
--- a/chrome/browser/chromeos/drive/change_list_loader.cc
+++ b/chrome/browser/chromeos/drive/change_list_loader.cc
@@ -16,8 +16,8 @@
 #include "chrome/browser/chromeos/drive/job_scheduler.h"
 #include "chrome/browser/chromeos/drive/logging.h"
 #include "chrome/browser/chromeos/drive/resource_metadata.h"
+#include "chrome/browser/drive/drive_api_util.h"
 #include "chrome/browser/google_apis/drive_api_parser.h"
-#include "chrome/browser/google_apis/drive_api_util.h"
 #include "content/public/browser/browser_thread.h"
 #include "googleurl/src/gurl.h"
 
diff --git a/chrome/browser/chromeos/drive/change_list_loader.h b/chrome/browser/chromeos/drive/change_list_loader.h
index 6845a04..a476dff 100644
--- a/chrome/browser/chromeos/drive/change_list_loader.h
+++ b/chrome/browser/chromeos/drive/change_list_loader.h
@@ -14,7 +14,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/scoped_vector.h"
 #include "base/observer_list.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/chromeos/drive/file_errors.h"
 #include "chrome/browser/google_apis/gdata_errorcode.h"
 
diff --git a/chrome/browser/chromeos/drive/change_list_loader_unittest.cc b/chrome/browser/chromeos/drive/change_list_loader_unittest.cc
index d7c635b..303845d 100644
--- a/chrome/browser/chromeos/drive/change_list_loader_unittest.cc
+++ b/chrome/browser/chromeos/drive/change_list_loader_unittest.cc
@@ -7,6 +7,7 @@
 #include "base/files/scoped_temp_dir.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/run_loop.h"
+#include "chrome/browser/chromeos/drive/change_list_loader_observer.h"
 #include "chrome/browser/chromeos/drive/file_cache.h"
 #include "chrome/browser/chromeos/drive/job_scheduler.h"
 #include "chrome/browser/chromeos/drive/resource_metadata.h"
@@ -20,24 +21,73 @@
 namespace drive {
 namespace internal {
 
+class TestChangeListLoaderObserver : public ChangeListLoaderObserver {
+ public:
+  explicit TestChangeListLoaderObserver(ChangeListLoader* loader)
+      : loader_(loader),
+        load_from_server_complete_count_(0),
+        initial_load_complete_count_(0) {
+    loader_->AddObserver(this);
+  }
+
+  virtual ~TestChangeListLoaderObserver() {
+    loader_->RemoveObserver(this);
+  }
+
+  const std::set<base::FilePath>& changed_directories() const {
+    return changed_directories_;
+  }
+  int load_from_server_complete_count() const {
+    return load_from_server_complete_count_;
+  }
+  int initial_load_complete_count() const {
+    return initial_load_complete_count_;
+  }
+
+  // ChageListObserver overrides:
+  virtual void OnDirectoryChanged(
+      const base::FilePath& directory_path) OVERRIDE {
+    changed_directories_.insert(directory_path);
+  }
+  virtual void OnLoadFromServerComplete() OVERRIDE {
+    ++load_from_server_complete_count_;
+  }
+  virtual void OnInitialLoadComplete() OVERRIDE {
+    ++initial_load_complete_count_;
+  }
+
+ private:
+  ChangeListLoader* loader_;
+  std::set<base::FilePath> changed_directories_;
+  int load_from_server_complete_count_;
+  int initial_load_complete_count_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestChangeListLoaderObserver);
+};
+
 class ChangeListLoaderTest : public testing::Test {
  protected:
   virtual void SetUp() OVERRIDE {
     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
     profile_.reset(new TestingProfile);
 
-    drive_service_.reset(new google_apis::FakeDriveService);
+    drive_service_.reset(new FakeDriveService);
     ASSERT_TRUE(drive_service_->LoadResourceListForWapi(
-        "chromeos/gdata/root_feed.json"));
+        "gdata/root_feed.json"));
     ASSERT_TRUE(drive_service_->LoadAccountMetadataForWapi(
-        "chromeos/gdata/account_metadata.json"));
+        "gdata/account_metadata.json"));
 
-    scheduler_.reset(new JobScheduler(profile_.get(), drive_service_.get()));
-    metadata_.reset(new ResourceMetadata(temp_dir_.path(),
+    scheduler_.reset(new JobScheduler(profile_.get(), drive_service_.get(),
+                                      base::MessageLoopProxy::current()));
+    metadata_storage_.reset(new ResourceMetadataStorage(
+        temp_dir_.path(), base::MessageLoopProxy::current()));
+    ASSERT_TRUE(metadata_storage_->Initialize());
+
+    metadata_.reset(new ResourceMetadata(metadata_storage_.get(),
                                          base::MessageLoopProxy::current()));
     ASSERT_EQ(FILE_ERROR_OK, metadata_->Initialize());
 
-    cache_.reset(new FileCache(temp_dir_.path(),
+    cache_.reset(new FileCache(metadata_storage_.get(),
                                temp_dir_.path(),
                                base::MessageLoopProxy::current(),
                                NULL /* free_disk_space_getter */));
@@ -50,8 +100,10 @@
   content::TestBrowserThreadBundle thread_bundle_;
   base::ScopedTempDir temp_dir_;
   scoped_ptr<TestingProfile> profile_;
-  scoped_ptr<google_apis::FakeDriveService> drive_service_;
+  scoped_ptr<FakeDriveService> drive_service_;
   scoped_ptr<JobScheduler> scheduler_;
+  scoped_ptr<ResourceMetadataStorage,
+             test_util::DestroyHelperForTests> metadata_storage_;
   scoped_ptr<ResourceMetadata, test_util::DestroyHelperForTests> metadata_;
   scoped_ptr<FileCache, test_util::DestroyHelperForTests> cache_;
   scoped_ptr<ChangeListLoader> change_list_loader_;
@@ -61,6 +113,8 @@
   EXPECT_FALSE(change_list_loader_->IsRefreshing());
 
   // Start initial load.
+  TestChangeListLoaderObserver observer(change_list_loader_.get());
+
   FileError error = FILE_ERROR_FAILED;
   change_list_loader_->LoadIfNeeded(
       DirectoryFetchInfo(),
@@ -72,6 +126,9 @@
   EXPECT_FALSE(change_list_loader_->IsRefreshing());
   EXPECT_LT(0, metadata_->GetLargestChangestamp());
   EXPECT_EQ(1, drive_service_->resource_list_load_count());
+  EXPECT_EQ(1, observer.initial_load_complete_count());
+  EXPECT_EQ(1, observer.load_from_server_complete_count());
+  EXPECT_TRUE(observer.changed_directories().empty());
 
   // Reload. This should result in no-op.
   int64 previous_changestamp = metadata_->GetLargestChangestamp();
diff --git a/chrome/browser/chromeos/drive/change_list_processor_unittest.cc b/chrome/browser/chromeos/drive/change_list_processor_unittest.cc
index 15affb8..1495563 100644
--- a/chrome/browser/chromeos/drive/change_list_processor_unittest.cc
+++ b/chrome/browser/chromeos/drive/change_list_processor_unittest.cc
@@ -23,7 +23,7 @@
 namespace {
 
 const int64 kBaseResourceListChangestamp = 123;
-const char kBaseResourceListFile[] = "chromeos/gdata/root_feed.json";
+const char kBaseResourceListFile[] = "gdata/root_feed.json";
 
 enum FileOrDirectory {
   FILE,
@@ -41,13 +41,14 @@
  protected:
   virtual void SetUp() OVERRIDE {
     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
-    metadata_.reset(new internal::ResourceMetadata(
-        temp_dir_.path(), base::MessageLoopProxy::current()));
-    ASSERT_EQ(FILE_ERROR_OK, metadata_->Initialize());
-  }
 
-  virtual void TearDown() OVERRIDE {
-    metadata_.reset();
+    metadata_storage_.reset(new ResourceMetadataStorage(
+        temp_dir_.path(), base::MessageLoopProxy::current()));
+    ASSERT_TRUE(metadata_storage_->Initialize());
+
+    metadata_.reset(new internal::ResourceMetadata(
+        metadata_storage_.get(), base::MessageLoopProxy::current()));
+    ASSERT_EQ(FILE_ERROR_OK, metadata_->Initialize());
   }
 
   // Parses a json file at |test_data_path| relative to Chrome test directory
@@ -98,8 +99,9 @@
 
   content::TestBrowserThreadBundle thread_bundle_;
   base::ScopedTempDir temp_dir_;
-  scoped_ptr<internal::ResourceMetadata, test_util::DestroyHelperForTests>
-      metadata_;
+  scoped_ptr<ResourceMetadataStorage,
+             test_util::DestroyHelperForTests> metadata_storage_;
+  scoped_ptr<ResourceMetadata, test_util::DestroyHelperForTests> metadata_;
 };
 
 }  // namespace
@@ -159,7 +161,7 @@
 
 TEST_F(ChangeListProcessorTest, DeltaFileAddedInNewDirectory) {
   const char kTestJson[] =
-      "chromeos/gdata/delta_file_added_in_new_directory.json";
+      "gdata/delta_file_added_in_new_directory.json";
 
   ChangeListProcessor::ResourceEntryMap entry_map;
   ChangeListProcessor::ConvertToMap(
@@ -200,7 +202,7 @@
 
 TEST_F(ChangeListProcessorTest, DeltaDirMovedFromRootToDirectory) {
   const char kTestJson[] =
-      "chromeos/gdata/delta_dir_moved_from_root_to_directory.json";
+      "gdata/delta_dir_moved_from_root_to_directory.json";
 
   ChangeListProcessor::ResourceEntryMap entry_map;
   ChangeListProcessor::ConvertToMap(
@@ -241,7 +243,7 @@
 
 TEST_F(ChangeListProcessorTest, DeltaFileMovedFromDirectoryToRoot) {
   const char kTestJson[] =
-      "chromeos/gdata/delta_file_moved_from_directory_to_root.json";
+      "gdata/delta_file_moved_from_directory_to_root.json";
 
   ChangeListProcessor::ResourceEntryMap entry_map;
   ChangeListProcessor::ConvertToMap(
@@ -277,7 +279,7 @@
 
 TEST_F(ChangeListProcessorTest, DeltaFileRenamedInDirectory) {
   const char kTestJson[] =
-      "chromeos/gdata/delta_file_renamed_in_directory.json";
+      "gdata/delta_file_renamed_in_directory.json";
 
   ChangeListProcessor::ResourceEntryMap entry_map;
   ChangeListProcessor::ConvertToMap(
@@ -315,9 +317,9 @@
 
 TEST_F(ChangeListProcessorTest, DeltaAddAndDeleteFileInRoot) {
   const char kTestJsonAdd[] =
-      "chromeos/gdata/delta_file_added_in_root.json";
+      "gdata/delta_file_added_in_root.json";
   const char kTestJsonDelete[] =
-      "chromeos/gdata/delta_file_deleted_in_root.json";
+      "gdata/delta_file_deleted_in_root.json";
 
   const std::string kParentId("fake_root");
   const std::string kFileId("document:added_in_root_id");
@@ -365,9 +367,9 @@
 
 TEST_F(ChangeListProcessorTest, DeltaAddAndDeleteFileFromExistingDirectory) {
   const char kTestJsonAdd[] =
-      "chromeos/gdata/delta_file_added_in_directory.json";
+      "gdata/delta_file_added_in_directory.json";
   const char kTestJsonDelete[] =
-      "chromeos/gdata/delta_file_deleted_in_directory.json";
+      "gdata/delta_file_deleted_in_directory.json";
 
   const std::string kParentId("folder:1_folder_resource_id");
   const std::string kFileId("document:added_in_root_id");
@@ -423,7 +425,7 @@
   // 2) but the new directory is marked "deleted" (i.e. moved to Trash)
   // Hence, the PDF file should be just ignored.
   const char kTestJson[] =
-      "chromeos/gdata/delta_file_added_in_new_but_deleted_directory.json";
+      "gdata/delta_file_added_in_new_but_deleted_directory.json";
 
   ChangeListProcessor::ResourceEntryMap entry_map;
   ChangeListProcessor::ConvertToMap(
diff --git a/chrome/browser/chromeos/drive/download_handler.cc b/chrome/browser/chromeos/drive/download_handler.cc
index 8e0bb33..850caf9 100644
--- a/chrome/browser/chromeos/drive/download_handler.cc
+++ b/chrome/browser/chromeos/drive/download_handler.cc
@@ -29,7 +29,7 @@
 class DriveUserData : public base::SupportsUserData::Data {
  public:
   explicit DriveUserData(const base::FilePath& path) : file_path_(path),
-                                                 is_complete_(false) {}
+                                                       is_complete_(false) {}
   virtual ~DriveUserData() {}
 
   const base::FilePath& file_path() const { return file_path_; }
@@ -72,7 +72,7 @@
                         const base::FilePath& dest_path) {
   if (error != FILE_ERROR_OK)
     return;
-  file_util::Move(downloaded_file, dest_path);
+  base::Move(downloaded_file, dest_path);
 }
 
 // Used to implement CheckForFileExistence().
diff --git a/chrome/browser/chromeos/drive/download_handler_unittest.cc b/chrome/browser/chromeos/drive/download_handler_unittest.cc
index 94a7e05..b828c1d 100644
--- a/chrome/browser/chromeos/drive/download_handler_unittest.cc
+++ b/chrome/browser/chromeos/drive/download_handler_unittest.cc
@@ -12,7 +12,6 @@
 #include "content/public/test/mock_download_item.h"
 #include "content/public/test/mock_download_manager.h"
 #include "content/public/test/test_browser_thread_bundle.h"
-#include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace drive {
diff --git a/chrome/browser/chromeos/drive/drive.proto b/chrome/browser/chromeos/drive/drive.proto
index 56a0363..07ac169 100644
--- a/chrome/browser/chromeos/drive/drive.proto
+++ b/chrome/browser/chromeos/drive/drive.proto
@@ -45,6 +45,9 @@
   // True if the file is a hosted document (i.e. document hosted on
   // drive.google.com such as documents, spreadsheets, and presentations).
   optional bool is_hosted_document = 6;
+
+  // This URL points to a page containing Share UI for this document.
+  optional string share_url = 7;
 }
 
 // Directory specific info, which is a part of ResourceEntry.
diff --git a/chrome/browser/chromeos/drive/drive_app_registry.cc b/chrome/browser/chromeos/drive/drive_app_registry.cc
index 5cb9dc0..4171fd6 100644
--- a/chrome/browser/chromeos/drive/drive_app_registry.cc
+++ b/chrome/browser/chromeos/drive/drive_app_registry.cc
@@ -42,7 +42,6 @@
   return components[components.size() - 1];
 }
 
-// TODO(kochi): This is duplicate from gdata_wapi_parser.cc.
 bool SortBySize(const google_apis::InstalledApp::IconList::value_type& a,
                 const google_apis::InstalledApp::IconList::value_type& b) {
   return a.first < b.first;
diff --git a/chrome/browser/chromeos/drive/drive_app_registry_unittest.cc b/chrome/browser/chromeos/drive/drive_app_registry_unittest.cc
index f8bea09..941cc77 100644
--- a/chrome/browser/chromeos/drive/drive_app_registry_unittest.cc
+++ b/chrome/browser/chromeos/drive/drive_app_registry_unittest.cc
@@ -20,12 +20,11 @@
   virtual void SetUp() OVERRIDE {
     profile_.reset(new TestingProfile);
 
-    // The fake object will be manually deleted in TearDown().
-    fake_drive_service_.reset(new google_apis::FakeDriveService);
-    fake_drive_service_->LoadAppListForDriveApi("chromeos/drive/applist.json");
+    fake_drive_service_.reset(new FakeDriveService);
+    fake_drive_service_->LoadAppListForDriveApi("drive/applist.json");
 
-    scheduler_.reset(
-        new JobScheduler(profile_.get(), fake_drive_service_.get()));
+    scheduler_.reset(new JobScheduler(profile_.get(), fake_drive_service_.get(),
+                                      base::MessageLoopProxy::current()));
 
     web_apps_registry_.reset(new DriveAppRegistry(scheduler_.get()));
     web_apps_registry_->Update();
@@ -58,7 +57,7 @@
 
   content::TestBrowserThreadBundle thread_bundle_;
   scoped_ptr<TestingProfile> profile_;
-  scoped_ptr<google_apis::FakeDriveService> fake_drive_service_;
+  scoped_ptr<FakeDriveService> fake_drive_service_;
   scoped_ptr<JobScheduler> scheduler_;
   scoped_ptr<DriveAppRegistry> web_apps_registry_;
 };
diff --git a/chrome/browser/chromeos/drive/drive_file_stream_reader.cc b/chrome/browser/chromeos/drive/drive_file_stream_reader.cc
index 7117085..a8c8e66 100644
--- a/chrome/browser/chromeos/drive/drive_file_stream_reader.cc
+++ b/chrome/browser/chromeos/drive/drive_file_stream_reader.cc
@@ -29,6 +29,12 @@
   return net::PlatformFileErrorToNetError(FileErrorToPlatformError(error));
 }
 
+// Runs task on UI thread.
+void RunTaskOnUIThread(const base::Closure& task) {
+  google_apis::RunTaskOnThread(
+      BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI), task);
+}
+
 }  // namespace
 
 namespace internal {
@@ -372,8 +378,7 @@
     reader_proxy_.reset(
         new internal::NetworkReaderProxy(
             byte_range.first_byte_position(), range_length,
-            base::Bind(&google_apis::RunTaskOnUIThread,
-                       ui_cancel_download_closure)));
+            base::Bind(&RunTaskOnUIThread, ui_cancel_download_closure)));
     callback.Run(net::OK, entry.Pass());
     return;
   }
diff --git a/chrome/browser/chromeos/drive/drive_file_stream_reader_unittest.cc b/chrome/browser/chromeos/drive/drive_file_stream_reader_unittest.cc
index 72ade07..c0c3de1 100644
--- a/chrome/browser/chromeos/drive/drive_file_stream_reader_unittest.cc
+++ b/chrome/browser/chromeos/drive/drive_file_stream_reader_unittest.cc
@@ -9,16 +9,13 @@
 #include "base/bind.h"
 #include "base/files/file_path.h"
 #include "base/files/scoped_temp_dir.h"
-#include "base/message_loop.h"
-#include "base/rand_util.h"
-#include "base/sequenced_task_runner.h"
+#include "base/run_loop.h"
 #include "base/threading/thread.h"
 #include "chrome/browser/chromeos/drive/fake_file_system.h"
 #include "chrome/browser/chromeos/drive/file_system_util.h"
 #include "chrome/browser/chromeos/drive/local_file_reader.h"
 #include "chrome/browser/chromeos/drive/test_util.h"
 #include "chrome/browser/drive/fake_drive_service.h"
-#include "chrome/browser/google_apis/task_util.h"
 #include "chrome/browser/google_apis/test_util.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "net/base/io_buffer.h"
@@ -54,10 +51,6 @@
     ASSERT_TRUE(worker_thread_->Start());
   }
 
-  virtual void TearDown() OVERRIDE {
-    worker_thread_.reset();
-  }
-
   content::TestBrowserThreadBundle thread_bundle_;
 
   base::ScopedTempDir temp_dir_;
@@ -78,7 +71,7 @@
   // Test instance.
   LocalReaderProxy proxy(file_reader.Pass(), file_content_.size());
 
-  // Make sure the read contant is as same as the file.
+  // Make sure the read content is as same as the file.
   std::string content;
   ASSERT_EQ(net::OK, test_util::ReadAllData(&proxy, &content));
   EXPECT_EQ(file_content_, content);
@@ -99,7 +92,7 @@
   // Test instance.
   LocalReaderProxy proxy(file_reader.Pass(), expected_content.size());
 
-  // Make sure the read contant is as same as the file.
+  // Make sure the read content is as same as the file.
   std::string content;
   ASSERT_EQ(net::OK, test_util::ReadAllData(&proxy, &content));
   EXPECT_EQ(expected_content, content);
@@ -295,11 +288,11 @@
     ASSERT_TRUE(worker_thread_->Start());
 
     // Initialize FakeDriveService.
-    fake_drive_service_.reset(new google_apis::FakeDriveService);
+    fake_drive_service_.reset(new FakeDriveService);
     fake_drive_service_->LoadResourceListForWapi(
-        "chromeos/gdata/root_feed.json");
+        "gdata/root_feed.json");
     fake_drive_service_->LoadAccountMetadataForWapi(
-        "chromeos/gdata/account_metadata.json");
+        "gdata/account_metadata.json");
 
     // Create a testee instance.
     fake_file_system_.reset(
@@ -327,7 +320,7 @@
 
   scoped_ptr<base::Thread> worker_thread_;
 
-  scoped_ptr<google_apis::FakeDriveService> fake_drive_service_;
+  scoped_ptr<FakeDriveService> fake_drive_service_;
   scoped_ptr<test_util::FakeFileSystem> fake_file_system_;
 };
 
@@ -343,14 +336,16 @@
 
   int error = net::ERR_FAILED;
   scoped_ptr<ResourceEntry> entry;
-  reader->Initialize(
-      kDriveFile,
-      net::HttpByteRange(),
-      google_apis::CreateComposedCallback(
-          base::Bind(&google_apis::test_util::RunAndQuit),
-                     google_apis::test_util::CreateCopyResultCallback(
-                         &error, &entry)));
-  base::MessageLoop::current()->Run();
+  {
+    base::RunLoop run_loop;
+    reader->Initialize(
+        kDriveFile,
+        net::HttpByteRange(),
+        google_apis::test_util::CreateQuitCallback(
+            &run_loop,
+            google_apis::test_util::CreateCopyResultCallback(&error, &entry)));
+    run_loop.Run();
+  }
   EXPECT_EQ(net::OK, error);
   ASSERT_TRUE(entry);
   EXPECT_TRUE(reader->IsInitialized());
@@ -370,14 +365,16 @@
 
   error = net::ERR_FAILED;
   entry.reset();
-  reader->Initialize(
-      kDriveFile,
-      net::HttpByteRange(),
-      google_apis::CreateComposedCallback(
-          base::Bind(&google_apis::test_util::RunAndQuit),
-                     google_apis::test_util::CreateCopyResultCallback(
-                         &error, &entry)));
-  base::MessageLoop::current()->Run();
+  {
+    base::RunLoop run_loop;
+    reader->Initialize(
+        kDriveFile,
+        net::HttpByteRange(),
+        google_apis::test_util::CreateQuitCallback(
+            &run_loop,
+            google_apis::test_util::CreateCopyResultCallback(&error, &entry)));
+    run_loop.Run();
+  }
   EXPECT_EQ(net::OK, error);
   ASSERT_TRUE(entry);
   EXPECT_TRUE(reader->IsInitialized());
@@ -413,14 +410,16 @@
   byte_range.set_first_byte_position(kRangeOffset);
   // Last byte position is inclusive.
   byte_range.set_last_byte_position(kRangeOffset + kRangeLength - 1);
-  reader->Initialize(
-      kDriveFile,
-      byte_range,
-      google_apis::CreateComposedCallback(
-          base::Bind(&google_apis::test_util::RunAndQuit),
-                     google_apis::test_util::CreateCopyResultCallback(
-                         &error, &entry)));
-  base::MessageLoop::current()->Run();
+  {
+    base::RunLoop run_loop;
+    reader->Initialize(
+        kDriveFile,
+        byte_range,
+        google_apis::test_util::CreateQuitCallback(
+            &run_loop,
+            google_apis::test_util::CreateCopyResultCallback(&error, &entry)));
+    run_loop.Run();
+  }
   EXPECT_EQ(net::OK, error);
   ASSERT_TRUE(entry);
   EXPECT_TRUE(reader->IsInitialized());
@@ -441,14 +440,16 @@
 
   error = net::ERR_FAILED;
   entry.reset();
-  reader->Initialize(
-      kDriveFile,
-      byte_range,
-      google_apis::CreateComposedCallback(
-          base::Bind(&google_apis::test_util::RunAndQuit),
-                     google_apis::test_util::CreateCopyResultCallback(
-                         &error, &entry)));
-  base::MessageLoop::current()->Run();
+  {
+    base::RunLoop run_loop;
+    reader->Initialize(
+        kDriveFile,
+        byte_range,
+        google_apis::test_util::CreateQuitCallback(
+            &run_loop,
+            google_apis::test_util::CreateCopyResultCallback(&error, &entry)));
+    run_loop.Run();
+  }
   EXPECT_EQ(net::OK, error);
   ASSERT_TRUE(entry);
   EXPECT_TRUE(reader->IsInitialized());
@@ -480,14 +481,16 @@
   byte_range.set_first_byte_position(kRangeOffset);
   // Last byte position is inclusive.
   byte_range.set_last_byte_position(kRangeOffset + kRangeLength - 1);
-  reader->Initialize(
-      kDriveFile,
-      byte_range,
-      google_apis::CreateComposedCallback(
-          base::Bind(&google_apis::test_util::RunAndQuit),
-                     google_apis::test_util::CreateCopyResultCallback(
-                         &error, &entry)));
-  base::MessageLoop::current()->Run();
+  {
+    base::RunLoop run_loop;
+    reader->Initialize(
+        kDriveFile,
+        byte_range,
+        google_apis::test_util::CreateQuitCallback(
+            &run_loop,
+            google_apis::test_util::CreateCopyResultCallback(&error, &entry)));
+    run_loop.Run();
+  }
   EXPECT_EQ(net::ERR_REQUEST_RANGE_NOT_SATISFIABLE, error);
   EXPECT_FALSE(entry);
 }
diff --git a/chrome/browser/chromeos/drive/drive_integration_service.cc b/chrome/browser/chromeos/drive/drive_integration_service.cc
index b9f6b57..7978b72 100644
--- a/chrome/browser/chromeos/drive/drive_integration_service.cc
+++ b/chrome/browser/chromeos/drive/drive_integration_service.cc
@@ -19,15 +19,17 @@
 #include "chrome/browser/chromeos/drive/file_write_helper.h"
 #include "chrome/browser/chromeos/drive/job_scheduler.h"
 #include "chrome/browser/chromeos/drive/logging.h"
+#include "chrome/browser/chromeos/drive/resource_metadata.h"
+#include "chrome/browser/chromeos/drive/resource_metadata_storage.h"
 #include "chrome/browser/download/download_service.h"
 #include "chrome/browser/download/download_service_factory.h"
 #include "chrome/browser/download/download_util.h"
 #include "chrome/browser/drive/drive_api_service.h"
+#include "chrome/browser/drive/drive_api_util.h"
 #include "chrome/browser/drive/drive_notification_manager.h"
 #include "chrome/browser/drive/drive_notification_manager_factory.h"
 #include "chrome/browser/drive/gdata_wapi_service.h"
 #include "chrome/browser/google_apis/auth_service.h"
-#include "chrome/browser/google_apis/drive_api_util.h"
 #include "chrome/browser/google_apis/gdata_wapi_url_generator.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/chrome_version_info.h"
@@ -91,9 +93,11 @@
 
 // Initializes FileCache and ResourceMetadata.
 // Must be run on the same task runner used by |cache| and |resource_metadata|.
-FileError InitializeMetadata(const base::FilePath& cache_root_directory,
-                             internal::FileCache* cache,
-                             internal::ResourceMetadata* resource_metadata) {
+FileError InitializeMetadata(
+    const base::FilePath& cache_root_directory,
+    internal::ResourceMetadataStorage* metadata_storage,
+    internal::FileCache* cache,
+    internal::ResourceMetadata* resource_metadata) {
   if (!file_util::CreateDirectory(cache_root_directory.Append(
           util::kMetadataDirectory)) ||
       !file_util::CreateDirectory(cache_root_directory.Append(
@@ -114,6 +118,11 @@
 
   util::MigrateCacheFilesFromOldDirectories(cache_root_directory);
 
+  if (!metadata_storage->Initialize()) {
+    LOG(WARNING) << "Failed to initialize the metadata storage.";
+    return FILE_ERROR_FAILED;
+  }
+
   if (!cache->Initialize()) {
     LOG(WARNING) << "Failed to initialize the cache.";
     return FILE_ERROR_FAILED;
@@ -129,7 +138,7 @@
 
 DriveIntegrationService::DriveIntegrationService(
     Profile* profile,
-    google_apis::DriveServiceInterface* test_drive_service,
+    DriveServiceInterface* test_drive_service,
     const base::FilePath& test_cache_root,
     FileSystemInterface* test_file_system)
     : profile_(profile),
@@ -145,28 +154,35 @@
 
   if (test_drive_service) {
     drive_service_.reset(test_drive_service);
-  } else if (google_apis::util::IsDriveV2ApiEnabled()) {
-    drive_service_.reset(new google_apis::DriveAPIService(
+  } else if (util::IsDriveV2ApiEnabled()) {
+    drive_service_.reset(new DriveAPIService(
         g_browser_process->system_request_context(),
+        blocking_task_runner_,
         GURL(google_apis::DriveApiUrlGenerator::kBaseUrlForProduction),
+        GURL(google_apis::DriveApiUrlGenerator::kBaseDownloadUrlForProduction),
         GetDriveUserAgent()));
   } else {
-    drive_service_.reset(new google_apis::GDataWapiService(
+    drive_service_.reset(new GDataWapiService(
         g_browser_process->system_request_context(),
+        blocking_task_runner_,
         GURL(google_apis::GDataWapiUrlGenerator::kBaseUrlForProduction),
+        GURL(google_apis::GDataWapiUrlGenerator::kBaseDownloadUrlForProduction),
         GetDriveUserAgent()));
   }
-  scheduler_.reset(new JobScheduler(profile_, drive_service_.get()));
-  cache_.reset(new internal::FileCache(
+  scheduler_.reset(new JobScheduler(
+      profile_, drive_service_.get(), blocking_task_runner_.get()));
+  metadata_storage_.reset(new internal::ResourceMetadataStorage(
       cache_root_directory_.Append(util::kMetadataDirectory),
+      blocking_task_runner_.get()));
+  cache_.reset(new internal::FileCache(
+      metadata_storage_.get(),
       cache_root_directory_.Append(util::kCacheFileDirectory),
       blocking_task_runner_.get(),
       NULL /* free_disk_space_getter */));
   drive_app_registry_.reset(new DriveAppRegistry(scheduler_.get()));
 
   resource_metadata_.reset(new internal::ResourceMetadata(
-      cache_root_directory_.Append(util::kMetadataDirectory),
-      blocking_task_runner_));
+      metadata_storage_.get(), blocking_task_runner_));
 
   file_system_.reset(
       test_file_system ? test_file_system : new FileSystem(
@@ -198,6 +214,7 @@
       FROM_HERE,
       base::Bind(&InitializeMetadata,
                  cache_root_directory_,
+                 metadata_storage_.get(),
                  cache_.get(),
                  resource_metadata_.get()),
       base::Bind(&DriveIntegrationService::InitializeAfterMetadataInitialized,
@@ -207,8 +224,8 @@
 void DriveIntegrationService::Shutdown() {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
 
-  google_apis::DriveNotificationManager* drive_notification_manager =
-      google_apis::DriveNotificationManagerFactory::GetForProfile(profile_);
+  DriveNotificationManager* drive_notification_manager =
+      DriveNotificationManagerFactory::GetForProfile(profile_);
   if (drive_notification_manager)
     drive_notification_manager->RemoveObserver(this);
 
@@ -356,8 +373,8 @@
       cache_root_directory_.Append(util::kTemporaryFileDirectory));
 
   // Register for Google Drive invalidation notifications.
-  google_apis::DriveNotificationManager* drive_notification_manager =
-      google_apis::DriveNotificationManagerFactory::GetForProfile(profile_);
+  DriveNotificationManager* drive_notification_manager =
+      DriveNotificationManagerFactory::GetForProfile(profile_);
   if (drive_notification_manager) {
     drive_notification_manager->AddObserver(this);
     const bool registered =
@@ -437,7 +454,7 @@
     : BrowserContextKeyedServiceFactory(
         "DriveIntegrationService",
         BrowserContextDependencyManager::GetInstance()) {
-  DependsOn(google_apis::DriveNotificationManagerFactory::GetInstance());
+  DependsOn(DriveNotificationManagerFactory::GetInstance());
   DependsOn(DownloadServiceFactory::GetInstance());
 }
 
diff --git a/chrome/browser/chromeos/drive/drive_integration_service.h b/chrome/browser/chromeos/drive/drive_integration_service.h
index c302467..ef954d3 100644
--- a/chrome/browser/chromeos/drive/drive_integration_service.h
+++ b/chrome/browser/chromeos/drive/drive_integration_service.h
@@ -13,7 +13,7 @@
 #include "chrome/browser/chromeos/drive/file_errors.h"
 #include "chrome/browser/chromeos/drive/file_system_util.h"
 #include "chrome/browser/chromeos/drive/job_scheduler.h"
-#include "chrome/browser/google_apis/drive_notification_observer.h"
+#include "chrome/browser/drive/drive_notification_observer.h"
 #include "components/browser_context_keyed_service/browser_context_keyed_service.h"
 #include "components/browser_context_keyed_service/browser_context_keyed_service_factory.h"
 
@@ -22,15 +22,12 @@
 class SequencedTaskRunner;
 }
 
-namespace google_apis {
-class DriveServiceInterface;
-}
-
 namespace drive {
 
 class DebugInfoCollector;
 class DownloadHandler;
 class DriveAppRegistry;
+class DriveServiceInterface;
 class FileSystemInterface;
 class FileSystemProxy;
 class FileWriteHelper;
@@ -39,6 +36,7 @@
 namespace internal {
 class FileCache;
 class ResourceMetadata;
+class ResourceMetadataStorage;
 }  // namespace internal
 
 // Interface for classes that need to observe events from
@@ -67,14 +65,14 @@
 // created per-profile.
 class DriveIntegrationService
     : public BrowserContextKeyedService,
-      public google_apis::DriveNotificationObserver {
+      public DriveNotificationObserver {
  public:
   // test_drive_service, test_cache_root and test_file_system are used by tests
   // to inject customized instances.
   // Pass NULL or the empty value when not interested.
   DriveIntegrationService(
       Profile* profile,
-      google_apis::DriveServiceInterface* test_drive_service,
+      DriveServiceInterface* test_drive_service,
       const base::FilePath& test_cache_root,
       FileSystemInterface* test_file_system);
   virtual ~DriveIntegrationService();
@@ -90,11 +88,11 @@
   void AddObserver(DriveIntegrationServiceObserver* observer);
   void RemoveObserver(DriveIntegrationServiceObserver* observer);
 
-  // google_apis::DriveNotificationObserver implementation.
+  // DriveNotificationObserver implementation.
   virtual void OnNotificationReceived() OVERRIDE;
   virtual void OnPushNotificationEnabled(bool enabled) OVERRIDE;
 
-  google_apis::DriveServiceInterface* drive_service() {
+  DriveServiceInterface* drive_service() {
     return drive_service_.get();
   }
 
@@ -149,8 +147,10 @@
 
   base::FilePath cache_root_directory_;
   scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
+  scoped_ptr<internal::ResourceMetadataStorage,
+             util::DestroyHelper> metadata_storage_;
   scoped_ptr<internal::FileCache, util::DestroyHelper> cache_;
-  scoped_ptr<google_apis::DriveServiceInterface> drive_service_;
+  scoped_ptr<DriveServiceInterface> drive_service_;
   scoped_ptr<JobScheduler> scheduler_;
   scoped_ptr<DriveAppRegistry> drive_app_registry_;
   scoped_ptr<internal::ResourceMetadata,
diff --git a/chrome/browser/chromeos/drive/drive_integration_service_unittest.cc b/chrome/browser/chromeos/drive/drive_integration_service_unittest.cc
index d44281b..bc20801 100644
--- a/chrome/browser/chromeos/drive/drive_integration_service_unittest.cc
+++ b/chrome/browser/chromeos/drive/drive_integration_service_unittest.cc
@@ -19,17 +19,11 @@
     profile_.reset(new TestingProfile);
     integration_service_.reset(new DriveIntegrationService(
         profile_.get(),
-        new google_apis::DummyDriveService,
+        new DummyDriveService,
         base::FilePath(),
         new DummyFileSystem));
   }
 
-  virtual void TearDown() OVERRIDE {
-    integration_service_.reset();
-    google_apis::test_util::RunBlockingPoolTask();
-    profile_.reset();
-  }
-
  protected:
   content::TestBrowserThreadBundle thread_bundle_;
   scoped_ptr<TestingProfile> profile_;
diff --git a/chrome/browser/chromeos/drive/drive_url_request_job_unittest.cc b/chrome/browser/chromeos/drive/drive_url_request_job_unittest.cc
index 4093cc5..95dd8dc 100644
--- a/chrome/browser/chromeos/drive/drive_url_request_job_unittest.cc
+++ b/chrome/browser/chromeos/drive/drive_url_request_job_unittest.cc
@@ -7,6 +7,7 @@
 #include "base/bind.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/run_loop.h"
 #include "base/sequenced_task_runner.h"
 #include "base/threading/sequenced_worker_pool.h"
 #include "base/threading/thread.h"
@@ -15,7 +16,6 @@
 #include "chrome/browser/chromeos/drive/file_system_util.h"
 #include "chrome/browser/chromeos/drive/test_util.h"
 #include "chrome/browser/drive/fake_drive_service.h"
-#include "chrome/browser/google_apis/task_util.h"
 #include "chrome/browser/google_apis/test_util.h"
 #include "chrome/common/url_constants.h"
 #include "content/public/browser/browser_thread.h"
@@ -104,11 +104,11 @@
 
   virtual void SetUp() OVERRIDE {
     // Initialize FakeDriveService.
-    fake_drive_service_.reset(new google_apis::FakeDriveService);
+    fake_drive_service_.reset(new FakeDriveService);
     ASSERT_TRUE(fake_drive_service_->LoadResourceListForWapi(
-        "chromeos/gdata/root_feed.json"));
+        "gdata/root_feed.json"));
     ASSERT_TRUE(fake_drive_service_->LoadAccountMetadataForWapi(
-        "chromeos/gdata/account_metadata.json"));
+        "gdata/account_metadata.json"));
 
     // Initialize FakeFileSystem.
     fake_file_system_.reset(
@@ -129,16 +129,6 @@
     test_delegate_.reset(new TestDelegate);
   }
 
-  virtual void TearDown() OVERRIDE {
-    test_delegate_.reset();
-    url_request_context_.reset();
-    test_url_request_job_factory_.reset();
-    test_network_delegate_.reset();
-
-    fake_file_system_.reset();
-    fake_drive_service_.reset();
-  }
-
   FileSystemInterface* GetFileSystem() {
     return fake_file_system_.get();
   }
@@ -156,14 +146,17 @@
         worker_thread->message_loop_proxy()));
     int error = net::ERR_FAILED;
     scoped_ptr<ResourceEntry> entry;
-    reader->Initialize(
-        file_path,
-        net::HttpByteRange(),
-        google_apis::CreateComposedCallback(
-            base::Bind(&google_apis::test_util::RunAndQuit),
-            google_apis::test_util::CreateCopyResultCallback(
-                &error, &entry)));
-    base::MessageLoop::current()->Run();
+    {
+      base::RunLoop run_loop;
+      reader->Initialize(
+          file_path,
+          net::HttpByteRange(),
+          google_apis::test_util::CreateQuitCallback(
+              &run_loop,
+              google_apis::test_util::CreateCopyResultCallback(
+                  &error, &entry)));
+      run_loop.Run();
+    }
     if (error != net::OK || !entry)
       return false;
 
@@ -181,7 +174,7 @@
 
   content::TestBrowserThreadBundle thread_bundle_;
 
-  scoped_ptr<google_apis::FakeDriveService> fake_drive_service_;
+  scoped_ptr<FakeDriveService> fake_drive_service_;
   scoped_ptr<test_util::FakeFileSystem> fake_file_system_;
 
   scoped_ptr<net::TestNetworkDelegate> test_network_delegate_;
@@ -197,7 +190,7 @@
   request.set_method("POST");  // Set non "GET" method.
   request.Start();
 
-  base::MessageLoop::current()->Run();
+  base::RunLoop().Run();
 
   EXPECT_EQ(net::URLRequestStatus::FAILED, request.status().status());
   EXPECT_EQ(net::ERR_METHOD_NOT_SUPPORTED, request.status().error());
@@ -214,7 +207,7 @@
         url_request_context_.get(), test_network_delegate_.get());
     request.Start();
 
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     EXPECT_EQ(net::URLRequestStatus::SUCCESS, request.status().status());
     // It looks weird, but the mime type for the "File 1.txt" is "audio/mpeg"
@@ -239,7 +232,7 @@
         url_request_context_.get(), test_network_delegate_.get());
     request.Start();
 
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     EXPECT_EQ(net::URLRequestStatus::SUCCESS, request.status().status());
     std::string mime_type;
@@ -261,7 +254,7 @@
       url_request_context_.get(), test_network_delegate_.get());
   request.Start();
 
-  base::MessageLoop::current()->Run();
+  base::RunLoop().Run();
 
   EXPECT_EQ(net::URLRequestStatus::SUCCESS, request.status().status());
   // Make sure that a hosted document triggers redirection.
@@ -276,7 +269,7 @@
       url_request_context_.get(), test_network_delegate_.get());
   request.Start();
 
-  base::MessageLoop::current()->Run();
+  base::RunLoop().Run();
 
   EXPECT_EQ(net::URLRequestStatus::FAILED, request.status().status());
   EXPECT_EQ(net::ERR_FAILED, request.status().error());
@@ -288,7 +281,7 @@
       url_request_context_.get(), test_network_delegate_.get());
   request.Start();
 
-  base::MessageLoop::current()->Run();
+  base::RunLoop().Run();
 
   EXPECT_EQ(net::URLRequestStatus::FAILED, request.status().status());
   EXPECT_EQ(net::ERR_FAILED, request.status().error());
@@ -300,7 +293,7 @@
       url_request_context_.get(), test_network_delegate_.get());
   request.Start();
 
-  base::MessageLoop::current()->Run();
+  base::RunLoop().Run();
 
   EXPECT_EQ(net::URLRequestStatus::FAILED, request.status().status());
   EXPECT_EQ(net::ERR_FILE_NOT_FOUND, request.status().error());
@@ -312,7 +305,7 @@
       url_request_context_.get(), test_network_delegate_.get());
   request.Start();
 
-  base::MessageLoop::current()->Run();
+  base::RunLoop().Run();
 
   EXPECT_EQ(net::URLRequestStatus::FAILED, request.status().status());
   EXPECT_EQ(net::ERR_INVALID_URL, request.status().error());
@@ -327,7 +320,7 @@
   request.Start();
   request.Cancel();
 
-  base::MessageLoop::current()->Run();
+  base::RunLoop().Run();
 
   EXPECT_EQ(net::URLRequestStatus::CANCELED, request.status().status());
 }
@@ -345,7 +338,7 @@
       "Range", "bytes=3-5", false /* overwrite */);
   request.Start();
 
-  base::MessageLoop::current()->Run();
+  base::RunLoop().Run();
 
   EXPECT_EQ(net::URLRequestStatus::SUCCESS, request.status().status());
 
@@ -368,7 +361,7 @@
       "Range", "Wrong Range Header Value", false /* overwrite */);
   request.Start();
 
-  base::MessageLoop::current()->Run();
+  base::RunLoop().Run();
 
   EXPECT_EQ(net::URLRequestStatus::FAILED, request.status().status());
   EXPECT_EQ(net::ERR_REQUEST_RANGE_NOT_SATISFIABLE, request.status().error());
diff --git a/chrome/browser/chromeos/drive/dummy_file_system.h b/chrome/browser/chromeos/drive/dummy_file_system.h
index 3d13719..e9743a9 100644
--- a/chrome/browser/chromeos/drive/dummy_file_system.h
+++ b/chrome/browser/chromeos/drive/dummy_file_system.h
@@ -53,6 +53,9 @@
                          const base::Time& last_access_time,
                          const base::Time& last_modified_time,
                          const FileOperationCallback& callback) OVERRIDE {}
+  virtual void TruncateFile(const base::FilePath& file_path,
+                            int64 length,
+                            const FileOperationCallback& callback) OVERRIDE {}
   virtual void Pin(const base::FilePath& file_path,
                    const FileOperationCallback& callback) OVERRIDE {}
   virtual void Unpin(const base::FilePath& file_path,
@@ -78,7 +81,7 @@
       const GetResourceEntryCallback& callback) OVERRIDE {}
   virtual void ReadDirectoryByPath(
       const base::FilePath& file_path,
-      const ReadDirectoryWithSettingCallback& callback) OVERRIDE {}
+      const ReadDirectoryCallback& callback) OVERRIDE {}
   virtual void RefreshDirectory(
       const base::FilePath& file_path,
       const FileOperationCallback& callback) OVERRIDE {}
diff --git a/chrome/browser/chromeos/drive/fake_file_system.cc b/chrome/browser/chromeos/drive/fake_file_system.cc
index 701cf63..c477e98 100644
--- a/chrome/browser/chromeos/drive/fake_file_system.cc
+++ b/chrome/browser/chromeos/drive/fake_file_system.cc
@@ -24,8 +24,7 @@
 
 using content::BrowserThread;
 
-FakeFileSystem::FakeFileSystem(
-    google_apis::DriveServiceInterface* drive_service)
+FakeFileSystem::FakeFileSystem(DriveServiceInterface* drive_service)
     : drive_service_(drive_service),
       weak_ptr_factory_(this) {
 }
@@ -130,6 +129,12 @@
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
 }
 
+void FakeFileSystem::TruncateFile(const base::FilePath& file_path,
+                                  int64 length,
+                                  const FileOperationCallback& callback) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+}
+
 void FakeFileSystem::Pin(const base::FilePath& file_path,
                          const FileOperationCallback& callback) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
@@ -164,7 +169,7 @@
       file_path,
       base::Bind(&FakeFileSystem::GetFileContentByPathAfterGetResourceEntry,
                  weak_ptr_factory_.GetWeakPtr(),
-                 file_path, initialized_callback, get_content_callback,
+                 initialized_callback, get_content_callback,
                  completion_callback));
 }
 
@@ -201,7 +206,7 @@
 
 void FakeFileSystem::ReadDirectoryByPath(
     const base::FilePath& file_path,
-    const ReadDirectoryWithSettingCallback& callback) {
+    const ReadDirectoryCallback& callback) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
 }
 
@@ -275,7 +280,6 @@
 
 // Implementation of GetFileContentByPath.
 void FakeFileSystem::GetFileContentByPathAfterGetResourceEntry(
-    const base::FilePath& file_path,
     const GetFileContentInitializedCallback& initialized_callback,
     const google_apis::GetContentCallback& get_content_callback,
     const FileOperationCallback& completion_callback,
@@ -301,14 +305,12 @@
       base::Bind(
           &FakeFileSystem::GetFileContentByPathAfterGetWapiResourceEntry,
           weak_ptr_factory_.GetWeakPtr(),
-          file_path,
           initialized_callback,
           get_content_callback,
           completion_callback));
 }
 
 void FakeFileSystem::GetFileContentByPathAfterGetWapiResourceEntry(
-    const base::FilePath& file_path,
     const GetFileContentInitializedCallback& initialized_callback,
     const google_apis::GetContentCallback& get_content_callback,
     const FileOperationCallback& completion_callback,
@@ -339,9 +341,8 @@
   initialized_callback.Run(FILE_ERROR_OK, entry.Pass(), base::FilePath(),
                            base::Bind(&base::DoNothing));
   drive_service_->DownloadFile(
-      file_path,
       cache_path,
-      GURL(gdata_entry->download_url()),
+      gdata_entry->resource_id(),
       base::Bind(&FakeFileSystem::GetFileContentByPathAfterDownloadFile,
                  weak_ptr_factory_.GetWeakPtr(),
                  completion_callback),
diff --git a/chrome/browser/chromeos/drive/fake_file_system.h b/chrome/browser/chromeos/drive/fake_file_system.h
index b61c55b..fc1c587 100644
--- a/chrome/browser/chromeos/drive/fake_file_system.h
+++ b/chrome/browser/chromeos/drive/fake_file_system.h
@@ -18,7 +18,6 @@
 namespace google_apis {
 
 class AboutResource;
-class DriveServiceInterface;
 class ResourceEntry;
 class ResourceList;
 
@@ -26,6 +25,7 @@
 
 namespace drive {
 
+class DriveServiceInterface;
 class FileSystemObserver;
 class ResourceEntry;
 
@@ -39,8 +39,7 @@
 // Currently most methods are empty (not implemented).
 class FakeFileSystem : public FileSystemInterface {
  public:
-  explicit FakeFileSystem(
-      google_apis::DriveServiceInterface* drive_service);
+  explicit FakeFileSystem(DriveServiceInterface* drive_service);
   virtual ~FakeFileSystem();
 
   // Initialization for testing. This can be called instead of Initialize
@@ -87,6 +86,9 @@
                          const base::Time& last_access_time,
                          const base::Time& last_modified_time,
                          const FileOperationCallback& callback) OVERRIDE;
+  virtual void TruncateFile(const base::FilePath& file_path,
+                            int64 length,
+                            const FileOperationCallback& callback) OVERRIDE;
   virtual void Pin(const base::FilePath& file_path,
                    const FileOperationCallback& callback) OVERRIDE;
   virtual void Unpin(const base::FilePath& file_path,
@@ -112,7 +114,7 @@
       const GetResourceEntryCallback& callback) OVERRIDE;
   virtual void ReadDirectoryByPath(
       const base::FilePath& file_path,
-      const ReadDirectoryWithSettingCallback& callback) OVERRIDE;
+      const ReadDirectoryCallback& callback) OVERRIDE;
   virtual void RefreshDirectory(
       const base::FilePath& file_path,
       const FileOperationCallback& callback) OVERRIDE;
@@ -153,14 +155,12 @@
   // 3) Otherwise start DownloadFile.
   // 4) Runs the |completion_callback| upon the download completion.
   void GetFileContentByPathAfterGetResourceEntry(
-      const base::FilePath& file_path,
       const GetFileContentInitializedCallback& initialized_callback,
       const google_apis::GetContentCallback& get_content_callback,
       const FileOperationCallback& completion_callback,
       FileError error,
       scoped_ptr<ResourceEntry> entry);
   void GetFileContentByPathAfterGetWapiResourceEntry(
-      const base::FilePath& file_path,
       const GetFileContentInitializedCallback& initialized_callback,
       const google_apis::GetContentCallback& get_content_callback,
       const FileOperationCallback& completion_callback,
@@ -197,7 +197,7 @@
       google_apis::GDataErrorCode gdata_error,
       scoped_ptr<google_apis::ResourceList> resource_list);
 
-  google_apis::DriveServiceInterface* drive_service_;  // Not owned.
+  DriveServiceInterface* drive_service_;  // Not owned.
   base::ScopedTempDir cache_dir_;
 
   // Note: This should remain the last member so it'll be destroyed and
diff --git a/chrome/browser/chromeos/drive/fake_file_system_unittest.cc b/chrome/browser/chromeos/drive/fake_file_system_unittest.cc
index cc46cc2..43011e3 100644
--- a/chrome/browser/chromeos/drive/fake_file_system_unittest.cc
+++ b/chrome/browser/chromeos/drive/fake_file_system_unittest.cc
@@ -19,11 +19,11 @@
  protected:
   virtual void SetUp() OVERRIDE {
     // Initialize FakeDriveService.
-    fake_drive_service_.reset(new google_apis::FakeDriveService);
+    fake_drive_service_.reset(new FakeDriveService);
     fake_drive_service_->LoadResourceListForWapi(
-        "chromeos/gdata/root_feed.json");
+        "gdata/root_feed.json");
     fake_drive_service_->LoadAccountMetadataForWapi(
-        "chromeos/gdata/account_metadata.json");
+        "gdata/account_metadata.json");
 
     // Create a testee instance.
     fake_file_system_.reset(new FakeFileSystem(fake_drive_service_.get()));
@@ -31,7 +31,7 @@
   }
 
   content::TestBrowserThreadBundle thread_bundle_;
-  scoped_ptr<google_apis::FakeDriveService> fake_drive_service_;
+  scoped_ptr<FakeDriveService> fake_drive_service_;
   scoped_ptr<FakeFileSystem> fake_file_system_;
 };
 
diff --git a/chrome/browser/chromeos/drive/file_cache.cc b/chrome/browser/chromeos/drive/file_cache.cc
index 1894aa6..2fbce21 100644
--- a/chrome/browser/chromeos/drive/file_cache.cc
+++ b/chrome/browser/chromeos/drive/file_cache.cc
@@ -16,6 +16,7 @@
 #include "chrome/browser/chromeos/drive/drive.pb.h"
 #include "chrome/browser/chromeos/drive/file_cache_metadata.h"
 #include "chrome/browser/chromeos/drive/file_system_util.h"
+#include "chrome/browser/chromeos/drive/resource_metadata_storage.h"
 #include "chrome/browser/google_apis/task_util.h"
 #include "chromeos/chromeos_constants.h"
 #include "content/public/browser/browser_thread.h"
@@ -80,7 +81,7 @@
 // Moves the file.
 bool MoveFile(const base::FilePath& source_path,
               const base::FilePath& dest_path) {
-  if (!file_util::Move(source_path, dest_path)) {
+  if (!base::Move(source_path, dest_path)) {
     LOG(ERROR) << "Failed to move " << source_path.value()
                << " to " << dest_path.value();
     return false;
@@ -122,7 +123,7 @@
     if (!path_to_keep.empty() && current == path_to_keep)
       continue;
 
-    success = file_util::Delete(current, false);
+    success = base::Delete(current, false);
     if (!success)
       DVLOG(1) << "Error deleting " << current.value();
     else
@@ -153,15 +154,27 @@
   callback.Run(success, *cache_entry);
 }
 
+// Calls |iteration_callback| with each entry in |cache|.
+void IterateCache(FileCache* cache,
+                  const CacheIterateCallback& iteration_callback) {
+  scoped_ptr<FileCache::Iterator> it = cache->GetIterator();
+  for (; !it->IsAtEnd(); it->Advance())
+    iteration_callback.Run(it->GetID(), it->GetValue());
+  DCHECK(!it->HasError());
+}
+
 }  // namespace
 
-FileCache::FileCache(const base::FilePath& metadata_directory,
+const base::FilePath::CharType FileCache::kOldCacheMetadataDBName[] =
+    FILE_PATH_LITERAL("cache_metadata.db");
+
+FileCache::FileCache(ResourceMetadataStorage* storage,
                      const base::FilePath& cache_file_directory,
                      base::SequencedTaskRunner* blocking_task_runner,
                      FreeDiskSpaceGetterInterface* free_disk_space_getter)
-    : metadata_directory_(metadata_directory),
-      cache_file_directory_(cache_file_directory),
+    : cache_file_directory_(cache_file_directory),
       blocking_task_runner_(blocking_task_runner),
+      storage_(storage),
       free_disk_space_getter_(free_disk_space_getter),
       weak_ptr_factory_(this) {
   DCHECK(blocking_task_runner_.get());
@@ -225,7 +238,7 @@
                               FileCacheEntry* entry) {
   DCHECK(entry);
   AssertOnSequencedWorkerPool();
-  return metadata_->GetCacheEntry(resource_id, entry) &&
+  return storage_->GetCacheEntry(resource_id, entry) &&
       CheckIfMd5Matches(md5, *entry);
 }
 
@@ -238,20 +251,15 @@
 
   blocking_task_runner_->PostTaskAndReply(
       FROM_HERE,
-      base::Bind(&FileCache::Iterate,
+      base::Bind(&IterateCache,
                  base::Unretained(this),
                  google_apis::CreateRelayCallback(iteration_callback)),
       completion_callback);
 }
 
-void FileCache::Iterate(const CacheIterateCallback& iteration_callback) {
+scoped_ptr<FileCache::Iterator> FileCache::GetIterator() {
   AssertOnSequencedWorkerPool();
-  DCHECK(!iteration_callback.is_null());
-
-  scoped_ptr<FileCacheMetadata::Iterator> it = metadata_->GetIterator();
-  for (; !it->IsAtEnd(); it->Advance())
-    iteration_callback.Run(it->GetKey(), it->GetValue());
-  DCHECK(!it->HasError());
+  return storage_->GetCacheEntryIterator();
 }
 
 void FileCache::FreeDiskSpaceIfNeededForOnUIThread(
@@ -280,13 +288,14 @@
   DVLOG(1) << "Freeing up disk space for " << num_bytes;
 
   // Remove all entries unless specially marked.
-  scoped_ptr<FileCacheMetadata::Iterator> it = metadata_->GetIterator();
+  scoped_ptr<ResourceMetadataStorage::CacheEntryIterator> it =
+      storage_->GetCacheEntryIterator();
   for (; !it->IsAtEnd(); it->Advance()) {
     const FileCacheEntry& entry = it->GetValue();
     if (!entry.is_pinned() &&
         !entry.is_dirty() &&
-        !mounted_files_.count(it->GetKey()))
-      metadata_->RemoveCacheEntry(it->GetKey());
+        !mounted_files_.count(it->GetID()))
+      storage_->RemoveCacheEntry(it->GetID());
   }
   DCHECK(!it->HasError());
 
@@ -301,7 +310,7 @@
        current = enumerator.Next()) {
     util::ParseCacheFilePath(current, &resource_id, &md5);
     if (!GetCacheEntry(resource_id, md5, &entry))
-      file_util::Delete(current, false /* recursive */);
+      base::Delete(current, false /* recursive */);
   }
 
   // Check the disk space again.
@@ -388,9 +397,9 @@
   AssertOnSequencedWorkerPool();
 
   FileCacheEntry cache_entry;
-  metadata_->GetCacheEntry(resource_id, &cache_entry);
+  storage_->GetCacheEntry(resource_id, &cache_entry);
   cache_entry.set_is_pinned(true);
-  metadata_->AddOrUpdateCacheEntry(resource_id, cache_entry);
+  storage_->PutCacheEntry(resource_id, cache_entry);
   return FILE_ERROR_OK;
 }
 
@@ -411,16 +420,16 @@
 
   // Unpinning a file means its entry must exist in cache.
   FileCacheEntry cache_entry;
-  if (!metadata_->GetCacheEntry(resource_id, &cache_entry))
+  if (!storage_->GetCacheEntry(resource_id, &cache_entry))
     return FILE_ERROR_NOT_FOUND;
 
   // Now that file operations have completed, update metadata.
   if (cache_entry.is_present()) {
     cache_entry.set_is_pinned(false);
-    metadata_->AddOrUpdateCacheEntry(resource_id, cache_entry);
+    storage_->PutCacheEntry(resource_id, cache_entry);
   } else {
     // Remove the existing entry if we are unpinning a non-present file.
-    metadata_->RemoveCacheEntry(resource_id);
+    storage_->RemoveCacheEntry(resource_id);
   }
 
   // Now it's a chance to free up space if needed.
@@ -487,7 +496,7 @@
   // Marking a file dirty means its entry and actual file blob must exist in
   // cache.
   FileCacheEntry cache_entry;
-  if (!metadata_->GetCacheEntry(resource_id, &cache_entry) ||
+  if (!storage_->GetCacheEntry(resource_id, &cache_entry) ||
       !cache_entry.is_present()) {
     LOG(WARNING) << "Can't mark dirty a file that wasn't cached: res_id="
                  << resource_id
@@ -511,7 +520,7 @@
   // Now that file operations have completed, update metadata.
   cache_entry.set_md5(md5);
   cache_entry.set_is_dirty(true);
-  metadata_->AddOrUpdateCacheEntry(resource_id, cache_entry);
+  storage_->PutCacheEntry(resource_id, cache_entry);
   return FILE_ERROR_OK;
 }
 
@@ -525,7 +534,7 @@
 
   // Clearing a dirty file means its entry and actual file blob must exist in
   // cache.
-  if (!metadata_->GetCacheEntry(resource_id, &cache_entry) ||
+  if (!storage_->GetCacheEntry(resource_id, &cache_entry) ||
       !cache_entry.is_present()) {
     LOG(WARNING) << "Can't clear dirty state of a file that wasn't cached: "
                  << "res_id=" << resource_id
@@ -552,7 +561,7 @@
   // Now that file operations have completed, update metadata.
   cache_entry.set_md5(md5);
   cache_entry.set_is_dirty(false);
-  metadata_->AddOrUpdateCacheEntry(resource_id, cache_entry);
+  storage_->PutCacheEntry(resource_id, cache_entry);
   return FILE_ERROR_OK;
 }
 
@@ -577,7 +586,7 @@
   FileCacheEntry cache_entry;
 
   // If entry doesn't exist, nothing to do.
-  if (!metadata_->GetCacheEntry(resource_id, &cache_entry))
+  if (!storage_->GetCacheEntry(resource_id, &cache_entry))
     return FILE_ERROR_OK;
 
   // Cannot delete a dirty or mounted file.
@@ -592,7 +601,7 @@
   DeleteFilesSelectively(path_to_delete, path_to_keep);
 
   // Now that all file operations have completed, remove from metadata.
-  metadata_->RemoveCacheEntry(resource_id);
+  storage_->RemoveCacheEntry(resource_id);
 
   return FILE_ERROR_OK;
 }
@@ -611,23 +620,14 @@
 bool FileCache::Initialize() {
   AssertOnSequencedWorkerPool();
 
-  metadata_.reset(new FileCacheMetadata(blocking_task_runner_.get()));
-
-  switch (metadata_->Initialize(metadata_directory_)) {
-    case FileCacheMetadata::INITIALIZE_FAILED:
-      return false;
-
-    case FileCacheMetadata::INITIALIZE_OPENED:  // Do nothing.
-      break;
-
-    case FileCacheMetadata::INITIALIZE_CREATED: {
-      CacheMap cache_map;
-      ScanCacheDirectory(cache_file_directory_, &cache_map);
-      for (CacheMap::const_iterator it = cache_map.begin();
-           it != cache_map.end(); ++it) {
-        metadata_->AddOrUpdateCacheEntry(it->first, it->second);
-      }
-      break;
+  if (!ImportOldDB(storage_->directory_path().Append(
+          kOldCacheMetadataDBName)) &&
+      !storage_->opened_existing_db()) {
+    CacheMap cache_map;
+    ScanCacheDirectory(cache_file_directory_, &cache_map);
+    for (CacheMap::const_iterator it = cache_map.begin();
+         it != cache_map.end(); ++it) {
+      storage_->PutCacheEntry(it->first, it->second);
     }
   }
   return true;
@@ -669,7 +669,7 @@
     return FILE_ERROR_NO_SPACE;
 
   FileCacheEntry cache_entry;
-  metadata_->GetCacheEntry(resource_id, &cache_entry);
+  storage_->GetCacheEntry(resource_id, &cache_entry);
 
   // If file is dirty or mounted, return error.
   if (cache_entry.is_dirty() || mounted_files_.count(resource_id))
@@ -716,7 +716,7 @@
     cache_entry.set_md5(md5);
     cache_entry.set_is_present(true);
     cache_entry.set_is_dirty(false);
-    metadata_->AddOrUpdateCacheEntry(resource_id, cache_entry);
+    storage_->PutCacheEntry(resource_id, cache_entry);
   }
 
   return success ? FILE_ERROR_OK : FILE_ERROR_FAILED;
@@ -729,7 +729,7 @@
 
   // Get cache entry associated with the resource_id and md5
   FileCacheEntry cache_entry;
-  if (!metadata_->GetCacheEntry(resource_id, &cache_entry))
+  if (!storage_->GetCacheEntry(resource_id, &cache_entry))
     return FILE_ERROR_NOT_FOUND;
 
   if (mounted_files_.count(resource_id))
@@ -777,9 +777,10 @@
   AssertOnSequencedWorkerPool();
 
   // Remove entries on the metadata.
-  scoped_ptr<FileCacheMetadata::Iterator> it = metadata_->GetIterator();
+  scoped_ptr<ResourceMetadataStorage::CacheEntryIterator> it =
+      storage_->GetCacheEntryIterator();
   for (; !it->IsAtEnd(); it->Advance())
-    metadata_->RemoveCacheEntry(it->GetKey());
+    storage_->RemoveCacheEntry(it->GetID());
 
   if (it->HasError())
     return false;
@@ -790,7 +791,7 @@
                                   base::FileEnumerator::FILES);
   for (base::FilePath file = enumerator.Next(); !file.empty();
        file = enumerator.Next())
-    file_util::Delete(file, false /* recursive */);
+    base::Delete(file, false /* recursive */);
 
   return true;
 }
@@ -808,5 +809,32 @@
   return (free_space >= num_bytes);
 }
 
+bool FileCache::ImportOldDB(const base::FilePath& old_db_path) {
+  if (!file_util::PathExists(old_db_path))  // Old DB is not there, do nothing.
+    return false;
+
+  // Copy all entries stored in the old DB.
+  bool imported = false;
+  {
+    FileCacheMetadata old_data(blocking_task_runner_);
+    if (old_data.Initialize(old_db_path) ==
+        FileCacheMetadata::INITIALIZE_OPENED) {
+      scoped_ptr<FileCacheMetadata::Iterator> it = old_data.GetIterator();
+      for (; !it->IsAtEnd(); it->Advance()) {
+        FileCacheEntry entry;
+        if (storage_->GetCacheEntry(it->GetKey(), &entry))
+          continue;  // Do not overwrite.
+
+        storage_->PutCacheEntry(it->GetKey(), it->GetValue());
+      }
+      imported = true;
+    }
+  }
+
+  // Delete old DB.
+  base::Delete(old_db_path, true /* recursive */ );
+  return imported;
+}
+
 }  // namespace internal
 }  // namespace drive
diff --git a/chrome/browser/chromeos/drive/file_cache.h b/chrome/browser/chromeos/drive/file_cache.h
index be0ccff..398e193 100644
--- a/chrome/browser/chromeos/drive/file_cache.h
+++ b/chrome/browser/chromeos/drive/file_cache.h
@@ -14,6 +14,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/chromeos/drive/file_errors.h"
+#include "chrome/browser/chromeos/drive/resource_metadata_storage.h"
 
 class Profile;
 
@@ -41,8 +42,6 @@
 
 namespace internal {
 
-class FileCacheMetadata;
-
 // Callback for GetFileFromCache.
 typedef base::Callback<void(FileError error,
                             const base::FilePath& cache_file_path)>
@@ -74,8 +73,13 @@
     FILE_OPERATION_COPY,
   };
 
-  // |metadata_directory| stores the metadata and |cache_file_directory| stores
-  // cached files.
+  typedef ResourceMetadataStorage::CacheEntryIterator Iterator;
+
+  // Name of the cache metadata DB previously used.
+  // TODO(hashimoto): Remove this at some point.
+  static const base::FilePath::CharType kOldCacheMetadataDBName[];
+
+  // |cache_file_directory| stores cached files.
   //
   // |blocking_task_runner| is used to post a task to the blocking worker
   // pool for file operations. Must not be null.
@@ -84,7 +88,7 @@
   // getter for testing. NULL must be passed for production code.
   //
   // Must be called on the UI thread.
-  FileCache(const base::FilePath& metadata_directory,
+  FileCache(ResourceMetadataStorage* storage,
             const base::FilePath& cache_file_directory,
             base::SequencedTaskRunner* blocking_task_runner,
             FreeDiskSpaceGetterInterface* free_disk_space_getter);
@@ -117,10 +121,8 @@
   void IterateOnUIThread(const CacheIterateCallback& iteration_callback,
                          const base::Closure& completion_callback);
 
-  // Iterates all files in the cache and calls |iteration_callback| for each
-  // file. |completion_callback| is run upon completion.
-  // TODO(hashimoto): Stop using callbacks for this method. crbug.com/242818
-  void Iterate(const CacheIterateCallback& iteration_callback);
+  // Returns an object to iterate over entries.
+  scoped_ptr<Iterator> GetIterator();
 
 
   // Runs FreeDiskSpaceIfNeededFor() on |blocking_task_runner_|, and calls
@@ -293,13 +295,15 @@
   // bytes, while keeping kMinFreeSpace bytes on the disk.
   bool HasEnoughSpaceFor(int64 num_bytes, const base::FilePath& path);
 
-  const base::FilePath metadata_directory_;
+  // Imports old format DB from |old_db_path| and deletes it.
+  // TODO(hashimoto): Remove this method and FileCacheMetadata at some point.
+  bool ImportOldDB(const base::FilePath& old_db_path);
+
   const base::FilePath cache_file_directory_;
 
   scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
 
-  // The cache state data. This member must be access only on the blocking pool.
-  scoped_ptr<FileCacheMetadata> metadata_;
+  ResourceMetadataStorage* storage_;
 
   FreeDiskSpaceGetterInterface* free_disk_space_getter_;  // Not owned.
 
diff --git a/chrome/browser/chromeos/drive/file_cache_metadata.cc b/chrome/browser/chromeos/drive/file_cache_metadata.cc
index 03ca62e..b421b43 100644
--- a/chrome/browser/chromeos/drive/file_cache_metadata.cc
+++ b/chrome/browser/chromeos/drive/file_cache_metadata.cc
@@ -29,10 +29,6 @@
 
 }  // namespace
 
-// static
-const base::FilePath::CharType* FileCacheMetadata::kCacheMetadataDBPath =
-    FILE_PATH_LITERAL("cache_metadata.db");
-
 FileCacheMetadata::Iterator::Iterator(scoped_ptr<leveldb::Iterator> it)
     : it_(it.Pass()) {
   base::ThreadRestrictions::AssertIOAllowed();
@@ -96,12 +92,9 @@
 }
 
 FileCacheMetadata::InitializeResult FileCacheMetadata::Initialize(
-    const base::FilePath& db_directory_path) {
+    const base::FilePath& db_path) {
   AssertOnSequencedWorkerPool();
 
-  const base::FilePath db_path = db_directory_path.Append(kCacheMetadataDBPath);
-  DVLOG(1) << "db path=" << db_path.value();
-
   bool created = !file_util::PathExists(db_path);
 
   leveldb::DB* level_db = NULL;
@@ -117,7 +110,7 @@
     LOG(WARNING) << "Cache db failed to open: " << db_status.ToString();
     uma_status = db_status.IsCorruption() ?
         DB_OPEN_FAILURE_CORRUPTION : DB_OPEN_FAILURE_OTHER;
-    const bool deleted = file_util::Delete(db_path, true);
+    const bool deleted = base::Delete(db_path, true);
     DCHECK(deleted);
     db_status = leveldb::DB::Open(options, db_path.value(), &level_db);
     if (!db_status.ok()) {
diff --git a/chrome/browser/chromeos/drive/file_cache_metadata.h b/chrome/browser/chromeos/drive/file_cache_metadata.h
index e98158f..7baf395 100644
--- a/chrome/browser/chromeos/drive/file_cache_metadata.h
+++ b/chrome/browser/chromeos/drive/file_cache_metadata.h
@@ -28,11 +28,11 @@
 // FileCacheMetadata maintains metadata of FileCache's cached files.
 // This class only manages metadata. File operations are done by FileCache.
 // All member access including ctor and dtor must be made on the blocking pool.
+//
+// OBSOLETE: This class is maintained only for importing old data.
+// TODO(hashimoto): Remove this class at some point.
 class FileCacheMetadata {
  public:
-  // Database path.
-  static const base::FilePath::CharType* kCacheMetadataDBPath;
-
   // Result of Initialize().
   enum InitializeResult {
     INITIALIZE_FAILED,  // Could not open nor create DB.
@@ -79,7 +79,7 @@
   ~FileCacheMetadata();
 
   // Initialize the cache metadata store. Returns true on success.
-  InitializeResult Initialize(const base::FilePath& db_directory_path);
+  InitializeResult Initialize(const base::FilePath& db_path);
   // Adds a new cache entry corresponding to |resource_id| if it doesn't
   // exist, otherwise update the existing entry.
   void AddOrUpdateCacheEntry(const std::string& resource_id,
diff --git a/chrome/browser/chromeos/drive/file_cache_metadata_unittest.cc b/chrome/browser/chromeos/drive/file_cache_metadata_unittest.cc
index 4f80668..7ceadf6 100644
--- a/chrome/browser/chromeos/drive/file_cache_metadata_unittest.cc
+++ b/chrome/browser/chromeos/drive/file_cache_metadata_unittest.cc
@@ -17,18 +17,12 @@
 
 class FileCacheMetadataTest : public testing::Test {
  public:
-  FileCacheMetadataTest() {}
-
   virtual void SetUp() OVERRIDE {
     // Create cache directories.
     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
     metadata_.reset(new FileCacheMetadata(NULL));
   }
 
-  virtual void TearDown() OVERRIDE {
-    metadata_.reset();
-  }
-
  protected:
   base::ScopedTempDir temp_dir_;
   scoped_ptr<FileCacheMetadata> metadata_;
@@ -38,7 +32,7 @@
 // RemoveTemporaryFiles.
 TEST_F(FileCacheMetadataTest, CacheTest) {
   ASSERT_EQ(FileCacheMetadata::INITIALIZE_CREATED,
-            metadata_->Initialize(temp_dir_.path()));
+            metadata_->Initialize(temp_dir_.path().AppendASCII("test.db")));
 
   // Save an initial entry.
   std::string test_resource_id("test_resource_id");
@@ -108,22 +102,22 @@
 }
 
 TEST_F(FileCacheMetadataTest, Initialize) {
-  const base::FilePath db_path =
-      temp_dir_.path().Append(FileCacheMetadata::kCacheMetadataDBPath);
+  const base::FilePath db_path = temp_dir_.path().AppendASCII("test.db");
 
   // Try to open a bogus file.
   ASSERT_TRUE(
       google_apis::test_util::WriteStringToFile(db_path, "Hello world"));
   ASSERT_EQ(FileCacheMetadata::INITIALIZE_CREATED,
-            metadata_->Initialize(temp_dir_.path()));
+            metadata_->Initialize(db_path));
 
   // Open an existing DB.
   metadata_.reset(new FileCacheMetadata(NULL));
   EXPECT_EQ(FileCacheMetadata::INITIALIZE_OPENED,
-            metadata_->Initialize(temp_dir_.path()));
+            metadata_->Initialize(db_path));
 
   // Try to open a nonexistent path.
-  base::FilePath non_existent_path(FILE_PATH_LITERAL("/somewhere/nonexistent"));
+  base::FilePath non_existent_path(FILE_PATH_LITERAL(
+      "/somewhere/nonexistent/test.db"));
   metadata_.reset(new FileCacheMetadata(NULL));
   EXPECT_EQ(FileCacheMetadata::INITIALIZE_FAILED,
             metadata_->Initialize(non_existent_path));
diff --git a/chrome/browser/chromeos/drive/file_cache_unittest.cc b/chrome/browser/chromeos/drive/file_cache_unittest.cc
index c28d20e..8a8e37b 100644
--- a/chrome/browser/chromeos/drive/file_cache_unittest.cc
+++ b/chrome/browser/chromeos/drive/file_cache_unittest.cc
@@ -14,7 +14,9 @@
 #include "base/threading/sequenced_worker_pool.h"
 #include "chrome/browser/chromeos/drive/drive.pb.h"
 #include "chrome/browser/chromeos/drive/fake_free_disk_space_getter.h"
+#include "chrome/browser/chromeos/drive/file_cache_metadata.h"
 #include "chrome/browser/chromeos/drive/file_system_util.h"
+#include "chrome/browser/chromeos/drive/resource_metadata_storage.h"
 #include "chrome/browser/chromeos/drive/test_util.h"
 #include "chrome/browser/google_apis/test_util.h"
 #include "content/public/browser/browser_thread.h"
@@ -73,13 +75,27 @@
         content::BrowserThread::GetBlockingPool();
     blocking_task_runner_ =
         pool->GetSequencedTaskRunner(pool->GetSequenceToken());
+
+    metadata_storage_.reset(new ResourceMetadataStorage(
+        temp_dir_.path(), blocking_task_runner_));
+
+    bool success = false;
+    base::PostTaskAndReplyWithResult(
+        blocking_task_runner_,
+        FROM_HERE,
+        base::Bind(&ResourceMetadataStorage::Initialize,
+                   base::Unretained(metadata_storage_.get())),
+        google_apis::test_util::CreateCopyResultCallback(&success));
+    google_apis::test_util::RunBlockingPoolTask();
+    ASSERT_TRUE(success);
+
     cache_.reset(new FileCache(
-        temp_dir_.path().Append(util::kMetadataDirectory),
+        metadata_storage_.get(),
         temp_dir_.path().Append(util::kCacheFileDirectory),
         blocking_task_runner_.get(),
         fake_free_disk_space_getter_.get()));
 
-    bool success = false;
+    success = false;
     base::PostTaskAndReplyWithResult(
         blocking_task_runner_,
         FROM_HERE,
@@ -90,10 +106,6 @@
     ASSERT_TRUE(success);
   }
 
-  virtual void TearDown() OVERRIDE {
-    cache_.reset();
-  }
-
   void TestGetFileFromCacheByResourceIdAndMd5(
       const std::string& resource_id,
       const std::string& md5,
@@ -418,6 +430,8 @@
   base::ScopedTempDir temp_dir_;
   base::FilePath dummy_file_path_;
 
+  scoped_ptr<ResourceMetadataStorage, test_util::DestroyHelperForTests>
+      metadata_storage_;
   scoped_ptr<FileCache, test_util::DestroyHelperForTests> cache_;
   scoped_ptr<FakeFreeDiskSpaceGetter> fake_free_disk_space_getter_;
 
@@ -852,20 +866,6 @@
   EXPECT_EQ(0U, CountCacheFiles(resource_id, md5));
 }
 
-// Don't use TEST_F, as we don't want SetUp() and TearDown() for this test.
-TEST(FileCacheExtraTest, InitializationFailure) {
-  content::TestBrowserThreadBundle thread_bundle;
-
-  // Set the cache root to a non existent path, so the initialization fails.
-  scoped_ptr<FileCache, test_util::DestroyHelperForTests> cache(new FileCache(
-      base::FilePath::FromUTF8Unsafe("/somewhere/nonexistent/blah/meta"),
-      base::FilePath::FromUTF8Unsafe("/somewhere/nonexistent/blah/files"),
-      base::MessageLoopProxy::current(),
-      NULL /* free_disk_space_getter */));
-
-  EXPECT_FALSE(cache->Initialize());
-}
-
 TEST_F(FileCacheTestOnUIThread, UpdatePinnedCache) {
   std::string resource_id("pdf:1a2b");
   std::string md5("abcdef0123456789");
@@ -896,41 +896,58 @@
 
     fake_free_disk_space_getter_.reset(new FakeFreeDiskSpaceGetter);
 
-    cache_.reset(new FileCache(
+    metadata_storage_.reset(new ResourceMetadataStorage(
         temp_dir_.path().Append(util::kMetadataDirectory),
+        base::MessageLoopProxy::current()));
+    ASSERT_TRUE(metadata_storage_->Initialize());
+
+    cache_.reset(new FileCache(
+        metadata_storage_.get(),
         temp_dir_.path().Append(util::kCacheFileDirectory),
         base::MessageLoopProxy::current(),
         fake_free_disk_space_getter_.get()));
-
     ASSERT_TRUE(cache_->Initialize());
   }
 
-  virtual void TearDown() OVERRIDE {
-    cache_.reset();
+  static bool ImportOldDB(FileCache* cache, const base::FilePath& old_db_path) {
+    return cache->ImportOldDB(old_db_path);
   }
 
   content::TestBrowserThreadBundle thread_bundle_;
   base::ScopedTempDir temp_dir_;
 
+  scoped_ptr<ResourceMetadataStorage, test_util::DestroyHelperForTests>
+      metadata_storage_;
   scoped_ptr<FileCache, test_util::DestroyHelperForTests> cache_;
   scoped_ptr<FakeFreeDiskSpaceGetter> fake_free_disk_space_getter_;
 };
 
 TEST_F(FileCacheTest, ScanCacheFile) {
   // Set up files in the cache directory.
-  const base::FilePath directory =
+  const base::FilePath file_directory =
       temp_dir_.path().Append(util::kCacheFileDirectory);
   ASSERT_TRUE(google_apis::test_util::WriteStringToFile(
-      directory.AppendASCII("id_foo.md5foo"), "foo"));
+      file_directory.AppendASCII("id_foo.md5foo"), "foo"));
   ASSERT_TRUE(google_apis::test_util::WriteStringToFile(
-      directory.AppendASCII("id_bar.local"), "bar"));
+      file_directory.AppendASCII("id_bar.local"), "bar"));
 
   // Remove the existing DB.
-  ASSERT_TRUE(file_util::Delete(
-      temp_dir_.path().Append(util::kMetadataDirectory), true /* recursive */));
+  const base::FilePath metadata_directory =
+      temp_dir_.path().Append(util::kMetadataDirectory);
+  ASSERT_TRUE(base::Delete(metadata_directory, true /* recursive */));
+
+  // Put an empty file with the same name as old DB.
+  // This file cannot be opened by ImportOldDB() and will be dismissed.
+  ASSERT_TRUE(file_util::CreateDirectory(metadata_directory));
+  ASSERT_TRUE(google_apis::test_util::WriteStringToFile(
+      metadata_directory.Append(FileCache::kOldCacheMetadataDBName), ""));
 
   // Create a new cache and initialize it.
-  cache_.reset(new FileCache(temp_dir_.path().Append(util::kMetadataDirectory),
+  metadata_storage_.reset(new ResourceMetadataStorage(
+      metadata_directory, base::MessageLoopProxy::current()));
+  ASSERT_TRUE(metadata_storage_->Initialize());
+
+  cache_.reset(new FileCache(metadata_storage_.get(),
                              temp_dir_.path().Append(util::kCacheFileDirectory),
                              base::MessageLoopProxy::current(),
                              fake_free_disk_space_getter_.get()));
@@ -989,5 +1006,41 @@
   EXPECT_FALSE(cache_->FreeDiskSpaceIfNeededFor(kNeededBytes));
 }
 
+TEST_F(FileCacheTest, ImportOldDB) {
+  const base::FilePath old_db_path = temp_dir_.path().AppendASCII("old_db.db");
+
+  const std::string key1 = "key1";
+  const std::string md5_1 = "md5_1";
+  const std::string key2 = "key2";
+  const std::string md5_2 = "md5_2";
+
+  // Set up data to be imported.
+  {
+    FileCacheMetadata old_metadata(NULL);
+    ASSERT_TRUE(old_metadata.Initialize(old_db_path));
+
+    FileCacheEntry entry;
+    entry.set_md5(md5_1);
+    old_metadata.AddOrUpdateCacheEntry(key1, entry);
+
+    entry.set_md5(md5_2);
+    old_metadata.AddOrUpdateCacheEntry(key2, entry);
+  }
+  EXPECT_TRUE(file_util::PathExists(old_db_path));
+
+  // Do import.
+  EXPECT_TRUE(ImportOldDB(cache_.get(), old_db_path));
+
+  // Old DB should be removed.
+  EXPECT_FALSE(file_util::PathExists(old_db_path));
+
+  // Data is imported correctly.
+  FileCacheEntry entry;
+  EXPECT_TRUE(cache_->GetCacheEntry(key1, std::string(), &entry));
+  EXPECT_EQ(md5_1, entry.md5());
+  EXPECT_TRUE(cache_->GetCacheEntry(key2, std::string(), &entry));
+  EXPECT_EQ(md5_2, entry.md5());
+}
+
 }  // namespace internal
 }  // namespace drive
diff --git a/chrome/browser/chromeos/drive/file_change_unittest.cc b/chrome/browser/chromeos/drive/file_change_unittest.cc
index 619f37f..97eead4 100644
--- a/chrome/browser/chromeos/drive/file_change_unittest.cc
+++ b/chrome/browser/chromeos/drive/file_change_unittest.cc
@@ -3,7 +3,8 @@
 // found in the LICENSE file.
 
 #include "chrome/browser/chromeos/drive/file_change.h"
-#include "testing/gmock/include/gmock/gmock.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
 
 namespace drive {
 
diff --git a/chrome/browser/chromeos/drive/file_system.cc b/chrome/browser/chromeos/drive/file_system.cc
index d24fbf6..53c2e9d 100644
--- a/chrome/browser/chromeos/drive/file_system.cc
+++ b/chrome/browser/chromeos/drive/file_system.cc
@@ -24,6 +24,7 @@
 #include "chrome/browser/chromeos/drive/file_system/remove_operation.h"
 #include "chrome/browser/chromeos/drive/file_system/search_operation.h"
 #include "chrome/browser/chromeos/drive/file_system/touch_operation.h"
+#include "chrome/browser/chromeos/drive/file_system/truncate_operation.h"
 #include "chrome/browser/chromeos/drive/file_system/update_operation.h"
 #include "chrome/browser/chromeos/drive/file_system_observer.h"
 #include "chrome/browser/chromeos/drive/file_system_util.h"
@@ -31,9 +32,9 @@
 #include "chrome/browser/chromeos/drive/remove_stale_cache_files.h"
 #include "chrome/browser/chromeos/drive/search_metadata.h"
 #include "chrome/browser/chromeos/drive/sync_client.h"
+#include "chrome/browser/drive/drive_api_util.h"
 #include "chrome/browser/drive/drive_service_interface.h"
 #include "chrome/browser/google_apis/drive_api_parser.h"
-#include "chrome/browser/google_apis/drive_api_util.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/pref_names.h"
 #include "content/public/browser/browser_thread.h"
@@ -72,7 +73,7 @@
 FileSystem::FileSystem(
     Profile* profile,
     internal::FileCache* cache,
-    google_apis::DriveServiceInterface* drive_service,
+    DriveServiceInterface* drive_service,
     JobScheduler* scheduler,
     internal::ResourceMetadata* resource_metadata,
     base::SequencedTaskRunner* blocking_task_runner,
@@ -129,6 +130,13 @@
                                        cache_));
   touch_operation_.reset(new file_system::TouchOperation(
       blocking_task_runner_.get(), observer, scheduler_, resource_metadata_));
+  truncate_operation_.reset(
+      new file_system::TruncateOperation(blocking_task_runner_.get(),
+                                         observer,
+                                         scheduler_,
+                                         resource_metadata_,
+                                         cache_,
+                                         temporary_file_directory_));
   download_operation_.reset(
       new file_system::DownloadOperation(blocking_task_runner_.get(),
                                          observer,
@@ -343,6 +351,14 @@
       file_path, last_access_time, last_modified_time, callback);
 }
 
+void FileSystem::TruncateFile(const base::FilePath& file_path,
+                              int64 length,
+                              const FileOperationCallback& callback) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  DCHECK(!callback.is_null());
+  truncate_operation_->Truncate(file_path, length, callback);
+}
+
 void FileSystem::Pin(const base::FilePath& file_path,
                      const FileOperationCallback& callback) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
@@ -564,7 +580,7 @@
 
 void FileSystem::ReadDirectoryByPath(
     const base::FilePath& directory_path,
-    const ReadDirectoryWithSettingCallback& callback) {
+    const ReadDirectoryCallback& callback) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   DCHECK(!callback.is_null());
 
@@ -624,17 +640,13 @@
 
 void FileSystem::ReadDirectoryByPathAfterLoad(
     const base::FilePath& directory_path,
-    const ReadDirectoryWithSettingCallback& callback,
+    const ReadDirectoryCallback& callback,
     FileError error) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   DCHECK(!callback.is_null());
 
-  if (error != FILE_ERROR_OK) {
-    callback.Run(error,
-                 hide_hosted_docs_,
-                 scoped_ptr<ResourceEntryVector>());
-    return;
-  }
+  DLOG_IF(INFO, error != FILE_ERROR_OK) << "LoadIfNeeded failed. "
+                                        << FileErrorToString(error);
 
   resource_metadata_->ReadDirectoryByPathOnUIThread(
       directory_path,
@@ -644,7 +656,7 @@
 }
 
 void FileSystem::ReadDirectoryByPathAfterRead(
-    const ReadDirectoryWithSettingCallback& callback,
+    const ReadDirectoryCallback& callback,
     FileError error,
     scoped_ptr<ResourceEntryVector> entries) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
@@ -652,13 +664,21 @@
 
   if (error != FILE_ERROR_OK) {
     callback.Run(error,
-                 hide_hosted_docs_,
                  scoped_ptr<ResourceEntryVector>());
     return;
   }
   DCHECK(entries.get());  // This is valid for empty directories too.
 
-  callback.Run(FILE_ERROR_OK, hide_hosted_docs_, entries.Pass());
+  // TODO(satorux): Stop handling hide_hosted_docs_ here. crbug.com/256520.
+  scoped_ptr<ResourceEntryVector> filtered(new ResourceEntryVector);
+  for (size_t i = 0; i < entries->size(); ++i) {
+    if (hide_hosted_docs_ &&
+        entries->at(i).file_specific_info().is_hosted_document()) {
+      continue;
+    }
+    filtered->push_back(entries->at(i));
+  }
+  callback.Run(FILE_ERROR_OK, filtered.Pass());
 }
 
 void FileSystem::RefreshDirectory(
diff --git a/chrome/browser/chromeos/drive/file_system.h b/chrome/browser/chromeos/drive/file_system.h
index d3f7c8d..6ed4e52 100644
--- a/chrome/browser/chromeos/drive/file_system.h
+++ b/chrome/browser/chromeos/drive/file_system.h
@@ -26,12 +26,12 @@
 
 namespace google_apis {
 class AboutResource;
-class DriveServiceInterface;
 class ResourceEntry;
 }
 
 namespace drive {
 
+class DriveServiceInterface;
 class FileCacheEntry;
 class FileSystemObserver;
 class JobScheduler;
@@ -52,6 +52,7 @@
 class RemoveOperation;
 class SearchOperation;
 class TouchOperation;
+class TruncateOperation;
 class UpdateOperation;
 }  // namespace file_system
 
@@ -62,7 +63,7 @@
  public:
   FileSystem(Profile* profile,
              internal::FileCache* cache,
-             google_apis::DriveServiceInterface* drive_service,
+             DriveServiceInterface* drive_service,
              JobScheduler* scheduler,
              internal::ResourceMetadata* resource_metadata,
              base::SequencedTaskRunner* blocking_task_runner,
@@ -116,6 +117,9 @@
                          const base::Time& last_access_time,
                          const base::Time& last_modified_time,
                          const FileOperationCallback& callback) OVERRIDE;
+  virtual void TruncateFile(const base::FilePath& file_path,
+                            int64 length,
+                            const FileOperationCallback& callback) OVERRIDE;
   virtual void Pin(const base::FilePath& file_path,
                    const FileOperationCallback& callback) OVERRIDE;
   virtual void Unpin(const base::FilePath& file_path,
@@ -141,7 +145,7 @@
       const GetResourceEntryCallback& callback) OVERRIDE;
   virtual void ReadDirectoryByPath(
       const base::FilePath& directory_path,
-      const ReadDirectoryWithSettingCallback& callback) OVERRIDE;
+      const ReadDirectoryCallback& callback) OVERRIDE;
   virtual void RefreshDirectory(
       const base::FilePath& directory_path,
       const FileOperationCallback& callback) OVERRIDE;
@@ -301,10 +305,10 @@
   // |callback| must not be null.
   void ReadDirectoryByPathAfterLoad(
       const base::FilePath& directory_path,
-      const ReadDirectoryWithSettingCallback& callback,
+      const ReadDirectoryCallback& callback,
       FileError error);
   void ReadDirectoryByPathAfterRead(
-      const ReadDirectoryWithSettingCallback& callback,
+      const ReadDirectoryCallback& callback,
       FileError error,
       scoped_ptr<ResourceEntryVector> entries);
 
@@ -358,7 +362,7 @@
 
   // Sub components owned by DriveIntegrationService.
   internal::FileCache* cache_;
-  google_apis::DriveServiceInterface* drive_service_;
+  DriveServiceInterface* drive_service_;
   JobScheduler* scheduler_;
   internal::ResourceMetadata* resource_metadata_;
 
@@ -394,13 +398,11 @@
   scoped_ptr<file_system::MoveOperation> move_operation_;
   scoped_ptr<file_system::RemoveOperation> remove_operation_;
   scoped_ptr<file_system::TouchOperation> touch_operation_;
+  scoped_ptr<file_system::TruncateOperation> truncate_operation_;
   scoped_ptr<file_system::DownloadOperation> download_operation_;
   scoped_ptr<file_system::UpdateOperation> update_operation_;
   scoped_ptr<file_system::SearchOperation> search_operation_;
 
-  // Polling interval for checking updates in seconds.
-  int polling_interval_sec_;
-
   // Note: This should remain the last member so it'll be destroyed and
   // invalidate the weak pointers before any other members are destroyed.
   base::WeakPtrFactory<FileSystem> weak_ptr_factory_;
diff --git a/chrome/browser/chromeos/drive/file_system/copy_operation.cc b/chrome/browser/chromeos/drive/file_system/copy_operation.cc
index 3c16ab1..72d6e07 100644
--- a/chrome/browser/chromeos/drive/file_system/copy_operation.cc
+++ b/chrome/browser/chromeos/drive/file_system/copy_operation.cc
@@ -17,7 +17,7 @@
 #include "chrome/browser/chromeos/drive/file_system_util.h"
 #include "chrome/browser/chromeos/drive/job_scheduler.h"
 #include "chrome/browser/chromeos/drive/resource_entry_conversion.h"
-#include "chrome/browser/google_apis/drive_api_util.h"
+#include "chrome/browser/drive/drive_api_util.h"
 #include "content/public/browser/browser_thread.h"
 
 using content::BrowserThread;
@@ -56,7 +56,7 @@
                              JobScheduler* scheduler,
                              internal::ResourceMetadata* metadata,
                              internal::FileCache* cache,
-                             google_apis::DriveServiceInterface* drive_service,
+                             DriveServiceInterface* drive_service,
                              const base::FilePath& temporary_file_directory)
   : blocking_task_runner_(blocking_task_runner),
     observer_(observer),
@@ -327,7 +327,7 @@
   }
 
   // If Drive API v2 is enabled, we can copy resources on server side.
-  if (google_apis::util::IsDriveV2ApiEnabled()) {
+  if (util::IsDriveV2ApiEnabled()) {
     base::FilePath new_name = dest_file_path.BaseName();
     if (src_file_proto->file_specific_info().is_hosted_document()) {
       // Drop the document extension, which should not be in the title.
diff --git a/chrome/browser/chromeos/drive/file_system/copy_operation.h b/chrome/browser/chromeos/drive/file_system/copy_operation.h
index b8db1c3..9ba481d 100644
--- a/chrome/browser/chromeos/drive/file_system/copy_operation.h
+++ b/chrome/browser/chromeos/drive/file_system/copy_operation.h
@@ -18,12 +18,12 @@
 }  // namespace base
 
 namespace google_apis {
-class DriveServiceInterface;
 class ResourceEntry;
 }  // namespace google_apis
 
 namespace drive {
 
+class DriveServiceInterface;
 class JobScheduler;
 class ResourceEntry;
 
@@ -48,7 +48,7 @@
                 JobScheduler* scheduler,
                 internal::ResourceMetadata* metadata,
                 internal::FileCache* cache,
-                google_apis::DriveServiceInterface* drive_service,
+                DriveServiceInterface* drive_service,
                 const base::FilePath& temporary_file_directory);
   ~CopyOperation();
 
@@ -179,7 +179,7 @@
   JobScheduler* scheduler_;
   internal::ResourceMetadata* metadata_;
   internal::FileCache* cache_;
-  google_apis::DriveServiceInterface* drive_service_;
+  DriveServiceInterface* drive_service_;
 
   // Uploading a new file is internally implemented by creating a dirty file.
   scoped_ptr<CreateFileOperation> create_file_operation_;
diff --git a/chrome/browser/chromeos/drive/file_system/create_directory_operation.cc b/chrome/browser/chromeos/drive/file_system/create_directory_operation.cc
index 7cd5a0d..89a7d60 100644
--- a/chrome/browser/chromeos/drive/file_system/create_directory_operation.cc
+++ b/chrome/browser/chromeos/drive/file_system/create_directory_operation.cc
@@ -239,7 +239,7 @@
     return;
   }
 
-  // Create descendent directories.
+  // Create descendant directories.
   CreateDirectoryRecursively(resource_id, remaining_path, callback);
 }
 
diff --git a/chrome/browser/chromeos/drive/file_system/download_operation.cc b/chrome/browser/chromeos/drive/file_system/download_operation.cc
index e787ec0..754bb46 100644
--- a/chrome/browser/chromeos/drive/file_system/download_operation.cc
+++ b/chrome/browser/chromeos/drive/file_system/download_operation.cc
@@ -14,7 +14,6 @@
 #include "chrome/browser/chromeos/drive/file_system/operation_observer.h"
 #include "chrome/browser/chromeos/drive/file_system_util.h"
 #include "chrome/browser/chromeos/drive/job_scheduler.h"
-#include "chrome/browser/chromeos/drive/resource_entry_conversion.h"
 #include "chrome/browser/chromeos/drive/resource_metadata.h"
 #include "chrome/browser/google_apis/gdata_errorcode.h"
 #include "content/public/browser/browser_thread.h"
@@ -97,15 +96,17 @@
 }
 
 // Calls CheckPreConditionForEnsureFileDownloaded() with the entry specified by
-// the given ID.
+// the given ID. Also fills |drive_file_path| with the path of the entry.
 FileError CheckPreConditionForEnsureFileDownloadedByResourceId(
     internal::ResourceMetadata* metadata,
     internal::FileCache* cache,
     const std::string& resource_id,
     const base::FilePath& temporary_file_directory,
+    base::FilePath* drive_file_path,
     base::FilePath* cache_file_path,
     ResourceEntry* entry) {
   FileError error = metadata->GetResourceEntryById(resource_id, entry);
+  *drive_file_path = metadata->GetFilePath(resource_id);
   if (error != FILE_ERROR_OK)
     return error;
   return CheckPreConditionForEnsureFileDownloaded(
@@ -145,44 +146,22 @@
       file_util::FILE_PERMISSION_READ_BY_OTHERS);
 }
 
-// Prepares for downloading the file. Given the |gdata_entry|, refreshes the
-// |metadata| and then allocates the enough space in the cache.
-// If succeeded, returns FILE_ERROR_OK with |entry| storing the ResourceEntry
-// of the resource, |drive_file_path| with storing the path of the entry,
-// and |temp_download_file| storing the path to the file in the cache.
-FileError PrepareForDownloadFile(
-    internal::ResourceMetadata* metadata,
-    internal::FileCache* cache,
-    scoped_ptr<google_apis::ResourceEntry> gdata_entry,
-    const base::FilePath& temporary_file_directory,
-    ResourceEntry* entry,
-    base::FilePath* drive_file_path,
-    base::FilePath* temp_download_file) {
-  DCHECK(metadata);
+// Prepares for downloading the file. Given the |resource_id|, allocates the
+// enough space for the file in the cache.
+// If succeeded, returns FILE_ERROR_OK with |temp_download_file| storing the
+// path to the file in the cache.
+FileError PrepareForDownloadFile(internal::FileCache* cache,
+                                 int64 expected_file_size,
+                                 const base::FilePath& temporary_file_directory,
+                                 base::FilePath* temp_download_file) {
   DCHECK(cache);
-  DCHECK(gdata_entry);
-  DCHECK(entry);
-  DCHECK(drive_file_path);
   DCHECK(temp_download_file);
 
-  *entry = ConvertToResourceEntry(*gdata_entry);
-  FileError error = metadata->RefreshEntry(*entry);
-  if (error != FILE_ERROR_OK)
-    return error;
-
-  error = metadata->GetResourceEntryById(entry->resource_id(), entry);
-  if (error != FILE_ERROR_OK)
-    return error;
-
-  *drive_file_path = metadata->GetFilePath(entry->resource_id());
-  if (drive_file_path->empty())
-    return FILE_ERROR_NOT_FOUND;
-
   // Ensure enough space in the cache.
-  if (!cache->FreeDiskSpaceIfNeededFor(entry->file_info().size()))
+  if (!cache->FreeDiskSpaceIfNeededFor(expected_file_size))
     return FILE_ERROR_NO_SPACE;
 
-  // Create the temporary file which will store the donwloaded content.
+  // Create the temporary file which will store the downloaded content.
   return CreateTemporaryReadableFileInDir(
       temporary_file_directory,
       temp_download_file) ? FILE_ERROR_OK : FILE_ERROR_FAILED;
@@ -203,7 +182,7 @@
 
   FileError error = util::GDataToFileError(gdata_error);
   if (error != FILE_ERROR_OK) {
-    file_util::Delete(downloaded_file_path, false /* recursive */);
+    base::Delete(downloaded_file_path, false /* recursive */);
     return error;
   }
 
@@ -211,7 +190,7 @@
   error = cache->Store(resource_id, md5, downloaded_file_path,
                        internal::FileCache::FILE_OPERATION_MOVE);
   if (error != FILE_ERROR_OK) {
-    file_util::Delete(downloaded_file_path, false /* recursive */);
+    base::Delete(downloaded_file_path, false /* recursive */);
     return error;
   }
 
@@ -275,21 +254,6 @@
   // This class is copiable.
 };
 
-struct DownloadOperation::DownloadParams {
-  DownloadParams(const ClientContext& context,
-                 const GURL& download_url)
-      : context(context),
-        download_url(download_url),
-        entry(new ResourceEntry) {
-  }
-
-  ClientContext context;
-  GURL download_url;
-  scoped_ptr<ResourceEntry> entry;
-  base::FilePath drive_file_path;
-  base::FilePath temp_download_file_path;
-};
-
 DownloadOperation::DownloadOperation(
     base::SequencedTaskRunner* blocking_task_runner,
     OperationObserver* observer,
@@ -321,8 +285,9 @@
   DownloadCallback callback(
       initialized_callback, get_content_callback, completion_callback);
 
-  ResourceEntry* entry = new ResourceEntry;
+  base::FilePath* drive_file_path = new base::FilePath;
   base::FilePath* cache_file_path = new base::FilePath;
+  ResourceEntry* entry = new ResourceEntry;
   base::PostTaskAndReplyWithResult(
       blocking_task_runner_.get(),
       FROM_HERE,
@@ -331,13 +296,15 @@
                  base::Unretained(cache_),
                  resource_id,
                  temporary_file_directory_,
+                 drive_file_path,
                  cache_file_path,
                  entry),
       base::Bind(&DownloadOperation::EnsureFileDownloadedAfterCheckPreCondition,
                  weak_ptr_factory_.GetWeakPtr(),
-                 context,
                  callback,
+                 context,
                  base::Passed(make_scoped_ptr(entry)),
+                 base::Owned(drive_file_path),
                  base::Owned(cache_file_path)));
 }
 
@@ -353,8 +320,9 @@
   DownloadCallback callback(
       initialized_callback, get_content_callback, completion_callback);
 
-  ResourceEntry* entry = new ResourceEntry;
+  base::FilePath* drive_file_path = new base::FilePath(file_path);
   base::FilePath* cache_file_path = new base::FilePath;
+  ResourceEntry* entry = new ResourceEntry;
   base::PostTaskAndReplyWithResult(
       blocking_task_runner_.get(),
       FROM_HERE,
@@ -367,20 +335,23 @@
                  entry),
       base::Bind(&DownloadOperation::EnsureFileDownloadedAfterCheckPreCondition,
                  weak_ptr_factory_.GetWeakPtr(),
-                 context,
                  callback,
+                 context,
                  base::Passed(make_scoped_ptr(entry)),
+                 base::Owned(drive_file_path),
                  base::Owned(cache_file_path)));
 }
 
 void DownloadOperation::EnsureFileDownloadedAfterCheckPreCondition(
-    const ClientContext& context,
     const DownloadCallback& callback,
+    const ClientContext& context,
     scoped_ptr<ResourceEntry> entry,
+    base::FilePath* drive_file_path,
     base::FilePath* cache_file_path,
     FileError error) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   DCHECK(entry);
+  DCHECK(drive_file_path);
   DCHECK(cache_file_path);
 
   if (error != FILE_ERROR_OK) {
@@ -397,94 +368,56 @@
   }
 
   // If cache file is not found, try to download the file from the server
-  // instead. This logic is rather complicated but here's how this works:
-  //
-  // Retrieve fresh file metadata from server. We will extract file size and
-  // download url from there. Note that the download url is transient.
-  //
-  // Check if we have enough space, based on the expected file size.
+  // instead. Check if we have enough space, based on the expected file size.
   // - if we don't have enough space, try to free up the disk space
   // - if we still don't have enough space, return "no space" error
   // - if we have enough space, start downloading the file from the server
-  scheduler_->GetResourceEntry(
-      entry->resource_id(),
-      context,
-      base::Bind(&DownloadOperation::EnsureFileDownloadedAfterGetResourceEntry,
-                 weak_ptr_factory_.GetWeakPtr(),
-                 context,
-                 callback));
-}
-
-void DownloadOperation::EnsureFileDownloadedAfterGetResourceEntry(
-    const ClientContext& context,
-    const DownloadCallback& callback,
-    google_apis::GDataErrorCode gdata_error,
-    scoped_ptr<google_apis::ResourceEntry> resource_entry) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
-  FileError error = util::GDataToFileError(gdata_error);
-  if (error != FILE_ERROR_OK) {
-    callback.OnError(error);
-    return;
-  }
-  DCHECK(resource_entry);
-
-  // The download URL is:
-  // 1) src attribute of content element, on GData WAPI.
-  // 2) the value of the key 'downloadUrl', on Drive API v2.
-  // In both cases, we can use ResourceEntry::download_url().
-  const GURL& download_url = resource_entry->download_url();
-
-  // The download URL can be empty for non-downloadable files (such as files
-  // shared from others with "prevent downloading by viewers" flag set.)
-  if (download_url.is_empty()) {
-    callback.OnError(FILE_ERROR_ACCESS_DENIED);
-    return;
-  }
-
-  // Before starting to download actually, refresh the metadata and allocate
-  // the cache space.
-  DownloadParams* params = new DownloadParams(context, download_url);
+  int64 size = entry->file_info().size();
+  base::FilePath* temp_download_file_path = new base::FilePath;
   base::PostTaskAndReplyWithResult(
       blocking_task_runner_.get(),
       FROM_HERE,
       base::Bind(&PrepareForDownloadFile,
-                 base::Unretained(metadata_),
                  base::Unretained(cache_),
-                 base::Passed(&resource_entry),
+                 size,
                  temporary_file_directory_,
-                 params->entry.get(),
-                 &params->drive_file_path,
-                 &params->temp_download_file_path),
+                 temp_download_file_path),
       base::Bind(
           &DownloadOperation::EnsureFileDownloadedAfterPrepareForDownloadFile,
           weak_ptr_factory_.GetWeakPtr(),
-          base::Owned(params),
-          callback));
+          callback,
+          context,
+          base::Passed(&entry),
+          *drive_file_path,
+          base::Owned(temp_download_file_path)));
 }
 
 void DownloadOperation::EnsureFileDownloadedAfterPrepareForDownloadFile(
-    DownloadParams* params,
     const DownloadCallback& callback,
+    const ClientContext& context,
+    scoped_ptr<ResourceEntry> entry,
+    const base::FilePath& drive_file_path,
+    base::FilePath* temp_download_file_path,
     FileError error) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  DCHECK(params);
+  DCHECK(entry);
+  DCHECK(temp_download_file_path);
 
   if (error != FILE_ERROR_OK) {
     callback.OnError(error);
     return;
   }
 
-  ResourceEntry* entry_ptr = params->entry.get();
+  ResourceEntry* entry_ptr = entry.get();
   JobID id = scheduler_->DownloadFile(
-      params->drive_file_path,
-      params->temp_download_file_path,
-      params->download_url,
-      params->context,
+      drive_file_path,
+      *temp_download_file_path,
+      entry_ptr->resource_id(),
+      context,
       base::Bind(&DownloadOperation::EnsureFileDownloadedAfterDownloadFile,
                  weak_ptr_factory_.GetWeakPtr(),
-                 params->drive_file_path,
-                 base::Passed(&params->entry),
+                 drive_file_path,
+                 base::Passed(&entry),
                  callback),
       callback.get_content_callback());
 
diff --git a/chrome/browser/chromeos/drive/file_system/download_operation.h b/chrome/browser/chromeos/drive/file_system/download_operation.h
index d102221..c95b809 100644
--- a/chrome/browser/chromeos/drive/file_system/download_operation.h
+++ b/chrome/browser/chromeos/drive/file_system/download_operation.h
@@ -81,31 +81,24 @@
   // Thin wrapper of Callbacks for EnsureFileDownloaded.
   class DownloadCallback;
 
-  // Parameters for JobScheduler::DownloadFile.
-  struct DownloadParams;
-
   // Part of EnsureFileDownloaded(). Called upon the completion of precondition
   // check.
   void EnsureFileDownloadedAfterCheckPreCondition(
-      const ClientContext& context,
       const DownloadCallback& callback,
+      const ClientContext& context,
       scoped_ptr<ResourceEntry> entry,
+      base::FilePath* drive_file_path,
       base::FilePath* cache_file_path,
       FileError error);
 
-  // Part of EnsureFileDownloaded(). Called upon the completion of fetching
-  // ResourceEntry from the server.
-  void EnsureFileDownloadedAfterGetResourceEntry(
-      const ClientContext& context,
-      const DownloadCallback& callback,
-      google_apis::GDataErrorCode gdata_error,
-      scoped_ptr<google_apis::ResourceEntry> resource_entry);
-
   // Part of EnsureFileDownloaded(). Called when it is ready to start
   // downloading the file.
   void EnsureFileDownloadedAfterPrepareForDownloadFile(
-      DownloadParams* params,
       const DownloadCallback& callback,
+      const ClientContext& context,
+      scoped_ptr<ResourceEntry> entry,
+      const base::FilePath& drive_file_path,
+      base::FilePath* temp_download_file_path,
       FileError error);
 
   // Part of EnsureFileDownloaded(). Called after the actual downloading.
diff --git a/chrome/browser/chromeos/drive/file_system/move_operation_unittest.cc b/chrome/browser/chromeos/drive/file_system/move_operation_unittest.cc
index a9b3cb6..22b6b62 100644
--- a/chrome/browser/chromeos/drive/file_system/move_operation_unittest.cc
+++ b/chrome/browser/chromeos/drive/file_system/move_operation_unittest.cc
@@ -18,11 +18,6 @@
    operation_.reset(new MoveOperation(observer(), scheduler(), metadata()));
  }
 
- virtual void TearDown() OVERRIDE {
-   operation_.reset();
-   OperationTestBase::TearDown();
- }
-
  scoped_ptr<MoveOperation> operation_;
 };
 
diff --git a/chrome/browser/chromeos/drive/file_system/operation_test_base.cc b/chrome/browser/chromeos/drive/file_system/operation_test_base.cc
index 43f2aae..91879c2 100644
--- a/chrome/browser/chromeos/drive/file_system/operation_test_base.cc
+++ b/chrome/browser/chromeos/drive/file_system/operation_test_base.cc
@@ -51,16 +51,28 @@
   profile_.reset(new TestingProfile);
   ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
 
-  fake_drive_service_.reset(new google_apis::FakeDriveService);
+  fake_drive_service_.reset(new FakeDriveService);
   fake_drive_service_->LoadResourceListForWapi(
-      "chromeos/gdata/root_feed.json");
+      "gdata/root_feed.json");
   fake_drive_service_->LoadAccountMetadataForWapi(
-      "chromeos/gdata/account_metadata.json");
+      "gdata/account_metadata.json");
 
-  scheduler_.reset(
-      new JobScheduler(profile_.get(), fake_drive_service_.get()));
+  scheduler_.reset(new JobScheduler(profile_.get(), fake_drive_service_.get(),
+                                    blocking_task_runner_));
 
-  metadata_.reset(new internal::ResourceMetadata(temp_dir_.path(),
+  metadata_storage_.reset(new internal::ResourceMetadataStorage(
+      temp_dir_.path(), blocking_task_runner_));
+  bool success = false;
+  base::PostTaskAndReplyWithResult(
+      blocking_task_runner_,
+      FROM_HERE,
+      base::Bind(&internal::ResourceMetadataStorage::Initialize,
+                 base::Unretained(metadata_storage_.get())),
+      google_apis::test_util::CreateCopyResultCallback(&success));
+  google_apis::test_util::RunBlockingPoolTask();
+  ASSERT_TRUE(success);
+
+  metadata_.reset(new internal::ResourceMetadata(metadata_storage_.get(),
                                                  blocking_task_runner_));
 
   FileError error = FILE_ERROR_FAILED;
@@ -74,11 +86,11 @@
   ASSERT_EQ(FILE_ERROR_OK, error);
 
   fake_free_disk_space_getter_.reset(new FakeFreeDiskSpaceGetter);
-  cache_.reset(new internal::FileCache(temp_dir_.path(),
+  cache_.reset(new internal::FileCache(metadata_storage_.get(),
                                        temp_dir_.path(),
                                        blocking_task_runner_.get(),
                                        fake_free_disk_space_getter_.get()));
-  bool success = false;
+  success = false;
   base::PostTaskAndReplyWithResult(
       blocking_task_runner_,
       FROM_HERE,
@@ -99,17 +111,6 @@
   ASSERT_EQ(FILE_ERROR_OK, error);
 }
 
-void OperationTestBase::TearDown() {
-  cache_.reset();
-  fake_free_disk_space_getter_.reset();
-  metadata_.reset();
-  scheduler_.reset();
-  fake_drive_service_.reset();
-  profile_.reset();
-
-  blocking_task_runner_ = NULL;
-}
-
 FileError OperationTestBase::GetLocalResourceEntry(const base::FilePath& path,
                                                    ResourceEntry* entry) {
   FileError error = FILE_ERROR_FAILED;
diff --git a/chrome/browser/chromeos/drive/file_system/operation_test_base.h b/chrome/browser/chromeos/drive/file_system/operation_test_base.h
index 026fae1..fd44a80 100644
--- a/chrome/browser/chromeos/drive/file_system/operation_test_base.h
+++ b/chrome/browser/chromeos/drive/file_system/operation_test_base.h
@@ -20,18 +20,16 @@
 class SequencedTaskRunner;
 }  // namespace base
 
-namespace google_apis {
-class FakeDriveService;
-}  // namespace google_apis
-
 namespace drive {
 
+class FakeDriveService;
 class FakeFreeDiskSpaceGetter;
 class JobScheduler;
 
 namespace internal {
 class FileCache;
 class ResourceMetadata;
+class ResourceMetadataStorage;
 }  // namespace internal
 
 namespace file_system {
@@ -73,7 +71,6 @@
 
   // testing::Test overrides.
   virtual void SetUp() OVERRIDE;
-  virtual void TearDown() OVERRIDE;
 
   // Returns the path of the temporary directory for putting test files.
   base::FilePath temp_dir() const { return temp_dir_.path(); }
@@ -84,7 +81,7 @@
                                   ResourceEntry* entry);
 
   // Accessors for the components.
-  google_apis::FakeDriveService* fake_service() {
+  FakeDriveService* fake_service() {
     return fake_drive_service_.get();
   }
   LoggingObserver* observer() { return &observer_; }
@@ -105,8 +102,10 @@
   base::ScopedTempDir temp_dir_;
 
   LoggingObserver observer_;
-  scoped_ptr<google_apis::FakeDriveService> fake_drive_service_;
+  scoped_ptr<FakeDriveService> fake_drive_service_;
   scoped_ptr<JobScheduler> scheduler_;
+  scoped_ptr<internal::ResourceMetadataStorage,
+             test_util::DestroyHelperForTests> metadata_storage_;
   scoped_ptr<internal::ResourceMetadata, test_util::DestroyHelperForTests>
       metadata_;
   scoped_ptr<FakeFreeDiskSpaceGetter> fake_free_disk_space_getter_;
diff --git a/chrome/browser/chromeos/drive/file_system/touch_operation.cc b/chrome/browser/chromeos/drive/file_system/touch_operation.cc
index 3226f16..2b3dff0 100644
--- a/chrome/browser/chromeos/drive/file_system/touch_operation.cc
+++ b/chrome/browser/chromeos/drive/file_system/touch_operation.cc
@@ -7,7 +7,7 @@
 #include "base/bind.h"
 #include "base/files/file_path.h"
 #include "base/sequenced_task_runner.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/chromeos/drive/file_errors.h"
 #include "chrome/browser/chromeos/drive/file_system/operation_observer.h"
 #include "chrome/browser/chromeos/drive/file_system_util.h"
diff --git a/chrome/browser/chromeos/drive/file_system/touch_operation_unittest.cc b/chrome/browser/chromeos/drive/file_system/touch_operation_unittest.cc
index 488bbb4..ff4380a 100644
--- a/chrome/browser/chromeos/drive/file_system/touch_operation_unittest.cc
+++ b/chrome/browser/chromeos/drive/file_system/touch_operation_unittest.cc
@@ -5,7 +5,7 @@
 #include "chrome/browser/chromeos/drive/file_system/touch_operation.h"
 
 #include "base/files/file_path.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/chromeos/drive/drive.pb.h"
 #include "chrome/browser/chromeos/drive/file_errors.h"
 #include "chrome/browser/chromeos/drive/file_system/operation_test_base.h"
diff --git a/chrome/browser/chromeos/drive/file_system/truncate_operation.cc b/chrome/browser/chromeos/drive/file_system/truncate_operation.cc
new file mode 100644
index 0000000..018d9a5
--- /dev/null
+++ b/chrome/browser/chromeos/drive/file_system/truncate_operation.cc
@@ -0,0 +1,169 @@
+// 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/drive/file_system/truncate_operation.h"
+
+#include "base/bind.h"
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/message_loop/message_loop_proxy.h"
+#include "base/platform_file.h"
+#include "base/sequenced_task_runner.h"
+#include "base/task_runner_util.h"
+#include "chrome/browser/chromeos/drive/drive.pb.h"
+#include "chrome/browser/chromeos/drive/file_cache.h"
+#include "chrome/browser/chromeos/drive/file_errors.h"
+#include "chrome/browser/chromeos/drive/file_system/download_operation.h"
+#include "chrome/browser/chromeos/drive/file_system/operation_observer.h"
+#include "content/public/browser/browser_thread.h"
+
+using content::BrowserThread;
+
+namespace drive {
+namespace file_system {
+namespace {
+
+// Automatically closes |platform_file| given via the constructor when
+// the instance is destroyed.
+class ScopedPlatformFileCloser {
+ public:
+  // |platform_file| must not be NULL.
+  explicit ScopedPlatformFileCloser(base::PlatformFile* platform_file)
+      : platform_file_(platform_file) {
+    DCHECK(platform_file_);
+  }
+
+  ~ScopedPlatformFileCloser() {
+    base::ClosePlatformFile(*platform_file_);
+  }
+
+ private:
+  base::PlatformFile* platform_file_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedPlatformFileCloser);
+};
+
+// Truncates the local file at |local_cache_path| to the |length| bytes,
+// then marks the resource is dirty on |cache|.
+FileError TruncateOnBlockingPool(internal::FileCache* cache,
+                                 const std::string& resource_id,
+                                 const std::string& md5,
+                                 const base::FilePath& local_cache_path,
+                                 int64 length) {
+  DCHECK(cache);
+
+  base::PlatformFileError result = base::PLATFORM_FILE_ERROR_FAILED;
+  base::PlatformFile file = base::CreatePlatformFile(
+      local_cache_path,
+      base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_WRITE,
+      NULL,
+      &result);
+  if (result != base::PLATFORM_FILE_OK)
+    return FILE_ERROR_FAILED;
+
+  DCHECK_NE(base::kInvalidPlatformFileValue, file);
+  ScopedPlatformFileCloser file_closer(&file);
+
+  if (!base::TruncatePlatformFile(file, length))
+    return FILE_ERROR_FAILED;
+
+  return cache->MarkDirty(resource_id, md5);
+}
+
+}  // namespace
+
+TruncateOperation::TruncateOperation(
+    base::SequencedTaskRunner* blocking_task_runner,
+    OperationObserver* observer,
+    JobScheduler* scheduler,
+    internal::ResourceMetadata* metadata,
+    internal::FileCache* cache,
+    const base::FilePath& temporary_file_directory)
+    : blocking_task_runner_(blocking_task_runner),
+      observer_(observer),
+      cache_(cache),
+      download_operation_(new DownloadOperation(blocking_task_runner,
+                                                observer,
+                                                scheduler,
+                                                metadata,
+                                                cache,
+                                                temporary_file_directory)),
+      weak_ptr_factory_(this) {
+}
+
+TruncateOperation::~TruncateOperation() {
+}
+
+void TruncateOperation::Truncate(const base::FilePath& file_path,
+                                 int64 length,
+                                 const FileOperationCallback& callback) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+  if (length < 0) {
+    base::MessageLoopProxy::current()->PostTask(
+        FROM_HERE,
+        base::Bind(callback, FILE_ERROR_INVALID_OPERATION));
+    return;
+  }
+
+  // TODO(kinaba): http://crbug.com/132780.
+  // Optimize the cases for small |length|, at least for |length| == 0.
+  download_operation_->EnsureFileDownloadedByPath(
+      file_path,
+      ClientContext(USER_INITIATED),
+      GetFileContentInitializedCallback(),
+      google_apis::GetContentCallback(),
+      base::Bind(&TruncateOperation::TruncateAfterEnsureFileDownloadedByPath,
+                 weak_ptr_factory_.GetWeakPtr(), file_path, length, callback));
+}
+
+void TruncateOperation::TruncateAfterEnsureFileDownloadedByPath(
+    const base::FilePath& file_path,
+    int64 length,
+    const FileOperationCallback& callback,
+    FileError error,
+    const base::FilePath& local_file_path,
+    scoped_ptr<ResourceEntry> entry) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  DCHECK(!callback.is_null());
+
+  if (error != FILE_ERROR_OK) {
+    callback.Run(error);
+    return;
+  }
+  DCHECK(entry);
+  DCHECK(entry->has_file_specific_info());
+
+  if (entry->file_specific_info().is_hosted_document()) {
+    callback.Run(FILE_ERROR_INVALID_OPERATION);
+    return;
+  }
+
+  base::PostTaskAndReplyWithResult(
+      blocking_task_runner_.get(),
+      FROM_HERE,
+      base::Bind(&TruncateOnBlockingPool,
+                 base::Unretained(cache_),
+                 entry->resource_id(), entry->file_specific_info().md5(),
+                 local_file_path, length),
+      base::Bind(
+          &TruncateOperation::TruncateAfterTruncateOnBlockingPool,
+          weak_ptr_factory_.GetWeakPtr(), entry->resource_id(), callback));
+}
+
+void TruncateOperation::TruncateAfterTruncateOnBlockingPool(
+    const std::string& resource_id,
+    const FileOperationCallback& callback,
+    FileError error) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  DCHECK(!callback.is_null());
+
+  if (error == FILE_ERROR_OK)
+    observer_->OnCacheFileUploadNeededByOperation(resource_id);
+
+  callback.Run(error);
+}
+
+}  // namespace file_system
+}  // namespace drive
diff --git a/chrome/browser/chromeos/drive/file_system/truncate_operation.h b/chrome/browser/chromeos/drive/file_system/truncate_operation.h
new file mode 100644
index 0000000..39eba6b
--- /dev/null
+++ b/chrome/browser/chromeos/drive/file_system/truncate_operation.h
@@ -0,0 +1,85 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_DRIVE_FILE_SYSTEM_TRUNCATE_OPERATION_H_
+#define CHROME_BROWSER_CHROMEOS_DRIVE_FILE_SYSTEM_TRUNCATE_OPERATION_H_
+
+#include "base/basictypes.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "chrome/browser/chromeos/drive/file_errors.h"
+
+namespace base {
+class FilePath;
+class SequencedTaskRunner;
+}  // namespace base
+
+namespace drive {
+
+class JobScheduler;
+class ResourceEntry;
+
+namespace internal {
+class FileCache;
+class ResourceMetadata;
+}  // namespace internal
+
+namespace file_system {
+
+class OperationObserver;
+class DownloadOperation;
+
+// This class encapsulates the drive Truncate function. It is responsible for
+// fetching the content from the Drive server if necessary, truncating the
+// file content actually, and then notifying the file is locally modified and
+// that it is necessary to upload the file to the server.
+class TruncateOperation {
+ public:
+  TruncateOperation(base::SequencedTaskRunner* blocking_task_runner,
+                    OperationObserver* observer,
+                    JobScheduler* scheduler,
+                    internal::ResourceMetadata* metadata,
+                    internal::FileCache* cache,
+                    const base::FilePath& temporary_file_directory);
+  ~TruncateOperation();
+
+  // Performs the truncate operation on the file at drive path |file_path| to
+  // |length| bytes. Invokes |callback| when finished with the result of the
+  // operation. |callback| must not be null.
+  void Truncate(const base::FilePath& file_path,
+                int64 length,
+                const FileOperationCallback& callback);
+ private:
+  // Part of Truncate(). Called after EnsureFileDownloadedByPath() is complete.
+  void TruncateAfterEnsureFileDownloadedByPath(
+      const base::FilePath& file_path,
+      int64 length,
+      const FileOperationCallback& callback,
+      FileError error,
+      const base::FilePath& local_file_path,
+      scoped_ptr<ResourceEntry> resource_entry);
+
+  // Part of Truncate(). Called after TruncateOnBlockingPool() is complete.
+  void TruncateAfterTruncateOnBlockingPool(
+      const std::string& resource_id,
+      const FileOperationCallback& callback,
+      FileError error);
+
+  scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
+  OperationObserver* observer_;
+  internal::FileCache* cache_;
+
+  scoped_ptr<DownloadOperation> download_operation_;
+
+  // Note: This should remain the last member so it'll be destroyed and
+  // invalidate the weak pointers before any other members are destroyed.
+  base::WeakPtrFactory<TruncateOperation> weak_ptr_factory_;
+  DISALLOW_COPY_AND_ASSIGN(TruncateOperation);
+};
+
+}  // namespace file_system
+}  // namespace drive
+
+#endif  // CHROME_BROWSER_CHROMEOS_DRIVE_FILE_SYSTEM_TRUNCATE_OPERATION_H_
diff --git a/chrome/browser/chromeos/drive/file_system/truncate_operation_unittest.cc b/chrome/browser/chromeos/drive/file_system/truncate_operation_unittest.cc
new file mode 100644
index 0000000..47a7205
--- /dev/null
+++ b/chrome/browser/chromeos/drive/file_system/truncate_operation_unittest.cc
@@ -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.
+
+#include "chrome/browser/chromeos/drive/file_system/truncate_operation.h"
+
+#include "base/file_util.h"
+#include "base/files/file_path.h"
+#include "chrome/browser/chromeos/drive/drive.pb.h"
+#include "chrome/browser/chromeos/drive/fake_free_disk_space_getter.h"
+#include "chrome/browser/chromeos/drive/file_system/operation_test_base.h"
+#include "chrome/browser/google_apis/test_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace drive {
+namespace file_system {
+
+class TruncateOperationTest : public OperationTestBase {
+ protected:
+  virtual void SetUp() {
+    OperationTestBase::SetUp();
+
+    operation_.reset(new TruncateOperation(
+        blocking_task_runner(), observer(), scheduler(),
+        metadata(), cache(), temp_dir()));
+  }
+
+  scoped_ptr<TruncateOperation> operation_;
+};
+
+TEST_F(TruncateOperationTest, Truncate) {
+  base::FilePath file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt"));
+  ResourceEntry src_entry;
+  ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(file_in_root, &src_entry));
+  const int64 file_size = src_entry.file_info().size();
+
+  // Make sure the file has at least 2 bytes.
+  ASSERT_GE(file_size, 2);
+
+  FileError error = FILE_ERROR_FAILED;
+  operation_->Truncate(
+      file_in_root,
+      1,  // Truncate to 1 byte.
+      google_apis::test_util::CreateCopyResultCallback(&error));
+  google_apis::test_util::RunBlockingPoolTask();
+  EXPECT_EQ(FILE_ERROR_OK, error);
+
+  base::FilePath local_path;
+  error = FILE_ERROR_FAILED;
+  cache()->GetFileOnUIThread(
+      src_entry.resource_id(), src_entry.file_specific_info().md5(),
+      google_apis::test_util::CreateCopyResultCallback(&error, &local_path));
+  google_apis::test_util::RunBlockingPoolTask();
+  ASSERT_EQ(FILE_ERROR_OK, error);
+
+  // The local file should be truncated.
+  int64 local_file_size = 0;
+  file_util::GetFileSize(local_path, &local_file_size);
+  EXPECT_EQ(1, local_file_size);
+}
+
+TEST_F(TruncateOperationTest, NegativeSize) {
+  base::FilePath file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt"));
+  ResourceEntry src_entry;
+  ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(file_in_root, &src_entry));
+  const int64 file_size = src_entry.file_info().size();
+
+  // Make sure the file has at least 2 bytes.
+  ASSERT_GE(file_size, 2);
+
+  FileError error = FILE_ERROR_FAILED;
+  operation_->Truncate(
+      file_in_root,
+      -1,  // Truncate to "-1" byte.
+      google_apis::test_util::CreateCopyResultCallback(&error));
+  google_apis::test_util::RunBlockingPoolTask();
+  EXPECT_EQ(FILE_ERROR_INVALID_OPERATION, error);
+}
+
+TEST_F(TruncateOperationTest, HostedDocument) {
+  base::FilePath file_in_root(FILE_PATH_LITERAL(
+      "drive/root/Document 1 excludeDir-test.gdoc"));
+
+  FileError error = FILE_ERROR_FAILED;
+  operation_->Truncate(
+      file_in_root,
+      1,  // Truncate to 1 byte.
+      google_apis::test_util::CreateCopyResultCallback(&error));
+  google_apis::test_util::RunBlockingPoolTask();
+  EXPECT_EQ(FILE_ERROR_INVALID_OPERATION, error);
+}
+
+TEST_F(TruncateOperationTest, Extend) {
+  base::FilePath file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt"));
+  ResourceEntry src_entry;
+  ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(file_in_root, &src_entry));
+  const int64 file_size = src_entry.file_info().size();
+
+  FileError error = FILE_ERROR_FAILED;
+  operation_->Truncate(
+      file_in_root,
+      file_size + 10,  // Extend to 10 bytes.
+      google_apis::test_util::CreateCopyResultCallback(&error));
+  google_apis::test_util::RunBlockingPoolTask();
+  EXPECT_EQ(FILE_ERROR_OK, error);
+
+  base::FilePath local_path;
+  error = FILE_ERROR_FAILED;
+  cache()->GetFileOnUIThread(
+      src_entry.resource_id(), src_entry.file_specific_info().md5(),
+      google_apis::test_util::CreateCopyResultCallback(&error, &local_path));
+  google_apis::test_util::RunBlockingPoolTask();
+  ASSERT_EQ(FILE_ERROR_OK, error);
+
+  // The local file should be truncated.
+  std::string content;
+  ASSERT_TRUE(file_util::ReadFileToString(local_path, &content));
+
+  EXPECT_EQ(file_size + 10, static_cast<int64>(content.size()));
+  // All trailing 10 bytes should be '\0'.
+  EXPECT_EQ(std::string(10, '\0'), content.substr(file_size));
+}
+
+}  // namespace file_system
+}  // namespace drive
diff --git a/chrome/browser/chromeos/drive/file_system/update_operation_unittest.cc b/chrome/browser/chromeos/drive/file_system/update_operation_unittest.cc
index e7517ec..58ba355 100644
--- a/chrome/browser/chromeos/drive/file_system/update_operation_unittest.cc
+++ b/chrome/browser/chromeos/drive/file_system/update_operation_unittest.cc
@@ -25,11 +25,6 @@
                                         cache()));
  }
 
- virtual void TearDown() OVERRIDE {
-   operation_.reset();
-   OperationTestBase::TearDown();
- }
-
  scoped_ptr<UpdateOperation> operation_;
 };
 
diff --git a/chrome/browser/chromeos/drive/file_system_interface.h b/chrome/browser/chromeos/drive/file_system_interface.h
index 562c4af..b7d61f8 100644
--- a/chrome/browser/chromeos/drive/file_system_interface.h
+++ b/chrome/browser/chromeos/drive/file_system_interface.h
@@ -81,16 +81,6 @@
                             const base::Closure& cancel_download_closure)>
     GetFileContentInitializedCallback;
 
-// Used to read a directory from the file system.
-// Similar to ReadDirectoryCallback but this one provides
-// |hide_hosted_documents|
-// If |error| is not FILE_ERROR_OK, |entries| is set to NULL.
-// |entries| are contents, both files and directories, of the directory.
-typedef base::Callback<void(FileError error,
-                            bool hide_hosted_documents,
-                            scoped_ptr<ResourceEntryVector> entries)>
-    ReadDirectoryWithSettingCallback;
-
 // Used to get drive content search results.
 // If |error| is not FILE_ERROR_OK, |result_paths| is empty.
 typedef base::Callback<void(
@@ -259,8 +249,6 @@
   // needs to be present in in-memory representation of the file system that
   // in order to be removed.
   //
-  // TODO(satorux): is_recursive is not supported yet. crbug.com/138282
-  //
   // |callback| must not be null.
   virtual void Remove(const base::FilePath& file_path,
                       bool is_recursive,
@@ -299,6 +287,13 @@
                          const base::Time& last_modified_time,
                          const FileOperationCallback& callback) = 0;
 
+  // Truncates the file content at |file_path| to the |length|.
+  //
+  // |callback| must not be null.
+  virtual void TruncateFile(const base::FilePath& file_path,
+                            int64 length,
+                            const FileOperationCallback& callback) = 0;
+
   // Pins a file at |file_path|.
   //
   // |callback| must not be null.
@@ -375,7 +370,7 @@
   // |callback| must not be null.
   virtual void ReadDirectoryByPath(
       const base::FilePath& file_path,
-      const ReadDirectoryWithSettingCallback& callback) = 0;
+      const ReadDirectoryCallback& callback) = 0;
 
   // Refreshes the directory pointed by |file_path| (i.e. fetches the latest
   // metadata of files in the target directory).
diff --git a/chrome/browser/chromeos/drive/file_system_metadata.h b/chrome/browser/chromeos/drive/file_system_metadata.h
index 76b5a9e..4ca0c87 100644
--- a/chrome/browser/chromeos/drive/file_system_metadata.h
+++ b/chrome/browser/chromeos/drive/file_system_metadata.h
@@ -6,7 +6,7 @@
 #define CHROME_BROWSER_CHROMEOS_DRIVE_FILE_SYSTEM_METADATA_H_
 
 #include "base/basictypes.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/chromeos/drive/file_errors.h"
 
 namespace drive {
diff --git a/chrome/browser/chromeos/drive/file_system_proxy.cc b/chrome/browser/chromeos/drive/file_system_proxy.cc
index d6bb3c7..37845ab 100644
--- a/chrome/browser/chromeos/drive/file_system_proxy.cc
+++ b/chrome/browser/chromeos/drive/file_system_proxy.cc
@@ -15,6 +15,7 @@
 #include "chrome/browser/chromeos/drive/drive.pb.h"
 #include "chrome/browser/chromeos/drive/file_system_interface.h"
 #include "chrome/browser/chromeos/drive/file_system_util.h"
+#include "chrome/browser/chromeos/drive/fileapi_worker.h"
 #include "chrome/browser/chromeos/drive/webkit_file_stream_reader_impl.h"
 #include "chrome/browser/google_apis/task_util.h"
 #include "chrome/browser/google_apis/time_util.h"
@@ -36,147 +37,51 @@
 
 namespace {
 
-typedef fileapi::RemoteFileSystemProxyInterface::OpenFileCallback
-    OpenFileCallback;
-
-// Helper function to run reply on results of base::CreatePlatformFile() on
-// IO thread.
-void OnPlatformFileOpened(
-    const OpenFileCallback& callback,
+// Runs |callback| with |error|, |file| and |peer_handle|.
+void RunOpenFileCallback(
     base::ProcessHandle peer_handle,
-    base::PlatformFileError* open_error,
-    base::PlatformFile platform_file) {
-  callback.Run(*open_error, platform_file, peer_handle);
+    const fileapi::RemoteFileSystemProxyInterface::OpenFileCallback& callback,
+    base::PlatformFileError error,
+    base::PlatformFile file) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+
+  callback.Run(error, file, peer_handle);
 }
 
-// Helper function to run OpenFileCallback from
-// FileSystemProxy::OpenFile().
-void OnGetFileByPathForOpen(
-    const OpenFileCallback& callback,
-    int file_flags,
-    base::ProcessHandle peer_handle,
-    FileError file_error,
-    const base::FilePath& local_path,
-    scoped_ptr<ResourceEntry> entry) {
-  base::PlatformFileError error =
-      FileErrorToPlatformError(file_error);
-  if (error != base::PLATFORM_FILE_OK) {
-    callback.Run(error, base::kInvalidPlatformFileValue, peer_handle);
-    return;
-  }
-
-  base::PlatformFileError* open_error =
-      new base::PlatformFileError(base::PLATFORM_FILE_ERROR_FAILED);
-  base::PostTaskAndReplyWithResult(
-      BrowserThread::GetBlockingPool(),
-      FROM_HERE,
-      base::Bind(&base::CreatePlatformFile,
-                 local_path,
-                 file_flags,
-                 static_cast<bool*>(NULL),
-                 open_error),
-      base::Bind(&OnPlatformFileOpened,
-                 callback,
-                 peer_handle,
-                 base::Owned(open_error)));
-}
-
-// Helper function to run SnapshotFileCallback from
-// FileSystemProxy::CreateSnapshotFile().
-void CallSnapshotFileCallback(
-    const FileSystemOperation::SnapshotFileCallback& callback,
+// Runs |callback| with the arguments based on the given arguments.
+void RunSnapshotFileCallback(
+    const fileapi::FileSystemOperation::SnapshotFileCallback& callback,
+    base::PlatformFileError error,
     const base::PlatformFileInfo& file_info,
-    FileError file_error,
     const base::FilePath& local_path,
-    scoped_ptr<ResourceEntry> entry) {
-  scoped_refptr<ShareableFileReference> file_ref;
-  base::PlatformFileError error =
-      FileErrorToPlatformError(file_error);
+    webkit_blob::ScopedFile::ScopeOutPolicy scope_out_policy) {
+  // ShareableFileReference is thread *unsafe* class. So it is necessary to
+  // create the instance (by invoking GetOrCreate) on IO thread, though
+  // most drive file system related operations run on UI thread.
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
 
-  // If the file is a hosted document, a temporary JSON file is created to
-  // represent the document. The JSON file is not cached and its lifetime
-  // is managed by ShareableFileReference.
-  if (error == base::PLATFORM_FILE_OK &&
-      entry && entry->file_specific_info().is_hosted_document()) {
-    file_ref = ShareableFileReference::GetOrCreate(
-        local_path, ShareableFileReference::DELETE_ON_FINAL_RELEASE,
-        BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE));
-  }
-
-  // When reading file, last modified time specified in file info will be
-  // compared to the last modified time of the local version of the drive file.
-  // Since those two values don't generally match (last modification time on the
-  // drive server vs. last modification time of the local, downloaded file), so
-  // we have to opt out from this check. We do this by unsetting last_modified
-  // value in the file info passed to the CreateSnapshot caller.
-  base::PlatformFileInfo final_file_info(file_info);
-  final_file_info.last_modified = base::Time();
-
-  callback.Run(error, final_file_info, local_path, file_ref);
-}
-
-// Emits debug log when FileSystem::CloseFile() is complete.
-void EmitDebugLogForCloseFile(const base::FilePath& local_path,
-                              FileError file_error) {
-  DVLOG(1) << "Closed: " << local_path.AsUTF8Unsafe() << ": " << file_error;
-}
-
-base::PlatformFileError DoTruncateOnBlockingPool(
-    const base::FilePath& local_cache_path,
-    int64 length) {
-  base::PlatformFileError result = base::PLATFORM_FILE_ERROR_FAILED;
-
-  base::PlatformFile file = base::CreatePlatformFile(
-      local_cache_path,
-      base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_WRITE,
-      NULL,
-      &result);
-  if (result == base::PLATFORM_FILE_OK) {
-    DCHECK_NE(base::kInvalidPlatformFileValue, file);
-    if (!base::TruncatePlatformFile(file, length))
-      result = base::PLATFORM_FILE_ERROR_FAILED;
-    base::ClosePlatformFile(file);
-  }
-  return result;
-}
-
-void DidCloseFileForTruncate(
-    const FileSystemOperation::StatusCallback& callback,
-    base::PlatformFileError truncate_result,
-    FileError close_result) {
-  // Reports the first error.
-  callback.Run(truncate_result == base::PLATFORM_FILE_OK ?
-               FileErrorToPlatformError(close_result) :
-               truncate_result);
+  scoped_refptr<webkit_blob::ShareableFileReference> file_reference =
+      webkit_blob::ShareableFileReference::GetOrCreate(
+          webkit_blob::ScopedFile(
+              local_path, scope_out_policy,
+              BrowserThread::GetMessageLoopProxyForThread(
+                  BrowserThread::FILE)));
+  callback.Run(error, file_info, local_path, file_reference);
 }
 
 }  // namespace
 
-DirectoryEntry ResourceEntryToDirectoryEntry(
-    const ResourceEntry& resource_entry) {
-  base::PlatformFileInfo file_info;
-  util::ConvertResourceEntryToPlatformFileInfo(
-      resource_entry.file_info(), &file_info);
-
-  DirectoryEntry entry;
-  entry.name = resource_entry.base_name();
-  entry.is_directory = file_info.is_directory;
-  entry.size = file_info.size;
-  entry.last_modified_time = file_info.last_modified;
-  return entry;
-}
-
-// FileSystemProxy class implementation.
-
 FileSystemProxy::FileSystemProxy(
     FileSystemInterface* file_system)
-    : file_system_(file_system) {
+    : file_system_(file_system),
+      worker_(new internal::FileApiWorker(file_system)) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
 }
 
 void FileSystemProxy::DetachFromFileSystem() {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   file_system_ = NULL;
+  worker_.reset();
 }
 
 void FileSystemProxy::GetFileInfo(
@@ -194,13 +99,9 @@
   }
 
   CallFileSystemMethodOnUIThread(
-      base::Bind(&FileSystemInterface::GetResourceEntryByPath,
-                 base::Unretained(file_system_),
-                 file_path,
-                 google_apis::CreateRelayCallback(
-                     base::Bind(&FileSystemProxy::OnGetMetadata,
-                                this,
-                                callback))));
+      base::Bind(&internal::FileApiWorker::GetFileInfo,
+                 base::Unretained(worker_.get()),
+                 file_path, google_apis::CreateRelayCallback(callback)));
 }
 
 void FileSystemProxy::Copy(
@@ -219,14 +120,10 @@
   }
 
   CallFileSystemMethodOnUIThread(
-      base::Bind(&FileSystemInterface::Copy,
-                 base::Unretained(file_system_),
-                 src_file_path,
-                 dest_file_path,
-                 google_apis::CreateRelayCallback(
-                     base::Bind(&FileSystemProxy::OnStatusCallback,
-                                this,
-                                callback))));
+      base::Bind(&internal::FileApiWorker::Copy,
+                 base::Unretained(worker_.get()),
+                 src_file_path, dest_file_path,
+                 google_apis::CreateRelayCallback(callback)));
 }
 
 void FileSystemProxy::Move(
@@ -245,14 +142,10 @@
   }
 
   CallFileSystemMethodOnUIThread(
-      base::Bind(&FileSystemInterface::Move,
-                 base::Unretained(file_system_),
-                 src_file_path,
-                 dest_file_path,
-                 google_apis::CreateRelayCallback(
-                     base::Bind(&FileSystemProxy::OnStatusCallback,
-                                this,
-                                callback))));
+      base::Bind(&internal::FileApiWorker::Move,
+                 base::Unretained(worker_.get()),
+                 src_file_path, dest_file_path,
+                 google_apis::CreateRelayCallback(callback)));
 }
 
 void FileSystemProxy::ReadDirectory(
@@ -272,13 +165,9 @@
   }
 
   CallFileSystemMethodOnUIThread(
-      base::Bind(&FileSystemInterface::ReadDirectoryByPath,
-                 base::Unretained(file_system_),
-                 file_path,
-                 google_apis::CreateRelayCallback(
-                     base::Bind(&FileSystemProxy::OnReadDirectory,
-                                this,
-                                callback))));
+      base::Bind(&internal::FileApiWorker::ReadDirectory,
+                 base::Unretained(worker_.get()),
+                 file_path, google_apis::CreateRelayCallback(callback)));
 }
 
 void FileSystemProxy::Remove(
@@ -296,14 +185,10 @@
   }
 
   CallFileSystemMethodOnUIThread(
-      base::Bind(&FileSystemInterface::Remove,
-                 base::Unretained(file_system_),
-                 file_path,
-                 recursive,
-                 google_apis::CreateRelayCallback(
-                     base::Bind(&FileSystemProxy::OnStatusCallback,
-                                this,
-                                callback))));
+      base::Bind(&internal::FileApiWorker::Remove,
+                 base::Unretained(worker_.get()),
+                 file_path, recursive,
+                 google_apis::CreateRelayCallback(callback)));
 }
 
 void FileSystemProxy::CreateDirectory(
@@ -322,15 +207,10 @@
   }
 
   CallFileSystemMethodOnUIThread(
-      base::Bind(&FileSystemInterface::CreateDirectory,
-                 base::Unretained(file_system_),
-                 file_path,
-                 exclusive,
-                 recursive,
-                 google_apis::CreateRelayCallback(
-                     base::Bind(&FileSystemProxy::OnStatusCallback,
-                                this,
-                                callback))));
+      base::Bind(&internal::FileApiWorker::CreateDirectory,
+                 base::Unretained(worker_.get()),
+                 file_path, exclusive, recursive,
+                 google_apis::CreateRelayCallback(callback)));
 }
 
 void FileSystemProxy::CreateFile(
@@ -348,14 +228,10 @@
   }
 
   CallFileSystemMethodOnUIThread(
-      base::Bind(&FileSystemInterface::CreateFile,
-                 base::Unretained(file_system_),
-                 file_path,
-                 exclusive,
-                 google_apis::CreateRelayCallback(
-                     base::Bind(&FileSystemProxy::OnStatusCallback,
-                                this,
-                                callback))));
+      base::Bind(&internal::FileApiWorker::CreateFile,
+                 base::Unretained(worker_.get()),
+                 file_path, exclusive,
+                 google_apis::CreateRelayCallback(callback)));
 }
 
 void FileSystemProxy::Truncate(
@@ -364,13 +240,6 @@
     const FileSystemOperation::StatusCallback& callback) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
 
-  if (length < 0) {
-    MessageLoopProxy::current()->PostTask(
-        FROM_HERE,
-        base::Bind(callback, base::PLATFORM_FILE_ERROR_INVALID_OPERATION));
-    return;
-  }
-
   base::FilePath file_path;
   if (!ValidateUrl(file_url, &file_path)) {
     MessageLoopProxy::current()->PostTask(
@@ -379,133 +248,11 @@
     return;
   }
 
-  // TODO(kinaba): http://crbug.com/132780.
-  // Optimize the cases for small |length|, at least for |length| == 0.
-  // CreateWritableSnapshotFile downloads the whole content unnecessarily.
   CallFileSystemMethodOnUIThread(
-      base::Bind(&FileSystemInterface::OpenFile,
-                 base::Unretained(file_system_),
-                 file_path,
-                 google_apis::CreateRelayCallback(
-                     base::Bind(&FileSystemProxy::OnFileOpenedForTruncate,
-                                this,
-                                file_path,
-                                length,
-                                callback))));
-}
-
-void FileSystemProxy::OnOpenFileForWriting(
-    int file_flags,
-    base::ProcessHandle peer_handle,
-    const OpenFileCallback& callback,
-    FileError file_error,
-    const base::FilePath& local_cache_path) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-
-  base::PlatformFileError error =
-      FileErrorToPlatformError(file_error);
-
-  if (error != base::PLATFORM_FILE_OK) {
-    callback.Run(error, base::kInvalidPlatformFileValue, peer_handle);
-    return;
-  }
-
-  // Cache file prepared for modification is available. Truncate it.
-  base::PlatformFileError* result =
-      new base::PlatformFileError(base::PLATFORM_FILE_ERROR_FAILED);
-  bool posted = base::PostTaskAndReplyWithResult(
-      BrowserThread::GetBlockingPool(), FROM_HERE,
-      base::Bind(&base::CreatePlatformFile,
-                 local_cache_path,
-                 file_flags,
-                 static_cast<bool*>(NULL),
-                 result),
-      base::Bind(&OnPlatformFileOpened,
-                 callback,
-                 peer_handle,
-                 base::Owned(result)));
-  DCHECK(posted);
-}
-
-void FileSystemProxy::OnCreateFileForOpen(
-    const base::FilePath& file_path,
-    int file_flags,
-    base::ProcessHandle peer_handle,
-    const OpenFileCallback& callback,
-    FileError file_error) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-  base::PlatformFileError create_result =
-      FileErrorToPlatformError(file_error);
-
-  if ((create_result == base::PLATFORM_FILE_OK) ||
-      ((create_result == base::PLATFORM_FILE_ERROR_EXISTS) &&
-       (file_flags & base::PLATFORM_FILE_CREATE_ALWAYS))) {
-    // If we are trying to always create an existing file, then
-    // if it really exists open it as truncated.
-    file_flags &= ~base::PLATFORM_FILE_CREATE;
-    file_flags &= ~base::PLATFORM_FILE_CREATE_ALWAYS;
-    file_flags |= base::PLATFORM_FILE_OPEN_TRUNCATED;
-  } else {
-    callback.Run(create_result, base::kInvalidPlatformFileValue, peer_handle);
-    return;
-  }
-
-  // Open created (or existing) file for writing.
-  CallFileSystemMethodOnUIThread(
-      base::Bind(&FileSystemInterface::OpenFile,
-                 base::Unretained(file_system_),
-                 file_path,
-                 google_apis::CreateRelayCallback(
-                     base::Bind(&FileSystemProxy::OnOpenFileForWriting,
-                                this,
-                                file_flags,
-                                peer_handle,
-                                callback))));
-}
-
-void FileSystemProxy::OnFileOpenedForTruncate(
-    const base::FilePath& virtual_path,
-    int64 length,
-    const fileapi::FileSystemOperation::StatusCallback& callback,
-    FileError open_result,
-    const base::FilePath& local_cache_path) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-
-  if (open_result != FILE_ERROR_OK) {
-    callback.Run(FileErrorToPlatformError(open_result));
-    return;
-  }
-
-  // Cache file prepared for modification is available. Truncate it.
-  bool posted = base::PostTaskAndReplyWithResult(
-      BrowserThread::GetBlockingPool(),
-      FROM_HERE,
-      base::Bind(&DoTruncateOnBlockingPool,
-                 local_cache_path,
-                 length),
-      base::Bind(&FileSystemProxy::DidTruncate,
-                 this,
-                 virtual_path,
-                 callback));
-  DCHECK(posted);
-}
-
-void FileSystemProxy::DidTruncate(
-    const base::FilePath& virtual_path,
-    const FileSystemOperation::StatusCallback& callback,
-    base::PlatformFileError truncate_result) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-
-  // Truncation finished. We must close the file no matter |truncate_result|
-  // indicates an error or not.
-  CallFileSystemMethodOnUIThread(
-      base::Bind(&FileSystemInterface::CloseFile,
-                 base::Unretained(file_system_),
-                 virtual_path,
-                 google_apis::CreateRelayCallback(
-                     base::Bind(&DidCloseFileForTruncate,
-                                callback,
-                                truncate_result))));
+      base::Bind(&internal::FileApiWorker::Truncate,
+                 base::Unretained(worker_.get()),
+                 file_path, length,
+                 google_apis::CreateRelayCallback(callback)));
 }
 
 void FileSystemProxy::OpenFile(
@@ -526,73 +273,12 @@
     return;
   }
 
-  // TODO(zelidrag): Wire all other file open operations.
-  if ((file_flags & base::PLATFORM_FILE_DELETE_ON_CLOSE)) {
-    NOTIMPLEMENTED() << "File create/write operations not yet supported "
-                     << file_path.value();
-    MessageLoopProxy::current()->PostTask(
-        FROM_HERE,
-        base::Bind(callback,
-                   base::PLATFORM_FILE_ERROR_FAILED,
-                   base::kInvalidPlatformFileValue,
-                   peer_handle));
-    return;
-  }
-
-  if ((file_flags & base::PLATFORM_FILE_OPEN) ||
-      (file_flags & base::PLATFORM_FILE_OPEN_ALWAYS) ||
-      (file_flags & base::PLATFORM_FILE_OPEN_TRUNCATED)) {
-    if ((file_flags & base::PLATFORM_FILE_OPEN_TRUNCATED) ||
-        (file_flags & base::PLATFORM_FILE_OPEN_ALWAYS) ||
-        (file_flags & base::PLATFORM_FILE_WRITE) ||
-        (file_flags & base::PLATFORM_FILE_EXCLUSIVE_WRITE)) {
-      // Open existing file for writing.
-      CallFileSystemMethodOnUIThread(
-          base::Bind(&FileSystemInterface::OpenFile,
-                     base::Unretained(file_system_),
-                     file_path,
-                     google_apis::CreateRelayCallback(
-                         base::Bind(&FileSystemProxy::OnOpenFileForWriting,
-                                    this,
-                                    file_flags,
-                                    peer_handle,
-                                    callback))));
-    } else {
-      // Read-only file open.
-      CallFileSystemMethodOnUIThread(
-          base::Bind(&FileSystemInterface::GetFileByPath,
-                     base::Unretained(file_system_),
-                     file_path,
-                     google_apis::CreateRelayCallback(
-                         base::Bind(&OnGetFileByPathForOpen,
-                                    callback,
-                                    file_flags,
-                                    peer_handle))));
-    }
-  } else if ((file_flags & base::PLATFORM_FILE_CREATE) ||
-             (file_flags & base::PLATFORM_FILE_CREATE_ALWAYS)) {
-    // Open existing file for writing.
-    CallFileSystemMethodOnUIThread(
-        base::Bind(&FileSystemInterface::CreateFile,
-                   base::Unretained(file_system_),
-                   file_path,
-                   file_flags & base::PLATFORM_FILE_EXCLUSIVE_WRITE,
-                   google_apis::CreateRelayCallback(
-                       base::Bind(&FileSystemProxy::OnCreateFileForOpen,
-                                  this,
-                                  file_path,
-                                  file_flags,
-                                  peer_handle,
-                                  callback))));
-  } else {
-    NOTREACHED() << "Unhandled file flags combination " << file_flags;
-    MessageLoopProxy::current()->PostTask(
-        FROM_HERE,
-        base::Bind(callback,
-                   base::PLATFORM_FILE_ERROR_FAILED,
-                   base::kInvalidPlatformFileValue,
-                   peer_handle));
-  }
+  CallFileSystemMethodOnUIThread(
+      base::Bind(&internal::FileApiWorker::OpenFile,
+                 base::Unretained(worker_.get()),
+                 file_path, file_flags,
+                 google_apis::CreateRelayCallback(
+                     base::Bind(&RunOpenFileCallback, peer_handle, callback))));
 }
 
 void FileSystemProxy::NotifyCloseFile(const FileSystemURL& url) {
@@ -601,12 +287,8 @@
     return;
 
   CallFileSystemMethodOnUIThread(
-      base::Bind(&FileSystemInterface::CloseFile,
-                 base::Unretained(file_system_),
-                 file_path,
-                 google_apis::CreateRelayCallback(
-                     base::Bind(&EmitDebugLogForCloseFile,
-                                file_path))));
+      base::Bind(&internal::FileApiWorker::CloseFile,
+                 base::Unretained(worker_.get()), file_path));
 }
 
 void FileSystemProxy::TouchFile(
@@ -621,13 +303,10 @@
     return;
 
   CallFileSystemMethodOnUIThread(
-      base::Bind(&FileSystemInterface::TouchFile,
-                 base::Unretained(file_system_),
+      base::Bind(&internal::FileApiWorker::TouchFile,
+                 base::Unretained(worker_.get()),
                  file_path, last_access_time, last_modified_time,
-                 google_apis::CreateRelayCallback(
-                     base::Bind(&FileSystemProxy::OnStatusCallback,
-                                this,
-                                callback))));
+                 google_apis::CreateRelayCallback(callback)));
 }
 
 void FileSystemProxy::CreateSnapshotFile(
@@ -643,47 +322,15 @@
                    base::PLATFORM_FILE_ERROR_NOT_FOUND,
                    base::PlatformFileInfo(),
                    base::FilePath(),
-                   scoped_refptr<ShareableFileReference>(NULL)));
+                   scoped_refptr<ShareableFileReference>()));
     return;
   }
 
   CallFileSystemMethodOnUIThread(
-      base::Bind(&FileSystemInterface::GetResourceEntryByPath,
-                 base::Unretained(file_system_),
-                 file_path,
+      base::Bind(&internal::FileApiWorker::CreateSnapshotFile,
+                 base::Unretained(worker_.get()), file_path,
                  google_apis::CreateRelayCallback(
-                     base::Bind(&FileSystemProxy::OnGetResourceEntryByPath,
-                                this,
-                                file_path,
-                                callback))));
-}
-
-void FileSystemProxy::OnGetResourceEntryByPath(
-    const base::FilePath& entry_path,
-    const FileSystemOperation::SnapshotFileCallback& callback,
-    FileError error,
-    scoped_ptr<ResourceEntry> entry) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-
-  if (error != FILE_ERROR_OK || !entry.get()) {
-    callback.Run(base::PLATFORM_FILE_ERROR_NOT_FOUND,
-                 base::PlatformFileInfo(),
-                 base::FilePath(),
-                 scoped_refptr<ShareableFileReference>(NULL));
-    return;
-  }
-
-  base::PlatformFileInfo file_info;
-  util::ConvertResourceEntryToPlatformFileInfo(entry->file_info(), &file_info);
-
-  CallFileSystemMethodOnUIThread(
-      base::Bind(&FileSystemInterface::GetFileByPath,
-                 base::Unretained(file_system_),
-                 entry_path,
-                 google_apis::CreateRelayCallback(
-                     base::Bind(&CallSnapshotFileCallback,
-                                callback,
-                                file_info))));
+                     base::Bind(&RunSnapshotFileCallback, callback))));
 }
 
 void FileSystemProxy::CreateWritableSnapshotFile(
@@ -767,62 +414,6 @@
     method_call.Run();
 }
 
-void FileSystemProxy::OnStatusCallback(
-    const fileapi::FileSystemOperation::StatusCallback& callback,
-    FileError error) {
-  callback.Run(FileErrorToPlatformError(error));
-}
-
-void FileSystemProxy::OnGetMetadata(
-    const FileSystemOperation::GetMetadataCallback& callback,
-    FileError error,
-    scoped_ptr<ResourceEntry> entry) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-
-  if (error != FILE_ERROR_OK) {
-    callback.Run(FileErrorToPlatformError(error),
-                 base::PlatformFileInfo());
-    return;
-  }
-  DCHECK(entry.get());
-
-  base::PlatformFileInfo file_info;
-  util::ConvertResourceEntryToPlatformFileInfo(entry->file_info(), &file_info);
-
-  callback.Run(base::PLATFORM_FILE_OK, file_info);
-}
-
-void FileSystemProxy::OnReadDirectory(
-    const FileSystemOperation::ReadDirectoryCallback&
-    callback,
-    FileError error,
-    bool hide_hosted_documents,
-    scoped_ptr<ResourceEntryVector> resource_entries) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-
-  if (error != FILE_ERROR_OK) {
-    callback.Run(FileErrorToPlatformError(error),
-                 std::vector<DirectoryEntry>(),
-                 false);
-    return;
-  }
-  DCHECK(resource_entries.get());
-
-  std::vector<DirectoryEntry> entries;
-  // Convert Drive files to something File API stack can understand.
-  for (size_t i = 0; i < resource_entries->size(); ++i) {
-    const ResourceEntry& resource_entry = (*resource_entries)[i];
-    if (resource_entry.has_file_specific_info() &&
-        resource_entry.file_specific_info().is_hosted_document() &&
-        hide_hosted_documents) {
-      continue;
-    }
-    entries.push_back(ResourceEntryToDirectoryEntry(resource_entry));
-  }
-
-  callback.Run(base::PLATFORM_FILE_OK, entries, false);
-}
-
 void FileSystemProxy::OnCreateWritableSnapshotFile(
     const base::FilePath& virtual_path,
     const fileapi::WritableSnapshotFile& callback,
@@ -852,12 +443,8 @@
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
 
   CallFileSystemMethodOnUIThread(
-      base::Bind(&FileSystemInterface::CloseFile,
-                 base::Unretained(file_system_),
-                 virtual_path,
-                 google_apis::CreateRelayCallback(
-                     base::Bind(&EmitDebugLogForCloseFile,
-                                virtual_path))));
+      base::Bind(&internal::FileApiWorker::CloseFile,
+                 base::Unretained(worker_.get()), virtual_path));
 }
 
 FileSystemInterface* FileSystemProxy::GetFileSystemOnUIThread() {
diff --git a/chrome/browser/chromeos/drive/file_system_proxy.h b/chrome/browser/chromeos/drive/file_system_proxy.h
index 0d674f4..f4dcaca 100644
--- a/chrome/browser/chromeos/drive/file_system_proxy.h
+++ b/chrome/browser/chromeos/drive/file_system_proxy.h
@@ -10,7 +10,7 @@
 
 namespace fileapi {
 class FileSystemURL;
-}
+}  // namespace fileapi
 
 namespace drive {
 
@@ -19,6 +19,10 @@
 
 typedef std::vector<ResourceEntry> ResourceEntryVector;
 
+namespace internal {
+class FileApiWorker;
+}  // namespace internal
+
 // Implementation of File API's remote file system proxy for Drive-backed
 // file system.
 class FileSystemProxy : public fileapi::RemoteFileSystemProxyInterface {
@@ -113,38 +117,6 @@
   void CallFileSystemMethodOnUIThreadInternal(
       const base::Closure& method_call);
 
-  // Helper callback for relaying reply for status callbacks to the
-  // calling thread.
-  void OnStatusCallback(
-      const fileapi::FileSystemOperation::StatusCallback& callback,
-      FileError error);
-
-  // Helper callback for relaying reply for metadata retrieval request to the
-  // calling thread.
-  void OnGetMetadata(
-      const fileapi::FileSystemOperation::GetMetadataCallback&
-          callback,
-      FileError error,
-      scoped_ptr<ResourceEntry> entry);
-
-  // Helper callback for relaying reply for GetResourceEntryByPath() to the
-  // calling thread.
-  void OnGetResourceEntryByPath(
-      const base::FilePath& entry_path,
-      const fileapi::FileSystemOperation::SnapshotFileCallback&
-          callback,
-      FileError error,
-      scoped_ptr<ResourceEntry> entry);
-
-  // Helper callback for relaying reply for ReadDirectory() to the calling
-  // thread.
-  void OnReadDirectory(
-      const fileapi::FileSystemOperation::ReadDirectoryCallback&
-          callback,
-      FileError error,
-      bool hide_hosted_documents,
-      scoped_ptr<ResourceEntryVector> resource_entries);
-
   // Helper callback for relaying reply for CreateWritableSnapshotFile() to
   // the calling thread.
   void OnCreateWritableSnapshotFile(
@@ -160,53 +132,13 @@
       const base::FilePath& virtual_path,
       const base::FilePath& local_path);
 
-  // Invoked during Truncate() operation. This is called when a local modifiable
-  // cache is ready for truncation.
-  void OnFileOpenedForTruncate(
-      const base::FilePath& virtual_path,
-      int64 length,
-      const fileapi::FileSystemOperation::StatusCallback& callback,
-      FileError open_result,
-      const base::FilePath& local_cache_path);
-
-  // Invoked during Truncate() operation. This is called when the truncation of
-  // a local cache file is finished on FILE thread.
-  void DidTruncate(
-      const base::FilePath& virtual_path,
-      const fileapi::FileSystemOperation::StatusCallback& callback,
-      base::PlatformFileError truncate_result);
-
-  // Invoked during OpenFile() operation when truncate or write flags are set.
-  // This is called when a local modifiable cached file is ready for such
-  // operation.
-  void OnOpenFileForWriting(
-      int file_flags,
-      base::ProcessHandle peer_handle,
-      const OpenFileCallback& callback,
-      FileError file_error,
-      const base::FilePath& local_cache_path);
-
-  // Invoked during OpenFile() operation when file create flags are set.
-  void OnCreateFileForOpen(
-      const base::FilePath& file_path,
-      int file_flags,
-      base::ProcessHandle peer_handle,
-      const OpenFileCallback& callback,
-      FileError file_error);
-
-  // Invoked during OpenFile() operation when base::PLATFORM_FILE_OPEN_TRUNCATED
-  // flag is set. This is called when the truncation of a local cache file is
-  // finished on FILE thread.
-  void OnOpenAndTruncate(
-      base::ProcessHandle peer_handle,
-      const OpenFileCallback& callback,
-      base::PlatformFile* platform_file,
-      base::PlatformFileError* truncate_result);
-
   // Returns |file_system_| on UI thread.
   FileSystemInterface* GetFileSystemOnUIThread();
 
+  // TODO(hidehiko): Remove |file_system_| when all the core implementation
+  // is moved to FileApiWorker.
   FileSystemInterface* file_system_;
+  scoped_ptr<internal::FileApiWorker> worker_;
 };
 
 }  // namespace drive
diff --git a/chrome/browser/chromeos/drive/file_system_unittest.cc b/chrome/browser/chromeos/drive/file_system_unittest.cc
index 63bb0cb..430539b 100644
--- a/chrome/browser/chromeos/drive/file_system_unittest.cc
+++ b/chrome/browser/chromeos/drive/file_system_unittest.cc
@@ -17,9 +17,9 @@
 #include "chrome/browser/chromeos/drive/change_list_loader.h"
 #include "chrome/browser/chromeos/drive/drive.pb.h"
 #include "chrome/browser/chromeos/drive/fake_free_disk_space_getter.h"
+#include "chrome/browser/chromeos/drive/file_system_observer.h"
 #include "chrome/browser/chromeos/drive/file_system_util.h"
 #include "chrome/browser/chromeos/drive/job_scheduler.h"
-#include "chrome/browser/chromeos/drive/mock_directory_change_observer.h"
 #include "chrome/browser/chromeos/drive/sync_client.h"
 #include "chrome/browser/chromeos/drive/test_util.h"
 #include "chrome/browser/drive/fake_drive_service.h"
@@ -27,14 +27,8 @@
 #include "chrome/browser/google_apis/test_util.h"
 #include "chrome/test/base/testing_profile.h"
 #include "content/public/test/test_browser_thread_bundle.h"
-#include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-using ::testing::AtLeast;
-using ::testing::Eq;
-using ::testing::StrictMock;
-using ::testing::_;
-
 namespace drive {
 namespace {
 
@@ -58,6 +52,27 @@
     quit.Run();
 }
 
+// This class is used to record directory changes and examine them later.
+class MockDirectoryChangeObserver : public FileSystemObserver {
+ public:
+  MockDirectoryChangeObserver() {}
+  virtual ~MockDirectoryChangeObserver() {}
+
+  // FileSystemObserver overrides.
+  virtual void OnDirectoryChanged(
+      const base::FilePath& directory_path) OVERRIDE {
+    changed_directories_.push_back(directory_path);
+  }
+
+  const std::vector<base::FilePath>& changed_directories() const {
+    return changed_directories_;
+  }
+
+ private:
+  std::vector<base::FilePath> changed_directories_;
+  DISALLOW_COPY_AND_ASSIGN(MockDirectoryChangeObserver);
+};
+
 }  // namespace
 
 class FileSystemTest : public testing::Test {
@@ -65,17 +80,20 @@
   virtual void SetUp() OVERRIDE {
     profile_.reset(new TestingProfile);
 
-    // The fake object will be manually deleted in TearDown().
-    fake_drive_service_.reset(new google_apis::FakeDriveService);
+    fake_network_change_notifier_.reset(
+        new test_util::FakeNetworkChangeNotifier);
+
+    fake_drive_service_.reset(new FakeDriveService);
     fake_drive_service_->LoadResourceListForWapi(
-        "chromeos/gdata/root_feed.json");
+        "gdata/root_feed.json");
     fake_drive_service_->LoadAccountMetadataForWapi(
-        "chromeos/gdata/account_metadata.json");
+        "gdata/account_metadata.json");
 
     fake_free_disk_space_getter_.reset(new FakeFreeDiskSpaceGetter);
 
     scheduler_.reset(new JobScheduler(profile_.get(),
-                                      fake_drive_service_.get()));
+                                      fake_drive_service_.get(),
+                                      base::MessageLoopProxy::current()));
 
     ASSERT_TRUE(file_util::CreateDirectory(util::GetCacheRootPath(
         profile_.get()).Append(util::kMetadataDirectory)));
@@ -84,24 +102,27 @@
     ASSERT_TRUE(file_util::CreateDirectory(util::GetCacheRootPath(
         profile_.get()).Append(util::kTemporaryFileDirectory)));
 
-    cache_.reset(new internal::FileCache(
-        util::GetCacheRootPath(profile_.get()).Append(util::kMetadataDirectory),
-        util::GetCacheRootPath(profile_.get()).Append(
-            util::kCacheFileDirectory),
-        base::MessageLoopProxy::current(),
-        fake_free_disk_space_getter_.get()));
-
-    mock_directory_observer_.reset(new StrictMock<MockDirectoryChangeObserver>);
-
-    ASSERT_TRUE(cache_->Initialize());
+    mock_directory_observer_.reset(new MockDirectoryChangeObserver);
 
     SetUpResourceMetadataAndFileSystem();
   }
 
   void SetUpResourceMetadataAndFileSystem() {
-    resource_metadata_.reset(new internal::ResourceMetadata(
+    metadata_storage_.reset(new internal::ResourceMetadataStorage(
         util::GetCacheRootPath(profile_.get()).Append(util::kMetadataDirectory),
         base::MessageLoopProxy::current()));
+    ASSERT_TRUE(metadata_storage_->Initialize());
+
+    cache_.reset(new internal::FileCache(
+        metadata_storage_.get(),
+        util::GetCacheRootPath(profile_.get()).Append(
+            util::kCacheFileDirectory),
+        base::MessageLoopProxy::current(),
+        fake_free_disk_space_getter_.get()));
+    ASSERT_TRUE(cache_->Initialize());
+
+    resource_metadata_.reset(new internal::ResourceMetadata(
+        metadata_storage_.get(), base::MessageLoopProxy::current()));
 
     file_system_.reset(new FileSystem(
         profile_.get(),
@@ -122,15 +143,6 @@
     ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->Initialize());
   }
 
-  virtual void TearDown() OVERRIDE {
-    ASSERT_TRUE(file_system_);
-    file_system_.reset();
-    scheduler_.reset();
-    fake_drive_service_.reset();
-    cache_.reset();
-    profile_.reset(NULL);
-  }
-
   // Loads the full resource list via FakeDriveService.
   bool LoadFullResourceList() {
     FileError error = FILE_ERROR_FAILED;
@@ -158,12 +170,11 @@
   scoped_ptr<ResourceEntryVector> ReadDirectoryByPathSync(
       const base::FilePath& file_path) {
     FileError error = FILE_ERROR_FAILED;
-    bool unused_hide_hosted_documents;
     scoped_ptr<ResourceEntryVector> entries;
     file_system_->ReadDirectoryByPath(
         file_path,
         google_apis::test_util::CreateCopyResultCallback(
-            &error, &unused_hide_hosted_documents, &entries));
+            &error, &entries));
     google_apis::test_util::RunBlockingPoolTask();
 
     return entries.Pass();
@@ -199,13 +210,16 @@
     // Destroy the existing resource metadata to close DB.
     resource_metadata_.reset();
 
-    const std::string root_resource_id =
-        fake_drive_service_->GetRootResourceId();
+    base::FilePath metadata_directory =
+        util::GetCacheRootPath(profile_.get()).Append(util::kMetadataDirectory);
+    scoped_ptr<internal::ResourceMetadataStorage,
+               test_util::DestroyHelperForTests> metadata_storage(
+                   new internal::ResourceMetadataStorage(
+                       metadata_directory, base::MessageLoopProxy::current()));
+
     scoped_ptr<internal::ResourceMetadata, test_util::DestroyHelperForTests>
         resource_metadata(new internal::ResourceMetadata(
-            util::GetCacheRootPath(profile_.get()).Append(
-                util::kMetadataDirectory),
-            base::MessageLoopProxy::current()));
+            metadata_storage_.get(), base::MessageLoopProxy::current()));
 
     if (resource_metadata->Initialize() != FILE_ERROR_OK)
       return false;
@@ -215,6 +229,8 @@
       return false;
 
     // drive/root
+    const std::string root_resource_id =
+        fake_drive_service_->GetRootResourceId();
     if (resource_metadata->AddEntry(util::CreateMyDriveRootEntry(
             root_resource_id)) != FILE_ERROR_OK)
       return false;
@@ -278,22 +294,23 @@
 
   content::TestBrowserThreadBundle thread_bundle_;
   scoped_ptr<TestingProfile> profile_;
+  scoped_ptr<test_util::FakeNetworkChangeNotifier>
+      fake_network_change_notifier_;
 
-  scoped_ptr<internal::FileCache, test_util::DestroyHelperForTests> cache_;
-  scoped_ptr<FileSystem> file_system_;
-  scoped_ptr<google_apis::FakeDriveService> fake_drive_service_;
+  scoped_ptr<FakeDriveService> fake_drive_service_;
+  scoped_ptr<FakeFreeDiskSpaceGetter> fake_free_disk_space_getter_;
   scoped_ptr<JobScheduler> scheduler_;
+  scoped_ptr<MockDirectoryChangeObserver> mock_directory_observer_;
+
+  scoped_ptr<internal::ResourceMetadataStorage,
+             test_util::DestroyHelperForTests> metadata_storage_;
+  scoped_ptr<internal::FileCache, test_util::DestroyHelperForTests> cache_;
   scoped_ptr<internal::ResourceMetadata, test_util::DestroyHelperForTests>
       resource_metadata_;
-  scoped_ptr<FakeFreeDiskSpaceGetter> fake_free_disk_space_getter_;
-  scoped_ptr<StrictMock<MockDirectoryChangeObserver> > mock_directory_observer_;
+  scoped_ptr<FileSystem> file_system_;
 };
 
 TEST_F(FileSystemTest, DuplicatedAsyncInitialization) {
-  // "Fast fetch" will fire an OnirectoryChanged event.
-  EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged(
-      Eq(base::FilePath(FILE_PATH_LITERAL("drive"))))).Times(1);
-
   base::RunLoop loop;
 
   int counter = 0;
@@ -313,6 +330,11 @@
   EXPECT_EQ(1, fake_drive_service_->resource_list_load_count());
   // See the comment in GetMyDriveRoot test case why this is 2.
   EXPECT_EQ(2, fake_drive_service_->about_resource_load_count());
+
+  // "Fast fetch" will fire an OnirectoryChanged event.
+  ASSERT_EQ(1u, mock_directory_observer_->changed_directories().size());
+  EXPECT_EQ(base::FilePath(FILE_PATH_LITERAL("drive")),
+            mock_directory_observer_->changed_directories()[0]);
 }
 
 TEST_F(FileSystemTest, GetGrandRootEntry) {
@@ -339,10 +361,6 @@
 }
 
 TEST_F(FileSystemTest, GetMyDriveRoot) {
-  // "Fast fetch" will fire an OnirectoryChanged event.
-  EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged(
-      Eq(base::FilePath(FILE_PATH_LITERAL("drive"))))).Times(1);
-
   const base::FilePath kFilePath(FILE_PATH_LITERAL("drive/root"));
   scoped_ptr<ResourceEntry> entry = GetResourceEntryByPathSync(kFilePath);
   ASSERT_TRUE(entry);
@@ -359,6 +377,11 @@
 
   // After "fast fetch" is done, full resource list is fetched.
   EXPECT_EQ(1, fake_drive_service_->resource_list_load_count());
+
+  // "Fast fetch" will fire an OnirectoryChanged event.
+  ASSERT_EQ(1u, mock_directory_observer_->changed_directories().size());
+  EXPECT_EQ(base::FilePath(FILE_PATH_LITERAL("drive")),
+            mock_directory_observer_->changed_directories()[0]);
 }
 
 TEST_F(FileSystemTest, GetExistingFile) {
@@ -413,7 +436,7 @@
   const std::string resource_id1 = entry->resource_id();
 
   const base::FilePath kFilePath2(
-      FILE_PATH_LITERAL("drive/root/Duplicate Name (2).txt"));
+      FILE_PATH_LITERAL("drive/root/Duplicate Name (1).txt"));
   entry = GetResourceEntryByPathSync(kFilePath2);
   ASSERT_TRUE(entry);
   const std::string resource_id2 = entry->resource_id();
@@ -457,9 +480,6 @@
 }
 
 TEST_F(FileSystemTest, ReadDirectoryByPath_Root) {
-  EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged(
-      Eq(base::FilePath(FILE_PATH_LITERAL("drive"))))).Times(1);
-
   // ReadDirectoryByPath() should kick off the resource list loading.
   scoped_ptr<ResourceEntryVector> entries(
       ReadDirectoryByPathSync(base::FilePath::FromUTF8Unsafe("drive")));
@@ -482,6 +502,10 @@
 
   EXPECT_TRUE(found_other);
   EXPECT_TRUE(found_my_drive);
+
+  ASSERT_EQ(1u, mock_directory_observer_->changed_directories().size());
+  EXPECT_EQ(base::FilePath(FILE_PATH_LITERAL("drive")),
+            mock_directory_observer_->changed_directories()[0]);
 }
 
 TEST_F(FileSystemTest, ReadDirectoryByPath_NonRootDirectory) {
@@ -522,13 +546,19 @@
   // Make GetResourceList fail for simulating offline situation. This will
   // leave the file system "loaded from cache, but not synced with server"
   // state.
+  fake_network_change_notifier_->SetConnectionType(
+      net::NetworkChangeNotifier::CONNECTION_NONE);
   fake_drive_service_->set_offline(true);
 
-  // Kicks loading of cached file system and query for server update.
-  EXPECT_TRUE(ReadDirectoryByPathSync(util::GetDriveMyDriveRootPath()));
+  // Load the root.
+  EXPECT_TRUE(ReadDirectoryByPathSync(util::GetDriveGrandRootPath()));
   // Loading of about resource should not happen as it's offline.
   EXPECT_EQ(0, fake_drive_service_->about_resource_load_count());
 
+  // Load "My Drive".
+  EXPECT_TRUE(ReadDirectoryByPathSync(util::GetDriveMyDriveRootPath()));
+  EXPECT_EQ(0, fake_drive_service_->about_resource_load_count());
+
   // Tests that cached data can be loaded even if the server is not reachable.
   EXPECT_TRUE(EntryExists(base::FilePath(
       FILE_PATH_LITERAL("drive/root/File1"))));
@@ -545,21 +575,20 @@
   // the file system should be able to start periodic refresh.
   // To test it, call CheckForUpdates and verify it does try to check
   // updates, which will cause directory changes.
+  fake_network_change_notifier_->SetConnectionType(
+      net::NetworkChangeNotifier::CONNECTION_WIFI);
   fake_drive_service_->set_offline(false);
 
   file_system_->CheckForUpdates();
-  EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged(_))
-      .Times(AtLeast(1));
 
   google_apis::test_util::RunBlockingPoolTask();
   EXPECT_EQ(1, fake_drive_service_->about_resource_load_count());
   EXPECT_EQ(1, fake_drive_service_->change_list_load_count());
+
+  ASSERT_LE(1u, mock_directory_observer_->changed_directories().size());
 }
 
 TEST_F(FileSystemTest, ReadDirectoryWhileRefreshing) {
-  EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged(_))
-      .Times(AtLeast(1));
-
   // Enter the "refreshing" state so the fast fetch will be performed.
   ASSERT_TRUE(SetUpTestFileSystem(USE_OLD_TIMESTAMP));
   file_system_->CheckForUpdates();
@@ -568,6 +597,8 @@
   EXPECT_TRUE(ReadDirectoryByPathSync(base::FilePath(
       FILE_PATH_LITERAL("drive/root/Dir1"))));
   EXPECT_EQ(1, fake_drive_service_->directory_load_count());
+
+  ASSERT_LE(1u, mock_directory_observer_->changed_directories().size());
 }
 
 TEST_F(FileSystemTest, GetResourceEntryExistingWhileRefreshing) {
@@ -582,9 +613,6 @@
 }
 
 TEST_F(FileSystemTest, GetResourceEntryNonExistentWhileRefreshing) {
-  EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged(_))
-      .Times(AtLeast(1));
-
   // Enter the "refreshing" state so the fast fetch will be performed.
   ASSERT_TRUE(SetUpTestFileSystem(USE_OLD_TIMESTAMP));
   file_system_->CheckForUpdates();
@@ -593,6 +621,8 @@
   EXPECT_FALSE(GetResourceEntryByPathSync(base::FilePath(
       FILE_PATH_LITERAL("drive/root/Dir1/NonExistentFile"))));
   EXPECT_EQ(1, fake_drive_service_->directory_load_count());
+
+  ASSERT_LE(1u, mock_directory_observer_->changed_directories().size());
 }
 
 TEST_F(FileSystemTest, CreateDirectoryByImplicitLoad) {
@@ -614,10 +644,6 @@
 }
 
 TEST_F(FileSystemTest, PinAndUnpin) {
-  // Pinned file gets synced and it results in entry state changes.
-  EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged(
-      Eq(base::FilePath(FILE_PATH_LITERAL("drive/root"))))).Times(AtLeast(1));
-
   ASSERT_TRUE(LoadFullResourceList());
 
   base::FilePath file_path(FILE_PATH_LITERAL("drive/root/File 1.txt"));
@@ -649,6 +675,11 @@
   EXPECT_TRUE(cache_->GetCacheEntry(
       entry->resource_id(), std::string(), &cache_entry));
   EXPECT_FALSE(cache_entry.is_pinned());
+
+  // Pinned file gets synced and it results in entry state changes.
+  ASSERT_EQ(1u, mock_directory_observer_->changed_directories().size());
+  EXPECT_EQ(base::FilePath(FILE_PATH_LITERAL("drive/root")),
+            mock_directory_observer_->changed_directories()[0]);
 }
 
 TEST_F(FileSystemTest, PinAndUnpin_NotSynced) {
@@ -696,26 +727,22 @@
 TEST_F(FileSystemTest, RefreshDirectory) {
   ASSERT_TRUE(LoadFullResourceList());
 
-  // We'll notify the directory change to the observer.
-  EXPECT_CALL(*mock_directory_observer_,
-              OnDirectoryChanged(Eq(util::GetDriveMyDriveRootPath()))).Times(1);
-
   FileError error = FILE_ERROR_FAILED;
   file_system_->RefreshDirectory(
       util::GetDriveMyDriveRootPath(),
       google_apis::test_util::CreateCopyResultCallback(&error));
   google_apis::test_util::RunBlockingPoolTask();
   EXPECT_EQ(FILE_ERROR_OK, error);
+
+  // We'll notify the directory change to the observer.
+  ASSERT_EQ(1u, mock_directory_observer_->changed_directories().size());
+  EXPECT_EQ(util::GetDriveMyDriveRootPath(),
+            mock_directory_observer_->changed_directories()[0]);
 }
 
 TEST_F(FileSystemTest, OpenAndCloseFile) {
   ASSERT_TRUE(LoadFullResourceList());
 
-  // The transfered file is cached and the change of "offline available"
-  // attribute is notified.
-  EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged(
-      Eq(base::FilePath(FILE_PATH_LITERAL("drive/root"))))).Times(AtLeast(1));
-
   const base::FilePath kFileInRoot(FILE_PATH_LITERAL("drive/root/File 1.txt"));
   scoped_ptr<ResourceEntry> entry(GetResourceEntryByPathSync(kFileInRoot));
   const std::string& file_resource_id = entry->resource_id();
@@ -733,6 +760,13 @@
   // Verify that the file was properly opened.
   EXPECT_EQ(FILE_ERROR_OK, error);
 
+  // The opened file is downloaded, which means the file is available
+  // offline. The directory change should be notified so Files.app can change
+  // the offline availability status of the file.
+  ASSERT_EQ(1u, mock_directory_observer_->changed_directories().size());
+  EXPECT_EQ(base::FilePath(FILE_PATH_LITERAL("drive/root")),
+            mock_directory_observer_->changed_directories()[0]);
+
   // Try to open the already opened file.
   file_system_->OpenFile(
       kFileInRoot,
@@ -784,6 +818,12 @@
   ASSERT_TRUE(gdata_entry);
   EXPECT_EQ(static_cast<int>(kNewContent.size()), gdata_entry->file_size());
 
+  // The modified file is uploaded. The directory change should be notified
+  // so Files.app can show new metadata of the modified file.
+  ASSERT_EQ(2u, mock_directory_observer_->changed_directories().size());
+  EXPECT_EQ(base::FilePath(FILE_PATH_LITERAL("drive/root")),
+            mock_directory_observer_->changed_directories()[1]);
+
   // Try to close the same file twice.
   file_system_->CloseFile(
       kFileInRoot,
@@ -792,6 +832,8 @@
 
   // It must fail.
   EXPECT_EQ(FILE_ERROR_NOT_FOUND, error);
+  // There should be no new directory change.
+  ASSERT_EQ(2u, mock_directory_observer_->changed_directories().size());
 }
 
 TEST_F(FileSystemTest, MarkCacheFileAsMountedAndUnmounted) {
@@ -805,7 +847,7 @@
   ASSERT_EQ(FILE_ERROR_OK, cache_->Store(
       entry->resource_id(),
       entry->file_specific_info().md5(),
-      google_apis::test_util::GetTestFilePath("chromeos/gdata/root_feed.json"),
+      google_apis::test_util::GetTestFilePath("gdata/root_feed.json"),
       internal::FileCache::FILE_OPERATION_COPY));
 
   // Test for mounting.
diff --git a/chrome/browser/chromeos/drive/file_system_util.cc b/chrome/browser/chromeos/drive/file_system_util.cc
index 9d3ebd2..704450c 100644
--- a/chrome/browser/chromeos/drive/file_system_util.cc
+++ b/chrome/browser/chromeos/drive/file_system_util.cc
@@ -114,7 +114,7 @@
        file_from = enumerator.Next()) {
     const base::FilePath file_to = directory_to.Append(file_from.BaseName());
     if (!file_util::PathExists(file_to))  // Do not overwrite existing files.
-      file_util::Move(file_from, file_to);
+      base::Move(file_from, file_to);
   }
 }
 
@@ -323,7 +323,7 @@
 
   // Move all files inside "persistent" to "files".
   MoveAllFilesFromDirectory(persistent_directory, cache_file_directory);
-  file_util::Delete(persistent_directory,  true /* recursive */);
+  base::Delete(persistent_directory,  true /* recursive */);
 
   // Move all files inside "tmp" to "files".
   MoveAllFilesFromDirectory(tmp_directory, cache_file_directory);
diff --git a/chrome/browser/chromeos/drive/file_system_util.h b/chrome/browser/chromeos/drive/file_system_util.h
index ffde7bc..e57c695 100644
--- a/chrome/browser/chromeos/drive/file_system_util.h
+++ b/chrome/browser/chromeos/drive/file_system_util.h
@@ -179,7 +179,7 @@
 // If |directory| is not a Drive path, it won't check the existence and just
 // runs |callback|.
 //
-// Must be called from UI/IO thread.
+// Must be called from UI thread.
 void EnsureDirectoryExists(Profile* profile,
                            const base::FilePath& directory,
                            const FileOperationCallback& callback);
diff --git a/chrome/browser/chromeos/drive/file_task_executor.cc b/chrome/browser/chromeos/drive/file_task_executor.cc
index 038ea5c..a42f71c 100644
--- a/chrome/browser/chromeos/drive/file_task_executor.cc
+++ b/chrome/browser/chromeos/drive/file_task_executor.cc
@@ -82,7 +82,7 @@
     return;
   }
 
-  google_apis::DriveServiceInterface* drive_service =
+  DriveServiceInterface* drive_service =
       integration_service->drive_service();
 
   // Send off a request for the drive service to authorize the apps for the
diff --git a/chrome/browser/chromeos/drive/fileapi_worker.cc b/chrome/browser/chromeos/drive/fileapi_worker.cc
new file mode 100644
index 0000000..e69a386
--- /dev/null
+++ b/chrome/browser/chromeos/drive/fileapi_worker.cc
@@ -0,0 +1,346 @@
+// 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/drive/fileapi_worker.h"
+
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/task_runner_util.h"
+#include "base/threading/sequenced_worker_pool.h"
+#include "chrome/browser/chromeos/drive/drive.pb.h"
+#include "chrome/browser/chromeos/drive/file_errors.h"
+#include "chrome/browser/chromeos/drive/file_system_interface.h"
+#include "chrome/browser/chromeos/drive/file_system_util.h"
+#include "content/public/browser/browser_thread.h"
+#include "webkit/common/fileapi/directory_entry.h"
+
+using content::BrowserThread;
+
+namespace drive {
+namespace internal {
+namespace {
+
+// Runs |callback| with the PlatformFileError converted from |error|.
+void RunStatusCallbackByFileError(
+    const FileApiWorker::StatusCallback& callback,
+    FileError error) {
+  callback.Run(FileErrorToPlatformError(error));
+}
+
+// Runs |callback| with arguments converted from |error| and |entry|.
+void RunGetFileInfoCallback(const FileApiWorker::GetFileInfoCallback& callback,
+                            FileError error,
+                            scoped_ptr<ResourceEntry> entry) {
+  if (error != FILE_ERROR_OK) {
+    callback.Run(FileErrorToPlatformError(error), base::PlatformFileInfo());
+    return;
+  }
+
+  DCHECK(entry);
+  base::PlatformFileInfo file_info;
+  util::ConvertResourceEntryToPlatformFileInfo(entry->file_info(), &file_info);
+  callback.Run(base::PLATFORM_FILE_OK, file_info);
+}
+
+// Runs |callback| with arguments converted from |error| and |resource_entries|.
+void RunReadDirectoryCallback(
+    const FileApiWorker::ReadDirectoryCallback& callback,
+    FileError error,
+    scoped_ptr<ResourceEntryVector> resource_entries) {
+  if (error != FILE_ERROR_OK) {
+    callback.Run(FileErrorToPlatformError(error),
+                 std::vector<fileapi::DirectoryEntry>(), false);
+    return;
+  }
+
+  DCHECK(resource_entries);
+
+  std::vector<fileapi::DirectoryEntry> entries;
+  // Convert drive files to File API's directory entry.
+  entries.reserve(resource_entries->size());
+  for (size_t i = 0; i < resource_entries->size(); ++i) {
+    const ResourceEntry& resource_entry = (*resource_entries)[i];
+    fileapi::DirectoryEntry entry;
+    entry.name = resource_entry.base_name();
+
+    const PlatformFileInfoProto& file_info = resource_entry.file_info();
+    entry.is_directory = file_info.is_directory();
+    entry.size = file_info.size();
+    entry.last_modified_time =
+        base::Time::FromInternalValue(file_info.last_modified());
+    entries.push_back(entry);
+  }
+
+  callback.Run(base::PLATFORM_FILE_OK, entries, false);
+}
+
+// Runs |callback| with arguments based on |error|, |local_path| and |entry|.
+void RunCreateSnapshotFileCallback(
+    const FileApiWorker::CreateSnapshotFileCallback& callback,
+    FileError error,
+    const base::FilePath& local_path,
+    scoped_ptr<ResourceEntry> entry) {
+  if (error != FILE_ERROR_OK) {
+    callback.Run(
+        FileErrorToPlatformError(error),
+        base::PlatformFileInfo(), base::FilePath(),
+        webkit_blob::ScopedFile::ScopeOutPolicy());
+    return;
+  }
+
+  DCHECK(entry);
+
+  // When reading file, last modified time specified in file info will be
+  // compared to the last modified time of the local version of the drive file.
+  // Since those two values don't generally match (last modification time on the
+  // drive server vs. last modification time of the local, downloaded file), so
+  // we have to opt out from this check. We do this by unsetting last_modified
+  // value in the file info passed to the CreateSnapshot caller.
+  base::PlatformFileInfo file_info;
+  util::ConvertResourceEntryToPlatformFileInfo(entry->file_info(), &file_info);
+  file_info.last_modified = base::Time();
+
+  // If the file is a hosted document, a temporary JSON file is created to
+  // represent the document. The JSON file is not cached and its lifetime
+  // is managed by ShareableFileReference.
+  webkit_blob::ScopedFile::ScopeOutPolicy scope_out_policy =
+      entry->file_specific_info().is_hosted_document() ?
+      webkit_blob::ScopedFile::DELETE_ON_SCOPE_OUT :
+      webkit_blob::ScopedFile::DONT_DELETE_ON_SCOPE_OUT;
+
+  callback.Run(base::PLATFORM_FILE_OK, file_info, local_path, scope_out_policy);
+}
+
+// Runs |callback| with |error| and |platform_file|.
+void RunOpenFileCallback(
+    const FileApiWorker::OpenFileCallback& callback,
+    base::PlatformFileError* error,
+    base::PlatformFile platform_file) {
+  callback.Run(*error, platform_file);
+}
+
+// Part of FileApiWorker::OpenFile(). Called after FileSystem::OpenFile().
+void OpenFileAfterFileSystemOpenFile(
+    int file_flags,
+    const FileApiWorker::OpenFileCallback& callback,
+    FileError error,
+    const base::FilePath& local_path) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+  if (error != FILE_ERROR_OK) {
+    callback.Run(FileErrorToPlatformError(error),
+                 base::kInvalidPlatformFileValue);
+    return;
+  }
+
+  // Cache file prepared for modification is available. Open it locally.
+  base::PlatformFileError* result =
+      new base::PlatformFileError(base::PLATFORM_FILE_ERROR_FAILED);
+  bool posted = base::PostTaskAndReplyWithResult(
+      BrowserThread::GetBlockingPool(), FROM_HERE,
+      base::Bind(&base::CreatePlatformFile,
+                 local_path, file_flags, static_cast<bool*>(NULL), result),
+      base::Bind(&RunOpenFileCallback, callback, base::Owned(result)));
+  DCHECK(posted);
+}
+
+// Part of FileApiWorker::OpenFile(). Called after FileSystem::GetFileByPath().
+void OpenFileAfterGetFileByPath(int file_flags,
+                                const FileApiWorker::OpenFileCallback& callback,
+                                FileError error,
+                                const base::FilePath& local_path,
+                                scoped_ptr<ResourceEntry> entry) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+  // Just redirect to OpenFileAfterFileSystemOpenFile() with ignoring |entry|.
+  OpenFileAfterFileSystemOpenFile(file_flags, callback, error, local_path);
+}
+
+// Emits debug log when FileSystem::CloseFile() is complete.
+void EmitDebugLogForCloseFile(const base::FilePath& local_path,
+                              FileError file_error) {
+  DVLOG(1) << "Closed: " << local_path.AsUTF8Unsafe() << ": " << file_error;
+}
+
+}  // namespace
+
+FileApiWorker::FileApiWorker(FileSystemInterface* file_system)
+    : file_system_(file_system),
+      weak_ptr_factory_(this) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  DCHECK(file_system);
+}
+
+FileApiWorker::~FileApiWorker() {
+}
+
+void FileApiWorker::GetFileInfo(const base::FilePath& file_path,
+                                const GetFileInfoCallback& callback) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  file_system_->GetResourceEntryByPath(
+      file_path,
+      base::Bind(&RunGetFileInfoCallback, callback));
+}
+
+void FileApiWorker::Copy(const base::FilePath& src_file_path,
+                         const base::FilePath& dest_file_path,
+                         const StatusCallback& callback) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  file_system_->Copy(src_file_path, dest_file_path,
+                     base::Bind(&RunStatusCallbackByFileError, callback));
+}
+
+void FileApiWorker::Move(const base::FilePath& src_file_path,
+                         const base::FilePath& dest_file_path,
+                         const StatusCallback& callback) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  file_system_->Move(src_file_path, dest_file_path,
+                     base::Bind(&RunStatusCallbackByFileError, callback));
+}
+
+void FileApiWorker::ReadDirectory(const base::FilePath& file_path,
+                                  const ReadDirectoryCallback& callback) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  file_system_->ReadDirectoryByPath(
+      file_path,
+      base::Bind(&RunReadDirectoryCallback, callback));
+}
+
+void FileApiWorker::Remove(const base::FilePath& file_path,
+                           bool is_recursive,
+                           const StatusCallback& callback) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  file_system_->Remove(file_path, is_recursive,
+                       base::Bind(&RunStatusCallbackByFileError, callback));
+}
+
+void FileApiWorker::CreateDirectory(const base::FilePath& file_path,
+                                    bool is_exclusive,
+                                    bool is_recursive,
+                                    const StatusCallback& callback) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  file_system_->CreateDirectory(
+      file_path, is_exclusive, is_recursive,
+      base::Bind(&RunStatusCallbackByFileError, callback));
+}
+
+void FileApiWorker::CreateFile(const base::FilePath& file_path,
+                               bool is_exclusive,
+                               const StatusCallback& callback) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  file_system_->CreateFile(file_path, is_exclusive,
+                           base::Bind(&RunStatusCallbackByFileError, callback));
+}
+
+void FileApiWorker::Truncate(const base::FilePath& file_path,
+                             int64 length,
+                             const StatusCallback& callback) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  file_system_->TruncateFile(
+      file_path, length,
+      base::Bind(&RunStatusCallbackByFileError, callback));
+}
+
+void FileApiWorker::CreateSnapshotFile(
+    const base::FilePath& file_path,
+    const CreateSnapshotFileCallback& callback) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  file_system_->GetFileByPath(
+      file_path,
+      base::Bind(&RunCreateSnapshotFileCallback, callback));
+}
+
+void FileApiWorker::OpenFile(const base::FilePath& file_path,
+                             int file_flags,
+                             const OpenFileCallback& callback) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+  // TODO(zelidrag): Wire all other file open operations.
+  if (file_flags & base::PLATFORM_FILE_DELETE_ON_CLOSE) {
+    NOTIMPLEMENTED() << "File create/write operations not yet supported "
+                     << file_path.value();
+    callback.Run(base::PLATFORM_FILE_ERROR_FAILED,
+                 base::kInvalidPlatformFileValue);
+    return;
+  }
+
+  // TODO(hidehiko): The opening logic should be moved to FileSystem.
+  //   crbug.com/256583.
+  if (file_flags & (base::PLATFORM_FILE_OPEN |
+                    base::PLATFORM_FILE_OPEN_ALWAYS |
+                    base::PLATFORM_FILE_OPEN_TRUNCATED)) {
+    if (file_flags & (base::PLATFORM_FILE_OPEN_TRUNCATED |
+                      base::PLATFORM_FILE_OPEN_ALWAYS |
+                      base::PLATFORM_FILE_WRITE |
+                      base::PLATFORM_FILE_EXCLUSIVE_WRITE)) {
+      // Open existing file for writing.
+      file_system_->OpenFile(
+          file_path,
+          base::Bind(&OpenFileAfterFileSystemOpenFile, file_flags, callback));
+    } else {
+      // Read-only file open.
+      file_system_->GetFileByPath(
+          file_path,
+          base::Bind(&OpenFileAfterGetFileByPath, file_flags, callback));
+    }
+  } else if (file_flags & (base::PLATFORM_FILE_CREATE |
+                           base::PLATFORM_FILE_CREATE_ALWAYS)) {
+    // Create a new file.
+    file_system_->CreateFile(
+        file_path,
+        file_flags & base::PLATFORM_FILE_EXCLUSIVE_WRITE,
+        base::Bind(&FileApiWorker::OpenFileAfterCreateFile,
+                   weak_ptr_factory_.GetWeakPtr(),
+                   file_path, file_flags, callback));
+  } else {
+    NOTREACHED() << "Unhandled file flags combination " << file_flags;
+    callback.Run(base::PLATFORM_FILE_ERROR_FAILED,
+                 base::kInvalidPlatformFileValue);
+    return;
+  }
+}
+
+void FileApiWorker::CloseFile(const base::FilePath& file_path) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  file_system_->CloseFile(file_path,
+                          base::Bind(&EmitDebugLogForCloseFile, file_path));
+}
+
+void FileApiWorker::TouchFile(const base::FilePath& file_path,
+                              const base::Time& last_access_time,
+                              const base::Time& last_modified_time,
+                              const StatusCallback& callback) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  file_system_->TouchFile(file_path, last_access_time, last_modified_time,
+                          base::Bind(&RunStatusCallbackByFileError, callback));
+
+}
+
+void FileApiWorker::OpenFileAfterCreateFile(const base::FilePath& file_path,
+                                            int file_flags,
+                                            const OpenFileCallback& callback,
+                                            FileError error) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  if (error != FILE_ERROR_OK &&
+      (error != FILE_ERROR_EXISTS ||
+       (file_flags & base::PLATFORM_FILE_CREATE))) {
+    callback.Run(FileErrorToPlatformError(error),
+                 base::kInvalidPlatformFileValue);
+    return;
+  }
+
+  // If we are trying to always create an existing file, then
+  // if it really exists open it as truncated.
+  file_flags &=
+      ~(base::PLATFORM_FILE_CREATE | base::PLATFORM_FILE_CREATE_ALWAYS);
+  file_flags |= base::PLATFORM_FILE_OPEN_TRUNCATED;
+
+  // Open created (or existing) file for writing.
+  file_system_->OpenFile(
+      file_path,
+      base::Bind(&OpenFileAfterFileSystemOpenFile, file_flags, callback));
+}
+
+}  // namespace internal
+}  // namespace drive
diff --git a/chrome/browser/chromeos/drive/fileapi_worker.h b/chrome/browser/chromeos/drive/fileapi_worker.h
new file mode 100644
index 0000000..caac16c
--- /dev/null
+++ b/chrome/browser/chromeos/drive/fileapi_worker.h
@@ -0,0 +1,149 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_DRIVE_FILEAPI_WORKER_H_
+#define CHROME_BROWSER_CHROMEOS_DRIVE_FILEAPI_WORKER_H_
+
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/callback_forward.h"
+#include "base/memory/weak_ptr.h"
+#include "base/platform_file.h"
+#include "chrome/browser/chromeos/drive/file_errors.h"
+#include "webkit/common/blob/scoped_file.h"
+
+namespace base {
+class FilePath;
+}  // namespace base
+
+namespace fileapi {
+struct DirectoryEntry;
+}  // namespace fileapi
+
+namespace drive {
+
+class FileSystemInterface;
+
+namespace internal {
+
+// This provides the core implementation of the methods for fileapi.
+// This class lives on UI thread. Note that most method invocation of fileapi
+// is done on IO thread. The gap is filled by FileSystemProxy.
+class FileApiWorker {
+ public:
+  typedef base::Callback<
+      void(base::PlatformFileError result)> StatusCallback;
+  typedef base::Callback<
+      void(base::PlatformFileError result,
+           const base::PlatformFileInfo& file_info)> GetFileInfoCallback;
+  typedef base::Callback<
+      void(base::PlatformFileError result,
+           const std::vector<fileapi::DirectoryEntry>& file_list,
+           bool has_more)> ReadDirectoryCallback;
+  typedef base::Callback<
+      void(base::PlatformFileError result,
+           const base::PlatformFileInfo& file_info,
+           const base::FilePath& snapshot_file_path,
+           webkit_blob::ScopedFile::ScopeOutPolicy scope_out_policy)>
+      CreateSnapshotFileCallback;
+  typedef base::Callback<
+      void(base::PlatformFileError result,
+           base::PlatformFile platform_file)> OpenFileCallback;
+
+  // |file_system| must not be NULL.
+  explicit FileApiWorker(FileSystemInterface* file_system);
+  ~FileApiWorker();
+
+  FileSystemInterface* file_system() { return file_system_; }
+
+  // Returns the metadata info of the file at |file_path|.
+  // Called from FileSystemProxy::GetFileInfo().
+  void GetFileInfo(const base::FilePath& file_path,
+                   const GetFileInfoCallback& callback);
+
+  // Copies a file from |src_file_path| to |dest_file_path|.
+  // Called from FileSystemProxy::Copy().
+  void Copy(const base::FilePath& src_file_path,
+            const base::FilePath& dest_file_path,
+            const StatusCallback& callback);
+
+  // Moves a file from |src_file_path| to |dest_file_path|.
+  // Called from FileSystemProxy::Move().
+  void Move(const base::FilePath& src_file_path,
+            const base::FilePath& dest_file_path,
+            const StatusCallback& callback);
+
+  // Reads the contents of the directory at |file_path|.
+  // Called from FileSystemProxy::ReadDirectory().
+  void ReadDirectory(const base::FilePath& file_path,
+                     const ReadDirectoryCallback& callback);
+
+  // Removes a file at |file_path|. Called from FileSystemProxy::Remove().
+  void Remove(const base::FilePath& file_path,
+              bool is_recursive,
+              const StatusCallback& callback);
+
+  // Creates a new directory at |file_path|.
+  // Called from FileSystemProxy::CreateDirectory().
+  void CreateDirectory(const base::FilePath& file_path,
+                       bool is_exclusive,
+                       bool is_recursive,
+                       const StatusCallback& callback);
+
+  // Creates a new file at |file_path|.
+  // Called from FileSystemProxy::CreateFile().
+  void CreateFile(const base::FilePath& file_path,
+                  bool is_exclusive,
+                  const StatusCallback& callback);
+
+  // Truncates the file at |file_path| to |length| bytes.
+  // Called from FileSystemProxy::Truncate().
+  void Truncate(const base::FilePath& file_path,
+                int64 length,
+                const StatusCallback& callback);
+
+  // Creates a snapshot for the file at |file_path|.
+  // Called from FileSystemProxy::CreateSnapshotFile().
+  void CreateSnapshotFile(const base::FilePath& file_path,
+                          const CreateSnapshotFileCallback& callback);
+
+  // Opens the file at |file_path| with options |file_flags|.
+  // Called from FileSystemProxy::OpenFile.
+  void OpenFile(const base::FilePath& file_path,
+                int file_flags,
+                const OpenFileCallback& callback);
+
+  // Closes the file at |file_path|.
+  // Called from FileSystemProxy::NotifyCloseFile and
+  // FileSystemProxy::CloseWRitableSnapshotFile.
+  void CloseFile(const base::FilePath& file_path);
+
+  // Changes timestamp of the file at |file_path| to |last_access_time| and
+  // |last_modified_time|. Called from FileSystemProxy::TouchFile().
+  void TouchFile(const base::FilePath& file_path,
+                 const base::Time& last_access_time,
+                 const base::Time& last_modified_time,
+                 const StatusCallback& callback);
+
+ private:
+  // Part of OpenFile(). Called after FileSystem::CreateFile().
+  void OpenFileAfterCreateFile(const base::FilePath& file_path,
+                               int file_flags,
+                               const OpenFileCallback& callback,
+                               FileError error);
+
+  FileSystemInterface* file_system_;
+
+  // Note: This should remain the last member so it'll be destroyed and
+  // invalidate the weak pointers before any other members are destroyed.
+  base::WeakPtrFactory<FileApiWorker> weak_ptr_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(FileApiWorker);
+};
+
+}  // namespace internal
+}  // namespace drive
+
+#endif  // CHROME_BROWSER_CHROMEOS_DRIVE_FILEAPI_WORKER_H_
diff --git a/chrome/browser/chromeos/drive/job_queue.cc b/chrome/browser/chromeos/drive/job_queue.cc
index 40a9ed6..a142556 100644
--- a/chrome/browser/chromeos/drive/job_queue.cc
+++ b/chrome/browser/chromeos/drive/job_queue.cc
@@ -4,6 +4,8 @@
 
 #include "chrome/browser/chromeos/drive/job_queue.h"
 
+#include <algorithm>
+
 #include "base/logging.h"
 #include "base/strings/stringprintf.h"
 
@@ -37,6 +39,12 @@
   return false;
 }
 
+void JobQueue::GetQueuedJobs(int priority, std::vector<JobID>* jobs) const {
+  DCHECK_LT(priority, static_cast<int>(queue_.size()));
+
+  jobs->assign(queue_[priority].begin(), queue_[priority].end());
+}
+
 void JobQueue::Push(JobID id, int priority) {
   DCHECK_LT(priority, static_cast<int>(queue_.size()));
 
@@ -64,4 +72,15 @@
   return count;
 }
 
+void JobQueue::Remove(JobID id) {
+  for (size_t i = 0; i < queue_.size(); ++i) {
+    std::deque<JobID>::iterator iter =
+        std::find(queue_[i].begin(), queue_[i].end(), id);
+    if (iter != queue_[i].end()) {
+      queue_[i].erase(iter);
+      break;
+    }
+  }
+}
+
 }  // namespace drive
diff --git a/chrome/browser/chromeos/drive/job_queue.h b/chrome/browser/chromeos/drive/job_queue.h
index 0659ce9..20d8969 100644
--- a/chrome/browser/chromeos/drive/job_queue.h
+++ b/chrome/browser/chromeos/drive/job_queue.h
@@ -36,6 +36,9 @@
   // priority 1 in the queue is picked.
   bool PopForRun(int accepted_priority, JobID* id);
 
+  // Gets queued jobs with the given priority.
+  void GetQueuedJobs(int priority, std::vector<JobID>* jobs) const;
+
   // Marks a running job |id| as finished running. This decreases the count
   // of running parallel jobs and makes room for other jobs to be popped.
   void MarkFinished(JobID id);
@@ -46,6 +49,9 @@
   // Gets the total number of jobs in the queue.
   size_t GetNumberOfJobs() const;
 
+  // Removes the job from the queue.
+  void Remove(JobID id);
+
  private:
   size_t num_max_concurrent_jobs_;
   std::vector<std::deque<JobID> > queue_;
diff --git a/chrome/browser/chromeos/drive/job_queue_unittest.cc b/chrome/browser/chromeos/drive/job_queue_unittest.cc
index d02a31d..08d2ced 100644
--- a/chrome/browser/chromeos/drive/job_queue_unittest.cc
+++ b/chrome/browser/chromeos/drive/job_queue_unittest.cc
@@ -66,4 +66,39 @@
   EXPECT_EQ(105, id);
 }
 
+TEST(JobQueueTest, JobQueueRemove) {
+  const int kNumMaxConcurrentJobs = 3;
+  const int kNumPriorityLevels = 2;
+  enum {HIGH_PRIORITY, LOW_PRIORITY};
+
+  // Create a queue. Number of jobs are initially zero.
+  JobQueue queue(kNumMaxConcurrentJobs, kNumPriorityLevels);
+  EXPECT_EQ(0U, queue.GetNumberOfJobs());
+
+  // Push 4 jobs.
+  queue.Push(101, LOW_PRIORITY);
+  queue.Push(102, HIGH_PRIORITY);
+  queue.Push(103, LOW_PRIORITY);
+  queue.Push(104, HIGH_PRIORITY);
+  EXPECT_EQ(4U, queue.GetNumberOfJobs());
+
+  // Remove 2.
+  queue.Remove(101);
+  queue.Remove(104);
+  EXPECT_EQ(2U, queue.GetNumberOfJobs());
+
+  // Pop the 2 jobs.
+  JobID id;
+  EXPECT_TRUE(queue.PopForRun(LOW_PRIORITY, &id));
+  EXPECT_EQ(102, id);
+  EXPECT_TRUE(queue.PopForRun(LOW_PRIORITY, &id));
+  EXPECT_EQ(103, id);
+  queue.MarkFinished(102);
+  queue.MarkFinished(103);
+
+  // 0 job left.
+  EXPECT_EQ(0U, queue.GetNumberOfJobs());
+  EXPECT_FALSE(queue.PopForRun(LOW_PRIORITY, &id));
+}
+
 }  // namespace drive
diff --git a/chrome/browser/chromeos/drive/job_scheduler.cc b/chrome/browser/chromeos/drive/job_scheduler.cc
index 4de6477..621021e 100644
--- a/chrome/browser/chromeos/drive/job_scheduler.cc
+++ b/chrome/browser/chromeos/drive/job_scheduler.cc
@@ -4,8 +4,6 @@
 
 #include "chrome/browser/chromeos/drive/job_scheduler.h"
 
-#include <math.h>
-
 #include "base/message_loop.h"
 #include "base/prefs/pref_service.h"
 #include "base/rand_util.h"
@@ -30,20 +28,18 @@
 // Parameter struct for RunUploadNewFile.
 struct UploadNewFileParams {
   std::string parent_resource_id;
-  base::FilePath drive_file_path;
   base::FilePath local_file_path;
   std::string title;
   std::string content_type;
-  google_apis::UploadCompletionCallback callback;
+  UploadCompletionCallback callback;
   google_apis::ProgressCallback progress_callback;
 };
 
 // Helper function to work around the arity limitation of base::Bind.
 google_apis::CancelCallback RunUploadNewFile(
-    google_apis::DriveUploaderInterface* uploader,
+    DriveUploaderInterface* uploader,
     const UploadNewFileParams& params) {
   return uploader->UploadNewFile(params.parent_resource_id,
-                                 params.drive_file_path,
                                  params.local_file_path,
                                  params.title,
                                  params.content_type,
@@ -54,20 +50,18 @@
 // Parameter struct for RunUploadExistingFile.
 struct UploadExistingFileParams {
   std::string resource_id;
-  base::FilePath drive_file_path;
   base::FilePath local_file_path;
   std::string content_type;
   std::string etag;
-  google_apis::UploadCompletionCallback callback;
+  UploadCompletionCallback callback;
   google_apis::ProgressCallback progress_callback;
 };
 
 // Helper function to work around the arity limitation of base::Bind.
 google_apis::CancelCallback RunUploadExistingFile(
-    google_apis::DriveUploaderInterface* uploader,
+    DriveUploaderInterface* uploader,
     const UploadExistingFileParams& params) {
   return uploader->UploadExistingFile(params.resource_id,
-                                      params.drive_file_path,
                                       params.local_file_path,
                                       params.content_type,
                                       params.etag,
@@ -78,25 +72,51 @@
 // Parameter struct for RunResumeUploadFile.
 struct ResumeUploadFileParams {
   GURL upload_location;
-  base::FilePath drive_file_path;
   base::FilePath local_file_path;
   std::string content_type;
-  google_apis::UploadCompletionCallback callback;
+  UploadCompletionCallback callback;
   google_apis::ProgressCallback progress_callback;
 };
 
 // Helper function to adjust the return type.
 google_apis::CancelCallback RunResumeUploadFile(
-    google_apis::DriveUploaderInterface* uploader,
+    DriveUploaderInterface* uploader,
     const ResumeUploadFileParams& params) {
   return uploader->ResumeUploadFile(params.upload_location,
-                                    params.drive_file_path,
                                     params.local_file_path,
                                     params.content_type,
                                     params.callback,
                                     params.progress_callback);
 }
 
+// Helper for CreateErrorRunCallback.
+template<typename P1>
+struct CreateErrorRunCallbackHelper {
+  static void Run(
+      const base::Callback<void(google_apis::GDataErrorCode, P1)>& callback,
+      google_apis::GDataErrorCode error) {
+    callback.Run(error, P1());
+  }
+};
+
+template<typename P1>
+struct CreateErrorRunCallbackHelper<const P1&> {
+  static void Run(
+      const base::Callback<void(google_apis::GDataErrorCode,
+                                const P1&)>& callback,
+      google_apis::GDataErrorCode error) {
+    callback.Run(error, P1());
+  }
+};
+
+// Returns a callback with the tail parameter bound to its default value.
+// In other words, returned_callback.Run(error) runs callback.Run(error, T()).
+template<typename P1>
+base::Callback<void(google_apis::GDataErrorCode)> CreateErrorRunCallback(
+    const base::Callback<void(google_apis::GDataErrorCode, P1)>& callback) {
+  return base::Bind(&CreateErrorRunCallbackHelper<P1>::Run, callback);
+}
+
 }  // namespace
 
 const int JobScheduler::kMaxJobCount[] = {
@@ -123,11 +143,12 @@
 
 JobScheduler::JobScheduler(
     Profile* profile,
-    google_apis::DriveServiceInterface* drive_service)
+    DriveServiceInterface* drive_service,
+    base::SequencedTaskRunner* blocking_task_runner)
     : throttle_count_(0),
       disable_throttling_(false),
       drive_service_(drive_service),
-      uploader_(new google_apis::DriveUploader(drive_service)),
+      uploader_(new DriveUploader(drive_service, blocking_task_runner)),
       profile_(profile),
       weak_ptr_factory_(this) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
@@ -171,9 +192,15 @@
 
   JobEntry* job = job_map_.Lookup(job_id);
   if (job) {
-    // TODO(kinaba): crbug.com/251116 Support cancelling jobs not yet started.
-    if (!job->cancel_callback.is_null())
-      job->cancel_callback.Run();
+    if (job->job_info.state == STATE_RUNNING) {
+      // If the job is running an HTTP request, cancel it via |cancel_callback|
+      // returned from the request, and wait for termination in the normal
+      // callback handler, OnJobDone.
+      if (!job->cancel_callback.is_null())
+        job->cancel_callback.Run();
+    } else {
+      AbortNotRunningJob(job, google_apis::GDATA_CANCELLED);
+    }
   }
 }
 
@@ -193,12 +220,13 @@
 
   JobEntry* new_job = CreateNewJob(TYPE_GET_ABOUT_RESOURCE);
   new_job->task = base::Bind(
-      &google_apis::DriveServiceInterface::GetAboutResource,
+      &DriveServiceInterface::GetAboutResource,
       base::Unretained(drive_service_),
       base::Bind(&JobScheduler::OnGetAboutResourceJobDone,
                  weak_ptr_factory_.GetWeakPtr(),
                  new_job->job_info.job_id,
                  callback));
+  new_job->abort_callback = CreateErrorRunCallback(callback);
   StartJob(new_job);
 }
 
@@ -209,12 +237,13 @@
 
   JobEntry* new_job = CreateNewJob(TYPE_GET_APP_LIST);
   new_job->task = base::Bind(
-      &google_apis::DriveServiceInterface::GetAppList,
+      &DriveServiceInterface::GetAppList,
       base::Unretained(drive_service_),
       base::Bind(&JobScheduler::OnGetAppListJobDone,
                  weak_ptr_factory_.GetWeakPtr(),
                  new_job->job_info.job_id,
                  callback));
+  new_job->abort_callback = CreateErrorRunCallback(callback);
   StartJob(new_job);
 }
 
@@ -225,12 +254,13 @@
 
   JobEntry* new_job = CreateNewJob(TYPE_GET_ALL_RESOURCE_LIST);
   new_job->task = base::Bind(
-      &google_apis::DriveServiceInterface::GetAllResourceList,
+      &DriveServiceInterface::GetAllResourceList,
       base::Unretained(drive_service_),
       base::Bind(&JobScheduler::OnGetResourceListJobDone,
                  weak_ptr_factory_.GetWeakPtr(),
                  new_job->job_info.job_id,
                  callback));
+  new_job->abort_callback = CreateErrorRunCallback(callback);
   StartJob(new_job);
 }
 
@@ -243,13 +273,14 @@
   JobEntry* new_job = CreateNewJob(
       TYPE_GET_RESOURCE_LIST_IN_DIRECTORY);
   new_job->task = base::Bind(
-      &google_apis::DriveServiceInterface::GetResourceListInDirectory,
+      &DriveServiceInterface::GetResourceListInDirectory,
       base::Unretained(drive_service_),
       directory_resource_id,
       base::Bind(&JobScheduler::OnGetResourceListJobDone,
                  weak_ptr_factory_.GetWeakPtr(),
                  new_job->job_info.job_id,
                  callback));
+  new_job->abort_callback = CreateErrorRunCallback(callback);
   StartJob(new_job);
 }
 
@@ -261,13 +292,14 @@
 
   JobEntry* new_job = CreateNewJob(TYPE_SEARCH);
   new_job->task = base::Bind(
-      &google_apis::DriveServiceInterface::Search,
+      &DriveServiceInterface::Search,
       base::Unretained(drive_service_),
       search_query,
       base::Bind(&JobScheduler::OnGetResourceListJobDone,
                  weak_ptr_factory_.GetWeakPtr(),
                  new_job->job_info.job_id,
                  callback));
+  new_job->abort_callback = CreateErrorRunCallback(callback);
   StartJob(new_job);
 }
 
@@ -279,13 +311,14 @@
 
   JobEntry* new_job = CreateNewJob(TYPE_GET_CHANGE_LIST);
   new_job->task = base::Bind(
-      &google_apis::DriveServiceInterface::GetChangeList,
+      &DriveServiceInterface::GetChangeList,
       base::Unretained(drive_service_),
       start_changestamp,
       base::Bind(&JobScheduler::OnGetResourceListJobDone,
                  weak_ptr_factory_.GetWeakPtr(),
                  new_job->job_info.job_id,
                  callback));
+  new_job->abort_callback = CreateErrorRunCallback(callback);
   StartJob(new_job);
 }
 
@@ -297,13 +330,14 @@
 
   JobEntry* new_job = CreateNewJob(TYPE_CONTINUE_GET_RESOURCE_LIST);
   new_job->task = base::Bind(
-      &google_apis::DriveServiceInterface::ContinueGetResourceList,
+      &DriveServiceInterface::ContinueGetResourceList,
       base::Unretained(drive_service_),
       next_url,
       base::Bind(&JobScheduler::OnGetResourceListJobDone,
                  weak_ptr_factory_.GetWeakPtr(),
                  new_job->job_info.job_id,
                  callback));
+  new_job->abort_callback = CreateErrorRunCallback(callback);
   StartJob(new_job);
 }
 
@@ -317,13 +351,14 @@
   JobEntry* new_job = CreateNewJob(TYPE_GET_RESOURCE_ENTRY);
   new_job->context = context;
   new_job->task = base::Bind(
-      &google_apis::DriveServiceInterface::GetResourceEntry,
+      &DriveServiceInterface::GetResourceEntry,
       base::Unretained(drive_service_),
       resource_id,
       base::Bind(&JobScheduler::OnGetResourceEntryJobDone,
                  weak_ptr_factory_.GetWeakPtr(),
                  new_job->job_info.job_id,
                  callback));
+  new_job->abort_callback = CreateErrorRunCallback(callback);
   StartJob(new_job);
 }
 
@@ -335,7 +370,7 @@
 
   JobEntry* new_job = CreateNewJob(TYPE_DELETE_RESOURCE);
   new_job->task = base::Bind(
-      &google_apis::DriveServiceInterface::DeleteResource,
+      &DriveServiceInterface::DeleteResource,
       base::Unretained(drive_service_),
       resource_id,
       "",  // etag
@@ -343,6 +378,7 @@
                  weak_ptr_factory_.GetWeakPtr(),
                  new_job->job_info.job_id,
                  callback));
+  new_job->abort_callback = callback;
   StartJob(new_job);
 }
 
@@ -356,7 +392,7 @@
 
   JobEntry* new_job = CreateNewJob(TYPE_COPY_RESOURCE);
   new_job->task = base::Bind(
-      &google_apis::DriveServiceInterface::CopyResource,
+      &DriveServiceInterface::CopyResource,
       base::Unretained(drive_service_),
       resource_id,
       parent_resource_id,
@@ -365,6 +401,7 @@
                  weak_ptr_factory_.GetWeakPtr(),
                  new_job->job_info.job_id,
                  callback));
+  new_job->abort_callback = CreateErrorRunCallback(callback);
   StartJob(new_job);
 }
 
@@ -377,7 +414,7 @@
 
   JobEntry* new_job = CreateNewJob(TYPE_COPY_HOSTED_DOCUMENT);
   new_job->task = base::Bind(
-      &google_apis::DriveServiceInterface::CopyHostedDocument,
+      &DriveServiceInterface::CopyHostedDocument,
       base::Unretained(drive_service_),
       resource_id,
       new_name,
@@ -385,6 +422,7 @@
                  weak_ptr_factory_.GetWeakPtr(),
                  new_job->job_info.job_id,
                  callback));
+  new_job->abort_callback = CreateErrorRunCallback(callback);
   StartJob(new_job);
 }
 
@@ -397,7 +435,7 @@
 
   JobEntry* new_job = CreateNewJob(TYPE_RENAME_RESOURCE);
   new_job->task = base::Bind(
-      &google_apis::DriveServiceInterface::RenameResource,
+      &DriveServiceInterface::RenameResource,
       base::Unretained(drive_service_),
       resource_id,
       new_name,
@@ -405,6 +443,7 @@
                  weak_ptr_factory_.GetWeakPtr(),
                  new_job->job_info.job_id,
                  callback));
+  new_job->abort_callback = callback;
   StartJob(new_job);
 }
 
@@ -418,7 +457,7 @@
 
   JobEntry* new_job = CreateNewJob(TYPE_TOUCH_RESOURCE);
   new_job->task = base::Bind(
-      &google_apis::DriveServiceInterface::TouchResource,
+      &DriveServiceInterface::TouchResource,
       base::Unretained(drive_service_),
       resource_id,
       modified_date,
@@ -427,6 +466,7 @@
                  weak_ptr_factory_.GetWeakPtr(),
                  new_job->job_info.job_id,
                  callback));
+  new_job->abort_callback = CreateErrorRunCallback(callback);
   StartJob(new_job);
 }
 
@@ -439,7 +479,7 @@
 
   JobEntry* new_job = CreateNewJob(TYPE_ADD_RESOURCE_TO_DIRECTORY);
   new_job->task = base::Bind(
-      &google_apis::DriveServiceInterface::AddResourceToDirectory,
+      &DriveServiceInterface::AddResourceToDirectory,
       base::Unretained(drive_service_),
       parent_resource_id,
       resource_id,
@@ -447,6 +487,7 @@
                  weak_ptr_factory_.GetWeakPtr(),
                  new_job->job_info.job_id,
                  callback));
+  new_job->abort_callback = callback;
   StartJob(new_job);
 }
 
@@ -458,7 +499,7 @@
 
   JobEntry* new_job = CreateNewJob(TYPE_REMOVE_RESOURCE_FROM_DIRECTORY);
   new_job->task = base::Bind(
-      &google_apis::DriveServiceInterface::RemoveResourceFromDirectory,
+      &DriveServiceInterface::RemoveResourceFromDirectory,
       base::Unretained(drive_service_),
       parent_resource_id,
       resource_id,
@@ -466,6 +507,7 @@
                  weak_ptr_factory_.GetWeakPtr(),
                  new_job->job_info.job_id,
                  callback));
+  new_job->abort_callback = callback;
   StartJob(new_job);
 }
 
@@ -477,7 +519,7 @@
 
   JobEntry* new_job = CreateNewJob(TYPE_ADD_NEW_DIRECTORY);
   new_job->task = base::Bind(
-      &google_apis::DriveServiceInterface::AddNewDirectory,
+      &DriveServiceInterface::AddNewDirectory,
       base::Unretained(drive_service_),
       parent_resource_id,
       directory_name,
@@ -485,13 +527,14 @@
                  weak_ptr_factory_.GetWeakPtr(),
                  new_job->job_info.job_id,
                  callback));
+  new_job->abort_callback = CreateErrorRunCallback(callback);
   StartJob(new_job);
 }
 
 JobID JobScheduler::DownloadFile(
     const base::FilePath& virtual_path,
     const base::FilePath& local_cache_path,
-    const GURL& download_url,
+    const std::string& resource_id,
     const ClientContext& context,
     const google_apis::DownloadActionCallback& download_action_callback,
     const google_apis::GetContentCallback& get_content_callback) {
@@ -501,11 +544,10 @@
   new_job->job_info.file_path = virtual_path;
   new_job->context = context;
   new_job->task = base::Bind(
-      &google_apis::DriveServiceInterface::DownloadFile,
+      &DriveServiceInterface::DownloadFile,
       base::Unretained(drive_service_),
-      virtual_path,
       local_cache_path,
-      download_url,
+      resource_id,
       base::Bind(&JobScheduler::OnDownloadActionJobDone,
                  weak_ptr_factory_.GetWeakPtr(),
                  new_job->job_info.job_id,
@@ -514,7 +556,7 @@
       base::Bind(&JobScheduler::UpdateProgress,
                  weak_ptr_factory_.GetWeakPtr(),
                  new_job->job_info.job_id));
-
+  new_job->abort_callback = CreateErrorRunCallback(download_action_callback);
   StartJob(new_job);
   return new_job->job_info.job_id;
 }
@@ -535,13 +577,11 @@
 
   UploadNewFileParams params;
   params.parent_resource_id = parent_resource_id;
-  params.drive_file_path = drive_file_path;
   params.local_file_path = local_file_path;
   params.title = title;
   params.content_type = content_type;
 
   ResumeUploadParams resume_params;
-  resume_params.drive_file_path = params.drive_file_path;
   resume_params.local_file_path = params.local_file_path;
   resume_params.content_type = params.content_type;
 
@@ -554,7 +594,7 @@
                                         weak_ptr_factory_.GetWeakPtr(),
                                         new_job->job_info.job_id);
   new_job->task = base::Bind(&RunUploadNewFile, uploader_.get(), params);
-
+  new_job->abort_callback = CreateErrorRunCallback(callback);
   StartJob(new_job);
 }
 
@@ -574,13 +614,11 @@
 
   UploadExistingFileParams params;
   params.resource_id = resource_id;
-  params.drive_file_path = drive_file_path;
   params.local_file_path = local_file_path;
   params.content_type = content_type;
   params.etag = etag;
 
   ResumeUploadParams resume_params;
-  resume_params.drive_file_path = params.drive_file_path;
   resume_params.local_file_path = params.local_file_path;
   resume_params.content_type = params.content_type;
 
@@ -593,7 +631,7 @@
                                         weak_ptr_factory_.GetWeakPtr(),
                                         new_job->job_info.job_id);
   new_job->task = base::Bind(&RunUploadExistingFile, uploader_.get(), params);
-
+  new_job->abort_callback = CreateErrorRunCallback(callback);
   StartJob(new_job);
 }
 
@@ -614,13 +652,11 @@
 
   UploadNewFileParams params;
   params.parent_resource_id = parent_resource_id;
-  params.drive_file_path = drive_file_path;
   params.local_file_path = kDevNull;  // Upload an empty file.
   params.title = title;
   params.content_type = content_type;
 
   ResumeUploadParams resume_params;
-  resume_params.drive_file_path = params.drive_file_path;
   resume_params.local_file_path = params.local_file_path;
   resume_params.content_type = params.content_type;
 
@@ -632,7 +668,7 @@
   params.progress_callback = google_apis::ProgressCallback();
 
   new_job->task = base::Bind(&RunUploadNewFile, uploader_.get(), params);
-
+  new_job->abort_callback = CreateErrorRunCallback(callback);
   StartJob(new_job);
 }
 
@@ -667,12 +703,24 @@
 void JobScheduler::DoJobLoop(QueueType queue_type) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
 
-  JobID job_id = -1;
-  if (!queue_[queue_type]->PopForRun(GetCurrentAcceptedPriority(queue_type),
-                                     &job_id)) {
-    return;
+  const int accepted_priority = GetCurrentAcceptedPriority(queue_type);
+
+  // Abort all USER_INITAITED jobs when not accepted.
+  if (accepted_priority < USER_INITIATED) {
+    std::vector<JobID> jobs;
+    queue_[queue_type]->GetQueuedJobs(USER_INITIATED, &jobs);
+    for (size_t i = 0; i < jobs.size(); ++i) {
+      JobEntry* job = job_map_.Lookup(jobs[i]);
+      DCHECK(job);
+      AbortNotRunningJob(job, google_apis::GDATA_NO_CONNECTION);
+    }
   }
 
+  // Run the job with the highest priority in the queue.
+  JobID job_id = -1;
+  if (!queue_[queue_type]->PopForRun(accepted_priority, &job_id))
+    return;
+
   JobEntry* entry = job_map_.Lookup(job_id);
   DCHECK(entry);
 
@@ -693,8 +741,7 @@
 
   const int kNoJobShouldRun = -1;
 
-  // Should stop if the gdata feature was disabled while running the fetch
-  // loop.
+  // Should stop if Drive was disabled while running the fetch loop.
   if (profile_->GetPrefs()->GetBoolean(prefs::kDisableDrive))
     return kNoJobShouldRun;
 
@@ -724,8 +771,9 @@
   if (disable_throttling_) {
     delay = base::TimeDelta::FromSeconds(0);
   } else {
+    // Exponential backoff: https://developers.google.com/drive/handle-errors.
     delay =
-      base::TimeDelta::FromSeconds(pow(2, throttle_count_ - 1)) +
+      base::TimeDelta::FromSeconds(1 << (throttle_count_ - 1)) +
       base::TimeDelta::FromMilliseconds(base::RandInt(0, 1000));
   }
   VLOG(1) << "Throttling for " << delay.InMillisecondsF();
@@ -785,7 +833,7 @@
   } 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. This is the only place of the removal.
+    // remove the job info from the map.
     job_map_.Remove(job_id);
 
     ResetThrottleAndContinueJobLoop(queue_type);
@@ -884,7 +932,6 @@
 
     ResumeUploadFileParams params;
     params.upload_location = upload_location;
-    params.drive_file_path = resume_params.drive_file_path;
     params.local_file_path = resume_params.local_file_path;
     params.content_type = resume_params.content_type;
     params.callback = base::Bind(&JobScheduler::OnUploadCompletionJobDone,
@@ -915,14 +962,11 @@
     net::NetworkChangeNotifier::ConnectionType type) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
 
-  // Resume the job loop if the network is back online. Note that we don't
-  // need to check the type of the network as it will be checked in
-  // ShouldStopJobLoop() as soon as the loop is resumed.
-  if (!net::NetworkChangeNotifier::IsOffline()) {
-    for (int i = METADATA_QUEUE; i < NUM_QUEUES; ++i) {
-      DoJobLoop(static_cast<QueueType>(i));
-    }
-  }
+  // Resume the job loop.
+  // Note that we don't need to check the network connection status as it will
+  // be checked in GetCurrentAcceptedPriority().
+  for (int i = METADATA_QUEUE; i < NUM_QUEUES; ++i)
+    DoJobLoop(static_cast<QueueType>(i));
 }
 
 JobScheduler::QueueType JobScheduler::GetJobQueueType(JobType type) {
@@ -955,6 +999,26 @@
   return FILE_QUEUE;
 }
 
+void JobScheduler::AbortNotRunningJob(JobEntry* job,
+                                      google_apis::GDataErrorCode error) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+  const base::TimeDelta elapsed = base::Time::Now() - job->job_info.start_time;
+  const QueueType queue_type = GetJobQueueType(job->job_info.job_type);
+  util::Log("Job aborted: %s => %s (elapsed time: %sms) - %s",
+            job->job_info.ToString().c_str(),
+            GDataErrorCodeToString(error).c_str(),
+            base::Int64ToString(elapsed.InMilliseconds()).c_str(),
+            GetQueueInfo(queue_type).c_str());
+
+  base::Callback<void(google_apis::GDataErrorCode)> callback =
+      job->abort_callback;
+  queue_[GetJobQueueType(job->job_info.job_type)]->Remove(job->job_info.job_id);
+  job_map_.Remove(job->job_info.job_id);
+  base::MessageLoopProxy::current()->PostTask(FROM_HERE,
+                                              base::Bind(callback, error));
+}
+
 void JobScheduler::NotifyJobAdded(const JobInfo& job_info) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   FOR_EACH_OBSERVER(JobListObserver, observer_list_, OnJobAdded(job_info));
diff --git a/chrome/browser/chromeos/drive/job_scheduler.h b/chrome/browser/chromeos/drive/job_scheduler.h
index 55bd7bc..d0388fd 100644
--- a/chrome/browser/chromeos/drive/job_scheduler.h
+++ b/chrome/browser/chromeos/drive/job_scheduler.h
@@ -19,6 +19,10 @@
 
 class Profile;
 
+namespace base {
+class SeqencedTaskRunner;
+}
+
 namespace drive {
 
 // The JobScheduler is responsible for queuing and scheduling drive
@@ -48,7 +52,8 @@
       public JobListInterface {
  public:
   JobScheduler(Profile* profile,
-               google_apis::DriveServiceInterface* drive_service);
+               DriveServiceInterface* drive_service,
+               base::SequencedTaskRunner* blocking_task_runner);
   virtual ~JobScheduler();
 
   // JobListInterface overrides.
@@ -146,7 +151,7 @@
   JobID DownloadFile(
       const base::FilePath& virtual_path,
       const base::FilePath& local_cache_path,
-      const GURL& download_url,
+      const std::string& resource_id,
       const ClientContext& context,
       const google_apis::DownloadActionCallback& download_action_callback,
       const google_apis::GetContentCallback& get_content_callback);
@@ -208,6 +213,10 @@
 
     // The callback to cancel the running job. It is returned from task.Run().
     google_apis::CancelCallback cancel_callback;
+
+    // The callback to notify an error to the client of JobScheduler.
+    // This is used to notify cancel of a job that is not running yet.
+    base::Callback<void(google_apis::GDataErrorCode)> abort_callback;
   };
 
   // Parameters for DriveUploader::ResumeUploadFile.
@@ -302,6 +311,9 @@
   // For testing only.  Disables throttling so that testing is faster.
   void SetDisableThrottling(bool disable) { disable_throttling_ = disable; }
 
+  // Aborts a job which is not in STATE_RUNNING.
+  void AbortNotRunningJob(JobEntry* job, google_apis::GDataErrorCode error);
+
   // Notifies updates to observers.
   void NotifyJobAdded(const JobInfo& job_info);
   void NotifyJobDone(const JobInfo& job_info,
@@ -332,8 +344,8 @@
   // The list of observers for the scheduler.
   ObserverList<JobListObserver> observer_list_;
 
-  google_apis::DriveServiceInterface* drive_service_;
-  scoped_ptr<google_apis::DriveUploaderInterface> uploader_;
+  DriveServiceInterface* drive_service_;
+  scoped_ptr<DriveUploaderInterface> uploader_;
 
   Profile* profile_;
 
diff --git a/chrome/browser/chromeos/drive/job_scheduler_unittest.cc b/chrome/browser/chromeos/drive/job_scheduler_unittest.cc
index 6bb720a..57f3dbe 100644
--- a/chrome/browser/chromeos/drive/job_scheduler_unittest.cc
+++ b/chrome/browser/chromeos/drive/job_scheduler_unittest.cc
@@ -9,12 +9,13 @@
 #include "base/bind.h"
 #include "base/file_util.h"
 #include "base/prefs/pref_service.h"
+#include "base/run_loop.h"
 #include "base/stl_util.h"
-#include "base/threading/sequenced_worker_pool.h"
 #include "chrome/browser/chromeos/drive/test_util.h"
 #include "chrome/browser/drive/fake_drive_service.h"
 #include "chrome/browser/google_apis/drive_api_parser.h"
 #include "chrome/browser/google_apis/gdata_wapi_parser.h"
+#include "chrome/browser/google_apis/test_util.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/testing_profile.h"
 #include "content/public/test/test_browser_thread_bundle.h"
@@ -24,20 +25,6 @@
 
 namespace {
 
-class FakeNetworkChangeNotifier : public net::NetworkChangeNotifier {
- public:
-  FakeNetworkChangeNotifier() : type_(CONNECTION_NONE) {}
-
-  void set_connection_type(ConnectionType type) { type_ = type; }
-
-  virtual ConnectionType GetCurrentConnectionType() const OVERRIDE {
-    return type_;
-  }
-
- private:
-  net::NetworkChangeNotifier::ConnectionType type_;
-};
-
 void CopyResourceIdFromGetResourceEntryCallback(
     std::vector<std::string>* id_list_out,
     const std::string& requested_id,
@@ -105,39 +92,28 @@
   }
 
   virtual void SetUp() OVERRIDE {
-    fake_network_change_notifier_.reset(new FakeNetworkChangeNotifier);
+    fake_network_change_notifier_.reset(
+        new test_util::FakeNetworkChangeNotifier);
 
-    fake_drive_service_.reset(new google_apis::FakeDriveService());
+    fake_drive_service_.reset(new FakeDriveService());
     fake_drive_service_->LoadResourceListForWapi(
-        "chromeos/gdata/root_feed.json");
+        "gdata/root_feed.json");
     fake_drive_service_->LoadAccountMetadataForWapi(
-        "chromeos/gdata/account_metadata.json");
+        "gdata/account_metadata.json");
     fake_drive_service_->LoadAppListForDriveApi(
-        "chromeos/drive/applist.json");
+        "drive/applist.json");
 
     scheduler_.reset(new JobScheduler(profile_.get(),
-                                      fake_drive_service_.get()));
+                                      fake_drive_service_.get(),
+                                      base::MessageLoopProxy::current()));
     scheduler_->SetDisableThrottling(true);
   }
 
-  virtual void TearDown() OVERRIDE {
-    // The scheduler should be deleted before NetworkLibrary, as it
-    // registers itself as observer of NetworkLibrary.
-    scheduler_.reset();
-    google_apis::test_util::RunBlockingPoolTask();
-    fake_drive_service_.reset();
-    fake_network_change_notifier_.reset();
-  }
-
  protected:
   // Sets up FakeNetworkChangeNotifier as if it's connected to a network with
   // the specified connection type.
   void ChangeConnectionType(net::NetworkChangeNotifier::ConnectionType type) {
-    fake_network_change_notifier_->set_connection_type(type);
-    // Notify the sync client that the network is changed. This is done via
-    // NetworkChangeNotifier in production, but here, we simulate the behavior
-    // by directly calling OnConnectionTypeChanged().
-    scheduler_->OnConnectionTypeChanged(type);
+    fake_network_change_notifier_->SetConnectionType(type);
   }
 
   // Sets up FakeNetworkChangeNotifier as if it's connected to wifi network.
@@ -160,11 +136,16 @@
     ChangeConnectionType(net::NetworkChangeNotifier::CONNECTION_NONE);
   }
 
+  static int GetMetadataQueueMaxJobCount() {
+    return JobScheduler::kMaxJobCount[JobScheduler::METADATA_QUEUE];
+  }
+
   content::TestBrowserThreadBundle thread_bundle_;
   scoped_ptr<TestingProfile> profile_;
+  scoped_ptr<test_util::FakeNetworkChangeNotifier>
+      fake_network_change_notifier_;
+  scoped_ptr<FakeDriveService> fake_drive_service_;
   scoped_ptr<JobScheduler> scheduler_;
-  scoped_ptr<FakeNetworkChangeNotifier> fake_network_change_notifier_;
-  scoped_ptr<google_apis::FakeDriveService> fake_drive_service_;
 };
 
 TEST_F(JobSchedulerTest, GetAboutResource) {
@@ -175,7 +156,7 @@
   scheduler_->GetAboutResource(
       google_apis::test_util::CreateCopyResultCallback(
           &error, &about_resource));
-  google_apis::test_util::RunBlockingPoolTask();
+  base::RunLoop().RunUntilIdle();
   ASSERT_EQ(google_apis::HTTP_SUCCESS, error);
   ASSERT_TRUE(about_resource);
 }
@@ -188,7 +169,7 @@
 
   scheduler_->GetAppList(
       google_apis::test_util::CreateCopyResultCallback(&error, &app_list));
-  google_apis::test_util::RunBlockingPoolTask();
+  base::RunLoop().RunUntilIdle();
 
   ASSERT_EQ(google_apis::HTTP_SUCCESS, error);
   ASSERT_TRUE(app_list);
@@ -203,7 +184,7 @@
   scheduler_->GetAllResourceList(
       google_apis::test_util::CreateCopyResultCallback(
           &error, &resource_list));
-  google_apis::test_util::RunBlockingPoolTask();
+  base::RunLoop().RunUntilIdle();
 
   ASSERT_EQ(google_apis::HTTP_SUCCESS, error);
   ASSERT_TRUE(resource_list);
@@ -219,7 +200,7 @@
       fake_drive_service_->GetRootResourceId(),
       google_apis::test_util::CreateCopyResultCallback(
           &error, &resource_list));
-  google_apis::test_util::RunBlockingPoolTask();
+  base::RunLoop().RunUntilIdle();
 
   ASSERT_EQ(google_apis::HTTP_SUCCESS, error);
   ASSERT_TRUE(resource_list);
@@ -235,7 +216,7 @@
       "File",  // search query
       google_apis::test_util::CreateCopyResultCallback(
           &error, &resource_list));
-  google_apis::test_util::RunBlockingPoolTask();
+  base::RunLoop().RunUntilIdle();
 
   ASSERT_EQ(google_apis::HTTP_SUCCESS, error);
   ASSERT_TRUE(resource_list);
@@ -256,7 +237,7 @@
         "new directory",
         google_apis::test_util::CreateCopyResultCallback(
             &error, &resource_entry));
-    google_apis::test_util::RunBlockingPoolTask();
+    base::RunLoop().RunUntilIdle();
     ASSERT_EQ(google_apis::HTTP_CREATED, error);
   }
 
@@ -266,7 +247,7 @@
       654321 + 1,  // start_changestamp
       google_apis::test_util::CreateCopyResultCallback(
           &error, &resource_list));
-  google_apis::test_util::RunBlockingPoolTask();
+  base::RunLoop().RunUntilIdle();
 
   ASSERT_EQ(google_apis::HTTP_SUCCESS, error);
   ASSERT_TRUE(resource_list);
@@ -282,7 +263,7 @@
   scheduler_->GetAllResourceList(
       google_apis::test_util::CreateCopyResultCallback(
           &error, &resource_list));
-  google_apis::test_util::RunBlockingPoolTask();
+  base::RunLoop().RunUntilIdle();
 
   ASSERT_EQ(google_apis::HTTP_SUCCESS, error);
   ASSERT_TRUE(resource_list);
@@ -300,7 +281,7 @@
       next_url,
       google_apis::test_util::CreateCopyResultCallback(
           &error, &resource_list));
-  google_apis::test_util::RunBlockingPoolTask();
+  base::RunLoop().RunUntilIdle();
 
   ASSERT_EQ(google_apis::HTTP_SUCCESS, error);
   ASSERT_TRUE(resource_list);
@@ -316,7 +297,7 @@
       "file:2_file_resource_id",  // resource ID
       ClientContext(USER_INITIATED),
       google_apis::test_util::CreateCopyResultCallback(&error, &entry));
-  google_apis::test_util::RunBlockingPoolTask();
+  base::RunLoop().RunUntilIdle();
 
   ASSERT_EQ(google_apis::HTTP_SUCCESS, error);
   ASSERT_TRUE(entry);
@@ -330,7 +311,7 @@
   scheduler_->DeleteResource(
       "file:2_file_resource_id",
       google_apis::test_util::CreateCopyResultCallback(&error));
-  google_apis::test_util::RunBlockingPoolTask();
+  base::RunLoop().RunUntilIdle();
 
   ASSERT_EQ(google_apis::HTTP_SUCCESS, error);
 }
@@ -346,7 +327,7 @@
       "folder:1_folder_resource_id",  // parent resource ID
       "New Document",  // new name
       google_apis::test_util::CreateCopyResultCallback(&error, &entry));
-  google_apis::test_util::RunBlockingPoolTask();
+  base::RunLoop().RunUntilIdle();
 
   ASSERT_EQ(google_apis::HTTP_SUCCESS, error);
   ASSERT_TRUE(entry);
@@ -362,7 +343,7 @@
       "document:5_document_resource_id",  // resource ID
       "New Document",  // new name
       google_apis::test_util::CreateCopyResultCallback(&error, &entry));
-  google_apis::test_util::RunBlockingPoolTask();
+  base::RunLoop().RunUntilIdle();
 
   ASSERT_EQ(google_apis::HTTP_SUCCESS, error);
   ASSERT_TRUE(entry);
@@ -377,7 +358,7 @@
       "file:2_file_resource_id",
       "New Name",
       google_apis::test_util::CreateCopyResultCallback(&error));
-  google_apis::test_util::RunBlockingPoolTask();
+  base::RunLoop().RunUntilIdle();
 
   ASSERT_EQ(google_apis::HTTP_SUCCESS, error);
 }
@@ -391,7 +372,7 @@
       "folder:1_folder_resource_id",
       "file:2_file_resource_id",
       google_apis::test_util::CreateCopyResultCallback(&error));
-  google_apis::test_util::RunBlockingPoolTask();
+  base::RunLoop().RunUntilIdle();
 
   ASSERT_EQ(google_apis::HTTP_SUCCESS, error);
 }
@@ -405,7 +386,7 @@
       "folder:1_folder_resource_id",
       "file:subdirectory_file_1_id",  // resource ID
       google_apis::test_util::CreateCopyResultCallback(&error));
-  google_apis::test_util::RunBlockingPoolTask();
+  base::RunLoop().RunUntilIdle();
 
   ASSERT_EQ(google_apis::HTTP_SUCCESS, error);
 }
@@ -420,16 +401,26 @@
       fake_drive_service_->GetRootResourceId(),  // Root directory.
       "New Directory",
       google_apis::test_util::CreateCopyResultCallback(&error, &entry));
-  google_apis::test_util::RunBlockingPoolTask();
+  base::RunLoop().RunUntilIdle();
 
   ASSERT_EQ(google_apis::HTTP_CREATED, error);
   ASSERT_TRUE(entry);
 }
 
 TEST_F(JobSchedulerTest, GetResourceEntryPriority) {
-  // Disconnect from the network to prevent jobs from starting.
-  ConnectToNone();
+  // Saturate the metadata job queue with uninteresting jobs to prevent
+  // following jobs from starting.
+  google_apis::GDataErrorCode error_dontcare = google_apis::GDATA_OTHER_ERROR;
+  scoped_ptr<google_apis::ResourceEntry> entry_dontcare;
+  for (int i = 0; i < GetMetadataQueueMaxJobCount(); ++i) {
+    scheduler_->GetResourceEntry(
+        "uninteresting_resource_id",
+        ClientContext(USER_INITIATED),
+        google_apis::test_util::CreateCopyResultCallback(&error_dontcare,
+                                                         &entry_dontcare));
+  }
 
+  // Start jobs with different priorities.
   std::string resource_1("file:1_file_resource_id");
   std::string resource_2("file:2_file_resource_id");
   std::string resource_3("file:3_file_resource_id");
@@ -461,40 +452,54 @@
                  &resource_ids,
                  resource_4));
 
-  // Reconnect to the network to start all jobs.
-  ConnectToWifi();
-  google_apis::test_util::RunBlockingPoolTask();
+  base::RunLoop().RunUntilIdle();
 
   ASSERT_EQ(resource_ids.size(), 4ul);
-  ASSERT_EQ(resource_ids[0], resource_1);
-  ASSERT_EQ(resource_ids[1], resource_4);
-  ASSERT_EQ(resource_ids[2], resource_2);
-  ASSERT_EQ(resource_ids[3], resource_3);
+  EXPECT_EQ(resource_ids[0], resource_1);
+  EXPECT_EQ(resource_ids[1], resource_4);
+  EXPECT_EQ(resource_ids[2], resource_2);
+  EXPECT_EQ(resource_ids[3], resource_3);
 }
 
-TEST_F(JobSchedulerTest, GetResourceEntryNoConnection) {
+TEST_F(JobSchedulerTest, GetResourceEntryNoConnectionUserInitiated) {
   ConnectToNone();
 
-  std::string resource("file:1_file_resource_id");
-  std::vector<std::string> resource_ids;
+  std::string resource_id("file:2_file_resource_id");
 
+  google_apis::GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
+  scoped_ptr<google_apis::ResourceEntry> entry;
   scheduler_->GetResourceEntry(
-      resource,  // resource ID
-      ClientContext(BACKGROUND),
-      base::Bind(&CopyResourceIdFromGetResourceEntryCallback,
-                 &resource_ids,
-                 resource));
-  google_apis::test_util::RunBlockingPoolTask();
+      resource_id,
+      ClientContext(USER_INITIATED),
+      google_apis::test_util::CreateCopyResultCallback(&error, &entry));
+  base::RunLoop().RunUntilIdle();
 
-  ASSERT_EQ(resource_ids.size(), 0ul);
+  EXPECT_EQ(google_apis::GDATA_NO_CONNECTION, error);
+}
+
+TEST_F(JobSchedulerTest, GetResourceEntryNoConnectionBackground) {
+  ConnectToNone();
+
+  std::string resource_id("file:2_file_resource_id");
+
+  google_apis::GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
+  scoped_ptr<google_apis::ResourceEntry> entry;
+  scheduler_->GetResourceEntry(
+      resource_id,
+      ClientContext(BACKGROUND),
+      google_apis::test_util::CreateCopyResultCallback(&error, &entry));
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_FALSE(entry);
 
   // Reconnect to the net.
   ConnectToWifi();
 
-  google_apis::test_util::RunBlockingPoolTask();
+  base::RunLoop().RunUntilIdle();
 
-  ASSERT_EQ(resource_ids.size(), 1ul);
-  ASSERT_EQ(resource_ids[0], resource);
+  EXPECT_EQ(google_apis::HTTP_SUCCESS, error);
+  ASSERT_TRUE(entry);
+  EXPECT_EQ(resource_id, entry->resource_id());
 }
 
 TEST_F(JobSchedulerTest, DownloadFileCellularDisabled) {
@@ -507,7 +512,6 @@
   base::ScopedTempDir temp_dir;
   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
 
-  const GURL kContentUrl("https://file_content_url/");
   const base::FilePath kOutputFilePath =
       temp_dir.path().AppendASCII("whatever.txt");
   google_apis::GDataErrorCode download_error = google_apis::GDATA_OTHER_ERROR;
@@ -515,7 +519,7 @@
   scheduler_->DownloadFile(
       base::FilePath::FromUTF8Unsafe("drive/whatever.txt"),  // virtual path
       kOutputFilePath,
-      kContentUrl,
+      "file:2_file_resource_id",
       ClientContext(BACKGROUND),
       google_apis::test_util::CreateCopyResultCallback(
           &download_error, &output_file_path),
@@ -528,7 +532,7 @@
   scheduler_->GetAboutResource(
       google_apis::test_util::CreateCopyResultCallback(
           &metadata_error, &about_resource));
-  google_apis::test_util::RunBlockingPoolTask();
+  base::RunLoop().RunUntilIdle();
 
   // Check the metadata
   ASSERT_EQ(google_apis::HTTP_SUCCESS, metadata_error);
@@ -540,7 +544,7 @@
   // Switch to a Wifi connection
   ConnectToWifi();
 
-  google_apis::test_util::RunBlockingPoolTask();
+  base::RunLoop().RunUntilIdle();
 
   // Check the download again
   EXPECT_EQ(google_apis::HTTP_SUCCESS, download_error);
@@ -560,7 +564,6 @@
   base::ScopedTempDir temp_dir;
   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
 
-  const GURL kContentUrl("https://file_content_url/");
   const base::FilePath kOutputFilePath =
       temp_dir.path().AppendASCII("whatever.txt");
   google_apis::GDataErrorCode download_error = google_apis::GDATA_OTHER_ERROR;
@@ -568,7 +571,7 @@
   scheduler_->DownloadFile(
       base::FilePath::FromUTF8Unsafe("drive/whatever.txt"),  // virtual path
       kOutputFilePath,
-      kContentUrl,
+      "file:2_file_resource_id",
       ClientContext(BACKGROUND),
       google_apis::test_util::CreateCopyResultCallback(
           &download_error, &output_file_path),
@@ -581,7 +584,7 @@
   scheduler_->GetAboutResource(
       google_apis::test_util::CreateCopyResultCallback(
           &metadata_error, &about_resource));
-  google_apis::test_util::RunBlockingPoolTask();
+  base::RunLoop().RunUntilIdle();
 
   // Check the metadata
   ASSERT_EQ(google_apis::HTTP_SUCCESS, metadata_error);
@@ -593,7 +596,7 @@
   // Switch to a Wifi connection
   ConnectToWifi();
 
-  google_apis::test_util::RunBlockingPoolTask();
+  base::RunLoop().RunUntilIdle();
 
   // Check the download again
   EXPECT_EQ(google_apis::HTTP_SUCCESS, download_error);
@@ -613,7 +616,6 @@
   base::ScopedTempDir temp_dir;
   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
 
-  const GURL kContentUrl("https://file_content_url/");
   const base::FilePath kOutputFilePath =
       temp_dir.path().AppendASCII("whatever.txt");
   google_apis::GDataErrorCode download_error = google_apis::GDATA_OTHER_ERROR;
@@ -621,7 +623,7 @@
   scheduler_->DownloadFile(
       base::FilePath::FromUTF8Unsafe("drive/whatever.txt"),  // virtual path
       kOutputFilePath,
-      kContentUrl,
+      "file:2_file_resource_id",
       ClientContext(BACKGROUND),
       google_apis::test_util::CreateCopyResultCallback(
           &download_error, &output_file_path),
@@ -634,7 +636,7 @@
   scheduler_->GetAboutResource(
       google_apis::test_util::CreateCopyResultCallback(
           &metadata_error, &about_resource));
-  google_apis::test_util::RunBlockingPoolTask();
+  base::RunLoop().RunUntilIdle();
 
   // Check the metadata
   ASSERT_EQ(google_apis::HTTP_SUCCESS, metadata_error);
@@ -658,7 +660,6 @@
   base::ScopedTempDir temp_dir;
   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
 
-  const GURL kContentUrl("https://file_content_url/");
   const base::FilePath kOutputFilePath =
       temp_dir.path().AppendASCII("whatever.txt");
   google_apis::GDataErrorCode download_error = google_apis::GDATA_OTHER_ERROR;
@@ -666,7 +667,7 @@
   scheduler_->DownloadFile(
       base::FilePath::FromUTF8Unsafe("drive/whatever.txt"),  // virtual path
       kOutputFilePath,
-      kContentUrl,
+      "file:2_file_resource_id",
       ClientContext(BACKGROUND),
       google_apis::test_util::CreateCopyResultCallback(
           &download_error, &output_file_path),
@@ -679,7 +680,7 @@
   scheduler_->GetAboutResource(
       google_apis::test_util::CreateCopyResultCallback(
           &metadata_error, &about_resource));
-  google_apis::test_util::RunBlockingPoolTask();
+  base::RunLoop().RunUntilIdle();
 
   // Check the metadata
   ASSERT_EQ(google_apis::HTTP_SUCCESS, metadata_error);
@@ -730,7 +731,7 @@
   scheduler_->DownloadFile(
       base::FilePath::FromUTF8Unsafe("drive/whatever.txt"),  // virtual path
       temp_dir.path().AppendASCII("whatever.txt"),
-      GURL("https://file_content_url/"),
+      "file:2_file_resource_id",
       ClientContext(BACKGROUND),
       google_apis::test_util::CreateCopyResultCallback(&error, &path),
       google_apis::GetContentCallback());
@@ -775,7 +776,7 @@
   EXPECT_FALSE(logger.Has(JobListLogger::DONE, TYPE_COPY_HOSTED_DOCUMENT));
 
   // Run the jobs.
-  google_apis::test_util::RunBlockingPoolTask();
+  base::RunLoop().RunUntilIdle();
 
   // All jobs except the BACKGROUND job should have started running (UPDATED)
   // and then finished (DONE).
@@ -800,7 +801,7 @@
 
   // Run the background downloading job as well.
   ConnectToWifi();
-  google_apis::test_util::RunBlockingPoolTask();
+  base::RunLoop().RunUntilIdle();
 
   // All jobs should have finished.
   EXPECT_EQ(0U, scheduler_->GetJobInfoList().size());
@@ -825,11 +826,11 @@
   scheduler_->DownloadFile(
       base::FilePath::FromUTF8Unsafe("drive/whatever.txt"),  // virtual path
       temp_dir.path().AppendASCII("whatever.txt"),
-      GURL("https://file_content_url/"),
+      "file:2_file_resource_id",
       ClientContext(BACKGROUND),
       google_apis::test_util::CreateCopyResultCallback(&error, &path),
       google_apis::GetContentCallback());
-  google_apis::test_util::RunBlockingPoolTask();
+  base::RunLoop().RunUntilIdle();
 
   std::vector<int64> download_progress;
   logger.GetProgressInfo(TYPE_DOWNLOAD_FILE, &download_progress);
@@ -853,7 +854,7 @@
       "plain/plain",
       ClientContext(BACKGROUND),
       google_apis::test_util::CreateCopyResultCallback(&upload_error, &entry));
-  google_apis::test_util::RunBlockingPoolTask();
+  base::RunLoop().RunUntilIdle();
 
   std::vector<int64> upload_progress;
   logger.GetProgressInfo(TYPE_UPLOAD_NEW_FILE, &upload_progress);
diff --git a/chrome/browser/chromeos/drive/local_file_reader_unittest.cc b/chrome/browser/chromeos/drive/local_file_reader_unittest.cc
index dd8acf4..0af9c0a 100644
--- a/chrome/browser/chromeos/drive/local_file_reader_unittest.cc
+++ b/chrome/browser/chromeos/drive/local_file_reader_unittest.cc
@@ -44,9 +44,6 @@
 
 class LocalFileReaderTest : public ::testing::Test {
  protected:
-  LocalFileReaderTest() {
-  }
-
   virtual void SetUp() OVERRIDE {
     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
     worker_thread_.reset(new base::Thread("LocalFileReaderTest"));
@@ -55,11 +52,6 @@
         new LocalFileReader(worker_thread_->message_loop_proxy()));
   }
 
-  virtual void TearDown() OVERRIDE {
-    file_reader_.reset();
-    worker_thread_.reset();
-  }
-
   base::MessageLoop message_loop_;
   base::ScopedTempDir temp_dir_;
   scoped_ptr<base::Thread> worker_thread_;
diff --git a/chrome/browser/chromeos/drive/logging.cc b/chrome/browser/chromeos/drive/logging.cc
index 8370957..48702a1 100644
--- a/chrome/browser/chromeos/drive/logging.cc
+++ b/chrome/browser/chromeos/drive/logging.cc
@@ -6,13 +6,13 @@
 
 #include "base/lazy_instance.h"
 #include "base/strings/stringprintf.h"
-#include "chrome/browser/google_apis/event_logger.h"
+#include "chrome/browser/drive/event_logger.h"
 
 namespace drive {
 namespace util {
 namespace {
 
-static base::LazyInstance<google_apis::EventLogger> g_logger =
+static base::LazyInstance<EventLogger> g_logger =
     LAZY_INSTANCE_INITIALIZER;
 
 }  // namespace
@@ -27,12 +27,12 @@
 
   // On thread-safety: LazyInstance guarantees thread-safety for the object
   // creation. EventLogger::Log() internally maintains the lock.
-  google_apis::EventLogger* ptr = g_logger.Pointer();
+  EventLogger* ptr = g_logger.Pointer();
   ptr->Log("%s", what.c_str());
 }
 
-std::vector<google_apis::EventLogger::Event> GetLogHistory() {
-  google_apis::EventLogger* ptr = g_logger.Pointer();
+std::vector<EventLogger::Event> GetLogHistory() {
+  EventLogger* ptr = g_logger.Pointer();
   return ptr->GetHistory();
 }
 
diff --git a/chrome/browser/chromeos/drive/logging.h b/chrome/browser/chromeos/drive/logging.h
index 1c679be..a2e4625 100644
--- a/chrome/browser/chromeos/drive/logging.h
+++ b/chrome/browser/chromeos/drive/logging.h
@@ -8,7 +8,7 @@
 #include <string>
 #include <vector>
 
-#include "chrome/browser/google_apis/event_logger.h"
+#include "chrome/browser/drive/event_logger.h"
 
 namespace drive {
 // Originally wanted to use 'logging' here, but it conflicts with
@@ -21,7 +21,7 @@
 
 // Returns the log history.
 // This function can be called from any thread.
-std::vector<google_apis::EventLogger::Event> GetLogHistory();
+std::vector<EventLogger::Event> GetLogHistory();
 
 }  // namespace util
 }  // namespace drive
diff --git a/chrome/browser/chromeos/drive/mock_directory_change_observer.cc b/chrome/browser/chromeos/drive/mock_directory_change_observer.cc
deleted file mode 100644
index 1331ab5..0000000
--- a/chrome/browser/chromeos/drive/mock_directory_change_observer.cc
+++ /dev/null
@@ -1,15 +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/chromeos/drive/mock_directory_change_observer.h"
-
-namespace drive {
-
-MockDirectoryChangeObserver::MockDirectoryChangeObserver() {
-}
-
-MockDirectoryChangeObserver::~MockDirectoryChangeObserver() {
-}
-
-}  // namespace drive
diff --git a/chrome/browser/chromeos/drive/mock_directory_change_observer.h b/chrome/browser/chromeos/drive/mock_directory_change_observer.h
deleted file mode 100644
index b503a70..0000000
--- a/chrome/browser/chromeos/drive/mock_directory_change_observer.h
+++ /dev/null
@@ -1,26 +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_CHROMEOS_DRIVE_MOCK_DIRECTORY_CHANGE_OBSERVER_H_
-#define CHROME_BROWSER_CHROMEOS_DRIVE_MOCK_DIRECTORY_CHANGE_OBSERVER_H_
-
-#include "base/files/file_path.h"
-#include "chrome/browser/chromeos/drive/file_system_observer.h"
-#include "testing/gmock/include/gmock/gmock.h"
-
-namespace drive {
-
-// Mock for FileSystemObserver::OnDirectoryChanged().
-class MockDirectoryChangeObserver : public FileSystemObserver {
- public:
-  MockDirectoryChangeObserver();
-  virtual ~MockDirectoryChangeObserver();
-
-  // FileSystemObserver overrides.
-  MOCK_METHOD1(OnDirectoryChanged, void(const base::FilePath& directory_path));
-};
-
-}  // namespace drive
-
-#endif  // CHROME_BROWSER_CHROMEOS_DRIVE_MOCK_DIRECTORY_CHANGE_OBSERVER_H_
diff --git a/chrome/browser/chromeos/drive/remove_stale_cache_files.cc b/chrome/browser/chromeos/drive/remove_stale_cache_files.cc
index c013fdf..798a559 100644
--- a/chrome/browser/chromeos/drive/remove_stale_cache_files.cc
+++ b/chrome/browser/chromeos/drive/remove_stale_cache_files.cc
@@ -16,38 +16,23 @@
 namespace drive {
 namespace internal {
 
-namespace {
-
-// Collects resource IDs of stale cache files.
-void CollectStaleCacheFiles(
-    ResourceMetadata* resource_metadata,
-    std::vector<std::string>* out_resource_ids_to_be_removed,
-    const std::string& resource_id,
-    const FileCacheEntry& cache_entry) {
-  ResourceEntry entry;
-  FileError error = resource_metadata->GetResourceEntryById(
-      resource_id, &entry);
-
-  // The entry is not found or the MD5 does not match.
-  if (error != FILE_ERROR_OK ||
-      cache_entry.md5() != entry.file_specific_info().md5())
-    out_resource_ids_to_be_removed->push_back(resource_id);
-}
-
-}  // namespace
-
 void RemoveStaleCacheFiles(FileCache* cache,
                            ResourceMetadata* resource_metadata) {
   std::vector<std::string> resource_ids_to_be_removed;
-  cache->Iterate(base::Bind(&CollectStaleCacheFiles,
-                            resource_metadata,
-                            &resource_ids_to_be_removed));
 
-  for (size_t i = 0; i < resource_ids_to_be_removed.size(); ++i) {
-    const std::string& resource_id = resource_ids_to_be_removed[i];
-    FileError error = cache->Remove(resource_id);
-    LOG_IF(WARNING, error != FILE_ERROR_OK)
-        << "Failed to remove a stale cache file. resource_id: " << resource_id;
+  scoped_ptr<FileCache::Iterator> it = cache->GetIterator();
+  for (; !it->IsAtEnd(); it->Advance()) {
+    ResourceEntry entry;
+    FileError error = resource_metadata->GetResourceEntryById(it->GetID(),
+                                                              &entry);
+    // The entry is not found or the MD5 does not match.
+    if (error != FILE_ERROR_OK ||
+        it->GetValue().md5() != entry.file_specific_info().md5()) {
+      FileError error = cache->Remove(it->GetID());
+      LOG_IF(WARNING, error != FILE_ERROR_OK)
+          << "Failed to remove a stale cache file. resource_id: "
+          << it->GetID();
+    }
   }
 }
 
diff --git a/chrome/browser/chromeos/drive/remove_stale_cache_files_unittest.cc b/chrome/browser/chromeos/drive/remove_stale_cache_files_unittest.cc
index a0e4c89..f99c6f1 100644
--- a/chrome/browser/chromeos/drive/remove_stale_cache_files_unittest.cc
+++ b/chrome/browser/chromeos/drive/remove_stale_cache_files_unittest.cc
@@ -28,14 +28,18 @@
 
     fake_free_disk_space_getter_.reset(new FakeFreeDiskSpaceGetter);
 
-    cache_.reset(new FileCache(temp_dir_.path(),
+    metadata_storage_.reset(new ResourceMetadataStorage(
+        temp_dir_.path(), base::MessageLoopProxy::current()));
+
+    cache_.reset(new FileCache(metadata_storage_.get(),
                                temp_dir_.path(),
                                base::MessageLoopProxy::current(),
                                fake_free_disk_space_getter_.get()));
 
     resource_metadata_.reset(new ResourceMetadata(
-        temp_dir_.path(), base::MessageLoopProxy::current()));
+        metadata_storage_.get(), base::MessageLoopProxy::current()));
 
+    ASSERT_TRUE(metadata_storage_->Initialize());
     ASSERT_TRUE(cache_->Initialize());
     ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->Initialize());
   }
@@ -43,6 +47,8 @@
   content::TestBrowserThreadBundle thread_bundle_;
   base::ScopedTempDir temp_dir_;
 
+  scoped_ptr<ResourceMetadataStorage,
+             test_util::DestroyHelperForTests> metadata_storage_;
   scoped_ptr<FileCache, test_util::DestroyHelperForTests> cache_;
   scoped_ptr<ResourceMetadata, test_util::DestroyHelperForTests>
       resource_metadata_;
diff --git a/chrome/browser/chromeos/drive/resource_entry_conversion.cc b/chrome/browser/chromeos/drive/resource_entry_conversion.cc
index 08d0eac..9ba85ad 100644
--- a/chrome/browser/chromeos/drive/resource_entry_conversion.cc
+++ b/chrome/browser/chromeos/drive/resource_entry_conversion.cc
@@ -12,7 +12,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/chromeos/drive/drive.pb.h"
 #include "chrome/browser/chromeos/drive/file_system_util.h"
-#include "chrome/browser/google_apis/drive_api_util.h"
+#include "chrome/browser/drive/drive_api_util.h"
 #include "chrome/browser/google_apis/gdata_wapi_parser.h"
 #include "googleurl/src/gurl.h"
 #include "net/base/escape.h"
@@ -54,9 +54,8 @@
   const google_apis::Link* parent_link =
       input.GetLinkByType(google_apis::Link::LINK_PARENT);
   if (parent_link) {
-    output.set_parent_resource_id(
-        google_apis::drive::util::ExtractResourceIdFromUrl(
-            parent_link->href()));
+    output.set_parent_resource_id(util::ExtractResourceIdFromUrl(
+        parent_link->href()));
   }
   // Apply mapping from an empty parent to the special dummy directory.
   if (output.parent_resource_id().empty())
@@ -108,6 +107,11 @@
         input.GetLinkByType(google_apis::Link::LINK_ALTERNATE);
     if (alternate_link)
       file_specific_info->set_alternate_url(alternate_link->href().spec());
+
+    const google_apis::Link* share_link =
+        input.GetLinkByType(google_apis::Link::LINK_SHARE);
+    if (share_link)
+      file_specific_info->set_share_url(share_link->href().spec());
   } else if (input.is_folder()) {
     file_info->set_is_directory(true);
   } else {
diff --git a/chrome/browser/chromeos/drive/resource_entry_conversion_unittest.cc b/chrome/browser/chromeos/drive/resource_entry_conversion_unittest.cc
index 0c7b06c..619d5d1 100644
--- a/chrome/browser/chromeos/drive/resource_entry_conversion_unittest.cc
+++ b/chrome/browser/chromeos/drive/resource_entry_conversion_unittest.cc
@@ -17,7 +17,7 @@
 
 TEST(ResourceEntryConversionTest, ConvertToResourceEntry_File) {
   scoped_ptr<base::Value> value =
-      google_apis::test_util::LoadJSONFile("chromeos/gdata/file_entry.json");
+      google_apis::test_util::LoadJSONFile("gdata/file_entry.json");
   ASSERT_TRUE(value.get());
 
   scoped_ptr<google_apis::ResourceEntry> gdata_resource_entry(
@@ -81,6 +81,8 @@
             entry.file_specific_info().thumbnail_url());
   EXPECT_EQ("https://file_link_alternate/",
             entry.file_specific_info().alternate_url());
+  EXPECT_EQ("https://file_link_share/",
+            entry.file_specific_info().share_url());
 
   // Regular file specific fields.
   EXPECT_EQ(892721,  entry.file_info().size());
@@ -93,7 +95,7 @@
      ConvertToResourceEntry_HostedDocument) {
   scoped_ptr<base::Value> value =
       google_apis::test_util::LoadJSONFile(
-          "chromeos/gdata/hosted_document_entry.json");
+          "gdata/hosted_document_entry.json");
   ASSERT_TRUE(value.get());
 
   scoped_ptr<google_apis::ResourceEntry> gdata_resource_entry(
@@ -174,7 +176,7 @@
      ConvertToResourceEntry_Directory) {
   scoped_ptr<base::Value> value =
       google_apis::test_util::LoadJSONFile(
-          "chromeos/gdata/directory_entry.json");
+          "gdata/directory_entry.json");
   ASSERT_TRUE(value.get());
 
   scoped_ptr<google_apis::ResourceEntry> gdata_resource_entry(
@@ -245,7 +247,7 @@
      ConvertToResourceEntry_DeletedHostedDocument) {
   scoped_ptr<base::Value> value =
       google_apis::test_util::LoadJSONFile(
-          "chromeos/gdata/deleted_hosted_document_entry.json");
+          "gdata/deleted_hosted_document_entry.json");
   ASSERT_TRUE(value.get());
 
   scoped_ptr<google_apis::ResourceEntry> gdata_resource_entry(
@@ -315,6 +317,8 @@
             entry.file_specific_info().thumbnail_url());
   EXPECT_EQ("https://alternate/document%3Adeleted_in_root_id/edit",
             entry.file_specific_info().alternate_url());
+  EXPECT_EQ("",
+            entry.file_specific_info().share_url());
 
   // The size should be 0 for a hosted document.
   EXPECT_EQ(0,  entry.file_info().size());
@@ -323,7 +327,7 @@
 TEST(ResourceEntryConversionTest,
      ConvertToResourceEntry_SharedWithMeEntry) {
   scoped_ptr<base::Value> value = google_apis::test_util::LoadJSONFile(
-      "chromeos/gdata/shared_with_me_entry.json");
+      "gdata/shared_with_me_entry.json");
   ASSERT_TRUE(value.get());
 
   scoped_ptr<google_apis::ResourceEntry> gdata_resource_entry(
diff --git a/chrome/browser/chromeos/drive/resource_metadata.cc b/chrome/browser/chromeos/drive/resource_metadata.cc
index 69973e9..4e79a57 100644
--- a/chrome/browser/chromeos/drive/resource_metadata.cc
+++ b/chrome/browser/chromeos/drive/resource_metadata.cc
@@ -34,7 +34,7 @@
   return entry;
 }
 
-// Returns true if enough disk space is avilable for DB operation.
+// Returns true if enough disk space is available for DB operation.
 // TODO(hashimoto): Merge this with FileCache's FreeDiskSpaceGetterInterface.
 bool EnoughDiskSpaceIsAvailableForDBOperation(const base::FilePath& path) {
   const int64 kRequiredDiskSpaceInMB = 128;  // 128 MB seems to be large enough.
@@ -125,11 +125,10 @@
 namespace internal {
 
 ResourceMetadata::ResourceMetadata(
-    const base::FilePath& data_directory_path,
+    ResourceMetadataStorage* storage,
     scoped_refptr<base::SequencedTaskRunner> blocking_task_runner)
-    : data_directory_path_(data_directory_path),
-      blocking_task_runner_(blocking_task_runner),
-      storage_(new ResourceMetadataStorage(data_directory_path)),
+    : blocking_task_runner_(blocking_task_runner),
+      storage_(storage),
       weak_ptr_factory_(this) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
 }
@@ -137,13 +136,9 @@
 FileError ResourceMetadata::Initialize() {
   DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread());
 
-  if (!EnoughDiskSpaceIsAvailableForDBOperation(data_directory_path_))
+  if (!EnoughDiskSpaceIsAvailableForDBOperation(storage_->directory_path()))
     return FILE_ERROR_NO_SPACE;
 
-  // Initialize the storage.
-  if (!storage_->Initialize())
-    return FILE_ERROR_FAILED;
-
   if (!SetUpDefaultEntries())
     return FILE_ERROR_FAILED;
 
@@ -174,7 +169,7 @@
 FileError ResourceMetadata::Reset() {
   DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread());
 
-  if (!EnoughDiskSpaceIsAvailableForDBOperation(data_directory_path_))
+  if (!EnoughDiskSpaceIsAvailableForDBOperation(storage_->directory_path()))
     return FILE_ERROR_NO_SPACE;
 
   if (!storage_->SetLargestChangestamp(0) ||
@@ -249,7 +244,7 @@
 FileError ResourceMetadata::SetLargestChangestamp(int64 value) {
   DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread());
 
-  if (!EnoughDiskSpaceIsAvailableForDBOperation(data_directory_path_))
+  if (!EnoughDiskSpaceIsAvailableForDBOperation(storage_->directory_path()))
     return FILE_ERROR_NO_SPACE;
 
   storage_->SetLargestChangestamp(value);
@@ -270,7 +265,7 @@
 FileError ResourceMetadata::AddEntry(const ResourceEntry& entry) {
   DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread());
 
-  if (!EnoughDiskSpaceIsAvailableForDBOperation(data_directory_path_))
+  if (!EnoughDiskSpaceIsAvailableForDBOperation(storage_->directory_path()))
     return FILE_ERROR_NO_SPACE;
 
   ResourceEntry existing_entry;
@@ -320,7 +315,7 @@
 FileError ResourceMetadata::RemoveEntry(const std::string& resource_id) {
   DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread());
 
-  if (!EnoughDiskSpaceIsAvailableForDBOperation(data_directory_path_))
+  if (!EnoughDiskSpaceIsAvailableForDBOperation(storage_->directory_path()))
     return FILE_ERROR_NO_SPACE;
 
   // Disallow deletion of special entries "/drive" and "/drive/other".
@@ -438,7 +433,7 @@
 FileError ResourceMetadata::RefreshEntry(const ResourceEntry& entry) {
   DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread());
 
-  if (!EnoughDiskSpaceIsAvailableForDBOperation(data_directory_path_))
+  if (!EnoughDiskSpaceIsAvailableForDBOperation(storage_->directory_path()))
     return FILE_ERROR_NO_SPACE;
 
   ResourceEntry old_entry;
@@ -529,7 +524,7 @@
   DCHECK(!file_path.empty());
   DCHECK(out_file_path);
 
-  if (!EnoughDiskSpaceIsAvailableForDBOperation(data_directory_path_))
+  if (!EnoughDiskSpaceIsAvailableForDBOperation(storage_->directory_path()))
     return FILE_ERROR_NO_SPACE;
 
   ResourceEntry entry, destination;
@@ -558,7 +553,7 @@
 
   DVLOG(1) << "RenameEntry " << file_path.value() << " to " << new_name;
 
-  if (!EnoughDiskSpaceIsAvailableForDBOperation(data_directory_path_))
+  if (!EnoughDiskSpaceIsAvailableForDBOperation(storage_->directory_path()))
     return FILE_ERROR_NO_SPACE;
 
   ResourceEntry entry;
@@ -631,7 +626,7 @@
   DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread());
   DCHECK(!directory_fetch_info.empty());
 
-  if (!EnoughDiskSpaceIsAvailableForDBOperation(data_directory_path_))
+  if (!EnoughDiskSpaceIsAvailableForDBOperation(storage_->directory_path()))
     return FILE_ERROR_NO_SPACE;
 
   ResourceEntry directory;
@@ -649,7 +644,7 @@
   // entries in the loop. We'll process deleted entries afterwards.
   for (ResourceEntryMap::const_iterator it = entry_map.begin();
        it != entry_map.end(); ++it) {
-    if (!EnoughDiskSpaceIsAvailableForDBOperation(data_directory_path_))
+    if (!EnoughDiskSpaceIsAvailableForDBOperation(storage_->directory_path()))
       return FILE_ERROR_NO_SPACE;
 
     const ResourceEntry& entry = it->second;
@@ -674,7 +669,7 @@
   std::vector<std::string> children;
   storage_->GetChildren(directory.resource_id(), &children);
   for (size_t i = 0; i < children.size(); ++i) {
-    if (!EnoughDiskSpaceIsAvailableForDBOperation(data_directory_path_))
+    if (!EnoughDiskSpaceIsAvailableForDBOperation(storage_->directory_path()))
       return FILE_ERROR_NO_SPACE;
 
     if (entry_map.count(children[i]) == 0) {
@@ -751,7 +746,7 @@
 
   // Do file name de-duplication - Keep changing |entry|'s name until there is
   // no other entry with the same name under the parent.
-  int modifier = 1;
+  int modifier = 0;
   std::string new_base_name = updated_entry.base_name();
   while (true) {
     const std::string existing_entry_id =
@@ -764,7 +759,7 @@
     new_path =
         new_path.InsertBeforeExtension(base::StringPrintf(" (%d)", ++modifier));
     // The new filename must be different from the previous one.
-    DCHECK(new_base_name != new_path.AsUTF8Unsafe());
+    DCHECK_NE(new_base_name, new_path.AsUTF8Unsafe());
     new_base_name = new_path.AsUTF8Unsafe();
   }
   updated_entry.set_base_name(new_base_name);
diff --git a/chrome/browser/chromeos/drive/resource_metadata.h b/chrome/browser/chromeos/drive/resource_metadata.h
index 345e663..848c2b2 100644
--- a/chrome/browser/chromeos/drive/resource_metadata.h
+++ b/chrome/browser/chromeos/drive/resource_metadata.h
@@ -14,7 +14,7 @@
 #include "base/files/file_path.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/chromeos/drive/file_errors.h"
 #include "chrome/browser/chromeos/drive/resource_metadata_storage.h"
 
@@ -25,7 +25,6 @@
 namespace drive {
 
 class ResourceEntry;
-class ResourceMetadataStorage;
 
 typedef std::vector<ResourceEntry> ResourceEntryVector;
 typedef std::map<std::string /* resource_id */, ResourceEntry>
@@ -112,10 +111,8 @@
  public:
   typedef ResourceMetadataStorage::Iterator Iterator;
 
-  // |root_resource_id| is the resource id for the root directory.
-  // Must be called on the UI thread.
   ResourceMetadata(
-      const base::FilePath& data_directory_path,
+      ResourceMetadataStorage* storage,
       scoped_refptr<base::SequencedTaskRunner> blocking_task_runner);
 
   // Initializes this object.
@@ -304,11 +301,9 @@
   // Removes the entry and its descendants.
   bool RemoveEntryRecursively(const std::string& resource_id);
 
-  const base::FilePath data_directory_path_;
-
   scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
 
-  scoped_ptr<ResourceMetadataStorage> storage_;
+  ResourceMetadataStorage* storage_;
 
   // This should remain the last member so it'll be destroyed first and
   // invalidate its weak pointers before other members are destroyed.
diff --git a/chrome/browser/chromeos/drive/resource_metadata_storage.cc b/chrome/browser/chromeos/drive/resource_metadata_storage.cc
index 2cdf41e..b7a6264 100644
--- a/chrome/browser/chromeos/drive/resource_metadata_storage.cc
+++ b/chrome/browser/chromeos/drive/resource_metadata_storage.cc
@@ -4,15 +4,19 @@
 
 #include "chrome/browser/chromeos/drive/resource_metadata_storage.h"
 
+#include "base/bind.h"
 #include "base/file_util.h"
+#include "base/location.h"
 #include "base/logging.h"
 #include "base/metrics/histogram.h"
+#include "base/sequenced_task_runner.h"
 #include "base/threading/thread_restrictions.h"
 #include "chrome/browser/chromeos/drive/drive.pb.h"
 #include "third_party/leveldatabase/src/include/leveldb/db.h"
 #include "third_party/leveldatabase/src/include/leveldb/write_batch.h"
 
 namespace drive {
+namespace internal {
 
 namespace {
 
@@ -36,6 +40,9 @@
 // Meant to be a character which never happen to be in real resource IDs.
 const char kDBKeyDelimeter = '\0';
 
+// String used as a suffix of a key for a cache entry.
+const char kCacheEntryKeySuffix[] = "CACHE";
+
 // Returns a string to be used as the key for the header.
 std::string GetHeaderDBKey() {
   std::string key;
@@ -49,6 +56,28 @@
   return !key.empty() && key[key.size() - 1] == kDBKeyDelimeter;
 }
 
+// Returns a string to be used as a key for a cache entry.
+std::string GetCacheEntryKey(const std::string& resource_id) {
+  std::string key(resource_id);
+  key.push_back(kDBKeyDelimeter);
+  key.append(kCacheEntryKeySuffix);
+  return key;
+}
+
+// Returns true if |key| is a key for a cache entry.
+bool IsCacheEntryKey(const leveldb::Slice& key) {
+  // A cache entry key should end with |kDBKeyDelimeter + kCacheEntryKeySuffix|.
+  const leveldb::Slice expected_suffix(kCacheEntryKeySuffix,
+                                       arraysize(kCacheEntryKeySuffix) - 1);
+  if (key.size() < 1 + expected_suffix.size() ||
+      key[key.size() - expected_suffix.size() - 1] != kDBKeyDelimeter)
+    return false;
+
+  const leveldb::Slice key_substring(
+      key.data() + key.size() - expected_suffix.size(), expected_suffix.size());
+  return key_substring.compare(expected_suffix) == 0;
+}
+
 // Converts leveldb::Status to DBInitStatus.
 DBInitStatus LevelDBStatusToDBInitStatus(const leveldb::Status status) {
   if (status.ok())
@@ -98,6 +127,7 @@
 
   for (it_->Next() ; it_->Valid(); it_->Next()) {
     if (!IsChildEntryKey(it_->key()) &&
+        !IsCacheEntryKey(it_->key()) &&
         entry_.ParseFromArray(it_->value().data(), it_->value().size()))
       break;
   }
@@ -108,21 +138,86 @@
   return !it_->status().ok();
 }
 
-ResourceMetadataStorage::ResourceMetadataStorage(
-    const base::FilePath& directory_path)
-    : directory_path_(directory_path) {
+ResourceMetadataStorage::CacheEntryIterator::CacheEntryIterator(
+    scoped_ptr<leveldb::Iterator> it) : it_(it.Pass()) {
+  base::ThreadRestrictions::AssertIOAllowed();
+  DCHECK(it_);
+
+  it_->SeekToFirst();
+  AdvanceInternal();
 }
 
-ResourceMetadataStorage::~ResourceMetadataStorage() {
+ResourceMetadataStorage::CacheEntryIterator::~CacheEntryIterator() {
   base::ThreadRestrictions::AssertIOAllowed();
 }
 
+bool ResourceMetadataStorage::CacheEntryIterator::IsAtEnd() const {
+  base::ThreadRestrictions::AssertIOAllowed();
+  return !it_->Valid();
+}
+
+const std::string& ResourceMetadataStorage::CacheEntryIterator::GetID() const {
+  base::ThreadRestrictions::AssertIOAllowed();
+  DCHECK(!IsAtEnd());
+  return resource_id_;
+}
+
+const FileCacheEntry&
+ResourceMetadataStorage::CacheEntryIterator::GetValue() const {
+  base::ThreadRestrictions::AssertIOAllowed();
+  DCHECK(!IsAtEnd());
+  return entry_;
+}
+
+void ResourceMetadataStorage::CacheEntryIterator::Advance() {
+  base::ThreadRestrictions::AssertIOAllowed();
+  DCHECK(!IsAtEnd());
+
+  it_->Next();
+  AdvanceInternal();
+}
+
+bool ResourceMetadataStorage::CacheEntryIterator::HasError() const {
+  base::ThreadRestrictions::AssertIOAllowed();
+  return !it_->status().ok();
+}
+
+void ResourceMetadataStorage::CacheEntryIterator::AdvanceInternal() {
+  for (; it_->Valid(); it_->Next()) {
+    // Skip unparsable broken entries.
+    // TODO(hashimoto): Broken entries should be cleaned up at some point.
+    if (IsCacheEntryKey(it_->key()) &&
+        entry_.ParseFromArray(it_->value().data(), it_->value().size())) {
+      // Drop the suffix |kDBKeyDelimeter + kCacheEntryKeySuffix| from the key.
+      const size_t kSuffixLength = arraysize(kCacheEntryKeySuffix) - 1;
+      const int id_length = it_->key().size() - 1 - kSuffixLength;
+      resource_id_.assign(it_->key().data(), id_length);
+      break;
+    }
+  }
+}
+
+ResourceMetadataStorage::ResourceMetadataStorage(
+    const base::FilePath& directory_path,
+    base::SequencedTaskRunner* blocking_task_runner)
+    : directory_path_(directory_path),
+      opened_existing_db_(false),
+      blocking_task_runner_(blocking_task_runner) {
+}
+
+void ResourceMetadataStorage::Destroy() {
+  blocking_task_runner_->PostTask(
+      FROM_HERE,
+      base::Bind(&ResourceMetadataStorage::DestroyOnBlockingPool,
+                 base::Unretained(this)));
+}
+
 bool ResourceMetadataStorage::Initialize() {
   base::ThreadRestrictions::AssertIOAllowed();
 
   // Remove unused child map DB.
   const base::FilePath child_map_path = directory_path_.Append(kChildMapDBName);
-  file_util::Delete(child_map_path, true /* recursive */);
+  base::Delete(child_map_path, true /* recursive */);
 
   resource_map_.reset();
 
@@ -145,8 +240,8 @@
     resource_map_.reset(db);
 
     // Check the validity of existing DB.
-    scoped_ptr<ResourceMetadataHeader> header = GetHeader();
-    if (!header || header->version() != kDBVersion) {
+    ResourceMetadataHeader header;
+    if (!GetHeader(&header) || header.version() != kDBVersion) {
       open_existing_result = DB_INIT_INCOMPATIBLE;
       LOG(INFO) << "Reject incompatible DB.";
     } else if (!CheckValidity()) {
@@ -154,7 +249,9 @@
       LOG(ERROR) << "Reject invalid DB.";
     }
 
-    if (open_existing_result != DB_INIT_SUCCESS)
+    if (open_existing_result == DB_INIT_SUCCESS)
+      opened_existing_db_ = true;
+    else
       resource_map_.reset();
   }
 
@@ -170,7 +267,7 @@
 
     // Clean up the destination.
     const bool kRecursive = true;
-    file_util::Delete(resource_map_path, kRecursive);
+    base::Delete(resource_map_path, kRecursive);
 
     // Create DB.
     options.create_if_missing = true;
@@ -203,23 +300,23 @@
     int64 largest_changestamp) {
   base::ThreadRestrictions::AssertIOAllowed();
 
-  scoped_ptr<ResourceMetadataHeader> header = GetHeader();
-  if (!header) {
+  ResourceMetadataHeader header;
+  if (!GetHeader(&header)) {
     DLOG(ERROR) << "Failed to get the header.";
     return false;
   }
-  header->set_largest_changestamp(largest_changestamp);
-  return PutHeader(*header);
+  header.set_largest_changestamp(largest_changestamp);
+  return PutHeader(header);
 }
 
 int64 ResourceMetadataStorage::GetLargestChangestamp() {
   base::ThreadRestrictions::AssertIOAllowed();
-  scoped_ptr<ResourceMetadataHeader> header = GetHeader();
-  if (!header) {
+  ResourceMetadataHeader header;
+  if (!GetHeader(&header)) {
     DLOG(ERROR) << "Failed to get the header.";
     return 0;
   }
-  return header->largest_changestamp();
+  return header.largest_changestamp();
 }
 
 bool ResourceMetadataStorage::PutEntry(const ResourceEntry& entry) {
@@ -313,9 +410,8 @@
   return child_resource_id;
 }
 
-void ResourceMetadataStorage::GetChildren(
-    const std::string& parent_resource_id,
-    std::vector<std::string>* children) {
+void ResourceMetadataStorage::GetChildren(const std::string& parent_resource_id,
+                                          std::vector<std::string>* children) {
   base::ThreadRestrictions::AssertIOAllowed();
 
   // Iterate over all entries with keys starting with |parent_resource_id|.
@@ -330,6 +426,64 @@
   DCHECK(it->status().ok());
 }
 
+bool ResourceMetadataStorage::PutCacheEntry(const std::string& resource_id,
+                                            const FileCacheEntry& entry) {
+  base::ThreadRestrictions::AssertIOAllowed();
+  DCHECK(!resource_id.empty());
+
+  std::string serialized_entry;
+  if (!entry.SerializeToString(&serialized_entry)) {
+    DLOG(ERROR) << "Failed to serialize the entry.";
+    return false;
+  }
+
+  const leveldb::Status status = resource_map_->Put(
+      leveldb::WriteOptions(),
+      leveldb::Slice(GetCacheEntryKey(resource_id)),
+      leveldb::Slice(serialized_entry));
+  return status.ok();
+}
+
+bool ResourceMetadataStorage::GetCacheEntry(const std::string& resource_id,
+                                            FileCacheEntry* out_entry) {
+  base::ThreadRestrictions::AssertIOAllowed();
+  DCHECK(!resource_id.empty());
+
+  std::string serialized_entry;
+  const leveldb::Status status = resource_map_->Get(
+      leveldb::ReadOptions(),
+      leveldb::Slice(GetCacheEntryKey(resource_id)),
+      &serialized_entry);
+  return status.ok() && out_entry->ParseFromString(serialized_entry);
+}
+
+bool ResourceMetadataStorage::RemoveCacheEntry(const std::string& resource_id) {
+  base::ThreadRestrictions::AssertIOAllowed();
+  DCHECK(!resource_id.empty());
+
+  const leveldb::Status status = resource_map_->Delete(
+      leveldb::WriteOptions(),
+      leveldb::Slice(GetCacheEntryKey(resource_id)));
+  return status.ok();
+}
+
+scoped_ptr<ResourceMetadataStorage::CacheEntryIterator>
+ResourceMetadataStorage::GetCacheEntryIterator() {
+  base::ThreadRestrictions::AssertIOAllowed();
+
+  scoped_ptr<leveldb::Iterator> it(
+      resource_map_->NewIterator(leveldb::ReadOptions()));
+  return make_scoped_ptr(new CacheEntryIterator(it.Pass()));
+}
+
+ResourceMetadataStorage::~ResourceMetadataStorage() {
+  base::ThreadRestrictions::AssertIOAllowed();
+}
+
+void ResourceMetadataStorage::DestroyOnBlockingPool() {
+  delete this;
+}
+
 // static
 std::string ResourceMetadataStorage::GetChildEntryKey(
     const std::string& parent_resource_id,
@@ -358,8 +512,7 @@
   return status.ok();
 }
 
-scoped_ptr<ResourceMetadataHeader>
-ResourceMetadataStorage::GetHeader() {
+bool ResourceMetadataStorage::GetHeader(ResourceMetadataHeader* header) {
   base::ThreadRestrictions::AssertIOAllowed();
 
   std::string serialized_header;
@@ -367,14 +520,7 @@
       leveldb::ReadOptions(),
       leveldb::Slice(GetHeaderDBKey()),
       &serialized_header);
-  if (!status.ok())
-    return scoped_ptr<ResourceMetadataHeader>();
-
-  scoped_ptr<ResourceMetadataHeader> header(
-      new ResourceMetadataHeader);
-  if (!header->ParseFromString(serialized_header))
-    return scoped_ptr<ResourceMetadataHeader>();
-  return header.Pass();
+  return status.ok() && header->ParseFromString(serialized_header);
 }
 
 bool ResourceMetadataStorage::CheckValidity() {
@@ -387,6 +533,20 @@
   scoped_ptr<leveldb::Iterator> it(resource_map_->NewIterator(options));
   it->SeekToFirst();
 
+  // DB is organized like this:
+  //
+  // <key>                          : <value>
+  // "\0HEADER"                     : ResourceMetadataHeader
+  // "|ID of A|"                    : ResourceEntry for entry A.
+  // "|ID of A|\0CACHE"             : FileCacheEntry for entry A.
+  // "|ID of A|\0|child name 1|\0"  : ID of the 1st child entry of entry A.
+  // "|ID of A|\0|child name 2|\0"  : ID of the 2nd child entry of entry A.
+  // ...
+  // "|ID of A|\0|child name n|\0"  : ID of the nth child entry of entry A.
+  // "|ID of B|"                    : ResourceEntry for entry B.
+  // "|ID of B|\0CACHE"             : FileCacheEntry for entry B.
+  // ...
+
   // Check the header.
   ResourceMetadataHeader header;
   if (!it->Valid() ||
@@ -410,6 +570,10 @@
       continue;
     }
 
+    // Ignore cache entries.
+    if (IsCacheEntryKey(it->key()))
+      continue;
+
     // Check if stored data is broken.
     if (!entry.ParseFromArray(it->value().data(), it->value().size()) ||
         entry.resource_id() != it->key()) {
@@ -449,4 +613,5 @@
   return true;
 }
 
+}  // namespace internal
 }  // namespace drive
diff --git a/chrome/browser/chromeos/drive/resource_metadata_storage.h b/chrome/browser/chromeos/drive/resource_metadata_storage.h
index a2b4532..adac420 100644
--- a/chrome/browser/chromeos/drive/resource_metadata_storage.h
+++ b/chrome/browser/chromeos/drive/resource_metadata_storage.h
@@ -10,9 +10,14 @@
 
 #include "base/basictypes.h"
 #include "base/files/file_path.h"
+#include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "chrome/browser/chromeos/drive/drive.pb.h"
 
+namespace base {
+class SequencedTaskRunner;
+}
+
 namespace leveldb {
 class DB;
 class Iterator;
@@ -23,20 +28,24 @@
 class ResourceEntry;
 class ResourceMetadataHeader;
 
+namespace internal {
+
 // Storage for ResourceMetadata which is responsible to manage resource
 // entries and child-parent relationships between entries.
 class ResourceMetadataStorage {
  public:
   // This should be incremented when incompatibility change is made to DB
   // format.
-  static const int kDBVersion = 6;
+  static const int kDBVersion = 7;
 
+  // Object to iterate over entries stored in this storage.
   class Iterator {
    public:
     explicit Iterator(scoped_ptr<leveldb::Iterator> it);
     ~Iterator();
 
-    // Returns true if this iterator cannot advance any more.
+    // Returns true if this iterator cannot advance any more and does not point
+    // to a valid entry. Get() and Advance() should not be called in such cases.
     bool IsAtEnd() const;
 
     // Returns the entry currently pointed by this object.
@@ -55,8 +64,51 @@
     DISALLOW_COPY_AND_ASSIGN(Iterator);
   };
 
-  explicit ResourceMetadataStorage(const base::FilePath& directory_path);
-  virtual ~ResourceMetadataStorage();
+  // Object to iterate over cache entries stored in this storage.
+  class CacheEntryIterator {
+   public:
+    explicit CacheEntryIterator(scoped_ptr<leveldb::Iterator> it);
+    ~CacheEntryIterator();
+
+    // Returns true if this iterator cannot advance any more and does not point
+    // to a valid entry. GetID(), GetValue() and Advance() should not be called
+    // in such cases.
+    bool IsAtEnd() const;
+
+    // Returns the ID of the entry currently pointed by this object.
+    const std::string& GetID() const;
+
+    // Returns the value of the entry currently pointed by this object.
+    const FileCacheEntry& GetValue() const;
+
+    // Advances to the next entry.
+    void Advance();
+
+    // Returns true if this object has encountered any error.
+    bool HasError() const;
+
+   private:
+    // Used to implement Advance().
+    void AdvanceInternal();
+
+    scoped_ptr<leveldb::Iterator> it_;
+    std::string resource_id_;
+    FileCacheEntry entry_;
+
+    DISALLOW_COPY_AND_ASSIGN(CacheEntryIterator);
+  };
+
+  ResourceMetadataStorage(const base::FilePath& directory_path,
+                          base::SequencedTaskRunner* blocking_task_runner);
+
+  const base::FilePath& directory_path() const { return directory_path_; }
+
+  // Returns true if the DB used by this storage was opened, not created, during
+  // Initialize().
+  bool opened_existing_db() const { return opened_existing_db_; }
+
+  // Destroys this object.
+  void Destroy();
 
   // Initializes this object.
   bool Initialize();
@@ -87,9 +139,28 @@
   void GetChildren(const std::string& parent_resource_id,
                    std::vector<std::string>* children);
 
+  // Puts the cache entry to this storage.
+  bool PutCacheEntry(const std::string& resource_id,
+                     const FileCacheEntry& entry);
+
+  // Gets a cache entry stored in this storage.
+  bool GetCacheEntry(const std::string& resource_id, FileCacheEntry* out_entry);
+
+  // Removes a cache entry from this storage.
+  bool RemoveCacheEntry(const std::string& resource_id);
+
+  // Returns an object to iterate over cache entries stored in this storage.
+  scoped_ptr<CacheEntryIterator> GetCacheEntryIterator();
+
  private:
   friend class ResourceMetadataStorageTest;
 
+  // To destruct this object, use Destroy().
+  ~ResourceMetadataStorage();
+
+  // Used to implement Destroy().
+  void DestroyOnBlockingPool();
+
   // Returns a string to be used as a key for child entry.
   static std::string GetChildEntryKey(const std::string& parent_resource_id,
                                       const std::string& child_name);
@@ -98,7 +169,7 @@
   bool PutHeader(const ResourceMetadataHeader& header);
 
   // Gets header.
-  scoped_ptr<ResourceMetadataHeader> GetHeader();
+  bool GetHeader(ResourceMetadataHeader* out_header);
 
   // Checks validity of the data.
   bool CheckValidity();
@@ -106,12 +177,17 @@
   // Path to the directory where the data is stored.
   base::FilePath directory_path_;
 
+  bool opened_existing_db_;
+
   // Entries stored in this storage.
   scoped_ptr<leveldb::DB> resource_map_;
 
+  scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
+
   DISALLOW_COPY_AND_ASSIGN(ResourceMetadataStorage);
 };
 
+}  // namespace internal
 }  // namespace drive
 
 #endif  // CHROME_BROWSER_CHROMEOS_DRIVE_RESOURCE_METADATA_STORAGE_H_
diff --git a/chrome/browser/chromeos/drive/resource_metadata_storage_unittest.cc b/chrome/browser/chromeos/drive/resource_metadata_storage_unittest.cc
index b384cca..4ab0acf 100644
--- a/chrome/browser/chromeos/drive/resource_metadata_storage_unittest.cc
+++ b/chrome/browser/chromeos/drive/resource_metadata_storage_unittest.cc
@@ -9,29 +9,30 @@
 #include "base/file_util.h"
 #include "base/files/scoped_temp_dir.h"
 #include "chrome/browser/chromeos/drive/drive.pb.h"
+#include "chrome/browser/chromeos/drive/test_util.h"
+#include "content/public/test/test_browser_thread_bundle.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/leveldatabase/src/include/leveldb/db.h"
 
 namespace drive {
+namespace internal {
 
 class ResourceMetadataStorageTest : public testing::Test {
  protected:
   virtual void SetUp() OVERRIDE {
     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
 
-    storage_.reset(new ResourceMetadataStorage(temp_dir_.path()));
+    storage_.reset(new ResourceMetadataStorage(
+        temp_dir_.path(), base::MessageLoopProxy::current()));
     ASSERT_TRUE(storage_->Initialize());
   }
 
-  virtual void TearDown() OVERRIDE {
-  }
-
   // Overwrites |storage_|'s version.
   void SetDBVersion(int version) {
-    scoped_ptr<ResourceMetadataHeader> header = storage_->GetHeader();
-    ASSERT_TRUE(header);
-    header->set_version(version);
-    storage_->PutHeader(*header);
+    ResourceMetadataHeader header;
+    ASSERT_TRUE(storage_->GetHeader(&header));
+    header.set_version(version);
+    EXPECT_TRUE(storage_->PutHeader(header));
   }
 
   bool CheckValidity() {
@@ -58,8 +59,10 @@
                                                   child_base_name));
   }
 
+  content::TestBrowserThreadBundle thread_bundle_;
   base::ScopedTempDir temp_dir_;
-  scoped_ptr<ResourceMetadataStorage> storage_;
+  scoped_ptr<ResourceMetadataStorage,
+             test_util::DestroyHelperForTests> storage_;
 };
 
 TEST_F(ResourceMetadataStorageTest, LargestChangestamp) {
@@ -148,6 +151,11 @@
   for (size_t i = 0; i < entries.size(); ++i)
     EXPECT_TRUE(storage_->PutEntry(entries[i]));
 
+  // Insert some dummy cache entries.
+  FileCacheEntry cache_entry;
+  EXPECT_TRUE(storage_->PutCacheEntry(entries[0].resource_id(), cache_entry));
+  EXPECT_TRUE(storage_->PutCacheEntry(entries[1].resource_id(), cache_entry));
+
   // Iterate and check the result.
   std::map<std::string, ResourceEntry> result;
   scoped_ptr<ResourceMetadataStorage::Iterator> it = storage_->GetIterator();
@@ -163,6 +171,72 @@
     EXPECT_EQ(1U, result.count(entries[i].resource_id()));
 }
 
+TEST_F(ResourceMetadataStorageTest, PutCacheEntry) {
+  FileCacheEntry entry;
+  const std::string key1 = "abcdefg";
+  const std::string key2 = "abcd";
+  const std::string md5_1 = "foo";
+  const std::string md5_2 = "bar";
+
+  // Put cache entries.
+  entry.set_md5(md5_1);
+  EXPECT_TRUE(storage_->PutCacheEntry(key1, entry));
+  entry.set_md5(md5_2);
+  EXPECT_TRUE(storage_->PutCacheEntry(key2, entry));
+
+  // Get cache entires.
+  EXPECT_TRUE(storage_->GetCacheEntry(key1, &entry));
+  EXPECT_EQ(md5_1, entry.md5());
+  EXPECT_TRUE(storage_->GetCacheEntry(key2, &entry));
+  EXPECT_EQ(md5_2, entry.md5());
+
+  // Remove cache entries.
+  EXPECT_TRUE(storage_->RemoveCacheEntry(key1));
+  EXPECT_FALSE(storage_->GetCacheEntry(key1, &entry));
+
+  EXPECT_TRUE(storage_->RemoveCacheEntry(key2));
+  EXPECT_FALSE(storage_->GetCacheEntry(key2, &entry));
+}
+
+TEST_F(ResourceMetadataStorageTest, CacheEntryIterator) {
+  // Prepare data.
+  std::map<std::string, FileCacheEntry> entries;
+  FileCacheEntry cache_entry;
+
+  cache_entry.set_md5("aA");
+  entries["entry1"] = cache_entry;
+  cache_entry.set_md5("bB");
+  entries["entry2"] = cache_entry;
+  cache_entry.set_md5("cC");
+  entries["entry3"] = cache_entry;
+  cache_entry.set_md5("dD");
+  entries["entry4"] = cache_entry;
+
+  for (std::map<std::string, FileCacheEntry>::iterator it = entries.begin();
+       it != entries.end(); ++it)
+    EXPECT_TRUE(storage_->PutCacheEntry(it->first, it->second));
+
+  // Insert some dummy entries.
+  ResourceEntry entry;
+  entry.set_resource_id("entry1");
+  EXPECT_TRUE(storage_->PutEntry(entry));
+  entry.set_resource_id("entry2");
+  EXPECT_TRUE(storage_->PutEntry(entry));
+
+  // Iterate and check the result.
+  scoped_ptr<ResourceMetadataStorage::CacheEntryIterator> it =
+      storage_->GetCacheEntryIterator();
+  ASSERT_TRUE(it);
+  size_t num_entries = 0;
+  for (; !it->IsAtEnd(); it->Advance()) {
+    EXPECT_EQ(1U, entries.count(it->GetID()));
+    EXPECT_EQ(entries[it->GetID()].md5(), it->GetValue().md5());
+    ++num_entries;
+  }
+  EXPECT_FALSE(it->HasError());
+  EXPECT_EQ(entries.size(), num_entries);
+}
+
 TEST_F(ResourceMetadataStorageTest, GetChildren) {
   const std::string parents_id[] = { "mercury", "venus", "mars", "jupiter",
                                      "saturn" };
@@ -190,7 +264,7 @@
     EXPECT_TRUE(storage_->PutEntry(entry));
   }
 
-  // Put some data.
+  // Put children.
   for (size_t i = 0; i < children_name_id.size(); ++i) {
     for (size_t j = 0; j < children_name_id[i].size(); ++j) {
       ResourceEntry entry;
@@ -201,6 +275,12 @@
     }
   }
 
+  // Put some dummy cache entries.
+  for (size_t i = 0; i < arraysize(parents_id); ++i) {
+    FileCacheEntry cache_entry;
+    EXPECT_TRUE(storage_->PutCacheEntry(parents_id[i], cache_entry));
+  }
+
   // Try to get children.
   for (size_t i = 0; i < children_name_id.size(); ++i) {
     std::vector<std::string> children;
@@ -231,7 +311,8 @@
   EXPECT_TRUE(storage_->PutEntry(entry2));
 
   // Close DB and reopen.
-  storage_.reset(new ResourceMetadataStorage(temp_dir_.path()));
+  storage_.reset(new ResourceMetadataStorage(
+      temp_dir_.path(), base::MessageLoopProxy::current()));
   ASSERT_TRUE(storage_->Initialize());
 
   // Can read data.
@@ -262,7 +343,8 @@
 
   // Set incompatible version and reopen DB.
   SetDBVersion(ResourceMetadataStorage::kDBVersion - 1);
-  storage_.reset(new ResourceMetadataStorage(temp_dir_.path()));
+  storage_.reset(new ResourceMetadataStorage(
+      temp_dir_.path(), base::MessageLoopProxy::current()));
   ASSERT_TRUE(storage_->Initialize());
 
   // Data is erased because of the incompatible version.
@@ -275,7 +357,8 @@
   base::FilePath path;
   ASSERT_TRUE(file_util::CreateTemporaryFileInDir(temp_dir_.path(), &path));
 
-  storage_.reset(new ResourceMetadataStorage(path));
+  storage_.reset(new ResourceMetadataStorage(
+      path, base::MessageLoopProxy::current()));
   // Cannot initialize DB beacause the path does not point a directory.
   ASSERT_FALSE(storage_->Initialize());
 }
@@ -335,6 +418,11 @@
   PutChild(key2, name3, key3);
   EXPECT_TRUE(CheckValidity());
 
+  // Add some cache entries.
+  FileCacheEntry cache_entry;
+  EXPECT_TRUE(storage_->PutCacheEntry(key1, cache_entry));
+  EXPECT_TRUE(storage_->PutCacheEntry(key2, cache_entry));
+
   // Remove key2.
   RemoveChild(key1, name2);
   EXPECT_FALSE(CheckValidity());
@@ -352,4 +440,5 @@
   EXPECT_TRUE(CheckValidity());
 }
 
+}  // namespace internal
 }  // namespace drive
diff --git a/chrome/browser/chromeos/drive/resource_metadata_unittest.cc b/chrome/browser/chromeos/drive/resource_metadata_unittest.cc
index 82801e8..27608c6 100644
--- a/chrome/browser/chromeos/drive/resource_metadata_unittest.cc
+++ b/chrome/browser/chromeos/drive/resource_metadata_unittest.cc
@@ -123,7 +123,20 @@
         content::BrowserThread::GetBlockingPool();
     blocking_task_runner_ =
         pool->GetSequencedTaskRunner(pool->GetSequenceToken());
-    resource_metadata_.reset(new ResourceMetadata(temp_dir_.path(),
+
+    metadata_storage_.reset(new ResourceMetadataStorage(
+        temp_dir_.path(), blocking_task_runner_));
+    bool success = false;
+    base::PostTaskAndReplyWithResult(
+        blocking_task_runner_,
+        FROM_HERE,
+        base::Bind(&ResourceMetadataStorage::Initialize,
+                   base::Unretained(metadata_storage_.get())),
+        google_apis::test_util::CreateCopyResultCallback(&success));
+    google_apis::test_util::RunBlockingPoolTask();
+    ASSERT_TRUE(success);
+
+    resource_metadata_.reset(new ResourceMetadata(metadata_storage_.get(),
                                                   blocking_task_runner_));
 
     FileError error = FILE_ERROR_FAILED;
@@ -144,6 +157,7 @@
   }
 
   virtual void TearDown() OVERRIDE {
+    metadata_storage_.reset();
     resource_metadata_.reset();
     base::ThreadRestrictions::SetIOAllowed(true);
   }
@@ -175,61 +189,36 @@
     return entries.Pass();
   }
 
+  content::TestBrowserThreadBundle thread_bundle_;
   base::ScopedTempDir temp_dir_;
   scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
+  scoped_ptr<ResourceMetadataStorage, test_util::DestroyHelperForTests>
+      metadata_storage_;
   scoped_ptr<ResourceMetadata, test_util::DestroyHelperForTests>
       resource_metadata_;
-
- private:
-  content::TestBrowserThreadBundle thread_bundle_;
 };
 
 TEST_F(ResourceMetadataTestOnUIThread, LargestChangestamp) {
-  scoped_ptr<ResourceMetadata, test_util::DestroyHelperForTests>
-      resource_metadata(new ResourceMetadata(temp_dir_.path(),
-                                             blocking_task_runner_));
   FileError error = FILE_ERROR_FAILED;
-  base::PostTaskAndReplyWithResult(
-      blocking_task_runner_,
-      FROM_HERE,
-      base::Bind(&ResourceMetadata::Initialize,
-                 base::Unretained(resource_metadata.get())),
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  google_apis::test_util::RunBlockingPoolTask();
-  ASSERT_EQ(FILE_ERROR_OK, error);
-
   int64 in_changestamp = 123456;
-  resource_metadata->SetLargestChangestampOnUIThread(
+  resource_metadata_->SetLargestChangestampOnUIThread(
       in_changestamp,
       google_apis::test_util::CreateCopyResultCallback(&error));
   google_apis::test_util::RunBlockingPoolTask();
   EXPECT_EQ(FILE_ERROR_OK, error);
 
   int64 out_changestamp = 0;
-  resource_metadata->GetLargestChangestampOnUIThread(
+  resource_metadata_->GetLargestChangestampOnUIThread(
       google_apis::test_util::CreateCopyResultCallback(&out_changestamp));
   google_apis::test_util::RunBlockingPoolTask();
   DCHECK_EQ(in_changestamp, out_changestamp);
 }
 
 TEST_F(ResourceMetadataTestOnUIThread, GetResourceEntryById_RootDirectory) {
-  scoped_ptr<ResourceMetadata, test_util::DestroyHelperForTests>
-      resource_metadata(new ResourceMetadata(temp_dir_.path(),
-                                             blocking_task_runner_));
-  FileError error = FILE_ERROR_FAILED;
-  base::PostTaskAndReplyWithResult(
-      blocking_task_runner_,
-      FROM_HERE,
-      base::Bind(&ResourceMetadata::Initialize,
-                 base::Unretained(resource_metadata.get())),
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  google_apis::test_util::RunBlockingPoolTask();
-  ASSERT_EQ(FILE_ERROR_OK, error);
-
-  scoped_ptr<ResourceEntry> entry;
-
   // Look up the root directory by its resource ID.
-  resource_metadata->GetResourceEntryByIdOnUIThread(
+  FileError error = FILE_ERROR_FAILED;
+  scoped_ptr<ResourceEntry> entry;
+  resource_metadata_->GetResourceEntryByIdOnUIThread(
       util::kDriveGrandRootSpecialResourceId,
       google_apis::test_util::CreateCopyResultCallback(&error, &entry));
   google_apis::test_util::RunBlockingPoolTask();
@@ -524,13 +513,13 @@
           &error, &drive_file_path));
   google_apis::test_util::RunBlockingPoolTask();
   EXPECT_EQ(FILE_ERROR_OK, error);
-  EXPECT_EQ(base::FilePath::FromUTF8Unsafe("drive/root/dir2/file7 (2)"),
+  EXPECT_EQ(base::FilePath::FromUTF8Unsafe("drive/root/dir2/file7 (1)"),
             drive_file_path);
 
   // Rename to same name. This should fail.
   resource_metadata_->RenameEntryOnUIThread(
-      base::FilePath::FromUTF8Unsafe("drive/root/dir2/file7 (2)"),
-      "file7 (2)",
+      base::FilePath::FromUTF8Unsafe("drive/root/dir2/file7 (1)"),
+      "file7 (1)",
       google_apis::test_util::CreateCopyResultCallback(
           &error, &drive_file_path));
   google_apis::test_util::RunBlockingPoolTask();
@@ -869,20 +858,22 @@
   virtual void SetUp() OVERRIDE {
     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
 
-    // Use the main thread as the blocking task runner.
-    resource_metadata_.reset(new ResourceMetadata(
+    metadata_storage_.reset(new ResourceMetadataStorage(
         temp_dir_.path(), base::MessageLoopProxy::current()));
+    ASSERT_TRUE(metadata_storage_->Initialize());
+
+    resource_metadata_.reset(new ResourceMetadata(
+        metadata_storage_.get(), base::MessageLoopProxy::current()));
 
     ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->Initialize());
 
     SetUpEntries(resource_metadata_.get());
   }
 
-  virtual void TearDown() OVERRIDE {
-  }
-
   base::ScopedTempDir temp_dir_;
   content::TestBrowserThreadBundle thread_bundle_;
+  scoped_ptr<ResourceMetadataStorage, test_util::DestroyHelperForTests>
+      metadata_storage_;
   scoped_ptr<ResourceMetadata, test_util::DestroyHelperForTests>
       resource_metadata_;
 };
diff --git a/chrome/browser/chromeos/drive/search_metadata.cc b/chrome/browser/chromeos/drive/search_metadata.cc
index 9df8abb..b0824f9 100644
--- a/chrome/browser/chromeos/drive/search_metadata.cc
+++ b/chrome/browser/chromeos/drive/search_metadata.cc
@@ -8,8 +8,7 @@
 #include <queue>
 
 #include "base/bind.h"
-#include "base/i18n/string_search.h"
-#include "base/strings/utf_string_conversions.h"
+#include "base/strings/string_util.h"
 #include "chrome/browser/chromeos/drive/file_cache.h"
 #include "chrome/browser/chromeos/drive/file_system_util.h"
 #include "content/public/browser/browser_thread.h"
@@ -177,7 +176,7 @@
     results->push_back(*result_candidates.top());
 
   // Reverse the order here because |result_candidates| puts the most
-  // uninterested candidate at the top.
+  // uninteresting candidate at the top.
   std::reverse(results->begin(), results->end());
 
   return results.Pass();
@@ -219,22 +218,21 @@
   if (query.empty())
     return true;
 
-  string16 text16 = base::UTF8ToUTF16(text);
-  string16 query16 = base::UTF8ToUTF16(query);
-  size_t match_start = 0;
-  size_t match_length = 0;
-  if (!base::i18n::StringSearchIgnoringCaseAndAccents(
-      query16, text16, &match_start, &match_length)) {
+  // TODO(kinaba): Should support non-ASCII characters.
+  std::string lower_text = StringToLowerASCII(text);
+  std::string lower_query = StringToLowerASCII(query);
+  std::string::size_type match_start = lower_text.find(lower_query);
+  if (match_start == std::string::npos)
     return false;
-  }
-  string16 pre = text16.substr(0, match_start);
-  string16 match = text16.substr(match_start, match_length);
-  string16 post = text16.substr(match_start + match_length);
-  highlighted_text->append(net::EscapeForHTML(UTF16ToUTF8(pre)));
+
+  std::string pre = text.substr(0, match_start);
+  std::string match = text.substr(match_start, query.size());
+  std::string post = text.substr(match_start + query.size());
+  highlighted_text->append(net::EscapeForHTML(pre));
   highlighted_text->append("<b>");
-  highlighted_text->append(net::EscapeForHTML(UTF16ToUTF8(match)));
+  highlighted_text->append(net::EscapeForHTML(match));
   highlighted_text->append("</b>");
-  highlighted_text->append(net::EscapeForHTML(UTF16ToUTF8(post)));
+  highlighted_text->append(net::EscapeForHTML(post));
   return true;
 }
 
diff --git a/chrome/browser/chromeos/drive/search_metadata.h b/chrome/browser/chromeos/drive/search_metadata.h
index 9a6d5bf..e250a09 100644
--- a/chrome/browser/chromeos/drive/search_metadata.h
+++ b/chrome/browser/chromeos/drive/search_metadata.h
@@ -37,7 +37,7 @@
 // Returns true if |query| is found. |highlighted_text| will have the original
 // text with matched portions highlighted with <b> tag (only the first match
 // is highlighted). Meta characters are escaped like &lt;. The original
-// contents of |highlighted| will be lost.
+// contents of |highlighted_text| will be lost.
 bool FindAndHighlight(const std::string& text,
                       const std::string& query,
                       std::string* highlighted_text);
diff --git a/chrome/browser/chromeos/drive/search_metadata_unittest.cc b/chrome/browser/chromeos/drive/search_metadata_unittest.cc
index 94c2074..645ccb5 100644
--- a/chrome/browser/chromeos/drive/search_metadata_unittest.cc
+++ b/chrome/browser/chromeos/drive/search_metadata_unittest.cc
@@ -67,14 +67,18 @@
     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
     fake_free_disk_space_getter_.reset(new FakeFreeDiskSpaceGetter);
 
-    cache_.reset(new internal::FileCache(temp_dir_.path(),
-                                         temp_dir_.path(),
-                                         base::MessageLoopProxy::current(),
-                                         fake_free_disk_space_getter_.get()));
+    metadata_storage_.reset(new ResourceMetadataStorage(
+        temp_dir_.path(), base::MessageLoopProxy::current()));
+    ASSERT_TRUE(metadata_storage_->Initialize());
+
+    cache_.reset(new FileCache(metadata_storage_.get(),
+                               temp_dir_.path(),
+                               base::MessageLoopProxy::current(),
+                               fake_free_disk_space_getter_.get()));
     ASSERT_TRUE(cache_->Initialize());
 
     resource_metadata_.reset(
-        new ResourceMetadata(temp_dir_.path(),
+        new ResourceMetadata(metadata_storage_.get(),
                              base::MessageLoopProxy::current()));
     ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->Initialize());
 
@@ -188,6 +192,8 @@
   content::TestBrowserThreadBundle thread_bundle_;
   base::ScopedTempDir temp_dir_;
   scoped_ptr<FakeFreeDiskSpaceGetter> fake_free_disk_space_getter_;
+  scoped_ptr<ResourceMetadataStorage,
+             test_util::DestroyHelperForTests> metadata_storage_;
   scoped_ptr<ResourceMetadata, test_util::DestroyHelperForTests>
       resource_metadata_;
   scoped_ptr<FileCache, test_util::DestroyHelperForTests> cache_;
@@ -552,28 +558,6 @@
   EXPECT_EQ("<b>HeLLo</b>", highlighted_text);
 }
 
-TEST(SearchMetadataSimpleTest, FindAndHighlight_IgnoreCaseNonASCII) {
-  std::string highlighted_text;
-
-  // Case and accent ignorance in Greek. Find "socra" in "Socra'tes".
-  EXPECT_TRUE(FindAndHighlight(
-      "\xCE\xA3\xCF\x89\xCE\xBA\xCF\x81\xCE\xAC\xCF\x84\xCE\xB7\xCF\x82",
-      "\xCF\x83\xCF\x89\xCE\xBA\xCF\x81\xCE\xB1", &highlighted_text));
-  EXPECT_EQ(
-      "<b>\xCE\xA3\xCF\x89\xCE\xBA\xCF\x81\xCE\xAC</b>\xCF\x84\xCE\xB7\xCF\x82",
-      highlighted_text);
-
-  // In Japanese characters.
-  // Find Hiragana "pi" + "(small)ya" in Katakana "hi" + semi-voiced-mark + "ya"
-  EXPECT_TRUE(FindAndHighlight(
-      "\xE3\x81\xB2\xE3\x82\x9A\xE3\x82\x83\xE3\x83\xBC",
-      "\xE3\x83\x94\xE3\x83\xA4",
-      &highlighted_text));
-  EXPECT_EQ(
-      "<b>\xE3\x81\xB2\xE3\x82\x9A\xE3\x82\x83</b>\xE3\x83\xBC",
-      highlighted_text);
-}
-
 TEST(SearchMetadataSimpleTest, FindAndHighlight_MetaChars) {
   std::string highlighted_text;
   EXPECT_TRUE(FindAndHighlight("<hello>", "hello", &highlighted_text));
diff --git a/chrome/browser/chromeos/drive/sync_client.cc b/chrome/browser/chromeos/drive/sync_client.cc
index 4d12ff3..fca455e 100644
--- a/chrome/browser/chromeos/drive/sync_client.cc
+++ b/chrome/browser/chromeos/drive/sync_client.cc
@@ -322,9 +322,15 @@
   if (error == FILE_ERROR_OK) {
     DVLOG(1) << "Uploaded " << resource_id;
   } else {
-    // TODO(satorux): We should re-queue if the error is recoverable.
-    LOG(WARNING) << "Failed to upload " << resource_id << ": "
-                 << FileErrorToString(error);
+    switch (error) {
+      case FILE_ERROR_NO_CONNECTION:
+        // Re-queue the task so that we'll retry once the connection is back.
+        AddTaskToQueue(UPLOAD, resource_id);
+        break;
+      default:
+        LOG(WARNING) << "Failed to upload " << resource_id << ": "
+                     << FileErrorToString(error);
+    }
   }
 }
 
diff --git a/chrome/browser/chromeos/drive/sync_client.h b/chrome/browser/chromeos/drive/sync_client.h
index a5a66e8..c9b6614 100644
--- a/chrome/browser/chromeos/drive/sync_client.h
+++ b/chrome/browser/chromeos/drive/sync_client.h
@@ -11,7 +11,7 @@
 
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/chromeos/drive/file_errors.h"
 
 namespace base {
diff --git a/chrome/browser/chromeos/drive/sync_client_unittest.cc b/chrome/browser/chromeos/drive/sync_client_unittest.cc
index 4aae520..ec76076 100644
--- a/chrome/browser/chromeos/drive/sync_client_unittest.cc
+++ b/chrome/browser/chromeos/drive/sync_client_unittest.cc
@@ -12,6 +12,7 @@
 #include "base/test/test_timeouts.h"
 #include "chrome/browser/chromeos/drive/change_list_loader.h"
 #include "chrome/browser/chromeos/drive/drive.pb.h"
+#include "chrome/browser/chromeos/drive/fake_free_disk_space_getter.h"
 #include "chrome/browser/chromeos/drive/file_cache.h"
 #include "chrome/browser/chromeos/drive/file_system/operation_observer.h"
 #include "chrome/browser/chromeos/drive/job_scheduler.h"
@@ -29,7 +30,7 @@
 
 namespace {
 
-// The content of files iniitally stored in the cache.
+// The content of files initially stored in the cache.
 const char kLocalContent[] = "Hello!";
 
 // The content of files stored in the service.
@@ -37,22 +38,28 @@
 
 // SyncClientTestDriveService will return GDATA_CANCELLED when a request is
 // made with the specified resource ID.
-class SyncClientTestDriveService : public google_apis::FakeDriveService {
+class SyncClientTestDriveService : public ::drive::FakeDriveService {
  public:
   // FakeDriveService override:
-  virtual google_apis::CancelCallback GetResourceEntry(
+  virtual google_apis::CancelCallback DownloadFile(
+      const base::FilePath& local_cache_path,
       const std::string& resource_id,
-      const google_apis::GetResourceEntryCallback& callback) OVERRIDE {
+      const google_apis::DownloadActionCallback& download_action_callback,
+      const google_apis::GetContentCallback& get_content_callback,
+      const google_apis::ProgressCallback& progress_callback) OVERRIDE {
     if (resource_id == resource_id_to_be_cancelled_) {
-      scoped_ptr<google_apis::ResourceEntry> null;
       base::MessageLoopProxy::current()->PostTask(
           FROM_HERE,
-          base::Bind(callback,
+          base::Bind(download_action_callback,
                      google_apis::GDATA_CANCELLED,
-                     base::Passed(&null)));
+                     base::FilePath()));
       return google_apis::CancelCallback();
     }
-    return FakeDriveService::GetResourceEntry(resource_id, callback);
+    return FakeDriveService::DownloadFile(local_cache_path,
+                                          resource_id,
+                                          download_action_callback,
+                                          get_content_callback,
+                                          progress_callback);
   }
 
   void set_resource_id_to_be_cancelled(const std::string& resource_id) {
@@ -80,17 +87,26 @@
 
     profile_.reset(new TestingProfile);
 
-    drive_service_.reset(new SyncClientTestDriveService);
-    drive_service_->LoadResourceListForWapi("chromeos/gdata/empty_feed.json");
-    drive_service_->LoadAccountMetadataForWapi(
-        "chromeos/gdata/account_metadata.json");
+    fake_network_change_notifier_.reset(
+        new test_util::FakeNetworkChangeNotifier);
 
-    scheduler_.reset(new JobScheduler(profile_.get(), drive_service_.get()));
-    metadata_.reset(new internal::ResourceMetadata(
+    drive_service_.reset(new SyncClientTestDriveService);
+    drive_service_->LoadResourceListForWapi("gdata/empty_feed.json");
+    drive_service_->LoadAccountMetadataForWapi(
+        "gdata/account_metadata.json");
+
+    scheduler_.reset(new JobScheduler(profile_.get(), drive_service_.get(),
+                                      base::MessageLoopProxy::current()));
+
+    metadata_storage_.reset(new ResourceMetadataStorage(
         temp_dir_.path(), base::MessageLoopProxy::current()));
+    ASSERT_TRUE(metadata_storage_->Initialize());
+
+    metadata_.reset(new internal::ResourceMetadata(
+        metadata_storage_.get(), base::MessageLoopProxy::current()));
     ASSERT_EQ(FILE_ERROR_OK, metadata_->Initialize());
 
-    cache_.reset(new FileCache(temp_dir_.path(),
+    cache_.reset(new FileCache(metadata_storage_.get(),
                                temp_dir_.path(),
                                base::MessageLoopProxy::current(),
                                NULL /* free_disk_space_getter */));
@@ -109,12 +125,6 @@
     sync_client_->set_delay_for_testing(base::TimeDelta::FromSeconds(0));
   }
 
-  virtual void TearDown() OVERRIDE {
-    sync_client_.reset();
-    cache_.reset();
-    metadata_.reset();
-  }
-
   // Adds a file to the service root and |resource_ids_|.
   void AddFileEntry(const std::string& title) {
     google_apis::GDataErrorCode error = google_apis::GDATA_FILE_ERROR;
@@ -184,11 +194,14 @@
   content::TestBrowserThreadBundle thread_bundle_;
   base::ScopedTempDir temp_dir_;
   scoped_ptr<TestingProfile> profile_;
+  scoped_ptr<test_util::FakeNetworkChangeNotifier>
+      fake_network_change_notifier_;
   scoped_ptr<SyncClientTestDriveService> drive_service_;
   DummyOperationObserver observer_;
   scoped_ptr<JobScheduler> scheduler_;
-  scoped_ptr<internal::ResourceMetadata, test_util::DestroyHelperForTests>
-      metadata_;
+  scoped_ptr<ResourceMetadataStorage,
+             test_util::DestroyHelperForTests> metadata_storage_;
+  scoped_ptr<ResourceMetadata, test_util::DestroyHelperForTests> metadata_;
   scoped_ptr<FileCache, test_util::DestroyHelperForTests> cache_;
   scoped_ptr<SyncClient> sync_client_;
 
@@ -288,5 +301,48 @@
   EXPECT_EQ(kLocalContent, content);
 }
 
+TEST_F(SyncClientTest, RetryOnDisconnection) {
+  // Let the service go down.
+  drive_service_->set_offline(true);
+  // Change the network connection state after some delay, to test that
+  // FILE_ERROR_NO_CONNECTION is handled by SyncClient correctly.
+  // Without this delay, JobScheduler will keep the jobs unrun and SyncClient
+  // will receive no error.
+  base::MessageLoopProxy::current()->PostDelayedTask(
+      FROM_HERE,
+      base::Bind(&test_util::FakeNetworkChangeNotifier::SetConnectionType,
+                 base::Unretained(fake_network_change_notifier_.get()),
+                 net::NetworkChangeNotifier::CONNECTION_NONE),
+      TestTimeouts::tiny_timeout());
+
+  // Try fetch and upload.
+  sync_client_->AddFetchTask(resource_ids_["foo"]);
+  sync_client_->AddUploadTask(resource_ids_["dirty"]);
+  base::RunLoop().RunUntilIdle();
+
+  // Not yet fetched nor uploaded.
+  FileCacheEntry cache_entry;
+  EXPECT_TRUE(cache_->GetCacheEntry(resource_ids_["foo"], std::string(),
+                                    &cache_entry));
+  EXPECT_FALSE(cache_entry.is_present());
+  EXPECT_TRUE(cache_->GetCacheEntry(resource_ids_["dirty"], std::string(),
+                                    &cache_entry));
+  EXPECT_TRUE(cache_entry.is_dirty());
+
+  // Switch to online.
+  fake_network_change_notifier_->SetConnectionType(
+      net::NetworkChangeNotifier::CONNECTION_WIFI);
+  drive_service_->set_offline(false);
+  base::RunLoop().RunUntilIdle();
+
+  // Fetched and uploaded.
+  EXPECT_TRUE(cache_->GetCacheEntry(resource_ids_["foo"], std::string(),
+                                    &cache_entry));
+  EXPECT_TRUE(cache_entry.is_present());
+  EXPECT_TRUE(cache_->GetCacheEntry(resource_ids_["dirty"], std::string(),
+                                    &cache_entry));
+  EXPECT_FALSE(cache_entry.is_dirty());
+}
+
 }  // namespace internal
 }  // namespace drive
diff --git a/chrome/browser/chromeos/drive/test_util.cc b/chrome/browser/chromeos/drive/test_util.cc
index 93307a2..8caaa31 100644
--- a/chrome/browser/chromeos/drive/test_util.cc
+++ b/chrome/browser/chromeos/drive/test_util.cc
@@ -123,5 +123,19 @@
   return true;
 }
 
+FakeNetworkChangeNotifier::FakeNetworkChangeNotifier()
+    : type_(CONNECTION_WIFI) {
+}
+
+void FakeNetworkChangeNotifier::SetConnectionType(ConnectionType type) {
+  type_ = type;
+  NotifyObserversOfConnectionTypeChange();
+}
+
+net::NetworkChangeNotifier::ConnectionType
+FakeNetworkChangeNotifier::GetCurrentConnectionType() const {
+  return type_;
+}
+
 }  // namespace test_util
 }  // namespace drive
diff --git a/chrome/browser/chromeos/drive/test_util.h b/chrome/browser/chromeos/drive/test_util.h
index 3fa88b0..823ffd7 100644
--- a/chrome/browser/chromeos/drive/test_util.h
+++ b/chrome/browser/chromeos/drive/test_util.h
@@ -12,6 +12,7 @@
 #include "chrome/browser/google_apis/test_util.h"
 #include "net/base/completion_callback.h"
 #include "net/base/io_buffer.h"
+#include "net/base/network_change_notifier.h"
 #include "net/base/test_completion_callback.h"
 
 namespace net {
@@ -81,6 +82,20 @@
     internal::FileCache* cache,
     const std::vector<TestCacheResource>& resources);
 
+// Fake NetworkChangeNotifier implementation.
+class FakeNetworkChangeNotifier : public net::NetworkChangeNotifier {
+ public:
+  FakeNetworkChangeNotifier();
+
+  void SetConnectionType(ConnectionType type);
+
+  // NetworkChangeNotifier override.
+  virtual ConnectionType GetCurrentConnectionType() const OVERRIDE;
+
+ private:
+  net::NetworkChangeNotifier::ConnectionType type_;
+};
+
 }  // namespace test_util
 }  // namespace drive
 
diff --git a/chrome/browser/chromeos/drive/webkit_file_stream_reader_impl.h b/chrome/browser/chromeos/drive/webkit_file_stream_reader_impl.h
index 0f94eb7..f0a7c2f 100644
--- a/chrome/browser/chromeos/drive/webkit_file_stream_reader_impl.h
+++ b/chrome/browser/chromeos/drive/webkit_file_stream_reader_impl.h
@@ -10,7 +10,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/chromeos/drive/drive_file_stream_reader.h"
 #include "net/base/completion_callback.h"
 #include "webkit/browser/blob/file_stream_reader.h"
diff --git a/chrome/browser/chromeos/drive/webkit_file_stream_reader_impl_unittest.cc b/chrome/browser/chromeos/drive/webkit_file_stream_reader_impl_unittest.cc
index 48e8307..1392ac5 100644
--- a/chrome/browser/chromeos/drive/webkit_file_stream_reader_impl_unittest.cc
+++ b/chrome/browser/chromeos/drive/webkit_file_stream_reader_impl_unittest.cc
@@ -11,7 +11,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/message_loop.h"
 #include "base/threading/thread.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/chromeos/drive/fake_file_system.h"
 #include "chrome/browser/chromeos/drive/file_system_interface.h"
 #include "chrome/browser/chromeos/drive/file_system_util.h"
@@ -40,11 +40,11 @@
     ASSERT_TRUE(worker_thread_->Start());
 
     // Initialize FakeDriveService.
-    fake_drive_service_.reset(new google_apis::FakeDriveService);
+    fake_drive_service_.reset(new FakeDriveService);
     fake_drive_service_->LoadResourceListForWapi(
-        "chromeos/gdata/root_feed.json");
+        "gdata/root_feed.json");
     fake_drive_service_->LoadAccountMetadataForWapi(
-        "chromeos/gdata/account_metadata.json");
+        "gdata/account_metadata.json");
 
     // Create a testee instance.
     fake_file_system_.reset(
@@ -52,13 +52,6 @@
     fake_file_system_->Initialize();
   }
 
-  virtual void TearDown() OVERRIDE {
-    fake_file_system_.reset();
-    fake_drive_service_.reset();
-
-    worker_thread_.reset();
-  }
-
   FileSystemInterface* GetFileSystem() {
     return fake_file_system_.get();
   }
@@ -72,7 +65,7 @@
 
   scoped_ptr<base::Thread> worker_thread_;
 
-  scoped_ptr<google_apis::FakeDriveService> fake_drive_service_;
+  scoped_ptr<FakeDriveService> fake_drive_service_;
   scoped_ptr<test_util::FakeFileSystem> fake_file_system_;
 };
 
diff --git a/chrome/browser/chromeos/extensions/OWNERS b/chrome/browser/chromeos/extensions/OWNERS
index 838137a..d85d766 100644
--- a/chrome/browser/chromeos/extensions/OWNERS
+++ b/chrome/browser/chromeos/extensions/OWNERS
@@ -3,7 +3,6 @@
 benwells@chromium.org
 erikkay@chromium.org
 finnur@chromium.org
-jeremya@chromium.org
 jyasskin@chromium.org
 kalman@chromium.org
 koz@chromium.org
diff --git a/chrome/browser/chromeos/extensions/default_app_order.cc b/chrome/browser/chromeos/extensions/default_app_order.cc
index 7a8551e..4ffc078 100644
--- a/chrome/browser/chromeos/extensions/default_app_order.cc
+++ b/chrome/browser/chromeos/extensions/default_app_order.cc
@@ -10,7 +10,7 @@
 #include "base/files/file_path.h"
 #include "base/json/json_file_value_serializer.h"
 #include "base/path_service.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/common/extensions/extension_constants.h"
 #include "chromeos/chromeos_paths.h"
 #include "content/public/browser/browser_thread.h"
diff --git a/chrome/browser/chromeos/extensions/echo_private_api.cc b/chrome/browser/chromeos/extensions/echo_private_api.cc
index 5580cc2..edf3f6f 100644
--- a/chrome/browser/chromeos/extensions/echo_private_api.cc
+++ b/chrome/browser/chromeos/extensions/echo_private_api.cc
@@ -11,7 +11,7 @@
 #include "base/location.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/chromeos/kiosk_mode/kiosk_mode_settings.h"
 #include "chrome/browser/chromeos/settings/cros_settings.h"
 #include "chrome/browser/chromeos/system/statistics_provider.h"
@@ -51,9 +51,7 @@
   }
   // Possible ECHO code type and corresponding key name in StatisticsProvider.
   const std::string kCouponType = "COUPON_CODE";
-  const std::string kCouponCodeKey = "ubind_attribute";
   const std::string kGroupType = "GROUP_CODE";
-  const std::string kGroupCodeKey = "gbind_attribute";
 
   chromeos::system::StatisticsProvider* provider =
       chromeos::system::StatisticsProvider::GetInstance();
@@ -61,10 +59,13 @@
   if (!chromeos::KioskModeSettings::Get()->IsKioskModeEnabled()) {
     // In Kiosk mode, we effectively disable the registration API
     // by always returning an empty code.
-    if (type == kCouponType)
-      provider->GetMachineStatistic(kCouponCodeKey, &result);
-    else if (type == kGroupType)
-      provider->GetMachineStatistic(kGroupCodeKey, &result);
+    if (type == kCouponType) {
+      provider->GetMachineStatistic(chromeos::system::kOffersCouponCodeKey,
+                                    &result);
+    } else if (type == kGroupType) {
+      provider->GetMachineStatistic(chromeos::system::kOffersGroupCodeKey,
+                                    &result);
+    }
   }
 
   results_ = echo_api::GetRegistrationCode::Results::Create(result);
diff --git a/chrome/browser/chromeos/extensions/file_manager/drive_test_util.cc b/chrome/browser/chromeos/extensions/file_manager/drive_test_util.cc
index 87aece5..4fe56ae 100644
--- a/chrome/browser/chromeos/extensions/file_manager/drive_test_util.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/drive_test_util.cc
@@ -2,11 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "base/bind.h"
+#include "chrome/browser/chromeos/extensions/file_manager/drive_test_util.h"
+
 #include "base/files/file_path.h"
 #include "base/run_loop.h"
 #include "chrome/browser/chromeos/drive/drive_integration_service.h"
-#include "chrome/browser/chromeos/drive/file_system.h"
 #include "chrome/browser/profiles/profile.h"
 #include "content/public/browser/browser_context.h"
 #include "webkit/browser/fileapi/external_mount_points.h"
@@ -15,8 +15,6 @@
 
 namespace {
 
-const char kDriveMountPointName[] = "drive";
-
 // Helper class used to wait for |OnFileSystemMounted| event from a drive file
 // system.
 class DriveMountPointWaiter : public drive::DriveIntegrationServiceObserver {
@@ -65,16 +63,18 @@
           profile);
   DCHECK(integration_service);
 
-  DriveMountPointWaiter mount_point_waiter(integration_service);
-
+  const std::string drive_mount_point_name =
+      drive::util::GetDriveMountPointPath().BaseName().AsUTF8Unsafe();
   base::FilePath ignored;
   // GetRegisteredPath succeeds iff the mount point exists.
-  if (!content::BrowserContext::GetMountPoints(profile)->
-      GetRegisteredPath(kDriveMountPointName, &ignored)) {
-    LOG(WARNING) << "Waiting for drive mount point to get mounted.";
-    mount_point_waiter.Wait();
-    LOG(WARNING) << "Drive mount point found.";
-  }
+  if (content::BrowserContext::GetMountPoints(profile)->
+      GetRegisteredPath(drive_mount_point_name, &ignored))
+    return;
+
+  DriveMountPointWaiter mount_point_waiter(integration_service);
+  LOG(INFO) << "Waiting for drive mount point to get mounted.";
+  mount_point_waiter.Wait();
+  LOG(INFO) << "Drive mount point found.";
 }
 
 }  // namespace drive_test_util
diff --git a/chrome/browser/chromeos/extensions/file_manager/external_filesystem_apitest.cc b/chrome/browser/chromeos/extensions/file_manager/external_filesystem_apitest.cc
index 7e76626..ba56fda 100644
--- a/chrome/browser/chromeos/extensions/file_manager/external_filesystem_apitest.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/external_filesystem_apitest.cc
@@ -6,32 +6,15 @@
 #include "base/file_util.h"
 #include "base/files/file_path.h"
 #include "base/files/scoped_temp_dir.h"
-#include "base/json/json_file_value_serializer.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop_proxy.h"
-#include "base/path_service.h"
-#include "base/threading/worker_pool.h"
-#include "base/values.h"
 #include "chrome/browser/chromeos/drive/drive_integration_service.h"
-#include "chrome/browser/chromeos/drive/file_system.h"
 #include "chrome/browser/chromeos/extensions/file_manager/drive_test_util.h"
 #include "chrome/browser/drive/fake_drive_service.h"
-#include "chrome/browser/extensions/event_router.h"
 #include "chrome/browser/extensions/extension_apitest.h"
-#include "chrome/browser/extensions/extension_service.h"
-#include "chrome/browser/extensions/extension_system.h"
-#include "chrome/browser/extensions/extension_test_message_listener.h"
-#include "chrome/browser/google_apis/gdata_wapi_parser.h"
 #include "chrome/browser/google_apis/test_util.h"
-#include "chrome/browser/google_apis/time_util.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/common/chrome_notification_types.h"
-#include "chrome/common/chrome_paths.h"
-#include "chrome/common/chrome_switches.h"
-#include "chrome/test/base/ui_test_utils.h"
 #include "content/public/browser/browser_context.h"
-#include "content/public/browser/browser_thread.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/test/test_utils.h"
 #include "webkit/browser/fileapi/external_mount_points.h"
@@ -60,7 +43,6 @@
 // - Doing searches on drive file system from file browser extension (using
 //   fileBrowserPrivate API).
 
-using content::BrowserContext;
 using extensions::Extension;
 
 namespace {
@@ -94,15 +76,7 @@
 // All files except test_dir/empty_file.foo, which is empty, initially contain
 // kTestFileContent.
 const char kTestRootFeed[] =
-    "chromeos/gdata/remote_file_system_apitest_root_feed.json";
-
-// Creates a test file with predetermined content. Returns true on success.
-bool CreateFileWithContent(const base::FilePath& path,
-                           const std::string& content) {
-  int content_size = static_cast<int>(content.length());
-  int written = file_util::WriteFile(path, content.c_str(), content_size);
-  return written == content_size;
-}
+    "gdata/remote_file_system_apitest_root_feed.json";
 
 // Sets up the initial file system state for native local and restricted native
 // local file systems. The hierarchy is the same as for the drive file system.
@@ -111,16 +85,16 @@
   if (!tmp_dir->CreateUniqueTempDir())
     return false;
 
-  *mount_point_dir = tmp_dir->path().Append("mount");
+  *mount_point_dir = tmp_dir->path().AppendASCII("mount");
   // Create the mount point.
   if (!file_util::CreateDirectory(*mount_point_dir))
     return false;
 
-  base::FilePath test_dir = mount_point_dir->Append("test_dir");
+  base::FilePath test_dir = mount_point_dir->AppendASCII("test_dir");
   if (!file_util::CreateDirectory(test_dir))
     return false;
 
-  base::FilePath test_subdir = test_dir.Append("empty_test_dir");
+  base::FilePath test_subdir = test_dir.AppendASCII("empty_test_dir");
   if (!file_util::CreateDirectory(test_subdir))
     return false;
 
@@ -129,23 +103,23 @@
     return false;
 
   base::FilePath test_file = test_dir.AppendASCII("test_file.xul");
-  if (!CreateFileWithContent(test_file, kTestFileContent))
+  if (!google_apis::test_util::WriteStringToFile(test_file, kTestFileContent))
     return false;
 
   test_file = test_dir.AppendASCII("test_file.xul.foo");
-  if (!CreateFileWithContent(test_file, kTestFileContent))
+  if (!google_apis::test_util::WriteStringToFile(test_file, kTestFileContent))
     return false;
 
   test_file = test_dir.AppendASCII("test_file.tiff");
-  if (!CreateFileWithContent(test_file, kTestFileContent))
+  if (!google_apis::test_util::WriteStringToFile(test_file, kTestFileContent))
     return false;
 
   test_file = test_dir.AppendASCII("test_file.tiff.foo");
-  if (!CreateFileWithContent(test_file, kTestFileContent))
+  if (!google_apis::test_util::WriteStringToFile(test_file, kTestFileContent))
     return false;
 
   test_file = test_dir.AppendASCII("empty_test_file.foo");
-  if (!CreateFileWithContent(test_file, ""))
+  if (!google_apis::test_util::WriteStringToFile(test_file, ""))
     return false;
 
   return true;
@@ -273,8 +247,8 @@
   virtual void AddTestMountPoint() OVERRIDE {
     EXPECT_TRUE(content::BrowserContext::GetMountPoints(browser()->profile())->
         RegisterFileSystem(kLocalMountPointName,
-                            fileapi::kFileSystemTypeNativeLocal,
-                            mount_point_dir_));
+                           fileapi::kFileSystemTypeNativeLocal,
+                           mount_point_dir_));
   }
 
  private:
@@ -320,9 +294,7 @@
     // system service. This has to be done early on (before the browser is
     // created) because the system service instance is initialized very early
     // by FileManagerEventRouter.
-    base::FilePath tmp_dir_path;
-    PathService::Get(base::DIR_TEMP, &tmp_dir_path);
-    ASSERT_TRUE(test_cache_root_.CreateUniqueTempDirUnderPath(tmp_dir_path));
+    ASSERT_TRUE(test_cache_root_.CreateUniqueTempDir());
 
     drive::DriveIntegrationServiceFactory::SetFactoryForTest(
         base::Bind(
@@ -339,11 +311,11 @@
   // DriveIntegrationService factory function for this test.
   drive::DriveIntegrationService* CreateDriveIntegrationService(
       Profile* profile) {
-    fake_drive_service_ = new google_apis::FakeDriveService;
+    fake_drive_service_ = new drive::FakeDriveService;
     fake_drive_service_->LoadResourceListForWapi(kTestRootFeed);
     fake_drive_service_->LoadAccountMetadataForWapi(
-        "chromeos/gdata/account_metadata.json");
-    fake_drive_service_->LoadAppListForDriveApi("chromeos/drive/applist.json");
+        "gdata/account_metadata.json");
+    fake_drive_service_->LoadAppListForDriveApi("drive/applist.json");
 
     return new drive::DriveIntegrationService(profile,
                                               fake_drive_service_,
@@ -352,7 +324,7 @@
   }
 
   base::ScopedTempDir test_cache_root_;
-  google_apis::FakeDriveService* fake_drive_service_;
+  drive::FakeDriveService* fake_drive_service_;
 };
 
 //
diff --git a/chrome/browser/chromeos/extensions/file_manager/file_browser_handler.cc b/chrome/browser/chromeos/extensions/file_manager/file_browser_handler.cc
index 715c0b6..ed894d3 100644
--- a/chrome/browser/chromeos/extensions/file_manager/file_browser_handler.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/file_browser_handler.cc
@@ -15,8 +15,6 @@
 #include "content/public/common/url_constants.h"
 #include "extensions/common/error_utils.h"
 #include "extensions/common/url_pattern.h"
-#include "googleurl/src/gurl.h"
-#include "googleurl/src/url_util.h"
 
 namespace keys = extension_manifest_keys;
 namespace errors = extension_manifest_errors;
diff --git a/chrome/browser/chromeos/extensions/file_manager/file_browser_handler.h b/chrome/browser/chromeos/extensions/file_manager/file_browser_handler.h
index da1f4b2..7b9169c 100644
--- a/chrome/browser/chromeos/extensions/file_manager/file_browser_handler.h
+++ b/chrome/browser/chromeos/extensions/file_manager/file_browser_handler.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_CHROMEOS_EXTENSIONS_FILE_MANAGER_FILE_BROWSER_HANDLER_H_
 #define CHROME_BROWSER_CHROMEOS_EXTENSIONS_FILE_MANAGER_FILE_BROWSER_HANDLER_H_
 
-#include <set>
 #include <string>
 #include <vector>
 
@@ -14,8 +13,8 @@
 #include "chrome/common/extensions/manifest_handler.h"
 #include "extensions/common/url_pattern.h"
 #include "extensions/common/url_pattern_set.h"
-#include "googleurl/src/gurl.h"
 
+class GURL;
 class URLPattern;
 
 // FileBrowserHandler encapsulates the state of a file browser action.
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 556f12a..cfe538b 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
@@ -35,9 +35,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/message_loop/message_loop_proxy.h"
 #include "base/platform_file.h"
-#include "base/values.h"
 #include "chrome/browser/chromeos/extensions/file_manager/file_handler_util.h"
-#include "chrome/browser/chromeos/extensions/file_manager/file_manager_util.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_window.h"
@@ -49,7 +47,6 @@
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/storage_partition.h"
-#include "googleurl/src/gurl.h"
 #include "ui/shell_dialogs/select_file_dialog.h"
 #include "webkit/browser/fileapi/file_system_context.h"
 #include "webkit/browser/fileapi/file_system_mount_point_provider.h"
@@ -183,7 +180,7 @@
     // function.
     base::MessageLoopProxy::current()->PostTask(FROM_HERE,
         base::Bind(&FileSelectorImpl::FileSelectionCanceled,
-                   base::Unretained(this), reinterpret_cast<void*>(NULL)));
+                   base::Unretained(this), static_cast<void*>(NULL)));
   }
 }
 
@@ -401,7 +398,7 @@
     result->entry.reset(new FileEntryInfo());
     result->entry->file_system_name = file_system_name_;
     result->entry->file_system_root = file_system_root_.spec();
-    result->entry->file_full_path = "/" + virtual_path_.value();
+    result->entry->file_full_path = "/" + virtual_path_.AsUTF8Unsafe();
     result->entry->file_is_directory = false;
   }
 
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 c330c7b..6f827f7 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
@@ -10,12 +10,9 @@
 
 #include "base/bind.h"
 #include "base/files/scoped_temp_dir.h"
-#include "base/path_service.h"
 #include "base/values.h"
 #include "chrome/browser/extensions/extension_apitest.h"
 #include "chrome/browser/extensions/extension_function_test_utils.h"
-#include "chrome/browser/extensions/extension_service.h"
-#include "chrome/browser/extensions/extension_system.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/common/extensions/extension.h"
@@ -137,7 +134,7 @@
   }
   virtual ~MockFileSelectorFactory() {}
 
-  // file_handler::FileSelectorFactory imaplementation.
+  // file_handler::FileSelectorFactory implementation.
   virtual file_handler::FileSelector* CreateFileSelector() const OVERRIDE {
     return new MockFileSelector(suggested_name_,
                                 allowed_extensions_,
@@ -165,9 +162,7 @@
     // Create mount point directory that will be used in the test.
     // Mount point will be called "tmp", and it will be located in a tmp
     // directory with an unique name.
-    base::FilePath tmp_dir_path;
-    PathService::Get(base::DIR_TEMP, &tmp_dir_path);
-    ASSERT_TRUE(scoped_tmp_dir_.CreateUniqueTempDirUnderPath(tmp_dir_path));
+    ASSERT_TRUE(scoped_tmp_dir_.CreateUniqueTempDir());
     tmp_mount_point_ = scoped_tmp_dir_.path().Append("tmp");
     file_util::CreateDirectory(tmp_mount_point_);
 
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 f5bc671..fe15db1 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
@@ -20,7 +20,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
 #include "base/threading/sequenced_worker_pool.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "base/values.h"
 #include "chrome/browser/chromeos/drive/drive.pb.h"
 #include "chrome/browser/chromeos/drive/drive_app_registry.h"
@@ -35,6 +35,7 @@
 #include "chrome/browser/chromeos/extensions/file_manager/file_manager_event_router.h"
 #include "chrome/browser/chromeos/extensions/file_manager/file_manager_util.h"
 #include "chrome/browser/chromeos/extensions/file_manager/zip_file_creator.h"
+#include "chrome/browser/chromeos/fileapi/cros_mount_point_provider.h"
 #include "chrome/browser/chromeos/settings/cros_settings.h"
 #include "chrome/browser/chromeos/system/statistics_provider.h"
 #include "chrome/browser/extensions/api/file_handlers/app_file_handler_util.h"
@@ -59,6 +60,7 @@
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/storage_partition.h"
+#include "content/public/common/page_zoom.h"
 #include "googleurl/src/gurl.h"
 #include "grit/app_locale_settings.h"
 #include "grit/generated_resources.h"
@@ -67,7 +69,6 @@
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/shell_dialogs/selected_file_info.h"
 #include "ui/webui/web_ui_util.h"
-#include "webkit/browser/chromeos/fileapi/cros_mount_point_provider.h"
 #include "webkit/browser/fileapi/file_system_context.h"
 #include "webkit/browser/fileapi/file_system_file_util.h"
 #include "webkit/browser/fileapi/file_system_operation_context.h"
@@ -356,10 +357,9 @@
       entry_proto.file_specific_info();
 
   property_dict->SetString("thumbnailUrl", file_specific_info.thumbnail_url());
-
+  property_dict->SetString("shareUrl", file_specific_info.share_url());
   property_dict->SetBoolean("isHosted",
                             file_specific_info.is_hosted_document());
-
   property_dict->SetString("contentMimeType",
                            file_specific_info.content_mime_type());
 }
@@ -452,8 +452,7 @@
   registry->RegisterFunction<SetLastModifiedFunction>();
   registry->RegisterFunction<ZipSelectionFunction>();
   registry->RegisterFunction<ValidatePathNameLengthFunction>();
-  registry->RegisterFunction<OpenNewWindowFunction>();
-
+  registry->RegisterFunction<ZoomFunction>();
   event_router_->ObserveFileSystemEvents();
 }
 
@@ -1875,6 +1874,7 @@
   SET_STRING("GALLERY_SLIDESHOW", IDS_FILE_BROWSER_GALLERY_SLIDESHOW);
 
   SET_STRING("GALLERY_EDIT", IDS_FILE_BROWSER_GALLERY_EDIT);
+  SET_STRING("GALLERY_PRINT", IDS_FILE_BROWSER_GALLERY_PRINT);
   SET_STRING("GALLERY_SHARE", IDS_FILE_BROWSER_GALLERY_SHARE);
   SET_STRING("GALLERY_ENTER_WHEN_DONE",
              IDS_FILE_BROWSER_GALLERY_ENTER_WHEN_DONE);
@@ -1904,6 +1904,8 @@
   SET_STRING("GALLERY_VIDEO_ERROR", IDS_FILE_BROWSER_GALLERY_VIDEO_ERROR);
   SET_STRING("GALLERY_VIDEO_DECODING_ERROR",
              IDS_FILE_BROWSER_GALLERY_VIDEO_DECODING_ERROR);
+  SET_STRING("GALLERY_VIDEO_LOOPED_MODE",
+             IDS_FILE_BROWSER_GALLERY_VIDEO_LOOPED_MODE);
   SET_STRING("AUDIO_ERROR", IDS_FILE_BROWSER_AUDIO_ERROR);
   SET_STRING("GALLERY_IMAGE_OFFLINE", IDS_FILE_BROWSER_GALLERY_IMAGE_OFFLINE);
   SET_STRING("GALLERY_VIDEO_OFFLINE", IDS_FILE_BROWSER_GALLERY_VIDEO_OFFLINE);
@@ -1995,6 +1997,8 @@
   SET_STRING("CUT_BUTTON_LABEL", IDS_FILE_BROWSER_CUT_BUTTON_LABEL);
   SET_STRING("ZIP_SELECTION_BUTTON_LABEL",
              IDS_FILE_BROWSER_ZIP_SELECTION_BUTTON_LABEL);
+  SET_STRING("SHARE_BUTTON_LABEL",
+             IDS_FILE_BROWSER_SHARE_BUTTON_LABEL);
 
   SET_STRING("OPEN_WITH_BUTTON_LABEL", IDS_FILE_BROWSER_OPEN_WITH_BUTTON_LABEL);
 
@@ -2113,6 +2117,8 @@
   SET_STRING("DRIVE_WELCOME_CHECK_ELIGIBILITY",
              IDS_FILE_BROWSER_DRIVE_WELCOME_CHECK_ELIGIBILITY);
   SET_STRING("NO_ACTION_FOR_FILE", IDS_FILE_BROWSER_NO_ACTION_FOR_FILE);
+  SET_STRING("NO_ACTION_FOR_EXECUTABLE",
+             IDS_FILE_BROWSER_NO_ACTION_FOR_EXECUTABLE);
 
   // MP3 metadata extractor plugin
   SET_STRING("ID3_ALBUM", IDS_FILE_BROWSER_ID3_ALBUM);                // TALB
@@ -2255,13 +2261,13 @@
 #endif
 
   std::string board;
-  const char kMachineInfoBoard[] = "CHROMEOS_RELEASE_BOARD";
   chromeos::system::StatisticsProvider* provider =
       chromeos::system::StatisticsProvider::GetInstance();
-  if (!provider->GetMachineStatistic(kMachineInfoBoard, &board))
+  if (!provider->GetMachineStatistic(chromeos::system::kMachineInfoBoard,
+                                     &board)) {
     board = "unknown";
-  dict->SetString(kMachineInfoBoard, board);
-
+  }
+  dict->SetString(chromeos::system::kMachineInfoBoard, board);
   return true;
 }
 
@@ -3077,13 +3083,21 @@
   SendResponse(true);
 }
 
-OpenNewWindowFunction::OpenNewWindowFunction() {}
-
-OpenNewWindowFunction::~OpenNewWindowFunction() {}
-
-bool OpenNewWindowFunction::RunImpl() {
-  std::string url;
-  EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &url));
-  file_manager_util::OpenNewWindow(profile_, GURL(url));
+bool ZoomFunction::RunImpl() {
+  content::RenderViewHost* const view_host = render_view_host();
+  std::string operation;
+  args_->GetString(0, &operation);
+  content::PageZoom zoom_type;
+  if (operation == "in") {
+    zoom_type = content::PAGE_ZOOM_IN;
+  } else if (operation == "out") {
+    zoom_type = content::PAGE_ZOOM_OUT;
+  } else if (operation == "reset") {
+    zoom_type = content::PAGE_ZOOM_RESET;
+  } else {
+    NOTREACHED();
+    return false;
+  }
+  view_host->Zoom(zoom_type);
   return true;
 }
diff --git a/chrome/browser/chromeos/extensions/file_manager/file_browser_private_api.h b/chrome/browser/chromeos/extensions/file_manager/file_browser_private_api.h
index 1d4f391..c408946 100644
--- a/chrome/browser/chromeos/extensions/file_manager/file_browser_private_api.h
+++ b/chrome/browser/chromeos/extensions/file_manager/file_browser_private_api.h
@@ -13,7 +13,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/platform_file.h"
 #include "base/prefs/pref_service.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/chromeos/drive/file_errors.h"
 #include "chrome/browser/chromeos/drive/file_system_interface.h"
 #include "chrome/browser/chromeos/extensions/file_manager/zip_file_creator.h"
@@ -782,18 +782,13 @@
   virtual bool RunImpl() OVERRIDE;
 };
 
-// Implements the chrome.fileBrowserPrivate.newWindow method.
-class OpenNewWindowFunction : public AsyncExtensionFunction {
+class ZoomFunction : public SyncExtensionFunction {
  public:
-  DECLARE_EXTENSION_FUNCTION("fileBrowserPrivate.openNewWindow",
-                             FILEBROWSERPRIVATE_OPENNEWWINDOW)
-
-  OpenNewWindowFunction();
+  DECLARE_EXTENSION_FUNCTION("fileBrowserPrivate.zoom",
+                             FILEBROWSERPRIVATE_ZOOM);
 
  protected:
-  virtual ~OpenNewWindowFunction();
-
-  // AsyncExtensionFunction overrides.
+  virtual ~ZoomFunction() {}
   virtual bool RunImpl() OVERRIDE;
 };
 
diff --git a/chrome/browser/chromeos/extensions/file_manager/file_browser_private_apitest.cc b/chrome/browser/chromeos/extensions/file_manager/file_browser_private_apitest.cc
index 623abd6..7506110 100644
--- a/chrome/browser/chromeos/extensions/file_manager/file_browser_private_apitest.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/file_browser_private_apitest.cc
@@ -2,19 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include <stdio.h>
-
 #include "base/stl_util.h"
 #include "chrome/browser/extensions/extension_apitest.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/test/base/ui_test_utils.h"
 #include "chromeos/dbus/cros_disks_client.h"
 #include "chromeos/disks/mock_disk_mount_manager.h"
-#include "content/public/browser/browser_context.h"
-#include "content/public/browser/storage_partition.h"
-#include "webkit/browser/fileapi/file_system_context.h"
-#include "webkit/browser/fileapi/file_system_mount_point_provider.h"
 
 using ::testing::_;
 using ::testing::ReturnRef;
diff --git a/chrome/browser/chromeos/extensions/file_manager/file_handler_util.cc b/chrome/browser/chromeos/extensions/file_manager/file_handler_util.cc
index 85508c1..53815ab 100644
--- a/chrome/browser/chromeos/extensions/file_manager/file_handler_util.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/file_handler_util.cc
@@ -7,7 +7,6 @@
 #include "base/bind.h"
 #include "base/file_util.h"
 #include "base/i18n/case_conversion.h"
-#include "base/json/json_writer.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
@@ -15,6 +14,7 @@
 #include "chrome/browser/chromeos/drive/file_task_executor.h"
 #include "chrome/browser/chromeos/extensions/file_manager/file_browser_handler.h"
 #include "chrome/browser/chromeos/extensions/file_manager/file_manager_util.h"
+#include "chrome/browser/chromeos/fileapi/cros_mount_point_provider.h"
 #include "chrome/browser/extensions/event_router.h"
 #include "chrome/browser/extensions/extension_host.h"
 #include "chrome/browser/extensions/extension_service.h"
@@ -36,7 +36,6 @@
 #include "content/public/browser/storage_partition.h"
 #include "content/public/browser/web_contents.h"
 #include "net/base/escape.h"
-#include "webkit/browser/chromeos/fileapi/cros_mount_point_provider.h"
 #include "webkit/browser/fileapi/file_system_context.h"
 #include "webkit/browser/fileapi/file_system_url.h"
 #include "webkit/browser/fileapi/isolated_context.h"
@@ -172,6 +171,15 @@
   return true;
 }
 
+fileapi::FileSystemContext* GetFileSystemContextForExtension(
+    Profile* profile,
+    const std::string& extension_id) {
+  GURL site = extensions::ExtensionSystem::Get(profile)->
+      extension_service()->GetSiteForExtensionId(extension_id);
+  return BrowserContext::GetStoragePartitionForSite(profile, site)->
+      GetFileSystemContext();
+}
+
 // Checks if the file browser extension has permissions for the files in its
 // file system context.
 bool FileBrowserHasAccessPermissionForFiles(
@@ -179,12 +187,9 @@
     const GURL& source_url,
     const std::string& file_browser_id,
     const std::vector<FileSystemURL>& files) {
-  GURL site = extensions::ExtensionSystem::Get(profile)->extension_service()->
-      GetSiteForExtensionId(file_browser_id);
   fileapi::ExternalFileSystemMountPointProvider* external_provider =
-      BrowserContext::GetStoragePartitionForSite(profile, site)->
-          GetFileSystemContext()->external_provider();
-
+      GetFileSystemContextForExtension(profile, file_browser_id)->
+      external_provider();
   if (!external_provider)
     return false;
 
@@ -491,22 +496,19 @@
 }
 
 // ExtensionTaskExecutor executes tasks with kTaskFile type.
-// TODO(hashimoto): Make this non ref-counted. crbug.com/231173
-class ExtensionTaskExecutor
-    : public base::RefCountedThreadSafe<ExtensionTaskExecutor> {
+class ExtensionTaskExecutor {
  public:
   ExtensionTaskExecutor(Profile* profile,
                         const Extension* extension,
                         int32 tab_id,
                         const std::string& action_id);
 
-  // Executes the task for each file. When true is returned, |done| will be run
-  // with the execution result.
-  bool Execute(const std::vector<FileSystemURL>& file_urls,
+  // Executes the task for each file. |done| will be run with the result.
+  void Execute(const std::vector<FileSystemURL>& file_urls,
                const FileTaskFinishedCallback& done);
 
  private:
-  friend class base::RefCountedThreadSafe<ExtensionTaskExecutor>;
+  // This object is responsible to delete itself.
   virtual ~ExtensionTaskExecutor();
 
   struct FileDefinition {
@@ -519,13 +521,23 @@
   };
 
   typedef std::vector<FileDefinition> FileDefinitionList;
-  class ExecuteTasksFileSystemCallbackDispatcher;
+
+  // Checks legitimacy of file url and grants file RO access permissions from
+  // handler (target) extension and its renderer process.
+  static FileDefinitionList SetupFileAccessPermissions(
+      scoped_refptr<fileapi::FileSystemContext> file_system_context_handler,
+      const scoped_refptr<const Extension>& handler_extension,
+      const std::vector<FileSystemURL>& file_urls);
+
+  void DidOpenFileSystem(const std::vector<FileSystemURL>& file_urls,
+                         base::PlatformFileError result,
+                         const std::string& file_system_name,
+                         const GURL& file_system_root);
 
   void ExecuteDoneOnUIThread(bool success);
   void ExecuteFileActionsOnUIThread(const std::string& file_system_name,
                                     const GURL& file_system_root,
-                                    const FileDefinitionList& file_list,
-                                    int handler_pid);
+                                    const FileDefinitionList& file_list);
   void SetupPermissionsAndDispatchEvent(const std::string& file_system_name,
                                         const GURL& file_system_root,
                                         const FileDefinitionList& file_list,
@@ -544,6 +556,9 @@
   int32 tab_id_;
   const std::string action_id_;
   FileTaskFinishedCallback done_;
+  base::WeakPtrFactory<ExtensionTaskExecutor> weak_ptr_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(ExtensionTaskExecutor);
 };
 
 bool ExecuteFileTask(Profile* profile,
@@ -578,9 +593,13 @@
 
   // Execute the task.
   if (task_type == kTaskFile) {
-    scoped_refptr<ExtensionTaskExecutor> executor(
-        new ExtensionTaskExecutor(profile, extension, tab_id, action_id));
-    return executor->Execute(file_urls, done);
+    // Forbid calling undeclared handlers.
+    if (!FindFileBrowserHandler(extension, action_id))
+      return false;
+
+    (new ExtensionTaskExecutor(
+        profile, extension, tab_id, action_id))->Execute(file_urls, done);
+    return true;
   } else if (task_type == kTaskApp) {
     for (size_t i = 0; i != file_urls.size(); ++i) {
       extensions::LaunchPlatformAppWithFileHandler(
@@ -601,99 +620,21 @@
 ExtensionTaskExecutor::FileDefinition::~FileDefinition() {
 }
 
-class ExtensionTaskExecutor::ExecuteTasksFileSystemCallbackDispatcher {
- public:
-  static fileapi::FileSystemContext::OpenFileSystemCallback CreateCallback(
-      ExtensionTaskExecutor* executor,
-      scoped_refptr<fileapi::FileSystemContext> file_system_context_handler,
-      scoped_refptr<const Extension> handler_extension,
-      int handler_pid,
-      const std::string& action_id,
-      const std::vector<FileSystemURL>& file_urls) {
-    return base::Bind(
-        &ExecuteTasksFileSystemCallbackDispatcher::DidOpenFileSystem,
-        base::Owned(new ExecuteTasksFileSystemCallbackDispatcher(
-            executor, file_system_context_handler, handler_extension,
-            handler_pid, action_id, file_urls)));
-  }
+// static
+ExtensionTaskExecutor::FileDefinitionList
+ExtensionTaskExecutor::SetupFileAccessPermissions(
+    scoped_refptr<fileapi::FileSystemContext> file_system_context_handler,
+    const scoped_refptr<const Extension>& handler_extension,
+    const std::vector<FileSystemURL>& file_urls) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+  DCHECK(handler_extension.get());
 
-  void DidOpenFileSystem(base::PlatformFileError result,
-                         const std::string& file_system_name,
-                         const GURL& file_system_root) {
-    if (result != base::PLATFORM_FILE_OK) {
-      DidFail(result);
-      return;
-    }
-    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
-    ExtensionTaskExecutor::FileDefinitionList file_list;
-    for (std::vector<FileSystemURL>::iterator iter = urls_.begin();
-         iter != urls_.end();
-         ++iter) {
-      // Set up file permission access.
-      ExtensionTaskExecutor::FileDefinition file;
-      if (!SetupFileAccessPermissions(*iter, &file))
-        continue;
-      file_list.push_back(file);
-    }
-    if (file_list.empty()) {
-      BrowserThread::PostTask(
-          BrowserThread::UI, FROM_HERE,
-          base::Bind(
-              &ExtensionTaskExecutor::ExecuteDoneOnUIThread,
-              executor_,
-              false));
-      return;
-    }
+  fileapi::ExternalFileSystemMountPointProvider* external_provider_handler =
+      file_system_context_handler->external_provider();
 
-    BrowserThread::PostTask(
-        BrowserThread::UI, FROM_HERE,
-        base::Bind(
-            &ExtensionTaskExecutor::ExecuteFileActionsOnUIThread,
-            executor_,
-            file_system_name,
-            file_system_root,
-            file_list,
-            handler_pid_));
-  }
-
-  void DidFail(base::PlatformFileError error_code) {
-    BrowserThread::PostTask(
-        BrowserThread::UI, FROM_HERE,
-        base::Bind(
-            &ExtensionTaskExecutor::ExecuteDoneOnUIThread,
-            executor_,
-            false));
-  }
-
- private:
-  ExecuteTasksFileSystemCallbackDispatcher(
-      ExtensionTaskExecutor* executor,
-      scoped_refptr<fileapi::FileSystemContext> file_system_context_handler,
-      const scoped_refptr<const Extension>& handler_extension,
-      int handler_pid,
-      const std::string& action_id,
-      const std::vector<FileSystemURL>& file_urls)
-      : executor_(executor),
-        file_system_context_handler_(file_system_context_handler),
-        handler_extension_(handler_extension),
-        handler_pid_(handler_pid),
-        action_id_(action_id),
-        urls_(file_urls) {
-    DCHECK(executor_.get());
-  }
-
-  // Checks legitimacy of file url and grants file RO access permissions from
-  // handler (target) extension and its renderer process.
-  bool SetupFileAccessPermissions(const FileSystemURL& url,
-                                  FileDefinition* file) {
-    if (!handler_extension_.get())
-      return false;
-
-    if (handler_pid_ == 0)
-      return false;
-
-    fileapi::ExternalFileSystemMountPointProvider* external_provider_handler =
-        file_system_context_handler_->external_provider();
+  FileDefinitionList file_list;
+  for (size_t i = 0; i < file_urls.size(); ++i) {
+    const FileSystemURL& url = file_urls[i];
 
     // Check if this file system entry exists first.
     base::PlatformFileInfo file_info;
@@ -704,13 +645,13 @@
     bool is_drive_file = url.type() == fileapi::kFileSystemTypeDrive;
     DCHECK(!is_drive_file || drive::util::IsUnderDriveMountPoint(local_path));
 
-    // If the file is under gdata mount point, there is no actual file to be
+    // If the file is under drive mount point, there is no actual file to be
     // found on the url.path().
     if (!is_drive_file) {
       if (!file_util::PathExists(local_path) ||
           file_util::IsLink(local_path) ||
           !file_util::GetFileInfo(local_path, &file_info)) {
-        return false;
+        continue;
       }
     }
 
@@ -718,23 +659,17 @@
     // ensure that the target extension can access only this FS entry and
     // prevent from traversing FS hierarchy upward.
     external_provider_handler->GrantFileAccessToExtension(
-        handler_extension_->id(), virtual_path);
+        handler_extension->id(), virtual_path);
 
     // Output values.
-    file->virtual_path = virtual_path;
-    file->is_directory = file_info.is_directory;
-    file->absolute_path = local_path;
-    return true;
+    FileDefinition file;
+    file.virtual_path = virtual_path;
+    file.is_directory = file_info.is_directory;
+    file.absolute_path = local_path;
+    file_list.push_back(file);
   }
-
-  scoped_refptr<ExtensionTaskExecutor> executor_;
-  scoped_refptr<fileapi::FileSystemContext> file_system_context_handler_;
-  scoped_refptr<const Extension> handler_extension_;
-  int handler_pid_;
-  std::string action_id_;
-  std::vector<FileSystemURL> urls_;
-  DISALLOW_COPY_AND_ASSIGN(ExecuteTasksFileSystemCallbackDispatcher);
-};
+  return file_list;
+}
 
 ExtensionTaskExecutor::ExtensionTaskExecutor(
     Profile* profile,
@@ -744,66 +679,78 @@
     : profile_(profile),
       extension_(extension),
       tab_id_(tab_id),
-      action_id_(action_id) {
+      action_id_(action_id),
+      weak_ptr_factory_(this) {
 }
 
 ExtensionTaskExecutor::~ExtensionTaskExecutor() {}
 
-bool ExtensionTaskExecutor::Execute(const std::vector<FileSystemURL>& file_urls,
+void ExtensionTaskExecutor::Execute(const std::vector<FileSystemURL>& file_urls,
                                     const FileTaskFinishedCallback& done) {
-  // Forbid calling undeclared handlers.
-  if (!FindFileBrowserHandler(extension_, action_id_))
-    return false;
-
-  int extension_pid = ExtractProcessFromExtensionId(profile_, extension_->id());
-  if (extension_pid <= 0) {
-    if (!extensions::BackgroundInfo::HasLazyBackgroundPage(extension_))
-      return false;
-  }
-
   done_ = done;
 
   // Get file system context for the extension to which onExecute event will be
-  // send. The file access permissions will be granted to the extension in the
+  // sent. The file access permissions will be granted to the extension in the
   // file system context for the files in |file_urls|.
-  GURL site = extensions::ExtensionSystem::Get(profile_)->extension_service()->
-      GetSiteForExtensionId(extension_->id());
-  scoped_refptr<fileapi::FileSystemContext> file_system_context_handler =
-      BrowserContext::GetStoragePartitionForSite(profile_, site)->
-      GetFileSystemContext();
+  GetFileSystemContextForExtension(profile_, extension_->id())->OpenFileSystem(
+      Extension::GetBaseURLFromExtensionId(extension_->id()).GetOrigin(),
+      fileapi::kFileSystemTypeExternal,
+      fileapi::OPEN_FILE_SYSTEM_FAIL_IF_NONEXISTENT,
+      base::Bind(&ExtensionTaskExecutor::DidOpenFileSystem,
+                 weak_ptr_factory_.GetWeakPtr(),
+                 file_urls));
+}
 
-  GURL origin_url =
-      Extension::GetBaseURLFromExtensionId(extension_->id()).GetOrigin();
-  BrowserThread::PostTask(
-      BrowserThread::FILE, FROM_HERE,
-      base::Bind(&fileapi::FileSystemContext::OpenFileSystem,
-                 file_system_context_handler,
-                 origin_url, fileapi::kFileSystemTypeExternal,
-                 fileapi::OPEN_FILE_SYSTEM_FAIL_IF_NONEXISTENT,
-                 ExecuteTasksFileSystemCallbackDispatcher::CreateCallback(
-                     this,
-                     file_system_context_handler,
-                     extension_,
-                     extension_pid,
-                     action_id_,
-                     file_urls)));
-  return true;
+void ExtensionTaskExecutor::DidOpenFileSystem(
+    const std::vector<FileSystemURL>& file_urls,
+    base::PlatformFileError result,
+    const std::string& file_system_name,
+    const GURL& file_system_root) {
+  if (result != base::PLATFORM_FILE_OK) {
+    ExecuteDoneOnUIThread(false);
+    return;
+  }
+
+  scoped_refptr<fileapi::FileSystemContext> file_system_context(
+      GetFileSystemContextForExtension(profile_, extension_->id()));
+  BrowserThread::PostTaskAndReplyWithResult(
+      BrowserThread::FILE,
+      FROM_HERE,
+      base::Bind(&SetupFileAccessPermissions,
+                 file_system_context,
+                 extension_,
+                 file_urls),
+      base::Bind(&ExtensionTaskExecutor::ExecuteFileActionsOnUIThread,
+                 weak_ptr_factory_.GetWeakPtr(),
+                 file_system_name,
+                 file_system_root));
 }
 
 void ExtensionTaskExecutor::ExecuteDoneOnUIThread(bool success) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   if (!done_.is_null())
     done_.Run(success);
-  done_.Reset();
+  delete this;
 }
 
 void ExtensionTaskExecutor::ExecuteFileActionsOnUIThread(
     const std::string& file_system_name,
     const GURL& file_system_root,
-    const FileDefinitionList& file_list,
-    int handler_pid) {
+    const FileDefinitionList& file_list) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
 
+  if (file_list.empty()) {
+    ExecuteDoneOnUIThread(false);
+    return;
+  }
+
+  int handler_pid = ExtractProcessFromExtensionId(profile_, extension_->id());
+  if (handler_pid <= 0 &&
+      !extensions::BackgroundInfo::HasLazyBackgroundPage(extension_)) {
+    ExecuteDoneOnUIThread(false);
+    return;
+  }
+
   if (handler_pid > 0) {
     SetupPermissionsAndDispatchEvent(file_system_name, file_system_root,
         file_list, handler_pid, NULL);
@@ -819,7 +766,10 @@
     queue->AddPendingTask(
         profile_, extension_->id(),
         base::Bind(&ExtensionTaskExecutor::SetupPermissionsAndDispatchEvent,
-                   this, file_system_name, file_system_root, file_list,
+                   weak_ptr_factory_.GetWeakPtr(),
+                   file_system_name,
+                   file_system_root,
+                   file_list,
                    handler_pid));
   }
 }
diff --git a/chrome/browser/chromeos/extensions/file_manager/file_handler_util.h b/chrome/browser/chromeos/extensions/file_manager/file_handler_util.h
index 72cf682..e994bfa 100644
--- a/chrome/browser/chromeos/extensions/file_manager/file_handler_util.h
+++ b/chrome/browser/chromeos/extensions/file_manager/file_handler_util.h
@@ -8,20 +8,15 @@
 #include <string>
 #include <vector>
 
-#include "base/callback.h"
+#include "base/callback_forward.h"
 #include "base/platform_file.h"
 #include "chrome/common/extensions/extension.h"
-#include "extensions/common/url_pattern_set.h"
 
 class Browser;
 class FileBrowserHandler;
 class GURL;
 class Profile;
 
-namespace extensions {
-class Extension;
-}  // namespace extensions
-
 namespace fileapi {
 class FileSystemURL;
 }
diff --git a/chrome/browser/chromeos/extensions/file_manager/file_manager_browsertest.cc b/chrome/browser/chromeos/extensions/file_manager/file_manager_browsertest.cc
index ff09572..2072be6 100644
--- a/chrome/browser/chromeos/extensions/file_manager/file_manager_browsertest.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/file_manager_browsertest.cc
@@ -8,27 +8,32 @@
 //  - Selecting a file and copy-pasting it with the keyboard copies the file.
 //  - Selecting a file and pressing delete deletes it.
 
+#include <deque>
 #include <string>
 
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/file_util.h"
 #include "base/files/file_path.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/chromeos/drive/drive_integration_service.h"
 #include "chrome/browser/chromeos/drive/file_system_interface.h"
 #include "chrome/browser/chromeos/extensions/file_manager/drive_test_util.h"
 #include "chrome/browser/drive/fake_drive_service.h"
+#include "chrome/browser/extensions/api/test/test_api.h"
 #include "chrome/browser/extensions/component_loader.h"
 #include "chrome/browser/extensions/extension_apitest.h"
 #include "chrome/browser/extensions/extension_test_message_listener.h"
 #include "chrome/browser/google_apis/gdata_wapi_parser.h"
 #include "chrome/browser/google_apis/test_util.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/common/chrome_notification_types.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/extensions/extension.h"
 #include "chromeos/chromeos_switches.h"
 #include "content/public/browser/browser_context.h"
+#include "content/public/browser/notification_service.h"
+#include "content/public/test/test_utils.h"
 #include "webkit/browser/fileapi/external_mount_points.h"
 
 namespace {
@@ -251,12 +256,12 @@
 
   drive::DriveIntegrationService* CreateDriveIntegrationService(
       Profile* profile) {
-    fake_drive_service_ = new google_apis::FakeDriveService;
+    fake_drive_service_ = new drive::FakeDriveService;
     fake_drive_service_->LoadResourceListForWapi(
-        "chromeos/gdata/empty_feed.json");
+        "gdata/empty_feed.json");
     fake_drive_service_->LoadAccountMetadataForWapi(
-        "chromeos/gdata/account_metadata.json");
-    fake_drive_service_->LoadAppListForDriveApi("chromeos/drive/applist.json");
+        "gdata/account_metadata.json");
+    fake_drive_service_->LoadAppListForDriveApi("drive/applist.json");
     integration_service_ = new drive::DriveIntegrationService(
         profile,
         fake_drive_service_,
@@ -267,24 +272,72 @@
 
  private:
   base::ScopedTempDir test_cache_root_;
-  google_apis::FakeDriveService* fake_drive_service_;
+  drive::FakeDriveService* fake_drive_service_;
   drive::DriveIntegrationService* integration_service_;
 };
 
-// Parameter of FileManagerBrowserTestBase.
-// The second value is the case name of javascript.
+// Listener to obtain the test relative messages synchronously.
+class FileManagerTestListener : public content::NotificationObserver {
+ public:
+  struct Message {
+    int type;
+    std::string message;
+    extensions::TestSendMessageFunction* function;
+  };
+
+  FileManagerTestListener() {
+    registrar_.Add(this,
+                   chrome::NOTIFICATION_EXTENSION_TEST_PASSED,
+                   content::NotificationService::AllSources());
+    registrar_.Add(this,
+                   chrome::NOTIFICATION_EXTENSION_TEST_FAILED,
+                   content::NotificationService::AllSources());
+    registrar_.Add(this,
+                   chrome::NOTIFICATION_EXTENSION_TEST_MESSAGE,
+                   content::NotificationService::AllSources());
+  }
+
+  Message GetNextMessage() {
+    if (messages_.empty())
+      content::RunMessageLoop();
+    const Message entry = messages_.front();
+    messages_.pop_front();
+    return entry;
+  }
+
+  virtual void Observe(int type,
+                       const content::NotificationSource& source,
+                       const content::NotificationDetails& details) OVERRIDE {
+    Message entry;
+    entry.type = type;
+    entry.message = type != chrome::NOTIFICATION_EXTENSION_TEST_PASSED ?
+        *content::Details<std::string>(details).ptr() :
+        std::string();
+    entry.function = type == chrome::NOTIFICATION_EXTENSION_TEST_MESSAGE ?
+        content::Source<extensions::TestSendMessageFunction>(source).ptr() :
+        NULL;
+    messages_.push_back(entry);
+    base::MessageLoopForUI::current()->Quit();
+  }
+
+ private:
+  std::deque<Message> messages_;
+  content::NotificationRegistrar registrar_;
+};
+
+// Parameter of FileManagerBrowserTest.
+// The second value is the case name of JavaScript.
 typedef std::tr1::tuple<GuestMode, const char*> TestParameter;
 
 // The base test class.
-class FileManagerBrowserTestBase :
+class FileManagerBrowserTest :
       public ExtensionApiTest,
       public ::testing::WithParamInterface<TestParameter> {
  protected:
-  FileManagerBrowserTestBase() :
+  FileManagerBrowserTest() :
       local_volume_(new LocalTestVolume),
       drive_volume_(std::tr1::get<0>(GetParam()) != IN_GUEST_MODE ?
-                    new DriveTestVolume() : NULL),
-      guest_mode_(std::tr1::get<0>(GetParam())) {}
+                    new DriveTestVolume() : NULL) {}
 
   virtual void SetUpInProcessBrowserTestFixture() OVERRIDE;
 
@@ -297,22 +350,18 @@
   // test.
   void StartTest();
 
- protected:
   const scoped_ptr<LocalTestVolume> local_volume_;
   const scoped_ptr<DriveTestVolume> drive_volume_;
-
- private:
-  GuestMode guest_mode_;
 };
 
-void FileManagerBrowserTestBase::SetUpInProcessBrowserTestFixture() {
+void FileManagerBrowserTest::SetUpInProcessBrowserTestFixture() {
   ExtensionApiTest::SetUpInProcessBrowserTestFixture();
   extensions::ComponentLoader::EnableBackgroundExtensionsForTesting();
   if (drive_volume_)
     ASSERT_TRUE(drive_volume_->SetUp());
 }
 
-void FileManagerBrowserTestBase::SetUpOnMainThread() {
+void FileManagerBrowserTest::SetUpOnMainThread() {
   ExtensionApiTest::SetUpOnMainThread();
   ASSERT_TRUE(local_volume_->Mount(browser()->profile()));
 
@@ -332,8 +381,8 @@
   }
 }
 
-void FileManagerBrowserTestBase::SetUpCommandLine(CommandLine* command_line) {
-  if (guest_mode_ == IN_GUEST_MODE) {
+void FileManagerBrowserTest::SetUpCommandLine(CommandLine* command_line) {
+  if (std::tr1::get<0>(GetParam()) == IN_GUEST_MODE) {
     command_line->AppendSwitch(chromeos::switches::kGuestSession);
     command_line->AppendSwitchNative(chromeos::switches::kLoginUser, "");
     command_line->AppendSwitch(switches::kIncognito);
@@ -341,61 +390,59 @@
   ExtensionApiTest::SetUpCommandLine(command_line);
 }
 
-void FileManagerBrowserTestBase::StartTest() {
+IN_PROC_BROWSER_TEST_P(FileManagerBrowserTest, Test) {
+  // Launch the extension.
   base::FilePath path = test_data_dir_.AppendASCII("file_manager_browsertest");
   const extensions::Extension* extension = LoadExtensionAsComponent(path);
   ASSERT_TRUE(extension);
 
-  bool in_guest_mode = guest_mode_ == IN_GUEST_MODE;
-  ExtensionTestMessageListener listener(
-      in_guest_mode ? "which test guest" : "which test non-guest", true);
-  ASSERT_TRUE(listener.WaitUntilSatisfied());
-  listener.Reply(std::tr1::get<1>(GetParam()));
-}
-
-class FileManagerBrowserFileDisplayTest : public FileManagerBrowserTestBase {};
-
-IN_PROC_BROWSER_TEST_P(FileManagerBrowserFileDisplayTest, Test) {
-  ResultCatcher catcher;
-  ASSERT_NO_FATAL_FAILURE(StartTest());
-
-  ExtensionTestMessageListener listener("initial check done", true);
-  ASSERT_TRUE(listener.WaitUntilSatisfied());
-  const TestEntryInfo entry = {
-    FILE,
-    "music.ogg",  // Prototype file name.
-    "newly added file.ogg",  // Target file name.
-    "audio/ogg",
-    NONE,
-    "4 Sep 1998 00:00:00"
-  };
-  if (drive_volume_)
-    drive_volume_->CreateEntry(entry);
-  local_volume_->CreateEntry(entry);
-  listener.Reply("file added");
-
-  ASSERT_TRUE(catcher.GetNextResult()) << catcher.message();
+  // Handle the messages from JavaScript.
+  // The while loop is break when the test is passed or failed.
+  FileManagerTestListener listener;
+  while (true) {
+    FileManagerTestListener::Message entry = listener.GetNextMessage();
+    if (entry.type == chrome::NOTIFICATION_EXTENSION_TEST_PASSED) {
+      // Test succeed.
+      break;
+    } else if (entry.type == chrome::NOTIFICATION_EXTENSION_TEST_FAILED) {
+      // Test failed.
+      ADD_FAILURE() << entry.message;
+      break;
+    } else if (entry.message == "getTestName") {
+      // Pass the test case name.
+      entry.function->Reply(std::tr1::get<1>(GetParam()));
+    } else if (entry.message == "isInGuestMode") {
+      // Obtains whther the test is in guest mode or not.
+      entry.function->Reply(std::tr1::get<0>(GetParam()) ? "true" : "false");
+    } else if (entry.message == "addEntry") {
+      // Add the extra entry.
+      const TestEntryInfo file = {
+        FILE,
+        "music.ogg",  // Prototype file name.
+        "newly added file.ogg",  // Target file name.
+        "audio/ogg",
+        NONE,
+        "4 Sep 1998 00:00:00"
+      };
+      if (drive_volume_)
+        drive_volume_->CreateEntry(file);
+      local_volume_->CreateEntry(file);
+      entry.function->Reply("onEntryAdded");
+    }
+  }
 }
 
 INSTANTIATE_TEST_CASE_P(
-    AllTests,
-    FileManagerBrowserFileDisplayTest,
+    FileDisplay,
+    FileManagerBrowserTest,
     ::testing::Values(TestParameter(NOT_IN_GUEST_MODE, "fileDisplayDownloads"),
                       TestParameter(IN_GUEST_MODE, "fileDisplayDownloads"),
                       TestParameter(NOT_IN_GUEST_MODE, "fileDisplayDrive")));
 
-// A test class that just executes JavaScript unit test.
-class FileManagerBrowserSimpleTest : public FileManagerBrowserTestBase {};
-
-IN_PROC_BROWSER_TEST_P(FileManagerBrowserSimpleTest, Test) {
-  ResultCatcher catcher;
-  ASSERT_NO_FATAL_FAILURE(StartTest());
-  ASSERT_TRUE(catcher.GetNextResult()) << catcher.message();
-}
-
+// TODO(hirono): Fix this test. crbug.com/247299
 INSTANTIATE_TEST_CASE_P(
     DISABLED_OpenSpecialTypes,
-    FileManagerBrowserSimpleTest,
+    FileManagerBrowserTest,
     ::testing::Values(TestParameter(IN_GUEST_MODE, "videoOpenDownloads"),
                       TestParameter(NOT_IN_GUEST_MODE, "videoOpenDownloads"),
                       TestParameter(NOT_IN_GUEST_MODE, "videoOpenDrive"),
@@ -409,10 +456,9 @@
                       // ASAN Tests (2).  TODO(mtomasz): crbug.com/243611.
                       // TestParameter(NOT_IN_GUEST_MODE, "galleryOpenDrive")));
 
-// Test is flaky, see http://crbug.com/247299
 INSTANTIATE_TEST_CASE_P(
-    DISABLED_KeyboardOpeartions,
-    FileManagerBrowserSimpleTest,
+    KeyboardOpeartions,
+    FileManagerBrowserTest,
     ::testing::Values(TestParameter(IN_GUEST_MODE, "keyboardDeleteDownloads"),
                       TestParameter(NOT_IN_GUEST_MODE,
                                     "keyboardDeleteDownloads"),
@@ -423,7 +469,7 @@
 
 INSTANTIATE_TEST_CASE_P(
     DriveSpecific,
-    FileManagerBrowserSimpleTest,
+    FileManagerBrowserTest,
     ::testing::Values(TestParameter(NOT_IN_GUEST_MODE, "openSidebarRecent"),
                       TestParameter(NOT_IN_GUEST_MODE, "openSidebarOffline"),
                       TestParameter(NOT_IN_GUEST_MODE,
@@ -432,7 +478,7 @@
 
 INSTANTIATE_TEST_CASE_P(
     Transfer,
-    FileManagerBrowserSimpleTest,
+    FileManagerBrowserTest,
     ::testing::Values(TestParameter(NOT_IN_GUEST_MODE,
                                     "transferFromDriveToDownloads"),
                       TestParameter(NOT_IN_GUEST_MODE,
@@ -452,13 +498,13 @@
 
 INSTANTIATE_TEST_CASE_P(
      HideSearchBox,
-     FileManagerBrowserSimpleTest,
+     FileManagerBrowserTest,
      ::testing::Values(TestParameter(IN_GUEST_MODE, "hideSearchBox"),
                        TestParameter(NOT_IN_GUEST_MODE, "hideSearchBox")));
 
 INSTANTIATE_TEST_CASE_P(
     RestorePrefs,
-    FileManagerBrowserSimpleTest,
+    FileManagerBrowserTest,
     ::testing::Values(TestParameter(IN_GUEST_MODE, "restoreSortColumn"),
                       TestParameter(NOT_IN_GUEST_MODE, "restoreSortColumn"),
                       TestParameter(IN_GUEST_MODE, "restoreCurrentView"),
diff --git a/chrome/browser/chromeos/extensions/file_manager/file_manager_event_router.h b/chrome/browser/chromeos/extensions/file_manager/file_manager_event_router.h
index 38e5340..db63487 100644
--- a/chrome/browser/chromeos/extensions/file_manager/file_manager_event_router.h
+++ b/chrome/browser/chromeos/extensions/file_manager/file_manager_event_router.h
@@ -29,7 +29,7 @@
       public drive::DriveIntegrationServiceObserver,
       public drive::FileSystemObserver,
       public drive::JobListObserver,
-      public google_apis::DriveServiceObserver {
+      public drive::DriveServiceObserver {
  public:
   // Interface that should keep track of the system state in regards to system
   // suspend and resume events.
diff --git a/chrome/browser/chromeos/extensions/file_manager/file_manager_manifest_unittest.cc b/chrome/browser/chromeos/extensions/file_manager/file_manager_manifest_unittest.cc
index b088243..acc676e 100644
--- a/chrome/browser/chromeos/extensions/file_manager/file_manager_manifest_unittest.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/file_manager_manifest_unittest.cc
@@ -77,14 +77,14 @@
   FileBrowserHandler::List* handlers =
       FileBrowserHandler::GetHandlers(extension.get());
   ASSERT_TRUE(handlers != NULL);
-  ASSERT_EQ(handlers->size(), 1U);
+  ASSERT_EQ(1U, handlers->size());
   const FileBrowserHandler* action = handlers->at(0).get();
 
-  EXPECT_EQ(action->id(), "ExtremelyCoolAction");
-  EXPECT_EQ(action->title(), "Be Amazed");
-  EXPECT_EQ(action->icon_path(), "icon.png");
+  EXPECT_EQ("ExtremelyCoolAction", action->id());
+  EXPECT_EQ("Be Amazed", action->title());
+  EXPECT_EQ("icon.png", action->icon_path());
   const extensions::URLPatternSet& patterns = action->file_url_patterns();
-  ASSERT_EQ(patterns.patterns().size(), 1U);
+  ASSERT_EQ(1U, patterns.patterns().size());
   EXPECT_TRUE(action->MatchesURL(
       GURL("filesystem:chrome-extension://foo/local/test.txt")));
   EXPECT_FALSE(action->HasCreateAccessPermission());
@@ -113,11 +113,11 @@
   FileBrowserHandler::List* handlers =
       FileBrowserHandler::GetHandlers(extension.get());
   ASSERT_TRUE(handlers != NULL);
-  ASSERT_EQ(handlers->size(), 1U);
+  ASSERT_EQ(1U, handlers->size());
   const FileBrowserHandler* action = handlers->at(0).get();
 
   const extensions::URLPatternSet& patterns = action->file_url_patterns();
-  ASSERT_EQ(patterns.patterns().size(), 1U);
+  ASSERT_EQ(1U, patterns.patterns().size());
   EXPECT_TRUE(action->MatchesURL(
       GURL("filesystem:chrome-extension://foo/local/test.txt")));
 }
@@ -144,11 +144,11 @@
   FileBrowserHandler::List* handlers =
       FileBrowserHandler::GetHandlers(extension.get());
   ASSERT_TRUE(handlers != NULL);
-  ASSERT_EQ(handlers->size(), 1U);
+  ASSERT_EQ(1U, handlers->size());
   const FileBrowserHandler* action = handlers->at(0).get();
   const extensions::URLPatternSet& patterns = action->file_url_patterns();
 
-  EXPECT_EQ(patterns.patterns().size(), 0U);
+  EXPECT_EQ(0U, patterns.patterns().size());
   EXPECT_TRUE(action->HasCreateAccessPermission());
   EXPECT_FALSE(action->CanRead());
   EXPECT_FALSE(action->CanWrite());
@@ -164,11 +164,11 @@
               .Set("files", "main.html"))
       .Build();
 
-  // Non component extensions can't ovverride chrome://files/ URL.
+  // Non component extensions can't override chrome://files/ URL.
   LoadAndExpectError(Manifest(manifest_value.get(), "override_files"),
                      errors::kInvalidChromeURLOverrides);
 
-  // A component extention can override chrome://files/ URL.
+  // A component extension can override chrome://files/ URL.
   std::string error;
   LoadExtension(Manifest(manifest_value.get(), "override_files"),
                 &error, extensions::Manifest::COMPONENT, Extension::NO_FLAGS);
diff --git a/chrome/browser/chromeos/extensions/file_manager/file_manager_notifications.cc b/chrome/browser/chromeos/extensions/file_manager/file_manager_notifications.cc
index e780c40..b28a217 100644
--- a/chrome/browser/chromeos/extensions/file_manager/file_manager_notifications.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/file_manager_notifications.cc
@@ -7,19 +7,14 @@
 #include "base/bind.h"
 #include "base/message_loop.h"
 #include "base/stl_util.h"
-#include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/chromeos/extensions/file_manager/file_manager_util.h"
 #include "chrome/browser/notifications/desktop_notification_service.h"
 #include "chrome/browser/notifications/notification_delegate.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/browser_list.h"
 #include "grit/generated_resources.h"
 #include "grit/theme_resources.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/resource/resource_bundle.h"
-#include "ui/webui/web_ui_util.h"
 
 namespace {
 
@@ -248,29 +243,32 @@
   if (it->second.fail_message_finalized)
     return;
 
-  int notification_message_id = 0;
-
   // Do we have a multi-partition device for which at least one mount failed.
   bool fail_on_multipartition_device =
       success ? it->second.non_parent_device_failed
               : it->second.mount_success_exists ||
                 it->second.non_parent_device_failed;
 
+  base::string16 message;
   if (fail_on_multipartition_device) {
     it->second.fail_message_finalized = true;
-    notification_message_id =
-        label.empty() ? IDS_MULTIPART_DEVICE_UNSUPPORTED_DEFAULT_MESSAGE
-                      : IDS_MULTIPART_DEVICE_UNSUPPORTED_MESSAGE;
+    message = label.empty() ?
+        l10n_util::GetStringUTF16(
+            IDS_MULTIPART_DEVICE_UNSUPPORTED_DEFAULT_MESSAGE) :
+        l10n_util::GetStringFUTF16(
+            IDS_MULTIPART_DEVICE_UNSUPPORTED_MESSAGE, UTF8ToUTF16(label));
   } else if (!success) {
     // First device failed.
     if (!is_unsupported) {
-      notification_message_id =
-          label.empty() ? IDS_DEVICE_UNKNOWN_DEFAULT_MESSAGE
-                        : IDS_DEVICE_UNKNOWN_MESSAGE;
+      message = label.empty() ?
+          l10n_util::GetStringUTF16(IDS_DEVICE_UNKNOWN_DEFAULT_MESSAGE) :
+          l10n_util::GetStringFUTF16(IDS_DEVICE_UNKNOWN_MESSAGE,
+                                     UTF8ToUTF16(label));
     } else {
-      notification_message_id =
-          label.empty() ? IDS_DEVICE_UNSUPPORTED_DEFAULT_MESSAGE
-                        : IDS_DEVICE_UNSUPPORTED_MESSAGE;
+      message = label.empty() ?
+          l10n_util::GetStringUTF16(IDS_DEVICE_UNSUPPORTED_DEFAULT_MESSAGE) :
+          l10n_util::GetStringFUTF16(IDS_DEVICE_UNSUPPORTED_MESSAGE,
+                                     UTF8ToUTF16(label));
     }
   }
 
@@ -280,7 +278,7 @@
     it->second.non_parent_device_failed |= !is_parent;
   }
 
-  if (notification_message_id == 0)
+  if (message.empty())
     return;
 
   if (it->second.fail_notification_shown) {
@@ -289,14 +287,7 @@
     it->second.fail_notification_shown = true;
   }
 
-  if (!label.empty()) {
-    ShowNotificationWithMessage(DEVICE_FAIL, system_path,
-        l10n_util::GetStringFUTF16(notification_message_id,
-                                   ASCIIToUTF16(label)));
-  } else {
-    ShowNotificationWithMessage(DEVICE_FAIL, system_path,
-        l10n_util::GetStringUTF16(notification_message_id));
-  }
+  ShowNotificationWithMessage(DEVICE_FAIL, system_path, message);
 }
 
 void FileManagerNotifications::ShowNotification(NotificationType type,
diff --git a/chrome/browser/chromeos/extensions/file_manager/file_manager_notifications.h b/chrome/browser/chromeos/extensions/file_manager/file_manager_notifications.h
index 771ecaa..5325b50 100644
--- a/chrome/browser/chromeos/extensions/file_manager/file_manager_notifications.h
+++ b/chrome/browser/chromeos/extensions/file_manager/file_manager_notifications.h
@@ -12,7 +12,7 @@
 #include "base/basictypes.h"
 #include "base/memory/weak_ptr.h"
 #include "base/strings/string16.h"
-#include "base/time.h"
+#include "base/time/time.h"
 
 class Profile;
 
diff --git a/chrome/browser/chromeos/extensions/file_manager/file_manager_notifications_unittest.cc b/chrome/browser/chromeos/extensions/file_manager/file_manager_notifications_unittest.cc
index b3df077..7a22c3b 100644
--- a/chrome/browser/chromeos/extensions/file_manager/file_manager_notifications_unittest.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/file_manager_notifications_unittest.cc
@@ -2,21 +2,20 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
+#include "chrome/browser/chromeos/extensions/file_manager/file_manager_notifications.h"
+
 #include <string>
 
+#include "base/memory/scoped_ptr.h"
 #include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/chromeos/extensions/file_manager/file_manager_notifications.h"
-#include "chrome/browser/ui/browser.h"
 #include "grit/generated_resources.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/l10n/l10n_util.h"
 
 using ::testing::_;
 using ::testing::InSequence;
-using ::testing::Return;
 using ::testing::StrEq;
-using ::testing::AnyNumber;
 
 namespace chromeos {
 
@@ -30,13 +29,13 @@
 
   virtual ~MockFileManagerNotificationsOnMount() {}
 
-  MOCK_METHOD3(ShowNotificationWithMessage, void(NotificationType,
-      const std::string&, const string16&));
+  MOCK_METHOD3(ShowNotificationWithMessage,
+               void(NotificationType, const std::string&, const string16&));
   MOCK_METHOD2(HideNotification, void(NotificationType, const std::string&));
 };
 
 MATCHER_P2(String16Equals, id, label, "") {
-  return arg == l10n_util::GetStringFUTF16(id, ASCIIToUTF16(label));
+  return arg == l10n_util::GetStringFUTF16(id, UTF8ToUTF16(label));
 }
 
 }  // namespace
@@ -182,6 +181,26 @@
       device_label, false, false, false);
 }
 
+TEST(FileManagerMountNotificationsTest, NonASCIILabel) {
+  MockFileManagerNotificationsOnMount* mocked_notifications =
+      new MockFileManagerNotificationsOnMount(NULL);
+  scoped_ptr<FileManagerNotifications> notifications(mocked_notifications);
+
+  std::string notification_path("system_path_prefix");
+  // "RA (U+30E9) BE (U+30D9) RU (U+30EB)" in Katakana letters.
+  std::string device_label("\xE3\x83\xA9\xE3\x83\x99\xE3\x83\xAB");
+
+  notifications->RegisterDevice(notification_path);
+  EXPECT_CALL(*mocked_notifications, HideNotification(
+              FileManagerNotifications::DEVICE, StrEq(notification_path)));
+  EXPECT_CALL(*mocked_notifications, ShowNotificationWithMessage(
+      FileManagerNotifications::DEVICE_FAIL, StrEq(notification_path),
+      String16Equals(IDS_DEVICE_UNKNOWN_MESSAGE, device_label)));
+
+  notifications->ManageNotificationsOnMountCompleted(notification_path,
+      device_label, false, false, false);
+}
+
 TEST(FileManagerMountNotificationsTest, MulitpleFail) {
   MockFileManagerNotificationsOnMount* mocked_notifications =
       new MockFileManagerNotificationsOnMount(NULL);
@@ -195,21 +214,21 @@
               FileManagerNotifications::DEVICE, StrEq(notification_path)));
   {
     InSequence s;
-      EXPECT_CALL(*mocked_notifications, ShowNotificationWithMessage(
-          FileManagerNotifications::DEVICE_FAIL, StrEq(notification_path),
-              String16Equals(IDS_DEVICE_UNKNOWN_MESSAGE, device_label)))
-          .RetiresOnSaturation();
-      EXPECT_CALL(*mocked_notifications, HideNotification(
-          FileManagerNotifications::DEVICE_FAIL, notification_path));
-      EXPECT_CALL(*mocked_notifications, ShowNotificationWithMessage(
-          FileManagerNotifications::DEVICE_FAIL, StrEq(notification_path),
-              String16Equals(IDS_DEVICE_UNKNOWN_MESSAGE, device_label)));
-      EXPECT_CALL(*mocked_notifications, HideNotification(
-          FileManagerNotifications::DEVICE_FAIL, notification_path));
-      EXPECT_CALL(*mocked_notifications, ShowNotificationWithMessage(
-          FileManagerNotifications::DEVICE_FAIL, StrEq(notification_path),
-              String16Equals(IDS_MULTIPART_DEVICE_UNSUPPORTED_MESSAGE,
-              device_label)));
+    EXPECT_CALL(*mocked_notifications, ShowNotificationWithMessage(
+        FileManagerNotifications::DEVICE_FAIL, StrEq(notification_path),
+        String16Equals(IDS_DEVICE_UNKNOWN_MESSAGE, device_label)))
+        .RetiresOnSaturation();
+    EXPECT_CALL(*mocked_notifications, HideNotification(
+        FileManagerNotifications::DEVICE_FAIL, notification_path));
+    EXPECT_CALL(*mocked_notifications, ShowNotificationWithMessage(
+        FileManagerNotifications::DEVICE_FAIL, StrEq(notification_path),
+        String16Equals(IDS_DEVICE_UNKNOWN_MESSAGE, device_label)));
+    EXPECT_CALL(*mocked_notifications, HideNotification(
+        FileManagerNotifications::DEVICE_FAIL, notification_path));
+    EXPECT_CALL(*mocked_notifications, ShowNotificationWithMessage(
+        FileManagerNotifications::DEVICE_FAIL, StrEq(notification_path),
+        String16Equals(IDS_MULTIPART_DEVICE_UNSUPPORTED_MESSAGE,
+                       device_label)));
   }
 
   notifications->ManageNotificationsOnMountCompleted(notification_path,
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 abfc42e..e5549f8 100644
--- a/chrome/browser/chromeos/extensions/file_manager/file_manager_util.h
+++ b/chrome/browser/chromeos/extensions/file_manager/file_manager_util.h
@@ -8,16 +8,12 @@
 #include <string>
 
 #include "base/files/file_path.h"
-#include "googleurl/src/gurl.h"
 #include "ui/shell_dialogs/select_file_dialog.h"
 
 class Browser;
+class GURL;
 class Profile;
 
-namespace base {
-class ListValue;
-}
-
 extern const char kFileBrowserDomain[];
 extern const char kFileBrowserGalleryTaskId[];
 extern const char kFileBrowserWatchTaskId[];
diff --git a/chrome/browser/chromeos/extensions/file_manager/zip_file_creator.h b/chrome/browser/chromeos/extensions/file_manager/zip_file_creator.h
index 01bf2ad..bc9defb 100644
--- a/chrome/browser/chromeos/extensions/file_manager/zip_file_creator.h
+++ b/chrome/browser/chromeos/extensions/file_manager/zip_file_creator.h
@@ -48,7 +48,6 @@
   void Start();
 
  private:
-  class ProcessHostClient;
   friend class ProcessHostClient;
 
   virtual ~ZipFileCreator();
diff --git a/chrome/browser/chromeos/extensions/info_private_api.cc b/chrome/browser/chromeos/extensions/info_private_api.cc
index 872d790..8bd78aa 100644
--- a/chrome/browser/chromeos/extensions/info_private_api.cc
+++ b/chrome/browser/chromeos/extensions/info_private_api.cc
@@ -18,9 +18,6 @@
 
 namespace {
 
-// Name of machine statistic property with HWID.
-const char kHardwareClass[] = "hardware_class";
-
 // Key which corresponds to the HWID setting.
 const char kPropertyHWID[] = "hwid";
 
@@ -30,9 +27,6 @@
 // Key which corresponds to the initial_locale property.
 const char kPropertyInitialLocale[] = "initialLocale";
 
-// Name of machine statistic property with board.
-const char kPropertyReleaseBoard[] = "CHROMEOS_RELEASE_BOARD";
-
 // Key which corresponds to the board property in JS.
 const char kPropertyBoard[] = "board";
 
@@ -69,7 +63,7 @@
     std::string hwid;
     chromeos::system::StatisticsProvider* provider =
         chromeos::system::StatisticsProvider::GetInstance();
-    provider->GetMachineStatistic(kHardwareClass, &hwid);
+    provider->GetMachineStatistic(chromeos::system::kHardwareClass, &hwid);
     return new base::StringValue(hwid);
   } else if (property_name == kPropertyHomeProvider) {
     NetworkLibrary* netlib = CrosLibrary::Get()->GetNetworkLibrary();
@@ -81,7 +75,7 @@
     std::string board;
     chromeos::system::StatisticsProvider* provider =
         chromeos::system::StatisticsProvider::GetInstance();
-    provider->GetMachineStatistic(kPropertyReleaseBoard, &board);
+    provider->GetMachineStatistic(chromeos::system::kMachineInfoBoard, &board);
     return new base::StringValue(board);
   } else if (property_name == kPropertyOwner) {
     return Value::CreateBooleanValue(
diff --git a/chrome/browser/chromeos/extensions/install_limiter.h b/chrome/browser/chromeos/extensions/install_limiter.h
index c0fff26..2839c29 100644
--- a/chrome/browser/chromeos/extensions/install_limiter.h
+++ b/chrome/browser/chromeos/extensions/install_limiter.h
@@ -13,7 +13,7 @@
 #include "base/files/file_path.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
-#include "base/timer.h"
+#include "base/timer/timer.h"
 #include "chrome/browser/extensions/crx_installer.h"
 #include "components/browser_context_keyed_service/browser_context_keyed_service.h"
 #include "content/public/browser/notification_observer.h"
diff --git a/chrome/browser/chromeos/extensions/networking_private_apitest.cc b/chrome/browser/chromeos/extensions/networking_private_apitest.cc
index 8104cbf..0cb874a 100644
--- a/chrome/browser/chromeos/extensions/networking_private_apitest.cc
+++ b/chrome/browser/chromeos/extensions/networking_private_apitest.cc
@@ -6,7 +6,6 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chromeos/login/user.h"
 #include "chrome/browser/chromeos/login/user_manager.h"
-#include "chrome/browser/chromeos/policy/network_configuration_updater.h"
 #include "chrome/browser/extensions/extension_apitest.h"
 #include "chrome/browser/policy/browser_policy_connector.h"
 #include "chrome/browser/policy/mock_configuration_policy_provider.h"
@@ -119,20 +118,29 @@
                            flimflam::kTypeCellular, "stub_cellular_device1");
 
     const bool add_to_watchlist = true;
+    const bool add_to_visible = true;
     service_test->AddService("stub_ethernet", "eth0",
                              flimflam::kTypeEthernet, flimflam::kStateOnline,
-                             add_to_watchlist);
+                             add_to_visible, add_to_watchlist);
 
     service_test->AddService("stub_wifi1", "wifi1",
                              flimflam::kTypeWifi, flimflam::kStateOnline,
-                             add_to_watchlist);
+                             add_to_visible, add_to_watchlist);
     service_test->SetServiceProperty("stub_wifi1",
                                      flimflam::kSecurityProperty,
                                      base::StringValue(flimflam::kSecurityWep));
+    base::ListValue frequencies1;
+    frequencies1.AppendInteger(2400);
+    service_test->SetServiceProperty("stub_wifi1",
+                                     shill::kWifiFrequencyListProperty,
+                                     frequencies1);
+    service_test->SetServiceProperty("stub_wifi1",
+                                     flimflam::kWifiFrequency,
+                                     base::FundamentalValue(2400));
 
     service_test->AddService("stub_wifi2", "wifi2_PSK",
                              flimflam::kTypeWifi, flimflam::kStateIdle,
-                             add_to_watchlist);
+                             add_to_visible, add_to_watchlist);
     service_test->SetServiceProperty("stub_wifi2",
                                      flimflam::kGuidProperty,
                                      base::StringValue("stub_wifi2"));
@@ -142,14 +150,23 @@
     service_test->SetServiceProperty("stub_wifi2",
                                      flimflam::kSignalStrengthProperty,
                                      base::FundamentalValue(80));
+    base::ListValue frequencies2;
+    frequencies2.AppendInteger(2400);
+    frequencies2.AppendInteger(5000);
+    service_test->SetServiceProperty("stub_wifi2",
+                                     shill::kWifiFrequencyListProperty,
+                                     frequencies2);
+    service_test->SetServiceProperty("stub_wifi2",
+                                     flimflam::kWifiFrequency,
+                                     base::FundamentalValue(5000));
     service_test->SetServiceProperty("stub_wifi2",
                                      flimflam::kProfileProperty,
                                      base::StringValue(kUser1ProfilePath));
-    profile_test->AddService("stub_wifi2");
+    profile_test->AddService(kUser1ProfilePath, "stub_wifi2");
 
     service_test->AddService("stub_cellular1", "cellular1",
                              flimflam::kTypeCellular, flimflam::kStateIdle,
-                             add_to_watchlist);
+                             add_to_visible, add_to_watchlist);
     service_test->SetServiceProperty(
         "stub_cellular1",
         flimflam::kNetworkTechnologyProperty,
@@ -166,7 +183,7 @@
     service_test->AddService("stub_vpn1", "vpn1",
                              flimflam::kTypeVPN,
                              flimflam::kStateOnline,
-                             add_to_watchlist);
+                             add_to_visible, add_to_watchlist);
 
     content::RunAllPendingInMessageLoop();
   }
@@ -251,7 +268,7 @@
   ShillProfileClient::TestInterface* profile_test =
       DBusThreadManager::Get()->GetShillProfileClient()->GetTestInterface();
   // Update the profile entry.
-  profile_test->AddService("stub_wifi2");
+  profile_test->AddService(kUser1ProfilePath, "stub_wifi2");
 
   content::RunAllPendingInMessageLoop();
 
diff --git a/chrome/browser/chromeos/extensions/wallpaper_private_apitest.cc b/chrome/browser/chromeos/extensions/wallpaper_private_apitest.cc
index 20de42a..14f164f 100644
--- a/chrome/browser/chromeos/extensions/wallpaper_private_apitest.cc
+++ b/chrome/browser/chromeos/extensions/wallpaper_private_apitest.cc
@@ -7,6 +7,6 @@
 
 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, WallpaperPicker) {
   host_resolver()->AddRule("a.com", "127.0.0.1");
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
   ASSERT_TRUE(RunComponentExtensionTest("wallpaper_manager")) << message_;
 }
diff --git a/chrome/browser/chromeos/external_metrics.cc b/chrome/browser/chromeos/external_metrics.cc
index fe24805..cabac24 100644
--- a/chrome/browser/chromeos/external_metrics.cc
+++ b/chrome/browser/chromeos/external_metrics.cc
@@ -13,16 +13,19 @@
 #include <sys/types.h>
 #include <unistd.h>
 
+#include <map>
 #include <string>
 
 #include "base/basictypes.h"
 #include "base/bind.h"
+#include "base/file_util.h"
 #include "base/metrics/histogram.h"
 #include "base/metrics/sparse_histogram.h"
 #include "base/metrics/statistics_recorder.h"
 #include "base/perftimer.h"
 #include "base/posix/eintr_wrapper.h"
-#include "base/time.h"
+#include "base/sys_info.h"
+#include "base/time/time.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/metrics/metrics_service.h"
 #include "content/public/browser/browser_thread.h"
@@ -53,6 +56,83 @@
   return CheckValues(name, 1, maximum, maximum + 1);
 }
 
+// Establishes field trial for wifi scanning in chromeos.  crbug.com/242733.
+void SetupProgressiveScanFieldTrial() {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+  const char name_of_experiment[] = "ProgressiveScan";
+  const char path_to_group_file[] = "/home/chronos/.progressive_scan_variation";
+  const base::FieldTrial::Probability kDivisor = 1000;
+  scoped_refptr<base::FieldTrial> trial =
+      base::FieldTrialList::FactoryGetFieldTrial(name_of_experiment,
+                                                 kDivisor,
+                                                 "Default",
+                                                 2013, 12, 31, NULL);
+  // Announce the groups with 0 percentage; the actual percentages come from
+  // the server configuration.
+  std::map<int, std::string> group_to_char;
+  group_to_char[trial->AppendGroup("FullScan", 0)] = "c";
+  group_to_char[trial->AppendGroup("33Percent_4MinMax", 0)] = "1";
+  group_to_char[trial->AppendGroup("50Percent_4MinMax", 0)] = "2";
+  group_to_char[trial->AppendGroup("50Percent_8MinMax", 0)] = "3";
+  group_to_char[trial->AppendGroup("100Percent_8MinMax", 0)] = "4";
+
+  // Announce the experiment to any listeners (especially important is the UMA
+  // software, which will append the group names to UMA statistics).
+  const int group_num = trial->group();
+  std::string group_char = "x";
+  if (ContainsKey(group_to_char, group_num))
+    group_char = group_to_char[group_num];
+
+  // Write the group to the file to be read by ChromeOS.
+  const base::FilePath kPathToGroupFile(path_to_group_file);
+
+  if (file_util::WriteFile(kPathToGroupFile, group_char.c_str(),
+                           group_char.length())) {
+    LOG(INFO) << "Configured in group '" << trial->group_name()
+              << "' ('" << group_char << "') for "
+              << name_of_experiment << " field trial";
+  } else {
+    LOG(ERROR) << "Couldn't write to " << path_to_group_file;
+  }
+}
+
+// Sets up field trial for measuring swap and CPU metrics after tab switch
+// and scroll events. crbug.com/253994
+void SetupSwapJankFieldTrial() {
+  const char name_of_experiment[] = "SwapJank64vs32";
+
+  // Determine if this is a 32 or 64 bit build of Chrome.
+  bool is_chrome_64 = sizeof(void*) == 8;
+
+  // Determine if this is a 32 or 64 bit kernel.
+  bool is_kernel_64 = base::SysInfo::OperatingSystemArchitecture() == "x86_64";
+
+  // A 32 bit kernel requires 32 bit Chrome.
+  DCHECK(is_kernel_64 || !is_chrome_64);
+
+  // All groups are either on or off.
+  const base::FieldTrial::Probability kTotalProbability = 1;
+  scoped_refptr<base::FieldTrial> trial =
+      base::FieldTrialList::FactoryGetFieldTrial(name_of_experiment,
+                                                 kTotalProbability,
+                                                 "default",
+                                                 2013, 12, 31, NULL);
+  // Assign probability of 1 to this Chrome's group.  Assign 0 to all other
+  // choices.
+  trial->AppendGroup("kernel_64_chrome_64",
+                     is_kernel_64 && is_chrome_64 ? kTotalProbability : 0);
+  trial->AppendGroup("kernel_64_chrome_32",
+                     is_kernel_64 && !is_chrome_64 ? kTotalProbability : 0);
+  trial->AppendGroup("kernel_32_chrome_32",
+                     !is_kernel_64 && !is_chrome_64 ? kTotalProbability : 0);
+
+  // Announce the experiment to any listeners (especially important is the UMA
+  // software, which will append the group names to UMA statistics).
+  trial->group();
+  DVLOG(1) << "Configured in group '" << trial->group_name() << "' for "
+           << name_of_experiment << " field trial";
+}
+
 }  // namespace
 
 // The interval between external metrics collections in seconds
@@ -72,7 +152,19 @@
   valid_user_actions_.insert("Updater.ServerCertificateChanged");
   valid_user_actions_.insert("Updater.ServerCertificateFailed");
 
-  ScheduleCollector();
+  // Initialize field trials that don't need to read from files.
+  SetupSwapJankFieldTrial();
+
+  // Initialize any chromeos field trials that need to read from a file (e.g.,
+  // those that have an upstart script determine their experimental group for
+  // them) then schedule the data collection.  All of this is done on the file
+  // thread.
+  bool task_posted = BrowserThread::PostTask(
+      BrowserThread::FILE,
+      FROM_HERE,
+      base::Bind(&chromeos::ExternalMetrics::SetupFieldTrialsOnFileThread,
+                 this));
+  DCHECK(task_posted);
 }
 
 void ExternalMetrics::RecordActionUI(std::string action_string) {
@@ -291,4 +383,13 @@
   DCHECK(result);
 }
 
+void ExternalMetrics::SetupFieldTrialsOnFileThread() {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+  // Field trials that do not read from files can be initialized in
+  // ExternalMetrics::Start() above.
+  SetupProgressiveScanFieldTrial();
+
+  ScheduleCollector();
+}
+
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/external_metrics.h b/chrome/browser/chromeos/external_metrics.h
index c5894e5..5be9fc2 100644
--- a/chrome/browser/chromeos/external_metrics.h
+++ b/chrome/browser/chromeos/external_metrics.h
@@ -5,6 +5,8 @@
 #ifndef CHROME_BROWSER_CHROMEOS_EXTERNAL_METRICS_H_
 #define CHROME_BROWSER_CHROMEOS_EXTERNAL_METRICS_H_
 
+#include <string>
+
 #include "base/basictypes.h"
 #include "base/compiler_specific.h"
 #include "base/containers/hash_tables.h"
@@ -21,9 +23,6 @@
 // normal UMA mechanism. The file is then truncated to zero size. Chrome uses
 // flock() to synchronize accesses to the file.
 class ExternalMetrics : public base::RefCountedThreadSafe<ExternalMetrics> {
-  FRIEND_TEST_ALL_PREFIXES(ExternalMetricsTest, ParseExternalMetricsFile);
-  friend class base::RefCountedThreadSafe<ExternalMetrics>;
-
  public:
   ExternalMetrics();
 
@@ -33,6 +32,9 @@
   void Start();
 
  private:
+  friend class base::RefCountedThreadSafe<ExternalMetrics>;
+  FRIEND_TEST_ALL_PREFIXES(ExternalMetricsTest, ParseExternalMetricsFile);
+
   // There is one function with this type for each action.
   typedef void (*RecordFunctionType)();
 
@@ -78,6 +80,12 @@
   // Schedules a metrics event collection in the future.
   void ScheduleCollector();
 
+  // Calls setup methods for Chrome OS field trials that need to be initialized
+  // based on data from the file system.  They are setup here so that we can
+  // make absolutely sure that they are setup before we gather UMA statistics
+  // from ChromeOS.
+  void SetupFieldTrialsOnFileThread();
+
   // Maps histogram or action names to recorder structs.
   base::hash_map<std::string, RecordFunctionType> action_recorders_;
 
@@ -87,6 +95,7 @@
   // Used for testing only.
   RecorderType test_recorder_;
   base::FilePath test_path_;
+
   DISALLOW_COPY_AND_ASSIGN(ExternalMetrics);
 };
 
diff --git a/chrome/browser/chromeos/external_protocol_dialog.h b/chrome/browser/chromeos/external_protocol_dialog.h
index bf11eba..cee403e 100644
--- a/chrome/browser/chromeos/external_protocol_dialog.h
+++ b/chrome/browser/chromeos/external_protocol_dialog.h
@@ -8,7 +8,7 @@
 #include <string>
 
 #include "base/strings/string16.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "ui/views/window/dialog_delegate.h"
 
 class GURL;
diff --git a/chrome/browser/chromeos/fileapi/cros_mount_point_provider.cc b/chrome/browser/chromeos/fileapi/cros_mount_point_provider.cc
new file mode 100644
index 0000000..82da083
--- /dev/null
+++ b/chrome/browser/chromeos/fileapi/cros_mount_point_provider.cc
@@ -0,0 +1,354 @@
+// 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/fileapi/cros_mount_point_provider.h"
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop.h"
+#include "base/path_service.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/synchronization/lock.h"
+#include "chrome/browser/chromeos/fileapi/file_access_permissions.h"
+#include "chrome/browser/chromeos/fileapi/remote_file_stream_writer.h"
+#include "chrome/browser/chromeos/fileapi/remote_file_system_operation.h"
+#include "chromeos/dbus/cros_disks_client.h"
+#include "webkit/browser/fileapi/async_file_util_adapter.h"
+#include "webkit/browser/fileapi/copy_or_move_file_validator.h"
+#include "webkit/browser/fileapi/external_mount_points.h"
+#include "webkit/browser/fileapi/file_system_context.h"
+#include "webkit/browser/fileapi/file_system_file_stream_reader.h"
+#include "webkit/browser/fileapi/file_system_operation_context.h"
+#include "webkit/browser/fileapi/file_system_task_runners.h"
+#include "webkit/browser/fileapi/file_system_url.h"
+#include "webkit/browser/fileapi/isolated_context.h"
+#include "webkit/browser/fileapi/isolated_file_util.h"
+#include "webkit/browser/fileapi/local_file_stream_writer.h"
+#include "webkit/browser/fileapi/local_file_system_operation.h"
+
+namespace {
+
+const char kChromeUIScheme[] = "chrome";
+
+}  // namespace
+
+namespace chromeos {
+
+// static
+bool CrosMountPointProvider::CanHandleURL(const fileapi::FileSystemURL& url) {
+  if (!url.is_valid())
+    return false;
+  return url.type() == fileapi::kFileSystemTypeNativeLocal ||
+         url.type() == fileapi::kFileSystemTypeRestrictedNativeLocal ||
+         url.type() == fileapi::kFileSystemTypeDrive;
+}
+
+CrosMountPointProvider::CrosMountPointProvider(
+    scoped_refptr<quota::SpecialStoragePolicy> special_storage_policy,
+    scoped_refptr<fileapi::ExternalMountPoints> mount_points,
+    fileapi::ExternalMountPoints* system_mount_points)
+    : special_storage_policy_(special_storage_policy),
+      file_access_permissions_(new FileAccessPermissions()),
+      local_file_util_(new fileapi::AsyncFileUtilAdapter(
+          new fileapi::IsolatedFileUtil())),
+      mount_points_(mount_points),
+      system_mount_points_(system_mount_points) {
+}
+
+CrosMountPointProvider::~CrosMountPointProvider() {
+}
+
+void CrosMountPointProvider::AddSystemMountPoints() {
+  // RegisterFileSystem() is no-op if the mount point with the same name
+  // already exists, hence it's safe to call without checking if a mount
+  // point already exists or not.
+
+  // TODO(satorux): "Downloads" directory should probably be per-profile. For
+  // this to be per-profile, a unique directory path should be chosen per
+  // profile, and the mount point should be added to
+  // mount_points_. crbug.com/247236
+  base::FilePath home_path;
+  if (PathService::Get(base::DIR_HOME, &home_path)) {
+    system_mount_points_->RegisterFileSystem(
+        "Downloads",
+        fileapi::kFileSystemTypeNativeLocal,
+        home_path.AppendASCII("Downloads"));
+  }
+
+  system_mount_points_->RegisterFileSystem(
+      "archive",
+      fileapi::kFileSystemTypeNativeLocal,
+      chromeos::CrosDisksClient::GetArchiveMountPoint());
+  system_mount_points_->RegisterFileSystem(
+      "removable",
+      fileapi::kFileSystemTypeNativeLocal,
+      chromeos::CrosDisksClient::GetRemovableDiskMountPoint());
+  system_mount_points_->RegisterFileSystem(
+      "oem",
+      fileapi::kFileSystemTypeRestrictedNativeLocal,
+      base::FilePath(FILE_PATH_LITERAL("/usr/share/oem")));
+}
+
+bool CrosMountPointProvider::CanHandleType(fileapi::FileSystemType type) const {
+  switch (type) {
+    case fileapi::kFileSystemTypeExternal:
+    case fileapi::kFileSystemTypeDrive:
+    case fileapi::kFileSystemTypeRestrictedNativeLocal:
+    case fileapi::kFileSystemTypeNativeLocal:
+    case fileapi::kFileSystemTypeNativeForPlatformApp:
+      return true;
+    default:
+      return false;
+  }
+}
+
+void CrosMountPointProvider::OpenFileSystem(
+    const GURL& origin_url,
+    fileapi::FileSystemType type,
+    fileapi::OpenFileSystemMode mode,
+    const OpenFileSystemCallback& callback) {
+  DCHECK(fileapi::IsolatedContext::IsIsolatedType(type));
+  // Nothing to validate for external filesystem.
+  callback.Run(base::PLATFORM_FILE_OK);
+}
+
+fileapi::FileSystemQuotaUtil* CrosMountPointProvider::GetQuotaUtil() {
+  // No quota support.
+  return NULL;
+}
+
+void CrosMountPointProvider::DeleteFileSystem(
+    const GURL& origin_url,
+    fileapi::FileSystemType type,
+    fileapi::FileSystemContext* context,
+    const DeleteFileSystemCallback& callback) {
+  NOTREACHED();
+  callback.Run(base::PLATFORM_FILE_ERROR_INVALID_OPERATION);
+}
+
+bool CrosMountPointProvider::IsAccessAllowed(
+    const fileapi::FileSystemURL& url) const {
+  if (!url.is_valid())
+    return false;
+
+  // Permit access to mount points from internal WebUI.
+  const GURL& origin_url = url.origin();
+  if (origin_url.SchemeIs(kChromeUIScheme))
+    return true;
+
+  // No extra check is needed for isolated file systems.
+  if (url.mount_type() == fileapi::kFileSystemTypeIsolated)
+    return true;
+
+  if (!CanHandleURL(url))
+    return false;
+
+  std::string extension_id = origin_url.host();
+  // Check first to make sure this extension has fileBrowserHander permissions.
+  if (!special_storage_policy_->IsFileHandler(extension_id))
+    return false;
+
+  return file_access_permissions_->HasAccessPermission(extension_id,
+                                                       url.virtual_path());
+}
+
+void CrosMountPointProvider::GrantFullAccessToExtension(
+    const std::string& extension_id) {
+  DCHECK(special_storage_policy_->IsFileHandler(extension_id));
+  if (!special_storage_policy_->IsFileHandler(extension_id))
+    return;
+
+  std::vector<fileapi::MountPoints::MountPointInfo> files;
+  mount_points_->AddMountPointInfosTo(&files);
+  system_mount_points_->AddMountPointInfosTo(&files);
+
+  for (size_t i = 0; i < files.size(); ++i) {
+    file_access_permissions_->GrantAccessPermission(
+        extension_id,
+        base::FilePath::FromUTF8Unsafe(files[i].name));
+  }
+}
+
+void CrosMountPointProvider::GrantFileAccessToExtension(
+    const std::string& extension_id, const base::FilePath& virtual_path) {
+  // All we care about here is access from extensions for now.
+  DCHECK(special_storage_policy_->IsFileHandler(extension_id));
+  if (!special_storage_policy_->IsFileHandler(extension_id))
+    return;
+
+  std::string id;
+  fileapi::FileSystemType type;
+  base::FilePath path;
+  if (!mount_points_->CrackVirtualPath(virtual_path, &id, &type, &path) &&
+      !system_mount_points_->CrackVirtualPath(virtual_path,
+                                              &id, &type, &path)) {
+    return;
+  }
+
+  if (type == fileapi::kFileSystemTypeRestrictedNativeLocal) {
+    LOG(ERROR) << "Can't grant access for restricted mount point";
+    return;
+  }
+
+  file_access_permissions_->GrantAccessPermission(extension_id, virtual_path);
+}
+
+void CrosMountPointProvider::RevokeAccessForExtension(
+      const std::string& extension_id) {
+  file_access_permissions_->RevokePermissions(extension_id);
+}
+
+std::vector<base::FilePath> CrosMountPointProvider::GetRootDirectories() const {
+  std::vector<fileapi::MountPoints::MountPointInfo> mount_points;
+  mount_points_->AddMountPointInfosTo(&mount_points);
+  system_mount_points_->AddMountPointInfosTo(&mount_points);
+
+  std::vector<base::FilePath> root_dirs;
+  for (size_t i = 0; i < mount_points.size(); ++i)
+    root_dirs.push_back(mount_points[i].path);
+  return root_dirs;
+}
+
+fileapi::FileSystemFileUtil* CrosMountPointProvider::GetFileUtil(
+    fileapi::FileSystemType type) {
+  DCHECK(type == fileapi::kFileSystemTypeNativeLocal ||
+         type == fileapi::kFileSystemTypeRestrictedNativeLocal);
+  return local_file_util_->sync_file_util();
+}
+
+fileapi::AsyncFileUtil* CrosMountPointProvider::GetAsyncFileUtil(
+    fileapi::FileSystemType type) {
+  DCHECK(type == fileapi::kFileSystemTypeNativeLocal ||
+         type == fileapi::kFileSystemTypeRestrictedNativeLocal);
+  return local_file_util_.get();
+}
+
+fileapi::CopyOrMoveFileValidatorFactory*
+CrosMountPointProvider::GetCopyOrMoveFileValidatorFactory(
+    fileapi::FileSystemType type, base::PlatformFileError* error_code) {
+  DCHECK(error_code);
+  *error_code = base::PLATFORM_FILE_OK;
+  return NULL;
+}
+
+fileapi::FileSystemOperation* CrosMountPointProvider::CreateFileSystemOperation(
+    const fileapi::FileSystemURL& url,
+    fileapi::FileSystemContext* context,
+    base::PlatformFileError* error_code) const {
+  DCHECK(url.is_valid());
+
+  if (!IsAccessAllowed(url)) {
+    *error_code = base::PLATFORM_FILE_ERROR_SECURITY;
+    return NULL;
+  }
+
+  if (url.type() == fileapi::kFileSystemTypeDrive) {
+    fileapi::RemoteFileSystemProxyInterface* remote_proxy =
+        GetRemoteProxy(url.filesystem_id());
+    if (!remote_proxy) {
+      *error_code = base::PLATFORM_FILE_ERROR_NOT_FOUND;
+      return NULL;
+    }
+    return new RemoteFileSystemOperation(remote_proxy);
+  }
+
+  DCHECK(url.type() == fileapi::kFileSystemTypeNativeLocal ||
+         url.type() == fileapi::kFileSystemTypeRestrictedNativeLocal);
+  scoped_ptr<fileapi::FileSystemOperationContext> operation_context(
+      new fileapi::FileSystemOperationContext(context));
+  operation_context->set_root_path(GetFileSystemRootPath(url));
+  return new fileapi::LocalFileSystemOperation(url, context,
+                                               operation_context.Pass());
+}
+
+scoped_ptr<webkit_blob::FileStreamReader>
+CrosMountPointProvider::CreateFileStreamReader(
+    const fileapi::FileSystemURL& url,
+    int64 offset,
+    const base::Time& expected_modification_time,
+    fileapi::FileSystemContext* context) const {
+  DCHECK(url.is_valid());
+
+  if (!IsAccessAllowed(url))
+    return scoped_ptr<webkit_blob::FileStreamReader>();
+
+  if (url.type() == fileapi::kFileSystemTypeDrive) {
+    fileapi::RemoteFileSystemProxyInterface* remote_proxy =
+        GetRemoteProxy(url.filesystem_id());
+    if (!remote_proxy)
+      return scoped_ptr<webkit_blob::FileStreamReader>();
+    return remote_proxy->CreateFileStreamReader(
+        context->task_runners()->file_task_runner(),
+        url, offset, expected_modification_time);
+  }
+
+  return scoped_ptr<webkit_blob::FileStreamReader>(
+      new fileapi::FileSystemFileStreamReader(
+          context, url, offset, expected_modification_time));
+}
+
+scoped_ptr<fileapi::FileStreamWriter>
+CrosMountPointProvider::CreateFileStreamWriter(
+    const fileapi::FileSystemURL& url,
+    int64 offset,
+    fileapi::FileSystemContext* context) const {
+  DCHECK(url.is_valid());
+
+  if (!IsAccessAllowed(url))
+    return scoped_ptr<fileapi::FileStreamWriter>();
+
+  if (url.type() == fileapi::kFileSystemTypeDrive) {
+    fileapi::RemoteFileSystemProxyInterface* remote_proxy =
+        GetRemoteProxy(url.filesystem_id());
+    if (!remote_proxy)
+      return scoped_ptr<fileapi::FileStreamWriter>();
+    return scoped_ptr<fileapi::FileStreamWriter>(
+        new RemoteFileStreamWriter(
+            remote_proxy, url, offset,
+            context->task_runners()->file_task_runner()));
+  }
+
+  if (url.type() == fileapi::kFileSystemTypeRestrictedNativeLocal)
+    return scoped_ptr<fileapi::FileStreamWriter>();
+
+  DCHECK(url.type() == fileapi::kFileSystemTypeNativeLocal);
+  return scoped_ptr<fileapi::FileStreamWriter>(
+      new fileapi::LocalFileStreamWriter(
+          context->task_runners()->file_task_runner(), url.path(), offset));
+}
+
+bool CrosMountPointProvider::GetVirtualPath(
+    const base::FilePath& filesystem_path,
+    base::FilePath* virtual_path) {
+  return mount_points_->GetVirtualPath(filesystem_path, virtual_path) ||
+         system_mount_points_->GetVirtualPath(filesystem_path, virtual_path);
+}
+
+fileapi::RemoteFileSystemProxyInterface* CrosMountPointProvider::GetRemoteProxy(
+    const std::string& mount_name) const {
+  fileapi::RemoteFileSystemProxyInterface* proxy =
+      mount_points_->GetRemoteFileSystemProxy(mount_name);
+  if (proxy)
+    return proxy;
+  return system_mount_points_->GetRemoteFileSystemProxy(mount_name);
+}
+
+base::FilePath CrosMountPointProvider::GetFileSystemRootPath(
+    const fileapi::FileSystemURL& url) const {
+  DCHECK(fileapi::IsolatedContext::IsIsolatedType(url.mount_type()));
+  if (!url.is_valid())
+    return base::FilePath();
+
+  base::FilePath root_path;
+  std::string mount_name = url.filesystem_id();
+  if (!mount_points_->GetRegisteredPath(mount_name, &root_path) &&
+      !system_mount_points_->GetRegisteredPath(mount_name, &root_path)) {
+    return base::FilePath();
+  }
+
+  return root_path.DirName();
+}
+
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/fileapi/cros_mount_point_provider.h b/chrome/browser/chromeos/fileapi/cros_mount_point_provider.h
new file mode 100644
index 0000000..c68589d
--- /dev/null
+++ b/chrome/browser/chromeos/fileapi/cros_mount_point_provider.h
@@ -0,0 +1,170 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_FILEAPI_CROS_MOUNT_POINT_PROVIDER_H_
+#define CHROME_BROWSER_CHROMEOS_FILEAPI_CROS_MOUNT_POINT_PROVIDER_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "base/compiler_specific.h"
+#include "base/files/file_path.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/synchronization/lock.h"
+#include "webkit/browser/fileapi/file_system_mount_point_provider.h"
+#include "webkit/browser/quota/special_storage_policy.h"
+#include "webkit/browser/webkit_storage_browser_export.h"
+#include "webkit/common/fileapi/file_system_types.h"
+
+namespace fileapi {
+class AsyncFileUtilAdapter;
+class CopyOrMoveFileValidatorFactory;
+class ExternalMountPoints;
+class FileSystemFileUtil;
+class FileSystemURL;
+class IsolatedContext;
+}
+
+namespace chromeos {
+
+class FileAccessPermissions;
+
+// CrosMountPointProvider is a Chrome OS specific implementation of
+// ExternalFileSystemMountPointProvider. This class is responsible for a
+// number of things, including:
+//
+// - Add system mount points
+// - Grant/revoke/check file access permissions
+// - Create FileSystemOperation per file system type
+// - Create FileStreamReader/Writer per file system type
+//
+// Chrome OS specific mount points:
+//
+// "Downloads" is a mount point for user's Downloads directory on the local
+// disk, where downloaded files are stored by default.
+//
+// "archive" is a mount point for an archive file, such as a zip file. This
+// mount point exposes contents of an archive file via cros_disks and AVFS
+// <http://avf.sourceforge.net/>.
+//
+// "removable" is a mount point for removable media such as an SD card.
+// Insertion and removal of removable media are handled by cros_disks.
+//
+// "oem" is a read-only mount point for a directory containing OEM data.
+//
+// "drive" is a mount point for Google Drive. Drive is integrated with the
+// FileSystem API layer via drive::FileSystemProxy. This mount point is added
+// by drive::DriveIntegrationService.
+//
+// These mount points are placed under the "external" namespace, and file
+// system URLs for these mount points look like:
+//
+//   filesystem:<origin>/external/<mount_name>/...
+//
+class CrosMountPointProvider
+    : public fileapi::ExternalFileSystemMountPointProvider {
+ public:
+  using fileapi::FileSystemMountPointProvider::OpenFileSystemCallback;
+  using fileapi::FileSystemMountPointProvider::DeleteFileSystemCallback;
+
+  // CrosMountPointProvider will take an ownership of a |mount_points|
+  // reference. On the other hand, |system_mount_points| will be kept as a raw
+  // pointer and it should outlive CrosMountPointProvider instance.
+  CrosMountPointProvider(
+      scoped_refptr<quota::SpecialStoragePolicy> special_storage_policy,
+      scoped_refptr<fileapi::ExternalMountPoints> mount_points,
+      fileapi::ExternalMountPoints* system_mount_points);
+  virtual ~CrosMountPointProvider();
+
+  // Adds system mount points, such as "archive", and "removable". This
+  // function is no-op if these mount points are already present.
+  void AddSystemMountPoints();
+
+  // Returns true if CrosMountpointProvider can handle |url|, i.e. its
+  // file system type matches with what this provider supports.
+  // This could be called on any threads.
+  static bool CanHandleURL(const fileapi::FileSystemURL& url);
+
+  // fileapi::FileSystemMountPointProvider overrides.
+  virtual bool CanHandleType(fileapi::FileSystemType type) const OVERRIDE;
+  virtual void OpenFileSystem(
+      const GURL& origin_url,
+      fileapi::FileSystemType type,
+      fileapi::OpenFileSystemMode mode,
+      const OpenFileSystemCallback& callback) OVERRIDE;
+  virtual fileapi::FileSystemFileUtil* GetFileUtil(
+      fileapi::FileSystemType type) OVERRIDE;
+  virtual fileapi::AsyncFileUtil* GetAsyncFileUtil(
+      fileapi::FileSystemType type) OVERRIDE;
+  virtual fileapi::CopyOrMoveFileValidatorFactory*
+      GetCopyOrMoveFileValidatorFactory(
+          fileapi::FileSystemType type,
+          base::PlatformFileError* error_code) OVERRIDE;
+  virtual fileapi::FileSystemOperation* CreateFileSystemOperation(
+      const fileapi::FileSystemURL& url,
+      fileapi::FileSystemContext* context,
+      base::PlatformFileError* error_code) const OVERRIDE;
+  virtual scoped_ptr<webkit_blob::FileStreamReader> CreateFileStreamReader(
+      const fileapi::FileSystemURL& path,
+      int64 offset,
+      const base::Time& expected_modification_time,
+      fileapi::FileSystemContext* context) const OVERRIDE;
+  virtual scoped_ptr<fileapi::FileStreamWriter> CreateFileStreamWriter(
+      const fileapi::FileSystemURL& url,
+      int64 offset,
+      fileapi::FileSystemContext* context) const OVERRIDE;
+  virtual fileapi::FileSystemQuotaUtil* GetQuotaUtil() OVERRIDE;
+  virtual void DeleteFileSystem(
+      const GURL& origin_url,
+      fileapi::FileSystemType type,
+      fileapi::FileSystemContext* context,
+      const DeleteFileSystemCallback& callback) OVERRIDE;
+
+  // fileapi::ExternalFileSystemMountPointProvider overrides.
+  virtual bool IsAccessAllowed(const fileapi::FileSystemURL& url)
+      const OVERRIDE;
+  virtual std::vector<base::FilePath> GetRootDirectories() const OVERRIDE;
+  virtual void GrantFullAccessToExtension(
+      const std::string& extension_id) OVERRIDE;
+  virtual void GrantFileAccessToExtension(
+      const std::string& extension_id,
+      const base::FilePath& virtual_path) OVERRIDE;
+  virtual void RevokeAccessForExtension(
+      const std::string& extension_id) OVERRIDE;
+  virtual bool GetVirtualPath(const base::FilePath& filesystem_path,
+                              base::FilePath* virtual_path) OVERRIDE;
+
+ private:
+  fileapi::RemoteFileSystemProxyInterface* GetRemoteProxy(
+      const std::string& mount_name) const;
+  base::FilePath GetFileSystemRootPath(const fileapi::FileSystemURL& url) const;
+
+  scoped_refptr<quota::SpecialStoragePolicy> special_storage_policy_;
+  scoped_ptr<FileAccessPermissions> file_access_permissions_;
+  scoped_ptr<fileapi::AsyncFileUtilAdapter> local_file_util_;
+
+  // Mount points specific to the owning context (i.e. per-profile mount
+  // points).
+  //
+  // It is legal to have mount points with the same name as in
+  // system_mount_points_. Also, mount point paths may overlap with mount point
+  // paths in system_mount_points_. In both cases mount points in
+  // |mount_points_| will have a priority.
+  // E.g. if |mount_points_| map 'foo1' to '/foo/foo1' and
+  // |file_system_mount_points_| map 'xxx' to '/foo/foo1/xxx', |GetVirtualPaths|
+  // will resolve '/foo/foo1/xxx/yyy' as 'foo1/xxx/yyy' (i.e. the mapping from
+  // |mount_points_| will be used).
+  scoped_refptr<fileapi::ExternalMountPoints> mount_points_;
+
+  // Globally visible mount points. System MountPonts instance should outlive
+  // all CrosMountPointProvider instances, so raw pointer is safe.
+  fileapi::ExternalMountPoints* system_mount_points_;
+
+  DISALLOW_COPY_AND_ASSIGN(CrosMountPointProvider);
+};
+
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_CHROMEOS_FILEAPI_CROS_MOUNT_POINT_PROVIDER_H_
diff --git a/chrome/browser/chromeos/fileapi/cros_mount_point_provider_unittest.cc b/chrome/browser/chromeos/fileapi/cros_mount_point_provider_unittest.cc
new file mode 100644
index 0000000..b74bdf8
--- /dev/null
+++ b/chrome/browser/chromeos/fileapi/cros_mount_point_provider_unittest.cc
@@ -0,0 +1,268 @@
+// 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/fileapi/cros_mount_point_provider.h"
+
+#include <set>
+
+#include "base/files/file_path.h"
+#include "base/path_service.h"
+#include "chromeos/dbus/cros_disks_client.h"
+#include "googleurl/src/url_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "webkit/browser/fileapi/external_mount_points.h"
+#include "webkit/browser/fileapi/file_permission_policy.h"
+#include "webkit/browser/fileapi/file_system_url.h"
+#include "webkit/browser/fileapi/isolated_context.h"
+#include "webkit/browser/quota/mock_special_storage_policy.h"
+
+#define FPL(x) FILE_PATH_LITERAL(x)
+
+using fileapi::ExternalMountPoints;
+using fileapi::FileSystemURL;
+
+namespace {
+
+FileSystemURL CreateFileSystemURL(const std::string& extension,
+                                  const char* path,
+                                  ExternalMountPoints* mount_points) {
+  return mount_points->CreateCrackedFileSystemURL(
+      GURL("chrome-extension://" + extension + "/"),
+      fileapi::kFileSystemTypeExternal,
+      base::FilePath::FromUTF8Unsafe(path));
+}
+
+TEST(CrosMountPointProviderTest, DefaultMountPoints) {
+  scoped_refptr<quota::SpecialStoragePolicy> storage_policy =
+      new quota::MockSpecialStoragePolicy();
+  scoped_refptr<fileapi::ExternalMountPoints> mount_points(
+      fileapi::ExternalMountPoints::CreateRefCounted());
+  chromeos::CrosMountPointProvider provider(
+      storage_policy,
+      mount_points.get(),
+      fileapi::ExternalMountPoints::GetSystemInstance());
+  provider.AddSystemMountPoints();
+  std::vector<base::FilePath> root_dirs = provider.GetRootDirectories();
+  std::set<base::FilePath> root_dirs_set(root_dirs.begin(), root_dirs.end());
+
+  // By default there should be 4 mount points (in system mount points):
+  EXPECT_EQ(4u, root_dirs.size());
+  base::FilePath home_path;
+  ASSERT_TRUE(PathService::Get(base::DIR_HOME, &home_path));
+
+  EXPECT_TRUE(root_dirs_set.count(home_path.AppendASCII("Downloads")));
+  EXPECT_TRUE(root_dirs_set.count(
+      chromeos::CrosDisksClient::GetRemovableDiskMountPoint()));
+  EXPECT_TRUE(root_dirs_set.count(
+      chromeos::CrosDisksClient::GetArchiveMountPoint()));
+  EXPECT_TRUE(root_dirs_set.count(base::FilePath(FPL("/usr/share/oem"))));
+}
+
+TEST(CrosMountPointProviderTest, GetRootDirectories) {
+  scoped_refptr<quota::SpecialStoragePolicy> storage_policy =
+      new quota::MockSpecialStoragePolicy();
+  scoped_refptr<fileapi::ExternalMountPoints> mount_points(
+      fileapi::ExternalMountPoints::CreateRefCounted());
+
+  scoped_refptr<fileapi::ExternalMountPoints> system_mount_points(
+      fileapi::ExternalMountPoints::CreateRefCounted());
+
+  chromeos::CrosMountPointProvider provider(
+      storage_policy,
+      mount_points.get(),
+      system_mount_points.get());
+
+  const size_t initial_root_dirs_size = provider.GetRootDirectories().size();
+
+  // Register 'local' test mount points.
+  mount_points->RegisterFileSystem("c",
+                                   fileapi::kFileSystemTypeNativeLocal,
+                                   base::FilePath(FPL("/a/b/c")));
+  mount_points->RegisterFileSystem("d",
+                                   fileapi::kFileSystemTypeNativeLocal,
+                                   base::FilePath(FPL("/b/c/d")));
+
+  // Register system test mount points.
+  system_mount_points->RegisterFileSystem("d",
+                                          fileapi::kFileSystemTypeNativeLocal,
+                                          base::FilePath(FPL("/g/c/d")));
+  system_mount_points->RegisterFileSystem("e",
+                                          fileapi::kFileSystemTypeNativeLocal,
+                                          base::FilePath(FPL("/g/d/e")));
+
+  std::vector<base::FilePath> root_dirs = provider.GetRootDirectories();
+  std::set<base::FilePath> root_dirs_set(root_dirs.begin(), root_dirs.end());
+  EXPECT_EQ(initial_root_dirs_size + 4, root_dirs.size());
+  EXPECT_TRUE(root_dirs_set.count(base::FilePath(FPL("/a/b/c"))));
+  EXPECT_TRUE(root_dirs_set.count(base::FilePath(FPL("/b/c/d"))));
+  EXPECT_TRUE(root_dirs_set.count(base::FilePath(FPL("/g/c/d"))));
+  EXPECT_TRUE(root_dirs_set.count(base::FilePath(FPL("/g/d/e"))));
+}
+
+TEST(CrosMountPointProviderTest, AccessPermissions) {
+  url_util::AddStandardScheme("chrome-extension");
+
+  scoped_refptr<quota::MockSpecialStoragePolicy> storage_policy =
+      new quota::MockSpecialStoragePolicy();
+  scoped_refptr<fileapi::ExternalMountPoints> mount_points(
+      fileapi::ExternalMountPoints::CreateRefCounted());
+  scoped_refptr<fileapi::ExternalMountPoints> system_mount_points(
+      fileapi::ExternalMountPoints::CreateRefCounted());
+  chromeos::CrosMountPointProvider provider(
+      storage_policy,
+      mount_points.get(),
+      system_mount_points.get());
+
+  std::string extension("ddammdhioacbehjngdmkjcjbnfginlla");
+
+  storage_policy->AddFileHandler(extension);
+
+  // Initialize mount points.
+  ASSERT_TRUE(system_mount_points->RegisterFileSystem(
+      "system",
+      fileapi::kFileSystemTypeNativeLocal,
+      base::FilePath(FPL("/g/system"))));
+  ASSERT_TRUE(mount_points->RegisterFileSystem(
+      "removable",
+      fileapi::kFileSystemTypeNativeLocal,
+      base::FilePath(FPL("/media/removable"))));
+  ASSERT_TRUE(mount_points->RegisterFileSystem(
+      "oem",
+      fileapi::kFileSystemTypeRestrictedNativeLocal,
+      base::FilePath(FPL("/usr/share/oem"))));
+
+  // Provider specific mount point access.
+  EXPECT_FALSE(provider.IsAccessAllowed(
+      CreateFileSystemURL(extension, "removable/foo", mount_points.get())));
+
+  provider.GrantFileAccessToExtension(extension,
+                                      base::FilePath(FPL("removable/foo")));
+  EXPECT_TRUE(provider.IsAccessAllowed(
+      CreateFileSystemURL(extension, "removable/foo", mount_points.get())));
+  EXPECT_FALSE(provider.IsAccessAllowed(
+      CreateFileSystemURL(extension, "removable/foo1", mount_points.get())));
+
+  // System mount point access.
+  EXPECT_FALSE(provider.IsAccessAllowed(
+      CreateFileSystemURL(extension, "system/foo", system_mount_points.get())));
+
+  provider.GrantFileAccessToExtension(extension,
+                                      base::FilePath(FPL("system/foo")));
+  EXPECT_TRUE(provider.IsAccessAllowed(
+      CreateFileSystemURL(extension, "system/foo", system_mount_points.get())));
+  EXPECT_FALSE(provider.IsAccessAllowed(
+      CreateFileSystemURL(extension, "system/foo1",
+                          system_mount_points.get())));
+
+  // oem is restricted file system.
+  provider.GrantFileAccessToExtension(
+      extension, base::FilePath(FPL("oem/foo")));
+  // The extension should not be able to access the file even if
+  // GrantFileAccessToExtension was called.
+  EXPECT_FALSE(provider.IsAccessAllowed(
+      CreateFileSystemURL(extension, "oem/foo", mount_points.get())));
+
+  provider.GrantFullAccessToExtension(extension);
+  // The extension should be able to access restricted file system after it was
+  // granted full access.
+  EXPECT_TRUE(provider.IsAccessAllowed(
+      CreateFileSystemURL(extension, "oem/foo", mount_points.get())));
+  // The extension which was granted full access should be able to access any
+  // path on current file systems.
+  EXPECT_TRUE(provider.IsAccessAllowed(
+      CreateFileSystemURL(extension, "removable/foo1", mount_points.get())));
+  EXPECT_TRUE(provider.IsAccessAllowed(
+      CreateFileSystemURL(extension, "system/foo1",
+                          system_mount_points.get())));
+
+  // The extension cannot access new mount points.
+  // TODO(tbarzic): This should probably be changed.
+  ASSERT_TRUE(mount_points->RegisterFileSystem(
+      "test",
+      fileapi::kFileSystemTypeNativeLocal,
+      base::FilePath(FPL("/foo/test"))));
+  EXPECT_FALSE(provider.IsAccessAllowed(
+      CreateFileSystemURL(extension, "test_/foo", mount_points.get())));
+
+  provider.RevokeAccessForExtension(extension);
+  EXPECT_FALSE(provider.IsAccessAllowed(
+      CreateFileSystemURL(extension, "removable/foo", mount_points.get())));
+
+  fileapi::FileSystemURL internal_url = FileSystemURL::CreateForTest(
+      GURL("chrome://foo"),
+      fileapi::kFileSystemTypeExternal,
+      base::FilePath(FPL("removable/")));
+  // Internal WebUI should have full access.
+  EXPECT_TRUE(provider.IsAccessAllowed(internal_url));
+}
+
+TEST(CrosMountPointProvider, GetVirtualPathConflictWithSystemPoints) {
+  scoped_refptr<quota::MockSpecialStoragePolicy> storage_policy =
+      new quota::MockSpecialStoragePolicy();
+  scoped_refptr<fileapi::ExternalMountPoints> mount_points(
+      fileapi::ExternalMountPoints::CreateRefCounted());
+  scoped_refptr<fileapi::ExternalMountPoints> system_mount_points(
+      fileapi::ExternalMountPoints::CreateRefCounted());
+  chromeos::CrosMountPointProvider provider(storage_policy,
+      mount_points.get(),
+      system_mount_points.get());
+
+  const fileapi::FileSystemType type = fileapi::kFileSystemTypeNativeLocal;
+
+  // Provider specific mount points.
+  ASSERT_TRUE(
+      mount_points->RegisterFileSystem("b", type, base::FilePath(FPL("/a/b"))));
+  ASSERT_TRUE(
+      mount_points->RegisterFileSystem("y", type, base::FilePath(FPL("/z/y"))));
+  ASSERT_TRUE(
+      mount_points->RegisterFileSystem("n", type, base::FilePath(FPL("/m/n"))));
+
+  // System mount points
+  ASSERT_TRUE(system_mount_points->RegisterFileSystem(
+      "gb", type, base::FilePath(FPL("/a/b"))));
+  ASSERT_TRUE(
+      system_mount_points->RegisterFileSystem(
+          "gz", type, base::FilePath(FPL("/z"))));
+  ASSERT_TRUE(system_mount_points->RegisterFileSystem(
+       "gp", type, base::FilePath(FPL("/m/n/o/p"))));
+
+  struct TestCase {
+    const base::FilePath::CharType* const local_path;
+    bool success;
+    const base::FilePath::CharType* const virtual_path;
+  };
+
+  const TestCase kTestCases[] = {
+    // Same paths in both mount points.
+    { FPL("/a/b/c/d"), true, FPL("b/c/d") },
+    // System mount points path more specific.
+    { FPL("/m/n/o/p/r/s"), true, FPL("n/o/p/r/s") },
+    // System mount points path less specific.
+    { FPL("/z/y/x"), true, FPL("y/x") },
+    // Only system mount points path matches.
+    { FPL("/z/q/r/s"), true, FPL("gz/q/r/s") },
+    // No match.
+    { FPL("/foo/xxx"), false, FPL("") },
+  };
+
+  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTestCases); ++i) {
+    // Initialize virtual path with a value.
+    base::FilePath virtual_path(FPL("/mount"));
+    base::FilePath local_path(kTestCases[i].local_path);
+    EXPECT_EQ(kTestCases[i].success,
+              provider.GetVirtualPath(local_path, &virtual_path))
+        << "Resolving " << kTestCases[i].local_path;
+
+    // There are no guarantees for |virtual_path| value if |GetVirtualPath|
+    // fails.
+    if (!kTestCases[i].success)
+      continue;
+
+    base::FilePath expected_virtual_path(kTestCases[i].virtual_path);
+    EXPECT_EQ(expected_virtual_path, virtual_path)
+        << "Resolving " << kTestCases[i].local_path;
+  }
+}
+
+}  // namespace
diff --git a/chrome/browser/chromeos/fileapi/file_access_permissions.cc b/chrome/browser/chromeos/fileapi/file_access_permissions.cc
new file mode 100644
index 0000000..dba65b3
--- /dev/null
+++ b/chrome/browser/chromeos/fileapi/file_access_permissions.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/chromeos/fileapi/file_access_permissions.h"
+
+#include "base/command_line.h"
+#include "base/logging.h"
+
+namespace chromeos {
+
+FileAccessPermissions::FileAccessPermissions() {}
+
+FileAccessPermissions::~FileAccessPermissions() {}
+
+
+void FileAccessPermissions::GrantAccessPermission(
+    const std::string& extension_id, const base::FilePath& path) {
+  base::AutoLock locker(lock_);
+  PathAccessMap::iterator path_map_iter = path_map_.find(extension_id);
+  if (path_map_iter == path_map_.end()) {
+    PathSet path_set;
+    path_set.insert(path);
+    path_map_.insert(PathAccessMap::value_type(extension_id, path_set));
+  } else {
+    if (path_map_iter->second.find(path) != path_map_iter->second.end())
+      return;
+    path_map_iter->second.insert(path);
+  }
+}
+
+bool FileAccessPermissions::HasAccessPermission(
+    const std::string& extension_id, const base::FilePath& path) const {
+  base::AutoLock locker(lock_);
+  PathAccessMap::const_iterator path_map_iter = path_map_.find(extension_id);
+  if (path_map_iter == path_map_.end())
+    return false;
+
+  // Check this file and walk up its directory tree to find if this extension
+  // has access to it.
+  base::FilePath current_path = path.StripTrailingSeparators();
+  base::FilePath last_path;
+  while (current_path != last_path) {
+    if (path_map_iter->second.find(current_path) != path_map_iter->second.end())
+      return true;
+    last_path = current_path;
+    current_path = current_path.DirName();
+  }
+  return false;
+}
+
+void FileAccessPermissions::RevokePermissions(
+    const std::string& extension_id) {
+  base::AutoLock locker(lock_);
+  path_map_.erase(extension_id);
+}
+
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/fileapi/file_access_permissions.h b/chrome/browser/chromeos/fileapi/file_access_permissions.h
new file mode 100644
index 0000000..165ac27
--- /dev/null
+++ b/chrome/browser/chromeos/fileapi/file_access_permissions.h
@@ -0,0 +1,45 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_FILEAPI_FILE_ACCESS_PERMISSIONS_H_
+#define CHROME_BROWSER_CHROMEOS_FILEAPI_FILE_ACCESS_PERMISSIONS_H_
+
+#include <map>
+#include <set>
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/files/file_path.h"
+#include "base/synchronization/lock.h"
+#include "webkit/browser/webkit_storage_browser_export.h"
+
+namespace chromeos {
+
+class FileAccessPermissions {
+ public:
+  FileAccessPermissions();
+  virtual ~FileAccessPermissions();
+
+  // Grants |extension_id| access to |path|.
+  void GrantAccessPermission(const std::string& extension_id,
+                             const base::FilePath& path);
+  // Checks id |extension_id| has permission to access to |path|.
+  bool HasAccessPermission(const std::string& extension_id,
+                           const base::FilePath& path) const;
+  // Revokes all file permissions for |extension_id|.
+  void RevokePermissions(const std::string& extension_id);
+
+ private:
+  typedef std::set<base::FilePath> PathSet;
+  typedef std::map<std::string, PathSet> PathAccessMap;
+
+  mutable base::Lock lock_;  // Synchronize all access to path_map_.
+  PathAccessMap path_map_;
+
+  DISALLOW_COPY_AND_ASSIGN(FileAccessPermissions);
+};
+
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_CHROMEOS_FILEAPI_FILE_ACCESS_PERMISSIONS_H_
diff --git a/chrome/browser/chromeos/fileapi/file_access_permissions_unittest.cc b/chrome/browser/chromeos/fileapi/file_access_permissions_unittest.cc
new file mode 100644
index 0000000..f0f466c
--- /dev/null
+++ b/chrome/browser/chromeos/fileapi/file_access_permissions_unittest.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 "chrome/browser/chromeos/fileapi/file_access_permissions.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace chromeos {
+
+TEST(FileAccessPermissionsTest, FileAccessChecks) {
+  base::FilePath good_dir(FILE_PATH_LITERAL("/root/dir"));
+  base::FilePath bad_dir(FILE_PATH_LITERAL("/root"));
+  base::FilePath good_file(FILE_PATH_LITERAL("/root/dir/good_file.txt"));
+  base::FilePath bad_file(FILE_PATH_LITERAL("/root/dir/bad_file.txt"));
+
+  std::string extension1("ddammdhioacbehjngdmkjcjbnfginlla");
+  std::string extension2("jkhdjkhkhsdkfhsdkhrterwmtermeter");
+
+  FileAccessPermissions permissions;
+  // By default extension have no access to any local file.
+  EXPECT_FALSE(permissions.HasAccessPermission(extension1, good_dir));
+  EXPECT_FALSE(permissions.HasAccessPermission(extension1, good_file));
+  EXPECT_FALSE(permissions.HasAccessPermission(extension1, bad_file));
+  EXPECT_FALSE(permissions.HasAccessPermission(extension2, good_dir));
+  EXPECT_FALSE(permissions.HasAccessPermission(extension2, good_file));
+  EXPECT_FALSE(permissions.HasAccessPermission(extension2, bad_file));
+
+  // After granting file access to the handler extension for a given file, it
+  // can only access that file an nothing else.
+  permissions.GrantAccessPermission(extension1, good_file);
+  EXPECT_FALSE(permissions.HasAccessPermission(extension1, good_dir));
+  EXPECT_TRUE(permissions.HasAccessPermission(extension1, good_file));
+  EXPECT_FALSE(permissions.HasAccessPermission(extension1, bad_file));
+  EXPECT_FALSE(permissions.HasAccessPermission(extension2, good_dir));
+  EXPECT_FALSE(permissions.HasAccessPermission(extension2, good_file));
+  EXPECT_FALSE(permissions.HasAccessPermission(extension2, bad_file));
+
+
+  // After granting file access to the handler extension for a given directory,
+  // it can access that directory and all files within it.
+  permissions.GrantAccessPermission(extension2, good_dir);
+  EXPECT_FALSE(permissions.HasAccessPermission(extension1, good_dir));
+  EXPECT_TRUE(permissions.HasAccessPermission(extension1, good_file));
+  EXPECT_FALSE(permissions.HasAccessPermission(extension1, bad_file));
+  EXPECT_TRUE(permissions.HasAccessPermission(extension2, good_dir));
+  EXPECT_TRUE(permissions.HasAccessPermission(extension2, good_file));
+  EXPECT_TRUE(permissions.HasAccessPermission(extension2, bad_file));
+
+  // After revoking rights for extensions, they should not be able to access
+  // any file system element anymore.
+  permissions.RevokePermissions(extension1);
+  permissions.RevokePermissions(extension2);
+  EXPECT_FALSE(permissions.HasAccessPermission(extension1, good_dir));
+  EXPECT_FALSE(permissions.HasAccessPermission(extension1, good_file));
+  EXPECT_FALSE(permissions.HasAccessPermission(extension1, bad_file));
+  EXPECT_FALSE(permissions.HasAccessPermission(extension2, good_dir));
+  EXPECT_FALSE(permissions.HasAccessPermission(extension2, good_file));
+  EXPECT_FALSE(permissions.HasAccessPermission(extension2, bad_file));
+}
+
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/fileapi/remote_file_stream_writer.cc b/chrome/browser/chromeos/fileapi/remote_file_stream_writer.cc
new file mode 100644
index 0000000..5f2db47
--- /dev/null
+++ b/chrome/browser/chromeos/fileapi/remote_file_stream_writer.cc
@@ -0,0 +1,122 @@
+// 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/fileapi/remote_file_stream_writer.h"
+
+#include "net/base/io_buffer.h"
+#include "net/base/net_errors.h"
+#include "webkit/browser/blob/local_file_stream_reader.h"
+#include "webkit/browser/fileapi/local_file_stream_writer.h"
+#include "webkit/browser/fileapi/remote_file_system_proxy.h"
+#include "webkit/common/blob/shareable_file_reference.h"
+
+namespace chromeos {
+
+RemoteFileStreamWriter::RemoteFileStreamWriter(
+    const scoped_refptr<fileapi::RemoteFileSystemProxyInterface>&
+        remote_filesystem,
+    const fileapi::FileSystemURL& url,
+    int64 offset,
+    base::TaskRunner *local_task_runner)
+    : remote_filesystem_(remote_filesystem),
+      local_task_runner_(local_task_runner),
+      url_(url),
+      initial_offset_(offset),
+      has_pending_create_snapshot_(false),
+      weak_factory_(this) {
+}
+
+RemoteFileStreamWriter::~RemoteFileStreamWriter() {
+}
+
+int RemoteFileStreamWriter::Write(net::IOBuffer* buf,
+                                  int buf_len,
+                                  const net::CompletionCallback& callback) {
+  DCHECK(!has_pending_create_snapshot_);
+  DCHECK(pending_cancel_callback_.is_null());
+
+  if (!local_file_writer_) {
+    has_pending_create_snapshot_ = true;
+    // In this RemoteFileStreamWriter, we only create snapshot file and don't
+    // have explicit close operation. This is ok, because close is automatically
+    // triggered by a refcounted |file_ref_| passed to OnFileOpened, from the
+    // destructor of RemoteFileStreamWriter.
+    remote_filesystem_->CreateWritableSnapshotFile(
+        url_,
+        base::Bind(&RemoteFileStreamWriter::OnFileOpened,
+                   weak_factory_.GetWeakPtr(),
+                   make_scoped_refptr(buf),
+                   buf_len,
+                   callback));
+    return net::ERR_IO_PENDING;
+  }
+  return local_file_writer_->Write(buf, buf_len, callback);
+}
+
+void RemoteFileStreamWriter::OnFileOpened(
+    net::IOBuffer* buf,
+    int buf_len,
+    const net::CompletionCallback& callback,
+    base::PlatformFileError open_result,
+    const base::FilePath& local_path,
+    const scoped_refptr<webkit_blob::ShareableFileReference>& file_ref) {
+  has_pending_create_snapshot_ = false;
+  if (!pending_cancel_callback_.is_null()) {
+    InvokePendingCancelCallback(net::OK);
+    return;
+  }
+
+  if (open_result != base::PLATFORM_FILE_OK) {
+    callback.Run(net::PlatformFileErrorToNetError(open_result));
+    return;
+  }
+
+  // Hold the reference to the file. Releasing the reference notifies the file
+  // system about to close file.
+  file_ref_ = file_ref;
+
+  DCHECK(!local_file_writer_.get());
+  local_file_writer_.reset(new fileapi::LocalFileStreamWriter(
+      local_task_runner_, local_path, initial_offset_));
+  int result = local_file_writer_->Write(buf, buf_len, callback);
+  if (result != net::ERR_IO_PENDING)
+    callback.Run(result);
+}
+
+int RemoteFileStreamWriter::Cancel(const net::CompletionCallback& callback) {
+  DCHECK(!callback.is_null());
+  DCHECK(pending_cancel_callback_.is_null());
+
+  // If file open operation is in-flight, wait for its completion and cancel
+  // further write operation in OnFileOpened.
+  if (has_pending_create_snapshot_) {
+    pending_cancel_callback_ = callback;
+    return net::ERR_IO_PENDING;
+  }
+
+  // If LocalFileWriter is already created, just delegate the cancel to it.
+  if (local_file_writer_) {
+    pending_cancel_callback_ = callback;
+    return local_file_writer_->Cancel(
+        base::Bind(&RemoteFileStreamWriter::InvokePendingCancelCallback,
+                   weak_factory_.GetWeakPtr()));
+  }
+
+  // Write() is not called yet.
+  return net::ERR_UNEXPECTED;
+}
+
+int RemoteFileStreamWriter::Flush(const net::CompletionCallback& callback) {
+  // For remote file writer, Flush() is a no-op. Synchronization to the remote
+  // server is not done until the file is closed.
+  return net::OK;
+}
+
+void RemoteFileStreamWriter::InvokePendingCancelCallback(int result) {
+  net::CompletionCallback callback = pending_cancel_callback_;
+  pending_cancel_callback_.Reset();
+  callback.Run(result);
+}
+
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/fileapi/remote_file_stream_writer.h b/chrome/browser/chromeos/fileapi/remote_file_stream_writer.h
new file mode 100644
index 0000000..c1f3aff
--- /dev/null
+++ b/chrome/browser/chromeos/fileapi/remote_file_stream_writer.h
@@ -0,0 +1,82 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_FILEAPI_REMOTE_FILE_STREAM_WRITER_H_
+#define CHROME_BROWSER_CHROMEOS_FILEAPI_REMOTE_FILE_STREAM_WRITER_H_
+
+#include "base/basictypes.h"
+#include "base/files/file_path.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "base/platform_file.h"
+#include "webkit/browser/fileapi/file_stream_writer.h"
+#include "webkit/browser/fileapi/file_system_context.h"
+#include "webkit/browser/fileapi/file_system_url.h"
+
+namespace fileapi {
+class RemoteFileSystemProxyInterface;
+}
+
+namespace net {
+class IOBuffer;
+}
+
+namespace webkit_blob {
+class ShareableFileReference;
+}
+
+namespace chromeos {
+
+// FileStreamWriter interface for writing to a file on remote file system.
+class RemoteFileStreamWriter : public fileapi::FileStreamWriter {
+ public:
+  // Creates a writer for a file on |remote_filesystem| with path url |url|
+  // (like "filesystem:chrome-extension://id/external/drive/...") that
+  // starts writing from |offset|. When invalid parameters are set, the first
+  // call to Write() method fails.
+  // Uses |local_task_runner| for local file operations.
+  RemoteFileStreamWriter(
+      const scoped_refptr<fileapi::RemoteFileSystemProxyInterface>&
+          remote_filesystem,
+      const fileapi::FileSystemURL& url,
+      int64 offset,
+      base::TaskRunner* local_task_runner);
+  virtual ~RemoteFileStreamWriter();
+
+  // FileWriter override.
+  virtual int Write(net::IOBuffer* buf, int buf_len,
+                    const net::CompletionCallback& callback) OVERRIDE;
+  virtual int Cancel(const net::CompletionCallback& callback) OVERRIDE;
+  virtual int Flush(const net::CompletionCallback& callback) OVERRIDE;
+
+ private:
+  // Callback function to do the continuation of the work of the first Write()
+  // call, which tries to open the local copy of the file before writing.
+  void OnFileOpened(
+      net::IOBuffer* buf,
+      int buf_len,
+      const net::CompletionCallback& callback,
+      base::PlatformFileError open_result,
+      const base::FilePath& local_path,
+      const scoped_refptr<webkit_blob::ShareableFileReference>& file_ref);
+  // Calls |pending_cancel_callback_|, assuming it is non-null.
+  void InvokePendingCancelCallback(int result);
+
+  scoped_refptr<fileapi::RemoteFileSystemProxyInterface> remote_filesystem_;
+  scoped_refptr<base::TaskRunner> local_task_runner_;
+  const fileapi::FileSystemURL url_;
+  const int64 initial_offset_;
+  scoped_ptr<fileapi::FileStreamWriter> local_file_writer_;
+  scoped_refptr<webkit_blob::ShareableFileReference> file_ref_;
+  bool has_pending_create_snapshot_;
+  net::CompletionCallback pending_cancel_callback_;
+
+  base::WeakPtrFactory<RemoteFileStreamWriter> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(RemoteFileStreamWriter);
+};
+
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_CHROMEOS_FILEAPI_REMOTE_FILE_STREAM_WRITER_H_
diff --git a/chrome/browser/chromeos/fileapi/remote_file_system_operation.cc b/chrome/browser/chromeos/fileapi/remote_file_system_operation.cc
new file mode 100644
index 0000000..2a036d2
--- /dev/null
+++ b/chrome/browser/chromeos/fileapi/remote_file_system_operation.cc
@@ -0,0 +1,245 @@
+// 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/fileapi/remote_file_system_operation.h"
+
+#include "base/bind.h"
+#include "base/platform_file.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/values.h"
+#include "chrome/browser/chromeos/fileapi/remote_file_stream_writer.h"
+#include "googleurl/src/gurl.h"
+#include "net/url_request/url_request.h"
+#include "webkit/browser/fileapi/file_system_url.h"
+#include "webkit/browser/fileapi/file_writer_delegate.h"
+
+using fileapi::FileSystemURL;
+
+namespace chromeos {
+
+RemoteFileSystemOperation::RemoteFileSystemOperation(
+    scoped_refptr<fileapi::RemoteFileSystemProxyInterface> remote_proxy)
+      : remote_proxy_(remote_proxy),
+        pending_operation_(kOperationNone) {
+}
+
+RemoteFileSystemOperation::~RemoteFileSystemOperation() {
+}
+
+void RemoteFileSystemOperation::GetMetadata(const FileSystemURL& url,
+    const GetMetadataCallback& callback) {
+  DCHECK(SetPendingOperationType(kOperationGetMetadata));
+  remote_proxy_->GetFileInfo(url, callback);
+}
+
+void RemoteFileSystemOperation::DirectoryExists(const FileSystemURL& url,
+    const StatusCallback& callback) {
+  DCHECK(SetPendingOperationType(kOperationDirectoryExists));
+  remote_proxy_->GetFileInfo(url,
+      base::Bind(&RemoteFileSystemOperation::DidDirectoryExists,
+                 AsWeakPtr(), callback));
+}
+
+void RemoteFileSystemOperation::FileExists(const FileSystemURL& url,
+    const StatusCallback& callback) {
+  DCHECK(SetPendingOperationType(kOperationFileExists));
+  remote_proxy_->GetFileInfo(url,
+      base::Bind(base::Bind(&RemoteFileSystemOperation::DidFileExists,
+                            AsWeakPtr(), callback)));
+}
+
+void RemoteFileSystemOperation::ReadDirectory(const FileSystemURL& url,
+    const ReadDirectoryCallback& callback) {
+  DCHECK(SetPendingOperationType(kOperationReadDirectory));
+  remote_proxy_->ReadDirectory(url, callback);
+}
+
+void RemoteFileSystemOperation::Remove(const FileSystemURL& url, bool recursive,
+                                       const StatusCallback& callback) {
+  DCHECK(SetPendingOperationType(kOperationRemove));
+  remote_proxy_->Remove(url, recursive,
+      base::Bind(&RemoteFileSystemOperation::DidFinishFileOperation,
+                 AsWeakPtr(), callback));
+}
+
+
+void RemoteFileSystemOperation::CreateDirectory(
+    const FileSystemURL& url, bool exclusive, bool recursive,
+    const StatusCallback& callback) {
+  DCHECK(SetPendingOperationType(kOperationCreateDirectory));
+  remote_proxy_->CreateDirectory(url, exclusive, recursive,
+      base::Bind(&RemoteFileSystemOperation::DidFinishFileOperation,
+                 AsWeakPtr(), callback));
+}
+
+void RemoteFileSystemOperation::CreateFile(const FileSystemURL& url,
+                                           bool exclusive,
+                                           const StatusCallback& callback) {
+  DCHECK(SetPendingOperationType(kOperationCreateFile));
+  remote_proxy_->CreateFile(url, exclusive,
+      base::Bind(&RemoteFileSystemOperation::DidFinishFileOperation,
+                 AsWeakPtr(), callback));
+}
+
+void RemoteFileSystemOperation::Copy(const FileSystemURL& src_url,
+                                     const FileSystemURL& dest_url,
+                                     const StatusCallback& callback) {
+  DCHECK(SetPendingOperationType(kOperationCopy));
+
+  remote_proxy_->Copy(src_url, dest_url,
+      base::Bind(&RemoteFileSystemOperation::DidFinishFileOperation,
+                 AsWeakPtr(), callback));
+}
+
+void RemoteFileSystemOperation::Move(const FileSystemURL& src_url,
+                                     const FileSystemURL& dest_url,
+                                     const StatusCallback& callback) {
+  DCHECK(SetPendingOperationType(kOperationMove));
+
+  remote_proxy_->Move(src_url, dest_url,
+      base::Bind(&RemoteFileSystemOperation::DidFinishFileOperation,
+                 AsWeakPtr(), callback));
+}
+
+void RemoteFileSystemOperation::Write(
+    const FileSystemURL& url,
+    scoped_ptr<fileapi::FileWriterDelegate> writer_delegate,
+    scoped_ptr<net::URLRequest> blob_request,
+    const WriteCallback& callback) {
+  DCHECK(SetPendingOperationType(kOperationWrite));
+  file_writer_delegate_ = writer_delegate.Pass();
+  file_writer_delegate_->Start(
+      blob_request.Pass(),
+      base::Bind(&RemoteFileSystemOperation::DidWrite, AsWeakPtr(), callback));
+}
+
+void RemoteFileSystemOperation::Truncate(const FileSystemURL& url,
+                                         int64 length,
+                                         const StatusCallback& callback) {
+  DCHECK(SetPendingOperationType(kOperationTruncate));
+
+  remote_proxy_->Truncate(url, length,
+      base::Bind(&RemoteFileSystemOperation::DidFinishFileOperation,
+                 AsWeakPtr(), callback));
+}
+
+void RemoteFileSystemOperation::Cancel(const StatusCallback& cancel_callback) {
+  DCHECK(cancel_callback_.is_null());
+  cancel_callback_ = cancel_callback;
+
+  if (file_writer_delegate_) {
+    DCHECK_EQ(kOperationWrite, pending_operation_);
+    // This will call DidWrite() with ABORT status code.
+    file_writer_delegate_->Cancel();
+  } else {
+    // For truncate we have no way to cancel the inflight operation (for now).
+    // Let it just run and dispatch cancel callback later.
+    DCHECK_EQ(kOperationTruncate, pending_operation_);
+  }
+}
+
+void RemoteFileSystemOperation::TouchFile(const FileSystemURL& url,
+                                          const base::Time& last_access_time,
+                                          const base::Time& last_modified_time,
+                                          const StatusCallback& callback) {
+  DCHECK(SetPendingOperationType(kOperationTouchFile));
+  remote_proxy_->TouchFile(
+      url,
+      last_access_time,
+      last_modified_time,
+      base::Bind(&RemoteFileSystemOperation::DidFinishFileOperation,
+                 AsWeakPtr(), callback));
+}
+
+void RemoteFileSystemOperation::OpenFile(const FileSystemURL& url,
+                                         int file_flags,
+                                         base::ProcessHandle peer_handle,
+                                         const OpenFileCallback& callback) {
+  DCHECK(SetPendingOperationType(kOperationOpenFile));
+  remote_proxy_->OpenFile(
+      url,
+      file_flags,
+      peer_handle,
+      base::Bind(&RemoteFileSystemOperation::DidOpenFile,
+                 AsWeakPtr(), url, callback));
+}
+
+fileapi::LocalFileSystemOperation*
+RemoteFileSystemOperation::AsLocalFileSystemOperation() {
+  NOTIMPLEMENTED();
+  return NULL;
+}
+
+void RemoteFileSystemOperation::CreateSnapshotFile(
+    const FileSystemURL& url,
+    const SnapshotFileCallback& callback) {
+  DCHECK(SetPendingOperationType(kOperationCreateSnapshotFile));
+  remote_proxy_->CreateSnapshotFile(url, callback);
+}
+
+bool RemoteFileSystemOperation::SetPendingOperationType(OperationType type) {
+  if (pending_operation_ != kOperationNone)
+    return false;
+  pending_operation_ = type;
+  return true;
+}
+
+void RemoteFileSystemOperation::DidDirectoryExists(
+    const StatusCallback& callback,
+    base::PlatformFileError rv,
+    const base::PlatformFileInfo& file_info) {
+  if (rv == base::PLATFORM_FILE_OK && !file_info.is_directory)
+    rv = base::PLATFORM_FILE_ERROR_NOT_A_DIRECTORY;
+  callback.Run(rv);
+}
+
+void RemoteFileSystemOperation::DidFileExists(
+    const StatusCallback& callback,
+    base::PlatformFileError rv,
+    const base::PlatformFileInfo& file_info) {
+  if (rv == base::PLATFORM_FILE_OK && file_info.is_directory)
+    rv = base::PLATFORM_FILE_ERROR_NOT_A_FILE;
+  callback.Run(rv);
+}
+
+void RemoteFileSystemOperation::DidWrite(
+    const WriteCallback& write_callback,
+    base::PlatformFileError rv,
+    int64 bytes,
+    FileWriterDelegate::WriteProgressStatus write_status) {
+  bool complete = (write_status != FileWriterDelegate::SUCCESS_IO_PENDING);
+  StatusCallback cancel_callback = cancel_callback_;
+  write_callback.Run(rv, bytes, complete);
+  if (!cancel_callback.is_null())
+    cancel_callback.Run(base::PLATFORM_FILE_OK);
+}
+
+void RemoteFileSystemOperation::DidFinishFileOperation(
+    const StatusCallback& callback,
+    base::PlatformFileError rv) {
+  if (!cancel_callback_.is_null()) {
+    DCHECK_EQ(kOperationTruncate, pending_operation_);
+
+    StatusCallback cancel_callback = cancel_callback_;
+    callback.Run(base::PLATFORM_FILE_ERROR_ABORT);
+    cancel_callback.Run(base::PLATFORM_FILE_OK);
+  } else {
+    callback.Run(rv);
+  }
+}
+
+void RemoteFileSystemOperation::DidOpenFile(
+    const fileapi::FileSystemURL& url,
+    const OpenFileCallback& callback,
+    base::PlatformFileError result,
+    base::PlatformFile file,
+    base::ProcessHandle peer_handle) {
+  callback.Run(
+      result, file,
+      base::Bind(&fileapi::RemoteFileSystemProxyInterface::NotifyCloseFile,
+                 remote_proxy_, url),
+      peer_handle);
+}
+
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/fileapi/remote_file_system_operation.h b/chrome/browser/chromeos/fileapi/remote_file_system_operation.h
new file mode 100644
index 0000000..95f1142
--- /dev/null
+++ b/chrome/browser/chromeos/fileapi/remote_file_system_operation.h
@@ -0,0 +1,121 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_FILEAPI_REMOTE_FILE_SYSTEM_OPERATION_H_
+#define CHROME_BROWSER_CHROMEOS_FILEAPI_REMOTE_FILE_SYSTEM_OPERATION_H_
+
+#include "base/basictypes.h"
+#include "base/memory/weak_ptr.h"
+#include "webkit/browser/fileapi/file_system_operation.h"
+#include "webkit/browser/fileapi/file_writer_delegate.h"
+#include "webkit/browser/fileapi/remote_file_system_proxy.h"
+
+namespace base {
+class Value;
+}
+
+namespace fileapi {
+class FileWriterDelegate;
+class LocalFileSystemOperation;
+}
+
+namespace chromeos {
+
+// FileSystemOperation implementation for local file systems.
+class RemoteFileSystemOperation
+    : public fileapi::FileSystemOperation,
+      public base::SupportsWeakPtr<RemoteFileSystemOperation> {
+ public:
+  typedef fileapi::FileWriterDelegate FileWriterDelegate;
+  virtual ~RemoteFileSystemOperation();
+
+  // FileSystemOperation overrides.
+  virtual void CreateFile(const fileapi::FileSystemURL& url,
+                          bool exclusive,
+                          const StatusCallback& callback) OVERRIDE;
+  virtual void CreateDirectory(const fileapi::FileSystemURL& url,
+                               bool exclusive,
+                               bool recursive,
+                               const StatusCallback& callback) OVERRIDE;
+  virtual void Copy(const fileapi::FileSystemURL& src_url,
+                    const fileapi::FileSystemURL& dest_url,
+                    const StatusCallback& callback) OVERRIDE;
+  virtual void Move(const fileapi::FileSystemURL& src_url,
+                    const fileapi::FileSystemURL& dest_url,
+                    const StatusCallback& callback) OVERRIDE;
+  virtual void DirectoryExists(const fileapi::FileSystemURL& url,
+                               const StatusCallback& callback) OVERRIDE;
+  virtual void FileExists(const fileapi::FileSystemURL& url,
+                          const StatusCallback& callback) OVERRIDE;
+  virtual void GetMetadata(const fileapi::FileSystemURL& url,
+                           const GetMetadataCallback& callback) OVERRIDE;
+  virtual void ReadDirectory(const fileapi::FileSystemURL& url,
+                             const ReadDirectoryCallback& callback) OVERRIDE;
+  virtual void Remove(const fileapi::FileSystemURL& url, bool recursive,
+                      const StatusCallback& callback) OVERRIDE;
+  virtual void Write(const fileapi::FileSystemURL& url,
+                     scoped_ptr<fileapi::FileWriterDelegate> writer_delegate,
+                     scoped_ptr<net::URLRequest> blob_request,
+                     const WriteCallback& callback) OVERRIDE;
+  virtual void Truncate(const fileapi::FileSystemURL& url, int64 length,
+                        const StatusCallback& callback) OVERRIDE;
+  virtual void Cancel(const StatusCallback& cancel_callback) OVERRIDE;
+  virtual void TouchFile(const fileapi::FileSystemURL& url,
+                         const base::Time& last_access_time,
+                         const base::Time& last_modified_time,
+                         const StatusCallback& callback) OVERRIDE;
+  virtual void OpenFile(
+      const fileapi::FileSystemURL& url,
+      int file_flags,
+      base::ProcessHandle peer_handle,
+      const OpenFileCallback& callback) OVERRIDE;
+  virtual fileapi::LocalFileSystemOperation*
+      AsLocalFileSystemOperation() OVERRIDE;
+  virtual void CreateSnapshotFile(
+      const fileapi::FileSystemURL& url,
+      const SnapshotFileCallback& callback) OVERRIDE;
+
+ private:
+  friend class CrosMountPointProvider;
+
+  RemoteFileSystemOperation(
+      scoped_refptr<fileapi::RemoteFileSystemProxyInterface> remote_proxy);
+
+  // Used only for internal assertions.
+  // Returns false if there's another inflight pending operation.
+  bool SetPendingOperationType(OperationType type);
+
+  // Generic callback that translates platform errors to WebKit error codes.
+  void DidDirectoryExists(const StatusCallback& callback,
+                          base::PlatformFileError rv,
+                          const base::PlatformFileInfo& file_info);
+  void DidFileExists(const StatusCallback& callback,
+                     base::PlatformFileError rv,
+                     const base::PlatformFileInfo& file_info);
+  void DidWrite(const WriteCallback& write_callback,
+                base::PlatformFileError result,
+                int64 bytes,
+                FileWriterDelegate::WriteProgressStatus write_status);
+  void DidFinishFileOperation(const StatusCallback& callback,
+                              base::PlatformFileError rv);
+  void DidOpenFile(
+      const fileapi::FileSystemURL& url,
+      const OpenFileCallback& callback,
+      base::PlatformFileError result,
+      base::PlatformFile file,
+      base::ProcessHandle peer_handle);
+
+  scoped_refptr<fileapi::RemoteFileSystemProxyInterface> remote_proxy_;
+  // A flag to make sure we call operation only once per instance.
+  OperationType pending_operation_;
+  scoped_ptr<fileapi::FileWriterDelegate> file_writer_delegate_;
+
+  StatusCallback cancel_callback_;
+
+  DISALLOW_COPY_AND_ASSIGN(RemoteFileSystemOperation);
+};
+
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_CHROMEOS_FILEAPI_REMOTE_FILE_SYSTEM_OPERATION_H_
diff --git a/chrome/browser/chromeos/imageburner/burn_manager.cc b/chrome/browser/chromeos/imageburner/burn_manager.cc
index 9630131..9d3ab26 100644
--- a/chrome/browser/chromeos/imageburner/burn_manager.cc
+++ b/chrome/browser/chromeos/imageburner/burn_manager.cc
@@ -27,9 +27,6 @@
 
 namespace {
 
-// Name for hwid in machine statistics.
-const char kHwidStatistic[] = "hardware_class";
-
 const char kConfigFileUrl[] =
     "https://dl.google.com/dl/edgedl/chromeos/recovery/recovery.conf";
 const char kTempImageFolderName[] = "chromeos_image";
@@ -241,7 +238,7 @@
 
 BurnManager::~BurnManager() {
   if (image_dir_created_) {
-    file_util::Delete(image_dir_, true);
+    base::Delete(image_dir_, true);
   }
   if (NetworkHandler::IsInitialized()) {
     NetworkHandler::Get()->network_state_handler()->RemoveObserver(
@@ -559,7 +556,7 @@
   // Get image file name and image download URL.
   std::string hwid;
   if (fetched && system::StatisticsProvider::GetInstance()->
-      GetMachineStatistic(kHwidStatistic, &hwid)) {
+      GetMachineStatistic(system::kHardwareClass, &hwid)) {
     ConfigFile config_file(content);
     image_file_name_ = config_file.GetProperty(kFileName, hwid);
     image_download_url_ = GURL(config_file.GetProperty(kUrl, hwid));
diff --git a/chrome/browser/chromeos/imageburner/burn_manager.h b/chrome/browser/chromeos/imageburner/burn_manager.h
index 11cd281..b44a307 100644
--- a/chrome/browser/chromeos/imageburner/burn_manager.h
+++ b/chrome/browser/chromeos/imageburner/burn_manager.h
@@ -15,7 +15,7 @@
 #include "base/memory/ref_counted_memory.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/observer_list.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/chromeos/imageburner/burn_device_handler.h"
 #include "chromeos/disks/disk_mount_manager.h"
 #include "chromeos/network/network_state_handler_observer.h"
diff --git a/chrome/browser/chromeos/input_method/component_extension_ime_manager_impl.cc b/chrome/browser/chromeos/input_method/component_extension_ime_manager_impl.cc
index 913844d..f2c0292 100644
--- a/chrome/browser/chromeos/input_method/component_extension_ime_manager_impl.cc
+++ b/chrome/browser/chromeos/input_method/component_extension_ime_manager_impl.cc
@@ -26,6 +26,16 @@
   const char* id;
   const char* path;
 } whitelisted_component_extension[] = {
+  {
+    // ChromeOS Keyboards extension.
+    "jhffeifommiaekmbkkjlpmilogcfdohp",
+    "/usr/share/chromeos-assets/input_methods/keyboard_layouts",
+  },
+  {
+    // ChromeOS Hangul Input.
+    "bdgdidmhaijohebebipajioienkglgfo",
+    "/usr/share/chromeos-assets/input_methods/hangul",
+  },
 #if defined(OFFICIAL_BUILD)
   {
     // Official Google Japanese Input.
@@ -53,17 +63,27 @@
     "/usr/share/chromeos-assets/input_methods/wubi",
   },
   {
-    // Chromeos Keyboard Layouts.
-    "jhffeifommiaekmbkkjlpmilogcfdohp",
-    "/usr/share/chromeos-assets/input_methods/keyboard_layouts",
-  },
-  {
     // Google input tools.
     "gjaehgfemfahhmlgpdfknkhdnemmolop",
     "/usr/share/chromeos-assets/input_methods/input_tools",
   },
 #else
   {
+    // Open-sourced Pinyin Chinese Input Method.
+    "cpgalbafkoofkjmaeonnfijgpfennjjn",
+    "/usr/share/chromeos-assets/input_methods/pinyin",
+  },
+  {
+    // Open-sourced Zhuyin Chinese Input Method.
+    "ekbifjdfhkmdeeajnolmgdlmkllopefi",
+    "/usr/share/chromeos-assets/input_methods/zhuyin",
+  },
+  {
+    // Open-sourced Cangjie Chinese Input Method.
+    "aeebooiibjahgpgmhkeocbeekccfknbj",
+    "/usr/share/chromeos-assets/input_methods/cangjie",
+  },
+  {
     // Open-sourced Mozc Japanese Input.
     "bbaiamgfapehflhememkfglaehiobjnk",
     "/usr/share/chromeos-assets/input_methods/nacl_mozc",
diff --git a/chrome/browser/chromeos/input_method/delayable_widget.h b/chrome/browser/chromeos/input_method/delayable_widget.h
index aa18ff2..8b4846c 100644
--- a/chrome/browser/chromeos/input_method/delayable_widget.h
+++ b/chrome/browser/chromeos/input_method/delayable_widget.h
@@ -5,7 +5,7 @@
 #ifndef CHROME_BROWSER_CHROMEOS_INPUT_METHOD_DELAYABLE_WIDGET_H_
 #define CHROME_BROWSER_CHROMEOS_INPUT_METHOD_DELAYABLE_WIDGET_H_
 
-#include "base/timer.h"
+#include "base/timer/timer.h"
 #include "ui/views/widget/widget.h"
 
 namespace chromeos {
diff --git a/chrome/browser/chromeos/input_method/input_method_engine_ibus.cc b/chrome/browser/chromeos/input_method/input_method_engine_ibus.cc
index a7b5056..25c9d4e 100644
--- a/chrome/browser/chromeos/input_method/input_method_engine_ibus.cc
+++ b/chrome/browser/chromeos/input_method/input_method_engine_ibus.cc
@@ -201,7 +201,7 @@
   GetCurrentService()->UpdatePreedit(
       *preedit_text_.get(),
       0,
-      true,
+      false,
       chromeos::IBusEngineService::IBUS_ENGINE_PREEEDIT_FOCUS_OUT_MODE_COMMIT);
   return true;
 }
diff --git a/chrome/browser/chromeos/input_method/input_method_engine_ibus_browserttests.cc b/chrome/browser/chromeos/input_method/input_method_engine_ibus_browserttests.cc
index 92fbe75..cda8462 100644
--- a/chrome/browser/chromeos/input_method/input_method_engine_ibus_browserttests.cc
+++ b/chrome/browser/chromeos/input_method/input_method_engine_ibus_browserttests.cc
@@ -5,6 +5,7 @@
 #include "base/bind_helpers.h"
 #include "chrome/browser/extensions/extension_browsertest.h"
 #include "chrome/browser/extensions/extension_test_message_listener.h"
+#include "chrome/common/extensions/background_info.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/ibus/mock_ibus_client.h"
 #include "chromeos/dbus/ibus/mock_ibus_engine_factory_service.h"
@@ -12,6 +13,7 @@
 #include "chromeos/dbus/mock_dbus_thread_manager_without_gmock.h"
 #include "chromeos/ime/input_method_descriptor.h"
 #include "chromeos/ime/input_method_manager.h"
+#include "content/public/test/browser_test_utils.h"
 #include "content/public/test/test_utils.h"
 #include "dbus/mock_bus.h"
 
@@ -62,6 +64,7 @@
 
   virtual void TearDownInProcessBrowserTestFixture() OVERRIDE {
     DBusThreadManager::Shutdown();
+    extension_ = NULL;
   }
 
  protected:
@@ -73,7 +76,8 @@
     // This will load "chrome/test/data/extensions/input_ime"
     ExtensionTestMessageListener ime_ready_listener("ReadyToUseImeEvent",
                                                     false);
-    ASSERT_TRUE(LoadExtensionWithType("input_ime", GetParam()));
+    extension_ = LoadExtensionWithType("input_ime", GetParam());
+    ASSERT_TRUE(extension_);
     ASSERT_TRUE(ime_ready_listener.WaitUntilSatisfied());
 
     // The reason why not EXPECT_EQ is that extension will be reloaded in the
@@ -103,8 +107,8 @@
     EXPECT_EQ(3U, extension_imes.size());
   }
 
-  bool LoadExtensionWithType(const std::string& extension_name,
-                             TestType type) {
+  const extensions::Extension* LoadExtensionWithType(
+      const std::string& extension_name, TestType type) {
     switch (type) {
       case kTestTypeNormal:
         return LoadExtension(test_data_dir_.AppendASCII(extension_name));
@@ -116,9 +120,10 @@
             test_data_dir_.AppendASCII(extension_name));
     }
     NOTREACHED();
-    return false;
+    return NULL;
   }
 
+  const extensions::Extension* extension_;
   MockDBusThreadManagerWithoutGMock* mock_dbus_thread_manager_;
   scoped_refptr<dbus::MockBus> mock_bus_;
 };
@@ -244,6 +249,11 @@
   IBusEngineHandlerInterface* engine_handler = engine_service->GetEngine();
   ASSERT_TRUE(engine_handler);
 
+  extensions::ExtensionHost* host = FindHostWithPath(
+      extensions::ExtensionSystem::Get(profile())->process_manager(),
+      extensions::BackgroundInfo::GetBackgroundURL(extension_).path(),
+      1);
+
   engine_handler->Enable();
   engine_handler->FocusIn();
 
@@ -360,6 +370,377 @@
     callback.WaitUntilCalled();
   }
   // TODO(nona): Add browser tests for other API as well.
+  {
+    SCOPED_TRACE("commitText test");
+    const char commit_text_test_script[] =
+        "chrome.input.ime.commitText({"
+        "  contextID: engineBridge.getFocusedContextID().contextID,"
+        "  text:'COMMIT_TEXT'"
+        "});";
+
+    engine_service->Clear();
+    ASSERT_TRUE(content::ExecuteScript(host->host_contents(),
+                                       commit_text_test_script));
+    EXPECT_EQ(1, engine_service->commit_text_call_count());
+    EXPECT_EQ("COMMIT_TEXT", engine_service->last_commit_text());
+  }
+  {
+    SCOPED_TRACE("setComposition test");
+    const char set_composition_test_script[] =
+        "chrome.input.ime.setComposition({"
+        "  contextID: engineBridge.getFocusedContextID().contextID,"
+        "  text:'COMPOSITION_TEXT',"
+        "  cursor:4,"
+        "  segments : [{"
+        "    start: 0,"
+        "    end: 5,"
+        "    style: 'underline'"
+        "  },{"
+        "    start: 6,"
+        "    end: 10,"
+        "    style: 'doubleUnderline'"
+        "  }]"
+        "});";
+
+    engine_service->Clear();
+    ASSERT_TRUE(content::ExecuteScript(host->host_contents(),
+                                       set_composition_test_script));
+    EXPECT_EQ(1, engine_service->update_preedit_call_count());
+
+    EXPECT_EQ(4U, engine_service->last_update_preedit_arg().cursor_pos);
+    EXPECT_TRUE(engine_service->last_update_preedit_arg().is_visible);
+
+    const IBusText& ibus_text =
+        engine_service->last_update_preedit_arg().ibus_text;
+    EXPECT_EQ("COMPOSITION_TEXT", ibus_text.text());
+    const std::vector<IBusText::UnderlineAttribute>& underlines =
+        ibus_text.underline_attributes();
+
+    ASSERT_EQ(2U, underlines.size());
+    EXPECT_EQ(IBusText::IBUS_TEXT_UNDERLINE_SINGLE, underlines[0].type);
+    EXPECT_EQ(0U, underlines[0].start_index);
+    EXPECT_EQ(5U, underlines[0].end_index);
+
+    EXPECT_EQ(IBusText::IBUS_TEXT_UNDERLINE_DOUBLE, underlines[1].type);
+    EXPECT_EQ(6U, underlines[1].start_index);
+    EXPECT_EQ(10U, underlines[1].end_index);
+  }
+  {
+    SCOPED_TRACE("clearComposition test");
+    const char commite_text_test_script[] =
+        "chrome.input.ime.clearComposition({"
+        "  contextID: engineBridge.getFocusedContextID().contextID,"
+        "});";
+
+    engine_service->Clear();
+    ASSERT_TRUE(content::ExecuteScript(host->host_contents(),
+                                       commite_text_test_script));
+    EXPECT_EQ(1, engine_service->update_preedit_call_count());
+    EXPECT_FALSE(engine_service->last_update_preedit_arg().is_visible);
+    const IBusText& ibus_text =
+        engine_service->last_update_preedit_arg().ibus_text;
+    EXPECT_TRUE(ibus_text.text().empty());
+  }
+  {
+    SCOPED_TRACE("setCandidateWindowProperties:visibility test");
+    const char set_candidate_window_properties_test_script[] =
+        "chrome.input.ime.setCandidateWindowProperties({"
+        "  engineID: engineBridge.getActiveEngineID(),"
+        "  properties: {"
+        "    visible: true,"
+        "  }"
+        "});";
+    engine_service->Clear();
+    ASSERT_TRUE(content::ExecuteScript(
+        host->host_contents(),
+        set_candidate_window_properties_test_script));
+    EXPECT_EQ(1, engine_service->update_lookup_table_call_count());
+    EXPECT_TRUE(engine_service->last_update_lookup_table_arg().is_visible);
+  }
+  {
+    SCOPED_TRACE("setCandidateWindowProperties:cursor_visibility test");
+    const char set_candidate_window_properties_test_script[] =
+        "chrome.input.ime.setCandidateWindowProperties({"
+        "  engineID: engineBridge.getActiveEngineID(),"
+        "  properties: {"
+        "    cursorVisible: true,"
+        "  }"
+        "});";
+    engine_service->Clear();
+    ASSERT_TRUE(content::ExecuteScript(
+        host->host_contents(),
+        set_candidate_window_properties_test_script));
+    EXPECT_EQ(1, engine_service->update_lookup_table_call_count());
+
+    // window visibility is kept as before.
+    EXPECT_TRUE(engine_service->last_update_lookup_table_arg().is_visible);
+
+    const IBusLookupTable& table =
+        engine_service->last_update_lookup_table_arg().lookup_table;
+    EXPECT_TRUE(table.is_cursor_visible());
+  }
+  {
+    SCOPED_TRACE("setCandidateWindowProperties:vertical test");
+    const char set_candidate_window_properties_test_script[] =
+        "chrome.input.ime.setCandidateWindowProperties({"
+        "  engineID: engineBridge.getActiveEngineID(),"
+        "  properties: {"
+        "    vertical: true,"
+        "  }"
+        "});";
+    engine_service->Clear();
+    ASSERT_TRUE(content::ExecuteScript(
+        host->host_contents(),
+        set_candidate_window_properties_test_script));
+    EXPECT_EQ(1, engine_service->update_lookup_table_call_count());
+
+    // window visibility is kept as before.
+    EXPECT_TRUE(engine_service->last_update_lookup_table_arg().is_visible);
+
+    const IBusLookupTable& table =
+        engine_service->last_update_lookup_table_arg().lookup_table;
+
+    // cursor visibility is kept as before.
+    EXPECT_TRUE(table.is_cursor_visible());
+
+    EXPECT_EQ(IBusLookupTable::VERTICAL, table.orientation());
+  }
+  {
+    SCOPED_TRACE("setCandidateWindowProperties:pageSize test");
+    const char set_candidate_window_properties_test_script[] =
+        "chrome.input.ime.setCandidateWindowProperties({"
+        "  engineID: engineBridge.getActiveEngineID(),"
+        "  properties: {"
+        "    pageSize: 7,"
+        "  }"
+        "});";
+    engine_service->Clear();
+    ASSERT_TRUE(content::ExecuteScript(
+        host->host_contents(),
+        set_candidate_window_properties_test_script));
+    EXPECT_EQ(1, engine_service->update_lookup_table_call_count());
+
+    // window visibility is kept as before.
+    EXPECT_TRUE(engine_service->last_update_lookup_table_arg().is_visible);
+
+    const IBusLookupTable& table =
+        engine_service->last_update_lookup_table_arg().lookup_table;
+
+    // cursor visibility is kept as before.
+    EXPECT_TRUE(table.is_cursor_visible());
+
+    // oritantation is kept as before.
+    EXPECT_EQ(IBusLookupTable::VERTICAL, table.orientation());
+
+    EXPECT_EQ(7U, table.page_size());
+  }
+  {
+    SCOPED_TRACE("setCandidateWindowProperties:auxTextVisibility test");
+    const char set_candidate_window_properties_test_script[] =
+        "chrome.input.ime.setCandidateWindowProperties({"
+        "  engineID: engineBridge.getActiveEngineID(),"
+        "  properties: {"
+        "    auxiliaryTextVisible: true"
+        "  }"
+        "});";
+    engine_service->Clear();
+    ASSERT_TRUE(content::ExecuteScript(
+        host->host_contents(),
+        set_candidate_window_properties_test_script));
+    EXPECT_EQ(1, engine_service->update_auxiliary_text_call_count());
+    EXPECT_TRUE(engine_service->last_update_aux_text_arg().is_visible);
+  }
+  {
+    SCOPED_TRACE("setCandidateWindowProperties:auxText test");
+    const char set_candidate_window_properties_test_script[] =
+        "chrome.input.ime.setCandidateWindowProperties({"
+        "  engineID: engineBridge.getActiveEngineID(),"
+        "  properties: {"
+        "    auxiliaryText: 'AUXILIARY_TEXT'"
+        "  }"
+        "});";
+    engine_service->Clear();
+    ASSERT_TRUE(content::ExecuteScript(
+        host->host_contents(),
+        set_candidate_window_properties_test_script));
+    EXPECT_EQ(1, engine_service->update_auxiliary_text_call_count());
+
+    // aux text visibility is kept as before.
+    EXPECT_TRUE(engine_service->last_update_aux_text_arg().is_visible);
+
+    EXPECT_EQ("AUXILIARY_TEXT",
+              engine_service->last_update_aux_text_arg().ibus_text.text());
+  }
+  {
+    SCOPED_TRACE("setCandidates test");
+    const char set_candidates_test_script[] =
+        "chrome.input.ime.setCandidates({"
+        "  contextID: engineBridge.getFocusedContextID().contextID,"
+        "  candidates: [{"
+        "    candidate: 'CANDIDATE_1',"
+        "    id: 1,"
+        "    },{"
+        "    candidate: 'CANDIDATE_2',"
+        "    id: 2,"
+        "    label: 'LABEL_2',"
+        "    },{"
+        "    candidate: 'CANDIDATE_3',"
+        "    id: 3,"
+        "    label: 'LABEL_3',"
+        "    annotation: 'ANNOTACTION_3'"
+        "    },{"
+        "    candidate: 'CANDIDATE_4',"
+        "    id: 4,"
+        "    label: 'LABEL_4',"
+        "    annotation: 'ANNOTACTION_4',"
+        "    usage: {"
+        "      title: 'TITLE_4',"
+        "      body: 'BODY_4'"
+        "    }"
+        "  }]"
+        "});";
+    engine_service->Clear();
+    ASSERT_TRUE(content::ExecuteScript(host->host_contents(),
+                                       set_candidates_test_script));
+
+    // window visibility is kept as before.
+    EXPECT_TRUE(engine_service->last_update_lookup_table_arg().is_visible);
+
+    const IBusLookupTable& table =
+        engine_service->last_update_lookup_table_arg().lookup_table;
+
+    // cursor visibility is kept as before.
+    EXPECT_TRUE(table.is_cursor_visible());
+
+    // oritantation is kept as before.
+    EXPECT_EQ(IBusLookupTable::VERTICAL, table.orientation());
+
+    // page size is kept as before.
+    EXPECT_EQ(7U, table.page_size());
+
+    ASSERT_EQ(4U, table.candidates().size());
+
+    EXPECT_EQ("CANDIDATE_1", table.candidates().at(0).value);
+
+    EXPECT_EQ("CANDIDATE_2", table.candidates().at(1).value);
+    EXPECT_EQ("LABEL_2", table.candidates().at(1).label);
+
+    EXPECT_EQ("CANDIDATE_3", table.candidates().at(2).value);
+    EXPECT_EQ("LABEL_3", table.candidates().at(2).label);
+    EXPECT_EQ("ANNOTACTION_3", table.candidates().at(2).annotation);
+
+    EXPECT_EQ("CANDIDATE_4", table.candidates().at(3).value);
+    EXPECT_EQ("LABEL_4", table.candidates().at(3).label);
+    EXPECT_EQ("ANNOTACTION_4", table.candidates().at(3).annotation);
+    EXPECT_EQ("TITLE_4", table.candidates().at(3).description_title);
+    EXPECT_EQ("BODY_4", table.candidates().at(3).description_body);
+  }
+  {
+    SCOPED_TRACE("setCursorPosition test");
+    const char set_cursor_position_test_script[] =
+        "chrome.input.ime.setCursorPosition({"
+        "  contextID: engineBridge.getFocusedContextID().contextID,"
+        "  candidateID: 2"
+        "});";
+    engine_service->Clear();
+    ASSERT_TRUE(content::ExecuteScript(
+        host->host_contents(), set_cursor_position_test_script));
+    EXPECT_EQ(1, engine_service->update_lookup_table_call_count());
+
+    // window visibility is kept as before.
+    EXPECT_TRUE(engine_service->last_update_lookup_table_arg().is_visible);
+
+    const IBusLookupTable& table =
+        engine_service->last_update_lookup_table_arg().lookup_table;
+
+    // cursor visibility is kept as before.
+    EXPECT_TRUE(table.is_cursor_visible());
+
+    // oritantation is kept as before.
+    EXPECT_EQ(IBusLookupTable::VERTICAL, table.orientation());
+
+    // page size is kept as before.
+    EXPECT_EQ(7U, table.page_size());
+
+    // candidates are same as before.
+    ASSERT_EQ(4U, table.candidates().size());
+
+    // Candidate ID == 2 is 1 in index.
+    EXPECT_EQ(1U, table.cursor_position());
+  }
+  {
+    SCOPED_TRACE("setMenuItem test");
+    const char set_menu_item_test_script[] =
+        "chrome.input.ime.setMenuItems({"
+        "  engineID: engineBridge.getActiveEngineID(),"
+        "  items: [{"
+        "    id: 'ID0',"
+        "  },{"
+        "    id: 'ID1',"
+        "    label: 'LABEL1',"
+        "  },{"
+        "    id: 'ID2',"
+        "    label: 'LABEL2',"
+        "    style: 'radio',"
+        "  },{"
+        "    id: 'ID3',"
+        "    label: 'LABEL3',"
+        "    style: 'check',"
+        "    visible: true,"
+        "  },{"
+        "    id: 'ID4',"
+        "    label: 'LABEL4',"
+        "    style: 'separator',"
+        "    visible: true,"
+        "    checked: true"
+        "  }]"
+        "});";
+    engine_service->Clear();
+    ASSERT_TRUE(content::ExecuteScript(
+        host->host_contents(), set_menu_item_test_script));
+    EXPECT_EQ(1, engine_service->register_properties_call_count());
+
+    const IBusPropertyList& props =
+        engine_service->last_registered_properties();
+    ASSERT_EQ(5U, props.size());
+
+    EXPECT_EQ("ID0", props[0]->key());
+    EXPECT_EQ("ID1", props[1]->key());
+    EXPECT_EQ("ID2", props[2]->key());
+    EXPECT_EQ("ID3", props[3]->key());
+    EXPECT_EQ("ID4", props[4]->key());
+
+    EXPECT_EQ("LABEL1", props[1]->label());
+    EXPECT_EQ("LABEL2", props[2]->label());
+    EXPECT_EQ("LABEL3", props[3]->label());
+    EXPECT_EQ("LABEL4", props[4]->label());
+
+    EXPECT_EQ(IBusProperty::IBUS_PROPERTY_TYPE_RADIO, props[2]->type());
+    EXPECT_EQ(IBusProperty::IBUS_PROPERTY_TYPE_TOGGLE, props[3]->type());
+    EXPECT_EQ(IBusProperty::IBUS_PROPERTY_TYPE_SEPARATOR, props[4]->type());
+
+    EXPECT_TRUE(props[3]->visible());
+    EXPECT_TRUE(props[4]->visible());
+
+    EXPECT_TRUE(props[4]->checked());
+  }
+  {
+    SCOPED_TRACE("deleteSurroundingText test");
+    const char delete_surrounding_text_test_script[] =
+        "chrome.input.ime.deleteSurroundingText({"
+        "  engineID: engineBridge.getActiveEngineID(),"
+        "  contextID: engineBridge.getFocusedContextID().contextID,"
+        "  offset: 5,"
+        "  length: 3"
+        "});";
+    engine_service->Clear();
+    ASSERT_TRUE(content::ExecuteScript(
+        host->host_contents(), delete_surrounding_text_test_script));
+
+    EXPECT_EQ(1, engine_service->delete_surrounding_text_call_count());
+    EXPECT_EQ(5, engine_service->last_delete_surrounding_text_arg().offset);
+    EXPECT_EQ(3U, engine_service->last_delete_surrounding_text_arg().length);
+  }
 }
 
 }  // namespace
diff --git a/chrome/browser/chromeos/input_method/input_method_manager_impl.cc b/chrome/browser/chromeos/input_method/input_method_manager_impl.cc
index f2c5d8d..4f21a46 100644
--- a/chrome/browser/chromeos/input_method/input_method_manager_impl.cc
+++ b/chrome/browser/chromeos/input_method/input_method_manager_impl.cc
@@ -49,6 +49,63 @@
   { "mozc", "_comp_ime_fpfbhcjppmaeaijcidgiibchfbnhbeljnacl_mozc_us" },
   { "mozc-jp", "_comp_ime_fpfbhcjppmaeaijcidgiibchfbnhbeljnacl_mozc_jp" },
   { "mozc-dv", "_comp_ime_fpfbhcjppmaeaijcidgiibchfbnhbeljnacl_mozc_us" },
+  { "pinyin", "_comp_ime_nmblnjkfdkabgdofidlkienfnnbjhnabzh-t-i0-pinyin" },
+  { "pinyin-dv", "_comp_ime_nmblnjkfdkabgdofidlkienfnnbjhnabzh-t-i0-pinyin" },
+  { "mozc-chewing",
+    "_comp_ime_ekbifjdfhkmdeeajnolmgdlmkllopefizh-hant-t-i0-und "},
+  { "m17n:zh:cangjie",
+    "_comp_ime_gjhclobljhjhgoebiipblnmdodbmpdgdzh-hant-t-i0-cangjie-1987" },
+  // TODO(nona): Remove following migration map in M31.
+  { "m17n:ta:itrans",
+    "_comp_ime_jhffeifommiaekmbkkjlpmilogcfdohpvkd_ta_itrans" },
+  { "m17n:ta:tamil99",
+    "_comp_ime_jhffeifommiaekmbkkjlpmilogcfdohpvkd_ta_tamil99" },
+  { "m17n:ta:typewriter",
+    "_comp_ime_jhffeifommiaekmbkkjlpmilogcfdohpvkd_ta_typewriter" },
+  { "m17n:ta:inscript",
+    "_comp_ime_jhffeifommiaekmbkkjlpmilogcfdohpvkd_ta_phone" },
+  { "m17n:ta:phonetic",
+    "_comp_ime_jhffeifommiaekmbkkjlpmilogcfdohpvkd_ta_inscript" },
+  { "m17n:th:pattachote",
+    "_comp_ime_jhffeifommiaekmbkkjlpmilogcfdohpvkd_th_pattajoti" },
+  { "m17n:th:tis820", "_comp_ime_jhffeifommiaekmbkkjlpmilogcfdohpvkd_th_tis" },
+  { "m17n:th:kesmanee",
+    "_comp_ime_jhffeifommiaekmbkkjlpmilogcfdohpvkd_th" },
+  { "m17n:vi:tcvn", "_comp_ime_jhffeifommiaekmbkkjlpmilogcfdohpvkd_vi_tcvn" },
+  { "m17n:vi:viqr", "_comp_ime_jhffeifommiaekmbkkjlpmilogcfdohpvkd_vi_viqr" },
+  { "m17n:vi:telex",
+    "_comp_ime_jhffeifommiaekmbkkjlpmilogcfdohpvkd_vi_telex" },
+  { "m17n:am:sera",
+    "_comp_ime_jhffeifommiaekmbkkjlpmilogcfdohpvkd_ethi" },
+  { "m17n:bn:itrans",
+    "_comp_ime_jhffeifommiaekmbkkjlpmilogcfdohpvkd_bn_phone" },
+  { "m17n:gu:itrans",
+    "_comp_ime_jhffeifommiaekmbkkjlpmilogcfdohpvkd_gu_phone" },
+  { "m17n:hi:itrans",
+    "_comp_ime_jhffeifommiaekmbkkjlpmilogcfdohpvkd_deva_phone" },
+  { "m17n:kn:itrans",
+    "_comp_ime_jhffeifommiaekmbkkjlpmilogcfdohpvkd_kn_phone" },
+  { "m17n:ml:itrans",
+    "_comp_ime_jhffeifommiaekmbkkjlpmilogcfdohpvkd_ml_phone" },
+  { "m17n:mr:itrans",
+    "_comp_ime_jhffeifommiaekmbkkjlpmilogcfdohpvkd_deva_phone-" },
+  { "m17n:te:itrans",
+    "_comp_ime_jhffeifommiaekmbkkjlpmilogcfdohpvkd_te_phone" },
+  { "m17n:fa:isiri", "_comp_ime_jhffeifommiaekmbkkjlpmilogcfdohpvkd_fa" },
+  // TODO(nona): Remove following migration map in M32
+  { "m17n:zh:quick",
+    "_comp_ime_ekbifjdfhkmdeeajnolmgdlmkllopefizh-hant-t-i0-und" },
+};
+
+const struct MigrationHangulKeyboardToInputMethodID {
+  const char* keyboard_id;
+  const char* ime_id;
+} kMigrationHangulKeyboardToInputMethodID[] = {
+  { "2", "_comp_ime_bdgdidmhaijohebebipajioienkglgfohangul_2set" },
+  { "3f", "_comp_ime_bdgdidmhaijohebebipajioienkglgfohangul_3setfinal" },
+  { "39", "_comp_ime_bdgdidmhaijohebebipajioienkglgfohangul_3set390" },
+  { "3s", "_comp_ime_bdgdidmhaijohebebipajioienkglgfohangul_3setnoshift" },
+  { "ro", "_comp_ime_bdgdidmhaijohebebipajioienkglgfohangul_romaja" },
 };
 
 }  // namespace
@@ -261,6 +318,28 @@
   return rewritten;
 }
 
+bool InputMethodManagerImpl::MigrateKoreanKeyboard(
+    const std::string& keyboard_id,
+    std::vector<std::string>* input_method_ids) {
+  std::vector<std::string>::iterator it =
+      std::find(active_input_method_ids_.begin(),
+                active_input_method_ids_.end(),
+                "mozc-hangul");
+  if (it == active_input_method_ids_.end())
+    return false;
+
+  for (size_t i = 0;
+       i < ARRAYSIZE_UNSAFE(kMigrationHangulKeyboardToInputMethodID); ++i) {
+    if (kMigrationHangulKeyboardToInputMethodID[i].keyboard_id == keyboard_id) {
+      *it = kMigrationHangulKeyboardToInputMethodID[i].ime_id;
+      input_method_ids->assign(active_input_method_ids_.begin(),
+                               active_input_method_ids_.end());
+      return true;
+    }
+  }
+  return false;
+}
+
 bool InputMethodManagerImpl::SetInputMethodConfig(
     const std::string& section,
     const std::string& config_name,
@@ -270,6 +349,7 @@
 
   if (state_ == STATE_TERMINATING)
     return false;
+
   return ibus_controller_->SetInputMethodConfig(section, config_name, value);
 }
 
@@ -634,10 +714,6 @@
       input_method_ids_to_switch.push_back(nacl_mozc_jp_id);
       input_method_ids_to_switch.push_back("xkb:jp::jpn");
       break;
-    case ui::VKEY_HANGUL:  // Hangul (or right Alt) key on Korean keyboard
-      input_method_ids_to_switch.push_back("mozc-hangul");
-      input_method_ids_to_switch.push_back("xkb:kr:kr104:kor");
-      break;
     default:
       NOTREACHED();
       break;
diff --git a/chrome/browser/chromeos/input_method/input_method_manager_impl.h b/chrome/browser/chromeos/input_method/input_method_manager_impl.h
index c585b46..521e04a 100644
--- a/chrome/browser/chromeos/input_method/input_method_manager_impl.h
+++ b/chrome/browser/chromeos/input_method/input_method_manager_impl.h
@@ -65,6 +65,9 @@
       const std::vector<std::string>& new_active_input_method_ids) OVERRIDE;
   virtual bool MigrateOldInputMethods(
       std::vector<std::string>* input_method_ids) OVERRIDE;
+  virtual bool MigrateKoreanKeyboard(
+      const std::string& keyboard_id,
+      std::vector<std::string>* input_method_ids) OVERRIDE;
   virtual bool SetInputMethodConfig(
       const std::string& section,
       const std::string& config_name,
diff --git a/chrome/browser/chromeos/input_method/input_method_manager_impl_unittest.cc b/chrome/browser/chromeos/input_method/input_method_manager_impl_unittest.cc
index f08cbf9..29c35f9 100644
--- a/chrome/browser/chromeos/input_method/input_method_manager_impl_unittest.cc
+++ b/chrome/browser/chromeos/input_method/input_method_manager_impl_unittest.cc
@@ -98,7 +98,7 @@
     ime_list_.push_back(ext1);
 
     ComponentExtensionIME ext2;
-    ext2.id = "ext2_id";
+    ext2.id = "nmblnjkfdkabgdofidlkienfnnbjhnab";
     ext2.description = "ext2_description";
     ext2.path = base::FilePath("ext2_file_path");
 
@@ -109,6 +109,13 @@
     ext2_engine1.layouts.push_back("us");
     ext2.engines.push_back(ext2_engine1);
 
+    ComponentExtensionEngine ext2_engine2;
+    ext2_engine2.engine_id = "ext2_engine2_engine_id";
+    ext2_engine2.display_name = "ext2_engine_2_display_name";
+    ext2_engine2.language_code = "en";
+    ext2_engine2.layouts.push_back("us(dvorak)");
+    ext2.engines.push_back(ext2_engine2);
+
     ime_list_.push_back(ext2);
 
     mock_ibus_daemon_controller_->EmulateConnect();
@@ -271,6 +278,8 @@
 }
 
 TEST_F(InputMethodManagerImplTest, TestGetSupportedInputMethods) {
+  InitComponentExtension();
+  InitIBusBus();
   scoped_ptr<InputMethodDescriptors> methods(
       manager_->GetSupportedInputMethods());
   ASSERT_TRUE(methods.get());
@@ -280,9 +289,6 @@
       manager_->GetInputMethodUtil()->GetInputMethodDescriptorFromId(
           nacl_mozc_us_id);
   id_to_find = manager_->GetInputMethodUtil()->GetInputMethodDescriptorFromId(
-      "mozc-chewing");
-  EXPECT_TRUE(Contain(*methods.get(), *id_to_find));
-  id_to_find = manager_->GetInputMethodUtil()->GetInputMethodDescriptorFromId(
       "xkb:us::eng");
   EXPECT_TRUE(Contain(*methods.get(), *id_to_find));
   id_to_find = manager_->GetInputMethodUtil()->GetInputMethodDescriptorFromId(
@@ -332,7 +338,7 @@
 }
 
 TEST_F(InputMethodManagerImplTest, TestActiveInputMethods) {
-  manager_->EnableLayouts("ko", "");  // Korean
+  manager_->EnableLayouts("ja", "");  // Japanese
   EXPECT_EQ(2U, manager_->GetNumActiveInputMethods());
   scoped_ptr<InputMethodDescriptors> methods(
       manager_->GetActiveInputMethods());
@@ -343,7 +349,7 @@
           "xkb:us::eng");
   EXPECT_TRUE(Contain(*methods.get(), *id_to_find));
   id_to_find = manager_->GetInputMethodUtil()->GetInputMethodDescriptorFromId(
-      "xkb:kr:kr104:kor");
+      "xkb:jp::jpn");
   EXPECT_TRUE(Contain(*methods.get(), *id_to_find));
 }
 
@@ -499,7 +505,7 @@
   InitIBusBus();
   manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
   std::vector<std::string> ids;
-  ids.push_back("mozc-chewing");
+  ids.push_back("_comp_ime_nmblnjkfdkabgdofidlkienfnnbjhnabext2_engine1_engine_id");
   ids.push_back("mozc-dv");
   EXPECT_TRUE(manager_->EnableInputMethods(ids));
   EXPECT_EQ(1, mock_ibus_daemon_controller_->start_count());
@@ -567,7 +573,7 @@
   manager_->RemoveObserver(&observer);
 }
 
-TEST_F(InputMethodManagerImplTest, TestEnableLayoutAndImeThenLock) {
+TEST_F(InputMethodManagerImplTest, SwithchInputMethodTest) {
   // For http://crbug.com/19655#c11 - (15).
   TestObserver observer;
   manager_->AddObserver(&observer);
@@ -576,8 +582,8 @@
   manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
   std::vector<std::string> ids;
   ids.push_back("xkb:us:dvorak:eng");
-  ids.push_back("pinyin-dv");
-  ids.push_back("mozc-chewing");
+  ids.push_back("_comp_ime_nmblnjkfdkabgdofidlkienfnnbjhnabext2_engine2_engine_id");
+  ids.push_back("_comp_ime_nmblnjkfdkabgdofidlkienfnnbjhnabext2_engine1_engine_id");
   EXPECT_TRUE(manager_->EnableInputMethods(ids));
   EXPECT_EQ(3U, manager_->GetNumActiveInputMethods());
   EXPECT_EQ(1, observer.input_method_changed_count_);
@@ -700,7 +706,7 @@
   manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
   std::vector<std::string> ids;
   ids.push_back(nacl_mozc_us_id);  // Japanese
-  ids.push_back("mozc-chewing");  // T-Chinese
+  ids.push_back("_comp_ime_nmblnjkfdkabgdofidlkienfnnbjhnabext2_engine1_engine_id");  // T-Chinese
   EXPECT_TRUE(manager_->EnableInputMethods(ids));
   EXPECT_EQ(2U, manager_->GetNumActiveInputMethods());
   EXPECT_TRUE(manager_->GetCurrentInputMethodProperties().empty());
@@ -716,7 +722,7 @@
   ASSERT_EQ(1U, manager_->GetCurrentInputMethodProperties().size());
   EXPECT_EQ("key-mozc", manager_->GetCurrentInputMethodProperties().at(0).key);
 
-  manager_->ChangeInputMethod("mozc-chewing");
+  manager_->ChangeInputMethod("_comp_ime_nmblnjkfdkabgdofidlkienfnnbjhnabext2_engine1_engine_id");
   // Since the IME is changed, the property for mozc Japanese should be hidden.
   EXPECT_TRUE(manager_->GetCurrentInputMethodProperties().empty());
 
@@ -842,12 +848,6 @@
   EXPECT_EQ("xkb:us::eng", manager_->GetCurrentInputMethod().id());
   EXPECT_EQ("us", xkeyboard_->last_layout_);
 
-  // Do the same tests for Korean.
-  EXPECT_FALSE(manager_->SwitchInputMethod(
-      ui::Accelerator(ui::VKEY_HANGUL, ui::EF_NONE)));
-  EXPECT_EQ("xkb:us::eng", manager_->GetCurrentInputMethod().id());
-  EXPECT_EQ("us", xkeyboard_->last_layout_);
-
   manager_->RemoveObserver(&observer);
 }
 
@@ -879,27 +879,6 @@
   EXPECT_EQ("jp", xkeyboard_->last_layout_);
 }
 
-TEST_F(InputMethodManagerImplTest, TestSwitchInputMethodWithKoLayout) {
-  // Do the same tests for Korean.
-  InitComponentExtension();
-  InitIBusBus();
-  manager_->EnableLayouts("ko", "xkb:us::eng");
-  EXPECT_EQ(2U, manager_->GetNumActiveInputMethods());
-  EXPECT_EQ("xkb:us::eng", manager_->GetCurrentInputMethod().id());
-  EXPECT_EQ("us", xkeyboard_->last_layout_);
-  EXPECT_TRUE(manager_->SwitchInputMethod(
-      ui::Accelerator(ui::VKEY_HANGUL, ui::EF_NONE)));
-  EXPECT_EQ("xkb:kr:kr104:kor", manager_->GetCurrentInputMethod().id());
-  EXPECT_EQ("kr(kr104)", xkeyboard_->last_layout_);
-  manager_->SwitchToPreviousInputMethod();
-  EXPECT_EQ("xkb:us::eng", manager_->GetCurrentInputMethod().id());
-  EXPECT_EQ("us", xkeyboard_->last_layout_);
-  EXPECT_TRUE(manager_->SwitchInputMethod(
-      ui::Accelerator(ui::VKEY_HANGUL, ui::EF_NONE)));
-  EXPECT_EQ("xkb:kr:kr104:kor", manager_->GetCurrentInputMethod().id());
-  EXPECT_EQ("kr(kr104)", xkeyboard_->last_layout_);
-}
-
 TEST_F(InputMethodManagerImplTest, TestSwitchInputMethodWithJpIme) {
   InitComponentExtension();
   InitIBusBus();
@@ -950,40 +929,6 @@
   EXPECT_EQ("jp", xkeyboard_->last_layout_);
 }
 
-TEST_F(InputMethodManagerImplTest, TestSwitchInputMethodWithKoIme) {
-  InitComponentExtension();
-  InitIBusBus();
-  manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
-  std::vector<std::string> ids;
-  ids.push_back("xkb:kr:kr104:kor");
-  ids.push_back("mozc-hangul");
-  EXPECT_TRUE(manager_->EnableInputMethods(ids));
-  EXPECT_EQ("xkb:kr:kr104:kor", manager_->GetCurrentInputMethod().id());
-  EXPECT_EQ("kr(kr104)", xkeyboard_->last_layout_);
-  EXPECT_TRUE(manager_->SwitchInputMethod(
-      ui::Accelerator(ui::VKEY_HANGUL, ui::EF_NONE)));
-  EXPECT_EQ("mozc-hangul", manager_->GetCurrentInputMethod().id());
-  EXPECT_EQ("kr(kr104)", xkeyboard_->last_layout_);
-  EXPECT_TRUE(manager_->SwitchInputMethod(
-      ui::Accelerator(ui::VKEY_HANGUL, ui::EF_NONE)));
-  EXPECT_EQ("xkb:kr:kr104:kor", manager_->GetCurrentInputMethod().id());
-  EXPECT_EQ("kr(kr104)", xkeyboard_->last_layout_);
-
-  // Add Dvorak.
-  ids.push_back("xkb:us:dvorak:eng");
-  EXPECT_TRUE(manager_->EnableInputMethods(ids));
-  EXPECT_EQ("xkb:kr:kr104:kor", manager_->GetCurrentInputMethod().id());
-  EXPECT_EQ("kr(kr104)", xkeyboard_->last_layout_);
-  EXPECT_TRUE(manager_->SwitchInputMethod(
-      ui::Accelerator(ui::VKEY_HANGUL, ui::EF_NONE)));
-  EXPECT_EQ("mozc-hangul", manager_->GetCurrentInputMethod().id());
-  EXPECT_EQ("kr(kr104)", xkeyboard_->last_layout_);
-  EXPECT_TRUE(manager_->SwitchInputMethod(
-      ui::Accelerator(ui::VKEY_HANGUL, ui::EF_NONE)));
-  EXPECT_EQ("xkb:kr:kr104:kor", manager_->GetCurrentInputMethod().id());
-  EXPECT_EQ("kr(kr104)", xkeyboard_->last_layout_);
-}
-
 TEST_F(InputMethodManagerImplTest, TestAddRemoveExtensionInputMethods) {
   TestObserver observer;
   manager_->AddObserver(&observer);
@@ -1177,16 +1122,16 @@
   manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
   std::vector<std::string> ids;
   ids.push_back(nacl_mozc_us_id);
-  ids.push_back("m17n:kn:itrans");
+  ids.push_back(nacl_mozc_jp_id);
   EXPECT_TRUE(manager_->EnableInputMethods(ids));
   EXPECT_EQ(2U, manager_->GetNumActiveInputMethods());
   manager_->ChangeInputMethod(nacl_mozc_us_id);
-  manager_->ChangeInputMethod("m17n:kn:itrans");
+  manager_->ChangeInputMethod(nacl_mozc_jp_id);
 
   InitComponentExtension();
   InitIBusBus();
   EXPECT_EQ(1, mock_ibus_client_->set_global_engine_call_count());
-  EXPECT_EQ("m17n:kn:itrans", mock_ibus_client_->latest_global_engine_name());
+  EXPECT_EQ(nacl_mozc_jp_id, mock_ibus_client_->latest_global_engine_name());
 }
 
 TEST_F(InputMethodManagerImplTest,
@@ -1281,7 +1226,7 @@
   input_method_ids.push_back("mozc");
   input_method_ids.push_back("mozc-jp");
   input_method_ids.push_back("xkb:us::eng");
-  input_method_ids.push_back("mozc-hangul");
+  input_method_ids.push_back(nacl_mozc_us_id);
 
   manager_->MigrateOldInputMethods(&input_method_ids);
 
@@ -1297,14 +1242,14 @@
                       "xkb:us::eng"));
   EXPECT_NE(input_method_ids.end(),
             std::find(input_method_ids.begin(), input_method_ids.end(),
-                      "mozc-hangul"));
+                      nacl_mozc_us_id));
 
 }
 
 TEST_F(InputMethodManagerImplTest,
        AsyncComponentExtentionInitializeBeforeIBusDaemonConnection) {
   const std::string xkb_id = "xkb:cz::cze";
-  const std::string ime_id = "mozc-hangul";
+  const std::string ime_id = nacl_mozc_us_id;
   const std::string fallback_id = "xkb:us::eng";
   std::vector<std::string> ids;
   ids.push_back(xkb_id);
@@ -1336,7 +1281,7 @@
 TEST_F(InputMethodManagerImplTest,
        AsyncComponentExtentionInitializeAfterIBusDaemonConnection) {
   const std::string xkb_id = "xkb:cz::cze";
-  const std::string ime_id = "mozc-hangul";
+  const std::string ime_id = nacl_mozc_us_id;
   const std::string fallback_id = "xkb:us::eng";
   std::vector<std::string> ids;
   ids.push_back(xkb_id);
diff --git a/chrome/browser/chromeos/input_method/input_method_util.cc b/chrome/browser/chromeos/input_method/input_method_util.cc
index f70f0eb..3258cda 100644
--- a/chrome/browser/chromeos/input_method/input_method_util.cc
+++ b/chrome/browser/chromeos/input_method/input_method_util.cc
@@ -49,10 +49,24 @@
   { "_comp_ime_bbaiamgfapehflhememkfglaehiobjnknacl_mozc_jp", "\xe3\x81\x82" },
   // For simplified Chinese input methods
   { "pinyin", "\xe6\x8b\xbc" },  // U+62FC
+  { "_comp_ime_cpgalbafkoofkjmaeonnfijgpfennjjnzh-t-i0-pinyin",
+    "\xe6\x8b\xbc" },
+  { "_comp_ime_nmblnjkfdkabgdofidlkienfnnbjhnabzh-t-i0-pinyin",
+    "\xe6\x8b\xbc" },
+  { "_comp_ime_jcffnbbngddhenhcnebafkbdomehdhpdzh-t-i0-wubi-1986",
+    "\xe4\xba\x94" }, // U+4E94
   { "pinyin-dv", "\xe6\x8b\xbc" },
   // For traditional Chinese input methods
   { "mozc-chewing", "\xe9\x85\xb7" },  // U+9177
+  { "_comp_ime_ekbifjdfhkmdeeajnolmgdlmkllopefizh-hant-t-i0-und",
+    "\xe9\x85\xb7" },  // U+9177
+  { "_comp_ime_goedamlknlnjaengojinmfgpmdjmkooozh-hant-t-i0-und",
+    "\xe9\x85\xb7" },  // U+9177
   { "m17n:zh:cangjie", "\xe5\x80\x89" },  // U+5009
+  { "_comp_ime_aeebooiibjahgpgmhkeocbeekccfknbjzh-hant-t-i0-cangjie-1987",
+    "\xe5\x80\x89" },  // U+5009
+  { "_comp_ime_gjhclobljhjhgoebiipblnmdodbmpdgdzh-hant-t-i0-cangjie-1987",
+    "\xe5\x80\x89" },  // U+5009
   { "m17n:zh:quick", "\xe9\x80\x9f" },  // U+901F
   // For Hangul input method.
   { "mozc-hangul", "\xed\x95\x9c" },  // U+D55C
@@ -76,6 +90,20 @@
   { "mozc-hangul", IDS_LANGUAGES_MEDIUM_LEN_NAME_KOREAN },
   { "pinyin", IDS_LANGUAGES_MEDIUM_LEN_NAME_CHINESE_SIMPLIFIED },
   { "pinyin-dv", IDS_LANGUAGES_MEDIUM_LEN_NAME_CHINESE_SIMPLIFIED },
+  { "_comp_ime_cpgalbafkoofkjmaeonnfijgpfennjjnzh-t-i0-pinyin",
+    IDS_LANGUAGES_MEDIUM_LEN_NAME_CHINESE_SIMPLIFIED},
+  { "_comp_ime_nmblnjkfdkabgdofidlkienfnnbjhnabzh-t-i0-pinyin",
+    IDS_LANGUAGES_MEDIUM_LEN_NAME_CHINESE_SIMPLIFIED },
+  { "_comp_ime_jcffnbbngddhenhcnebafkbdomehdhpdzh-t-i0-wubi-1986",
+    IDS_LANGUAGES_MEDIUM_LEN_NAME_CHINESE_SIMPLIFIED },
+  { "_comp_ime_ekbifjdfhkmdeeajnolmgdlmkllopefizh-hant-t-i0-und",
+    IDS_LANGUAGES_MEDIUM_LEN_NAME_CHINESE_TRADITIONAL },
+  { "_comp_ime_goedamlknlnjaengojinmfgpmdjmkooozh-hant-t-i0-und",
+    IDS_LANGUAGES_MEDIUM_LEN_NAME_CHINESE_TRADITIONAL },
+  { "_comp_ime_aeebooiibjahgpgmhkeocbeekccfknbjzh-hant-t-i0-cangjie-1987",
+    IDS_LANGUAGES_MEDIUM_LEN_NAME_CHINESE_TRADITIONAL },
+  { "_comp_ime_gjhclobljhjhgoebiipblnmdodbmpdgdzh-hant-t-i0-cangjie-1987",
+    IDS_LANGUAGES_MEDIUM_LEN_NAME_CHINESE_TRADITIONAL },
 };
 const size_t kMappingImeIdToMediumLenNameResourceIdLen =
     ARRAYSIZE_UNSAFE(kMappingImeIdToMediumLenNameResourceId);
@@ -91,6 +119,12 @@
 } kDefaultInputMethodRecommendation[] = {
   { "ja", "us", "_comp_ime_fpfbhcjppmaeaijcidgiibchfbnhbeljnacl_mozc_us" },
   { "ja", "jp", "_comp_ime_fpfbhcjppmaeaijcidgiibchfbnhbeljnacl_mozc_jp" },
+  { "zh-CN", "us", "_comp_ime_nmblnjkfdkabgdofidlkienfnnbjhnabzh-t-i0-pinyin" },
+  { "zh-TW", "us",
+    "_comp_ime_goedamlknlnjaengojinmfgpmdjmkooozh-hant-t-i0-und" },
+  { "th", "us", "_comp_ime_jhffeifommiaekmbkkjlpmilogcfdohpvkd_th" },
+  { "vi", "us", "_comp_ime_jhffeifommiaekmbkkjlpmilogcfdohpvkd_vi_tcvn" },
+  { "vi", "us", "_comp_ime_jhffeifommiaekmbkkjlpmilogcfdohpvkd_vi_tcvn" },
 };
 
 }  // namespace
diff --git a/chrome/browser/chromeos/input_method/input_method_util_unittest.cc b/chrome/browser/chromeos/input_method/input_method_util_unittest.cc
index 7a4a33f..74a16b9 100644
--- a/chrome/browser/chromeos/input_method/input_method_util_unittest.cc
+++ b/chrome/browser/chromeos/input_method/input_method_util_unittest.cc
@@ -24,6 +24,11 @@
 
 namespace {
 
+const char pinyin_ime_id[] =
+    "_comp_ime_nmblnjkfdkabgdofidlkienfnnbjhnabzh-t-i0-pinyin";
+const char zhuyin_ime_id[] =
+    "_comp_ime_goedamlknlnjaengojinmfgpmdjmkooozh-hant-t-i0-und";
+
 class TestableInputMethodUtil : public InputMethodUtil {
  public:
   explicit TestableInputMethodUtil(InputMethodDelegate* delegate,
@@ -49,6 +54,33 @@
         base::Bind(&InputMethodUtilTest::GetDisplayLanguageName));
   }
 
+  virtual void SetUp() OVERRIDE {
+    InputMethodDescriptors input_methods;
+
+    std::vector<std::string> layouts;
+    std::vector<std::string> languages;
+    layouts.push_back("us");
+    languages.push_back("zh-CN");
+
+    InputMethodDescriptor pinyin_ime(pinyin_ime_id,
+                                     "Pinyin input for testing",
+                                     layouts,
+                                     languages,
+                                     GURL(""));
+    input_methods.push_back(pinyin_ime);
+
+    languages.clear();
+    languages.push_back("zh-TW");
+    InputMethodDescriptor zhuyin_ime(zhuyin_ime_id,
+                                     "Zhuyin input for testing",
+                                     layouts,
+                                     languages,
+                                     GURL(""));
+    input_methods.push_back(zhuyin_ime);
+
+    util_.SetComponentExtensions(input_methods);
+  }
+
   InputMethodDescriptor GetDesc(const std::string& id,
                                 const std::string& raw_layout,
                                 const std::string& language_code) {
@@ -118,17 +150,12 @@
     EXPECT_EQ(ASCIIToUTF16("CAS"), util_.GetInputMethodShortName(desc));
   }
   {
-    InputMethodDescriptor desc = GetDesc("pinyin", "us", "zh-CN");
+    InputMethodDescriptor desc = GetDesc(pinyin_ime_id, "us", "zh-CN");
     EXPECT_EQ(UTF8ToUTF16("\xe6\x8b\xbc"),
               util_.GetInputMethodShortName(desc));
   }
   {
-    InputMethodDescriptor desc = GetDesc("pinyin-dv", "us(dvorak)", "zh-CN");
-    EXPECT_EQ(UTF8ToUTF16("\xe6\x8b\xbc"),
-              util_.GetInputMethodShortName(desc));
-  }
-  {
-    InputMethodDescriptor desc = GetDesc("mozc-chewing", "us", "zh-TW");
+    InputMethodDescriptor desc = GetDesc(zhuyin_ime_id, "us", "zh-TW");
     EXPECT_EQ(UTF8ToUTF16("\xe9\x85\xb7"),
               util_.GetInputMethodShortName(desc));
   }
@@ -170,12 +197,11 @@
     const char * input_method_id[] = {
       "m17n:zh:cangjie",
       "m17n:zh:quick",
-      "pinyin",
-      "mozc-chewing",
+      pinyin_ime_id,
+      zhuyin_ime_id,
       "mozc-hangul",
-      "pinyin",
-      "pinyin",
-      "pinyin-dv",
+      pinyin_ime_id,
+      pinyin_ime_id,
     };
     const int len = ARRAYSIZE_UNSAFE(input_method_id);
     for (int i=0; i<len; ++i) {
@@ -206,11 +232,6 @@
               util_.GetInputMethodLongName(desc));
   }
   {
-    InputMethodDescriptor desc = GetDesc("pinyin", "us", "ja");
-    EXPECT_EQ(ASCIIToUTF16("Pinyin input method"),
-              util_.GetInputMethodLongName(desc));
-  }
-  {
     InputMethodDescriptor desc = GetDesc("xkb:jp::jpn", "jp", "ja");
     EXPECT_EQ(ASCIIToUTF16("Japanese keyboard"),
               util_.GetInputMethodLongName(desc));
@@ -275,20 +296,15 @@
   }
 }
 
-TEST_F(InputMethodUtilTest, TestGetStringUTF8) {
-  EXPECT_EQ(UTF8ToUTF16("Pinyin input method"),
-            util_.TranslateString("pinyin"));
-}
-
 TEST_F(InputMethodUtilTest, TestIsValidInputMethodId) {
   EXPECT_TRUE(util_.IsValidInputMethodId("xkb:us:colemak:eng"));
-  EXPECT_TRUE(util_.IsValidInputMethodId("pinyin"));
+  EXPECT_TRUE(util_.IsValidInputMethodId(pinyin_ime_id));
   EXPECT_FALSE(util_.IsValidInputMethodId("unsupported-input-method"));
 }
 
 TEST_F(InputMethodUtilTest, TestIsKeyboardLayout) {
   EXPECT_TRUE(InputMethodUtil::IsKeyboardLayout("xkb:us::eng"));
-  EXPECT_FALSE(InputMethodUtil::IsKeyboardLayout("pinyin"));
+  EXPECT_FALSE(InputMethodUtil::IsKeyboardLayout(pinyin_ime_id));
 }
 
 TEST_F(InputMethodUtilTest, TestGetKeyboardLayoutName) {
@@ -296,9 +312,7 @@
   EXPECT_EQ("", util_.GetKeyboardLayoutName("UNSUPPORTED_ID"));
 
   // Supported cases (samples).
-  EXPECT_EQ("us", util_.GetKeyboardLayoutName("pinyin"));
-  EXPECT_EQ("us(dvorak)", util_.GetKeyboardLayoutName("pinyin-dv"));
-  EXPECT_EQ("us", util_.GetKeyboardLayoutName("m17n:ar:kbd"));
+  EXPECT_EQ("us", util_.GetKeyboardLayoutName(pinyin_ime_id));
   EXPECT_EQ("es", util_.GetKeyboardLayoutName("xkb:es::spa"));
   EXPECT_EQ("es(cat)", util_.GetKeyboardLayoutName("xkb:es:cat:cat"));
   EXPECT_EQ("gb(extd)", util_.GetKeyboardLayoutName("xkb:gb:extd:eng"));
@@ -310,12 +324,10 @@
 
 TEST_F(InputMethodUtilTest, TestGetLanguageCodeFromInputMethodId) {
   // Make sure that the -CN is added properly.
-  EXPECT_EQ("zh-CN", util_.GetLanguageCodeFromInputMethodId("pinyin"));
+  EXPECT_EQ("zh-CN", util_.GetLanguageCodeFromInputMethodId(pinyin_ime_id));
 }
 
 TEST_F(InputMethodUtilTest, TestGetInputMethodDisplayNameFromId) {
-  EXPECT_EQ("Pinyin input method",
-            util_.GetInputMethodDisplayNameFromId("pinyin"));
   EXPECT_EQ("US keyboard",
             util_.GetInputMethodDisplayNameFromId("xkb:us::eng"));
   EXPECT_EQ("", util_.GetInputMethodDisplayNameFromId("nonexistent"));
@@ -325,9 +337,9 @@
   EXPECT_EQ(NULL, util_.GetInputMethodDescriptorFromId("non_existent"));
 
   const InputMethodDescriptor* descriptor =
-      util_.GetInputMethodDescriptorFromId("pinyin");
+      util_.GetInputMethodDescriptorFromId(pinyin_ime_id);
   ASSERT_TRUE(NULL != descriptor);  // ASSERT_NE doesn't compile.
-  EXPECT_EQ("pinyin", descriptor->id());
+  EXPECT_EQ(pinyin_ime_id, descriptor->id());
   EXPECT_EQ("us", descriptor->GetPreferredKeyboardLayout());
   // This used to be "zh" but now we have "zh-CN" in input_methods.h,
   // hence this should be zh-CN now.
@@ -337,8 +349,8 @@
 
 TEST_F(InputMethodUtilTest, TestGetInputMethodIdsForLanguageCode) {
   std::multimap<std::string, std::string> language_code_to_ids_map;
-  language_code_to_ids_map.insert(std::make_pair("ja", "pinyin"));
-  language_code_to_ids_map.insert(std::make_pair("ja", "pinyin"));
+  language_code_to_ids_map.insert(std::make_pair("ja", pinyin_ime_id));
+  language_code_to_ids_map.insert(std::make_pair("ja", pinyin_ime_id));
   language_code_to_ids_map.insert(std::make_pair("ja", "xkb:jp:jpn"));
   language_code_to_ids_map.insert(std::make_pair("fr", "xkb:fr:fra"));
 
@@ -386,20 +398,7 @@
   util_.GetFirstLoginInputMethodIds("zh-CN", *descriptor, &input_method_ids);
   ASSERT_EQ(2U, input_method_ids.size());
   EXPECT_EQ("xkb:us::eng", input_method_ids[0]);
-  EXPECT_EQ("pinyin", input_method_ids[1]);  // Pinyin for US keybaord.
-}
-
-// Korean keyboard + Korean UI = Korean keyboard + mozc-hangul.
-TEST_F(InputMethodUtilTest, TestGetFirstLoginInputMethodIds_KR_And_Ko) {
-  // Korean keyboard
-  const InputMethodDescriptor* descriptor =
-      util_.GetInputMethodDescriptorFromId("xkb:kr:kr104:kor");
-  ASSERT_TRUE(NULL != descriptor);  // ASSERT_NE doesn't compile.
-  std::vector<std::string> input_method_ids;
-  util_.GetFirstLoginInputMethodIds("ko", *descriptor, &input_method_ids);
-  ASSERT_EQ(2U, input_method_ids.size());
-  EXPECT_EQ("xkb:kr:kr104:kor", input_method_ids[0]);
-  EXPECT_EQ("mozc-hangul", input_method_ids[1]);  // Mozc for JP keybaord.
+  EXPECT_EQ(pinyin_ime_id, input_method_ids[1]);  // Pinyin for US keybaord.
 }
 
 // US keyboard + Russian UI = US keyboard + Russsian keyboard
@@ -423,7 +422,7 @@
   util_.GetFirstLoginInputMethodIds("zh-TW", *descriptor, &input_method_ids);
   ASSERT_EQ(2U, input_method_ids.size());
   EXPECT_EQ("xkb:us::eng", input_method_ids[0]);
-  EXPECT_EQ("mozc-chewing", input_method_ids[1]);  // Chewing.
+  EXPECT_EQ(zhuyin_ime_id, input_method_ids[1]);  // Chewing.
 }
 
 // US keyboard + Thai = US keyboard + kesmanee.
@@ -435,7 +434,8 @@
   util_.GetFirstLoginInputMethodIds("th", *descriptor, &input_method_ids);
   ASSERT_EQ(2U, input_method_ids.size());
   EXPECT_EQ("xkb:us::eng", input_method_ids[0]);
-  EXPECT_EQ("m17n:th:kesmanee", input_method_ids[1]);  // Kesmanee.
+  EXPECT_EQ("_comp_ime_jhffeifommiaekmbkkjlpmilogcfdohpvkd_th",
+            input_method_ids[1]);  // Kesmanee.
 }
 
 // US keyboard + Vietnamese = US keyboard + TCVN6064.
@@ -447,14 +447,15 @@
   util_.GetFirstLoginInputMethodIds("vi", *descriptor, &input_method_ids);
   ASSERT_EQ(2U, input_method_ids.size());
   EXPECT_EQ("xkb:us::eng", input_method_ids[0]);
-  EXPECT_EQ("m17n:vi:tcvn", input_method_ids[1]);  // TCVN6064.
+  EXPECT_EQ("_comp_ime_jhffeifommiaekmbkkjlpmilogcfdohpvkd_vi_tcvn",
+            input_method_ids[1]);  // TCVN6064.
 }
 
 TEST_F(InputMethodUtilTest, TestGetLanguageCodesFromInputMethodIds) {
   std::vector<std::string> input_method_ids;
   input_method_ids.push_back("xkb:us::eng");  // English US.
   input_method_ids.push_back("xkb:us:dvorak:eng");  // English US Dvorak.
-  input_method_ids.push_back("pinyin");  // Pinyin
+  input_method_ids.push_back(pinyin_ime_id);  // Pinyin
   input_method_ids.push_back("xkb:fr::fra");  // French France.
   std::vector<std::string> language_codes;
   util_.GetLanguageCodesFromInputMethodIds(input_method_ids, &language_codes);
diff --git a/chrome/browser/chromeos/input_method/mock_input_method_manager.cc b/chrome/browser/chromeos/input_method/mock_input_method_manager.cc
index 9efe97f..ad18c70 100644
--- a/chrome/browser/chromeos/input_method/mock_input_method_manager.cc
+++ b/chrome/browser/chromeos/input_method/mock_input_method_manager.cc
@@ -68,6 +68,12 @@
   return false;
 }
 
+bool MockInputMethodManager::MigrateKoreanKeyboard(
+    const std::string& keyboard_id,
+    std::vector<std::string>* input_method_ids) {
+  return false;
+}
+
 bool MockInputMethodManager::SetInputMethodConfig(
     const std::string& section,
     const std::string& config_name,
diff --git a/chrome/browser/chromeos/input_method/mock_input_method_manager.h b/chrome/browser/chromeos/input_method/mock_input_method_manager.h
index 77d760d..e373707 100644
--- a/chrome/browser/chromeos/input_method/mock_input_method_manager.h
+++ b/chrome/browser/chromeos/input_method/mock_input_method_manager.h
@@ -38,6 +38,9 @@
       const std::vector<std::string>& new_active_input_method_ids) OVERRIDE;
   virtual bool MigrateOldInputMethods(
       std::vector<std::string>* input_method_ids) OVERRIDE;
+  virtual bool MigrateKoreanKeyboard(
+      const std::string& keyboard_id,
+      std::vector<std::string>* input_method_ids) OVERRIDE;
   virtual bool SetInputMethodConfig(
       const std::string& section,
       const std::string& config_name,
diff --git a/chrome/browser/chromeos/keyboard_driven_event_rewriter.cc b/chrome/browser/chromeos/keyboard_driven_event_rewriter.cc
new file mode 100644
index 0000000..7c451d2
--- /dev/null
+++ b/chrome/browser/chromeos/keyboard_driven_event_rewriter.cc
@@ -0,0 +1,72 @@
+// 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/keyboard_driven_event_rewriter.h"
+
+#include <X11/Xlib.h>
+
+#include "chrome/browser/chromeos/login/user_manager.h"
+#include "chrome/browser/chromeos/system/statistics_provider.h"
+#include "ui/base/events/event.h"
+
+namespace chromeos {
+
+namespace {
+
+const int kModifierMask = (ui::EF_CONTROL_DOWN |
+                           ui::EF_ALT_DOWN |
+                           ui::EF_SHIFT_DOWN);
+
+// Returns true if and only if it is on login screen (i.e. user is not logged
+// in) and the keyboard driven flag in the OEM manifest is on.
+bool ShouldStripModifiersForArrowKeysAndEnter() {
+  if (chromeos::UserManager::IsInitialized() &&
+      !chromeos::UserManager::Get()->IsUserLoggedIn()) {
+    bool keyboard_driven_oobe = false;
+    chromeos::system::StatisticsProvider::GetInstance()->GetMachineFlag(
+        chromeos::system::kOemKeyboardDrivenOobeKey, &keyboard_driven_oobe);
+    return keyboard_driven_oobe;
+  }
+
+  return false;
+}
+
+}  // namespace
+
+KeyboardDrivenEventRewriter::KeyboardDrivenEventRewriter() {}
+
+KeyboardDrivenEventRewriter::~KeyboardDrivenEventRewriter() {}
+
+void KeyboardDrivenEventRewriter::RewriteIfKeyboardDrivenOnLoginScreen(
+    ui::KeyEvent* event) {
+  if (!ShouldStripModifiersForArrowKeysAndEnter())
+    return;
+
+  RewriteEvent(event);
+}
+
+void KeyboardDrivenEventRewriter::RewriteForTesting(ui::KeyEvent* event) {
+  RewriteEvent(event);
+}
+
+void KeyboardDrivenEventRewriter::RewriteEvent(ui::KeyEvent* event) {
+  if ((event->flags() & kModifierMask) != kModifierMask)
+    return;
+
+  if (event->key_code() != ui::VKEY_LEFT &&
+      event->key_code() != ui::VKEY_RIGHT &&
+      event->key_code() != ui::VKEY_UP &&
+      event->key_code() != ui::VKEY_DOWN &&
+      event->key_code() != ui::VKEY_RETURN) {
+    return;
+  }
+
+  XEvent* xev = event->native_event();
+  XKeyEvent* xkey = &(xev->xkey);
+  xkey->state &= ~(ControlMask | Mod1Mask | ShiftMask);
+  event->set_flags(event->flags() & ~kModifierMask);
+  event->NormalizeFlags();
+}
+
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/keyboard_driven_event_rewriter.h b/chrome/browser/chromeos/keyboard_driven_event_rewriter.h
new file mode 100644
index 0000000..be274c0
--- /dev/null
+++ b/chrome/browser/chromeos/keyboard_driven_event_rewriter.h
@@ -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.
+
+#ifndef CHROME_BROWSER_CHROMEOS_KEYBOARD_DRIVEN_EVENT_REWRITER_H_
+#define CHROME_BROWSER_CHROMEOS_KEYBOARD_DRIVEN_EVENT_REWRITER_H_
+
+#include "base/basictypes.h"
+
+namespace ui {
+class KeyEvent;
+}
+
+namespace chromeos {
+
+// KeyboardDrivenEventRewriter removes the modifier flags from
+// Ctrl+Alt+Shift+<Arrow keys|Enter> key events. This mapping only happens
+// on login screen and only when the keyboard driven oobe flag is enabled in the
+// OEM manifest.
+class KeyboardDrivenEventRewriter {
+ public:
+  KeyboardDrivenEventRewriter();
+  ~KeyboardDrivenEventRewriter();
+
+  // Calls RewriteEvent to modify |event| if it is on login screen and the
+  // keyboard driven flag is enabled.
+  void RewriteIfKeyboardDrivenOnLoginScreen(ui::KeyEvent* event);
+
+  // Calls RewriteEvent for testing.
+  void RewriteForTesting(ui::KeyEvent* event);
+
+ private:
+  void RewriteEvent(ui::KeyEvent* event);
+
+  DISALLOW_COPY_AND_ASSIGN(KeyboardDrivenEventRewriter);
+};
+
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_CHROMEOS_KEYBOARD_DRIVEN_EVENT_REWRITER_H_
diff --git a/chrome/browser/chromeos/keyboard_driven_event_rewriter_unittest.cc b/chrome/browser/chromeos/keyboard_driven_event_rewriter_unittest.cc
new file mode 100644
index 0000000..fb32552
--- /dev/null
+++ b/chrome/browser/chromeos/keyboard_driven_event_rewriter_unittest.cc
@@ -0,0 +1,165 @@
+// 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/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/strings/stringprintf.h"
+#include "chrome/browser/chromeos/keyboard_driven_event_rewriter.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/events/event.h"
+#include "ui/base/x/x11_util.h"
+
+#include <X11/keysym.h>
+#include <X11/XF86keysym.h>
+#include <X11/Xlib.h>
+
+namespace chromeos {
+
+// Creates an XKeyEvent to initialize a ui::KeyEvent that is passed to
+// KeyboardDrivenEventRewriter for processing.
+void InitXKeyEvent(ui::KeyboardCode ui_keycode,
+                   int ui_flags,
+                   ui::EventType ui_type,
+                   KeyCode x_keycode,
+                   unsigned int x_state,
+                   XEvent* event) {
+  ui::InitXKeyEventForTesting(ui_type,
+                              ui_keycode,
+                              ui_flags,
+                              event);
+  event->xkey.keycode = x_keycode;
+  event->xkey.state = x_state;
+}
+
+class KeyboardDrivenEventRewriterTest : public testing::Test {
+ public:
+  KeyboardDrivenEventRewriterTest()
+      : display_(ui::GetXDisplay()),
+        keycode_a_(XKeysymToKeycode(display_, XK_a)),
+        keycode_up_(XKeysymToKeycode(display_, XK_Up)),
+        keycode_down_(XKeysymToKeycode(display_, XK_Down)),
+        keycode_left_(XKeysymToKeycode(display_, XK_Left)),
+        keycode_right_(XKeysymToKeycode(display_, XK_Right)),
+        keycode_return_(XKeysymToKeycode(display_, XK_Return)) {
+  }
+
+  virtual ~KeyboardDrivenEventRewriterTest() {}
+
+ protected:
+  std::string GetRewrittenEventAsString(ui::KeyboardCode ui_keycode,
+                                        int ui_flags,
+                                        ui::EventType ui_type,
+                                        KeyCode x_keycode,
+                                        unsigned int x_state) {
+    XEvent xev;
+    InitXKeyEvent(ui_keycode, ui_flags, ui_type, x_keycode, x_state, &xev);
+    ui::KeyEvent keyevent(&xev, false /* is_char */);
+    rewriter_.RewriteForTesting(&keyevent);
+    return base::StringPrintf(
+        "ui_flags=%d x_state=%u", keyevent.flags(), xev.xkey.state);
+  }
+
+  std::string GetExpectedResultAsString(int ui_flags, unsigned int x_state) {
+    return base::StringPrintf("ui_flags=%d x_state=%u", ui_flags, x_state);
+  }
+
+  Display* display_;
+  const KeyCode keycode_a_;
+  const KeyCode keycode_up_;
+  const KeyCode keycode_down_;
+  const KeyCode keycode_left_;
+  const KeyCode keycode_right_;
+  const KeyCode keycode_return_;
+
+  KeyboardDrivenEventRewriter rewriter_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(KeyboardDrivenEventRewriterTest);
+};
+
+TEST_F(KeyboardDrivenEventRewriterTest, PassThrough) {
+  struct {
+    ui::KeyboardCode ui_keycode;
+    int ui_flags;
+    KeyCode x_keycode;
+    unsigned int x_state;
+  } kTests[] = {
+    { ui::VKEY_A, ui::EF_NONE, keycode_a_, 0 },
+    { ui::VKEY_A, ui::EF_CONTROL_DOWN, keycode_a_, ControlMask },
+    { ui::VKEY_A, ui::EF_ALT_DOWN, keycode_a_, Mod1Mask },
+    { ui::VKEY_A, ui::EF_SHIFT_DOWN, keycode_a_, ShiftMask },
+    { ui::VKEY_A, ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN,
+        keycode_a_, ControlMask | Mod1Mask },
+    { ui::VKEY_A, ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN | ui::EF_SHIFT_DOWN,
+        keycode_a_, ControlMask | Mod1Mask | ShiftMask },
+
+    { ui::VKEY_LEFT, ui::EF_NONE, keycode_left_, 0 },
+    { ui::VKEY_LEFT, ui::EF_CONTROL_DOWN, keycode_left_, ControlMask },
+    { ui::VKEY_LEFT, ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN,
+        keycode_left_, ControlMask | Mod1Mask },
+
+    { ui::VKEY_RIGHT, ui::EF_NONE, keycode_right_, 0 },
+    { ui::VKEY_RIGHT, ui::EF_CONTROL_DOWN, keycode_right_, ControlMask },
+    { ui::VKEY_RIGHT, ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN,
+        keycode_right_, ControlMask | Mod1Mask },
+
+    { ui::VKEY_UP, ui::EF_NONE, keycode_up_, 0 },
+    { ui::VKEY_UP, ui::EF_CONTROL_DOWN, keycode_up_, ControlMask },
+    { ui::VKEY_UP, ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN,
+        keycode_up_, ControlMask | Mod1Mask },
+
+    { ui::VKEY_DOWN, ui::EF_NONE, keycode_down_, 0 },
+    { ui::VKEY_DOWN, ui::EF_CONTROL_DOWN, keycode_down_, ControlMask },
+    { ui::VKEY_DOWN, ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN,
+        keycode_down_, ControlMask | Mod1Mask },
+
+    { ui::VKEY_RETURN, ui::EF_NONE, keycode_return_, 0 },
+    { ui::VKEY_RETURN, ui::EF_CONTROL_DOWN, keycode_return_, ControlMask },
+    { ui::VKEY_RETURN, ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN,
+        keycode_return_, ControlMask | Mod1Mask },
+  };
+
+  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTests); ++i) {
+    EXPECT_EQ(GetExpectedResultAsString(kTests[i].ui_flags,
+                                        kTests[i].x_state),
+              GetRewrittenEventAsString(kTests[i].ui_keycode,
+                                        kTests[i].ui_flags,
+                                        ui::ET_KEY_PRESSED,
+                                        kTests[i].x_keycode,
+                                        kTests[i].x_state))
+    << "Test case " << i;
+  }
+}
+
+TEST_F(KeyboardDrivenEventRewriterTest, Rewrite) {
+  const int kModifierMask = (ui::EF_CONTROL_DOWN |
+                             ui::EF_ALT_DOWN |
+                             ui::EF_SHIFT_DOWN);
+  const unsigned int kXState = (ControlMask | Mod1Mask | ShiftMask);
+
+  struct {
+    ui::KeyboardCode ui_keycode;
+    int ui_flags;
+    KeyCode x_keycode;
+    unsigned int x_state;
+  } kTests[] = {
+    { ui::VKEY_LEFT, kModifierMask, keycode_left_, kXState },
+    { ui::VKEY_RIGHT, kModifierMask, keycode_right_, kXState },
+    { ui::VKEY_UP, kModifierMask, keycode_up_, kXState },
+    { ui::VKEY_DOWN, kModifierMask, keycode_down_, kXState },
+    { ui::VKEY_RETURN, kModifierMask, keycode_return_, kXState },
+  };
+
+  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTests); ++i) {
+    EXPECT_EQ(GetExpectedResultAsString(ui::EF_NONE, 0),
+              GetRewrittenEventAsString(kTests[i].ui_keycode,
+                                        kTests[i].ui_flags,
+                                        ui::ET_KEY_PRESSED,
+                                        kTests[i].x_keycode,
+                                        kTests[i].x_state))
+    << "Test case " << i;
+  }
+}
+
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/kiosk_mode/kiosk_mode_idle_logout.h b/chrome/browser/chromeos/kiosk_mode/kiosk_mode_idle_logout.h
index 02da2a1..51d0792 100644
--- a/chrome/browser/chromeos/kiosk_mode/kiosk_mode_idle_logout.h
+++ b/chrome/browser/chromeos/kiosk_mode/kiosk_mode_idle_logout.h
@@ -8,7 +8,7 @@
 #include "ash/wm/user_activity_observer.h"
 #include "base/basictypes.h"
 #include "base/compiler_specific.h"
-#include "base/timer.h"
+#include "base/timer/timer.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
 
diff --git a/chrome/browser/chromeos/kiosk_mode/kiosk_mode_settings.h b/chrome/browser/chromeos/kiosk_mode/kiosk_mode_settings.h
index eb35c6a..7a90169 100644
--- a/chrome/browser/chromeos/kiosk_mode/kiosk_mode_settings.h
+++ b/chrome/browser/chromeos/kiosk_mode/kiosk_mode_settings.h
@@ -9,7 +9,7 @@
 
 #include "base/basictypes.h"
 #include "base/callback_forward.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/chromeos/policy/app_pack_updater.h"
 #include "chrome/browser/chromeos/settings/device_settings_service.h"
 
diff --git a/chrome/browser/chromeos/kiosk_mode/mock_kiosk_mode_settings.h b/chrome/browser/chromeos/kiosk_mode/mock_kiosk_mode_settings.h
index bd789d4..539fde7 100644
--- a/chrome/browser/chromeos/kiosk_mode/mock_kiosk_mode_settings.h
+++ b/chrome/browser/chromeos/kiosk_mode/mock_kiosk_mode_settings.h
@@ -12,7 +12,7 @@
 #include "base/basictypes.h"
 #include "base/callback_forward.h"
 #include "base/compiler_specific.h"
-#include "base/time.h"
+#include "base/time/time.h"
 
 namespace base {
 template <typename T> struct DefaultLazyInstanceTraits;
diff --git a/chrome/browser/chromeos/login/chrome_restart_request.cc b/chrome/browser/chromeos/login/chrome_restart_request.cc
index 8b7b35e..5096919 100644
--- a/chrome/browser/chromeos/login/chrome_restart_request.cc
+++ b/chrome/browser/chromeos/login/chrome_restart_request.cc
@@ -17,7 +17,7 @@
 #include "base/process_util.h"
 #include "base/strings/string_split.h"
 #include "base/strings/stringprintf.h"
-#include "base/timer.h"
+#include "base/timer/timer.h"
 #include "base/values.h"
 #include "cc/base/switches.h"
 #include "chrome/browser/browser_process.h"
@@ -90,6 +90,7 @@
       ::switches::kEnableBeginFrameScheduling,
       ::switches::kEnableBrowserInputController,
       ::switches::kEnableCompositingForFixedPosition,
+      ::switches::kEnableEncodedScreenCapture,
       ::switches::kEnableEncryptedMedia,
       ::switches::kEnableGestureTapHighlight,
       ::switches::kDisableGestureTapHighlight,
@@ -130,16 +131,20 @@
       ::switches::kUseExynosVda,
       ::switches::kV,
       ::switches::kEnableWebGLDraftExtensions,
-      ash::switches::kAshTouchHud,
-      ash::switches::kAuraLegacyPowerButton,
+      ash::switches::kAshDefaultGuestWallpaperLarge,
+      ash::switches::kAshDefaultGuestWallpaperSmall,
+      ash::switches::kAshDefaultWallpaperLarge,
+      ash::switches::kAshDefaultWallpaperSmall,
       ash::switches::kAshDisableNewAudioHandler,
       ash::switches::kAshEnableAudioDeviceMenu,
+      ash::switches::kAshHostWindowBounds,
+      ash::switches::kAshTouchHud,
+      ash::switches::kAuraLegacyPowerButton,
       // Please keep these in alphabetical order. Non-UI Compositor switches
       // here should also be added to
       // content/browser/renderer_host/render_process_host_impl.cc.
       cc::switches::kBackgroundColorInsteadOfCheckerboard,
       cc::switches::kCompositeToMailbox,
-      cc::switches::kDisableColorEstimator,
       cc::switches::kDisableImplSidePainting,
       cc::switches::kDisableThreadedAnimation,
       cc::switches::kEnableImplSidePainting,
@@ -153,7 +158,6 @@
       cc::switches::kMaxUnusedResourceMemoryUsagePercentage,
       cc::switches::kNumRasterThreads,
       cc::switches::kShowCompositedLayerBorders,
-      cc::switches::kShowCompositedLayerTree,
       cc::switches::kShowFPSCounter,
       cc::switches::kShowNonOccludingRects,
       cc::switches::kShowOccludingRects,
diff --git a/chrome/browser/chromeos/login/enrollment/enrollment_screen.cc b/chrome/browser/chromeos/login/enrollment/enrollment_screen.cc
index 72b3075..b0f64b7 100644
--- a/chrome/browser/chromeos/login/enrollment/enrollment_screen.cc
+++ b/chrome/browser/chromeos/login/enrollment/enrollment_screen.cc
@@ -105,7 +105,6 @@
     const GoogleServiceAuthError& error) {
   enrollment_failed_once_ = true;
   actor_->ShowAuthError(error);
-  NotifyTestingObservers(false);
 
   switch (error.state()) {
     case GoogleServiceAuthError::NONE:
@@ -114,6 +113,8 @@
     case GoogleServiceAuthError::HOSTED_NOT_ALLOWED:
     case GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS:
     case GoogleServiceAuthError::REQUEST_CANCELED:
+    case GoogleServiceAuthError::UNEXPECTED_SERVICE_RESPONSE:
+    case GoogleServiceAuthError::SERVICE_ERROR:
       UMAFailure(policy::kMetricEnrollmentLoginFailed);
       LOG(ERROR) << "Auth error " << error.state();
       return;
@@ -160,7 +161,6 @@
       base::Bind(&ScreenObserver::OnExit,
                  base::Unretained(get_screen_observer()),
                  ScreenObserver::ENTERPRISE_ENROLLMENT_COMPLETED));
-  NotifyTestingObservers(false);
 }
 
 void EnrollmentScreen::OnConfirmationClosed() {
@@ -187,15 +187,6 @@
   }
 }
 
-void EnrollmentScreen::AddTestingObserver(TestingObserver* observer) {
-  observers_.AddObserver(observer);
-}
-
-void EnrollmentScreen::RemoveTestingObserver(
-    TestingObserver* observer) {
-  observers_.RemoveObserver(observer);
-}
-
 void EnrollmentScreen::RegisterForDevicePolicy(
     const std::string& token) {
   policy::BrowserPolicyConnector* connector =
@@ -207,7 +198,6 @@
     UMAFailure(policy::kMetricEnrollmentWrongUserError);
     actor_->ShowUIError(
         EnrollmentScreenActor::UI_ERROR_DOMAIN_MISMATCH);
-    NotifyTestingObservers(false);
     return;
   }
 
@@ -226,7 +216,6 @@
   bool success = status.status() == policy::EnrollmentStatus::STATUS_SUCCESS;
   enrollment_failed_once_ |= !success;
   actor_->ShowEnrollmentStatus(status);
-  NotifyTestingObservers(success);
 
   switch (status.status()) {
     case policy::EnrollmentStatus::STATUS_SUCCESS:
@@ -294,9 +283,4 @@
   actor_->ShowSigninScreen();
 }
 
-void EnrollmentScreen::NotifyTestingObservers(bool succeeded) {
-  FOR_EACH_OBSERVER(TestingObserver, observers_,
-                    OnEnrollmentComplete(succeeded));
-}
-
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/enrollment/enrollment_screen.h b/chrome/browser/chromeos/login/enrollment/enrollment_screen.h
index 3114978..0db7475 100644
--- a/chrome/browser/chromeos/login/enrollment/enrollment_screen.h
+++ b/chrome/browser/chromeos/login/enrollment/enrollment_screen.h
@@ -10,7 +10,6 @@
 #include "base/basictypes.h"
 #include "base/compiler_specific.h"
 #include "base/memory/weak_ptr.h"
-#include "base/observer_list.h"
 #include "chrome/browser/chromeos/login/enrollment/enrollment_screen_actor.h"
 #include "chrome/browser/chromeos/login/screens/wizard_screen.h"
 #include "chrome/browser/policy/cloud/cloud_policy_constants.h"
@@ -25,15 +24,6 @@
     : public WizardScreen,
       public EnrollmentScreenActor::Controller {
  public:
-  // Used in PyAuto testing.
-  class TestingObserver {
-   public:
-    virtual ~TestingObserver() {}
-
-    // Notifies observers of a change in enrollment state.
-    virtual void OnEnrollmentComplete(bool succeeded) = 0;
-  };
-
   EnrollmentScreen(ScreenObserver* observer,
                    EnrollmentScreenActor* actor);
   virtual ~EnrollmentScreen();
@@ -61,10 +51,6 @@
     return actor_;
   }
 
-  // Used for testing.
-  void AddTestingObserver(TestingObserver* observer);
-  void RemoveTestingObserver(TestingObserver* observer);
-
  private:
   // Starts the Lockbox storage process.
   void WriteInstallAttributesData();
@@ -84,9 +70,6 @@
   // Shows the signin screen. Used as a callback to run after auth reset.
   void ShowSigninScreen();
 
-  // Notifies testing observers about the result of the enrollment.
-  void NotifyTestingObservers(bool succeeded);
-
   EnrollmentScreenActor* actor_;
   bool is_auto_enrollment_;
   bool can_exit_enrollment_;
@@ -95,9 +78,6 @@
   int lockbox_init_duration_;
   base::WeakPtrFactory<EnrollmentScreen> weak_ptr_factory_;
 
-  // Observers.
-  ObserverList<TestingObserver, true> observers_;
-
   DISALLOW_COPY_AND_ASSIGN(EnrollmentScreen);
 };
 
diff --git a/chrome/browser/chromeos/login/enrollment/enrollment_screen_actor.h b/chrome/browser/chromeos/login/enrollment/enrollment_screen_actor.h
index d9b5470..1430309 100644
--- a/chrome/browser/chromeos/login/enrollment/enrollment_screen_actor.h
+++ b/chrome/browser/chromeos/login/enrollment/enrollment_screen_actor.h
@@ -84,10 +84,6 @@
 
   // Update the UI to report the |status| of the enrollment procedure.
   virtual void ShowEnrollmentStatus(policy::EnrollmentStatus status) = 0;
-
-  // Used for testing only.
-  virtual void SubmitTestCredentials(const std::string& email,
-                                     const std::string& password) = 0;
 };
 
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/enrollment/mock_enrollment_screen.h b/chrome/browser/chromeos/login/enrollment/mock_enrollment_screen.h
index dca38f4..5687331 100644
--- a/chrome/browser/chromeos/login/enrollment/mock_enrollment_screen.h
+++ b/chrome/browser/chromeos/login/enrollment/mock_enrollment_screen.h
@@ -38,8 +38,6 @@
   MOCK_METHOD1(ShowAuthError, void(const GoogleServiceAuthError&));
   MOCK_METHOD1(ShowUIError, void(UIError));
   MOCK_METHOD1(ShowEnrollmentStatus, void(policy::EnrollmentStatus status));
-  MOCK_METHOD2(SubmitTestCredentials, void(const std::string& email,
-                                           const std::string& password));
 };
 
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/existing_user_controller.cc b/chrome/browser/chromeos/login/existing_user_controller.cc
index 505746b..aa9b0ea 100644
--- a/chrome/browser/chromeos/login/existing_user_controller.cc
+++ b/chrome/browser/chromeos/login/existing_user_controller.cc
@@ -181,8 +181,13 @@
   if (show_users_on_signin) {
     for (UserList::const_iterator it = users.begin(); it != users.end(); ++it) {
       // TODO(xiyuan): Clean user profile whose email is not in whitelist.
-      if (LoginUtils::IsWhitelisted((*it)->email()) ||
-          (*it)->GetType() != User::USER_TYPE_REGULAR) {
+      bool meets_locally_managed_requirements =
+          (*it)->GetType() != User::USER_TYPE_LOCALLY_MANAGED ||
+          UserManager::Get()->AreLocallyManagedUsersAllowed();
+      bool meets_whitelist_requirements =
+          LoginUtils::IsWhitelisted((*it)->email()) ||
+          (*it)->GetType() != User::USER_TYPE_REGULAR;
+      if (meets_locally_managed_requirements && meets_whitelist_requirements) {
         filtered_users.push_back(*it);
       }
     }
@@ -438,6 +443,11 @@
   is_login_in_progress_ = true;
   if (gaia::ExtractDomainName(user_context.username) ==
           UserManager::kLocallyManagedUserDomain) {
+    if (!UserManager::Get()->AreLocallyManagedUsersAllowed()) {
+      LOG(ERROR) << "Login attempt of locally managed user detected.";
+      login_display_->SetUIEnabled(true);
+      return;
+    }
     login_performer_->LoginAsLocallyManagedUser(
         UserContext(user_context.username,
                     user_context.password,
diff --git a/chrome/browser/chromeos/login/existing_user_controller.h b/chrome/browser/chromeos/login/existing_user_controller.h
index a9557b6..1dc7609 100644
--- a/chrome/browser/chromeos/login/existing_user_controller.h
+++ b/chrome/browser/chromeos/login/existing_user_controller.h
@@ -14,8 +14,8 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/strings/string16.h"
-#include "base/time.h"
-#include "base/timer.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
 #include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h"
 #include "chrome/browser/chromeos/login/login_display.h"
 #include "chrome/browser/chromeos/login/login_performer.h"
diff --git a/chrome/browser/chromeos/login/hwid_checker.cc b/chrome/browser/chromeos/login/hwid_checker.cc
index 9554a5e..0f1f0f6 100644
--- a/chrome/browser/chromeos/login/hwid_checker.cc
+++ b/chrome/browser/chromeos/login/hwid_checker.cc
@@ -91,7 +91,7 @@
   std::string hwid;
   chromeos::system::StatisticsProvider* stats =
       chromeos::system::StatisticsProvider::GetInstance();
-  if (!stats->GetMachineStatistic("hardware_class", &hwid)) {
+  if (!stats->GetMachineStatistic(chromeos::system::kHardwareClass, &hwid)) {
     LOG(ERROR) << "Couldn't get machine statistic 'hardware_class'.";
     return false;
   }
diff --git a/chrome/browser/chromeos/login/kiosk_browsertest.cc b/chrome/browser/chromeos/login/kiosk_browsertest.cc
index 3998ea9..5f24137 100644
--- a/chrome/browser/chromeos/login/kiosk_browsertest.cc
+++ b/chrome/browser/chromeos/login/kiosk_browsertest.cc
@@ -443,7 +443,7 @@
 
     scoped_ptr<BasicHttpResponse> http_response(new BasicHttpResponse());
     if (url.path() == "/ServiceLogin") {
-      http_response->set_code(net::test_server::SUCCESS);
+      http_response->set_code(net::HTTP_OK);
       http_response->set_content(service_login_response_);
       http_response->set_content_type("text/html");
     } else if (url.path() == "/ServiceLoginAuth") {
@@ -454,7 +454,7 @@
       int continue_arg_end = request.content.find("&", continue_arg_begin);
       const std::string continue_url = request.content.substr(
           continue_arg_begin, continue_arg_end - continue_arg_begin);
-      http_response->set_code(net::test_server::SUCCESS);
+      http_response->set_code(net::HTTP_OK);
       const std::string redirect_js =
           "document.location.href = unescape('" + continue_url + "');";
       http_response->set_content(
diff --git a/chrome/browser/chromeos/login/lock_window_aura.cc b/chrome/browser/chromeos/login/lock_window_aura.cc
index 79191b7..ea9cc17 100644
--- a/chrome/browser/chromeos/login/lock_window_aura.cc
+++ b/chrome/browser/chromeos/login/lock_window_aura.cc
@@ -43,7 +43,7 @@
   views::Widget::InitParams params(
       views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
   params.show_state = ui::SHOW_STATE_FULLSCREEN;
-  params.transparent = true;
+  params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
   // TODO(oshima): move the lock screen harness to ash.
   params.parent =
       ash::Shell::GetContainer(
diff --git a/chrome/browser/chromeos/login/login_display_host_impl.cc b/chrome/browser/chromeos/login/login_display_host_impl.cc
index aa656d2..67fe948 100644
--- a/chrome/browser/chromeos/login/login_display_host_impl.cc
+++ b/chrome/browser/chromeos/login/login_display_host_impl.cc
@@ -18,7 +18,7 @@
 #include "base/prefs/pref_service.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/thread_restrictions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/browser_shutdown.h"
@@ -42,6 +42,7 @@
 #include "chrome/browser/chromeos/policy/auto_enrollment_client.h"
 #include "chrome/browser/chromeos/system/statistics_provider.h"
 #include "chrome/browser/chromeos/system/timezone_settings.h"
+#include "chrome/browser/chromeos/ui/focus_ring_controller.h"
 #include "chrome/browser/lifetime/application_lifetime.h"
 #include "chrome/browser/managed_mode/managed_mode.h"
 #include "chrome/browser/policy/browser_policy_connector.h"
@@ -261,9 +262,14 @@
 
   bool keyboard_driven_oobe = false;
   system::StatisticsProvider::GetInstance()->GetMachineFlag(
-      chromeos::kOemKeyboardDrivenOobeKey, &keyboard_driven_oobe);
-  if (keyboard_driven_oobe)
+      chromeos::system::kOemKeyboardDrivenOobeKey,
+      &keyboard_driven_oobe);
+  if (keyboard_driven_oobe) {
     views::FocusManager::set_arrow_key_traversal_enabled(true);
+
+    focus_ring_controller_.reset(new FocusRingController);
+    focus_ring_controller_->SetVisible(true);
+  }
 }
 
 LoginDisplayHostImpl::~LoginDisplayHostImpl() {
@@ -753,7 +759,7 @@
       views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
   params.bounds = background_bounds();
   params.show_state = ui::SHOW_STATE_FULLSCREEN;
-  params.transparent = true;
+  params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
   params.parent =
       ash::Shell::GetContainer(
           ash::Shell::GetPrimaryRootWindow(),
diff --git a/chrome/browser/chromeos/login/login_display_host_impl.h b/chrome/browser/chromeos/login/login_display_host_impl.h
index 14d8251..42c279e 100644
--- a/chrome/browser/chromeos/login/login_display_host_impl.h
+++ b/chrome/browser/chromeos/login/login_display_host_impl.h
@@ -29,6 +29,7 @@
 
 namespace chromeos {
 
+class FocusRingController;
 class OobeUI;
 class WebUILoginDisplay;
 class WebUILoginView;
@@ -221,6 +222,10 @@
   // Active instance of authentication prewarmer.
   scoped_ptr<AuthPrewarmer> auth_prewarmer_;
 
+  // A focus ring controller to draw focus ring around view for keyboard
+  // driven oobe.
+  scoped_ptr<FocusRingController> focus_ring_controller_;
+
   DISALLOW_COPY_AND_ASSIGN(LoginDisplayHostImpl);
 };
 
diff --git a/chrome/browser/chromeos/login/login_utils.cc b/chrome/browser/chromeos/login/login_utils.cc
index ecb901d..98f1764 100644
--- a/chrome/browser/chromeos/login/login_utils.cc
+++ b/chrome/browser/chromeos/login/login_utils.cc
@@ -26,7 +26,7 @@
 #include "base/synchronization/lock.h"
 #include "base/task_runner_util.h"
 #include "base/threading/worker_pool.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/about_flags.h"
 #include "chrome/browser/app_mode/app_mode_utils.h"
 #include "chrome/browser/browser_process.h"
@@ -254,7 +254,9 @@
   CommandLine user_flags(CommandLine::NO_PROGRAM);
   about_flags::PrefServiceFlagsStorage flags_storage_(profile->GetPrefs());
   about_flags::ConvertFlagsToSwitches(&flags_storage_, &user_flags);
-  if (!about_flags::AreSwitchesIdenticalToCurrentCommandLine(
+  // Only restart if needed and if not going into managed mode.
+  if (!UserManager::Get()->IsLoggedInAsLocallyManagedUser() &&
+      !about_flags::AreSwitchesIdenticalToCurrentCommandLine(
           user_flags, *CommandLine::ForCurrentProcess())) {
     CommandLine::StringVector flags;
     // argv[0] is the program name |CommandLine::NO_PROGRAM|.
diff --git a/chrome/browser/chromeos/login/login_utils_browsertest.cc b/chrome/browser/chromeos/login/login_utils_browsertest.cc
index 9b633a0..275c521 100644
--- a/chrome/browser/chromeos/login/login_utils_browsertest.cc
+++ b/chrome/browser/chromeos/login/login_utils_browsertest.cc
@@ -736,4 +736,4 @@
 
 }  // namespace
 
-}  // namespace chromeos
+}
diff --git a/chrome/browser/chromeos/login/managed/locally_managed_user_creation_controller.cc b/chrome/browser/chromeos/login/managed/locally_managed_user_creation_controller.cc
index 6ce2359..55b1d82 100644
--- a/chrome/browser/chromeos/login/managed/locally_managed_user_creation_controller.cc
+++ b/chrome/browser/chromeos/login/managed/locally_managed_user_creation_controller.cc
@@ -90,6 +90,12 @@
 
 void LocallyManagedUserCreationController::StartCreation() {
   DCHECK(creation_context_);
+  VLOG(1) << "Starting supervised user creation";
+  timeout_timer_.Start(
+      FROM_HERE, base::TimeDelta::FromSeconds(kUserCreationTimeoutSeconds),
+      this,
+      &LocallyManagedUserCreationController::CreationTimedOut);
+
   UserManager::Get()->StartLocallyManagedUserCreationTransaction(
       creation_context_->display_name);
 
@@ -102,7 +108,7 @@
 
   UserManager::Get()->SetLocallyManagedUserCreationTransactionUserId(
       creation_context_->user_id);
-
+  VLOG(1) << "Creating cryptohome";
   authenticator_ = new ManagedUserAuthenticator(this);
   authenticator_->AuthenticateToCreate(user->email(),
                                        creation_context_->password);
@@ -110,6 +116,7 @@
 
 void LocallyManagedUserCreationController::OnAuthenticationFailure(
     ManagedUserAuthenticator::AuthState error) {
+  timeout_timer_.Stop();
   ErrorCode code = NO_ERROR;
   switch (error) {
     case ManagedUserAuthenticator::NO_MOUNT:
@@ -138,18 +145,18 @@
   creation_context_->master_key = StringToLowerASCII(base::HexEncode(
       reinterpret_cast<const void*>(master_key_bytes),
       sizeof(master_key_bytes)));
-  // TODO(antrim): Add this key as secondary as soon as wad@ adds API in
-  // cryptohome.
+  VLOG(1) << "Adding master key";
+  authenticator_->AddMasterKey(creation_context_->user_id,
+                               creation_context_->password,
+                               creation_context_->master_key);
+}
 
-  timeout_timer_.Start(
-      FROM_HERE, base::TimeDelta::FromSeconds(kUserCreationTimeoutSeconds),
-      this,
-      &LocallyManagedUserCreationController::CreationTimedOut);
-
+void LocallyManagedUserCreationController::OnAddKeySuccess() {
   creation_context_->service =
       ManagedUserRegistrationServiceFactory::GetForProfile(
           creation_context_->manager_profile);
 
+  VLOG(1) << "Creating user on server";
   ManagedUserRegistrationInfo info(creation_context_->display_name);
   info.master_key = creation_context_->master_key;
   creation_context_->service->Register(
@@ -161,20 +168,18 @@
 void LocallyManagedUserCreationController::RegistrationCallback(
     const GoogleServiceAuthError& error,
     const std::string& token) {
-  timeout_timer_.Stop();
   if (error.state() == GoogleServiceAuthError::NONE) {
     TokenFetched(token);
   } else {
-    // Do not report error if we cancelled request.
+    timeout_timer_.Stop();
     LOG(ERROR) << "Managed user creation failed. Error code " << error.state();
-    if (error.state() == GoogleServiceAuthError::REQUEST_CANCELED)
-      return;
     if (consumer_)
       consumer_->OnCreationError(CLOUD_SERVER_ERROR);
   }
 }
 
 void LocallyManagedUserCreationController::CreationTimedOut() {
+  LOG(ERROR) << "Supervised user creation timed out.";
   if (consumer_)
     consumer_->OnCreationTimeout();
 }
@@ -212,6 +217,7 @@
 
 void LocallyManagedUserCreationController::OnManagedUserFilesStored(
     bool success) {
+  timeout_timer_.Stop();
   if (!success) {
     if (consumer_)
       consumer_->OnCreationError(TOKEN_WRITE_FAILED);
diff --git a/chrome/browser/chromeos/login/managed/locally_managed_user_creation_controller.h b/chrome/browser/chromeos/login/managed/locally_managed_user_creation_controller.h
index cd0fa83..2185fe8 100644
--- a/chrome/browser/chromeos/login/managed/locally_managed_user_creation_controller.h
+++ b/chrome/browser/chromeos/login/managed/locally_managed_user_creation_controller.h
@@ -11,7 +11,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/strings/string16.h"
-#include "base/timer.h"
+#include "base/timer/timer.h"
 #include "chrome/browser/chromeos/login/managed/managed_user_authenticator.h"
 #include "chrome/browser/managed_mode/managed_user_registration_service.h"
 
@@ -94,6 +94,7 @@
   virtual void OnAuthenticationFailure(
       ManagedUserAuthenticator::AuthState error) OVERRIDE;
   virtual void OnMountSuccess(const std::string& mount_hash) OVERRIDE;
+  virtual void OnAddKeySuccess() OVERRIDE;
 
   void CreationTimedOut();
   void RegistrationCallback(const GoogleServiceAuthError& error,
diff --git a/chrome/browser/chromeos/login/managed/locally_managed_user_creation_screen.cc b/chrome/browser/chromeos/login/managed/locally_managed_user_creation_screen.cc
index cb83007..78fe1b1 100644
--- a/chrome/browser/chromeos/login/managed/locally_managed_user_creation_screen.cc
+++ b/chrome/browser/chromeos/login/managed/locally_managed_user_creation_screen.cc
@@ -5,14 +5,20 @@
 #include "chrome/browser/chromeos/login/managed/locally_managed_user_creation_screen.h"
 
 #include "base/values.h"
+#include "chrome/browser/chromeos/camera_detector.h"
 #include "chrome/browser/chromeos/login/existing_user_controller.h"
 #include "chrome/browser/chromeos/login/managed/locally_managed_user_creation_controller.h"
 #include "chrome/browser/chromeos/login/screens/error_screen.h"
 #include "chrome/browser/chromeos/login/screens/screen_observer.h"
+#include "chrome/browser/chromeos/login/user_image.h"
+#include "chrome/browser/chromeos/login/user_image_manager.h"
 #include "chrome/browser/chromeos/login/wizard_controller.h"
 #include "chromeos/network/network_state.h"
+#include "content/public/browser/browser_thread.h"
 #include "grit/generated_resources.h"
+#include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/base/l10n/l10n_util.h"
+#include "ui/gfx/image/image_skia.h"
 
 namespace chromeos {
 
@@ -51,9 +57,13 @@
     ScreenObserver* observer,
     LocallyManagedUserCreationScreenHandler* actor)
     : WizardScreen(observer),
+      weak_factory_(this),
       actor_(actor),
       on_error_screen_(false),
-      on_image_screen_(false) {
+      on_image_screen_(false),
+      image_decoder_(NULL),
+      apply_photo_after_decoding_(false),
+      selected_image_(0) {
   DCHECK(actor_);
   if (actor_)
     actor_->SetDelegate(this);
@@ -62,6 +72,8 @@
 LocallyManagedUserCreationScreen::~LocallyManagedUserCreationScreen() {
   if (actor_)
     actor_->SetDelegate(NULL);
+  if (image_decoder_.get())
+    image_decoder_->set_delegate(NULL);
 }
 
 void LocallyManagedUserCreationScreen::PrepareToShow() {
@@ -221,22 +233,6 @@
     actor_->ShowErrorPage(title, message, button);
 }
 
-void LocallyManagedUserCreationScreen::SelectPicture() {
-  on_image_screen_ = true;
-  WizardController::default_controller()->
-      EnableUserImageScreenReturnToPreviousHack();
-  DictionaryValue* params = new DictionaryValue();
-  params->SetBoolean("profile_picture_enabled", false);
-  params->SetString("user_id", controller_->GetManagedUserId());
-
-  WizardController::default_controller()->
-      AdvanceToScreenWithParams(WizardController::kUserImageScreenName, params);
-}
-
-void LocallyManagedUserCreationScreen::OnCreationSuccess() {
-  SelectPicture();
-}
-
 void LocallyManagedUserCreationScreen::OnCreationTimeout() {
   if (actor_) {
     actor_->ShowStatusMessage(false /* error */, l10n_util::GetStringUTF16(
@@ -244,4 +240,97 @@
   }
 }
 
+// TODO(antrim) : this is an explicit code duplications with UserImageScreen.
+// It should be removed by issue 251179.
+
+void LocallyManagedUserCreationScreen::ApplyPicture() {
+  UserManager* user_manager = UserManager::Get();
+  UserImageManager* image_manager = user_manager->GetUserImageManager();
+  std::string user_id = controller_->GetManagedUserId();
+  switch (selected_image_) {
+    case User::kExternalImageIndex:
+      // Photo decoding may not have been finished yet.
+      if (user_photo_.isNull()) {
+        apply_photo_after_decoding_ = true;
+        return;
+      }
+      image_manager->
+          SaveUserImage(user_id, UserImage::CreateAndEncode(user_photo_));
+      break;
+    case User::kProfileImageIndex:
+      NOTREACHED() << "Supervised users have no profile pictures";
+      break;
+    default:
+      DCHECK(selected_image_ >= 0 && selected_image_ < kDefaultImagesCount);
+      image_manager->SaveUserDefaultImageIndex(user_id, selected_image_);
+      break;
+  }
+  // Proceed to tutorial.
+  actor_->ShowTutorialPage();
+}
+
+void LocallyManagedUserCreationScreen::OnCreationSuccess() {
+  ApplyPicture();
+}
+
+void LocallyManagedUserCreationScreen::CheckCameraPresence() {
+  CameraDetector::StartPresenceCheck(
+      base::Bind(&LocallyManagedUserCreationScreen::OnCameraPresenceCheckDone,
+                 weak_factory_.GetWeakPtr()));
+}
+
+void LocallyManagedUserCreationScreen::OnCameraPresenceCheckDone() {
+  if (actor_) {
+    actor_->SetCameraPresent(
+        CameraDetector::camera_presence() == CameraDetector::kCameraPresent);
+  }
+}
+
+void LocallyManagedUserCreationScreen::OnPhotoTaken(
+    const std::string& raw_data) {
+  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+  user_photo_ = gfx::ImageSkia();
+  if (image_decoder_.get())
+    image_decoder_->set_delegate(NULL);
+  image_decoder_ = new ImageDecoder(this, raw_data,
+                                    ImageDecoder::DEFAULT_CODEC);
+  scoped_refptr<base::MessageLoopProxy> task_runner =
+      content::BrowserThread::GetMessageLoopProxyForThread(
+          content::BrowserThread::UI);
+  image_decoder_->Start(task_runner);
+}
+
+void LocallyManagedUserCreationScreen::OnImageDecoded(
+    const ImageDecoder* decoder,
+    const SkBitmap& decoded_image) {
+  DCHECK_EQ(image_decoder_.get(), decoder);
+  user_photo_ = gfx::ImageSkia::CreateFrom1xBitmap(decoded_image);
+  if (apply_photo_after_decoding_)
+    ApplyPicture();
+}
+
+void LocallyManagedUserCreationScreen::OnDecodeImageFailed(
+    const ImageDecoder* decoder) {
+  NOTREACHED() << "Failed to decode PNG image from WebUI";
+}
+
+void LocallyManagedUserCreationScreen::OnImageSelected(
+    const std::string& image_type,
+    const std::string& image_url) {
+  if (image_url.empty())
+    return;
+  int user_image_index = User::kInvalidImageIndex;
+  if (image_type == "default" &&
+      IsDefaultImageUrl(image_url, &user_image_index)) {
+    selected_image_ = user_image_index;
+  } else if (image_type == "camera") {
+    selected_image_ = User::kExternalImageIndex;
+  } else {
+    NOTREACHED() << "Unexpected image type: " << image_type;
+  }
+}
+
+void LocallyManagedUserCreationScreen::OnImageAccepted() {
+}
+
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/managed/locally_managed_user_creation_screen.h b/chrome/browser/chromeos/login/managed/locally_managed_user_creation_screen.h
index efef788..f5b338d 100644
--- a/chrome/browser/chromeos/login/managed/locally_managed_user_creation_screen.h
+++ b/chrome/browser/chromeos/login/managed/locally_managed_user_creation_screen.h
@@ -12,7 +12,9 @@
 #include "chrome/browser/chromeos/login/managed/locally_managed_user_creation_controller.h"
 #include "chrome/browser/chromeos/login/screens/wizard_screen.h"
 #include "chrome/browser/chromeos/net/network_portal_detector.h"
+#include "chrome/browser/image_decoder.h"
 #include "chrome/browser/ui/webui/chromeos/login/locally_managed_user_creation_screen_handler.h"
+#include "ui/gfx/image/image_skia.h"
 
 class Profile;
 
@@ -25,6 +27,7 @@
     : public WizardScreen,
       public LocallyManagedUserCreationScreenHandler::Delegate,
       public LocallyManagedUserCreationController::StatusConsumer,
+      public ImageDecoder::Delegate,
       public NetworkPortalDetector::Observer {
  public:
   LocallyManagedUserCreationScreen(
@@ -73,7 +76,6 @@
       const std::string& manager_password) OVERRIDE;
   virtual void AbortFlow() OVERRIDE;
   virtual void FinishFlow() OVERRIDE;
-  virtual void SelectPicture() OVERRIDE;
 
   // LocallyManagedUserController::StatusConsumer overrides.
   virtual void OnCreationError(
@@ -85,7 +87,26 @@
   virtual void OnPortalDetectionCompleted(
           const NetworkState* network,
           const NetworkPortalDetector::CaptivePortalState& state) OVERRIDE;
+
+  // TODO(antrim) : this is an explicit code duplications with UserImageScreen.
+  // It should be removed by issue 251179.
+
+  // LocallyManagedUserCreationScreenHandler::Delegate (image) implementation:
+  virtual void CheckCameraPresence() OVERRIDE;
+  virtual void OnPhotoTaken(const std::string& raw_data) OVERRIDE;
+  virtual void OnImageSelected(const std::string& image_url,
+                               const std::string& image_type) OVERRIDE;
+  virtual void OnImageAccepted() OVERRIDE;
+  // ImageDecoder::Delegate overrides:
+  virtual void OnImageDecoded(const ImageDecoder* decoder,
+                              const SkBitmap& decoded_image) OVERRIDE;
+  virtual void OnDecodeImageFailed(const ImageDecoder* decoder) OVERRIDE;
+
  private:
+  void ApplyPicture();
+  void OnCameraPresenceCheckDone();
+
+  base::WeakPtrFactory<LocallyManagedUserCreationScreen> weak_factory_;
   LocallyManagedUserCreationScreenHandler* actor_;
 
   scoped_ptr<LocallyManagedUserCreationController> controller_;
@@ -93,6 +114,11 @@
   bool on_error_screen_;
   bool on_image_screen_;
 
+  gfx::ImageSkia user_photo_;
+  scoped_refptr<ImageDecoder> image_decoder_;
+  bool apply_photo_after_decoding_;
+  int selected_image_;
+
   DISALLOW_COPY_AND_ASSIGN(LocallyManagedUserCreationScreen);
 };
 
diff --git a/chrome/browser/chromeos/login/managed/managed_user_authenticator.cc b/chrome/browser/chromeos/login/managed/managed_user_authenticator.cc
index 1f82c38..4984cf0 100644
--- a/chrome/browser/chromeos/login/managed/managed_user_authenticator.cc
+++ b/chrome/browser/chromeos/login/managed/managed_user_authenticator.cc
@@ -64,7 +64,6 @@
 void Mount(ManagedUserAuthenticator::AuthAttempt* attempt,
            scoped_refptr<ManagedUserAuthenticator> resolver,
            int flags) {
-  // TODO(antrim) : use additional mount function here.
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   chromeos::BootTimesLoader::Get()->AddLoginTimeMarker(
       "CryptohomeMount-LMU-Start", false);
@@ -82,6 +81,23 @@
       base::Bind(&TriggerResolveResult, attempt, resolver));
 }
 
+// Calls cryptohome's addKey method.
+void AddKey(ManagedUserAuthenticator::AuthAttempt* attempt,
+            scoped_refptr<ManagedUserAuthenticator> resolver,
+            const std::string& hashed_master_key) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  chromeos::BootTimesLoader::Get()->AddLoginTimeMarker(
+      "CryptohomeAddKey-LMU-Start", false);
+  cryptohome::AsyncMethodCaller::GetInstance()->AsyncAddKey(
+      attempt->username,
+      attempt->hashed_password,
+      hashed_master_key,
+      base::Bind(&TriggerResolveWithLoginTimeMarker,
+                 "CryptohomeAddKey-LMU-End",
+                 attempt,
+                 resolver));
+}
+
 // Returns hash of |password|, salted with the system salt.
 std::string HashPassword(const std::string& password) {
   // Get salt, ascii encode, update sha with that, then update with ascii
@@ -106,12 +122,13 @@
 ManagedUserAuthenticator::ManagedUserAuthenticator(AuthStatusConsumer* consumer)
     : consumer_(consumer) {}
 
-void ManagedUserAuthenticator::AuthenticateToMount(const std::string& username,
-                                               const std::string& password) {
+void ManagedUserAuthenticator::AuthenticateToMount(
+    const std::string& username,
+    const std::string& password) {
   std::string canonicalized = gaia::CanonicalizeEmail(username);
 
   current_state_.reset(new ManagedUserAuthenticator::AuthAttempt(
-      canonicalized, password, HashPassword(password)));
+      canonicalized, password, HashPassword(password), false));
 
   BrowserThread::PostTask(BrowserThread::UI,
       FROM_HERE,
@@ -121,13 +138,13 @@
           cryptohome::MOUNT_FLAGS_NONE));
 }
 
-void ManagedUserAuthenticator::AuthenticateToCreate(const std::string& username,
-                                                const std::string& password) {
-
+void ManagedUserAuthenticator::AuthenticateToCreate(
+    const std::string& username,
+    const std::string& password) {
   std::string canonicalized = gaia::CanonicalizeEmail(username);
 
   current_state_.reset(new ManagedUserAuthenticator::AuthAttempt(
-      canonicalized, password, HashPassword(password)));
+      canonicalized, password, HashPassword(password), false));
 
   BrowserThread::PostTask(BrowserThread::UI,
       FROM_HERE,
@@ -137,13 +154,34 @@
            cryptohome::CREATE_IF_MISSING));
 }
 
+void ManagedUserAuthenticator::AddMasterKey(
+    const std::string& username,
+    const std::string& password,
+    const std::string& master_key) {
+  std::string canonicalized = gaia::CanonicalizeEmail(username);
+
+  current_state_.reset(new ManagedUserAuthenticator::AuthAttempt(
+      canonicalized, password, HashPassword(password), true));
+
+  BrowserThread::PostTask(BrowserThread::UI,
+      FROM_HERE,
+      base::Bind(&AddKey,
+           current_state_.get(),
+           scoped_refptr<ManagedUserAuthenticator>(this),
+           HashPassword(master_key)));
+}
+
 void ManagedUserAuthenticator::OnAuthenticationSuccess(
-    const std::string& mount_hash) {
+    const std::string& mount_hash,
+    bool add_key) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   VLOG(1) << "Locally managed user authentication success";
-
-  if (consumer_)
-    consumer_->OnMountSuccess(mount_hash);
+  if (consumer_) {
+    if (add_key)
+      consumer_->OnAddKeySuccess();
+    else
+      consumer_->OnMountSuccess(mount_hash);
+  }
 }
 
 void ManagedUserAuthenticator::OnAuthenticationFailure(
@@ -200,7 +238,8 @@
           FROM_HERE,
           base::Bind(&ManagedUserAuthenticator::OnAuthenticationSuccess,
                      this,
-                     current_state_->hash()));
+                     current_state_->hash(),
+                     current_state_->add_key));
       break;
     default:
       NOTREACHED();
@@ -217,7 +256,7 @@
   // This is an important invariant.
   if (!current_state_->cryptohome_complete())
     return CONTINUE;
-  if (!current_state_->hash_obtained())
+  if (!current_state_->add_key && !current_state_->hash_obtained())
     return CONTINUE;
 
   AuthState state;
@@ -228,7 +267,7 @@
     state = ResolveCryptohomeFailureState();
 
   DCHECK(current_state_->cryptohome_complete());
-  DCHECK(current_state_->hash_obtained());
+  DCHECK(current_state_->hash_obtained() || current_state_->add_key);
   return state;
 }
 
@@ -258,11 +297,13 @@
 }
 
 ManagedUserAuthenticator::AuthAttempt::AuthAttempt(const std::string& username,
-                                               const std::string& password,
-                                               const std::string& hashed)
+                                                   const std::string& password,
+                                                   const std::string& hashed,
+                                                   bool add_key_attempt)
     : username(username),
       password(password),
       hashed_password(hashed),
+      add_key(add_key_attempt),
       cryptohome_complete_(false),
       cryptohome_outcome_(false),
       hash_obtained_(false),
diff --git a/chrome/browser/chromeos/login/managed/managed_user_authenticator.h b/chrome/browser/chromeos/login/managed/managed_user_authenticator.h
index 19b0c3d..2e12630 100644
--- a/chrome/browser/chromeos/login/managed/managed_user_authenticator.h
+++ b/chrome/browser/chromeos/login/managed/managed_user_authenticator.h
@@ -35,7 +35,8 @@
    public:
     AuthAttempt(const std::string& username,
                 const std::string& password,
-                const std::string& hashed_password);
+                const std::string& hashed_password,
+                bool add_key_attempt);
     ~AuthAttempt();
 
     // Copy |cryptohome_code| and |cryptohome_outcome| into this object,
@@ -58,6 +59,7 @@
     const std::string username;
     const std::string password;
     const std::string hashed_password;
+    const bool add_key;
 
    private:
     bool cryptohome_complete_;
@@ -76,6 +78,8 @@
     virtual void OnAuthenticationFailure(AuthState state) = 0;
     // The current login attempt has ended succesfully.
     virtual void OnMountSuccess(const std::string& mount_hash) = 0;
+    // The current add key attempt has ended succesfully.
+    virtual void OnAddKeySuccess() = 0;
   };
 
   explicit ManagedUserAuthenticator(AuthStatusConsumer* consumer);
@@ -85,6 +89,10 @@
 
   void AuthenticateToCreate(const std::string& username,
                             const std::string& password);
+
+  void AddMasterKey(const std::string& username,
+                    const std::string& password,
+                    const std::string& master_key);
   void Resolve();
 
  private:
@@ -95,7 +103,7 @@
   AuthState ResolveState();
   AuthState ResolveCryptohomeFailureState();
   AuthState ResolveCryptohomeSuccessState();
-  void OnAuthenticationSuccess(const std::string& mount_hash);
+  void OnAuthenticationSuccess(const std::string& mount_hash, bool add_key);
   void OnAuthenticationFailure(AuthState state);
 
   scoped_ptr<AuthAttempt> current_state_;
diff --git a/chrome/browser/chromeos/login/mock_user_manager.h b/chrome/browser/chromeos/login/mock_user_manager.h
index 92efb2b..503f04a 100644
--- a/chrome/browser/chromeos/login/mock_user_manager.h
+++ b/chrome/browser/chromeos/login/mock_user_manager.h
@@ -95,6 +95,7 @@
                                                      std::string*));
   MOCK_METHOD2(SetAppModeChromeClientOAuthInfo, void(const std::string&,
                                                      const std::string&));
+  MOCK_CONST_METHOD0(AreLocallyManagedUsersAllowed, bool(void));
 
   // You can't mock these functions easily because nobody can create
   // User objects but the UserManagerImpl and us.
diff --git a/chrome/browser/chromeos/login/oauth2_login_verifier.cc b/chrome/browser/chromeos/login/oauth2_login_verifier.cc
index ad31626..abff7b1 100644
--- a/chrome/browser/chromeos/login/oauth2_login_verifier.cc
+++ b/chrome/browser/chromeos/login/oauth2_login_verifier.cc
@@ -10,7 +10,7 @@
 #include "base/metrics/histogram.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/chromeos/cros/cros_library.h"
 #include "chrome/browser/chromeos/net/connectivity_state_helper.h"
 #include "content/public/browser/browser_thread.h"
diff --git a/chrome/browser/chromeos/login/oobe_browsertest.cc b/chrome/browser/chromeos/login/oobe_browsertest.cc
index 676fe87..ec6c1f8 100644
--- a/chrome/browser/chromeos/login/oobe_browsertest.cc
+++ b/chrome/browser/chromeos/login/oobe_browsertest.cc
@@ -176,7 +176,7 @@
 
     scoped_ptr<BasicHttpResponse> http_response(new BasicHttpResponse());
     if (url.path() == "/ServiceLogin") {
-      http_response->set_code(net::test_server::SUCCESS);
+      http_response->set_code(net::HTTP_OK);
       http_response->set_content(service_login_response_);
       http_response->set_content_type("text/html");
     } else if (url.path() == "/ServiceLoginAuth") {
@@ -187,7 +187,7 @@
       int continue_arg_end = request.content.find("&", continue_arg_begin);
       const std::string continue_url = request.content.substr(
           continue_arg_begin, continue_arg_end - continue_arg_begin);
-      http_response->set_code(net::test_server::SUCCESS);
+      http_response->set_code(net::HTTP_OK);
       const std::string redirect_js =
           "document.location.href = unescape('" + continue_url + "');";
       http_response->set_content(
diff --git a/chrome/browser/chromeos/login/screen_locker.cc b/chrome/browser/chromeos/login/screen_locker.cc
index 263c7ca..f2b0bda 100644
--- a/chrome/browser/chromeos/login/screen_locker.cc
+++ b/chrome/browser/chromeos/login/screen_locker.cc
@@ -18,7 +18,7 @@
 #include "base/message_loop.h"
 #include "base/metrics/histogram.h"
 #include "base/strings/string_util.h"
-#include "base/timer.h"
+#include "base/timer/timer.h"
 #include "chrome/browser/chromeos/login/authenticator.h"
 #include "chrome/browser/chromeos/login/login_performer.h"
 #include "chrome/browser/chromeos/login/login_utils.h"
diff --git a/chrome/browser/chromeos/login/screen_locker.h b/chrome/browser/chromeos/login/screen_locker.h
index eac312c..42c8a52 100644
--- a/chrome/browser/chromeos/login/screen_locker.h
+++ b/chrome/browser/chromeos/login/screen_locker.h
@@ -11,7 +11,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/sequenced_task_runner_helpers.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/chromeos/login/help_app_launcher.h"
 #include "chrome/browser/chromeos/login/login_status_consumer.h"
 #include "chrome/browser/chromeos/login/screen_locker_delegate.h"
diff --git a/chrome/browser/chromeos/login/screens/network_screen.cc b/chrome/browser/chromeos/login/screens/network_screen.cc
index c79d620..167c867 100644
--- a/chrome/browser/chromeos/login/screens/network_screen.cc
+++ b/chrome/browser/chromeos/login/screens/network_screen.cc
@@ -59,9 +59,9 @@
 }
 
 void NetworkScreen::Show() {
+  Refresh();
   if (actor_)
     actor_->Show();
-  Refresh();
 }
 
 void NetworkScreen::Hide() {
diff --git a/chrome/browser/chromeos/login/screens/network_screen.h b/chrome/browser/chromeos/login/screens/network_screen.h
index ad9fdf6..1a3ccf2 100644
--- a/chrome/browser/chromeos/login/screens/network_screen.h
+++ b/chrome/browser/chromeos/login/screens/network_screen.h
@@ -8,7 +8,7 @@
 #include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
 #include "base/strings/string16.h"
-#include "base/timer.h"
+#include "base/timer/timer.h"
 #include "chrome/browser/chromeos/login/language_switch_menu.h"
 #include "chrome/browser/chromeos/login/screens/network_screen_actor.h"
 #include "chrome/browser/chromeos/login/screens/wizard_screen.h"
diff --git a/chrome/browser/chromeos/login/screens/terms_of_service_screen.cc b/chrome/browser/chromeos/login/screens/terms_of_service_screen.cc
index f5be2fd..4cc4060 100644
--- a/chrome/browser/chromeos/login/screens/terms_of_service_screen.cc
+++ b/chrome/browser/chromeos/login/screens/terms_of_service_screen.cc
@@ -9,7 +9,7 @@
 #include "base/location.h"
 #include "base/logging.h"
 #include "base/prefs/pref_service.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chromeos/login/screens/screen_observer.h"
 #include "chrome/browser/chromeos/login/wizard_controller.h"
diff --git a/chrome/browser/chromeos/login/screens/terms_of_service_screen.h b/chrome/browser/chromeos/login/screens/terms_of_service_screen.h
index c1cec5d..1b79569 100644
--- a/chrome/browser/chromeos/login/screens/terms_of_service_screen.h
+++ b/chrome/browser/chromeos/login/screens/terms_of_service_screen.h
@@ -8,7 +8,7 @@
 #include "base/basictypes.h"
 #include "base/compiler_specific.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/timer.h"
+#include "base/timer/timer.h"
 #include "chrome/browser/chromeos/login/screens/terms_of_service_screen_actor.h"
 #include "chrome/browser/chromeos/login/screens/wizard_screen.h"
 #include "net/url_request/url_fetcher_delegate.h"
diff --git a/chrome/browser/chromeos/login/screens/update_screen.h b/chrome/browser/chromeos/login/screens/update_screen.h
index bdfd26b..cb10c67 100644
--- a/chrome/browser/chromeos/login/screens/update_screen.h
+++ b/chrome/browser/chromeos/login/screens/update_screen.h
@@ -11,8 +11,8 @@
 #include "base/compiler_specific.h"
 #include "base/gtest_prod_util.h"
 #include "base/memory/weak_ptr.h"
-#include "base/time.h"
-#include "base/timer.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
 #include "chrome/browser/chromeos/login/screens/update_screen_actor.h"
 #include "chrome/browser/chromeos/login/screens/wizard_screen.h"
 #include "chrome/browser/chromeos/net/network_portal_detector.h"
diff --git a/chrome/browser/chromeos/login/screens/update_screen_actor.h b/chrome/browser/chromeos/login/screens/update_screen_actor.h
index d17276c..89095ae 100644
--- a/chrome/browser/chromeos/login/screens/update_screen_actor.h
+++ b/chrome/browser/chromeos/login/screens/update_screen_actor.h
@@ -5,7 +5,7 @@
 #ifndef CHROME_BROWSER_CHROMEOS_LOGIN_SCREENS_UPDATE_SCREEN_ACTOR_H_
 #define CHROME_BROWSER_CHROMEOS_LOGIN_SCREENS_UPDATE_SCREEN_ACTOR_H_
 
-#include "base/time.h"
+#include "base/time/time.h"
 
 namespace chromeos {
 
diff --git a/chrome/browser/chromeos/login/screens/user_image_screen.cc b/chrome/browser/chromeos/login/screens/user_image_screen.cc
index 7fd947e..def0424 100644
--- a/chrome/browser/chromeos/login/screens/user_image_screen.cc
+++ b/chrome/browser/chromeos/login/screens/user_image_screen.cc
@@ -166,7 +166,7 @@
 }
 
 void UserImageScreen::SetUserID(const std::string& user_id) {
-  DCHECK(!user_id_.empty());
+  DCHECK(!user_id.empty());
   user_id_ = user_id;
 }
 
diff --git a/chrome/browser/chromeos/login/user_image_manager_browsertest.cc b/chrome/browser/chromeos/login/user_image_manager_browsertest.cc
index 4e967e8..e485561 100644
--- a/chrome/browser/chromeos/login/user_image_manager_browsertest.cc
+++ b/chrome/browser/chromeos/login/user_image_manager_browsertest.cc
@@ -250,7 +250,8 @@
   EXPECT_EQ(saved_image.height(), user->image().height());
 }
 
-IN_PROC_BROWSER_TEST_F(UserImageManagerTest, NonJPEGImageFromFile) {
+// http://crbug.com/257009.
+IN_PROC_BROWSER_TEST_F(UserImageManagerTest, DISABLED_NonJPEGImageFromFile) {
   ExpectImageChange();
   UserManager::Get()->GetUsers();  // Load users.
   // Wait for image load.
diff --git a/chrome/browser/chromeos/login/user_image_manager_impl.cc b/chrome/browser/chromeos/login/user_image_manager_impl.cc
index 0af1479..f22a8d4 100644
--- a/chrome/browser/chromeos/login/user_image_manager_impl.cc
+++ b/chrome/browser/chromeos/login/user_image_manager_impl.cc
@@ -15,7 +15,7 @@
 #include "base/prefs/pref_service.h"
 #include "base/rand_util.h"
 #include "base/threading/worker_pool.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chromeos/login/default_user_images.h"
@@ -145,7 +145,7 @@
   BrowserThread::PostTask(
       BrowserThread::FILE,
       FROM_HERE,
-      base::Bind(base::IgnoreResult(&file_util::Delete),
+      base::Bind(base::IgnoreResult(&base::Delete),
                  fp, /* recursive= */  false));
 }
 
diff --git a/chrome/browser/chromeos/login/user_image_manager_impl.h b/chrome/browser/chromeos/login/user_image_manager_impl.h
index e6fb534..ef6da72 100644
--- a/chrome/browser/chromeos/login/user_image_manager_impl.h
+++ b/chrome/browser/chromeos/login/user_image_manager_impl.h
@@ -10,8 +10,8 @@
 
 #include "base/basictypes.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/time.h"
-#include "base/timer.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
 #include "chrome/browser/chromeos/login/user.h"
 #include "chrome/browser/chromeos/login/user_image_loader.h"
 #include "chrome/browser/chromeos/login/user_image_manager.h"
diff --git a/chrome/browser/chromeos/login/user_manager.h b/chrome/browser/chromeos/login/user_manager.h
index 49c3448..2b9b93a 100644
--- a/chrome/browser/chromeos/login/user_manager.h
+++ b/chrome/browser/chromeos/login/user_manager.h
@@ -349,6 +349,9 @@
 
   virtual void NotifyLocalStateChanged() = 0;
 
+  // Returns true if locally managed users allowed.
+  virtual bool AreLocallyManagedUsersAllowed() const = 0;
+
  private:
   friend class ScopedUserManagerEnabler;
 
diff --git a/chrome/browser/chromeos/login/user_manager_impl.cc b/chrome/browser/chromeos/login/user_manager_impl.cc
index 0fc5a6a..7edf248 100644
--- a/chrome/browser/chromeos/login/user_manager_impl.cc
+++ b/chrome/browser/chromeos/login/user_manager_impl.cc
@@ -35,6 +35,7 @@
 #include "chrome/browser/chromeos/policy/device_local_account.h"
 #include "chrome/browser/chromeos/session_length_limiter.h"
 #include "chrome/browser/chromeos/settings/cros_settings_names.h"
+#include "chrome/browser/managed_mode/managed_user_service.h"
 #include "chrome/browser/policy/browser_policy_connector.h"
 #include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/profiles/profile_manager.h"
@@ -205,6 +206,7 @@
       is_current_user_new_(false),
       is_current_user_ephemeral_regular_user_(false),
       ephemeral_users_enabled_(false),
+      locally_managed_users_enabled_by_policy_(false),
       merge_session_state_(MERGE_STATUS_NOT_STARTED),
       observed_sync_service_(NULL),
       user_image_manager_(new UserImageManagerImpl) {
@@ -215,6 +217,10 @@
   registrar_.Add(this, chrome::NOTIFICATION_LOGIN_USER_PROFILE_PREPARED,
       content::NotificationService::AllSources());
   RetrieveTrustedDevicePolicies();
+  cros_settings_->AddSettingsObserver(kAccountsPrefDeviceLocalAccounts,
+                                      this);
+  cros_settings_->AddSettingsObserver(kAccountsPrefSupervisedUsersEnabled,
+                                      this);
   UpdateLoginState();
 }
 
@@ -237,6 +243,9 @@
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   cros_settings_->RemoveSettingsObserver(kAccountsPrefDeviceLocalAccounts,
                                          this);
+  cros_settings_->RemoveSettingsObserver(
+      kAccountsPrefSupervisedUsersEnabled,
+      this);
   // Stop the session length limiter.
   session_length_limiter_.reset();
 
@@ -436,8 +445,7 @@
   prefs_new_users_update->Insert(0, new base::StringValue(e_mail));
   users_.insert(users_.begin(), new_user);
 
-
-  const User* manager = FindUser(manager_id);
+  const User* manager = FindUser(gaia::CanonicalizeEmail(manager_id));
   CHECK(manager);
 
   DictionaryPrefUpdate manager_update(local_state, kManagedUserManagers);
@@ -713,11 +721,14 @@
         }
       }
       break;
-    case chrome::NOTIFICATION_SYSTEM_SETTING_CHANGED:
-      DCHECK_EQ(*content::Details<const std::string>(details).ptr(),
-                kAccountsPrefDeviceLocalAccounts);
+    case chrome::NOTIFICATION_SYSTEM_SETTING_CHANGED: {
+      std::string changed_setting =
+          *content::Details<const std::string>(details).ptr();
+      DCHECK(changed_setting == kAccountsPrefDeviceLocalAccounts ||
+             changed_setting == kAccountsPrefSupervisedUsersEnabled);
       RetrieveTrustedDevicePolicies();
       break;
+    }
     default:
       NOTREACHED();
   }
@@ -1010,6 +1021,7 @@
 
 void UserManagerImpl::RetrieveTrustedDevicePolicies() {
   ephemeral_users_enabled_ = false;
+  locally_managed_users_enabled_by_policy_ = false;
   owner_email_ = "";
 
   // Schedule a callback if device policy has not yet been verified.
@@ -1021,6 +1033,8 @@
 
   cros_settings_->GetBoolean(kAccountsPrefEphemeralUsersEnabled,
                              &ephemeral_users_enabled_);
+  cros_settings_->GetBoolean(kAccountsPrefSupervisedUsersEnabled,
+                             &locally_managed_users_enabled_by_policy_);
   cros_settings_->GetString(kDeviceOwner, &owner_email_);
 
   EnsureUsersLoaded();
@@ -1052,9 +1066,6 @@
 
   if (changed)
     NotifyUserListChanged();
-
-  cros_settings_->AddSettingsObserver(kAccountsPrefDeviceLocalAccounts,
-                                      this);
 }
 
 bool UserManagerImpl::AreEphemeralUsersEnabled() const {
@@ -1542,7 +1553,9 @@
 
 UserFlow* UserManagerImpl::GetUserFlow(const std::string& email) const {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  FlowMap::const_iterator it = specific_flows_.find(email);
+  std::string canonical_email = email.empty() ? email :
+      gaia::CanonicalizeEmail(email);
+  FlowMap::const_iterator it = specific_flows_.find(canonical_email);
   if (it != specific_flows_.end())
     return it->second;
   return GetDefaultUserFlow();
@@ -1550,13 +1563,15 @@
 
 void UserManagerImpl::SetUserFlow(const std::string& email, UserFlow* flow) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  ResetUserFlow(email);
-  specific_flows_[email] = flow;
+  std::string canonical_email = gaia::CanonicalizeEmail(email);
+  ResetUserFlow(canonical_email);
+  specific_flows_[canonical_email] = flow;
 }
 
 void UserManagerImpl::ResetUserFlow(const std::string& email) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  FlowMap::iterator it = specific_flows_.find(email);
+  std::string canonical_email = gaia::CanonicalizeEmail(email);
+  FlowMap::iterator it = specific_flows_.find(canonical_email);
   if (it != specific_flows_.end()) {
     delete it->second;
     specific_flows_.erase(it);
@@ -1586,6 +1601,12 @@
   chrome_client_secret_ = chrome_client_secret;
 }
 
+bool UserManagerImpl::AreLocallyManagedUsersAllowed() const {
+  return ManagedUserService::AreManagedUsersEnabled() &&
+        (locally_managed_users_enabled_by_policy_ ||
+         !g_browser_process->browser_policy_connector()->IsEnterpriseManaged());
+}
+
 UserFlow* UserManagerImpl::GetDefaultUserFlow() const {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   if (!default_flow_.get())
diff --git a/chrome/browser/chromeos/login/user_manager_impl.h b/chrome/browser/chromeos/login/user_manager_impl.h
index 63be822..19c8d45 100644
--- a/chrome/browser/chromeos/login/user_manager_impl.h
+++ b/chrome/browser/chromeos/login/user_manager_impl.h
@@ -134,6 +134,7 @@
   virtual void SetAppModeChromeClientOAuthInfo(
       const std::string& chrome_client_id,
       const std::string& chrome_client_secret) OVERRIDE;
+  virtual bool AreLocallyManagedUsersAllowed() const OVERRIDE;
 
   // content::NotificationObserver implementation.
   virtual void Observe(int type,
@@ -357,6 +358,11 @@
   // policy yet.
   bool ephemeral_users_enabled_;
 
+  // Cached flag indicating whether the locally managed users are enabled by
+  // policy. Defaults to |false| if the value has not been read from trusted
+  // device policy yet.
+  bool locally_managed_users_enabled_by_policy_;
+
   // Merge session state (cookie restore process state).
   MergeSessionState merge_session_state_;
 
@@ -392,7 +398,8 @@
   // Lazy-initialized default flow.
   mutable scoped_ptr<UserFlow> default_flow_;
 
-  // Specific flows by user e-mail.
+  // Specific flows by user e-mail. Keys should be canonicalized before
+  // access.
   FlowMap specific_flows_;
 
   // User sessions that have to be restored after browser crash.
diff --git a/chrome/browser/chromeos/login/user_manager_unittest.cc b/chrome/browser/chromeos/login/user_manager_unittest.cc
index b0fe8d8..e2c4773 100644
--- a/chrome/browser/chromeos/login/user_manager_unittest.cc
+++ b/chrome/browser/chromeos/login/user_manager_unittest.cc
@@ -47,12 +47,11 @@
     cros_settings_->AddSettingsProvider(&stub_settings_provider_);
 
     // Populate the stub DeviceSettingsProvider with valid values.
-    SetDeviceSettings(false, "");
+    SetDeviceSettings(false, "", false);
 
     // Register an in-memory local settings instance.
     local_state_.reset(new TestingPrefServiceSimple);
-    reinterpret_cast<TestingBrowserProcess*>(g_browser_process)
-        ->SetLocalState(local_state_.get());
+    TestingBrowserProcess::GetGlobal()->SetLocalState(local_state_.get());
     UserManager::RegisterPrefs(local_state_->registry());
     // Wallpaper manager and user image managers prefs will be accessed by the
     // unit-test as well.
@@ -64,8 +63,7 @@
 
   virtual void TearDown() OVERRIDE {
     // Unregister the in-memory local settings instance.
-    reinterpret_cast<TestingBrowserProcess*>(g_browser_process)
-        ->SetLocalState(0);
+    TestingBrowserProcess::GetGlobal()->SetLocalState(0);
 
     // Restore the real DeviceSettingsProvider.
     EXPECT_TRUE(
@@ -78,24 +76,28 @@
     base::RunLoop().RunUntilIdle();
   }
 
+  UserManagerImpl* GetUserManagerImpl() const {
+    return static_cast<UserManagerImpl*>(UserManager::Get());
+  }
+
   bool GetUserManagerEphemeralUsersEnabled() const {
-    return reinterpret_cast<UserManagerImpl*>(UserManager::Get())->
-        ephemeral_users_enabled_;
+    return GetUserManagerImpl()->ephemeral_users_enabled_;
+  }
+
+  bool GetUserManagerLocallyManagedUsersEnabledByPolicy() const {
+    return GetUserManagerImpl()->locally_managed_users_enabled_by_policy_;
   }
 
   void SetUserManagerEphemeralUsersEnabled(bool ephemeral_users_enabled) {
-    reinterpret_cast<UserManagerImpl*>(UserManager::Get())->
-        ephemeral_users_enabled_ = ephemeral_users_enabled;
+    GetUserManagerImpl()->ephemeral_users_enabled_ = ephemeral_users_enabled;
   }
 
   const std::string& GetUserManagerOwnerEmail() const {
-    return reinterpret_cast<UserManagerImpl*>(UserManager::Get())->
-        owner_email_;
+    return GetUserManagerImpl()-> owner_email_;
   }
 
   void SetUserManagerOwnerEmail(const std::string& owner_email) {
-    reinterpret_cast<UserManagerImpl*>(UserManager::Get())->
-        owner_email_ = owner_email;
+    GetUserManagerImpl()->owner_email_ = owner_email;
   }
 
   void ResetUserManager() {
@@ -107,18 +109,20 @@
   }
 
   void SetDeviceSettings(bool ephemeral_users_enabled,
-                         const std::string &owner) {
+                         const std::string &owner,
+                         bool locally_managed_users_enabled) {
     base::FundamentalValue
         ephemeral_users_enabled_value(ephemeral_users_enabled);
     stub_settings_provider_.Set(kAccountsPrefEphemeralUsersEnabled,
         ephemeral_users_enabled_value);
     base::StringValue owner_value(owner);
     stub_settings_provider_.Set(kDeviceOwner, owner_value);
+    stub_settings_provider_.Set(kAccountsPrefSupervisedUsersEnabled,
+        base::FundamentalValue(locally_managed_users_enabled));
   }
 
   void RetrieveTrustedDevicePolicies() {
-    reinterpret_cast<UserManagerImpl*>(UserManager::Get())->
-        RetrieveTrustedDevicePolicies();
+    GetUserManagerImpl()->RetrieveTrustedDevicePolicies();
   }
 
  protected:
@@ -142,7 +146,7 @@
   SetUserManagerEphemeralUsersEnabled(true);
   SetUserManagerOwnerEmail("");
 
-  SetDeviceSettings(false, "owner@invalid.domain");
+  SetDeviceSettings(false, "owner@invalid.domain", false);
   RetrieveTrustedDevicePolicies();
 
   EXPECT_FALSE(GetUserManagerEphemeralUsersEnabled());
@@ -166,7 +170,7 @@
   EXPECT_EQ((*users)[1]->email(), "user0@invalid.domain");
   EXPECT_EQ((*users)[2]->email(), "owner@invalid.domain");
 
-  SetDeviceSettings(true, "owner@invalid.domain");
+  SetDeviceSettings(true, "owner@invalid.domain", false);
   RetrieveTrustedDevicePolicies();
 
   users = &UserManager::Get()->GetUsers();
@@ -175,7 +179,7 @@
 }
 
 TEST_F(UserManagerTest, RegularUserLoggedInAsEphemeral) {
-  SetDeviceSettings(true, "owner@invalid.domain");
+  SetDeviceSettings(true, "owner@invalid.domain", false);
   RetrieveTrustedDevicePolicies();
 
   UserManager::Get()->UserLoggedIn(
@@ -190,4 +194,13 @@
   EXPECT_EQ((*users)[0]->email(), "owner@invalid.domain");
 }
 
+TEST_F(UserManagerTest, DisablingLMUByDeviceSettings) {
+  SetDeviceSettings(false, "owner@invalid.domain", false);
+  RetrieveTrustedDevicePolicies();
+  EXPECT_EQ(GetUserManagerLocallyManagedUsersEnabledByPolicy(), false);
+  SetDeviceSettings(false, "owner@invalid.domain", true);
+  RetrieveTrustedDevicePolicies();
+  EXPECT_EQ(GetUserManagerLocallyManagedUsersEnabledByPolicy(), true);
+}
+
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/wallpaper_manager.cc b/chrome/browser/chromeos/login/wallpaper_manager.cc
index 9a0cc85..dcd09ae 100644
--- a/chrome/browser/chromeos/login/wallpaper_manager.cc
+++ b/chrome/browser/chromeos/login/wallpaper_manager.cc
@@ -20,7 +20,7 @@
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/threading/worker_pool.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chromeos/login/startup_utils.h"
@@ -393,7 +393,7 @@
   if (layout == ash::WALLPAPER_LAYOUT_CENTER) {
     // TODO(bshe): Generates cropped custom wallpaper for CENTER layout.
     if (file_util::PathExists(path))
-      file_util::Delete(path, false);
+      base::Delete(path, false);
     return;
   }
   scoped_refptr<base::RefCountedBytes> data;
@@ -490,25 +490,10 @@
 }
 
 void WallpaperManager::SetDefaultWallpaper() {
-  ash::DesktopBackgroundController* controller =
-      ash::Shell::GetInstance()->desktop_background_controller();
-  ash::WallpaperResolution resolution = controller->GetAppropriateResolution();
-  ash::WallpaperInfo info;
-  if (UserManager::Get()->IsLoggedInAsGuest()) {
-    info = (resolution == ash::WALLPAPER_RESOLUTION_LARGE) ?
-        ash::kGuestLargeWallpaper : ash::kGuestSmallWallpaper;
-  } else {
-    info = (resolution == ash::WALLPAPER_RESOLUTION_LARGE) ?
-        ash::kDefaultLargeWallpaper : ash::kDefaultSmallWallpaper;
-  }
-
-  // Prevents loading of the same wallpaper as the currently loading/loaded one.
-  if (controller->GetWallpaperIDR() == info.idr)
-    return;
-
   current_wallpaper_path_.clear();
-  loaded_wallpapers_++;
-  controller->SetDefaultWallpaper(info);
+  if (ash::Shell::GetInstance()->desktop_background_controller()->
+          SetDefaultWallpaper(UserManager::Get()->IsLoggedInAsGuest()))
+    loaded_wallpapers_++;
 }
 
 void WallpaperManager::SetInitialUserWallpaper(const std::string& username,
@@ -690,7 +675,7 @@
     for (base::FilePath current = files.Next(); !current.empty();
          current = files.Next()) {
       if (current != path)
-        file_util::Delete(current, false);
+        base::Delete(current, false);
     }
   }
 }
@@ -702,8 +687,8 @@
     base::FilePath path = *it;
     // Some users may still have legacy wallpapers with png extension. We need
     // to delete these wallpapers too.
-    if (!file_util::Delete(path, true) &&
-        !file_util::Delete(path.AddExtension(".png"), false)) {
+    if (!base::Delete(path, true) &&
+        !base::Delete(path.AddExtension(".png"), false)) {
       LOG(ERROR) << "Failed to remove user wallpaper at " << path.value();
     }
   }
@@ -866,14 +851,14 @@
       // Appends DUMMY to the file name of moved custom wallpaper. This way we
       // do not need to update WallpaperInfo for user.
       to_path = GetCustomWallpaperPath(kSmallWallpaperSubDir, email, "DUMMY");
-      file_util::Move(from_path, to_path);
+      base::Move(from_path, to_path);
     }
     from_path = GetWallpaperPathForUser(email, false);
     if (!file_util::PathExists(from_path))
       from_path = from_path.AddExtension(".png");
     if (file_util::PathExists(from_path)) {
       to_path = GetCustomWallpaperPath(kLargeWallpaperSubDir, email, "DUMMY");
-      file_util::Move(from_path, to_path);
+      base::Move(from_path, to_path);
     }
     from_path = GetOriginalWallpaperPathForUser(email);
     if (!file_util::PathExists(from_path))
@@ -881,7 +866,7 @@
     if (file_util::PathExists(from_path)) {
       to_path = GetCustomWallpaperPath(kOriginalWallpaperSubDir, email,
                                        "DUMMY");
-      file_util::Move(from_path, to_path);
+      base::Move(from_path, to_path);
     }
   }
 }
diff --git a/chrome/browser/chromeos/login/wallpaper_manager.h b/chrome/browser/chromeos/login/wallpaper_manager.h
index 882bcc4..62e00d7 100644
--- a/chrome/browser/chromeos/login/wallpaper_manager.h
+++ b/chrome/browser/chromeos/login/wallpaper_manager.h
@@ -12,8 +12,8 @@
 #include "base/memory/ref_counted_memory.h"
 #include "base/memory/weak_ptr.h"
 #include "base/threading/sequenced_worker_pool.h"
-#include "base/time.h"
-#include "base/timer.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
 #include "chrome/browser/chromeos/login/user.h"
 #include "chrome/browser/chromeos/login/user_image.h"
 #include "chrome/browser/chromeos/login/user_image_loader.h"
diff --git a/chrome/browser/chromeos/login/wallpaper_manager_browsertest.cc b/chrome/browser/chromeos/login/wallpaper_manager_browsertest.cc
index 0bb93e6..77b3be6 100644
--- a/chrome/browser/chromeos/login/wallpaper_manager_browsertest.cc
+++ b/chrome/browser/chromeos/login/wallpaper_manager_browsertest.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/chromeos/login/wallpaper_manager.h"
 
+#include "ash/ash_resources/grit/ash_wallpaper_resources.h"
 #include "ash/desktop_background/desktop_background_controller.h"
 #include "ash/desktop_background/desktop_background_controller_observer.h"
 #include "ash/display/display_manager.h"
@@ -13,7 +14,7 @@
 #include "base/file_util.h"
 #include "base/message_loop.h"
 #include "base/strings/string_number_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "base/values.h"
 #include "chrome/browser/chromeos/cros/cros_in_process_browser_test.h"
 #include "chrome/browser/chromeos/login/user.h"
@@ -31,19 +32,13 @@
 
 namespace {
 
-#if defined(GOOGLE_CHROME_BUILD)
-int kExpectedSmallWallpaperWidth = ash::kSmallWallpaperMaxWidth;
-int kExpectedSmallWallpaperHeight = ash::kSmallWallpaperMaxHeight;
-int kExpectedLargeWallpaperWidth = ash::kLargeWallpaperMaxWidth;
-int kExpectedLargeWallpaperHeight = ash::kLargeWallpaperMaxHeight;
-#else
-// The defualt wallpaper for non official build is a gradient wallpaper which
-// stretches to fit screen.
-int kExpectedSmallWallpaperWidth = 256;
-int kExpectedSmallWallpaperHeight = ash::kSmallWallpaperMaxHeight;
-int kExpectedLargeWallpaperWidth = 256;
-int kExpectedLargeWallpaperHeight = ash::kLargeWallpaperMaxHeight;
-#endif
+const int kLargeWallpaperResourceId = IDR_AURA_WALLPAPERS_5_GRADIENT5_LARGE;
+const int kSmallWallpaperResourceId = IDR_AURA_WALLPAPERS_5_GRADIENT5_SMALL;
+
+int kLargeWallpaperWidth = 256;
+int kLargeWallpaperHeight = ash::kLargeWallpaperMaxHeight;
+int kSmallWallpaperWidth = 256;
+int kSmallWallpaperHeight = ash::kSmallWallpaperMaxHeight;
 
 const char kTestUser1[] = "test@domain.com";
 
@@ -95,8 +90,8 @@
  protected:
   // Return custom wallpaper path. Create directory if not exist.
   base::FilePath GetCustomWallpaperPath(const char* sub_dir,
-                                  const std::string& email,
-                                  const std::string& id) {
+                                        const std::string& email,
+                                        const std::string& id) {
     base::FilePath wallpaper_path =
         WallpaperManager::Get()->GetCustomWallpaperPath(sub_dir, email, id);
     if (!file_util::DirectoryExists(wallpaper_path.DirName()))
@@ -135,57 +130,8 @@
   DISALLOW_COPY_AND_ASSIGN(WallpaperManagerBrowserTest);
 };
 
-// The large resolution wallpaper should be loaded when a large external screen
-// is hooked up. If the external screen is smaller than small wallpaper
-// resolution, do not load large resolution wallpaper.
-IN_PROC_BROWSER_TEST_F(WallpaperManagerBrowserTest,
-                       LoadLargeWallpaperForLargeExternalScreen) {
-  LogIn(kTestUser1);
-  WaitAsyncWallpaperLoad();
-  gfx::ImageSkia wallpaper = controller_->GetWallpaper();
-
-  // Display is initialized to 800x600. The small resolution default wallpaper
-  // is expected.
-  EXPECT_EQ(kExpectedSmallWallpaperWidth, wallpaper.width());
-  EXPECT_EQ(kExpectedSmallWallpaperHeight, wallpaper.height());
-
-  // Hook up another 800x600 display.
-  UpdateDisplay("800x600,800x600");
-#if !defined(GOOGLE_CHROME_BUILD)
-  // wallpaper.width() < 800, expect to reload wallpaper.
-  WaitAsyncWallpaperLoad();
-#endif
-  // The small resolution wallpaper is expected.
-  EXPECT_EQ(kExpectedSmallWallpaperWidth, wallpaper.width());
-  EXPECT_EQ(kExpectedSmallWallpaperHeight, wallpaper.height());
-
-  // Detach the secondary display.
-  UpdateDisplay("800x600");
-  // Hook up a 2000x2000 display. The large resolution default wallpaper should
-  // be loaded.
-  UpdateDisplay("800x600,2000x2000");
-  WaitAsyncWallpaperLoad();
-  wallpaper = controller_->GetWallpaper();
-
-  // The large resolution default wallpaper is expected.
-  EXPECT_EQ(kExpectedLargeWallpaperWidth, wallpaper.width());
-  EXPECT_EQ(kExpectedLargeWallpaperHeight, wallpaper.height());
-
-  // Detach the secondary display.
-  UpdateDisplay("800x600");
-  // Hook up the 2000x2000 display again. The large resolution default wallpaper
-  // should persist. Test for crbug/165788.
-  UpdateDisplay("800x600,2000x2000");
-  WaitAsyncWallpaperLoad();
-  wallpaper = controller_->GetWallpaper();
-
-  // The large resolution default wallpaper is expected.
-  EXPECT_EQ(kExpectedLargeWallpaperWidth, wallpaper.width());
-  EXPECT_EQ(kExpectedLargeWallpaperHeight, wallpaper.height());
-}
-
-// This test is similar to LoadLargeWallpaperForExternalScreen test. Instead of
-// testing default wallpaper, it tests custom wallpaper.
+// Tests that the appropriate custom wallpaper (large vs. small) is loaded
+// depending on the desktop resolution.
 IN_PROC_BROWSER_TEST_F(WallpaperManagerBrowserTest,
                        LoadCustomLargeWallpaperForLargeExternalScreen) {
   WallpaperManager* wallpaper_manager = WallpaperManager::Get();
@@ -206,10 +152,10 @@
   // wallpaper paths.
   SaveUserWallpaperData(kTestUser1,
                         small_wallpaper_path,
-                        ash::kDefaultSmallWallpaper.idr);
+                        kSmallWallpaperResourceId);
   SaveUserWallpaperData(kTestUser1,
                         large_wallpaper_path,
-                        ash::kDefaultLargeWallpaper.idr);
+                        kLargeWallpaperResourceId);
 
   // Saves wallpaper info to local state for user |kTestUser1|.
   WallpaperInfo info = {
@@ -227,18 +173,15 @@
 
   // Display is initialized to 800x600. The small resolution custom wallpaper is
   // expected.
-  EXPECT_EQ(kExpectedSmallWallpaperWidth, wallpaper.width());
-  EXPECT_EQ(kExpectedSmallWallpaperHeight, wallpaper.height());
+  EXPECT_EQ(kSmallWallpaperWidth, wallpaper.width());
+  EXPECT_EQ(kSmallWallpaperHeight, wallpaper.height());
 
   // Hook up another 800x600 display.
   UpdateDisplay("800x600,800x600");
-#if !defined(GOOGLE_CHROME_BUILD)
-  // wallpaper.width() < 800, expect to reload wallpaper.
   WaitAsyncWallpaperLoad();
-#endif
   // The small resolution custom wallpaper is expected.
-  EXPECT_EQ(kExpectedSmallWallpaperWidth, wallpaper.width());
-  EXPECT_EQ(kExpectedSmallWallpaperHeight, wallpaper.height());
+  EXPECT_EQ(kSmallWallpaperWidth, wallpaper.width());
+  EXPECT_EQ(kSmallWallpaperHeight, wallpaper.height());
 
   // Detach the secondary display.
   UpdateDisplay("800x600");
@@ -249,8 +192,8 @@
   wallpaper = controller_->GetWallpaper();
 
   // The large resolution custom wallpaper is expected.
-  EXPECT_EQ(kExpectedLargeWallpaperWidth, wallpaper.width());
-  EXPECT_EQ(kExpectedLargeWallpaperHeight, wallpaper.height());
+  EXPECT_EQ(kLargeWallpaperWidth, wallpaper.width());
+  EXPECT_EQ(kLargeWallpaperHeight, wallpaper.height());
 
   // Detach the secondary display.
   UpdateDisplay("800x600");
@@ -261,8 +204,8 @@
   wallpaper = controller_->GetWallpaper();
 
   // The large resolution custom wallpaper is expected.
-  EXPECT_EQ(kExpectedLargeWallpaperWidth, wallpaper.width());
-  EXPECT_EQ(kExpectedLargeWallpaperHeight, wallpaper.height());
+  EXPECT_EQ(kLargeWallpaperWidth, wallpaper.width());
+  EXPECT_EQ(kLargeWallpaperHeight, wallpaper.height());
 }
 
 // If chrome tries to reload the same wallpaper twice, the latter request should
@@ -293,7 +236,7 @@
       id);
   SaveUserWallpaperData(kTestUser1,
                         small_wallpaper_path,
-                        ash::kDefaultSmallWallpaper.idr);
+                        kSmallWallpaperResourceId);
 
   // Saves wallpaper info to local state for user |kTestUser1|.
   WallpaperInfo info = {
@@ -328,7 +271,7 @@
       GetOriginalWallpaperPathForUser(kTestUser1);
   SaveUserWallpaperData(kTestUser1,
                         old_wallpaper_path,
-                        ash::kDefaultSmallWallpaper.idr);
+                        kSmallWallpaperResourceId);
   // Saves wallpaper info to local state for user |kTestUser1|.
   WallpaperInfo info = {
       "DUMMY",
@@ -463,4 +406,4 @@
   // can not handle pre migrated user profile (M21 profile or older).
 }
 
-}  // namepace chromeos
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/webui_login_display.h b/chrome/browser/chromeos/login/webui_login_display.h
index 04a880b..de2f8cd 100644
--- a/chrome/browser/chromeos/login/webui_login_display.h
+++ b/chrome/browser/chromeos/login/webui_login_display.h
@@ -10,7 +10,7 @@
 
 #include "ash/wm/user_activity_observer.h"
 #include "base/compiler_specific.h"
-#include "base/timer.h"
+#include "base/timer/timer.h"
 #include "chrome/browser/chromeos/login/login_display.h"
 #include "chrome/browser/chromeos/login/user.h"
 #include "chrome/browser/ui/webui/chromeos/login/native_window_delegate.h"
diff --git a/chrome/browser/chromeos/login/webui_screen_locker.h b/chrome/browser/chromeos/login/webui_screen_locker.h
index 888f422..8c52c81 100644
--- a/chrome/browser/chromeos/login/webui_screen_locker.h
+++ b/chrome/browser/chromeos/login/webui_screen_locker.h
@@ -11,7 +11,7 @@
 #include "base/compiler_specific.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/chromeos/login/lock_window.h"
 #include "chrome/browser/chromeos/login/login_display.h"
 #include "chrome/browser/chromeos/login/screen_locker_delegate.h"
diff --git a/chrome/browser/chromeos/login/wizard_controller.cc b/chrome/browser/chromeos/login/wizard_controller.cc
index bd83578..a8adf9c 100644
--- a/chrome/browser/chromeos/login/wizard_controller.cc
+++ b/chrome/browser/chromeos/login/wizard_controller.cc
@@ -47,8 +47,6 @@
 #include "chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.h"
 #include "chrome/browser/chromeos/settings/cros_settings.h"
 #include "chrome/browser/chromeos/settings/cros_settings_names.h"
-#include "chrome/browser/chromeos/system/statistics_provider.h"
-#include "chrome/browser/chromeos/ui/focus_ring_controller.h"
 #include "chrome/browser/policy/browser_policy_connector.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
@@ -187,18 +185,9 @@
   screen_parameters_ = screen_parameters.Pass();
 
   bool oobe_complete = StartupUtils::IsOobeCompleted();
-  if (!oobe_complete || first_screen_name == kOutOfBoxScreenName) {
+  if (!oobe_complete || first_screen_name == kOutOfBoxScreenName)
     is_out_of_box_ = true;
 
-    bool keyboard_driven_oobe = false;
-    system::StatisticsProvider::GetInstance()->GetMachineFlag(
-        chromeos::kOemKeyboardDrivenOobeKey, &keyboard_driven_oobe);
-    if (keyboard_driven_oobe) {
-      focus_ring_controller_.reset(new FocusRingController);
-      focus_ring_controller_->SetVisible(true);
-    }
-  }
-
   AdvanceToScreen(first_screen_name);
   content::NotificationService::current()->Notify(
       chrome::NOTIFICATION_WIZARD_FIRST_SCREEN_SHOWN,
diff --git a/chrome/browser/chromeos/login/wizard_controller.h b/chrome/browser/chromeos/login/wizard_controller.h
index 4b77900..192ef93 100644
--- a/chrome/browser/chromeos/login/wizard_controller.h
+++ b/chrome/browser/chromeos/login/wizard_controller.h
@@ -11,8 +11,8 @@
 #include "base/gtest_prod_util.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/observer_list.h"
-#include "base/time.h"
-#include "base/timer.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
 #include "chrome/browser/chromeos/login/screens/screen_observer.h"
 #include "chrome/browser/chromeos/login/screens/wizard_screen.h"
 #include "googleurl/src/gurl.h"
@@ -29,7 +29,6 @@
 class EnrollmentScreen;
 class ErrorScreen;
 class EulaScreen;
-class FocusRingController;
 class KioskAutolaunchScreen;
 class KioskEnableScreen;
 class LocallyManagedUserCreationScreen;
@@ -309,10 +308,6 @@
   // a previous screen instead of proceeding with usual flow.
   bool user_image_screen_return_to_previous_hack_;
 
-  // A focus ring controller to draw focus ring around view for keyboard
-  // driven oobe.
-  scoped_ptr<FocusRingController> focus_ring_controller_;
-
   FRIEND_TEST_ALL_PREFIXES(EnrollmentScreenTest, TestCancel);
   FRIEND_TEST_ALL_PREFIXES(WizardControllerFlowTest, Accelerators);
   friend class WizardControllerFlowTest;
diff --git a/chrome/browser/chromeos/memory/oom_priority_manager.cc b/chrome/browser/chromeos/memory/oom_priority_manager.cc
index 4fda45b..85b6217 100644
--- a/chrome/browser/chromeos/memory/oom_priority_manager.cc
+++ b/chrome/browser/chromeos/memory/oom_priority_manager.cc
@@ -21,7 +21,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/synchronization/lock.h"
 #include "base/threading/thread.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/browser_process_platform_part_chromeos.h"
diff --git a/chrome/browser/chromeos/memory/oom_priority_manager.h b/chrome/browser/chromeos/memory/oom_priority_manager.h
index 56f8668..f666db7 100644
--- a/chrome/browser/chromeos/memory/oom_priority_manager.h
+++ b/chrome/browser/chromeos/memory/oom_priority_manager.h
@@ -14,8 +14,8 @@
 #include "base/process.h"
 #include "base/strings/string16.h"
 #include "base/synchronization/lock.h"
-#include "base/time.h"
-#include "base/timer.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
 #include "chromeos/memory/low_memory_listener_delegate.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
diff --git a/chrome/browser/chromeos/memory/oom_priority_manager_unittest.cc b/chrome/browser/chromeos/memory/oom_priority_manager_unittest.cc
index 88ebe32..cf5fa16 100644
--- a/chrome/browser/chromeos/memory/oom_priority_manager_unittest.cc
+++ b/chrome/browser/chromeos/memory/oom_priority_manager_unittest.cc
@@ -7,7 +7,7 @@
 
 #include "base/logging.h"
 #include "base/strings/string16.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/chromeos/memory/oom_priority_manager.h"
 #include "chrome/common/url_constants.h"
 #include "googleurl/src/gurl.h"
diff --git a/chrome/browser/chromeos/mobile/mobile_activator.cc b/chrome/browser/chromeos/mobile/mobile_activator.cc
index b4e8022..2628fb1 100644
--- a/chrome/browser/chromeos/mobile/mobile_activator.cc
+++ b/chrome/browser/chromeos/mobile/mobile_activator.cc
@@ -21,7 +21,7 @@
 #include "base/strings/string_piece.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/timer.h"
+#include "base/timer/timer.h"
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chromeos/cros/cros_library.h"
diff --git a/chrome/browser/chromeos/mobile_config.h b/chrome/browser/chromeos/mobile_config.h
index d44b7bd..014231f 100644
--- a/chrome/browser/chromeos/mobile_config.h
+++ b/chrome/browser/chromeos/mobile_config.h
@@ -12,7 +12,7 @@
 #include "base/gtest_prod_util.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/singleton.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/chromeos/customization_document.h"
 
 namespace base {
diff --git a/chrome/browser/chromeos/mobile_config_unittest.cc b/chrome/browser/chromeos/mobile_config_unittest.cc
index 95aece9..abd3992 100644
--- a/chrome/browser/chromeos/mobile_config_unittest.cc
+++ b/chrome/browser/chromeos/mobile_config_unittest.cc
@@ -4,7 +4,7 @@
 
 #include "chrome/browser/chromeos/mobile_config.h"
 
-#include "base/time.h"
+#include "base/time/time.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace {
diff --git a/chrome/browser/chromeos/net/network_portal_detector_impl.h b/chrome/browser/chromeos/net/network_portal_detector_impl.h
index bbc40f9..b523f65 100644
--- a/chrome/browser/chromeos/net/network_portal_detector_impl.h
+++ b/chrome/browser/chromeos/net/network_portal_detector_impl.h
@@ -16,7 +16,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
 #include "base/threading/non_thread_safe.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/captive_portal/captive_portal_detector.h"
 #include "chrome/browser/chromeos/net/network_portal_detector.h"
 #include "chromeos/network/network_state_handler_observer.h"
diff --git a/chrome/browser/chromeos/net/network_portal_detector_impl_unittest.cc b/chrome/browser/chromeos/net/network_portal_detector_impl_unittest.cc
index 6b497dd..16994e8 100644
--- a/chrome/browser/chromeos/net/network_portal_detector_impl_unittest.cc
+++ b/chrome/browser/chromeos/net/network_portal_detector_impl_unittest.cc
@@ -190,23 +190,24 @@
     ShillServiceClient::TestInterface* service_test =
         DBusThreadManager::Get()->GetShillServiceClient()->GetTestInterface();
     service_test->ClearServices();
+    const bool add_to_visible = true;
     const bool add_to_watchlist = true;
     service_test->AddService(kStubEthernet,
                              kStubEthernet,
                              flimflam::kTypeEthernet, flimflam::kStateIdle,
-                             add_to_watchlist);
+                             add_to_visible, add_to_watchlist);
     service_test->AddService(kStubWireless1,
                              kStubWireless1,
                              flimflam::kTypeWifi, flimflam::kStateIdle,
-                             add_to_watchlist);
+                             add_to_visible, add_to_watchlist);
     service_test->AddService(kStubWireless2,
                              kStubWireless2,
                              flimflam::kTypeWifi, flimflam::kStateIdle,
-                             add_to_watchlist);
+                             add_to_visible, add_to_watchlist);
     service_test->AddService(kStubCellular,
                              kStubCellular,
                              flimflam::kTypeCellular, flimflam::kStateIdle,
-                             add_to_watchlist);
+                             add_to_visible, add_to_watchlist);
   }
 
   void SetupNetworkHandler() {
diff --git a/chrome/browser/chromeos/options/network_connect.cc b/chrome/browser/chromeos/options/network_connect.cc
index 8ebe55c..4daccc2 100644
--- a/chrome/browser/chromeos/options/network_connect.cc
+++ b/chrome/browser/chromeos/options/network_connect.cc
@@ -10,7 +10,7 @@
 #include "ash/system/chromeos/network/network_observer.h"
 #include "ash/system/tray/system_tray_notifier.h"
 #include "base/command_line.h"
-#include "base/stringprintf.h"
+#include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/chromeos/cros/cros_library.h"
 #include "chrome/browser/chromeos/cros/network_library.h"
diff --git a/chrome/browser/chromeos/options/vpn_config_view.cc b/chrome/browser/chromeos/options/vpn_config_view.cc
index 0894749..f35536e 100644
--- a/chrome/browser/chromeos/options/vpn_config_view.cc
+++ b/chrome/browser/chromeos/options/vpn_config_view.cc
@@ -313,7 +313,7 @@
         config_data.group_name = GetGroupName();
         break;
       case PROVIDER_TYPE_L2TP_IPSEC_USER_CERT: {
-        config_data.server_ca_cert_nss_nickname = GetServerCACertNssNickname();
+        config_data.server_ca_cert_pem = GetServerCACertPEM();
         config_data.client_cert_pkcs11_id = GetUserCertID();
         config_data.username = GetUsername();
         config_data.user_passphrase = GetUserPassphrase();
@@ -321,7 +321,7 @@
         break;
       }
       case PROVIDER_TYPE_OPEN_VPN:
-        config_data.server_ca_cert_nss_nickname = GetServerCACertNssNickname();
+        config_data.server_ca_cert_pem = GetServerCACertPEM();
         config_data.client_cert_pkcs11_id = GetUserCertID();
         config_data.username = GetUsername();
         config_data.user_passphrase = GetUserPassphrase();
@@ -421,7 +421,7 @@
   return GetTextFromField(otp_textfield_, true);
 }
 
-const std::string VPNConfigView::GetServerCACertNssNickname() const {
+const std::string VPNConfigView::GetServerCACertPEM() const {
   int index = server_ca_cert_combobox_ ?
       server_ca_cert_combobox_->selected_index() : 0;
   if (index == 0) {
@@ -429,7 +429,7 @@
     return std::string();
   } else {
     int cert_index = index - 1;
-    return CertLibrary::Get()->GetCertNicknameAt(
+    return CertLibrary::Get()->GetCertPEMAt(
         CertLibrary::CERT_TYPE_SERVER_CA, cert_index);
   }
 }
@@ -453,14 +453,20 @@
   if (vpn) {
     ProviderType type = vpn->provider_type();
     std::string type_dict_name = ProviderTypeToONCDictKey(type);
-    ParseVPNUIProperty(&ca_cert_ui_data_, vpn, type_dict_name,
-                       onc::vpn::kServerCARef);
-    ParseVPNUIProperty(&psk_passphrase_ui_data_, vpn, type_dict_name,
-                       onc::vpn::kPSK);
+
+    if (type == PROVIDER_TYPE_L2TP_IPSEC_PSK) {
+      ParseVPNUIProperty(&ca_cert_ui_data_, vpn, type_dict_name,
+                         onc::ipsec::kServerCARef);
+      ParseVPNUIProperty(&psk_passphrase_ui_data_, vpn, type_dict_name,
+                         onc::ipsec::kPSK);
+      ParseVPNUIProperty(&group_name_ui_data_, vpn, type_dict_name,
+                         onc::ipsec::kGroup);
+    } else { // OpenVPN
+      ParseVPNUIProperty(&ca_cert_ui_data_, vpn, type_dict_name,
+                         onc::openvpn::kServerCARef);
+    }
     ParseVPNUIProperty(&user_cert_ui_data_, vpn, type_dict_name,
                        onc::vpn::kClientCertRef);
-    ParseVPNUIProperty(&group_name_ui_data_, vpn, type_dict_name,
-                       onc::vpn::kGroup);
 
     const std::string credentials_dict_name(
         type == PROVIDER_TYPE_L2TP_IPSEC_PSK ?
@@ -718,10 +724,10 @@
   if (server_ca_cert_combobox_) {
     server_ca_cert_combobox_->ModelChanged();
     if (enable_server_ca_cert_ &&
-        (vpn && !vpn->ca_cert_nss().empty())) {
+        (vpn && !vpn->ca_cert_pem().empty())) {
       // Select the current server CA certificate in the combobox.
-      int cert_index = CertLibrary::Get()->GetCertIndexByNickname(
-          CertLibrary::CERT_TYPE_SERVER_CA, vpn->ca_cert_nss());
+      int cert_index = CertLibrary::Get()->GetCertIndexByPEM(
+          CertLibrary::CERT_TYPE_SERVER_CA, vpn->ca_cert_pem());
       if (cert_index >= 0) {
         // Skip item for "Default"
         server_ca_cert_combobox_->SetSelectedIndex(1 + cert_index);
diff --git a/chrome/browser/chromeos/options/vpn_config_view.h b/chrome/browser/chromeos/options/vpn_config_view.h
index 4b437e8..cb5f7ce 100644
--- a/chrome/browser/chromeos/options/vpn_config_view.h
+++ b/chrome/browser/chromeos/options/vpn_config_view.h
@@ -106,7 +106,7 @@
   const std::string GetUserPassphrase() const;
   const std::string GetOTP() const;
   const std::string GetGroupName() const;
-  const std::string GetServerCACertNssNickname() const;
+  const std::string GetServerCACertPEM() const;
   const std::string GetUserCertID() const;
   bool GetSaveCredentials() const;
 
diff --git a/chrome/browser/chromeos/options/wifi_config_view.cc b/chrome/browser/chromeos/options/wifi_config_view.cc
index cd72843..4e7257d 100644
--- a/chrome/browser/chromeos/options/wifi_config_view.cc
+++ b/chrome/browser/chromeos/options/wifi_config_view.cc
@@ -681,7 +681,7 @@
       chromeos::NetworkLibrary::EAPConfigData config_data;
       config_data.method = GetEapMethod();
       config_data.auth = GetEapPhase2Auth();
-      config_data.server_ca_cert_nss_nickname = GetEapServerCaCertNssNickname();
+      config_data.server_ca_cert_pem = GetEapServerCaCertPEM();
       config_data.use_system_cas = GetEapUseSystemCas();
       config_data.client_cert_pkcs11_id = GetEapClientCertPkcs11Id();
       config_data.identity = GetEapIdentity();
@@ -708,7 +708,7 @@
       DCHECK(method != EAP_METHOD_UNKNOWN);
       wifi->SetEAPMethod(method);
       wifi->SetEAPPhase2Auth(GetEapPhase2Auth());
-      wifi->SetEAPServerCaCertNssNickname(GetEapServerCaCertNssNickname());
+      wifi->SetEAPServerCaCertPEM(GetEapServerCaCertPEM());
       wifi->SetEAPUseSystemCAs(GetEapUseSystemCas());
       wifi->SetEAPClientCertPkcs11Id(GetEapClientCertPkcs11Id());
       wifi->SetEAPIdentity(GetEapIdentity());
@@ -799,7 +799,7 @@
   }
 }
 
-std::string WifiConfigView::GetEapServerCaCertNssNickname() const {
+std::string WifiConfigView::GetEapServerCaCertPEM() const {
   DCHECK(server_ca_cert_combobox_);
   int index = server_ca_cert_combobox_->selected_index();
   if (index == 0) {
@@ -810,7 +810,7 @@
     return std::string();
   } else {
     int cert_index = index - 1;
-    return CertLibrary::Get()->GetCertNicknameAt(
+    return CertLibrary::Get()->GetCertPEMAt(
         CertLibrary::CERT_TYPE_SERVER_CA, cert_index);
   }
 }
@@ -1180,9 +1180,9 @@
 
     // Server CA certificate.
     if (CaCertActive()) {
-      const std::string& nss_nickname =
-          (wifi ? wifi->eap_server_ca_cert_nss_nickname() : std::string());
-      if (nss_nickname.empty()) {
+      const std::string& ca_cert_pem =
+          (wifi ? wifi->eap_server_ca_cert_pem() : std::string());
+      if (ca_cert_pem.empty()) {
         if (wifi->eap_use_system_cas()) {
           // "Default".
           server_ca_cert_combobox_->SetSelectedIndex(0);
@@ -1193,8 +1193,8 @@
         }
       } else {
         // Select the certificate if available.
-        int cert_index = CertLibrary::Get()->GetCertIndexByNickname(
-            CertLibrary::CERT_TYPE_SERVER_CA, nss_nickname);
+        int cert_index = CertLibrary::Get()->GetCertIndexByPEM(
+            CertLibrary::CERT_TYPE_SERVER_CA, ca_cert_pem);
         if (cert_index >= 0) {
           // Skip item for "Default".
           server_ca_cert_combobox_->SetSelectedIndex(1 + cert_index);
diff --git a/chrome/browser/chromeos/options/wifi_config_view.h b/chrome/browser/chromeos/options/wifi_config_view.h
index 6e05033..574072d 100644
--- a/chrome/browser/chromeos/options/wifi_config_view.h
+++ b/chrome/browser/chromeos/options/wifi_config_view.h
@@ -99,7 +99,7 @@
   // Get various 802.1X EAP values from the widgets.
   EAPMethod GetEapMethod() const;
   EAPPhase2Auth GetEapPhase2Auth() const;
-  std::string GetEapServerCaCertNssNickname() const;
+  std::string GetEapServerCaCertPEM() const;
   bool GetEapUseSystemCas() const;
   std::string GetEapClientCertPkcs11Id() const;
   std::string GetEapIdentity() const;
diff --git a/chrome/browser/chromeos/policy/app_pack_updater.cc b/chrome/browser/chromeos/policy/app_pack_updater.cc
index 74bb18d..628150f 100644
--- a/chrome/browser/chromeos/policy/app_pack_updater.cc
+++ b/chrome/browser/chromeos/policy/app_pack_updater.cc
@@ -261,7 +261,7 @@
 
     if (info.IsDirectory() || file_util::IsLink(info.GetName())) {
       LOG(ERROR) << "Erasing bad file in AppPack directory: " << basename;
-      file_util::Delete(path, true /* recursive */);
+      base::Delete(path, true /* recursive */);
       continue;
     }
 
@@ -294,7 +294,7 @@
 
     if (id.empty() || version.empty()) {
       LOG(ERROR) << "Invalid file in AppPack cache, erasing: " << basename;
-      file_util::Delete(path, true /* recursive */);
+      base::Delete(path, true /* recursive */);
       continue;
     }
 
@@ -313,10 +313,10 @@
       DCHECK(vEntry.IsValid());
       DCHECK(vCurrent.IsValid());
       if (vEntry.CompareTo(vCurrent) < 0) {
-        file_util::Delete(base::FilePath(entry.path), true /* recursive */);
+        base::Delete(base::FilePath(entry.path), true /* recursive */);
         entry.path = path.value();
       } else {
-        file_util::Delete(path, true /* recursive */);
+        base::Delete(path, true /* recursive */);
       }
       continue;
     }
@@ -470,7 +470,7 @@
   if (!version_validator.IsValid()) {
     LOG(ERROR) << "AppPack downloaded extension " << id << " but got bad "
                << "version: " << version;
-    file_util::Delete(path, true /* recursive */);
+    base::Delete(path, true /* recursive */);
     return;
   }
 
@@ -481,7 +481,7 @@
   if (file_util::PathExists(cached_crx_path)) {
     LOG(WARNING) << "AppPack downloaded a crx whose filename will overwrite "
                  << "an existing cached crx.";
-    file_util::Delete(cached_crx_path, true /* recursive */);
+    base::Delete(cached_crx_path, true /* recursive */);
   }
 
   if (!file_util::DirectoryExists(cache_dir)) {
@@ -489,15 +489,15 @@
                << cache_dir.value();
     if (!file_util::CreateDirectory(cache_dir)) {
       LOG(ERROR) << "Failed to create the AppPack cache dir!";
-      file_util::Delete(path, true /* recursive */);
+      base::Delete(path, true /* recursive */);
       return;
     }
   }
 
-  if (!file_util::Move(path, cached_crx_path)) {
+  if (!base::Move(path, cached_crx_path)) {
     LOG(ERROR) << "Failed to move AppPack crx from " << path.value()
                << " to " << cached_crx_path.value();
-    file_util::Delete(path, true /* recursive */);
+    base::Delete(path, true /* recursive */);
     return;
   }
 
@@ -539,7 +539,7 @@
       // The file will be downloaded again on the next restart.
       BrowserThread::PostTask(
           BrowserThread::FILE, FROM_HERE,
-          base::Bind(base::IgnoreResult(file_util::Delete), path, true));
+          base::Bind(base::IgnoreResult(base::Delete), path, true));
 
       // Don't try to DownloadMissingExtensions() from here,
       // since it can cause a fail/retry loop.
diff --git a/chrome/browser/chromeos/policy/auto_enrollment_client.h b/chrome/browser/chromeos/policy/auto_enrollment_client.h
index 2e8b424..95c22ef 100644
--- a/chrome/browser/chromeos/policy/auto_enrollment_client.h
+++ b/chrome/browser/chromeos/policy/auto_enrollment_client.h
@@ -11,7 +11,7 @@
 #include "base/callback.h"
 #include "base/compiler_specific.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/policy/cloud/cloud_policy_constants.h"
 #include "third_party/protobuf/src/google/protobuf/repeated_field.h"
 
diff --git a/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.cc b/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.cc
index ebc0442..e12200f 100644
--- a/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.cc
+++ b/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.cc
@@ -138,10 +138,12 @@
   std::string requisition;
   const PrefService::Preference* pref = local_state_->FindPreference(
       prefs::kDeviceEnrollmentRequisition);
-  if (pref->IsDefaultValue())
-    requisition = GetMachineStatistic(chromeos::kOemDeviceRequisitionKey);
-  else
+  if (pref->IsDefaultValue()) {
+    requisition =
+        GetMachineStatistic(chromeos::system::kOemDeviceRequisitionKey);
+  } else {
     pref->GetValue()->GetAsString(&requisition);
+  }
 
   return requisition;
 }
@@ -165,14 +167,15 @@
   if (local_state_->HasPrefPath(prefs::kDeviceEnrollmentAutoStart))
     return local_state_->GetBoolean(prefs::kDeviceEnrollmentAutoStart);
 
-  return GetMachineFlag(chromeos::kOemIsEnterpriseManagedKey, false);
+  return GetMachineFlag(chromeos::system::kOemIsEnterpriseManagedKey, false);
 }
 
 bool DeviceCloudPolicyManagerChromeOS::CanExitEnrollment() const {
   if (local_state_->HasPrefPath(prefs::kDeviceEnrollmentCanExit))
     return local_state_->GetBoolean(prefs::kDeviceEnrollmentCanExit);
 
-  return GetMachineFlag(chromeos::kOemCanExitEnterpriseEnrollmentKey, true);
+  return GetMachineFlag(chromeos::system::kOemCanExitEnterpriseEnrollmentKey,
+                        true);
 }
 
 void DeviceCloudPolicyManagerChromeOS::Shutdown() {
@@ -220,6 +223,11 @@
   return GetMachineStatistic(kMachineInfoSystemHwqual);
 }
 
+std::string DeviceCloudPolicyManagerChromeOS::GetRobotAccountId() {
+  const enterprise_management::PolicyData* policy = device_store_->policy();
+  return policy ? policy->service_account_identity() : std::string();
+}
+
 scoped_ptr<CloudPolicyClient> DeviceCloudPolicyManagerChromeOS::CreateClient() {
   return make_scoped_ptr(
       new CloudPolicyClient(GetMachineID(), GetMachineModel(),
diff --git a/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.h b/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.h
index 005028d..e10a54a 100644
--- a/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.h
+++ b/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.h
@@ -88,6 +88,11 @@
   // Returns the machine model, or an empty string if not available.
   static std::string GetMachineModel();
 
+  // Returns the robot 'email address' associated with the device robot
+  // account (sometimes called a service account) associated with this device
+  // during enterprise enrollment.
+  std::string GetRobotAccountId();
+
  private:
   // Creates a new CloudPolicyClient.
   scoped_ptr<CloudPolicyClient> CreateClient();
diff --git a/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos_unittest.cc b/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos_unittest.cc
index 22b47d6..2c7c0be 100644
--- a/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos_unittest.cc
+++ b/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos_unittest.cc
@@ -28,6 +28,7 @@
 #include "chromeos/cryptohome/mock_cryptohome_library.h"
 #include "chromeos/dbus/cryptohome_client.h"
 #include "chromeos/dbus/dbus_client_implementation_type.h"
+#include "google_apis/gaia/gaia_oauth_client.h"
 #include "net/url_request/test_url_fetcher_factory.h"
 #include "net/url_request/url_request_test_util.h"
 #include "policy/policy_constants.h"
@@ -158,6 +159,9 @@
 
   manager_.Shutdown();
   EXPECT_TRUE(manager_.policies().Equals(bundle));
+
+  EXPECT_EQ(manager_.GetRobotAccountId(),
+            PolicyBuilder::kFakeServiceAccountIdentity);
 }
 
 TEST_F(DeviceCloudPolicyManagerChromeOSTest, ConsumerDevice) {
@@ -326,7 +330,8 @@
     // We return a successful OAuth response via a TestURLFetcher to trigger the
     // happy path for these classes so that enrollment can continue.
     if (robot_auth_fetch_status_ == DM_STATUS_SUCCESS) {
-      net::TestURLFetcher* url_fetcher = url_fetcher_factory_.GetFetcherByID(0);
+      net::TestURLFetcher* url_fetcher = url_fetcher_factory_.GetFetcherByID(
+          gaia::GaiaOAuthClient::kUrlFetcherId);
       ASSERT_TRUE(url_fetcher);
       url_fetcher->SetMaxRetriesOn5xx(0);
       url_fetcher->set_status(net::URLRequestStatus());
@@ -484,5 +489,5 @@
             status_.store_status());
 }
 
-}  // namespace test
+}  // namespace
 }  // namespace policy
diff --git a/chrome/browser/chromeos/policy/device_local_account_browsertest.cc b/chrome/browser/chromeos/policy/device_local_account_browsertest.cc
index 9a13741..ac604d6 100644
--- a/chrome/browser/chromeos/policy/device_local_account_browsertest.cc
+++ b/chrome/browser/chromeos/policy/device_local_account_browsertest.cc
@@ -8,30 +8,28 @@
 #include "base/basictypes.h"
 #include "base/bind.h"
 #include "base/command_line.h"
-#include "base/file_util.h"
-#include "base/files/file_path.h"
-#include "base/files/scoped_temp_dir.h"
+#include "base/memory/scoped_ptr.h"
 #include "base/message_loop.h"
-#include "base/path_service.h"
 #include "base/run_loop.h"
-#include "base/stl_util.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chromeos/login/existing_user_controller.h"
 #include "chrome/browser/chromeos/login/login_display_host.h"
 #include "chrome/browser/chromeos/login/login_display_host_impl.h"
+#include "chrome/browser/chromeos/login/mock_login_status_consumer.h"
+#include "chrome/browser/chromeos/login/screens/wizard_screen.h"
 #include "chrome/browser/chromeos/login/user.h"
 #include "chrome/browser/chromeos/login/user_manager.h"
+#include "chrome/browser/chromeos/login/wizard_controller.h"
 #include "chrome/browser/chromeos/policy/device_local_account.h"
 #include "chrome/browser/chromeos/policy/device_policy_builder.h"
-#include "chrome/browser/chromeos/policy/enterprise_install_attributes.h"
+#include "chrome/browser/chromeos/policy/device_policy_cros_browser_test.h"
 #include "chrome/browser/lifetime/application_lifetime.h"
 #include "chrome/browser/policy/cloud/cloud_policy_constants.h"
 #include "chrome/browser/policy/cloud/policy_builder.h"
 #include "chrome/browser/policy/policy_service.h"
 #include "chrome/browser/policy/proto/chromeos/chrome_device_policy.pb.h"
-#include "chrome/browser/policy/proto/chromeos/install_attributes.pb.h"
 #include "chrome/browser/policy/test/local_policy_test_server.h"
 #include "chrome/browser/prefs/session_startup_pref.h"
 #include "chrome/browser/ui/browser.h"
@@ -40,24 +38,23 @@
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/common/chrome_notification_types.h"
 #include "chrome/common/chrome_switches.h"
-#include "chrome/test/base/in_process_browser_test.h"
-#include "chromeos/chromeos_paths.h"
 #include "chromeos/chromeos_switches.h"
 #include "chromeos/dbus/cryptohome_client.h"
 #include "chromeos/dbus/dbus_method_call_status.h"
-#include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/fake_cryptohome_client.h"
 #include "chromeos/dbus/fake_session_manager_client.h"
-#include "chromeos/dbus/mock_dbus_thread_manager_without_gmock.h"
 #include "chromeos/dbus/session_manager_client.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/test_utils.h"
+#include "crypto/rsa_private_key.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "third_party/cros_system_api/dbus/service_constants.h"
 
 namespace em = enterprise_management;
 
+using testing::InvokeWithoutArgs;
 using testing::Return;
+using testing::_;
 
 namespace policy {
 
@@ -65,8 +62,7 @@
 
 const char kAccountId1[] = "dla1@example.com";
 const char kAccountId2[] = "dla2@example.com";
-const char kDisplayName1[] = "display name for account 1";
-const char kDisplayName2[] = "display name for account 2";
+const char kDisplayName[] = "display name";
 const char* kStartupURLs[] = {
   "chrome://policy",
   "chrome://about",
@@ -74,7 +70,7 @@
 
 }  // namespace
 
-class DeviceLocalAccountTest : public InProcessBrowserTest {
+class DeviceLocalAccountTest : public DevicePolicyCrosBrowserTest {
  protected:
   DeviceLocalAccountTest()
       : user_id_1_(GenerateDeviceLocalAccountUserId(
@@ -94,7 +90,7 @@
                                 PolicyBuilder::kFakeDeviceId);
     ASSERT_TRUE(test_server_.Start());
 
-    InProcessBrowserTest::SetUp();
+    DevicePolicyCrosBrowserTest::SetUp();
   }
 
   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
@@ -106,7 +102,7 @@
   }
 
   virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
-    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+    DevicePolicyCrosBrowserTest::SetUpInProcessBrowserTestFixture();
 
     // Clear command-line arguments (but keep command-line switches) so the
     // startup pages policy takes effect.
@@ -116,17 +112,10 @@
                argv.end());
     command_line->InitFromArgv(argv);
 
-    // Mark the device enterprise-enrolled.
-    SetUpInstallAttributes();
+    InstallOwnerKey();
+    MarkAsEnterpriseOwned();
 
-    // Redirect session_manager DBus calls to FakeSessionManagerClient.
-    chromeos::MockDBusThreadManagerWithoutGMock* dbus_thread_manager =
-        new chromeos::MockDBusThreadManagerWithoutGMock();
-    session_manager_client_ =
-        dbus_thread_manager->fake_session_manager_client();
-    chromeos::DBusThreadManager::InitializeForTesting(dbus_thread_manager);
-
-    SetUpPolicy();
+    InitializePolicy();
   }
 
   virtual void CleanUpOnMainThread() OVERRIDE {
@@ -136,98 +125,68 @@
     base::RunLoop().RunUntilIdle();
   }
 
-  void SetUpInstallAttributes() {
-    cryptohome::SerializedInstallAttributes install_attrs_proto;
-    cryptohome::SerializedInstallAttributes::Attribute* attribute = NULL;
-
-    attribute = install_attrs_proto.add_attributes();
-    attribute->set_name(EnterpriseInstallAttributes::kAttrEnterpriseOwned);
-    attribute->set_value("true");
-
-    attribute = install_attrs_proto.add_attributes();
-    attribute->set_name(EnterpriseInstallAttributes::kAttrEnterpriseUser);
-    attribute->set_value(PolicyBuilder::kFakeUsername);
-
-    base::FilePath install_attrs_file =
-        temp_dir_.path().AppendASCII("install_attributes.pb");
-    const std::string install_attrs_blob(
-        install_attrs_proto.SerializeAsString());
-    ASSERT_EQ(static_cast<int>(install_attrs_blob.size()),
-              file_util::WriteFile(install_attrs_file,
-                                   install_attrs_blob.c_str(),
-                                   install_attrs_blob.size()));
-    ASSERT_TRUE(PathService::Override(chromeos::FILE_INSTALL_ATTRIBUTES,
-                                      install_attrs_file));
+  void RemoveOwnerPrivateKeyFromPolicyBuilders() {
+    // Any instances of the private half of the owner key held by policy
+    // builders must be dropped as otherwise the NSS library will tell Chrome
+    // that the key is available - which is incorrect and leads to Chrome
+    // behaving as if a local owner were logged in.
+    device_policy()->set_signing_key(scoped_ptr<crypto::RSAPrivateKey>());
+    device_policy()->set_new_signing_key(scoped_ptr<crypto::RSAPrivateKey>());
+    device_local_account_policy_.set_signing_key(
+        scoped_ptr<crypto::RSAPrivateKey>());
+    device_local_account_policy_.set_new_signing_key(
+        scoped_ptr<crypto::RSAPrivateKey>());
   }
 
-  void SetUpPolicy() {
-    // Configure two device-local accounts in device settings.
-    DevicePolicyBuilder device_policy;
-    device_policy.policy_data().set_public_key_version(1);
-    em::ChromeDeviceSettingsProto& proto(device_policy.payload());
+  void InitializePolicy() {
+    device_policy()->policy_data().set_public_key_version(1);
+    em::ChromeDeviceSettingsProto& proto(device_policy()->payload());
     proto.mutable_show_user_names()->set_show_user_names(true);
-    em::DeviceLocalAccountInfoProto* account1 =
-        proto.mutable_device_local_accounts()->add_account();
-    account1->set_account_id(kAccountId1);
-    account1->set_type(
-        em::DeviceLocalAccountInfoProto::ACCOUNT_TYPE_PUBLIC_SESSION);
-    em::DeviceLocalAccountInfoProto* account2 =
-        proto.mutable_device_local_accounts()->add_account();
-    account2->set_account_id(kAccountId2);
-    account2->set_type(
-        em::DeviceLocalAccountInfoProto::ACCOUNT_TYPE_PUBLIC_SESSION);
-    device_policy.Build();
-    session_manager_client_->set_device_policy(device_policy.GetBlob());
-    test_server_.UpdatePolicy(dm_protocol::kChromeDevicePolicyType,
-                              std::string(), proto.SerializeAsString());
 
-    // Install the owner key.
-    base::FilePath owner_key_file = temp_dir_.path().AppendASCII("owner.key");
-    std::vector<uint8> owner_key_bits;
-    ASSERT_TRUE(device_policy.signing_key()->ExportPublicKey(&owner_key_bits));
-    ASSERT_EQ(
-        static_cast<int>(owner_key_bits.size()),
-        file_util::WriteFile(
-            owner_key_file,
-            reinterpret_cast<const char*>(vector_as_array(&owner_key_bits)),
-            owner_key_bits.size()));
-    ASSERT_TRUE(
-        PathService::Override(chromeos::FILE_OWNER_KEY, owner_key_file));
-
-    // Configure device-local account policy for the first device-local account.
-    UserPolicyBuilder device_local_account_policy;
-    device_local_account_policy.policy_data().set_policy_type(
+    device_local_account_policy_.policy_data().set_policy_type(
         dm_protocol::kChromePublicAccountPolicyType);
-    device_local_account_policy.policy_data().set_username(kAccountId1);
-    device_local_account_policy.policy_data().set_settings_entity_id(
+    device_local_account_policy_.policy_data().set_username(kAccountId1);
+    device_local_account_policy_.policy_data().set_settings_entity_id(
         kAccountId1);
-    device_local_account_policy.policy_data().set_public_key_version(1);
-    device_local_account_policy.payload().mutable_restoreonstartup()->set_value(
-        SessionStartupPref::kPrefValueURLs);
-    em::StringListPolicyProto* startup_urls_proto =
-        device_local_account_policy.payload().mutable_restoreonstartupurls();
-    for (size_t i = 0; i < arraysize(kStartupURLs); ++i)
-      startup_urls_proto->mutable_value()->add_entries(kStartupURLs[i]);
-    device_local_account_policy.payload().mutable_userdisplayname()->set_value(
-        kDisplayName1);
-    device_local_account_policy.Build();
-    session_manager_client_->set_device_local_account_policy(
-        kAccountId1, device_local_account_policy.GetBlob());
+    device_local_account_policy_.policy_data().set_public_key_version(1);
+    device_local_account_policy_.payload().mutable_userdisplayname()->set_value(
+        kDisplayName);
+
+    RemoveOwnerPrivateKeyFromPolicyBuilders();
+  }
+
+  void BuildDeviceLocalAccountPolicy() {
+    device_local_account_policy_.set_signing_key(
+        PolicyBuilder::CreateTestSigningKey());
+    device_local_account_policy_.Build();
+    RemoveOwnerPrivateKeyFromPolicyBuilders();
+  }
+
+  void InstallDeviceLocalAccountPolicy() {
+    BuildDeviceLocalAccountPolicy();
+    session_manager_client()->set_device_local_account_policy(
+        kAccountId1, device_local_account_policy_.GetBlob());
+  }
+
+  void UploadDeviceLocalAccountPolicy() {
+    BuildDeviceLocalAccountPolicy();
+    ASSERT_TRUE(session_manager_client()->device_local_account_policy(
+        kAccountId1).empty());
     test_server_.UpdatePolicy(
         dm_protocol::kChromePublicAccountPolicyType, kAccountId1,
-        device_local_account_policy.payload().SerializeAsString());
+        device_local_account_policy_.payload().SerializeAsString());
+  }
 
-    // Make policy for the second account available from the server.
-    device_local_account_policy.payload().mutable_userdisplayname()->set_value(
-        kDisplayName2);
-    test_server_.UpdatePolicy(
-        dm_protocol::kChromePublicAccountPolicyType, kAccountId2,
-        device_local_account_policy.payload().SerializeAsString());
-
-    // Don't install policy for |kAccountId2| yet so initial download gets
-    // test coverage.
-    ASSERT_TRUE(session_manager_client_->device_local_account_policy(
-        kAccountId2).empty());
+  void AddPublicSessionToDevicePolicy(const std::string& username) {
+    em::ChromeDeviceSettingsProto& proto(device_policy()->payload());
+    em::DeviceLocalAccountInfoProto* account =
+        proto.mutable_device_local_accounts()->add_account();
+    account->set_account_id(username);
+    account->set_type(
+        em::DeviceLocalAccountInfoProto::ACCOUNT_TYPE_PUBLIC_SESSION);
+    RefreshDevicePolicy();
+    test_server_.UpdatePolicy(dm_protocol::kChromeDevicePolicyType,
+                              std::string(), proto.SerializeAsString());
   }
 
   void CheckPublicSessionPresent(const std::string& id) {
@@ -240,10 +199,8 @@
   const std::string user_id_1_;
   const std::string user_id_2_;
 
+  UserPolicyBuilder device_local_account_policy_;
   LocalPolicyTestServer test_server_;
-  base::ScopedTempDir temp_dir_;
-
-  chromeos::FakeSessionManagerClient* session_manager_client_;
 };
 
 static bool IsKnownUser(const std::string& account_id) {
@@ -251,6 +208,9 @@
 }
 
 IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, LoginScreen) {
+  AddPublicSessionToDevicePolicy(kAccountId1);
+  AddPublicSessionToDevicePolicy(kAccountId2);
+
   content::WindowedNotificationObserver(chrome::NOTIFICATION_USER_LIST_CHANGED,
                                         base::Bind(&IsKnownUser, user_id_1_))
       .Wait();
@@ -263,7 +223,7 @@
 }
 
 static bool DisplayNameMatches(const std::string& account_id,
-                        const std::string& display_name) {
+                               const std::string& display_name) {
   const chromeos::User* user =
       chromeos::UserManager::Get()->FindUser(account_id);
   if (!user || user->display_name().empty())
@@ -273,23 +233,28 @@
 }
 
 IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, DisplayName) {
+  InstallDeviceLocalAccountPolicy();
+  AddPublicSessionToDevicePolicy(kAccountId1);
+
   content::WindowedNotificationObserver(
       chrome::NOTIFICATION_USER_LIST_CHANGED,
-      base::Bind(&DisplayNameMatches, user_id_1_, kDisplayName1)).Wait();
+      base::Bind(&DisplayNameMatches, user_id_1_, kDisplayName)).Wait();
 }
 
 IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, PolicyDownload) {
-  // Policy for kAccountId2 is not installed in session_manager_client, make
-  // sure it gets fetched from the server. Note that the test setup doesn't set
-  // up policy for kAccountId2, so the presence of the display name can be used
-  // as signal to indicate successful policy download.
+  UploadDeviceLocalAccountPolicy();
+  AddPublicSessionToDevicePolicy(kAccountId1);
+
+  // Policy for the account is not installed in session_manager_client. Because
+  // of this, the presence of the display name (which comes from policy) can be
+  // used as a signal that indicates successful policy download.
   content::WindowedNotificationObserver(
       chrome::NOTIFICATION_USER_LIST_CHANGED,
-      base::Bind(&DisplayNameMatches, user_id_2_, kDisplayName2)).Wait();
+      base::Bind(&DisplayNameMatches, user_id_1_, kDisplayName)).Wait();
 
   // Sanity check: The policy should be present now.
-  ASSERT_FALSE(session_manager_client_->device_local_account_policy(
-      kAccountId2).empty());
+  ASSERT_FALSE(session_manager_client()->device_local_account_policy(
+      kAccountId1).empty());
 }
 
 static bool IsNotKnownUser(const std::string& account_id) {
@@ -297,6 +262,9 @@
 }
 
 IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, DevicePolicyChange) {
+  AddPublicSessionToDevicePolicy(kAccountId1);
+  AddPublicSessionToDevicePolicy(kAccountId2);
+
   // Wait until the login screen is up.
   content::WindowedNotificationObserver(chrome::NOTIFICATION_USER_LIST_CHANGED,
                                         base::Bind(&IsKnownUser, user_id_1_))
@@ -306,6 +274,10 @@
       .Wait();
 
   // Update policy to remove kAccountId2.
+  em::ChromeDeviceSettingsProto& proto(device_policy()->payload());
+  proto.mutable_device_local_accounts()->clear_account();
+  AddPublicSessionToDevicePolicy(kAccountId1);
+
   em::ChromeDeviceSettingsProto policy;
   policy.mutable_show_user_names()->set_show_user_names(true);
   em::DeviceLocalAccountInfoProto* account1 =
@@ -329,12 +301,22 @@
 }
 
 IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, StartSession) {
+  // Specify startup pages.
+  device_local_account_policy_.payload().mutable_restoreonstartup()->set_value(
+      SessionStartupPref::kPrefValueURLs);
+  em::StringListPolicyProto* startup_urls_proto =
+      device_local_account_policy_.payload().mutable_restoreonstartupurls();
+  for (size_t i = 0; i < arraysize(kStartupURLs); ++i)
+    startup_urls_proto->mutable_value()->add_entries(kStartupURLs[i]);
+  InstallDeviceLocalAccountPolicy();
+  AddPublicSessionToDevicePolicy(kAccountId1);
+
   // This observes the display name becoming available as this indicates
   // device-local account policy is fully loaded, which is a prerequisite for
   // successful login.
   content::WindowedNotificationObserver(
       chrome::NOTIFICATION_USER_LIST_CHANGED,
-      base::Bind(&DisplayNameMatches, user_id_1_, kDisplayName1)).Wait();
+      base::Bind(&DisplayNameMatches, user_id_1_, kDisplayName)).Wait();
 
   chromeos::LoginDisplayHost* host =
       chromeos::LoginDisplayHostImpl::default_host();
@@ -363,4 +345,49 @@
     EXPECT_EQ(GURL(kStartupURLs[i]), tabs->GetWebContentsAt(i)->GetURL());
 }
 
+IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, TermsOfService) {
+  // Specify Terms of Service. The URL does not really matter as the test does
+  // not wait for the terms to load.
+  device_local_account_policy_.payload().mutable_termsofserviceurl()->set_value(
+      "http://localhost/tos");
+  InstallDeviceLocalAccountPolicy();
+  AddPublicSessionToDevicePolicy(kAccountId1);
+
+  // Wait for the device-local account policy to be fully loaded.
+  content::WindowedNotificationObserver(
+      chrome::NOTIFICATION_USER_LIST_CHANGED,
+      base::Bind(&DisplayNameMatches, user_id_1_, kDisplayName)).Wait();
+
+  // Start login into the device-local account.
+  chromeos::LoginDisplayHost* host =
+      chromeos::LoginDisplayHostImpl::default_host();
+  ASSERT_TRUE(host);
+  host->StartSignInScreen();
+  chromeos::ExistingUserController* controller =
+      chromeos::ExistingUserController::current_controller();
+  ASSERT_TRUE(controller);
+  controller->LoginAsPublicAccount(user_id_1_);
+
+  // Set up an observer that will quit the message loop when login has succeeded
+  // and the first wizard screen, if any, is being shown.
+  base::RunLoop run_loop;
+  chromeos::MockConsumer login_status_consumer;
+  EXPECT_CALL(login_status_consumer, OnLoginSuccess(_, false, false))
+      .Times(1)
+      .WillOnce(InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit));
+
+  // Spin the loop until the observer fires. Then, unregister the observer.
+  controller->set_login_status_consumer(&login_status_consumer);
+  run_loop.Run();
+  controller->set_login_status_consumer(NULL);
+
+  // Verify that the Terms of Service screen is being shown.
+  chromeos::WizardController* wizard_controller =
+        chromeos::WizardController::default_controller();
+  ASSERT_TRUE(wizard_controller);
+  ASSERT_TRUE(wizard_controller->current_screen());
+  EXPECT_EQ(chromeos::WizardController::kTermsOfServiceScreenName,
+            wizard_controller->current_screen()->GetName());
+}
+
 }  // namespace policy
diff --git a/chrome/browser/chromeos/policy/device_policy_cros_browser_test.cc b/chrome/browser/chromeos/policy/device_policy_cros_browser_test.cc
index bbc8471..d62c486 100644
--- a/chrome/browser/chromeos/policy/device_policy_cros_browser_test.cc
+++ b/chrome/browser/chromeos/policy/device_policy_cros_browser_test.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/chromeos/policy/device_policy_cros_browser_test.h"
 
+#include <string>
 #include <vector>
 
 #include "base/file_util.h"
@@ -12,6 +13,8 @@
 #include "base/path_service.h"
 #include "base/stl_util.h"
 #include "chrome/browser/chromeos/policy/device_policy_builder.h"
+#include "chrome/browser/chromeos/policy/enterprise_install_attributes.h"
+#include "chrome/browser/policy/proto/chromeos/install_attributes.pb.h"
 #include "chromeos/chromeos_paths.h"
 #include "chromeos/dbus/mock_dbus_thread_manager_without_gmock.h"
 #include "crypto/rsa_private_key.h"
@@ -24,6 +27,30 @@
 
 namespace policy {
 
+void DevicePolicyCrosBrowserTest::MarkAsEnterpriseOwned() {
+  cryptohome::SerializedInstallAttributes install_attrs_proto;
+  cryptohome::SerializedInstallAttributes::Attribute* attribute = NULL;
+
+  attribute = install_attrs_proto.add_attributes();
+  attribute->set_name(EnterpriseInstallAttributes::kAttrEnterpriseOwned);
+  attribute->set_value("true");
+
+  attribute = install_attrs_proto.add_attributes();
+  attribute->set_name(EnterpriseInstallAttributes::kAttrEnterpriseUser);
+  attribute->set_value(DevicePolicyBuilder::kFakeUsername);
+
+  base::FilePath install_attrs_file =
+      temp_dir_.path().AppendASCII("install_attributes.pb");
+  const std::string install_attrs_blob(
+      install_attrs_proto.SerializeAsString());
+  ASSERT_EQ(static_cast<int>(install_attrs_blob.size()),
+            file_util::WriteFile(install_attrs_file,
+                                 install_attrs_blob.c_str(),
+                                 install_attrs_blob.size()));
+  ASSERT_TRUE(PathService::Override(chromeos::FILE_INSTALL_ATTRIBUTES,
+                                    install_attrs_file));
+}
+
 DevicePolicyCrosBrowserTest::DevicePolicyCrosBrowserTest()
     : mock_dbus_thread_manager_(
         new chromeos::MockDBusThreadManagerWithoutGMock) {
diff --git a/chrome/browser/chromeos/policy/device_policy_cros_browser_test.h b/chrome/browser/chromeos/policy/device_policy_cros_browser_test.h
index 88961e6..41efb7f 100644
--- a/chrome/browser/chromeos/policy/device_policy_cros_browser_test.h
+++ b/chrome/browser/chromeos/policy/device_policy_cros_browser_test.h
@@ -20,6 +20,12 @@
 // Used to test Device policy changes in Chrome OS.
 class DevicePolicyCrosBrowserTest :
     public chromeos::CrosInProcessBrowserTest {
+ public:
+  // Marks the device as enterprise-owned. Must be called to make device
+  // policies apply Chrome-wide. If this is not called, device policies will
+  // affect CrosSettings only.
+  void MarkAsEnterpriseOwned();
+
  protected:
   DevicePolicyCrosBrowserTest();
   virtual ~DevicePolicyCrosBrowserTest();
@@ -46,15 +52,15 @@
   DevicePolicyBuilder* device_policy() { return &device_policy_; }
 
  private:
+  // Stores the device owner key and the install attributes.
+  base::ScopedTempDir temp_dir_;
+
   // MockDBusThreadManagerWithoutGMock uses FakeSessionManagerClient.
   chromeos::MockDBusThreadManagerWithoutGMock* mock_dbus_thread_manager_;
 
   // Carries Chrome OS device policies for tests.
   DevicePolicyBuilder device_policy_;
 
-  // Stores the device owner key.
-  base::ScopedTempDir temp_dir_;
-
   DISALLOW_COPY_AND_ASSIGN(DevicePolicyCrosBrowserTest);
 };
 
diff --git a/chrome/browser/chromeos/policy/device_policy_decoder_chromeos.cc b/chrome/browser/chromeos/policy/device_policy_decoder_chromeos.cc
index b1d9b62..15359ec 100644
--- a/chrome/browser/chromeos/policy/device_policy_decoder_chromeos.cc
+++ b/chrome/browser/chromeos/policy/device_policy_decoder_chromeos.cc
@@ -177,6 +177,19 @@
                         container.enable_auto_login_bailout()));
     }
   }
+
+  if (policy.has_supervised_users_settings()) {
+    const em::SupervisedUsersSettingsProto& container =
+        policy.supervised_users_settings();
+    if (container.has_supervised_users_enabled()) {
+      Value* value = Value::CreateBooleanValue(
+          container.supervised_users_enabled());
+      policies->Set(key::kSupervisedUsersEnabled,
+                    POLICY_LEVEL_MANDATORY,
+                    POLICY_SCOPE_MACHINE,
+                    value);
+    }
+  }
 }
 
 void DecodeKioskPolicies(const em::ChromeDeviceSettingsProto& policy,
@@ -416,6 +429,50 @@
   }
 }
 
+void DecodeAccessibilityPolicies(const em::ChromeDeviceSettingsProto& policy,
+                                 PolicyMap* policies) {
+  if (policy.has_accessibility_settings()) {
+    const em::AccessibilitySettingsProto&
+        container(policy.accessibility_settings());
+
+    if (container.has_login_screen_default_large_cursor_enabled()) {
+      policies->Set(
+          key::kDeviceLoginScreenDefaultLargeCursorEnabled,
+          POLICY_LEVEL_MANDATORY,
+          POLICY_SCOPE_MACHINE,
+          Value::CreateBooleanValue(
+              container.login_screen_default_large_cursor_enabled()));
+    }
+
+    if (container.has_login_screen_default_spoken_feedback_enabled()) {
+      policies->Set(
+          key::kDeviceLoginScreenDefaultSpokenFeedbackEnabled,
+          POLICY_LEVEL_MANDATORY,
+          POLICY_SCOPE_MACHINE,
+          Value::CreateBooleanValue(
+              container.login_screen_default_spoken_feedback_enabled()));
+    }
+
+    if (container.has_login_screen_default_high_contrast_enabled()) {
+      policies->Set(
+          key::kDeviceLoginScreenDefaultHighContrastEnabled,
+          POLICY_LEVEL_MANDATORY,
+          POLICY_SCOPE_MACHINE,
+          Value::CreateBooleanValue(
+              container.login_screen_default_high_contrast_enabled()));
+    }
+
+    if (container.has_login_screen_default_screen_magnifier_type()) {
+      policies->Set(
+          key::kDeviceLoginScreenDefaultScreenMagnifierType,
+          POLICY_LEVEL_MANDATORY,
+          POLICY_SCOPE_MACHINE,
+          DecodeIntegerValue(
+              container.login_screen_default_screen_magnifier_type()));
+    }
+  }
+}
+
 void DecodeGenericPolicies(const em::ChromeDeviceSettingsProto& policy,
                            PolicyMap* policies) {
   if (policy.has_device_policy_refresh_rate()) {
@@ -533,6 +590,7 @@
   DecodeNetworkPolicies(policy, policies, install_attributes);
   DecodeReportingPolicies(policy, policies);
   DecodeAutoUpdatePolicies(policy, policies);
+  DecodeAccessibilityPolicies(policy, policies);
   DecodeGenericPolicies(policy, policies);
 }
 
diff --git a/chrome/browser/chromeos/policy/device_status_collector.cc b/chrome/browser/chromeos/policy/device_status_collector.cc
index 215de16..2c31a3a 100644
--- a/chrome/browser/chromeos/policy/device_status_collector.cc
+++ b/chrome/browser/chromeos/policy/device_status_collector.cc
@@ -371,7 +371,7 @@
     em::DeviceStatusReportRequest* request) {
   std::string dev_switch_mode;
   if (statistics_provider_->GetMachineStatistic(
-      "devsw_boot", &dev_switch_mode)) {
+          chromeos::system::kDevSwitchBootMode, &dev_switch_mode)) {
     if (dev_switch_mode == "1")
       request->set_boot_mode("Dev");
     else if (dev_switch_mode == "0")
diff --git a/chrome/browser/chromeos/policy/device_status_collector.h b/chrome/browser/chromeos/policy/device_status_collector.h
index 7eb8f90..2144019 100644
--- a/chrome/browser/chromeos/policy/device_status_collector.h
+++ b/chrome/browser/chromeos/policy/device_status_collector.h
@@ -12,8 +12,8 @@
 #include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
-#include "base/time.h"
-#include "base/timer.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
 #include "chrome/browser/chromeos/version_loader.h"
 #include "chrome/browser/idle.h"
 #include "chrome/browser/policy/cloud/cloud_policy_client.h"
diff --git a/chrome/browser/chromeos/policy/enrollment_handler_chromeos.cc b/chrome/browser/chromeos/policy/enrollment_handler_chromeos.cc
index 9f74d3f..e23ce1e 100644
--- a/chrome/browser/chromeos/policy/enrollment_handler_chromeos.cc
+++ b/chrome/browser/chromeos/policy/enrollment_handler_chromeos.cc
@@ -216,7 +216,6 @@
 
   // Use the system request context to avoid sending user cookies.
   gaia_oauth_client_.reset(new gaia::GaiaOAuthClient(
-      GaiaUrls::GetInstance()->oauth2_token_url(),
       g_browser_process->system_request_context()));
   gaia_oauth_client_->GetTokensFromAuthCode(client_info,
                                             client->robot_api_auth_code(),
diff --git a/chrome/browser/chromeos/policy/login_profile_policy_provider.cc b/chrome/browser/chromeos/policy/login_profile_policy_provider.cc
new file mode 100644
index 0000000..da88bea
--- /dev/null
+++ b/chrome/browser/chromeos/policy/login_profile_policy_provider.cc
@@ -0,0 +1,114 @@
+// 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/policy/login_profile_policy_provider.h"
+
+#include <string>
+
+#include "base/bind.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/values.h"
+#include "chrome/browser/policy/policy_bundle.h"
+#include "chrome/browser/policy/policy_map.h"
+#include "chrome/browser/policy/policy_types.h"
+#include "policy/policy_constants.h"
+
+namespace policy {
+
+namespace {
+
+// Applies the value of |device_policy| in |device_policy_map| as the
+// recommended value of |user_policy| in |user_policy_map|. If the value of
+// |device_policy| is unset, does nothing.
+void ApplyDevicePolicy(const std::string& device_policy,
+                       const std::string& user_policy,
+                       const PolicyMap& device_policy_map,
+                       PolicyMap* user_policy_map) {
+  const base::Value* value = device_policy_map.GetValue(device_policy);
+  if (value) {
+    user_policy_map->Set(user_policy,
+                         POLICY_LEVEL_RECOMMENDED,
+                         POLICY_SCOPE_USER,
+                         value->DeepCopy());
+  }
+}
+
+}  // namespace
+
+LoginProfilePolicyProvider::LoginProfilePolicyProvider(
+    PolicyService* device_policy_service)
+    : device_policy_service_(device_policy_service),
+      waiting_for_device_policy_refresh_(false),
+      weak_factory_(this) {
+}
+
+LoginProfilePolicyProvider::~LoginProfilePolicyProvider() {
+}
+
+void LoginProfilePolicyProvider::Init() {
+  ConfigurationPolicyProvider::Init();
+  device_policy_service_->AddObserver(POLICY_DOMAIN_CHROME, this);
+  if (device_policy_service_->IsInitializationComplete(POLICY_DOMAIN_CHROME))
+    UpdateFromDevicePolicy();
+}
+
+void LoginProfilePolicyProvider::Shutdown() {
+  device_policy_service_->RemoveObserver(POLICY_DOMAIN_CHROME, this);
+  weak_factory_.InvalidateWeakPtrs();
+  ConfigurationPolicyProvider::Shutdown();
+}
+
+void LoginProfilePolicyProvider::RefreshPolicies() {
+  waiting_for_device_policy_refresh_ = true;
+  weak_factory_.InvalidateWeakPtrs();
+  device_policy_service_->RefreshPolicies(base::Bind(
+      &LoginProfilePolicyProvider::OnDevicePolicyRefreshDone,
+      weak_factory_.GetWeakPtr()));
+}
+
+void LoginProfilePolicyProvider::OnPolicyUpdated(const PolicyNamespace& ns,
+                                                 const PolicyMap& previous,
+                                                 const PolicyMap& current) {
+  if (ns == PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()))
+    UpdateFromDevicePolicy();
+}
+
+void LoginProfilePolicyProvider::OnPolicyServiceInitialized(
+    PolicyDomain domain) {
+  if (domain == POLICY_DOMAIN_CHROME)
+    UpdateFromDevicePolicy();
+}
+
+void LoginProfilePolicyProvider::OnDevicePolicyRefreshDone() {
+  waiting_for_device_policy_refresh_ = false;
+  UpdateFromDevicePolicy();
+}
+
+void LoginProfilePolicyProvider::UpdateFromDevicePolicy() {
+  // If a policy refresh is in progress, wait for it to finish.
+  if (waiting_for_device_policy_refresh_)
+    return;
+
+  const PolicyNamespace chrome_namespaces(POLICY_DOMAIN_CHROME, std::string());
+  const PolicyMap& device_policy_map =
+      device_policy_service_->GetPolicies(chrome_namespaces);
+  scoped_ptr<PolicyBundle> bundle(new PolicyBundle);
+  PolicyMap& user_policy_map = bundle->Get(chrome_namespaces);
+
+  ApplyDevicePolicy(key::kDeviceLoginScreenDefaultLargeCursorEnabled,
+                    key::kLargeCursorEnabled,
+                    device_policy_map, &user_policy_map);
+  ApplyDevicePolicy(key::kDeviceLoginScreenDefaultSpokenFeedbackEnabled,
+                    key::kSpokenFeedbackEnabled,
+                    device_policy_map, &user_policy_map);
+  ApplyDevicePolicy(key::kDeviceLoginScreenDefaultHighContrastEnabled,
+                    key::kHighContrastEnabled,
+                    device_policy_map, &user_policy_map);
+  ApplyDevicePolicy(key::kDeviceLoginScreenDefaultScreenMagnifierType,
+                    key::kScreenMagnifierType,
+                    device_policy_map, &user_policy_map);
+  UpdatePolicy(bundle.Pass());
+}
+
+}  // namespace policy
diff --git a/chrome/browser/chromeos/policy/login_profile_policy_provider.h b/chrome/browser/chromeos/policy/login_profile_policy_provider.h
new file mode 100644
index 0000000..47ee1af
--- /dev/null
+++ b/chrome/browser/chromeos/policy/login_profile_policy_provider.h
@@ -0,0 +1,53 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_POLICY_LOGIN_PROFILE_POLICY_PROVIDER_H_
+#define CHROME_BROWSER_CHROMEOS_POLICY_LOGIN_PROFILE_POLICY_PROVIDER_H_
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/memory/weak_ptr.h"
+#include "chrome/browser/policy/configuration_policy_provider.h"
+#include "chrome/browser/policy/policy_service.h"
+
+namespace policy {
+
+// Policy provider for the login profile. Since the login profile is not
+// associated with any user, it does not receive regular user policy. However,
+// several device policies that control features on the login screen surface as
+// recommended user policies in the login profile.
+class LoginProfilePolicyProvider : public ConfigurationPolicyProvider,
+                                   public PolicyService::Observer {
+ public:
+  explicit LoginProfilePolicyProvider(PolicyService* device_policy_service);
+  virtual ~LoginProfilePolicyProvider();
+
+  // ConfigurationPolicyProvider:
+  virtual void Init() OVERRIDE;
+  virtual void Shutdown() OVERRIDE;
+  virtual void RefreshPolicies() OVERRIDE;
+
+  // PolicyService::Observer:
+  virtual void OnPolicyUpdated(const PolicyNamespace& ns,
+                               const PolicyMap& previous,
+                               const PolicyMap& current) OVERRIDE;
+  virtual void OnPolicyServiceInitialized(PolicyDomain domain) OVERRIDE;
+
+  void OnDevicePolicyRefreshDone();
+
+ private:
+  void UpdateFromDevicePolicy();
+
+  PolicyService* device_policy_service_;  // Not owned.
+
+  bool waiting_for_device_policy_refresh_;
+
+  base::WeakPtrFactory<LoginProfilePolicyProvider> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(LoginProfilePolicyProvider);
+};
+
+}  // namespace policy
+
+#endif  // CHROME_BROWSER_CHROMEOS_POLICY_LOGIN_PROFILE_POLICY_PROVIDER_H_
diff --git a/chrome/browser/chromeos/policy/login_screen_default_policy_browsertest.cc b/chrome/browser/chromeos/policy/login_screen_default_policy_browsertest.cc
new file mode 100644
index 0000000..e58cb3c
--- /dev/null
+++ b/chrome/browser/chromeos/policy/login_screen_default_policy_browsertest.cc
@@ -0,0 +1,437 @@
+// 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 "ash/magnifier/magnifier_constants.h"
+#include "base/basictypes.h"
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/command_line.h"
+#include "base/compiler_specific.h"
+#include "base/location.h"
+#include "base/message_loop.h"
+#include "base/prefs/pref_change_registrar.h"
+#include "base/prefs/pref_service.h"
+#include "base/run_loop.h"
+#include "base/values.h"
+#include "chrome/browser/chromeos/accessibility/accessibility_manager.h"
+#include "chrome/browser/chromeos/accessibility/magnification_manager.h"
+#include "chrome/browser/chromeos/policy/device_policy_builder.h"
+#include "chrome/browser/chromeos/policy/device_policy_cros_browser_test.h"
+#include "chrome/browser/chromeos/profiles/profile_helper.h"
+#include "chrome/browser/chromeos/settings/device_settings_service.h"
+#include "chrome/browser/lifetime/application_lifetime.h"
+#include "chrome/browser/policy/proto/chromeos/chrome_device_policy.pb.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/common/pref_names.h"
+#include "chromeos/chromeos_switches.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace em = enterprise_management;
+
+namespace policy {
+
+namespace {
+
+const em::AccessibilitySettingsProto_ScreenMagnifierType kFullScreenMagnifier =
+    em::AccessibilitySettingsProto_ScreenMagnifierType_SCREEN_MAGNIFIER_TYPE_FULL;
+
+// Spins the loop until a notification is received from |prefs| that the value
+// of |pref_name| has changed. If the notification is received before Wait()
+// has been called, Wait() returns immediately and no loop is spun.
+class PrefChangeWatcher {
+ public:
+  PrefChangeWatcher(const char* pref_name, PrefService* prefs);
+
+  void Wait();
+
+  void OnPrefChange();
+
+ private:
+  bool pref_changed_;
+
+  base::RunLoop run_loop_;
+  PrefChangeRegistrar registrar_;
+
+  DISALLOW_COPY_AND_ASSIGN(PrefChangeWatcher);
+};
+
+PrefChangeWatcher::PrefChangeWatcher(const char* pref_name,
+                                     PrefService* prefs)
+    : pref_changed_(false) {
+  registrar_.Init(prefs);
+  registrar_.Add(pref_name, base::Bind(&PrefChangeWatcher::OnPrefChange,
+                                       base::Unretained(this)));
+}
+
+void PrefChangeWatcher::Wait() {
+  if (!pref_changed_)
+    run_loop_.Run();
+}
+
+void PrefChangeWatcher::OnPrefChange() {
+  pref_changed_ = true;
+  run_loop_.Quit();
+}
+
+}  // namespace
+
+class LoginScreenDefaultPolicyBrowsertestBase
+    : public DevicePolicyCrosBrowserTest {
+ protected:
+  LoginScreenDefaultPolicyBrowsertestBase();
+  virtual ~LoginScreenDefaultPolicyBrowsertestBase();
+
+  // DevicePolicyCrosBrowserTest:
+  virtual void SetUpInProcessBrowserTestFixture() OVERRIDE;
+  virtual void SetUpOnMainThread() OVERRIDE;
+
+  void RefreshDevicePolicyAndWaitForPrefChange(const char* pref_name);
+
+  Profile* login_profile_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(LoginScreenDefaultPolicyBrowsertestBase);
+};
+
+class LoginScreenDefaultPolicyLoginScreenBrowsertest
+    : public LoginScreenDefaultPolicyBrowsertestBase {
+ protected:
+  LoginScreenDefaultPolicyLoginScreenBrowsertest();
+  virtual ~LoginScreenDefaultPolicyLoginScreenBrowsertest();
+
+  // LoginScreenDefaultPolicyBrowsertestBase:
+  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE;
+  virtual void SetUpOnMainThread() OVERRIDE;
+  virtual void CleanUpOnMainThread() OVERRIDE;
+
+  void VerifyPrefFollowsRecommendation(const char* pref_name,
+                                       const base::Value& recommended_value);
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(LoginScreenDefaultPolicyLoginScreenBrowsertest);
+};
+
+class LoginScreenDefaultPolicyInSessionBrowsertest
+    : public LoginScreenDefaultPolicyBrowsertestBase {
+ protected:
+  LoginScreenDefaultPolicyInSessionBrowsertest();
+  virtual ~LoginScreenDefaultPolicyInSessionBrowsertest();
+
+  // LoginScreenDefaultPolicyBrowsertestBase:
+  virtual void SetUpOnMainThread() OVERRIDE;
+
+  void VerifyPrefFollowsDefault(const char* pref_name);
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(LoginScreenDefaultPolicyInSessionBrowsertest);
+};
+
+LoginScreenDefaultPolicyBrowsertestBase::
+    LoginScreenDefaultPolicyBrowsertestBase() : login_profile_(NULL) {
+}
+
+LoginScreenDefaultPolicyBrowsertestBase::
+    ~LoginScreenDefaultPolicyBrowsertestBase() {
+}
+
+void LoginScreenDefaultPolicyBrowsertestBase::
+    SetUpInProcessBrowserTestFixture() {
+  InstallOwnerKey();
+  MarkAsEnterpriseOwned();
+  DevicePolicyCrosBrowserTest::SetUpInProcessBrowserTestFixture();
+}
+
+void LoginScreenDefaultPolicyBrowsertestBase::SetUpOnMainThread() {
+  DevicePolicyCrosBrowserTest::SetUpOnMainThread();
+  login_profile_ = chromeos::ProfileHelper::GetSigninProfile();
+  ASSERT_TRUE(login_profile_);
+}
+
+void LoginScreenDefaultPolicyBrowsertestBase::
+    RefreshDevicePolicyAndWaitForPrefChange(const char* pref_name) {
+  PrefChangeWatcher watcher(pref_name, login_profile_->GetPrefs());
+  RefreshDevicePolicy();
+  watcher.Wait();
+}
+
+LoginScreenDefaultPolicyLoginScreenBrowsertest::
+    LoginScreenDefaultPolicyLoginScreenBrowsertest() {
+}
+
+LoginScreenDefaultPolicyLoginScreenBrowsertest::
+    ~LoginScreenDefaultPolicyLoginScreenBrowsertest() {
+}
+
+void LoginScreenDefaultPolicyLoginScreenBrowsertest::SetUpCommandLine(
+    CommandLine* command_line) {
+  LoginScreenDefaultPolicyBrowsertestBase::SetUpCommandLine(command_line);
+  command_line->AppendSwitch(chromeos::switches::kLoginManager);
+  command_line->AppendSwitch(chromeos::switches::kForceLoginManagerInTests);
+}
+
+void LoginScreenDefaultPolicyLoginScreenBrowsertest::SetUpOnMainThread() {
+  LoginScreenDefaultPolicyBrowsertestBase::SetUpOnMainThread();
+
+  // Set the login screen profile.
+  chromeos::AccessibilityManager* accessibility_manager =
+      chromeos::AccessibilityManager::Get();
+  ASSERT_TRUE(accessibility_manager);
+  accessibility_manager->SetProfileForTest(
+      chromeos::ProfileHelper::GetSigninProfile());
+
+  chromeos::MagnificationManager* magnification_manager =
+      chromeos::MagnificationManager::Get();
+  ASSERT_TRUE(magnification_manager);
+  magnification_manager->SetProfileForTest(
+      chromeos::ProfileHelper::GetSigninProfile());
+}
+
+void LoginScreenDefaultPolicyLoginScreenBrowsertest::CleanUpOnMainThread() {
+  base::MessageLoop::current()->PostTask(FROM_HERE,
+                                         base::Bind(&chrome::AttemptExit));
+  base::RunLoop().RunUntilIdle();
+  LoginScreenDefaultPolicyBrowsertestBase::CleanUpOnMainThread();
+}
+
+void LoginScreenDefaultPolicyLoginScreenBrowsertest::
+    VerifyPrefFollowsRecommendation(const char* pref_name,
+                                    const base::Value& recommended_value) {
+  const PrefService::Preference* pref =
+      login_profile_->GetPrefs()->FindPreference(pref_name);
+  ASSERT_TRUE(pref);
+  EXPECT_FALSE(pref->IsManaged());
+  EXPECT_FALSE(pref->IsDefaultValue());
+  EXPECT_TRUE(base::Value::Equals(&recommended_value, pref->GetValue()));
+  EXPECT_TRUE(base::Value::Equals(&recommended_value,
+                                  pref->GetRecommendedValue()));
+}
+
+LoginScreenDefaultPolicyInSessionBrowsertest::
+    LoginScreenDefaultPolicyInSessionBrowsertest() {
+}
+
+LoginScreenDefaultPolicyInSessionBrowsertest::
+    ~LoginScreenDefaultPolicyInSessionBrowsertest() {
+}
+
+void LoginScreenDefaultPolicyInSessionBrowsertest::SetUpOnMainThread() {
+  LoginScreenDefaultPolicyBrowsertestBase::SetUpOnMainThread();
+
+  // Tell the DeviceSettingsService that there is no local owner.
+  chromeos::DeviceSettingsService::Get()->SetUsername(std::string());
+}
+
+void LoginScreenDefaultPolicyInSessionBrowsertest::VerifyPrefFollowsDefault(
+    const char* pref_name) {
+  Profile* profile = ProfileManager::GetDefaultProfile();
+  ASSERT_TRUE(profile);
+  const PrefService::Preference* pref =
+      profile->GetPrefs()->FindPreference(pref_name);
+  ASSERT_TRUE(pref);
+  EXPECT_FALSE(pref->IsManaged());
+  EXPECT_TRUE(pref->IsDefaultValue());
+  EXPECT_FALSE(pref->GetRecommendedValue());
+}
+
+IN_PROC_BROWSER_TEST_F(LoginScreenDefaultPolicyLoginScreenBrowsertest,
+                       DeviceLoginScreenDefaultLargeCursorEnabled) {
+  // Verifies that the default state of the large cursor accessibility feature
+  // on the login screen can be controlled through device policy.
+
+  // Enable the large cursor through device policy and wait for the change to
+  // take effect.
+  em::ChromeDeviceSettingsProto& proto(device_policy()->payload());
+  proto.mutable_accessibility_settings()->
+      set_login_screen_default_large_cursor_enabled(true);
+  RefreshDevicePolicyAndWaitForPrefChange(prefs::kLargeCursorEnabled);
+
+  // Verify that the pref which controls the large cursor in the login profile
+  // has changed to the policy-supplied default.
+  VerifyPrefFollowsRecommendation(prefs::kLargeCursorEnabled,
+                                  base::FundamentalValue(true));
+
+  // Verify that the large cursor is enabled.
+  chromeos::AccessibilityManager* accessibility_manager =
+      chromeos::AccessibilityManager::Get();
+  ASSERT_TRUE(accessibility_manager);
+  EXPECT_TRUE(accessibility_manager->IsLargeCursorEnabled());
+}
+
+IN_PROC_BROWSER_TEST_F(LoginScreenDefaultPolicyLoginScreenBrowsertest,
+                       DeviceLoginScreenDefaultSpokenFeedbackEnabled) {
+  // Verifies that the default state of the spoken feedback accessibility
+  // feature on the login screen can be controlled through device policy.
+
+  // Enable spoken feedback through device policy and wait for the change to
+  // take effect.
+  em::ChromeDeviceSettingsProto& proto(device_policy()->payload());
+  proto.mutable_accessibility_settings()->
+      set_login_screen_default_spoken_feedback_enabled(true);
+  RefreshDevicePolicyAndWaitForPrefChange(prefs::kSpokenFeedbackEnabled);
+
+  // Verify that the pref which controls spoken feedback in the login profile
+  // has changed to the policy-supplied default.
+  VerifyPrefFollowsRecommendation(prefs::kSpokenFeedbackEnabled,
+                                  base::FundamentalValue(true));
+
+  // Verify that spoken feedback is enabled.
+  chromeos::AccessibilityManager* accessibility_manager =
+      chromeos::AccessibilityManager::Get();
+  ASSERT_TRUE(accessibility_manager);
+  EXPECT_TRUE(accessibility_manager->IsSpokenFeedbackEnabled());
+}
+
+IN_PROC_BROWSER_TEST_F(LoginScreenDefaultPolicyLoginScreenBrowsertest,
+                       DeviceLoginScreenDefaultHighContrastEnabled) {
+  // Verifies that the default state of the high contrast mode accessibility
+  // feature on the login screen can be controlled through device policy.
+
+  // Enable high contrast mode through device policy and wait for the change to
+  // take effect.
+  em::ChromeDeviceSettingsProto& proto(device_policy()->payload());
+  proto.mutable_accessibility_settings()->
+      set_login_screen_default_high_contrast_enabled(true);
+  RefreshDevicePolicyAndWaitForPrefChange(prefs::kHighContrastEnabled);
+
+  // Verify that the pref which controls high contrast mode in the login profile
+  // has changed to the policy-supplied default.
+  VerifyPrefFollowsRecommendation(prefs::kHighContrastEnabled,
+                                  base::FundamentalValue(true));
+
+  // Verify that high contrast mode is enabled.
+  chromeos::AccessibilityManager* accessibility_manager =
+      chromeos::AccessibilityManager::Get();
+  ASSERT_TRUE(accessibility_manager);
+  EXPECT_TRUE(accessibility_manager->IsHighContrastEnabled());
+}
+
+IN_PROC_BROWSER_TEST_F(LoginScreenDefaultPolicyLoginScreenBrowsertest,
+                       DeviceLoginScreenDefaultScreenMagnifierType) {
+  // Verifies that the default screen magnifier type enabled on the login screen
+  // can be controlled through device policy.
+
+  // Set the screen magnifier type through device policy and wait for the change
+  // to take effect.
+  em::ChromeDeviceSettingsProto& proto(device_policy()->payload());
+  proto.mutable_accessibility_settings()->
+      set_login_screen_default_screen_magnifier_type(kFullScreenMagnifier);
+  RefreshDevicePolicyAndWaitForPrefChange(prefs::kScreenMagnifierType);
+
+  // Verify that the prefs which control the screen magnifier type have changed
+  // to the policy-supplied default.
+  VerifyPrefFollowsRecommendation(prefs::kScreenMagnifierEnabled,
+                                  base::FundamentalValue(true));
+  VerifyPrefFollowsRecommendation(prefs::kScreenMagnifierType,
+                                  base::FundamentalValue(ash::MAGNIFIER_FULL));
+
+  // Verify that the full-screen magnifier is enabled.
+  chromeos::MagnificationManager* magnification_manager =
+      chromeos::MagnificationManager::Get();
+  ASSERT_TRUE(magnification_manager);
+  EXPECT_TRUE(magnification_manager->IsMagnifierEnabled());
+  EXPECT_EQ(ash::MAGNIFIER_FULL, magnification_manager->GetMagnifierType());
+}
+
+IN_PROC_BROWSER_TEST_F(LoginScreenDefaultPolicyInSessionBrowsertest,
+                       DeviceLoginScreenDefaultLargeCursorEnabled) {
+  // Verifies that changing the default state of the large cursor accessibility
+  // feature on the login screen through policy does not affect its state in a
+  // session.
+
+  // Enable the large cursor through device policy and wait for the change to
+  // take effect.
+  em::ChromeDeviceSettingsProto& proto(device_policy()->payload());
+  proto.mutable_accessibility_settings()->
+      set_login_screen_default_large_cursor_enabled(true);
+  RefreshDevicePolicyAndWaitForPrefChange(prefs::kLargeCursorEnabled);
+
+  // Verify that the pref which controls the large cursor in the session is
+  // unchanged.
+  VerifyPrefFollowsDefault(prefs::kLargeCursorEnabled);
+
+  // Verify that the large cursor is disabled.
+  chromeos::AccessibilityManager* accessibility_manager =
+      chromeos::AccessibilityManager::Get();
+  ASSERT_TRUE(accessibility_manager);
+  EXPECT_FALSE(accessibility_manager->IsLargeCursorEnabled());
+}
+
+IN_PROC_BROWSER_TEST_F(LoginScreenDefaultPolicyInSessionBrowsertest,
+                       DeviceLoginScreenDefaultSpokenFeedbackEnabled) {
+  // Verifies that changing the default state of the spoken feedback
+  // accessibility feature on the login screen through policy does not affect
+  // its state in a session.
+
+  // Enable spoken feedback through device policy and wait for the change to
+  // take effect.
+  em::ChromeDeviceSettingsProto& proto(device_policy()->payload());
+  proto.mutable_accessibility_settings()->
+      set_login_screen_default_spoken_feedback_enabled(true);
+  RefreshDevicePolicyAndWaitForPrefChange(prefs::kSpokenFeedbackEnabled);
+
+  // Verify that the pref which controls the spoken feedback in the session is
+  // unchanged.
+  VerifyPrefFollowsDefault(prefs::kSpokenFeedbackEnabled);
+
+  // Verify that spoken feedback is disabled.
+  chromeos::AccessibilityManager* accessibility_manager =
+      chromeos::AccessibilityManager::Get();
+  ASSERT_TRUE(accessibility_manager);
+  EXPECT_FALSE(accessibility_manager->IsSpokenFeedbackEnabled());
+}
+
+IN_PROC_BROWSER_TEST_F(LoginScreenDefaultPolicyInSessionBrowsertest,
+                       DeviceLoginScreenDefaultHighContrastEnabled) {
+  // Verifies that changing the default state of the high contrast mode
+  // accessibility feature on the login screen through policy does not affect
+  // its state in a session.
+
+  // Enable high contrast mode through device policy and wait for the change to
+  // take effect.
+  em::ChromeDeviceSettingsProto& proto(device_policy()->payload());
+  proto.mutable_accessibility_settings()->
+      set_login_screen_default_high_contrast_enabled(true);
+  RefreshDevicePolicyAndWaitForPrefChange(prefs::kHighContrastEnabled);
+
+  // Verify that the pref which controls high contrast mode in the session is
+  // unchanged.
+  VerifyPrefFollowsDefault(prefs::kHighContrastEnabled);
+
+  // Verify that high contrast mode is disabled.
+  chromeos::AccessibilityManager* accessibility_manager =
+      chromeos::AccessibilityManager::Get();
+  ASSERT_TRUE(accessibility_manager);
+  EXPECT_FALSE(accessibility_manager->IsHighContrastEnabled());
+}
+
+IN_PROC_BROWSER_TEST_F(LoginScreenDefaultPolicyInSessionBrowsertest,
+                       DeviceLoginScreenDefaultScreenMagnifierType) {
+  // Verifies that changing the default screen magnifier type enabled on the
+  // login screen through policy does not affect its state in a session.
+
+  // Set the screen magnifier type through device policy and wait for the change
+  // to take effect.
+  em::ChromeDeviceSettingsProto& proto(device_policy()->payload());
+  proto.mutable_accessibility_settings()->
+      set_login_screen_default_screen_magnifier_type(kFullScreenMagnifier);
+  RefreshDevicePolicyAndWaitForPrefChange(prefs::kScreenMagnifierType);
+
+  // Verify that the prefs which control the screen magnifier in the session are
+  // unchanged.
+  VerifyPrefFollowsDefault(prefs::kScreenMagnifierEnabled);
+  VerifyPrefFollowsDefault(prefs::kScreenMagnifierType);
+
+  // Verify that the screen magnifier is disabled.
+  chromeos::MagnificationManager* magnification_manager =
+      chromeos::MagnificationManager::Get();
+  ASSERT_TRUE(magnification_manager);
+  EXPECT_FALSE(magnification_manager->IsMagnifierEnabled());
+  EXPECT_EQ(ash::kDefaultMagnifierType,
+            magnification_manager->GetMagnifierType());
+}
+
+} // namespace policy
diff --git a/chrome/browser/chromeos/policy/network_configuration_updater_impl.cc b/chrome/browser/chromeos/policy/network_configuration_updater_impl.cc
index 54e4033..5fa896c 100644
--- a/chrome/browser/chromeos/policy/network_configuration_updater_impl.cc
+++ b/chrome/browser/chromeos/policy/network_configuration_updater_impl.cc
@@ -97,15 +97,24 @@
   ParseAndValidateOncForImport(
       onc_blob, onc_source, "", &network_configs, &certificates);
 
+  chromeos::CertificateHandler::CertsByGUID imported_server_and_ca_certs;
+  scoped_ptr<net::CertificateList> web_trust_certs(new net::CertificateList);
+  certificate_handler_->ImportCertificates(
+      certificates, onc_source, web_trust_certs.get(),
+      &imported_server_and_ca_certs);
+
+  if (!chromeos::onc::ResolveServerCertRefsInNetworks(
+          imported_server_and_ca_certs, &network_configs)) {
+    LOG(ERROR) << "Some certificate references in the ONC policy for source "
+               << chromeos::onc::GetSourceAsString(onc_source)
+               << " could not be resolved.";
+  }
+
   std::string userhash = onc_source == chromeos::onc::ONC_SOURCE_USER_POLICY ?
       hashed_username_ : std::string();
   chromeos::NetworkHandler::Get()->managed_network_configuration_handler()->
       SetPolicy(onc_source, userhash, network_configs);
 
-  scoped_ptr<net::CertificateList> web_trust_certs(new net::CertificateList);
-  certificate_handler_->ImportCertificates(
-      certificates, onc_source, web_trust_certs.get());
-
   if (onc_source == chromeos::onc::ONC_SOURCE_USER_POLICY)
     SetTrustAnchors(web_trust_certs.Pass());
 }
diff --git a/chrome/browser/chromeos/policy/network_configuration_updater_impl_cros.cc b/chrome/browser/chromeos/policy/network_configuration_updater_impl_cros.cc
index 41a9986..ea60fc2 100644
--- a/chrome/browser/chromeos/policy/network_configuration_updater_impl_cros.cc
+++ b/chrome/browser/chromeos/policy/network_configuration_updater_impl_cros.cc
@@ -165,11 +165,20 @@
   ParseAndValidateOncForImport(
       onc_blob, onc_source, "", &network_configs, &certificates);
 
-  network_library_->LoadOncNetworks(network_configs, onc_source);
-
+  chromeos::CertificateHandler::CertsByGUID imported_server_and_ca_certs;
   scoped_ptr<net::CertificateList> web_trust_certs(new net::CertificateList);
   certificate_handler_->ImportCertificates(
-      certificates, onc_source, web_trust_certs.get());
+      certificates, onc_source, web_trust_certs.get(),
+      &imported_server_and_ca_certs);
+
+  if (!chromeos::onc::ResolveServerCertRefsInNetworks(
+          imported_server_and_ca_certs, &network_configs)) {
+    LOG(ERROR) << "Some certificate references in the ONC policy for source "
+               << chromeos::onc::GetSourceAsString(onc_source)
+               << " could not be resolved.";
+  }
+
+  network_library_->LoadOncNetworks(network_configs, onc_source);
 
   if (onc_source == chromeos::onc::ONC_SOURCE_USER_POLICY)
     SetTrustAnchors(web_trust_certs.Pass());
diff --git a/chrome/browser/chromeos/policy/network_configuration_updater_impl_cros_unittest.cc b/chrome/browser/chromeos/policy/network_configuration_updater_impl_cros_unittest.cc
index b62bca7..afbdb9f 100644
--- a/chrome/browser/chromeos/policy/network_configuration_updater_impl_cros_unittest.cc
+++ b/chrome/browser/chromeos/policy/network_configuration_updater_impl_cros_unittest.cc
@@ -23,6 +23,7 @@
 #include "net/cert/cert_trust_anchor_provider.h"
 #include "net/cert/x509_certificate.h"
 #include "net/test/cert_test_util.h"
+#include "net/test/test_certificate_data.h"
 #include "policy/policy_constants.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -77,6 +78,11 @@
   return true;
 }
 
+ACTION_P(SetImportedCerts, map) {
+  *arg3 = map;
+  return true;
+}
+
 }  // namespace
 
 // Tests of NetworkConfigurationUpdaterImplCros
@@ -175,7 +181,7 @@
   EXPECT_CALL(network_library_, LoadOncNetworks(_, _));
   StrictMock<chromeos::MockCertificateHandler>* certificate_handler =
       new StrictMock<chromeos::MockCertificateHandler>();
-  EXPECT_CALL(*certificate_handler, ImportCertificates(_, _, _));
+  EXPECT_CALL(*certificate_handler, ImportCertificates(_, _, _, _));
 
   NetworkConfigurationUpdaterImplCros updater(
       policy_service_.get(),
@@ -191,7 +197,18 @@
   EXPECT_CALL(network_library_, LoadOncNetworks(
       IsEqualTo(network_configs_repaired),
       onc::ONC_SOURCE_USER_POLICY));
-  EXPECT_CALL(*certificate_handler, ImportCertificates(_, _, _)).Times(2);
+  EXPECT_CALL(*certificate_handler,
+              ImportCertificates(_, chromeos::onc::ONC_SOURCE_DEVICE_POLICY,
+                                 _, _));
+  scoped_refptr<net::X509Certificate> google_cert(
+      net::X509Certificate::CreateFromBytes(
+          reinterpret_cast<const char*>(google_der), sizeof(google_der)));
+  chromeos::CertificateHandler::CertsByGUID imported_certs;
+  imported_certs["test-ca"] = google_cert;
+  EXPECT_CALL(*certificate_handler,
+              ImportCertificates(_, chromeos::onc::ONC_SOURCE_USER_POLICY,
+                                 _, _))
+      .WillOnce(SetImportedCerts(imported_certs));
 
   EXPECT_CALL(network_library_, RemoveNetworkProfileObserver(_));
 
@@ -235,7 +252,7 @@
   StrictMock<chromeos::MockCertificateHandler>* certificate_handler =
       new StrictMock<chromeos::MockCertificateHandler>();
   EXPECT_CALL(*certificate_handler, ImportCertificates(
-      IsEqualTo(device_certs), onc::ONC_SOURCE_DEVICE_POLICY, _));
+      IsEqualTo(device_certs), onc::ONC_SOURCE_DEVICE_POLICY, _, _));
 
   NetworkConfigurationUpdaterImplCros updater(
       policy_service_.get(),
@@ -249,12 +266,12 @@
   EXPECT_CALL(network_library_, LoadOncNetworks(
       IsEqualTo(device_networks), onc::ONC_SOURCE_DEVICE_POLICY));
   EXPECT_CALL(*certificate_handler, ImportCertificates(
-      IsEqualTo(device_certs), onc::ONC_SOURCE_DEVICE_POLICY, _));
+      IsEqualTo(device_certs), onc::ONC_SOURCE_DEVICE_POLICY, _, _));
 
   EXPECT_CALL(network_library_, LoadOncNetworks(
       IsEqualTo(user_networks), onc::ONC_SOURCE_USER_POLICY));
   EXPECT_CALL(*certificate_handler, ImportCertificates(
-      IsEqualTo(user_certs), onc::ONC_SOURCE_USER_POLICY, _));
+      IsEqualTo(user_certs), onc::ONC_SOURCE_USER_POLICY, _, _));
 
   EXPECT_CALL(network_library_, RemoveNetworkProfileObserver(_));
 
@@ -279,7 +296,7 @@
   EXPECT_CALL(network_library_, LoadOncNetworks(_, _)).Times(AnyNumber());
   StrictMock<chromeos::MockCertificateHandler>* certificate_handler =
       new StrictMock<chromeos::MockCertificateHandler>();
-  EXPECT_CALL(*certificate_handler, ImportCertificates(_, _, _))
+  EXPECT_CALL(*certificate_handler, ImportCertificates(_, _, _, _))
       .WillRepeatedly(SetCertificateList(empty_cert_list));
   NetworkConfigurationUpdaterImplCros updater(
       policy_service_.get(),
@@ -302,11 +319,11 @@
   // Certificates with the "Web" trust flag set should be forwarded to the
   // trust provider.
   EXPECT_CALL(network_library_, LoadOncNetworks(_, _));
-  EXPECT_CALL(*certificate_handler, ImportCertificates(_, _, _))
+  EXPECT_CALL(*certificate_handler, ImportCertificates(_, _, _, _))
       .WillRepeatedly(SetCertificateList(empty_cert_list));
   onc::ONCSource current_source = NameToONCSource(GetParam());
   EXPECT_CALL(network_library_, LoadOncNetworks(_, current_source));
-  EXPECT_CALL(*certificate_handler, ImportCertificates(_, current_source, _))
+  EXPECT_CALL(*certificate_handler, ImportCertificates(_, current_source, _, _))
       .WillRepeatedly(SetCertificateList(cert_list));
   // Trigger a new policy load, and spin the IO message loop to pass the
   // certificates to the |trust_provider| on the IO thread.
@@ -336,7 +353,7 @@
       .Times(AnyNumber());
   StrictMock<chromeos::MockCertificateHandler>* certificate_handler =
       new StrictMock<chromeos::MockCertificateHandler>();
-  EXPECT_CALL(*certificate_handler, ImportCertificates(_, _, _))
+  EXPECT_CALL(*certificate_handler, ImportCertificates(_, _, _, _))
       .Times(AnyNumber());
   NetworkConfigurationUpdaterImplCros updater(
       policy_service_.get(),
@@ -350,7 +367,7 @@
   EXPECT_CALL(network_library_, LoadOncNetworks(
       IsEqualTo(fake_network_configs_.get()), NameToONCSource(GetParam())));
   EXPECT_CALL(*certificate_handler, ImportCertificates(
-      IsEqualTo(fake_certificates_.get()), NameToONCSource(GetParam()), _));
+      IsEqualTo(fake_certificates_.get()), NameToONCSource(GetParam()), _, _));
 
   // In the current implementation, we always apply both policies.
   EXPECT_CALL(network_library_, LoadOncNetworks(
@@ -359,7 +376,7 @@
   EXPECT_CALL(*certificate_handler, ImportCertificates(
       IsEqualTo(empty_certificates_.get()),
       Ne(NameToONCSource(GetParam())),
-      _));
+      _, _));
 
   PolicyMap policy;
   policy.Set(GetParam(), POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
@@ -376,7 +393,7 @@
   EXPECT_CALL(*certificate_handler, ImportCertificates(
       IsEqualTo(empty_certificates_.get()),
       onc::ONC_SOURCE_DEVICE_POLICY,
-      _));
+      _, _));
 
   EXPECT_CALL(network_library_, LoadOncNetworks(
       IsEqualTo(empty_network_configs_.get()),
@@ -384,7 +401,7 @@
   EXPECT_CALL(*certificate_handler, ImportCertificates(
       IsEqualTo(empty_certificates_.get()),
       onc::ONC_SOURCE_USER_POLICY,
-      _));
+      _, _));
 
   EXPECT_CALL(network_library_, RemoveNetworkProfileObserver(_));
 
diff --git a/chrome/browser/chromeos/policy/policy_cert_verifier_browsertest.cc b/chrome/browser/chromeos/policy/policy_cert_verifier_browsertest.cc
index aea0574..4f00bcf 100644
--- a/chrome/browser/chromeos/policy/policy_cert_verifier_browsertest.cc
+++ b/chrome/browser/chromeos/policy/policy_cert_verifier_browsertest.cc
@@ -152,7 +152,7 @@
 TEST_F(PolicyCertVerifierTest, VerifyTrustedCert) {
   // |ca_cert| is the issuer of |cert|.
   scoped_refptr<net::X509Certificate> ca_cert =
-      LoadCertificate("root_ca_cert.crt", net::CA_CERT);
+      LoadCertificate("root_ca_cert.pem", net::CA_CERT);
   ASSERT_TRUE(ca_cert.get());
   scoped_refptr<net::X509Certificate> cert =
       LoadCertificate("ok_cert.pem", net::SERVER_CERT);
@@ -206,7 +206,7 @@
 
   // |ca_cert| is the issuer of |cert|.
   scoped_refptr<net::X509Certificate> ca_cert =
-      LoadCertificate("root_ca_cert.crt", net::CA_CERT);
+      LoadCertificate("root_ca_cert.pem", net::CA_CERT);
   ASSERT_TRUE(ca_cert.get());
   scoped_refptr<net::X509Certificate> cert =
       LoadCertificate("ok_cert.pem", net::SERVER_CERT);
@@ -251,7 +251,7 @@
 
   // |ca_cert| is the issuer of |cert|.
   scoped_refptr<net::X509Certificate> ca_cert =
-      LoadCertificate("root_ca_cert.crt", net::CA_CERT);
+      LoadCertificate("root_ca_cert.pem", net::CA_CERT);
   ASSERT_TRUE(ca_cert.get());
   scoped_refptr<net::X509Certificate> cert =
       LoadCertificate("ok_cert.pem", net::SERVER_CERT);
diff --git a/chrome/browser/chromeos/policy/power_policy_browsertest.cc b/chrome/browser/chromeos/policy/power_policy_browsertest.cc
index 13889cc..72d4a44 100644
--- a/chrome/browser/chromeos/policy/power_policy_browsertest.cc
+++ b/chrome/browser/chromeos/policy/power_policy_browsertest.cc
@@ -84,10 +84,19 @@
 
   pm::PowerManagementPolicy power_management_policy =
       original_power_management_policy;
-  power_management_policy.set_idle_action(
+  power_management_policy.set_ac_idle_action(
       pm::PowerManagementPolicy::STOP_SESSION);
   SetUserPolicy(
-      key::kIdleAction,
+      key::kIdleActionAC,
+      base::Value::CreateIntegerValue(pm::PowerManagementPolicy::STOP_SESSION));
+  EXPECT_EQ(GetDebugString(power_management_policy),
+            GetDebugString(power_manager_client_->get_policy()));
+
+  power_management_policy = original_power_management_policy;
+  power_management_policy.set_battery_idle_action(
+      pm::PowerManagementPolicy::STOP_SESSION);
+  SetUserPolicy(
+      key::kIdleActionBattery,
       base::Value::CreateIntegerValue(pm::PowerManagementPolicy::STOP_SESSION));
   EXPECT_EQ(GetDebugString(power_management_policy),
             GetDebugString(power_manager_client_->get_policy()));
@@ -181,8 +190,8 @@
             GetDebugString(power_manager_client_->get_policy()));
 
   power_management_policy = original_power_management_policy;
-  power_management_policy.set_presentation_idle_delay_factor(3.0);
-  SetUserPolicy(key::kPresentationIdleDelayScale,
+  power_management_policy.set_presentation_screen_dim_delay_factor(3.0);
+  SetUserPolicy(key::kPresentationScreenDimDelayScale,
                 base::Value::CreateIntegerValue(300));
   EXPECT_EQ(GetDebugString(power_management_policy),
             GetDebugString(power_manager_client_->get_policy()));
@@ -211,7 +220,10 @@
   policy.mutable_ac_delays()->set_screen_off_ms(0);
   policy.mutable_battery_delays()->set_screen_dim_ms(0);
   policy.mutable_battery_delays()->set_screen_off_ms(0);
-  policy.set_idle_action(power_manager_client_->get_policy().idle_action());
+  policy.set_ac_idle_action(
+      power_manager_client_->get_policy().ac_idle_action());
+  policy.set_battery_idle_action(
+      power_manager_client_->get_policy().battery_idle_action());
   policy.set_reason(power_manager_client_->get_policy().reason());
   EXPECT_EQ(GetDebugString(policy),
             GetDebugString(power_manager_client_->get_policy()));
@@ -220,7 +232,10 @@
   SetUserPolicy(key::kAllowScreenWakeLocks,
                 base::Value::CreateBooleanValue(false));
   policy = baseline_policy;
-  policy.set_idle_action(power_manager_client_->get_policy().idle_action());
+  policy.set_ac_idle_action(
+      power_manager_client_->get_policy().ac_idle_action());
+  policy.set_battery_idle_action(
+      power_manager_client_->get_policy().battery_idle_action());
   policy.set_reason(power_manager_client_->get_policy().reason());
   EXPECT_EQ(GetDebugString(policy),
             GetDebugString(power_manager_client_->get_policy()));
diff --git a/chrome/browser/chromeos/policy/recommendation_restorer.cc b/chrome/browser/chromeos/policy/recommendation_restorer.cc
new file mode 100644
index 0000000..ba2945c
--- /dev/null
+++ b/chrome/browser/chromeos/policy/recommendation_restorer.cc
@@ -0,0 +1,153 @@
+// 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/policy/recommendation_restorer.h"
+
+#include "ash/shell.h"
+#include "ash/wm/user_activity_detector.h"
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/prefs/pref_service.h"
+#include "base/time/time.h"
+#include "base/values.h"
+#include "chrome/browser/chromeos/profiles/profile_helper.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/common/chrome_notification_types.h"
+#include "chrome/common/pref_names.h"
+#include "content/public/browser/notification_details.h"
+#include "content/public/browser/notification_service.h"
+#include "content/public/browser/notification_source.h"
+
+namespace policy {
+
+namespace {
+// The amount of idle time after which recommended values are restored.
+const int kRestoreDelayInMs = 60 * 1000;  // 1 minute.
+}  // namespace
+
+RecommendationRestorer::RecommendationRestorer(Profile* profile)
+    : logged_in_(false) {
+  if (!chromeos::ProfileHelper::IsSigninProfile(profile))
+    return;
+
+  pref_change_registrar_.Init(profile->GetPrefs());
+  pref_change_registrar_.Add(prefs::kLargeCursorEnabled,
+                             base::Bind(&RecommendationRestorer::Restore,
+                                        base::Unretained(this), true));
+  pref_change_registrar_.Add(prefs::kSpokenFeedbackEnabled,
+                             base::Bind(&RecommendationRestorer::Restore,
+                                        base::Unretained(this), true));
+  pref_change_registrar_.Add(prefs::kHighContrastEnabled,
+                             base::Bind(&RecommendationRestorer::Restore,
+                                        base::Unretained(this), true));
+  pref_change_registrar_.Add(prefs::kScreenMagnifierEnabled,
+                             base::Bind(&RecommendationRestorer::Restore,
+                                        base::Unretained(this), true));
+  pref_change_registrar_.Add(prefs::kScreenMagnifierType,
+                             base::Bind(&RecommendationRestorer::Restore,
+                                        base::Unretained(this), true));
+
+  notification_registrar_.Add(this, chrome::NOTIFICATION_LOGIN_USER_CHANGED,
+                              content::NotificationService::AllSources());
+
+  RestoreAll();
+}
+
+RecommendationRestorer::~RecommendationRestorer() {
+}
+
+void RecommendationRestorer::Shutdown() {
+  StopTimer();
+  pref_change_registrar_.RemoveAll();
+  notification_registrar_.RemoveAll();
+}
+
+void RecommendationRestorer::Observe(
+    int type,
+    const content::NotificationSource& source,
+    const content::NotificationDetails& details) {
+  if (type == chrome::NOTIFICATION_LOGIN_USER_CHANGED) {
+    logged_in_ = true;
+    notification_registrar_.RemoveAll();
+    StopTimer();
+    RestoreAll();
+  } else {
+    NOTREACHED();
+  }
+}
+
+void RecommendationRestorer::OnUserActivity() {
+  if (restore_timer_.IsRunning())
+    restore_timer_.Reset();
+}
+
+void RecommendationRestorer::Restore(bool allow_delay,
+                                     const std::string& pref_name) {
+  const PrefService::Preference* pref =
+      pref_change_registrar_.prefs()->FindPreference(pref_name.c_str());
+  if (!pref) {
+    NOTREACHED();
+    return;
+  }
+
+  if (!pref->GetRecommendedValue() || !pref->HasUserSetting())
+    return;
+
+  if (logged_in_) {
+    allow_delay = false;
+  } else if (allow_delay && ash::Shell::HasInstance()) {
+    // Skip the delay if there has been no user input since the browser started.
+    const ash::UserActivityDetector* user_activity_detector =
+        ash::Shell::GetInstance()->user_activity_detector();
+    allow_delay = !user_activity_detector->last_activity_time().is_null();
+  }
+
+  if (allow_delay)
+    StartTimer();
+  else
+    pref_change_registrar_.prefs()->ClearPref(pref->name().c_str());
+}
+
+void RecommendationRestorer::RestoreAll() {
+  Restore(false, prefs::kLargeCursorEnabled);
+  Restore(false, prefs::kSpokenFeedbackEnabled);
+  Restore(false, prefs::kHighContrastEnabled);
+  Restore(false, prefs::kScreenMagnifierEnabled);
+  Restore(false, prefs::kScreenMagnifierType);
+}
+
+void RecommendationRestorer::StartTimer() {
+  // Listen for user activity so that the timer can be reset while the user is
+  // active, causing it to fire only when the user remains idle for
+  // |kRestoreDelayInMs|.
+  if (ash::Shell::HasInstance()) {
+    ash::UserActivityDetector* user_activity_detector =
+        ash::Shell::GetInstance()->user_activity_detector();
+    if (!user_activity_detector->HasObserver(this))
+      user_activity_detector->AddObserver(this);
+  }
+
+  // There should be a separate timer for each pref. However, in the common
+  // case of the user changing settings, a single timer is sufficient. This is
+  // because a change initiated by the user implies user activity, so that even
+  // if there was a separate timer per pref, they would all be reset at that
+  // point, causing them to fire at exactly the same time. In the much rarer
+  // case of a recommended value changing, a single timer is a close
+  // approximation of the behavior that would be obtained by resetting the timer
+  // for the affected pref only.
+  restore_timer_.Start(FROM_HERE,
+                       base::TimeDelta::FromMilliseconds(kRestoreDelayInMs),
+                       base::Bind(&RecommendationRestorer::RestoreAll,
+                                  base::Unretained(this)));
+}
+
+void RecommendationRestorer::StopTimer() {
+  restore_timer_.Stop();
+  if (ash::Shell::HasInstance())
+    ash::Shell::GetInstance()->user_activity_detector()->RemoveObserver(this);
+}
+
+}  // namespace policy
diff --git a/chrome/browser/chromeos/policy/recommendation_restorer.h b/chrome/browser/chromeos/policy/recommendation_restorer.h
new file mode 100644
index 0000000..1d67159
--- /dev/null
+++ b/chrome/browser/chromeos/policy/recommendation_restorer.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 CHROME_BROWSER_CHROMEOS_POLICY_RECOMMENDATION_RESTORER_H_
+#define CHROME_BROWSER_CHROMEOS_POLICY_RECOMMENDATION_RESTORER_H_
+
+#include <string>
+
+#include "ash/wm/user_activity_observer.h"
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/prefs/pref_change_registrar.h"
+#include "base/timer/timer.h"
+#include "components/browser_context_keyed_service/browser_context_keyed_service.h"
+#include "content/public/browser/notification_observer.h"
+#include "content/public/browser/notification_registrar.h"
+
+class Profile;
+
+namespace policy {
+
+// Observes a set of prefs in the login profile. If any of the prefs has a
+// recommended value, its user setting is cleared so that the recommendation can
+// take effect. This happens immediately when the login screen is shown, when
+// a session is being started and whenever recommended values change during a
+// user session. On the login screen, user settings are cleared when the user
+// becomes idle for one minute.
+class RecommendationRestorer : public BrowserContextKeyedService,
+                               public content::NotificationObserver,
+                               public ash::UserActivityObserver {
+ public:
+  explicit RecommendationRestorer(Profile* profile);
+  virtual ~RecommendationRestorer();
+
+  // BrowserContextKeyedService:
+  virtual void Shutdown() OVERRIDE;
+
+  // content::NotificationObserver:
+  virtual void Observe(int type,
+                       const content::NotificationSource& source,
+                       const content::NotificationDetails& details) OVERRIDE;
+
+  // ash::UserActivityObserver::Observer:
+  virtual void OnUserActivity() OVERRIDE;
+
+  // If a recommended value and a user setting exist for |pref_name|, clears the
+  // user setting so that the recommended value can take effect. If
+  // |allow_delay| is |true| and the login screen is being shown, a timer is
+  // started that will clear the setting when the user becomes idle for one
+  // minute. Otherwise, the setting is cleared immediately.
+  void Restore(bool allow_delay, const std::string& pref_name);
+
+ private:
+  friend class RecommendationRestorerTest;
+
+  void RestoreAll();
+
+  void StartTimer();
+  void StopTimer();
+
+  PrefChangeRegistrar pref_change_registrar_;
+  content::NotificationRegistrar notification_registrar_;
+
+  bool logged_in_;
+
+  base::OneShotTimer<RecommendationRestorer> restore_timer_;
+
+  DISALLOW_COPY_AND_ASSIGN(RecommendationRestorer);
+};
+
+}  // namespace policy
+
+#endif  // CHROME_BROWSER_CHROMEOS_POLICY_RECOMMENDATION_RESTORER_H_
diff --git a/chrome/browser/chromeos/policy/recommendation_restorer_factory.cc b/chrome/browser/chromeos/policy/recommendation_restorer_factory.cc
new file mode 100644
index 0000000..59cab9a
--- /dev/null
+++ b/chrome/browser/chromeos/policy/recommendation_restorer_factory.cc
@@ -0,0 +1,45 @@
+// 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/policy/recommendation_restorer_factory.h"
+
+#include "chrome/browser/chromeos/policy/recommendation_restorer.h"
+#include "chrome/browser/profiles/profile.h"
+#include "components/browser_context_keyed_service/browser_context_dependency_manager.h"
+#include "content/public/browser/browser_context.h"
+
+namespace policy {
+
+// static
+RecommendationRestorerFactory* RecommendationRestorerFactory::GetInstance() {
+  return Singleton<RecommendationRestorerFactory>::get();
+}
+
+// static
+RecommendationRestorer* RecommendationRestorerFactory::GetForProfile(
+    Profile* profile) {
+  return reinterpret_cast<RecommendationRestorer*>(
+          GetInstance()->GetServiceForBrowserContext(profile, false));
+}
+
+BrowserContextKeyedService*
+    RecommendationRestorerFactory::BuildServiceInstanceFor(
+        content::BrowserContext* context) const {
+  return new RecommendationRestorer(static_cast<Profile*>(context));
+}
+
+bool RecommendationRestorerFactory::ServiceIsCreatedWithBrowserContext() const {
+  return true;
+}
+
+RecommendationRestorerFactory::RecommendationRestorerFactory()
+    : BrowserContextKeyedServiceFactory(
+          "RecommendationRestorer",
+          BrowserContextDependencyManager::GetInstance()) {
+}
+
+RecommendationRestorerFactory::~RecommendationRestorerFactory() {
+}
+
+}  // namespace policy
diff --git a/chrome/browser/chromeos/policy/recommendation_restorer_factory.h b/chrome/browser/chromeos/policy/recommendation_restorer_factory.h
new file mode 100644
index 0000000..9b5cda2
--- /dev/null
+++ b/chrome/browser/chromeos/policy/recommendation_restorer_factory.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 CHROME_BROWSER_CHROMEOS_POLICY_RECOMMENDATION_RESTORER_FACTORY_H_
+#define CHROME_BROWSER_CHROMEOS_POLICY_RECOMMENDATION_RESTORER_FACTORY_H_
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/memory/singleton.h"
+#include "components/browser_context_keyed_service/browser_context_keyed_service_factory.h"
+
+class Profile;
+
+namespace policy {
+
+class RecommendationRestorer;
+
+class RecommendationRestorerFactory : public BrowserContextKeyedServiceFactory {
+ public:
+  static RecommendationRestorerFactory* GetInstance();
+
+  static RecommendationRestorer* GetForProfile(Profile* profile);
+
+ protected:
+  // BrowserContextKeyedServiceFactory:
+  virtual BrowserContextKeyedService* BuildServiceInstanceFor(
+      content::BrowserContext* context) const OVERRIDE;
+  virtual bool ServiceIsCreatedWithBrowserContext() const OVERRIDE;
+
+ private:
+  friend struct DefaultSingletonTraits<RecommendationRestorerFactory>;
+
+  RecommendationRestorerFactory();
+  virtual ~RecommendationRestorerFactory();
+
+  DISALLOW_COPY_AND_ASSIGN(RecommendationRestorerFactory);
+};
+
+} //  namespace policy
+
+#endif  // CHROME_BROWSER_CHROMEOS_POLICY_RECOMMENDATION_RESTORER_FACTORY_H_
diff --git a/chrome/browser/chromeos/policy/recommendation_restorer_unittest.cc b/chrome/browser/chromeos/policy/recommendation_restorer_unittest.cc
new file mode 100644
index 0000000..c5d5b3a
--- /dev/null
+++ b/chrome/browser/chromeos/policy/recommendation_restorer_unittest.cc
@@ -0,0 +1,485 @@
+// 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/policy/recommendation_restorer.h"
+
+#include "ash/magnifier/magnifier_constants.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/prefs/pref_notifier_impl.h"
+#include "base/prefs/testing_pref_store.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/test/test_simple_task_runner.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/time/time.h"
+#include "base/values.h"
+#include "chrome/browser/chromeos/policy/recommendation_restorer_factory.h"
+#include "chrome/browser/prefs/browser_prefs.h"
+#include "chrome/browser/prefs/pref_service_syncable.h"
+#include "chrome/common/chrome_constants.h"
+#include "chrome/common/chrome_notification_types.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/test/base/testing_browser_process.h"
+#include "chrome/test/base/testing_pref_service_syncable.h"
+#include "chrome/test/base/testing_profile.h"
+#include "chrome/test/base/testing_profile_manager.h"
+#include "components/user_prefs/pref_registry_syncable.h"
+#include "content/public/browser/notification_details.h"
+#include "content/public/browser/notification_service.h"
+#include "content/public/browser/notification_source.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace policy {
+
+namespace {
+  // The amount of idle time after which recommended values are restored.
+  const int kRestoreDelayInMs = 60 * 1000;  // 1 minute.
+}  // namespace
+
+class RecommendationRestorerTest : public testing::Test {
+ protected:
+  RecommendationRestorerTest();
+
+  // testing::Test:
+  virtual void SetUp() OVERRIDE;
+
+  void SetRecommendedValues();
+  void SetUserSettings();
+
+  void CreateLoginProfile();
+  void CreateUserProfile();
+
+  void NotifyOfSessionStart();
+  void NotifyOfUserActivity();
+
+  void VerifyPrefFollowsUser(const char* pref_name,
+                             const base::Value& expected_value) const;
+  void VerifyPrefsFollowUser() const;
+  void VerifyPrefFollowsRecommendation(const char* pref_name,
+                                       const base::Value& expected_value) const;
+  void VerifyPrefsFollowRecommendations() const;
+
+  void VerifyNotListeningForNotifications() const;
+  void VerifyTimerIsStopped() const;
+  void VerifyTimerIsRunning() const;
+
+  TestingPrefStore* recommended_prefs_;  // Not owned.
+  TestingPrefServiceSyncable* prefs_;    // Not owned.
+  RecommendationRestorer* restorer_;     // Not owned.
+
+  scoped_refptr<base::TestSimpleTaskRunner> runner_;
+  base::ThreadTaskRunnerHandle runner_handler_;
+
+ private:
+  scoped_ptr<PrefServiceSyncable> prefs_owner_;
+
+  TestingProfileManager profile_manager_;
+
+  DISALLOW_COPY_AND_ASSIGN(RecommendationRestorerTest);
+};
+
+RecommendationRestorerTest::RecommendationRestorerTest()
+    : recommended_prefs_(new TestingPrefStore),
+      prefs_(new TestingPrefServiceSyncable(
+          new TestingPrefStore,
+          new TestingPrefStore,
+          recommended_prefs_,
+          new user_prefs::PrefRegistrySyncable,
+          new PrefNotifierImpl)),
+      restorer_(NULL),
+      runner_(new base::TestSimpleTaskRunner),
+      runner_handler_(runner_),
+      prefs_owner_(prefs_),
+      profile_manager_(TestingBrowserProcess::GetGlobal()) {
+  chrome::RegisterUserPrefs(prefs_->registry());
+}
+
+void RecommendationRestorerTest::SetUp() {
+  testing::Test::SetUp();
+  ASSERT_TRUE(profile_manager_.SetUp());
+}
+
+void RecommendationRestorerTest::SetRecommendedValues() {
+  recommended_prefs_->SetBoolean(prefs::kLargeCursorEnabled, false);
+  recommended_prefs_->SetBoolean(prefs::kSpokenFeedbackEnabled, false);
+  recommended_prefs_->SetBoolean(prefs::kHighContrastEnabled, false);
+  recommended_prefs_->SetBoolean(prefs::kScreenMagnifierEnabled, false);
+  recommended_prefs_->SetInteger(prefs::kScreenMagnifierType, 0);
+}
+
+void RecommendationRestorerTest::SetUserSettings() {
+  prefs_->SetBoolean(prefs::kLargeCursorEnabled, true);
+  prefs_->SetBoolean(prefs::kSpokenFeedbackEnabled, true);
+  prefs_->SetBoolean(prefs::kHighContrastEnabled, true);
+  prefs_->SetBoolean(prefs::kScreenMagnifierEnabled, true);
+  prefs_->SetInteger(prefs::kScreenMagnifierType, ash::MAGNIFIER_FULL);
+}
+
+void RecommendationRestorerTest::CreateLoginProfile() {
+  ASSERT_FALSE(restorer_);
+  TestingProfile* profile = profile_manager_.CreateTestingProfile(
+      chrome::kInitialProfile, prefs_owner_.Pass(),
+      UTF8ToUTF16(chrome::kInitialProfile), 0);
+  restorer_ = RecommendationRestorerFactory::GetForProfile(profile);
+  EXPECT_TRUE(restorer_);
+}
+
+void RecommendationRestorerTest::CreateUserProfile() {
+  ASSERT_FALSE(restorer_);
+  TestingProfile* profile = profile_manager_.CreateTestingProfile(
+      "user", prefs_owner_.Pass(), UTF8ToUTF16("user"), 0);
+  restorer_ = RecommendationRestorerFactory::GetForProfile(profile);
+  EXPECT_TRUE(restorer_);
+}
+
+void RecommendationRestorerTest::NotifyOfSessionStart() {
+  ASSERT_TRUE(restorer_);
+  restorer_->Observe(chrome::NOTIFICATION_LOGIN_USER_CHANGED,
+                     content::Source<RecommendationRestorerTest>(this),
+                     content::NotificationService::NoDetails());
+}
+
+void RecommendationRestorerTest::NotifyOfUserActivity() {
+  ASSERT_TRUE(restorer_);
+  restorer_->OnUserActivity();
+}
+
+void RecommendationRestorerTest::VerifyPrefFollowsUser(
+    const char* pref_name,
+    const base::Value& expected_value) const {
+  const PrefServiceSyncable::Preference* pref =
+      prefs_->FindPreference(pref_name);
+  ASSERT_TRUE(pref);
+  EXPECT_TRUE(pref->HasUserSetting());
+  const base::Value* value = pref->GetValue();
+  ASSERT_TRUE(value);
+  EXPECT_TRUE(expected_value.Equals(value));
+}
+
+void RecommendationRestorerTest::VerifyPrefsFollowUser() const {
+  VerifyPrefFollowsUser(prefs::kLargeCursorEnabled,
+                        base::FundamentalValue(true));
+  VerifyPrefFollowsUser(prefs::kSpokenFeedbackEnabled,
+                        base::FundamentalValue(true));
+  VerifyPrefFollowsUser(prefs::kHighContrastEnabled,
+                        base::FundamentalValue(true));
+  VerifyPrefFollowsUser(prefs::kScreenMagnifierEnabled,
+                        base::FundamentalValue(true));
+  VerifyPrefFollowsUser(prefs::kScreenMagnifierType,
+                        base::FundamentalValue(ash::MAGNIFIER_FULL));
+}
+
+void RecommendationRestorerTest::VerifyPrefFollowsRecommendation(
+    const char* pref_name,
+    const base::Value& expected_value) const {
+  const PrefServiceSyncable::Preference* pref =
+      prefs_->FindPreference(pref_name);
+  ASSERT_TRUE(pref);
+  EXPECT_TRUE(pref->IsRecommended());
+  EXPECT_FALSE(pref->HasUserSetting());
+  const base::Value* value = pref->GetValue();
+  ASSERT_TRUE(value);
+  EXPECT_TRUE(expected_value.Equals(value));
+}
+
+void RecommendationRestorerTest::VerifyPrefsFollowRecommendations() const {
+  VerifyPrefFollowsRecommendation(prefs::kLargeCursorEnabled,
+                                  base::FundamentalValue(false));
+  VerifyPrefFollowsRecommendation(prefs::kSpokenFeedbackEnabled,
+                                  base::FundamentalValue(false));
+  VerifyPrefFollowsRecommendation(prefs::kHighContrastEnabled,
+                                  base::FundamentalValue(false));
+  VerifyPrefFollowsRecommendation(prefs::kScreenMagnifierEnabled,
+                                  base::FundamentalValue(false));
+  VerifyPrefFollowsRecommendation(prefs::kScreenMagnifierType,
+                                  base::FundamentalValue(0));
+}
+
+void RecommendationRestorerTest::VerifyNotListeningForNotifications() const {
+  ASSERT_TRUE(restorer_);
+  EXPECT_TRUE(restorer_->pref_change_registrar_.IsEmpty());
+  EXPECT_TRUE(restorer_->notification_registrar_.IsEmpty());
+}
+
+void RecommendationRestorerTest::VerifyTimerIsStopped() const {
+  ASSERT_TRUE(restorer_);
+  EXPECT_FALSE(restorer_->restore_timer_.IsRunning());
+}
+
+void RecommendationRestorerTest::VerifyTimerIsRunning() const {
+  ASSERT_TRUE(restorer_);
+  EXPECT_TRUE(restorer_->restore_timer_.IsRunning());
+  EXPECT_EQ(base::TimeDelta::FromMilliseconds(kRestoreDelayInMs),
+            restorer_->restore_timer_.GetCurrentDelay());
+}
+
+TEST_F(RecommendationRestorerTest, CreateForUserProfile) {
+  // Verifies that when a RecommendationRestorer is created for a user profile,
+  // it does not start listening for any notifications, does not clear user
+  // settings on initialization and does not start a timer that will clear user
+  // settings eventually.
+  SetRecommendedValues();
+  SetUserSettings();
+
+  CreateUserProfile();
+  VerifyNotListeningForNotifications();
+  VerifyPrefsFollowUser();
+  VerifyTimerIsStopped();
+}
+
+TEST_F(RecommendationRestorerTest, NoRecommendations) {
+  // Verifies that when no recommended values have been set and a
+  // RecommendationRestorer is created for the login profile, it does not clear
+  // user settings on initialization and does not start a timer that will clear
+  // user settings eventually.
+  SetUserSettings();
+
+  CreateLoginProfile();
+  VerifyPrefsFollowUser();
+  VerifyTimerIsStopped();
+}
+
+TEST_F(RecommendationRestorerTest, RestoreOnStartup) {
+  // Verifies that when recommended values have been set and a
+  // RecommendationRestorer is created for the login profile, it clears user
+  // settings on initialization.
+  SetRecommendedValues();
+  SetUserSettings();
+
+  CreateLoginProfile();
+  VerifyPrefsFollowRecommendations();
+  VerifyTimerIsStopped();
+}
+
+TEST_F(RecommendationRestorerTest, RestoreOnRecommendationChangeOnLoginScreen) {
+  // Verifies that if recommended values change while the login screen is being
+  // shown, a timer is started that will clear user settings eventually.
+  SetUserSettings();
+
+  CreateLoginProfile();
+
+  VerifyTimerIsStopped();
+  recommended_prefs_->SetBoolean(prefs::kLargeCursorEnabled, false);
+  VerifyPrefFollowsUser(prefs::kLargeCursorEnabled,
+                        base::FundamentalValue(true));
+  VerifyTimerIsRunning();
+  runner_->RunUntilIdle();
+  VerifyPrefFollowsRecommendation(prefs::kLargeCursorEnabled,
+                                  base::FundamentalValue(false));
+
+  VerifyTimerIsStopped();
+  recommended_prefs_->SetBoolean(prefs::kSpokenFeedbackEnabled, false);
+  VerifyPrefFollowsUser(prefs::kSpokenFeedbackEnabled,
+                        base::FundamentalValue(true));
+  VerifyTimerIsRunning();
+  runner_->RunUntilIdle();
+  VerifyPrefFollowsRecommendation(prefs::kSpokenFeedbackEnabled,
+                                  base::FundamentalValue(false));
+
+  VerifyTimerIsStopped();
+  recommended_prefs_->SetBoolean(prefs::kHighContrastEnabled, false);
+  VerifyPrefFollowsUser(prefs::kHighContrastEnabled,
+                        base::FundamentalValue(true));
+  VerifyTimerIsRunning();
+  runner_->RunUntilIdle();
+  VerifyPrefFollowsRecommendation(prefs::kHighContrastEnabled,
+                                  base::FundamentalValue(false));
+
+  VerifyTimerIsStopped();
+  recommended_prefs_->SetBoolean(prefs::kScreenMagnifierEnabled, false);
+  recommended_prefs_->SetInteger(prefs::kScreenMagnifierType, 0);
+  VerifyPrefFollowsUser(prefs::kScreenMagnifierEnabled,
+                        base::FundamentalValue(true));
+  VerifyPrefFollowsUser(prefs::kScreenMagnifierType,
+                        base::FundamentalValue(ash::MAGNIFIER_FULL));
+  VerifyTimerIsRunning();
+  runner_->RunUntilIdle();
+  VerifyPrefFollowsRecommendation(prefs::kScreenMagnifierEnabled,
+                                  base::FundamentalValue(false));
+  VerifyPrefFollowsRecommendation(prefs::kScreenMagnifierType,
+                                  base::FundamentalValue(0));
+
+  VerifyTimerIsStopped();
+}
+
+TEST_F(RecommendationRestorerTest, RestoreOnRecommendationChangeInUserSession) {
+  // Verifies that if recommended values change while a user session is in
+  // progress, user settings are cleared immediately.
+  SetUserSettings();
+
+  CreateLoginProfile();
+  NotifyOfSessionStart();
+
+  VerifyPrefFollowsUser(prefs::kLargeCursorEnabled,
+                        base::FundamentalValue(true));
+  recommended_prefs_->SetBoolean(prefs::kLargeCursorEnabled, false);
+  VerifyTimerIsStopped();
+  VerifyPrefFollowsRecommendation(prefs::kLargeCursorEnabled,
+                                  base::FundamentalValue(false));
+
+  VerifyPrefFollowsUser(prefs::kSpokenFeedbackEnabled,
+                        base::FundamentalValue(true));
+  recommended_prefs_->SetBoolean(prefs::kSpokenFeedbackEnabled, false);
+  VerifyTimerIsStopped();
+  VerifyPrefFollowsRecommendation(prefs::kSpokenFeedbackEnabled,
+                                  base::FundamentalValue(false));
+
+  VerifyPrefFollowsUser(prefs::kHighContrastEnabled,
+                        base::FundamentalValue(true));
+  recommended_prefs_->SetBoolean(prefs::kHighContrastEnabled, false);
+  VerifyTimerIsStopped();
+  VerifyPrefFollowsRecommendation(prefs::kHighContrastEnabled,
+                                  base::FundamentalValue(false));
+
+  VerifyPrefFollowsUser(prefs::kScreenMagnifierEnabled,
+                        base::FundamentalValue(true));
+  VerifyPrefFollowsUser(prefs::kScreenMagnifierType,
+                        base::FundamentalValue(ash::MAGNIFIER_FULL));
+  recommended_prefs_->SetBoolean(prefs::kScreenMagnifierEnabled, false);
+  recommended_prefs_->SetInteger(prefs::kScreenMagnifierType, 0);
+  VerifyTimerIsStopped();
+  VerifyPrefFollowsRecommendation(prefs::kScreenMagnifierEnabled,
+                                  base::FundamentalValue(false));
+  VerifyPrefFollowsRecommendation(prefs::kScreenMagnifierType,
+                                  base::FundamentalValue(0));
+}
+
+TEST_F(RecommendationRestorerTest, DoNothingOnUserChange) {
+  // Verifies that if no recommended values have been set and user settings
+  // change, the user settings are not cleared immediately and no timer is
+  // started that will clear the user settings eventually.
+  CreateLoginProfile();
+
+  prefs_->SetBoolean(prefs::kLargeCursorEnabled, true);
+  VerifyPrefFollowsUser(prefs::kLargeCursorEnabled,
+                        base::FundamentalValue(true));
+  VerifyTimerIsStopped();
+
+  prefs_->SetBoolean(prefs::kSpokenFeedbackEnabled, true);
+  VerifyPrefFollowsUser(prefs::kSpokenFeedbackEnabled,
+                        base::FundamentalValue(true));
+  VerifyTimerIsStopped();
+
+  prefs_->SetBoolean(prefs::kHighContrastEnabled, true);
+  VerifyPrefFollowsUser(prefs::kHighContrastEnabled,
+                        base::FundamentalValue(true));
+  VerifyTimerIsStopped();
+
+  prefs_->SetBoolean(prefs::kScreenMagnifierEnabled, true);
+  VerifyPrefFollowsUser(prefs::kScreenMagnifierEnabled,
+                        base::FundamentalValue(true));
+  VerifyTimerIsStopped();
+
+  prefs_->SetBoolean(prefs::kScreenMagnifierEnabled, true);
+  prefs_->SetInteger(prefs::kScreenMagnifierType, ash::MAGNIFIER_FULL);
+  VerifyPrefFollowsUser(prefs::kScreenMagnifierEnabled,
+                        base::FundamentalValue(true));
+  VerifyPrefFollowsUser(prefs::kScreenMagnifierType,
+                        base::FundamentalValue(ash::MAGNIFIER_FULL));
+  VerifyTimerIsStopped();
+}
+
+TEST_F(RecommendationRestorerTest, RestoreOnUserChange) {
+  // Verifies that if recommended values have been set and user settings change
+  // while the login screen is being shown, a timer is started that will clear
+  // the user settings eventually.
+  SetRecommendedValues();
+
+  CreateLoginProfile();
+
+  VerifyTimerIsStopped();
+  prefs_->SetBoolean(prefs::kLargeCursorEnabled, true);
+  VerifyPrefFollowsUser(prefs::kLargeCursorEnabled,
+                        base::FundamentalValue(true));
+  VerifyTimerIsRunning();
+  runner_->RunUntilIdle();
+  VerifyPrefFollowsRecommendation(prefs::kLargeCursorEnabled,
+                                  base::FundamentalValue(false));
+
+  VerifyTimerIsStopped();
+  prefs_->SetBoolean(prefs::kSpokenFeedbackEnabled, true);
+  VerifyPrefFollowsUser(prefs::kSpokenFeedbackEnabled,
+                        base::FundamentalValue(true));
+  VerifyTimerIsRunning();
+  runner_->RunUntilIdle();
+  VerifyPrefFollowsRecommendation(prefs::kSpokenFeedbackEnabled,
+                                  base::FundamentalValue(false));
+
+  VerifyTimerIsStopped();
+  prefs_->SetBoolean(prefs::kHighContrastEnabled, true);
+  VerifyPrefFollowsUser(prefs::kHighContrastEnabled,
+                        base::FundamentalValue(true));
+  VerifyTimerIsRunning();
+  runner_->RunUntilIdle();
+  VerifyPrefFollowsRecommendation(prefs::kHighContrastEnabled,
+                                  base::FundamentalValue(false));
+
+  VerifyTimerIsStopped();
+  prefs_->SetBoolean(prefs::kScreenMagnifierEnabled, true);
+  prefs_->SetInteger(prefs::kScreenMagnifierType, ash::MAGNIFIER_FULL);
+  VerifyPrefFollowsUser(prefs::kScreenMagnifierEnabled,
+                        base::FundamentalValue(true));
+  VerifyPrefFollowsUser(prefs::kScreenMagnifierType,
+                        base::FundamentalValue(ash::MAGNIFIER_FULL));
+  VerifyTimerIsRunning();
+  runner_->RunUntilIdle();
+  VerifyPrefFollowsRecommendation(prefs::kScreenMagnifierEnabled,
+                                  base::FundamentalValue(false));
+  VerifyPrefFollowsRecommendation(prefs::kScreenMagnifierType,
+                                  base::FundamentalValue(0));
+
+  VerifyTimerIsStopped();
+}
+
+TEST_F(RecommendationRestorerTest, RestoreOnSessionStart) {
+  // Verifies that if recommended values have been set, user settings have
+  // changed and a session is then started, the user settings are cleared
+  // immediately and the timer that would have cleared them eventually on the
+  // login screen is stopped.
+  SetRecommendedValues();
+
+  CreateLoginProfile();
+  SetUserSettings();
+
+  NotifyOfSessionStart();
+  VerifyPrefsFollowRecommendations();
+  VerifyTimerIsStopped();
+}
+
+TEST_F(RecommendationRestorerTest, DoNothingOnSessionStart) {
+  // Verifies that if recommended values have not been set, user settings have
+  // changed and a session is then started, the user settings are not cleared
+  // immediately.
+  CreateLoginProfile();
+  SetUserSettings();
+
+  NotifyOfSessionStart();
+  VerifyPrefsFollowUser();
+  VerifyTimerIsStopped();
+}
+
+TEST_F(RecommendationRestorerTest, UserActivityResetsTimer) {
+  // Verifies that user activity resets the timer which clears user settings.
+  recommended_prefs_->SetBoolean(prefs::kLargeCursorEnabled, false);
+
+  CreateLoginProfile();
+
+  prefs_->SetBoolean(prefs::kLargeCursorEnabled, true);
+  VerifyTimerIsRunning();
+
+  // Notify that there is user activity, then fast forward until the originally
+  // set timer fires.
+  NotifyOfUserActivity();
+  runner_->RunPendingTasks();
+  VerifyPrefFollowsUser(prefs::kLargeCursorEnabled,
+                        base::FundamentalValue(true));
+
+  // Fast forward until the reset timer fires.
+  VerifyTimerIsRunning();
+  runner_->RunUntilIdle();
+  VerifyPrefFollowsRecommendation(prefs::kLargeCursorEnabled,
+                                  base::FundamentalValue(false));
+  VerifyTimerIsStopped();
+}
+
+}  // namespace policy
diff --git a/chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos_unittest.cc b/chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos_unittest.cc
index 1beca08..fce36a9 100644
--- a/chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos_unittest.cc
+++ b/chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos_unittest.cc
@@ -24,6 +24,7 @@
 #include "chrome/browser/policy/mock_configuration_policy_provider.h"
 #include "chrome/browser/policy/proto/cloud/device_management_backend.pb.h"
 #include "chrome/browser/prefs/browser_prefs.h"
+#include "chrome/browser/prefs/pref_service_syncable.h"
 #include "chrome/browser/signin/token_service.h"
 #include "chrome/browser/signin/token_service_factory.h"
 #include "chrome/common/chrome_constants.h"
@@ -85,7 +86,8 @@
         new TestingProfileManager(TestingBrowserProcess::GetGlobal()));
     ASSERT_TRUE(profile_manager_->SetUp());
     profile_ = profile_manager_->CreateTestingProfile(
-        chrome::kInitialProfile, UTF8ToUTF16("testing_profile"), 0);
+        chrome::kInitialProfile, scoped_ptr<PrefServiceSyncable>(),
+        UTF8ToUTF16("testing_profile"), 0);
     signin_profile_ = profile_manager_->CreateTestingProfile("signin_profile");
     signin_profile_->set_incognito(true);
     // Usually the signin Profile and the main Profile are separate, but since
diff --git a/chrome/browser/chromeos/policy/user_cloud_policy_store_chromeos.cc b/chrome/browser/chromeos/policy/user_cloud_policy_store_chromeos.cc
index 884cda0..ae9b79c 100644
--- a/chrome/browser/chromeos/policy/user_cloud_policy_store_chromeos.cc
+++ b/chrome/browser/chromeos/policy/user_cloud_policy_store_chromeos.cc
@@ -409,7 +409,7 @@
 // static
 void UserCloudPolicyStoreChromeOS::RemoveLegacyCacheDir(
     const base::FilePath& dir) {
-  if (file_util::PathExists(dir) && !file_util::Delete(dir, true))
+  if (file_util::PathExists(dir) && !base::Delete(dir, true))
     LOG(ERROR) << "Failed to remove cache dir " << dir.value();
 }
 
diff --git a/chrome/browser/chromeos/policy/user_cloud_policy_store_chromeos_unittest.cc b/chrome/browser/chromeos/policy/user_cloud_policy_store_chromeos_unittest.cc
index 9cb2b9c..ec73418 100644
--- a/chrome/browser/chromeos/policy/user_cloud_policy_store_chromeos_unittest.cc
+++ b/chrome/browser/chromeos/policy/user_cloud_policy_store_chromeos_unittest.cc
@@ -239,7 +239,7 @@
 
 TEST_F(UserCloudPolicyStoreChromeOSTest, InitialStore) {
   // Start without any public key to trigger the initial key checks.
-  ASSERT_TRUE(file_util::Delete(user_policy_key_file(), false));
+  ASSERT_TRUE(base::Delete(user_policy_key_file(), false));
   // Make the policy blob contain a new public key.
   policy_.set_new_signing_key(PolicyBuilder::CreateTestNewSigningKey());
   policy_.Build();
@@ -383,7 +383,7 @@
 
 TEST_F(UserCloudPolicyStoreChromeOSTest, LoadNoKey) {
   // The loaded policy can't be verified without the public key.
-  ASSERT_TRUE(file_util::Delete(user_policy_key_file(), false));
+  ASSERT_TRUE(base::Delete(user_policy_key_file(), false));
   ExpectError(CloudPolicyStore::STATUS_VALIDATION_ERROR);
   ASSERT_NO_FATAL_FAILURE(PerformPolicyLoad(policy_.GetBlob()));
   VerifyStoreHasValidationError();
@@ -480,7 +480,7 @@
 
 TEST_F(UserCloudPolicyStoreChromeOSTest, MigrationAndStoreNew) {
   // Start without an existing public key.
-  ASSERT_TRUE(file_util::Delete(user_policy_key_file(), false));
+  ASSERT_TRUE(base::Delete(user_policy_key_file(), false));
 
   std::string data;
   em::CachedCloudPolicyResponse cached_policy;
diff --git a/chrome/browser/chromeos/power/suspend_observer.cc b/chrome/browser/chromeos/power/suspend_observer.cc
index fd7eb21..3ae7f11 100644
--- a/chrome/browser/chromeos/power/suspend_observer.cc
+++ b/chrome/browser/chromeos/power/suspend_observer.cc
@@ -39,8 +39,7 @@
   if (profile && profile->GetPrefs()->GetBoolean(prefs::kEnableScreenLock) &&
       UserManager::Get()->CanCurrentUserLock() && !screen_locked_) {
     screen_lock_callback_ = power_client_->GetSuspendReadinessCallback();
-    // TODO(antrim) : additional logging for crbug/173178
-    LOG(WARNING) << "Requesting screen lock from SuspendObserver";
+    VLOG(1) << "Requesting screen lock from SuspendObserver";
     session_client_->RequestLockScreen();
   }
 
@@ -53,14 +52,14 @@
 
   // Stop blocking suspend after the screen is locked.
   if (!screen_lock_callback_.is_null()) {
-    LOG(WARNING) << "Locking screen due to suspend.";
+    VLOG(1) << "Screen locked due to suspend";
     // Run the callback asynchronously.  ScreenIsLocked() is currently
     // called asynchronously after RequestLockScreen(), but this guards
     // against it being made synchronous later.
     base::MessageLoop::current()->PostTask(FROM_HERE, screen_lock_callback_);
     screen_lock_callback_.Reset();
   } else {
-    LOG(WARNING) << "Locking screen without suspend.";
+    VLOG(1) << "Screen locked without suspend";
   }
 }
 
diff --git a/chrome/browser/chromeos/power/user_activity_notifier.h b/chrome/browser/chromeos/power/user_activity_notifier.h
index 0e96e54..f1189ef 100644
--- a/chrome/browser/chromeos/power/user_activity_notifier.h
+++ b/chrome/browser/chromeos/power/user_activity_notifier.h
@@ -8,7 +8,7 @@
 #include "ash/wm/user_activity_observer.h"
 #include "base/basictypes.h"
 #include "base/compiler_specific.h"
-#include "base/time.h"
+#include "base/time/time.h"
 
 namespace chromeos {
 
diff --git a/chrome/browser/chromeos/power/video_activity_notifier.cc b/chrome/browser/chromeos/power/video_activity_notifier.cc
index a92dcac..3f0698c 100644
--- a/chrome/browser/chromeos/power/video_activity_notifier.cc
+++ b/chrome/browser/chromeos/power/video_activity_notifier.cc
@@ -29,8 +29,8 @@
   base::TimeTicks now = base::TimeTicks::Now();
   if (last_notify_time_.is_null() ||
       (now - last_notify_time_).InSeconds() >= kNotifyIntervalSec) {
-    DBusThreadManager::Get()->GetPowerManagerClient()->
-        NotifyVideoActivity(now, is_fullscreen);
+    DBusThreadManager::Get()->GetPowerManagerClient()->NotifyVideoActivity(
+        is_fullscreen);
     last_notify_time_ = now;
   }
 }
diff --git a/chrome/browser/chromeos/power/video_activity_notifier.h b/chrome/browser/chromeos/power/video_activity_notifier.h
index 9ba22d9..ffe2a2c 100644
--- a/chrome/browser/chromeos/power/video_activity_notifier.h
+++ b/chrome/browser/chromeos/power/video_activity_notifier.h
@@ -8,7 +8,7 @@
 #include "ash/wm/video_detector.h"
 #include "base/basictypes.h"
 #include "base/compiler_specific.h"
-#include "base/time.h"
+#include "base/time/time.h"
 
 namespace chromeos {
 
diff --git a/chrome/browser/chromeos/preferences.cc b/chrome/browser/chromeos/preferences.cc
index 41b3e64..c73dadf 100644
--- a/chrome/browser/chromeos/preferences.cc
+++ b/chrome/browser/chromeos/preferences.cc
@@ -370,7 +370,11 @@
       600000,
       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
   registry->RegisterIntegerPref(
-      prefs::kPowerIdleAction,
+      prefs::kPowerAcIdleAction,
+      PowerPolicyController::ACTION_SUSPEND,
+      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
+  registry->RegisterIntegerPref(
+      prefs::kPowerBatteryIdleAction,
       PowerPolicyController::ACTION_SUSPEND,
       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
   registry->RegisterIntegerPref(
@@ -390,10 +394,6 @@
       true,
       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
   registry->RegisterDoublePref(
-      prefs::kPowerPresentationIdleDelayFactor,
-      2.0,
-      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
-  registry->RegisterDoublePref(
       prefs::kPowerPresentationScreenDimDelayFactor,
       2.0,
       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
@@ -525,7 +525,9 @@
       prefs::kPowerBatteryIdleWarningDelayMs, prefs, callback);
   power_battery_idle_delay_ms_.Init(
       prefs::kPowerBatteryIdleDelayMs, prefs, callback);
-  power_idle_action_.Init(prefs::kPowerIdleAction, prefs, callback);
+  power_ac_idle_action_.Init(prefs::kPowerAcIdleAction, prefs, callback);
+  power_battery_idle_action_.Init(
+      prefs::kPowerBatteryIdleAction, prefs, callback);
   power_lid_closed_action_.Init(prefs::kPowerLidClosedAction, prefs, callback);
   power_use_audio_activity_.Init(
       prefs::kPowerUseAudioActivity, prefs, callback);
@@ -625,22 +627,26 @@
     const int sensitivity = mouse_sensitivity_.GetValue();
     system::mouse_settings::SetSensitivity(sensitivity);
     if (pref_name) {
-      UMA_HISTOGRAM_CUSTOM_COUNTS(
-          "Mouse.Sensitivity.Changed", sensitivity, 1, 5, 5);
+      UMA_HISTOGRAM_ENUMERATION("Mouse.PointerSensitivity.Changed",
+                                sensitivity,
+                                system::kMaxPointerSensitivity + 1);
     } else {
-      UMA_HISTOGRAM_CUSTOM_COUNTS(
-          "Mouse.Sensitivity.Started", sensitivity, 1, 5, 5);
+      UMA_HISTOGRAM_ENUMERATION("Mouse.PointerSensitivity.Started",
+                                sensitivity,
+                                system::kMaxPointerSensitivity + 1);
     }
   }
   if (!pref_name || *pref_name == prefs::kTouchpadSensitivity) {
     const int sensitivity = touchpad_sensitivity_.GetValue();
     system::touchpad_settings::SetSensitivity(sensitivity);
     if (pref_name) {
-      UMA_HISTOGRAM_CUSTOM_COUNTS(
-          "Touchpad.Sensitivity.Changed", sensitivity, 1, 5, 5);
+      UMA_HISTOGRAM_ENUMERATION("Touchpad.PointerSensitivity.Changed",
+                                sensitivity,
+                                system::kMaxPointerSensitivity + 1);
     } else {
-      UMA_HISTOGRAM_CUSTOM_COUNTS(
-          "Touchpad.Sensitivity.Started", sensitivity, 1, 5, 5);
+      UMA_HISTOGRAM_ENUMERATION("Touchpad.PointerSensitivity.Started",
+                                sensitivity,
+                                system::kMaxPointerSensitivity + 1);
     }
   }
   if (!pref_name || *pref_name == prefs::kPrimaryMouseButtonRight) {
@@ -733,6 +739,7 @@
   // Do not check |*pref_name| of the prefs for remembering current/previous
   // input methods here. We're only interested in initial values of the prefs.
 
+  // TODO(nona): remove all IME preference entries. crbug.com/256102
   for (size_t i = 0; i < language_prefs::kNumChewingBooleanPrefs; ++i) {
     if (!pref_name ||
         *pref_name == language_prefs::kChewingBooleanPrefs[i].pref_name) {
@@ -770,9 +777,13 @@
   }
   if (!pref_name ||
       *pref_name == prefs::kLanguageHangulKeyboard) {
-    SetLanguageConfigString(language_prefs::kHangulSectionName,
-                            language_prefs::kHangulKeyboardConfigName,
-                            hangul_keyboard_.GetValue());
+    std::vector<std::string> new_input_method_ids;
+    if (input_method_manager_->MigrateKoreanKeyboard(
+            hangul_keyboard_.GetValue(),
+            &new_input_method_ids)) {
+      preload_engines_.SetValue(JoinString(new_input_method_ids, ','));
+      hangul_keyboard_.SetValue("dummy_value_already_migrated");
+    }
   }
   if (!pref_name || *pref_name == prefs::kLanguageHangulHanjaBindingKeys) {
     SetLanguageConfigString(language_prefs::kHangulSectionName,
@@ -855,7 +866,8 @@
       *pref_name == prefs::kPowerBatteryScreenLockDelayMs ||
       *pref_name == prefs::kPowerBatteryIdleWarningDelayMs ||
       *pref_name == prefs::kPowerBatteryIdleDelayMs ||
-      *pref_name == prefs::kPowerIdleAction ||
+      *pref_name == prefs::kPowerAcIdleAction ||
+      *pref_name == prefs::kPowerBatteryIdleAction ||
       *pref_name == prefs::kPowerLidClosedAction ||
       *pref_name == prefs::kPowerUseAudioActivity ||
       *pref_name == prefs::kPowerUseVideoActivity ||
@@ -879,8 +891,10 @@
     values.battery_idle_warning_delay_ms =
         power_battery_idle_warning_delay_ms_.GetValue();
     values.battery_idle_delay_ms = power_battery_idle_delay_ms_.GetValue();
-    values.idle_action = static_cast<PowerPolicyController::Action>(
-        power_idle_action_.GetValue());
+    values.ac_idle_action = static_cast<PowerPolicyController::Action>(
+        power_ac_idle_action_.GetValue());
+    values.battery_idle_action = static_cast<PowerPolicyController::Action>(
+        power_battery_idle_action_.GetValue());
     values.lid_closed_action = static_cast<PowerPolicyController::Action>(
         power_lid_closed_action_.GetValue());
     values.use_audio_activity = power_use_audio_activity_.GetValue();
diff --git a/chrome/browser/chromeos/preferences.h b/chrome/browser/chromeos/preferences.h
index e23c051..e1e3c81 100644
--- a/chrome/browser/chromeos/preferences.h
+++ b/chrome/browser/chromeos/preferences.h
@@ -180,7 +180,8 @@
   IntegerPrefMember power_battery_screen_lock_delay_ms_;
   IntegerPrefMember power_battery_idle_warning_delay_ms_;
   IntegerPrefMember power_battery_idle_delay_ms_;
-  IntegerPrefMember power_idle_action_;
+  IntegerPrefMember power_ac_idle_action_;
+  IntegerPrefMember power_battery_idle_action_;
   IntegerPrefMember power_lid_closed_action_;
   BooleanPrefMember power_use_audio_activity_;
   BooleanPrefMember power_use_video_activity_;
diff --git a/chrome/browser/chromeos/profiles/profile_helper.cc b/chrome/browser/chromeos/profiles/profile_helper.cc
index c94cf27..3d83458 100644
--- a/chrome/browser/chromeos/profiles/profile_helper.cc
+++ b/chrome/browser/chromeos/profiles/profile_helper.cc
@@ -19,6 +19,16 @@
 
 namespace chromeos {
 
+namespace {
+
+base::FilePath GetSigninProfileDir() {
+  ProfileManager* profile_manager = g_browser_process->profile_manager();
+  base::FilePath user_data_dir = profile_manager->user_data_dir();
+  return user_data_dir.AppendASCII(chrome::kInitialProfile);
+}
+
+}  // anonymous namespace
+
 ////////////////////////////////////////////////////////////////////////////////
 // ProfileHelper, public
 
@@ -61,10 +71,7 @@
 // static
 Profile* ProfileHelper::GetSigninProfile() {
   ProfileManager* profile_manager = g_browser_process->profile_manager();
-  base::FilePath user_data_dir = profile_manager->user_data_dir();
-  base::FilePath signin_profile_dir =
-      user_data_dir.AppendASCII(chrome::kInitialProfile);
-  return profile_manager->GetProfile(signin_profile_dir)->
+  return profile_manager->GetProfile(GetSigninProfileDir())->
       GetOffTheRecordProfile();
 }
 
@@ -123,6 +130,12 @@
   on_clear_callbacks_.push_back(on_clear_callback);
   if (signin_profile_clear_requested_)
     return;
+  ProfileManager* profile_manager = g_browser_process->profile_manager();
+  // Check if signin profile was loaded.
+  if (!profile_manager->GetProfileByPath(GetSigninProfileDir())) {
+    OnBrowsingDataRemoverDone();
+    return;
+  }
   signin_profile_clear_requested_ = true;
   BrowsingDataRemover* remover =
       BrowsingDataRemover::CreateForUnboundedRange(GetSigninProfile());
diff --git a/chrome/browser/chromeos/proxy_config_service_impl_unittest.cc b/chrome/browser/chromeos/proxy_config_service_impl_unittest.cc
index b3f48c0..feffd4d 100644
--- a/chrome/browser/chromeos/proxy_config_service_impl_unittest.cc
+++ b/chrome/browser/chromeos/proxy_config_service_impl_unittest.cc
@@ -245,14 +245,11 @@
 
     service_test->AddService("stub_wifi2", "wifi2_PSK",
                              flimflam::kTypeWifi, flimflam::kStateOnline,
-                             true /* add to watchlist */);
+                             true /* visible */, true /* watch */);
     service_test->SetServiceProperty("stub_wifi2",
                                      flimflam::kGuidProperty,
                                      base::StringValue("stub_wifi2"));
-    service_test->SetServiceProperty("stub_wifi2",
-                                     flimflam::kProfileProperty,
-                                     base::StringValue(kUserProfilePath));
-    profile_test->AddService("stub_wifi2");
+    profile_test->AddService(kUserProfilePath, "stub_wifi2");
 
     loop_.RunUntilIdle();
   }
diff --git a/chrome/browser/chromeos/screensaver/screensaver_controller.h b/chrome/browser/chromeos/screensaver/screensaver_controller.h
index 36e9877..1223415 100644
--- a/chrome/browser/chromeos/screensaver/screensaver_controller.h
+++ b/chrome/browser/chromeos/screensaver/screensaver_controller.h
@@ -11,7 +11,7 @@
 #include "base/basictypes.h"
 #include "base/gtest_prod_util.h"
 #include "base/memory/weak_ptr.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chromeos/dbus/power_manager_client.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
diff --git a/chrome/browser/chromeos/session_length_limiter.h b/chrome/browser/chromeos/session_length_limiter.h
index f634000..8c6d089 100644
--- a/chrome/browser/chromeos/session_length_limiter.h
+++ b/chrome/browser/chromeos/session_length_limiter.h
@@ -9,8 +9,8 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/prefs/pref_change_registrar.h"
 #include "base/threading/thread_checker.h"
-#include "base/time.h"
-#include "base/timer.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
 
 class PrefService;
 class PrefRegistrySimple;
diff --git a/chrome/browser/chromeos/settings/cros_settings_names.cc b/chrome/browser/chromeos/settings/cros_settings_names.cc
index b9dedf3..0468c6c 100644
--- a/chrome/browser/chromeos/settings/cros_settings_names.cc
+++ b/chrome/browser/chromeos/settings/cros_settings_names.cc
@@ -32,6 +32,8 @@
     "cros.accounts.deviceLocalAccountAutoLoginDelay";
 const char kAccountsPrefDeviceLocalAccountAutoLoginBailoutEnabled[] =
     "cros.accounts.deviceLocalAccountAutoLoginBailoutEnabled";
+const char kAccountsPrefSupervisedUsersEnabled[] =
+    "cros.accounts.supervisedUsersEnabled";
 
 // All cros.signed.* settings are stored in SignedSettings.
 const char kSignedDataRoamingEnabled[] = "cros.signed.data_roaming_enabled";
diff --git a/chrome/browser/chromeos/settings/cros_settings_names.h b/chrome/browser/chromeos/settings/cros_settings_names.h
index be47a46..cd6a9be 100644
--- a/chrome/browser/chromeos/settings/cros_settings_names.h
+++ b/chrome/browser/chromeos/settings/cros_settings_names.h
@@ -22,6 +22,7 @@
 extern const char kAccountsPrefDeviceLocalAccountAutoLoginId[];
 extern const char kAccountsPrefDeviceLocalAccountAutoLoginDelay[];
 extern const char kAccountsPrefDeviceLocalAccountAutoLoginBailoutEnabled[];
+extern const char kAccountsPrefSupervisedUsersEnabled[];
 
 extern const char kSignedDataRoamingEnabled[];
 
diff --git a/chrome/browser/chromeos/settings/device_oauth2_token_service.cc b/chrome/browser/chromeos/settings/device_oauth2_token_service.cc
index 1e277a5..361d49e 100644
--- a/chrome/browser/chromeos/settings/device_oauth2_token_service.cc
+++ b/chrome/browser/chromeos/settings/device_oauth2_token_service.cc
@@ -4,22 +4,244 @@
 
 #include "chrome/browser/chromeos/settings/device_oauth2_token_service.h"
 
+#include <string>
+#include <vector>
+
 #include "base/prefs/pref_registry_simple.h"
 #include "base/prefs/pref_service.h"
+#include "base/values.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.h"
+#include "chrome/browser/policy/browser_policy_connector.h"
+#include "chrome/browser/policy/proto/cloud/device_management_backend.pb.h"
 #include "chrome/common/pref_names.h"
 #include "chromeos/cryptohome/cryptohome_library.h"
 #include "content/public/browser/browser_thread.h"
+#include "google_apis/gaia/gaia_urls.h"
+#include "google_apis/gaia/google_service_auth_error.h"
+
+namespace {
+const char kServiceScopeGetUserInfo[] =
+    "https://www.googleapis.com/auth/userinfo.email";
+}  // namespace
 
 namespace chromeos {
 
+// A wrapper for the consumer passed to StartRequest, which doesn't call
+// through to the target Consumer unless the refresh token validation is
+// complete.
+class DeviceOAuth2TokenService::ValidatingConsumer
+    : public OAuth2TokenService::Consumer,
+      public gaia::GaiaOAuthClient::Delegate {
+ public:
+  explicit ValidatingConsumer(DeviceOAuth2TokenService* token_service,
+                              Consumer* consumer);
+  virtual ~ValidatingConsumer();
+
+  void StartValidation();
+
+  // OAuth2TokenService::Consumer
+  virtual void OnGetTokenSuccess(
+      const Request* request,
+      const std::string& access_token,
+      const base::Time& expiration_time) OVERRIDE;
+  virtual void OnGetTokenFailure(
+      const Request* request,
+      const GoogleServiceAuthError& error) OVERRIDE;
+
+  // gaia::GaiaOAuthClient::Delegate implementation.
+  virtual void OnRefreshTokenResponse(const std::string& access_token,
+                                      int expires_in_seconds) OVERRIDE;
+  virtual void OnGetTokenInfoResponse(scoped_ptr<DictionaryValue> token_info)
+      OVERRIDE;
+  virtual void OnOAuthError() OVERRIDE;
+  virtual void OnNetworkError(int response_code) OVERRIDE;
+
+ private:
+  void RefreshTokenIsValid(bool is_valid);
+  void InformConsumer();
+
+  DeviceOAuth2TokenService* token_service_;
+  Consumer* consumer_;
+  scoped_ptr<gaia::GaiaOAuthClient> gaia_oauth_client_;
+
+  // We don't know which will complete first: the validation or the token
+  // minting.  So, we need to cache the results so the final callback can
+  // take action.
+
+  // RefreshTokenValidationConsumer results
+  bool token_validation_done_;
+  bool token_is_valid_;
+
+  // OAuth2TokenService::Consumer results
+  const Request* request_;
+  std::string access_token_;
+  base::Time expiration_time_;
+  scoped_ptr<GoogleServiceAuthError> error_;
+};
+
+DeviceOAuth2TokenService::ValidatingConsumer::ValidatingConsumer(
+    DeviceOAuth2TokenService* token_service,
+    Consumer* consumer)
+        : token_service_(token_service),
+          consumer_(consumer),
+          token_validation_done_(false),
+          token_is_valid_(false),
+          request_(NULL) {
+}
+
+DeviceOAuth2TokenService::ValidatingConsumer::~ValidatingConsumer() {
+}
+
+void DeviceOAuth2TokenService::ValidatingConsumer::StartValidation() {
+  DCHECK(!gaia_oauth_client_);
+  gaia_oauth_client_.reset(new gaia::GaiaOAuthClient(
+      g_browser_process->system_request_context()));
+
+  GaiaUrls* gaia_urls = GaiaUrls::GetInstance();
+  gaia::OAuthClientInfo client_info;
+  client_info.client_id = gaia_urls->oauth2_chrome_client_id();
+  client_info.client_secret = gaia_urls->oauth2_chrome_client_secret();
+
+  gaia_oauth_client_->RefreshToken(
+      client_info,
+      token_service_->GetRefreshToken(),
+      std::vector<std::string>(1, kServiceScopeGetUserInfo),
+      token_service_->max_refresh_token_validation_retries_,
+      this);
+}
+
+void DeviceOAuth2TokenService::ValidatingConsumer::OnRefreshTokenResponse(
+    const std::string& access_token,
+    int expires_in_seconds) {
+  gaia_oauth_client_->GetTokenInfo(
+      access_token,
+      token_service_->max_refresh_token_validation_retries_,
+      this);
+}
+
+void DeviceOAuth2TokenService::ValidatingConsumer::OnGetTokenInfoResponse(
+    scoped_ptr<DictionaryValue> token_info) {
+  std::string gaia_robot_id;
+  token_info->GetString("email", &gaia_robot_id);
+
+  std::string policy_robot_id = token_service_->GetRobotAccountId();
+
+  if (policy_robot_id == gaia_robot_id) {
+    RefreshTokenIsValid(true);
+  } else {
+    if (gaia_robot_id.empty()) {
+      LOG(WARNING) << "Device service account owner in policy is empty.";
+    } else {
+      LOG(INFO) << "Device service account owner in policy does not match "
+                << "refresh token owner \"" << gaia_robot_id << "\".";
+    }
+    RefreshTokenIsValid(false);
+  }
+}
+
+void DeviceOAuth2TokenService::ValidatingConsumer::OnOAuthError() {
+  RefreshTokenIsValid(false);
+}
+
+void DeviceOAuth2TokenService::ValidatingConsumer::OnNetworkError(
+    int response_code) {
+  RefreshTokenIsValid(false);
+}
+
+void DeviceOAuth2TokenService::ValidatingConsumer::OnGetTokenSuccess(
+      const Request* request,
+      const std::string& access_token,
+      const base::Time& expiration_time) {
+  request_ = request;
+  access_token_ = access_token;
+  expiration_time_ = expiration_time;
+  if (token_validation_done_)
+    InformConsumer();
+}
+
+void DeviceOAuth2TokenService::ValidatingConsumer::OnGetTokenFailure(
+      const Request* request,
+      const GoogleServiceAuthError& error) {
+  request_ = request;
+  error_.reset(new GoogleServiceAuthError(error.state()));
+  if (token_validation_done_)
+    InformConsumer();
+}
+
+void DeviceOAuth2TokenService::ValidatingConsumer::RefreshTokenIsValid(
+    bool is_valid) {
+  token_validation_done_ = true;
+  token_is_valid_ = is_valid;
+  // If we have a request pointer, then the minting is complete.
+  if (request_)
+    InformConsumer();
+}
+
+void DeviceOAuth2TokenService::ValidatingConsumer::InformConsumer() {
+  DCHECK(request_);
+  DCHECK(token_validation_done_);
+  if (!token_is_valid_) {
+    consumer_->OnGetTokenFailure(request_, GoogleServiceAuthError(
+        GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS));
+  } else if (error_) {
+    consumer_->OnGetTokenFailure(request_, *error_.get());
+  } else {
+    consumer_->OnGetTokenSuccess(request_, access_token_, expiration_time_);
+  }
+  token_service_->OnValidationComplete(this, token_is_valid_);
+}
+
 DeviceOAuth2TokenService::DeviceOAuth2TokenService(
     net::URLRequestContextGetter* getter,
     PrefService* local_state)
     : OAuth2TokenService(getter),
+      refresh_token_is_valid_(false),
+      max_refresh_token_validation_retries_(3),
+      pending_validators_(new std::set<ValidatingConsumer*>()),
       local_state_(local_state) {
 }
 
 DeviceOAuth2TokenService::~DeviceOAuth2TokenService() {
+  STLDeleteElements(pending_validators_.get());
+}
+
+// TODO(davidroche): if the caller deletes the returned Request while
+// the fetches are in-flight, the OAuth2TokenService class won't call
+// back into the ValidatingConsumer and we'll end up with stale values
+// in pending_validators_ until this object is deleted.  Probably not a
+// big deal, but it should be resolved by returning a Request that this
+// object owns.
+scoped_ptr<OAuth2TokenService::Request> DeviceOAuth2TokenService::StartRequest(
+    const OAuth2TokenService::ScopeSet& scopes,
+    OAuth2TokenService::Consumer* consumer) {
+  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+
+  if (refresh_token_is_valid_) {
+    return OAuth2TokenService::StartRequest(scopes, consumer).Pass();
+  } else {
+    ValidatingConsumer* validating_consumer = new ValidatingConsumer(this,
+                                                                     consumer);
+    pending_validators_->insert(validating_consumer);
+
+    validating_consumer->StartValidation();
+    return OAuth2TokenService::StartRequest(scopes, validating_consumer).Pass();
+  }
+}
+
+void DeviceOAuth2TokenService::OnValidationComplete(
+    ValidatingConsumer* validator,
+    bool refresh_token_is_valid) {
+  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+  refresh_token_is_valid_ = refresh_token_is_valid;
+  std::set<ValidatingConsumer*>::iterator iter = pending_validators_->find(
+      validator);
+  if (iter != pending_validators_->end()) {
+    delete *iter;
+    pending_validators_->erase(iter);
+  } else {
+    LOG(ERROR) << "OnValidationComplete called for unknown validator";
+  }
 }
 
 // static
@@ -49,4 +271,12 @@
   return refresh_token_;
 }
 
+std::string DeviceOAuth2TokenService::GetRobotAccountId() {
+  policy::BrowserPolicyConnector* connector =
+      g_browser_process->browser_policy_connector();
+  if (connector)
+    return connector->GetDeviceCloudPolicyManager()->GetRobotAccountId();
+  return std::string();
+}
+
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/settings/device_oauth2_token_service.h b/chrome/browser/chromeos/settings/device_oauth2_token_service.h
index 9d4bc6a..9ace020 100644
--- a/chrome/browser/chromeos/settings/device_oauth2_token_service.h
+++ b/chrome/browser/chromeos/settings/device_oauth2_token_service.h
@@ -5,12 +5,16 @@
 #ifndef CHROME_BROWSER_CHROMEOS_SETTINGS_DEVICE_OAUTH2_TOKEN_SERVICE_H_
 #define CHROME_BROWSER_CHROMEOS_SETTINGS_DEVICE_OAUTH2_TOKEN_SERVICE_H_
 
+#include <set>
 #include <string>
 
 #include "base/basictypes.h"
 #include "base/gtest_prod_util.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/stl_util.h"
+#include "base/time/time.h"
 #include "chrome/browser/signin/oauth2_token_service.h"
+#include "google_apis/gaia/gaia_oauth_client.h"
 #include "net/url_request/url_request_context_getter.h"
 
 namespace net {
@@ -33,6 +37,11 @@
 // Note that requests must be made from the UI thread.
 class DeviceOAuth2TokenService : public OAuth2TokenService {
  public:
+  // Specialization of StartRequest that in parallel validates that the refresh
+  // token stored on the device is owned by the device service account.
+  virtual scoped_ptr<Request> StartRequest(const ScopeSet& scopes,
+                                           Consumer* consumer) OVERRIDE;
+
   // Persist the given refresh token on the device.  Overwrites any previous
   // value.  Should only be called during initial device setup.
   void SetAndSaveRefreshToken(const std::string& refresh_token);
@@ -41,15 +50,29 @@
 
   virtual std::string GetRefreshToken() OVERRIDE;
 
+ protected:
+  // Pull the robot account ID from device policy.
+  virtual std::string GetRobotAccountId();
+
  private:
+  class ValidatingConsumer;
+  friend class ValidatingConsumer;
   friend class DeviceOAuth2TokenServiceFactory;
-  FRIEND_TEST_ALL_PREFIXES(DeviceOAuth2TokenServiceTest, SaveEncryptedToken);
+  friend class DeviceOAuth2TokenServiceTest;
+  friend class TestDeviceOAuth2TokenService;
 
   // Use DeviceOAuth2TokenServiceFactory to get an instance of this class.
   explicit DeviceOAuth2TokenService(net::URLRequestContextGetter* getter,
                                     PrefService* local_state);
   virtual ~DeviceOAuth2TokenService();
 
+  void OnValidationComplete(ValidatingConsumer* validator, bool token_is_valid);
+
+  bool refresh_token_is_valid_;
+  int max_refresh_token_validation_retries_;
+
+  scoped_ptr<std::set<ValidatingConsumer*> > pending_validators_;
+
   // Cache the decrypted refresh token, so we only decrypt once.
   std::string refresh_token_;
   PrefService* local_state_;
diff --git a/chrome/browser/chromeos/settings/device_oauth2_token_service_unittest.cc b/chrome/browser/chromeos/settings/device_oauth2_token_service_unittest.cc
index 6424ccb..c01fda7 100644
--- a/chrome/browser/chromeos/settings/device_oauth2_token_service_unittest.cc
+++ b/chrome/browser/chromeos/settings/device_oauth2_token_service_unittest.cc
@@ -6,11 +6,18 @@
 
 #include "base/message_loop.h"
 #include "base/prefs/testing_pref_service.h"
+#include "base/run_loop.h"
+#include "chrome/browser/signin/oauth2_token_service_test_util.h"
+#include "chrome/common/pref_names.h"
 #include "chrome/test/base/scoped_testing_local_state.h"
 #include "chrome/test/base/testing_browser_process.h"
 #include "chromeos/cryptohome/mock_cryptohome_library.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/test/test_browser_thread.h"
+#include "google_apis/gaia/gaia_oauth_client.h"
+#include "net/http/http_status_code.h"
+#include "net/url_request/test_url_fetcher_factory.h"
+#include "net/url_request/url_fetcher_delegate.h"
 #include "net/url_request/url_request_test_util.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -23,25 +30,122 @@
 
 namespace chromeos {
 
+static const int kOAuthTokenServiceUrlFetcherId = 0;
+static const int kValidatorUrlFetcherId = gaia::GaiaOAuthClient::kUrlFetcherId;
+
+class TestDeviceOAuth2TokenService : public DeviceOAuth2TokenService {
+ public:
+  explicit TestDeviceOAuth2TokenService(net::URLRequestContextGetter* getter,
+                                        PrefService* local_state)
+      : DeviceOAuth2TokenService(getter, local_state) {
+  }
+  void SetRobotAccountIdPolicyValue(const std::string& id) {
+    robot_account_id_ = id;
+  }
+
+ protected:
+  // Skip calling into the policy subsystem and return our test value.
+  virtual std::string GetRobotAccountId() OVERRIDE {
+    return robot_account_id_;
+  }
+
+ private:
+  std::string robot_account_id_;
+  DISALLOW_COPY_AND_ASSIGN(TestDeviceOAuth2TokenService);
+};
+
 class DeviceOAuth2TokenServiceTest : public testing::Test {
  public:
   DeviceOAuth2TokenServiceTest()
       : ui_thread_(content::BrowserThread::UI, &message_loop_),
-        scoped_testing_local_state_(TestingBrowserProcess::GetGlobal()) {}
+        scoped_testing_local_state_(TestingBrowserProcess::GetGlobal()),
+        request_context_getter_(new net::TestURLRequestContextGetter(
+            message_loop_.message_loop_proxy())),
+        oauth2_service_(request_context_getter_,
+                        scoped_testing_local_state_.Get()) {
+    oauth2_service_.max_refresh_token_validation_retries_ = 0;
+    oauth2_service_.set_max_authorization_token_fetch_retries_for_testing(0);
+  }
   virtual ~DeviceOAuth2TokenServiceTest() {}
 
-  virtual void SetUp() OVERRIDE {
+  // Most tests just want a noop crypto impl with a dummy refresh token value in
+  // Local State (if the value is an empty string, it will be ignored).
+  void SetUpDefaultValues() {
+    cryptohome_library_.reset(chromeos::CryptohomeLibrary::GetTestImpl());
+    chromeos::CryptohomeLibrary::SetForTest(cryptohome_library_.get());
+    SetDeviceRefreshTokenInLocalState("device_refresh_token_4_test");
+    oauth2_service_.SetRobotAccountIdPolicyValue("service_acct@g.com");
+    AssertConsumerTokensAndErrors(0, 0);
+  }
+
+  scoped_ptr<OAuth2TokenService::Request> StartTokenRequest() {
+    return oauth2_service_.StartRequest(std::set<std::string>(), &consumer_);
   }
 
   virtual void TearDown() OVERRIDE {
+    CryptohomeLibrary::SetForTest(NULL);
+    base::RunLoop().RunUntilIdle();
   }
 
+  // Utility method to set a value in Local State for the device refresh token
+  // (it must have a non-empty value or it won't be used).
+  void SetDeviceRefreshTokenInLocalState(const std::string& refresh_token) {
+    scoped_testing_local_state_.Get()->SetManagedPref(
+        prefs::kDeviceRobotAnyApiRefreshToken,
+        Value::CreateStringValue(refresh_token));
+  }
+
+  std::string GetValidTokenInfoResponse(const std::string email) {
+    return "{ \"email\": \"" + email + "\","
+           "  \"user_id\": \"1234567890\" }";
+  }
+
+  // A utility method to return fake URL results, for testing the refresh token
+  // validation logic.  For a successful validation attempt, this method will be
+  // called three times for the steps listed below (steps 1 and 2 happen in
+  // parallel).
+  //
+  // Step 1a: fetch the access token for the tokeninfo API.
+  // Step 1b: call the tokeninfo API.
+  // Step 2:  Fetch the access token for the requested scope
+  //          (in this case, cloudprint).
+  void ReturnOAuthUrlFetchResults(int fetcher_id,
+                                  net::HttpStatusCode response_code,
+                                  const std::string&  response_string);
+
+  void AssertConsumerTokensAndErrors(int num_tokens, int num_errors);
+
  protected:
   base::MessageLoop message_loop_;
   content::TestBrowserThread ui_thread_;
   ScopedTestingLocalState scoped_testing_local_state_;
+  scoped_refptr<net::TestURLRequestContextGetter> request_context_getter_;
+  net::TestURLFetcherFactory factory_;
+  TestDeviceOAuth2TokenService oauth2_service_;
+  TestingOAuth2TokenServiceConsumer consumer_;
+  scoped_ptr<chromeos::CryptohomeLibrary> cryptohome_library_;
+
 };
 
+void DeviceOAuth2TokenServiceTest::ReturnOAuthUrlFetchResults(
+    int fetcher_id,
+    net::HttpStatusCode response_code,
+    const std::string&  response_string) {
+
+  net::TestURLFetcher* fetcher = factory_.GetFetcherByID(fetcher_id);
+  ASSERT_TRUE(fetcher);
+  fetcher->set_response_code(response_code);
+  fetcher->SetResponseString(response_string);
+  fetcher->delegate()->OnURLFetchComplete(fetcher);
+}
+
+void DeviceOAuth2TokenServiceTest::AssertConsumerTokensAndErrors(
+    int num_tokens,
+    int num_errors) {
+  ASSERT_EQ(num_tokens, consumer_.number_of_successful_tokens_);
+  ASSERT_EQ(num_errors, consumer_.number_of_errors_);
+}
+
 TEST_F(DeviceOAuth2TokenServiceTest, SaveEncryptedToken) {
   StrictMock<MockCryptohomeLibrary> mock_cryptohome_library;
   CryptohomeLibrary::SetForTest(&mock_cryptohome_library);
@@ -58,16 +162,207 @@
       .Times(1)
       .WillOnce(Return("test-token"));
 
-  DeviceOAuth2TokenService oauth2_service(
-      new net::TestURLRequestContextGetter(message_loop_.message_loop_proxy()),
-      scoped_testing_local_state_.Get());
-
-  ASSERT_EQ("", oauth2_service.GetRefreshToken());
-  oauth2_service.SetAndSaveRefreshToken("test-token");
-  ASSERT_EQ("test-token", oauth2_service.GetRefreshToken());
+  ASSERT_EQ("", oauth2_service_.GetRefreshToken());
+  oauth2_service_.SetAndSaveRefreshToken("test-token");
+  ASSERT_EQ("test-token", oauth2_service_.GetRefreshToken());
 
   // This call won't invoke decrypt again, since the value is cached.
-  ASSERT_EQ("test-token", oauth2_service.GetRefreshToken());
+  ASSERT_EQ("test-token", oauth2_service_.GetRefreshToken());
+}
+
+TEST_F(DeviceOAuth2TokenServiceTest, RefreshTokenValidation_Success) {
+  SetUpDefaultValues();
+  scoped_ptr<OAuth2TokenService::Request> request = StartTokenRequest();
+
+  ReturnOAuthUrlFetchResults(
+      kValidatorUrlFetcherId,
+      net::HTTP_OK,
+      GetValidTokenResponse("tokeninfo_access_token", 3600));
+
+  ReturnOAuthUrlFetchResults(
+      kValidatorUrlFetcherId,
+      net::HTTP_OK,
+      GetValidTokenInfoResponse("service_acct@g.com"));
+
+  ReturnOAuthUrlFetchResults(
+      kOAuthTokenServiceUrlFetcherId,
+      net::HTTP_OK,
+      GetValidTokenResponse("scoped_access_token", 3600));
+
+  AssertConsumerTokensAndErrors(1, 0);
+
+  EXPECT_EQ("scoped_access_token", consumer_.last_token_);
+}
+
+TEST_F(DeviceOAuth2TokenServiceTest,
+       RefreshTokenValidation_Failure_TokenInfoAccessTokenHttpError) {
+  SetUpDefaultValues();
+  scoped_ptr<OAuth2TokenService::Request> request = StartTokenRequest();
+
+  ReturnOAuthUrlFetchResults(
+      kValidatorUrlFetcherId,
+      net::HTTP_UNAUTHORIZED,
+      "");
+
+  // TokenInfo API call skipped (error returned in previous step).
+
+  // CloudPrint access token fetch is successful, but consumer still given error
+  // due to bad refresh token.
+  ReturnOAuthUrlFetchResults(
+      kOAuthTokenServiceUrlFetcherId,
+      net::HTTP_OK,
+      GetValidTokenResponse("ignored_scoped_access_token", 3600));
+
+  AssertConsumerTokensAndErrors(0, 1);
+}
+
+TEST_F(DeviceOAuth2TokenServiceTest,
+       RefreshTokenValidation_Failure_TokenInfoAccessTokenInvalidResponse) {
+  SetUpDefaultValues();
+  scoped_ptr<OAuth2TokenService::Request> request = StartTokenRequest();
+
+  ReturnOAuthUrlFetchResults(
+      kValidatorUrlFetcherId,
+      net::HTTP_OK,
+      "invalid response");
+
+  // TokenInfo API call skipped (error returned in previous step).
+
+  ReturnOAuthUrlFetchResults(
+      kOAuthTokenServiceUrlFetcherId,
+      net::HTTP_OK,
+      GetValidTokenResponse("ignored_scoped_access_token", 3600));
+
+  // CloudPrint access token fetch is successful, but consumer still given error
+  // due to bad refresh token.
+  AssertConsumerTokensAndErrors(0, 1);
+}
+
+TEST_F(DeviceOAuth2TokenServiceTest,
+       RefreshTokenValidation_Failure_TokenInfoApiCallHttpError) {
+  SetUpDefaultValues();
+  scoped_ptr<OAuth2TokenService::Request> request = StartTokenRequest();
+
+  ReturnOAuthUrlFetchResults(
+      kValidatorUrlFetcherId,
+      net::HTTP_OK,
+      GetValidTokenResponse("tokeninfo_access_token", 3600));
+
+  ReturnOAuthUrlFetchResults(
+      kValidatorUrlFetcherId,
+      net::HTTP_INTERNAL_SERVER_ERROR,
+      "");
+
+  ReturnOAuthUrlFetchResults(
+      kOAuthTokenServiceUrlFetcherId,
+      net::HTTP_OK,
+      GetValidTokenResponse("ignored_scoped_access_token", 3600));
+
+  // CloudPrint access token fetch is successful, but consumer still given error
+  // due to bad refresh token.
+  AssertConsumerTokensAndErrors(0, 1);
+}
+
+TEST_F(DeviceOAuth2TokenServiceTest,
+       RefreshTokenValidation_Failure_TokenInfoApiCallInvalidResponse) {
+  SetUpDefaultValues();
+  scoped_ptr<OAuth2TokenService::Request> request = StartTokenRequest();
+
+  ReturnOAuthUrlFetchResults(
+      kValidatorUrlFetcherId,
+      net::HTTP_OK,
+      GetValidTokenResponse("tokeninfo_access_token", 3600));
+
+  ReturnOAuthUrlFetchResults(
+      kValidatorUrlFetcherId,
+      net::HTTP_OK,
+      "invalid response");
+
+  ReturnOAuthUrlFetchResults(
+      kOAuthTokenServiceUrlFetcherId,
+      net::HTTP_OK,
+      GetValidTokenResponse("ignored_scoped_access_token", 3600));
+
+  // CloudPrint access token fetch is successful, but consumer still given error
+  // due to bad refresh token.
+  AssertConsumerTokensAndErrors(0, 1);
+}
+
+TEST_F(DeviceOAuth2TokenServiceTest,
+       RefreshTokenValidation_Failure_CloudPrintAccessTokenHttpError) {
+  SetUpDefaultValues();
+  scoped_ptr<OAuth2TokenService::Request> request = StartTokenRequest();
+
+  ReturnOAuthUrlFetchResults(
+      kValidatorUrlFetcherId,
+      net::HTTP_OK,
+      GetValidTokenResponse("tokeninfo_access_token", 3600));
+
+  ReturnOAuthUrlFetchResults(
+      kValidatorUrlFetcherId,
+      net::HTTP_OK,
+      GetValidTokenInfoResponse("service_acct@g.com"));
+
+  ReturnOAuthUrlFetchResults(
+      kOAuthTokenServiceUrlFetcherId,
+      net::HTTP_BAD_REQUEST,
+      "");
+
+  AssertConsumerTokensAndErrors(0, 1);
+}
+
+TEST_F(DeviceOAuth2TokenServiceTest,
+       RefreshTokenValidation_Failure_CloudPrintAccessTokenInvalidResponse) {
+  SetUpDefaultValues();
+  scoped_ptr<OAuth2TokenService::Request> request = StartTokenRequest();
+
+  ReturnOAuthUrlFetchResults(
+      kValidatorUrlFetcherId,
+      net::HTTP_OK,
+      GetValidTokenResponse("tokeninfo_access_token", 3600));
+
+  ReturnOAuthUrlFetchResults(
+      kValidatorUrlFetcherId,
+      net::HTTP_OK,
+      GetValidTokenInfoResponse("service_acct@g.com"));
+
+  ReturnOAuthUrlFetchResults(
+      kOAuthTokenServiceUrlFetcherId,
+      net::HTTP_OK,
+      "invalid request");
+
+  AssertConsumerTokensAndErrors(0, 1);
+}
+
+TEST_F(DeviceOAuth2TokenServiceTest, RefreshTokenValidation_Failure_BadOwner) {
+  SetUpDefaultValues();
+  scoped_ptr<OAuth2TokenService::Request> request = StartTokenRequest();
+
+  oauth2_service_.SetRobotAccountIdPolicyValue("WRONG_service_acct@g.com");
+
+  // The requested token comes in before any of the validation calls complete,
+  // but the consumer still gets an error, since the results don't get returned
+  // until validation is over.
+  ReturnOAuthUrlFetchResults(
+      kOAuthTokenServiceUrlFetcherId,
+      net::HTTP_OK,
+      GetValidTokenResponse("ignored_scoped_access_token", 3600));
+  AssertConsumerTokensAndErrors(0, 0);
+
+  ReturnOAuthUrlFetchResults(
+      kValidatorUrlFetcherId,
+      net::HTTP_OK,
+      GetValidTokenResponse("tokeninfo_access_token", 3600));
+  AssertConsumerTokensAndErrors(0, 0);
+
+  ReturnOAuthUrlFetchResults(
+      kValidatorUrlFetcherId,
+      net::HTTP_OK,
+      GetValidTokenInfoResponse("service_acct@g.com"));
+
+  // All fetches were successful, but consumer still given error since
+  // the token owner doesn't match the policy value.
+  AssertConsumerTokensAndErrors(0, 1);
 }
 
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/settings/device_settings_provider.cc b/chrome/browser/chromeos/settings/device_settings_provider.cc
index 6a7876c..98293ad 100644
--- a/chrome/browser/chromeos/settings/device_settings_provider.cc
+++ b/chrome/browser/chromeos/settings/device_settings_provider.cc
@@ -47,6 +47,7 @@
   kAccountsPrefDeviceLocalAccountAutoLoginId,
   kAccountsPrefEphemeralUsersEnabled,
   kAccountsPrefShowUserNamesOnSignIn,
+  kAccountsPrefSupervisedUsersEnabled,
   kAccountsPrefUsers,
   kAllowRedeemChromeOsRegistrationOffers,
   kAllowedConnectionTypesForUpdate,
@@ -366,16 +367,17 @@
   } else {
     // The remaining settings don't support Set(), since they are not
     // intended to be customizable by the user:
+    //   kAccountsPrefSupervisedUsersEnabled
     //   kAppPack
     //   kDeviceAttestationEnabled
     //   kDeviceOwner
     //   kIdleLogoutTimeout
     //   kIdleLogoutWarningDuration
     //   kReleaseChannelDelegated
-    //   kReportDeviceVersionInfo
     //   kReportDeviceActivityTimes
     //   kReportDeviceBootMode
     //   kReportDeviceLocation
+    //   kReportDeviceVersionInfo
     //   kScreenSaverExtensionId
     //   kScreenSaverTimeout
     //   kStartUpUrls
@@ -448,6 +450,11 @@
       policy.ephemeral_users_enabled().has_ephemeral_users_enabled() &&
       policy.ephemeral_users_enabled().ephemeral_users_enabled());
 
+  new_values_cache->SetBoolean(
+      kAccountsPrefSupervisedUsersEnabled,
+      policy.has_supervised_users_settings() &&
+      policy.supervised_users_settings().supervised_users_enabled());
+
   base::ListValue* list = new base::ListValue();
   const em::UserWhitelistProto& whitelist_proto = policy.user_whitelist();
   const RepeatedPtrField<std::string>& whitelist =
diff --git a/chrome/browser/chromeos/settings/owner_flags_storage.cc b/chrome/browser/chromeos/settings/owner_flags_storage.cc
new file mode 100644
index 0000000..38c2ba9
--- /dev/null
+++ b/chrome/browser/chromeos/settings/owner_flags_storage.cc
@@ -0,0 +1,63 @@
+// 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/settings/owner_flags_storage.h"
+
+#include "base/prefs/pref_service.h"
+#include "base/values.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/chromeos/settings/cros_settings.h"
+#include "chrome/browser/chromeos/settings/cros_settings_names.h"
+#include "chrome/common/pref_names.h"
+
+namespace chromeos {
+namespace about_flags {
+
+OwnerFlagsStorage::OwnerFlagsStorage(PrefService *prefs,
+                                     CrosSettings *cros_settings)
+    : ::about_flags::PrefServiceFlagsStorage(prefs),
+      cros_settings_(cros_settings) {
+  // Make this code more unit test friendly.
+  if (g_browser_process->local_state()) {
+    const ListValue* legacy_experiments =
+        g_browser_process->local_state()->GetList(
+            prefs::kEnabledLabsExperiments);
+    if (!legacy_experiments->empty()) {
+      // If there are any flags set in local state migrate them to the owner's
+      // prefs and device settings.
+      std::set<std::string> flags;
+      for (ListValue::const_iterator it = legacy_experiments->begin();
+           it != legacy_experiments->end(); ++it) {
+        std::string experiment_name;
+        if (!(*it)->GetAsString(&experiment_name)) {
+          LOG(WARNING) << "Invalid entry in " << prefs::kEnabledLabsExperiments;
+          continue;
+        }
+        flags.insert(experiment_name);
+      }
+      SetFlags(flags);
+      g_browser_process->local_state()->ClearPref(
+          prefs::kEnabledLabsExperiments);
+    }
+  }
+}
+
+OwnerFlagsStorage::~OwnerFlagsStorage() {}
+
+bool OwnerFlagsStorage::SetFlags(std::set<std::string> flags) {
+  PrefServiceFlagsStorage::SetFlags(flags);
+
+  base::ListValue experiments_list;
+
+  for (std::set<std::string>::const_iterator it = flags.begin();
+       it != flags.end(); ++it) {
+    experiments_list.Append(new base::StringValue(*it));
+  }
+  cros_settings_->Set(kStartUpFlags, experiments_list);
+
+  return true;
+}
+
+}  // namespace about_flags
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/settings/owner_flags_storage.h b/chrome/browser/chromeos/settings/owner_flags_storage.h
new file mode 100644
index 0000000..77d7830
--- /dev/null
+++ b/chrome/browser/chromeos/settings/owner_flags_storage.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 CHROME_BROWSER_CHROMEOS_SETTINGS_OWNER_FLAGS_STORAGE_H_
+#define CHROME_BROWSER_CHROMEOS_SETTINGS_OWNER_FLAGS_STORAGE_H_
+
+#include "base/compiler_specific.h"
+#include "chrome/browser/pref_service_flags_storage.h"
+
+namespace chromeos {
+
+class CrosSettings;
+
+namespace about_flags {
+
+// Implements the FlagsStorage interface for the owner flags. It inherits from
+// PrefServiceFlagsStorage but extends it with storing the flags in the signed
+// settings as well which effectively applies them to the login session as well.
+class OwnerFlagsStorage : public ::about_flags::PrefServiceFlagsStorage {
+ public:
+  OwnerFlagsStorage(PrefService *prefs, CrosSettings *cros_settings);
+  virtual ~OwnerFlagsStorage();
+
+  virtual bool SetFlags(std::set<std::string> flags) OVERRIDE;
+
+ private:
+  CrosSettings* cros_settings_;
+};
+
+}  // namespace about_flags
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_CHROMEOS_SETTINGS_OWNER_FLAGS_STORAGE_H_
diff --git a/chrome/browser/chromeos/settings/session_manager_operation.cc b/chrome/browser/chromeos/settings/session_manager_operation.cc
index e7c9a9d..5339f3f 100644
--- a/chrome/browser/chromeos/settings/session_manager_operation.cc
+++ b/chrome/browser/chromeos/settings/session_manager_operation.cc
@@ -11,7 +11,7 @@
 #include "base/stl_util.h"
 #include "base/task_runner_util.h"
 #include "base/threading/sequenced_worker_pool.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/chromeos/settings/owner_key_util.h"
 #include "chrome/browser/policy/cloud/cloud_policy_constants.h"
 #include "chrome/browser/policy/proto/chromeos/chrome_device_policy.pb.h"
diff --git a/chrome/browser/chromeos/settings/system_settings_provider.cc b/chrome/browser/chromeos/settings/system_settings_provider.cc
index 5f2741f..35549aa 100644
--- a/chrome/browser/chromeos/settings/system_settings_provider.cc
+++ b/chrome/browser/chromeos/settings/system_settings_provider.cc
@@ -5,7 +5,7 @@
 #include "chrome/browser/chromeos/settings/system_settings_provider.h"
 
 #include "base/strings/string16.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "base/values.h"
 #include "chrome/browser/chromeos/login/user_manager.h"
 #include "chrome/browser/chromeos/settings/cros_settings.h"
diff --git a/chrome/browser/chromeos/status/network_menu_icon.h b/chrome/browser/chromeos/status/network_menu_icon.h
index 5e8fc7b..f0fb554 100644
--- a/chrome/browser/chromeos/status/network_menu_icon.h
+++ b/chrome/browser/chromeos/status/network_menu_icon.h
@@ -35,7 +35,7 @@
 
 #include "ash/system/chromeos/network/network_icon_animation_observer.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/chromeos/cros/network_library.h"
 #include "ui/gfx/image/image_skia.h"
 
diff --git a/chrome/browser/chromeos/swap_metrics.cc b/chrome/browser/chromeos/swap_metrics.cc
new file mode 100644
index 0000000..6b25be0
--- /dev/null
+++ b/chrome/browser/chromeos/swap_metrics.cc
@@ -0,0 +1,432 @@
+// 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/swap_metrics.h"
+
+#include <string>
+#include <vector>
+
+#include "ash/shell.h"
+#include "base/file_util.h"
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/metrics/histogram.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/synchronization/cancellation_flag.h"
+#include "base/sys_info.h"
+#include "base/threading/sequenced_worker_pool.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_list.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "content/public/browser/browser_thread.h"
+#include "ui/base/events/event.h"
+
+using base::FilePath;
+
+namespace chromeos {
+namespace {
+
+// Time delays for metrics collections, starting after an interesting UI event.
+// Times are relative to the UI event. Start with zero to record the initial
+// state of the metrics immediately.
+const int kMetricsDelayMs[] = { 0, 100, 300, 1000, 3000 };
+
+}  // namespace
+
+///////////////////////////////////////////////////////////////////////////////
+
+// Runs in the blocking thread pool to load metrics and record them.
+// Reads data about CPU utilization and swap activity from the /proc and /sys
+// file systems. Owned by SwapMetrics on the UI thread.
+class SwapMetrics::Backend : public base::RefCountedThreadSafe<Backend> {
+ public:
+  explicit Backend(const std::string& reason);
+
+  // Records one set of statistics for |time_index| after the interesting
+  // event. May trigger another delayed task to record more statistics.
+  void RecordMetricsOnBlockingPool(size_t time_index);
+
+  // Sets the thread-safe cancellation flag.
+  void CancelOnUIThread() { cancelled_.Set(); }
+
+ private:
+  friend class base::RefCountedThreadSafe<Backend>;
+
+  virtual ~Backend();
+
+  // Extracts a field value from a list of name-value pairs
+  // in a file (typically a /proc or /sys file). Returns false
+  // if the field is not found, or for other errors.
+  bool GetFieldFromKernelOutput(const std::string& path,
+                                const std::string& field,
+                                int64* value);
+
+  // Reads a file whose content is a single line, and returns its content as a
+  // list of tokens. |expected_tokens_count| is the expected number of tokens.
+  // |delimiters| is a string containing characters that may appear between
+  // tokens. Returns true on success, false otherwise.
+  bool TokenizeOneLineFile(const std::string& path,
+                           size_t expected_tokens_count,
+                           const std::string& delimiters,
+                           std::vector<std::string>* tokens);
+
+  // Retrieve various system metrics. Return true on success.
+  bool GetMeminfoField(const std::string& field, int64* value);
+  bool GetUptime(double* uptime_secs, double* idle_time_secs);
+  bool GetPageFaults(int64* page_faults);
+
+  // Record histogram samples.
+  void RecordFaultsHistogramSample(int faults,
+                                   const std::string& reason,
+                                   int swap_group,
+                                   int time_index);
+  void RecordCpuHistogramSample(int cpu,
+                                const std::string& reason,
+                                int swap_group,
+                                int time_index);
+
+  // Cancellation flag that can be written from the UI thread (which owns this
+  // object) and read from any thread.
+  base::CancellationFlag cancelled_;
+
+  // Data initialized once and shared by all instances of this class.
+  static bool first_time_;
+  static int64 swap_total_kb_;
+  static int number_of_cpus_;
+
+  // Values at the beginning of each sampling interval.
+  double last_uptime_secs_;
+  double last_idle_time_secs_;
+  int64 last_page_faults_;
+
+  // Swap group for a set of samples, chosen at the beginning of the set.
+  int swap_group_;
+
+  // Reason for sampling.
+  const std::string reason_;
+
+  DISALLOW_COPY_AND_ASSIGN(Backend);
+};
+
+// static
+bool SwapMetrics::Backend::first_time_ = true;
+// static
+int64 SwapMetrics::Backend::swap_total_kb_ = 0;
+// static
+int SwapMetrics::Backend::number_of_cpus_ = 0;
+
+SwapMetrics::Backend::Backend(const std::string& reason)
+    : last_uptime_secs_(0.0),
+      last_idle_time_secs_(0.0),
+      last_page_faults_(0),
+      swap_group_(0),
+      reason_(reason) {
+}
+
+SwapMetrics::Backend::~Backend() {
+}
+
+void SwapMetrics::Backend::RecordMetricsOnBlockingPool(size_t time_index) {
+  DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
+  // Another UI event might have occurred. Don't run this metrics collection
+  // and don't post another task. This object's refcount will drop and it will
+  // be deleted when the next backend is created on the UI thread.
+  if (cancelled_.IsSet())
+    return;
+  DVLOG(1) << "RecordMetricsInBlockingPool " << time_index;
+
+  // At init time, get the number of cpus and the total swap. The number of cpus
+  // is necessary because the idle time reported is the sum of the idle
+  // times of all cpus.
+  //
+  // When an event occurs:
+  // - At time t_0, save the initial values for uptime, idle_time, page_faults,
+  //   and swap used.
+  //
+  // - At time t_i, compute cpu utilization as a fraction (1 = fully utilized):
+  //  utilization =
+  //      1 - (idle_time_i - idle_time_0) / (uptime_i - uptime_0) / ncpus
+  //
+  // then UMA-report it in the right swap group. Do the same for page faults.
+
+  if (first_time_) {
+    first_time_ = false;
+    number_of_cpus_ = base::SysInfo::NumberOfProcessors();
+    // Avoid divide by zero in case of errors.
+    if (number_of_cpus_ == 0)
+      number_of_cpus_ = 1;
+    GetMeminfoField("SwapTotal:", &swap_total_kb_);
+  }
+
+  if (time_index == 0) {
+    // Record baseline data.
+    GetUptime(&last_uptime_secs_, &last_idle_time_secs_);
+    GetPageFaults(&last_page_faults_);
+    int64 swap_free_kb = 0;
+    GetMeminfoField("SwapFree:", &swap_free_kb);
+    int swap_percent = swap_total_kb_ > 0
+        ? (swap_total_kb_ - swap_free_kb) * 100 / swap_total_kb_
+        : 0;
+    if (swap_percent < 10)
+      swap_group_ = 0;
+    else if (swap_percent < 30)
+      swap_group_ = 1;
+    else if (swap_percent < 60)
+      swap_group_ = 2;
+    else
+      swap_group_ = 3;
+  } else {
+    int64 page_faults = 0;
+    double idle_time_secs = 0.0;
+    double uptime_secs = 0.0;
+    GetUptime(&uptime_secs, &idle_time_secs);
+    GetPageFaults(&page_faults);
+    double delta_time_secs = uptime_secs - last_uptime_secs_;
+    // Unexpected, but not worth agonizing over it.
+    if (delta_time_secs == 0)
+      return;
+
+    int cpu = (1.0 - (idle_time_secs - last_idle_time_secs_) /
+               delta_time_secs / number_of_cpus_) * 100;
+    int faults_per_sec = (page_faults - last_page_faults_) / delta_time_secs;
+
+    RecordCpuHistogramSample(cpu, reason_, swap_group_, time_index);
+    RecordFaultsHistogramSample(faults_per_sec, reason_,
+                                swap_group_, time_index);
+
+    last_uptime_secs_ = uptime_secs;
+    last_page_faults_ = page_faults;
+    last_idle_time_secs_ = idle_time_secs;
+  }
+
+  // Check if another metrics recording is needed.
+  if (++time_index >= arraysize(kMetricsDelayMs))
+    return;
+  PostTaskRecordMetrics(
+      scoped_refptr<Backend>(this),
+      time_index,
+      kMetricsDelayMs[time_index] - kMetricsDelayMs[time_index - 1]);
+}
+
+void SwapMetrics::Backend::RecordFaultsHistogramSample(
+    int faults,
+    const std::string& reason,
+    int swap_group,
+    int time_index) {
+  std::string name =
+      base::StringPrintf("Platform.SwapJank.%s.Faults.Swap%d.Time%d",
+                         reason.c_str(),
+                         swap_group,
+                         time_index);
+  const int kMinimumBucket = 10;
+  const int kMaximumBucket = 200000;
+  const size_t kBucketCount = 50;
+  base::HistogramBase* counter =
+      base::Histogram::FactoryGet(name,
+                                  kMinimumBucket,
+                                  kMaximumBucket,
+                                  kBucketCount,
+                                  base::Histogram::kUmaTargetedHistogramFlag);
+  counter->Add(faults);
+}
+
+void SwapMetrics::Backend::RecordCpuHistogramSample(int cpu,
+                                                    const std::string& reason,
+                                                    int swap_group,
+                                                    int time_index) {
+  std::string name =
+      base::StringPrintf("Platform.SwapJank.%s.Cpu.Swap%d.Time%d",
+                         reason.c_str(),
+                         swap_group,
+                         time_index);
+  const int kMinimumBucket = 0;
+  const int kMaximumBucket = 101;
+  const size_t kBucketCount = 102;
+  base::HistogramBase* counter = base::LinearHistogram::FactoryGet(
+      name,
+      kMinimumBucket,
+      kMaximumBucket,
+      kBucketCount,
+      base::Histogram::kUmaTargetedHistogramFlag);
+  counter->Add(cpu);
+}
+
+// Extracts a field value from a list of name-value pairs
+// in a file (typically a /proc or /sys file). Returns false
+// if the field is not found, or for other errors.
+bool SwapMetrics::Backend::GetFieldFromKernelOutput(const std::string& path,
+                                                    const std::string& field,
+                                                    int64* value) {
+  std::string file_content;
+  if (!file_util::ReadFileToString(FilePath(path), &file_content)) {
+    LOG(WARNING) << "Cannot read " << path;
+    return false;
+  }
+  std::vector<std::string> lines;
+  size_t line_count = Tokenize(file_content, "\n", &lines);
+  if (line_count < 2) {
+    LOG(WARNING) << "Error breaking " << path << " into lines";
+    return false;
+  }
+  for (size_t i = 0; i < line_count; ++i) {
+    std::vector<std::string> tokens;
+    size_t token_count = Tokenize(lines[i], " ", &tokens);
+    if (token_count < 2) {
+      LOG(WARNING) << "Unexpected line: " << lines[i];
+      return false;
+    }
+    if (tokens[0].compare(field) != 0)
+      continue;
+    if (!base::StringToInt64(tokens[1], value)) {
+      LOG(WARNING) << "Cannot convert " << tokens[1] << " to int";
+      return false;
+    }
+    return true;
+  }
+  LOG(WARNING) << "could not find field " << field;
+  return false;
+}
+
+bool SwapMetrics::Backend::TokenizeOneLineFile(const std::string& path,
+                                               size_t expected_tokens_count,
+                                               const std::string& delimiters,
+                                               std::vector<std::string>*
+                                               tokens) {
+  std::string file_content;
+  if (!file_util::ReadFileToString(FilePath(path), &file_content)) {
+    LOG(WARNING) << "cannot read " << path;
+    return false;
+  }
+  size_t tokens_count = Tokenize(file_content, delimiters, tokens);
+  if (tokens_count != expected_tokens_count) {
+    LOG(WARNING) << "unexpected content of " << path << ": " << file_content;
+    return false;
+  }
+  return true;
+}
+
+bool SwapMetrics::Backend::GetMeminfoField(const std::string& name,
+                                           int64* value) {
+  return GetFieldFromKernelOutput("/proc/meminfo", name, value);
+}
+
+bool SwapMetrics::Backend::GetUptime(double* uptime_secs,
+                                     double* idle_time_secs) {
+  // Get the time since boot.
+  const char kUptimePath[] = "/proc/uptime";
+  std::vector<std::string> tokens;
+  if (!TokenizeOneLineFile(kUptimePath, 2, " \n", &tokens))
+    return false;
+
+  if (!base::StringToDouble(tokens[0], uptime_secs)) {
+    LOG(WARNING) << "cannot convert " << tokens[0] << " to double";
+    return false;
+  }
+
+  // Get the idle time since boot. The number available in /proc/stat is more
+  // precise, but this one should be good enough.
+  if (!base::StringToDouble(tokens[1], idle_time_secs)) {
+    LOG(WARNING) << "cannot convert " << tokens[0] << " to double";
+    return false;
+  }
+  return true;
+}
+
+bool SwapMetrics::Backend::GetPageFaults(int64* page_faults) {
+  // Get number of page faults.
+  return GetFieldFromKernelOutput("/proc/vmstat", "pgmajfault", page_faults);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+SwapMetrics::SwapMetrics() : browser_(NULL) {
+  ash::Shell::GetInstance()->AddPreTargetHandler(this);
+  BrowserList::AddObserver(this);
+}
+
+SwapMetrics::~SwapMetrics() {
+  if (backend_)
+    backend_->CancelOnUIThread();
+  ash::Shell::GetInstance()->RemovePreTargetHandler(this);
+  BrowserList::RemoveObserver(this);
+  SetBrowser(NULL);
+}
+
+void SwapMetrics::OnBrowserRemoved(Browser* browser) {
+  if (browser_ == browser)
+    SetBrowser(NULL);
+}
+
+void SwapMetrics::OnBrowserSetLastActive(Browser* browser) {
+  if (browser && browser->type() == Browser::TYPE_TABBED)
+    SetBrowser(browser);
+  else
+    SetBrowser(NULL);
+}
+
+void SwapMetrics::ActiveTabChanged(content::WebContents* old_contents,
+                                   content::WebContents* new_contents,
+                                   int index,
+                                   int reason) {
+  // Only measure tab switches, not tabs being replaced with new contents.
+  if (reason != TabStripModelObserver::CHANGE_REASON_USER_GESTURE)
+    return;
+  DVLOG(1) << "ActiveTabChanged";
+  StartMetricsCollection("TabSwitch");
+}
+
+// This exists primarily for debugging on desktop builds.
+void SwapMetrics::OnMouseEvent(ui::MouseEvent* event) {
+  if (event->type() != ui::ET_MOUSEWHEEL)
+    return;
+  DVLOG(1) << "OnMouseEvent";
+  StartMetricsCollection("Scroll");
+}
+
+void SwapMetrics::OnScrollEvent(ui::ScrollEvent* event) {
+  if (event->type() != ui::ET_SCROLL &&
+      event->type() != ui::ET_SCROLL_FLING_START)
+    return;
+  DVLOG(1) << "OnScrollEvent";
+  StartMetricsCollection("Scroll");
+}
+
+// static
+void SwapMetrics::PostTaskRecordMetrics(scoped_refptr<Backend> backend,
+                                        size_t time_index,
+                                        int delay_ms) {
+  // Don't block shutdown on these tasks, as UMA will be disappearing.
+  scoped_refptr<base::TaskRunner> runner =
+      content::BrowserThread::GetBlockingPool()->
+          GetTaskRunnerWithShutdownBehavior(
+                base::SequencedWorkerPool::SKIP_ON_SHUTDOWN);
+  runner->PostDelayedTask(
+      FROM_HERE,
+      base::Bind(&SwapMetrics::Backend::RecordMetricsOnBlockingPool,
+                 backend,
+                 time_index),
+      base::TimeDelta::FromMilliseconds(delay_ms));
+}
+
+void SwapMetrics::StartMetricsCollection(const std::string& reason) {
+  // Cancel any existing metrics run.
+  if (backend_)
+    backend_->CancelOnUIThread();
+  backend_ = new Backend(reason);
+  PostTaskRecordMetrics(backend_, 0, kMetricsDelayMs[0]);
+}
+
+void SwapMetrics::SetBrowser(Browser* browser) {
+  if (browser_ == browser)
+    return;
+  if (browser_)
+    browser_->tab_strip_model()->RemoveObserver(this);
+  browser_ = browser;
+  if (browser_)
+    browser_->tab_strip_model()->AddObserver(this);
+}
+
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/swap_metrics.h b/chrome/browser/chromeos/swap_metrics.h
new file mode 100644
index 0000000..ccda9db
--- /dev/null
+++ b/chrome/browser/chromeos/swap_metrics.h
@@ -0,0 +1,72 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_SWAP_METRICS_H_
+#define CHROME_BROWSER_CHROMEOS_SWAP_METRICS_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/memory/ref_counted.h"
+#include "chrome/browser/ui/browser_list_observer.h"
+#include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
+#include "ui/base/events/event_handler.h"
+
+namespace base {
+class FilePath;
+}
+
+namespace chromeos {
+
+// Watches for bursts of swap activity and CPU consumption after interesting UI
+// events like tab switch or scrolling, recording the values to UMA statistics.
+// Only records stats for the last active browser.
+class SwapMetrics : public chrome::BrowserListObserver,
+                    public TabStripModelObserver,
+                    public ui::EventHandler {
+ public:
+  SwapMetrics();
+  virtual ~SwapMetrics();
+
+  // chrome::BrowserListObserver overrides:
+  virtual void OnBrowserRemoved(Browser* browser) OVERRIDE;
+  virtual void OnBrowserSetLastActive(Browser* browser) OVERRIDE;
+
+  // TabStripModelObserver overrides:
+  virtual void ActiveTabChanged(content::WebContents* old_contents,
+                                content::WebContents* new_contents,
+                                int index,
+                                int reason) OVERRIDE;
+
+  // ui::EventHandler overrides:
+  virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE;
+  virtual void OnScrollEvent(ui::ScrollEvent* event) OVERRIDE;
+
+ private:
+  class Backend;
+
+  // Posts a task to record metrics for |sample_index| after |delay_ms|.
+  static void PostTaskRecordMetrics(scoped_refptr<Backend> backend,
+                                    size_t sample_index,
+                                    int delay_ms);
+
+  // Starts a metrics collection run, canceling any run already in progress.
+  void StartMetricsCollection(const std::string& reason);
+
+  // Sets the browser being monitored for events.
+  void SetBrowser(Browser* browser);
+
+  // Browser being monitored for UI events.
+  Browser* browser_;
+
+  // Backend to handle processing in the blocking thread pool.
+  scoped_refptr<Backend> backend_;
+
+  DISALLOW_COPY_AND_ASSIGN(SwapMetrics);
+};
+
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_CHROMEOS_SWAP_METRICS_H_
diff --git a/chrome/browser/chromeos/system/ash_system_tray_delegate.cc b/chrome/browser/chromeos/system/ash_system_tray_delegate.cc
index d17df61..f4a6030 100644
--- a/chrome/browser/chromeos/system/ash_system_tray_delegate.cc
+++ b/chrome/browser/chromeos/system/ash_system_tray_delegate.cc
@@ -43,7 +43,7 @@
 #include "base/prefs/pref_service.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chromeos/accessibility/accessibility_manager.h"
 #include "chrome/browser/chromeos/accessibility/magnification_manager.h"
@@ -84,6 +84,7 @@
 #include "chrome/browser/ui/chrome_pages.h"
 #include "chrome/browser/ui/host_desktop.h"
 #include "chrome/browser/ui/singleton_tabs.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/upgrade_detector.h"
 #include "chrome/common/chrome_notification_types.h"
 #include "chrome/common/pref_names.h"
@@ -104,6 +105,7 @@
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/user_metrics.h"
+#include "content/public/browser/web_contents.h"
 #include "device/bluetooth/bluetooth_adapter.h"
 #include "device/bluetooth/bluetooth_adapter_factory.h"
 #include "device/bluetooth/bluetooth_device.h"
@@ -127,6 +129,9 @@
 // The maximum session length limit that can be set.
 const int kSessionLengthLimitMaxMs = 24 * 60 * 60 * 1000;  // 24 hours.
 
+const char kDisplaySettingsSubPageName[] = "display";
+const char kDisplayOverscanSettingsSubPageName[] = "displayOverscan";
+
 void ExtractIMEInfo(const input_method::InputMethodDescriptor& ime,
                     const input_method::InputMethodUtil& util,
                     ash::IMEInfo* info) {
@@ -464,12 +469,18 @@
         chromeos::UserManager::Get()->GetActiveUser()->email());
   }
 
+  virtual const string16 GetLocallyManagedUserManagerName() const OVERRIDE {
+    if (GetUserLoginStatus() != ash::user::LOGGED_IN_LOCALLY_MANAGED)
+      return string16();
+    return UserManager::Get()->GetManagerDisplayNameForManagedUser(
+        chromeos::UserManager::Get()->GetActiveUser()->email());
+  }
+
   virtual const string16 GetLocallyManagedUserMessage() const OVERRIDE {
     if (GetUserLoginStatus() != ash::user::LOGGED_IN_LOCALLY_MANAGED)
         return string16();
     return l10n_util::GetStringFUTF16(IDS_USER_IS_LOCALLY_MANAGED_BY_NOTICE,
-                                      UTF8ToUTF16(
-                                          GetLocallyManagedUserManager()));
+                                      GetLocallyManagedUserManagerName());
   }
 
   virtual bool SystemShouldUpgrade() const OVERRIDE {
@@ -520,7 +531,32 @@
 
   virtual void ShowDisplaySettings() OVERRIDE {
     content::RecordAction(content::UserMetricsAction("ShowDisplayOptions"));
-    chrome::ShowSettingsSubPage(GetAppropriateBrowser(), "display");
+    chrome::ShowSettingsSubPage(GetAppropriateBrowser(),
+                                kDisplaySettingsSubPageName);
+  }
+
+  virtual bool ShouldShowDisplayNotification() OVERRIDE {
+    // Packaged app is not counted as 'last active', so if a browser opening the
+    // display settings is in background of a packaged app, it will return true.
+    // TODO(mukai): fix this.
+    Browser* active_browser = chrome::FindLastActiveWithHostDesktopType(
+        chrome::HOST_DESKTOP_TYPE_ASH);
+    if (!active_browser)
+      return true;
+
+    content::WebContents* active_contents =
+        active_browser->tab_strip_model()->GetActiveWebContents();
+    if (!active_contents)
+      return true;
+
+    GURL active_url = active_contents->GetActiveURL();
+    std::string display_settings_url =
+        std::string(chrome::kChromeUISettingsURL) + kDisplaySettingsSubPageName;
+    std::string display_overscan_url =
+        std::string(chrome::kChromeUISettingsURL) +
+        kDisplayOverscanSettingsSubPageName;
+    return (active_url.spec() != display_settings_url) &&
+        (active_url.spec() != display_overscan_url);
   }
 
   virtual void ShowDriveSettings() OVERRIDE {
diff --git a/chrome/browser/chromeos/system/automatic_reboot_manager.cc b/chrome/browser/chromeos/system/automatic_reboot_manager.cc
index b13db1c..c77d06e 100644
--- a/chrome/browser/chromeos/system/automatic_reboot_manager.cc
+++ b/chrome/browser/chromeos/system/automatic_reboot_manager.cc
@@ -33,6 +33,7 @@
 #include "base/time/tick_clock.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chromeos/login/user_manager.h"
+#include "chrome/browser/chromeos/system/automatic_reboot_manager_observer.h"
 #include "chrome/common/chrome_notification_types.h"
 #include "chrome/common/pref_names.h"
 #include "chromeos/chromeos_paths.h"
@@ -194,6 +195,10 @@
 }
 
 AutomaticRebootManager::~AutomaticRebootManager() {
+  FOR_EACH_OBSERVER(AutomaticRebootManagerObserver,
+                    observers_,
+                    WillDestroyAutomaticRebootManager());
+
   DBusThreadManager* dbus_thread_manager = DBusThreadManager::Get();
   dbus_thread_manager->GetPowerManagerClient()->RemoveObserver(this);
   dbus_thread_manager->GetUpdateEngineClient()->RemoveObserver(this);
@@ -201,6 +206,16 @@
     ash::Shell::GetInstance()->user_activity_detector()->RemoveObserver(this);
 }
 
+void AutomaticRebootManager::AddObserver(
+    AutomaticRebootManagerObserver* observer) {
+  observers_.AddObserver(observer);
+}
+
+void AutomaticRebootManager::RemoveObserver(
+    AutomaticRebootManagerObserver* observer) {
+  observers_.RemoveObserver(observer);
+}
+
 void AutomaticRebootManager::SystemResumed(
     const base::TimeDelta& sleep_duration) {
   MaybeReboot(true);
@@ -303,6 +318,8 @@
   reboot_requested_ = false;
 
   const base::TimeDelta kZeroTimeDelta;
+  AutomaticRebootManagerObserver::Reason reboot_reason =
+      AutomaticRebootManagerObserver::REBOOT_REASON_UNKNOWN;
 
   // If an uptime limit is set, calculate the time at which it should cause a
   // reboot to be requested.
@@ -310,6 +327,8 @@
       local_state_registrar_.prefs()->GetInteger(prefs::kUptimeLimit));
   base::TimeTicks reboot_request_time = boot_time_ + uptime_limit;
   bool have_reboot_request_time = uptime_limit != kZeroTimeDelta;
+  if (have_reboot_request_time)
+    reboot_reason = AutomaticRebootManagerObserver::REBOOT_REASON_PERIODIC;
 
   // If the policy to automatically reboot after an update is enabled and an
   // update has been applied, set the time at which a reboot should be
@@ -321,6 +340,7 @@
        update_reboot_needed_time_ < reboot_request_time)) {
     reboot_request_time = update_reboot_needed_time_;
     have_reboot_request_time = true;
+    reboot_reason = AutomaticRebootManagerObserver::REBOOT_REASON_OS_UPDATE;
   }
 
   // If no reboot should be requested, remove any grace period.
@@ -355,6 +375,12 @@
                           std::max(grace_end_time - now, kZeroTimeDelta),
                           base::Bind(&AutomaticRebootManager::Reboot,
                                      base::Unretained(this)));
+
+  DCHECK_NE(AutomaticRebootManagerObserver::REBOOT_REASON_UNKNOWN,
+            reboot_reason);
+  FOR_EACH_OBSERVER(AutomaticRebootManagerObserver,
+                    observers_,
+                    OnRebootScheduled(reboot_reason));
 }
 
 void AutomaticRebootManager::RequestReboot() {
diff --git a/chrome/browser/chromeos/system/automatic_reboot_manager.h b/chrome/browser/chromeos/system/automatic_reboot_manager.h
index 9d29262..faafcd4 100644
--- a/chrome/browser/chromeos/system/automatic_reboot_manager.h
+++ b/chrome/browser/chromeos/system/automatic_reboot_manager.h
@@ -10,9 +10,10 @@
 #include "base/compiler_specific.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
+#include "base/observer_list.h"
 #include "base/prefs/pref_change_registrar.h"
-#include "base/time.h"
-#include "base/timer.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
 #include "chromeos/dbus/power_manager_client.h"
 #include "chromeos/dbus/update_engine_client.h"
 #include "content/public/browser/notification_observer.h"
@@ -27,6 +28,8 @@
 namespace chromeos {
 namespace system {
 
+class AutomaticRebootManagerObserver;
+
 // Schedules and executes automatic reboots.
 //
 // Automatic reboots may be scheduled for any number of reasons. Currently, the
@@ -90,6 +93,9 @@
   explicit AutomaticRebootManager(scoped_ptr<base::TickClock> clock);
   virtual ~AutomaticRebootManager();
 
+  void AddObserver(AutomaticRebootManagerObserver* observer);
+  void RemoveObserver(AutomaticRebootManagerObserver* observer);
+
   // PowerManagerClient::Observer:
   virtual void SystemResumed(const base::TimeDelta& sleep_duration) OVERRIDE;
 
@@ -160,6 +166,8 @@
 
   base::WeakPtrFactory<AutomaticRebootManager> weak_ptr_factory_;
 
+  ObserverList<AutomaticRebootManagerObserver, true> observers_;
+
   DISALLOW_COPY_AND_ASSIGN(AutomaticRebootManager);
 };
 
diff --git a/chrome/browser/chromeos/system/automatic_reboot_manager_observer.h b/chrome/browser/chromeos/system/automatic_reboot_manager_observer.h
new file mode 100644
index 0000000..67c1b50
--- /dev/null
+++ b/chrome/browser/chromeos/system/automatic_reboot_manager_observer.h
@@ -0,0 +1,32 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_SYSTEM_AUTOMATIC_REBOOT_MANAGER_OBSERVER_H_
+#define CHROME_BROWSER_CHROMEOS_SYSTEM_AUTOMATIC_REBOOT_MANAGER_OBSERVER_H_
+
+namespace chromeos {
+namespace system {
+
+class AutomaticRebootManagerObserver {
+ public:
+  enum Reason {
+    REBOOT_REASON_UNKNOWN,
+    REBOOT_REASON_OS_UPDATE,
+    REBOOT_REASON_PERIODIC,
+  };
+
+  // Invoked when a reboot is scheduled.
+  virtual void OnRebootScheduled(Reason reason) = 0;
+
+  // Invoked before the automatic reboot manager is destroyed.
+  virtual void WillDestroyAutomaticRebootManager() = 0;
+
+ protected:
+  virtual ~AutomaticRebootManagerObserver() {}
+};
+
+}  // namespace system
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_CHROMEOS_SYSTEM_AUTOMATIC_REBOOT_MANAGER_OBSERVER_H_
diff --git a/chrome/browser/chromeos/system/input_device_settings.cc b/chrome/browser/chromeos/system/input_device_settings.cc
index 261dca1..68e6f01 100644
--- a/chrome/browser/chromeos/system/input_device_settings.cc
+++ b/chrome/browser/chromeos/system/input_device_settings.cc
@@ -14,6 +14,7 @@
 #include "base/file_util.h"
 #include "base/files/file_path.h"
 #include "base/message_loop.h"
+#include "base/process.h"
 #include "base/process_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/threading/sequenced_worker_pool.h"
@@ -23,6 +24,7 @@
 namespace system {
 
 namespace {
+
 const char kTpControl[] = "/opt/google/touchpad/tpcontrol";
 const char kMouseControl[] = "/opt/google/mouse/mousecontrol";
 
@@ -43,9 +45,9 @@
   if (!ScriptExists(script))
     return;
 
-  base::LaunchOptions options;
-  options.wait = true;
-  base::LaunchProcess(CommandLine(argv), options, NULL);
+  base::ProcessHandle handle;
+  base::LaunchProcess(CommandLine(argv), base::LaunchOptions(), &handle);
+  base::EnsureProcessGetsReaped(handle);
 }
 
 void ExecuteScript(int argc, ...) {
@@ -64,7 +66,7 @@
 
 void SetPointerSensitivity(const char* script, int value) {
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
-  DCHECK(value > 0 && value < 6);
+  DCHECK(value >= kMinPointerSensitivity && value <= kMaxPointerSensitivity);
   ExecuteScript(
       3, script, "sensitivity", base::StringPrintf("%d", value).c_str());
 }
diff --git a/chrome/browser/chromeos/system/input_device_settings.h b/chrome/browser/chromeos/system/input_device_settings.h
index 5116f92..821c179 100644
--- a/chrome/browser/chromeos/system/input_device_settings.h
+++ b/chrome/browser/chromeos/system/input_device_settings.h
@@ -10,6 +10,11 @@
 namespace chromeos {
 namespace system {
 
+// Min/max possible pointer sensitivity values. Defined in CrOS inputcontrol
+// scripts (see kTpControl/kMouseControl in the source file).
+const int kMinPointerSensitivity = 1;
+const int kMaxPointerSensitivity = 5;
+
 typedef base::Callback<void(bool)> DeviceExistsCallback;
 
 namespace touchpad_settings {
diff --git a/chrome/browser/chromeos/system/statistics_provider.cc b/chrome/browser/chromeos/system/statistics_provider.cc
index 5f82b2a..e58278b 100644
--- a/chrome/browser/chromeos/system/statistics_provider.cc
+++ b/chrome/browser/chromeos/system/statistics_provider.cc
@@ -13,7 +13,7 @@
 #include "base/path_service.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/threading/thread_restrictions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chromeos/app_mode/kiosk_oem_manifest_parser.h"
 #include "chromeos/chromeos_constants.h"
 #include "chromeos/chromeos_switches.h"
@@ -75,6 +75,22 @@
 
 }  // namespace
 
+// Key values for GetMachineStatistic()/GetMachineFlag() calls.
+const char kDevSwitchBootMode[] = "devsw_boot";
+const char kHardwareClass[] = "hardware_class";
+const char kMachineInfoBoard[] =
+    "CHROMEOS_RELEASE_BOARD";
+const char kOffersCouponCodeKey[] = "ubind_attribute";
+const char kOffersGroupCodeKey[] = "gbind_attribute";
+const char kOemCanExitEnterpriseEnrollmentKey[] =
+    "oem_can_exit_enrollment";
+const char kOemDeviceRequisitionKey[] =
+    "oem_device_requisition";
+const char kOemIsEnterpriseManagedKey[] =
+    "oem_enterprise_managed";
+const char kOemKeyboardDrivenOobeKey[] =
+    "oem_keyboard_driven_oobe";
+
 // The StatisticsProvider implementation used in production.
 class StatisticsProviderImpl : public StatisticsProvider {
  public:
@@ -252,13 +268,13 @@
   if (!KioskOemManifestParser::Load(file, &oem_manifest))
     return;
 
-  machine_info_[chromeos::kOemDeviceRequisitionKey] =
+  machine_info_[kOemDeviceRequisitionKey] =
       oem_manifest.device_requisition;
-  machine_flags_[chromeos::kOemIsEnterpriseManagedKey] =
+  machine_flags_[kOemIsEnterpriseManagedKey] =
       oem_manifest.enterprise_managed;
-  machine_flags_[chromeos::kOemCanExitEnterpriseEnrollmentKey] =
+  machine_flags_[kOemCanExitEnterpriseEnrollmentKey] =
       oem_manifest.can_exit_enrollment;
-  machine_flags_[chromeos::kOemKeyboardDrivenOobeKey] =
+  machine_flags_[kOemKeyboardDrivenOobeKey] =
       oem_manifest.keyboard_driven_oobe;
 }
 
diff --git a/chrome/browser/chromeos/system/statistics_provider.h b/chrome/browser/chromeos/system/statistics_provider.h
index b193563..48e7dd8 100644
--- a/chrome/browser/chromeos/system/statistics_provider.h
+++ b/chrome/browser/chromeos/system/statistics_provider.h
@@ -10,6 +10,35 @@
 namespace chromeos {
 namespace system {
 
+// Developer switch value.
+extern const char kDevSwitchBootMode[];
+
+// HWID key.
+extern const char kHardwareClass[];
+
+// Machine board key.
+extern const char kMachineInfoBoard[];
+
+// OEM customization flag that permits exiting enterprise enrollment flow in
+// OOBE when 'oem_enterprise_managed' flag is set.
+extern const char kOemCanExitEnterpriseEnrollmentKey[];
+
+// OEM customization directive that specified intended device purpose.
+extern const char kOemDeviceRequisitionKey[];
+
+// OEM customization flag that enforces enterprise enrollment flow in OOBE.
+extern const char kOemIsEnterpriseManagedKey[];
+
+// OEM customization flag that specifies if OOBE flow should be enhanced for
+// keyboard driven control.
+extern const char kOemKeyboardDrivenOobeKey[];
+
+// Offer coupon code key.
+extern const char kOffersCouponCodeKey[];
+
+// Offer group key.
+extern const char kOffersGroupCodeKey[];
+
 // This interface provides access to Chrome OS statistics.
 class StatisticsProvider {
  public:
diff --git a/chrome/browser/chromeos/system/syslogs_provider.cc b/chrome/browser/chromeos/system/syslogs_provider.cc
index 1c7e06a..643d355 100644
--- a/chrome/browser/chromeos/system/syslogs_provider.cc
+++ b/chrome/browser/chromeos/system/syslogs_provider.cc
@@ -146,7 +146,7 @@
                                                   &data);
   // if we were using an internal temp file, the user does not need the
   // logs to stay past the ReadFile call - delete the file
-  file_util::Delete(temp_filename, false);
+  base::Delete(temp_filename, false);
 
   if (!read_success)
     return NULL;
@@ -321,7 +321,7 @@
     // Load compressed logs.
     zip_content = new std::string();
     LoadCompressedLogs(zip_file, zip_content);
-    file_util::Delete(zip_file, false);
+    base::Delete(zip_file, false);
   }
 
   // Include dbus statistics summary
diff --git a/chrome/browser/chromeos/system/timezone_settings.cc b/chrome/browser/chromeos/system/timezone_settings.cc
index 4f59057..5aa6593 100644
--- a/chrome/browser/chromeos/system/timezone_settings.cc
+++ b/chrome/browser/chromeos/system/timezone_settings.cc
@@ -208,7 +208,7 @@
   }
 
   // Delete old symlink2 if it exists.
-  file_util::Delete(timezone_symlink2, false);
+  base::Delete(timezone_symlink2, false);
 
   // Create new symlink2.
   if (symlink(timezone_file.value().c_str(),
@@ -219,7 +219,7 @@
   }
 
   // Move symlink2 to symlink.
-  if (!file_util::ReplaceFile(timezone_symlink2, timezone_symlink)) {
+  if (!base::ReplaceFile(timezone_symlink2, timezone_symlink, NULL)) {
     LOG(ERROR) << "SetTimezoneID: Unable to move symlink "
                << timezone_symlink2.value() << " to "
                << timezone_symlink.value();
@@ -352,21 +352,12 @@
 }
 
 void TimezoneSettingsBaseImpl::NotifyRenderers() {
-  content::RenderProcessHost::iterator process_iterator(
-      content::RenderProcessHost::AllHostsIterator());
-  for (; !process_iterator.IsAtEnd(); process_iterator.Advance()) {
-    content::RenderProcessHost* render_process_host =
-        process_iterator.GetCurrentValue();
-    content::RenderProcessHost::RenderWidgetHostsIterator widget_iterator(
-        render_process_host->GetRenderWidgetHostsIterator());
-    for (; !widget_iterator.IsAtEnd(); widget_iterator.Advance()) {
-      const content::RenderWidgetHost* widget =
-          widget_iterator.GetCurrentValue();
-      if (widget->IsRenderView()) {
-        content::RenderViewHost* view = content::RenderViewHost::From(
-            const_cast<content::RenderWidgetHost*>(widget));
-        view->NotifyTimezoneChange();
-      }
+  content::RenderWidgetHost::List widgets =
+      content::RenderWidgetHost::GetRenderWidgetHosts();
+  for (size_t i = 0; i < widgets.size(); ++i) {
+    if (widgets[i]->IsRenderView()) {
+      content::RenderViewHost* view = content::RenderViewHost::From(widgets[i]);
+      view->NotifyTimezoneChange();
     }
   }
 }
diff --git a/chrome/browser/chromeos/system_logs/touch_log_source.cc b/chrome/browser/chromeos/system_logs/touch_log_source.cc
index 7e2b263..2acbdee 100644
--- a/chrome/browser/chromeos/system_logs/touch_log_source.cc
+++ b/chrome/browser/chromeos/system_logs/touch_log_source.cc
@@ -4,7 +4,7 @@
 
 #include "chrome/browser/chromeos/system_logs/touch_log_source.h"
 
-#include "ash/touch/touch_observer_hud.h"
+#include "ash/touch/touch_hud_debug.h"
 #include "base/json/json_string_value_serializer.h"
 #include "chrome/browser/feedback/feedback_util.h"
 #include "content/public/browser/browser_thread.h"
@@ -25,7 +25,7 @@
 
   SystemLogsResponse response;
   scoped_ptr<DictionaryValue> dictionary =
-      ash::internal::TouchObserverHUD::GetAllAsDictionary();
+      ash::internal::TouchHudDebug::GetAllAsDictionary();
   if (!dictionary->empty()) {
     std::string touch_log;
     JSONStringValueSerializer json(&touch_log);
diff --git a/chrome/browser/chromeos/ui/focus_ring_controller.cc b/chrome/browser/chromeos/ui/focus_ring_controller.cc
index 1c089de..6a9459a 100644
--- a/chrome/browser/chromeos/ui/focus_ring_controller.cc
+++ b/chrome/browser/chromeos/ui/focus_ring_controller.cc
@@ -27,8 +27,9 @@
 
   if (visible_) {
     views::WidgetFocusManager::GetInstance()->AddFocusChangeListener(this);
-    SetWidget(views::Widget::GetWidgetForNativeWindow(
-        ash::wm::GetActiveWindow()));
+    aura::Window* active_window = ash::wm::GetActiveWindow();
+    if (active_window)
+      SetWidget(views::Widget::GetWidgetForNativeWindow(active_window));
   } else {
     views::WidgetFocusManager::GetInstance()->RemoveFocusChangeListener(this);
     SetWidget(NULL);
@@ -86,7 +87,8 @@
 
 void FocusRingController::OnNativeFocusChange(gfx::NativeView focused_before,
                                               gfx::NativeView focused_now) {
-  views::Widget* widget = views::Widget::GetWidgetForNativeWindow(focused_now);
+  views::Widget* widget =
+      focused_now ? views::Widget::GetWidgetForNativeWindow(focused_now) : NULL;
   SetWidget(widget);
 }
 
diff --git a/chrome/browser/chromeos/ui/idle_logout_dialog_view.cc b/chrome/browser/chromeos/ui/idle_logout_dialog_view.cc
index 7d87000..63b9c7e 100644
--- a/chrome/browser/chromeos/ui/idle_logout_dialog_view.cc
+++ b/chrome/browser/chromeos/ui/idle_logout_dialog_view.cc
@@ -9,7 +9,7 @@
 #include "base/bind_helpers.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/chromeos/kiosk_mode/kiosk_mode_settings.h"
 #include "chrome/browser/ui/browser_list.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
diff --git a/chrome/browser/chromeos/ui/idle_logout_dialog_view.h b/chrome/browser/chromeos/ui/idle_logout_dialog_view.h
index 720f12d..f96cd64 100644
--- a/chrome/browser/chromeos/ui/idle_logout_dialog_view.h
+++ b/chrome/browser/chromeos/ui/idle_logout_dialog_view.h
@@ -7,7 +7,7 @@
 
 #include "base/gtest_prod_util.h"
 #include "base/memory/weak_ptr.h"
-#include "base/timer.h"
+#include "base/timer/timer.h"
 #include "ui/views/window/dialog_delegate.h"
 
 namespace base {
diff --git a/chrome/browser/chromeos/upgrade_detector_chromeos.h b/chrome/browser/chromeos/upgrade_detector_chromeos.h
index 62eb07a..f3853b7 100644
--- a/chrome/browser/chromeos/upgrade_detector_chromeos.h
+++ b/chrome/browser/chromeos/upgrade_detector_chromeos.h
@@ -6,7 +6,7 @@
 #define CHROME_BROWSER_CHROMEOS_UPGRADE_DETECTOR_CHROMEOS_H_
 
 #include "base/compiler_specific.h"
-#include "base/timer.h"
+#include "base/timer/timer.h"
 #include "chrome/browser/upgrade_detector.h"
 #include "chromeos/dbus/update_engine_client.h"
 
diff --git a/chrome/browser/chromeos/version_loader.cc b/chrome/browser/chromeos/version_loader.cc
index cd4aa04..5e65c26 100644
--- a/chrome/browser/chromeos/version_loader.cc
+++ b/chrome/browser/chromeos/version_loader.cc
@@ -16,7 +16,7 @@
 #include "base/strings/stringprintf.h"
 #include "base/threading/sequenced_worker_pool.h"
 #include "base/threading/thread.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/browser_process.h"
 #include "content/public/browser/browser_thread.h"
 
diff --git a/chrome/browser/collected_cookies_browsertest.cc b/chrome/browser/collected_cookies_browsertest.cc
index 539fcac..b26c17e 100644
--- a/chrome/browser/collected_cookies_browsertest.cc
+++ b/chrome/browser/collected_cookies_browsertest.cc
@@ -13,20 +13,13 @@
 #include "chrome/common/url_constants.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
-#include "net/test/spawned_test_server/spawned_test_server.h"
-
-namespace {
-
-const base::FilePath::CharType kDocRoot[] =
-    FILE_PATH_LITERAL("chrome/test/data");
-
-}  // namespace
+#include "net/test/embedded_test_server/embedded_test_server.h"
 
 typedef InProcessBrowserTest CollectedCookiesTest;
 
 // If this crashes on Windows, use http://crbug.com/79331
 IN_PROC_BROWSER_TEST_F(CollectedCookiesTest, DoubleDisplay) {
-  ASSERT_TRUE(test_server()->Start());
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
 
   // Disable cookies.
   CookieSettings::Factory::GetForProfile(browser()->profile())->
@@ -34,7 +27,7 @@
 
   // Load a page with cookies.
   ui_test_utils::NavigateToURL(
-      browser(), test_server()->GetURL("files/cookie1.html"));
+      browser(), embedded_test_server()->GetURL("/cookie1.html"));
 
   // Click on the info link twice.
   content::WebContents* web_contents =
@@ -52,7 +45,7 @@
 
   // Load a page with cookies.
   ui_test_utils::NavigateToURL(
-      browser(), test_server()->GetURL("files/cookie1.html"));
+      browser(), embedded_test_server()->GetURL("/cookie1.html"));
 
   // Click on the info link.
   content::WebContents* web_contents =
@@ -61,5 +54,5 @@
 
   // Navigate to another page.
   ui_test_utils::NavigateToURL(
-      browser(), test_server()->GetURL("files/cookie2.html"));
+      browser(), embedded_test_server()->GetURL("/cookie2.html"));
 }
diff --git a/chrome/browser/component_updater/component_patcher.cc b/chrome/browser/component_updater/component_patcher.cc
new file mode 100644
index 0000000..54bc62d
--- /dev/null
+++ b/chrome/browser/component_updater/component_patcher.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/component_updater/component_patcher.h"
+
+#include <string>
+#include <vector>
+
+#include "base/file_util.h"
+#include "base/json/json_file_value_serializer.h"
+#include "base/values.h"
+#include "chrome/browser/component_updater/component_patcher_operation.h"
+#include "chrome/browser/component_updater/component_updater_service.h"
+
+namespace {
+
+// Deserialize the commands file (present in delta update packages). The top
+// level must be a list.
+base::ListValue* ReadCommands(const base::FilePath& unpack_path) {
+  const base::FilePath commands =
+      unpack_path.Append(FILE_PATH_LITERAL("commands.json"));
+  if (!file_util::PathExists(commands))
+    return NULL;
+
+  JSONFileValueSerializer serializer(commands);
+  scoped_ptr<base::Value> root(serializer.Deserialize(NULL, NULL));
+
+  return (root.get() && root->IsType(base::Value::TYPE_LIST)) ?
+      static_cast<base::ListValue*>(root.release()) : NULL;
+}
+
+}  // namespace
+
+
+// The patching support is not cross-platform at the moment.
+ComponentPatcherCrossPlatform::ComponentPatcherCrossPlatform() {}
+
+ComponentUnpacker::Error ComponentPatcherCrossPlatform::Patch(
+    PatchType patch_type,
+    const base::FilePath& input_file,
+    const base::FilePath& patch_file,
+    const base::FilePath& output_file,
+    int* error) {
+  return ComponentUnpacker::kDeltaUnsupportedCommand;
+}
+
+
+// Takes the contents of a differential component update in input_dir
+// and produces the contents of a full component update in unpack_dir
+// using input_abs_path_ files that the installer knows about.
+ComponentUnpacker::Error DifferentialUpdatePatch(
+    const base::FilePath& input_dir,
+    const base::FilePath& unpack_dir,
+    ComponentPatcher* patcher,
+    ComponentInstaller* installer,
+    int* error) {
+  *error = 0;
+  scoped_ptr<base::ListValue> commands(ReadCommands(input_dir));
+  if (!commands.get())
+    return ComponentUnpacker::kDeltaBadCommands;
+
+  for (base::ValueVector::const_iterator command = commands->begin(),
+      end = commands->end(); command != end; command++) {
+    if (!(*command)->IsType(base::Value::TYPE_DICTIONARY))
+      return ComponentUnpacker::kDeltaBadCommands;
+    base::DictionaryValue* command_args =
+        static_cast<base::DictionaryValue*>(*command);
+    scoped_ptr<DeltaUpdateOp> operation(CreateDeltaUpdateOp(command_args));
+    if (!operation)
+      return ComponentUnpacker::kDeltaUnsupportedCommand;
+
+    ComponentUnpacker::Error result = operation->Run(
+        command_args, input_dir, unpack_dir, patcher, installer, error);
+    if (result != ComponentUnpacker::kNone)
+      return result;
+  }
+
+  return ComponentUnpacker::kNone;
+}
+
diff --git a/chrome/browser/component_updater/component_patcher.h b/chrome/browser/component_updater/component_patcher.h
new file mode 100644
index 0000000..1990922
--- /dev/null
+++ b/chrome/browser/component_updater/component_patcher.h
@@ -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.
+
+// Component updates can be either differential updates or full updates.
+// Full updates come in CRX format; differential updates come in CRX-style
+// archives, but have a different magic number. They contain "commands.json", a
+// list of commands for the patcher to follow. The patcher uses these commands,
+// the other files in the archive, and the files from the existing installation
+// of the component to create the contents of a full update, which is then
+// installed normally.
+// Component updates are specified by the 'codebasediff' attribute of an
+// updatecheck response:
+//   <updatecheck codebase="http://example.com/extension_1.2.3.4.crx"
+//                hash="12345" size="9854" status="ok" version="1.2.3.4"
+//                prodversionmin="2.0.143.0"
+//                codebasediff="http://example.com/diff_1.2.3.4.crx"
+//                hashdiff="123" sizediff="101"
+//                fp="1.123" />
+// The component updater will attempt a differential update if it is available
+// and allowed to, and fall back to a full update if it fails.
+//
+// After installation (diff or full), the component updater records "fp", the
+// fingerprint of the installed files, to later identify the existing files to
+// the server so that a proper differential update can be provided next cycle.
+
+
+#ifndef CHROME_BROWSER_COMPONENT_UPDATER_COMPONENT_PATCHER_H_
+#define CHROME_BROWSER_COMPONENT_UPDATER_COMPONENT_PATCHER_H_
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "chrome/browser/component_updater/component_unpacker.h"
+
+namespace base {
+class FilePath;
+}
+
+class ComponentInstaller;
+
+// Applies a delta patch to a single file. Specifically, creates a file at
+// |output_file| using |input_file| patched according to the algorithm
+// specified by |patch_type| using |patch_file|. Sets the value of error to
+// the error code of the failing patch operation, if there is such a failure.
+class ComponentPatcher {
+ public:
+  // The type of a patch file.
+  enum PatchType {
+    kPatchTypeUnknown,
+    kPatchTypeCourgette,
+    kPatchTypeBsdiff,
+  };
+
+  virtual ComponentUnpacker::Error Patch(PatchType patch_type,
+                                         const base::FilePath& input_file,
+                                         const base::FilePath& patch_file,
+                                         const base::FilePath& output_file,
+                                         int* error) = 0;
+  virtual ~ComponentPatcher() {}
+};
+
+class ComponentPatcherCrossPlatform : public ComponentPatcher {
+ public:
+  ComponentPatcherCrossPlatform();
+  virtual ComponentUnpacker::Error Patch(PatchType patch_type,
+                                         const base::FilePath& input_file,
+                                         const base::FilePath& patch_file,
+                                         const base::FilePath& output_file,
+                                         int* error) OVERRIDE;
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ComponentPatcherCrossPlatform);
+};
+
+// This function takes an unpacked differential CRX (|input_dir|) and a
+// component installer, and creates a new (non-differential) unpacked CRX, which
+// is then installed normally.
+// The non-differential files are written into the |unpack_dir| directory.
+// Sets |error| to the error code of the first failing patch operation.
+ComponentUnpacker::Error DifferentialUpdatePatch(
+    const base::FilePath& input_dir,
+    const base::FilePath& unpack_dir,
+    ComponentPatcher* component_patcher,
+    ComponentInstaller* installer,
+    int* error);
+
+#endif  // CHROME_BROWSER_COMPONENT_UPDATER_COMPONENT_PATCHER_H_
diff --git a/chrome/browser/component_updater/component_patcher_operation.cc b/chrome/browser/component_updater/component_patcher_operation.cc
new file mode 100644
index 0000000..f814238
--- /dev/null
+++ b/chrome/browser/component_updater/component_patcher_operation.cc
@@ -0,0 +1,222 @@
+// 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/component_updater/component_patcher_operation.h"
+
+#include <string>
+#include <vector>
+
+#include "base/file_util.h"
+#include "base/files/memory_mapped_file.h"
+#include "base/json/json_file_value_serializer.h"
+#include "base/memory/scoped_handle.h"
+#include "base/path_service.h"
+#include "base/strings/string_number_conversions.h"
+#include "chrome/browser/component_updater/component_patcher.h"
+#include "chrome/browser/component_updater/component_updater_service.h"
+#include "chrome/common/extensions/extension_constants.h"
+#include "crypto/secure_hash.h"
+#include "crypto/sha2.h"
+#include "crypto/signature_verifier.h"
+#include "extensions/common/crx_file.h"
+#include "third_party/zlib/google/zip.h"
+
+using crypto::SecureHash;
+
+namespace {
+
+const char kInput[] = "input";
+const char kOp[] = "op";
+const char kOutput[] = "output";
+const char kPatch[] = "patch";
+const char kSha256[] = "sha256";
+
+}  // namespace
+
+DeltaUpdateOp* CreateDeltaUpdateOp(base::DictionaryValue* command) {
+  std::string operation;
+  if (!command->GetString(kOp, &operation))
+    return NULL;
+  if (operation == "copy")
+    return new DeltaUpdateOpCopy();
+  else if (operation == "create")
+    return new DeltaUpdateOpCreate();
+  else if (operation == "bsdiff")
+    return new DeltaUpdateOpPatchBsdiff();
+  else if (operation == "courgette")
+    return new DeltaUpdateOpPatchCourgette();
+  return NULL;
+}
+
+DeltaUpdateOp::DeltaUpdateOp() {}
+
+DeltaUpdateOp::~DeltaUpdateOp() {}
+
+ComponentUnpacker::Error DeltaUpdateOp::Run(base::DictionaryValue* command_args,
+                                            const base::FilePath& input_dir,
+                                            const base::FilePath& unpack_dir,
+                                            ComponentPatcher* patcher,
+                                            ComponentInstaller* installer,
+                                            int* error) {
+  std::string output_rel_path;
+  if (!command_args->GetString(kOutput, &output_rel_path) ||
+      !command_args->GetString(kSha256, &output_sha256_))
+    return ComponentUnpacker::kDeltaBadCommands;
+
+  output_abs_path_ = unpack_dir.Append(
+      base::FilePath::FromUTF8Unsafe(output_rel_path));
+  ComponentUnpacker::Error parse_result = DoParseArguments(
+      command_args, input_dir, installer);
+  if (parse_result != ComponentUnpacker::kNone)
+    return parse_result;
+
+  const base::FilePath parent = output_abs_path_.DirName();
+  if (!file_util::DirectoryExists(parent)) {
+    if (!file_util::CreateDirectory(parent))
+      return ComponentUnpacker::kIoError;
+  }
+
+  ComponentUnpacker::Error run_result = DoRun(patcher, error);
+  if (run_result != ComponentUnpacker::kNone)
+    return run_result;
+
+  return CheckHash();
+}
+
+// Uses the hash as a checksum to confirm that the file now residing in the
+// output directory probably has the contents it should.
+ComponentUnpacker::Error DeltaUpdateOp::CheckHash() {
+  std::vector<uint8> expected_hash;
+  if (!base::HexStringToBytes(output_sha256_, &expected_hash) ||
+      expected_hash.size() != crypto::kSHA256Length)
+    return ComponentUnpacker::kDeltaVerificationFailure;
+
+  base::MemoryMappedFile output_file_mmapped;
+  if (!output_file_mmapped.Initialize(output_abs_path_))
+    return ComponentUnpacker::kDeltaVerificationFailure;
+
+  uint8 actual_hash[crypto::kSHA256Length] = {0};
+  const scoped_ptr<SecureHash> hasher(SecureHash::Create(SecureHash::SHA256));
+  hasher->Update(output_file_mmapped.data(), output_file_mmapped.length());
+  hasher->Finish(actual_hash, sizeof(actual_hash));
+  if (memcmp(actual_hash, &expected_hash[0], sizeof(actual_hash)))
+    return ComponentUnpacker::kDeltaVerificationFailure;
+
+  return ComponentUnpacker::kNone;
+}
+
+DeltaUpdateOpCopy::DeltaUpdateOpCopy() {}
+
+ComponentUnpacker::Error DeltaUpdateOpCopy::DoParseArguments(
+    base::DictionaryValue* command_args,
+    const base::FilePath& input_dir,
+    ComponentInstaller* installer) {
+  std::string input_rel_path;
+  if (!command_args->GetString(kInput, &input_rel_path))
+    return ComponentUnpacker::kDeltaBadCommands;
+
+  if (!installer->GetInstalledFile(input_rel_path, &input_abs_path_))
+    return ComponentUnpacker::kDeltaMissingExistingFile;
+
+  return ComponentUnpacker::kNone;
+}
+
+ComponentUnpacker::Error DeltaUpdateOpCopy::DoRun(ComponentPatcher*,
+                                                  int* error) {
+  *error = 0;
+  if (!file_util::CopyFile(input_abs_path_, output_abs_path_))
+    return ComponentUnpacker::kDeltaOperationFailure;
+
+  return ComponentUnpacker::kNone;
+}
+
+DeltaUpdateOpCreate::DeltaUpdateOpCreate() {}
+
+ComponentUnpacker::Error DeltaUpdateOpCreate::DoParseArguments(
+    base::DictionaryValue* command_args,
+    const base::FilePath& input_dir,
+    ComponentInstaller* installer) {
+  std::string patch_rel_path;
+  if (!command_args->GetString(kPatch, &patch_rel_path))
+    return ComponentUnpacker::kDeltaBadCommands;
+
+  patch_abs_path_ = input_dir.Append(
+      base::FilePath::FromUTF8Unsafe(patch_rel_path));
+
+  return ComponentUnpacker::kNone;
+}
+
+ComponentUnpacker::Error DeltaUpdateOpCreate::DoRun(ComponentPatcher*,
+                                                    int* error) {
+  *error = 0;
+  if (!base::Move(patch_abs_path_, output_abs_path_))
+    return ComponentUnpacker::kDeltaOperationFailure;
+
+  return ComponentUnpacker::kNone;
+}
+
+DeltaUpdateOpPatchBsdiff::DeltaUpdateOpPatchBsdiff() {}
+
+ComponentUnpacker::Error DeltaUpdateOpPatchBsdiff::DoParseArguments(
+    base::DictionaryValue* command_args,
+    const base::FilePath& input_dir,
+    ComponentInstaller* installer) {
+  std::string patch_rel_path;
+  std::string input_rel_path;
+  if (!command_args->GetString(kPatch, &patch_rel_path) ||
+      !command_args->GetString(kInput, &input_rel_path))
+    return ComponentUnpacker::kDeltaBadCommands;
+
+  if (!installer->GetInstalledFile(input_rel_path, &input_abs_path_))
+    return ComponentUnpacker::kDeltaMissingExistingFile;
+
+  patch_abs_path_ = input_dir.Append(
+      base::FilePath::FromUTF8Unsafe(patch_rel_path));
+
+  return ComponentUnpacker::kNone;
+}
+
+ComponentUnpacker::Error DeltaUpdateOpPatchBsdiff::DoRun(
+    ComponentPatcher* patcher,
+    int* error) {
+  *error = 0;
+  return patcher->Patch(ComponentPatcher::kPatchTypeBsdiff,
+                        input_abs_path_,
+                        patch_abs_path_,
+                        output_abs_path_,
+                        error);
+}
+
+DeltaUpdateOpPatchCourgette::DeltaUpdateOpPatchCourgette() {}
+
+ComponentUnpacker::Error DeltaUpdateOpPatchCourgette::DoParseArguments(
+    base::DictionaryValue* command_args,
+    const base::FilePath& input_dir,
+    ComponentInstaller* installer) {
+  std::string patch_rel_path;
+  std::string input_rel_path;
+  if (!command_args->GetString(kPatch, &patch_rel_path) ||
+      !command_args->GetString(kInput, &input_rel_path))
+    return ComponentUnpacker::kDeltaBadCommands;
+
+  if (!installer->GetInstalledFile(input_rel_path, &input_abs_path_))
+    return ComponentUnpacker::kDeltaMissingExistingFile;
+
+  patch_abs_path_ = input_dir.Append(
+      base::FilePath::FromUTF8Unsafe(patch_rel_path));
+
+  return ComponentUnpacker::kNone;
+}
+
+ComponentUnpacker::Error DeltaUpdateOpPatchCourgette::DoRun(
+    ComponentPatcher* patcher,
+    int* error) {
+  *error = 0;
+  return patcher->Patch(ComponentPatcher::kPatchTypeCourgette,
+                        input_abs_path_,
+                        patch_abs_path_,
+                        output_abs_path_,
+                        error);
+}
+
diff --git a/chrome/browser/component_updater/component_patcher_operation.h b/chrome/browser/component_updater/component_patcher_operation.h
new file mode 100644
index 0000000..6e9fe5b
--- /dev/null
+++ b/chrome/browser/component_updater/component_patcher_operation.h
@@ -0,0 +1,158 @@
+// 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_COMPONENT_UPDATER_COMPONENT_PATCHER_OPERATION_H_
+#define CHROME_BROWSER_COMPONENT_UPDATER_COMPONENT_PATCHER_OPERATION_H_
+
+#include <string>
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "chrome/browser/component_updater/component_unpacker.h"
+
+namespace base {
+
+class FilePath;
+class DictionaryValue;
+
+}  // namespace base
+
+class ComponentInstaller;
+class ComponentPatcher;
+
+class DeltaUpdateOp {
+ public:
+
+  DeltaUpdateOp();
+  virtual ~DeltaUpdateOp();
+
+  // Parses, runs, and verifies the operation, returning an error code if an
+  // error is encountered, and DELTA_OK otherwise. In case of errors,
+  // extended error information can be returned in the |error| parameter.
+  ComponentUnpacker::Error Run(
+      base::DictionaryValue* command_args,
+      const base::FilePath& input_dir,
+      const base::FilePath& unpack_dir,
+      ComponentPatcher* patcher,
+      ComponentInstaller* installer,
+      int* error);
+
+ protected:
+  std::string output_sha256_;
+  base::FilePath output_abs_path_;
+
+ private:
+  ComponentUnpacker::Error CheckHash();
+
+  // Subclasses must override DoParseArguments to parse operation-specific
+  // arguments. DoParseArguments returns DELTA_OK on success; any other code
+  // represents failure.
+  virtual ComponentUnpacker::Error DoParseArguments(
+      base::DictionaryValue* command_args,
+      const base::FilePath& input_dir,
+      ComponentInstaller* installer) = 0;
+
+  // Subclasses must override DoRun to actually perform the patching operation.
+  // DoRun returns DELTA_OK on success; any other code represents failure.
+  // Additional error information can be returned in the |error| parameter.
+  virtual ComponentUnpacker::Error DoRun(ComponentPatcher* patcher,
+                                         int* error) = 0;
+
+  DISALLOW_COPY_AND_ASSIGN(DeltaUpdateOp);
+};
+
+// A 'copy' operation takes a file currently residing on the disk and moves it
+// into the unpacking directory: this represents "no change" in the file being
+// installed.
+class DeltaUpdateOpCopy : public DeltaUpdateOp {
+ public:
+  DeltaUpdateOpCopy();
+
+ private:
+  // Overrides of DeltaUpdateOp.
+  virtual ComponentUnpacker::Error DoParseArguments(
+      base::DictionaryValue* command_args,
+      const base::FilePath& input_dir,
+      ComponentInstaller* installer) OVERRIDE;
+
+  virtual ComponentUnpacker::Error DoRun(ComponentPatcher* patcher,
+                                         int* error) OVERRIDE;
+
+  base::FilePath input_abs_path_;
+
+  DISALLOW_COPY_AND_ASSIGN(DeltaUpdateOpCopy);
+};
+
+// A 'create' operation takes a full file that was sent in the delta update
+// archive and moves it into the unpacking directory: this represents the
+// addition of a new file, or a file so different that no bandwidth could be
+// saved by transmitting a differential update.
+class DeltaUpdateOpCreate : public DeltaUpdateOp {
+ public:
+  DeltaUpdateOpCreate();
+
+ private:
+  // Overrides of DeltaUpdateOp.
+  virtual ComponentUnpacker::Error DoParseArguments(
+      base::DictionaryValue* command_args,
+      const base::FilePath& input_dir,
+      ComponentInstaller* installer) OVERRIDE;
+
+  virtual ComponentUnpacker::Error DoRun(ComponentPatcher* patcher,
+                                         int* error) OVERRIDE;
+
+  base::FilePath patch_abs_path_;
+
+  DISALLOW_COPY_AND_ASSIGN(DeltaUpdateOpCreate);
+};
+
+// A 'bsdiff' operation takes an existing file on disk, and a bsdiff-
+// format patch file provided in the delta update package, and runs bsdiff
+// to construct an output file in the unpacking directory.
+class DeltaUpdateOpPatchBsdiff : public DeltaUpdateOp {
+ public:
+  DeltaUpdateOpPatchBsdiff();
+
+ private:
+  // Overrides of DeltaUpdateOp.
+  virtual ComponentUnpacker::Error DoParseArguments(
+      base::DictionaryValue* command_args,
+      const base::FilePath& input_dir,
+      ComponentInstaller* installer) OVERRIDE;
+
+  virtual ComponentUnpacker::Error DoRun(ComponentPatcher* patcher,
+                                         int* error) OVERRIDE;
+
+  base::FilePath patch_abs_path_;
+  base::FilePath input_abs_path_;
+
+  DISALLOW_COPY_AND_ASSIGN(DeltaUpdateOpPatchBsdiff);
+};
+
+// A 'courgette' operation takes an existing file on disk, and a Courgette-
+// format patch file provided in the delta update package, and runs Courgette
+// to construct an output file in the unpacking directory.
+class DeltaUpdateOpPatchCourgette : public DeltaUpdateOp {
+ public:
+  DeltaUpdateOpPatchCourgette();
+
+ private:
+  // Overrides of DeltaUpdateOp.
+  virtual ComponentUnpacker::Error DoParseArguments(
+      base::DictionaryValue* command_args,
+      const base::FilePath& input_dir,
+      ComponentInstaller* installer) OVERRIDE;
+
+  virtual ComponentUnpacker::Error DoRun(ComponentPatcher* patcher,
+                                         int* error) OVERRIDE;
+
+  base::FilePath patch_abs_path_;
+  base::FilePath input_abs_path_;
+
+  DISALLOW_COPY_AND_ASSIGN(DeltaUpdateOpPatchCourgette);
+};
+
+// Factory function to create DeltaUpdateOp instances.
+DeltaUpdateOp* CreateDeltaUpdateOp(base::DictionaryValue* command);
+
+#endif  // CHROME_BROWSER_COMPONENT_UPDATER_COMPONENT_PATCHER_OPERATION_H_
diff --git a/chrome/browser/component_updater/component_patcher_win.cc b/chrome/browser/component_updater/component_patcher_win.cc
new file mode 100644
index 0000000..a2f6865
--- /dev/null
+++ b/chrome/browser/component_updater/component_patcher_win.cc
@@ -0,0 +1,112 @@
+// 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/component_updater/component_patcher_win.h"
+
+#include <string>
+
+#include "base/base_paths.h"
+#include "base/command_line.h"
+#include "base/file_util.h"
+#include "base/path_service.h"
+#include "base/process_util.h"
+#include "base/strings/string_util.h"
+#include "base/win/scoped_handle.h"
+#include "chrome/installer/util/util_constants.h"
+
+namespace {
+
+std::string PatchTypeToCommandLineSwitch(
+    ComponentPatcher::PatchType patch_type) {
+  if (patch_type == ComponentPatcher::kPatchTypeCourgette)
+    return std::string(installer::kCourgette);
+  else if (patch_type == ComponentPatcher::kPatchTypeBsdiff)
+    return std::string(installer::kBsdiff);
+  else
+    return std::string();
+}
+
+// Finds the path to the setup.exe. First, it looks for the program in the
+// "installer" directory. If the program is not found there, it tries to find it
+// in the directory where chrome.dll lives. Returns the path to the setup.exe,
+// if the path exists, otherwise it returns an an empty path.
+base::FilePath FindSetupProgram() {
+  base::FilePath exe_dir;
+  if (!PathService::Get(base::DIR_MODULE, &exe_dir))
+    return base::FilePath();
+
+  const std::string installer_dir(WideToASCII(installer::kInstallerDir));
+  const std::string setup_exe(WideToASCII(installer::kSetupExe));
+
+  base::FilePath setup_path = exe_dir;
+  setup_path = setup_path.AppendASCII(installer_dir);
+  setup_path = setup_path.AppendASCII(setup_exe);
+  if (file_util::PathExists(setup_path))
+    return setup_path;
+
+  setup_path = exe_dir;
+  setup_path = setup_path.AppendASCII(setup_exe);
+  if (file_util::PathExists(setup_path))
+    return setup_path;
+
+  return base::FilePath();
+}
+
+}  // namespace
+
+// Applies the patch to the input file. Returns kNone if the patch was
+// successfully applied, kDeltaOperationFailure if the patch operation
+// encountered errors, and kDeltaPatchProcessFailure if there was an error
+// when running the patch code out of process. In the error case, detailed error
+// information could be returned in the error parameter.
+ComponentUnpacker::Error ComponentPatcherWin::Patch(
+    PatchType patch_type,
+    const base::FilePath& input_file,
+    const base::FilePath& patch_file,
+    const base::FilePath& output_file,
+    int* error) {
+  *error = 0;
+
+  const base::FilePath exe_path = FindSetupProgram();
+  if (exe_path.empty())
+    return ComponentUnpacker::kDeltaPatchProcessFailure;
+
+  const std::string patch_type_str(PatchTypeToCommandLineSwitch(patch_type));
+
+  CommandLine cl(CommandLine::NO_PROGRAM);
+  cl.AppendSwitchASCII(installer::switches::kPatch, patch_type_str.c_str());
+  cl.AppendSwitchPath(installer::switches::kInputFile, input_file);
+  cl.AppendSwitchPath(installer::switches::kPatchFile, patch_file);
+  cl.AppendSwitchPath(installer::switches::kOutputFile, output_file);
+
+  // Create the child process in a job object. The job object prevents leaving
+  // child processes around when the parent process exits, either gracefully or
+  // accidentally.
+  base::win::ScopedHandle job(CreateJobObject(NULL, NULL));
+  if (!job || !base::SetJobObjectAsKillOnJobClose(job)) {
+    *error = GetLastError();
+    return ComponentUnpacker::kDeltaPatchProcessFailure;
+  }
+
+  base::LaunchOptions launch_options;
+  launch_options.wait = true;
+  launch_options.job_handle = job;
+  launch_options.start_hidden = true;
+  CommandLine setup_path(exe_path);
+  setup_path.AppendArguments(cl, false);
+
+  // |ph| is closed by WaitForExitCode.
+  base::ProcessHandle ph = base::kNullProcessHandle;
+  int exit_code = 0;
+  if (!base::LaunchProcess(setup_path, launch_options, &ph) ||
+      !base::WaitForExitCode(ph, &exit_code)) {
+    *error = GetLastError();
+    return ComponentUnpacker::kDeltaPatchProcessFailure;
+  }
+
+  *error = exit_code;
+  return *error ? ComponentUnpacker::kDeltaOperationFailure :
+                  ComponentUnpacker::kNone;
+}
+
diff --git a/chrome/browser/component_updater/component_patcher_win.h b/chrome/browser/component_updater/component_patcher_win.h
new file mode 100644
index 0000000..d87ba54
--- /dev/null
+++ b/chrome/browser/component_updater/component_patcher_win.h
@@ -0,0 +1,24 @@
+// 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_COMPONENT_UPDATER_COMPONENT_PATCHER_WIN_H_
+#define CHROME_BROWSER_COMPONENT_UPDATER_COMPONENT_PATCHER_WIN_H_
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "chrome/browser/component_updater/component_patcher.h"
+
+class ComponentPatcherWin : public ComponentPatcher {
+ public:
+  ComponentPatcherWin() {}
+  virtual ComponentUnpacker::Error Patch(PatchType patch_type,
+                                         const base::FilePath& input_file,
+                                         const base::FilePath& patch_file,
+                                         const base::FilePath& output_file,
+                                         int* error) OVERRIDE;
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ComponentPatcherWin);
+};
+
+#endif  // CHROME_BROWSER_COMPONENT_UPDATER_COMPONENT_PATCHER_WIN_H_
diff --git a/chrome/browser/component_updater/component_unpacker.cc b/chrome/browser/component_updater/component_unpacker.cc
index 9454637..de7cfcb 100644
--- a/chrome/browser/component_updater/component_unpacker.cc
+++ b/chrome/browser/component_updater/component_unpacker.cc
@@ -12,6 +12,7 @@
 #include "base/memory/scoped_handle.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
+#include "chrome/browser/component_updater/component_patcher.h"
 #include "chrome/browser/component_updater/component_updater_service.h"
 #include "chrome/common/extensions/extension_constants.h"
 #include "crypto/secure_hash.h"
@@ -22,11 +23,12 @@
 using crypto::SecureHash;
 
 namespace {
+
 // This class makes sure that the CRX digital signature is valid
 // and well formed.
 class CRXValidator {
  public:
-  explicit CRXValidator(FILE* crx_file) : valid_(false) {
+  explicit CRXValidator(FILE* crx_file) : valid_(false), delta_(false) {
     extensions::CrxFile::Header header;
     size_t len = fread(&header, 1, sizeof(header), crx_file);
     if (len < sizeof(header))
@@ -37,6 +39,7 @@
         extensions::CrxFile::Parse(header, &error));
     if (!crx.get())
       return;
+    delta_ = extensions::CrxFile::HeaderIsDelta(header);
 
     std::vector<uint8> key(header.key_size);
     len = fread(&key[0], sizeof(uint8), header.key_size, crx_file);
@@ -72,10 +75,13 @@
 
   bool valid() const { return valid_; }
 
+  bool delta() const { return delta_; }
+
   const std::vector<uint8>& public_key() const { return public_key_; }
 
  private:
   bool valid_;
+  bool delta_;
   std::vector<uint8> public_key_;
 };
 
@@ -98,12 +104,29 @@
   return static_cast<base::DictionaryValue*>(root.release());
 }
 
+// Deletes a path if it exists, and then creates a directory there.
+// Returns true if and only if these operations were successful.
+// This method doesn't take any special steps to prevent files from
+// being inserted into the target directory by another process or thread.
+bool MakeEmptyDirectory(const base::FilePath& path) {
+  if (file_util::PathExists(path)) {
+    if (!base::Delete(path, true))
+      return false;
+  }
+  if (!file_util::CreateDirectory(path))
+    return false;
+  return true;
+}
+
 }  // namespace.
 
 ComponentUnpacker::ComponentUnpacker(const std::vector<uint8>& pk_hash,
                                      const base::FilePath& path,
+                                     const std::string& fingerprint,
+                                     ComponentPatcher* patcher,
                                      ComponentInstaller* installer)
-  : error_(kNone) {
+    : error_(kNone),
+      extended_error_(0) {
   if (pk_hash.empty() || path.empty()) {
     error_ = kInvalidParams;
     return;
@@ -135,31 +158,61 @@
     return;
   }
   // We want the temporary directory to be unique and yet predictable, so
-  // we can easily find the package in a end user machine.
-  std::string dir(
+  // we can easily find the package in an end user machine.
+  const std::string dir(
       base::StringPrintf("CRX_%s", base::HexEncode(hash, 6).c_str()));
   unpack_path_ = path.DirName().AppendASCII(dir.c_str());
-  if (file_util::DirectoryExists(unpack_path_)) {
-    if (!file_util::Delete(unpack_path_, true)) {
-      unpack_path_.clear();
-      error_ = kUzipPathError;
+  if (!MakeEmptyDirectory(unpack_path_)) {
+    unpack_path_.clear();
+    error_ = kUnzipPathError;
+    return;
+  }
+  if (validator.delta()) {  // Package is a diff package.
+    // We want a different temp directory for the delta files; we'll put the
+    // patch output into unpack_path_.
+    std::string dir(
+        base::StringPrintf("CRX_%s_diff", base::HexEncode(hash, 6).c_str()));
+    base::FilePath unpack_diff_path = path.DirName().AppendASCII(dir.c_str());
+    if (!MakeEmptyDirectory(unpack_diff_path)) {
+      error_ = kUnzipPathError;
       return;
     }
-  }
-  if (!file_util::CreateDirectory(unpack_path_)) {
-    unpack_path_.clear();
-    error_ = kUzipPathError;
-    return;
-  }
-  if (!zip::Unzip(path, unpack_path_)) {
-    error_ = kUnzipFailed;
-    return;
+    if (!zip::Unzip(path, unpack_diff_path)) {
+      error_ = kUnzipFailed;
+      return;
+    }
+    ComponentUnpacker::Error result = DifferentialUpdatePatch(unpack_diff_path,
+                                                              unpack_path_,
+                                                              patcher,
+                                                              installer,
+                                                              &extended_error_);
+    base::Delete(unpack_diff_path, true);
+    unpack_diff_path.clear();
+    error_ = result;
+    if (error_ != kNone) {
+      return;
+    }
+  } else {
+    // Package is a normal update/install; unzip it into unpack_path_ directly.
+    if (!zip::Unzip(path, unpack_path_)) {
+      error_ = kUnzipFailed;
+      return;
+    }
   }
   scoped_ptr<base::DictionaryValue> manifest(ReadManifest(unpack_path_));
   if (!manifest.get()) {
     error_ = kBadManifest;
     return;
   }
+  // Write the fingerprint to disk.
+  if (static_cast<int>(fingerprint.size()) !=
+      file_util::WriteFile(
+          unpack_path_.Append(FILE_PATH_LITERAL("manifest.fingerprint")),
+          fingerprint.c_str(),
+          fingerprint.size())) {
+    error_ = kFingerprintWriteFailed;
+    return;
+  }
   if (!installer->Install(*manifest, unpack_path_)) {
     error_ = kInstallerError;
     return;
@@ -169,7 +222,6 @@
 }
 
 ComponentUnpacker::~ComponentUnpacker() {
-  if (!unpack_path_.empty()) {
-    file_util::Delete(unpack_path_, true);
-  }
+  if (!unpack_path_.empty())
+    base::Delete(unpack_path_, true);
 }
diff --git a/chrome/browser/component_updater/component_unpacker.h b/chrome/browser/component_updater/component_unpacker.h
index e51555c..6ae7277 100644
--- a/chrome/browser/component_updater/component_unpacker.h
+++ b/chrome/browser/component_updater/component_unpacker.h
@@ -5,11 +5,13 @@
 #ifndef CHROME_BROWSER_COMPONENT_UPDATER_COMPONENT_UNPACKER_H_
 #define CHROME_BROWSER_COMPONENT_UPDATER_COMPONENT_UNPACKER_H_
 
+#include <string>
 #include <vector>
-
+#include "base/basictypes.h"
 #include "base/files/file_path.h"
 
 class ComponentInstaller;
+class ComponentPatcher;
 
 // In charge of unpacking the component CRX package and verifying that it is
 // well formed and the cryptographic signature is correct. If there is no
@@ -26,22 +28,33 @@
 class ComponentUnpacker {
  public:
   // Possible error conditions.
+  // Add only to the bottom of this enum; the order must be kept stable.
   enum Error {
     kNone,
     kInvalidParams,
     kInvalidFile,
-    kUzipPathError,
+    kUnzipPathError,
     kUnzipFailed,
     kNoManifest,
     kBadManifest,
     kBadExtension,
     kInvalidId,
     kInstallerError,
+    kIoError,
+    kDeltaVerificationFailure,
+    kDeltaBadCommands,
+    kDeltaUnsupportedCommand,
+    kDeltaOperationFailure,
+    kDeltaPatchProcessFailure,
+    kDeltaMissingExistingFile,
+    kFingerprintWriteFailed,
   };
   // Unpacks, verifies and calls the installer. |pk_hash| is the expected
   // public key SHA256 hash. |path| is the current location of the CRX.
   ComponentUnpacker(const std::vector<uint8>& pk_hash,
                     const base::FilePath& path,
+                    const std::string& fingerprint,
+                    ComponentPatcher* patcher,
                     ComponentInstaller* installer);
 
   // If something went wrong during unpacking or installer invocation, the
@@ -50,9 +63,12 @@
 
   Error error() const { return error_; }
 
+  int extended_error() const { return extended_error_; }
+
  private:
   base::FilePath unpack_path_;
   Error error_;
+  int extended_error_;  // Provides additional error information.
 };
 
 #endif  // CHROME_BROWSER_COMPONENT_UPDATER_COMPONENT_UNPACKER_H_
diff --git a/chrome/browser/component_updater/component_updater_configurator.cc b/chrome/browser/component_updater/component_updater_configurator.cc
index 16fa3e9..d211e5e 100644
--- a/chrome/browser/component_updater/component_updater_configurator.cc
+++ b/chrome/browser/component_updater/component_updater_configurator.cc
@@ -14,36 +14,66 @@
 #include "base/strings/string_util.h"
 #include "base/win/windows_version.h"
 #include "build/build_config.h"
+#include "chrome/browser/component_updater/component_patcher.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/omaha_query_params/omaha_query_params.h"
 #include "net/url_request/url_request_context_getter.h"
 
+#if defined(OS_WIN)
+#include "chrome/browser/component_updater/component_patcher_win.h"
+#endif
+
 namespace {
+
 // Default time constants.
 const int kDelayOneMinute = 60;
 const int kDelayOneHour = kDelayOneMinute * 60;
 
-// Debug values you can pass to --component-updater-debug=value1,value2.
+// Debug values you can pass to --component-updater=value1,value2.
 // Speed up component checking.
-const char kDebugFastUpdate[] = "fast-update";
+const char kSwitchFastUpdate[] = "fast-update";
 // Force out-of-process-xml parsing.
-const char kDebugOutOfProcess[] = "out-of-process";
+const char kSwitchOutOfProcess[] = "out-of-process";
 // Add "testrequest=1" parameter to the update check query.
-const char kDebugRequestParam[] = "test-request";
+const char kSwitchRequestParam[] = "test-request";
+// Disables differential updates.
+const char kSwitchDisableDeltaUpdates[] = "disable-delta-updates";
+// Sets the URL for updates.
+const char kSwitchUrlSource[] = "url-source";
 
-// The urls from which an update manifest can be fetched.
-const char* kUrlSources[] = {
-  "http://clients2.google.com/service/update2/crx",       // BANDAID
-  "http://omaha.google.com/service/update2/crx",          // CWS_PUBLIC
-  "http://omaha.sandbox.google.com/service/update2/crx"   // CWS_SANDBOX
-};
+// The default url from which an update manifest can be fetched. Can be
+// overridden with --component-updater=url-source=someurl.
+const char kDefaultUrlSource[] =
+    "http://clients2.google.com/service/update2/crx";
 
-bool HasDebugValue(const std::vector<std::string>& vec, const char* test) {
+// Returns true if and only if |test| is contained in |vec|.
+bool HasSwitchValue(const std::vector<std::string>& vec, const char* test) {
   if (vec.empty())
     return 0;
   return (std::find(vec.begin(), vec.end(), test) != vec.end());
 }
 
+// If there is an element of |vec| of the form |test|=.*, returns the right-
+// hand side of that assignment. Otherwise, returns an empty string.
+// The right-hand side may contain additional '=' characters, allowing for
+// further nesting of switch arguments.
+std::string GetSwitchArgument(const std::vector<std::string>& vec,
+                              const char* test) {
+  if (vec.empty())
+    return std::string();
+  for (std::vector<std::string>::const_iterator it = vec.begin();
+      it != vec.end();
+      ++it) {
+    const std::size_t found = it->find("=");
+    if (found != std::string::npos) {
+      if (it->substr(0, found) == test) {
+        return it->substr(found + 1);
+      }
+    }
+  }
+  return std::string();
+}
+
 }  // namespace
 
 class ChromeConfigurator : public ComponentUpdateService::Configurator {
@@ -58,31 +88,48 @@
   virtual int StepDelay() OVERRIDE;
   virtual int MinimumReCheckWait() OVERRIDE;
   virtual int OnDemandDelay() OVERRIDE;
-  virtual GURL UpdateUrl(CrxComponent::UrlSource source) OVERRIDE;
+  virtual GURL UpdateUrl() OVERRIDE;
   virtual const char* ExtraRequestParams() OVERRIDE;
   virtual size_t UrlSizeLimit() OVERRIDE;
   virtual net::URLRequestContextGetter* RequestContext() OVERRIDE;
   virtual bool InProcess() OVERRIDE;
   virtual void OnEvent(Events event, int val) OVERRIDE;
+  virtual ComponentPatcher* CreateComponentPatcher() OVERRIDE;
+  virtual bool DeltasEnabled() const OVERRIDE;
 
  private:
   net::URLRequestContextGetter* url_request_getter_;
   std::string extra_info_;
+  std::string url_source_;
   bool fast_update_;
   bool out_of_process_;
+  bool deltas_enabled_;
 };
 
 ChromeConfigurator::ChromeConfigurator(const CommandLine* cmdline,
     net::URLRequestContextGetter* url_request_getter)
       : url_request_getter_(url_request_getter),
         extra_info_(chrome::OmahaQueryParams::Get(
-            chrome::OmahaQueryParams::CHROME)) {
+            chrome::OmahaQueryParams::CHROME)),
+        fast_update_(false),
+        out_of_process_(false),
+        deltas_enabled_(false) {
   // Parse comma-delimited debug flags.
-  std::vector<std::string> debug_values;
-  Tokenize(cmdline->GetSwitchValueASCII(switches::kComponentUpdaterDebug),
-      ",", &debug_values);
-  fast_update_ = HasDebugValue(debug_values, kDebugFastUpdate);
-  out_of_process_ = HasDebugValue(debug_values, kDebugOutOfProcess);
+  std::vector<std::string> switch_values;
+  Tokenize(cmdline->GetSwitchValueASCII(switches::kComponentUpdater),
+      ",", &switch_values);
+  fast_update_ = HasSwitchValue(switch_values, kSwitchFastUpdate);
+  out_of_process_ = HasSwitchValue(switch_values, kSwitchOutOfProcess);
+#if defined(OS_WIN)
+  deltas_enabled_ = !HasSwitchValue(switch_values, kSwitchDisableDeltaUpdates);
+#else
+  deltas_enabled_ = false;
+#endif
+
+  url_source_ = GetSwitchArgument(switch_values, kSwitchUrlSource);
+  if (url_source_.empty()) {
+    url_source_ = kDefaultUrlSource;
+  }
 
   // Make the extra request params, they are necessary so omaha does
   // not deliver components that are going to be rejected at install time.
@@ -91,7 +138,7 @@
       base::win::OSInfo::WOW64_ENABLED)
     extra_info_ += "&wow64=1";
 #endif
-  if (HasDebugValue(debug_values, kDebugRequestParam))
+  if (HasSwitchValue(switch_values, kSwitchRequestParam))
     extra_info_ += "&testrequest=1";
 }
 
@@ -115,8 +162,8 @@
   return fast_update_ ? 2 : (30 * kDelayOneMinute);
 }
 
-GURL ChromeConfigurator::UpdateUrl(CrxComponent::UrlSource source) {
-  return GURL(kUrlSources[source]);
+GURL ChromeConfigurator::UpdateUrl() {
+  return GURL(url_source_);
 }
 
 const char* ChromeConfigurator::ExtraRequestParams() {
@@ -161,6 +208,18 @@
   }
 }
 
+ComponentPatcher* ChromeConfigurator::CreateComponentPatcher() {
+#if defined(OS_WIN)
+  return new ComponentPatcherWin();
+#else
+  return new ComponentPatcherCrossPlatform();
+#endif
+}
+
+bool ChromeConfigurator::DeltasEnabled() const {
+  return deltas_enabled_;
+}
+
 ComponentUpdateService::Configurator* MakeChromeComponentUpdaterConfigurator(
     const CommandLine* cmdline, net::URLRequestContextGetter* context_getter) {
   return new ChromeConfigurator(cmdline, context_getter);
diff --git a/chrome/browser/component_updater/component_updater_service.cc b/chrome/browser/component_updater/component_updater_service.cc
index f3eee77..7b3d683 100644
--- a/chrome/browser/component_updater/component_updater_service.cc
+++ b/chrome/browser/component_updater/component_updater_service.cc
@@ -10,6 +10,7 @@
 
 #include "base/at_exit.h"
 #include "base/bind.h"
+#include "base/compiler_specific.h"
 #include "base/file_util.h"
 #include "base/files/file_path.h"
 #include "base/logging.h"
@@ -19,24 +20,26 @@
 #include "base/strings/string_piece.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
-#include "base/timer.h"
+#include "base/timer/timer.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/component_updater/component_patcher.h"
 #include "chrome/browser/component_updater/component_unpacker.h"
 #include "chrome/common/chrome_notification_types.h"
 #include "chrome/common/chrome_utility_messages.h"
 #include "chrome/common/chrome_version_info.h"
 #include "chrome/common/extensions/extension.h"
+#include "chrome/common/omaha_query_params/omaha_query_params.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/utility_process_host.h"
 #include "content/public/browser/utility_process_host_client.h"
-#include "googleurl/src/gurl.h"
 #include "net/base/escape.h"
 #include "net/base/load_flags.h"
 #include "net/base/net_errors.h"
 #include "net/url_request/url_fetcher.h"
 #include "net/url_request/url_fetcher_delegate.h"
 #include "net/url_request/url_request_status.h"
+#include "url/gurl.h"
 
 using content::BrowserThread;
 using content::UtilityProcessHost;
@@ -47,21 +50,21 @@
 // base::Bind() calls are not refcounted.
 
 namespace {
-// Manifest sources, from most important to least important.
-const CrxComponent::UrlSource kManifestSources[] = {
-  CrxComponent::BANDAID,
-  CrxComponent::CWS_PUBLIC,
-  CrxComponent::CWS_SANDBOX
-};
 
 // Extends an omaha compatible update check url |query| string. Does
 // not mutate the string if it would be longer than |limit| chars.
 bool AddQueryString(const std::string& id,
                     const std::string& version,
+                    const std::string& fingerprint,
+                    bool ondemand,
                     size_t limit,
                     std::string* query) {
   std::string additional =
-      base::StringPrintf("id=%s&v=%s&uc", id.c_str(), version.c_str());
+      base::StringPrintf("id=%s&v=%s&fp=%s&uc%s",
+                         id.c_str(),
+                         version.c_str(),
+                         fingerprint.c_str(),
+                         ondemand ? "&installsource=ondemand" : "");
   additional = "x=" + net::EscapeQueryParamValue(additional, true);
   if ((additional.size() + query->size() + 1) > limit)
     return false;
@@ -163,7 +166,7 @@
   fetcher->Start();
 }
 
-// Returs true if the url request of |fetcher| was succesful.
+// Returns true if the url request of |fetcher| was succesful.
 bool FetchSuccess(const net::URLFetcher& fetcher) {
   return (fetcher.GetStatus().status() == net::URLRequestStatus::SUCCESS) &&
          (fetcher.GetResponseCode() == 200);
@@ -174,23 +177,44 @@
 // which is supplied by the the component updater client and |status| which
 // is modified as the item is processed by the update pipeline. The expected
 // transition graph is:
-//                                error          error         error
-//              +--kNoUpdate<------<-------+------<------+------<------+
-//              |                          |             |             |
-//              V                  yes     |             |             |
-//  kNew --->kChecking-->[update?]----->kCanUpdate-->kDownloading-->kUpdating
-//              ^               |                                      |
-//              |               |no                                    |
-//              |--kUpToDate<---+                                      |
-//              |                                  success             |
-//              +--kUpdated<-------------------------------------------+
+//
+//                                 kNew
+//                                  |
+//                                  V
+//     +----------------------> kChecking -<---------+-----<-------+
+//     |                            |                |             |
+//     |              error         V       no       |             |
+//  kNoUpdate <---------------- [update?] ->---- kUpToDate     kUpdated
+//     ^                            |                              ^
+//     |                        yes |                              |
+//     |        diff=false          V                              |
+//     |          +-----------> kCanUpdate                         |
+//     |          |                 |                              |
+//     |          |                 V              no              |
+//     |          |        [differential update?]->----+           |
+//     |          |                 |                  |           |
+//     |          |             yes |                  |           |
+//     |          |   error         V                  |           |
+//     |          +---------<- kDownloadingDiff        |           |
+//     |          |                 |                  |           |
+//     |          |                 |                  |           |
+//     |          |   error         V                  |           |
+//     |          +---------<- kUpdatingDiff ->--------|-----------+ success
+//     |                                               |           |
+//     |              error                            V           |
+//     +----------------------------------------- kDownloading     |
+//     |                                               |           |
+//     |              error                            V           |
+//     +------------------------------------------ kUpdating ->----+ success
 //
 struct CrxUpdateItem {
   enum Status {
     kNew,
     kChecking,
     kCanUpdate,
+    kDownloadingDiff,
     kDownloading,
+    kUpdatingDiff,
     kUpdating,
     kUpdated,
     kUpToDate,
@@ -199,13 +223,33 @@
   };
 
   Status status;
-  GURL crx_url;
   std::string id;
-  base::Time last_check;
   CrxComponent component;
-  Version next_version;
 
-  CrxUpdateItem() : status(kNew) {}
+  base::Time last_check;
+
+  // These members are initialized with their corresponding values from the
+  // update server response.
+  GURL crx_url;
+  GURL diff_crx_url;
+  int size;
+  int diff_size;
+
+  // The from/to version and fingerprint values.
+  Version previous_version;
+  Version next_version;
+  std::string previous_fp;
+  std::string next_fp;
+
+  // True if the differential update failed for any reason.
+  bool diff_update_failed;
+
+  CrxUpdateItem()
+      : status(kNew),
+        size(0),
+        diff_size(0),
+        diff_update_failed(false) {
+  }
 
   // Function object used to find a specific component.
   class FindById {
@@ -220,13 +264,24 @@
   };
 };
 
+// Returns true if a differential update is available for the update item.
+bool IsDiffUpdateAvailable(const CrxUpdateItem* update_item) {
+  return update_item->diff_crx_url.is_valid();
+}
+
+// Returns true if a differential update is available, it has not failed yet,
+// and the configuration allows it.
+bool CanTryDiffUpdate(const CrxUpdateItem* update_item,
+                      const ComponentUpdateService::Configurator& config) {
+  return IsDiffUpdateAvailable(update_item) &&
+         !update_item->diff_update_failed &&
+         config.DeltasEnabled();
+}
+
 }  // namespace.
 
-typedef ComponentUpdateService::Configurator Config;
-
 CrxComponent::CrxComponent()
-    : installer(NULL),
-      source(BANDAID) {
+    : installer(NULL) {
 }
 
 CrxComponent::~CrxComponent() {
@@ -240,7 +295,7 @@
 // rest of the browser, so even if we have many components registered and
 // eligible for update, we only do one thing at a time with pauses in between
 // the tasks. Also when we do network requests there is only one |url_fetcher_|
-// in flight at at a time.
+// in flight at a time.
 // There are no locks in this code, the main structure |work_items_| is mutated
 // only from the UI thread. The unpack and installation is done in the file
 // thread and the network requests are done in the IO thread and in the file
@@ -304,6 +359,7 @@
     ComponentInstaller* installer;
     std::vector<uint8> pk_hash;
     std::string id;
+    std::string fingerprint;
     CRXContext() : installer(NULL) {}
   };
 
@@ -319,8 +375,7 @@
       const UpdateManifest::Results& results);
 
   // See ManifestParserBridge.
-  void OnParseUpdateManifestFailed(
-      const std::string& error_message);
+  void OnParseUpdateManifestFailed(const std::string& error_message);
 
   bool AddItemToUpdateCheck(CrxUpdateItem* item, std::string* query);
 
@@ -333,19 +388,22 @@
   void Install(const CRXContext* context, const base::FilePath& crx_path);
 
   void DoneInstalling(const std::string& component_id,
-                      ComponentUnpacker::Error error);
+                      ComponentUnpacker::Error error,
+                      int extended_error);
 
   size_t ChangeItemStatus(CrxUpdateItem::Status from,
                           CrxUpdateItem::Status to);
 
   CrxUpdateItem* FindUpdateItemById(const std::string& id);
 
-  scoped_ptr<Config> config_;
+  scoped_ptr<ComponentUpdateService::Configurator> config_;
+
+  scoped_ptr<ComponentPatcher> component_patcher_;
 
   scoped_ptr<net::URLFetcher> url_fetcher_;
 
-  typedef std::vector<CrxUpdateItem*> UpdateItems;
   // A collection of every work item.
+  typedef std::vector<CrxUpdateItem*> UpdateItems;
   UpdateItems work_items_;
 
   // A particular set of items from work_items_, which should be checked ASAP.
@@ -353,7 +411,8 @@
 
   base::OneShotTimer<CrxUpdateService> timer_;
 
-  Version chrome_version_;
+  const Version chrome_version_;
+  const std::string prod_id_;
 
   bool running_;
 
@@ -362,10 +421,12 @@
 
 //////////////////////////////////////////////////////////////////////////////
 
-CrxUpdateService::CrxUpdateService(
-    ComponentUpdateService::Configurator* config)
+CrxUpdateService::CrxUpdateService(ComponentUpdateService::Configurator* config)
     : config_(config),
+      component_patcher_(config->CreateComponentPatcher()),
       chrome_version_(chrome::VersionInfo().Version()),
+      prod_id_(chrome::OmahaQueryParams::GetProdIdString(
+          chrome::OmahaQueryParams::CHROME)),
       running_(false) {
 }
 
@@ -450,7 +511,7 @@
 }
 
 // Changes all the components in |work_items_| that have |from| status to
-// |to| statatus and returns how many have been changed.
+// |to| status and returns how many have been changed.
 size_t CrxUpdateService::ChangeItemStatus(CrxUpdateItem::Status from,
                                           CrxUpdateItem::Status to) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
@@ -491,6 +552,7 @@
   uit = new CrxUpdateItem;
   uit->id.swap(id);
   uit->component = component;
+
   work_items_.push_back(uit);
   // If this is the first component registered we call Start to
   // schedule the first timer.
@@ -501,17 +563,29 @@
 }
 
 // Sets a component to be checked for updates.
-// The componet to add is |crxit| and the |query| string is modified with the
-// required omaha compatible query. Returns false when the query strings
-// is longer than specified by UrlSizeLimit().
+// The component to add is |item| and the |query| string is modified with the
+// required omaha compatible query. Returns false when the query string is
+// longer than specified by UrlSizeLimit().
+// If the item is currently on the requested_work_items_ list, the update check
+// is considered to be "on-demand": the server may honor on-demand checks by
+// serving updates at 100% rather than a gated fraction.
 bool CrxUpdateService::AddItemToUpdateCheck(CrxUpdateItem* item,
                                             std::string* query) {
   if (!AddQueryString(item->id,
                       item->component.version.GetString(),
-                      config_->UrlSizeLimit(), query))
+                      item->component.fingerprint,
+                      requested_work_items_.count(item) > 0,  // is_ondemand
+                      config_->UrlSizeLimit(),
+                      query))
     return false;
+
   item->status = CrxUpdateItem::kChecking;
   item->last_check = base::Time::Now();
+  item->previous_version = item->component.version;
+  item->next_version = Version();
+  item->previous_fp = item->component.fingerprint;
+  item->next_fp.clear();
+  item->diff_update_failed = false;
   return true;
 }
 
@@ -535,16 +609,17 @@
 
   // Check if the request is too soon.
   base::TimeDelta delta = base::Time::Now() - uit->last_check;
-  if (delta < base::TimeDelta::FromSeconds(config_->OnDemandDelay())) {
+  if (delta < base::TimeDelta::FromSeconds(config_->OnDemandDelay()))
     return kError;
-  }
 
   switch (uit->status) {
     // If the item is already in the process of being updated, there is
     // no point in this call, so return kInProgress.
     case CrxUpdateItem::kChecking:
     case CrxUpdateItem::kCanUpdate:
+    case CrxUpdateItem::kDownloadingDiff:
     case CrxUpdateItem::kDownloading:
+    case CrxUpdateItem::kUpdatingDiff:
     case CrxUpdateItem::kUpdating:
       return kInProgress;
     // Otherwise the item was already checked a while back (or it is new),
@@ -583,85 +658,81 @@
     if (item->status != CrxUpdateItem::kCanUpdate)
       continue;
     // Found component to update, start the process.
-    item->status = CrxUpdateItem::kDownloading;
     CRXContext* context = new CRXContext;
     context->pk_hash = item->component.pk_hash;
     context->id = item->id;
     context->installer = item->component.installer;
+    context->fingerprint = item->next_fp;
+    GURL package_url;
+    if (CanTryDiffUpdate(item, *config_)) {
+      package_url = item->diff_crx_url;
+      item->status = CrxUpdateItem::kDownloadingDiff;
+    } else {
+      package_url = item->crx_url;
+      item->status = CrxUpdateItem::kDownloading;
+    }
     url_fetcher_.reset(net::URLFetcher::Create(
-        0, item->crx_url, net::URLFetcher::GET,
+        0, package_url, net::URLFetcher::GET,
         MakeContextDelegate(this, context)));
     StartFetch(url_fetcher_.get(), config_->RequestContext(), true);
     return;
   }
 
-  for (size_t ix = 0; ix != arraysize(kManifestSources); ++ix) {
-    const CrxComponent::UrlSource manifest_source = kManifestSources[ix];
-
-    std::string query;
-    // If no pending upgrades, we check if there are new components we have not
-    // checked against the server. We can batch some in a single url request.
-    for (UpdateItems::const_iterator it = work_items_.begin();
-         it != work_items_.end(); ++it) {
-      CrxUpdateItem* item = *it;
-      if (item->status != CrxUpdateItem::kNew)
-        continue;
-      if (item->component.source != manifest_source)
-        continue;
-      if (!AddItemToUpdateCheck(item, &query))
-        break;
-      // Requested work items may speed up the update cycle up until
-      // the point that we start an update check. I.e., transition
-      // from kNew -> kChecking.  Since the service doesn't guarantee that
-      // the requested items make it any further than kChecking,
-      // forget them now.
-      requested_work_items_.erase(item);
-    }
-
-    // Next we can go back to components we already checked, here
-    // we can also batch them in a single url request, as long as
-    // we have not checked them recently.
-    const base::TimeDelta min_delta_time =
-        base::TimeDelta::FromSeconds(config_->MinimumReCheckWait());
-
-    for (UpdateItems::const_iterator it = work_items_.begin();
-         it != work_items_.end(); ++it) {
-      CrxUpdateItem* item = *it;
-      if ((item->status != CrxUpdateItem::kNoUpdate) &&
-          (item->status != CrxUpdateItem::kUpToDate))
-        continue;
-      if (item->component.source != manifest_source)
-        continue;
-      base::TimeDelta delta = base::Time::Now() - item->last_check;
-      if (delta < min_delta_time)
-        continue;
-      if (!AddItemToUpdateCheck(item, &query))
-        break;
-    }
-
-    // Finally, we check components that we already updated as long as
-    // we have not checked them recently.
-    for (UpdateItems::const_iterator it = work_items_.begin();
-         it != work_items_.end(); ++it) {
-      CrxUpdateItem* item = *it;
-      if (item->status != CrxUpdateItem::kUpdated)
-        continue;
-      if (item->component.source != manifest_source)
-        continue;
-      base::TimeDelta delta = base::Time::Now() - item->last_check;
-      if (delta < min_delta_time)
-        continue;
-      if (!AddItemToUpdateCheck(item, &query))
-        break;
-    }
-
-    // If no components to update we move down to the next source.
-    if (query.empty())
+  std::string query;
+  // If no pending upgrades, we check if there are new components we have not
+  // checked against the server. We can batch some in a single url request.
+  for (UpdateItems::const_iterator it = work_items_.begin();
+       it != work_items_.end(); ++it) {
+    CrxUpdateItem* item = *it;
+    if (item->status != CrxUpdateItem::kNew)
       continue;
+    if (!AddItemToUpdateCheck(item, &query))
+      break;
+    // Requested work items may speed up the update cycle up until
+    // the point that we start an update check. I.e., transition
+    // from kNew -> kChecking.  Since the service doesn't guarantee that
+    // the requested items make it any further than kChecking,
+    // forget them now.
+    requested_work_items_.erase(item);
+  }
 
+  // Next we can go back to components we already checked, here
+  // we can also batch them in a single url request, as long as
+  // we have not checked them recently.
+  const base::TimeDelta min_delta_time =
+      base::TimeDelta::FromSeconds(config_->MinimumReCheckWait());
+
+  for (UpdateItems::const_iterator it = work_items_.begin();
+       it != work_items_.end(); ++it) {
+    CrxUpdateItem* item = *it;
+    if ((item->status != CrxUpdateItem::kNoUpdate) &&
+        (item->status != CrxUpdateItem::kUpToDate))
+      continue;
+    base::TimeDelta delta = base::Time::Now() - item->last_check;
+    if (delta < min_delta_time)
+      continue;
+    if (!AddItemToUpdateCheck(item, &query))
+      break;
+  }
+
+  // Finally, we check components that we already updated as long as
+  // we have not checked them recently.
+  for (UpdateItems::const_iterator it = work_items_.begin();
+       it != work_items_.end(); ++it) {
+    CrxUpdateItem* item = *it;
+    if (item->status != CrxUpdateItem::kUpdated)
+      continue;
+    base::TimeDelta delta = base::Time::Now() - item->last_check;
+    if (delta < min_delta_time)
+      continue;
+    if (!AddItemToUpdateCheck(item, &query))
+      break;
+  }
+
+  if (!query.empty()) {
     // We got components to check. Start the url request and exit.
     const std::string full_query =
-        MakeFinalQuery(config_->UpdateUrl(manifest_source).spec(),
+        MakeFinalQuery(config_->UpdateUrl().spec(),
                        query,
                        config_->ExtraRequestParams());
 
@@ -700,11 +771,10 @@
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   if (config_->InProcess()) {
     UpdateManifest manifest;
-    if (!manifest.Parse(xml)) {
+    if (!manifest.Parse(xml))
        CrxUpdateService::OnParseUpdateManifestFailed(manifest.errors());
-    } else {
+    else
        CrxUpdateService::OnParseUpdateManifestSucceeded(manifest.results());
-    }
   } else {
     UtilityProcessHost* host =
         UtilityProcessHost::Create(new ManifestParserBridge(this),
@@ -753,8 +823,12 @@
     // All test passed. Queue an upgrade for this component and fire the
     // notifications.
     crx->crx_url = it->crx_url;
+    crx->size = it->size;
+    crx->diff_crx_url = it->diff_crx_url;
+    crx->diff_size = it->diff_size;
     crx->status = CrxUpdateItem::kCanUpdate;
     crx->next_version = Version(it->version);
+    crx->next_fp = it->package_fingerprint;
     ++update_pending;
 
     content::NotificationService::current()->Notify(
@@ -789,19 +863,40 @@
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   int error_code = net::OK;
 
+  CrxUpdateItem* crx = FindUpdateItemById(context->id);
+  DCHECK(crx->status == CrxUpdateItem::kDownloadingDiff ||
+         crx->status == CrxUpdateItem::kDownloading);
+
   if (source->FileErrorOccurred(&error_code) || !FetchSuccess(*source)) {
+    if (crx->status == CrxUpdateItem::kDownloadingDiff) {
+      crx->diff_update_failed = true;
+      size_t count = ChangeItemStatus(CrxUpdateItem::kDownloadingDiff,
+                                      CrxUpdateItem::kCanUpdate);
+      DCHECK_EQ(count, 1ul);
+      ScheduleNextRun(true);
+      return;
+    }
     size_t count = ChangeItemStatus(CrxUpdateItem::kDownloading,
                                     CrxUpdateItem::kNoUpdate);
     DCHECK_EQ(count, 1ul);
     config_->OnEvent(Configurator::kNetworkError, CrxIdtoUMAId(context->id));
     url_fetcher_.reset();
+
     ScheduleNextRun(false);
   } else {
     base::FilePath temp_crx_path;
     CHECK(source->GetResponseAsFilePath(true, &temp_crx_path));
-    size_t count = ChangeItemStatus(CrxUpdateItem::kDownloading,
-                                    CrxUpdateItem::kUpdating);
+
+    size_t count = 0;
+    if (crx->status == CrxUpdateItem::kDownloadingDiff) {
+      count = ChangeItemStatus(CrxUpdateItem::kDownloadingDiff,
+                               CrxUpdateItem::kUpdatingDiff);
+    } else {
+      count = ChangeItemStatus(CrxUpdateItem::kDownloading,
+                               CrxUpdateItem::kUpdating);
+    }
     DCHECK_EQ(count, 1ul);
+
     url_fetcher_.reset();
 
     content::NotificationService::current()->Notify(
@@ -829,17 +924,19 @@
                                const base::FilePath& crx_path) {
   // This function owns the |crx_path| and the |context| object.
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
-  ComponentUnpacker
-      unpacker(context->pk_hash, crx_path, context->installer);
-  if (!file_util::Delete(crx_path, false)) {
+  ComponentUnpacker unpacker(context->pk_hash,
+                             crx_path,
+                             context->fingerprint,
+                             component_patcher_.get(),
+                             context->installer);
+  if (!base::Delete(crx_path, false))
     NOTREACHED() << crx_path.value();
-  }
   // Why unretained? See comment at top of file.
   BrowserThread::PostDelayedTask(
       BrowserThread::UI,
       FROM_HERE,
       base::Bind(&CrxUpdateService::DoneInstalling, base::Unretained(this),
-                 context->id, unpacker.error()),
+                 context->id, unpacker.error(), unpacker.extended_error()),
       base::TimeDelta::FromMilliseconds(config_->StepDelay()));
   delete context;
 }
@@ -847,14 +944,28 @@
 // Installation has been completed. Adjust the component status and
 // schedule the next check.
 void CrxUpdateService::DoneInstalling(const std::string& component_id,
-                                      ComponentUnpacker::Error error) {
+                                      ComponentUnpacker::Error error,
+                                      int extra_code) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
 
   CrxUpdateItem* item = FindUpdateItemById(component_id);
+  if (item->status == CrxUpdateItem::kUpdatingDiff) {
+    if (error != ComponentUnpacker::kNone) {
+      item->diff_update_failed = true;
+      size_t count = ChangeItemStatus(CrxUpdateItem::kUpdatingDiff,
+                                      CrxUpdateItem::kCanUpdate);
+      DCHECK_EQ(count, 1ul);
+      ScheduleNextRun(true);
+      return;
+    }
+  }
+
   item->status = (error == ComponentUnpacker::kNone) ? CrxUpdateItem::kUpdated :
                                                        CrxUpdateItem::kNoUpdate;
-  if (item->status == CrxUpdateItem::kUpdated)
+  if (item->status == CrxUpdateItem::kUpdated) {
     item->component.version = item->next_version;
+    item->component.fingerprint = item->next_fp;
+  }
 
   Configurator::Events event;
   switch (error) {
diff --git a/chrome/browser/component_updater/component_updater_service.h b/chrome/browser/component_updater/component_updater_service.h
index 3ac645d..de1748b 100644
--- a/chrome/browser/component_updater/component_updater_service.h
+++ b/chrome/browser/component_updater/component_updater_service.h
@@ -9,7 +9,7 @@
 #include <vector>
 
 #include "base/version.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 namespace net {
 class URLRequestContextGetter;
@@ -20,6 +20,8 @@
 class FilePath;
 }
 
+class ComponentPatcher;
+
 // Component specific installers must derive from this class and implement
 // OnUpdateError() and Install(). A valid instance of this class must be
 // given to ComponentUpdateService::RegisterComponent().
@@ -37,32 +39,28 @@
   virtual bool Install(const base::DictionaryValue& manifest,
                        const base::FilePath& unpack_path) = 0;
 
+  // Set |installed_file| to the full path to the installed |file|. |file| is
+  // the filename of the file in this component's CRX. Returns false if this is
+  // not possible (the file has been removed or modified, or its current
+  // location is unknown). Otherwise, returns true.
+  virtual bool GetInstalledFile(const std::string& file,
+                                base::FilePath* installed_file) = 0;
+
  protected:
   virtual ~ComponentInstaller() {}
 };
 
 // Describes a particular component that can be installed or updated. This
 // structure is required to register a component with the component updater.
-// Only |name| is optional. |pk_hash| is the SHA256 hash of the component's
-// public key. If the component is to be installed then version should be
-// "0" or "0.0", else it should be the current version.
-// |source| is by default pointing to BANDAID but if needed it can be made
-// to point to the webstore (CWS_PUBLIC) or to the webstore sandbox. It is
-// important to note that the BANDAID source if active throught the day
-// can pre-empt updates from the other sources down the list.
+// |pk_hash| is the SHA256 hash of the component's public key. If the component
+// is to be installed then version should be "0" or "0.0", else it should be
+// the current version. |fingerprint| and |name| are optional.
 struct CrxComponent {
-  // Specifies the source url for manifest check.
-  enum UrlSource {
-    BANDAID,
-    CWS_PUBLIC,
-    CWS_SANDBOX
-  };
-
   std::vector<uint8> pk_hash;
   ComponentInstaller* installer;
   Version version;
+  std::string fingerprint;
   std::string name;
-  UrlSource source;
   CrxComponent();
   ~CrxComponent();
 };
@@ -115,7 +113,7 @@
     // for the same component.
     virtual int OnDemandDelay() = 0;
     // The url that is going to be used update checks over Omaha protocol.
-    virtual GURL UpdateUrl(CrxComponent::UrlSource source) = 0;
+    virtual GURL UpdateUrl() = 0;
     // Parameters added to each url request. It can be null if none are needed.
     virtual const char* ExtraRequestParams() = 0;
     // How big each update request can be. Don't go above 2000.
@@ -128,6 +126,11 @@
     // happens. It should be used mostly as a place to add application specific
     // logging or telemetry. |extra| is |event| dependent.
     virtual void OnEvent(Events event, int extra) = 0;
+    // Creates a new ComponentPatcher in a platform-specific way. This is useful
+    // for dependency injection.
+    virtual ComponentPatcher* CreateComponentPatcher() = 0;
+    // True means that this client can handle delta updates.
+    virtual bool DeltasEnabled() const = 0;
   };
 
   // Start doing update checks and installing new versions of registered
diff --git a/chrome/browser/component_updater/pepper_flash_component_installer.cc b/chrome/browser/component_updater/pepper_flash_component_installer.cc
index 696c6d9..c7cf4da 100644
--- a/chrome/browser/component_updater/pepper_flash_component_installer.cc
+++ b/chrome/browser/component_updater/pepper_flash_component_installer.cc
@@ -250,6 +250,9 @@
   virtual bool Install(const base::DictionaryValue& manifest,
                        const base::FilePath& unpack_path) OVERRIDE;
 
+  virtual bool GetInstalledFile(const std::string& file,
+                                base::FilePath* installed_file) OVERRIDE;
+
  private:
   Version current_version_;
 };
@@ -279,7 +282,7 @@
       GetPepperFlashBaseDirectory().AppendASCII(version.GetString());
   if (file_util::PathExists(path))
     return false;
-  if (!file_util::Move(unpack_path, path))
+  if (!base::Move(unpack_path, path))
     return false;
   // Installation is done. Now tell the rest of chrome. Both the path service
   // and to the plugin service.
@@ -292,6 +295,11 @@
   return true;
 }
 
+bool PepperFlashComponentInstaller::GetInstalledFile(
+    const std::string& file, base::FilePath* installed_file) {
+  return false;
+}
+
 bool CheckPepperFlashManifest(const base::DictionaryValue& manifest,
                               Version* version_out) {
   std::string name;
@@ -377,7 +385,7 @@
   // Remove older versions of Pepper Flash.
   for (std::vector<base::FilePath>::iterator iter = older_dirs.begin();
        iter != older_dirs.end(); ++iter) {
-    file_util::Delete(*iter, true);
+    base::Delete(*iter, true);
   }
 }
 #endif  // defined(GOOGLE_CHROME_BUILD) && !defined(OS_LINUX)
diff --git a/chrome/browser/component_updater/pnacl/pnacl_component_installer.cc b/chrome/browser/component_updater/pnacl/pnacl_component_installer.cc
index 8da767b..44b66f3 100644
--- a/chrome/browser/component_updater/pnacl/pnacl_component_installer.cc
+++ b/chrome/browser/component_updater/pnacl/pnacl_component_installer.cc
@@ -6,6 +6,7 @@
 
 #include "base/base_paths.h"
 #include "base/bind.h"
+#include "base/callback.h"
 #include "base/command_line.h"
 #include "base/compiler_specific.h"
 #include "base/file_util.h"
@@ -33,11 +34,6 @@
 
 namespace {
 
-// If PNaCl isn't installed yet, but a user is running chrome with
-// --enable-pnacl, this is the amount of time to wait before starting
-// a background install.
-const int kInitialDelaySeconds = 10;
-
 // Name of the Pnacl component specified in the manifest.
 const char kPnaclManifestName[] = "PNaCl Translator";
 
@@ -150,7 +146,10 @@
                                  Version* version_out) {
   // Make sure we have the right |manifest| file.
   std::string name;
-  manifest.GetStringASCII("name", &name);
+  if (!manifest.GetStringASCII("name", &name)) {
+    LOG(WARNING) << "'name' field is missing from manifest!";
+    return false;
+  }
   // For the webstore, we've given different names to each of the
   // architecture specific packages (and test/QA vs not test/QA)
   // so only part of it is the same.
@@ -162,7 +161,10 @@
   }
 
   std::string proposed_version;
-  manifest.GetStringASCII("version", &proposed_version);
+  if (!manifest.GetStringASCII("version", &proposed_version)) {
+    LOG(WARNING) << "'version' field is missing from manifest!";
+    return false;
+  }
   Version version(proposed_version.c_str());
   if (!version.IsValid()) {
     LOG(WARNING) << "'version' field in manifest is invalid "
@@ -172,7 +174,10 @@
 
   // Now check the |pnacl_manifest|.
   std::string arch;
-  pnacl_manifest.GetStringASCII("pnacl-arch", &arch);
+  if (!pnacl_manifest.GetStringASCII("pnacl-arch", &arch)) {
+    LOG(WARNING) << "'pnacl-arch' field is missing from pnacl-manifest!";
+    return false;
+  }
   if (arch.compare(OmahaQueryParams::getNaclArch()) != 0) {
     LOG(WARNING) << "'pnacl-arch' field in manifest is invalid ("
                  << arch << " vs " << OmahaQueryParams::getNaclArch() << ")";
@@ -185,10 +190,13 @@
 
 PnaclComponentInstaller::PnaclComponentInstaller()
     : per_user_(false),
-      cus_(NULL) {
+      updates_disabled_(false),
+      cus_(NULL),
+      callback_nums_(0) {
 #if defined(OS_CHROMEOS)
   per_user_ = true;
 #endif
+  updater_observer_.reset(new PnaclUpdaterObserver(this));
 }
 
 PnaclComponentInstaller::~PnaclComponentInstaller() {
@@ -232,56 +240,115 @@
 
 bool PnaclComponentInstaller::Install(const base::DictionaryValue& manifest,
                                       const base::FilePath& unpack_path) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
   scoped_ptr<base::DictionaryValue> pnacl_manifest(
       ReadPnaclManifest(unpack_path));
   if (pnacl_manifest == NULL) {
     LOG(WARNING) << "Failed to read pnacl manifest.";
+    NotifyInstallError();
     return false;
   }
 
   Version version;
   if (!CheckPnaclComponentManifest(manifest, *pnacl_manifest, &version)) {
     LOG(WARNING) << "CheckPnaclComponentManifest failed, not installing.";
+    NotifyInstallError();
     return false;
   }
 
   // Don't install if the current version is actually newer.
-  if (current_version().CompareTo(version) > 0)
+  if (current_version().CompareTo(version) > 0) {
+    NotifyInstallError();
     return false;
+  }
 
   // Passed the basic tests. Time to install it.
   base::FilePath path = GetPnaclBaseDirectory().AppendASCII(
       version.GetString());
   if (file_util::PathExists(path)) {
     LOG(WARNING) << "Target path already exists, not installing.";
+    NotifyInstallError();
     return false;
   }
-  if (!file_util::Move(unpack_path, path)) {
+  if (!base::Move(unpack_path, path)) {
     LOG(WARNING) << "Move failed, not installing.";
+    NotifyInstallError();
     return false;
   }
 
-  // Installation is done. Now tell the rest of chrome (just the path service
-  // for now). TODO(jvoung): we need notifications if someone surfed to a
-  // Pnacl webpage and Pnacl was just installed at this time. They should
-  // then be able to reload the page and retry (or something).
-  // See: http://code.google.com/p/chromium/issues/detail?id=107438
+  // Installation is done. Now tell the rest of chrome.
+  // - The path service.
+  // - Callbacks that requested an update.
   set_current_version(version);
-
+  NotifyInstallSuccess();
   OverrideDirPnaclComponent(path);
   return true;
 }
 
-namespace {
+// Given |file|, which can be a path like "_platform_specific/arm/pnacl_foo",
+// 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 PnaclComponentInstaller::GetInstalledFile(
+    const std::string& file, base::FilePath* installed_file) {
+  if (current_version().Equals(Version(kNullVersion)))
+    return false;
 
-void DoCheckForUpdate(ComponentUpdateService* cus,
-                   const CrxComponent& pnacl) {
-  if (cus->CheckForUpdateSoon(pnacl) != ComponentUpdateService::kOk) {
-    LOG(WARNING) << "Pnacl check for update failed.";
+  *installed_file = GetPnaclBaseDirectory().AppendASCII(
+      current_version().GetString()).AppendASCII(file);
+  return true;
+}
+
+void PnaclComponentInstaller::AddInstallCallback(
+    const InstallCallback& cb) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  int num = ++callback_nums_;
+  install_callbacks_.push_back(std::make_pair(cb, num));
+}
+
+void PnaclComponentInstaller::CancelCallback(int num) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  for (std::list<std::pair<InstallCallback, int> >::iterator
+           i = install_callbacks_.begin(),
+           e = install_callbacks_.end(); i != e; ++i) {
+    if (i->second == num) {
+      i->first.Run(false);
+      install_callbacks_.erase(i);
+      return;
+    }
   }
 }
 
-// Finally, do the registration with the right version number.
+void PnaclComponentInstaller::NotifyAllWithResult(bool status) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  while (!install_callbacks_.empty()) {
+    install_callbacks_.front().first.Run(status);
+    install_callbacks_.pop_front();
+  }
+}
+
+void PnaclComponentInstaller::NotifyInstallError() {
+  if (!install_callbacks_.empty()) {
+    BrowserThread::PostTask(
+        BrowserThread::UI, FROM_HERE,
+        base::Bind(&PnaclComponentInstaller::NotifyAllWithResult,
+                   // Unretained because installer lives until process shutdown.
+                   base::Unretained(this), false));
+  }
+}
+
+void PnaclComponentInstaller::NotifyInstallSuccess() {
+  if (!install_callbacks_.empty()) {
+    BrowserThread::PostTask(
+        BrowserThread::UI, FROM_HERE,
+        base::Bind(&PnaclComponentInstaller::NotifyAllWithResult,
+                   // Unretained because installer lives until process shutdown.
+                   base::Unretained(this), true));
+  }
+}
+
+namespace {
+
 void FinishPnaclUpdateRegistration(const Version& current_version,
                                    PnaclComponentInstaller* pci) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
@@ -298,17 +365,6 @@
       && status != ComponentUpdateService::kReplaced) {
     NOTREACHED() << "Pnacl component registration failed.";
   }
-
-  // If PNaCl is not yet installed but it is requested by --enable-pnacl,
-  // we want it to be available "soon", so kick off an update check
-  // earlier than usual.
-  Version null_version(kNullVersion);
-  if (pci->current_version().Equals(null_version)) {
-    BrowserThread::PostDelayedTask(
-        BrowserThread::UI, FROM_HERE,
-        base::Bind(DoCheckForUpdate, pci->cus(), pnacl_component),
-        base::TimeDelta::FromSeconds(kInitialDelaySeconds));
-  }
 }
 
 // Check if there is an existing version on disk first to know when
@@ -334,8 +390,10 @@
     // Check that the component manifest and PNaCl manifest files
     // are legit, and that the indicated version matches the one
     // encoded within the path name.
-    if (!CheckPnaclComponentManifest(*manifest, *pnacl_manifest,
-                                     &manifest_version)
+    if (manifest == NULL || pnacl_manifest == NULL
+        || !CheckPnaclComponentManifest(*manifest,
+                                        *pnacl_manifest,
+                                        &manifest_version)
         || !version.Equals(manifest_version)) {
       version = Version(kNullVersion);
     } else {
@@ -343,6 +401,13 @@
     }
   }
 
+  // If updates are disabled, only discover the current version
+  // and OverrideDirPnaclComponent. That way, developers can use
+  // a pinned version. Do not actually finish registration with
+  // the component update service.
+  if (pci->updates_disabled())
+    return;
+
   BrowserThread::PostTask(
       BrowserThread::UI, FROM_HERE,
       base::Bind(&FinishPnaclUpdateRegistration, version, pci));
@@ -350,7 +415,7 @@
   // Remove older versions of PNaCl.
   for (std::vector<base::FilePath>::iterator iter = older_dirs.begin();
        iter != older_dirs.end(); ++iter) {
-    file_util::Delete(*iter, true);
+    base::Delete(*iter, true);
   }
 }
 
@@ -373,36 +438,48 @@
 void PnaclComponentInstaller::RegisterPnaclComponent(
                             ComponentUpdateService* cus,
                             const CommandLine& command_line) {
-  // Only register when given the right flag.  This is important since
-  // we do an early component updater check above (in DoCheckForUpdate).
-  if (command_line.HasSwitch(switches::kEnablePnacl)) {
-    cus_ = cus;
-    // If per_user, create a profile observer to watch for logins.
-    // Only do so after cus_ is set to something non-null.
-    if (per_user_ && !profile_observer_) {
-      profile_observer_.reset(new PnaclProfileObserver(this));
-    }
-    if (per_user_) {
-      // Figure out profile information, before proceeding to look for files.
-      BrowserThread::PostTask(
-           BrowserThread::UI, FROM_HERE,
-           base::Bind(&GetProfileInformation, this));
-    } else {
-      BrowserThread::PostTask(
-           BrowserThread::FILE, FROM_HERE,
-           base::Bind(&StartPnaclUpdateRegistration, this));
-    }
+  // Register PNaCl by default (can be disabled).
+  updates_disabled_ = command_line.HasSwitch(switches::kDisablePnaclInstall);
+  cus_ = cus;
+  // If per_user, create a profile observer to watch for logins.
+  // Only do so after cus_ is set to something non-null.
+  if (per_user_ && !profile_observer_) {
+    profile_observer_.reset(new PnaclProfileObserver(this));
+  }
+  if (per_user_) {
+    // Figure out profile information, before proceeding to look for files.
+    BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+                            base::Bind(&GetProfileInformation, this));
+  } else {
+    BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
+                            base::Bind(&StartPnaclUpdateRegistration, this));
   }
 }
 
 void PnaclComponentInstaller::ReRegisterPnacl() {
-  // No need to check the commandline flags again here.
-  // We could only have gotten here after RegisterPnaclComponent
-  // found --enable-pnacl, since that is where we create the profile_observer_,
-  // which in turn calls ReRegisterPnacl.
   DCHECK(per_user_);
   // Figure out profile information, before proceeding to look for files.
   BrowserThread::PostTask(
       BrowserThread::UI, FROM_HERE,
       base::Bind(&GetProfileInformation, this));
 }
+
+void RequestFirstInstall(ComponentUpdateService* cus,
+                         PnaclComponentInstaller* pci,
+                          const base::Callback<void(bool)>& installed) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  Version null_version(kNullVersion);
+  CrxComponent pnacl_component;
+  pci->set_current_version(null_version);
+  pnacl_component.version = null_version;
+  pnacl_component.name = "pnacl";
+  pnacl_component.installer = pci;
+  SetPnaclHash(&pnacl_component);
+  ComponentUpdateService::Status status = cus->CheckForUpdateSoon(
+      pnacl_component);
+  if (status != ComponentUpdateService::kOk) {
+    installed.Run(false);
+    return;
+  }
+  pci->AddInstallCallback(installed);
+}
diff --git a/chrome/browser/component_updater/pnacl/pnacl_component_installer.h b/chrome/browser/component_updater/pnacl/pnacl_component_installer.h
index 9ba2997..88fb61f 100644
--- a/chrome/browser/component_updater/pnacl/pnacl_component_installer.h
+++ b/chrome/browser/component_updater/pnacl/pnacl_component_installer.h
@@ -5,11 +5,16 @@
 #ifndef CHROME_BROWSER_COMPONENT_UPDATER_PNACL_PNACL_COMPONENT_INSTALLER_H_
 #define CHROME_BROWSER_COMPONENT_UPDATER_PNACL_PNACL_COMPONENT_INSTALLER_H_
 
+#include <list>
+
+#include "base/callback_forward.h"
+#include "base/compiler_specific.h"
 #include "base/files/file_path.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/version.h"
 #include "chrome/browser/component_updater/component_updater_service.h"
 #include "chrome/browser/component_updater/pnacl/pnacl_profile_observer.h"
+#include "chrome/browser/component_updater/pnacl/pnacl_updater_observer.h"
 
 class CommandLine;
 
@@ -31,6 +36,9 @@
   virtual bool Install(const base::DictionaryValue& manifest,
                        const base::FilePath& unpack_path) OVERRIDE;
 
+  virtual bool GetInstalledFile(const std::string& file,
+                                base::FilePath* installed_file) OVERRIDE;
+
   // Register a PNaCl component for the first time.
   void RegisterPnaclComponent(ComponentUpdateService* cus,
                               const CommandLine& command_line);
@@ -39,11 +47,15 @@
   // updater service.
   void ReRegisterPnacl();
 
+  // Return true if PNaCl installs are separated by user.
   bool per_user() const { return per_user_; }
 
   // If per_user, function to call when profile is changed.
   void OnProfileChange();
 
+  // Return true if PNaCl updates are disabled.
+  bool updates_disabled() const { return updates_disabled_; }
+
   // Determine the base directory for storing each version of PNaCl.
   base::FilePath GetPnaclBaseDirectory();
 
@@ -53,12 +65,32 @@
 
   ComponentUpdateService* cus() const { return cus_; }
 
+  typedef base::Callback<void(bool)> InstallCallback;
+  void AddInstallCallback(const InstallCallback& cb);
+
+  void NotifyInstallError();
+
+  void NotifyInstallSuccess();
+
  private:
+  // Cancel a particular callback after a timeout.
+  void CancelCallback(int callback_num);
+
+  void NotifyAllWithResult(bool status);
+
   bool per_user_;
+  bool updates_disabled_;
   scoped_ptr<PnaclProfileObserver> profile_observer_;
   base::FilePath current_profile_path_;
   base::Version current_version_;
   ComponentUpdateService* cus_;
+  // Counter to issue identifiers to each callback.
+  int callback_nums_;
+  // List of callbacks to issue when an install completes successfully.
+  std::list<std::pair<InstallCallback, int> > install_callbacks_;
+  // Component updater service observer, to determine when an on-demand
+  // install request failed.
+  scoped_ptr<PnaclUpdaterObserver> updater_observer_;
   DISALLOW_COPY_AND_ASSIGN(PnaclComponentInstaller);
 };
 
@@ -67,4 +99,11 @@
 bool CheckPnaclComponentManifest(const base::DictionaryValue& manifest,
                                  base::Version* version_out);
 
+// Ask the given component updater service to do a first-install for PNaCl.
+// The |installed| callback will be run with |true| on success,
+// or run with |false| on an error. The callback is called on the UI thread.
+void RequestFirstInstall(ComponentUpdateService* cus,
+                         PnaclComponentInstaller* pci,
+                         const base::Callback<void(bool)>& installed);
+
 #endif  // CHROME_BROWSER_COMPONENT_UPDATER_PNACL_PNACL_COMPONENT_INSTALLER_H_
diff --git a/chrome/browser/component_updater/pnacl/pnacl_profile_observer.h b/chrome/browser/component_updater/pnacl/pnacl_profile_observer.h
index 52ab984..18ef4e8 100644
--- a/chrome/browser/component_updater/pnacl/pnacl_profile_observer.h
+++ b/chrome/browser/component_updater/pnacl/pnacl_profile_observer.h
@@ -5,6 +5,7 @@
 #ifndef CHROME_BROWSER_COMPONENT_UPDATER_PNACL_PNACL_PROFILE_OBSERVER_H_
 #define CHROME_BROWSER_COMPONENT_UPDATER_PNACL_PNACL_PROFILE_OBSERVER_H_
 
+#include "base/compiler_specific.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
 
diff --git a/chrome/browser/component_updater/pnacl/pnacl_updater_observer.cc b/chrome/browser/component_updater/pnacl/pnacl_updater_observer.cc
new file mode 100644
index 0000000..2a3a6fa
--- /dev/null
+++ b/chrome/browser/component_updater/pnacl/pnacl_updater_observer.cc
@@ -0,0 +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.
+
+#include "chrome/browser/component_updater/pnacl/pnacl_updater_observer.h"
+
+#include "base/logging.h"
+#include "chrome/browser/component_updater/pnacl/pnacl_component_installer.h"
+#include "chrome/common/chrome_notification_types.h"
+#include "content/public/browser/notification_service.h"
+
+PnaclUpdaterObserver::PnaclUpdaterObserver(
+    PnaclComponentInstaller* installer) : pnacl_installer_(installer) {
+  registrar_.Add(this,
+                 chrome::NOTIFICATION_COMPONENT_UPDATER_SLEEPING,
+                 content::NotificationService::AllSources());
+}
+
+PnaclUpdaterObserver::~PnaclUpdaterObserver() { }
+
+void PnaclUpdaterObserver::Observe(
+    int type,
+    const content::NotificationSource& source,
+    const content::NotificationDetails& details) {
+  if (type == chrome::NOTIFICATION_COMPONENT_UPDATER_SLEEPING) {
+    // If the component updater sleeps before a NotifyInstallSuccess,
+    // then requests for installs were likely skipped, or an error occurred.
+    pnacl_installer_->NotifyInstallError();
+    return;
+  }
+}
diff --git a/chrome/browser/component_updater/pnacl/pnacl_updater_observer.h b/chrome/browser/component_updater/pnacl/pnacl_updater_observer.h
new file mode 100644
index 0000000..48a6f0d
--- /dev/null
+++ b/chrome/browser/component_updater/pnacl/pnacl_updater_observer.h
@@ -0,0 +1,32 @@
+// 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_COMPONENT_UPDATER_PNACL_PNACL_UPDATER_OBSERVER_H_
+#define CHROME_BROWSER_COMPONENT_UPDATER_PNACL_PNACL_UPDATER_OBSERVER_H_
+
+#include "base/compiler_specific.h"
+#include "content/public/browser/notification_observer.h"
+#include "content/public/browser/notification_registrar.h"
+
+class PnaclComponentInstaller;
+
+// Monitors the component updater service, so that the callbacks registered
+// against the PnaclComponentInstaller can be notified of events.
+class PnaclUpdaterObserver : public content::NotificationObserver {
+ public:
+  explicit PnaclUpdaterObserver(PnaclComponentInstaller* installer);
+  virtual ~PnaclUpdaterObserver();
+
+  virtual void Observe(
+      int type,
+      const content::NotificationSource& source,
+      const content::NotificationDetails& details) OVERRIDE;
+
+ private:
+  content::NotificationRegistrar registrar_;
+  PnaclComponentInstaller* pnacl_installer_;
+  DISALLOW_COPY_AND_ASSIGN(PnaclUpdaterObserver);
+};
+
+#endif  // CHROME_BROWSER_COMPONENT_UPDATER_PNACL_PNACL_UPDATER_OBSERVER_H_
diff --git a/chrome/browser/component_updater/recovery_component_installer.cc b/chrome/browser/component_updater/recovery_component_installer.cc
index c2a7d5a..4891aab 100644
--- a/chrome/browser/component_updater/recovery_component_installer.cc
+++ b/chrome/browser/component_updater/recovery_component_installer.cc
@@ -56,6 +56,9 @@
   virtual bool Install(const base::DictionaryValue& manifest,
                        const base::FilePath& unpack_path) OVERRIDE;
 
+  virtual bool GetInstalledFile(const std::string& file,
+                                base::FilePath* installed_file) OVERRIDE;
+
  private:
   Version current_version_;
   PrefService* prefs_;
@@ -130,6 +133,11 @@
   return base::LaunchProcess(cmdline, base::LaunchOptions(), NULL);
 }
 
+bool RecoveryComponentInstaller::GetInstalledFile(
+    const std::string& file, base::FilePath* installed_file) {
+  return false;
+}
+
 void RegisterRecoveryComponent(ComponentUpdateService* cus,
                                PrefService* prefs) {
 #if !defined(OS_CHROMEOS)
diff --git a/chrome/browser/component_updater/swiftshader_component_installer.cc b/chrome/browser/component_updater/swiftshader_component_installer.cc
index e09e524..9aa42e0 100644
--- a/chrome/browser/component_updater/swiftshader_component_installer.cc
+++ b/chrome/browser/component_updater/swiftshader_component_installer.cc
@@ -105,6 +105,9 @@
   virtual bool Install(const base::DictionaryValue& manifest,
                        const base::FilePath& unpack_path) OVERRIDE;
 
+  virtual bool GetInstalledFile(const std::string& file,
+                                base::FilePath* installed_file) OVERRIDE;
+
  private:
   Version current_version_;
 };
@@ -140,7 +143,7 @@
       GetSwiftShaderBaseDirectory().AppendASCII(version.GetString());
   if (file_util::PathExists(path))
     return false;
-  if (!file_util::Move(unpack_path, path))
+  if (!base::Move(unpack_path, path))
     return false;
   // Installation is done. Now tell the rest of chrome.
   current_version_ = version;
@@ -149,6 +152,11 @@
   return true;
 }
 
+bool SwiftShaderComponentInstaller::GetInstalledFile(
+    const std::string& file, base::FilePath* installed_file) {
+  return false;
+}
+
 void FinishSwiftShaderUpdateRegistration(ComponentUpdateService* cus,
                                          const Version& version) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
@@ -222,7 +230,7 @@
   // Remove older versions of SwiftShader.
   for (std::vector<base::FilePath>::iterator iter = older_dirs.begin();
        iter != older_dirs.end(); ++iter) {
-    file_util::Delete(*iter, true);
+    base::Delete(*iter, true);
   }
 }
 
diff --git a/chrome/browser/component_updater/test/DEPS b/chrome/browser/component_updater/test/DEPS
index e63018d..397b12e 100644
--- a/chrome/browser/component_updater/test/DEPS
+++ b/chrome/browser/component_updater/test/DEPS
@@ -1,4 +1,5 @@
 include_rules = [
   # For access to the ppapi test globals.
   "+ppapi/shared_impl",
+  "+courgette",
 ]
diff --git a/chrome/browser/component_updater/test/component_patcher_mock.h b/chrome/browser/component_updater/test/component_patcher_mock.h
new file mode 100644
index 0000000..1843b29
--- /dev/null
+++ b/chrome/browser/component_updater/test/component_patcher_mock.h
@@ -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.
+
+#ifndef CHROME_BROWSER_COMPONENT_UPDATER_TEST_COMPONENT_PATCHER_MOCK_H_
+#define CHROME_BROWSER_COMPONENT_UPDATER_TEST_COMPONENT_PATCHER_MOCK_H_
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "chrome/browser/component_updater/component_patcher.h"
+
+namespace base {
+class FilePath;
+}
+
+class MockComponentPatcher : public ComponentPatcher {
+ public:
+  MockComponentPatcher() {}
+  virtual ComponentUnpacker::Error Patch(PatchType patch_type,
+                                         const base::FilePath& input_file,
+                                         const base::FilePath& patch_file,
+                                         const base::FilePath& output_file,
+                                         int* error) OVERRIDE;
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MockComponentPatcher);
+};
+
+#endif  // CHROME_BROWSER_COMPONENT_UPDATER_TEST_COMPONENT_PATCHER_MOCK_H_
diff --git a/chrome/browser/component_updater/test/component_patcher_unittest.cc b/chrome/browser/component_updater/test/component_patcher_unittest.cc
new file mode 100644
index 0000000..7593a4b
--- /dev/null
+++ b/chrome/browser/component_updater/test/component_patcher_unittest.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 "base/compiler_specific.h"
+#include "base/file_util.h"
+#include "base/files/file_path.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/path_service.h"
+#include "base/values.h"
+#include "chrome/browser/component_updater/component_patcher.h"
+#include "chrome/browser/component_updater/component_patcher_operation.h"
+#include "chrome/browser/component_updater/component_updater_service.h"
+#include "chrome/browser/component_updater/test/component_patcher_mock.h"
+#include "chrome/browser/component_updater/test/component_patcher_unittest.h"
+#include "chrome/browser/component_updater/test/test_installer.h"
+#include "chrome/common/chrome_paths.h"
+#include "courgette/courgette.h"
+#include "courgette/third_party/bsdiff.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+base::FilePath test_file(const char* file) {
+  base::FilePath path;
+  PathService::Get(chrome::DIR_TEST_DATA, &path);
+  return path.AppendASCII("components").AppendASCII(file);
+}
+
+ComponentPatcherOperationTest::ComponentPatcherOperationTest() {
+  EXPECT_TRUE(unpack_dir_.CreateUniqueTempDir());
+  EXPECT_TRUE(input_dir_.CreateUniqueTempDir());
+  EXPECT_TRUE(installed_dir_.CreateUniqueTempDir());
+  patcher_.reset(new MockComponentPatcher());
+  installer_.reset(new ReadOnlyTestInstaller(installed_dir_.path()));
+}
+
+ComponentPatcherOperationTest::~ComponentPatcherOperationTest() {
+}
+
+ComponentUnpacker::Error MockComponentPatcher::Patch(
+    PatchType patch_type,
+    const base::FilePath& input_file,
+    const base::FilePath& patch_file,
+    const base::FilePath& output_file,
+    int* error) {
+  *error = 0;
+  int exit_code;
+  if (patch_type == kPatchTypeCourgette) {
+    exit_code = courgette::ApplyEnsemblePatch(input_file.value().c_str(),
+                                              patch_file.value().c_str(),
+                                              output_file.value().c_str());
+    if (exit_code == courgette::C_OK)
+      return ComponentUnpacker::kNone;
+    *error = exit_code + kCourgetteErrorOffset;
+  } else if (patch_type == kPatchTypeBsdiff) {
+    exit_code = courgette::ApplyBinaryPatch(input_file,
+                                            patch_file,
+                                            output_file);
+    if (exit_code == courgette::OK)
+      return ComponentUnpacker::kNone;
+    *error = exit_code + kBsdiffErrorOffset;
+  }
+  return ComponentUnpacker::kDeltaOperationFailure;
+}
+
+// Verify that a 'create' delta update operation works correctly.
+TEST_F(ComponentPatcherOperationTest, CheckCreateOperation) {
+  EXPECT_TRUE(file_util::CopyFile(
+      test_file("binary_output.bin"),
+      input_dir_.path().Append(FILE_PATH_LITERAL("binary_output.bin"))));
+
+  scoped_ptr<base::DictionaryValue> command_args(new base::DictionaryValue());
+  command_args->SetString("output", "output.bin");
+  command_args->SetString("sha256", binary_output_hash);
+  command_args->SetString("op", "create");
+  command_args->SetString("patch", "binary_output.bin");
+
+  int error = 0;
+  scoped_ptr<DeltaUpdateOp> op(new DeltaUpdateOpCreate());
+  ComponentUnpacker::Error result = op->Run(command_args.get(),
+                                     input_dir_.path(),
+                                     unpack_dir_.path(),
+                                     patcher_.get(),
+                                     NULL,
+                                     &error);
+
+  EXPECT_EQ(ComponentUnpacker::kNone, result);
+  EXPECT_EQ(0, error);
+  EXPECT_TRUE(file_util::ContentsEqual(
+      unpack_dir_.path().Append(FILE_PATH_LITERAL("output.bin")),
+      test_file("binary_output.bin")));
+}
+
+// Verify that a 'copy' delta update operation works correctly.
+TEST_F(ComponentPatcherOperationTest, CheckCopyOperation) {
+  EXPECT_TRUE(file_util::CopyFile(
+      test_file("binary_output.bin"),
+      installed_dir_.path().Append(FILE_PATH_LITERAL("binary_output.bin"))));
+
+  scoped_ptr<base::DictionaryValue> command_args(new base::DictionaryValue());
+  command_args->SetString("output", "output.bin");
+  command_args->SetString("sha256", binary_output_hash);
+  command_args->SetString("op", "copy");
+  command_args->SetString("input", "binary_output.bin");
+
+  int error = 0;
+  scoped_ptr<DeltaUpdateOp> op(new DeltaUpdateOpCopy());
+  ComponentUnpacker::Error result = op->Run(command_args.get(),
+                                     input_dir_.path(),
+                                     unpack_dir_.path(),
+                                     patcher_.get(),
+                                     installer_.get(),
+                                     &error);
+  EXPECT_EQ(ComponentUnpacker::kNone, result);
+  EXPECT_EQ(0, error);
+  EXPECT_TRUE(file_util::ContentsEqual(
+      unpack_dir_.path().Append(FILE_PATH_LITERAL("output.bin")),
+      test_file("binary_output.bin")));
+}
diff --git a/chrome/browser/component_updater/test/component_patcher_unittest.h b/chrome/browser/component_updater/test/component_patcher_unittest.h
new file mode 100644
index 0000000..ee30308
--- /dev/null
+++ b/chrome/browser/component_updater/test/component_patcher_unittest.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 CHROME_BROWSER_COMPONENT_UPDATER_TEST_COMPONENT_PATCHER_UNITTEST_H_
+#define CHROME_BROWSER_COMPONENT_UPDATER_TEST_COMPONENT_PATCHER_UNITTEST_H_
+
+#include "base/files/file_path.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/memory/scoped_ptr.h"
+#include "chrome/common/chrome_paths.h"
+#include "courgette/courgette.h"
+#include "courgette/third_party/bsdiff.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+class MockComponentPatcher;
+class ReadOnlyTestInstaller;
+
+const char binary_output_hash[] =
+    "599aba6d15a7da390621ef1bacb66601ed6aed04dadc1f9b445dcfe31296142a";
+
+// These constants are duplicated from chrome/installer/util/util_constants.h,
+// to avoid introducing a dependency from the unit tests to the installer.
+const int kCourgetteErrorOffset = 300;
+const int kBsdiffErrorOffset = 600;
+
+base::FilePath test_file(const char* file);
+
+class ComponentPatcherOperationTest : public testing::Test {
+ public:
+  explicit ComponentPatcherOperationTest();
+  virtual ~ComponentPatcherOperationTest();
+
+ protected:
+  base::ScopedTempDir input_dir_;
+  base::ScopedTempDir installed_dir_;
+  base::ScopedTempDir unpack_dir_;
+  scoped_ptr<MockComponentPatcher> patcher_;
+  scoped_ptr<ReadOnlyTestInstaller> installer_;
+};
+
+#endif  // CHROME_BROWSER_COMPONENT_UPDATER_TEST_COMPONENT_PATCHER_UNITTEST_H_
diff --git a/chrome/browser/component_updater/test/component_patcher_unittest_win.cc b/chrome/browser/component_updater/test/component_patcher_unittest_win.cc
new file mode 100644
index 0000000..896cf59
--- /dev/null
+++ b/chrome/browser/component_updater/test/component_patcher_unittest_win.cc
@@ -0,0 +1,83 @@
+// 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/compiler_specific.h"
+#include "base/file_util.h"
+#include "base/files/file_path.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/path_service.h"
+#include "base/values.h"
+#include "chrome/browser/component_updater/component_patcher.h"
+#include "chrome/browser/component_updater/component_patcher_operation.h"
+#include "chrome/browser/component_updater/component_updater_service.h"
+#include "chrome/browser/component_updater/test/component_patcher_mock.h"
+#include "chrome/browser/component_updater/test/component_patcher_unittest.h"
+#include "chrome/browser/component_updater/test/test_installer.h"
+#include "chrome/common/chrome_paths.h"
+#include "courgette/courgette.h"
+#include "courgette/third_party/bsdiff.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+// Verify that a 'courgette' delta update operation works correctly.
+TEST_F(ComponentPatcherOperationTest, CheckCourgetteOperation) {
+  EXPECT_TRUE(file_util::CopyFile(
+      test_file("binary_input.bin"),
+      installed_dir_.path().Append(FILE_PATH_LITERAL("binary_input.bin"))));
+  EXPECT_TRUE(file_util::CopyFile(
+      test_file("binary_courgette_patch.bin"),
+      input_dir_.path().Append(
+          FILE_PATH_LITERAL("binary_courgette_patch.bin"))));
+
+  scoped_ptr<base::DictionaryValue> command_args(new base::DictionaryValue());
+  command_args->SetString("output", "output.bin");
+  command_args->SetString("sha256", binary_output_hash);
+  command_args->SetString("op", "courgette");
+  command_args->SetString("input", "binary_input.bin");
+  command_args->SetString("patch", "binary_courgette_patch.bin");
+
+  int error = 0;
+  scoped_ptr<DeltaUpdateOp> op(new DeltaUpdateOpPatchCourgette());
+  ComponentUnpacker::Error result = op->Run(command_args.get(),
+                                     input_dir_.path(),
+                                     unpack_dir_.path(),
+                                     patcher_.get(),
+                                     installer_.get(),
+                                     &error);
+  EXPECT_EQ(ComponentUnpacker::kNone, result);
+  EXPECT_EQ(0, error);
+  EXPECT_TRUE(file_util::ContentsEqual(
+      unpack_dir_.path().Append(FILE_PATH_LITERAL("output.bin")),
+      test_file("binary_output.bin")));
+}
+
+// Verify that a 'bsdiff' delta update operation works correctly.
+TEST_F(ComponentPatcherOperationTest, CheckBsdiffOperation) {
+  EXPECT_TRUE(file_util::CopyFile(
+      test_file("binary_input.bin"),
+      installed_dir_.path().Append(FILE_PATH_LITERAL("binary_input.bin"))));
+  EXPECT_TRUE(file_util::CopyFile(
+      test_file("binary_bsdiff_patch.bin"),
+      input_dir_.path().Append(FILE_PATH_LITERAL("binary_bsdiff_patch.bin"))));
+
+  scoped_ptr<base::DictionaryValue> command_args(new base::DictionaryValue());
+  command_args->SetString("output", "output.bin");
+  command_args->SetString("sha256", binary_output_hash);
+  command_args->SetString("op", "courgette");
+  command_args->SetString("input", "binary_input.bin");
+  command_args->SetString("patch", "binary_bsdiff_patch.bin");
+
+  int error = 0;
+  scoped_ptr<DeltaUpdateOp> op(new DeltaUpdateOpPatchBsdiff());
+  ComponentUnpacker::Error result = op->Run(command_args.get(),
+                                     input_dir_.path(),
+                                     unpack_dir_.path(),
+                                     patcher_.get(),
+                                     installer_.get(),
+                                     &error);
+  EXPECT_EQ(ComponentUnpacker::kNone, result);
+  EXPECT_EQ(0, error);
+  EXPECT_TRUE(file_util::ContentsEqual(
+      unpack_dir_.path().Append(FILE_PATH_LITERAL("output.bin")),
+      test_file("binary_output.bin")));
+}
diff --git a/chrome/browser/component_updater/test/component_updater_service_unittest.cc b/chrome/browser/component_updater/test/component_updater_service_unittest.cc
index 080b1d2..9277e88 100644
--- a/chrome/browser/component_updater/test/component_updater_service_unittest.cc
+++ b/chrome/browser/component_updater/test/component_updater_service_unittest.cc
@@ -2,18 +2,21 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/component_updater/component_updater_service.h"
-
 #include <list>
 #include <utility>
-
 #include "base/compiler_specific.h"
 #include "base/file_util.h"
 #include "base/files/file_path.h"
 #include "base/memory/scoped_vector.h"
 #include "base/message_loop.h"
 #include "base/path_service.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/stringprintf.h"
 #include "base/values.h"
+#include "chrome/browser/component_updater/component_updater_service.h"
+#include "chrome/browser/component_updater/test/component_patcher_mock.h"
+#include "chrome/browser/component_updater/test/component_updater_service_unittest.h"
+#include "chrome/browser/component_updater/test/test_installer.h"
 #include "chrome/common/chrome_notification_types.h"
 #include "chrome/common/chrome_paths.h"
 #include "content/public/browser/notification_observer.h"
@@ -21,244 +24,178 @@
 #include "content/public/test/test_browser_thread.h"
 #include "content/public/test/test_notification_tracker.h"
 #include "content/test/net/url_request_prepackaged_interceptor.h"
-#include "googleurl/src/gurl.h"
 #include "libxml/globals.h"
+#include "net/base/upload_bytes_element_reader.h"
 #include "net/url_request/url_fetcher.h"
+#include "net/url_request/url_request.h"
+#include "net/url_request/url_request_filter.h"
+#include "net/url_request/url_request_simple_job.h"
 #include "net/url_request/url_request_test_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
 
 using content::BrowserThread;
 using content::TestNotificationTracker;
 
-namespace {
-// Overrides some of the component updater behaviors so it is easier to test
-// and loops faster. In actual usage it takes hours do to a full cycle.
-class TestConfigurator : public ComponentUpdateService::Configurator {
- public:
-  TestConfigurator()
-      : times_(1), recheck_time_(0), ondemand_time_(0), cus_(NULL) {
-  }
+TestConfigurator::TestConfigurator()
+    : times_(1), recheck_time_(0), ondemand_time_(0), cus_(NULL) {
+}
 
-  virtual int InitialDelay() OVERRIDE { return 0; }
+TestConfigurator::~TestConfigurator() {
+}
 
-  typedef std::pair<CrxComponent*, int> CheckAtLoopCount;
+int TestConfigurator::InitialDelay() { return 0; }
 
-  virtual int NextCheckDelay() OVERRIDE {
-    // This is called when a new full cycle of checking for updates is going
-    // to happen. In test we normally only test one cycle so it is a good
-    // time to break from the test messageloop Run() method so the test can
-    // finish.
-    if (--times_ <= 0) {
-      base::MessageLoop::current()->Quit();
-      return 0;
-
-    }
-
-    // Look for checks to issue in the middle of the loop.
-    for (std::list<CheckAtLoopCount>::iterator
-             i = components_to_check_.begin();
-         i != components_to_check_.end(); ) {
-      if (i->second == times_) {
-        cus_->CheckForUpdateSoon(*i->first);
-        i = components_to_check_.erase(i);
-      } else {
-        ++i;
-      }
-    }
-    return 1;
-  }
-
-  virtual int StepDelay() OVERRIDE {
+int TestConfigurator::NextCheckDelay() {
+  // This is called when a new full cycle of checking for updates is going
+  // to happen. In test we normally only test one cycle so it is a good
+  // time to break from the test messageloop Run() method so the test can
+  // finish.
+  if (--times_ <= 0) {
+    base::MessageLoop::current()->Quit();
     return 0;
   }
 
-  virtual int MinimumReCheckWait() OVERRIDE {
-    return recheck_time_;
+  // Look for checks to issue in the middle of the loop.
+  for (std::list<CheckAtLoopCount>::iterator
+           i = components_to_check_.begin();
+       i != components_to_check_.end(); ) {
+    if (i->second == times_) {
+      cus_->CheckForUpdateSoon(*i->first);
+      i = components_to_check_.erase(i);
+    } else {
+      ++i;
+    }
   }
+  return 1;
+}
 
-  virtual int OnDemandDelay() OVERRIDE {
-    return ondemand_time_;
-  }
+int TestConfigurator::StepDelay() {
+  return 0;
+}
 
-  virtual GURL UpdateUrl(CrxComponent::UrlSource source) OVERRIDE {
-    switch (source) {
-      case CrxComponent::BANDAID:
-        return GURL("http://localhost/upd");
-      case CrxComponent::CWS_PUBLIC:
-        return GURL("http://localhost/cws");
-      default:
-        return GURL("http://wronghost/bad");
-    };
-  }
+int TestConfigurator::MinimumReCheckWait() {
+  return recheck_time_;
+}
 
-  virtual const char* ExtraRequestParams() OVERRIDE { return "extra=foo"; }
+int TestConfigurator::OnDemandDelay() {
+  return ondemand_time_;
+}
 
-  virtual size_t UrlSizeLimit() OVERRIDE { return 256; }
+GURL TestConfigurator::UpdateUrl() {
+  return GURL("http://localhost/upd");
+}
 
-  virtual net::URLRequestContextGetter* RequestContext() OVERRIDE {
-    return new net::TestURLRequestContextGetter(
-        BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO));
-  }
+const char* TestConfigurator::ExtraRequestParams() { return "extra=foo"; }
 
-  // Don't use the utility process to decode files.
-  virtual bool InProcess() OVERRIDE { return true; }
+size_t TestConfigurator::UrlSizeLimit() { return 256; }
 
-  virtual void OnEvent(Events event, int extra) OVERRIDE { }
+net::URLRequestContextGetter* TestConfigurator::RequestContext() {
+  return new net::TestURLRequestContextGetter(
+      BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO));
+}
 
-  // Set how many update checks are called, the default value is just once.
-  void SetLoopCount(int times) { times_ = times; }
+// Don't use the utility process to decode files.
+bool TestConfigurator::InProcess() { return true; }
 
-  void SetRecheckTime(int seconds) {
-    recheck_time_ = seconds;
-  }
+void TestConfigurator::OnEvent(Events event, int extra) { }
 
-  void SetOnDemandTime(int seconds) {
-    ondemand_time_ = seconds;
-  }
+ComponentPatcher* TestConfigurator::CreateComponentPatcher() {
+  return new MockComponentPatcher();
+}
 
-  void AddComponentToCheck(CrxComponent* com, int at_loop_iter) {
-    components_to_check_.push_back(std::make_pair(com, at_loop_iter));
-  }
+bool TestConfigurator::DeltasEnabled() const {
+  return true;
+}
 
-  void SetComponentUpdateService(ComponentUpdateService* cus) {
-    cus_ = cus;
-  }
+// Set how many update checks are called, the default value is just once.
+void TestConfigurator::SetLoopCount(int times) { times_ = times; }
 
- private:
-  int times_;
-  int recheck_time_;
-  int ondemand_time_;
+void TestConfigurator::SetRecheckTime(int seconds) {
+  recheck_time_ = seconds;
+}
 
-  std::list<CheckAtLoopCount> components_to_check_;
-  ComponentUpdateService* cus_;
-};
+void TestConfigurator::SetOnDemandTime(int seconds) {
+  ondemand_time_ = seconds;
+}
 
-class TestInstaller : public ComponentInstaller {
- public :
-  explicit TestInstaller()
-      : error_(0), install_count_(0) {
-  }
+void TestConfigurator::AddComponentToCheck(CrxComponent* com,
+                                           int at_loop_iter) {
+  components_to_check_.push_back(std::make_pair(com, at_loop_iter));
+}
 
-  virtual void OnUpdateError(int error) OVERRIDE {
-    EXPECT_NE(0, error);
-    error_ = error;
-  }
+void TestConfigurator::SetComponentUpdateService(ComponentUpdateService* cus) {
+  cus_ = cus;
+}
 
-  virtual bool Install(const base::DictionaryValue& manifest,
-                       const base::FilePath& unpack_path) OVERRIDE {
-    ++install_count_;
-    return file_util::Delete(unpack_path, true);
-  }
+ComponentUpdaterTest::ComponentUpdaterTest() : test_config_(NULL) {
+  // The component updater instance under test.
+  test_config_ = new TestConfigurator;
+  component_updater_.reset(ComponentUpdateServiceFactory(test_config_));
+  test_config_->SetComponentUpdateService(component_updater_.get());
+  // The test directory is chrome/test/data/components.
+  PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir_);
+  test_data_dir_ = test_data_dir_.AppendASCII("components");
 
-  int error() const { return error_; }
-
-  int install_count() const { return install_count_; }
-
- private:
-  int error_;
-  int install_count_;
-};
-
-// component 1 has extension id "jebgalgnebhfojomionfpkfelancnnkf", and
-// the RSA public key the following hash:
-const uint8 jebg_hash[] = {0x94,0x16,0x0b,0x6d,0x41,0x75,0xe9,0xec,0x8e,0xd5,
-                           0xfa,0x54,0xb0,0xd2,0xdd,0xa5,0x6e,0x05,0x6b,0xe8,
-                           0x73,0x47,0xf6,0xc4,0x11,0x9f,0xbc,0xb3,0x09,0xb3,
-                           0x5b,0x40};
-// component 2 has extension id "abagagagagagagagagagagagagagagag", and
-// the RSA public key the following hash:
-const uint8 abag_hash[] = {0x01,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,
-                           0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,
-                           0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,
-                           0x06,0x01};
-
-const char expected_crx_url[] =
-    "http://localhost/download/jebgalgnebhfojomionfpkfelancnnkf.crx";
-
-}  // namespace
-
-// Common fixture for all the component updater tests.
-class ComponentUpdaterTest : public testing::Test {
- public:
-  enum TestComponents {
-    kTestComponent_abag,
-    kTestComponent_jebg
+  // Subscribe to all component updater notifications.
+  const int notifications[] = {
+    chrome::NOTIFICATION_COMPONENT_UPDATER_STARTED,
+    chrome::NOTIFICATION_COMPONENT_UPDATER_SLEEPING,
+    chrome::NOTIFICATION_COMPONENT_UPDATE_FOUND,
+    chrome::NOTIFICATION_COMPONENT_UPDATE_READY
   };
 
-  ComponentUpdaterTest() : test_config_(NULL) {
-    // The component updater instance under test.
-    test_config_ = new TestConfigurator;
-    component_updater_.reset(ComponentUpdateServiceFactory(test_config_));
-    test_config_->SetComponentUpdateService(component_updater_.get());
-    // The test directory is chrome/test/data/components.
-    PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir_);
-    test_data_dir_ = test_data_dir_.AppendASCII("components");
-
-    // Subscribe to all component updater notifications.
-    const int notifications[] = {
-      chrome::NOTIFICATION_COMPONENT_UPDATER_STARTED,
-      chrome::NOTIFICATION_COMPONENT_UPDATER_SLEEPING,
-      chrome::NOTIFICATION_COMPONENT_UPDATE_FOUND,
-      chrome::NOTIFICATION_COMPONENT_UPDATE_READY
-    };
-
-    for (int ix = 0; ix != arraysize(notifications); ++ix) {
-      notification_tracker_.ListenFor(
-          notifications[ix], content::NotificationService::AllSources());
-    }
-    net::URLFetcher::SetEnableInterceptionForTests(true);
+  for (int ix = 0; ix != arraysize(notifications); ++ix) {
+    notification_tracker_.ListenFor(
+        notifications[ix], content::NotificationService::AllSources());
   }
+  net::URLFetcher::SetEnableInterceptionForTests(true);
+}
 
-  virtual ~ComponentUpdaterTest() {
-    net::URLFetcher::SetEnableInterceptionForTests(false);
-  }
+ComponentUpdaterTest::~ComponentUpdaterTest() {
+  net::URLFetcher::SetEnableInterceptionForTests(false);
+}
 
-  virtual void TearDown() {
-    xmlCleanupGlobals();
-  }
+void ComponentUpdaterTest::TearDown() {
+  xmlCleanupGlobals();
+}
 
-  ComponentUpdateService* component_updater() {
-    return component_updater_.get();
-  }
+ComponentUpdateService* ComponentUpdaterTest::component_updater() {
+  return component_updater_.get();
+}
 
   // Makes the full path to a component updater test file.
-  const base::FilePath test_file(const char* file) {
-    return test_data_dir_.AppendASCII(file);
-  }
+const base::FilePath ComponentUpdaterTest::test_file(const char* file) {
+  return test_data_dir_.AppendASCII(file);
+}
 
-  TestNotificationTracker& notification_tracker() {
-    return notification_tracker_;
-  }
+TestNotificationTracker& ComponentUpdaterTest::notification_tracker() {
+  return notification_tracker_;
+}
 
-  TestConfigurator* test_configurator() {
-    return test_config_;
-  }
+TestConfigurator* ComponentUpdaterTest::test_configurator() {
+  return test_config_;
+}
 
-  ComponentUpdateService::Status RegisterComponent(CrxComponent* com,
-                                                   TestComponents component,
-                                                   const Version& version) {
-    if (component == kTestComponent_abag) {
-      com->name = "test_abag";
-      com->pk_hash.assign(abag_hash, abag_hash + arraysize(abag_hash));
-    } else {
-      com->name = "test_jebg";
-      com->pk_hash.assign(jebg_hash, jebg_hash + arraysize(jebg_hash));
-    }
-    com->version = version;
-    TestInstaller* installer = new TestInstaller;
-    com->installer = installer;
-    test_installers_.push_back(installer);
-    return component_updater_->RegisterComponent(*com);
+ComponentUpdateService::Status ComponentUpdaterTest::RegisterComponent(
+    CrxComponent* com,
+    TestComponents component,
+    const Version& version,
+    TestInstaller* installer) {
+  if (component == kTestComponent_abag) {
+    com->name = "test_abag";
+    com->pk_hash.assign(abag_hash, abag_hash + arraysize(abag_hash));
+  } else if (component == kTestComponent_jebg) {
+    com->name = "test_jebg";
+    com->pk_hash.assign(jebg_hash, jebg_hash + arraysize(jebg_hash));
+  } else {
+    com->name = "test_ihfo";
+    com->pk_hash.assign(ihfo_hash, ihfo_hash + arraysize(ihfo_hash));
   }
-
- private:
-  scoped_ptr<ComponentUpdateService> component_updater_;
-  base::FilePath test_data_dir_;
-  TestNotificationTracker notification_tracker_;
-  TestConfigurator* test_config_;
-  // ComponentInstaller objects to delete after each test.
-  ScopedVector<TestInstaller> test_installers_;
-};
+  com->version = version;
+  com->installer = installer;
+  return component_updater_->RegisterComponent(*com);
+}
 
 // Verify that our test fixture work and the component updater can
 // be created and destroyed with no side effects.
@@ -295,13 +232,17 @@
 
   content::URLLocalHostRequestPrepackagedInterceptor interceptor;
 
+  TestInstaller installer;
   CrxComponent com;
   EXPECT_EQ(ComponentUpdateService::kOk,
-            RegisterComponent(&com, kTestComponent_abag, Version("1.1")));
+            RegisterComponent(&com,
+                              kTestComponent_abag,
+                              Version("1.1"),
+                              &installer));
 
   const GURL expected_update_url(
-      "http://localhost/upd?extra=foo&x=id%3D"
-      "abagagagagagagagagagagagagagagag%26v%3D1.1%26uc");
+      "http://localhost/upd?extra=foo"
+      "&x=id%3Dabagagagagagagagagagagagagagagag%26v%3D1.1%26fp%3D%26uc");
 
   interceptor.SetResponse(expected_update_url,
                           test_file("updatecheck_reply_1.xml"));
@@ -374,20 +315,22 @@
 
   content::URLLocalHostRequestPrepackagedInterceptor interceptor;
 
+  TestInstaller installer1;
   CrxComponent com1;
-  RegisterComponent(&com1, kTestComponent_jebg, Version("0.9"));
+  RegisterComponent(&com1, kTestComponent_jebg, Version("0.9"), &installer1);
+  TestInstaller installer2;
   CrxComponent com2;
-  RegisterComponent(&com2, kTestComponent_abag, Version("2.2"));
+  RegisterComponent(&com2, kTestComponent_abag, Version("2.2"), &installer2);
 
   const GURL expected_update_url_1(
-      "http://localhost/upd?extra=foo&x=id%3D"
-      "jebgalgnebhfojomionfpkfelancnnkf%26v%3D0.9%26uc&x=id%3D"
-      "abagagagagagagagagagagagagagagag%26v%3D2.2%26uc");
+      "http://localhost/upd?extra=foo"
+      "&x=id%3Djebgalgnebhfojomionfpkfelancnnkf%26v%3D0.9%26fp%3D%26uc"
+      "&x=id%3Dabagagagagagagagagagagagagagagag%26v%3D2.2%26fp%3D%26uc");
 
   const GURL expected_update_url_2(
-      "http://localhost/upd?extra=foo&x=id%3D"
-      "abagagagagagagagagagagagagagagag%26v%3D2.2%26uc&x=id%3D"
-      "jebgalgnebhfojomionfpkfelancnnkf%26v%3D1.0%26uc");
+      "http://localhost/upd?extra=foo"
+      "&x=id%3Dabagagagagagagagagagagagagagagag%26v%3D2.2%26fp%3D%26uc"
+      "&x=id%3Djebgalgnebhfojomionfpkfelancnnkf%26v%3D1.0%26fp%3D%26uc");
 
   interceptor.SetResponse(expected_update_url_1,
                           test_file("updatecheck_reply_1.xml"));
@@ -425,78 +368,6 @@
   component_updater()->Stop();
 }
 
-// This test is like the above InstallCrx but the second component
-// has a different source. In this case there would be two manifest
-// checks to different urls, each only containing one component.
-TEST_F(ComponentUpdaterTest, InstallCrxTwoSources) {
-  base::MessageLoop message_loop;
-  content::TestBrowserThread ui_thread(BrowserThread::UI, &message_loop);
-  content::TestBrowserThread file_thread(BrowserThread::FILE);
-  content::TestBrowserThread io_thread(BrowserThread::IO);
-
-  io_thread.StartIOThread();
-  file_thread.Start();
-
-  content::URLLocalHostRequestPrepackagedInterceptor interceptor;
-
-  CrxComponent com1;
-  RegisterComponent(&com1, kTestComponent_abag, Version("2.2"));
-  CrxComponent com2;
-  com2.source = CrxComponent::CWS_PUBLIC;
-  RegisterComponent(&com2, kTestComponent_jebg, Version("0.9"));
-
-  const GURL expected_update_url_1(
-      "http://localhost/upd?extra=foo&x=id%3D"
-      "abagagagagagagagagagagagagagagag%26v%3D2.2%26uc");
-
-  const GURL expected_update_url_2(
-      "http://localhost/cws?extra=foo&x=id%3D"
-      "jebgalgnebhfojomionfpkfelancnnkf%26v%3D0.9%26uc");
-
-  interceptor.SetResponse(expected_update_url_1,
-                          test_file("updatecheck_reply_3.xml"));
-  interceptor.SetResponse(expected_update_url_2,
-                          test_file("updatecheck_reply_1.xml"));
-  interceptor.SetResponse(GURL(expected_crx_url),
-                          test_file("jebgalgnebhfojomionfpkfelancnnkf.crx"));
-
-  test_configurator()->SetLoopCount(3);
-
-  // We have to set SetRecheckTime to something bigger than 0 or else the
-  // component updater will keep re-checking the 'abag' component because
-  // the default source pre-empts the other sources.
-  test_configurator()->SetRecheckTime(60*60);
-
-  component_updater()->Start();
-  message_loop.Run();
-
-  EXPECT_EQ(0, static_cast<TestInstaller*>(com1.installer)->error());
-  EXPECT_EQ(0, static_cast<TestInstaller*>(com1.installer)->install_count());
-  EXPECT_EQ(0, static_cast<TestInstaller*>(com2.installer)->error());
-  EXPECT_EQ(1, static_cast<TestInstaller*>(com2.installer)->install_count());
-
-  EXPECT_EQ(3, interceptor.GetHitCount());
-
-  ASSERT_EQ(6ul, notification_tracker().size());
-
-  TestNotificationTracker::Event ev0 = notification_tracker().at(1);
-  EXPECT_EQ(chrome::NOTIFICATION_COMPONENT_UPDATER_SLEEPING, ev0.type);
-
-  TestNotificationTracker::Event ev1 = notification_tracker().at(2);
-  EXPECT_EQ(chrome::NOTIFICATION_COMPONENT_UPDATE_FOUND, ev1.type);
-
-  TestNotificationTracker::Event ev2 = notification_tracker().at(3);
-  EXPECT_EQ(chrome::NOTIFICATION_COMPONENT_UPDATE_READY, ev2.type);
-
-  TestNotificationTracker::Event ev3 = notification_tracker().at(4);
-  EXPECT_EQ(chrome::NOTIFICATION_COMPONENT_UPDATER_SLEEPING, ev3.type);
-
-  TestNotificationTracker::Event ev4 = notification_tracker().at(5);
-  EXPECT_EQ(chrome::NOTIFICATION_COMPONENT_UPDATER_SLEEPING, ev4.type);
-
-  component_updater()->Stop();
-}
-
 // This test checks that the "prodversionmin" value is handled correctly. In
 // particular there should not be an install because the minimum product
 // version is much higher than of chrome.
@@ -511,12 +382,13 @@
 
   content::URLLocalHostRequestPrepackagedInterceptor interceptor;
 
+  TestInstaller installer;
   CrxComponent com;
-  RegisterComponent(&com, kTestComponent_jebg, Version("0.9"));
+  RegisterComponent(&com, kTestComponent_jebg, Version("0.9"), &installer);
 
   const GURL expected_update_url(
       "http://localhost/upd?extra=foo&x=id%3D"
-      "jebgalgnebhfojomionfpkfelancnnkf%26v%3D0.9%26uc");
+      "jebgalgnebhfojomionfpkfelancnnkf%26v%3D0.9%26fp%3D%26uc");
 
   interceptor.SetResponse(expected_update_url,
                           test_file("updatecheck_reply_2.xml"));
@@ -551,20 +423,23 @@
 
   content::URLLocalHostRequestPrepackagedInterceptor interceptor;
 
+  TestInstaller installer1;
   CrxComponent com1;
-  RegisterComponent(&com1, kTestComponent_abag, Version("2.2"));
+  RegisterComponent(&com1, kTestComponent_abag, Version("2.2"), &installer1);
+  TestInstaller installer2;
   CrxComponent com2;
-  RegisterComponent(&com2, kTestComponent_jebg, Version("0.9"));
+  RegisterComponent(&com2, kTestComponent_jebg, Version("0.9"), &installer2);
 
   const GURL expected_update_url_1(
-      "http://localhost/upd?extra=foo&x=id%3D"
-      "abagagagagagagagagagagagagagagag%26v%3D2.2%26uc&x=id%3D"
-      "jebgalgnebhfojomionfpkfelancnnkf%26v%3D0.9%26uc");
+      "http://localhost/upd?extra=foo"
+      "&x=id%3Dabagagagagagagagagagagagagagagag%26v%3D2.2%26fp%3D%26uc"
+      "&x=id%3Djebgalgnebhfojomionfpkfelancnnkf%26v%3D0.9%26fp%3D%26uc");
 
   const GURL expected_update_url_2(
-      "http://localhost/upd?extra=foo&x=id%3D"
-      "jebgalgnebhfojomionfpkfelancnnkf%26v%3D0.9%26uc&x=id%3D"
-      "abagagagagagagagagagagagagagagag%26v%3D2.2%26uc");
+      "http://localhost/upd?extra=foo"
+      "&x=id%3Djebgalgnebhfojomionfpkfelancnnkf%26v%3D0.9%26fp%3D%26uc"
+      "%26installsource%3Dondemand"
+      "&x=id%3Dabagagagagagagagagagagagagagagag%26v%3D2.2%26fp%3D%26uc");
 
   interceptor.SetResponse(expected_update_url_1,
                           test_file("updatecheck_reply_empty"));
@@ -613,9 +488,9 @@
   // Test a few error cases. NOTE: We don't have callbacks for
   // when the updates failed yet.
   const GURL expected_update_url_3(
-      "http://localhost/upd?extra=foo&x=id%3D"
-      "jebgalgnebhfojomionfpkfelancnnkf%26v%3D1.0%26uc&x=id%3D"
-      "abagagagagagagagagagagagagagagag%26v%3D2.2%26uc");
+      "http://localhost/upd?extra=foo"
+      "&x=id%3Djebgalgnebhfojomionfpkfelancnnkf%26v%3D1.0%26fp%3D%26uc"
+      "&x=id%3Dabagagagagagagagagagagagagagagag%26v%3D2.2%26fp%3D%26uc");
 
   // No update: error from no server response
   interceptor.SetResponse(expected_update_url_3,
@@ -667,21 +542,23 @@
 
   content::URLLocalHostRequestPrepackagedInterceptor interceptor;
 
+  TestInstaller installer1;
   CrxComponent com1;
-  RegisterComponent(&com1, kTestComponent_jebg, Version("0.9"));
+  RegisterComponent(&com1, kTestComponent_jebg, Version("0.9"), &installer1);
+  TestInstaller installer2;
   CrxComponent com2;
-  RegisterComponent(&com2, kTestComponent_abag, Version("2.2"));
+  RegisterComponent(&com2, kTestComponent_abag, Version("2.2"), &installer2);
 
   // Start with 0.9, and update to 1.0
   const GURL expected_update_url_1(
-      "http://localhost/upd?extra=foo&x=id%3D"
-      "jebgalgnebhfojomionfpkfelancnnkf%26v%3D0.9%26uc&x=id%3D"
-      "abagagagagagagagagagagagagagagag%26v%3D2.2%26uc");
+      "http://localhost/upd?extra=foo"
+      "&x=id%3Djebgalgnebhfojomionfpkfelancnnkf%26v%3D0.9%26fp%3D%26uc"
+      "&x=id%3Dabagagagagagagagagagagagagagagag%26v%3D2.2%26fp%3D%26uc");
 
   const GURL expected_update_url_2(
-      "http://localhost/upd?extra=foo&x=id%3D"
-      "abagagagagagagagagagagagagagagag%26v%3D2.2%26uc&x=id%3D"
-      "jebgalgnebhfojomionfpkfelancnnkf%26v%3D1.0%26uc");
+      "http://localhost/upd?extra=foo"
+      "&x=id%3Dabagagagagagagagagagagagagagagag%26v%3D2.2%26fp%3D%26uc"
+      "&x=id%3Djebgalgnebhfojomionfpkfelancnnkf%26v%3D1.0%26fp%3D%26uc");
 
   interceptor.SetResponse(expected_update_url_1,
                           test_file("updatecheck_reply_1.xml"));
@@ -722,16 +599,20 @@
   EXPECT_EQ(chrome::NOTIFICATION_COMPONENT_UPDATER_SLEEPING, ev4.type);
 
   // Now re-register, pretending to be an even newer version (2.2)
+  TestInstaller installer3;
   component_updater()->Stop();
   EXPECT_EQ(ComponentUpdateService::kReplaced,
-            RegisterComponent(&com1, kTestComponent_jebg, Version("2.2")));
+            RegisterComponent(&com1,
+                              kTestComponent_jebg,
+                              Version("2.2"),
+                              &installer3));
 
   // Check that we send out 2.2 as our version.
   // Interceptor's hit count should go up by 1.
   const GURL expected_update_url_3(
-      "http://localhost/upd?extra=foo&x=id%3D"
-      "jebgalgnebhfojomionfpkfelancnnkf%26v%3D2.2%26uc&x=id%3D"
-      "abagagagagagagagagagagagagagagag%26v%3D2.2%26uc");
+      "http://localhost/upd?extra=foo"
+      "&x=id%3Djebgalgnebhfojomionfpkfelancnnkf%26v%3D2.2%26fp%3D%26uc"
+      "&x=id%3Dabagagagagagagagagagagagagagagag%26v%3D2.2%26fp%3D%26uc");
 
   interceptor.SetResponse(expected_update_url_3,
                           test_file("updatecheck_reply_1.xml"));
@@ -753,8 +634,7 @@
 
   EXPECT_EQ(4, interceptor.GetHitCount());
 
-  // The test harness's Register() function creates a new installer,
-  // so the counts go back to 0.
+  // We created a new installer, so the counts go back to 0.
   EXPECT_EQ(0, static_cast<TestInstaller*>(com1.installer)->error());
   EXPECT_EQ(0, static_cast<TestInstaller*>(com1.installer)->install_count());
   EXPECT_EQ(0, static_cast<TestInstaller*>(com2.installer)->error());
@@ -762,3 +642,127 @@
 
   component_updater()->Stop();
 }
+
+// Verify that component installation falls back to downloading and installing
+// a full update if the differential update fails (in this case, because the
+// installer does not know about the existing files). We do two loops; the final
+// loop should do nothing.
+// We also check that exactly 4 network requests are issued:
+// 1- update check (loop 1)
+// 2- download differential crx
+// 3- download full crx
+// 4- update check (loop 2 - no update available)
+TEST_F(ComponentUpdaterTest, DifferentialUpdateFails) {
+  base::MessageLoop message_loop;
+  content::TestBrowserThread ui_thread(BrowserThread::UI, &message_loop);
+  content::TestBrowserThread file_thread(BrowserThread::FILE);
+  content::TestBrowserThread io_thread(BrowserThread::IO);
+
+  io_thread.StartIOThread();
+  file_thread.Start();
+
+  content::URLLocalHostRequestPrepackagedInterceptor interceptor;
+
+  TestInstaller installer;
+  CrxComponent com;
+  RegisterComponent(&com, kTestComponent_ihfo, Version("1.0"), &installer);
+
+  const GURL expected_update_url_1(
+      "http://localhost/upd?extra=foo"
+      "&x=id%3Dihfokbkgjpifnbbojhneepfflplebdkc%26v%3D1.0%26fp%3D%26uc");
+  const GURL expected_update_url_2(
+      "http://localhost/upd?extra=foo"
+      "&x=id%3Dihfokbkgjpifnbbojhneepfflplebdkc%26v%3D2.0%26fp%3Df22%26uc");
+  const GURL expected_crx_url_1(
+      "http://localhost/download/ihfokbkgjpifnbbojhneepfflplebdkc_1.crx");
+  const GURL expected_crx_url_1_diff_2(
+      "http://localhost/download/ihfokbkgjpifnbbojhneepfflplebdkc_1to2.crx");
+  const GURL expected_crx_url_2(
+      "http://localhost/download/ihfokbkgjpifnbbojhneepfflplebdkc_2.crx");
+
+  interceptor.SetResponse(expected_update_url_1,
+                          test_file("updatecheck_diff_reply_2.xml"));
+  interceptor.SetResponse(expected_update_url_2,
+                          test_file("updatecheck_diff_reply_3.xml"));
+  interceptor.SetResponse(expected_crx_url_1,
+                          test_file("ihfokbkgjpifnbbojhneepfflplebdkc_1.crx"));
+  interceptor.SetResponse(
+      expected_crx_url_1_diff_2,
+      test_file("ihfokbkgjpifnbbojhneepfflplebdkc_1to2.crx"));
+  interceptor.SetResponse(expected_crx_url_2,
+                          test_file("ihfokbkgjpifnbbojhneepfflplebdkc_2.crx"));
+
+  test_configurator()->SetLoopCount(2);
+
+  component_updater()->Start();
+  message_loop.Run();
+
+  // A failed differential update does not count as a failed install.
+  EXPECT_EQ(0, static_cast<TestInstaller*>(com.installer)->error());
+  EXPECT_EQ(1, static_cast<TestInstaller*>(com.installer)->install_count());
+
+  EXPECT_EQ(4, interceptor.GetHitCount());
+
+  component_updater()->Stop();
+}
+
+// Verify that we successfully propagate a patcher error.
+// ihfokbkgjpifnbbojhneepfflplebdkc_1to2_bad.crx contains an incorrect
+// patching instruction that should fail.
+TEST_F(ComponentUpdaterTest, DifferentialUpdateFailErrorcode) {
+  base::MessageLoop message_loop;
+  content::TestBrowserThread ui_thread(BrowserThread::UI, &message_loop);
+  content::TestBrowserThread file_thread(BrowserThread::FILE);
+  content::TestBrowserThread io_thread(BrowserThread::IO);
+
+  io_thread.StartIOThread();
+  file_thread.Start();
+
+  content::URLLocalHostRequestPrepackagedInterceptor interceptor;
+
+  VersionedTestInstaller installer;
+  CrxComponent com;
+  RegisterComponent(&com, kTestComponent_ihfo, Version("0.0"), &installer);
+
+  const GURL expected_update_url_0(
+      "http://localhost/upd?extra=foo"
+      "&x=id%3Dihfokbkgjpifnbbojhneepfflplebdkc%26v%3D0.0%26fp%3D%26uc");
+  const GURL expected_update_url_1(
+      "http://localhost/upd?extra=foo"
+      "&x=id%3Dihfokbkgjpifnbbojhneepfflplebdkc%26v%3D1.0%26fp%3D1%26uc");
+  const GURL expected_update_url_2(
+      "http://localhost/upd?extra=foo"
+      "&x=id%3Dihfokbkgjpifnbbojhneepfflplebdkc%26v%3D2.0%26fp%3Df22%26uc");
+  const GURL expected_crx_url_1(
+      "http://localhost/download/ihfokbkgjpifnbbojhneepfflplebdkc_1.crx");
+  const GURL expected_crx_url_1_diff_2(
+      "http://localhost/download/ihfokbkgjpifnbbojhneepfflplebdkc_1to2.crx");
+  const GURL expected_crx_url_2(
+      "http://localhost/download/ihfokbkgjpifnbbojhneepfflplebdkc_2.crx");
+
+  interceptor.SetResponse(expected_update_url_0,
+                          test_file("updatecheck_diff_reply_1.xml"));
+  interceptor.SetResponse(expected_update_url_1,
+                          test_file("updatecheck_diff_reply_2.xml"));
+  interceptor.SetResponse(expected_update_url_2,
+                          test_file("updatecheck_diff_reply_3.xml"));
+  interceptor.SetResponse(expected_crx_url_1,
+                          test_file("ihfokbkgjpifnbbojhneepfflplebdkc_1.crx"));
+  interceptor.SetResponse(
+      expected_crx_url_1_diff_2,
+      test_file("ihfokbkgjpifnbbojhneepfflplebdkc_1to2_bad.crx"));
+  interceptor.SetResponse(expected_crx_url_2,
+                          test_file("ihfokbkgjpifnbbojhneepfflplebdkc_2.crx"));
+
+  test_configurator()->SetLoopCount(3);
+
+  component_updater()->Start();
+  message_loop.Run();
+
+  EXPECT_EQ(0, static_cast<TestInstaller*>(com.installer)->error());
+  EXPECT_EQ(2, static_cast<TestInstaller*>(com.installer)->install_count());
+
+  EXPECT_EQ(6, interceptor.GetHitCount());
+
+  component_updater()->Stop();
+}
diff --git a/chrome/browser/component_updater/test/component_updater_service_unittest.h b/chrome/browser/component_updater/test/component_updater_service_unittest.h
new file mode 100644
index 0000000..ba98102
--- /dev/null
+++ b/chrome/browser/component_updater/test/component_updater_service_unittest.h
@@ -0,0 +1,134 @@
+// 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_COMPONENT_UPDATER_TEST_COMPONENT_UPDATER_SERVICE_UNITTEST_H_
+#define CHROME_BROWSER_COMPONENT_UPDATER_TEST_COMPONENT_UPDATER_SERVICE_UNITTEST_H_
+
+#include <list>
+#include <utility>
+
+#include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
+#include "chrome/browser/component_updater/component_updater_service.h"
+#include "chrome/browser/component_updater/test/component_patcher_mock.h"
+#include "content/public/test/test_notification_tracker.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using content::TestNotificationTracker;
+
+class GURL;
+class TestInstaller;
+
+// component 1 has extension id "jebgalgnebhfojomionfpkfelancnnkf", and
+// the RSA public key the following hash:
+const uint8 jebg_hash[] = {0x94, 0x16, 0x0b, 0x6d, 0x41, 0x75, 0xe9, 0xec,
+                           0x8e, 0xd5, 0xfa, 0x54, 0xb0, 0xd2, 0xdd, 0xa5,
+                           0x6e, 0x05, 0x6b, 0xe8, 0x73, 0x47, 0xf6, 0xc4,
+                           0x11, 0x9f, 0xbc, 0xb3, 0x09, 0xb3, 0x5b, 0x40};
+// component 2 has extension id "abagagagagagagagagagagagagagagag", and
+// the RSA public key the following hash:
+const uint8 abag_hash[] = {0x01, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+                           0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+                           0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+                           0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x01};
+// component 3 has extension id "ihfokbkgjpifnbbojhneepfflplebdkc", and
+// the RSA public key the following hash:
+const uint8 ihfo_hash[] = {0x87, 0x5e, 0xa1, 0xa6, 0x9f, 0x85, 0xd1, 0x1e,
+                           0x97, 0xd4, 0x4f, 0x55, 0xbf, 0xb4, 0x13, 0xa2,
+                           0xe7, 0xc5, 0xc8, 0xf5, 0x60, 0x19, 0x78, 0x1b,
+                           0x6d, 0xe9, 0x4c, 0xeb, 0x96, 0x05, 0x42, 0x17};
+
+class TestConfigurator : public ComponentUpdateService::Configurator {
+ public:
+  explicit TestConfigurator();
+
+  virtual ~TestConfigurator();
+
+  virtual int InitialDelay() OVERRIDE;
+
+  typedef std::pair<CrxComponent*, int> CheckAtLoopCount;
+
+  virtual int NextCheckDelay() OVERRIDE;
+
+  virtual int StepDelay() OVERRIDE;
+
+  virtual int MinimumReCheckWait() OVERRIDE;
+
+  virtual int OnDemandDelay() OVERRIDE;
+
+  virtual GURL UpdateUrl() OVERRIDE;
+
+  virtual const char* ExtraRequestParams() OVERRIDE;
+
+  virtual size_t UrlSizeLimit() OVERRIDE;
+
+  virtual net::URLRequestContextGetter* RequestContext() OVERRIDE;
+
+  // Don't use the utility process to decode files.
+  virtual bool InProcess() OVERRIDE;
+
+  virtual void OnEvent(Events event, int extra) OVERRIDE;
+
+  virtual ComponentPatcher* CreateComponentPatcher() OVERRIDE;
+
+  virtual bool DeltasEnabled() const OVERRIDE;
+
+  void SetLoopCount(int times);
+
+  void SetRecheckTime(int seconds);
+
+  void SetOnDemandTime(int seconds);
+
+  void AddComponentToCheck(CrxComponent* com, int at_loop_iter);
+
+  void SetComponentUpdateService(ComponentUpdateService* cus);
+
+ private:
+  int times_;
+  int recheck_time_;
+  int ondemand_time_;
+
+  std::list<CheckAtLoopCount> components_to_check_;
+  ComponentUpdateService* cus_;
+};
+
+class ComponentUpdaterTest : public testing::Test {
+ public:
+  enum TestComponents {
+    kTestComponent_abag,
+    kTestComponent_jebg,
+    kTestComponent_ihfo,
+  };
+
+  ComponentUpdaterTest();
+
+  virtual ~ComponentUpdaterTest();
+
+  virtual void TearDown();
+
+  ComponentUpdateService* component_updater();
+
+  // Makes the full path to a component updater test file.
+  const base::FilePath test_file(const char* file);
+
+  TestNotificationTracker& notification_tracker();
+
+  TestConfigurator* test_configurator();
+
+  ComponentUpdateService::Status RegisterComponent(CrxComponent* com,
+                                                   TestComponents component,
+                                                   const Version& version,
+                                                   TestInstaller* installer);
+
+ private:
+  scoped_ptr<ComponentUpdateService> component_updater_;
+  base::FilePath test_data_dir_;
+  TestNotificationTracker notification_tracker_;
+  TestConfigurator* test_config_;
+};
+
+const char expected_crx_url[] =
+    "http://localhost/download/jebgalgnebhfojomionfpkfelancnnkf.crx";
+
+#endif  // CHROME_BROWSER_COMPONENT_UPDATER_TEST_COMPONENT_UPDATER_SERVICE_UNITTEST_H_
diff --git a/chrome/browser/component_updater/test/component_updater_service_unittest_win.cc b/chrome/browser/component_updater/test/component_updater_service_unittest_win.cc
new file mode 100644
index 0000000..973f037
--- /dev/null
+++ b/chrome/browser/component_updater/test/component_updater_service_unittest_win.cc
@@ -0,0 +1,101 @@
+// 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 <list>
+#include <utility>
+#include "base/compiler_specific.h"
+#include "base/file_util.h"
+#include "base/files/file_path.h"
+#include "base/memory/scoped_vector.h"
+#include "base/message_loop.h"
+#include "base/path_service.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/stringprintf.h"
+#include "base/values.h"
+#include "chrome/browser/component_updater/component_updater_service.h"
+#include "chrome/browser/component_updater/test/component_patcher_mock.h"
+#include "chrome/browser/component_updater/test/component_updater_service_unittest.h"
+#include "chrome/browser/component_updater/test/test_installer.h"
+#include "chrome/common/chrome_notification_types.h"
+#include "chrome/common/chrome_paths.h"
+#include "content/public/browser/notification_observer.h"
+#include "content/public/browser/notification_service.h"
+#include "content/public/test/test_browser_thread.h"
+#include "content/public/test/test_notification_tracker.h"
+#include "content/test/net/url_request_prepackaged_interceptor.h"
+#include "libxml/globals.h"
+#include "net/base/upload_bytes_element_reader.h"
+#include "net/url_request/url_fetcher.h"
+#include "net/url_request/url_request.h"
+#include "net/url_request/url_request_filter.h"
+#include "net/url_request/url_request_simple_job.h"
+#include "net/url_request/url_request_test_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+using content::BrowserThread;
+using content::TestNotificationTracker;
+
+// Verify that we can download and install a component and a differential
+// update to that component. We do three loops; the final loop should do
+// nothing.
+// We also check that exactly 5 network requests are issued:
+// 1- update check (response: v1 available)
+// 2- download crx (v1)
+// 3- update check (response: v2 available)
+// 4- download differential crx (v1 to v2)
+// 5- update check (response: no further update available)
+TEST_F(ComponentUpdaterTest, DifferentialUpdate) {
+  base::MessageLoop message_loop;
+  content::TestBrowserThread ui_thread(BrowserThread::UI, &message_loop);
+  content::TestBrowserThread file_thread(BrowserThread::FILE);
+  content::TestBrowserThread io_thread(BrowserThread::IO);
+
+  io_thread.StartIOThread();
+  file_thread.Start();
+
+  content::URLLocalHostRequestPrepackagedInterceptor interceptor;
+
+  VersionedTestInstaller installer;
+  CrxComponent com;
+  RegisterComponent(&com, kTestComponent_ihfo, Version("0.0"), &installer);
+
+  const GURL expected_update_url_0(
+      "http://localhost/upd?extra=foo"
+      "&x=id%3Dihfokbkgjpifnbbojhneepfflplebdkc%26v%3D0.0%26fp%3D%26uc");
+  const GURL expected_update_url_1(
+      "http://localhost/upd?extra=foo"
+      "&x=id%3Dihfokbkgjpifnbbojhneepfflplebdkc%26v%3D1.0%26fp%3D1%26uc");
+  const GURL expected_update_url_2(
+      "http://localhost/upd?extra=foo"
+      "&x=id%3Dihfokbkgjpifnbbojhneepfflplebdkc%26v%3D2.0%26fp%3Df22%26uc");
+  const GURL expected_crx_url_1(
+      "http://localhost/download/ihfokbkgjpifnbbojhneepfflplebdkc_1.crx");
+  const GURL expected_crx_url_1_diff_2(
+      "http://localhost/download/ihfokbkgjpifnbbojhneepfflplebdkc_1to2.crx");
+
+  interceptor.SetResponse(expected_update_url_0,
+                          test_file("updatecheck_diff_reply_1.xml"));
+  interceptor.SetResponse(expected_update_url_1,
+                          test_file("updatecheck_diff_reply_2.xml"));
+  interceptor.SetResponse(expected_update_url_2,
+                          test_file("updatecheck_diff_reply_3.xml"));
+  interceptor.SetResponse(expected_crx_url_1,
+                          test_file("ihfokbkgjpifnbbojhneepfflplebdkc_1.crx"));
+  interceptor.SetResponse(
+      expected_crx_url_1_diff_2,
+      test_file("ihfokbkgjpifnbbojhneepfflplebdkc_1to2.crx"));
+
+  test_configurator()->SetLoopCount(3);
+
+  component_updater()->Start();
+  message_loop.Run();
+
+  EXPECT_EQ(0, static_cast<TestInstaller*>(com.installer)->error());
+  EXPECT_EQ(2, static_cast<TestInstaller*>(com.installer)->install_count());
+
+  EXPECT_EQ(5, interceptor.GetHitCount());
+
+  component_updater()->Stop();
+}
diff --git a/chrome/browser/component_updater/test/test_installer.cc b/chrome/browser/component_updater/test/test_installer.cc
new file mode 100644
index 0000000..3f9b0e0
--- /dev/null
+++ b/chrome/browser/component_updater/test/test_installer.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/component_updater/test/test_installer.h"
+
+#include "base/file_util.h"
+#include "base/files/file_path.h"
+#include "base/values.h"
+
+TestInstaller::TestInstaller()
+    : error_(0), install_count_(0) {
+}
+
+void TestInstaller::OnUpdateError(int error) {
+  error_ = error;
+}
+
+bool TestInstaller::Install(const base::DictionaryValue& manifest,
+                            const base::FilePath& unpack_path) {
+  ++install_count_;
+  return base::Delete(unpack_path, true);
+}
+
+bool TestInstaller::GetInstalledFile(const std::string& file,
+                                     base::FilePath* installed_file) {
+  return false;
+}
+
+int TestInstaller::error() const { return error_; }
+
+int TestInstaller::install_count() const { return install_count_; }
+
+
+ReadOnlyTestInstaller::ReadOnlyTestInstaller(const base::FilePath& install_dir)
+    : install_directory_(install_dir) {
+}
+
+ReadOnlyTestInstaller::~ReadOnlyTestInstaller() {
+}
+
+bool ReadOnlyTestInstaller::GetInstalledFile(const std::string& file,
+                                             base::FilePath* installed_file) {
+  *installed_file = install_directory_.AppendASCII(file);
+  return true;
+}
+
+
+VersionedTestInstaller::VersionedTestInstaller() {
+  file_util::CreateNewTempDirectory(FILE_PATH_LITERAL("TEST_"),
+                                    &install_directory_);
+}
+
+VersionedTestInstaller::~VersionedTestInstaller() {
+  base::Delete(install_directory_, true);
+}
+
+
+bool VersionedTestInstaller::Install(const base::DictionaryValue& manifest,
+                                     const base::FilePath& unpack_path) {
+  std::string version_string;
+  manifest.GetStringASCII("version", &version_string);
+  Version version(version_string.c_str());
+
+  base::FilePath path;
+  path = install_directory_.AppendASCII(version.GetString());
+  file_util::CreateDirectory(path.DirName());
+  if (!base::Move(unpack_path, path))
+    return false;
+  current_version_ = version;
+  ++install_count_;
+  return true;
+}
+
+bool VersionedTestInstaller::GetInstalledFile(const std::string& file,
+                                              base::FilePath* installed_file) {
+  base::FilePath path;
+  path = install_directory_.AppendASCII(current_version_.GetString());
+  *installed_file = path.Append(base::FilePath::FromUTF8Unsafe(file));
+  return true;
+}
diff --git a/chrome/browser/component_updater/test/test_installer.h b/chrome/browser/component_updater/test/test_installer.h
new file mode 100644
index 0000000..2233d88
--- /dev/null
+++ b/chrome/browser/component_updater/test/test_installer.h
@@ -0,0 +1,73 @@
+// 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_COMPONENT_UPDATER_TEST_TEST_INSTALLER_H_
+#define CHROME_BROWSER_COMPONENT_UPDATER_TEST_TEST_INSTALLER_H_
+
+#include "base/compiler_specific.h"
+#include "base/files/file_path.h"
+#include "chrome/browser/component_updater/component_updater_service.h"
+
+namespace base {
+class DictionaryValue;
+}
+
+// A TestInstaller is an installer that does nothing for installation except
+// increment a counter.
+class TestInstaller : public ComponentInstaller {
+ public:
+  explicit TestInstaller();
+
+  virtual void OnUpdateError(int error) OVERRIDE;
+
+  virtual bool Install(const base::DictionaryValue& manifest,
+                       const base::FilePath& unpack_path) OVERRIDE;
+
+  virtual bool GetInstalledFile(const std::string& file,
+                                base::FilePath* installed_file) OVERRIDE;
+
+  int error() const;
+
+  int install_count() const;
+
+ protected:
+  int error_;
+  int install_count_;
+};
+
+// A ReadOnlyTestInstaller is an installer that knows about files in an existing
+// directory. It will not write to the directory.
+class ReadOnlyTestInstaller : public TestInstaller {
+ public:
+  explicit ReadOnlyTestInstaller(const base::FilePath& installed_path);
+
+  virtual ~ReadOnlyTestInstaller();
+
+  virtual bool GetInstalledFile(const std::string& file,
+                                base::FilePath* installed_file) OVERRIDE;
+
+ private:
+  base::FilePath install_directory_;
+};
+
+// A VersionedTestInstaller is an installer that installs files into versioned
+// directories (e.g. somedir/25.23.89.141/<files>).
+class VersionedTestInstaller : public TestInstaller {
+ public :
+  explicit VersionedTestInstaller();
+
+  virtual ~VersionedTestInstaller();
+
+  virtual bool Install(const base::DictionaryValue& manifest,
+                       const base::FilePath& unpack_path) OVERRIDE;
+
+  virtual bool GetInstalledFile(const std::string& file,
+                                base::FilePath* installed_file) OVERRIDE;
+
+ private:
+  base::FilePath install_directory_;
+  Version current_version_;
+};
+
+#endif  // CHROME_BROWSER_COMPONENT_UPDATER_TEST_TEST_INSTALLER_H_
diff --git a/chrome/browser/component_updater/widevine_cdm_component_installer.cc b/chrome/browser/component_updater/widevine_cdm_component_installer.cc
index 822aff2..bbfebbd 100644
--- a/chrome/browser/component_updater/widevine_cdm_component_installer.cc
+++ b/chrome/browser/component_updater/widevine_cdm_component_installer.cc
@@ -195,6 +195,9 @@
   virtual bool Install(const base::DictionaryValue& manifest,
                        const base::FilePath& unpack_path) OVERRIDE;
 
+  virtual bool GetInstalledFile(const std::string& file,
+                                base::FilePath* installed_file) OVERRIDE;
+
  private:
   base::Version current_version_;
 };
@@ -231,7 +234,7 @@
       GetWidevineCdmBaseDirectory().AppendASCII(version.GetString());
   if (file_util::PathExists(install_path))
     return false;
-  if (!file_util::Move(unpack_path, install_path))
+  if (!base::Move(unpack_path, install_path))
     return false;
 
   base::FilePath adapter_install_path =
@@ -246,6 +249,21 @@
   return true;
 }
 
+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);
+  return true;
+}
+
 void FinishWidevineCdmUpdateRegistration(ComponentUpdateService* cus,
                                          const base::Version& version) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
@@ -284,7 +302,7 @@
           BrowserThread::UI, FROM_HERE,
           base::Bind(&RegisterWidevineCdmWithChrome, adapter_path, version));
     } else {
-      file_util::Delete(latest_dir, true);
+      base::Delete(latest_dir, true);
       version = base::Version(kNullVersion);
     }
   }
@@ -296,7 +314,7 @@
   // Remove older versions of Widevine CDM.
   for (std::vector<base::FilePath>::iterator iter = older_dirs.begin();
        iter != older_dirs.end(); ++iter) {
-    file_util::Delete(*iter, true);
+    base::Delete(*iter, true);
   }
 }
 
diff --git a/chrome/browser/content_settings/content_settings_browsertest.cc b/chrome/browser/content_settings/content_settings_browsertest.cc
index 3bb6c42..857612c 100644
--- a/chrome/browser/content_settings/content_settings_browsertest.cc
+++ b/chrome/browser/content_settings/content_settings_browsertest.cc
@@ -489,7 +489,7 @@
     const char kLibraryName[] = "clearkeycdmadapter.plugin";
 #elif defined(OS_POSIX)
     const char kLibraryName[] = "libclearkeycdmadapter.so";
-#endif
+#endif  // defined(OS_MACOSX)
 #endif  // defined(OS_WIN)
 
     // Append the switch to register the External Clear Key CDM.
@@ -571,7 +571,7 @@
 
 #if defined(ENABLE_PEPPER_CDMS)
   RunLoadPepperPluginTest(kExternalClearKeyMimeType, true);
-#endif
+#endif  // defined(ENABLE_PEPPER_CDMS)
 
   // Next, test behavior when plug-ins are blocked.
   content_settings->SetDefaultContentSetting(
@@ -583,12 +583,12 @@
 
 #if defined(WIDEVINE_CDM_AVAILABLE)
   RunLoadPepperPluginTest(kWidevineCdmPluginMimeType, true);
-#endif
+#endif  // defined(WIDEVINE_CDM_AVAILABLE)
 #endif  // defined(ENABLE_PEPPER_CDMS)
 
 #if !defined(DISABLE_NACL)
   RunLoadPepperPluginTest("application/x-nacl", true);
-#endif
+#endif  // !defined(DISABLE_NACL)
 
   // Finally, test behavior when (just) JavaScript is blocked.
   content_settings->SetDefaultContentSetting(
@@ -602,12 +602,12 @@
 
 #if defined(WIDEVINE_CDM_AVAILABLE)
   RunJavaScriptBlockedTest("load_widevine_no_js.html", true);
-#endif
+#endif  // defined(WIDEVINE_CDM_AVAILABLE)
 #endif  // defined(ENABLE_PEPPER_CDMS)
 
 #if !defined(DISABLE_NACL)
   RunJavaScriptBlockedTest("load_nacl_no_js.html", true);
-#endif
+#endif  // !defined(DISABLE_NACL)
 }
 
 #endif  // defined(ENABLE_PLUGINS)
diff --git a/chrome/browser/content_settings/content_settings_default_provider.cc b/chrome/browser/content_settings/content_settings_default_provider.cc
index 51592fa..af80637 100644
--- a/chrome/browser/content_settings/content_settings_default_provider.cc
+++ b/chrome/browser/content_settings/content_settings_default_provider.cc
@@ -24,7 +24,7 @@
 #include "content/public/browser/notification_details.h"
 #include "content/public/browser/notification_source.h"
 #include "content/public/browser/user_metrics.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 using content::BrowserThread;
 using content::UserMetricsAction;
diff --git a/chrome/browser/content_settings/content_settings_default_provider_unittest.cc b/chrome/browser/content_settings/content_settings_default_provider_unittest.cc
index cfd7448..0e2fdcf 100644
--- a/chrome/browser/content_settings/content_settings_default_provider_unittest.cc
+++ b/chrome/browser/content_settings/content_settings_default_provider_unittest.cc
@@ -12,8 +12,8 @@
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/testing_profile.h"
 #include "content/public/test/test_browser_thread.h"
-#include "googleurl/src/gurl.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
 
 using ::testing::_;
 using content::BrowserThread;
diff --git a/chrome/browser/content_settings/content_settings_origin_identifier_value_map.cc b/chrome/browser/content_settings/content_settings_origin_identifier_value_map.cc
index 56cc0bd..c46cf91 100644
--- a/chrome/browser/content_settings/content_settings_origin_identifier_value_map.cc
+++ b/chrome/browser/content_settings/content_settings_origin_identifier_value_map.cc
@@ -12,7 +12,7 @@
 #include "chrome/browser/content_settings/content_settings_rule.h"
 #include "chrome/browser/content_settings/content_settings_utils.h"
 #include "chrome/common/content_settings_types.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 namespace content_settings {
 
diff --git a/chrome/browser/content_settings/content_settings_origin_identifier_value_map_unittest.cc b/chrome/browser/content_settings/content_settings_origin_identifier_value_map_unittest.cc
index b8612a5..aad03fa 100644
--- a/chrome/browser/content_settings/content_settings_origin_identifier_value_map_unittest.cc
+++ b/chrome/browser/content_settings/content_settings_origin_identifier_value_map_unittest.cc
@@ -8,8 +8,8 @@
 #include "base/values.h"
 #include "chrome/browser/content_settings/content_settings_rule.h"
 #include "chrome/browser/content_settings/content_settings_utils.h"
-#include "googleurl/src/gurl.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
 
 TEST(OriginIdentifierValueMapTest, SetGetValue) {
   content_settings::OriginIdentifierValueMap map;
diff --git a/chrome/browser/content_settings/content_settings_policy_provider_unittest.cc b/chrome/browser/content_settings/content_settings_policy_provider_unittest.cc
index ca4ab11..345663f 100644
--- a/chrome/browser/content_settings/content_settings_policy_provider_unittest.cc
+++ b/chrome/browser/content_settings/content_settings_policy_provider_unittest.cc
@@ -20,8 +20,8 @@
 #include "chrome/test/base/testing_pref_service_syncable.h"
 #include "chrome/test/base/testing_profile.h"
 #include "content/public/test/test_browser_thread.h"
-#include "googleurl/src/gurl.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
 
 using ::testing::_;
 using content::BrowserThread;
diff --git a/chrome/browser/content_settings/content_settings_pref_provider.cc b/chrome/browser/content_settings/content_settings_pref_provider.cc
index 8f53c68..d5b4894 100644
--- a/chrome/browser/content_settings/content_settings_pref_provider.cc
+++ b/chrome/browser/content_settings/content_settings_pref_provider.cc
@@ -27,7 +27,7 @@
 #include "content/public/browser/notification_details.h"
 #include "content/public/browser/notification_source.h"
 #include "content/public/browser/user_metrics.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 using content::BrowserThread;
 using content::UserMetricsAction;
diff --git a/chrome/browser/content_settings/content_settings_pref_provider_unittest.cc b/chrome/browser/content_settings/content_settings_pref_provider_unittest.cc
index b227855..efbe7cf 100644
--- a/chrome/browser/content_settings/content_settings_pref_provider_unittest.cc
+++ b/chrome/browser/content_settings/content_settings_pref_provider_unittest.cc
@@ -28,8 +28,8 @@
 #include "chrome/test/base/testing_profile.h"
 #include "components/user_prefs/pref_registry_syncable.h"
 #include "content/public/test/test_browser_thread.h"
-#include "googleurl/src/gurl.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
 
 using ::testing::_;
 using content::BrowserThread;
diff --git a/chrome/browser/content_settings/content_settings_provider.h b/chrome/browser/content_settings/content_settings_provider.h
index 6bc64de..c75aca0 100644
--- a/chrome/browser/content_settings/content_settings_provider.h
+++ b/chrome/browser/content_settings/content_settings_provider.h
@@ -54,7 +54,7 @@
       const ContentSettingsPattern& secondary_pattern,
       ContentSettingsType content_type,
       const ResourceIdentifier& resource_identifier,
-      Value* value) = 0;
+      base::Value* value) = 0;
 
   // Resets all content settings for the given |content_type| and empty resource
   // identifier to CONTENT_SETTING_DEFAULT.
diff --git a/chrome/browser/content_settings/content_settings_provider_unittest.cc b/chrome/browser/content_settings/content_settings_provider_unittest.cc
index 0832a1c..d3d092c 100644
--- a/chrome/browser/content_settings/content_settings_provider_unittest.cc
+++ b/chrome/browser/content_settings/content_settings_provider_unittest.cc
@@ -7,7 +7,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "chrome/browser/content_settings/content_settings_mock_provider.h"
 #include "chrome/browser/content_settings/content_settings_utils.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 namespace content_settings {
 
diff --git a/chrome/browser/content_settings/content_settings_utils.cc b/chrome/browser/content_settings/content_settings_utils.cc
index 9754ba1..52f1650 100644
--- a/chrome/browser/content_settings/content_settings_utils.cc
+++ b/chrome/browser/content_settings/content_settings_utils.cc
@@ -17,7 +17,7 @@
 #include "chrome/browser/content_settings/host_content_settings_map.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/content_settings_pattern.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 namespace {
 
diff --git a/chrome/browser/content_settings/cookie_settings.cc b/chrome/browser/content_settings/cookie_settings.cc
index 2513a0c..bd82c1d 100644
--- a/chrome/browser/content_settings/cookie_settings.cc
+++ b/chrome/browser/content_settings/cookie_settings.cc
@@ -22,9 +22,9 @@
 #include "content/public/browser/notification_source.h"
 #include "content/public/browser/user_metrics.h"
 #include "extensions/common/constants.h"
-#include "googleurl/src/gurl.h"
 #include "net/base/net_errors.h"
 #include "net/base/static_cookie_policy.h"
+#include "url/gurl.h"
 
 using content::BrowserThread;
 using content::UserMetricsAction;
diff --git a/chrome/browser/content_settings/cookie_settings_unittest.cc b/chrome/browser/content_settings/cookie_settings_unittest.cc
index 59f4570..45e1eeb 100644
--- a/chrome/browser/content_settings/cookie_settings_unittest.cc
+++ b/chrome/browser/content_settings/cookie_settings_unittest.cc
@@ -12,9 +12,9 @@
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/testing_profile.h"
 #include "content/public/test/test_browser_thread.h"
-#include "googleurl/src/gurl.h"
 #include "net/base/static_cookie_policy.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
 
 using content::BrowserThread;
 
diff --git a/chrome/browser/content_settings/host_content_settings_map.cc b/chrome/browser/content_settings/host_content_settings_map.cc
index 4cc1d77..fad7c9d 100644
--- a/chrome/browser/content_settings/host_content_settings_map.cc
+++ b/chrome/browser/content_settings/host_content_settings_map.cc
@@ -35,9 +35,9 @@
 #include "content/public/browser/user_metrics.h"
 #include "content/public/common/content_switches.h"
 #include "extensions/common/constants.h"
-#include "googleurl/src/gurl.h"
 #include "net/base/net_errors.h"
 #include "net/base/static_cookie_policy.h"
+#include "url/gurl.h"
 
 using content::BrowserThread;
 using content::UserMetricsAction;
diff --git a/chrome/browser/content_settings/host_content_settings_map_unittest.cc b/chrome/browser/content_settings/host_content_settings_map_unittest.cc
index 78f5a39..76f0dff 100644
--- a/chrome/browser/content_settings/host_content_settings_map_unittest.cc
+++ b/chrome/browser/content_settings/host_content_settings_map_unittest.cc
@@ -19,9 +19,9 @@
 #include "chrome/test/base/testing_pref_service_syncable.h"
 #include "chrome/test/base/testing_profile.h"
 #include "content/public/test/test_browser_thread.h"
-#include "googleurl/src/gurl.h"
 #include "net/base/static_cookie_policy.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
 
 using content::BrowserThread;
 
diff --git a/chrome/browser/content_settings/local_shared_objects_container.cc b/chrome/browser/content_settings/local_shared_objects_container.cc
index 3fd6d06..d4a996d 100644
--- a/chrome/browser/content_settings/local_shared_objects_container.cc
+++ b/chrome/browser/content_settings/local_shared_objects_container.cc
@@ -14,9 +14,9 @@
 #include "chrome/browser/browsing_data/cookies_tree_model.h"
 #include "chrome/browser/profiles/profile.h"
 #include "content/public/common/url_constants.h"
-#include "googleurl/src/gurl.h"
 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
 #include "net/cookies/canonical_cookie.h"
+#include "url/gurl.h"
 
 namespace {
 
diff --git a/chrome/browser/content_settings/mock_settings_observer.cc b/chrome/browser/content_settings/mock_settings_observer.cc
index c8de7fa..0640a2e 100644
--- a/chrome/browser/content_settings/mock_settings_observer.cc
+++ b/chrome/browser/content_settings/mock_settings_observer.cc
@@ -9,7 +9,7 @@
 #include "chrome/common/chrome_notification_types.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/notification_source.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 MockSettingsObserver::MockSettingsObserver() {
   registrar_.Add(this, chrome::NOTIFICATION_CONTENT_SETTINGS_CHANGED,
diff --git a/chrome/browser/crash_handler_host_linux.cc b/chrome/browser/crash_handler_host_linux.cc
index 51e1a3c..b25696f 100644
--- a/chrome/browser/crash_handler_host_linux.cc
+++ b/chrome/browser/crash_handler_host_linux.cc
@@ -28,8 +28,8 @@
 #include "breakpad/src/client/linux/minidump_writer/linux_dumper.h"
 #include "breakpad/src/client/linux/minidump_writer/minidump_writer.h"
 #include "chrome/app/breakpad_linux_impl.h"
+#include "chrome/common/chrome_paths.h"
 #include "chrome/common/env_vars.h"
-#include "components/breakpad/common/breakpad_paths.h"
 #include "content/public/browser/browser_thread.h"
 
 #if defined(OS_ANDROID)
@@ -379,7 +379,7 @@
   base::FilePath dumps_path("/tmp");
   PathService::Get(base::DIR_TEMP, &dumps_path);
   if (!info->upload)
-    PathService::Get(breakpad::DIR_CRASH_DUMPS, &dumps_path);
+    PathService::Get(chrome::DIR_CRASH_DUMPS, &dumps_path);
   const uint64 rand = base::RandUint64();
   const std::string minidump_filename =
       base::StringPrintf("%s/chromium-%s-minidump-%016" PRIx64 ".dmp",
diff --git a/chrome/browser/crash_upload_list.cc b/chrome/browser/crash_upload_list.cc
index d5463ac..911fec4 100644
--- a/chrome/browser/crash_upload_list.cc
+++ b/chrome/browser/crash_upload_list.cc
@@ -4,107 +4,31 @@
 
 #include "chrome/browser/crash_upload_list.h"
 
-#include <algorithm>
-#include <iterator>
-
-#include "base/bind.h"
-#include "base/file_util.h"
 #include "base/files/file_path.h"
 #include "base/path_service.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_split.h"
+#include "chrome/common/chrome_paths.h"
 #if defined(OS_WIN)
 #include "chrome/browser/crash_upload_list_win.h"
 #endif
-#include "components/breakpad/common/breakpad_paths.h"
-#include "content/public/browser/browser_thread.h"
-
-using content::BrowserThread;
-
-CrashUploadList::CrashInfo::CrashInfo(const std::string& c, const base::Time& t)
-    : crash_id(c), crash_time(t) {}
-
-CrashUploadList::CrashInfo::~CrashInfo() {}
-
-// static
-CrashUploadList* CrashUploadList::Create(Delegate* delegate) {
-#if defined(OS_WIN)
-  return new CrashUploadListWin(delegate);
-#else
-  return new CrashUploadList(delegate);
-#endif
-}
 
 // static
 const char* CrashUploadList::kReporterLogFilename = "uploads.log";
 
-CrashUploadList::CrashUploadList(Delegate* delegate) : delegate_(delegate) {}
+// static
+CrashUploadList* CrashUploadList::Create(Delegate* delegate) {
+  base::FilePath crash_dir_path;
+  PathService::Get(chrome::DIR_CRASH_DUMPS, &crash_dir_path);
+  base::FilePath upload_log_path =
+      crash_dir_path.AppendASCII(kReporterLogFilename);
+#if defined(OS_WIN)
+  return new CrashUploadListWin(delegate, upload_log_path);
+#else
+  return new CrashUploadList(delegate, upload_log_path);
+#endif
+}
+
+CrashUploadList::CrashUploadList(Delegate* delegate,
+                                 const base::FilePath& upload_log_path)
+    : UploadList(delegate, upload_log_path) {}
 
 CrashUploadList::~CrashUploadList() {}
-
-void CrashUploadList::LoadCrashListAsynchronously() {
-  BrowserThread::PostBlockingPoolTask(
-      FROM_HERE,
-      base::Bind(&CrashUploadList::LoadCrashListAndInformDelegateOfCompletion,
-                 this));
-}
-
-void CrashUploadList::ClearDelegate() {
-  delegate_ = NULL;
-}
-
-
-void CrashUploadList::LoadCrashListAndInformDelegateOfCompletion() {
-  LoadCrashList();
-  BrowserThread::PostTask(
-      BrowserThread::UI,
-      FROM_HERE,
-      base::Bind(&CrashUploadList::InformDelegateOfCompletion, this));
-}
-
-void CrashUploadList::LoadCrashList() {
-  base::FilePath crash_dir_path;
-  PathService::Get(breakpad::DIR_CRASH_DUMPS, &crash_dir_path);
-  base::FilePath upload_log_path = crash_dir_path.AppendASCII("uploads.log");
-  if (file_util::PathExists(upload_log_path)) {
-    std::string contents;
-    file_util::ReadFileToString(upload_log_path, &contents);
-    std::vector<std::string> log_entries;
-    base::SplitStringAlongWhitespace(contents, &log_entries);
-    ParseLogEntries(log_entries);
-  }
-}
-
-void CrashUploadList::ParseLogEntries(
-    const std::vector<std::string>& log_entries) {
-  std::vector<std::string>::const_reverse_iterator i;
-  for (i = log_entries.rbegin(); i != log_entries.rend(); ++i) {
-    std::vector<std::string> components;
-    base::SplitString(*i, ',', &components);
-    // Skip any blank (or corrupted) lines.
-    if (components.size() != 2)
-      continue;
-    double seconds_since_epoch;
-    if (!base::StringToDouble(components[0], &seconds_since_epoch))
-      continue;
-    CrashInfo info(components[1], base::Time::FromDoubleT(seconds_since_epoch));
-    crashes_.push_back(info);
-  }
-}
-
-void CrashUploadList::InformDelegateOfCompletion() {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  if (delegate_)
-    delegate_->OnCrashListAvailable();
-}
-
-void CrashUploadList::GetUploadedCrashes(unsigned int max_count,
-                                         std::vector<CrashInfo>* crashes) {
-  std::copy(crashes_.begin(),
-            crashes_.begin() + std::min<size_t>(crashes_.size(), max_count),
-            std::back_inserter(*crashes));
-}
-
-std::vector<CrashUploadList::CrashInfo>& CrashUploadList::crashes() {
-  return crashes_;
-}
diff --git a/chrome/browser/crash_upload_list.h b/chrome/browser/crash_upload_list.h
index 78af39d..f0b201c 100644
--- a/chrome/browser/crash_upload_list.h
+++ b/chrome/browser/crash_upload_list.h
@@ -5,32 +5,11 @@
 #ifndef CHROME_BROWSER_CRASH_UPLOAD_LIST_H_
 #define CHROME_BROWSER_CRASH_UPLOAD_LIST_H_
 
-#include <string>
-#include <vector>
+#include "chrome/browser/upload_list.h"
 
-#include "base/memory/ref_counted.h"
-#include "base/time.h"
-
-class CrashUploadList : public base::RefCountedThreadSafe<CrashUploadList> {
+// An upload list manager for crash reports from breakpad.
+class CrashUploadList : public UploadList {
  public:
-  struct CrashInfo {
-    CrashInfo(const std::string& c, const base::Time& t);
-    ~CrashInfo();
-
-    std::string crash_id;
-    base::Time crash_time;
-  };
-
-  class Delegate {
-   public:
-    // Invoked when the crash list has been loaded. Will be called on the
-    // UI thread.
-    virtual void OnCrashListAvailable() = 0;
-
-   protected:
-    virtual ~Delegate() {}
-  };
-
   // Static factory method that creates the platform-specific implementation
   // of the crash upload list with the given callback delegate.
   static CrashUploadList* Create(Delegate* delegate);
@@ -40,46 +19,12 @@
   static const char* kReporterLogFilename;
 
   // Creates a new crash upload list with the given callback delegate.
-  explicit CrashUploadList(Delegate* delegate);
-
-  // Starts loading the crash list. OnCrashListAvailable will be called when
-  // loading is complete.
-  void LoadCrashListAsynchronously();
-
-  // Clears the delegate, so that any outstanding asynchronous load will not
-  // call the delegate on completion.
-  void ClearDelegate();
-
-  // Populates |crashes| with the |max_count| most recent uploaded crashes,
-  // in reverse chronological order.
-  // Must be called only after OnCrashListAvailable has been called.
-  void GetUploadedCrashes(unsigned int max_count,
-                          std::vector<CrashInfo>* crashes);
+  CrashUploadList(Delegate* delegate, const base::FilePath& upload_log_path);
 
  protected:
   virtual ~CrashUploadList();
 
-  // Reads the upload log and stores the entries in crashes_.
-  virtual void LoadCrashList();
-
-  // Returns a reference to the list of crashes.
-  std::vector<CrashInfo>& crashes();
-
  private:
-  friend class base::RefCountedThreadSafe<CrashUploadList>;
-
-  // Manages the background thread work for LoadCrashListAsynchronously().
-  void LoadCrashListAndInformDelegateOfCompletion();
-
-  // Calls the delegate's callback method, if there is a delegate.
-  void InformDelegateOfCompletion();
-
-  // Parses crash log lines, converting them to CrashInfo entries.
-  void ParseLogEntries(const std::vector<std::string>& log_entries);
-
-  std::vector<CrashInfo> crashes_;
-  Delegate* delegate_;
-
   DISALLOW_COPY_AND_ASSIGN(CrashUploadList);
 };
 
diff --git a/chrome/browser/crash_upload_list_win.cc b/chrome/browser/crash_upload_list_win.cc
index e0130ac..418cbcb 100644
--- a/chrome/browser/crash_upload_list_win.cc
+++ b/chrome/browser/crash_upload_list_win.cc
@@ -8,10 +8,11 @@
 #include "base/strings/stringprintf.h"
 #include "base/strings/sys_string_conversions.h"
 
-CrashUploadListWin::CrashUploadListWin(Delegate* delegate)
-    : CrashUploadList(delegate) {}
+CrashUploadListWin::CrashUploadListWin(Delegate* delegate,
+                                       const base::FilePath& upload_log_path)
+    : CrashUploadList(delegate, upload_log_path) {}
 
-void CrashUploadListWin::LoadCrashList() {
+void CrashUploadListWin::LoadUploadList() {
   std::vector<uint8> buffer(1024);
   HANDLE event_log = OpenEventLog(NULL, L"Application");
   if (event_log) {
@@ -72,9 +73,9 @@
     if (end_index != std::wstring::npos) {
       std::wstring crash_id =
           message.substr(start_index, end_index - start_index);
-      crashes().push_back(
-          CrashInfo(base::SysWideToUTF8(crash_id),
-                    base::Time::FromDoubleT(record->TimeGenerated)));
+      AppendUploadInfo(
+          UploadInfo(base::SysWideToUTF8(crash_id),
+                     base::Time::FromDoubleT(record->TimeGenerated)));
     }
   }
 }
diff --git a/chrome/browser/crash_upload_list_win.h b/chrome/browser/crash_upload_list_win.h
index c42365f..fd93e22 100644
--- a/chrome/browser/crash_upload_list_win.h
+++ b/chrome/browser/crash_upload_list_win.h
@@ -12,11 +12,11 @@
 // from the Windows Event Log.
 class CrashUploadListWin : public CrashUploadList {
  public:
-  explicit CrashUploadListWin(Delegate* delegate);
+  CrashUploadListWin(Delegate* delegate, const base::FilePath& upload_log_path);
 
  protected:
   // Loads the list of crashes from the Windows Event Log.
-  virtual void LoadCrashList() OVERRIDE;
+  virtual void LoadUploadList() OVERRIDE;
 
  private:
   // Returns whether the event record is likely a Chrome crash log.
diff --git a/chrome/browser/custom_home_pages_table_model.cc b/chrome/browser/custom_home_pages_table_model.cc
index 0af2677..2460717 100644
--- a/chrome/browser/custom_home_pages_table_model.cc
+++ b/chrome/browser/custom_home_pages_table_model.cc
@@ -18,13 +18,13 @@
 #include "chrome/common/pref_names.h"
 #include "chrome/common/url_constants.h"
 #include "content/public/browser/web_contents.h"
-#include "googleurl/src/gurl.h"
 #include "grit/generated_resources.h"
 #include "grit/ui_resources.h"
 #include "net/base/net_util.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/models/table_model_observer.h"
 #include "ui/gfx/codec/png_codec.h"
+#include "url/gurl.h"
 
 namespace {
 
diff --git a/chrome/browser/devtools/adb/android_usb_device.cc b/chrome/browser/devtools/adb/android_usb_device.cc
new file mode 100644
index 0000000..c77fd4e
--- /dev/null
+++ b/chrome/browser/devtools/adb/android_usb_device.cc
@@ -0,0 +1,403 @@
+// 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/adb/android_usb_device.h"
+
+#include "base/base64.h"
+#include "base/message_loop/message_loop.h"
+#include "base/strings/stringprintf.h"
+#include "chrome/browser/devtools/adb/android_usb_socket.h"
+#include "chrome/browser/usb/usb_interface.h"
+#include "chrome/browser/usb/usb_service.h"
+#include "chrome/browser/usb/usb_service_factory.h"
+#include "net/base/ip_endpoint.h"
+#include "net/base/net_errors.h"
+#include "net/socket/stream_socket.h"
+
+namespace {
+
+void Noop() {}
+void BoolNoop(bool success) {}
+
+const size_t kHeaderSize = 24;
+
+const int kAdbClass = 0xff;
+const int kAdbSubclass = 0x42;
+const int kAdbProtocol = 0x1;
+
+const int kUsbTimeout = 1000;
+
+const uint32 kMaxPayload = 4096;
+const uint32 kVersion = 0x01000000;
+
+static const char kHostConnectMessage[] = "host::";
+static const char kRSAPublicKey[] =
+    "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA6OSJ64q+ZLg7VV2ojEPh5TRbYjwbT"
+    "TifSPeFIV45CHnbTWYiiIn41wrozpYizNsMWZUBjdah1N78WVhbyDrnr0bDgFp+gXjfVppa3I"
+    "gjiohEcemK3omXi3GDMK8ERhriLUKfQS842SXtQ8I+KoZtpCkGM//0h7+P+Rhm0WwdipIRMhR"
+    "8haNAeyDiiCvqJcvevv2T52vqKtS3aWz+GjaTJJLVWydEpz9WdvWeLfFVhe2ZnqwwZNa30Qoj"
+    "fsnvjaMwK2MU7uYfRBPuvLyK5QESWBpArNDd6ULl8Y+NU6kwNOVDc87OASCVEM1gw2IMi2mo2"
+    "WO5ywp0UWRiGZCkK+wOFQIDAQAB";
+
+static bool CheckUsbInterface(
+    const UsbInterface* interface,
+    int* inbound_address,
+    int* outbound_address,
+    int* zero_mask) {
+  if (interface->GetNumAltSettings() == 0)
+    return false;
+
+  scoped_refptr<const UsbInterfaceDescriptor> idesc =
+      interface->GetAltSetting(0).get();
+
+  if (idesc->GetInterfaceClass() != kAdbClass ||
+      idesc->GetInterfaceSubclass() != kAdbSubclass ||
+      idesc->GetInterfaceProtocol() != kAdbProtocol ||
+      idesc->GetNumEndpoints() != 2) {
+    return false;
+  }
+
+  for (size_t i = 0; i < idesc->GetNumEndpoints(); ++i) {
+    scoped_refptr<const UsbEndpointDescriptor> edesc =
+        idesc->GetEndpoint(i).get();
+    if (edesc->GetTransferType() != USB_TRANSFER_BULK)
+      continue;
+    if (edesc->GetDirection() == USB_DIRECTION_INBOUND)
+      *inbound_address = edesc->GetAddress();
+    else
+      *outbound_address = edesc->GetAddress();
+    *zero_mask = edesc->GetMaximumPacketSize() - 1;
+  }
+
+  if (inbound_address == 0 || outbound_address == 0)
+    return false;
+  return true;
+}
+
+static uint32 Checksum(const std::string& data) {
+  unsigned char* x = (unsigned char*)data.data();
+  int count = data.length();
+  uint32 sum = 0;
+  while (count-- > 0)
+    sum += *x++;
+  return sum;
+}
+
+static void DumpMessage(bool outgoing, const char* data, size_t length) {
+#if 0
+  std::string result = "";
+  if (length == kHeaderSize) {
+    for (size_t i = 0; i < 24; ++i) {
+      result += base::StringPrintf("%02x",
+          data[i] > 0 ? data[i] : (data[i] + 0x100) & 0xFF);
+      if ((i + 1) % 4 == 0)
+        result += " ";
+    }
+    for (size_t i = 0; i < 24; ++i) {
+      if (data[i] >= 0x20 && data[i] <= 0x7E)
+        result += data[i];
+      else
+        result += ".";
+    }
+  } else {
+    result = base::StringPrintf("%d: ", (int)length);
+    for (size_t i = 0; i < length; ++i) {
+      if (data[i] >= 0x20 && data[i] <= 0x7E)
+        result += data[i];
+      else
+        result += ".";
+    }
+  }
+  LOG(ERROR) << (outgoing ? "[out] " : "[ in] ") << result;
+#endif  // 0
+}
+
+}  // namespace
+
+AdbMessage::AdbMessage(uint32 command,
+                       uint32 arg0,
+                       uint32 arg1,
+                       const std::string& body)
+    : command(command),
+      arg0(arg0),
+      arg1(arg1),
+      body(body) {
+}
+
+AdbMessage::~AdbMessage() {
+}
+
+// static
+void AndroidUsbDevice::Enumerate(
+    Profile* profile,
+    std::vector<scoped_refptr<AndroidUsbDevice> >* devices) {
+  UsbService* service =
+      UsbServiceFactory::GetInstance()->GetForProfile(profile);
+
+  // Enumerate usb devices.
+  std::vector<scoped_refptr<UsbDevice> > usb_devices;
+  service->EnumerateDevices(&usb_devices);
+  for (size_t i = 0; i < usb_devices.size(); ++i) {
+    scoped_refptr<UsbDevice> usb_device = usb_devices[i];
+
+    // Enumerate device interfaces.
+    scoped_refptr<UsbConfigDescriptor> config = new UsbConfigDescriptor();
+    usb_device->ListInterfaces(config.get(), base::Bind(&BoolNoop));
+    for (size_t i = 0; i < config->GetNumInterfaces(); ++i) {
+      scoped_refptr<const UsbInterface> interface = config->GetInterface(i);
+
+      int inbound_address = 0;
+      int outbound_address = 0;
+      int zero_mask = 0;
+      if (CheckUsbInterface(interface, &inbound_address, &outbound_address,
+                            &zero_mask)) {
+        devices->push_back(new AndroidUsbDevice(usb_device, inbound_address,
+                                                outbound_address, zero_mask));
+      }
+    }
+  }
+}
+
+AndroidUsbDevice::AndroidUsbDevice(scoped_refptr<UsbDevice> usb_device,
+                                   int inbound_address,
+                                   int outbound_address,
+                                   int zero_mask)
+    : message_loop_(NULL),
+      usb_device_(usb_device),
+      inbound_address_(inbound_address),
+      outbound_address_(outbound_address),
+      zero_mask_(zero_mask),
+      is_connected_(false),
+      last_socket_id_(256) {
+  message_loop_ = base::MessageLoop::current();
+  usb_device_->ClaimInterface(1, base::Bind(&AndroidUsbDevice::InterfaceClaimed,
+                                            this));
+}
+
+net::StreamSocket* AndroidUsbDevice::CreateSocket(const std::string& command) {
+  uint32 socket_id = ++last_socket_id_;
+  sockets_[socket_id] = new AndroidUsbSocket(this, socket_id, command,
+      base::Bind(&AndroidUsbDevice::SocketDeleted, this));
+  return sockets_[socket_id];
+}
+
+void AndroidUsbDevice::Send(uint32 command,
+                            uint32 arg0,
+                            uint32 arg1,
+                            const std::string& body) {
+  scoped_refptr<AdbMessage> m = new AdbMessage(command, arg0, arg1, body);
+  // Delay open request if not yet connected.
+  if (!is_connected_) {
+    pending_messages_.push_back(m);
+    return;
+  }
+  Queue(m);
+}
+
+AndroidUsbDevice::~AndroidUsbDevice() {
+  usb_device_->ReleaseInterface(1, base::Bind(&BoolNoop));
+  usb_device_->Close(base::Bind(&Noop));
+}
+
+void AndroidUsbDevice::InterfaceClaimed(bool success) {
+  if (!success)
+    return;
+  Queue(new AdbMessage(AdbMessage::kCommandCNXN, kVersion, kMaxPayload,
+                       kHostConnectMessage));
+  ReadHeader();
+}
+
+void AndroidUsbDevice::Queue(scoped_refptr<AdbMessage> message) {
+  // Queue header.
+  std::vector<uint32> header;
+  header.push_back(message->command);
+  header.push_back(message->arg0);
+  header.push_back(message->arg1);
+  bool append_zero = true;
+  if (message->body.empty())
+    append_zero = false;
+  if (message->command == AdbMessage::kCommandAUTH &&
+      message->arg0 == AdbMessage::kAuthSignature)
+    append_zero = false;
+  if (message->command == AdbMessage::kCommandWRTE)
+    append_zero = false;
+
+  size_t body_length = message->body.length() + (append_zero ? 1 : 0);
+  header.push_back(body_length);
+  header.push_back(Checksum(message->body));
+  header.push_back(message->command ^ 0xffffffff);
+  scoped_refptr<net::IOBuffer> header_buffer = new net::IOBuffer(kHeaderSize);
+  memcpy(header_buffer.get()->data(), &header[0], kHeaderSize);
+  outgoing_queue_.push(std::make_pair(header_buffer, kHeaderSize));
+
+  // Queue body.
+  if (!message->body.empty()) {
+    scoped_refptr<net::IOBuffer> body_buffer = new net::IOBuffer(body_length);
+    memcpy(body_buffer->data(), message->body.data(), message->body.length());
+    if (append_zero)
+      body_buffer->data()[body_length - 1] = 0;
+    outgoing_queue_.push(std::make_pair(body_buffer, body_length));
+  }
+  ProcessOutgoing();
+}
+
+void AndroidUsbDevice::ProcessOutgoing() {
+  if (outgoing_queue_.empty())
+    return;
+
+  BulkMessage message = outgoing_queue_.front();
+  outgoing_queue_.pop();
+  DumpMessage(true, message.first->data(), message.second);
+  usb_device_->BulkTransfer(USB_DIRECTION_OUTBOUND, outbound_address_,
+      message.first, message.second, kUsbTimeout,
+      base::Bind(&AndroidUsbDevice::OutgoingMessageSent, this));
+}
+
+void AndroidUsbDevice::OutgoingMessageSent(UsbTransferStatus status,
+                                           scoped_refptr<net::IOBuffer> buffer,
+                                           size_t result) {
+  if (status != USB_TRANSFER_COMPLETED)
+    return;
+  message_loop_->PostTask(FROM_HERE,
+                          base::Bind(&AndroidUsbDevice::ProcessOutgoing,
+                                     this));
+}
+
+void AndroidUsbDevice::ReadHeader() {
+  if (HasOneRef())
+    return;  // Stop polling.
+  scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(kHeaderSize);
+  usb_device_->BulkTransfer(USB_DIRECTION_INBOUND, inbound_address_,
+      buffer, kHeaderSize, kUsbTimeout,
+      base::Bind(&AndroidUsbDevice::ParseHeader, this));
+}
+
+void AndroidUsbDevice::ParseHeader(UsbTransferStatus status,
+                                   scoped_refptr<net::IOBuffer> buffer,
+                                   size_t result) {
+  if (status == USB_TRANSFER_TIMEOUT) {
+    message_loop_->PostTask(FROM_HERE,
+                            base::Bind(&AndroidUsbDevice::ReadHeader, this));
+    return;
+  }
+
+  if (status != USB_TRANSFER_COMPLETED) {
+    LOG(ERROR) << "Unexpeced transfer status: " << status;
+    return;
+  }
+
+  if (result != kHeaderSize) {
+    LOG(ERROR) << "Unexpeced header size: " << result;
+    return;
+  }
+
+  DumpMessage(false, buffer->data(), result);
+  std::vector<uint32> header(6);
+  memcpy(&header[0], buffer->data(), result);
+  scoped_refptr<AdbMessage> message =
+      new AdbMessage(header[0], header[1], header[2], "");
+  uint32 data_length = header[3];
+  uint32 data_check = header[4];
+  uint32 magic = header[5];
+  if ((message->command ^ 0xffffffff) != magic)
+    return;
+
+  if (data_length == 0) {
+    message_loop_->PostTask(FROM_HERE,
+                            base::Bind(&AndroidUsbDevice::HandleIncoming, this,
+                                       message));
+    return;
+  }
+
+  message_loop_->PostTask(FROM_HERE,
+                          base::Bind(&AndroidUsbDevice::ReadBody, this,
+                                     message, data_length, data_check));
+}
+
+void AndroidUsbDevice::ReadBody(scoped_refptr<AdbMessage> message,
+                                uint32 data_length,
+                                uint32 data_check) {
+  scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(data_length);
+  usb_device_->BulkTransfer(USB_DIRECTION_INBOUND, inbound_address_,
+      buffer, data_length, kUsbTimeout,
+      base::Bind(&AndroidUsbDevice::ParseBody, this, message, data_length,
+                 data_check));
+}
+
+void AndroidUsbDevice::ParseBody(scoped_refptr<AdbMessage> message,
+                                 uint32 data_length,
+                                 uint32 data_check,
+                                 UsbTransferStatus status,
+                                 scoped_refptr<net::IOBuffer> buffer,
+                                 size_t result) {
+  if (status == USB_TRANSFER_TIMEOUT) {
+    message_loop_->PostTask(FROM_HERE,
+                            base::Bind(&AndroidUsbDevice::ReadBody, this,
+                            message, data_length, data_check));
+    return;
+  }
+
+  if (status != USB_TRANSFER_COMPLETED) {
+    LOG(ERROR) << "Unexpeced transfer status: " << status;
+    return;
+  }
+
+  if (static_cast<uint32>(result) != data_length) {
+    LOG(ERROR) << "Unexpeced body length: " << result << ", expecteced" <<
+        data_length;
+    return;
+  }
+
+  DumpMessage(false, buffer->data(), data_length);
+  message->body = std::string(buffer->data(), result);
+  if (Checksum(message->body) != data_check) {
+    LOG(ERROR) << "Wrong body checksum";
+    return;
+  }
+
+  message_loop_->PostTask(FROM_HERE,
+                          base::Bind(&AndroidUsbDevice::HandleIncoming, this,
+                                     message));
+}
+
+void AndroidUsbDevice::HandleIncoming(scoped_refptr<AdbMessage> message) {
+  switch (message->command) {
+    case AdbMessage::kCommandAUTH:
+      {
+        DCHECK_EQ(message->arg0, static_cast<uint32>(AdbMessage::kAuthToken));
+        Queue(new AdbMessage(AdbMessage::kCommandAUTH,
+                             AdbMessage::kAuthRSAPublicKey, 0,
+                             kRSAPublicKey));
+      }
+      break;
+    case AdbMessage::kCommandCNXN:
+      {
+        is_connected_ = true;
+        PendingMessages pending;
+        pending.swap(pending_messages_);
+        for (PendingMessages::iterator it = pending.begin();
+             it != pending.end(); ++it) {
+          Queue(*it);
+        }
+      }
+      break;
+    case AdbMessage::kCommandOKAY:
+    case AdbMessage::kCommandWRTE:
+    case AdbMessage::kCommandCLSE:
+      {
+        // Route these to sockets
+        AndroidUsbSockets::iterator it = sockets_.find(message->arg1);
+        if (it != sockets_.end())
+          it->second->HandleIncoming(message);
+      }
+      break;
+    default:
+      break;
+  }
+  ReadHeader();
+}
+
+void AndroidUsbDevice::SocketDeleted(uint32 socket_id) {
+  sockets_.erase(socket_id);
+}
diff --git a/chrome/browser/devtools/adb/android_usb_device.h b/chrome/browser/devtools/adb/android_usb_device.h
new file mode 100644
index 0000000..4b27a13
--- /dev/null
+++ b/chrome/browser/devtools/adb/android_usb_device.h
@@ -0,0 +1,135 @@
+// 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_ADB_ANDROID_USB_DEVICE_H_
+#define CHROME_BROWSER_DEVTOOLS_ADB_ANDROID_USB_DEVICE_H_
+
+#include <map>
+#include <queue>
+#include <vector>
+#include "base/memory/ref_counted.h"
+#include "chrome/browser/usb/usb_device.h"
+
+namespace base {
+class MessageLoop;
+}
+
+namespace net {
+class StreamSocket;
+}
+
+class AndroidUsbSocket;
+class Profile;
+
+class AdbMessage : public base::RefCounted<AdbMessage> {
+ public:
+  enum Command {
+    kCommandSYNC = 0x434e5953,
+    kCommandCNXN = 0x4e584e43,
+    kCommandOPEN = 0x4e45504f,
+    kCommandOKAY = 0x59414b4f,
+    kCommandCLSE = 0x45534c43,
+    kCommandWRTE = 0x45545257,
+    kCommandAUTH = 0x48545541
+  };
+
+  enum Auth {
+    kAuthToken = 1,
+    kAuthSignature = 2,
+    kAuthRSAPublicKey = 3
+  };
+
+  AdbMessage(uint32 command,
+             uint32 arg0,
+             uint32 arg1,
+             const std::string& body);
+
+  uint32 command;
+  uint32 arg0;
+  uint32 arg1;
+  std::string body;
+ private:
+  friend class base::RefCounted<AdbMessage>;
+  ~AdbMessage();
+
+  DISALLOW_COPY_AND_ASSIGN(AdbMessage);
+};
+
+typedef base::Callback<void(int, AdbMessage*)> AdbCallback;
+
+class AndroidUsbDevice : public base::RefCountedThreadSafe<AndroidUsbDevice> {
+ public:
+  static void Enumerate(
+      Profile* profile,
+      std::vector<scoped_refptr<AndroidUsbDevice> >* devices);
+  AndroidUsbDevice(scoped_refptr<UsbDevice> device,
+                   int inbound_address,
+                   int outbound_address,
+                   int zero_mask);
+
+  net::StreamSocket* CreateSocket(const std::string& command);
+
+  void Send(uint32 command,
+            uint32 arg0,
+            uint32 arg1,
+            const std::string& body);
+
+ private:
+  friend class base::RefCountedThreadSafe<AndroidUsbDevice>;
+  virtual ~AndroidUsbDevice();
+
+  void InterfaceClaimed(bool success);
+
+  void Queue(scoped_refptr<AdbMessage> message);
+  void ProcessOutgoing();
+  void OutgoingMessageSent(UsbTransferStatus status,
+                           scoped_refptr<net::IOBuffer> buffer,
+                           size_t result);
+
+  void ReadHeader();
+  void ParseHeader(UsbTransferStatus status,
+                   scoped_refptr<net::IOBuffer> buffer,
+                   size_t result);
+
+  void ReadBody(scoped_refptr<AdbMessage> message,
+                uint32 data_length,
+                uint32 data_check);
+  void ParseBody(scoped_refptr<AdbMessage> message,
+                 uint32 data_length,
+                 uint32 data_check,
+                 UsbTransferStatus status,
+                 scoped_refptr<net::IOBuffer> buffer,
+                 size_t result);
+
+  void HandleIncoming(scoped_refptr<AdbMessage> message);
+
+  void SocketDeleted(uint32 socket_id);
+
+  base::MessageLoop* message_loop_;
+
+  // Device info
+  scoped_refptr<UsbDevice> usb_device_;
+  int inbound_address_;
+  int outbound_address_;
+  int zero_mask_;
+
+  bool is_connected_;
+
+  // Created sockets info
+  uint32 last_socket_id_;
+  typedef std::map<uint32, AndroidUsbSocket*> AndroidUsbSockets;
+  AndroidUsbSockets sockets_;
+
+  // Outgoing bulk queue
+  typedef std::pair<scoped_refptr<net::IOBuffer>, size_t> BulkMessage;
+  std::queue<BulkMessage> outgoing_queue_;
+
+  // Outgoing messages pending connect
+  typedef std::vector<scoped_refptr<AdbMessage> > PendingMessages;
+  PendingMessages pending_messages_;
+
+  DISALLOW_COPY_AND_ASSIGN(AndroidUsbDevice);
+};
+
+#endif  // CHROME_BROWSER_DEVTOOLS_ADB_ANDROID_USB_DEVICE_H_
diff --git a/chrome/browser/devtools/adb/android_usb_socket.cc b/chrome/browser/devtools/adb/android_usb_socket.cc
new file mode 100644
index 0000000..2baefe1
--- /dev/null
+++ b/chrome/browser/devtools/adb/android_usb_socket.cc
@@ -0,0 +1,219 @@
+// 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/adb/android_usb_socket.h"
+
+#include "base/message_loop/message_loop.h"
+
+namespace {
+
+const int kMaxPayload = 4096;
+
+}  // namespace
+
+AndroidUsbSocket::IORequest::IORequest(
+    net::IOBuffer* buffer,
+    int length,
+    const net::CompletionCallback& callback)
+    : buffer(buffer),
+      length(length),
+      callback(callback) {
+}
+
+AndroidUsbSocket::IORequest::~IORequest() {
+}
+
+AndroidUsbSocket::AndroidUsbSocket(scoped_refptr<AndroidUsbDevice> device,
+                                   uint32 socket_id,
+                                   const std::string& command,
+                                   base::Callback<void(uint32)> delete_callback)
+    : message_loop_(base::MessageLoop::current()),
+      device_(device),
+      command_(command),
+      delete_callback_(delete_callback),
+      local_id_(socket_id),
+      remote_id_(0),
+      is_connected_(false) {
+}
+
+AndroidUsbSocket::~AndroidUsbSocket() {
+  DCHECK_EQ(message_loop_, base::MessageLoop::current());
+  if (is_connected_)
+    Disconnect();
+  delete_callback_.Run(local_id_);
+}
+
+void AndroidUsbSocket::HandleIncoming(scoped_refptr<AdbMessage> message) {
+  CHECK_EQ(message->arg1, local_id_);
+  switch (message->command) {
+    case AdbMessage::kCommandOKAY:
+      if (!is_connected_) {
+        remote_id_ = message->arg0;
+        is_connected_ = true;
+        connect_callback_.Run(net::OK);
+        // Can be NULL after response.
+      } else {
+        RespondToWriters();
+        // Can be NULL after response.
+      }
+      break;
+    case AdbMessage::kCommandWRTE:
+      read_buffer_ += message->body;
+      device_->Send(AdbMessage::kCommandOKAY, local_id_, remote_id_, "");
+      RespondToReaders(false);
+      // Can be NULL after response.
+      break;
+    case AdbMessage::kCommandCLSE:
+      if (is_connected_) {
+        device_->Send(AdbMessage::kCommandCLSE, local_id_, 0, "");
+      }
+      is_connected_ = false;
+      RespondToReaders(true);
+      // Can be NULL after response.
+      break;
+    default:
+      break;
+  }
+}
+
+int AndroidUsbSocket::Read(net::IOBuffer* buffer,
+                           int length,
+                           const net::CompletionCallback& callback) {
+  if (!is_connected_)
+    return net::ERR_SOCKET_NOT_CONNECTED;
+
+  if (read_buffer_.empty()) {
+    read_requests_.push_back(IORequest(buffer, length, callback));
+    return net::ERR_IO_PENDING;
+  }
+
+  size_t bytes_to_copy = static_cast<size_t>(length) > read_buffer_.length() ?
+      read_buffer_.length() : static_cast<size_t>(length);
+  memcpy(buffer->data(), read_buffer_.data(), bytes_to_copy);
+  if (read_buffer_.length() > bytes_to_copy)
+    read_buffer_ = read_buffer_.substr(bytes_to_copy);
+  else
+    read_buffer_ = "";
+  return net::OK;
+}
+
+int AndroidUsbSocket::Write(net::IOBuffer* buffer,
+                            int length,
+                            const net::CompletionCallback& callback) {
+  if (!is_connected_)
+    return net::ERR_SOCKET_NOT_CONNECTED;
+
+  if (length > kMaxPayload)
+    length = kMaxPayload;
+  write_requests_.push_back(IORequest(NULL, length, callback));
+  device_->Send(AdbMessage::kCommandWRTE, local_id_, remote_id_,
+                 std::string(buffer->data(), length));
+  return net::ERR_IO_PENDING;
+}
+
+bool AndroidUsbSocket::SetReceiveBufferSize(int32 size) {
+  NOTIMPLEMENTED();
+  return false;
+}
+
+bool AndroidUsbSocket::SetSendBufferSize(int32 size) {
+  NOTIMPLEMENTED();
+  return false;
+}
+
+int AndroidUsbSocket::Connect(const net::CompletionCallback& callback) {
+  CHECK_EQ(message_loop_, base::MessageLoop::current());
+  connect_callback_ = callback;
+  device_->Send(AdbMessage::kCommandOPEN, local_id_, 0, command_);
+  return net::ERR_IO_PENDING;
+}
+
+void AndroidUsbSocket::Disconnect() {
+  is_connected_ = false;
+  device_->Send(AdbMessage::kCommandCLSE, local_id_, remote_id_, "");
+  RespondToReaders(true);
+}
+
+bool AndroidUsbSocket::IsConnected() const {
+  CHECK_EQ(message_loop_, base::MessageLoop::current());
+  return is_connected_;
+}
+
+bool AndroidUsbSocket::IsConnectedAndIdle() const {
+  NOTIMPLEMENTED();
+  return false;
+}
+
+int AndroidUsbSocket::GetPeerAddress(net::IPEndPoint* address) const {
+  net::IPAddressNumber ip(net::kIPv4AddressSize);
+  *address = net::IPEndPoint(ip, 0);
+  return net::OK;
+}
+
+int AndroidUsbSocket::GetLocalAddress(net::IPEndPoint* address) const {
+  NOTIMPLEMENTED();
+  return net::ERR_FAILED;
+}
+
+const net::BoundNetLog& AndroidUsbSocket::NetLog() const {
+  return net_log_;
+}
+
+void AndroidUsbSocket::SetSubresourceSpeculation() {
+  NOTIMPLEMENTED();
+}
+
+void AndroidUsbSocket::SetOmniboxSpeculation() {
+  NOTIMPLEMENTED();
+}
+
+bool AndroidUsbSocket::WasEverUsed() const {
+  NOTIMPLEMENTED();
+  return true;
+}
+
+bool AndroidUsbSocket::UsingTCPFastOpen() const {
+  NOTIMPLEMENTED();
+  return true;
+}
+
+bool AndroidUsbSocket::WasNpnNegotiated() const {
+  NOTIMPLEMENTED();
+  return true;
+}
+
+net::NextProto AndroidUsbSocket::GetNegotiatedProtocol() const {
+  NOTIMPLEMENTED();
+  return net::kProtoUnknown;
+}
+
+bool AndroidUsbSocket::GetSSLInfo(net::SSLInfo* ssl_info) {
+  return false;
+}
+
+void AndroidUsbSocket::RespondToReaders(bool disconnect) {
+  std::deque<IORequest> read_requests;
+  read_requests.swap(read_requests_);
+  while (!read_requests.empty() && (!read_buffer_.empty() || disconnect)) {
+    IORequest read_request = read_requests.front();
+    read_requests.pop_front();
+    size_t bytes_to_copy =
+        static_cast<size_t>(read_request.length) > read_buffer_.length() ?
+            read_buffer_.length() : static_cast<size_t>(read_request.length);
+    memcpy(read_request.buffer->data(), read_buffer_.data(), bytes_to_copy);
+    if (read_buffer_.length() > bytes_to_copy)
+      read_buffer_ = read_buffer_.substr(bytes_to_copy);
+    else
+      read_buffer_ = "";
+    read_request.callback.Run(bytes_to_copy);
+  }
+}
+
+void AndroidUsbSocket::RespondToWriters() {
+  if (!write_requests_.empty()) {
+    IORequest write_request = write_requests_.front();
+    write_requests_.pop_front();
+    write_request.callback.Run(write_request.length);
+  }
+}
diff --git a/chrome/browser/devtools/adb/android_usb_socket.h b/chrome/browser/devtools/adb/android_usb_socket.h
new file mode 100644
index 0000000..d6367f8
--- /dev/null
+++ b/chrome/browser/devtools/adb/android_usb_socket.h
@@ -0,0 +1,86 @@
+// 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_ADB_ANDROID_USB_SOCKET_H_
+#define CHROME_BROWSER_DEVTOOLS_ADB_ANDROID_USB_SOCKET_H_
+
+#include <deque>
+
+#include "base/memory/ref_counted.h"
+#include "chrome/browser/devtools/adb/android_usb_device.h"
+#include "net/base/ip_endpoint.h"
+#include "net/base/net_errors.h"
+#include "net/socket/stream_socket.h"
+
+namespace base {
+class MessageLoop;
+}
+
+class AdbMessage;
+
+class AndroidUsbSocket : public net::StreamSocket {
+ public:
+  AndroidUsbSocket(scoped_refptr<AndroidUsbDevice> device,
+                   uint32 socket_id,
+                   const std::string& command,
+                   base::Callback<void(uint32)> delete_callback);
+  virtual ~AndroidUsbSocket();
+
+  void HandleIncoming(scoped_refptr<AdbMessage> message);
+
+  // net::StreamSocket implementation.
+  virtual int Read(net::IOBuffer* buf, int buf_len,
+                   const net::CompletionCallback& callback) OVERRIDE;
+  virtual int Write(net::IOBuffer* buf, int buf_len,
+                    const net::CompletionCallback& callback) OVERRIDE;
+  virtual bool SetReceiveBufferSize(int32 size) OVERRIDE;
+  virtual bool SetSendBufferSize(int32 size) OVERRIDE;
+  virtual int Connect(const net::CompletionCallback& callback) OVERRIDE;
+  virtual void Disconnect() OVERRIDE;
+  virtual bool IsConnected() const OVERRIDE;
+  virtual bool IsConnectedAndIdle() const OVERRIDE;
+  virtual int GetPeerAddress(net::IPEndPoint* address) const OVERRIDE;
+  virtual int GetLocalAddress(net::IPEndPoint* address) const OVERRIDE;
+  virtual const net::BoundNetLog& NetLog() const OVERRIDE;
+  virtual void SetSubresourceSpeculation() OVERRIDE;
+  virtual void SetOmniboxSpeculation() OVERRIDE;
+  virtual bool WasEverUsed() const OVERRIDE;
+  virtual bool UsingTCPFastOpen() const OVERRIDE;
+  virtual bool WasNpnNegotiated() const OVERRIDE;
+  virtual net::NextProto GetNegotiatedProtocol() const OVERRIDE;
+  virtual bool GetSSLInfo(net::SSLInfo* ssl_info) OVERRIDE;
+
+ private:
+  class IORequest {
+   public:
+    IORequest(net::IOBuffer* buffer,
+              int length,
+              const net::CompletionCallback& callback);
+    ~IORequest();
+
+    scoped_refptr<net::IOBuffer> buffer;
+    int length;
+    net::CompletionCallback callback;
+  };
+
+  void RespondToReaders(bool diconnect);
+  void RespondToWriters();
+
+  base::MessageLoop* message_loop_;
+  scoped_refptr<AndroidUsbDevice> device_;
+  std::string command_;
+  base::Callback<void(uint32)> delete_callback_;
+  uint32 local_id_;
+  uint32 remote_id_;
+  net::BoundNetLog net_log_;
+  bool is_connected_;
+  std::string read_buffer_;
+  net::CompletionCallback connect_callback_;
+  std::deque<IORequest> read_requests_;
+  std::deque<IORequest> write_requests_;
+
+  DISALLOW_COPY_AND_ASSIGN(AndroidUsbSocket);
+};
+
+#endif  // CHROME_BROWSER_DEVTOOLS_ADB_ANDROID_USB_SOCKET_H_
diff --git a/chrome/browser/devtools/devtools_adb_bridge.cc b/chrome/browser/devtools/devtools_adb_bridge.cc
index fb006f1..c903b5a 100644
--- a/chrome/browser/devtools/devtools_adb_bridge.cc
+++ b/chrome/browser/devtools/devtools_adb_bridge.cc
@@ -38,7 +38,6 @@
 namespace {
 
 static const char kDevToolsAdbBridgeThreadName[] = "Chrome_DevToolsADBThread";
-static const char kDevToolsChannelPattern[] = "devtools_remote";
 static const char kHostDevicesCommand[] = "host:devices";
 static const char kDeviceModelCommand[] =
     "host:transport:%s|shell:getprop ro.product.model";
@@ -274,7 +273,8 @@
     socket_to_package_.clear();
     std::vector<std::string> entries;
     Tokenize(response, "\n", &entries);
-    const std::string channel_pattern = kDevToolsChannelPattern;
+    const std::string channel_pattern =
+        base::StringPrintf(kDevToolsChannelNameFormat, "");
     for (size_t i = 1; i < entries.size(); ++i) {
       std::vector<std::string> fields;
       Tokenize(entries[i], " ", &fields);
@@ -309,6 +309,8 @@
 
 }  // namespace
 
+const char kDevToolsChannelNameFormat[] = "%s_devtools_remote";
+
 class AgentHostDelegate;
 
 typedef std::map<std::string, AgentHostDelegate*> AgentHostDelegates;
diff --git a/chrome/browser/devtools/devtools_adb_bridge.h b/chrome/browser/devtools/devtools_adb_bridge.h
index e2ef879..a828cb1 100644
--- a/chrome/browser/devtools/devtools_adb_bridge.h
+++ b/chrome/browser/devtools/devtools_adb_bridge.h
@@ -22,6 +22,9 @@
 
 class Profile;
 
+// The format used for constructing DevTools server socket names.
+extern const char kDevToolsChannelNameFormat[];
+
 class DevToolsAdbBridge {
  public:
   typedef base::Callback<void(int result,
diff --git a/chrome/browser/devtools/devtools_sanity_browsertest.cc b/chrome/browser/devtools/devtools_sanity_browsertest.cc
index 40a2c38..aba2865 100644
--- a/chrome/browser/devtools/devtools_sanity_browsertest.cc
+++ b/chrome/browser/devtools/devtools_sanity_browsertest.cc
@@ -552,9 +552,15 @@
   ASSERT_EQ(GetInspectedTab()->GetURL(), url);
 }
 
+#if defined(OS_WIN)
+// Flakily times out: http://crbug.com/163411
+#define MAYBE_TestReattachAfterCrash DISABLED_TestReattachAfterCrash
+#else
+#define MAYBE_TestReattachAfterCrash TestReattachAfterCrash
+#endif
 // Tests that inspector will reattach to inspected page when it is reloaded
 // after a crash. See http://crbug.com/101952
-IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestReattachAfterCrash) {
+IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, MAYBE_TestReattachAfterCrash) {
   OpenDevToolsWindow(kDebuggerTestPage);
 
   content::CrashTab(GetInspectedTab());
diff --git a/chrome/browser/diagnostics/OWNERS b/chrome/browser/diagnostics/OWNERS
index 3aae3d6..4478b09 100644
--- a/chrome/browser/diagnostics/OWNERS
+++ b/chrome/browser/diagnostics/OWNERS
@@ -1 +1,2 @@
 cpu@chromium.org
+gspencer@chromium.org
diff --git a/chrome/browser/diagnostics/diagnostics_main.cc b/chrome/browser/diagnostics/diagnostics_main.cc
index cd9530b..7d02a23 100644
--- a/chrome/browser/diagnostics/diagnostics_main.cc
+++ b/chrome/browser/diagnostics/diagnostics_main.cc
@@ -20,7 +20,7 @@
 #include "base/strings/stringprintf.h"
 #include "base/strings/sys_string_conversions.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/diagnostics/diagnostics_model.h"
 #include "chrome/common/chrome_paths.h"
 #include "ui/base/resource/resource_bundle.h"
diff --git a/chrome/browser/diagnostics/recon_diagnostics.cc b/chrome/browser/diagnostics/recon_diagnostics.cc
index b4be36b..b66fd03 100644
--- a/chrome/browser/diagnostics/recon_diagnostics.cc
+++ b/chrome/browser/diagnostics/recon_diagnostics.cc
@@ -243,7 +243,7 @@
 
     int64 dir_or_file_size = 0;
     if (path_info_.is_directory) {
-      dir_or_file_size = file_util::ComputeDirectorySize(dir_or_file);
+      dir_or_file_size = base::ComputeDirectorySize(dir_or_file);
     } else {
       file_util::GetFileSize(dir_or_file, &dir_or_file_size);
     }
diff --git a/chrome/browser/download/chrome_download_manager_delegate.cc b/chrome/browser/download/chrome_download_manager_delegate.cc
index f894dc0..2274fb7 100644
--- a/chrome/browser/download/chrome_download_manager_delegate.cc
+++ b/chrome/browser/download/chrome_download_manager_delegate.cc
@@ -15,7 +15,7 @@
 #include "base/rand_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/download/download_completion_blocker.h"
 #include "chrome/browser/download/download_crx_util.h"
diff --git a/chrome/browser/download/download_browsertest.cc b/chrome/browser/download/download_browsertest.cc
index 2f9700c..505c42a 100644
--- a/chrome/browser/download/download_browsertest.cc
+++ b/chrome/browser/download/download_browsertest.cc
@@ -899,7 +899,7 @@
         base::FilePath destination_folder = GetDownloadDirectory(browser());
         base::FilePath my_downloaded_file = item->GetTargetFilePath();
         EXPECT_TRUE(file_util::PathExists(my_downloaded_file));
-        EXPECT_TRUE(file_util::Delete(my_downloaded_file, false));
+        EXPECT_TRUE(base::Delete(my_downloaded_file, false));
 
         EXPECT_EQ(download_info.should_redirect_to_documents ?
                       std::string::npos :
diff --git a/chrome/browser/download/download_item_model.cc b/chrome/browser/download/download_item_model.cc
index 8561c6b..ec11fc0 100644
--- a/chrome/browser/download/download_item_model.cc
+++ b/chrome/browser/download/download_item_model.cc
@@ -10,7 +10,7 @@
 #include "base/strings/sys_string_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/supports_user_data.h"
-#include "base/time.h"
+#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"
diff --git a/chrome/browser/download/download_query.cc b/chrome/browser/download/download_query.cc
index 3f7ed10..14bc73e 100644
--- a/chrome/browser/download/download_query.cc
+++ b/chrome/browser/download/download_query.cc
@@ -21,15 +21,15 @@
 #include "base/strings/string_split.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "base/values.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/pref_names.h"
 #include "content/public/browser/content_browser_client.h"
 #include "content/public/browser/download_item.h"
-#include "googleurl/src/gurl.h"
 #include "net/base/net_util.h"
 #include "third_party/re2/re2/re2.h"
+#include "url/gurl.h"
 
 using content::DownloadDangerType;
 using content::DownloadItem;
diff --git a/chrome/browser/download/download_query_unittest.cc b/chrome/browser/download/download_query_unittest.cc
index d7bf5a1..e86e40e 100644
--- a/chrome/browser/download/download_query_unittest.cc
+++ b/chrome/browser/download/download_query_unittest.cc
@@ -10,7 +10,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/stl_util.h"
 #include "base/strings/string16.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "base/values.h"
 #include "chrome/browser/download/download_query.h"
 #include "content/public/test/mock_download_item.h"
diff --git a/chrome/browser/download/download_shelf.h b/chrome/browser/download/download_shelf.h
index 9498a86..dd61a49 100644
--- a/chrome/browser/download/download_shelf.h
+++ b/chrome/browser/download/download_shelf.h
@@ -6,7 +6,7 @@
 #define CHROME_BROWSER_DOWNLOAD_DOWNLOAD_SHELF_H_
 
 #include "base/memory/weak_ptr.h"
-#include "base/time.h"
+#include "base/time/time.h"
 
 namespace content {
 class DownloadItem;
diff --git a/chrome/browser/download/download_status_updater.cc b/chrome/browser/download/download_status_updater.cc
index 646e106..b084378 100644
--- a/chrome/browser/download/download_status_updater.cc
+++ b/chrome/browser/download/download_status_updater.cc
@@ -10,6 +10,10 @@
 #include "base/stl_util.h"
 #include "chrome/browser/download/download_util.h"
 
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+#include "ui/linux_ui/linux_ui.h"
+#endif
+
 namespace {
 
 // DownloadStatusUpdater::UpdateAppIconDownloadProgress() expects to only be
@@ -133,7 +137,16 @@
 #if defined(USE_AURA) || defined(OS_ANDROID)
 void DownloadStatusUpdater::UpdateAppIconDownloadProgress(
     content::DownloadItem* download) {
-  // TODO(davemoore): Implement once UX for aura download is decided <104742>
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+  const ui::LinuxUI* linux_ui = ui::LinuxUI::instance();
+  if (linux_ui) {
+    float progress = 0;
+    int download_count = 0;
+    GetProgress(&progress, &download_count);
+    linux_ui->SetDownloadCount(download_count);
+    linux_ui->SetProgressFraction(progress);
+  }
+#endif
   // TODO(avi): Implement for Android?
 }
 #endif
diff --git a/chrome/browser/download/download_status_updater_mac.mm b/chrome/browser/download/download_status_updater_mac.mm
index fbf010e..4e80610 100644
--- a/chrome/browser/download/download_status_updater_mac.mm
+++ b/chrome/browser/download/download_status_updater_mac.mm
@@ -5,12 +5,12 @@
 #include "chrome/browser/download/download_status_updater.h"
 
 #include "base/mac/foundation_util.h"
-#include "base/memory/scoped_nsobject.h"
-#include "base/supports_user_data.h"
+#include "base/mac/scoped_nsobject.h"
 #include "base/strings/sys_string_conversions.h"
-#include "content/public/browser/download_item.h"
+#include "base/supports_user_data.h"
 #import "chrome/browser/ui/cocoa/dock_icon.h"
-#include "googleurl/src/gurl.h"
+#include "content/public/browser/download_item.h"
+#include "url/gurl.h"
 
 // --- Private 10.8 API for showing progress ---
 // rdar://12058866 http://www.openradar.me/12058866
@@ -19,6 +19,11 @@
 
 NSString* const kNSProgressAppBundleIdentifierKey =
     @"NSProgressAppBundleIdentifierKey";
+NSString* const kNSProgressEstimatedTimeRemainingKey =
+    @"NSProgressEstimatedTimeRemainingKey";
+
+// NSProgressEstimatedTimeKey is 10.8 SPI only; it became
+// NSProgressEstimatedTimeRemainingKey when NSProgress became API in 10.9.
 NSString* const kNSProgressEstimatedTimeKey =
     @"NSProgressEstimatedTimeKey";
 NSString* const kNSProgressFileCompletedCountKey =
@@ -67,8 +72,19 @@
   NSString* result = [cache objectForKey:string];
   if (!result) {
     NSString** ref = static_cast<NSString**>(
-        CFBundleGetDataPointerForName(foundation,
-                                      base::mac::NSToCFCast(string)));
+        CFBundleGetDataPointerForName(
+            foundation, base::mac::NSToCFCast(string)));
+    if (ref) {
+      result = *ref;
+      [cache setObject:result forKey:string];
+    }
+  }
+
+  if (!result && string == kNSProgressEstimatedTimeRemainingKey) {
+    // Perhaps this is 10.8; try the old name of this key.
+    NSString** ref = static_cast<NSString**>(
+        CFBundleGetDataPointerForName(
+            foundation, base::mac::NSToCFCast(kNSProgressEstimatedTimeKey)));
     if (ref) {
       result = *ref;
       [cache setObject:result forKey:string];
@@ -169,7 +185,7 @@
   void setTarget(const base::FilePath& target) { target_ = target; }
 
  private:
-  scoped_nsobject<NSProgress> progress_;
+  base::scoped_nsobject<NSProgress> progress_;
   base::FilePath target_;
 };
 
@@ -236,6 +252,15 @@
   NSProgress* progress = progress_data->progress();
   progress.totalUnitCount = download->GetTotalBytes();
   progress.completedUnitCount = download->GetReceivedBytes();
+  [progress setUserInfoObject:@(download->CurrentSpeed())
+                       forKey:ProgressString(kNSProgressThroughputKey)];
+
+  base::TimeDelta time_remaining;
+  NSNumber* time_remaining_ns = nil;
+  if (download->TimeRemaining(&time_remaining))
+    time_remaining_ns = @(time_remaining.InSeconds());
+  [progress setUserInfoObject:time_remaining_ns
+                   forKey:ProgressString(kNSProgressEstimatedTimeRemainingKey)];
 
   base::FilePath download_path = download->GetFullPath();
   if (progress_data->target() != download_path) {
diff --git a/chrome/browser/download/download_status_updater_win.cc b/chrome/browser/download/download_status_updater_win.cc
index df74cea..515e54e 100644
--- a/chrome/browser/download/download_status_updater_win.cc
+++ b/chrome/browser/download/download_status_updater_win.cc
@@ -20,9 +20,9 @@
 #include "chrome/browser/ui/browser_window.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_thread.h"
-#include "googleurl/src/gurl.h"
 #include "grit/generated_resources.h"
 #include "ui/base/l10n/l10n_util.h"
+#include "url/gurl.h"
 #include "win8/util/win8_util.h"
 
 // This code doesn't compile with Aura on. TODO(avi): hook it up so that
diff --git a/chrome/browser/download/download_target_determiner.cc b/chrome/browser/download/download_target_determiner.cc
index 1d23aba..794886f 100644
--- a/chrome/browser/download/download_target_determiner.cc
+++ b/chrome/browser/download/download_target_determiner.cc
@@ -7,7 +7,7 @@
 #include "base/prefs/pref_service.h"
 #include "base/rand_util.h"
 #include "base/strings/stringprintf.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/download/chrome_download_manager_delegate.h"
 #include "chrome/browser/download/download_crx_util.h"
 #include "chrome/browser/download/download_extensions.h"
diff --git a/chrome/browser/drive/drive_api_service.cc b/chrome/browser/drive/drive_api_service.cc
index 85f7a8ac..4ad4732 100644
--- a/chrome/browser/drive/drive_api_service.cc
+++ b/chrome/browser/drive/drive_api_service.cc
@@ -8,24 +8,62 @@
 #include <vector>
 
 #include "base/bind.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/strings/stringprintf.h"
 #include "base/task_runner_util.h"
-#include "base/threading/sequenced_worker_pool.h"
 #include "base/values.h"
+#include "chrome/browser/drive/drive_api_util.h"
 #include "chrome/browser/google_apis/auth_service.h"
 #include "chrome/browser/google_apis/drive_api_parser.h"
 #include "chrome/browser/google_apis/drive_api_requests.h"
-#include "chrome/browser/google_apis/drive_api_util.h"
 #include "chrome/browser/google_apis/gdata_wapi_parser.h"
 #include "chrome/browser/google_apis/request_sender.h"
-#include "chrome/browser/google_apis/time_util.h"
-#include "chrome/browser/profiles/profile.h"
 #include "content/public/browser/browser_thread.h"
 
 using content::BrowserThread;
+using google_apis::AppList;
+using google_apis::AuthorizeAppCallback;
+using google_apis::CancelCallback;
+using google_apis::ChangeList;
+using google_apis::DownloadActionCallback;
+using google_apis::EntryActionCallback;
+using google_apis::FileList;
+using google_apis::FileResource;
+using google_apis::GDATA_OTHER_ERROR;
+using google_apis::GDATA_PARSE_ERROR;
+using google_apis::GDataErrorCode;
+using google_apis::GetAboutRequest;
+using google_apis::GetAboutResourceCallback;
+using google_apis::GetAppListCallback;
+using google_apis::GetApplistRequest;
+using google_apis::GetChangelistRequest;
+using google_apis::GetContentCallback;
+using google_apis::GetFileRequest;
+using google_apis::GetFilelistRequest;
+using google_apis::GetResourceEntryCallback;
+using google_apis::GetResourceListCallback;
+using google_apis::HTTP_SUCCESS;
+using google_apis::InitiateUploadCallback;
+using google_apis::ProgressCallback;
+using google_apis::RequestSender;
+using google_apis::ResourceEntry;
+using google_apis::ResourceList;
+using google_apis::UploadRangeCallback;
+using google_apis::UploadRangeResponse;
+using google_apis::drive::ContinueGetFileListRequest;
+using google_apis::drive::CopyResourceRequest;
+using google_apis::drive::CreateDirectoryRequest;
+using google_apis::drive::DeleteResourceRequest;
+using google_apis::drive::DownloadFileRequest;
+using google_apis::drive::GetUploadStatusRequest;
+using google_apis::drive::InitiateUploadExistingFileRequest;
+using google_apis::drive::InitiateUploadNewFileRequest;
+using google_apis::drive::InsertResourceRequest;
+using google_apis::drive::RenameResourceRequest;
+using google_apis::drive::ResumeUploadRequest;
+using google_apis::drive::TouchResourceRequest;
+using google_apis::drive::TrashResourceRequest;
 
-namespace google_apis {
+namespace drive {
 
 namespace {
 
@@ -91,6 +129,7 @@
 // Sends a task to parse the JSON value into ResourceList on blocking pool,
 // with a callback which is called when the task is done.
 void ParseResourceListOnBlockingPoolAndRun(
+    scoped_refptr<base::TaskRunner> blocking_task_runner,
     const GetResourceListCallback& callback,
     GDataErrorCode error,
     scoped_ptr<base::Value> value) {
@@ -104,7 +143,7 @@
   }
 
   PostTaskAndReplyWithResult(
-      BrowserThread::GetBlockingPool(),
+      blocking_task_runner.get(),
       FROM_HERE,
       base::Bind(&ParseResourceListOnBlockingPool, base::Passed(&value)),
       base::Bind(&DidParseResourceListOnBlockingPool, callback));
@@ -221,11 +260,14 @@
 
 DriveAPIService::DriveAPIService(
     net::URLRequestContextGetter* url_request_context_getter,
+    base::TaskRunner* blocking_task_runner,
     const GURL& base_url,
+    const GURL& base_download_url,
     const std::string& custom_user_agent)
     : url_request_context_getter_(url_request_context_getter),
+      blocking_task_runner_(blocking_task_runner),
       profile_(NULL),
-      url_generator_(base_url),
+      url_generator_(base_url, base_download_url),
       custom_user_agent_(custom_user_agent) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
 }
@@ -287,12 +329,13 @@
   return sender_->StartRequestWithRetry(
       new GetChangelistRequest(
           sender_.get(),
-          url_request_context_getter_,
           url_generator_,
           false,  // include deleted
           0,
           kMaxNumFilesResourcePerRequest,
-          base::Bind(&ParseResourceListOnBlockingPoolAndRun, callback)));
+          base::Bind(&ParseResourceListOnBlockingPoolAndRun,
+                     blocking_task_runner_,
+                     callback)));
 }
 
 CancelCallback DriveAPIService::GetResourceListInDirectory(
@@ -306,20 +349,21 @@
   // children's references, but we need all file resource list.
   // So, here we use files.list method instead, with setting parents query.
   // After the migration from GData WAPI to Drive API v2, we should clean the
-  // code up by moving the resposibility to include "parents" in the query
+  // code up by moving the responsibility to include "parents" in the query
   // to client side.
   // We aren't interested in files in trash in this context, neither.
   return sender_->StartRequestWithRetry(
       new GetFilelistRequest(
           sender_.get(),
-          url_request_context_getter_,
           url_generator_,
           base::StringPrintf(
               "'%s' in parents and trashed = false",
               drive::util::EscapeQueryStringValue(
                   directory_resource_id).c_str()),
           kMaxNumFilesResourcePerRequest,
-          base::Bind(&ParseResourceListOnBlockingPoolAndRun, callback)));
+          base::Bind(&ParseResourceListOnBlockingPoolAndRun,
+                     blocking_task_runner_,
+                     callback)));
 }
 
 CancelCallback DriveAPIService::Search(
@@ -332,11 +376,12 @@
   return sender_->StartRequestWithRetry(
       new GetFilelistRequest(
           sender_.get(),
-          url_request_context_getter_,
           url_generator_,
           drive::util::TranslateQuery(search_query),
           kMaxNumFilesResourcePerRequestForSearch,
-          base::Bind(&ParseResourceListOnBlockingPoolAndRun, callback)));
+          base::Bind(&ParseResourceListOnBlockingPoolAndRun,
+                     blocking_task_runner_,
+                     callback)));
 }
 
 CancelCallback DriveAPIService::SearchByTitle(
@@ -360,11 +405,12 @@
   return sender_->StartRequestWithRetry(
       new GetFilelistRequest(
           sender_.get(),
-          url_request_context_getter_,
           url_generator_,
           query,
           kMaxNumFilesResourcePerRequest,
-          base::Bind(&ParseResourceListOnBlockingPoolAndRun, callback)));
+          base::Bind(&ParseResourceListOnBlockingPoolAndRun,
+                     blocking_task_runner_,
+                     callback)));
 }
 
 CancelCallback DriveAPIService::GetChangeList(
@@ -376,12 +422,13 @@
   return sender_->StartRequestWithRetry(
       new GetChangelistRequest(
           sender_.get(),
-          url_request_context_getter_,
           url_generator_,
           true,  // include deleted
           start_changestamp,
           kMaxNumFilesResourcePerRequest,
-          base::Bind(&ParseResourceListOnBlockingPoolAndRun, callback)));
+          base::Bind(&ParseResourceListOnBlockingPoolAndRun,
+                     blocking_task_runner_,
+                     callback)));
 }
 
 CancelCallback DriveAPIService::ContinueGetResourceList(
@@ -391,11 +438,12 @@
   DCHECK(!callback.is_null());
 
   return sender_->StartRequestWithRetry(
-      new drive::ContinueGetFileListRequest(
+      new ContinueGetFileListRequest(
           sender_.get(),
-          url_request_context_getter_,
           override_url,
-          base::Bind(&ParseResourceListOnBlockingPoolAndRun, callback)));
+          base::Bind(&ParseResourceListOnBlockingPoolAndRun,
+                     blocking_task_runner_,
+                     callback)));
 }
 
 CancelCallback DriveAPIService::GetResourceEntry(
@@ -406,7 +454,6 @@
 
   return sender_->StartRequestWithRetry(new GetFileRequest(
       sender_.get(),
-      url_request_context_getter_,
       url_generator_,
       resource_id,
       base::Bind(&ParseResourceEntryAndRun, callback)));
@@ -420,7 +467,6 @@
   return sender_->StartRequestWithRetry(
       new GetAboutRequest(
           sender_.get(),
-          url_request_context_getter_,
           url_generator_,
           callback));
 }
@@ -431,15 +477,13 @@
 
   return sender_->StartRequestWithRetry(new GetApplistRequest(
       sender_.get(),
-      url_request_context_getter_,
       url_generator_,
       base::Bind(&ParseAppListAndRun, callback)));
 }
 
 CancelCallback DriveAPIService::DownloadFile(
-    const base::FilePath& virtual_path,
     const base::FilePath& local_cache_path,
-    const GURL& download_url,
+    const std::string& resource_id,
     const DownloadActionCallback& download_action_callback,
     const GetContentCallback& get_content_callback,
     const ProgressCallback& progress_callback) {
@@ -449,13 +493,12 @@
 
   return sender_->StartRequestWithRetry(
       new DownloadFileRequest(sender_.get(),
-                              url_request_context_getter_,
+                              url_generator_,
+                              resource_id,
+                              local_cache_path,
                               download_action_callback,
                               get_content_callback,
-                              progress_callback,
-                              download_url,
-                              virtual_path,
-                              local_cache_path));
+                              progress_callback));
 }
 
 CancelCallback DriveAPIService::DeleteResource(
@@ -465,9 +508,8 @@
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   DCHECK(!callback.is_null());
 
-  return sender_->StartRequestWithRetry(new drive::TrashResourceRequest(
+  return sender_->StartRequestWithRetry(new TrashResourceRequest(
       sender_.get(),
-      url_request_context_getter_,
       url_generator_,
       resource_id,
       callback));
@@ -481,9 +523,8 @@
   DCHECK(!callback.is_null());
 
   return sender_->StartRequestWithRetry(
-      new drive::CreateDirectoryRequest(
+      new CreateDirectoryRequest(
           sender_.get(),
-          url_request_context_getter_,
           url_generator_,
           parent_resource_id,
           directory_name,
@@ -499,9 +540,8 @@
   DCHECK(!callback.is_null());
 
   return sender_->StartRequestWithRetry(
-      new drive::CopyResourceRequest(
+      new CopyResourceRequest(
           sender_.get(),
-          url_request_context_getter_,
           url_generator_,
           resource_id,
           parent_resource_id,
@@ -517,9 +557,8 @@
   DCHECK(!callback.is_null());
 
   return sender_->StartRequestWithRetry(
-      new drive::CopyResourceRequest(
+      new CopyResourceRequest(
           sender_.get(),
-          url_request_context_getter_,
           url_generator_,
           resource_id,
           std::string(),  // parent_resource_id.
@@ -535,9 +574,8 @@
   DCHECK(!callback.is_null());
 
   return sender_->StartRequestWithRetry(
-      new drive::RenameResourceRequest(
+      new RenameResourceRequest(
           sender_.get(),
-          url_request_context_getter_,
           url_generator_,
           resource_id,
           new_name,
@@ -555,9 +593,8 @@
   DCHECK(!callback.is_null());
 
   return sender_->StartRequestWithRetry(
-      new drive::TouchResourceRequest(
+      new TouchResourceRequest(
           sender_.get(),
-          url_request_context_getter_,
           url_generator_,
           resource_id,
           modified_date,
@@ -573,9 +610,8 @@
   DCHECK(!callback.is_null());
 
   return sender_->StartRequestWithRetry(
-      new drive::InsertResourceRequest(
+      new InsertResourceRequest(
           sender_.get(),
-          url_request_context_getter_,
           url_generator_,
           parent_resource_id,
           resource_id,
@@ -590,9 +626,8 @@
   DCHECK(!callback.is_null());
 
   return sender_->StartRequestWithRetry(
-      new drive::DeleteResourceRequest(
+      new DeleteResourceRequest(
           sender_.get(),
-          url_request_context_getter_,
           url_generator_,
           parent_resource_id,
           resource_id,
@@ -600,7 +635,6 @@
 }
 
 CancelCallback DriveAPIService::InitiateUploadNewFile(
-    const base::FilePath& drive_file_path,
     const std::string& content_type,
     int64 content_length,
     const std::string& parent_resource_id,
@@ -610,11 +644,9 @@
   DCHECK(!callback.is_null());
 
   return sender_->StartRequestWithRetry(
-      new drive::InitiateUploadNewFileRequest(
+      new InitiateUploadNewFileRequest(
           sender_.get(),
-          url_request_context_getter_,
           url_generator_,
-          drive_file_path,
           content_type,
           content_length,
           parent_resource_id,
@@ -623,7 +655,6 @@
 }
 
 CancelCallback DriveAPIService::InitiateUploadExistingFile(
-    const base::FilePath& drive_file_path,
     const std::string& content_type,
     int64 content_length,
     const std::string& resource_id,
@@ -633,11 +664,9 @@
   DCHECK(!callback.is_null());
 
   return sender_->StartRequestWithRetry(
-      new drive::InitiateUploadExistingFileRequest(
+      new InitiateUploadExistingFileRequest(
           sender_.get(),
-          url_request_context_getter_,
           url_generator_,
-          drive_file_path,
           content_type,
           content_length,
           resource_id,
@@ -646,7 +675,6 @@
 }
 
 CancelCallback DriveAPIService::ResumeUpload(
-    const base::FilePath& drive_file_path,
     const GURL& upload_url,
     int64 start_position,
     int64 end_position,
@@ -659,10 +687,8 @@
   DCHECK(!callback.is_null());
 
   return sender_->StartRequestWithRetry(
-      new drive::ResumeUploadRequest(
+      new ResumeUploadRequest(
           sender_.get(),
-          url_request_context_getter_,
-          drive_file_path,
           upload_url,
           start_position,
           end_position,
@@ -674,17 +700,14 @@
 }
 
 CancelCallback DriveAPIService::GetUploadStatus(
-    const base::FilePath& drive_file_path,
     const GURL& upload_url,
     int64 content_length,
     const UploadRangeCallback& callback) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   DCHECK(!callback.is_null());
 
-  return sender_->StartRequestWithRetry(new drive::GetUploadStatusRequest(
+  return sender_->StartRequestWithRetry(new GetUploadStatusRequest(
       sender_.get(),
-      url_request_context_getter_,
-      drive_file_path,
       upload_url,
       content_length,
       base::Bind(&ParseResourceEntryForUploadRangeAndRun, callback)));
@@ -699,7 +722,6 @@
 
   return sender_->StartRequestWithRetry(new GetFileRequest(
       sender_.get(),
-      url_request_context_getter_,
       url_generator_,
       resource_id,
       base::Bind(&ExtractOpenUrlAndRun, app_id, callback)));
@@ -738,4 +760,4 @@
   }
 }
 
-}  // namespace google_apis
+}  // namespace drive
diff --git a/chrome/browser/drive/drive_api_service.h b/chrome/browser/drive/drive_api_service.h
index e869355..3a330d6 100644
--- a/chrome/browser/drive/drive_api_service.h
+++ b/chrome/browser/drive/drive_api_service.h
@@ -7,6 +7,7 @@
 
 #include <string>
 
+#include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/observer_list.h"
 #include "chrome/browser/drive/drive_service_interface.h"
@@ -18,28 +19,37 @@
 
 namespace base {
 class FilePath;
+class TaskRunner;
+}
+
+namespace google_apis {
+class RequestSender;
 }
 
 namespace net {
 class URLRequestContextGetter;
 }  // namespace net
 
-namespace google_apis {
-class RequestSender;
+namespace drive {
 
 // This class provides Drive request calls using Drive V2 API.
 // Details of API call are abstracted in each request class and this class
 // works as a thin wrapper for the API.
 class DriveAPIService : public DriveServiceInterface,
-                        public AuthServiceObserver {
+                        public google_apis::AuthServiceObserver {
  public:
   // |url_request_context_getter| is used to initialize URLFetcher.
+  // |blocking_task_runner| is used to run blocking tasks (like parsing JSON).
   // |base_url| is used to generate URLs for communication with the drive API.
+  // |base_download_url| is used to generate URLs for downloading file from the
+  // drive API.
   // |custom_user_agent| will be used for the User-Agent header in HTTP
   // requests issues through the service if the value is not empty.
   DriveAPIService(
       net::URLRequestContextGetter* url_request_context_getter,
+      base::TaskRunner* blocking_task_runner,
       const GURL& base_url,
+      const GURL& base_download_url,
       const std::string& custom_user_agent);
   virtual ~DriveAPIService();
 
@@ -55,120 +65,116 @@
   virtual void ClearAccessToken() OVERRIDE;
   virtual void ClearRefreshToken() OVERRIDE;
   virtual std::string GetRootResourceId() const OVERRIDE;
-  virtual CancelCallback GetAllResourceList(
-      const GetResourceListCallback& callback) OVERRIDE;
-  virtual CancelCallback GetResourceListInDirectory(
+  virtual google_apis::CancelCallback GetAllResourceList(
+      const google_apis::GetResourceListCallback& callback) OVERRIDE;
+  virtual google_apis::CancelCallback GetResourceListInDirectory(
       const std::string& directory_resource_id,
-      const GetResourceListCallback& callback) OVERRIDE;
-  virtual CancelCallback Search(
+      const google_apis::GetResourceListCallback& callback) OVERRIDE;
+  virtual google_apis::CancelCallback Search(
       const std::string& search_query,
-      const GetResourceListCallback& callback) OVERRIDE;
-  virtual CancelCallback SearchByTitle(
+      const google_apis::GetResourceListCallback& callback) OVERRIDE;
+  virtual google_apis::CancelCallback SearchByTitle(
       const std::string& title,
       const std::string& directory_resource_id,
-      const GetResourceListCallback& callback) OVERRIDE;
-  virtual CancelCallback GetChangeList(
+      const google_apis::GetResourceListCallback& callback) OVERRIDE;
+  virtual google_apis::CancelCallback GetChangeList(
       int64 start_changestamp,
-      const GetResourceListCallback& callback) OVERRIDE;
-  virtual CancelCallback ContinueGetResourceList(
+      const google_apis::GetResourceListCallback& callback) OVERRIDE;
+  virtual google_apis::CancelCallback ContinueGetResourceList(
       const GURL& override_url,
-      const GetResourceListCallback& callback) OVERRIDE;
-  virtual CancelCallback GetResourceEntry(
+      const google_apis::GetResourceListCallback& callback) OVERRIDE;
+  virtual google_apis::CancelCallback GetResourceEntry(
       const std::string& resource_id,
-      const GetResourceEntryCallback& callback) OVERRIDE;
-  virtual CancelCallback GetAboutResource(
-      const GetAboutResourceCallback& callback) OVERRIDE;
-  virtual CancelCallback GetAppList(
-      const GetAppListCallback& callback) OVERRIDE;
-  virtual CancelCallback DeleteResource(
+      const google_apis::GetResourceEntryCallback& callback) OVERRIDE;
+  virtual google_apis::CancelCallback GetAboutResource(
+      const google_apis::GetAboutResourceCallback& callback) OVERRIDE;
+  virtual google_apis::CancelCallback GetAppList(
+      const google_apis::GetAppListCallback& callback) OVERRIDE;
+  virtual google_apis::CancelCallback DeleteResource(
       const std::string& resource_id,
       const std::string& etag,
-      const EntryActionCallback& callback) OVERRIDE;
-  virtual CancelCallback DownloadFile(
-      const base::FilePath& virtual_path,
+      const google_apis::EntryActionCallback& callback) OVERRIDE;
+  virtual google_apis::CancelCallback DownloadFile(
       const base::FilePath& local_cache_path,
-      const GURL& download_url,
-      const DownloadActionCallback& download_action_callback,
-      const GetContentCallback& get_content_callback,
-      const ProgressCallback& progress_callback) OVERRIDE;
-  virtual CancelCallback CopyResource(
+      const std::string& resource_id,
+      const google_apis::DownloadActionCallback& download_action_callback,
+      const google_apis::GetContentCallback& get_content_callback,
+      const google_apis::ProgressCallback& progress_callback) OVERRIDE;
+  virtual google_apis::CancelCallback CopyResource(
       const std::string& resource_id,
       const std::string& parent_resource_id,
       const std::string& new_name,
-      const GetResourceEntryCallback& callback) OVERRIDE;
-  virtual CancelCallback CopyHostedDocument(
+      const google_apis::GetResourceEntryCallback& callback) OVERRIDE;
+  virtual google_apis::CancelCallback CopyHostedDocument(
       const std::string& resource_id,
       const std::string& new_name,
-      const GetResourceEntryCallback& callback) OVERRIDE;
-  virtual CancelCallback RenameResource(
+      const google_apis::GetResourceEntryCallback& callback) OVERRIDE;
+  virtual google_apis::CancelCallback RenameResource(
       const std::string& resource_id,
       const std::string& new_name,
-      const EntryActionCallback& callback) OVERRIDE;
-  virtual CancelCallback TouchResource(
+      const google_apis::EntryActionCallback& callback) OVERRIDE;
+  virtual google_apis::CancelCallback TouchResource(
       const std::string& resource_id,
       const base::Time& modified_date,
       const base::Time& last_viewed_by_me_date,
-      const GetResourceEntryCallback& callback) OVERRIDE;
-  virtual CancelCallback AddResourceToDirectory(
+      const google_apis::GetResourceEntryCallback& callback) OVERRIDE;
+  virtual google_apis::CancelCallback AddResourceToDirectory(
       const std::string& parent_resource_id,
       const std::string& resource_id,
-      const EntryActionCallback& callback) OVERRIDE;
-  virtual CancelCallback RemoveResourceFromDirectory(
+      const google_apis::EntryActionCallback& callback) OVERRIDE;
+  virtual google_apis::CancelCallback RemoveResourceFromDirectory(
       const std::string& parent_resource_id,
       const std::string& resource_id,
-      const EntryActionCallback& callback) OVERRIDE;
-  virtual CancelCallback AddNewDirectory(
+      const google_apis::EntryActionCallback& callback) OVERRIDE;
+  virtual google_apis::CancelCallback AddNewDirectory(
       const std::string& parent_resource_id,
       const std::string& directory_name,
-      const GetResourceEntryCallback& callback) OVERRIDE;
-  virtual CancelCallback InitiateUploadNewFile(
-      const base::FilePath& drive_file_path,
+      const google_apis::GetResourceEntryCallback& callback) OVERRIDE;
+  virtual google_apis::CancelCallback InitiateUploadNewFile(
       const std::string& content_type,
       int64 content_length,
       const std::string& parent_resource_id,
       const std::string& title,
-      const InitiateUploadCallback& callback) OVERRIDE;
-  virtual CancelCallback InitiateUploadExistingFile(
-      const base::FilePath& drive_file_path,
+      const google_apis::InitiateUploadCallback& callback) OVERRIDE;
+  virtual google_apis::CancelCallback InitiateUploadExistingFile(
       const std::string& content_type,
       int64 content_length,
       const std::string& resource_id,
       const std::string& etag,
-      const InitiateUploadCallback& callback) OVERRIDE;
-  virtual CancelCallback ResumeUpload(
-      const base::FilePath& drive_file_path,
+      const google_apis::InitiateUploadCallback& callback) OVERRIDE;
+  virtual google_apis::CancelCallback ResumeUpload(
       const GURL& upload_url,
       int64 start_position,
       int64 end_position,
       int64 content_length,
       const std::string& content_type,
       const base::FilePath& local_file_path,
-      const UploadRangeCallback& callback,
-      const ProgressCallback& progress_callback) OVERRIDE;
-  virtual CancelCallback GetUploadStatus(
-      const base::FilePath& drive_file_path,
+      const google_apis::UploadRangeCallback& callback,
+      const google_apis::ProgressCallback& progress_callback) OVERRIDE;
+  virtual google_apis::CancelCallback GetUploadStatus(
       const GURL& upload_url,
       int64 content_length,
-      const UploadRangeCallback& callback) OVERRIDE;
-  virtual CancelCallback AuthorizeApp(
+      const google_apis::UploadRangeCallback& callback) OVERRIDE;
+  virtual google_apis::CancelCallback AuthorizeApp(
       const std::string& resource_id,
       const std::string& app_id,
-      const AuthorizeAppCallback& callback) OVERRIDE;
+      const google_apis::AuthorizeAppCallback& callback) OVERRIDE;
 
  private:
   // AuthServiceObserver override.
   virtual void OnOAuth2RefreshTokenChanged() OVERRIDE;
 
   net::URLRequestContextGetter* url_request_context_getter_;
+  scoped_refptr<base::TaskRunner> blocking_task_runner_;
   Profile* profile_;
-  scoped_ptr<RequestSender> sender_;
+  scoped_ptr<google_apis::RequestSender> sender_;
   ObserverList<DriveServiceObserver> observers_;
-  DriveApiUrlGenerator url_generator_;
+  google_apis::DriveApiUrlGenerator url_generator_;
   const std::string custom_user_agent_;
 
   DISALLOW_COPY_AND_ASSIGN(DriveAPIService);
 };
 
-}  // namespace google_apis
+}  // namespace drive
 
 #endif  // CHROME_BROWSER_DRIVE_DRIVE_API_SERVICE_H_
diff --git a/chrome/browser/drive/drive_api_util.cc b/chrome/browser/drive/drive_api_util.cc
new file mode 100644
index 0000000..b9a8274
--- /dev/null
+++ b/chrome/browser/drive/drive_api_util.cc
@@ -0,0 +1,132 @@
+// 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/drive/drive_api_util.h"
+
+#include <string>
+
+#include "base/command_line.h"
+#include "base/logging.h"
+#include "base/strings/string16.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/drive/drive_switches.h"
+#include "net/base/escape.h"
+#include "third_party/re2/re2/re2.h"
+#include "url/gurl.h"
+
+namespace drive {
+namespace util {
+
+bool IsDriveV2ApiEnabled() {
+  const CommandLine* command_line = CommandLine::ForCurrentProcess();
+
+  // Disable Drive API v2 by default.
+  if (!command_line->HasSwitch(switches::kEnableDriveV2Api))
+    return false;
+
+  std::string value =
+      command_line->GetSwitchValueASCII(switches::kEnableDriveV2Api);
+  StringToLowerASCII(&value);
+  // The value must be "" or "true" for true, or "false" for false.
+  DCHECK(value.empty() || value == "true" || value == "false");
+  return value != "false";
+}
+
+std::string EscapeQueryStringValue(const std::string& str) {
+  std::string result;
+  result.reserve(str.size());
+  for (size_t i = 0; i < str.size(); ++i) {
+    if (str[i] == '\\' || str[i] == '\'') {
+      result.push_back('\\');
+    }
+    result.push_back(str[i]);
+  }
+  return result;
+}
+
+std::string TranslateQuery(const std::string& original_query) {
+  // In order to handle non-ascii white spaces correctly, convert to UTF16.
+  base::string16 query = UTF8ToUTF16(original_query);
+  const base::string16 kDelimiter(
+      kWhitespaceUTF16 + base::string16(1, static_cast<char16>('"')));
+
+  std::string result;
+  for (size_t index = query.find_first_not_of(kWhitespaceUTF16);
+       index != base::string16::npos;
+       index = query.find_first_not_of(kWhitespaceUTF16, index)) {
+    bool is_exclusion = (query[index] == '-');
+    if (is_exclusion)
+      ++index;
+    if (index == query.length()) {
+      // Here, the token is '-' and it should be ignored.
+      continue;
+    }
+
+    size_t begin_token = index;
+    base::string16 token;
+    if (query[begin_token] == '"') {
+      // Quoted query.
+      ++begin_token;
+      size_t end_token = query.find('"', begin_token);
+      if (end_token == base::string16::npos) {
+        // This is kind of syntax error, since quoted string isn't finished.
+        // However, the query is built by user manually, so here we treat
+        // whole remaining string as a token as a fallback, by appending
+        // a missing double-quote character.
+        end_token = query.length();
+        query.push_back('"');
+      }
+
+      token = query.substr(begin_token, end_token - begin_token);
+      index = end_token + 1;  // Consume last '"', too.
+    } else {
+      size_t end_token = query.find_first_of(kDelimiter, begin_token);
+      if (end_token == base::string16::npos) {
+        end_token = query.length();
+      }
+
+      token = query.substr(begin_token, end_token - begin_token);
+      index = end_token;
+    }
+
+    if (token.empty()) {
+      // Just ignore an empty token.
+      continue;
+    }
+
+    if (!result.empty()) {
+      // If there are two or more tokens, need to connect with "and".
+      result.append(" and ");
+    }
+
+    // The meaning of "fullText" should include title, description and content.
+    base::StringAppendF(
+        &result,
+        "%sfullText contains \'%s\'",
+        is_exclusion ? "not " : "",
+        EscapeQueryStringValue(UTF16ToUTF8(token)).c_str());
+  }
+
+  return result;
+}
+
+std::string ExtractResourceIdFromUrl(const GURL& url) {
+  return net::UnescapeURLComponent(url.ExtractFileName(),
+                                   net::UnescapeRule::URL_SPECIAL_CHARS);
+}
+
+std::string CanonicalizeResourceId(const std::string& resource_id) {
+  // If resource ID is in the old WAPI format starting with a prefix like
+  // "document:", strip it and return the remaining part.
+  std::string stripped_resource_id;
+  if (RE2::FullMatch(resource_id, "^[a-z-]+(?::|%3A)([\\w-]+)$",
+                     &stripped_resource_id))
+    return stripped_resource_id;
+  return resource_id;
+}
+
+}  // namespace util
+}  // namespace drive
diff --git a/chrome/browser/drive/drive_api_util.h b/chrome/browser/drive/drive_api_util.h
new file mode 100644
index 0000000..2d1d991
--- /dev/null
+++ b/chrome/browser/drive/drive_api_util.h
@@ -0,0 +1,43 @@
+// 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_DRIVE_DRIVE_API_UTIL_H_
+#define CHROME_BROWSER_DRIVE_DRIVE_API_UTIL_H_
+
+#include <string>
+
+class GURL;
+
+namespace drive {
+namespace util {
+
+// Returns true if Drive v2 API is enabled via commandline switch.
+bool IsDriveV2ApiEnabled();
+
+// Escapes ' to \' in the |str|. This is designed to use for string value of
+// search parameter on Drive API v2.
+// See also: https://developers.google.com/drive/search-parameters
+std::string EscapeQueryStringValue(const std::string& str);
+
+// Parses the query, and builds a search query for Drive API v2.
+// This only supports:
+//   Regular query (e.g. dog => fullText contains 'dog')
+//   Conjunctions
+//     (e.g. dog cat => fullText contains 'dog' and fullText contains 'cat')
+//   Exclusion query (e.g. -cat => not fullText contains 'cat').
+//   Quoted query (e.g. "dog cat" => fullText contains 'dog cat').
+// See also: https://developers.google.com/drive/search-parameters
+std::string TranslateQuery(const std::string& original_query);
+
+// Extracts resource_id out of edit url.
+std::string ExtractResourceIdFromUrl(const GURL& url);
+
+// If |resource_id| is in the old resource ID format used by WAPI, converts it
+// into the new format.
+std::string CanonicalizeResourceId(const std::string& resource_id);
+
+}  // namespace util
+}  // namespace drive
+
+#endif  // CHROME_BROWSER_DRIVE_DRIVE_API_UTIL_H_
diff --git a/chrome/browser/drive/drive_api_util_unittest.cc b/chrome/browser/drive/drive_api_util_unittest.cc
new file mode 100644
index 0000000..1b4e32e
--- /dev/null
+++ b/chrome/browser/drive/drive_api_util_unittest.cc
@@ -0,0 +1,78 @@
+// 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/drive/drive_api_util.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+namespace drive {
+namespace util {
+
+TEST(DriveApiUtilTest, EscapeQueryStringValue) {
+  EXPECT_EQ("abcde", EscapeQueryStringValue("abcde"));
+  EXPECT_EQ("\\'", EscapeQueryStringValue("'"));
+  EXPECT_EQ("\\'abcde\\'", EscapeQueryStringValue("'abcde'"));
+  EXPECT_EQ("\\\\", EscapeQueryStringValue("\\"));
+  EXPECT_EQ("\\\\\\'", EscapeQueryStringValue("\\'"));
+}
+
+TEST(DriveApiUtilTest, TranslateQuery) {
+  EXPECT_EQ("", TranslateQuery(""));
+  EXPECT_EQ("fullText contains 'dog'", TranslateQuery("dog"));
+  EXPECT_EQ("fullText contains 'dog' and fullText contains 'cat'",
+            TranslateQuery("dog cat"));
+  EXPECT_EQ("not fullText contains 'cat'", TranslateQuery("-cat"));
+  EXPECT_EQ("fullText contains 'dog cat'", TranslateQuery("\"dog cat\""));
+
+  // Should handles full-width white space correctly.
+  // Note: \xE3\x80\x80 (\u3000) is Ideographic Space (a.k.a. Japanese
+  //   full-width whitespace).
+  EXPECT_EQ("fullText contains 'dog' and fullText contains 'cat'",
+            TranslateQuery("dog" "\xE3\x80\x80" "cat"));
+
+  // If the quoted token is not closed (i.e. the last '"' is missing),
+  // we handle the remaining string is one token, as a fallback.
+  EXPECT_EQ("fullText contains 'dog cat'", TranslateQuery("\"dog cat"));
+
+  // For quoted text with leading '-'.
+  EXPECT_EQ("not fullText contains 'dog cat'", TranslateQuery("-\"dog cat\""));
+
+  // Empty tokens should be simply ignored.
+  EXPECT_EQ("", TranslateQuery("-"));
+  EXPECT_EQ("", TranslateQuery("\"\""));
+  EXPECT_EQ("", TranslateQuery("-\"\""));
+  EXPECT_EQ("", TranslateQuery("\"\"\"\""));
+  EXPECT_EQ("", TranslateQuery("\"\" \"\""));
+  EXPECT_EQ("fullText contains 'dog'", TranslateQuery("\"\" dog \"\""));
+}
+
+TEST(FileSystemUtilTest, ExtractResourceIdFromUrl) {
+  EXPECT_EQ("file:2_file_resource_id", ExtractResourceIdFromUrl(
+      GURL("https://file1_link_self/file:2_file_resource_id")));
+  // %3A should be unescaped.
+  EXPECT_EQ("file:2_file_resource_id", ExtractResourceIdFromUrl(
+      GURL("https://file1_link_self/file%3A2_file_resource_id")));
+
+  // The resource ID cannot be extracted, hence empty.
+  EXPECT_EQ("", ExtractResourceIdFromUrl(GURL("https://www.example.com/")));
+}
+
+TEST(FileSystemUtilTest, CanonicalizeResourceId) {
+  std::string resource_id("1YsCnrMxxgp7LDdtlFDt-WdtEIth89vA9inrILtvK-Ug");
+
+  // New style ID is unchanged.
+  EXPECT_EQ(resource_id, CanonicalizeResourceId(resource_id));
+
+  // Drop prefixes from old style IDs.
+  EXPECT_EQ(resource_id, CanonicalizeResourceId("document:" + resource_id));
+  EXPECT_EQ(resource_id, CanonicalizeResourceId("spreadsheet:" + resource_id));
+  EXPECT_EQ(resource_id, CanonicalizeResourceId("presentation:" + resource_id));
+  EXPECT_EQ(resource_id, CanonicalizeResourceId("drawing:" + resource_id));
+  EXPECT_EQ(resource_id, CanonicalizeResourceId("table:" + resource_id));
+  EXPECT_EQ(resource_id, CanonicalizeResourceId("externalapp:" + resource_id));
+}
+
+}  // namespace util
+}  // namespace drive
diff --git a/chrome/browser/drive/drive_notification_manager.cc b/chrome/browser/drive/drive_notification_manager.cc
index 7979715..ae94124 100644
--- a/chrome/browser/drive/drive_notification_manager.cc
+++ b/chrome/browser/drive/drive_notification_manager.cc
@@ -5,13 +5,13 @@
 #include "chrome/browser/drive/drive_notification_manager.h"
 
 #include "base/metrics/histogram.h"
-#include "chrome/browser/google_apis/drive_notification_observer.h"
+#include "chrome/browser/drive/drive_notification_observer.h"
+#include "chrome/browser/invalidation/invalidation_service.h"
+#include "chrome/browser/invalidation/invalidation_service_factory.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/sync/profile_sync_service.h"
-#include "chrome/browser/sync/profile_sync_service_factory.h"
 #include "google/cacheinvalidation/types.pb.h"
 
-namespace google_apis {
+namespace drive {
 
 namespace {
 
@@ -42,15 +42,16 @@
 
 void DriveNotificationManager::Shutdown() {
   // Unregister for Drive notifications.
-  ProfileSyncService* profile_sync_service =
-      ProfileSyncServiceFactory::GetForProfile(profile_);
-  if (!profile_sync_service || !push_notification_registered_) {
+  invalidation::InvalidationService* invalidation_service =
+      invalidation::InvalidationServiceFactory::GetForProfile(profile_);
+  if (!invalidation_service || !push_notification_registered_) {
     return;
   }
 
-  profile_sync_service->UpdateRegisteredInvalidationIds(
-      this, syncer::ObjectIdSet());
-  profile_sync_service->UnregisterInvalidationHandler(this);
+  // We unregister the handler without updating unregistering our IDs on
+  // purpose.  See the class comment on the InvalidationService interface for
+  // more information.
+  invalidation_service->UnregisterInvalidationHandler(this);
 }
 
 void DriveNotificationManager::OnInvalidatorStateChange(
@@ -76,9 +77,10 @@
 
   // TODO(dcheng): Only acknowledge the invalidation once the fetch has
   // completed. http://crbug.com/156843
-  ProfileSyncService* profile_sync_service =
-      ProfileSyncServiceFactory::GetForProfile(profile_);
-  profile_sync_service->AcknowledgeInvalidation(
+  invalidation::InvalidationService* invalidation_service =
+      invalidation::InvalidationServiceFactory::GetForProfile(profile_);
+  DCHECK(invalidation_service);
+  invalidation_service->AcknowledgeInvalidation(
       invalidation_map.begin()->first,
       invalidation_map.begin()->second.ack_handle);
 
@@ -128,19 +130,19 @@
 void DriveNotificationManager::RegisterDriveNotifications() {
   DCHECK(!push_notification_enabled_);
 
-  ProfileSyncService* profile_sync_service =
-      ProfileSyncServiceFactory::GetForProfile(profile_);
-  if (!profile_sync_service)
+  invalidation::InvalidationService* invalidation_service =
+      invalidation::InvalidationServiceFactory::GetForProfile(profile_);
+  if (!invalidation_service)
     return;
 
-  profile_sync_service->RegisterInvalidationHandler(this);
+  invalidation_service->RegisterInvalidationHandler(this);
   syncer::ObjectIdSet ids;
   ids.insert(invalidation::ObjectId(
       ipc::invalidation::ObjectSource::COSMO_CHANGELOG,
       kDriveInvalidationObjectId));
-  profile_sync_service->UpdateRegisteredInvalidationIds(this, ids);
+  invalidation_service->UpdateRegisteredInvalidationIds(this, ids);
   push_notification_registered_ = true;
-  OnInvalidatorStateChange(profile_sync_service->GetInvalidatorState());
+  OnInvalidatorStateChange(invalidation_service->GetInvalidatorState());
 
   UMA_HISTOGRAM_BOOLEAN("Drive.PushNotificationRegistered",
                         push_notification_registered_);
@@ -160,4 +162,4 @@
   return "";
 }
 
-}  // namespace google_apis
+}  // namespace drive
diff --git a/chrome/browser/drive/drive_notification_manager.h b/chrome/browser/drive/drive_notification_manager.h
index 007709a..f519a41 100644
--- a/chrome/browser/drive/drive_notification_manager.h
+++ b/chrome/browser/drive/drive_notification_manager.h
@@ -7,15 +7,15 @@
 
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
-#include "base/timer.h"
-#include "chrome/browser/google_apis/drive_notification_observer.h"
+#include "base/timer/timer.h"
+#include "chrome/browser/drive/drive_notification_observer.h"
 #include "components/browser_context_keyed_service/browser_context_keyed_service.h"
 #include "sync/notifier/invalidation_handler.h"
 
 class Profile;
 class ProfileSyncService;
 
-namespace google_apis {
+namespace drive {
 
 // Informs observers when they should check Google Drive for updates.
 // Conditions under which updates should be searched:
@@ -90,6 +90,6 @@
   DISALLOW_COPY_AND_ASSIGN(DriveNotificationManager);
 };
 
-}  // namespace google_apis
+}  // namespace drive
 
 #endif  // CHROME_BROWSER_DRIVE_DRIVE_NOTIFICATION_MANAGER_H_
diff --git a/chrome/browser/drive/drive_notification_manager_factory.cc b/chrome/browser/drive/drive_notification_manager_factory.cc
index cebea28..4792e08 100644
--- a/chrome/browser/drive/drive_notification_manager_factory.cc
+++ b/chrome/browser/drive/drive_notification_manager_factory.cc
@@ -5,12 +5,13 @@
 #include "chrome/browser/drive/drive_notification_manager_factory.h"
 
 #include "chrome/browser/drive/drive_notification_manager.h"
+#include "chrome/browser/invalidation/invalidation_service_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/sync/profile_sync_service.h"
 #include "chrome/browser/sync/profile_sync_service_factory.h"
 #include "components/browser_context_keyed_service/browser_context_dependency_manager.h"
 
-namespace google_apis {
+namespace drive {
 
 // static
 DriveNotificationManager*
@@ -33,6 +34,7 @@
         "DriveNotificationManager",
         BrowserContextDependencyManager::GetInstance()) {
   DependsOn(ProfileSyncServiceFactory::GetInstance());
+  DependsOn(invalidation::InvalidationServiceFactory::GetInstance());
 }
 
 DriveNotificationManagerFactory::~DriveNotificationManagerFactory() {}
@@ -43,4 +45,4 @@
   return new DriveNotificationManager(static_cast<Profile*>(profile));
 }
 
-}  // namespace google_apis
+}  // namespace drive
diff --git a/chrome/browser/drive/drive_notification_manager_factory.h b/chrome/browser/drive/drive_notification_manager_factory.h
index b273577..65340d0 100644
--- a/chrome/browser/drive/drive_notification_manager_factory.h
+++ b/chrome/browser/drive/drive_notification_manager_factory.h
@@ -10,7 +10,7 @@
 
 class Profile;
 
-namespace google_apis {
+namespace drive {
 
 class DriveNotificationManager;
 
@@ -34,6 +34,6 @@
       content::BrowserContext* profile) const OVERRIDE;
 };
 
-}  // namespace google_apis
+}  // namespace drive
 
 #endif  // CHROME_BROWSER_DRIVE_DRIVE_NOTIFICATION_MANAGER_FACTORY_H_
diff --git a/chrome/browser/drive/drive_notification_observer.h b/chrome/browser/drive/drive_notification_observer.h
new file mode 100644
index 0000000..5f6738f
--- /dev/null
+++ b/chrome/browser/drive/drive_notification_observer.h
@@ -0,0 +1,26 @@
+// 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_DRIVE_DRIVE_NOTIFICATION_OBSERVER_H_
+#define CHROME_BROWSER_DRIVE_DRIVE_NOTIFICATION_OBSERVER_H_
+
+namespace drive {
+
+// Interface for classes which need to know when to check Google Drive for
+// updates.
+class DriveNotificationObserver {
+ public:
+  // Called when a notification from Google Drive is received.
+  virtual void OnNotificationReceived() = 0;
+
+  // Called when XMPP-based push notification is enabled or disabled.
+  virtual void OnPushNotificationEnabled(bool enabled) {}
+
+ protected:
+  virtual ~DriveNotificationObserver() {}
+};
+
+}  // namespace drive
+
+#endif  // CHROME_BROWSER_DRIVE_DRIVE_NOTIFICATION_OBSERVER_H_
diff --git a/chrome/browser/drive/drive_service_interface.h b/chrome/browser/drive/drive_service_interface.h
index 774de4f..f792d24 100644
--- a/chrome/browser/drive/drive_service_interface.h
+++ b/chrome/browser/drive/drive_service_interface.h
@@ -12,7 +12,7 @@
 
 class Profile;
 
-namespace google_apis {
+namespace drive {
 
 // Observer interface for DriveServiceInterface.
 class DriveServiceObserver {
@@ -80,8 +80,8 @@
   // ContinueGetResourceList.
   //
   // |callback| must not be null.
-  virtual CancelCallback GetAllResourceList(
-      const GetResourceListCallback& callback) = 0;
+  virtual google_apis::CancelCallback GetAllResourceList(
+      const google_apis::GetResourceListCallback& callback) = 0;
 
   // Fetches a resource list in the directory with |directory_resource_id|.
   // |callback| will be called upon completion.
@@ -91,9 +91,9 @@
   //
   // |directory_resource_id| must not be empty.
   // |callback| must not be null.
-  virtual CancelCallback GetResourceListInDirectory(
+  virtual google_apis::CancelCallback GetResourceListInDirectory(
       const std::string& directory_resource_id,
-      const GetResourceListCallback& callback) = 0;
+      const google_apis::GetResourceListCallback& callback) = 0;
 
   // Searches the resources for the |search_query| from all the user's
   // resources. |callback| will be called upon completion.
@@ -103,9 +103,9 @@
   //
   // |search_query| must not be empty.
   // |callback| must not be null.
-  virtual CancelCallback Search(
+  virtual google_apis::CancelCallback Search(
       const std::string& search_query,
-      const GetResourceListCallback& callback) = 0;
+      const google_apis::GetResourceListCallback& callback) = 0;
 
   // Searches the resources with the |title|.
   // |directory_resource_id| is an optional parameter. If it is empty,
@@ -116,10 +116,10 @@
   // ContinueGetResourceList.
   //
   // |title| must not be empty, and |callback| must not be null.
-  virtual CancelCallback SearchByTitle(
+  virtual google_apis::CancelCallback SearchByTitle(
       const std::string& title,
       const std::string& directory_resource_id,
-      const GetResourceListCallback& callback) = 0;
+      const google_apis::GetResourceListCallback& callback) = 0;
 
   // Fetches change list since |start_changestamp|. |callback| will be
   // called upon completion.
@@ -128,9 +128,9 @@
   // ContinueGetResourceList.
   //
   // |callback| must not be null.
-  virtual CancelCallback GetChangeList(
+  virtual google_apis::CancelCallback GetChangeList(
       int64 start_changestamp,
-      const GetResourceListCallback& callback) = 0;
+      const google_apis::GetResourceListCallback& callback) = 0;
 
   // Requests returning GetResourceList may be paged. In such a case,
   // a URL to fetch remaining result is returned. The URL can be used for this
@@ -138,38 +138,39 @@
   //
   // |override_url| must not be empty.
   // |callback| must not be null.
-  virtual CancelCallback ContinueGetResourceList(
+  virtual google_apis::CancelCallback ContinueGetResourceList(
       const GURL& override_url,
-      const GetResourceListCallback& callback) = 0;
+      const google_apis::GetResourceListCallback& callback) = 0;
 
   // Fetches single entry metadata from server. The entry's resource id equals
   // |resource_id|.
   // Upon completion, invokes |callback| with results on the calling thread.
   // |callback| must not be null.
-  virtual CancelCallback GetResourceEntry(
+  virtual google_apis::CancelCallback GetResourceEntry(
       const std::string& resource_id,
-      const GetResourceEntryCallback& callback) = 0;
+      const google_apis::GetResourceEntryCallback& callback) = 0;
 
   // Gets the about resource information from the server.
   // Upon completion, invokes |callback| with results on the calling thread.
   // |callback| must not be null.
-  virtual CancelCallback GetAboutResource(
-      const GetAboutResourceCallback& callback) = 0;
+  virtual google_apis::CancelCallback GetAboutResource(
+      const google_apis::GetAboutResourceCallback& callback) = 0;
 
   // Gets the application information from the server.
   // Upon completion, invokes |callback| with results on the calling thread.
   // |callback| must not be null.
-  virtual CancelCallback GetAppList(const GetAppListCallback& callback) = 0;
+  virtual google_apis::CancelCallback GetAppList(
+      const google_apis::GetAppListCallback& callback) = 0;
 
   // Deletes a resource identified by its |resource_id|.
   // If |etag| is not empty and did not match, the deletion fails with
   // HTTP_PRECONDITION error.
   // Upon completion, invokes |callback| with results on the calling thread.
   // |callback| must not be null.
-  virtual CancelCallback DeleteResource(
+  virtual google_apis::CancelCallback DeleteResource(
       const std::string& resource_id,
       const std::string& etag,
-      const EntryActionCallback& callback) = 0;
+      const google_apis::EntryActionCallback& callback) = 0;
 
   // Makes a copy of a resource with |resource_id|.
   // The new resource will be put under a directory with |parent_resource_id|,
@@ -178,11 +179,11 @@
   // doesn't support the function unfortunately.
   // Upon completion, invokes |callback| with results on the calling thread.
   // |callback| must not be null.
-  virtual CancelCallback CopyResource(
+  virtual google_apis::CancelCallback CopyResource(
       const std::string& resource_id,
       const std::string& parent_resource_id,
       const std::string& new_name,
-      const GetResourceEntryCallback& callback) = 0;
+      const google_apis::GetResourceEntryCallback& callback) = 0;
 
   // Makes a copy of a hosted document identified by its |resource_id|.
   // The copy is named as the UTF-8 encoded |new_name| and is not added to any
@@ -192,47 +193,48 @@
   // |callback| must not be null.
   // TODO(hidehiko): After the migration to Drive API v2, remove this method,
   // because we can use CopyResource instead.
-  virtual CancelCallback CopyHostedDocument(
+  virtual google_apis::CancelCallback CopyHostedDocument(
       const std::string& resource_id,
       const std::string& new_name,
-      const GetResourceEntryCallback& callback) = 0;
+      const google_apis::GetResourceEntryCallback& callback) = 0;
 
   // Renames a document or collection identified by its |resource_id|
   // to the UTF-8 encoded |new_name|. Upon completion,
   // invokes |callback| with results on the calling thread.
   // |callback| must not be null.
-  virtual CancelCallback RenameResource(const std::string& resource_id,
-                                       const std::string& new_name,
-                                       const EntryActionCallback& callback) = 0;
+  virtual google_apis::CancelCallback RenameResource(
+      const std::string& resource_id,
+      const std::string& new_name,
+      const google_apis::EntryActionCallback& callback) = 0;
 
   // Touches the resource with |resource_id|.
   // Its modifiedDate and lastViewedByMeDate fields on the server will be
   // updated to |modified_date| and |last_viewed_by_me_date| respectively.
   // Upon completion, invokes |callback| with the updated resource data.
   // |modified_date|, |last_viewed_by_me_date| and |callback| must not be null.
-  virtual CancelCallback TouchResource(
+  virtual google_apis::CancelCallback TouchResource(
       const std::string& resource_id,
       const base::Time& modified_date,
       const base::Time& last_viewed_by_me_date,
-      const GetResourceEntryCallback& callback) = 0;
+      const google_apis::GetResourceEntryCallback& callback) = 0;
 
   // Adds a resource (document, file, or collection) identified by its
   // |resource_id| to a collection represented by the |parent_resource_id|.
   // Upon completion, invokes |callback| with results on the calling thread.
   // |callback| must not be null.
-  virtual CancelCallback AddResourceToDirectory(
+  virtual google_apis::CancelCallback AddResourceToDirectory(
       const std::string& parent_resource_id,
       const std::string& resource_id,
-      const EntryActionCallback& callback) = 0;
+      const google_apis::EntryActionCallback& callback) = 0;
 
   // Removes a resource (document, file, collection) identified by its
   // |resource_id| from a collection represented by the |parent_resource_id|.
   // Upon completion, invokes |callback| with results on the calling thread.
   // |callback| must not be null.
-  virtual CancelCallback RemoveResourceFromDirectory(
+  virtual google_apis::CancelCallback RemoveResourceFromDirectory(
       const std::string& parent_resource_id,
       const std::string& resource_id,
-      const EntryActionCallback& callback) = 0;
+      const google_apis::EntryActionCallback& callback) = 0;
 
   // Adds new collection with |directory_name| under parent directory
   // identified with |parent_resource_id|. |parent_resource_id| can be the
@@ -242,12 +244,12 @@
   // This function cannot be named as "CreateDirectory" as it conflicts with
   // a macro on Windows.
   // |callback| must not be null.
-  virtual CancelCallback AddNewDirectory(
+  virtual google_apis::CancelCallback AddNewDirectory(
       const std::string& parent_resource_id,
       const std::string& directory_name,
-      const GetResourceEntryCallback& callback) = 0;
+      const google_apis::GetResourceEntryCallback& callback) = 0;
 
-  // Downloads a file from |download_url|. The downloaded file will
+  // Downloads a file with |resourced_id|. The downloaded file will
   // be stored at |local_cache_path| location. Upon completion, invokes
   // |download_action_callback| with results on the calling thread.
   // If |get_content_callback| is not empty,
@@ -258,70 +260,65 @@
   //
   // |download_action_callback| must not be null.
   // |get_content_callback| and |progress_callback| may be null.
-  virtual CancelCallback DownloadFile(
-      const base::FilePath& virtual_path,
+  virtual google_apis::CancelCallback DownloadFile(
       const base::FilePath& local_cache_path,
-      const GURL& download_url,
-      const DownloadActionCallback& download_action_callback,
-      const GetContentCallback& get_content_callback,
-      const ProgressCallback& progress_callback) = 0;
+      const std::string& resource_id,
+      const google_apis::DownloadActionCallback& download_action_callback,
+      const google_apis::GetContentCallback& get_content_callback,
+      const google_apis::ProgressCallback& progress_callback) = 0;
 
   // Initiates uploading of a new document/file.
   // |content_type| and |content_length| should be the ones of the file to be
   // uploaded.
   // |callback| must not be null.
-  virtual CancelCallback InitiateUploadNewFile(
-      const base::FilePath& drive_file_path,
+  virtual google_apis::CancelCallback InitiateUploadNewFile(
       const std::string& content_type,
       int64 content_length,
       const std::string& parent_resource_id,
       const std::string& title,
-      const InitiateUploadCallback& callback) = 0;
+      const google_apis::InitiateUploadCallback& callback) = 0;
 
   // Initiates uploading of an existing document/file.
   // |content_type| and |content_length| should be the ones of the file to be
   // uploaded.
   // |callback| must not be null.
-  virtual CancelCallback InitiateUploadExistingFile(
-      const base::FilePath& drive_file_path,
+  virtual google_apis::CancelCallback InitiateUploadExistingFile(
       const std::string& content_type,
       int64 content_length,
       const std::string& resource_id,
       const std::string& etag,
-      const InitiateUploadCallback& callback) = 0;
+      const google_apis::InitiateUploadCallback& callback) = 0;
 
   // Resumes uploading of a document/file on the calling thread.
   // |callback| must not be null. |progress_callback| may be null.
-  virtual CancelCallback ResumeUpload(
-      const base::FilePath& drive_file_path,
+  virtual google_apis::CancelCallback ResumeUpload(
       const GURL& upload_url,
       int64 start_position,
       int64 end_position,
       int64 content_length,
       const std::string& content_type,
       const base::FilePath& local_file_path,
-      const UploadRangeCallback& callback,
-      const ProgressCallback& progress_callback) = 0;
+      const google_apis::UploadRangeCallback& callback,
+      const google_apis::ProgressCallback& progress_callback) = 0;
 
   // Gets the current status of the uploading to |upload_url| from the server.
   // |drive_file_path| and |content_length| should be set to the same value
   // which is used for ResumeUpload.
   // |callback| must not be null.
-  virtual CancelCallback GetUploadStatus(
-      const base::FilePath& drive_file_path,
+  virtual google_apis::CancelCallback GetUploadStatus(
       const GURL& upload_url,
       int64 content_length,
-      const UploadRangeCallback& callback) = 0;
+      const google_apis::UploadRangeCallback& callback) = 0;
 
   // Authorizes a Drive app with the id |app_id| to open the given file.
   // Upon completion, invokes |callback| with the link to open the file with
   // the provided app. |callback| must not be null.
-  virtual CancelCallback AuthorizeApp(
+  virtual google_apis::CancelCallback AuthorizeApp(
       const std::string& resource_id,
       const std::string& app_id,
-      const AuthorizeAppCallback& callback) = 0;
+      const google_apis::AuthorizeAppCallback& callback) = 0;
 };
 
-}  // namespace google_apis
+}  // namespace drive
 
 #endif  // CHROME_BROWSER_DRIVE_DRIVE_SERVICE_INTERFACE_H_
diff --git a/chrome/browser/drive/drive_switches.cc b/chrome/browser/drive/drive_switches.cc
new file mode 100644
index 0000000..0505a00
--- /dev/null
+++ b/chrome/browser/drive/drive_switches.cc
@@ -0,0 +1,14 @@
+// Copyright 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/drive/drive_switches.h"
+
+namespace drive {
+namespace switches {
+
+// Enables Drive v2 API instead of Google Documents List API.
+const char kEnableDriveV2Api[] = "enable-drive-v2-api";
+
+}  // namespace switches
+}  // namespace drive
diff --git a/chrome/browser/drive/drive_switches.h b/chrome/browser/drive/drive_switches.h
new file mode 100644
index 0000000..59282e4
--- /dev/null
+++ b/chrome/browser/drive/drive_switches.h
@@ -0,0 +1,16 @@
+// Copyright 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_DRIVE_DRIVE_SWITCHES_H_
+#define CHROME_BROWSER_DRIVE_DRIVE_SWITCHES_H_
+
+namespace drive {
+namespace switches {
+
+extern const char kEnableDriveV2Api[];
+
+}  // namespace switches
+}  // namespace drive
+
+#endif  // CHROME_BROWSER_DRIVE_DRIVE_SWITCHES_H_
diff --git a/chrome/browser/drive/drive_uploader.cc b/chrome/browser/drive/drive_uploader.cc
index 4f9247a..0d4866a 100644
--- a/chrome/browser/drive/drive_uploader.cc
+++ b/chrome/browser/drive/drive_uploader.cc
@@ -11,26 +11,37 @@
 #include "base/file_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/task_runner_util.h"
-#include "base/threading/sequenced_worker_pool.h"
 #include "chrome/browser/drive/drive_service_interface.h"
 #include "chrome/browser/google_apis/gdata_wapi_parser.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/power_save_blocker.h"
 
 using content::BrowserThread;
+using google_apis::CancelCallback;
+using google_apis::GDATA_CANCELLED;
+using google_apis::GDataErrorCode;
+using google_apis::GDATA_NO_SPACE;
+using google_apis::HTTP_CONFLICT;
+using google_apis::HTTP_CREATED;
+using google_apis::HTTP_FORBIDDEN;
+using google_apis::HTTP_NOT_FOUND;
+using google_apis::HTTP_PRECONDITION;
+using google_apis::HTTP_RESUME_INCOMPLETE;
+using google_apis::HTTP_SUCCESS;
+using google_apis::ProgressCallback;
+using google_apis::ResourceEntry;
+using google_apis::UploadRangeResponse;
 
-namespace google_apis {
+namespace drive {
 
 // Structure containing current upload information of file, passed between
 // DriveServiceInterface methods and callbacks.
 struct DriveUploader::UploadFileInfo {
-  UploadFileInfo(const base::FilePath& drive_path,
-                 const base::FilePath& local_path,
+  UploadFileInfo(const base::FilePath& local_path,
                  const std::string& content_type,
                  const UploadCompletionCallback& callback,
                  const ProgressCallback& progress_callback)
-      : drive_path(drive_path),
-        file_path(local_path),
+      : file_path(local_path),
         content_type(content_type),
         completion_callback(callback),
         progress_callback(progress_callback),
@@ -50,7 +61,6 @@
     return "file_path=[" + file_path.AsUTF8Unsafe() +
            "], content_type=[" + content_type +
            "], content_length=[" + base::UintToString(content_length) +
-           "], drive_path=[" + drive_path.AsUTF8Unsafe() +
            "]";
   }
 
@@ -59,9 +69,6 @@
     return base::Bind(&UploadFileInfo::Cancel, weak_ptr_factory_.GetWeakPtr());
   }
 
-  // Final path in gdata. Looks like /special/drive/MyFolder/MyFile.
-  const base::FilePath drive_path;
-
   // The local file path of the file to be uploaded.
   const base::FilePath file_path;
 
@@ -105,8 +112,10 @@
   DISALLOW_COPY_AND_ASSIGN(UploadFileInfo);
 };
 
-DriveUploader::DriveUploader(DriveServiceInterface* drive_service)
+DriveUploader::DriveUploader(DriveServiceInterface* drive_service,
+                             base::TaskRunner* blocking_task_runner)
     : drive_service_(drive_service),
+      blocking_task_runner_(blocking_task_runner),
       weak_ptr_factory_(this) {
 }
 
@@ -114,7 +123,6 @@
 
 CancelCallback DriveUploader::UploadNewFile(
     const std::string& parent_resource_id,
-    const base::FilePath& drive_file_path,
     const base::FilePath& local_file_path,
     const std::string& title,
     const std::string& content_type,
@@ -122,15 +130,13 @@
     const ProgressCallback& progress_callback) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   DCHECK(!parent_resource_id.empty());
-  DCHECK(!drive_file_path.empty());
   DCHECK(!local_file_path.empty());
   DCHECK(!title.empty());
   DCHECK(!content_type.empty());
   DCHECK(!callback.is_null());
 
   return StartUploadFile(
-      scoped_ptr<UploadFileInfo>(new UploadFileInfo(drive_file_path,
-                                                    local_file_path,
+      scoped_ptr<UploadFileInfo>(new UploadFileInfo(local_file_path,
                                                     content_type,
                                                     callback,
                                                     progress_callback)),
@@ -142,7 +148,6 @@
 
 CancelCallback DriveUploader::UploadExistingFile(
     const std::string& resource_id,
-    const base::FilePath& drive_file_path,
     const base::FilePath& local_file_path,
     const std::string& content_type,
     const std::string& etag,
@@ -150,14 +155,12 @@
     const ProgressCallback& progress_callback) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   DCHECK(!resource_id.empty());
-  DCHECK(!drive_file_path.empty());
   DCHECK(!local_file_path.empty());
   DCHECK(!content_type.empty());
   DCHECK(!callback.is_null());
 
   return StartUploadFile(
-      scoped_ptr<UploadFileInfo>(new UploadFileInfo(drive_file_path,
-                                                    local_file_path,
+      scoped_ptr<UploadFileInfo>(new UploadFileInfo(local_file_path,
                                                     content_type,
                                                     callback,
                                                     progress_callback)),
@@ -169,19 +172,17 @@
 
 CancelCallback DriveUploader::ResumeUploadFile(
     const GURL& upload_location,
-    const base::FilePath& drive_file_path,
     const base::FilePath& local_file_path,
     const std::string& content_type,
     const UploadCompletionCallback& callback,
     const ProgressCallback& progress_callback) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  DCHECK(!drive_file_path.empty());
   DCHECK(!local_file_path.empty());
   DCHECK(!content_type.empty());
   DCHECK(!callback.is_null());
 
   scoped_ptr<UploadFileInfo> upload_file_info(new UploadFileInfo(
-      drive_file_path, local_file_path, content_type,
+      local_file_path, content_type,
       callback, progress_callback));
   upload_file_info->upload_location = upload_location;
 
@@ -199,9 +200,10 @@
 
   UploadFileInfo* info_ptr = upload_file_info.get();
   base::PostTaskAndReplyWithResult(
-      BrowserThread::GetBlockingPool(),
+      blocking_task_runner_.get(),
       FROM_HERE,
-      base::Bind(&file_util::GetFileSize, info_ptr->file_path,
+      base::Bind(&file_util::GetFileSize,
+                 info_ptr->file_path,
                  &info_ptr->content_length),
       base::Bind(&DriveUploader::StartUploadFileAfterGetFileSize,
                  weak_ptr_factory_.GetWeakPtr(),
@@ -237,7 +239,6 @@
 
   UploadFileInfo* info_ptr = upload_file_info.get();
   info_ptr->cancel_callback = drive_service_->InitiateUploadNewFile(
-      info_ptr->drive_path,
       info_ptr->content_type,
       info_ptr->content_length,
       parent_resource_id,
@@ -255,7 +256,6 @@
 
   UploadFileInfo* info_ptr = upload_file_info.get();
   info_ptr->cancel_callback = drive_service_->InitiateUploadExistingFile(
-      info_ptr->drive_path,
       info_ptr->content_type,
       info_ptr->content_length,
       resource_id,
@@ -272,7 +272,7 @@
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
 
   DVLOG(1) << "Got upload location [" << upload_location.spec()
-           << "] for [" << upload_file_info->drive_path.value() << "]";
+           << "] for [" << upload_file_info->file_path.value() << "]";
 
   if (code != HTTP_SUCCESS) {
     // TODO(achuith): Handle error codes from Google Docs server.
@@ -296,7 +296,6 @@
 
   UploadFileInfo* info_ptr = upload_file_info.get();
   info_ptr->cancel_callback = drive_service_->GetUploadStatus(
-      info_ptr->drive_path,
       info_ptr->upload_location,
       info_ptr->content_length,
       base::Bind(&DriveUploader::OnUploadRangeResponseReceived,
@@ -319,7 +318,6 @@
 
   UploadFileInfo* info_ptr = upload_file_info.get();
   info_ptr->cancel_callback = drive_service_->ResumeUpload(
-      info_ptr->drive_path,
       info_ptr->upload_location,
       start_position,
       info_ptr->content_length,
@@ -353,7 +351,7 @@
     // TODO(hidehiko): Upload metadata only for empty files, after GData WAPI
     // code is gone.
     DVLOG(1) << "Successfully created uploaded file=["
-             << upload_file_info->drive_path.value() << "]";
+             << upload_file_info->file_path.value() << "]";
 
     // Done uploading.
     upload_file_info->completion_callback.Run(
@@ -384,7 +382,7 @@
 
   DVLOG(1) << "Received range " << response.start_position_received
            << "-" << response.end_position_received
-           << " for [" << upload_file_info->drive_path.value() << "]";
+           << " for [" << upload_file_info->file_path.value() << "]";
 
   UploadNextChunk(upload_file_info.Pass(), response.end_position_received);
 }
@@ -408,4 +406,4 @@
       error, upload_file_info->upload_location, scoped_ptr<ResourceEntry>());
 }
 
-}  // namespace google_apis
+}  // namespace drive
diff --git a/chrome/browser/drive/drive_uploader.h b/chrome/browser/drive/drive_uploader.h
index d93b2f3..cb8bc80 100644
--- a/chrome/browser/drive/drive_uploader.h
+++ b/chrome/browser/drive/drive_uploader.h
@@ -9,6 +9,7 @@
 
 #include "base/basictypes.h"
 #include "base/callback_forward.h"
+#include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/drive/drive_service_interface.h"
 #include "chrome/browser/google_apis/gdata_errorcode.h"
@@ -18,19 +19,24 @@
 
 namespace base {
 class FilePath;
+class TaskRunner;
 }
 
 namespace google_apis {
-class DriveServiceInterface;
 struct UploadRangeResponse;
+}
+
+namespace drive {
+class DriveServiceInterface;
 
 // Callback to be invoked once the upload has completed.
 // |upload_location| will be returned when the uploading process is started but
 // terminated before the completion due to some errors. It can be used to
 // resume it.
-typedef base::Callback<void(GDataErrorCode error,
-                            const GURL& upload_location,
-                            scoped_ptr<ResourceEntry> resource_entry)>
+typedef base::Callback<void(
+    google_apis::GDataErrorCode error,
+    const GURL& upload_location,
+    scoped_ptr<google_apis::ResourceEntry> resource_entry)>
     UploadCompletionCallback;
 
 class DriveUploaderInterface {
@@ -43,9 +49,6 @@
   // parent_resource_id:
   //   resource id of the destination directory.
   //
-  // drive_file_path:
-  //   The destination path like "drive/foo/bar.txt".
-  //
   // local_file_path:
   //   The path to the local file to be uploaded.
   //
@@ -62,14 +65,13 @@
   // progress_callback:
   //   Periodically called back with the total number of bytes sent so far.
   //   May be null if the information is not needed.
-  virtual CancelCallback UploadNewFile(
+  virtual google_apis::CancelCallback UploadNewFile(
       const std::string& parent_resource_id,
-      const base::FilePath& drive_file_path,
       const base::FilePath& local_file_path,
       const std::string& title,
       const std::string& content_type,
       const UploadCompletionCallback& callback,
-      const ProgressCallback& progress_callback) = 0;
+      const google_apis::ProgressCallback& progress_callback) = 0;
 
   // Uploads an existing file (a file that already exists on Drive).
   //
@@ -82,14 +84,13 @@
   //   Expected ETag for the destination file. If it does not match, the upload
   //   fails with UPLOAD_ERROR_CONFLICT.
   //   If |etag| is empty, the test is skipped.
-  virtual CancelCallback UploadExistingFile(
+  virtual google_apis::CancelCallback UploadExistingFile(
       const std::string& resource_id,
-      const base::FilePath& drive_file_path,
       const base::FilePath& local_file_path,
       const std::string& content_type,
       const std::string& etag,
       const UploadCompletionCallback& callback,
-      const ProgressCallback& progress_callback) = 0;
+      const google_apis::ProgressCallback& progress_callback) = 0;
 
   // Resumes the uploading process terminated before the completion.
   // |upload_location| should be the one returned via UploadCompletionCallback
@@ -97,44 +98,41 @@
   // |content_type| must be set to the same ones for previous invocation.
   //
   // See comments at UploadNewFile about common parameters and the return value.
-  virtual CancelCallback ResumeUploadFile(
+  virtual google_apis::CancelCallback ResumeUploadFile(
       const GURL& upload_location,
-      const base::FilePath& drive_file_path,
       const base::FilePath& local_file_path,
       const std::string& content_type,
       const UploadCompletionCallback& callback,
-      const ProgressCallback& progress_callback) = 0;
+      const google_apis::ProgressCallback& progress_callback) = 0;
 };
 
 class DriveUploader : public DriveUploaderInterface {
  public:
-  explicit DriveUploader(DriveServiceInterface* drive_service);
+  DriveUploader(DriveServiceInterface* drive_service,
+                base::TaskRunner* blocking_task_runner);
   virtual ~DriveUploader();
 
   // DriveUploaderInterface overrides.
-  virtual CancelCallback UploadNewFile(
+  virtual google_apis::CancelCallback UploadNewFile(
       const std::string& parent_resource_id,
-      const base::FilePath& drive_file_path,
       const base::FilePath& local_file_path,
       const std::string& title,
       const std::string& content_type,
       const UploadCompletionCallback& callback,
-      const ProgressCallback& progress_callback) OVERRIDE;
-  virtual CancelCallback UploadExistingFile(
+      const google_apis::ProgressCallback& progress_callback) OVERRIDE;
+  virtual google_apis::CancelCallback UploadExistingFile(
       const std::string& resource_id,
-      const base::FilePath& drive_file_path,
       const base::FilePath& local_file_path,
       const std::string& content_type,
       const std::string& etag,
       const UploadCompletionCallback& callback,
-      const ProgressCallback& progress_callback) OVERRIDE;
-  virtual CancelCallback ResumeUploadFile(
+      const google_apis::ProgressCallback& progress_callback) OVERRIDE;
+  virtual google_apis::CancelCallback ResumeUploadFile(
       const GURL& upload_location,
-      const base::FilePath& drive_file_path,
       const base::FilePath& local_file_path,
       const std::string& content_type,
       const UploadCompletionCallback& callback,
-      const ProgressCallback& progress_callback) OVERRIDE;
+      const google_apis::ProgressCallback& progress_callback) OVERRIDE;
 
  private:
   struct UploadFileInfo;
@@ -142,7 +140,7 @@
       StartInitiateUploadCallback;
 
   // Starts uploading a file with |upload_file_info|.
-  CancelCallback StartUploadFile(
+  google_apis::CancelCallback StartUploadFile(
       scoped_ptr<UploadFileInfo> upload_file_info,
       const StartInitiateUploadCallback& start_initiate_upload_callback);
   void StartUploadFileAfterGetFileSize(
@@ -166,7 +164,7 @@
 
   // DriveService callback for InitiateUpload.
   void OnUploadLocationReceived(scoped_ptr<UploadFileInfo> upload_file_info,
-                                GDataErrorCode code,
+                                google_apis::GDataErrorCode code,
                                 const GURL& upload_location);
 
   // Starts to get the current upload status for the file uploading.
@@ -180,9 +178,9 @@
   // DriveService callback for ResumeUpload.
   void OnUploadRangeResponseReceived(
       scoped_ptr<UploadFileInfo> upload_file_info,
-      const UploadRangeResponse& response,
-      scoped_ptr<ResourceEntry> entry);
-  void OnUploadProgress(const ProgressCallback& callback,
+      const google_apis::UploadRangeResponse& response,
+      scoped_ptr<google_apis::ResourceEntry> entry);
+  void OnUploadProgress(const google_apis::ProgressCallback& callback,
                         int64 start_position,
                         int64 total_size,
                         int64 progress_of_chunk,
@@ -190,18 +188,20 @@
 
   // Handle failed uploads.
   void UploadFailed(scoped_ptr<UploadFileInfo> upload_file_info,
-                    GDataErrorCode error);
+                    google_apis::GDataErrorCode error);
 
   // The lifetime of this object should be guaranteed to exceed that of the
   // DriveUploader instance.
   DriveServiceInterface* drive_service_;  // Not owned by this class.
 
+  scoped_refptr<base::TaskRunner> blocking_task_runner_;
+
   // Note: This should remain the last member so it'll be destroyed and
   // invalidate its weak pointers before any other members are destroyed.
   base::WeakPtrFactory<DriveUploader> weak_ptr_factory_;
   DISALLOW_COPY_AND_ASSIGN(DriveUploader);
 };
 
-}  // namespace google_apis
+}  // namespace drive
 
 #endif  // CHROME_BROWSER_DRIVE_DRIVE_UPLOADER_H_
diff --git a/chrome/browser/drive/drive_uploader_unittest.cc b/chrome/browser/drive/drive_uploader_unittest.cc
index 363e5af..117cdba 100644
--- a/chrome/browser/drive/drive_uploader_unittest.cc
+++ b/chrome/browser/drive/drive_uploader_unittest.cc
@@ -4,29 +4,43 @@
 
 #include "chrome/browser/drive/drive_uploader.h"
 
-#include <algorithm>
-#include <cstdlib>
 #include <string>
-#include <utility>
 #include <vector>
 
 #include "base/bind.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/message_loop.h"
+#include "base/run_loop.h"
 #include "base/values.h"
 #include "chrome/browser/drive/dummy_drive_service.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 google_apis {
+using google_apis::CancelCallback;
+using google_apis::GDataErrorCode;
+using google_apis::GDATA_NO_CONNECTION;
+using google_apis::GDATA_OTHER_ERROR;
+using google_apis::HTTP_CONFLICT;
+using google_apis::HTTP_CREATED;
+using google_apis::HTTP_NOT_FOUND;
+using google_apis::HTTP_PRECONDITION;
+using google_apis::HTTP_RESUME_INCOMPLETE;
+using google_apis::HTTP_SUCCESS;
+using google_apis::InitiateUploadCallback;
+using google_apis::ProgressCallback;
+using google_apis::ResourceEntry;
+using google_apis::UploadRangeCallback;
+using google_apis::UploadRangeResponse;
+namespace test_util = google_apis::test_util;
+
+namespace drive {
 
 namespace {
 
 const char kTestDummyId[] = "file:dummy_id";
 const char kTestDocumentTitle[] = "Hello world";
-const char kTestDrivePath[] = "drive/dummy.txt";
 const char kTestInitiateUploadParentResourceId[] = "parent_resource_id";
 const char kTestInitiateUploadResourceId[] = "resource_id";
 const char kTestMimeType[] = "text/plain";
@@ -61,7 +75,6 @@
   // DriveServiceInterface overrides.
   // Handles a request for obtaining an upload location URL.
   virtual CancelCallback InitiateUploadNewFile(
-      const base::FilePath& drive_file_path,
       const std::string& content_type,
       int64 content_length,
       const std::string& parent_resource_id,
@@ -80,7 +93,6 @@
   }
 
   virtual CancelCallback InitiateUploadExistingFile(
-      const base::FilePath& drive_file_path,
       const std::string& content_type,
       int64 content_length,
       const std::string& resource_id,
@@ -105,7 +117,6 @@
 
   // Handles a request for uploading a chunk of bytes.
   virtual CancelCallback ResumeUpload(
-      const base::FilePath& drive_file_path,
       const GURL& upload_location,
       int64 start_position,
       int64 end_position,
@@ -150,7 +161,6 @@
 
   // Handles a request to fetch the current upload status.
   virtual CancelCallback GetUploadStatus(
-      const base::FilePath& drive_file_path,
       const GURL& upload_location,
       int64 content_length,
       const UploadRangeCallback& callback) OVERRIDE {
@@ -197,7 +207,6 @@
 class MockDriveServiceNoConnectionAtInitiate : public DummyDriveService {
   // Returns error.
   virtual CancelCallback InitiateUploadNewFile(
-      const base::FilePath& drive_file_path,
       const std::string& content_type,
       int64 content_length,
       const std::string& parent_resource_id,
@@ -209,7 +218,6 @@
   }
 
   virtual CancelCallback InitiateUploadExistingFile(
-      const base::FilePath& drive_file_path,
       const std::string& content_type,
       int64 content_length,
       const std::string& resource_id,
@@ -222,7 +230,6 @@
 
   // Should not be used.
   virtual CancelCallback ResumeUpload(
-      const base::FilePath& drive_file_path,
       const GURL& upload_url,
       int64 start_position,
       int64 end_position,
@@ -240,7 +247,6 @@
 class MockDriveServiceNoConnectionAtResume : public DummyDriveService {
   // Succeeds and returns an upload location URL.
   virtual CancelCallback InitiateUploadNewFile(
-      const base::FilePath& drive_file_path,
       const std::string& content_type,
       int64 content_length,
       const std::string& parent_resource_id,
@@ -252,7 +258,6 @@
   }
 
   virtual CancelCallback InitiateUploadExistingFile(
-      const base::FilePath& drive_file_path,
       const std::string& content_type,
       int64 content_length,
       const std::string& resource_id,
@@ -265,7 +270,6 @@
 
   // Returns error.
   virtual CancelCallback ResumeUpload(
-      const base::FilePath& drive_file_path,
       const GURL& upload_url,
       int64 start_position,
       int64 end_position,
@@ -288,10 +292,6 @@
     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
   }
 
-  virtual void TearDown() OVERRIDE {
-    ASSERT_TRUE(temp_dir_.Delete());
-  }
-
  protected:
   content::TestBrowserThreadBundle thread_bundle_;
   base::ScopedTempDir temp_dir_;
@@ -310,11 +310,11 @@
   scoped_ptr<ResourceEntry> resource_entry;
 
   MockDriveServiceWithUploadExpectation mock_service(local_path, data.size());
-  DriveUploader uploader(&mock_service);
+  DriveUploader uploader(&mock_service,
+                         base::MessageLoopProxy::current().get());
   std::vector<test_util::ProgressInfo> upload_progress_values;
   uploader.UploadExistingFile(
       kTestInitiateUploadResourceId,
-      base::FilePath::FromUTF8Unsafe(kTestDrivePath),
       local_path,
       kTestMimeType,
       std::string(),  // etag
@@ -322,7 +322,7 @@
           &error, &upload_location, &resource_entry),
       base::Bind(&test_util::AppendProgressCallbackResult,
                  &upload_progress_values));
-  test_util::RunBlockingPoolTask();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(1, mock_service.resume_upload_call_count());
   EXPECT_EQ(0, mock_service.received_bytes());
@@ -345,11 +345,11 @@
   scoped_ptr<ResourceEntry> resource_entry;
 
   MockDriveServiceWithUploadExpectation mock_service(local_path, data.size());
-  DriveUploader uploader(&mock_service);
+  DriveUploader uploader(&mock_service,
+                         base::MessageLoopProxy::current().get());
   std::vector<test_util::ProgressInfo> upload_progress_values;
   uploader.UploadExistingFile(
       kTestInitiateUploadResourceId,
-      base::FilePath::FromUTF8Unsafe(kTestDrivePath),
       local_path,
       kTestMimeType,
       std::string(),  // etag
@@ -357,7 +357,7 @@
           &error, &upload_location, &resource_entry),
       base::Bind(&test_util::AppendProgressCallbackResult,
                  &upload_progress_values));
-  test_util::RunBlockingPoolTask();
+  base::RunLoop().RunUntilIdle();
 
   // 512KB upload should not be split into multiple chunks.
   EXPECT_EQ(1, mock_service.resume_upload_call_count());
@@ -382,17 +382,16 @@
   scoped_ptr<ResourceEntry> resource_entry;
 
   MockDriveServiceNoConnectionAtInitiate mock_service;
-  DriveUploader uploader(&mock_service);
-  uploader.UploadExistingFile(
-      kTestInitiateUploadResourceId,
-      base::FilePath::FromUTF8Unsafe(kTestDrivePath),
-      local_path,
-      kTestMimeType,
-      std::string(),  // etag
-      test_util::CreateCopyResultCallback(
-          &error, &upload_location, &resource_entry),
-      google_apis::ProgressCallback());
-  test_util::RunBlockingPoolTask();
+  DriveUploader uploader(&mock_service,
+                         base::MessageLoopProxy::current().get());
+  uploader.UploadExistingFile(kTestInitiateUploadResourceId,
+                              local_path,
+                              kTestMimeType,
+                              std::string(),  // etag
+                              test_util::CreateCopyResultCallback(
+                                  &error, &upload_location, &resource_entry),
+                              google_apis::ProgressCallback());
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(GDATA_NO_CONNECTION, error);
   EXPECT_TRUE(upload_location.is_empty());
@@ -410,17 +409,16 @@
   scoped_ptr<ResourceEntry> resource_entry;
 
   MockDriveServiceWithUploadExpectation mock_service(local_path, data.size());
-  DriveUploader uploader(&mock_service);
-  uploader.UploadExistingFile(
-      kTestInitiateUploadResourceId,
-      base::FilePath::FromUTF8Unsafe(kTestDrivePath),
-      local_path,
-      kTestMimeType,
-      kTestETag,
-      test_util::CreateCopyResultCallback(
-          &error, &upload_location, &resource_entry),
-      google_apis::ProgressCallback());
-  test_util::RunBlockingPoolTask();
+  DriveUploader uploader(&mock_service,
+                         base::MessageLoopProxy::current().get());
+  uploader.UploadExistingFile(kTestInitiateUploadResourceId,
+                              local_path,
+                              kTestMimeType,
+                              kTestETag,
+                              test_util::CreateCopyResultCallback(
+                                  &error, &upload_location, &resource_entry),
+                              google_apis::ProgressCallback());
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(HTTP_SUCCESS, error);
   EXPECT_TRUE(upload_location.is_empty());
@@ -438,17 +436,16 @@
   scoped_ptr<ResourceEntry> resource_entry;
 
   MockDriveServiceWithUploadExpectation mock_service(local_path, data.size());
-  DriveUploader uploader(&mock_service);
-  uploader.UploadExistingFile(
-      kTestInitiateUploadResourceId,
-      base::FilePath::FromUTF8Unsafe(kTestDrivePath),
-      local_path,
-      kTestMimeType,
-      kDestinationETag,
-      test_util::CreateCopyResultCallback(
-          &error, &upload_location, &resource_entry),
-      google_apis::ProgressCallback());
-  test_util::RunBlockingPoolTask();
+  DriveUploader uploader(&mock_service,
+                         base::MessageLoopProxy::current().get());
+  uploader.UploadExistingFile(kTestInitiateUploadResourceId,
+                              local_path,
+                              kTestMimeType,
+                              kDestinationETag,
+                              test_util::CreateCopyResultCallback(
+                                  &error, &upload_location, &resource_entry),
+                              google_apis::ProgressCallback());
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(HTTP_CONFLICT, error);
   EXPECT_TRUE(upload_location.is_empty());
@@ -465,17 +462,16 @@
   scoped_ptr<ResourceEntry> resource_entry;
 
   MockDriveServiceNoConnectionAtResume mock_service;
-  DriveUploader uploader(&mock_service);
-  uploader.UploadExistingFile(
-      kTestInitiateUploadResourceId,
-      base::FilePath::FromUTF8Unsafe(kTestDrivePath),
-      local_path,
-      kTestMimeType,
-      std::string(),  // etag
-      test_util::CreateCopyResultCallback(
-          &error, &upload_location, &resource_entry),
-      google_apis::ProgressCallback());
-  test_util::RunBlockingPoolTask();
+  DriveUploader uploader(&mock_service,
+                         base::MessageLoopProxy::current().get());
+  uploader.UploadExistingFile(kTestInitiateUploadResourceId,
+                              local_path,
+                              kTestMimeType,
+                              std::string(),  // etag
+                              test_util::CreateCopyResultCallback(
+                                  &error, &upload_location, &resource_entry),
+                              google_apis::ProgressCallback());
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(GDATA_NO_CONNECTION, error);
   EXPECT_EQ(GURL(kTestUploadExistingFileURL), upload_location);
@@ -486,17 +482,17 @@
   GURL upload_location;
   scoped_ptr<ResourceEntry> resource_entry;
 
-  DriveUploader uploader(NULL);  // NULL, the service won't be used.
+  DriveUploader uploader(NULL,  // NULL, the service won't be used.
+                         base::MessageLoopProxy::current().get());
   uploader.UploadExistingFile(
       kTestInitiateUploadResourceId,
-      base::FilePath::FromUTF8Unsafe(kTestDrivePath),
       temp_dir_.path().AppendASCII("_this_path_should_not_exist_"),
       kTestMimeType,
-      std::string(),             // etag
+      std::string(),  // etag
       test_util::CreateCopyResultCallback(
           &error, &upload_location, &resource_entry),
       google_apis::ProgressCallback());
-  test_util::RunBlockingPoolTask();
+  base::RunLoop().RunUntilIdle();
 
   // Should return failure without doing any attempt to connect to the server.
   EXPECT_EQ(HTTP_NOT_FOUND, error);
@@ -514,7 +510,8 @@
   scoped_ptr<ResourceEntry> resource_entry;
 
   MockDriveServiceWithUploadExpectation mock_service(local_path, data.size());
-  DriveUploader uploader(&mock_service);
+  DriveUploader uploader(&mock_service,
+                         base::MessageLoopProxy::current().get());
   // Emulate the situation that the only first part is successfully uploaded,
   // but not the latter half.
   mock_service.set_received_bytes(512 * 1024);
@@ -522,14 +519,13 @@
   std::vector<test_util::ProgressInfo> upload_progress_values;
   uploader.ResumeUploadFile(
       GURL(kTestUploadExistingFileURL),
-      base::FilePath::FromUTF8Unsafe(kTestDrivePath),
       local_path,
       kTestMimeType,
       test_util::CreateCopyResultCallback(
           &error, &upload_location, &resource_entry),
       base::Bind(&test_util::AppendProgressCallbackResult,
                  &upload_progress_values));
-  test_util::RunBlockingPoolTask();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(1, mock_service.resume_upload_call_count());
   EXPECT_EQ(1024 * 1024, mock_service.received_bytes());
@@ -542,4 +538,4 @@
             upload_progress_values[0]);
 }
 
-}  // namespace google_apis
+}  // namespace drive
diff --git a/chrome/browser/drive/dummy_drive_service.cc b/chrome/browser/drive/dummy_drive_service.cc
index d9442d1..24da00a 100644
--- a/chrome/browser/drive/dummy_drive_service.cc
+++ b/chrome/browser/drive/dummy_drive_service.cc
@@ -4,7 +4,20 @@
 
 #include "chrome/browser/drive/dummy_drive_service.h"
 
-namespace google_apis {
+using google_apis::AuthorizeAppCallback;
+using google_apis::CancelCallback;
+using google_apis::DownloadActionCallback;
+using google_apis::EntryActionCallback;
+using google_apis::GetAboutResourceCallback;
+using google_apis::GetAppListCallback;
+using google_apis::GetContentCallback;
+using google_apis::GetResourceEntryCallback;
+using google_apis::GetResourceListCallback;
+using google_apis::InitiateUploadCallback;
+using google_apis::ProgressCallback;
+using google_apis::UploadRangeCallback;
+
+namespace drive {
 
 DummyDriveService::DummyDriveService() {}
 
@@ -75,9 +88,8 @@
     const EntryActionCallback& callback) { return CancelCallback(); }
 
 CancelCallback DummyDriveService::DownloadFile(
-    const base::FilePath& virtual_path,
     const base::FilePath& local_cache_path,
-    const GURL& download_url,
+    const std::string& resource_id,
     const DownloadActionCallback& download_action_callback,
     const GetContentCallback& get_content_callback,
     const ProgressCallback& progress_callback) { return CancelCallback(); }
@@ -120,7 +132,6 @@
     const GetResourceEntryCallback& callback) { return CancelCallback(); }
 
 CancelCallback DummyDriveService::InitiateUploadNewFile(
-    const base::FilePath& drive_file_path,
     const std::string& content_type,
     int64 content_length,
     const std::string& parent_resource_id,
@@ -128,7 +139,6 @@
     const InitiateUploadCallback& callback) { return CancelCallback(); }
 
 CancelCallback DummyDriveService::InitiateUploadExistingFile(
-    const base::FilePath& drive_file_path,
     const std::string& content_type,
     int64 content_length,
     const std::string& resource_id,
@@ -136,7 +146,6 @@
     const InitiateUploadCallback& callback) { return CancelCallback(); }
 
 CancelCallback DummyDriveService::ResumeUpload(
-    const base::FilePath& drive_file_path,
     const GURL& upload_url,
     int64 start_position,
     int64 end_position,
@@ -147,7 +156,6 @@
     const ProgressCallback& progress_callback) { return CancelCallback(); }
 
 CancelCallback DummyDriveService::GetUploadStatus(
-    const base::FilePath& drive_file_path,
     const GURL& upload_url,
     int64 content_length,
     const UploadRangeCallback& callback) { return CancelCallback(); }
@@ -157,4 +165,4 @@
     const std::string& app_id,
     const AuthorizeAppCallback& callback) { return CancelCallback(); }
 
-}  // namespace google_apis
+}  // namespace drive
diff --git a/chrome/browser/drive/dummy_drive_service.h b/chrome/browser/drive/dummy_drive_service.h
index e2c75ca..bcb89bf 100644
--- a/chrome/browser/drive/dummy_drive_service.h
+++ b/chrome/browser/drive/dummy_drive_service.h
@@ -7,7 +7,7 @@
 
 #include "chrome/browser/drive/drive_service_interface.h"
 
-namespace google_apis {
+namespace drive {
 
 // Dummy implementation of DriveServiceInterface.
 // All functions do nothing, or return place holder values like 'true'.
@@ -28,107 +28,102 @@
   virtual void ClearAccessToken() OVERRIDE;
   virtual void ClearRefreshToken() OVERRIDE;
   virtual std::string GetRootResourceId() const OVERRIDE;
-  virtual CancelCallback GetAllResourceList(
-      const GetResourceListCallback& callback) OVERRIDE;
-  virtual CancelCallback GetResourceListInDirectory(
+  virtual google_apis::CancelCallback GetAllResourceList(
+      const google_apis::GetResourceListCallback& callback) OVERRIDE;
+  virtual google_apis::CancelCallback GetResourceListInDirectory(
       const std::string& directory_resource_id,
-      const GetResourceListCallback& callback) OVERRIDE;
-  virtual CancelCallback Search(
+      const google_apis::GetResourceListCallback& callback) OVERRIDE;
+  virtual google_apis::CancelCallback Search(
       const std::string& search_query,
-      const GetResourceListCallback& callback) OVERRIDE;
-  virtual CancelCallback SearchByTitle(
+      const google_apis::GetResourceListCallback& callback) OVERRIDE;
+  virtual google_apis::CancelCallback SearchByTitle(
       const std::string& title,
       const std::string& directory_resource_id,
-      const GetResourceListCallback& callback) OVERRIDE;
-  virtual CancelCallback GetChangeList(
+      const google_apis::GetResourceListCallback& callback) OVERRIDE;
+  virtual google_apis::CancelCallback GetChangeList(
       int64 start_changestamp,
-      const GetResourceListCallback& callback) OVERRIDE;
-  virtual CancelCallback ContinueGetResourceList(
+      const google_apis::GetResourceListCallback& callback) OVERRIDE;
+  virtual google_apis::CancelCallback ContinueGetResourceList(
       const GURL& override_url,
-      const GetResourceListCallback& callback) OVERRIDE;
-  virtual CancelCallback GetResourceEntry(
+      const google_apis::GetResourceListCallback& callback) OVERRIDE;
+  virtual google_apis::CancelCallback GetResourceEntry(
       const std::string& resource_id,
-      const GetResourceEntryCallback& callback) OVERRIDE;
-  virtual CancelCallback GetAboutResource(
-      const GetAboutResourceCallback& callback) OVERRIDE;
-  virtual CancelCallback GetAppList(
-      const GetAppListCallback& callback) OVERRIDE;
-  virtual CancelCallback DeleteResource(
+      const google_apis::GetResourceEntryCallback& callback) OVERRIDE;
+  virtual google_apis::CancelCallback GetAboutResource(
+      const google_apis::GetAboutResourceCallback& callback) OVERRIDE;
+  virtual google_apis::CancelCallback GetAppList(
+      const google_apis::GetAppListCallback& callback) OVERRIDE;
+  virtual google_apis::CancelCallback DeleteResource(
       const std::string& resource_id,
       const std::string& etag,
-      const EntryActionCallback& callback) OVERRIDE;
-  virtual CancelCallback DownloadFile(
-      const base::FilePath& virtual_path,
+      const google_apis::EntryActionCallback& callback) OVERRIDE;
+  virtual google_apis::CancelCallback DownloadFile(
       const base::FilePath& local_cache_path,
-      const GURL& download_url,
-      const DownloadActionCallback& download_action_callback,
-      const GetContentCallback& get_content_callback,
-      const ProgressCallback& progress_callback) OVERRIDE;
-  virtual CancelCallback CopyResource(
+      const std::string& resource_id,
+      const google_apis::DownloadActionCallback& download_action_callback,
+      const google_apis::GetContentCallback& get_content_callback,
+      const google_apis::ProgressCallback& progress_callback) OVERRIDE;
+  virtual google_apis::CancelCallback CopyResource(
       const std::string& resource_id,
       const std::string& parent_resource_id,
       const std::string& new_name,
-      const GetResourceEntryCallback& callback) OVERRIDE;
-  virtual CancelCallback CopyHostedDocument(
+      const google_apis::GetResourceEntryCallback& callback) OVERRIDE;
+  virtual google_apis::CancelCallback CopyHostedDocument(
       const std::string& resource_id,
       const std::string& new_name,
-      const GetResourceEntryCallback& callback) OVERRIDE;
-  virtual CancelCallback RenameResource(
+      const google_apis::GetResourceEntryCallback& callback) OVERRIDE;
+  virtual google_apis::CancelCallback RenameResource(
       const std::string& resource_id,
       const std::string& new_name,
-      const EntryActionCallback& callback) OVERRIDE;
-  virtual CancelCallback TouchResource(
+      const google_apis::EntryActionCallback& callback) OVERRIDE;
+  virtual google_apis::CancelCallback TouchResource(
       const std::string& resource_id,
       const base::Time& modified_date,
       const base::Time& last_viewed_by_me_date,
-      const GetResourceEntryCallback& callback) OVERRIDE;
-  virtual CancelCallback AddResourceToDirectory(
+      const google_apis::GetResourceEntryCallback& callback) OVERRIDE;
+  virtual google_apis::CancelCallback AddResourceToDirectory(
       const std::string& parent_resource_id,
       const std::string& resource_id,
-      const EntryActionCallback& callback) OVERRIDE;
-  virtual CancelCallback RemoveResourceFromDirectory(
+      const google_apis::EntryActionCallback& callback) OVERRIDE;
+  virtual google_apis::CancelCallback RemoveResourceFromDirectory(
       const std::string& parent_resource_id,
       const std::string& resource_id,
-      const EntryActionCallback& callback) OVERRIDE;
-  virtual CancelCallback AddNewDirectory(
+      const google_apis::EntryActionCallback& callback) OVERRIDE;
+  virtual google_apis::CancelCallback AddNewDirectory(
       const std::string& parent_resource_id,
       const std::string& directory_name,
-      const GetResourceEntryCallback& callback) OVERRIDE;
-  virtual CancelCallback InitiateUploadNewFile(
-      const base::FilePath& drive_file_path,
+      const google_apis::GetResourceEntryCallback& callback) OVERRIDE;
+  virtual google_apis::CancelCallback InitiateUploadNewFile(
       const std::string& content_type,
       int64 content_length,
       const std::string& parent_resource_id,
       const std::string& title,
-      const InitiateUploadCallback& callback) OVERRIDE;
-  virtual CancelCallback InitiateUploadExistingFile(
-      const base::FilePath& drive_file_path,
+      const google_apis::InitiateUploadCallback& callback) OVERRIDE;
+  virtual google_apis::CancelCallback InitiateUploadExistingFile(
       const std::string& content_type,
       int64 content_length,
       const std::string& resource_id,
       const std::string& etag,
-      const InitiateUploadCallback& callback) OVERRIDE;
-  virtual CancelCallback ResumeUpload(
-      const base::FilePath& drive_file_path,
+      const google_apis::InitiateUploadCallback& callback) OVERRIDE;
+  virtual google_apis::CancelCallback ResumeUpload(
       const GURL& upload_url,
       int64 start_position,
       int64 end_position,
       int64 content_length,
       const std::string& content_type,
       const base::FilePath& local_file_path,
-      const UploadRangeCallback& callback,
-      const ProgressCallback& progress_callback) OVERRIDE;
-  virtual CancelCallback GetUploadStatus(
-      const base::FilePath& drive_file_path,
+      const google_apis::UploadRangeCallback& callback,
+      const google_apis::ProgressCallback& progress_callback) OVERRIDE;
+  virtual google_apis::CancelCallback GetUploadStatus(
       const GURL& upload_url,
       int64 content_length,
-      const UploadRangeCallback& callback) OVERRIDE;
-  virtual CancelCallback AuthorizeApp(
+      const google_apis::UploadRangeCallback& callback) OVERRIDE;
+  virtual google_apis::CancelCallback AuthorizeApp(
       const std::string& resource_id,
       const std::string& app_id,
-      const AuthorizeAppCallback& callback) OVERRIDE;
+      const google_apis::AuthorizeAppCallback& callback) OVERRIDE;
 };
 
-}  // namespace google_apis
+}  // namespace drive
 
 #endif  // CHROME_BROWSER_DRIVE_DUMMY_DRIVE_SERVICE_H_
diff --git a/chrome/browser/drive/event_logger.cc b/chrome/browser/drive/event_logger.cc
new file mode 100644
index 0000000..630a6be
--- /dev/null
+++ b/chrome/browser/drive/event_logger.cc
@@ -0,0 +1,54 @@
+// 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/drive/event_logger.h"
+
+#include "base/strings/stringprintf.h"
+
+namespace drive {
+
+EventLogger::Event::Event(int id, const std::string& what)
+    : id(id),
+      when(base::Time::Now()),
+      what(what) {
+}
+
+EventLogger::EventLogger()
+    : history_size_(kDefaultHistorySize),
+      next_event_id_(0) {
+}
+
+EventLogger::~EventLogger() {
+}
+
+void EventLogger::Log(const char* format, ...) {
+  std::string what;
+
+  va_list args;
+  va_start(args, format);
+  base::StringAppendV(&what, format, args);
+  va_end(args);
+
+  base::AutoLock auto_lock(lock_);
+  history_.push_back(Event(next_event_id_, what));
+  ++next_event_id_;
+  if (history_.size() > history_size_)
+    history_.pop_front();
+}
+
+void EventLogger::SetHistorySize(size_t history_size) {
+  base::AutoLock auto_lock(lock_);
+  history_.clear();
+  history_size_ = history_size;
+}
+
+std::vector<EventLogger::Event> EventLogger::GetHistory() {
+  base::AutoLock auto_lock(lock_);
+  std::vector<Event> output;
+  output.assign(history_.begin(), history_.end());
+  return output;
+}
+
+
+}  // namespace drive
diff --git a/chrome/browser/drive/event_logger.h b/chrome/browser/drive/event_logger.h
new file mode 100644
index 0000000..95a10e6
--- /dev/null
+++ b/chrome/browser/drive/event_logger.h
@@ -0,0 +1,65 @@
+// 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_DRIVE_EVENT_LOGGER_H_
+#define CHROME_BROWSER_DRIVE_EVENT_LOGGER_H_
+
+#include <stdarg.h>   // va_list
+#include <deque>
+#include <string>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/synchronization/lock.h"
+#include "base/time/time.h"
+
+namespace drive {
+
+// The default history size used by EventLogger.
+const int kDefaultHistorySize = 1000;
+
+// EventLogger is used to collect and expose text messages for diagnosing
+// behaviors of Google APIs stuff. For instance, the collected messages are
+// exposed to chrome:drive-internals.
+class EventLogger {
+ public:
+  // Represents a single event log.
+  struct Event {
+    Event(int id, const std::string& what);
+    int id;  // Monotonically increasing ID starting from 0.
+    base::Time when;  // When the event occurred.
+    std::string what;  // What happened.
+  };
+
+  // Creates an event logger that keeps the latest kDefaultHistorySize events.
+  EventLogger();
+  ~EventLogger();
+
+  // Logs a message using printf format.
+  // Can be called from any thread as long as the object is alive.
+  // Note that PRINTF_FORMAT should be (2, 3) instead of (1, 2) as this is a
+  // C++ member function.
+  void Log(const char* format, ...) PRINTF_FORMAT(2, 3);
+
+  // Sets the history size. The existing history is cleared.
+  // Can be called from any thread as long as the object is alive.
+  void SetHistorySize(size_t history_size);
+
+  // Gets the list of latest events (the oldest event comes first).
+  // Can be called from any thread as long as the object is alive.
+  std::vector<Event> GetHistory();
+
+ private:
+  std::deque<Event> history_;  // guarded by lock_.
+  size_t history_size_;  // guarded by lock_.
+  int next_event_id_;  // guarded by lock_.
+  base::Lock lock_;
+
+  DISALLOW_COPY_AND_ASSIGN(EventLogger);
+};
+
+}  // namespace drive
+
+#endif  // CHROME_BROWSER_DRIVE_EVENT_LOGGER_H_
diff --git a/chrome/browser/drive/event_logger_unittest.cc b/chrome/browser/drive/event_logger_unittest.cc
new file mode 100644
index 0000000..c57078f
--- /dev/null
+++ b/chrome/browser/drive/event_logger_unittest.cc
@@ -0,0 +1,43 @@
+// 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/drive/event_logger.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace drive {
+
+TEST(EventLoggerTest, BasicLogging) {
+  EventLogger logger;
+  logger.SetHistorySize(3);  // At most 3 events are kept.
+  EXPECT_EQ(0U, logger.GetHistory().size());
+
+  logger.Log("first");
+  logger.Log("%dnd", 2);
+  logger.Log("third");
+
+  // Events are recorded in the chronological order with sequential IDs.
+  std::vector<EventLogger::Event> history = logger.GetHistory();
+  ASSERT_EQ(3U, history.size());
+  EXPECT_EQ(0, history[0].id);
+  EXPECT_EQ("first", history[0].what);
+  EXPECT_EQ(1, history[1].id);
+  EXPECT_EQ("2nd", history[1].what);
+  EXPECT_EQ(2, history[2].id);
+  EXPECT_EQ("third", history[2].what);
+
+  logger.Log("fourth");
+  // It does not log events beyond the specified.
+  history = logger.GetHistory();
+  ASSERT_EQ(3U, history.size());
+  // The oldest events is pushed out.
+  EXPECT_EQ(1, history[0].id);
+  EXPECT_EQ("2nd", history[0].what);
+  EXPECT_EQ(2, history[1].id);
+  EXPECT_EQ("third", history[1].what);
+  EXPECT_EQ(3, history[2].id);
+  EXPECT_EQ("fourth", history[2].what);
+}
+
+}   // namespace drive
diff --git a/chrome/browser/drive/fake_drive_service.cc b/chrome/browser/drive/fake_drive_service.cc
index 8fec2c8..28899cf 100644
--- a/chrome/browser/drive/fake_drive_service.cc
+++ b/chrome/browser/drive/fake_drive_service.cc
@@ -6,7 +6,9 @@
 
 #include <string>
 
+#include "base/file_util.h"
 #include "base/logging.h"
+#include "base/md5.h"
 #include "base/message_loop.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
@@ -23,8 +25,39 @@
 #include "net/base/url_util.h"
 
 using content::BrowserThread;
+using google_apis::AboutResource;
+using google_apis::AccountMetadata;
+using google_apis::AppList;
+using google_apis::AuthorizeAppCallback;
+using google_apis::CancelCallback;
+using google_apis::DownloadActionCallback;
+using google_apis::EntryActionCallback;
+using google_apis::GDataErrorCode;
+using google_apis::GDATA_FILE_ERROR;
+using google_apis::GDATA_NO_CONNECTION;
+using google_apis::GDATA_OTHER_ERROR;
+using google_apis::GetAboutResourceCallback;
+using google_apis::GetAppListCallback;
+using google_apis::GetContentCallback;
+using google_apis::GetResourceEntryCallback;
+using google_apis::GetResourceListCallback;
+using google_apis::HTTP_BAD_REQUEST;
+using google_apis::HTTP_CREATED;
+using google_apis::HTTP_NOT_FOUND;
+using google_apis::HTTP_PRECONDITION;
+using google_apis::HTTP_RESUME_INCOMPLETE;
+using google_apis::HTTP_SUCCESS;
+using google_apis::InitiateUploadCallback;
+using google_apis::Link;
+using google_apis::ProgressCallback;
+using google_apis::ResourceEntry;
+using google_apis::ResourceList;
+using google_apis::UploadRangeCallback;
+using google_apis::UploadRangeResponse;
+namespace test_util = google_apis::test_util;
+namespace util = google_apis::util;
 
-namespace google_apis {
+namespace drive {
 namespace {
 
 // Rel property of upload link in the entries dictionary value.
@@ -66,28 +99,6 @@
   return true;
 }
 
-// Gets the upload URL from the given entry. Returns an empty URL if not
-// found.
-GURL GetUploadUrl(const base::DictionaryValue& entry) {
-  std::string upload_url;
-  const base::ListValue* links = NULL;
-  if (entry.GetList("link", &links) && links) {
-    for (size_t link_index = 0;
-         link_index < links->GetSize();
-         ++link_index) {
-      const base::DictionaryValue* link = NULL;
-      std::string rel;
-      if (links->GetDictionary(link_index, &link) &&
-          link && link->GetString("rel", &rel) &&
-          rel == kUploadUrlRel &&
-          link->GetString("href", &upload_url)) {
-        break;
-      }
-    }
-  }
-  return GURL(upload_url);
-}
-
 // Returns |url| without query parameter.
 GURL RemoveQueryParameter(const GURL& url) {
   GURL::Replacements replacements;
@@ -95,11 +106,57 @@
   return url.ReplaceComponents(replacements);
 }
 
+void ScheduleUploadRangeCallback(const UploadRangeCallback& callback,
+                                 int64 start_position,
+                                 int64 end_position,
+                                 GDataErrorCode error,
+                                 scoped_ptr<ResourceEntry> entry) {
+  base::MessageLoop::current()->PostTask(
+      FROM_HERE,
+      base::Bind(callback,
+                 UploadRangeResponse(error,
+                                     start_position,
+                                     end_position),
+                 base::Passed(&entry)));
+}
+
 }  // namespace
 
+struct FakeDriveService::UploadSession {
+  std::string content_type;
+  int64 content_length;
+  std::string parent_resource_id;
+  std::string resource_id;
+  std::string etag;
+  std::string title;
+
+  int64 uploaded_size;
+
+  UploadSession()
+      : content_length(0),
+        uploaded_size(0) {}
+
+  UploadSession(
+      std::string content_type,
+      int64 content_length,
+      std::string parent_resource_id,
+      std::string resource_id,
+      std::string etag,
+      std::string title)
+    : content_type(content_type),
+      content_length(content_length),
+      parent_resource_id(parent_resource_id),
+      resource_id(resource_id),
+      etag(etag),
+      title(title),
+      uploaded_size(0) {
+  }
+};
+
 FakeDriveService::FakeDriveService()
     : largest_changestamp_(0),
       published_date_seq_(0),
+      next_upload_sequence_number_(0),
       default_max_results_(0),
       resource_id_count_(0),
       resource_list_load_count_(0),
@@ -472,25 +529,29 @@
       if (entries->GetDictionary(i, &entry) &&
           entry->GetString("gd$resourceId.$t", &current_resource_id) &&
           resource_id == current_resource_id) {
-        entries->Remove(i, NULL);
+        GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
+        if (entry->HasKey("gd$deleted")) {
+          error = HTTP_NOT_FOUND;
+        } else {
+          entry->Set("gd$deleted", new DictionaryValue);
+          AddNewChangestampAndETag(entry);
+          error = HTTP_SUCCESS;
+        }
         base::MessageLoop::current()->PostTask(
-            FROM_HERE, base::Bind(callback, HTTP_SUCCESS));
+            FROM_HERE, base::Bind(callback, error));
         return CancelCallback();
       }
     }
   }
 
-  // TODO(satorux): Add support for returning "deleted" entries in
-  // changelists from GetResourceList().
   base::MessageLoop::current()->PostTask(
       FROM_HERE, base::Bind(callback, HTTP_NOT_FOUND));
   return CancelCallback();
 }
 
 CancelCallback FakeDriveService::DownloadFile(
-    const base::FilePath& virtual_path,
     const base::FilePath& local_cache_path,
-    const GURL& download_url,
+    const std::string& resource_id,
     const DownloadActionCallback& download_action_callback,
     const GetContentCallback& get_content_callback,
     const ProgressCallback& progress_callback) {
@@ -507,7 +568,7 @@
   }
 
   // The field content.src is the URL to download the file.
-  base::DictionaryValue* entry = FindEntryByContentUrl(download_url);
+  base::DictionaryValue* entry = FindEntryByResourceId(resource_id);
   if (!entry) {
     base::MessageLoopProxy::current()->PostTask(
         FROM_HERE,
@@ -518,7 +579,6 @@
   // Write "x"s of the file size specified in the entry.
   std::string file_size_string;
   entry->GetString("docs$size.$t", &file_size_string);
-  // TODO(satorux): To be correct, we should update docs$md5Checksum.$t here.
   int64 file_size = 0;
   if (base::StringToInt64(file_size_string, &file_size)) {
     base::BinaryValue* content_binary_data;
@@ -620,7 +680,7 @@
         link->SetString("href", GetFakeLinkUrl(parent_resource_id).spec());
         links->Append(link);
 
-        AddNewChangestamp(copied_entry.get());
+        AddNewChangestampAndETag(copied_entry.get());
 
         // Parse the new entry.
         scoped_ptr<ResourceEntry> resource_entry =
@@ -671,7 +731,7 @@
   base::DictionaryValue* entry = FindEntryByResourceId(resource_id);
   if (entry) {
     entry->SetString("title.$t", new_name);
-    AddNewChangestamp(entry);
+    AddNewChangestampAndETag(entry);
     base::MessageLoop::current()->PostTask(
         FROM_HERE, base::Bind(callback, HTTP_SUCCESS));
     return CancelCallback();
@@ -713,7 +773,7 @@
                    util::FormatTimeAsString(modified_date));
   entry->SetString("gd$lastViewed.$t",
                    util::FormatTimeAsString(last_viewed_by_me_date));
-  AddNewChangestamp(entry);
+  AddNewChangestampAndETag(entry);
 
   scoped_ptr<ResourceEntry> parsed_entry(ResourceEntry::CreateFrom(*entry));
   base::MessageLoop::current()->PostTask(
@@ -753,7 +813,7 @@
         "href", GetFakeLinkUrl(parent_resource_id).spec());
     links->Append(link);
 
-    AddNewChangestamp(entry);
+    AddNewChangestampAndETag(entry);
     base::MessageLoop::current()->PostTask(
         FROM_HERE, base::Bind(callback, HTTP_SUCCESS));
     return CancelCallback();
@@ -792,7 +852,7 @@
             rel == "http://schemas.google.com/docs/2007#parent" &&
             GURL(href) == parent_content_url) {
           links->Remove(i, NULL);
-          AddNewChangestamp(entry);
+          AddNewChangestampAndETag(entry);
           base::MessageLoop::current()->PostTask(
               FROM_HERE, base::Bind(callback, HTTP_SUCCESS));
           return CancelCallback();
@@ -846,7 +906,6 @@
 }
 
 CancelCallback FakeDriveService::InitiateUploadNewFile(
-    const base::FilePath& drive_file_path,
     const std::string& content_type,
     int64 content_length,
     const std::string& parent_resource_id,
@@ -862,32 +921,29 @@
     return CancelCallback();
   }
 
-  // Content length should be zero, as we'll create an empty file first. The
-  // content will be added in ResumeUpload().
-  const base::DictionaryValue* new_entry = AddNewEntry(content_type,
-                                                       "",  // content_data
-                                                       parent_resource_id,
-                                                       title,
-                                                       false,  // shared_with_me
-                                                       "file");
-  if (!new_entry) {
+  if (parent_resource_id != GetRootResourceId() &&
+      !FindEntryByResourceId(parent_resource_id)) {
     base::MessageLoop::current()->PostTask(
         FROM_HERE,
         base::Bind(callback, HTTP_NOT_FOUND, GURL()));
     return CancelCallback();
   }
-  const GURL upload_url = GetUploadUrl(*new_entry);
-  DCHECK(upload_url.is_valid());
+
+  GURL session_url = GetNewUploadSessionUrl();
+  upload_sessions_[session_url] =
+      UploadSession(content_type, content_length,
+                    parent_resource_id,
+                    "",  // resource_id
+                    "",  // etag
+                    title);
 
   base::MessageLoop::current()->PostTask(
       FROM_HERE,
-      base::Bind(callback, HTTP_SUCCESS,
-                 net::AppendQueryParameter(upload_url, "mode", "newfile")));
+      base::Bind(callback, HTTP_SUCCESS, session_url));
   return CancelCallback();
 }
 
 CancelCallback FakeDriveService::InitiateUploadExistingFile(
-    const base::FilePath& drive_file_path,
     const std::string& content_type,
     int64 content_length,
     const std::string& resource_id,
@@ -919,20 +975,22 @@
         base::Bind(callback, HTTP_PRECONDITION, GURL()));
     return CancelCallback();
   }
-  entry->SetString("docs$size.$t", "0");
 
-  const GURL upload_url = GetUploadUrl(*entry);
-  DCHECK(upload_url.is_valid());
+  GURL session_url = GetNewUploadSessionUrl();
+  upload_sessions_[session_url] =
+      UploadSession(content_type, content_length,
+                    "",  // parent_resource_id
+                    resource_id,
+                    entry_etag,
+                    "" /* title */);
 
   base::MessageLoop::current()->PostTask(
       FROM_HERE,
-      base::Bind(callback, HTTP_SUCCESS,
-                 net::AppendQueryParameter(upload_url, "mode", "existing")));
+      base::Bind(callback, HTTP_SUCCESS, session_url));
   return CancelCallback();
 }
 
 CancelCallback FakeDriveService::GetUploadStatus(
-    const base::FilePath& drive_file_path,
     const GURL& upload_url,
     int64 content_length,
     const UploadRangeCallback& callback) {
@@ -942,7 +1000,6 @@
 }
 
 CancelCallback FakeDriveService::ResumeUpload(
-      const base::FilePath& drive_file_path,
       const GURL& upload_url,
       int64 start_position,
       int64 end_position,
@@ -954,51 +1011,29 @@
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   DCHECK(!callback.is_null());
 
-  scoped_ptr<ResourceEntry> result_entry;
+  GetResourceEntryCallback completion_callback
+      = base::Bind(&ScheduleUploadRangeCallback,
+                   callback, start_position, end_position);
 
   if (offline_) {
-    base::MessageLoop::current()->PostTask(
-        FROM_HERE,
-        base::Bind(callback,
-                   UploadRangeResponse(GDATA_NO_CONNECTION,
-                                       start_position,
-                                       end_position),
-                   base::Passed(&result_entry)));
+    completion_callback.Run(GDATA_NO_CONNECTION, scoped_ptr<ResourceEntry>());
     return CancelCallback();
   }
 
-  DictionaryValue* entry = NULL;
-  entry = FindEntryByUploadUrl(RemoveQueryParameter(upload_url));
-  if (!entry) {
-    base::MessageLoop::current()->PostTask(
-        FROM_HERE,
-        base::Bind(callback,
-                   UploadRangeResponse(HTTP_NOT_FOUND,
-                                       start_position,
-                                       end_position),
-                   base::Passed(&result_entry)));
+  if (!upload_sessions_.count(upload_url)) {
+    completion_callback.Run(HTTP_NOT_FOUND, scoped_ptr<ResourceEntry>());
     return CancelCallback();
   }
 
+  UploadSession* session = &upload_sessions_[upload_url];
+
   // Chunks are required to be sent in such a ways that they fill from the start
   // of the not-yet-uploaded part with no gaps nor overlaps.
-  std::string current_size_string;
-  int64 current_size;
-  if (!entry->GetString("docs$size.$t", &current_size_string) ||
-      !base::StringToInt64(current_size_string, &current_size) ||
-      current_size != start_position) {
-    base::MessageLoop::current()->PostTask(
-        FROM_HERE,
-        base::Bind(callback,
-                   UploadRangeResponse(HTTP_BAD_REQUEST,
-                                       start_position,
-                                       end_position),
-                   base::Passed(&result_entry)));
+  if (session->uploaded_size != start_position) {
+    completion_callback.Run(HTTP_BAD_REQUEST, scoped_ptr<ResourceEntry>());
     return CancelCallback();
   }
 
-  entry->SetString("docs$size.$t", base::Int64ToString(end_position));
-
   if (!progress_callback.is_null()) {
     // In the real GDataWapi/Drive DriveService, progress is reported in
     // nondeterministic timing. In this fake implementation, we choose to call
@@ -1014,35 +1049,62 @@
   }
 
   if (content_length != end_position) {
-    base::MessageLoop::current()->PostTask(
-        FROM_HERE,
-        base::Bind(callback,
-                   UploadRangeResponse(HTTP_RESUME_INCOMPLETE,
-                                       start_position,
-                                       end_position),
-                    base::Passed(&result_entry)));
+    session->uploaded_size = end_position;
+    completion_callback.Run(HTTP_RESUME_INCOMPLETE,
+                            scoped_ptr<ResourceEntry>());
     return CancelCallback();
   }
 
-  AddNewChangestamp(entry);
-  result_entry = ResourceEntry::CreateFrom(*entry).Pass();
+  std::string content_data;
+  if (!file_util::ReadFileToString(local_file_path, &content_data)) {
+    session->uploaded_size = end_position;
+    completion_callback.Run(GDATA_FILE_ERROR, scoped_ptr<ResourceEntry>());
+    return CancelCallback();
+  }
+  session->uploaded_size = end_position;
 
-  std::string upload_mode;
-  bool upload_mode_found =
-      net::GetValueForKeyInQuery(upload_url, "mode", &upload_mode);
-  DCHECK(upload_mode_found &&
-         (upload_mode == "newfile" || upload_mode == "existing"));
+  // |resource_id| is empty if the upload is for new file.
+  if (session->resource_id.empty()) {
+    DCHECK(!session->parent_resource_id.empty());
+    DCHECK(!session->title.empty());
+    const DictionaryValue* new_entry = AddNewEntry(
+        session->content_type,
+        content_data,
+        session->parent_resource_id,
+        session->title,
+        false,  // shared_with_me
+        "file");
+    if (!new_entry) {
+      completion_callback.Run(HTTP_NOT_FOUND, scoped_ptr<ResourceEntry>());
+      return CancelCallback();
+    }
 
-  GDataErrorCode return_code =
-      upload_mode == "newfile" ? HTTP_CREATED : HTTP_SUCCESS;
+    completion_callback.Run(HTTP_CREATED,
+                            ResourceEntry::CreateFrom(*new_entry));
+    return CancelCallback();
+  }
 
-  base::MessageLoop::current()->PostTask(
-      FROM_HERE,
-      base::Bind(callback,
-                 UploadRangeResponse(return_code,
-                                     start_position,
-                                     end_position),
-                 base::Passed(&result_entry)));
+  DictionaryValue* entry = FindEntryByResourceId(session->resource_id);
+  if (!entry) {
+    completion_callback.Run(HTTP_NOT_FOUND, scoped_ptr<ResourceEntry>());
+    return CancelCallback();
+  }
+
+  std::string entry_etag;
+  entry->GetString("gd$etag", &entry_etag);
+  if (entry_etag.empty() || session->etag != entry_etag) {
+    completion_callback.Run(HTTP_PRECONDITION, scoped_ptr<ResourceEntry>());
+    return CancelCallback();
+  }
+
+  entry->SetString("docs$md5Checksum.$t", base::MD5String(content_data));
+  entry->Set("test$data",
+             base::BinaryValue::CreateWithCopiedBuffer(
+                 content_data.data(), content_data.size()));
+  entry->SetString("docs$size.$t", base::Int64ToString(end_position));
+  AddNewChangestampAndETag(entry);
+
+  completion_callback.Run(HTTP_SUCCESS, ResourceEntry::CreateFrom(*entry));
   return CancelCallback();
 }
 
@@ -1184,40 +1246,6 @@
   return NULL;
 }
 
-base::DictionaryValue* FakeDriveService::FindEntryByUploadUrl(
-    const GURL& upload_url) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
-  base::ListValue* entries = NULL;
-  // Go through entries and return the one that matches |upload_url|.
-  if (resource_list_value_->GetList("entry", &entries)) {
-    for (size_t i = 0; i < entries->GetSize(); ++i) {
-      base::DictionaryValue* entry = NULL;
-      base::ListValue* links = NULL;
-      if (entries->GetDictionary(i, &entry) &&
-          entry->GetList("link", &links) &&
-          links) {
-        for (size_t link_index = 0;
-            link_index < links->GetSize();
-            ++link_index) {
-          base::DictionaryValue* link = NULL;
-          std::string rel;
-          std::string found_upload_url;
-          if (links->GetDictionary(link_index, &link) &&
-              link && link->GetString("rel", &rel) &&
-              rel == kUploadUrlRel &&
-              link->GetString("href", &found_upload_url) &&
-              GURL(found_upload_url) == upload_url) {
-            return entry;
-          }
-        }
-      }
-    }
-  }
-
-  return NULL;
-}
-
 std::string FakeDriveService::GetNewResourceId() {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
 
@@ -1225,10 +1253,12 @@
   return base::StringPrintf("resource_id_%d", resource_id_count_);
 }
 
-void FakeDriveService::AddNewChangestamp(base::DictionaryValue* entry) {
+void FakeDriveService::AddNewChangestampAndETag(base::DictionaryValue* entry) {
   ++largest_changestamp_;
   entry->SetString("docs$changestamp.value",
                    base::Int64ToString(largest_changestamp_));
+  entry->SetString("gd$etag",
+                   "etag_" + base::Int64ToString(largest_changestamp_));
 }
 
 const base::DictionaryValue* FakeDriveService::AddNewEntry(
@@ -1260,9 +1290,8 @@
             content_data.c_str(), content_data.size()));
     new_entry->SetString("docs$size.$t",
                          base::Int64ToString(content_data.size()));
-    // TODO(satorux): Set the correct MD5 here.
     new_entry->SetString("docs$md5Checksum.$t",
-                         "3b4385ebefec6e743574c76bbd0575de");
+                         base::MD5String(content_data));
   }
 
   // Add "category" which sets the resource type to |entry_kind|.
@@ -1311,7 +1340,7 @@
   links->Append(upload_link);
   new_entry->Set("link", links);
 
-  AddNewChangestamp(new_entry.get());
+  AddNewChangestampAndETag(new_entry.get());
 
   base::Time published_date =
       base::Time() + base::TimeDelta::FromMilliseconds(++published_date_seq_);
@@ -1390,6 +1419,11 @@
     if (start_changestamp > 0 && entry->changestamp() < start_changestamp)
       should_exclude = true;
 
+    // If the caller requests other list than change list by specifying
+    // zero-|start_changestamp|, exclude deleted entry from the result.
+    if (!start_changestamp && entry->deleted())
+      should_exclude = true;
+
     // The entry matched the criteria for inclusion.
     if (!should_exclude)
       ++num_entries_matched;
@@ -1447,4 +1481,9 @@
                  base::Passed(&resource_list)));
 }
 
-}  // namespace google_apis
+GURL FakeDriveService::GetNewUploadSessionUrl() {
+  return GURL("https://upload_session_url/" +
+              base::Int64ToString(next_upload_sequence_number_++));
+}
+
+}  // namespace drive
diff --git a/chrome/browser/drive/fake_drive_service.h b/chrome/browser/drive/fake_drive_service.h
index f677c7d..9b59e0c 100644
--- a/chrome/browser/drive/fake_drive_service.h
+++ b/chrome/browser/drive/fake_drive_service.h
@@ -9,7 +9,7 @@
 #include "base/values.h"
 #include "chrome/browser/drive/drive_service_interface.h"
 
-namespace google_apis {
+namespace drive {
 
 // This class implements a fake DriveService which acts like a real Drive
 // service. The fake service works as follows:
@@ -88,109 +88,104 @@
   virtual bool HasRefreshToken() const OVERRIDE;
   virtual void ClearAccessToken() OVERRIDE;
   virtual void ClearRefreshToken() OVERRIDE;
-  virtual CancelCallback GetAllResourceList(
-      const GetResourceListCallback& callback) OVERRIDE;
-  virtual CancelCallback GetResourceListInDirectory(
+  virtual google_apis::CancelCallback GetAllResourceList(
+      const google_apis::GetResourceListCallback& callback) OVERRIDE;
+  virtual google_apis::CancelCallback GetResourceListInDirectory(
       const std::string& directory_resource_id,
-      const GetResourceListCallback& callback) OVERRIDE;
+      const google_apis::GetResourceListCallback& callback) OVERRIDE;
   // See the comment for EntryMatchWidthQuery() in .cc file for details about
   // the supported search query types.
-  virtual CancelCallback Search(
+  virtual google_apis::CancelCallback Search(
       const std::string& search_query,
-      const GetResourceListCallback& callback) OVERRIDE;
-  virtual CancelCallback SearchByTitle(
+      const google_apis::GetResourceListCallback& callback) OVERRIDE;
+  virtual google_apis::CancelCallback SearchByTitle(
       const std::string& title,
       const std::string& directory_resource_id,
-      const GetResourceListCallback& callback) OVERRIDE;
-  virtual CancelCallback GetChangeList(
+      const google_apis::GetResourceListCallback& callback) OVERRIDE;
+  virtual google_apis::CancelCallback GetChangeList(
       int64 start_changestamp,
-      const GetResourceListCallback& callback) OVERRIDE;
-  virtual CancelCallback ContinueGetResourceList(
+      const google_apis::GetResourceListCallback& callback) OVERRIDE;
+  virtual google_apis::CancelCallback ContinueGetResourceList(
       const GURL& override_url,
-      const GetResourceListCallback& callback) OVERRIDE;
-  virtual CancelCallback GetResourceEntry(
+      const google_apis::GetResourceListCallback& callback) OVERRIDE;
+  virtual google_apis::CancelCallback GetResourceEntry(
       const std::string& resource_id,
-      const GetResourceEntryCallback& callback) OVERRIDE;
-  virtual CancelCallback GetAboutResource(
-      const GetAboutResourceCallback& callback) OVERRIDE;
-  virtual CancelCallback GetAppList(
-      const GetAppListCallback& callback) OVERRIDE;
-  virtual CancelCallback DeleteResource(
+      const google_apis::GetResourceEntryCallback& callback) OVERRIDE;
+  virtual google_apis::CancelCallback GetAboutResource(
+      const google_apis::GetAboutResourceCallback& callback) OVERRIDE;
+  virtual google_apis::CancelCallback GetAppList(
+      const google_apis::GetAppListCallback& callback) OVERRIDE;
+  virtual google_apis::CancelCallback DeleteResource(
       const std::string& resource_id,
       const std::string& etag,
-      const EntryActionCallback& callback) OVERRIDE;
-  virtual CancelCallback DownloadFile(
-      const base::FilePath& virtual_path,
+      const google_apis::EntryActionCallback& callback) OVERRIDE;
+  virtual google_apis::CancelCallback DownloadFile(
       const base::FilePath& local_cache_path,
-      const GURL& download_url,
-      const DownloadActionCallback& download_action_callback,
-      const GetContentCallback& get_content_callback,
-      const ProgressCallback& progress_callback) OVERRIDE;
-  virtual CancelCallback CopyResource(
+      const std::string& resource_id,
+      const google_apis::DownloadActionCallback& download_action_callback,
+      const google_apis::GetContentCallback& get_content_callback,
+      const google_apis::ProgressCallback& progress_callback) OVERRIDE;
+  virtual google_apis::CancelCallback CopyResource(
       const std::string& resource_id,
       const std::string& parent_resource_id,
       const std::string& new_name,
-      const GetResourceEntryCallback& callback) OVERRIDE;
+      const google_apis::GetResourceEntryCallback& callback) OVERRIDE;
   // The new resource ID for the copied document will look like
   // |resource_id| + "_copied".
-  virtual CancelCallback CopyHostedDocument(
+  virtual google_apis::CancelCallback CopyHostedDocument(
       const std::string& resource_id,
       const std::string& new_name,
-      const GetResourceEntryCallback& callback) OVERRIDE;
-  virtual CancelCallback RenameResource(
+      const google_apis::GetResourceEntryCallback& callback) OVERRIDE;
+  virtual google_apis::CancelCallback RenameResource(
       const std::string& resource_id,
       const std::string& new_name,
-      const EntryActionCallback& callback) OVERRIDE;
-  virtual CancelCallback TouchResource(
+      const google_apis::EntryActionCallback& callback) OVERRIDE;
+  virtual google_apis::CancelCallback TouchResource(
       const std::string& resource_id,
       const base::Time& modified_date,
       const base::Time& last_viewed_by_me_date,
-      const GetResourceEntryCallback& callback) OVERRIDE;
-  virtual CancelCallback AddResourceToDirectory(
+      const google_apis::GetResourceEntryCallback& callback) OVERRIDE;
+  virtual google_apis::CancelCallback AddResourceToDirectory(
       const std::string& parent_resource_id,
       const std::string& resource_id,
-      const EntryActionCallback& callback) OVERRIDE;
-  virtual CancelCallback RemoveResourceFromDirectory(
+      const google_apis::EntryActionCallback& callback) OVERRIDE;
+  virtual google_apis::CancelCallback RemoveResourceFromDirectory(
       const std::string& parent_resource_id,
       const std::string& resource_id,
-      const EntryActionCallback& callback) OVERRIDE;
-  virtual CancelCallback AddNewDirectory(
+      const google_apis::EntryActionCallback& callback) OVERRIDE;
+  virtual google_apis::CancelCallback AddNewDirectory(
       const std::string& parent_resource_id,
       const std::string& directory_name,
-      const GetResourceEntryCallback& callback) OVERRIDE;
-  virtual CancelCallback InitiateUploadNewFile(
-      const base::FilePath& drive_file_path,
+      const google_apis::GetResourceEntryCallback& callback) OVERRIDE;
+  virtual google_apis::CancelCallback InitiateUploadNewFile(
       const std::string& content_type,
       int64 content_length,
       const std::string& parent_resource_id,
       const std::string& title,
-      const InitiateUploadCallback& callback) OVERRIDE;
-  virtual CancelCallback InitiateUploadExistingFile(
-      const base::FilePath& drive_file_path,
+      const google_apis::InitiateUploadCallback& callback) OVERRIDE;
+  virtual google_apis::CancelCallback InitiateUploadExistingFile(
       const std::string& content_type,
       int64 content_length,
       const std::string& resource_id,
       const std::string& etag,
-      const InitiateUploadCallback& callback) OVERRIDE;
-  virtual CancelCallback ResumeUpload(
-      const base::FilePath& drive_file_path,
+      const google_apis::InitiateUploadCallback& callback) OVERRIDE;
+  virtual google_apis::CancelCallback ResumeUpload(
       const GURL& upload_url,
       int64 start_position,
       int64 end_position,
       int64 content_length,
       const std::string& content_type,
       const base::FilePath& local_file_path,
-      const UploadRangeCallback& callback,
-      const ProgressCallback& progress_callback) OVERRIDE;
-  virtual CancelCallback GetUploadStatus(
-      const base::FilePath& drive_file_path,
+      const google_apis::UploadRangeCallback& callback,
+      const google_apis::ProgressCallback& progress_callback) OVERRIDE;
+  virtual google_apis::CancelCallback GetUploadStatus(
       const GURL& upload_url,
       int64 content_length,
-      const UploadRangeCallback& callback) OVERRIDE;
-  virtual CancelCallback AuthorizeApp(
+      const google_apis::UploadRangeCallback& callback) OVERRIDE;
+  virtual google_apis::CancelCallback AuthorizeApp(
       const std::string& resource_id,
       const std::string& app_id,
-      const AuthorizeAppCallback& callback) OVERRIDE;
+      const google_apis::AuthorizeAppCallback& callback) OVERRIDE;
 
   // Adds a new file with the given parameters. On success, returns
   // HTTP_CREATED with the parsed entry.
@@ -200,15 +195,19 @@
                   const std::string& parent_resource_id,
                   const std::string& title,
                   bool shared_with_me,
-                  const GetResourceEntryCallback& callback);
+                  const google_apis::GetResourceEntryCallback& callback);
 
   // Sets the last modified time for an entry specified by |resource_id|.
   // On success, returns HTTP_SUCCESS with the parsed entry.
   // |callback| must not be null.
-  void SetLastModifiedTime(const std::string& resource_id,
-                           const base::Time& last_modified_time,
-                           const GetResourceEntryCallback& callback);
+  void SetLastModifiedTime(
+      const std::string& resource_id,
+      const base::Time& last_modified_time,
+      const google_apis::GetResourceEntryCallback& callback);
+
  private:
+  struct UploadSession;
+
   // Returns a pointer to the entry that matches |resource_id|, or NULL if
   // not found.
   base::DictionaryValue* FindEntryByResourceId(const std::string& resource_id);
@@ -217,17 +216,13 @@
   // not found.
   base::DictionaryValue* FindEntryByContentUrl(const GURL& content_url);
 
-  // Returns a pointer to the entry that matches |upload_url|, or NULL if
-  // not found.
-  base::DictionaryValue* FindEntryByUploadUrl(const GURL& upload_url);
-
   // Returns a new resource ID, which looks like "resource_id_<num>" where
   // <num> is a monotonically increasing number starting from 1.
   std::string GetNewResourceId();
 
-  // Increments |largest_changestamp_| and adds the new changestamp to
+  // Increments |largest_changestamp_| and adds the new changestamp and ETag to
   // |entry|.
-  void AddNewChangestamp(base::DictionaryValue* entry);
+  void AddNewChangestampAndETag(base::DictionaryValue* entry);
 
   // Adds a new entry based on the given parameters. |entry_kind| should be
   // "file" or "folder". Returns a pointer to the newly added entry, or NULL
@@ -245,19 +240,25 @@
   // is between |start_offset| (inclusive) and |start_offset| + |max_results|
   // (exclusive).
   // Increments *load_counter by 1 before it returns successfully.
-  void GetResourceListInternal(int64 start_changestamp,
-                               const std::string& search_query,
-                               const std::string& directory_resource_id,
-                               int start_offset,
-                               int max_results,
-                               int* load_counter,
-                               const GetResourceListCallback& callback);
+  void GetResourceListInternal(
+      int64 start_changestamp,
+      const std::string& search_query,
+      const std::string& directory_resource_id,
+      int start_offset,
+      int max_results,
+      int* load_counter,
+      const google_apis::GetResourceListCallback& callback);
+
+  // Returns new upload session URL.
+  GURL GetNewUploadSessionUrl();
 
   scoped_ptr<base::DictionaryValue> resource_list_value_;
   scoped_ptr<base::Value> account_metadata_value_;
   scoped_ptr<base::Value> app_info_value_;
+  std::map<GURL, UploadSession> upload_sessions_;
   int64 largest_changestamp_;
   int64 published_date_seq_;
+  int64 next_upload_sequence_number_;
   int default_max_results_;
   int resource_id_count_;
   int resource_list_load_count_;
@@ -270,6 +271,6 @@
   DISALLOW_COPY_AND_ASSIGN(FakeDriveService);
 };
 
-}  // namespace google_apis
+}  // namespace drive
 
 #endif  // CHROME_BROWSER_DRIVE_FAKE_DRIVE_SERVICE_H_
diff --git a/chrome/browser/drive/fake_drive_service_unittest.cc b/chrome/browser/drive/fake_drive_service_unittest.cc
index 20bd5bf..26334d5 100644
--- a/chrome/browser/drive/fake_drive_service_unittest.cc
+++ b/chrome/browser/drive/fake_drive_service_unittest.cc
@@ -9,6 +9,7 @@
 
 #include "base/file_util.h"
 #include "base/files/scoped_temp_dir.h"
+#include "base/md5.h"
 #include "base/run_loop.h"
 #include "base/stl_util.h"
 #include "base/strings/stringprintf.h"
@@ -20,7 +21,25 @@
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-namespace google_apis {
+using google_apis::AboutResource;
+using google_apis::AppList;
+using google_apis::GDataErrorCode;
+using google_apis::GDATA_NO_CONNECTION;
+using google_apis::GDATA_OTHER_ERROR;
+using google_apis::GetContentCallback;
+using google_apis::HTTP_CREATED;
+using google_apis::HTTP_NOT_FOUND;
+using google_apis::HTTP_PRECONDITION;
+using google_apis::HTTP_RESUME_INCOMPLETE;
+using google_apis::HTTP_SUCCESS;
+using google_apis::Link;
+using google_apis::ProgressCallback;
+using google_apis::ResourceEntry;
+using google_apis::ResourceList;
+using google_apis::UploadRangeResponse;
+namespace test_util = google_apis::test_util;
+
+namespace drive {
 
 namespace {
 
@@ -40,7 +59,7 @@
   // Returns true if the resource identified by |resource_id| exists.
   bool Exists(const std::string& resource_id) {
     scoped_ptr<ResourceEntry> resource_entry = FindEntry(resource_id);
-    return resource_entry;
+    return resource_entry && !resource_entry->deleted();
   }
 
   // Adds a new directory at |parent_resource_id| with the given name.
@@ -91,7 +110,7 @@
 
 TEST_F(FakeDriveServiceTest, GetAllResourceList) {
   ASSERT_TRUE(fake_service_.LoadResourceListForWapi(
-      "chromeos/gdata/root_feed.json"));
+      "gdata/root_feed.json"));
 
   GDataErrorCode error = GDATA_OTHER_ERROR;
   scoped_ptr<ResourceList> resource_list;
@@ -108,7 +127,7 @@
 
 TEST_F(FakeDriveServiceTest, GetAllResourceList_Offline) {
   ASSERT_TRUE(fake_service_.LoadResourceListForWapi(
-      "chromeos/gdata/root_feed.json"));
+      "gdata/root_feed.json"));
   fake_service_.set_offline(true);
 
   GDataErrorCode error = GDATA_OTHER_ERROR;
@@ -123,7 +142,7 @@
 
 TEST_F(FakeDriveServiceTest, GetResourceListInDirectory_InRootDirectory) {
   ASSERT_TRUE(fake_service_.LoadResourceListForWapi(
-      "chromeos/gdata/root_feed.json"));
+      "gdata/root_feed.json"));
 
   GDataErrorCode error = GDATA_OTHER_ERROR;
   scoped_ptr<ResourceList> resource_list;
@@ -141,7 +160,7 @@
 
 TEST_F(FakeDriveServiceTest, GetResourceListInDirectory_InNonRootDirectory) {
   ASSERT_TRUE(fake_service_.LoadResourceListForWapi(
-      "chromeos/gdata/root_feed.json"));
+      "gdata/root_feed.json"));
 
   GDataErrorCode error = GDATA_OTHER_ERROR;
   scoped_ptr<ResourceList> resource_list;
@@ -160,7 +179,7 @@
 
 TEST_F(FakeDriveServiceTest, GetResourceListInDirectory_Offline) {
   ASSERT_TRUE(fake_service_.LoadResourceListForWapi(
-      "chromeos/gdata/root_feed.json"));
+      "gdata/root_feed.json"));
   fake_service_.set_offline(true);
 
   GDataErrorCode error = GDATA_OTHER_ERROR;
@@ -176,7 +195,7 @@
 
 TEST_F(FakeDriveServiceTest, Search) {
   ASSERT_TRUE(fake_service_.LoadResourceListForWapi(
-      "chromeos/gdata/root_feed.json"));
+      "gdata/root_feed.json"));
 
   GDataErrorCode error = GDATA_OTHER_ERROR;
   scoped_ptr<ResourceList> resource_list;
@@ -194,7 +213,7 @@
 
 TEST_F(FakeDriveServiceTest, Search_WithAttribute) {
   ASSERT_TRUE(fake_service_.LoadResourceListForWapi(
-      "chromeos/gdata/root_feed.json"));
+      "gdata/root_feed.json"));
 
   GDataErrorCode error = GDATA_OTHER_ERROR;
   scoped_ptr<ResourceList> resource_list;
@@ -212,14 +231,14 @@
 
 TEST_F(FakeDriveServiceTest, Search_MultipleQueries) {
   ASSERT_TRUE(fake_service_.LoadResourceListForWapi(
-      "chromeos/gdata/root_feed.json"));
+      "gdata/root_feed.json"));
 
   GDataErrorCode error = GDATA_OTHER_ERROR;
   scoped_ptr<ResourceList> resource_list;
   fake_service_.Search(
       "Directory 1",  // search_query
       test_util::CreateCopyResultCallback(&error, &resource_list));
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(HTTP_SUCCESS, error);
   ASSERT_TRUE(resource_list);
@@ -229,7 +248,7 @@
   fake_service_.Search(
       "\"Directory 1\"",  // search_query
       test_util::CreateCopyResultCallback(&error, &resource_list));
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(HTTP_SUCCESS, error);
   ASSERT_TRUE(resource_list);
@@ -239,7 +258,7 @@
 
 TEST_F(FakeDriveServiceTest, Search_Offline) {
   ASSERT_TRUE(fake_service_.LoadResourceListForWapi(
-      "chromeos/gdata/root_feed.json"));
+      "gdata/root_feed.json"));
   fake_service_.set_offline(true);
 
   GDataErrorCode error = GDATA_OTHER_ERROR;
@@ -247,15 +266,40 @@
   fake_service_.Search(
       "Directory 1",  // search_query
       test_util::CreateCopyResultCallback(&error, &resource_list));
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(GDATA_NO_CONNECTION, error);
   EXPECT_FALSE(resource_list);
 }
 
+TEST_F(FakeDriveServiceTest, Search_Deleted) {
+  ASSERT_TRUE(fake_service_.LoadResourceListForWapi(
+      "gdata/root_feed.json"));
+
+  GDataErrorCode error = GDATA_OTHER_ERROR;
+  fake_service_.DeleteResource("file:2_file_resource_id",
+                               std::string(),  // etag
+                               test_util::CreateCopyResultCallback(&error));
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(HTTP_SUCCESS, error);
+
+  error = GDATA_OTHER_ERROR;
+  scoped_ptr<ResourceList> resource_list;
+  fake_service_.Search(
+      "File",  // search_query
+      test_util::CreateCopyResultCallback(&error, &resource_list));
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_EQ(HTTP_SUCCESS, error);
+  ASSERT_TRUE(resource_list);
+  // Do some sanity check. There are 4 entries that contain "File" in their
+  // titles and one of them is deleted.
+  EXPECT_EQ(3U, resource_list->entries().size());
+}
+
 TEST_F(FakeDriveServiceTest, SearchByTitle) {
   ASSERT_TRUE(fake_service_.LoadResourceListForWapi(
-      "chromeos/gdata/root_feed.json"));
+      "gdata/root_feed.json"));
 
   GDataErrorCode error = GDATA_OTHER_ERROR;
   scoped_ptr<ResourceList> resource_list;
@@ -263,7 +307,7 @@
       "1.txt",  // title
       fake_service_.GetRootResourceId(),  // directory_resource_id
       test_util::CreateCopyResultCallback(&error, &resource_list));
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(HTTP_SUCCESS, error);
   ASSERT_TRUE(resource_list);
@@ -274,7 +318,7 @@
 
 TEST_F(FakeDriveServiceTest, SearchByTitle_EmptyDirectoryResourceId) {
   ASSERT_TRUE(fake_service_.LoadResourceListForWapi(
-      "chromeos/gdata/root_feed.json"));
+      "gdata/root_feed.json"));
 
   GDataErrorCode error = GDATA_OTHER_ERROR;
   scoped_ptr<ResourceList> resource_list;
@@ -282,7 +326,7 @@
       "1.txt",  // title
       "",  // directory resource id
       test_util::CreateCopyResultCallback(&error, &resource_list));
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(HTTP_SUCCESS, error);
   ASSERT_TRUE(resource_list);
@@ -293,7 +337,7 @@
 
 TEST_F(FakeDriveServiceTest, SearchByTitle_Offline) {
   ASSERT_TRUE(fake_service_.LoadResourceListForWapi(
-      "chromeos/gdata/root_feed.json"));
+      "gdata/root_feed.json"));
   fake_service_.set_offline(true);
 
   GDataErrorCode error = GDATA_OTHER_ERROR;
@@ -302,7 +346,7 @@
       "Directory 1",  // title
       fake_service_.GetRootResourceId(),  // directory_resource_id
       test_util::CreateCopyResultCallback(&error, &resource_list));
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(GDATA_NO_CONNECTION, error);
   EXPECT_FALSE(resource_list);
@@ -310,18 +354,18 @@
 
 TEST_F(FakeDriveServiceTest, GetChangeList_NoNewEntries) {
   ASSERT_TRUE(fake_service_.LoadResourceListForWapi(
-      "chromeos/gdata/root_feed.json"));
+      "gdata/root_feed.json"));
   // Load the account_metadata.json as well to add the largest changestamp
   // (654321) to the existing entries.
   ASSERT_TRUE(fake_service_.LoadAccountMetadataForWapi(
-      "chromeos/gdata/account_metadata.json"));
+      "gdata/account_metadata.json"));
 
   GDataErrorCode error = GDATA_OTHER_ERROR;
   scoped_ptr<ResourceList> resource_list;
   fake_service_.GetChangeList(
       654321 + 1,  // start_changestamp
       test_util::CreateCopyResultCallback(&error, &resource_list));
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(HTTP_SUCCESS, error);
   ASSERT_TRUE(resource_list);
@@ -334,11 +378,11 @@
 
 TEST_F(FakeDriveServiceTest, GetChangeList_WithNewEntry) {
   ASSERT_TRUE(fake_service_.LoadResourceListForWapi(
-      "chromeos/gdata/root_feed.json"));
+      "gdata/root_feed.json"));
   // Load the account_metadata.json as well to add the largest changestamp
   // (654321) to the existing entries.
   ASSERT_TRUE(fake_service_.LoadAccountMetadataForWapi(
-      "chromeos/gdata/account_metadata.json"));
+      "gdata/account_metadata.json"));
   // Add a new directory in the root directory. The new directory will have
   // the changestamp of 654322.
   ASSERT_TRUE(AddNewDirectory(
@@ -350,7 +394,7 @@
   fake_service_.GetChangeList(
       654321 + 1,  // start_changestamp
       test_util::CreateCopyResultCallback(&error, &resource_list));
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(HTTP_SUCCESS, error);
   ASSERT_TRUE(resource_list);
@@ -362,7 +406,7 @@
 
 TEST_F(FakeDriveServiceTest, GetChangeList_Offline) {
   ASSERT_TRUE(fake_service_.LoadResourceListForWapi(
-      "chromeos/gdata/root_feed.json"));
+      "gdata/root_feed.json"));
   fake_service_.set_offline(true);
 
   GDataErrorCode error = GDATA_OTHER_ERROR;
@@ -370,22 +414,59 @@
   fake_service_.GetChangeList(
       654321,  // start_changestamp
       test_util::CreateCopyResultCallback(&error, &resource_list));
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(GDATA_NO_CONNECTION, error);
   EXPECT_FALSE(resource_list);
 }
 
+TEST_F(FakeDriveServiceTest, GetChangeList_DeletedEntry) {
+  ASSERT_TRUE(fake_service_.LoadResourceListForWapi(
+      "gdata/root_feed.json"));
+  // Load the account_metadata.json as well to add the largest changestamp
+  // (654321) to the existing entries.
+  ASSERT_TRUE(fake_service_.LoadAccountMetadataForWapi(
+      "gdata/account_metadata.json"));
+  // Add a new directory in the root directory. The new directory will have
+  // the changestamp of 654322.
+  ASSERT_TRUE(Exists("file:2_file_resource_id"));
+
+  GDataErrorCode error = GDATA_OTHER_ERROR;
+  fake_service_.DeleteResource("file:2_file_resource_id",
+                               std::string(),  // etag
+                               test_util::CreateCopyResultCallback(&error));
+  base::RunLoop().RunUntilIdle();
+  ASSERT_EQ(HTTP_SUCCESS, error);
+  ASSERT_FALSE(Exists("file:2_file_resource_id"));
+
+  // Get the resource list newer than 654321.
+  error = GDATA_OTHER_ERROR;
+  scoped_ptr<ResourceList> resource_list;
+  fake_service_.GetChangeList(
+      654321 + 1,  // start_changestamp
+      test_util::CreateCopyResultCallback(&error, &resource_list));
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_EQ(HTTP_SUCCESS, error);
+  ASSERT_TRUE(resource_list);
+  // The result should only contain the newly created directory.
+  ASSERT_EQ(1U, resource_list->entries().size());
+  const ResourceEntry& entry = *resource_list->entries()[0];
+  EXPECT_EQ("file:2_file_resource_id", entry.resource_id());
+  EXPECT_TRUE(entry.deleted());
+  EXPECT_EQ(1, fake_service_.change_list_load_count());
+}
+
 TEST_F(FakeDriveServiceTest, ContinueGetResourceList_GetAllResourceList) {
   ASSERT_TRUE(fake_service_.LoadResourceListForWapi(
-      "chromeos/gdata/root_feed.json"));
+      "gdata/root_feed.json"));
   fake_service_.set_default_max_results(6);
 
   GDataErrorCode error = GDATA_OTHER_ERROR;
   scoped_ptr<ResourceList> resource_list;
   fake_service_.GetAllResourceList(
       test_util::CreateCopyResultCallback(&error, &resource_list));
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
   EXPECT_EQ(HTTP_SUCCESS, error);
   ASSERT_TRUE(resource_list);
 
@@ -407,7 +488,7 @@
   fake_service_.ContinueGetResourceList(
       next_url,
       test_util::CreateCopyResultCallback(&error, &resource_list));
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(HTTP_SUCCESS, error);
   ASSERT_TRUE(resource_list);
@@ -425,7 +506,7 @@
   fake_service_.ContinueGetResourceList(
       next_url,
       test_util::CreateCopyResultCallback(&error, &resource_list));
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(HTTP_SUCCESS, error);
   ASSERT_TRUE(resource_list);
@@ -437,7 +518,7 @@
 TEST_F(FakeDriveServiceTest,
        ContinueGetResourceList_GetResourceListInDirectory) {
   ASSERT_TRUE(fake_service_.LoadResourceListForWapi(
-      "chromeos/gdata/root_feed.json"));
+      "gdata/root_feed.json"));
   fake_service_.set_default_max_results(3);
 
   GDataErrorCode error = GDATA_OTHER_ERROR;
@@ -445,7 +526,7 @@
   fake_service_.GetResourceListInDirectory(
       fake_service_.GetRootResourceId(),
       test_util::CreateCopyResultCallback(&error, &resource_list));
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
   EXPECT_EQ(HTTP_SUCCESS, error);
   ASSERT_TRUE(resource_list);
 
@@ -467,7 +548,7 @@
   fake_service_.ContinueGetResourceList(
       next_url,
       test_util::CreateCopyResultCallback(&error, &resource_list));
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(HTTP_SUCCESS, error);
   ASSERT_TRUE(resource_list);
@@ -485,7 +566,7 @@
   fake_service_.ContinueGetResourceList(
       next_url,
       test_util::CreateCopyResultCallback(&error, &resource_list));
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(HTTP_SUCCESS, error);
   ASSERT_TRUE(resource_list);
@@ -496,7 +577,7 @@
 
 TEST_F(FakeDriveServiceTest, ContinueGetResourceList_Search) {
   ASSERT_TRUE(fake_service_.LoadResourceListForWapi(
-      "chromeos/gdata/root_feed.json"));
+      "gdata/root_feed.json"));
   fake_service_.set_default_max_results(2);
 
   GDataErrorCode error = GDATA_OTHER_ERROR;
@@ -504,7 +585,7 @@
   fake_service_.Search(
       "File",  // search_query
       test_util::CreateCopyResultCallback(&error, &resource_list));
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
   EXPECT_EQ(HTTP_SUCCESS, error);
   ASSERT_TRUE(resource_list);
 
@@ -525,7 +606,7 @@
   fake_service_.ContinueGetResourceList(
       next_url,
       test_util::CreateCopyResultCallback(&error, &resource_list));
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(HTTP_SUCCESS, error);
   ASSERT_TRUE(resource_list);
@@ -535,13 +616,13 @@
 
 TEST_F(FakeDriveServiceTest, ContinueGetResourceList_GetChangeList) {
   ASSERT_TRUE(fake_service_.LoadResourceListForWapi(
-      "chromeos/gdata/root_feed.json"));
+      "gdata/root_feed.json"));
   fake_service_.set_default_max_results(2);
 
   // Load the account_metadata.json as well to add the largest changestamp
   // (654321) to the existing entries.
   ASSERT_TRUE(fake_service_.LoadAccountMetadataForWapi(
-      "chromeos/gdata/account_metadata.json"));
+      "gdata/account_metadata.json"));
   // Add 5 new directory in the root directory. The new directory will have
   // the changestamp of 654326.
   for (int i = 0; i < 5; ++i) {
@@ -555,7 +636,7 @@
   fake_service_.GetChangeList(
       654321 + 1,  // start_changestamp
       test_util::CreateCopyResultCallback(&error, &resource_list));
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
   EXPECT_EQ(HTTP_SUCCESS, error);
   ASSERT_TRUE(resource_list);
 
@@ -577,7 +658,7 @@
   fake_service_.ContinueGetResourceList(
       next_url,
       test_util::CreateCopyResultCallback(&error, &resource_list));
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(HTTP_SUCCESS, error);
   ASSERT_TRUE(resource_list);
@@ -595,7 +676,7 @@
   fake_service_.ContinueGetResourceList(
       next_url,
       test_util::CreateCopyResultCallback(&error, &resource_list));
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(HTTP_SUCCESS, error);
   ASSERT_TRUE(resource_list);
@@ -606,13 +687,13 @@
 
 TEST_F(FakeDriveServiceTest, GetAboutResource) {
   ASSERT_TRUE(fake_service_.LoadAccountMetadataForWapi(
-      "chromeos/gdata/account_metadata.json"));
+      "gdata/account_metadata.json"));
 
   GDataErrorCode error = GDATA_OTHER_ERROR;
   scoped_ptr<AboutResource> about_resource;
   fake_service_.GetAboutResource(
       test_util::CreateCopyResultCallback(&error, &about_resource));
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(HTTP_SUCCESS, error);
 
@@ -625,14 +706,14 @@
 
 TEST_F(FakeDriveServiceTest, GetAboutResource_Offline) {
   ASSERT_TRUE(fake_service_.LoadAccountMetadataForWapi(
-      "chromeos/gdata/account_metadata.json"));
+      "gdata/account_metadata.json"));
   fake_service_.set_offline(true);
 
   GDataErrorCode error = GDATA_OTHER_ERROR;
   scoped_ptr<AboutResource> about_resource;
   fake_service_.GetAboutResource(
       test_util::CreateCopyResultCallback(&error, &about_resource));
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(GDATA_NO_CONNECTION, error);
   EXPECT_FALSE(about_resource);
@@ -640,13 +721,13 @@
 
 TEST_F(FakeDriveServiceTest, GetAppList) {
   ASSERT_TRUE(fake_service_.LoadAppListForDriveApi(
-      "chromeos/drive/applist.json"));
+      "drive/applist.json"));
 
   GDataErrorCode error = GDATA_OTHER_ERROR;
   scoped_ptr<AppList> app_list;
   fake_service_.GetAppList(
       test_util::CreateCopyResultCallback(&error, &app_list));
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(HTTP_SUCCESS, error);
 
@@ -655,14 +736,14 @@
 
 TEST_F(FakeDriveServiceTest, GetAppList_Offline) {
   ASSERT_TRUE(fake_service_.LoadAppListForDriveApi(
-      "chromeos/drive/applist.json"));
+      "drive/applist.json"));
   fake_service_.set_offline(true);
 
   GDataErrorCode error = GDATA_OTHER_ERROR;
   scoped_ptr<AppList> app_list;
   fake_service_.GetAppList(
       test_util::CreateCopyResultCallback(&error, &app_list));
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(GDATA_NO_CONNECTION, error);
   EXPECT_FALSE(app_list);
@@ -670,7 +751,7 @@
 
 TEST_F(FakeDriveServiceTest, GetResourceEntry_ExistingFile) {
   ASSERT_TRUE(fake_service_.LoadResourceListForWapi(
-      "chromeos/gdata/root_feed.json"));
+      "gdata/root_feed.json"));
 
   const std::string kResourceId = "file:2_file_resource_id";
   GDataErrorCode error = GDATA_OTHER_ERROR;
@@ -678,7 +759,7 @@
   fake_service_.GetResourceEntry(
       kResourceId,
       test_util::CreateCopyResultCallback(&error, &resource_entry));
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(HTTP_SUCCESS, error);
   ASSERT_TRUE(resource_entry);
@@ -688,7 +769,7 @@
 
 TEST_F(FakeDriveServiceTest, GetResourceEntry_NonexistingFile) {
   ASSERT_TRUE(fake_service_.LoadResourceListForWapi(
-      "chromeos/gdata/root_feed.json"));
+      "gdata/root_feed.json"));
 
   const std::string kResourceId = "file:nonexisting_resource_id";
   GDataErrorCode error = GDATA_OTHER_ERROR;
@@ -696,7 +777,7 @@
   fake_service_.GetResourceEntry(
       kResourceId,
       test_util::CreateCopyResultCallback(&error, &resource_entry));
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(HTTP_NOT_FOUND, error);
   ASSERT_FALSE(resource_entry);
@@ -704,7 +785,7 @@
 
 TEST_F(FakeDriveServiceTest, GetResourceEntry_Offline) {
   ASSERT_TRUE(fake_service_.LoadResourceListForWapi(
-      "chromeos/gdata/root_feed.json"));
+      "gdata/root_feed.json"));
   fake_service_.set_offline(true);
 
   const std::string kResourceId = "file:2_file_resource_id";
@@ -713,7 +794,7 @@
   fake_service_.GetResourceEntry(
       kResourceId,
       test_util::CreateCopyResultCallback(&error, &resource_entry));
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(GDATA_NO_CONNECTION, error);
   EXPECT_FALSE(resource_entry);
@@ -721,7 +802,7 @@
 
 TEST_F(FakeDriveServiceTest, DeleteResource_ExistingFile) {
   ASSERT_TRUE(fake_service_.LoadResourceListForWapi(
-      "chromeos/gdata/root_feed.json"));
+      "gdata/root_feed.json"));
 
   // Resource "file:2_file_resource_id" should now exist.
   ASSERT_TRUE(Exists("file:2_file_resource_id"));
@@ -730,64 +811,70 @@
   fake_service_.DeleteResource("file:2_file_resource_id",
                                std::string(),  // etag
                                test_util::CreateCopyResultCallback(&error));
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(HTTP_SUCCESS, error);
   // Resource "file:2_file_resource_id" should be gone now.
   EXPECT_FALSE(Exists("file:2_file_resource_id"));
+
+  error = GDATA_OTHER_ERROR;
+  fake_service_.DeleteResource("file:2_file_resource_id",
+                               std::string(),  // etag
+                               test_util::CreateCopyResultCallback(&error));
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(HTTP_NOT_FOUND, error);
+  EXPECT_FALSE(Exists("file:2_file_resource_id"));
 }
 
 TEST_F(FakeDriveServiceTest, DeleteResource_NonexistingFile) {
   ASSERT_TRUE(fake_service_.LoadResourceListForWapi(
-      "chromeos/gdata/root_feed.json"));
+      "gdata/root_feed.json"));
 
   GDataErrorCode error = GDATA_OTHER_ERROR;
   fake_service_.DeleteResource("file:nonexisting_resource_id",
                                std::string(),  // etag
                                test_util::CreateCopyResultCallback(&error));
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(HTTP_NOT_FOUND, error);
 }
 
 TEST_F(FakeDriveServiceTest, DeleteResource_Offline) {
   ASSERT_TRUE(fake_service_.LoadResourceListForWapi(
-      "chromeos/gdata/root_feed.json"));
+      "gdata/root_feed.json"));
   fake_service_.set_offline(true);
 
   GDataErrorCode error = GDATA_OTHER_ERROR;
   fake_service_.DeleteResource("file:2_file_resource_id",
                                std::string(),  // etag
                                test_util::CreateCopyResultCallback(&error));
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(GDATA_NO_CONNECTION, error);
 }
 
 TEST_F(FakeDriveServiceTest, DownloadFile_ExistingFile) {
   ASSERT_TRUE(fake_service_.LoadResourceListForWapi(
-      "chromeos/gdata/root_feed.json"));
+      "gdata/root_feed.json"));
 
   base::ScopedTempDir temp_dir;
   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
 
   std::vector<test_util::ProgressInfo> download_progress_values;
 
-  const GURL kContentUrl("https://file_content_url/");
   const base::FilePath kOutputFilePath =
       temp_dir.path().AppendASCII("whatever.txt");
   GDataErrorCode error = GDATA_OTHER_ERROR;
   base::FilePath output_file_path;
   test_util::TestGetContentCallback get_content_callback;
   fake_service_.DownloadFile(
-      base::FilePath::FromUTF8Unsafe("/drive/whatever.txt"),  // virtual path
       kOutputFilePath,
-      kContentUrl,
+      "file:2_file_resource_id",
       test_util::CreateCopyResultCallback(&error, &output_file_path),
       get_content_callback.callback(),
       base::Bind(&test_util::AppendProgressCallbackResult,
                  &download_progress_values));
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(HTTP_SUCCESS, error);
   EXPECT_EQ(output_file_path, kOutputFilePath);
@@ -804,58 +891,54 @@
 
 TEST_F(FakeDriveServiceTest, DownloadFile_NonexistingFile) {
   ASSERT_TRUE(fake_service_.LoadResourceListForWapi(
-      "chromeos/gdata/root_feed.json"));
+      "gdata/root_feed.json"));
 
   base::ScopedTempDir temp_dir;
   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
 
-  const GURL kContentUrl("https://non_existing_content_url/");
   const base::FilePath kOutputFilePath =
       temp_dir.path().AppendASCII("whatever.txt");
   GDataErrorCode error = GDATA_OTHER_ERROR;
   base::FilePath output_file_path;
   fake_service_.DownloadFile(
-      base::FilePath::FromUTF8Unsafe("/drive/whatever.txt"),  // virtual path
       kOutputFilePath,
-      kContentUrl,
+      "file:non_existent_file_resource_id",
       test_util::CreateCopyResultCallback(&error, &output_file_path),
       GetContentCallback(),
       ProgressCallback());
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(HTTP_NOT_FOUND, error);
 }
 
 TEST_F(FakeDriveServiceTest, DownloadFile_Offline) {
   ASSERT_TRUE(fake_service_.LoadResourceListForWapi(
-      "chromeos/gdata/root_feed.json"));
+      "gdata/root_feed.json"));
   fake_service_.set_offline(true);
 
   base::ScopedTempDir temp_dir;
   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
 
-  const GURL kContentUrl("https://file_content_url/");
   const base::FilePath kOutputFilePath =
       temp_dir.path().AppendASCII("whatever.txt");
   GDataErrorCode error = GDATA_OTHER_ERROR;
   base::FilePath output_file_path;
   fake_service_.DownloadFile(
-      base::FilePath::FromUTF8Unsafe("/drive/whatever.txt"),  // virtual path
       kOutputFilePath,
-      kContentUrl,
+      "file:2_file_resource_id",
       test_util::CreateCopyResultCallback(&error, &output_file_path),
       GetContentCallback(),
       ProgressCallback());
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(GDATA_NO_CONNECTION, error);
 }
 
 TEST_F(FakeDriveServiceTest, CopyResource) {
   ASSERT_TRUE(fake_service_.LoadResourceListForWapi(
-      "chromeos/gdata/root_feed.json"));
+      "gdata/root_feed.json"));
   ASSERT_TRUE(fake_service_.LoadAccountMetadataForWapi(
-      "chromeos/gdata/account_metadata.json"));
+      "gdata/account_metadata.json"));
 
   int64 old_largest_change_id = GetLargestChangeByAboutResource();
 
@@ -868,7 +951,7 @@
       kParentResourceId,
       "new name",
       test_util::CreateCopyResultCallback(&error, &resource_entry));
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(HTTP_SUCCESS, error);
   ASSERT_TRUE(resource_entry);
@@ -883,7 +966,7 @@
 
 TEST_F(FakeDriveServiceTest, CopyResource_NonExisting) {
   ASSERT_TRUE(fake_service_.LoadResourceListForWapi(
-      "chromeos/gdata/root_feed.json"));
+      "gdata/root_feed.json"));
 
   const std::string kResourceId = "document:nonexisting_resource_id";
   GDataErrorCode error = GDATA_OTHER_ERROR;
@@ -893,16 +976,16 @@
       "folder:1_folder_resource_id",
       "new name",
       test_util::CreateCopyResultCallback(&error, &resource_entry));
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(HTTP_NOT_FOUND, error);
 }
 
 TEST_F(FakeDriveServiceTest, CopyResource_EmptyParentResourceId) {
   ASSERT_TRUE(fake_service_.LoadResourceListForWapi(
-      "chromeos/gdata/root_feed.json"));
+      "gdata/root_feed.json"));
   ASSERT_TRUE(fake_service_.LoadAccountMetadataForWapi(
-      "chromeos/gdata/account_metadata.json"));
+      "gdata/account_metadata.json"));
 
   int64 old_largest_change_id = GetLargestChangeByAboutResource();
 
@@ -914,7 +997,7 @@
       std::string(),
       "new name",
       test_util::CreateCopyResultCallback(&error, &resource_entry));
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(HTTP_SUCCESS, error);
   ASSERT_TRUE(resource_entry);
@@ -929,7 +1012,7 @@
 
 TEST_F(FakeDriveServiceTest, CopyResource_Offline) {
   ASSERT_TRUE(fake_service_.LoadResourceListForWapi(
-      "chromeos/gdata/root_feed.json"));
+      "gdata/root_feed.json"));
   fake_service_.set_offline(true);
 
   const std::string kResourceId = "file:2_file_resource_id";
@@ -940,7 +1023,7 @@
       "folder:1_folder_resource_id",
       "new name",
       test_util::CreateCopyResultCallback(&error, &resource_entry));
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(GDATA_NO_CONNECTION, error);
   EXPECT_FALSE(resource_entry);
@@ -948,9 +1031,9 @@
 
 TEST_F(FakeDriveServiceTest, CopyHostedDocument_Existing) {
   ASSERT_TRUE(fake_service_.LoadResourceListForWapi(
-      "chromeos/gdata/root_feed.json"));
+      "gdata/root_feed.json"));
   ASSERT_TRUE(fake_service_.LoadAccountMetadataForWapi(
-      "chromeos/gdata/account_metadata.json"));
+      "gdata/account_metadata.json"));
 
   int64 old_largest_change_id = GetLargestChangeByAboutResource();
 
@@ -961,7 +1044,7 @@
       kResourceId,
       "new name",
       test_util::CreateCopyResultCallback(&error, &resource_entry));
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(HTTP_SUCCESS, error);
   ASSERT_TRUE(resource_entry);
@@ -975,7 +1058,7 @@
 
 TEST_F(FakeDriveServiceTest, CopyHostedDocument_NonExisting) {
   ASSERT_TRUE(fake_service_.LoadResourceListForWapi(
-      "chromeos/gdata/root_feed.json"));
+      "gdata/root_feed.json"));
 
   const std::string kResourceId = "document:nonexisting_resource_id";
   GDataErrorCode error = GDATA_OTHER_ERROR;
@@ -984,14 +1067,14 @@
       kResourceId,
       "new name",
       test_util::CreateCopyResultCallback(&error, &resource_entry));
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(HTTP_NOT_FOUND, error);
 }
 
 TEST_F(FakeDriveServiceTest, CopyHostedDocument_Offline) {
   ASSERT_TRUE(fake_service_.LoadResourceListForWapi(
-      "chromeos/gdata/root_feed.json"));
+      "gdata/root_feed.json"));
   fake_service_.set_offline(true);
 
   const std::string kResourceId = "document:5_document_resource_id";
@@ -1001,7 +1084,7 @@
       kResourceId,
       "new name",
       test_util::CreateCopyResultCallback(&error, &resource_entry));
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(GDATA_NO_CONNECTION, error);
   EXPECT_FALSE(resource_entry);
@@ -1009,9 +1092,9 @@
 
 TEST_F(FakeDriveServiceTest, RenameResource_ExistingFile) {
   ASSERT_TRUE(fake_service_.LoadResourceListForWapi(
-      "chromeos/gdata/root_feed.json"));
+      "gdata/root_feed.json"));
   ASSERT_TRUE(fake_service_.LoadAccountMetadataForWapi(
-      "chromeos/gdata/account_metadata.json"));
+      "gdata/account_metadata.json"));
 
   int64 old_largest_change_id = GetLargestChangeByAboutResource();
 
@@ -1021,7 +1104,7 @@
   fake_service_.RenameResource(kResourceId,
                                "new name",
                                test_util::CreateCopyResultCallback(&error));
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(HTTP_SUCCESS, error);
 
@@ -1035,7 +1118,7 @@
 
 TEST_F(FakeDriveServiceTest, RenameResource_NonexistingFile) {
   ASSERT_TRUE(fake_service_.LoadResourceListForWapi(
-      "chromeos/gdata/root_feed.json"));
+      "gdata/root_feed.json"));
 
   const std::string kResourceId = "file:nonexisting_file";
 
@@ -1043,14 +1126,14 @@
   fake_service_.RenameResource(kResourceId,
                                "new name",
                                test_util::CreateCopyResultCallback(&error));
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(HTTP_NOT_FOUND, error);
 }
 
 TEST_F(FakeDriveServiceTest, RenameResource_Offline) {
   ASSERT_TRUE(fake_service_.LoadResourceListForWapi(
-      "chromeos/gdata/root_feed.json"));
+      "gdata/root_feed.json"));
   fake_service_.set_offline(true);
 
   const std::string kResourceId = "file:2_file_resource_id";
@@ -1059,16 +1142,16 @@
   fake_service_.RenameResource(kResourceId,
                                "new name",
                                test_util::CreateCopyResultCallback(&error));
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(GDATA_NO_CONNECTION, error);
 }
 
 TEST_F(FakeDriveServiceTest, TouchResource_ExistingFile) {
   ASSERT_TRUE(fake_service_.LoadResourceListForWapi(
-      "chromeos/gdata/root_feed.json"));
+      "gdata/root_feed.json"));
   ASSERT_TRUE(fake_service_.LoadAccountMetadataForWapi(
-      "chromeos/gdata/account_metadata.json"));
+      "gdata/account_metadata.json"));
 
   int64 old_largest_change_id = GetLargestChangeByAboutResource();
 
@@ -1084,7 +1167,7 @@
       base::Time::FromUTCExploded(kModifiedDate),
       base::Time::FromUTCExploded(kLastViewedByMeDate),
       test_util::CreateCopyResultCallback(&error, &entry));
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(HTTP_SUCCESS, error);
 
@@ -1101,7 +1184,7 @@
 
 TEST_F(FakeDriveServiceTest, TouchResource_NonexistingFile) {
   ASSERT_TRUE(fake_service_.LoadResourceListForWapi(
-      "chromeos/gdata/root_feed.json"));
+      "gdata/root_feed.json"));
 
   const std::string kResourceId = "file:nonexisting_file";
   const base::Time::Exploded kModifiedDate = {2012, 7, 0, 19, 15, 59, 13, 123};
@@ -1115,14 +1198,14 @@
       base::Time::FromUTCExploded(kModifiedDate),
       base::Time::FromUTCExploded(kLastViewedByMeDate),
       test_util::CreateCopyResultCallback(&error, &entry));
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(HTTP_NOT_FOUND, error);
 }
 
 TEST_F(FakeDriveServiceTest, TouchResource_Offline) {
   ASSERT_TRUE(fake_service_.LoadResourceListForWapi(
-      "chromeos/gdata/root_feed.json"));
+      "gdata/root_feed.json"));
   fake_service_.set_offline(true);
 
   const std::string kResourceId = "file:2_file_resource_id";
@@ -1137,16 +1220,16 @@
       base::Time::FromUTCExploded(kModifiedDate),
       base::Time::FromUTCExploded(kLastViewedByMeDate),
       test_util::CreateCopyResultCallback(&error, &entry));
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(GDATA_NO_CONNECTION, error);
 }
 
 TEST_F(FakeDriveServiceTest, AddResourceToDirectory_FileInRootDirectory) {
   ASSERT_TRUE(fake_service_.LoadResourceListForWapi(
-      "chromeos/gdata/root_feed.json"));
+      "gdata/root_feed.json"));
   ASSERT_TRUE(fake_service_.LoadAccountMetadataForWapi(
-      "chromeos/gdata/account_metadata.json"));
+      "gdata/account_metadata.json"));
 
   int64 old_largest_change_id = GetLargestChangeByAboutResource();
 
@@ -1163,7 +1246,7 @@
       kNewParentResourceId,
       kResourceId,
       test_util::CreateCopyResultCallback(&error));
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(HTTP_SUCCESS, error);
 
@@ -1177,9 +1260,9 @@
 
 TEST_F(FakeDriveServiceTest, AddResourceToDirectory_FileInNonRootDirectory) {
   ASSERT_TRUE(fake_service_.LoadResourceListForWapi(
-      "chromeos/gdata/root_feed.json"));
+      "gdata/root_feed.json"));
   ASSERT_TRUE(fake_service_.LoadAccountMetadataForWapi(
-      "chromeos/gdata/account_metadata.json"));
+      "gdata/account_metadata.json"));
 
   int64 old_largest_change_id = GetLargestChangeByAboutResource();
 
@@ -1196,7 +1279,7 @@
       kNewParentResourceId,
       kResourceId,
       test_util::CreateCopyResultCallback(&error));
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(HTTP_SUCCESS, error);
 
@@ -1210,7 +1293,7 @@
 
 TEST_F(FakeDriveServiceTest, AddResourceToDirectory_NonexistingFile) {
   ASSERT_TRUE(fake_service_.LoadResourceListForWapi(
-      "chromeos/gdata/root_feed.json"));
+      "gdata/root_feed.json"));
 
   const std::string kResourceId = "file:nonexisting_file";
   const std::string kNewParentResourceId = "folder:1_folder_resource_id";
@@ -1220,16 +1303,16 @@
       kNewParentResourceId,
       kResourceId,
       test_util::CreateCopyResultCallback(&error));
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(HTTP_NOT_FOUND, error);
 }
 
 TEST_F(FakeDriveServiceTest, AddResourceToDirectory_OrphanFile) {
   ASSERT_TRUE(fake_service_.LoadResourceListForWapi(
-      "chromeos/gdata/root_feed.json"));
+      "gdata/root_feed.json"));
   ASSERT_TRUE(fake_service_.LoadAccountMetadataForWapi(
-      "chromeos/gdata/account_metadata.json"));
+      "gdata/account_metadata.json"));
 
   int64 old_largest_change_id = GetLargestChangeByAboutResource();
 
@@ -1245,7 +1328,7 @@
       kNewParentResourceId,
       kResourceId,
       test_util::CreateCopyResultCallback(&error));
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(HTTP_SUCCESS, error);
 
@@ -1259,7 +1342,7 @@
 
 TEST_F(FakeDriveServiceTest, AddResourceToDirectory_Offline) {
   ASSERT_TRUE(fake_service_.LoadResourceListForWapi(
-      "chromeos/gdata/root_feed.json"));
+      "gdata/root_feed.json"));
   fake_service_.set_offline(true);
 
   const std::string kResourceId = "file:2_file_resource_id";
@@ -1270,16 +1353,16 @@
       kNewParentResourceId,
       kResourceId,
       test_util::CreateCopyResultCallback(&error));
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(GDATA_NO_CONNECTION, error);
 }
 
 TEST_F(FakeDriveServiceTest, RemoveResourceFromDirectory_ExistingFile) {
   ASSERT_TRUE(fake_service_.LoadResourceListForWapi(
-      "chromeos/gdata/root_feed.json"));
+      "gdata/root_feed.json"));
   ASSERT_TRUE(fake_service_.LoadAccountMetadataForWapi(
-      "chromeos/gdata/account_metadata.json"));
+      "gdata/account_metadata.json"));
 
   int64 old_largest_change_id = GetLargestChangeByAboutResource();
 
@@ -1298,7 +1381,7 @@
       kParentResourceId,
       kResourceId,
       test_util::CreateCopyResultCallback(&error));
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(HTTP_SUCCESS, error);
 
@@ -1314,7 +1397,7 @@
 
 TEST_F(FakeDriveServiceTest, RemoveResourceFromDirectory_NonexistingFile) {
   ASSERT_TRUE(fake_service_.LoadResourceListForWapi(
-      "chromeos/gdata/root_feed.json"));
+      "gdata/root_feed.json"));
 
   const std::string kResourceId = "file:nonexisting_file";
   const std::string kParentResourceId = "folder:1_folder_resource_id";
@@ -1324,14 +1407,14 @@
       kParentResourceId,
       kResourceId,
       test_util::CreateCopyResultCallback(&error));
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(HTTP_NOT_FOUND, error);
 }
 
 TEST_F(FakeDriveServiceTest, RemoveResourceFromDirectory_OrphanFile) {
   ASSERT_TRUE(fake_service_.LoadResourceListForWapi(
-      "chromeos/gdata/root_feed.json"));
+      "gdata/root_feed.json"));
 
   const std::string kResourceId = "file:1_orphanfile_resource_id";
   const std::string kParentResourceId = fake_service_.GetRootResourceId();
@@ -1341,14 +1424,14 @@
       kParentResourceId,
       kResourceId,
       test_util::CreateCopyResultCallback(&error));
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(HTTP_NOT_FOUND, error);
 }
 
 TEST_F(FakeDriveServiceTest, RemoveResourceFromDirectory_Offline) {
   ASSERT_TRUE(fake_service_.LoadResourceListForWapi(
-      "chromeos/gdata/root_feed.json"));
+      "gdata/root_feed.json"));
   fake_service_.set_offline(true);
 
   const std::string kResourceId = "file:subdirectory_file_1_id";
@@ -1359,16 +1442,16 @@
       kParentResourceId,
       kResourceId,
       test_util::CreateCopyResultCallback(&error));
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(GDATA_NO_CONNECTION, error);
 }
 
 TEST_F(FakeDriveServiceTest, AddNewDirectory_ToRootDirectory) {
   ASSERT_TRUE(fake_service_.LoadResourceListForWapi(
-      "chromeos/gdata/root_feed.json"));
+      "gdata/root_feed.json"));
   ASSERT_TRUE(fake_service_.LoadAccountMetadataForWapi(
-      "chromeos/gdata/account_metadata.json"));
+      "gdata/account_metadata.json"));
 
   int64 old_largest_change_id = GetLargestChangeByAboutResource();
 
@@ -1378,7 +1461,7 @@
       fake_service_.GetRootResourceId(),
       "new directory",
       test_util::CreateCopyResultCallback(&error, &resource_entry));
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(HTTP_CREATED, error);
   ASSERT_TRUE(resource_entry);
@@ -1394,9 +1477,9 @@
 
 TEST_F(FakeDriveServiceTest, AddNewDirectory_ToRootDirectoryOnEmptyFileSystem) {
   ASSERT_TRUE(fake_service_.LoadResourceListForWapi(
-      "chromeos/gdata/empty_feed.json"));
+      "gdata/empty_feed.json"));
   ASSERT_TRUE(fake_service_.LoadAccountMetadataForWapi(
-      "chromeos/gdata/account_metadata.json"));
+      "gdata/account_metadata.json"));
 
   int64 old_largest_change_id = GetLargestChangeByAboutResource();
 
@@ -1406,7 +1489,7 @@
       fake_service_.GetRootResourceId(),
       "new directory",
       test_util::CreateCopyResultCallback(&error, &resource_entry));
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(HTTP_CREATED, error);
   ASSERT_TRUE(resource_entry);
@@ -1422,9 +1505,9 @@
 
 TEST_F(FakeDriveServiceTest, AddNewDirectory_ToNonRootDirectory) {
   ASSERT_TRUE(fake_service_.LoadResourceListForWapi(
-      "chromeos/gdata/root_feed.json"));
+      "gdata/root_feed.json"));
   ASSERT_TRUE(fake_service_.LoadAccountMetadataForWapi(
-      "chromeos/gdata/account_metadata.json"));
+      "gdata/account_metadata.json"));
 
   int64 old_largest_change_id = GetLargestChangeByAboutResource();
 
@@ -1436,7 +1519,7 @@
       kParentResourceId,
       "new directory",
       test_util::CreateCopyResultCallback(&error, &resource_entry));
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(HTTP_CREATED, error);
   ASSERT_TRUE(resource_entry);
@@ -1451,7 +1534,7 @@
 
 TEST_F(FakeDriveServiceTest, AddNewDirectory_ToNonexistingDirectory) {
   ASSERT_TRUE(fake_service_.LoadResourceListForWapi(
-      "chromeos/gdata/root_feed.json"));
+      "gdata/root_feed.json"));
 
   const std::string kParentResourceId = "folder:nonexisting_resource_id";
 
@@ -1461,7 +1544,7 @@
       kParentResourceId,
       "new directory",
       test_util::CreateCopyResultCallback(&error, &resource_entry));
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(HTTP_NOT_FOUND, error);
   EXPECT_FALSE(resource_entry);
@@ -1469,7 +1552,7 @@
 
 TEST_F(FakeDriveServiceTest, AddNewDirectory_Offline) {
   ASSERT_TRUE(fake_service_.LoadResourceListForWapi(
-      "chromeos/gdata/root_feed.json"));
+      "gdata/root_feed.json"));
   fake_service_.set_offline(true);
 
   GDataErrorCode error = GDATA_OTHER_ERROR;
@@ -1478,7 +1561,7 @@
       fake_service_.GetRootResourceId(),
       "new directory",
       test_util::CreateCopyResultCallback(&error, &resource_entry));
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(GDATA_NO_CONNECTION, error);
   EXPECT_FALSE(resource_entry);
@@ -1486,19 +1569,18 @@
 
 TEST_F(FakeDriveServiceTest, InitiateUploadNewFile_Offline) {
   ASSERT_TRUE(fake_service_.LoadResourceListForWapi(
-      "chromeos/gdata/root_feed.json"));
+      "gdata/root_feed.json"));
   fake_service_.set_offline(true);
 
   GDataErrorCode error = GDATA_OTHER_ERROR;
   GURL upload_location;
   fake_service_.InitiateUploadNewFile(
-      base::FilePath(FILE_PATH_LITERAL("drive/Directory 1")),
       "test/foo",
       13,
       "folder:1_folder_resource_id",
       "new file.foo",
       test_util::CreateCopyResultCallback(&error, &upload_location));
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(GDATA_NO_CONNECTION, error);
   EXPECT_TRUE(upload_location.is_empty());
@@ -1506,18 +1588,17 @@
 
 TEST_F(FakeDriveServiceTest, InitiateUploadNewFile_NotFound) {
   ASSERT_TRUE(fake_service_.LoadResourceListForWapi(
-      "chromeos/gdata/root_feed.json"));
+      "gdata/root_feed.json"));
 
   GDataErrorCode error = GDATA_OTHER_ERROR;
   GURL upload_location;
   fake_service_.InitiateUploadNewFile(
-      base::FilePath(FILE_PATH_LITERAL("drive/Directory 1")),
       "test/foo",
       13,
       "non_existent",
       "new file.foo",
       test_util::CreateCopyResultCallback(&error, &upload_location));
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(HTTP_NOT_FOUND, error);
   EXPECT_TRUE(upload_location.is_empty());
@@ -1525,18 +1606,17 @@
 
 TEST_F(FakeDriveServiceTest, InitiateUploadNewFile) {
   ASSERT_TRUE(fake_service_.LoadResourceListForWapi(
-      "chromeos/gdata/root_feed.json"));
+      "gdata/root_feed.json"));
 
   GDataErrorCode error = GDATA_OTHER_ERROR;
   GURL upload_location;
   fake_service_.InitiateUploadNewFile(
-      base::FilePath(FILE_PATH_LITERAL("drive/Directory 1")),
       "test/foo",
       13,
       "folder:1_folder_resource_id",
       "new file.foo",
       test_util::CreateCopyResultCallback(&error, &upload_location));
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(HTTP_SUCCESS, error);
   EXPECT_FALSE(upload_location.is_empty());
@@ -1546,19 +1626,18 @@
 
 TEST_F(FakeDriveServiceTest, InitiateUploadExistingFile_Offline) {
   ASSERT_TRUE(fake_service_.LoadResourceListForWapi(
-      "chromeos/gdata/root_feed.json"));
+      "gdata/root_feed.json"));
   fake_service_.set_offline(true);
 
   GDataErrorCode error = GDATA_OTHER_ERROR;
   GURL upload_location;
   fake_service_.InitiateUploadExistingFile(
-      base::FilePath(FILE_PATH_LITERAL("drive/File 1")),
       "test/foo",
       13,
       "file:2_file_resource_id",
       std::string(),  // etag
       test_util::CreateCopyResultCallback(&error, &upload_location));
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(GDATA_NO_CONNECTION, error);
   EXPECT_TRUE(upload_location.is_empty());
@@ -1566,18 +1645,17 @@
 
 TEST_F(FakeDriveServiceTest, InitiateUploadExistingFile_NotFound) {
   ASSERT_TRUE(fake_service_.LoadResourceListForWapi(
-      "chromeos/gdata/root_feed.json"));
+      "gdata/root_feed.json"));
 
   GDataErrorCode error = GDATA_OTHER_ERROR;
   GURL upload_location;
   fake_service_.InitiateUploadExistingFile(
-      base::FilePath(FILE_PATH_LITERAL("drive/File 1")),
       "test/foo",
       13,
       "non_existent",
       std::string(),  // etag
       test_util::CreateCopyResultCallback(&error, &upload_location));
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(HTTP_NOT_FOUND, error);
   EXPECT_TRUE(upload_location.is_empty());
@@ -1585,18 +1663,17 @@
 
 TEST_F(FakeDriveServiceTest, InitiateUploadExistingFile_WrongETag) {
   ASSERT_TRUE(fake_service_.LoadResourceListForWapi(
-      "chromeos/gdata/root_feed.json"));
+      "gdata/root_feed.json"));
 
   GDataErrorCode error = GDATA_OTHER_ERROR;
   GURL upload_location;
   fake_service_.InitiateUploadExistingFile(
-      base::FilePath(FILE_PATH_LITERAL("drive/File 1.txt")),
       "text/plain",
       13,
       "file:2_file_resource_id",
       "invalid_etag",
       test_util::CreateCopyResultCallback(&error, &upload_location));
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(HTTP_PRECONDITION, error);
   EXPECT_TRUE(upload_location.is_empty());
@@ -1604,38 +1681,35 @@
 
 TEST_F(FakeDriveServiceTest, InitiateUpload_ExistingFile) {
   ASSERT_TRUE(fake_service_.LoadResourceListForWapi(
-      "chromeos/gdata/root_feed.json"));
+      "gdata/root_feed.json"));
 
   GDataErrorCode error = GDATA_OTHER_ERROR;
   GURL upload_location;
   fake_service_.InitiateUploadExistingFile(
-      base::FilePath(FILE_PATH_LITERAL("drive/File 1.txt")),
       "text/plain",
       13,
       "file:2_file_resource_id",
       "\"HhMOFgxXHit7ImBr\"",
       test_util::CreateCopyResultCallback(&error, &upload_location));
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(HTTP_SUCCESS, error);
-  EXPECT_EQ(GURL("https://2_file_link_resumable_create_media?mode=existing"),
-            upload_location);
+  EXPECT_TRUE(upload_location.is_valid());
 }
 
 TEST_F(FakeDriveServiceTest, ResumeUpload_Offline) {
   ASSERT_TRUE(fake_service_.LoadResourceListForWapi(
-      "chromeos/gdata/root_feed.json"));
+      "gdata/root_feed.json"));
 
   GDataErrorCode error = GDATA_OTHER_ERROR;
   GURL upload_location;
   fake_service_.InitiateUploadNewFile(
-      base::FilePath(FILE_PATH_LITERAL("drive/Directory 1/new file.foo")),
       "test/foo",
       15,
       "folder:1_folder_resource_id",
       "new file.foo",
       test_util::CreateCopyResultCallback(&error, &upload_location));
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(HTTP_SUCCESS, error);
   EXPECT_FALSE(upload_location.is_empty());
@@ -1647,13 +1721,12 @@
   UploadRangeResponse response;
   scoped_ptr<ResourceEntry> entry;
   fake_service_.ResumeUpload(
-      base::FilePath(FILE_PATH_LITERAL("drive/Directory 1/new file.foo")),
       upload_location,
       0, 13, 15, "test/foo",
       base::FilePath(),
       test_util::CreateCopyResultCallback(&response, &entry),
       ProgressCallback());
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(GDATA_NO_CONNECTION, response.code);
   EXPECT_FALSE(entry.get());
@@ -1661,50 +1734,54 @@
 
 TEST_F(FakeDriveServiceTest, ResumeUpload_NotFound) {
   ASSERT_TRUE(fake_service_.LoadResourceListForWapi(
-      "chromeos/gdata/root_feed.json"));
+      "gdata/root_feed.json"));
 
   GDataErrorCode error = GDATA_OTHER_ERROR;
   GURL upload_location;
   fake_service_.InitiateUploadNewFile(
-      base::FilePath(FILE_PATH_LITERAL("drive/Directory 1/new file.foo")),
       "test/foo",
       15,
       "folder:1_folder_resource_id",
       "new file.foo",
       test_util::CreateCopyResultCallback(&error, &upload_location));
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   ASSERT_EQ(HTTP_SUCCESS, error);
 
   UploadRangeResponse response;
   scoped_ptr<ResourceEntry> entry;
   fake_service_.ResumeUpload(
-      base::FilePath(FILE_PATH_LITERAL("drive/Directory 1/new file.foo")),
       GURL("https://foo.com/"),
       0, 13, 15, "test/foo",
       base::FilePath(),
       test_util::CreateCopyResultCallback(&response, &entry),
       ProgressCallback());
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(HTTP_NOT_FOUND, response.code);
   EXPECT_FALSE(entry.get());
 }
 
 TEST_F(FakeDriveServiceTest, ResumeUpload_ExistingFile) {
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  base::FilePath local_file_path =
+      temp_dir.path().Append(FILE_PATH_LITERAL("File 1.txt"));
+  std::string contents("hogefugapiyo");
+  ASSERT_TRUE(test_util::WriteStringToFile(local_file_path, contents));
+
   ASSERT_TRUE(fake_service_.LoadResourceListForWapi(
-      "chromeos/gdata/root_feed.json"));
+      "gdata/root_feed.json"));
 
   GDataErrorCode error = GDATA_OTHER_ERROR;
   GURL upload_location;
   fake_service_.InitiateUploadExistingFile(
-      base::FilePath(FILE_PATH_LITERAL("drive/File 1.txt")),
       "text/plain",
-      15,
+      contents.size(),
       "file:2_file_resource_id",
       "\"HhMOFgxXHit7ImBr\"",
       test_util::CreateCopyResultCallback(&error, &upload_location));
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   ASSERT_EQ(HTTP_SUCCESS, error);
 
@@ -1712,57 +1789,65 @@
   scoped_ptr<ResourceEntry> entry;
   std::vector<test_util::ProgressInfo> upload_progress_values;
   fake_service_.ResumeUpload(
-      base::FilePath(FILE_PATH_LITERAL("drive/File 1.txt")),
       upload_location,
-      0, 13, 15, "text/plain",
-      base::FilePath(),
+      0, contents.size() / 2, contents.size(), "text/plain",
+      local_file_path,
       test_util::CreateCopyResultCallback(&response, &entry),
       base::Bind(&test_util::AppendProgressCallbackResult,
                  &upload_progress_values));
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(HTTP_RESUME_INCOMPLETE, response.code);
   EXPECT_FALSE(entry.get());
   ASSERT_TRUE(!upload_progress_values.empty());
   EXPECT_TRUE(base::STLIsSorted(upload_progress_values));
   EXPECT_LE(0, upload_progress_values.front().first);
-  EXPECT_GE(13, upload_progress_values.back().first);
+  EXPECT_GE(static_cast<int64>(contents.size() / 2),
+            upload_progress_values.back().first);
 
   upload_progress_values.clear();
   fake_service_.ResumeUpload(
-      base::FilePath(FILE_PATH_LITERAL("drive/File 1.txt")),
       upload_location,
-      13, 15, 15, "text/plain",
-      base::FilePath(),
+      contents.size() / 2, contents.size(), contents.size(), "text/plain",
+      local_file_path,
       test_util::CreateCopyResultCallback(&response, &entry),
       base::Bind(&test_util::AppendProgressCallbackResult,
                  &upload_progress_values));
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(HTTP_SUCCESS, response.code);
   EXPECT_TRUE(entry.get());
-  EXPECT_EQ(15L, entry->file_size());
+  EXPECT_EQ(static_cast<int64>(contents.size()),
+            entry->file_size());
   EXPECT_TRUE(Exists(entry->resource_id()));
   ASSERT_TRUE(!upload_progress_values.empty());
   EXPECT_TRUE(base::STLIsSorted(upload_progress_values));
   EXPECT_LE(0, upload_progress_values.front().first);
-  EXPECT_GE(2, upload_progress_values.back().first);
+  EXPECT_GE(static_cast<int64>(contents.size() - contents.size() / 2),
+            upload_progress_values.back().first);
+  EXPECT_EQ(base::MD5String(contents), entry->file_md5());
 }
 
 TEST_F(FakeDriveServiceTest, ResumeUpload_NewFile) {
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  base::FilePath local_file_path =
+      temp_dir.path().Append(FILE_PATH_LITERAL("new file.foo"));
+  std::string contents("hogefugapiyo");
+  ASSERT_TRUE(test_util::WriteStringToFile(local_file_path, contents));
+
   ASSERT_TRUE(fake_service_.LoadResourceListForWapi(
-      "chromeos/gdata/root_feed.json"));
+      "gdata/root_feed.json"));
 
   GDataErrorCode error = GDATA_OTHER_ERROR;
   GURL upload_location;
   fake_service_.InitiateUploadNewFile(
-      base::FilePath(FILE_PATH_LITERAL("drive/Directory 1/new file.foo")),
       "test/foo",
-      15,
+      contents.size(),
       "folder:1_folder_resource_id",
       "new file.foo",
       test_util::CreateCopyResultCallback(&error, &upload_location));
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(HTTP_SUCCESS, error);
   EXPECT_FALSE(upload_location.is_empty());
@@ -1773,48 +1858,49 @@
   scoped_ptr<ResourceEntry> entry;
   std::vector<test_util::ProgressInfo> upload_progress_values;
   fake_service_.ResumeUpload(
-      base::FilePath(FILE_PATH_LITERAL("drive/Directory 1/new file.foo")),
       upload_location,
-      0, 13, 15, "test/foo",
-      base::FilePath(),
+      0, contents.size() / 2, contents.size(), "test/foo",
+      local_file_path,
       test_util::CreateCopyResultCallback(&response, &entry),
       base::Bind(&test_util::AppendProgressCallbackResult,
                  &upload_progress_values));
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(HTTP_RESUME_INCOMPLETE, response.code);
   EXPECT_FALSE(entry.get());
   ASSERT_TRUE(!upload_progress_values.empty());
   EXPECT_TRUE(base::STLIsSorted(upload_progress_values));
   EXPECT_LE(0, upload_progress_values.front().first);
-  EXPECT_GE(13, upload_progress_values.back().first);
+  EXPECT_GE(static_cast<int64>(contents.size() / 2),
+            upload_progress_values.back().first);
 
   upload_progress_values.clear();
   fake_service_.ResumeUpload(
-      base::FilePath(FILE_PATH_LITERAL("drive/Directory 1/new file.foo")),
       upload_location,
-      13, 15, 15, "test/foo",
-      base::FilePath(),
+      contents.size() / 2, contents.size(), contents.size(), "test/foo",
+      local_file_path,
       test_util::CreateCopyResultCallback(&response, &entry),
       base::Bind(&test_util::AppendProgressCallbackResult,
                  &upload_progress_values));
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(HTTP_CREATED, response.code);
   EXPECT_TRUE(entry.get());
-  EXPECT_EQ(15L, entry->file_size());
+  EXPECT_EQ(static_cast<int64>(contents.size()), entry->file_size());
   EXPECT_TRUE(Exists(entry->resource_id()));
   ASSERT_TRUE(!upload_progress_values.empty());
   EXPECT_TRUE(base::STLIsSorted(upload_progress_values));
   EXPECT_LE(0, upload_progress_values.front().first);
-  EXPECT_GE(2, upload_progress_values.back().first);
+  EXPECT_GE(static_cast<int64>(contents.size() - contents.size() / 2),
+            upload_progress_values.back().first);
+  EXPECT_EQ(base::MD5String(contents), entry->file_md5());
 }
 
 TEST_F(FakeDriveServiceTest, AddNewFile_ToRootDirectory) {
   ASSERT_TRUE(fake_service_.LoadResourceListForWapi(
-      "chromeos/gdata/root_feed.json"));
+      "gdata/root_feed.json"));
   ASSERT_TRUE(fake_service_.LoadAccountMetadataForWapi(
-      "chromeos/gdata/account_metadata.json"));
+      "gdata/account_metadata.json"));
 
   int64 old_largest_change_id = GetLargestChangeByAboutResource();
 
@@ -1831,7 +1917,7 @@
       kTitle,
       false,  // shared_with_me
       test_util::CreateCopyResultCallback(&error, &resource_entry));
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(HTTP_CREATED, error);
   ASSERT_TRUE(resource_entry);
@@ -1846,13 +1932,14 @@
   // Should be incremented as a new directory was created.
   EXPECT_EQ(old_largest_change_id + 1, fake_service_.largest_changestamp());
   EXPECT_EQ(old_largest_change_id + 1, GetLargestChangeByAboutResource());
+  EXPECT_EQ(base::MD5String(kContentData), resource_entry->file_md5());
 }
 
 TEST_F(FakeDriveServiceTest, AddNewFile_ToRootDirectoryOnEmptyFileSystem) {
   ASSERT_TRUE(fake_service_.LoadResourceListForWapi(
-      "chromeos/gdata/empty_feed.json"));
+      "gdata/empty_feed.json"));
   ASSERT_TRUE(fake_service_.LoadAccountMetadataForWapi(
-      "chromeos/gdata/account_metadata.json"));
+      "gdata/account_metadata.json"));
 
   int64 old_largest_change_id = GetLargestChangeByAboutResource();
 
@@ -1869,7 +1956,7 @@
       kTitle,
       false,  // shared_with_me
       test_util::CreateCopyResultCallback(&error, &resource_entry));
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(HTTP_CREATED, error);
   ASSERT_TRUE(resource_entry);
@@ -1884,13 +1971,14 @@
   // Should be incremented as a new directory was created.
   EXPECT_EQ(old_largest_change_id + 1, fake_service_.largest_changestamp());
   EXPECT_EQ(old_largest_change_id + 1, GetLargestChangeByAboutResource());
+  EXPECT_EQ(base::MD5String(kContentData), resource_entry->file_md5());
 }
 
 TEST_F(FakeDriveServiceTest, AddNewFile_ToNonRootDirectory) {
   ASSERT_TRUE(fake_service_.LoadResourceListForWapi(
-      "chromeos/gdata/root_feed.json"));
+      "gdata/root_feed.json"));
   ASSERT_TRUE(fake_service_.LoadAccountMetadataForWapi(
-      "chromeos/gdata/account_metadata.json"));
+      "gdata/account_metadata.json"));
 
   int64 old_largest_change_id = GetLargestChangeByAboutResource();
 
@@ -1908,7 +1996,7 @@
       kTitle,
       false,  // shared_with_me
       test_util::CreateCopyResultCallback(&error, &resource_entry));
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(HTTP_CREATED, error);
   ASSERT_TRUE(resource_entry);
@@ -1922,11 +2010,12 @@
   // Should be incremented as a new directory was created.
   EXPECT_EQ(old_largest_change_id + 1, fake_service_.largest_changestamp());
   EXPECT_EQ(old_largest_change_id + 1, GetLargestChangeByAboutResource());
+  EXPECT_EQ(base::MD5String(kContentData), resource_entry->file_md5());
 }
 
 TEST_F(FakeDriveServiceTest, AddNewFile_ToNonexistingDirectory) {
   ASSERT_TRUE(fake_service_.LoadResourceListForWapi(
-      "chromeos/gdata/root_feed.json"));
+      "gdata/root_feed.json"));
 
   const std::string kContentType = "text/plain";
   const std::string kContentData = "This is some test content.";
@@ -1942,7 +2031,7 @@
       kTitle,
       false,  // shared_with_me
       test_util::CreateCopyResultCallback(&error, &resource_entry));
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(HTTP_NOT_FOUND, error);
   EXPECT_FALSE(resource_entry);
@@ -1950,7 +2039,7 @@
 
 TEST_F(FakeDriveServiceTest, AddNewFile_Offline) {
   ASSERT_TRUE(fake_service_.LoadResourceListForWapi(
-      "chromeos/gdata/root_feed.json"));
+      "gdata/root_feed.json"));
   fake_service_.set_offline(true);
 
   const std::string kContentType = "text/plain";
@@ -1966,7 +2055,7 @@
       kTitle,
       false,  // shared_with_me
       test_util::CreateCopyResultCallback(&error, &resource_entry));
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(GDATA_NO_CONNECTION, error);
   EXPECT_FALSE(resource_entry);
@@ -1974,9 +2063,9 @@
 
 TEST_F(FakeDriveServiceTest, AddNewFile_SharedWithMeLabel) {
   ASSERT_TRUE(fake_service_.LoadResourceListForWapi(
-      "chromeos/gdata/root_feed.json"));
+      "gdata/root_feed.json"));
   ASSERT_TRUE(fake_service_.LoadAccountMetadataForWapi(
-      "chromeos/gdata/account_metadata.json"));
+      "gdata/account_metadata.json"));
 
   const std::string kContentType = "text/plain";
   const std::string kContentData = "This is some test content.";
@@ -1993,7 +2082,7 @@
       kTitle,
       true,  // shared_with_me
       test_util::CreateCopyResultCallback(&error, &resource_entry));
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(HTTP_CREATED, error);
   ASSERT_TRUE(resource_entry);
@@ -2010,11 +2099,12 @@
   // Should be incremented as a new directory was created.
   EXPECT_EQ(old_largest_change_id + 1, fake_service_.largest_changestamp());
   EXPECT_EQ(old_largest_change_id + 1, GetLargestChangeByAboutResource());
+  EXPECT_EQ(base::MD5String(kContentData), resource_entry->file_md5());
 }
 
 TEST_F(FakeDriveServiceTest, SetLastModifiedTime_ExistingFile) {
   ASSERT_TRUE(fake_service_.LoadResourceListForWapi(
-      "chromeos/gdata/root_feed.json"));
+      "gdata/root_feed.json"));
 
   const std::string kResourceId = "file:2_file_resource_id";
   base::Time time;
@@ -2026,7 +2116,7 @@
       kResourceId,
       time,
       test_util::CreateCopyResultCallback(&error, &resource_entry));
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(HTTP_SUCCESS, error);
   ASSERT_TRUE(resource_entry);
@@ -2035,7 +2125,7 @@
 
 TEST_F(FakeDriveServiceTest, SetLastModifiedTime_NonexistingFile) {
   ASSERT_TRUE(fake_service_.LoadResourceListForWapi(
-      "chromeos/gdata/root_feed.json"));
+      "gdata/root_feed.json"));
 
   const std::string kResourceId = "file:nonexisting_resource_id";
   base::Time time;
@@ -2047,7 +2137,7 @@
       kResourceId,
       time,
       test_util::CreateCopyResultCallback(&error, &resource_entry));
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(HTTP_NOT_FOUND, error);
   EXPECT_FALSE(resource_entry);
@@ -2055,7 +2145,7 @@
 
 TEST_F(FakeDriveServiceTest, SetLastModifiedTime_Offline) {
   ASSERT_TRUE(fake_service_.LoadResourceListForWapi(
-      "chromeos/gdata/root_feed.json"));
+      "gdata/root_feed.json"));
   fake_service_.set_offline(true);
 
   const std::string kResourceId = "file:2_file_resource_id";
@@ -2068,7 +2158,7 @@
       kResourceId,
       time,
       test_util::CreateCopyResultCallback(&error, &resource_entry));
-      base::RunLoop().RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(GDATA_NO_CONNECTION, error);
   EXPECT_FALSE(resource_entry);
@@ -2076,4 +2166,4 @@
 
 }  // namespace
 
-}  // namespace google_apis
+}  // namespace drive
diff --git a/chrome/browser/drive/gdata_wapi_service.cc b/chrome/browser/drive/gdata_wapi_service.cc
index 8c8209c..689726b 100644
--- a/chrome/browser/drive/gdata_wapi_service.cc
+++ b/chrome/browser/drive/gdata_wapi_service.cc
@@ -9,22 +9,56 @@
 
 #include "base/bind.h"
 #include "base/message_loop.h"
-#include "base/strings/stringprintf.h"
 #include "base/values.h"
+#include "chrome/browser/drive/drive_api_util.h"
 #include "chrome/browser/google_apis/auth_service.h"
 #include "chrome/browser/google_apis/drive_api_parser.h"
-#include "chrome/browser/google_apis/drive_api_util.h"
 #include "chrome/browser/google_apis/gdata_wapi_parser.h"
 #include "chrome/browser/google_apis/gdata_wapi_requests.h"
 #include "chrome/browser/google_apis/gdata_wapi_url_generator.h"
 #include "chrome/browser/google_apis/request_sender.h"
-#include "chrome/browser/google_apis/time_util.h"
 #include "content/public/browser/browser_thread.h"
-#include "net/base/url_util.h"
 
 using content::BrowserThread;
+using google_apis::AboutResource;
+using google_apis::AccountMetadata;
+using google_apis::AddResourceToDirectoryRequest;
+using google_apis::AppList;
+using google_apis::AuthorizeAppCallback;
+using google_apis::AuthorizeAppRequest;
+using google_apis::AuthService;
+using google_apis::CancelCallback;
+using google_apis::CopyHostedDocumentRequest;
+using google_apis::CreateDirectoryRequest;
+using google_apis::DeleteResourceRequest;
+using google_apis::DownloadActionCallback;
+using google_apis::DownloadFileRequest;
+using google_apis::EntryActionCallback;
+using google_apis::GDataErrorCode;
+using google_apis::GDATA_PARSE_ERROR;
+using google_apis::GetAboutResourceCallback;
+using google_apis::GetAccountMetadataRequest;
+using google_apis::GetAppListCallback;
+using google_apis::GetContentCallback;
+using google_apis::GetResourceEntryCallback;
+using google_apis::GetResourceEntryRequest;
+using google_apis::GetResourceListCallback;
+using google_apis::GetResourceListRequest;
+using google_apis::GetUploadStatusRequest;
+using google_apis::HTTP_NOT_IMPLEMENTED;
+using google_apis::InitiateUploadCallback;
+using google_apis::InitiateUploadExistingFileRequest;
+using google_apis::InitiateUploadNewFileRequest;
+using google_apis::ProgressCallback;
+using google_apis::RemoveResourceFromDirectoryRequest;
+using google_apis::RenameResourceRequest;
+using google_apis::RequestSender;
+using google_apis::ResourceEntry;
+using google_apis::ResumeUploadRequest;
+using google_apis::SearchByTitleRequest;
+using google_apis::UploadRangeCallback;
 
-namespace google_apis {
+namespace drive {
 
 namespace {
 
@@ -95,10 +129,13 @@
 
 GDataWapiService::GDataWapiService(
     net::URLRequestContextGetter* url_request_context_getter,
+    base::TaskRunner* blocking_task_runner,
     const GURL& base_url,
+    const GURL& base_download_url,
     const std::string& custom_user_agent)
     : url_request_context_getter_(url_request_context_getter),
-      url_generator_(base_url),
+      blocking_task_runner_(blocking_task_runner),
+      url_generator_(base_url, base_download_url),
       custom_user_agent_(custom_user_agent) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
 }
@@ -165,13 +202,12 @@
 
   return sender_->StartRequestWithRetry(
       new GetResourceListRequest(sender_.get(),
-                                   url_request_context_getter_,
-                                   url_generator_,
-                                   GURL(),         // No override url
-                                   0,              // start changestamp
-                                   std::string(),  // empty search query
-                                   std::string(),  // no directory resource id
-                                   callback));
+                                 url_generator_,
+                                 GURL(),         // No override url
+                                 0,              // start changestamp
+                                 std::string(),  // empty search query
+                                 std::string(),  // no directory resource id
+                                 callback));
 }
 
 CancelCallback GDataWapiService::GetResourceListInDirectory(
@@ -183,13 +219,12 @@
 
   return sender_->StartRequestWithRetry(
       new GetResourceListRequest(sender_.get(),
-                                   url_request_context_getter_,
-                                   url_generator_,
-                                   GURL(),         // No override url
-                                   0,              // start changestamp
-                                   std::string(),  // empty search query
-                                   directory_resource_id,
-                                   callback));
+                                 url_generator_,
+                                 GURL(),         // No override url
+                                 0,              // start changestamp
+                                 std::string(),  // empty search query
+                                 directory_resource_id,
+                                 callback));
 }
 
 CancelCallback GDataWapiService::Search(
@@ -201,13 +236,12 @@
 
   return sender_->StartRequestWithRetry(
       new GetResourceListRequest(sender_.get(),
-                                   url_request_context_getter_,
-                                   url_generator_,
-                                   GURL(),         // No override url
-                                   0,              // start changestamp
-                                   search_query,
-                                   std::string(),  // no directory resource id
-                                   callback));
+                                 url_generator_,
+                                 GURL(),         // No override url
+                                 0,              // start changestamp
+                                 search_query,
+                                 std::string(),  // no directory resource id
+                                 callback));
 }
 
 CancelCallback GDataWapiService::SearchByTitle(
@@ -219,13 +253,11 @@
   DCHECK(!callback.is_null());
 
   return sender_->StartRequestWithRetry(
-      new SearchByTitleRequest(
-          sender_.get(),
-          url_request_context_getter_,
-          url_generator_,
-          title,
-          directory_resource_id,
-          callback));
+      new SearchByTitleRequest(sender_.get(),
+                               url_generator_,
+                               title,
+                               directory_resource_id,
+                               callback));
 }
 
 CancelCallback GDataWapiService::GetChangeList(
@@ -236,13 +268,12 @@
 
   return sender_->StartRequestWithRetry(
       new GetResourceListRequest(sender_.get(),
-                                   url_request_context_getter_,
-                                   url_generator_,
-                                   GURL(),         // No override url
-                                   start_changestamp,
-                                   std::string(),  // empty search query
-                                   std::string(),  // no directory resource id
-                                   callback));
+                                 url_generator_,
+                                 GURL(),         // No override url
+                                 start_changestamp,
+                                 std::string(),  // empty search query
+                                 std::string(),  // no directory resource id
+                                 callback));
 }
 
 CancelCallback GDataWapiService::ContinueGetResourceList(
@@ -254,13 +285,12 @@
 
   return sender_->StartRequestWithRetry(
       new GetResourceListRequest(sender_.get(),
-                                   url_request_context_getter_,
-                                   url_generator_,
-                                   override_url,
-                                   0,              // start changestamp
-                                   std::string(),  // empty search query
-                                   std::string(),  // no directory resource id
-                                   callback));
+                                 url_generator_,
+                                 override_url,
+                                 0,              // start changestamp
+                                 std::string(),  // empty search query
+                                 std::string(),  // no directory resource id
+                                 callback));
 }
 
 CancelCallback GDataWapiService::GetResourceEntry(
@@ -270,12 +300,11 @@
   DCHECK(!callback.is_null());
 
   return sender_->StartRequestWithRetry(
-      new GetResourceEntryRequest(
-          sender_.get(),
-          url_request_context_getter_,
-          url_generator_,
-          resource_id,
-          base::Bind(&ParseResourceEntryAndRun, callback)));
+      new GetResourceEntryRequest(sender_.get(),
+                                  url_generator_,
+                                  resource_id,
+                                  base::Bind(&ParseResourceEntryAndRun,
+                                             callback)));
 }
 
 CancelCallback GDataWapiService::GetAboutResource(
@@ -286,7 +315,6 @@
   return sender_->StartRequestWithRetry(
       new GetAccountMetadataRequest(
           sender_.get(),
-          url_request_context_getter_,
           url_generator_,
           base::Bind(&ParseAboutResourceAndRun, callback),
           false));  // Exclude installed apps.
@@ -298,18 +326,15 @@
   DCHECK(!callback.is_null());
 
   return sender_->StartRequestWithRetry(
-      new GetAccountMetadataRequest(
-          sender_.get(),
-          url_request_context_getter_,
-          url_generator_,
-          base::Bind(&ParseAppListAndRun, callback),
-          true));  // Include installed apps.
+      new GetAccountMetadataRequest(sender_.get(),
+                                    url_generator_,
+                                    base::Bind(&ParseAppListAndRun, callback),
+                                    true));  // Include installed apps.
 }
 
 CancelCallback GDataWapiService::DownloadFile(
-    const base::FilePath& virtual_path,
     const base::FilePath& local_cache_path,
-    const GURL& download_url,
+    const std::string& resource_id,
     const DownloadActionCallback& download_action_callback,
     const GetContentCallback& get_content_callback,
     const ProgressCallback& progress_callback) {
@@ -319,12 +344,11 @@
 
   return sender_->StartRequestWithRetry(
       new DownloadFileRequest(sender_.get(),
-                              url_request_context_getter_,
+                              url_generator_,
                               download_action_callback,
                               get_content_callback,
                               progress_callback,
-                              download_url,
-                              virtual_path,
+                              resource_id,
                               local_cache_path));
 }
 
@@ -337,11 +361,10 @@
 
   return sender_->StartRequestWithRetry(
       new DeleteResourceRequest(sender_.get(),
-                                  url_request_context_getter_,
-                                  url_generator_,
-                                  callback,
-                                  resource_id,
-                                  etag));
+                                url_generator_,
+                                callback,
+                                resource_id,
+                                etag));
 }
 
 CancelCallback GDataWapiService::AddNewDirectory(
@@ -353,12 +376,11 @@
 
   return sender_->StartRequestWithRetry(
       new CreateDirectoryRequest(sender_.get(),
-                                   url_request_context_getter_,
-                                   url_generator_,
-                                   base::Bind(&ParseResourceEntryAndRun,
-                                              callback),
-                                   parent_resource_id,
-                                   directory_name));
+                                 url_generator_,
+                                 base::Bind(&ParseResourceEntryAndRun,
+                                            callback),
+                                 parent_resource_id,
+                                 directory_name));
 }
 
 CancelCallback GDataWapiService::CopyResource(
@@ -384,13 +406,12 @@
   DCHECK(!callback.is_null());
 
   return sender_->StartRequestWithRetry(
-      new CopyHostedDocumentRequest(
-          sender_.get(),
-          url_request_context_getter_,
-          url_generator_,
-          base::Bind(&ParseResourceEntryAndRun, callback),
-          resource_id,
-          new_name));
+      new CopyHostedDocumentRequest(sender_.get(),
+                                    url_generator_,
+                                    base::Bind(&ParseResourceEntryAndRun,
+                                               callback),
+                                    resource_id,
+                                    new_name));
 }
 
 CancelCallback GDataWapiService::RenameResource(
@@ -402,11 +423,10 @@
 
   return sender_->StartRequestWithRetry(
       new RenameResourceRequest(sender_.get(),
-                                  url_request_context_getter_,
-                                  url_generator_,
-                                  callback,
-                                  resource_id,
-                                  new_name));
+                                url_generator_,
+                                callback,
+                                resource_id,
+                                new_name));
 }
 
 CancelCallback GDataWapiService::TouchResource(
@@ -437,11 +457,10 @@
 
   return sender_->StartRequestWithRetry(
       new AddResourceToDirectoryRequest(sender_.get(),
-                                          url_request_context_getter_,
-                                          url_generator_,
-                                          callback,
-                                          parent_resource_id,
-                                          resource_id));
+                                        url_generator_,
+                                        callback,
+                                        parent_resource_id,
+                                        resource_id));
 }
 
 CancelCallback GDataWapiService::RemoveResourceFromDirectory(
@@ -453,15 +472,13 @@
 
   return sender_->StartRequestWithRetry(
       new RemoveResourceFromDirectoryRequest(sender_.get(),
-                                               url_request_context_getter_,
-                                               url_generator_,
-                                               callback,
-                                               parent_resource_id,
-                                               resource_id));
+                                             url_generator_,
+                                             callback,
+                                             parent_resource_id,
+                                             resource_id));
 }
 
 CancelCallback GDataWapiService::InitiateUploadNewFile(
-    const base::FilePath& drive_file_path,
     const std::string& content_type,
     int64 content_length,
     const std::string& parent_resource_id,
@@ -473,18 +490,15 @@
 
   return sender_->StartRequestWithRetry(
       new InitiateUploadNewFileRequest(sender_.get(),
-                                         url_request_context_getter_,
-                                         url_generator_,
-                                         callback,
-                                         drive_file_path,
-                                         content_type,
-                                         content_length,
-                                         parent_resource_id,
-                                         title));
+                                       url_generator_,
+                                       callback,
+                                       content_type,
+                                       content_length,
+                                       parent_resource_id,
+                                       title));
 }
 
 CancelCallback GDataWapiService::InitiateUploadExistingFile(
-    const base::FilePath& drive_file_path,
     const std::string& content_type,
     int64 content_length,
     const std::string& resource_id,
@@ -496,18 +510,15 @@
 
   return sender_->StartRequestWithRetry(
       new InitiateUploadExistingFileRequest(sender_.get(),
-                                              url_request_context_getter_,
-                                              url_generator_,
-                                              callback,
-                                              drive_file_path,
-                                              content_type,
-                                              content_length,
-                                              resource_id,
-                                              etag));
+                                            url_generator_,
+                                            callback,
+                                            content_type,
+                                            content_length,
+                                            resource_id,
+                                            etag));
 }
 
 CancelCallback GDataWapiService::ResumeUpload(
-    const base::FilePath& drive_file_path,
     const GURL& upload_url,
     int64 start_position,
     int64 end_position,
@@ -521,20 +532,17 @@
 
   return sender_->StartRequestWithRetry(
       new ResumeUploadRequest(sender_.get(),
-                                url_request_context_getter_,
-                                callback,
-                                progress_callback,
-                                drive_file_path,
-                                upload_url,
-                                start_position,
-                                end_position,
-                                content_length,
-                                content_type,
-                                local_file_path));
+                              callback,
+                              progress_callback,
+                              upload_url,
+                              start_position,
+                              end_position,
+                              content_length,
+                              content_type,
+                              local_file_path));
 }
 
 CancelCallback GDataWapiService::GetUploadStatus(
-    const base::FilePath& drive_file_path,
     const GURL& upload_url,
     int64 content_length,
     const UploadRangeCallback& callback) {
@@ -543,11 +551,9 @@
 
   return sender_->StartRequestWithRetry(
       new GetUploadStatusRequest(sender_.get(),
-                                   url_request_context_getter_,
-                                   callback,
-                                   drive_file_path,
-                                   upload_url,
-                                   content_length));
+                                 callback,
+                                 upload_url,
+                                 content_length));
 }
 
 CancelCallback GDataWapiService::AuthorizeApp(
@@ -558,13 +564,11 @@
   DCHECK(!callback.is_null());
 
   return sender_->StartRequestWithRetry(
-      new AuthorizeAppRequest(
-          sender_.get(),
-          url_request_context_getter_,
-          url_generator_,
-          callback,
-          resource_id,
-          app_id));
+      new AuthorizeAppRequest(sender_.get(),
+                              url_generator_,
+                              callback,
+                              resource_id,
+                              app_id));
 }
 
 bool GDataWapiService::HasAccessToken() const {
@@ -600,4 +604,4 @@
   }
 }
 
-}  // namespace google_apis
+}  // namespace drive
diff --git a/chrome/browser/drive/gdata_wapi_service.h b/chrome/browser/drive/gdata_wapi_service.h
index ee91ecc..72e6c6c 100644
--- a/chrome/browser/drive/gdata_wapi_service.h
+++ b/chrome/browser/drive/gdata_wapi_service.h
@@ -7,6 +7,7 @@
 
 #include <string>
 
+#include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
@@ -20,33 +21,41 @@
 
 namespace base {
 class FilePath;
+class TaskRunner;
+}
+
+namespace google_apis {
+class AuthService;
+class RequestSender;
 }
 
 namespace net {
 class URLRequestContextGetter;
 }  // namespace net
 
-namespace google_apis {
-class AuthService;
-class RequestSender;
+namespace drive {
 
 // This class provides documents feed service calls for WAPI (codename for
 // DocumentsList API).
 // Details of API call are abstracted in each request class and this class
 // works as a thin wrapper for the API.
 class GDataWapiService : public DriveServiceInterface,
-                         public AuthServiceObserver {
+                         public google_apis::AuthServiceObserver {
  public:
   // |url_request_context_getter| is used to initialize URLFetcher.
+  // |blocking_task_runner| is used to run blocking tasks (like parsing JSON).
   // |base_url| is used to generate URLs for communicating with the WAPI
+  // |base_download_url| is used to generate URLs for downloading file with WAPI
   // |custom_user_agent| is used for the User-Agent header in HTTP
   // requests issued through the service if the value is not empty.
   GDataWapiService(net::URLRequestContextGetter* url_request_context_getter,
+                   base::TaskRunner* blocking_task_runner,
                    const GURL& base_url,
+                   const GURL& base_download_url,
                    const std::string& custom_user_agent);
   virtual ~GDataWapiService();
 
-  AuthService* auth_service_for_testing();
+  google_apis::AuthService* auth_service_for_testing();
 
   // DriveServiceInterface Overrides
   virtual void Initialize(Profile* profile) OVERRIDE;
@@ -60,121 +69,117 @@
   virtual void ClearAccessToken() OVERRIDE;
   virtual void ClearRefreshToken() OVERRIDE;
   virtual std::string GetRootResourceId() const OVERRIDE;
-  virtual CancelCallback GetAllResourceList(
-      const GetResourceListCallback& callback) OVERRIDE;
-  virtual CancelCallback GetResourceListInDirectory(
+  virtual google_apis::CancelCallback GetAllResourceList(
+      const google_apis::GetResourceListCallback& callback) OVERRIDE;
+  virtual google_apis::CancelCallback GetResourceListInDirectory(
       const std::string& directory_resource_id,
-      const GetResourceListCallback& callback) OVERRIDE;
-  virtual CancelCallback Search(
+      const google_apis::GetResourceListCallback& callback) OVERRIDE;
+  virtual google_apis::CancelCallback Search(
       const std::string& search_query,
-      const GetResourceListCallback& callback) OVERRIDE;
-  virtual CancelCallback SearchByTitle(
+      const google_apis::GetResourceListCallback& callback) OVERRIDE;
+  virtual google_apis::CancelCallback SearchByTitle(
       const std::string& title,
       const std::string& directory_resource_id,
-      const GetResourceListCallback& callback) OVERRIDE;
-  virtual CancelCallback GetChangeList(
+      const google_apis::GetResourceListCallback& callback) OVERRIDE;
+  virtual google_apis::CancelCallback GetChangeList(
       int64 start_changestamp,
-      const GetResourceListCallback& callback) OVERRIDE;
-  virtual CancelCallback ContinueGetResourceList(
+      const google_apis::GetResourceListCallback& callback) OVERRIDE;
+  virtual google_apis::CancelCallback ContinueGetResourceList(
       const GURL& override_url,
-      const GetResourceListCallback& callback) OVERRIDE;
-  virtual CancelCallback GetResourceEntry(
+      const google_apis::GetResourceListCallback& callback) OVERRIDE;
+  virtual google_apis::CancelCallback GetResourceEntry(
       const std::string& resource_id,
-      const GetResourceEntryCallback& callback) OVERRIDE;
-  virtual CancelCallback GetAboutResource(
-      const GetAboutResourceCallback& callback) OVERRIDE;
-  virtual CancelCallback GetAppList(
-      const GetAppListCallback& callback) OVERRIDE;
-  virtual CancelCallback DeleteResource(
+      const google_apis::GetResourceEntryCallback& callback) OVERRIDE;
+  virtual google_apis::CancelCallback GetAboutResource(
+      const google_apis::GetAboutResourceCallback& callback) OVERRIDE;
+  virtual google_apis::CancelCallback GetAppList(
+      const google_apis::GetAppListCallback& callback) OVERRIDE;
+  virtual google_apis::CancelCallback DeleteResource(
       const std::string& resource_id,
       const std::string& etag,
-      const EntryActionCallback& callback) OVERRIDE;
-  virtual CancelCallback DownloadFile(
-      const base::FilePath& virtual_path,
+      const google_apis::EntryActionCallback& callback) OVERRIDE;
+  virtual google_apis::CancelCallback DownloadFile(
       const base::FilePath& local_cache_path,
-      const GURL& download_url,
-      const DownloadActionCallback& download_action_callback,
-      const GetContentCallback& get_content_callback,
-      const ProgressCallback& progress_callback) OVERRIDE;
-  virtual CancelCallback CopyResource(
+      const std::string& resource_id,
+      const google_apis::DownloadActionCallback& download_action_callback,
+      const google_apis::GetContentCallback& get_content_callback,
+      const google_apis::ProgressCallback& progress_callback) OVERRIDE;
+  virtual google_apis::CancelCallback CopyResource(
       const std::string& resource_id,
       const std::string& parent_resource_id,
       const std::string& new_name,
-      const GetResourceEntryCallback& callback) OVERRIDE;
-  virtual CancelCallback CopyHostedDocument(
+      const google_apis::GetResourceEntryCallback& callback) OVERRIDE;
+  virtual google_apis::CancelCallback CopyHostedDocument(
       const std::string& resource_id,
       const std::string& new_name,
-      const GetResourceEntryCallback& callback) OVERRIDE;
-  virtual CancelCallback RenameResource(
+      const google_apis::GetResourceEntryCallback& callback) OVERRIDE;
+  virtual google_apis::CancelCallback RenameResource(
       const std::string& resource_id,
       const std::string& new_name,
-      const EntryActionCallback& callback) OVERRIDE;
-  virtual CancelCallback TouchResource(
+      const google_apis::EntryActionCallback& callback) OVERRIDE;
+  virtual google_apis::CancelCallback TouchResource(
       const std::string& resource_id,
       const base::Time& modified_date,
       const base::Time& last_viewed_by_me_date,
-      const GetResourceEntryCallback& callback) OVERRIDE;
-  virtual CancelCallback AddResourceToDirectory(
+      const google_apis::GetResourceEntryCallback& callback) OVERRIDE;
+  virtual google_apis::CancelCallback AddResourceToDirectory(
       const std::string& parent_resource_id,
       const std::string& resource_id,
-      const EntryActionCallback& callback) OVERRIDE;
-  virtual CancelCallback RemoveResourceFromDirectory(
+      const google_apis::EntryActionCallback& callback) OVERRIDE;
+  virtual google_apis::CancelCallback RemoveResourceFromDirectory(
       const std::string& parent_resource_id,
       const std::string& resource_id,
-      const EntryActionCallback& callback) OVERRIDE;
-  virtual CancelCallback AddNewDirectory(
+      const google_apis::EntryActionCallback& callback) OVERRIDE;
+  virtual google_apis::CancelCallback AddNewDirectory(
       const std::string& parent_resource_id,
       const std::string& directory_name,
-      const GetResourceEntryCallback& callback) OVERRIDE;
-  virtual CancelCallback InitiateUploadNewFile(
-      const base::FilePath& drive_file_path,
+      const google_apis::GetResourceEntryCallback& callback) OVERRIDE;
+  virtual google_apis::CancelCallback InitiateUploadNewFile(
       const std::string& content_type,
       int64 content_length,
       const std::string& parent_resource_id,
       const std::string& title,
-      const InitiateUploadCallback& callback) OVERRIDE;
-  virtual CancelCallback InitiateUploadExistingFile(
-      const base::FilePath& drive_file_path,
+      const google_apis::InitiateUploadCallback& callback) OVERRIDE;
+  virtual google_apis::CancelCallback InitiateUploadExistingFile(
       const std::string& content_type,
       int64 content_length,
       const std::string& resource_id,
       const std::string& etag,
-      const InitiateUploadCallback& callback) OVERRIDE;
-  virtual CancelCallback ResumeUpload(
-      const base::FilePath& drive_file_path,
+      const google_apis::InitiateUploadCallback& callback) OVERRIDE;
+  virtual google_apis::CancelCallback ResumeUpload(
       const GURL& upload_url,
       int64 start_position,
       int64 end_position,
       int64 content_length,
       const std::string& content_type,
       const base::FilePath& local_file_path,
-      const UploadRangeCallback& callback,
-      const ProgressCallback& progress_callback) OVERRIDE;
-  virtual CancelCallback GetUploadStatus(
-      const base::FilePath& drive_file_path,
+      const google_apis::UploadRangeCallback& callback,
+      const google_apis::ProgressCallback& progress_callback) OVERRIDE;
+  virtual google_apis::CancelCallback GetUploadStatus(
       const GURL& upload_url,
       int64 content_length,
-      const UploadRangeCallback& callback) OVERRIDE;
-  virtual CancelCallback AuthorizeApp(
+      const google_apis::UploadRangeCallback& callback) OVERRIDE;
+  virtual google_apis::CancelCallback AuthorizeApp(
       const std::string& resource_id,
       const std::string& app_id,
-      const AuthorizeAppCallback& callback) OVERRIDE;
+      const google_apis::AuthorizeAppCallback& callback) OVERRIDE;
 
  private:
   // AuthService::Observer override.
   virtual void OnOAuth2RefreshTokenChanged() OVERRIDE;
 
   net::URLRequestContextGetter* url_request_context_getter_;  // Not owned.
-  scoped_ptr<RequestSender> sender_;
+  scoped_refptr<base::TaskRunner> blocking_task_runner_;
+  scoped_ptr<google_apis::RequestSender> sender_;
   ObserverList<DriveServiceObserver> observers_;
   // Request objects should hold a copy of this, rather than a const
   // reference, as they may outlive this object.
-  const GDataWapiUrlGenerator url_generator_;
+  const google_apis::GDataWapiUrlGenerator url_generator_;
   const std::string custom_user_agent_;
 
   DISALLOW_COPY_AND_ASSIGN(GDataWapiService);
 };
 
-}  // namespace google_apis
+}  // namespace drive
 
 #endif  // CHROME_BROWSER_DRIVE_GDATA_WAPI_SERVICE_H_
diff --git a/chrome/browser/drive/mock_drive_service.cc b/chrome/browser/drive/mock_drive_service.cc
deleted file mode 100644
index 0e94823..0000000
--- a/chrome/browser/drive/mock_drive_service.cc
+++ /dev/null
@@ -1,144 +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/drive/mock_drive_service.h"
-
-#include "base/bind.h"
-#include "base/files/file_path.h"
-#include "base/location.h"
-#include "base/message_loop/message_loop_proxy.h"
-#include "base/values.h"
-#include "chrome/browser/google_apis/gdata_wapi_parser.h"
-#include "chrome/browser/google_apis/test_util.h"
-#include "testing/gmock/include/gmock/gmock.h"
-
-using ::testing::_;
-using ::testing::Invoke;
-using ::testing::Return;
-
-namespace google_apis {
-
-MockDriveService::MockDriveService() {
-  ON_CALL(*this, GetChangeList(_, _))
-      .WillByDefault(Invoke(this, &MockDriveService::GetChangeListStub));
-  ON_CALL(*this, DeleteResource(_, _, _))
-      .WillByDefault(Invoke(this, &MockDriveService::DeleteResourceStub));
-  ON_CALL(*this, CopyHostedDocument(_, _, _))
-      .WillByDefault(Invoke(this, &MockDriveService::CopyHostedDocumentStub));
-  ON_CALL(*this, RenameResource(_, _, _))
-      .WillByDefault(Invoke(this, &MockDriveService::RenameResourceStub));
-  ON_CALL(*this, AddResourceToDirectory(_, _, _))
-      .WillByDefault(
-          Invoke(this, &MockDriveService::AddResourceToDirectoryStub));
-  ON_CALL(*this, RemoveResourceFromDirectory(_, _, _))
-      .WillByDefault(
-          Invoke(this, &MockDriveService::RemoveResourceFromDirectoryStub));
-  ON_CALL(*this, AddNewDirectory(_, _, _))
-      .WillByDefault(Invoke(this, &MockDriveService::CreateDirectoryStub));
-  ON_CALL(*this, DownloadFile(_, _, _, _, _, _))
-      .WillByDefault(Invoke(this, &MockDriveService::DownloadFileStub));
-
-  // Fill in the default values for mock data.
-  directory_data_ =
-      test_util::LoadJSONFile("chromeos/gdata/new_folder_entry.json");
-}
-
-MockDriveService::~MockDriveService() {}
-
-CancelCallback MockDriveService::GetChangeListStub(
-    int64 start_changestamp,
-    const GetResourceListCallback& callback) {
-  scoped_ptr<ResourceList> resource_list(new ResourceList());
-  base::MessageLoopProxy::current()->PostTask(
-      FROM_HERE,
-      base::Bind(callback, HTTP_SUCCESS,
-                 base::Passed(&resource_list)));
-  return CancelCallback();
-}
-
-CancelCallback MockDriveService::DeleteResourceStub(
-    const std::string& resource_id,
-    const std::string& etag,
-    const EntryActionCallback& callback) {
-  base::MessageLoopProxy::current()->PostTask(
-      FROM_HERE,
-      base::Bind(callback, HTTP_SUCCESS));
-  return CancelCallback();
-}
-
-CancelCallback MockDriveService::CopyHostedDocumentStub(
-    const std::string& resource_id,
-    const std::string& new_name,
-    const GetResourceEntryCallback& callback) {
-  scoped_ptr<ResourceEntry> resource_entry =
-      ResourceEntry::ExtractAndParse(*document_data_);
-  base::MessageLoopProxy::current()->PostTask(
-      FROM_HERE,
-      base::Bind(callback, HTTP_SUCCESS,
-                 base::Passed(&resource_entry)));
-  return CancelCallback();
-}
-
-CancelCallback MockDriveService::RenameResourceStub(
-    const std::string& resource_id,
-    const std::string& new_name,
-    const EntryActionCallback& callback) {
-  base::MessageLoopProxy::current()->PostTask(
-      FROM_HERE,
-      base::Bind(callback, HTTP_SUCCESS));
-  return CancelCallback();
-}
-
-CancelCallback MockDriveService::AddResourceToDirectoryStub(
-    const std::string& parent_resource_id,
-    const std::string& resource_id,
-    const EntryActionCallback& callback) {
-  base::MessageLoopProxy::current()->PostTask(
-      FROM_HERE,
-      base::Bind(callback, HTTP_SUCCESS));
-  return CancelCallback();
-}
-
-CancelCallback MockDriveService::RemoveResourceFromDirectoryStub(
-    const std::string& parent_resource_id,
-    const std::string& resource_id,
-    const EntryActionCallback& callback) {
-  base::MessageLoopProxy::current()->PostTask(
-      FROM_HERE,
-      base::Bind(callback, HTTP_SUCCESS));
-  return CancelCallback();
-}
-
-CancelCallback MockDriveService::CreateDirectoryStub(
-    const std::string& parent_resource_id,
-    const std::string& directory_name,
-    const GetResourceEntryCallback& callback) {
-  scoped_ptr<ResourceEntry> resource_entry =
-      ResourceEntry::ExtractAndParse(*directory_data_);
-  base::MessageLoopProxy::current()->PostTask(
-      FROM_HERE,
-      base::Bind(callback, HTTP_SUCCESS,
-                 base::Passed(&resource_entry)));
-  return CancelCallback();
-}
-
-CancelCallback MockDriveService::DownloadFileStub(
-    const base::FilePath& virtual_path,
-    const base::FilePath& local_tmp_path,
-    const GURL& download_url,
-    const DownloadActionCallback& download_action_callback,
-    const GetContentCallback& get_content_callback,
-    const ProgressCallback& progress_callback) {
-  GDataErrorCode error = HTTP_SUCCESS;
-  if (file_data_.get()) {
-    if (!test_util::WriteStringToFile(local_tmp_path, *file_data_))
-      error = GDATA_FILE_ERROR;
-  }
-  base::MessageLoopProxy::current()->PostTask(
-      FROM_HERE,
-      base::Bind(download_action_callback, error, local_tmp_path));
-  return CancelCallback();
-}
-
-}  // namespace google_apis
diff --git a/chrome/browser/drive/mock_drive_service.h b/chrome/browser/drive/mock_drive_service.h
deleted file mode 100644
index 77b7770..0000000
--- a/chrome/browser/drive/mock_drive_service.h
+++ /dev/null
@@ -1,216 +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.
-
-// This file contains mocks for classes in drive_service_interface.h
-
-#ifndef CHROME_BROWSER_DRIVE_MOCK_DRIVE_SERVICE_H_
-#define CHROME_BROWSER_DRIVE_MOCK_DRIVE_SERVICE_H_
-
-#include <string>
-
-#include "base/memory/scoped_ptr.h"
-#include "chrome/browser/drive/drive_service_interface.h"
-#include "testing/gmock/include/gmock/gmock.h"
-
-namespace base {
-class FilePath;
-}
-
-namespace google_apis {
-
-class MockDriveService : public DriveServiceInterface {
- public:
-  MockDriveService();
-  virtual ~MockDriveService();
-
-  // DriveServiceInterface overrides.
-  MOCK_METHOD1(Initialize, void(Profile* profile));
-  MOCK_METHOD1(AddObserver, void(DriveServiceObserver* observer));
-  MOCK_METHOD1(RemoveObserver,
-      void(DriveServiceObserver* observer));
-  MOCK_CONST_METHOD0(CanSendRequest, bool());
-  MOCK_CONST_METHOD1(CanonicalizeResourceId,
-                     std::string(const std::string& resource_id));
-  MOCK_CONST_METHOD0(GetRootResourceId, std::string());
-  MOCK_METHOD1(GetAllResourceList,
-      CancelCallback(const GetResourceListCallback& callback));
-  MOCK_METHOD2(GetResourceListInDirectory,
-      CancelCallback(const std::string& directory_resource_id,
-                     const GetResourceListCallback& callback));
-  MOCK_METHOD2(Search,
-      CancelCallback(const std::string& search_query,
-                     const GetResourceListCallback& callback));
-  MOCK_METHOD3(SearchByTitle,
-      CancelCallback(const std::string& title,
-                     const std::string& directory_resource_id,
-                     const GetResourceListCallback& callback));
-  MOCK_METHOD2(GetChangeList,
-      CancelCallback(int64 start_changestamp,
-                    const GetResourceListCallback& callback));
-  MOCK_METHOD2(ContinueGetResourceList,
-      CancelCallback(const GURL& override_url,
-                     const GetResourceListCallback& callback));
-  MOCK_METHOD2(GetResourceEntry,
-      CancelCallback(const std::string& resource_id,
-                     const GetResourceEntryCallback& callback));
-  MOCK_METHOD1(GetAboutResource,
-      CancelCallback(const GetAboutResourceCallback& callback));
-  MOCK_METHOD1(GetAppList,
-      CancelCallback(const GetAppListCallback& callback));
-  MOCK_METHOD3(DeleteResource,
-      CancelCallback(const std::string& resource_id,
-                     const std::string& etag,
-                     const EntryActionCallback& callback));
-  MOCK_METHOD4(CopyResource,
-      CancelCallback(const std::string& resource_id,
-                     const std::string& parent_resource_id,
-                     const std::string& new_name,
-                     const GetResourceEntryCallback& callback));
-  MOCK_METHOD3(CopyHostedDocument,
-      CancelCallback(const std::string& resource_id,
-                     const std::string& new_name,
-                     const GetResourceEntryCallback& callback));
-  MOCK_METHOD3(RenameResource,
-      CancelCallback(const std::string& resource_id,
-                     const std::string& new_name,
-                     const EntryActionCallback& callback));
-  MOCK_METHOD4(TouchResource,
-      CancelCallback(const std::string& resource_id,
-                     const base::Time& modified_date,
-                     const base::Time& last_viewed_by_me_date,
-                     const GetResourceEntryCallback& callback));
-  MOCK_METHOD3(AddResourceToDirectory,
-      CancelCallback(const std::string& parent_resource_id,
-                     const std::string& resource_id,
-                     const EntryActionCallback& callback));
-  MOCK_METHOD3(RemoveResourceFromDirectory,
-      CancelCallback(const std::string& parent_resource_id,
-                     const std::string& resource_id,
-                     const EntryActionCallback& callback));
-  MOCK_METHOD3(AddNewDirectory,
-      CancelCallback(const std::string& parent_resource_id,
-                     const std::string& directory_name,
-                     const GetResourceEntryCallback& callback));
-  MOCK_METHOD6(
-      DownloadFile,
-      CancelCallback(const base::FilePath& virtual_path,
-                     const base::FilePath& local_cache_path,
-                     const GURL& download_url,
-                     const DownloadActionCallback& donwload_action_callback,
-                     const GetContentCallback& get_content_callback,
-                     const ProgressCallback& progress_callback));
-  MOCK_METHOD6(InitiateUploadNewFile,
-      CancelCallback(const base::FilePath& drive_file_path,
-                     const std::string& content_type,
-                     int64 content_length,
-                     const std::string& parent_resource_id,
-                     const std::string& title,
-                     const InitiateUploadCallback& callback));
-  MOCK_METHOD6(InitiateUploadExistingFile,
-      CancelCallback(const base::FilePath& drive_file_path,
-                     const std::string& content_type,
-                     int64 content_length,
-                     const std::string& resource_id,
-                     const std::string& etag,
-                     const InitiateUploadCallback& callback));
-  MOCK_METHOD9(ResumeUpload,
-      CancelCallback(const base::FilePath& drive_file_path,
-                     const GURL& upload_url,
-                     int64 start_position,
-                     int64 end_position,
-                     int64 content_length,
-                     const std::string& content_type,
-                     const base::FilePath& local_file_path,
-                     const UploadRangeCallback& callback,
-                     const ProgressCallback& progress_callback));
-  MOCK_METHOD4(GetUploadStatus,
-      CancelCallback(const base::FilePath& drive_file_path,
-                     const GURL& upload_url,
-                     int64 content_length,
-                     const UploadRangeCallback& callback));
-  MOCK_METHOD3(AuthorizeApp,
-      CancelCallback(const std::string& resource_id,
-                     const std::string& app_id,
-                     const AuthorizeAppCallback& callback));
-  MOCK_CONST_METHOD0(HasAccessToken, bool());
-  MOCK_CONST_METHOD0(HasRefreshToken, bool());
-  MOCK_METHOD0(ClearAccessToken, void());
-  MOCK_METHOD0(ClearRefreshToken, void());
-
-  void set_file_data(std::string* file_data) {
-    file_data_.reset(file_data);
-  }
-
- private:
-  // Helper stub methods for functions which take callbacks, so that
-  // the callbacks get called with testable results.
-
-  // Will call |callback| with HTTP_SUCCESS and a empty ResourceList.
-  CancelCallback GetChangeListStub(
-      int64 start_changestamp,
-      const GetResourceListCallback& callback);
-
-  // Will call |callback| with HTTP_SUCCESS.
-  CancelCallback DeleteResourceStub(
-      const std::string& resource_id,
-      const std::string& etag,
-      const EntryActionCallback& callback);
-
-  // Will call |callback| with HTTP_SUCCESS and the current value of
-  // |document_data_|.
-  CancelCallback CopyHostedDocumentStub(
-      const std::string& resource_id,
-      const std::string& new_name,
-      const GetResourceEntryCallback& callback);
-
-  // Will call |callback| with HTTP_SUCCESS.
-  CancelCallback RenameResourceStub(
-      const std::string& resource_id,
-      const std::string& new_name,
-      const EntryActionCallback& callback);
-
-  // Will call |callback| with HTTP_SUCCESS.
-  CancelCallback AddResourceToDirectoryStub(
-      const std::string& parent_resource_id,
-      const std::string& resource_id,
-      const EntryActionCallback& callback);
-
-  // Will call |callback| with HTTP_SUCCESS.
-  CancelCallback RemoveResourceFromDirectoryStub(
-      const std::string& parent_resource_id,
-      const std::string& resource_id,
-      const EntryActionCallback& callback);
-
-  // Will call |callback| with HTTP_SUCCESS and the current value of
-  // |directory_data_|.
-  CancelCallback CreateDirectoryStub(
-      const std::string& parent_resource_id,
-      const std::string& directory_name,
-      const GetResourceEntryCallback& callback);
-
-  // Will call |callback| with HTTP_SUCCESS, the given URL, and the host+path
-  // portion of the URL as the temporary file path. If |file_data_| is not null,
-  // |file_data_| is written to the temporary file.
-  CancelCallback DownloadFileStub(
-      const base::FilePath& virtual_path,
-      const base::FilePath& local_tmp_path,
-      const GURL& download_url,
-      const DownloadActionCallback& download_action_callback,
-      const GetContentCallback& get_content_callback,
-      const ProgressCallback& progress_callback);
-
-  // JSON data to be returned from CreateDirectory.
-  scoped_ptr<base::Value> directory_data_;
-
-  // JSON data to be returned from CopyHostedDocument.
-  scoped_ptr<base::Value> document_data_;
-
-  // File data to be written to the local temporary file when
-  // DownloadFileStub is called.
-  scoped_ptr<std::string> file_data_;
-};
-
-}  // namespace google_apis
-
-#endif  // CHROME_BROWSER_DRIVE_MOCK_DRIVE_SERVICE_H_
diff --git a/chrome/browser/enumerate_modules_model_win.cc b/chrome/browser/enumerate_modules_model_win.cc
index a8bedbb..279cbd2 100644
--- a/chrome/browser/enumerate_modules_model_win.cc
+++ b/chrome/browser/enumerate_modules_model_win.cc
@@ -18,7 +18,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "base/values.h"
 #include "base/version.h"
 #include "base/win/registry.h"
diff --git a/chrome/browser/enumerate_modules_model_win.h b/chrome/browser/enumerate_modules_model_win.h
index 87e53c4..51243d1 100644
--- a/chrome/browser/enumerate_modules_model_win.h
+++ b/chrome/browser/enumerate_modules_model_win.h
@@ -12,9 +12,9 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/singleton.h"
 #include "base/strings/string16.h"
-#include "base/timer.h"
+#include "base/timer/timer.h"
 #include "content/public/browser/browser_thread.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 class EnumerateModulesModel;
 
diff --git a/chrome/browser/extensions/DEPS b/chrome/browser/extensions/DEPS
index 92be07f..05df41b 100644
--- a/chrome/browser/extensions/DEPS
+++ b/chrome/browser/extensions/DEPS
@@ -1,5 +1,10 @@
 include_rules = [
+  # TODO(benwells): Once the extensions component is established
+  # and there are only chrome specific extension things left in
+  # chrome/browser/extensions, the restriction of not being able
+  # to depend on apps will be lifted.
   "-apps",
+  "+apps/shell_window.h",
 
   # TODO(tfarina): Remove all these. crbug.com/125846.
   # DO NOT ADD ANY MORE ITEMS TO THE LIST BELOW!
diff --git a/chrome/browser/extensions/OWNERS b/chrome/browser/extensions/OWNERS
index 58e6f16..bb8432e 100644
--- a/chrome/browser/extensions/OWNERS
+++ b/chrome/browser/extensions/OWNERS
@@ -12,7 +12,6 @@
 benwells@chromium.org
 erikkay@chromium.org
 finnur@chromium.org
-jeremya@chromium.org
 jyasskin@chromium.org
 kalman@chromium.org
 koz@chromium.org
diff --git a/chrome/browser/extensions/active_tab_apitest.cc b/chrome/browser/extensions/active_tab_apitest.cc
index 836d94c..d6a6d1d 100644
--- a/chrome/browser/extensions/active_tab_apitest.cc
+++ b/chrome/browser/extensions/active_tab_apitest.cc
@@ -9,6 +9,7 @@
 #include "chrome/browser/ui/browser.h"
 #include "chrome/common/extensions/extension.h"
 #include "chrome/test/base/ui_test_utils.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
 
 namespace extensions {
 namespace {
@@ -20,7 +21,7 @@
 #define MAYBE_ActiveTab ActiveTab
 #endif
 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, MAYBE_ActiveTab) {
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
 
   const Extension* extension =
       LoadExtension(test_data_dir_.AppendASCII("active_tab"));
@@ -32,7 +33,10 @@
   // Shouldn't be initially granted based on activeTab.
   {
     ResultCatcher catcher;
-    ui_test_utils::NavigateToURL(browser(), test_server()->GetURL("page.html"));
+    ui_test_utils::NavigateToURL(
+        browser(),
+        embedded_test_server()->GetURL(
+            "/extensions/api_test/active_tab/page.html"));
     EXPECT_TRUE(catcher.GetNextResult()) << message_;
   }
 
@@ -46,8 +50,10 @@
   // Changing page should go back to it not having access.
   {
     ResultCatcher catcher;
-    ui_test_utils::NavigateToURL(browser(),
-                                 test_server()->GetURL("final_page.html"));
+    ui_test_utils::NavigateToURL(
+        browser(),
+        embedded_test_server()->GetURL(
+            "/extensions/api_test/active_tab/final_page.html"));
     EXPECT_TRUE(catcher.GetNextResult()) << message_;
   }
 }
diff --git a/chrome/browser/extensions/activity_log/activity_actions.h b/chrome/browser/extensions/activity_log/activity_actions.h
index 5e2cbd5..2a5d636 100644
--- a/chrome/browser/extensions/activity_log/activity_actions.h
+++ b/chrome/browser/extensions/activity_log/activity_actions.h
@@ -7,7 +7,7 @@
 
 #include <string>
 #include "base/memory/ref_counted_memory.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "base/values.h"
 #include "chrome/common/extensions/api/activity_log_private.h"
 #include "sql/connection.h"
diff --git a/chrome/browser/extensions/activity_log/activity_database.cc b/chrome/browser/extensions/activity_log/activity_database.cc
index 47e22a6..20f4b98 100644
--- a/chrome/browser/extensions/activity_log/activity_database.cc
+++ b/chrome/browser/extensions/activity_log/activity_database.cc
@@ -9,8 +9,8 @@
 #include "base/strings/stringprintf.h"
 #include "base/threading/thread.h"
 #include "base/threading/thread_checker.h"
-#include "base/time.h"
 #include "base/time/clock.h"
+#include "base/time/time.h"
 #include "chrome/browser/extensions/activity_log/activity_database.h"
 #include "chrome/common/chrome_switches.h"
 #include "sql/error_delegate_util.h"
diff --git a/chrome/browser/extensions/activity_log/activity_database.h b/chrome/browser/extensions/activity_log/activity_database.h
index 242aaf8..8c3c42f 100644
--- a/chrome/browser/extensions/activity_log/activity_database.h
+++ b/chrome/browser/extensions/activity_log/activity_database.h
@@ -11,7 +11,7 @@
 #include "base/files/file_path.h"
 #include "base/memory/ref_counted_memory.h"
 #include "base/synchronization/lock.h"
-#include "base/timer.h"
+#include "base/timer/timer.h"
 #include "chrome/browser/extensions/activity_log/api_actions.h"
 #include "chrome/browser/extensions/activity_log/blocked_actions.h"
 #include "chrome/browser/extensions/activity_log/dom_actions.h"
diff --git a/chrome/browser/extensions/activity_log/activity_database_unittest.cc b/chrome/browser/extensions/activity_log/activity_database_unittest.cc
index dae4f72..56ac824 100644
--- a/chrome/browser/extensions/activity_log/activity_database_unittest.cc
+++ b/chrome/browser/extensions/activity_log/activity_database_unittest.cc
@@ -9,7 +9,7 @@
 #include "base/files/scoped_temp_dir.h"
 #include "base/run_loop.h"
 #include "base/test/simple_test_clock.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/extensions/activity_log/activity_database.h"
 #include "chrome/browser/extensions/activity_log/api_actions.h"
 #include "chrome/browser/extensions/activity_log/blocked_actions.h"
@@ -75,7 +75,7 @@
   base::FilePath db_file;
   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
   db_file = temp_dir.path().AppendASCII("ActivityInit.db");
-  file_util::Delete(db_file, false);
+  base::Delete(db_file, false);
 
   ActivityDatabase* activity_db = new ActivityDatabase();
   activity_db->Init(db_file);
@@ -96,7 +96,7 @@
   base::FilePath db_file;
   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
   db_file = temp_dir.path().AppendASCII("ActivityRecord.db");
-  file_util::Delete(db_file, false);
+  base::Delete(db_file, false);
 
   ActivityDatabase* activity_db = new ActivityDatabase();
   activity_db->Init(db_file);
@@ -132,7 +132,7 @@
   base::FilePath db_file;
   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
   db_file = temp_dir.path().AppendASCII("ActivityRecord.db");
-  file_util::Delete(db_file, false);
+  base::Delete(db_file, false);
 
   ActivityDatabase* activity_db = new ActivityDatabase();
   activity_db->Init(db_file);
@@ -177,7 +177,7 @@
   base::FilePath db_file;
   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
   db_file = temp_dir.path().AppendASCII("ActivityRecord.db");
-  file_util::Delete(db_file, false);
+  base::Delete(db_file, false);
 
   ActivityDatabase* activity_db = new ActivityDatabase();
   activity_db->Init(db_file);
@@ -213,7 +213,7 @@
   base::FilePath db_file;
   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
   db_file = temp_dir.path().AppendASCII("ActivityRecord.db");
-  file_util::Delete(db_file, false);
+  base::Delete(db_file, false);
 
   // Use a mock clock to ensure that events are not recorded on the wrong day
   // when the test is run close to local midnight.
@@ -273,7 +273,7 @@
   base::FilePath db_file;
   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
   db_file = temp_dir.path().AppendASCII("ActivityRecord.db");
-  file_util::Delete(db_file, false);
+  base::Delete(db_file, false);
 
   // Use a mock clock to ensure that events are not recorded on the wrong day
   // when the test is run close to local midnight.
@@ -343,7 +343,7 @@
   base::FilePath db_file;
   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
   db_file = temp_dir.path().AppendASCII("ActivityRecord.db");
-  file_util::Delete(db_file, false);
+  base::Delete(db_file, false);
 
   // Use a mock clock to ensure that events are not recorded on the wrong day
   // when the test is run close to local midnight.
@@ -377,7 +377,7 @@
   base::FilePath db_file;
   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
   db_file = temp_dir.path().AppendASCII("ActivityRecord.db");
-  file_util::Delete(db_file, false);
+  base::Delete(db_file, false);
 
   // Use a mock clock to set the time, and a special timer to control the
   // timing and skip ahead in time.
@@ -421,7 +421,7 @@
   base::FilePath db_file;
   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
   db_file = temp_dir.path().AppendASCII("ActivityRecord.db");
-  file_util::Delete(db_file, false);
+  base::Delete(db_file, false);
 
   ActivityDatabase* activity_db = new ActivityDatabase();
   scoped_refptr<APIAction> action = new APIAction(
diff --git a/chrome/browser/extensions/activity_log/activity_log.cc b/chrome/browser/extensions/activity_log/activity_log.cc
index cecf3fe..278a157 100644
--- a/chrome/browser/extensions/activity_log/activity_log.cc
+++ b/chrome/browser/extensions/activity_log/activity_log.cc
@@ -32,9 +32,9 @@
 namespace {
 
 // Concatenate arguments.
-std::string MakeArgList(const ListValue* args) {
+std::string MakeArgList(const base::ListValue* args) {
   std::string call_signature;
-  ListValue::const_iterator it = args->begin();
+  base::ListValue::const_iterator it = args->begin();
   for (; it != args->end(); ++it) {
     std::string arg;
     JSONStringValueSerializer serializer(&arg);
@@ -237,7 +237,7 @@
 
 void ActivityLog::LogAPIActionInternal(const std::string& extension_id,
                                        const std::string& api_call,
-                                       ListValue* args,
+                                       base::ListValue* args,
                                        const std::string& extra,
                                        const APIAction::Type type) {
   std::string verb, manager;
@@ -283,7 +283,7 @@
 // A wrapper around LogAPIActionInternal, but we know it's an API call.
 void ActivityLog::LogAPIAction(const std::string& extension_id,
                                const std::string& api_call,
-                               ListValue* args,
+                               base::ListValue* args,
                                const std::string& extra) {
   if (!IsLogEnabled() ||
       ActivityLogAPI::IsExtensionWhitelisted(extension_id)) return;
@@ -300,7 +300,7 @@
 // handle them. Right now they're being handled almost the same.
 void ActivityLog::LogEventAction(const std::string& extension_id,
                                  const std::string& api_call,
-                                 ListValue* args,
+                                 base::ListValue* args,
                                  const std::string& extra) {
   if (!IsLogEnabled() ||
       ActivityLogAPI::IsExtensionWhitelisted(extension_id)) return;
@@ -313,7 +313,7 @@
 
 void ActivityLog::LogBlockedAction(const std::string& extension_id,
                                    const std::string& blocked_call,
-                                   ListValue* args,
+                                   base::ListValue* args,
                                    BlockedAction::Reason reason,
                                    const std::string& extra) {
   if (!IsLogEnabled() ||
@@ -348,7 +348,7 @@
                                const GURL& url,
                                const string16& url_title,
                                const std::string& api_call,
-                               const ListValue* args,
+                               const base::ListValue* args,
                                DomActionType::Type call_type,
                                const std::string& extra) {
   if (!IsLogEnabled() ||
@@ -480,8 +480,8 @@
         ext_scripts_str += *it2;
         ext_scripts_str += " ";
       }
-      scoped_ptr<ListValue> script_names(new ListValue());
-      script_names->Set(0, new StringValue(ext_scripts_str));
+      scoped_ptr<base::ListValue> script_names(new base::ListValue());
+      script_names->Set(0, new base::StringValue(ext_scripts_str));
       LogDOMAction(extension->id(),
                    on_url,
                    web_contents->GetTitle(),
diff --git a/chrome/browser/extensions/activity_log/activity_log.h b/chrome/browser/extensions/activity_log/activity_log.h
index 423de34..fd9b6e2 100644
--- a/chrome/browser/extensions/activity_log/activity_log.h
+++ b/chrome/browser/extensions/activity_log/activity_log.h
@@ -70,7 +70,7 @@
   // (Note: implemented as a wrapper for LogAPIActionInternal.)
   void LogAPIAction(const std::string& extension_id,
                     const std::string& name,    // e.g., tabs.get
-                    ListValue* args,            // the argument values e.g. 46
+                    base::ListValue* args,      // the argument values e.g. 46
                     const std::string& extra);  // any extra logging info
 
   // Log an event notification delivered to an extension.
@@ -78,14 +78,14 @@
   // (Note: implemented as a wrapper for LogAPIActionInternal.)
   void LogEventAction(const std::string& extension_id,
                       const std::string& name,    // e.g., tabs.onUpdate
-                      ListValue* args,            // arguments to the callback
+                      base::ListValue* args,      // arguments to the callback
                       const std::string& extra);  // any extra logging info
 
   // Log a blocked API call made by an extension.
   // This will create a BlockedAction for storage in the database.
   void LogBlockedAction(const std::string& extension_id,
                         const std::string& blocked_call,  // e.g., tabs.get
-                        ListValue* args,                  // argument values
+                        base::ListValue* args,            // argument values
                         BlockedAction::Reason reason,     // why it's blocked
                         const std::string& extra);        // extra logging info
 
@@ -95,7 +95,7 @@
                     const GURL& url,                      // target URL
                     const string16& url_title,            // title of the URL
                     const std::string& api_call,          // api call
-                    const ListValue* args,                // arguments
+                    const base::ListValue* args,          // arguments
                     DomActionType::Type call_type,        // type of the call
                     const std::string& extra);            // extra logging info
 
@@ -168,7 +168,7 @@
   void LogAPIActionInternal(
       const std::string& extension_id,
       const std::string& api_call,
-      ListValue* args,
+      base::ListValue* args,
       const std::string& extra,
       const APIAction::Type type);
 
diff --git a/chrome/browser/extensions/activity_log/activity_log_browsertest.cc b/chrome/browser/extensions/activity_log/activity_log_browsertest.cc
index 2080b6e..3368730 100644
--- a/chrome/browser/extensions/activity_log/activity_log_browsertest.cc
+++ b/chrome/browser/extensions/activity_log/activity_log_browsertest.cc
@@ -15,6 +15,7 @@
 #include "content/public/browser/notification_service.h"
 #include "content/public/test/browser_test_utils.h"
 #include "net/dns/mock_host_resolver.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
 
 namespace extensions {
 
@@ -37,9 +38,9 @@
   }
   // Start the test server, load the activity log extension, and navigate
   // the browser to the options page of the extension.
-  TabStripModel* StartTestServerAndInitialize() {
+  TabStripModel* StartEmbeddedTestServerAndInitialize() {
     host_resolver()->AddRule("*", "127.0.0.1");
-    StartTestServer();
+    StartEmbeddedTestServer();
 
     // Get the extension (chrome/test/data/extensions/activity_log)
     const extensions::Extension* ext =
@@ -81,12 +82,12 @@
 #endif
 
 IN_PROC_BROWSER_TEST_F(ActivityLogExtensionTest, MAYBE_ChromeEndToEnd) {
-  TabStripModel* tab_strip = StartTestServerAndInitialize();
+  TabStripModel* tab_strip = StartEmbeddedTestServerAndInitialize();
   ResultCatcher catcher;
   // Set the default URL so that is has the correct port number.
-  net::HostPortPair host_port = test_server()->host_port_pair();
   std::string url_setting_script = base::StringPrintf(
-      "defaultUrl = \'http://www.google.com:%d\';", host_port.port());
+      "defaultUrl = \'http://www.google.com:%d\';",
+      embedded_test_server()->port());
   ASSERT_TRUE(content::ExecuteScript(tab_strip->GetActiveWebContents(),
                                      url_setting_script));
   // Set the test buttons array
@@ -108,12 +109,12 @@
 #endif
 
 IN_PROC_BROWSER_TEST_F(ActivityLogExtensionTest, MAYBE_DOMEndToEnd) {
-  TabStripModel* tab_strip = StartTestServerAndInitialize();
+  TabStripModel* tab_strip = StartEmbeddedTestServerAndInitialize();
   ResultCatcher catcher;
   // Set the default URL so that is has the correct port number.
-  net::HostPortPair host_port = test_server()->host_port_pair();
   std::string url_setting_script = base::StringPrintf(
-      "defaultUrl = \'http://www.google.com:%d\';", host_port.port());
+      "defaultUrl = \'http://www.google.com:%d\';",
+      embedded_test_server()->port());
   ASSERT_TRUE(content::ExecuteScript(tab_strip->GetActiveWebContents(),
                                      url_setting_script));
   // Set the test buttons array
@@ -129,8 +130,8 @@
 
 IN_PROC_BROWSER_TEST_F(ActivityLogExtensionTest, ExtensionPrerender) {
   host_resolver()->AddRule("*", "127.0.0.1");
-  StartTestServer();
-  int port = test_server()->host_port_pair().port();
+  StartEmbeddedTestServer();
+  int port = embedded_test_server()->port();
 
   // Get the extension (chrome/test/data/extensions/activity_log)
   const Extension* ext =
diff --git a/chrome/browser/extensions/activity_log/activity_log_policy.cc b/chrome/browser/extensions/activity_log/activity_log_policy.cc
index 21d9deb..528f260 100644
--- a/chrome/browser/extensions/activity_log/activity_log_policy.cc
+++ b/chrome/browser/extensions/activity_log/activity_log_policy.cc
@@ -5,7 +5,7 @@
 #include <stdint.h>
 
 #include "base/logging.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/extensions/activity_log/activity_log_policy.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/extensions/extension.h"
diff --git a/chrome/browser/extensions/activity_log/activity_log_policy.h b/chrome/browser/extensions/activity_log/activity_log_policy.h
index 7dadeb9..797cba5 100644
--- a/chrome/browser/extensions/activity_log/activity_log_policy.h
+++ b/chrome/browser/extensions/activity_log/activity_log_policy.h
@@ -13,7 +13,7 @@
 #include "base/callback.h"
 #include "base/files/file_path.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/timer.h"
+#include "base/timer/timer.h"
 #include "base/values.h"
 #include "chrome/browser/extensions/activity_log/activity_actions.h"
 #include "content/public/browser/browser_thread.h"
diff --git a/chrome/browser/extensions/activity_log/activity_log_unittest.cc b/chrome/browser/extensions/activity_log/activity_log_unittest.cc
index 64b7d4d..01bdcd1 100644
--- a/chrome/browser/extensions/activity_log/activity_log_unittest.cc
+++ b/chrome/browser/extensions/activity_log/activity_log_unittest.cc
@@ -188,7 +188,7 @@
 
 TEST_F(ActivityLogTest, Construct) {
   ActivityLog* activity_log = ActivityLog::GetInstance(profile_.get());
-  scoped_ptr<ListValue> args(new ListValue());
+  scoped_ptr<base::ListValue> args(new base::ListValue());
   ASSERT_TRUE(activity_log->IsLogEnabled());
   activity_log->LogAPIAction(
       kExtensionId, std::string("tabs.testMethod"), args.get(), std::string());
@@ -196,7 +196,7 @@
 
 TEST_F(ActivityLogTest, LogAndFetchActions) {
   ActivityLog* activity_log = ActivityLog::GetInstance(profile_.get());
-  scoped_ptr<ListValue> args(new ListValue());
+  scoped_ptr<base::ListValue> args(new base::ListValue());
   ASSERT_TRUE(activity_log->IsLogEnabled());
 
   // Write some API calls
@@ -217,7 +217,7 @@
 
 TEST_F(ActivityLogTest, LogAndFetchPathActions) {
   ActivityLog* activity_log = ActivityLog::GetInstance(profile_.get());
-  scoped_ptr<ListValue> args(new ListValue());
+  scoped_ptr<base::ListValue> args(new base::ListValue());
   ASSERT_TRUE(activity_log->IsLogEnabled());
 
   activity_log->LogDOMAction(kExtensionId,
@@ -238,7 +238,7 @@
   activity_log->SetArgumentLoggingForTesting(false);
   ASSERT_TRUE(activity_log->IsLogEnabled());
   activity_log->SetDefaultPolicy(ActivityLogPolicy::POLICY_NOARGS);
-  scoped_ptr<ListValue> args(new ListValue());
+  scoped_ptr<base::ListValue> args(new base::ListValue());
   args->Set(0, new base::StringValue("hello"));
   args->Set(1, new base::StringValue("world"));
   activity_log->LogAPIAction(
@@ -252,7 +252,7 @@
   activity_log->SetDefaultPolicy(ActivityLogPolicy::POLICY_FULLSTREAM);
   ASSERT_TRUE(activity_log->IsLogEnabled());
 
-  scoped_ptr<ListValue> args(new ListValue());
+  scoped_ptr<base::ListValue> args(new base::ListValue());
   args->Set(0, new base::StringValue("hello"));
   args->Set(1, new base::StringValue("world"));
   activity_log->LogAPIAction(kExtensionId,
diff --git a/chrome/browser/extensions/activity_log/api_actions.cc b/chrome/browser/extensions/activity_log/api_actions.cc
index c1b4fe7..483d394 100644
--- a/chrome/browser/extensions/activity_log/api_actions.cc
+++ b/chrome/browser/extensions/activity_log/api_actions.cc
@@ -208,7 +208,7 @@
 
 // static
 void APIAction::LookupTabId(const std::string& api_call,
-                            ListValue* args,
+                            base::ListValue* args,
                             Profile* profile) {
   if (api_call == "tabs.get" ||                 // api calls, ID as int
       api_call == "tabs.connect" ||
@@ -228,7 +228,7 @@
       api_call == "tabs.onRemoved" ||
       api_call == "tabs.onReplaced") {
     int tab_id;
-    ListValue* id_list;
+    base::ListValue* id_list;
     if (args->GetInteger(0, &tab_id)) {
       std::string url = GetURLForTabId(tab_id, profile);
       if (url != std::string())
diff --git a/chrome/browser/extensions/activity_log/api_actions.h b/chrome/browser/extensions/activity_log/api_actions.h
index c56ed6a..70a16a7 100644
--- a/chrome/browser/extensions/activity_log/api_actions.h
+++ b/chrome/browser/extensions/activity_log/api_actions.h
@@ -55,7 +55,7 @@
   // the original int. There is a small chance that the URL translation could
   // be wrong, if the tab has already been navigated by the time of invocation.
   static void LookupTabId(const std::string& api_call,
-                          ListValue* args,
+                          base::ListValue* args,
                           Profile* profile);
 
   // Print a APIAction as a regular string for debugging purposes.
diff --git a/chrome/browser/extensions/activity_log/api_name_constants.h b/chrome/browser/extensions/activity_log/api_name_constants.h
index 350ac21..7a6383d 100644
--- a/chrome/browser/extensions/activity_log/api_name_constants.h
+++ b/chrome/browser/extensions/activity_log/api_name_constants.h
@@ -191,7 +191,8 @@
     "windows.onFocusChanged", "windows.onRemoved", "windows.remove",
     "windows.update",
     "tabs.getSelected", "tabs.sendRequest",
-    "systemInfo.cpu.get", "systemInfo.memory.get"
+    "systemInfo.cpu.get", "systemInfo.memory.get",
+    "runtime.onRestartRequired"
 };
 
 }  // namespace activity_log_api_name_constants
diff --git a/chrome/browser/extensions/activity_log/fullstream_ui_policy.cc b/chrome/browser/extensions/activity_log/fullstream_ui_policy.cc
index 0cfa146..ddf56c7 100644
--- a/chrome/browser/extensions/activity_log/fullstream_ui_policy.cc
+++ b/chrome/browser/extensions/activity_log/fullstream_ui_policy.cc
@@ -5,7 +5,7 @@
 #include "base/files/file_path.h"
 #include "base/json/json_string_value_serializer.h"
 #include "base/logging.h"
-#include "base/string16.h"
+#include "base/strings/string16.h"
 #include "chrome/browser/extensions/activity_log/activity_database.h"
 #include "chrome/browser/extensions/activity_log/api_actions.h"
 #include "chrome/browser/extensions/activity_log/blocked_actions.h"
@@ -94,10 +94,10 @@
 std::string FullStreamUIPolicy::ProcessArguments(
     ActionType action_type,
     const std::string& name,
-    const ListValue* args) const {
+    const base::ListValue* args) const {
   std::string processed_args;
   if (args) {
-    ListValue::const_iterator it = args->begin();
+    base::ListValue::const_iterator it = args->begin();
     // TODO(felt,dbabic) Think about replacing the loop with a single
     // call to SerializeAndOmitBinaryValues.
     for (; it != args->end(); ++it) {
@@ -126,7 +126,7 @@
     const std::string& extension_id,
     const std::string& name,
     const GURL& url_param,
-    const ListValue* args,
+    const base::ListValue* args,
     const DictionaryValue* details) {
   std::string concatenated_args = ProcessArguments(action_type, name, args);
   const Time now = Time::Now();
diff --git a/chrome/browser/extensions/activity_log/fullstream_ui_policy_unittest.cc b/chrome/browser/extensions/activity_log/fullstream_ui_policy_unittest.cc
index ebbfd83..19db206 100644
--- a/chrome/browser/extensions/activity_log/fullstream_ui_policy_unittest.cc
+++ b/chrome/browser/extensions/activity_log/fullstream_ui_policy_unittest.cc
@@ -97,8 +97,8 @@
                        .Set("version", "1.0.0")
                        .Set("manifest_version", 2))
           .Build();
-  extension_service_->AddExtension(extension);
-  scoped_ptr<ListValue> args(new ListValue());
+  extension_service_->AddExtension(extension.get());
+  scoped_ptr<base::ListValue> args(new base::ListValue());
   policy->ProcessAction(ActivityLogPolicy::ACTION_API, extension->id(),
       std::string("tabs.testMethod"), GURL(), args.get(), NULL);
 }
@@ -112,8 +112,8 @@
                        .Set("version", "1.0.0")
                        .Set("manifest_version", 2))
           .Build();
-  extension_service_->AddExtension(extension);
-  scoped_ptr<ListValue> args(new ListValue());
+  extension_service_->AddExtension(extension.get());
+  scoped_ptr<base::ListValue> args(new base::ListValue());
   GURL gurl("http://www.google.com");
 
   // Write some API calls
@@ -135,8 +135,8 @@
                        .Set("version", "1.0.0")
                        .Set("manifest_version", 2))
           .Build();
-  extension_service_->AddExtension(extension);
-  scoped_ptr<ListValue> args(new ListValue());
+  extension_service_->AddExtension(extension.get());
+  scoped_ptr<base::ListValue> args(new base::ListValue());
   args->Set(0, new base::StringValue("hello"));
   args->Set(1, new base::StringValue("world"));
   policy->ProcessAction(ActivityLogPolicy::ACTION_API, extension->id(),
diff --git a/chrome/browser/extensions/activity_log/stream_noargs_ui_policy_unittest.cc b/chrome/browser/extensions/activity_log/stream_noargs_ui_policy_unittest.cc
index 39e3235..df279d1 100644
--- a/chrome/browser/extensions/activity_log/stream_noargs_ui_policy_unittest.cc
+++ b/chrome/browser/extensions/activity_log/stream_noargs_ui_policy_unittest.cc
@@ -98,8 +98,8 @@
                        .Set("version", "1.0.0")
                        .Set("manifest_version", 2))
           .Build();
-  extension_service_->AddExtension(extension);
-  scoped_ptr<ListValue> args(new ListValue());
+  extension_service_->AddExtension(extension.get());
+  scoped_ptr<base::ListValue> args(new base::ListValue());
   policy->ProcessAction(ActivityLogPolicy::ACTION_API, extension->id(),
       std::string("tabs.testMethod"), GURL(), args.get(), NULL);
 }
@@ -114,8 +114,8 @@
                        .Set("version", "1.0.0")
                        .Set("manifest_version", 2))
           .Build();
-  extension_service_->AddExtension(extension);
-  scoped_ptr<ListValue> args(new ListValue());
+  extension_service_->AddExtension(extension.get());
+  scoped_ptr<base::ListValue> args(new base::ListValue());
   GURL gurl("http://www.google.com");
 
   // Write some API calls
@@ -139,8 +139,8 @@
                        .Set("version", "1.0.0")
                        .Set("manifest_version", 2))
           .Build();
-  extension_service_->AddExtension(extension);
-  scoped_ptr<ListValue> args(new ListValue());
+  extension_service_->AddExtension(extension.get());
+  scoped_ptr<base::ListValue> args(new base::ListValue());
   args->Set(0, new base::StringValue("hello"));
   args->Set(1, new base::StringValue("world"));
   policy->ProcessAction(ActivityLogPolicy::ACTION_API, extension->id(),
diff --git a/chrome/browser/extensions/ad_view_browsertest.cc b/chrome/browser/extensions/ad_view_browsertest.cc
index 615a674..494ab6b 100644
--- a/chrome/browser/extensions/ad_view_browsertest.cc
+++ b/chrome/browser/extensions/ad_view_browsertest.cc
@@ -19,14 +19,8 @@
 
 // This test checks the "loadcommit" event is called when the page inside an
 // <adview> is loaded.
-#if defined(OS_MACOSX)
-// Very flaky on MacOS 10.8.
-#define MAYBE_LoadCommitEventIsCalled DISABLED_LoadCommitEventIsCalled
-#else
-#define MAYBE_LoadCommitEventIsCalled LoadCommitEventIsCalled
-#endif
-IN_PROC_BROWSER_TEST_F(AdViewTest, MAYBE_LoadCommitEventIsCalled) {
-  ASSERT_TRUE(StartTestServer());
+IN_PROC_BROWSER_TEST_F(AdViewTest, LoadCommitEventIsCalled) {
+  ASSERT_TRUE(StartEmbeddedTestServer());
 
   ASSERT_TRUE(RunPlatformAppTest(
       "platform_apps/ad_view/loadcommit_event")) << message_;
@@ -35,7 +29,7 @@
 // This test checks the "loadabort" event is called when the "src" attribute
 // of an <adview> is an invalid URL.
 IN_PROC_BROWSER_TEST_F(AdViewTest, LoadAbortEventIsCalled) {
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
 
   ASSERT_TRUE(RunPlatformAppTest(
       "platform_apps/ad_view/loadabort_event")) << message_;
@@ -51,7 +45,7 @@
 #define MAYBE_CommitMessageFromAdNetwork CommitMessageFromAdNetwork
 #endif
 IN_PROC_BROWSER_TEST_F(AdViewTest, MAYBE_CommitMessageFromAdNetwork) {
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
 
   ASSERT_TRUE(RunPlatformAppTest(
       "platform_apps/ad_view/onloadcommit_ack")) << message_;
@@ -63,7 +57,7 @@
 //       file (image035.png) which the trybots don't process correctly when
 //       first checked-in.
 IN_PROC_BROWSER_TEST_F(AdViewTest, DISABLED_DisplayFirstAd) {
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
 
   ASSERT_TRUE(RunPlatformAppTest(
       "platform_apps/ad_view/display_first_ad")) << message_;
@@ -72,7 +66,7 @@
 // This test checks that <adview> attributes are also exposed as properties
 // (with the same name and value).
 IN_PROC_BROWSER_TEST_F(AdViewTest, PropertiesAreInSyncWithAttributes) {
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
 
   ASSERT_TRUE(RunPlatformAppTest(
       "platform_apps/ad_view/properties_exposed")) << message_;
@@ -81,7 +75,7 @@
 // This test checks an <adview> element has no behavior when the "adview"
 // permission is missing from the application manifest.
 IN_PROC_BROWSER_TEST_F(AdViewTest, AdViewPermissionIsRequired) {
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
 
   ASSERT_TRUE(RunPlatformAppTest(
       "platform_apps/ad_view/permission_required")) << message_;
@@ -90,8 +84,14 @@
 // This test checks that 1) it is possible change the value of the "ad-network"
 // attribute of an <adview> element and 2) changing the value will reset the
 // "src" attribute.
-IN_PROC_BROWSER_TEST_F(AdViewTest, ChangeAdNetworkValue) {
-  ASSERT_TRUE(StartTestServer());
+#if defined(OS_MACOSX)
+// Very flaky on MacOS 10.8 - crbug.com/253644.
+#define MAYBE_ChangeAdNetworkValue DISABLED_ChangeAdNetworkValue
+#else
+#define MAYBE_ChangeAdNetworkValue ChangeAdNetworkValue
+#endif
+IN_PROC_BROWSER_TEST_F(AdViewTest, MAYBE_ChangeAdNetworkValue) {
+  ASSERT_TRUE(StartEmbeddedTestServer());
 
   ASSERT_TRUE(RunPlatformAppTest(
       "platform_apps/ad_view/change_ad_network")) << message_;
@@ -109,7 +109,7 @@
 // This test checks an invalid "ad-network" value (i.e. not whitelisted)
 // is ignored.
 IN_PROC_BROWSER_TEST_F(AdViewNoSrcTest, InvalidAdNetworkIsIgnored) {
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
 
   ASSERT_TRUE(RunPlatformAppTest(
       "platform_apps/ad_view/invalid_ad_network")) << message_;
@@ -118,7 +118,7 @@
 // This test checks the "src" attribute is ignored when the
 // "kEnableAdviewSrcAttribute" is missing.
 IN_PROC_BROWSER_TEST_F(AdViewNoSrcTest, EnableAdviewSrcAttributeFlagRequired) {
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
 
   ASSERT_TRUE(RunPlatformAppTest(
       "platform_apps/ad_view/src_flag_required")) << message_;
@@ -158,7 +158,7 @@
 // This test checks an <adview> element has no behavior when the "kEnableAdview"
 // flag is missing.
 IN_PROC_BROWSER_TEST_F(AdViewNotEnabledTest, EnableAdviewFlagRequired) {
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
 
   ASSERT_TRUE(RunPlatformAppTest(
       "platform_apps/ad_view/flag_required")) << message_;
diff --git a/chrome/browser/extensions/api/alarms/alarm_manager.cc b/chrome/browser/extensions/api/alarms/alarm_manager.cc
index 9f96d2c..74b1e03 100644
--- a/chrome/browser/extensions/api/alarms/alarm_manager.cc
+++ b/chrome/browser/extensions/api/alarms/alarm_manager.cc
@@ -8,9 +8,9 @@
 #include "base/json/json_writer.h"
 #include "base/lazy_instance.h"
 #include "base/message_loop.h"
-#include "base/time.h"
 #include "base/time/clock.h"
 #include "base/time/default_clock.h"
+#include "base/time/time.h"
 #include "base/value_conversions.h"
 #include "base/values.h"
 #include "chrome/browser/extensions/event_router.h"
@@ -41,7 +41,7 @@
 
   virtual void OnAlarm(const std::string& extension_id,
                        const Alarm& alarm) OVERRIDE {
-    scoped_ptr<ListValue> args(new ListValue());
+    scoped_ptr<base::ListValue> args(new base::ListValue());
     args->Append(alarm.js_alarm->ToValue().release());
     scoped_ptr<Event> event(new Event(kOnAlarmEvent, args.Pass()));
     ExtensionSystem::Get(profile_)->event_router()->DispatchEventToExtension(
@@ -75,7 +75,7 @@
 }
 
 scoped_ptr<base::ListValue> AlarmsToValue(const std::vector<Alarm>& alarms) {
-  scoped_ptr<base::ListValue> list(new ListValue());
+  scoped_ptr<base::ListValue> list(new base::ListValue());
   for (size_t i = 0; i < alarms.size(); ++i) {
     scoped_ptr<base::DictionaryValue> alarm =
         alarms[i].js_alarm->ToValue().Pass();
@@ -234,7 +234,7 @@
   if (!storage)
     return;
 
-  scoped_ptr<Value> alarms;
+  scoped_ptr<base::Value> alarms;
   AlarmMap::iterator list = alarms_.find(extension_id);
   if (list != alarms_.end())
     alarms.reset(AlarmsToValue(list->second).release());
diff --git a/chrome/browser/extensions/api/alarms/alarm_manager.h b/chrome/browser/extensions/api/alarms/alarm_manager.h
index a021603..66ebfc8 100644
--- a/chrome/browser/extensions/api/alarms/alarm_manager.h
+++ b/chrome/browser/extensions/api/alarms/alarm_manager.h
@@ -5,12 +5,12 @@
 #ifndef CHROME_BROWSER_EXTENSIONS_API_ALARMS_ALARM_MANAGER_H__
 #define CHROME_BROWSER_EXTENSIONS_API_ALARMS_ALARM_MANAGER_H__
 
-#include <string>
 #include <map>
+#include <string>
 #include <vector>
 
 #include "base/memory/weak_ptr.h"
-#include "base/timer.h"
+#include "base/timer/timer.h"
 #include "chrome/browser/extensions/api/profile_keyed_api_factory.h"
 #include "chrome/browser/extensions/extension_function.h"
 #include "chrome/common/extensions/api/alarms.h"
diff --git a/chrome/browser/extensions/api/app_current_window_internal/app_current_window_internal_api.cc b/chrome/browser/extensions/api/app_current_window_internal/app_current_window_internal_api.cc
index c1912ea..2f1b92b 100644
--- a/chrome/browser/extensions/api/app_current_window_internal/app_current_window_internal_api.cc
+++ b/chrome/browser/extensions/api/app_current_window_internal/app_current_window_internal_api.cc
@@ -4,14 +4,15 @@
 
 #include "chrome/browser/extensions/api/app_current_window_internal/app_current_window_internal_api.h"
 
+#include "apps/shell_window.h"
 #include "base/command_line.h"
 #include "chrome/browser/extensions/shell_window_registry.h"
 #include "chrome/browser/ui/extensions/native_app_window.h"
-#include "chrome/browser/ui/extensions/shell_window.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/extensions/api/app_current_window_internal.h"
 #include "chrome/common/extensions/api/app_window.h"
 
+using apps::ShellWindow;
 namespace SetBounds = extensions::api::app_current_window_internal::SetBounds;
 using extensions::api::app_current_window_internal::Bounds;
 namespace SetIcon = extensions::api::app_current_window_internal::SetIcon;
diff --git a/chrome/browser/extensions/api/app_current_window_internal/app_current_window_internal_api.h b/chrome/browser/extensions/api/app_current_window_internal/app_current_window_internal_api.h
index 110b5eb..806ae3b 100644
--- a/chrome/browser/extensions/api/app_current_window_internal/app_current_window_internal_api.h
+++ b/chrome/browser/extensions/api/app_current_window_internal/app_current_window_internal_api.h
@@ -7,7 +7,9 @@
 
 #include "chrome/browser/extensions/extension_function.h"
 
+namespace apps {
 class ShellWindow;
+}
 
 namespace extensions {
 
@@ -16,7 +18,7 @@
   virtual ~AppCurrentWindowInternalExtensionFunction() {}
 
   // Invoked with the current shell window.
-  virtual bool RunWithWindow(ShellWindow* window) = 0;
+  virtual bool RunWithWindow(apps::ShellWindow* window) = 0;
 
  private:
   virtual bool RunImpl() OVERRIDE;
@@ -30,7 +32,7 @@
 
  protected:
   virtual ~AppCurrentWindowInternalFocusFunction() {}
-  virtual bool RunWithWindow(ShellWindow* window) OVERRIDE;
+  virtual bool RunWithWindow(apps::ShellWindow* window) OVERRIDE;
 };
 
 class AppCurrentWindowInternalFullscreenFunction
@@ -41,7 +43,7 @@
 
  protected:
   virtual ~AppCurrentWindowInternalFullscreenFunction() {}
-  virtual bool RunWithWindow(ShellWindow* window) OVERRIDE;
+  virtual bool RunWithWindow(apps::ShellWindow* window) OVERRIDE;
 };
 
 class AppCurrentWindowInternalMaximizeFunction
@@ -52,7 +54,7 @@
 
  protected:
   virtual ~AppCurrentWindowInternalMaximizeFunction() {}
-  virtual bool RunWithWindow(ShellWindow* window) OVERRIDE;
+  virtual bool RunWithWindow(apps::ShellWindow* window) OVERRIDE;
 };
 
 class AppCurrentWindowInternalMinimizeFunction
@@ -63,7 +65,7 @@
 
  protected:
   virtual ~AppCurrentWindowInternalMinimizeFunction() {}
-  virtual bool RunWithWindow(ShellWindow* window) OVERRIDE;
+  virtual bool RunWithWindow(apps::ShellWindow* window) OVERRIDE;
 };
 
 class AppCurrentWindowInternalRestoreFunction
@@ -74,7 +76,7 @@
 
  protected:
   virtual ~AppCurrentWindowInternalRestoreFunction() {}
-  virtual bool RunWithWindow(ShellWindow* window) OVERRIDE;
+  virtual bool RunWithWindow(apps::ShellWindow* window) OVERRIDE;
 };
 
 class AppCurrentWindowInternalDrawAttentionFunction
@@ -85,7 +87,7 @@
 
  protected:
   virtual ~AppCurrentWindowInternalDrawAttentionFunction() {}
-  virtual bool RunWithWindow(ShellWindow* window) OVERRIDE;
+  virtual bool RunWithWindow(apps::ShellWindow* window) OVERRIDE;
 };
 
 class AppCurrentWindowInternalClearAttentionFunction
@@ -96,7 +98,7 @@
 
  protected:
   virtual ~AppCurrentWindowInternalClearAttentionFunction() {}
-  virtual bool RunWithWindow(ShellWindow* window) OVERRIDE;
+  virtual bool RunWithWindow(apps::ShellWindow* window) OVERRIDE;
 };
 
 class AppCurrentWindowInternalShowFunction
@@ -107,7 +109,7 @@
 
  protected:
   virtual ~AppCurrentWindowInternalShowFunction() {}
-  virtual bool RunWithWindow(ShellWindow* window) OVERRIDE;
+  virtual bool RunWithWindow(apps::ShellWindow* window) OVERRIDE;
 };
 
 class AppCurrentWindowInternalHideFunction
@@ -118,7 +120,7 @@
 
  protected:
   virtual ~AppCurrentWindowInternalHideFunction() {}
-  virtual bool RunWithWindow(ShellWindow* window) OVERRIDE;
+  virtual bool RunWithWindow(apps::ShellWindow* window) OVERRIDE;
 };
 
 class AppCurrentWindowInternalSetBoundsFunction
@@ -128,7 +130,7 @@
                              APP_CURRENTWINDOWINTERNAL_SETBOUNDS)
  protected:
   virtual ~AppCurrentWindowInternalSetBoundsFunction() {}
-  virtual bool RunWithWindow(ShellWindow* window) OVERRIDE;
+  virtual bool RunWithWindow(apps::ShellWindow* window) OVERRIDE;
 };
 
 class AppCurrentWindowInternalSetIconFunction
@@ -139,7 +141,7 @@
 
  protected:
   virtual ~AppCurrentWindowInternalSetIconFunction() {}
-  virtual bool RunWithWindow(ShellWindow* window) OVERRIDE;
+  virtual bool RunWithWindow(apps::ShellWindow* window) OVERRIDE;
 };
 
 }  // namespace extensions
diff --git a/chrome/browser/extensions/api/app_runtime/app_runtime_api.cc b/chrome/browser/extensions/api/app_runtime/app_runtime_api.cc
index 52db244..d4af336 100644
--- a/chrome/browser/extensions/api/app_runtime/app_runtime_api.cc
+++ b/chrome/browser/extensions/api/app_runtime/app_runtime_api.cc
@@ -48,14 +48,14 @@
 // static.
 void AppEventRouter::DispatchOnLaunchedEvent(
     Profile* profile, const Extension* extension) {
-  scoped_ptr<ListValue> arguments(new ListValue());
+  scoped_ptr<base::ListValue> arguments(new base::ListValue());
   DispatchOnLaunchedEventImpl(extension->id(), arguments.Pass(), profile);
 }
 
 // static.
 void AppEventRouter::DispatchOnRestartedEvent(Profile* profile,
                                               const Extension* extension) {
-  scoped_ptr<ListValue> arguments(new ListValue());
+  scoped_ptr<base::ListValue> arguments(new base::ListValue());
   scoped_ptr<Event> event(new Event(kOnRestarted, arguments.Pass()));
   event->restrict_to_profile = profile;
   extensions::ExtensionSystem::Get(profile)->event_router()->
@@ -67,15 +67,15 @@
     Profile* profile, const Extension* extension,
     const std::string& handler_id, const std::string& mime_type,
     const extensions::app_file_handler_util::GrantedFileEntry& file_entry) {
-  scoped_ptr<ListValue> args(new ListValue());
-  DictionaryValue* launch_data = new DictionaryValue();
+  scoped_ptr<base::ListValue> args(new base::ListValue());
+  base::DictionaryValue* launch_data = new base::DictionaryValue();
   launch_data->SetString("id", handler_id);
-  DictionaryValue* launch_item = new DictionaryValue;
+  base::DictionaryValue* launch_item = new base::DictionaryValue;
   launch_item->SetString("fileSystemId", file_entry.filesystem_id);
   launch_item->SetString("baseName", file_entry.registered_name);
   launch_item->SetString("mimeType", mime_type);
   launch_item->SetString("entryId", file_entry.id);
-  ListValue* items = new ListValue;
+  base::ListValue* items = new base::ListValue;
   items->Append(launch_item);
   launch_data->Set("items", items);
   args->Append(launch_data);
diff --git a/chrome/browser/extensions/api/app_window/app_window_api.cc b/chrome/browser/extensions/api/app_window/app_window_api.cc
index 5655f04..1c0a0e5 100644
--- a/chrome/browser/extensions/api/app_window/app_window_api.cc
+++ b/chrome/browser/extensions/api/app_window/app_window_api.cc
@@ -4,16 +4,17 @@
 
 #include "chrome/browser/extensions/api/app_window/app_window_api.h"
 
+#include "apps/shell_window.h"
 #include "base/command_line.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "base/values.h"
 #include "chrome/browser/app_mode/app_mode_utils.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/devtools/devtools_window.h"
 #include "chrome/browser/extensions/shell_window_registry.h"
 #include "chrome/browser/extensions/window_controller.h"
+#include "chrome/browser/ui/apps/chrome_shell_window_delegate.h"
 #include "chrome/browser/ui/extensions/native_app_window.h"
-#include "chrome/browser/ui/extensions/shell_window.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/extensions/api/app_window.h"
 #include "content/public/browser/notification_registrar.h"
@@ -33,6 +34,8 @@
 #include "ui/aura/window.h"
 #endif
 
+using apps::ShellWindow;
+
 namespace app_window = extensions::api::app_window;
 namespace Create = app_window::Create;
 
@@ -89,7 +92,7 @@
   result->SetBoolean("fullscreen", window->GetBaseWindow()->IsFullscreen());
   result->SetBoolean("minimized", window->GetBaseWindow()->IsMinimized());
   result->SetBoolean("maximized", window->GetBaseWindow()->IsMaximized());
-  DictionaryValue* boundsValue = new DictionaryValue();
+  base::DictionaryValue* boundsValue = new base::DictionaryValue();
   gfx::Rect bounds = window->GetClientBounds();
   boundsValue->SetInteger("left", bounds.x());
   boundsValue->SetInteger("top", bounds.y());
@@ -289,8 +292,12 @@
   if (force_maximize)
     create_params.state = ui::SHOW_STATE_MAXIMIZED;
 
-  ShellWindow* shell_window =
-      ShellWindow::Create(profile(), GetExtension(), url, create_params);
+  ShellWindow* shell_window = ShellWindow::Create(
+      profile(),
+      new chrome::ChromeShellWindowDelegate(),
+      GetExtension(),
+      url,
+      create_params);
 
   if (chrome::ShouldForceFullscreenApp())
     shell_window->Fullscreen();
diff --git a/chrome/browser/extensions/api/app_window/app_window_apitest.cc b/chrome/browser/extensions/api/app_window/app_window_apitest.cc
index a7acfc3..31eeaf7 100644
--- a/chrome/browser/extensions/api/app_window/app_window_apitest.cc
+++ b/chrome/browser/extensions/api/app_window/app_window_apitest.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/shell_window.h"
 #include "base/run_loop.h"
 #include "base/strings/string_number_conversions.h"
 #include "chrome/browser/extensions/extension_test_message_listener.h"
@@ -9,7 +10,6 @@
 #include "chrome/browser/extensions/shell_window_registry.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/extensions/native_app_window.h"
-#include "chrome/browser/ui/extensions/shell_window.h"
 #include "chrome/test/base/testing_profile.h"
 #include "ui/base/base_window.h"
 #include "ui/gfx/rect.h"
@@ -18,6 +18,8 @@
 #include "content/public/test/test_utils.h"
 #endif
 
+using apps::ShellWindow;
+
 namespace {
 
 class TestShellWindowRegistryObserver
diff --git a/chrome/browser/extensions/api/audio/audio_api.cc b/chrome/browser/extensions/api/audio/audio_api.cc
index 0c717b1..b6c37fb 100644
--- a/chrome/browser/extensions/api/audio/audio_api.cc
+++ b/chrome/browser/extensions/api/audio/audio_api.cc
@@ -38,8 +38,9 @@
 
 void AudioAPI::OnDeviceChanged() {
   if (profile_ && ExtensionSystem::Get(profile_)->event_router()) {
-    scoped_ptr<Event> event(new Event(event_names::kOnAudioDeviceChanged,
-                                      scoped_ptr<ListValue>(new ListValue())));
+    scoped_ptr<Event> event(new Event(
+        event_names::kOnAudioDeviceChanged,
+        scoped_ptr<base::ListValue>(new base::ListValue())));
     ExtensionSystem::Get(profile_)->event_router()->BroadcastEvent(
         event.Pass());
   }
diff --git a/chrome/browser/extensions/api/autotest_private/autotest_private_api.cc b/chrome/browser/extensions/api/autotest_private/autotest_private_api.cc
index e6bb9cd..86fc7ea 100644
--- a/chrome/browser/extensions/api/autotest_private/autotest_private_api.cc
+++ b/chrome/browser/extensions/api/autotest_private/autotest_private_api.cc
@@ -53,7 +53,7 @@
 bool AutotestPrivateLoginStatusFunction::RunImpl() {
   DVLOG(1) << "AutotestPrivateLoginStatusFunction";
 
-  DictionaryValue* result(new DictionaryValue);
+  base::DictionaryValue* result(new base::DictionaryValue);
 #if defined(OS_CHROMEOS)
   const chromeos::UserManager* user_manager = chromeos::UserManager::Get();
   const bool is_screen_locked =
diff --git a/chrome/browser/extensions/api/bluetooth/bluetooth_api.cc b/chrome/browser/extensions/api/bluetooth/bluetooth_api.cc
index 11c91f5..0055d9b 100644
--- a/chrome/browser/extensions/api/bluetooth/bluetooth_api.cc
+++ b/chrome/browser/extensions/api/bluetooth/bluetooth_api.cc
@@ -15,7 +15,7 @@
 #include "chrome/browser/extensions/extension_system.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/extensions/api/bluetooth.h"
-#include "chrome/common/extensions/permissions/bluetooth_device_permission.h"
+#include "chrome/common/extensions/permissions/bluetooth_permission.h"
 #include "chrome/common/extensions/permissions/permissions_data.h"
 #include "content/public/browser/browser_thread.h"
 #include "device/bluetooth/bluetooth_adapter.h"
@@ -47,10 +47,10 @@
     "Could not get local Out Of Band Pairing Data";
 const char kCouldNotSetOutOfBandPairingData[] =
     "Could not set Out Of Band Pairing Data";
-const char kDevicePermissionDenied[] = "Permission to access device denied";
 const char kFailedToConnect[] = "Connection failed";
 const char kInvalidDevice[] = "Invalid device";
 const char kInvalidUuid[] = "Invalid UUID";
+const char kPermissionDenied[] = "Permission to add profile denied.";
 const char kPlatformNotSupported[] =
     "This operation is not supported on your platform";
 const char kProfileAlreadyRegistered[] =
@@ -126,6 +126,13 @@
     return false;
   }
 
+  BluetoothPermission::CheckParam param(params->profile.uuid);
+  if (!PermissionsData::CheckAPIPermissionWithParam(
+          GetExtension(), APIPermission::kBluetooth, &param)) {
+    SetError(kPermissionDenied);
+    return false;
+  }
+
   uuid_ = device::bluetooth_utils::CanonicalUuid(params->profile.uuid);
 
   if (GetEventRouter(profile())->HasProfile(uuid_)) {
@@ -229,7 +236,7 @@
 
   BluetoothDevice::ServiceList service_list = device->GetServices();
 
-  ListValue* profiles = new ListValue;
+  base::ListValue* profiles = new base::ListValue;
   for (BluetoothDevice::ServiceList::const_iterator iter = service_list.begin();
        iter != service_list.end();
        ++iter) {
@@ -348,7 +355,7 @@
     return false;
   }
 
-  ListValue* services = new ListValue;
+  base::ListValue* services = new base::ListValue;
   SetResult(services);
 
   device->GetServiceRecords(
@@ -375,14 +382,6 @@
   EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
   const bluetooth::ConnectOptions& options = params->options;
 
-  BluetoothDevicePermission::CheckParam param(options.device.address);
-  if (!PermissionsData::CheckAPIPermissionWithParam(
-          GetExtension(), APIPermission::kBluetoothDevice, &param)) {
-    SetError(kDevicePermissionDenied);
-    SendResponse(false);
-    return false;
-  }
-
   if (!BluetoothDevice::IsUUIDValid(options.profile.uuid)) {
     SetError(kInvalidUuid);
     SendResponse(false);
@@ -469,10 +468,10 @@
 bool BluetoothWriteFunction::Prepare() {
   // TODO(bryeung): update to new-style parameter passing when ArrayBuffer
   // support is added
-  DictionaryValue* options;
+  base::DictionaryValue* options;
   EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &options));
 
-  DictionaryValue* socket;
+  base::DictionaryValue* socket;
   EXTENSION_FUNCTION_VALIDATE(options->GetDictionary("socket", &socket));
 
   int socket_id;
@@ -506,8 +505,8 @@
   success_ = socket_->Send(drainable_io_buffer.get());
   if (success_) {
     if (drainable_io_buffer->BytesConsumed() > 0)
-      SetResult(
-          Value::CreateIntegerValue(drainable_io_buffer->BytesConsumed()));
+      SetResult(base::Value::CreateIntegerValue(
+          drainable_io_buffer->BytesConsumed()));
     else
       results_.reset();
   } else {
@@ -532,7 +531,7 @@
     scoped_refptr<BluetoothAdapter> adapter) {
   // TODO(bryeung): update to new-style parameter passing when ArrayBuffer
   // support is added
-  DictionaryValue* options;
+  base::DictionaryValue* options;
   EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &options));
   std::string address;
   EXTENSION_FUNCTION_VALIDATE(options->GetString("deviceAddress", &address));
@@ -545,7 +544,7 @@
   }
 
   if (options->HasKey("data")) {
-    DictionaryValue* data_in;
+    base::DictionaryValue* data_in;
     EXTENSION_FUNCTION_VALIDATE(options->GetDictionary("data", &data_in));
 
     device::BluetoothOutOfBandPairingData data_out;
@@ -593,7 +592,7 @@
 
   // TODO(bryeung): convert to bluetooth::OutOfBandPairingData
   // when ArrayBuffer support within objects is completed.
-  DictionaryValue* result = new DictionaryValue();
+  base::DictionaryValue* result = new base::DictionaryValue();
   result->Set("hash", hash);
   result->Set("randomizer", randomizer);
 
diff --git a/chrome/browser/extensions/api/bluetooth/bluetooth_apitest.cc b/chrome/browser/extensions/api/bluetooth/bluetooth_apitest.cc
index a2f43f2..92ad350 100644
--- a/chrome/browser/extensions/api/bluetooth/bluetooth_apitest.cc
+++ b/chrome/browser/extensions/api/bluetooth/bluetooth_apitest.cc
@@ -7,7 +7,6 @@
 #include "base/strings/stringprintf.h"
 #include "chrome/browser/extensions/api/bluetooth/bluetooth_api.h"
 #include "chrome/browser/extensions/api/bluetooth/bluetooth_event_router.h"
-#include "chrome/browser/extensions/api/permissions/permissions_api.h"
 #include "chrome/browser/extensions/extension_apitest.h"
 #include "chrome/browser/extensions/extension_function_test_utils.h"
 #include "chrome/browser/extensions/extension_service.h"
@@ -136,13 +135,6 @@
   return true;
 }
 
-static void CallConnectToProfileCallback(
-    BluetoothProfile* profile,
-    const base::Closure& callback,
-    const BluetoothDevice::ErrorCallback& error_callback) {
-  callback.Run();
-}
-
 static void CallDiscoveryCallback(
     const base::Closure& callback,
     const BluetoothAdapter::ErrorCallback& error_callback) {
@@ -164,46 +156,66 @@
 }  // namespace
 
 IN_PROC_BROWSER_TEST_F(BluetoothApiTest, Profiles) {
+  // Run in context of an extension that has permissions for the profiles
+  // we intend to register.
+  scoped_refptr<const Extension> extension(
+      LoadExtension(test_data_dir_.AppendASCII("bluetooth/profiles")));
+  ASSERT_TRUE(extension.get());
+
   EXPECT_CALL(*profile1_, SetConnectionCallback(testing::_));
   scoped_refptr<TestBluetoothAddProfileFunction> add_profile_function;
-  add_profile_function = setupFunction(
-      new TestBluetoothAddProfileFunction(profile1_.get()));
+  add_profile_function = new TestBluetoothAddProfileFunction(profile1_.get());
+  add_profile_function->set_extension(extension.get());
+  add_profile_function->set_has_callback(true);
   std::string error(utils::RunFunctionAndReturnError(
       add_profile_function.get(), "[{\"uuid\": \"1234\"}]", browser()));
   ASSERT_TRUE(error.empty());
 
   // Registering the profile for the same uuid again will throw an error.
-  add_profile_function = setupFunction(
-      new TestBluetoothAddProfileFunction(profile2_.get()));
+  add_profile_function = new TestBluetoothAddProfileFunction(profile2_.get());
+  add_profile_function->set_extension(extension.get());
+  add_profile_function->set_has_callback(true);
   error = utils::RunFunctionAndReturnError(
       add_profile_function.get(), "[{\"uuid\": \"1234\"}]", browser());
   ASSERT_FALSE(error.empty());
 
-  add_profile_function = setupFunction(
-      new TestBluetoothAddProfileFunction(profile2_.get()));
+  add_profile_function = new TestBluetoothAddProfileFunction(profile2_.get());
+  add_profile_function->set_extension(extension.get());
+  add_profile_function->set_has_callback(true);
   error = utils::RunFunctionAndReturnError(
       add_profile_function.get(), "[{\"uuid\": \"5678\"}]", browser());
   ASSERT_TRUE(error.empty());
 
   scoped_refptr<api::BluetoothRemoveProfileFunction> remove_profile_function;
-  remove_profile_function = setupFunction(
-      new api::BluetoothRemoveProfileFunction());
+  remove_profile_function = new api::BluetoothRemoveProfileFunction();
+  remove_profile_function->set_extension(extension.get());
+  remove_profile_function->set_has_callback(true);
   error = utils::RunFunctionAndReturnError(
       remove_profile_function.get(), "[{\"uuid\": \"1234\"}]", browser());
   ASSERT_TRUE(error.empty());
 
-  remove_profile_function = setupFunction(
-      new api::BluetoothRemoveProfileFunction());
+  remove_profile_function = new api::BluetoothRemoveProfileFunction();
+  remove_profile_function->set_extension(extension.get());
+  remove_profile_function->set_has_callback(true);
   error = utils::RunFunctionAndReturnError(
       remove_profile_function.get(), "[{\"uuid\": \"5678\"}]", browser());
   ASSERT_TRUE(error.empty());
 
   // Removing the same profile again will throw an error.
-  remove_profile_function = setupFunction(
-      new api::BluetoothRemoveProfileFunction());
+  remove_profile_function = new api::BluetoothRemoveProfileFunction();
+  remove_profile_function->set_extension(extension.get());
+  remove_profile_function->set_has_callback(true);
   error = utils::RunFunctionAndReturnError(
       remove_profile_function.get(), "[{\"uuid\": \"5678\"}]", browser());
   ASSERT_FALSE(error.empty());
+
+  // Registering a profile we don't have permission for will throw an error.
+  add_profile_function = new TestBluetoothAddProfileFunction(profile1_.get());
+  add_profile_function->set_extension(extension.get());
+  add_profile_function->set_has_callback(true);
+  error = utils::RunFunctionAndReturnError(
+      add_profile_function.get(), "[{\"uuid\": \"9999\"}]", browser());
+  ASSERT_FALSE(error.empty());
 }
 
 IN_PROC_BROWSER_TEST_F(BluetoothApiTest, GetAdapterState) {
@@ -571,19 +583,3 @@
 
   EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
 }
-
-IN_PROC_BROWSER_TEST_F(BluetoothApiTest, Permissions) {
-  extensions::PermissionsRequestFunction::SetAutoConfirmForTests(true);
-  extensions::PermissionsRequestFunction::SetIgnoreUserGestureForTests(true);
-
-  event_router()->AddProfile(
-      "00001101-0000-1000-8000-00805f9b34fb", profile1_.get());
-
-  EXPECT_CALL(*mock_adapter_, GetDevice(device1_->GetAddress()))
-      .WillOnce(testing::Return(device1_.get()));
-  EXPECT_CALL(*device1_,
-              ConnectToProfile(testing::_, testing::_, testing::_))
-      .WillOnce(testing::Invoke(CallConnectToProfileCallback));
-
-  EXPECT_TRUE(RunExtensionTest("bluetooth/permissions")) << message_;
-}
diff --git a/chrome/browser/extensions/api/bluetooth/bluetooth_event_router.cc b/chrome/browser/extensions/api/bluetooth/bluetooth_event_router.cc
index 5915b54..5147a7b 100644
--- a/chrome/browser/extensions/api/bluetooth/bluetooth_event_router.cc
+++ b/chrome/browser/extensions/api/bluetooth/bluetooth_event_router.cc
@@ -162,7 +162,7 @@
 
 void ExtensionBluetoothEventRouter::DispatchDeviceEvent(
     const char* event_name, const extensions::api::bluetooth::Device& device) {
-  scoped_ptr<ListValue> args(new ListValue());
+  scoped_ptr<base::ListValue> args(new base::ListValue());
   args->Append(device.ToValue().release());
   scoped_ptr<Event> event(new Event(event_name, args.Pass()));
   ExtensionSystem::Get(profile_)->event_router()->BroadcastEvent(event.Pass());
@@ -182,7 +182,7 @@
   result_socket.profile.uuid = uuid;
   result_socket.id = socket_id;
 
-  scoped_ptr<ListValue> args(new ListValue());
+  scoped_ptr<base::ListValue> args(new base::ListValue());
   args->Append(result_socket.ToValue().release());
   scoped_ptr<Event> event(new Event(
       extensions::event_names::kBluetoothOnConnection, args.Pass()));
@@ -271,7 +271,7 @@
   api::bluetooth::AdapterState state;
   PopulateAdapterState(*adapter_.get(), &state);
 
-  scoped_ptr<ListValue> args(new ListValue());
+  scoped_ptr<base::ListValue> args(new base::ListValue());
   args->Append(state.ToValue().release());
   scoped_ptr<Event> event(new Event(
       extensions::event_names::kBluetoothOnAdapterStateChanged,
diff --git a/chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api.cc b/chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api.cc
index c7f06e7..67d0cf1 100644
--- a/chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api.cc
+++ b/chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api.cc
@@ -88,8 +88,8 @@
 // Recursively adds a node to a list. This is by used |BookmarkNodeDataToJSON|
 // when the data comes from the current profile. In this case we have a
 // BookmarkNode since we got the data from the current profile.
-void AddNodeToList(ListValue* list, const BookmarkNode& node) {
-  DictionaryValue* dict = new DictionaryValue();
+void AddNodeToList(base::ListValue* list, const BookmarkNode& node) {
+  base::DictionaryValue* dict = new base::DictionaryValue();
 
   // Add id and parentId so we can associate the data with existing nodes on the
   // client side.
@@ -104,7 +104,7 @@
 
   dict->SetString(bookmark_keys::kTitleKey, node.GetTitle());
 
-  ListValue* children = new ListValue();
+  base::ListValue* children = new base::ListValue();
   for (int i = 0; i < node.child_count(); ++i)
     AddNodeToList(children, *node.GetChild(i));
   dict->Set(bookmark_keys::kChildrenKey, children);
@@ -115,16 +115,16 @@
 // Recursively adds an element to a list. This is used by
 // |BookmarkNodeDataToJSON| when the data comes from a different profile. When
 // the data comes from a different profile we do not have any IDs or parent IDs.
-void AddElementToList(ListValue* list,
+void AddElementToList(base::ListValue* list,
                       const BookmarkNodeData::Element& element) {
-  DictionaryValue* dict = new DictionaryValue();
+  base::DictionaryValue* dict = new base::DictionaryValue();
 
   if (element.is_url)
     dict->SetString(bookmark_keys::kUrlKey, element.url.spec());
 
   dict->SetString(bookmark_keys::kTitleKey, element.title);
 
-  ListValue* children = new ListValue();
+  base::ListValue* children = new base::ListValue();
   for (size_t i = 0; i < element.children.size(); ++i)
     AddElementToList(children, element.children[i]);
   dict->Set(bookmark_keys::kChildrenKey, children);
@@ -134,12 +134,12 @@
 
 // Builds the JSON structure based on the BookmarksDragData.
 void BookmarkNodeDataToJSON(Profile* profile, const BookmarkNodeData& data,
-                            ListValue* args) {
+                            base::ListValue* args) {
   bool same_profile = data.IsFromProfile(profile);
-  DictionaryValue* value = new DictionaryValue();
+  base::DictionaryValue* value = new base::DictionaryValue();
   value->SetBoolean(manager_keys::kSameProfileKey, same_profile);
 
-  ListValue* list = new ListValue();
+  base::ListValue* list = new base::ListValue();
   if (same_profile) {
     std::vector<const BookmarkNode*> nodes = data.GetNodes(profile);
     for (size_t i = 0; i < nodes.size(); ++i)
@@ -176,7 +176,7 @@
 
 void BookmarkManagerPrivateEventRouter::DispatchEvent(
     const char* event_name,
-    scoped_ptr<ListValue> args) {
+    scoped_ptr<base::ListValue> args) {
   if (!ExtensionSystem::Get(profile_)->event_router())
     return;
 
@@ -190,7 +190,7 @@
   if (data.size() == 0)
     return;
 
-  scoped_ptr<ListValue> args(new ListValue());
+  scoped_ptr<base::ListValue> args(new base::ListValue());
   BookmarkNodeDataToJSON(profile_, data, args.get());
   DispatchEvent(event_name, args.Pass());
 }
@@ -323,7 +323,7 @@
 }
 
 bool BookmarkManagerPrivateGetStringsFunction::RunImpl() {
-  DictionaryValue* localized_strings = new DictionaryValue();
+  base::DictionaryValue* localized_strings = new base::DictionaryValue();
 
   localized_strings->SetString("title",
       l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_TITLE));
@@ -501,7 +501,7 @@
     return false;
   }
 
-  scoped_ptr<ListValue> json(new ListValue());
+  scoped_ptr<base::ListValue> json(new base::ListValue());
   if (params->folders_only)
     bookmark_api_helpers::AddNodeFoldersOnly(node, json.get(), true);
   else
diff --git a/chrome/browser/extensions/api/bookmarks/bookmark_api_helpers.cc b/chrome/browser/extensions/api/bookmarks/bookmark_api_helpers.cc
index fc3a988..4b6a252 100644
--- a/chrome/browser/extensions/api/bookmarks/bookmark_api_helpers.cc
+++ b/chrome/browser/extensions/api/bookmarks/bookmark_api_helpers.cc
@@ -132,7 +132,8 @@
     for (int i = 0; i < node->child_count(); ++i) {
       const BookmarkNode* child = node->GetChild(i);
       if (child->IsVisible() && (!only_folders || child->is_folder())) {
-        DictionaryValue* dict = GetNodeDictionary(child, true, only_folders);
+        base::DictionaryValue* dict =
+            GetNodeDictionary(child, true, only_folders);
         children->Append(dict);
       }
     }
diff --git a/chrome/browser/extensions/api/bookmarks/bookmarks_api.cc b/chrome/browser/extensions/api/bookmarks/bookmarks_api.cc
index 0336c98..553a13f 100644
--- a/chrome/browser/extensions/api/bookmarks/bookmarks_api.cc
+++ b/chrome/browser/extensions/api/bookmarks/bookmarks_api.cc
@@ -19,7 +19,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/bookmarks/bookmark_html_writer.h"
 #include "chrome/browser/bookmarks/bookmark_model.h"
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
@@ -30,14 +30,14 @@
 #include "chrome/browser/extensions/extension_function_dispatcher.h"
 #include "chrome/browser/extensions/extension_system.h"
 #include "chrome/browser/extensions/extensions_quota_service.h"
-#include "chrome/browser/importer/importer_data_types.h"
-#include "chrome/browser/importer/importer_host.h"
-#include "chrome/browser/importer/importer_type.h"
+#include "chrome/browser/importer/external_process_importer_host.h"
+#include "chrome/browser/importer/importer_creator.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/chrome_select_file_policy.h"
 #include "chrome/common/chrome_notification_types.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/extensions/api/bookmarks.h"
+#include "chrome/common/importer/importer_data_types.h"
 #include "chrome/common/pref_names.h"
 #include "components/user_prefs/user_prefs.h"
 #include "content/public/browser/notification_service.h"
@@ -148,7 +148,7 @@
 
 void BookmarkEventRouter::DispatchEvent(
     const char* event_name,
-    scoped_ptr<ListValue> event_args) {
+    scoped_ptr<base::ListValue> event_args) {
   if (extensions::ExtensionSystem::Get(profile_)->event_router()) {
     extensions::ExtensionSystem::Get(profile_)->event_router()->BroadcastEvent(
         make_scoped_ptr(new extensions::Event(event_name, event_args.Pass())));
@@ -169,10 +169,10 @@
                                             int old_index,
                                             const BookmarkNode* new_parent,
                                             int new_index) {
-  scoped_ptr<ListValue> args(new ListValue());
+  scoped_ptr<base::ListValue> args(new base::ListValue());
   const BookmarkNode* node = new_parent->GetChild(new_index);
-  args->Append(new StringValue(base::Int64ToString(node->id())));
-  DictionaryValue* object_args = new DictionaryValue();
+  args->Append(new base::StringValue(base::Int64ToString(node->id())));
+  base::DictionaryValue* object_args = new base::DictionaryValue();
   object_args->SetString(keys::kParentIdKey,
                          base::Int64ToString(new_parent->id()));
   object_args->SetInteger(keys::kIndexKey, new_index);
@@ -187,9 +187,9 @@
 void BookmarkEventRouter::BookmarkNodeAdded(BookmarkModel* model,
                                             const BookmarkNode* parent,
                                             int index) {
-  scoped_ptr<ListValue> args(new ListValue());
+  scoped_ptr<base::ListValue> args(new base::ListValue());
   const BookmarkNode* node = parent->GetChild(index);
-  args->Append(new StringValue(base::Int64ToString(node->id())));
+  args->Append(new base::StringValue(base::Int64ToString(node->id())));
   scoped_ptr<BookmarkTreeNode> tree_node(
       bookmark_api_helpers::GetBookmarkTreeNode(node, false, false));
   args->Append(tree_node->ToValue().release());
@@ -201,9 +201,9 @@
                                               const BookmarkNode* parent,
                                               int index,
                                               const BookmarkNode* node) {
-  scoped_ptr<ListValue> args(new ListValue());
-  args->Append(new StringValue(base::Int64ToString(node->id())));
-  DictionaryValue* object_args = new DictionaryValue();
+  scoped_ptr<base::ListValue> args(new base::ListValue());
+  args->Append(new base::StringValue(base::Int64ToString(node->id())));
+  base::DictionaryValue* object_args = new base::DictionaryValue();
   object_args->SetString(keys::kParentIdKey,
                          base::Int64ToString(parent->id()));
   object_args->SetInteger(keys::kIndexKey, index);
@@ -221,15 +221,15 @@
 
 void BookmarkEventRouter::BookmarkNodeChanged(BookmarkModel* model,
                                               const BookmarkNode* node) {
-  scoped_ptr<ListValue> args(new ListValue());
-  args->Append(new StringValue(base::Int64ToString(node->id())));
+  scoped_ptr<base::ListValue> args(new base::ListValue());
+  args->Append(new base::StringValue(base::Int64ToString(node->id())));
 
   // TODO(erikkay) The only three things that BookmarkModel sends this
   // notification for are title, url and favicon.  Since we're currently
   // ignoring favicon and since the notification doesn't say which one anyway,
   // for now we only include title and url.  The ideal thing would be to change
   // BookmarkModel to indicate what changed.
-  DictionaryValue* object_args = new DictionaryValue();
+  base::DictionaryValue* object_args = new base::DictionaryValue();
   object_args->SetString(keys::kTitleKey, node->GetTitle());
   if (node->is_url())
     object_args->SetString(keys::kUrlKey, node->url().spec());
@@ -246,16 +246,17 @@
 void BookmarkEventRouter::BookmarkNodeChildrenReordered(
     BookmarkModel* model,
     const BookmarkNode* node) {
-  scoped_ptr<ListValue> args(new ListValue());
-  args->Append(new StringValue(base::Int64ToString(node->id())));
+  scoped_ptr<base::ListValue> args(new base::ListValue());
+  args->Append(new base::StringValue(base::Int64ToString(node->id())));
   int childCount = node->child_count();
-  ListValue* children = new ListValue();
+  base::ListValue* children = new base::ListValue();
   for (int i = 0; i < childCount; ++i) {
     const BookmarkNode* child = node->GetChild(i);
-    Value* child_id = new StringValue(base::Int64ToString(child->id()));
+    base::Value* child_id =
+        new base::StringValue(base::Int64ToString(child->id()));
     children->Append(child_id);
   }
-  DictionaryValue* reorder_info = new DictionaryValue();
+  base::DictionaryValue* reorder_info = new base::DictionaryValue();
   reorder_info->Set(keys::kChildIdsKey, children);
   args->Append(reorder_info);
 
@@ -264,12 +265,12 @@
 
 void BookmarkEventRouter::ExtensiveBookmarkChangesBeginning(
     BookmarkModel* model) {
-  scoped_ptr<ListValue> args(new ListValue());
+  scoped_ptr<base::ListValue> args(new base::ListValue());
   DispatchEvent(keys::kOnBookmarkImportBegan, args.Pass());
 }
 
 void BookmarkEventRouter::ExtensiveBookmarkChangesEnded(BookmarkModel* model) {
-  scoped_ptr<ListValue> args(new ListValue());
+  scoped_ptr<base::ListValue> args(new base::ListValue());
   DispatchEvent(keys::kOnBookmarkImportEnded, args.Pass());
 }
 
@@ -457,7 +458,7 @@
 }
 
 // static
-bool BookmarksRemoveFunction::ExtractIds(const ListValue* args,
+bool BookmarksRemoveFunction::ExtractIds(const base::ListValue* args,
                                          std::list<int64>* ids,
                                          bool* invalid_id) {
   std::string id_string;
@@ -568,7 +569,7 @@
 }
 
 // static
-bool BookmarksMoveFunction::ExtractIds(const ListValue* args,
+bool BookmarksMoveFunction::ExtractIds(const base::ListValue* args,
                                        std::list<int64>* ids,
                                        bool* invalid_id) {
   // For now, Move accepts ID parameters in the same way as an Update.
@@ -642,7 +643,7 @@
 }
 
 // static
-bool BookmarksUpdateFunction::ExtractIds(const ListValue* args,
+bool BookmarksUpdateFunction::ExtractIds(const base::ListValue* args,
                                          std::list<int64>* ids,
                                          bool* invalid_id) {
   // For now, Update accepts ID parameters in the same way as an Remove.
@@ -728,9 +729,9 @@
   explicit CreateBookmarkBucketMapper(Profile* profile) : profile_(profile) {}
   // TODO(tim): This should share code with BookmarksCreateFunction::RunImpl,
   // but I can't figure out a good way to do that with all the macros.
-  virtual void GetBucketsForArgs(const ListValue* args,
+  virtual void GetBucketsForArgs(const base::ListValue* args,
                                  BucketList* buckets) OVERRIDE {
-    const DictionaryValue* json;
+    const base::DictionaryValue* json;
     if (!args->GetDictionary(0, &json))
       return;
 
@@ -767,7 +768,7 @@
 class RemoveBookmarksBucketMapper : public BookmarkBucketMapper<std::string> {
  public:
   explicit RemoveBookmarksBucketMapper(Profile* profile) : profile_(profile) {}
-  virtual void GetBucketsForArgs(const ListValue* args,
+  virtual void GetBucketsForArgs(const base::ListValue* args,
                                  BucketList* buckets) OVERRIDE {
     typedef std::list<int64> IdList;
     IdList ids;
@@ -802,7 +803,8 @@
 class BookmarkIdMapper : public BookmarkBucketMapper<int64> {
  public:
   typedef std::list<int64> IdList;
-  virtual void GetBucketsForArgs(const ListValue* args, BucketList* buckets) {
+  virtual void GetBucketsForArgs(const base::ListValue* args,
+                                 BucketList* buckets) {
     IdList ids;
     bool invalid_id = false;
     if (!FunctionType::ExtractIds(args, &ids, &invalid_id) || invalid_id)
@@ -977,7 +979,7 @@
   // TODO(jgreenwald): remove ifdef once extensions are no longer built on
   // Android.
   // Deletes itself.
-  ImporterHost* importer_host = new ImporterHost;
+  ExternalProcessImporterHost* importer_host = new ExternalProcessImporterHost;
   importer::SourceProfile source_profile;
   source_profile.importer_type = importer::TYPE_BOOKMARKS_FILE;
   source_profile.source_path = path;
diff --git a/chrome/browser/extensions/api/browsing_data/browsing_data_api.cc b/chrome/browser/extensions/api/browsing_data/browsing_data_api.cc
index 0471aed..d8a5378 100644
--- a/chrome/browser/extensions/api/browsing_data/browsing_data_api.cc
+++ b/chrome/browser/extensions/api/browsing_data/browsing_data_api.cc
@@ -121,7 +121,7 @@
   // REMOVE_SITE_DATA in browsing_data_remover.h, the former for the unprotected
   // web, the latter for  protected web data. There is no UI control for
   // extension data.
-  scoped_ptr<DictionaryValue> origin_types(new DictionaryValue);
+  scoped_ptr<base::DictionaryValue> origin_types(new base::DictionaryValue);
   origin_types->SetBoolean(
       extension_browsing_data_api_constants::kUnprotectedWebKey,
       prefs->GetBoolean(prefs::kDeleteCookies));
@@ -141,14 +141,14 @@
     since = time.ToJsTime();
   }
 
-  scoped_ptr<DictionaryValue> options(new DictionaryValue);
+  scoped_ptr<base::DictionaryValue> options(new base::DictionaryValue);
   options->Set(extension_browsing_data_api_constants::kOriginTypesKey,
                origin_types.release());
   options->SetDouble(extension_browsing_data_api_constants::kSinceKey, since);
 
   // Fill dataToRemove and dataRemovalPermitted.
-  scoped_ptr<DictionaryValue> selected(new DictionaryValue);
-  scoped_ptr<DictionaryValue> permitted(new DictionaryValue);
+  scoped_ptr<base::DictionaryValue> selected(new base::DictionaryValue);
+  scoped_ptr<base::DictionaryValue> permitted(new base::DictionaryValue);
 
   bool delete_site_data = prefs->GetBoolean(prefs::kDeleteCookies) ||
                           prefs->GetBoolean(prefs::kDeleteHostedAppsData);
@@ -195,7 +195,7 @@
              extension_browsing_data_api_constants::kPasswordsKey,
              prefs->GetBoolean(prefs::kDeletePasswords));
 
-  scoped_ptr<DictionaryValue> result(new DictionaryValue);
+  scoped_ptr<base::DictionaryValue> result(new base::DictionaryValue);
   result->Set(extension_browsing_data_api_constants::kOptionsKey,
               options.release());
   result->Set(extension_browsing_data_api_constants::kDataToRemoveKey,
@@ -206,10 +206,11 @@
   return true;
 }
 
-void BrowsingDataSettingsFunction::SetDetails(DictionaryValue* selected_dict,
-                                              DictionaryValue* permitted_dict,
-                                              const char* data_type,
-                                              bool is_selected) {
+void BrowsingDataSettingsFunction::SetDetails(
+    base::DictionaryValue* selected_dict,
+    base::DictionaryValue* permitted_dict,
+    const char* data_type,
+    bool is_selected) {
   bool is_permitted = IsRemovalPermitted(MaskForKey(data_type),
                                          profile()->GetPrefs());
   selected_dict->SetBoolean(data_type, is_selected && is_permitted);
@@ -228,7 +229,7 @@
   DCHECK(profile());
 
   // Grab the initial |options| parameter, and parse out the arguments.
-  DictionaryValue* options;
+  base::DictionaryValue* options;
   EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &options));
   DCHECK(options);
 
@@ -311,7 +312,7 @@
   // UNPROTECTED_WEB if the developer doesn't specify anything.
   int mask = BrowsingDataHelper::UNPROTECTED_WEB;
 
-  const DictionaryValue* d = NULL;
+  const base::DictionaryValue* d = NULL;
   if (options.HasKey(extension_browsing_data_api_constants::kOriginTypesKey)) {
     EXTENSION_FUNCTION_VALIDATE(options.GetDictionary(
         extension_browsing_data_api_constants::kOriginTypesKey, &d));
@@ -358,7 +359,7 @@
 
   int removal_mask = 0;
 
-  for (DictionaryValue::Iterator i(*data_to_remove);
+  for (base::DictionaryValue::Iterator i(*data_to_remove);
        !i.IsAtEnd();
        i.Advance()) {
     bool selected = false;
diff --git a/chrome/browser/extensions/api/browsing_data/browsing_data_api.h b/chrome/browser/extensions/api/browsing_data/browsing_data_api.h
index cefc547..f0a4f79 100644
--- a/chrome/browser/extensions/api/browsing_data/browsing_data_api.h
+++ b/chrome/browser/extensions/api/browsing_data/browsing_data_api.h
@@ -67,8 +67,8 @@
   // indicating whether the data type is both selected and permitted to be
   // removed; and a value in the |permitted_dict| with the |data_type| as a
   // key, indicating only whether the data type is permitted to be removed.
-  void SetDetails(DictionaryValue* selected_dict,
-                  DictionaryValue* permitted_dict,
+  void SetDetails(base::DictionaryValue* selected_dict,
+                  base::DictionaryValue* permitted_dict,
                   const char* data_type,
                   bool is_selected);
 };
diff --git a/chrome/browser/extensions/api/browsing_data/browsing_data_test.cc b/chrome/browser/extensions/api/browsing_data/browsing_data_test.cc
index bfc91de..376a3f1 100644
--- a/chrome/browser/extensions/api/browsing_data/browsing_data_test.cc
+++ b/chrome/browser/extensions/api/browsing_data/browsing_data_test.cc
@@ -77,7 +77,8 @@
             details).ptr()));
   }
 
-  int GetAsMask(const DictionaryValue* dict, std::string path, int mask_value) {
+  int GetAsMask(const base::DictionaryValue* dict, std::string path,
+                int mask_value) {
     bool result;
     EXPECT_TRUE(dict->GetBoolean(path, &result)) << "for " << path;
     return result ? mask_value : 0;
@@ -347,7 +348,8 @@
       UNPROTECTED_WEB | PROTECTED_WEB | EXTENSION);
 }
 
-IN_PROC_BROWSER_TEST_F(ExtensionBrowsingDataTest, BrowsingDataRemovalMask) {
+IN_PROC_BROWSER_TEST_F(ExtensionBrowsingDataTest,
+                       FLAKY_BrowsingDataRemovalMask) {
   RunRemoveBrowsingDataWithKeyAndCompareRemovalMask(
       "appcache", BrowsingDataRemover::REMOVE_APPCACHE);
   RunRemoveBrowsingDataWithKeyAndCompareRemovalMask(
diff --git a/chrome/browser/extensions/api/commands/command_service.cc b/chrome/browser/extensions/api/commands/command_service.cc
index a14a38b..d5d75f3 100644
--- a/chrome/browser/extensions/api/commands/command_service.cc
+++ b/chrome/browser/extensions/api/commands/command_service.cc
@@ -43,7 +43,7 @@
 void SetInitialBindingsHaveBeenAssigned(
     ExtensionPrefs* prefs, const std::string& extension_id) {
   prefs->UpdateExtensionPref(extension_id, kInitialBindingsHaveBeenAssigned,
-                             Value::CreateBooleanValue(true));
+                             base::Value::CreateBooleanValue(true));
 }
 
 bool InitialBindingsHaveBeenAssigned(
@@ -165,14 +165,14 @@
 
   DictionaryPrefUpdate updater(profile_->GetPrefs(),
                                prefs::kExtensionCommands);
-  DictionaryValue* bindings = updater.Get();
+  base::DictionaryValue* bindings = updater.Get();
 
   std::string key = GetPlatformKeybindingKeyForAccelerator(accelerator);
 
   if (!allow_overrides && bindings->HasKey(key))
     return false;  // Already taken.
 
-  DictionaryValue* keybinding = new DictionaryValue();
+  base::DictionaryValue* keybinding = new base::DictionaryValue();
   keybinding->SetString(kExtension, extension_id);
   keybinding->SetString(kCommandName, command_name);
 
@@ -222,10 +222,11 @@
 
 ui::Accelerator CommandService::FindShortcutForCommand(
     const std::string& extension_id, const std::string& command) {
-  const DictionaryValue* bindings =
+  const base::DictionaryValue* bindings =
       profile_->GetPrefs()->GetDictionary(prefs::kExtensionCommands);
-  for (DictionaryValue::Iterator it(*bindings); !it.IsAtEnd(); it.Advance()) {
-    const DictionaryValue* item = NULL;
+  for (base::DictionaryValue::Iterator it(*bindings); !it.IsAtEnd();
+       it.Advance()) {
+    const base::DictionaryValue* item = NULL;
     it.value().GetAsDictionary(&item);
 
     std::string extension;
@@ -312,12 +313,13 @@
                                            const std::string& command_name) {
   DictionaryPrefUpdate updater(profile_->GetPrefs(),
                                prefs::kExtensionCommands);
-  DictionaryValue* bindings = updater.Get();
+  base::DictionaryValue* bindings = updater.Get();
 
   typedef std::vector<std::string> KeysToRemove;
   KeysToRemove keys_to_remove;
-  for (DictionaryValue::Iterator it(*bindings); !it.IsAtEnd(); it.Advance()) {
-    const DictionaryValue* item = NULL;
+  for (base::DictionaryValue::Iterator it(*bindings); !it.IsAtEnd();
+       it.Advance()) {
+    const base::DictionaryValue* item = NULL;
     it.value().GetAsDictionary(&item);
 
     std::string extension;
diff --git a/chrome/browser/extensions/api/commands/command_service_new.cc b/chrome/browser/extensions/api/commands/command_service_new.cc
index 98cbe6d..4143d6a 100644
--- a/chrome/browser/extensions/api/commands/command_service_new.cc
+++ b/chrome/browser/extensions/api/commands/command_service_new.cc
@@ -141,14 +141,14 @@
 
   DictionaryPrefUpdate updater(profile_->GetPrefs(),
                                prefs::kExtensionCommands);
-  DictionaryValue* bindings = updater.Get();
+  base::DictionaryValue* bindings = updater.Get();
 
   std::string key = GetPlatformKeybindingKeyForAccelerator(accelerator);
 
   if (!allow_overrides && bindings->HasKey(key))
     return false;  // Already taken.
 
-  DictionaryValue* keybinding = new DictionaryValue();
+  base::DictionaryValue* keybinding = new base::DictionaryValue();
   keybinding->SetString(kExtension, extension_id);
   keybinding->SetString(kCommandName, command_name);
 
@@ -198,10 +198,11 @@
 
 ui::Accelerator CommandService::FindShortcutForCommand(
     const std::string& extension_id, const std::string& command) {
-  const DictionaryValue* bindings =
+  const base::DictionaryValue* bindings =
       profile_->GetPrefs()->GetDictionary(prefs::kExtensionCommands);
-  for (DictionaryValue::Iterator it(*bindings); !it.IsAtEnd(); it.Advance()) {
-    const DictionaryValue* item = NULL;
+  for (base::DictionaryValue::Iterator it(*bindings); !it.IsAtEnd();
+       it.Advance()) {
+    const base::DictionaryValue* item = NULL;
     it.value().GetAsDictionary(&item);
 
     std::string extension;
@@ -269,12 +270,13 @@
                                            const std::string& command_name) {
   DictionaryPrefUpdate updater(profile_->GetPrefs(),
                                prefs::kExtensionCommands);
-  DictionaryValue* bindings = updater.Get();
+  base::DictionaryValue* bindings = updater.Get();
 
   typedef std::vector<std::string> KeysToRemove;
   KeysToRemove keys_to_remove;
-  for (DictionaryValue::Iterator it(*bindings); !it.IsAtEnd(); it.Advance()) {
-    const DictionaryValue* item = NULL;
+  for (base::DictionaryValue::Iterator it(*bindings); !it.IsAtEnd();
+       it.Advance()) {
+    const base::DictionaryValue* item = NULL;
     it.value().GetAsDictionary(&item);
 
     std::string extension;
diff --git a/chrome/browser/extensions/api/commands/commands.cc b/chrome/browser/extensions/api/commands/commands.cc
index ebe8bad..1bfe054 100644
--- a/chrome/browser/extensions/api/commands/commands.cc
+++ b/chrome/browser/extensions/api/commands/commands.cc
@@ -10,7 +10,7 @@
 
 base::DictionaryValue* CreateCommandValue(
     const extensions::Command& command, bool active) {
-  DictionaryValue* result = new DictionaryValue();
+  base::DictionaryValue* result = new base::DictionaryValue();
   result->SetString("name", command.command_name());
   result->SetString("description", command.description());
   result->SetString("shortcut",
@@ -22,7 +22,7 @@
 }  // namespace
 
 bool GetAllCommandsFunction::RunImpl() {
-  ListValue* command_list = new ListValue();
+  base::ListValue* command_list = new base::ListValue();
 
   extensions::CommandService* command_service =
       extensions::CommandService::Get(profile_);
diff --git a/chrome/browser/extensions/api/content_settings/content_settings_api.cc b/chrome/browser/extensions/api/content_settings/content_settings_api.cc
index 1f07c04..35223b8 100644
--- a/chrome/browser/extensions/api/content_settings/content_settings_api.cc
+++ b/chrome/browser/extensions/api/content_settings/content_settings_api.cc
@@ -42,7 +42,8 @@
 
 const std::vector<webkit::WebPluginInfo>* g_testing_plugins_;
 
-bool RemoveContentType(ListValue* args, ContentSettingsType* content_type) {
+bool RemoveContentType(base::ListValue* args,
+                       ContentSettingsType* content_type) {
   std::string content_type_str;
   if (!args->GetString(0, &content_type_str))
     return false;
@@ -160,7 +161,7 @@
                                      resource_identifier);
   }
 
-  DictionaryValue* result = new DictionaryValue();
+  base::DictionaryValue* result = new base::DictionaryValue();
   result->SetString(keys::kContentSettingKey,
                     helpers::ContentSettingToString(setting));
 
@@ -274,7 +275,7 @@
     const std::vector<webkit::WebPluginInfo>& plugins) {
   PluginFinder* finder = PluginFinder::GetInstance();
   std::set<std::string> group_identifiers;
-  ListValue* list = new ListValue();
+  base::ListValue* list = new base::ListValue();
   for (std::vector<webkit::WebPluginInfo>::const_iterator it = plugins.begin();
        it != plugins.end(); ++it) {
     scoped_ptr<PluginMetadata> plugin_metadata(finder->GetPluginMetadata(*it));
@@ -283,7 +284,7 @@
       continue;
 
     group_identifiers.insert(group_identifier);
-    DictionaryValue* dict = new DictionaryValue();
+    base::DictionaryValue* dict = new base::DictionaryValue();
     dict->SetString(keys::kIdKey, group_identifier);
     dict->SetString(keys::kDescriptionKey, plugin_metadata->name());
     list->Append(dict);
diff --git a/chrome/browser/extensions/api/content_settings/content_settings_store.h b/chrome/browser/extensions/api/content_settings/content_settings_store.h
index 07238c7..f3e9912 100644
--- a/chrome/browser/extensions/api/content_settings/content_settings_store.h
+++ b/chrome/browser/extensions/api/content_settings/content_settings_store.h
@@ -12,7 +12,7 @@
 #include "base/observer_list.h"
 #include "base/synchronization/lock.h"
 #include "base/threading/thread_checker.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "base/tuple.h"
 #include "chrome/browser/content_settings/content_settings_provider.h"
 #include "chrome/common/content_settings.h"
diff --git a/chrome/browser/extensions/api/context_menus/context_menus_api.cc b/chrome/browser/extensions/api/context_menus/context_menus_api.cc
index df0e743..de30534 100644
--- a/chrome/browser/extensions/api/context_menus/context_menus_api.cc
+++ b/chrome/browser/extensions/api/context_menus/context_menus_api.cc
@@ -166,7 +166,7 @@
     }
 
     // The Generated Id is added by context_menus_custom_bindings.js.
-    DictionaryValue* properties = NULL;
+    base::DictionaryValue* properties = NULL;
     EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &properties));
     EXTENSION_FUNCTION_VALIDATE(properties->GetInteger(kGeneratedIdKey,
                                                        &id.uid));
diff --git a/chrome/browser/extensions/api/cookies/cookies_api.cc b/chrome/browser/extensions/api/cookies/cookies_api.cc
index 72fc053..c2cd6de 100644
--- a/chrome/browser/extensions/api/cookies/cookies_api.cc
+++ b/chrome/browser/extensions/api/cookies/cookies_api.cc
@@ -13,7 +13,7 @@
 #include "base/lazy_instance.h"
 #include "base/memory/linked_ptr.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "base/values.h"
 #include "chrome/browser/extensions/api/cookies/cookies_api_constants.h"
 #include "chrome/browser/extensions/api/cookies/cookies_helpers.h"
@@ -82,8 +82,8 @@
 void CookiesEventRouter::CookieChanged(
     Profile* profile,
     ChromeCookieDetails* details) {
-  scoped_ptr<ListValue> args(new ListValue());
-  DictionaryValue* dict = new DictionaryValue();
+  scoped_ptr<base::ListValue> args(new base::ListValue());
+  base::DictionaryValue* dict = new base::DictionaryValue();
   dict->SetBoolean(keys::kRemovedKey, details->removed);
 
   scoped_ptr<Cookie> cookie(
@@ -129,7 +129,7 @@
 void CookiesEventRouter::DispatchEvent(
     Profile* profile,
     const std::string& event_name,
-    scoped_ptr<ListValue> event_args,
+    scoped_ptr<base::ListValue> event_args,
     GURL& cookie_domain) {
   EventRouter* router = profile ?
       extensions::ExtensionSystem::Get(profile)->event_router() : NULL;
@@ -511,13 +511,13 @@
 bool CookiesGetAllCookieStoresFunction::RunImpl() {
   Profile* original_profile = profile();
   DCHECK(original_profile);
-  scoped_ptr<ListValue> original_tab_ids(new ListValue());
+  scoped_ptr<base::ListValue> original_tab_ids(new base::ListValue());
   Profile* incognito_profile = NULL;
-  scoped_ptr<ListValue> incognito_tab_ids;
+  scoped_ptr<base::ListValue> incognito_tab_ids;
   if (include_incognito() && profile()->HasOffTheRecordProfile()) {
     incognito_profile = profile()->GetOffTheRecordProfile();
     if (incognito_profile)
-      incognito_tab_ids.reset(new ListValue());
+      incognito_tab_ids.reset(new base::ListValue());
   }
   DCHECK(original_profile != incognito_profile);
 
diff --git a/chrome/browser/extensions/api/cookies/cookies_helpers.cc b/chrome/browser/extensions/api/cookies/cookies_helpers.cc
index fe1f01f..c151c92 100644
--- a/chrome/browser/extensions/api/cookies/cookies_helpers.cc
+++ b/chrome/browser/extensions/api/cookies/cookies_helpers.cc
@@ -90,10 +90,10 @@
 }
 
 scoped_ptr<CookieStore> CreateCookieStore(Profile* profile,
-                                          ListValue* tab_ids) {
+                                          base::ListValue* tab_ids) {
   DCHECK(profile);
   DCHECK(tab_ids);
-  DictionaryValue dict;
+  base::DictionaryValue dict;
   dict.SetString(keys::kIdKey, GetStoreIdFromProfile(profile));
   dict.Set(keys::kTabIdsKey, tab_ids);
 
@@ -146,7 +146,7 @@
   }
 }
 
-void AppendToTabIdList(Browser* browser, ListValue* tab_ids) {
+void AppendToTabIdList(Browser* browser, base::ListValue* tab_ids) {
   DCHECK(browser);
   DCHECK(tab_ids);
   TabStripModel* tab_strip = browser->tab_strip_model();
diff --git a/chrome/browser/extensions/api/cookies/cookies_unittest.cc b/chrome/browser/extensions/api/cookies/cookies_unittest.cc
index 172ed31..f5f1523 100644
--- a/chrome/browser/extensions/api/cookies/cookies_unittest.cc
+++ b/chrome/browser/extensions/api/cookies/cookies_unittest.cc
@@ -143,7 +143,7 @@
   EXPECT_EQ(10000, *cookie2->expiration_date);
 
   TestingProfile profile;
-  ListValue* tab_ids_list = new ListValue();
+  base::ListValue* tab_ids_list = new base::ListValue();
   std::vector<int> tab_ids;
   scoped_ptr<CookieStore> cookie_store(
       cookies_helpers::CreateCookieStore(&profile, tab_ids_list));
@@ -168,7 +168,7 @@
 }
 
 TEST_F(ExtensionCookiesTest, EmptyDictionary) {
-  DictionaryValue dict;
+  base::DictionaryValue dict;
   GetAll::Params::Details details;
   bool rv = GetAll::Params::Details::Populate(dict, &details);
   ASSERT_TRUE(rv);
@@ -190,8 +190,8 @@
 
   for (size_t i = 0; i < arraysize(tests); ++i) {
     // Build up the Params struct.
-    ListValue args;
-    DictionaryValue* dict = new DictionaryValue();
+    base::ListValue args;
+    base::DictionaryValue* dict = new base::DictionaryValue();
     dict->SetString(keys::kDomainKey, std::string(tests[i].filter));
     args.Set(0, dict);
     scoped_ptr<GetAll::Params> params(GetAll::Params::Create(args));
diff --git a/chrome/browser/extensions/api/debugger/debugger_api.cc b/chrome/browser/extensions/api/debugger/debugger_api.cc
index 2ae2b7f..6ad5f83 100644
--- a/chrome/browser/extensions/api/debugger/debugger_api.cc
+++ b/chrome/browser/extensions/api/debugger/debugger_api.cc
@@ -33,6 +33,7 @@
 #include "chrome/common/extensions/extension.h"
 #include "content/public/browser/devtools_agent_host.h"
 #include "content/public/browser/devtools_client_host.h"
+#include "content/public/browser/devtools_http_handler.h"
 #include "content/public/browser/devtools_manager.h"
 #include "content/public/browser/favicon_status.h"
 #include "content/public/browser/navigation_entry.h"
@@ -48,10 +49,10 @@
 #include "extensions/common/error_utils.h"
 #include "grit/generated_resources.h"
 #include "ui/base/l10n/l10n_util.h"
-#include "webkit/glue/webkit_glue.h"
 
 using content::DevToolsAgentHost;
 using content::DevToolsClientHost;
+using content::DevToolsHttpHandler;
 using content::DevToolsManager;
 using content::RenderProcessHost;
 using content::RenderViewHost;
@@ -454,7 +455,7 @@
     DebuggerSendCommandFunction* function,
     const std::string& method,
     SendCommand::Params::CommandParams* command_params) {
-  DictionaryValue protocol_request;
+  base::DictionaryValue protocol_request;
   int request_id = ++last_request_id_;
   pending_requests_[request_id] = function;
   protocol_request.SetInteger("id", request_id);
@@ -517,7 +518,8 @@
   scoped_ptr<Value> result(base::JSONReader::Read(message));
   if (!result->IsType(Value::TYPE_DICTIONARY))
     return;
-  DictionaryValue* dictionary = static_cast<DictionaryValue*>(result.get());
+  base::DictionaryValue* dictionary =
+      static_cast<base::DictionaryValue*>(result.get());
 
   int id;
   if (!dictionary->GetInteger("id", &id)) {
@@ -526,7 +528,7 @@
       return;
 
     OnEvent::Params params;
-    DictionaryValue* params_value;
+    base::DictionaryValue* params_value;
     if (dictionary->GetDictionary("params", &params_value))
       params.additional_properties.Swap(params_value);
 
@@ -635,8 +637,8 @@
   if (!InitAgentHost())
     return false;
 
-  if (!webkit_glue::IsInspectorProtocolVersionSupported(
-      params->required_version)) {
+  if (!DevToolsHttpHandler::IsSupportedProtocolVersion(
+          params->required_version)) {
     error_ = ErrorUtils::FormatErrorMessage(
         keys::kProtocolVersionNotSupportedError,
         params->required_version);
@@ -715,7 +717,7 @@
 }
 
 void DebuggerSendCommandFunction::SendResponseBody(
-    DictionaryValue* response) {
+    base::DictionaryValue* response) {
   Value* error_body;
   if (response->Get("error", &error_body)) {
     base::JSONWriter::Write(error_body, &error_);
@@ -723,7 +725,7 @@
     return;
   }
 
-  DictionaryValue* result_body;
+  base::DictionaryValue* result_body;
   SendCommand::Results::Result result;
   if (response->GetDictionary("result", &result_body))
     result.additional_properties.Swap(result_body);
diff --git a/chrome/browser/extensions/api/declarative/declarative_rule.h b/chrome/browser/extensions/api/declarative/declarative_rule.h
index 11d223a..d1dab32 100644
--- a/chrome/browser/extensions/api/declarative/declarative_rule.h
+++ b/chrome/browser/extensions/api/declarative/declarative_rule.h
@@ -19,7 +19,7 @@
 #include "base/memory/linked_ptr.h"
 #include "base/memory/scoped_vector.h"
 #include "base/stl_util.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/common/extensions/api/events.h"
 #include "extensions/common/matcher/url_matcher.h"
 
diff --git a/chrome/browser/extensions/api/declarative/rules_registry_with_cache.cc b/chrome/browser/extensions/api/declarative/rules_registry_with_cache.cc
index 28096a1..059e7ba 100644
--- a/chrome/browser/extensions/api/declarative/rules_registry_with_cache.cc
+++ b/chrome/browser/extensions/api/declarative/rules_registry_with_cache.cc
@@ -9,7 +9,7 @@
 #include "base/message_loop.h"
 #include "base/metrics/histogram.h"
 #include "base/strings/stringprintf.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "base/values.h"
 #include "chrome/browser/extensions/extension_info_map.h"
 #include "chrome/browser/extensions/extension_prefs.h"
@@ -332,7 +332,7 @@
   if (!profile_)
     return;
 
-  const ListValue* rules = NULL;
+  const base::ListValue* rules = NULL;
   CHECK(value->GetAsList(&rules));
   bool rules_stored_previously = GetDeclarativeRulesStored(extension_id);
   bool store_rules = !rules->empty();
diff --git a/chrome/browser/extensions/api/declarative/rules_registry_with_cache_unittest.cc b/chrome/browser/extensions/api/declarative/rules_registry_with_cache_unittest.cc
index cf02cef..49bdf21 100644
--- a/chrome/browser/extensions/api/declarative/rules_registry_with_cache_unittest.cc
+++ b/chrome/browser/extensions/api/declarative/rules_registry_with_cache_unittest.cc
@@ -234,7 +234,7 @@
   // 2. Test writing behavior.
   int write_count = store->write_count();
 
-  scoped_ptr<base::ListValue> value(new ListValue);
+  scoped_ptr<base::ListValue> value(new base::ListValue);
   value->AppendBoolean(true);
   ui_part->WriteToStorage(extension_id, value.PassAs<base::Value>());
   EXPECT_TRUE(ui_part->GetDeclarativeRulesStored(extension_id));
@@ -242,7 +242,7 @@
   EXPECT_EQ(write_count + 1, store->write_count());
   write_count = store->write_count();
 
-  value.reset(new ListValue);
+  value.reset(new base::ListValue);
   ui_part->WriteToStorage(extension_id, value.PassAs<base::Value>());
   EXPECT_FALSE(ui_part->GetDeclarativeRulesStored(extension_id));
   message_loop_.RunUntilIdle();
@@ -250,7 +250,7 @@
   EXPECT_EQ(write_count + 1, store->write_count());
   write_count = store->write_count();
 
-  value.reset(new ListValue);
+  value.reset(new base::ListValue);
   ui_part->WriteToStorage(extension_id, value.PassAs<base::Value>());
   EXPECT_FALSE(ui_part->GetDeclarativeRulesStored(extension_id));
   message_loop_.RunUntilIdle();
diff --git a/chrome/browser/extensions/api/declarative_content/content_rules_registry.h b/chrome/browser/extensions/api/declarative_content/content_rules_registry.h
index 66c6a93..59fe6f4 100644
--- a/chrome/browser/extensions/api/declarative_content/content_rules_registry.h
+++ b/chrome/browser/extensions/api/declarative_content/content_rules_registry.h
@@ -13,7 +13,7 @@
 #include "base/memory/linked_ptr.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/extensions/api/declarative/declarative_rule.h"
 #include "chrome/browser/extensions/api/declarative/rules_registry_with_cache.h"
 #include "chrome/browser/extensions/api/declarative_content/content_action.h"
diff --git a/chrome/browser/extensions/api/declarative_webrequest/webrequest_action.cc b/chrome/browser/extensions/api/declarative_webrequest/webrequest_action.cc
index 1d267a8..fb38c55 100644
--- a/chrome/browser/extensions/api/declarative_webrequest/webrequest_action.cc
+++ b/chrome/browser/extensions/api/declarative_webrequest/webrequest_action.cc
@@ -46,7 +46,7 @@
   } while (0)
 
 scoped_ptr<helpers::RequestCookie> ParseRequestCookie(
-    const DictionaryValue* dict) {
+    const base::DictionaryValue* dict) {
   scoped_ptr<helpers::RequestCookie> result(new helpers::RequestCookie);
   std::string tmp;
   if (dict->GetString(keys::kNameKey, &tmp))
@@ -56,7 +56,7 @@
   return result.Pass();
 }
 
-void ParseResponseCookieImpl(const DictionaryValue* dict,
+void ParseResponseCookieImpl(const base::DictionaryValue* dict,
                              helpers::ResponseCookie* cookie) {
   std::string string_tmp;
   int int_tmp = 0;
@@ -80,14 +80,14 @@
 }
 
 scoped_ptr<helpers::ResponseCookie> ParseResponseCookie(
-    const DictionaryValue* dict) {
+    const base::DictionaryValue* dict) {
   scoped_ptr<helpers::ResponseCookie> result(new helpers::ResponseCookie);
   ParseResponseCookieImpl(dict, result.get());
   return result.Pass();
 }
 
 scoped_ptr<helpers::FilterResponseCookie> ParseFilterResponseCookie(
-    const DictionaryValue* dict) {
+    const base::DictionaryValue* dict) {
   scoped_ptr<helpers::FilterResponseCookie> result(
       new helpers::FilterResponseCookie);
   ParseResponseCookieImpl(dict, result.get());
@@ -266,18 +266,18 @@
   // Get filter.
   if (modification->type == helpers::EDIT ||
       modification->type == helpers::REMOVE) {
-    const DictionaryValue* filter = NULL;
+    const base::DictionaryValue* filter = NULL;
     INPUT_FORMAT_VALIDATE(dict->GetDictionary(keys::kFilterKey, &filter));
     modification->filter = ParseRequestCookie(filter);
   }
 
   // Get new value.
   if (modification->type == helpers::ADD) {
-    const DictionaryValue* value = NULL;
+    const base::DictionaryValue* value = NULL;
     INPUT_FORMAT_VALIDATE(dict->GetDictionary(keys::kCookieKey, &value));
     modification->modification = ParseRequestCookie(value);
   } else if (modification->type == helpers::EDIT) {
-    const DictionaryValue* value = NULL;
+    const base::DictionaryValue* value = NULL;
     INPUT_FORMAT_VALIDATE(dict->GetDictionary(keys::kModificationKey, &value));
     modification->modification = ParseRequestCookie(value);
   }
@@ -312,18 +312,18 @@
   // Get filter.
   if (modification->type == helpers::EDIT ||
       modification->type == helpers::REMOVE) {
-    const DictionaryValue* filter = NULL;
+    const base::DictionaryValue* filter = NULL;
     INPUT_FORMAT_VALIDATE(dict->GetDictionary(keys::kFilterKey, &filter));
     modification->filter = ParseFilterResponseCookie(filter);
   }
 
   // Get new value.
   if (modification->type == helpers::ADD) {
-    const DictionaryValue* value = NULL;
+    const base::DictionaryValue* value = NULL;
     INPUT_FORMAT_VALIDATE(dict->GetDictionary(keys::kCookieKey, &value));
     modification->modification = ParseResponseCookie(value);
   } else if (modification->type == helpers::EDIT) {
-    const DictionaryValue* value = NULL;
+    const base::DictionaryValue* value = NULL;
     INPUT_FORMAT_VALIDATE(dict->GetDictionary(keys::kModificationKey, &value));
     modification->modification = ParseResponseCookie(value);
   }
diff --git a/chrome/browser/extensions/api/declarative_webrequest/webrequest_action_unittest.cc b/chrome/browser/extensions/api/declarative_webrequest/webrequest_action_unittest.cc
index f5fc66c..998b8eb 100644
--- a/chrome/browser/extensions/api/declarative_webrequest/webrequest_action_unittest.cc
+++ b/chrome/browser/extensions/api/declarative_webrequest/webrequest_action_unittest.cc
@@ -11,7 +11,7 @@
 #include "base/message_loop.h"
 #include "base/path_service.h"
 #include "base/test/values_test_util.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "base/values.h"
 #include "chrome/browser/extensions/api/declarative_webrequest/request_stage.h"
 #include "chrome/browser/extensions/api/declarative_webrequest/webrequest_condition.h"
diff --git a/chrome/browser/extensions/api/declarative_webrequest/webrequest_rules_registry.h b/chrome/browser/extensions/api/declarative_webrequest/webrequest_rules_registry.h
index a1c4353..f628425 100644
--- a/chrome/browser/extensions/api/declarative_webrequest/webrequest_rules_registry.h
+++ b/chrome/browser/extensions/api/declarative_webrequest/webrequest_rules_registry.h
@@ -12,10 +12,10 @@
 #include <vector>
 
 #include "base/gtest_prod_util.h"
-#include "base/time.h"
 #include "base/memory/linked_ptr.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/time/time.h"
 #include "chrome/browser/extensions/api/declarative/declarative_rule.h"
 #include "chrome/browser/extensions/api/declarative/rules_registry_with_cache.h"
 #include "chrome/browser/extensions/api/declarative_webrequest/request_stage.h"
diff --git a/chrome/browser/extensions/api/declarative_webrequest/webrequest_rules_registry_unittest.cc b/chrome/browser/extensions/api/declarative_webrequest/webrequest_rules_registry_unittest.cc
index d80baf7..5452e18 100644
--- a/chrome/browser/extensions/api/declarative_webrequest/webrequest_rules_registry_unittest.cc
+++ b/chrome/browser/extensions/api/declarative_webrequest/webrequest_rules_registry_unittest.cc
@@ -93,28 +93,28 @@
   // Returns a rule that roughly matches http://*.example.com and
   // https://www.example.com and cancels it
   linked_ptr<RulesRegistry::Rule> CreateRule1() {
-    ListValue* scheme_http = new ListValue();
+    base::ListValue* scheme_http = new base::ListValue();
     scheme_http->Append(Value::CreateStringValue("http"));
-    DictionaryValue* http_condition_dict = new DictionaryValue();
+    base::DictionaryValue* http_condition_dict = new base::DictionaryValue();
     http_condition_dict->Set(keys2::kSchemesKey, scheme_http);
     http_condition_dict->SetString(keys2::kHostSuffixKey, "example.com");
-    DictionaryValue http_condition_url_filter;
+    base::DictionaryValue http_condition_url_filter;
     http_condition_url_filter.Set(keys::kUrlKey, http_condition_dict);
     http_condition_url_filter.SetString(keys::kInstanceTypeKey,
                                         keys::kRequestMatcherType);
 
-    ListValue* scheme_https = new ListValue();
+    base::ListValue* scheme_https = new base::ListValue();
     scheme_http->Append(Value::CreateStringValue("https"));
-    DictionaryValue* https_condition_dict = new DictionaryValue();
+    base::DictionaryValue* https_condition_dict = new base::DictionaryValue();
     https_condition_dict->Set(keys2::kSchemesKey, scheme_https);
     https_condition_dict->SetString(keys2::kHostSuffixKey, "example.com");
     https_condition_dict->SetString(keys2::kHostPrefixKey, "www");
-    DictionaryValue https_condition_url_filter;
+    base::DictionaryValue https_condition_url_filter;
     https_condition_url_filter.Set(keys::kUrlKey, https_condition_dict);
     https_condition_url_filter.SetString(keys::kInstanceTypeKey,
                                          keys::kRequestMatcherType);
 
-    DictionaryValue action_dict;
+    base::DictionaryValue action_dict;
     action_dict.SetString(keys::kInstanceTypeKey, keys::kCancelRequestType);
 
     linked_ptr<RulesRegistry::Rule> rule(new RulesRegistry::Rule);
@@ -130,10 +130,10 @@
 
   // Returns a rule that matches anything and cancels it.
   linked_ptr<RulesRegistry::Rule> CreateRule2() {
-    DictionaryValue condition_dict;
+    base::DictionaryValue condition_dict;
     condition_dict.SetString(keys::kInstanceTypeKey, keys::kRequestMatcherType);
 
-    DictionaryValue action_dict;
+    base::DictionaryValue action_dict;
     action_dict.SetString(keys::kInstanceTypeKey, keys::kCancelRequestType);
 
     linked_ptr<RulesRegistry::Rule> rule(new RulesRegistry::Rule);
@@ -147,10 +147,10 @@
 
   linked_ptr<RulesRegistry::Rule> CreateRedirectRule(
       const std::string& destination) {
-    DictionaryValue condition_dict;
+    base::DictionaryValue condition_dict;
     condition_dict.SetString(keys::kInstanceTypeKey, keys::kRequestMatcherType);
 
-    DictionaryValue action_dict;
+    base::DictionaryValue action_dict;
     action_dict.SetString(keys::kInstanceTypeKey, keys::kRedirectRequestType);
     action_dict.SetString(keys::kRedirectUrlKey, destination);
 
@@ -166,13 +166,13 @@
   // Create a rule to ignore all other rules for a destination that
   // contains index.html.
   linked_ptr<RulesRegistry::Rule> CreateIgnoreRule() {
-    DictionaryValue condition_dict;
-    DictionaryValue* http_condition_dict = new DictionaryValue();
+    base::DictionaryValue condition_dict;
+    base::DictionaryValue* http_condition_dict = new base::DictionaryValue();
     http_condition_dict->SetString(keys2::kPathContainsKey, "index.html");
     condition_dict.SetString(keys::kInstanceTypeKey, keys::kRequestMatcherType);
     condition_dict.Set(keys::kUrlKey, http_condition_dict);
 
-    DictionaryValue action_dict;
+    base::DictionaryValue action_dict;
     action_dict.SetString(keys::kInstanceTypeKey, keys::kIgnoreRulesType);
     action_dict.SetInteger(keys::kLowerPriorityThanKey, 150);
 
@@ -204,7 +204,7 @@
   linked_ptr<RulesRegistry::Rule> CreateCancellingRule(
       const char* rule_id,
       const std::vector<const std::string*>& attributes) {
-    DictionaryValue action_dict;
+    base::DictionaryValue action_dict;
     action_dict.SetString(keys::kInstanceTypeKey, keys::kCancelRequestType);
 
     linked_ptr<RulesRegistry::Rule> rule(new RulesRegistry::Rule);
diff --git a/chrome/browser/extensions/api/developer_private/developer_private_api.cc b/chrome/browser/extensions/api/developer_private/developer_private_api.cc
index 278d1d8..54d4db5 100644
--- a/chrome/browser/extensions/api/developer_private/developer_private_api.cc
+++ b/chrome/browser/extensions/api/developer_private/developer_private_api.cc
@@ -7,6 +7,7 @@
 #include "apps/app_load_service.h"
 #include "apps/app_restore_service.h"
 #include "apps/saved_files_service.h"
+#include "apps/shell_window.h"
 #include "base/base64.h"
 #include "base/command_line.h"
 #include "base/file_util.h"
@@ -19,6 +20,7 @@
 #include "chrome/browser/extensions/api/developer_private/developer_private_api_factory.h"
 #include "chrome/browser/extensions/api/developer_private/entry_picker.h"
 #include "chrome/browser/extensions/api/extension_action/extension_action_api.h"
+#include "chrome/browser/extensions/event_names.h"
 #include "chrome/browser/extensions/extension_disabled_ui.h"
 #include "chrome/browser/extensions/extension_error_reporter.h"
 #include "chrome/browser/extensions/extension_service.h"
@@ -31,7 +33,6 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/sync_file_system/drive_file_sync_service.h"
 #include "chrome/browser/ui/chrome_select_file_policy.h"
-#include "chrome/browser/ui/extensions/shell_window.h"
 #include "chrome/browser/ui/webui/extensions/extension_icon_source.h"
 #include "chrome/common/chrome_notification_types.h"
 #include "chrome/common/chrome_switches.h"
@@ -47,6 +48,7 @@
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_view_host.h"
+#include "content/public/browser/site_instance.h"
 #include "content/public/browser/storage_partition.h"
 #include "content/public/browser/web_contents.h"
 #include "extensions/browser/view_type_utils.h"
@@ -63,10 +65,13 @@
 #include "webkit/browser/fileapi/syncable/syncable_file_system_util.h"
 #include "webkit/common/blob/shareable_file_reference.h"
 
+using apps::ShellWindow;
 using content::RenderViewHost;
 
 namespace extensions {
 
+namespace events = event_names;
+
 namespace {
 
 const base::FilePath::CharType kUnpackedAppsFolder[]
@@ -105,6 +110,13 @@
   return NULL;
 }
 
+std::string GetExtensionID(const RenderViewHost* render_view_host) {
+  if (!render_view_host->GetSiteInstance())
+    return std::string();
+
+  return render_view_host->GetSiteInstance()->GetSiteURL().host();
+}
+
 }  // namespace
 
 namespace AllowFileAccess = api::developer_private::AllowFileAccess;
@@ -121,23 +133,87 @@
   return DeveloperPrivateAPIFactory::GetForProfile(profile);
 }
 
-DeveloperPrivateAPI::DeveloperPrivateAPI(Profile* profile) {
+DeveloperPrivateAPI::DeveloperPrivateAPI(Profile* profile) : profile_(profile) {
   RegisterNotifications();
 }
 
+DeveloperPrivateEventRouter::DeveloperPrivateEventRouter(Profile* profile)
+: profile_(profile) {
+  int types[] = {
+    chrome::NOTIFICATION_EXTENSION_INSTALLED,
+    chrome::NOTIFICATION_EXTENSION_UNINSTALLED,
+    chrome::NOTIFICATION_EXTENSION_LOADED,
+    chrome::NOTIFICATION_EXTENSION_UNLOADED,
+    chrome::NOTIFICATION_EXTENSION_VIEW_REGISTERED,
+    chrome::NOTIFICATION_EXTENSION_VIEW_UNREGISTERED
+  };
 
-void DeveloperPrivateAPI::Observe(
+  CHECK(registrar_.IsEmpty());
+  for (size_t i = 0; i < arraysize(types); ++i) {
+    registrar_.Add(this,
+                   types[i],
+                   content::Source<Profile>(profile_));
+  }
+}
+
+
+DeveloperPrivateEventRouter::~DeveloperPrivateEventRouter() {}
+
+void DeveloperPrivateEventRouter::Observe(
     int type,
     const content::NotificationSource& source,
     const content::NotificationDetails& details) {
+  const char* event_name = NULL;
+  Profile* profile = content::Source<Profile>(source).ptr();
+  CHECK(profile);
+  CHECK(profile_->IsSameProfile(profile));
+  developer::EventData event_data;
+  std::string extension_id;
+  const Extension* extension = NULL;
+
   switch (type) {
-    // TODO(grv): Listen to other notifications and expose them
-    // as events in API.
-    case chrome::NOTIFICATION_BACKGROUND_CONTENTS_DELETED:
+    case chrome::NOTIFICATION_EXTENSION_INSTALLED:
+      event_data.event_type = developer::EVENT_TYPE_INSTALLED;
+      extension =
+          content::Details<const InstalledExtensionInfo>(details)->extension;
+      break;
+    case chrome::NOTIFICATION_EXTENSION_UNINSTALLED:
+      event_data.event_type = developer::EVENT_TYPE_UNINSTALLED;
+      extension = content::Details<const Extension>(details).ptr();
+      break;
+    case chrome::NOTIFICATION_EXTENSION_LOADED:
+      event_data.event_type = developer::EVENT_TYPE_LOADED;
+      extension = content::Details<const Extension>(details).ptr();
+      break;
+    case chrome::NOTIFICATION_EXTENSION_UNLOADED:
+      event_data.event_type = developer::EVENT_TYPE_UNLOADED;
+      extension =
+          content::Details<const UnloadedExtensionInfo>(details)->extension;
+      break;
+    case chrome::NOTIFICATION_EXTENSION_VIEW_UNREGISTERED:
+      event_data.event_type = developer::EVENT_TYPE_VIEW_UNREGISTERED;
+      event_data.item_id = GetExtensionID(
+          content::Details<const RenderViewHost>(details).ptr());
+      break;
+    case chrome::NOTIFICATION_EXTENSION_VIEW_REGISTERED:
+      event_data.event_type = developer::EVENT_TYPE_VIEW_REGISTERED;
+      event_data.item_id = GetExtensionID(
+          content::Details<const RenderViewHost>(details).ptr());
       break;
     default:
       NOTREACHED();
+      return;
   }
+
+  if (extension)
+    event_data.item_id = extension->id();
+
+  scoped_ptr<ListValue> args(new ListValue());
+  args->Append(event_data.ToValue().release());
+
+  event_name = events::kDeveloperPrivateOnItemStateChanged;
+  scoped_ptr<Event> event(new Event(event_name, args.Pass()));
+  ExtensionSystem::Get(profile)->event_router()->BroadcastEvent(event.Pass());
 }
 
 void DeveloperPrivateAPI::SetLastUnpackedDirectory(const base::FilePath& path) {
@@ -145,15 +221,28 @@
 }
 
 void DeveloperPrivateAPI::RegisterNotifications() {
-  registrar_.Add(this,
-                 chrome::NOTIFICATION_BACKGROUND_CONTENTS_DELETED,
-                 content::NotificationService::AllBrowserContextsAndSources());
+  ExtensionSystem::Get(profile_)->event_router()->RegisterObserver(
+      this, events::kDeveloperPrivateOnItemStateChanged);
 }
 
 DeveloperPrivateAPI::~DeveloperPrivateAPI() {}
 
 void DeveloperPrivateAPI::Shutdown() {}
 
+void DeveloperPrivateAPI::OnListenerAdded(
+    const EventListenerInfo& details) {
+  if (!developer_private_event_router_)
+    developer_private_event_router_.reset(
+        new DeveloperPrivateEventRouter(profile_));
+}
+
+void DeveloperPrivateAPI::OnListenerRemoved(
+    const EventListenerInfo& details) {
+  if (!ExtensionSystem::Get(profile_)->event_router()->HasEventListener(
+          event_names::kDeveloperPrivateOnItemStateChanged))
+    developer_private_event_router_.reset(NULL);
+}
+
 namespace api {
 
 bool DeveloperPrivateAutoUpdateFunction::RunImpl() {
@@ -536,6 +625,11 @@
 
   apps::AppLoadService* service = apps::AppLoadService::Get(profile());
   EXTENSION_FUNCTION_VALIDATE(!params->item_id.empty());
+  ExtensionService* extension_service = profile()->GetExtensionService();
+  // Don't restart disabled applications.
+  if (!extension_service->IsExtensionEnabled(params->item_id))
+    return false;
+
   service->RestartApplication(params->item_id);
   return true;
 }
@@ -826,7 +920,7 @@
 
 void DeveloperPrivateExportSyncfsFolderToLocalfsFunction::
     ClearPrexistingDirectoryContent(const base::FilePath& project_path) {
-  if (!file_util::Delete(project_path, true/*recursive*/)) {
+  if (!base::Delete(project_path, true/*recursive*/)) {
     SetError("Error in copying files from sync filesystem.");
     content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
         base::Bind(&DeveloperPrivateExportSyncfsFolderToLocalfsFunction::
@@ -836,28 +930,33 @@
     return;
   }
 
+  pendingCopyOperationsCount_ = 1;
+
   content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE,
       base::Bind(&DeveloperPrivateExportSyncfsFolderToLocalfsFunction::
                  ReadSyncFileSystemDirectory,
-                 this, project_path));
+                 this, project_path, project_path.BaseName()));
 }
 
 void DeveloperPrivateExportSyncfsFolderToLocalfsFunction::
-    ReadSyncFileSystemDirectory(const base::FilePath& project_path) {
+    ReadSyncFileSystemDirectory(const base::FilePath& project_path,
+                                const base::FilePath& destination_path) {
   std::string origin_url(
       Extension::GetBaseURLFromExtensionId(extension_id()).spec());
   fileapi::FileSystemURL url(sync_file_system::CreateSyncableFileSystemURL(
       GURL(origin_url),
-      project_path.BaseName()));
+      destination_path));
 
   context_->operation_runner()->ReadDirectory(
       url, base::Bind(&DeveloperPrivateExportSyncfsFolderToLocalfsFunction::
-                      ReadSyncFileSystemDirectoryCb, this, project_path));
+                      ReadSyncFileSystemDirectoryCb,
+                      this, project_path, destination_path));
 }
 
 void DeveloperPrivateExportSyncfsFolderToLocalfsFunction::
     ReadSyncFileSystemDirectoryCb(
     const base::FilePath& project_path,
+    const base::FilePath& destination_path,
     base::PlatformFileError status,
     const fileapi::FileSystemOperation::FileEntryList& file_list,
     bool has_more) {
@@ -867,24 +966,27 @@
     return;
   }
 
-  // Create an empty project folder if there are no files.
-  if (!file_list.size()) {
-    content::BrowserThread::PostTask(content::BrowserThread::FILE, FROM_HERE,
-      base::Bind(&DeveloperPrivateExportSyncfsFolderToLocalfsFunction::
-                     CreateFolderAndSendResponse,
-                 this,
-                 project_path));
-    return;
-  }
-
-  pendingCallbacksCount_ = file_list.size();
+  // We add 1 to the pending copy operations for both files and directories. We
+  // release the directory copy operation once all the files under the directory
+  // are added for copying. We do that to ensure that pendingCopyOperationsCount
+  // does not become zero before all copy operations are finished.
+  // In case the directory happens to be executing the last copy operation it
+  // will call SendResponse to send the response to the API. The pending copy
+  // operations of files are released by the CopyFile function.
+  pendingCopyOperationsCount_ += file_list.size();
 
   for (size_t i = 0; i < file_list.size(); ++i) {
+    if (file_list[i].is_directory) {
+      ReadSyncFileSystemDirectory(project_path.Append(file_list[i].name),
+                                  destination_path.Append(file_list[i].name));
+      continue;
+    }
+
     std::string origin_url(
         Extension::GetBaseURLFromExtensionId(extension_id()).spec());
     fileapi::FileSystemURL url(sync_file_system::CreateSyncableFileSystemURL(
         GURL(origin_url),
-        project_path.BaseName().Append(file_list[i].name)));
+        destination_path.Append(file_list[i].name)));
     base::FilePath target_path = project_path;
     target_path = target_path.Append(file_list[i].name);
 
@@ -895,19 +997,19 @@
                 SnapshotFileCallback,
             this,
             target_path));
-  }
-}
 
-void DeveloperPrivateExportSyncfsFolderToLocalfsFunction::
-    CreateFolderAndSendResponse(const base::FilePath& project_path) {
-  if (!(success_ = file_util::CreateDirectory(project_path))) {
-    SetError("Error in copying files from sync filesystem.");
   }
-  content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
-      base::Bind(&DeveloperPrivateExportSyncfsFolderToLocalfsFunction::
-                     SendResponse,
-                 this,
-                 success_));
+
+  // Directory copy operation released here.
+  pendingCopyOperationsCount_--;
+
+  if (!pendingCopyOperationsCount_) {
+    content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
+        base::Bind(&DeveloperPrivateExportSyncfsFolderToLocalfsFunction::
+                       SendResponse,
+                   this,
+                   success_));
+  }
 }
 
 void DeveloperPrivateExportSyncfsFolderToLocalfsFunction::SnapshotFileCallback(
@@ -940,10 +1042,10 @@
   if (success_)
     file_util::CopyFile(src_path, target_path);
 
-  CHECK(pendingCallbacksCount_ > 0);
-  pendingCallbacksCount_--;
+  CHECK(pendingCopyOperationsCount_ > 0);
+  pendingCopyOperationsCount_--;
 
-  if (!pendingCallbacksCount_) {
+  if (!pendingCopyOperationsCount_) {
     content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
         base::Bind(&DeveloperPrivateExportSyncfsFolderToLocalfsFunction::
                        SendResponse,
@@ -954,7 +1056,7 @@
 
 DeveloperPrivateExportSyncfsFolderToLocalfsFunction::
     DeveloperPrivateExportSyncfsFolderToLocalfsFunction()
-    : pendingCallbacksCount_(0), success_(true) {}
+    : pendingCopyOperationsCount_(0), success_(true) {}
 
 DeveloperPrivateExportSyncfsFolderToLocalfsFunction::
     ~DeveloperPrivateExportSyncfsFolderToLocalfsFunction() {}
@@ -1063,7 +1165,7 @@
 DeveloperPrivateChoosePathFunction::~DeveloperPrivateChoosePathFunction() {}
 
 bool DeveloperPrivateGetStringsFunction::RunImpl() {
-  DictionaryValue* dict = new DictionaryValue();
+  base::DictionaryValue* dict = new base::DictionaryValue();
   SetResult(dict);
 
   webui::SetFontAndTextDirection(dict);
@@ -1107,7 +1209,7 @@
   SET_STRING("extensionSettingsPolicyControlled",
              IDS_EXTENSIONS_POLICY_CONTROLLED);
   SET_STRING("extensionSettingsManagedMode",
-             IDS_EXTENSIONS_LOCKED_MANAGED_MODE);
+             IDS_EXTENSIONS_LOCKED_MANAGED_USER);
   SET_STRING("extensionSettingsShowButton", IDS_EXTENSIONS_SHOW_BUTTON);
   SET_STRING("appsDevtoolLoadUnpackedButton",
              IDS_APPS_DEVTOOL_LOAD_UNPACKED_BUTTON);
diff --git a/chrome/browser/extensions/api/developer_private/developer_private_api.h b/chrome/browser/extensions/api/developer_private/developer_private_api.h
index 01361b9..567f2d9 100644
--- a/chrome/browser/extensions/api/developer_private/developer_private_api.h
+++ b/chrome/browser/extensions/api/developer_private/developer_private_api.h
@@ -8,6 +8,7 @@
 #include "base/platform_file.h"
 #include "chrome/browser/extensions/api/developer_private/entry_picker.h"
 #include "chrome/browser/extensions/api/file_system/file_system_api.h"
+#include "chrome/browser/extensions/event_router.h"
 #include "chrome/browser/extensions/extension_function.h"
 #include "chrome/browser/extensions/extension_install_prompt.h"
 #include "chrome/browser/extensions/extension_uninstall_dialog.h"
@@ -54,9 +55,27 @@
 
 namespace extensions {
 
+class DeveloperPrivateEventRouter : public content::NotificationObserver {
+ public:
+  explicit DeveloperPrivateEventRouter(Profile* profile);
+  virtual ~DeveloperPrivateEventRouter();
+
+ private:
+  // content::NotificationObserver implementation
+  virtual void Observe(int type,
+                       const content::NotificationSource& source,
+                       const content::NotificationDetails& details) OVERRIDE;
+
+  content::NotificationRegistrar registrar_;
+
+  Profile* profile_;
+
+  DISALLOW_COPY_AND_ASSIGN(DeveloperPrivateEventRouter);
+};
+
 // The profile-keyed service that manages the DeveloperPrivate API.
 class DeveloperPrivateAPI : public BrowserContextKeyedService,
-                            public content::NotificationObserver {
+                            public extensions::EventRouter::Observer {
  public:
   // Convenience method to get the DeveloperPrivateAPI for a profile.
   static DeveloperPrivateAPI* Get(Profile* profile);
@@ -73,19 +92,25 @@
   // BrowserContextKeyedService implementation
   virtual void Shutdown() OVERRIDE;
 
-  // content::NotificationObserver implementation.
-  virtual void Observe(int type,
-                       const content::NotificationSource& source,
-                       const content::NotificationDetails& details) OVERRIDE;
+  // EventRouter::Observer implementation.
+  virtual void OnListenerAdded(const extensions::EventListenerInfo& details)
+      OVERRIDE;
+  virtual void OnListenerRemoved(const extensions::EventListenerInfo& details)
+      OVERRIDE;
 
  private:
   void RegisterNotifications();
 
+  Profile* profile_;
+
   // Used to start the load |load_extension_dialog_| in the last directory that
   // was loaded.
   base::FilePath last_unpacked_directory_;
 
-  content::NotificationRegistrar registrar_;
+  // Created lazily upon OnListenerAdded.
+  scoped_ptr<DeveloperPrivateEventRouter> developer_private_event_router_;
+
+  DISALLOW_COPY_AND_ASSIGN(DeveloperPrivateAPI);
 
 };
 
@@ -351,16 +376,16 @@
 
    void ClearPrexistingDirectoryContent(const base::FilePath& project_path);
 
-   void ReadSyncFileSystemDirectory(const base::FilePath& project_path);
+   void ReadSyncFileSystemDirectory(const base::FilePath& project_path,
+                                    const base::FilePath& destination_path);
 
    void ReadSyncFileSystemDirectoryCb(
        const base::FilePath& project_path,
+       const base::FilePath& destination_path,
        base::PlatformFileError result,
        const fileapi::FileSystemOperation::FileEntryList& file_list,
        bool has_more);
 
-   void CreateFolderAndSendResponse(const base::FilePath& project_path);
-
    void SnapshotFileCallback(
        const base::FilePath& target_path,
        base::PlatformFileError result,
@@ -374,7 +399,7 @@
    scoped_refptr<fileapi::FileSystemContext> context_;
 
   private:
-   int pendingCallbacksCount_;
+   int pendingCopyOperationsCount_;
 
    // This is set to false if any of the copyFile operations fail on
    // call of the API. It is returned as a response of the API call.
diff --git a/chrome/browser/extensions/api/developer_private/entry_picker.cc b/chrome/browser/extensions/api/developer_private/entry_picker.cc
index e70ae4a..91bc1f3 100644
--- a/chrome/browser/extensions/api/developer_private/entry_picker.cc
+++ b/chrome/browser/extensions/api/developer_private/entry_picker.cc
@@ -8,10 +8,8 @@
 #include "base/files/file_path.h"
 #include "base/strings/string_util.h"
 #include "chrome/browser/extensions/api/developer_private/developer_private_api.h"
-#include "chrome/browser/extensions/shell_window_registry.h"
 #include "chrome/browser/platform_util.h"
 #include "chrome/browser/ui/chrome_select_file_policy.h"
-#include "chrome/browser/ui/extensions/shell_window.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_view.h"
 #include "ui/shell_dialogs/select_file_dialog.h"
diff --git a/chrome/browser/extensions/api/diagnostics/diagnostics_api.cc b/chrome/browser/extensions/api/diagnostics/diagnostics_api.cc
new file mode 100644
index 0000000..0f6e8d2
--- /dev/null
+++ b/chrome/browser/extensions/api/diagnostics/diagnostics_api.cc
@@ -0,0 +1,54 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/extensions/api/diagnostics/diagnostics_api.h"
+
+namespace SendPacket = extensions::api::diagnostics::SendPacket;
+
+namespace {
+
+const char kErrorPingNotImplemented[] = "Not implemented";
+const char kErrorPingFailed[] = "Failed to send ping packet";
+
+}
+
+namespace extensions {
+
+DiagnosticsSendPacketFunction::DiagnosticsSendPacketFunction() {}
+
+DiagnosticsSendPacketFunction::~DiagnosticsSendPacketFunction() {}
+
+bool DiagnosticsSendPacketFunction::Prepare() {
+  parameters_ = SendPacket::Params::Create(*args_);
+  EXTENSION_FUNCTION_VALIDATE(parameters_.get());
+  return true;
+}
+
+bool DiagnosticsSendPacketFunction::Respond() {
+  return error_.empty();
+}
+
+void DiagnosticsSendPacketFunction::OnCompleted(
+    SendPacketResultCode result_code,
+    const std::string& ip,
+    double latency) {
+  switch (result_code) {
+    case SEND_PACKET_OK: {
+      extensions::api::diagnostics::SendPacketResult result;
+      result.ip = ip;
+      result.latency = latency;
+      results_ = SendPacket::Results::Create(result);
+      break;
+    }
+    case SEND_PACKET_NOT_IMPLEMENTED:
+      SetError(kErrorPingNotImplemented);
+      break;
+    case SEND_PACKET_FAILED:
+      SetError(kErrorPingFailed);
+      break;
+  }
+  AsyncWorkCompleted();
+}
+
+}  // namespace extensions
diff --git a/chrome/browser/extensions/api/diagnostics/diagnostics_api.h b/chrome/browser/extensions/api/diagnostics/diagnostics_api.h
new file mode 100644
index 0000000..6397c71
--- /dev/null
+++ b/chrome/browser/extensions/api/diagnostics/diagnostics_api.h
@@ -0,0 +1,57 @@
+// 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_DIAGNOSTICS_DIAGNOSTICS_API_H_
+#define CHROME_BROWSER_EXTENSIONS_API_DIAGNOSTICS_DIAGNOSTICS_API_H_
+
+#include <string>
+
+#include "base/memory/scoped_ptr.h"
+#include "chrome/browser/extensions/api/api_function.h"
+#include "chrome/common/extensions/api/diagnostics.h"
+
+namespace extensions {
+
+class DiagnosticsSendPacketFunction : public AsyncApiFunction {
+ public:
+  // Result code for sending packet. Platform specific AsyncWorkStart() will
+  // finish with this ResultCode so we can maximize shared code.
+  enum SendPacketResultCode {
+    // Ping packed is sent and ICMP reply is received before time out.
+    SEND_PACKET_OK,
+
+    // Not implemented on the platform.
+    SEND_PACKET_NOT_IMPLEMENTED,
+
+    // The ping operation failed because of timeout or network unreachable.
+    SEND_PACKET_FAILED,
+  };
+
+  DECLARE_EXTENSION_FUNCTION("diagnostics.sendPacket",
+                             DIAGNOSTICS_SENDPACKET);
+
+  DiagnosticsSendPacketFunction();
+
+ protected:
+  virtual ~DiagnosticsSendPacketFunction();
+
+  // AsyncApiFunction:
+  virtual bool Prepare() OVERRIDE;
+  // This methods will be implemented differently on different platforms.
+  virtual void AsyncWorkStart() OVERRIDE;
+  virtual bool Respond() OVERRIDE;
+
+ private:
+  void SendPingPacket();
+  void OnCompleted(SendPacketResultCode result_code,
+                   const std::string& ip,
+                   double latency);
+
+  scoped_ptr<extensions::api::diagnostics::SendPacket::Params>
+      parameters_;
+};
+
+}  // namespace extensions
+
+#endif  // CHROME_BROWSER_EXTENSIONS_API_DIAGNOSTICS_DIAGNOSTICS_API_H_
diff --git a/chrome/browser/extensions/api/diagnostics/diagnostics_api_chromeos.cc b/chrome/browser/extensions/api/diagnostics/diagnostics_api_chromeos.cc
new file mode 100644
index 0000000..55f2cb0
--- /dev/null
+++ b/chrome/browser/extensions/api/diagnostics/diagnostics_api_chromeos.cc
@@ -0,0 +1,92 @@
+// 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/diagnostics/diagnostics_api.h"
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/json/json_reader.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/values.h"
+#include "chromeos/dbus/dbus_thread_manager.h"
+#include "chromeos/dbus/debug_daemon_client.h"
+
+namespace extensions {
+
+namespace {
+
+const char kCount[] = "count";
+const char kDefaultCount[] = "1";
+const char kTTL[] = "ttl";
+const char kTimeout[] = "timeout";
+const char kSize[] = "size";
+
+typedef base::Callback<void(
+    DiagnosticsSendPacketFunction::SendPacketResultCode result_code,
+    const std::string& ip,
+    double latency)>
+    SendPacketCallback;
+
+bool ParseResult(const std::string& status,
+                 std::string* ip,
+                 double* latency) {
+    // Parses the result and returns IP and latency.
+    scoped_ptr<base::Value> parsed_value(base::JSONReader::Read(status));
+    if (!parsed_value)
+      return false;
+
+    base::DictionaryValue* result = NULL;
+    if (!parsed_value->GetAsDictionary(&result) || result->size() != 1)
+      return false;
+
+    // Returns the first item.
+    base::DictionaryValue::Iterator iterator(*result);
+
+    const base::DictionaryValue* info;
+    if (!iterator.value().GetAsDictionary(&info))
+      return false;
+
+    if (info->GetDouble("avg", latency))
+      return false;
+
+    *ip = iterator.key();
+    return true;
+}
+
+void OnTestICMPCompleted(
+    const SendPacketCallback& callback,
+    bool succeeded,
+    const std::string& status) {
+  std::string ip;
+  double latency;
+  if (!succeeded || !ParseResult(status, &ip, &latency)) {
+    callback.Run(DiagnosticsSendPacketFunction::SEND_PACKET_FAILED, "", 0.0);
+  } else {
+    callback.Run(DiagnosticsSendPacketFunction::SEND_PACKET_OK,
+                 ip,
+                 latency);
+  }
+}
+
+}  // namespace
+
+void DiagnosticsSendPacketFunction::AsyncWorkStart() {
+  std::map<std::string, std::string> config;
+  config[kCount] = kDefaultCount;
+  if (parameters_->options.ttl)
+    config[kTTL] = base::IntToString(*parameters_->options.ttl);
+  if (parameters_->options.timeout)
+    config[kTimeout] = base::IntToString(*parameters_->options.timeout);
+  if (parameters_->options.size)
+    config[kSize] = base::IntToString(*parameters_->options.size);
+
+  chromeos::DBusThreadManager::Get()->GetDebugDaemonClient()->
+      TestICMPWithOptions(
+          parameters_->options.ip, config,
+          base::Bind(
+              OnTestICMPCompleted,
+              base::Bind(&DiagnosticsSendPacketFunction::OnCompleted, this)));
+}
+
+}  // namespace extensions
diff --git a/chrome/browser/extensions/api/diagnostics/diagnostics_api_nonchromeos.cc b/chrome/browser/extensions/api/diagnostics/diagnostics_api_nonchromeos.cc
new file mode 100644
index 0000000..4e75936
--- /dev/null
+++ b/chrome/browser/extensions/api/diagnostics/diagnostics_api_nonchromeos.cc
@@ -0,0 +1,13 @@
+// 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/diagnostics/diagnostics_api.h"
+
+namespace extensions {
+
+void DiagnosticsSendPacketFunction::AsyncWorkStart() {
+  OnCompleted(SEND_PACKET_NOT_IMPLEMENTED, "", 0.0);
+}
+
+}  // namespace extensions
diff --git a/chrome/browser/extensions/api/dial/dial_api.cc b/chrome/browser/extensions/api/dial/dial_api.cc
index c790185..2a30d9a 100644
--- a/chrome/browser/extensions/api/dial/dial_api.cc
+++ b/chrome/browser/extensions/api/dial/dial_api.cc
@@ -6,7 +6,7 @@
 
 #include <vector>
 
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/extensions/api/dial/dial_api_factory.h"
 #include "chrome/browser/extensions/event_names.h"
 #include "chrome/browser/extensions/event_router.h"
diff --git a/chrome/browser/extensions/api/dial/dial_device_data.h b/chrome/browser/extensions/api/dial/dial_device_data.h
index 1ee0c40..ddda6b7 100644
--- a/chrome/browser/extensions/api/dial/dial_device_data.h
+++ b/chrome/browser/extensions/api/dial/dial_device_data.h
@@ -8,7 +8,7 @@
 #include <string>
 #include <vector>
 
-#include "base/time.h"
+#include "base/time/time.h"
 #include "base/values.h"
 #include "googleurl/src/gurl.h"
 
diff --git a/chrome/browser/extensions/api/dial/dial_registry.cc b/chrome/browser/extensions/api/dial/dial_registry.cc
index bc1e2d7..e6191dc 100644
--- a/chrome/browser/extensions/api/dial/dial_registry.cc
+++ b/chrome/browser/extensions/api/dial/dial_registry.cc
@@ -7,7 +7,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/stl_util.h"
 #include "base/strings/string_number_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/extensions/api/dial/dial_api.h"
@@ -301,17 +301,10 @@
     NetworkChangeNotifier::ConnectionType type) {
   switch (type) {
     case NetworkChangeNotifier::CONNECTION_NONE:
-    case NetworkChangeNotifier::CONNECTION_2G:
-    case NetworkChangeNotifier::CONNECTION_3G:
-    case NetworkChangeNotifier::CONNECTION_4G:
       if (dial_.get()) {
         DVLOG(1) << "Lost connection, shutting down discovery and clearing"
                  << " list.";
-
-        if (NetworkChangeNotifier::IsConnectionCellular(type))
-          dial_api_->OnDialError(DIAL_CELLULAR_NETWORK);
-        else
-          dial_api_->OnDialError(DIAL_NETWORK_DISCONNECTED);
+        dial_api_->OnDialError(DIAL_NETWORK_DISCONNECTED);
 
         StopPeriodicDiscovery();
         // TODO(justinlin): As an optimization, we can probably keep our device
@@ -321,17 +314,17 @@
         MaybeSendEvent();
       }
       break;
-    case NetworkChangeNotifier::CONNECTION_UNKNOWN:
+    case NetworkChangeNotifier::CONNECTION_2G:
+    case NetworkChangeNotifier::CONNECTION_3G:
+    case NetworkChangeNotifier::CONNECTION_4G:
     case NetworkChangeNotifier::CONNECTION_ETHERNET:
     case NetworkChangeNotifier::CONNECTION_WIFI:
+    case NetworkChangeNotifier::CONNECTION_UNKNOWN:
       if (!dial_.get()) {
         DVLOG(1) << "Connection detected, restarting discovery.";
         StartPeriodicDiscovery();
       }
       break;
-    default:
-      NOTREACHED();
-      break;
   }
 }
 
diff --git a/chrome/browser/extensions/api/dial/dial_registry.h b/chrome/browser/extensions/api/dial/dial_registry.h
index f15628d..d78f531 100644
--- a/chrome/browser/extensions/api/dial/dial_registry.h
+++ b/chrome/browser/extensions/api/dial/dial_registry.h
@@ -15,8 +15,8 @@
 #include "base/memory/linked_ptr.h"
 #include "base/memory/ref_counted.h"
 #include "base/threading/thread_checker.h"
-#include "base/time.h"
-#include "base/timer.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
 #include "chrome/browser/extensions/api/dial/dial_service.h"
 #include "chrome/browser/profiles/profile.h"
 #include "net/base/network_change_notifier.h"
diff --git a/chrome/browser/extensions/api/dial/dial_registry_unittest.cc b/chrome/browser/extensions/api/dial/dial_registry_unittest.cc
index 0e3acfd..3e1b034 100644
--- a/chrome/browser/extensions/api/dial/dial_registry_unittest.cc
+++ b/chrome/browser/extensions/api/dial/dial_registry_unittest.cc
@@ -328,7 +328,8 @@
       .Times(1);
   EXPECT_CALL(mock_observer_, OnDialDeviceEvent(list_with_first_device_))
       .Times(1);
-  EXPECT_CALL(mock_observer_, OnDialError(DialRegistry::DIAL_CELLULAR_NETWORK))
+  EXPECT_CALL(mock_observer_,
+              OnDialError(DialRegistry::DIAL_NETWORK_DISCONNECTED))
       .Times(1);
   EXPECT_CALL(mock_observer_, OnDialDeviceEvent(empty_list_))
       .Times(2);
@@ -342,7 +343,7 @@
   registry_->OnDeviceDiscovered(NULL, first_device_);
   registry_->OnDiscoveryFinished(NULL);
 
-  registry_->OnNetworkChanged(net::NetworkChangeNotifier::CONNECTION_3G);
+  registry_->OnNetworkChanged(net::NetworkChangeNotifier::CONNECTION_NONE);
 
   registry_->OnDiscoveryRequest(NULL);
   registry_->OnDiscoveryFinished(NULL);
diff --git a/chrome/browser/extensions/api/dial/dial_service.cc b/chrome/browser/extensions/api/dial/dial_service.cc
index 8c106e3..b4bc70e 100644
--- a/chrome/browser/extensions/api/dial/dial_service.cc
+++ b/chrome/browser/extensions/api/dial/dial_service.cc
@@ -12,7 +12,7 @@
 #include "base/rand_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/extensions/api/dial/dial_device_data.h"
 #include "chrome/common/chrome_version_info.h"
 #include "content/public/browser/browser_thread.h"
@@ -24,6 +24,11 @@
 #include "net/base/net_util.h"
 #include "net/http/http_response_headers.h"
 #include "net/http/http_util.h"
+#if defined(OS_CHROMEOS)
+#include "chromeos/network/network_state.h"
+#include "chromeos/network/network_state_handler.h"
+#include "third_party/cros_system_api/dbus/service_constants.h"
+#endif
 
 using base::Time;
 using base::TimeDelta;
@@ -170,17 +175,51 @@
   if (socket_.get())
     return;
 
+#if defined(OS_CHROMEOS)
+  // The ChromeOS specific version of getting network interfaces does not
+  // require trampolining to another thread, and contains additional interface
+  // information such as interface types (i.e. wifi vs cellular).
+  BindSocketAndSendRequest(GetBestBindAddressChromeOS());
+#else
   BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, base::Bind(
       &GetNetworkListOnFileThread,
       base::MessageLoopProxy::current(), base::Bind(
           &DialServiceImpl::SendNetworkList, AsWeakPtr())));
+#endif
 }
 
+#if defined(OS_CHROMEOS)
+IPAddressNumber DialServiceImpl::GetBestBindAddressChromeOS() {
+  std::string connection_types[] =
+      {flimflam::kTypeWifi, flimflam::kTypeEthernet};
+  for (uint i = 0; i < arraysize(connection_types); ++i) {
+    IPAddressNumber bind_ip_address;
+    const chromeos::NetworkState* state =
+        chromeos::NetworkHandler::Get()->network_state_handler()->
+            ConnectedNetworkByType(connection_types[i]);
+    if (state &&
+        net::ParseIPLiteralToNumber(state->ip_address(), &bind_ip_address)) {
+      DCHECK(bind_ip_address.size() == net::kIPv4AddressSize);
+      DVLOG(1) << "Found " << state->type() << ", " << state->name() << ":"
+               << state->ip_address();
+      return bind_ip_address;
+    }
+  }
+  return IPAddressNumber();
+}
+#endif
+
 bool DialServiceImpl::BindSocketAndSendRequest(
       const IPAddressNumber& bind_ip_address) {
   DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!socket_.get());
 
+  if (bind_ip_address.size() == 0) {
+    DVLOG(1) << "Could not find a valid interface to bind.";
+    FinishDiscovery();
+    return false;
+  }
+
   net::RandIntCallback rand_cb = base::Bind(&base::RandInt);
   socket_.reset(new UDPSocket(net::DatagramSocket::RANDOM_BIND,
                               rand_cb,
@@ -393,7 +432,7 @@
 
 void DialServiceImpl::SendNetworkList(const NetworkInterfaceList& networks) {
   DCHECK(thread_checker_.CalledOnValidThread());
-  const NetworkInterface* interface = NULL;
+  IPAddressNumber bind_ip_address;
   // Returns the first IPv4 address found.  If there is a need for discovery
   // across multiple networks, we could manage multiple sockets.
 
@@ -403,17 +442,12 @@
     DVLOG(1) << "Found " << iter->name << ", "
              << net::IPAddressToString(iter->address);
     if (iter->address.size() == net::kIPv4AddressSize) {
-      interface = &*iter;
+      bind_ip_address = (*iter).address;
       break;
     }
   }
 
-  if (interface == NULL) {
-    DVLOG(1) << "Could not find a valid interface to bind.";
-    FinishDiscovery();
-  } else {
-    BindSocketAndSendRequest(interface->address);
-  }
+  BindSocketAndSendRequest(bind_ip_address);
 }
 
 void DialServiceImpl::FinishDiscovery() {
diff --git a/chrome/browser/extensions/api/dial/dial_service.h b/chrome/browser/extensions/api/dial/dial_service.h
index a714f35..05d328c 100644
--- a/chrome/browser/extensions/api/dial/dial_service.h
+++ b/chrome/browser/extensions/api/dial/dial_service.h
@@ -12,7 +12,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
 #include "base/threading/thread_checker.h"
-#include "base/timer.h"
+#include "base/timer/timer.h"
 #include "net/base/net_log.h"
 #include "net/udp/udp_socket.h"
 
@@ -113,6 +113,12 @@
   // Starts the control flow for one discovery cycle.
   void StartDiscovery();
 
+#if defined(OS_CHROMEOS)
+  // Returns the IP address of the preferred interface to bind the socket. This
+  // ChromeOS version can prioritize wifi and ethernet interfaces.
+  net::IPAddressNumber GetBestBindAddressChromeOS();
+#endif
+
   // Establishes the UDP socket that is used for requests and responses,
   // establishes a read callback on the socket, and sends the first discovery
   // request.  Returns true if successful.
diff --git a/chrome/browser/extensions/api/dns/dns_apitest.cc b/chrome/browser/extensions/api/dns/dns_apitest.cc
index 14c005f..ccd9602 100644
--- a/chrome/browser/extensions/api/dns/dns_apitest.cc
+++ b/chrome/browser/extensions/api/dns/dns_apitest.cc
@@ -63,7 +63,8 @@
   scoped_ptr<base::Value> result(RunFunctionAndReturnSingleResult(
       resolve_function.get(), "[\"127.0.0.1\"]", browser()));
   ASSERT_EQ(base::Value::TYPE_DICTIONARY, result->GetType());
-  DictionaryValue *value = static_cast<DictionaryValue*>(result.get());
+  base::DictionaryValue *value =
+      static_cast<base::DictionaryValue*>(result.get());
 
   int resultCode;
   EXPECT_TRUE(value->GetInteger("resultCode", &resultCode));
@@ -89,7 +90,8 @@
       RunFunctionAndReturnSingleResult(resolve_function.get(),
                                        function_arguments, browser()));
   ASSERT_EQ(base::Value::TYPE_DICTIONARY, result->GetType());
-  DictionaryValue *value = static_cast<DictionaryValue*>(result.get());
+  base::DictionaryValue *value =
+      static_cast<base::DictionaryValue*>(result.get());
 
   int resultCode;
   EXPECT_TRUE(value->GetInteger("resultCode", &resultCode));
diff --git a/chrome/browser/extensions/api/downloads/downloads_api.cc b/chrome/browser/extensions/api/downloads/downloads_api.cc
index bdd3ff4..b831d52 100644
--- a/chrome/browser/extensions/api/downloads/downloads_api.cc
+++ b/chrome/browser/extensions/api/downloads/downloads_api.cc
@@ -787,7 +787,7 @@
     ExtensionDownloadsEventRouterData* data,
     Profile* profile,
     const extensions::Extension* extension,
-    ListValue* event_args) {
+    base::ListValue* event_args) {
   *any_determiners = true;
   base::Time installed = extensions::ExtensionSystem::Get(
       profile)->extension_service()->extension_prefs()->
@@ -1046,7 +1046,7 @@
   DownloadItem* download_item = GetDownloadIfInProgress(
       profile(), include_incognito(), params->download_id);
   content::WebContents* web_contents =
-      dispatcher()->delegate()->GetAssociatedWebContents();
+      dispatcher()->delegate()->GetVisibleWebContents();
   if (!download_item ||
       !download_item->IsDangerous() ||
       !web_contents) {
@@ -1128,7 +1128,7 @@
   DownloadItem* download_item = GetDownload(
       profile(), include_incognito(), params->download_id);
   content::WebContents* web_contents =
-      dispatcher()->delegate()->GetAssociatedWebContents();
+      dispatcher()->delegate()->GetVisibleWebContents();
   if (!download_item || !web_contents) {
     error_ = download_extension_errors::kInvalidOperationError;
     return false;
diff --git a/chrome/browser/extensions/api/downloads/downloads_api_unittest.cc b/chrome/browser/extensions/api/downloads/downloads_api_unittest.cc
index 8eacf45..b3f08d0 100644
--- a/chrome/browser/extensions/api/downloads/downloads_api_unittest.cc
+++ b/chrome/browser/extensions/api/downloads/downloads_api_unittest.cc
@@ -1541,7 +1541,8 @@
 IN_PROC_BROWSER_TEST_F(DownloadExtensionTest,
                        DownloadExtensionTest_Download_Basic) {
   LoadExtension("downloads_split");
-  CHECK(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
+  ASSERT_TRUE(test_server()->Start());
   std::string download_url = test_server()->GetURL("slow?0").spec();
   GoOnTheRecord();
 
@@ -1584,7 +1585,8 @@
 IN_PROC_BROWSER_TEST_F(DownloadExtensionTest,
                        DownloadExtensionTest_Download_Incognito) {
   LoadExtension("downloads_split");
-  CHECK(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
+  ASSERT_TRUE(test_server()->Start());
   GoOffTheRecord();
   std::string download_url = test_server()->GetURL("slow?0").spec();
 
@@ -1635,7 +1637,8 @@
 IN_PROC_BROWSER_TEST_F(DownloadExtensionTest,
                        MAYBE_DownloadExtensionTest_Download_UnsafeHeaders) {
   LoadExtension("downloads_split");
-  CHECK(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
+  ASSERT_TRUE(test_server()->Start());
   GoOnTheRecord();
 
   static const char* kUnsafeHeaders[] = {
@@ -1687,7 +1690,8 @@
 IN_PROC_BROWSER_TEST_F(DownloadExtensionTest,
                        DownloadExtensionTest_Download_Subdirectory) {
   LoadExtension("downloads_split");
-  CHECK(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
+  ASSERT_TRUE(test_server()->Start());
   std::string download_url = test_server()->GetURL("slow?0").spec();
   GoOnTheRecord();
 
@@ -1703,7 +1707,8 @@
 IN_PROC_BROWSER_TEST_F(DownloadExtensionTest,
                        DownloadExtensionTest_Download_InvalidFilename) {
   LoadExtension("downloads_split");
-  CHECK(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
+  ASSERT_TRUE(test_server()->Start());
   std::string download_url = test_server()->GetURL("slow?0").spec();
   GoOnTheRecord();
 
@@ -1749,7 +1754,8 @@
 IN_PROC_BROWSER_TEST_F(DownloadExtensionTest,
                        DownloadExtensionTest_Download_URLFragment) {
   LoadExtension("downloads_split");
-  CHECK(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
+  ASSERT_TRUE(test_server()->Start());
   std::string download_url = test_server()->GetURL("slow?0#fragment").spec();
   GoOnTheRecord();
 
@@ -1886,7 +1892,8 @@
 IN_PROC_BROWSER_TEST_F(DownloadExtensionTest,
                        DownloadExtensionTest_Download_AuthBasic_Fail) {
   LoadExtension("downloads_split");
-  CHECK(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
+  ASSERT_TRUE(test_server()->Start());
   std::string download_url = test_server()->GetURL("auth-basic").spec();
   GoOnTheRecord();
 
@@ -1916,7 +1923,8 @@
 IN_PROC_BROWSER_TEST_F(DownloadExtensionTest,
                        DownloadExtensionTest_Download_Headers) {
   LoadExtension("downloads_split");
-  CHECK(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
+  ASSERT_TRUE(test_server()->Start());
   std::string download_url = test_server()->GetURL("files/downloads/"
       "a_zip_file.zip?expected_headers=Foo:bar&expected_headers=Qx:yo").spec();
   GoOnTheRecord();
@@ -1966,7 +1974,8 @@
 IN_PROC_BROWSER_TEST_F(DownloadExtensionTest,
                        DownloadExtensionTest_Download_Headers_Fail) {
   LoadExtension("downloads_split");
-  CHECK(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
+  ASSERT_TRUE(test_server()->Start());
   std::string download_url = test_server()->GetURL("files/downloads/"
       "a_zip_file.zip?expected_headers=Foo:bar&expected_headers=Qx:yo").spec();
   GoOnTheRecord();
@@ -1999,7 +2008,8 @@
 IN_PROC_BROWSER_TEST_F(DownloadExtensionTest,
                        DownloadExtensionTest_Download_AuthBasic) {
   LoadExtension("downloads_split");
-  CHECK(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
+  ASSERT_TRUE(test_server()->Start());
   std::string download_url = test_server()->GetURL("auth-basic").spec();
   // This is just base64 of 'username:secret'.
   static const char* kAuthorization = "dXNlcm5hbWU6c2VjcmV0";
@@ -2039,7 +2049,8 @@
 IN_PROC_BROWSER_TEST_F(DownloadExtensionTest,
                        DownloadExtensionTest_Download_Post) {
   LoadExtension("downloads_split");
-  CHECK(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
+  ASSERT_TRUE(test_server()->Start());
   std::string download_url = test_server()->GetURL("files/post/downloads/"
       "a_zip_file.zip?expected_body=BODY").spec();
   GoOnTheRecord();
@@ -2088,7 +2099,8 @@
 IN_PROC_BROWSER_TEST_F(DownloadExtensionTest,
                        DownloadExtensionTest_Download_Post_Get) {
   LoadExtension("downloads_split");
-  CHECK(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
+  ASSERT_TRUE(test_server()->Start());
   std::string download_url = test_server()->GetURL("files/post/downloads/"
       "a_zip_file.zip?expected_body=BODY").spec();
   GoOnTheRecord();
@@ -2126,7 +2138,8 @@
 IN_PROC_BROWSER_TEST_F(DownloadExtensionTest,
                        DownloadExtensionTest_Download_Post_NoBody) {
   LoadExtension("downloads_split");
-  CHECK(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
+  ASSERT_TRUE(test_server()->Start());
   std::string download_url = test_server()->GetURL("files/post/downloads/"
       "a_zip_file.zip?expected_body=BODY").spec();
   GoOnTheRecord();
@@ -2163,7 +2176,8 @@
 IN_PROC_BROWSER_TEST_F(DownloadExtensionTest,
                        DownloadExtensionTest_Download_Cancel) {
   LoadExtension("downloads_split");
-  CHECK(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
+  ASSERT_TRUE(test_server()->Start());
   std::string download_url = test_server()->GetURL(
       "download-known-size").spec();
   GoOnTheRecord();
@@ -2258,7 +2272,8 @@
   GoOnTheRecord();
   LoadExtension("downloads_split");
   AddFilenameDeterminer();
-  CHECK(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
+  ASSERT_TRUE(test_server()->Start());
   std::string download_url = test_server()->GetURL("slow?0").spec();
 
   // Start downloading a file.
@@ -2325,7 +2340,8 @@
   GoOnTheRecord();
   LoadExtension("downloads_split");
   AddFilenameDeterminer();
-  CHECK(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
+  ASSERT_TRUE(test_server()->Start());
   std::string download_url = test_server()->GetURL("slow?0").spec();
 
   // Start downloading a file.
@@ -2401,7 +2417,8 @@
   GoOnTheRecord();
   LoadExtension("downloads_split");
   AddFilenameDeterminer();
-  CHECK(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
+  ASSERT_TRUE(test_server()->Start());
   std::string download_url = test_server()->GetURL("slow?0").spec();
 
   // Start downloading a file.
@@ -2465,7 +2482,8 @@
   GoOnTheRecord();
   LoadExtension("downloads_split");
   AddFilenameDeterminer();
-  CHECK(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
+  ASSERT_TRUE(test_server()->Start());
   std::string download_url = test_server()->GetURL("slow?0").spec();
 
   // Start downloading a file.
@@ -2529,7 +2547,8 @@
   GoOnTheRecord();
   LoadExtension("downloads_split");
   AddFilenameDeterminer();
-  CHECK(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
+  ASSERT_TRUE(test_server()->Start());
   std::string download_url = test_server()->GetURL("slow?0").spec();
 
   // Start downloading a file.
@@ -2594,7 +2613,8 @@
   GoOnTheRecord();
   LoadExtension("downloads_split");
   AddFilenameDeterminer();
-  CHECK(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
+  ASSERT_TRUE(test_server()->Start());
   std::string download_url = test_server()->GetURL("slow?0").spec();
 
   // Start downloading a file.
@@ -2658,7 +2678,8 @@
   GoOnTheRecord();
   LoadExtension("downloads_split");
   AddFilenameDeterminer();
-  CHECK(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
+  ASSERT_TRUE(test_server()->Start());
   std::string download_url = test_server()->GetURL("slow?0").spec();
 
   // Start downloading a file.
@@ -2719,7 +2740,8 @@
 IN_PROC_BROWSER_TEST_F(
     DownloadExtensionTest,
     DownloadExtensionTest_OnDeterminingFilename_ParentDirInvalid) {
-  CHECK(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
+  ASSERT_TRUE(test_server()->Start());
   GoOnTheRecord();
   LoadExtension("downloads_split");
   AddFilenameDeterminer();
@@ -2786,7 +2808,8 @@
   GoOnTheRecord();
   LoadExtension("downloads_split");
   AddFilenameDeterminer();
-  CHECK(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
+  ASSERT_TRUE(test_server()->Start());
   std::string download_url = test_server()->GetURL("slow?0").spec();
 
   // Start downloading a file.
@@ -2851,7 +2874,8 @@
   GoOnTheRecord();
   LoadExtension("downloads_split");
   AddFilenameDeterminer();
-  CHECK(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
+  ASSERT_TRUE(test_server()->Start());
   std::string download_url = test_server()->GetURL("slow?0").spec();
 
   // Start downloading a file.
@@ -2916,7 +2940,8 @@
   GoOnTheRecord();
   LoadExtension("downloads_split");
   AddFilenameDeterminer();
-  CHECK(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
+  ASSERT_TRUE(test_server()->Start());
   std::string download_url = test_server()->GetURL("slow?0").spec();
 
   // Start downloading a file.
@@ -3037,7 +3062,8 @@
 IN_PROC_BROWSER_TEST_F(
     DownloadExtensionTest,
     DownloadExtensionTest_OnDeterminingFilename_RemoveFilenameDeterminer) {
-  CHECK(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
+  ASSERT_TRUE(test_server()->Start());
   GoOnTheRecord();
   LoadExtension("downloads_split");
   content::RenderProcessHost* host = AddFilenameDeterminer();
@@ -3087,7 +3113,8 @@
     DownloadExtensionTest,
     DownloadExtensionTest_OnDeterminingFilename_IncognitoSplit) {
   LoadExtension("downloads_split");
-  CHECK(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
+  ASSERT_TRUE(test_server()->Start());
   std::string download_url = test_server()->GetURL("slow?0").spec();
 
   GoOnTheRecord();
@@ -3219,7 +3246,8 @@
     DownloadExtensionTest,
     DownloadExtensionTest_OnDeterminingFilename_IncognitoSpanning) {
   LoadExtension("downloads_spanning");
-  CHECK(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
+  ASSERT_TRUE(test_server()->Start());
   std::string download_url = test_server()->GetURL("slow?0").spec();
 
   GoOnTheRecord();
@@ -3364,7 +3392,8 @@
   CommandLine::ForCurrentProcess()->AppendSwitch(
       switches::kEnableDownloadResumption);
   LoadExtension("downloads_split");
-  CHECK(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
+  ASSERT_TRUE(test_server()->Start());
   GoOnTheRecord();
   content::RenderProcessHost* host = AddFilenameDeterminer();
 
diff --git a/chrome/browser/extensions/api/execute_code_function.cc b/chrome/browser/extensions/api/execute_code_function.cc
index 0665657..d1a0f83 100644
--- a/chrome/browser/extensions/api/execute_code_function.cc
+++ b/chrome/browser/extensions/api/execute_code_function.cc
@@ -172,7 +172,7 @@
     const std::string& error,
     int32 on_page_id,
     const GURL& on_url,
-    const ListValue& result) {
+    const base::ListValue& result) {
   if (!error.empty())
     SetError(error);
 
diff --git a/chrome/browser/extensions/api/execute_code_function.h b/chrome/browser/extensions/api/execute_code_function.h
index 2e6dbb9..b3de979 100644
--- a/chrome/browser/extensions/api/execute_code_function.h
+++ b/chrome/browser/extensions/api/execute_code_function.h
@@ -36,7 +36,7 @@
   virtual void OnExecuteCodeFinished(const std::string& error,
                                      int32 on_page_id,
                                      const GURL& on_url,
-                                     const ListValue& result);
+                                     const base::ListValue& result);
 
   // The injection details.
   scoped_ptr<api::tabs::InjectDetails> details_;
diff --git a/chrome/browser/extensions/api/extension_action/extension_action_api.cc b/chrome/browser/extensions/api/extension_action/extension_action_api.cc
index 1047994..5102b6e 100644
--- a/chrome/browser/extensions/api/extension_action/extension_action_api.cc
+++ b/chrome/browser/extensions/api/extension_action/extension_action_api.cc
@@ -150,7 +150,7 @@
 // disk.
 scoped_ptr<base::DictionaryValue> DefaultsToValue(ExtensionAction* action) {
   const int kTabId = ExtensionAction::kDefaultTabId;
-  scoped_ptr<base::DictionaryValue> dict(new DictionaryValue());
+  scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
 
   dict->SetString(kPopupUrlStorageKey, action->GetPopupUrl(kTabId).spec());
   dict->SetString(kTitleStorageKey, action->GetTitle(kTabId));
@@ -631,7 +631,7 @@
   EXTENSION_FUNCTION_VALIDATE(details_->Get("color", &color_value));
   SkColor color = 0;
   if (color_value->IsType(Value::TYPE_LIST)) {
-    ListValue* list = NULL;
+    base::ListValue* list = NULL;
     EXTENSION_FUNCTION_VALIDATE(details_->GetList("color", &list));
     EXTENSION_FUNCTION_VALIDATE(list->GetSize() == 4);
 
@@ -671,7 +671,7 @@
 }
 
 bool ExtensionActionGetBadgeBackgroundColorFunction::RunExtensionAction() {
-  ListValue* list = new ListValue();
+  base::ListValue* list = new base::ListValue();
   SkColor color = extension_action_->GetBadgeBackgroundColor(tab_id_);
   list->Append(Value::CreateIntegerValue(SkColorGetR(color)));
   list->Append(Value::CreateIntegerValue(SkColorGetG(color)));
diff --git a/chrome/browser/extensions/api/extension_action/script_badge_apitest.cc b/chrome/browser/extensions/api/extension_action/script_badge_apitest.cc
index f81f958..c30884d 100644
--- a/chrome/browser/extensions/api/extension_action/script_badge_apitest.cc
+++ b/chrome/browser/extensions/api/extension_action/script_badge_apitest.cc
@@ -19,7 +19,7 @@
 #include "chrome/test/base/ui_test_utils.h"
 #include "content/public/browser/web_contents.h"
 #include "net/dns/mock_host_resolver.h"
-#include "net/test/spawned_test_server/spawned_test_server.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
 namespace extensions {
@@ -40,7 +40,7 @@
 };
 
 IN_PROC_BROWSER_TEST_F(ScriptBadgeApiTest, Basics) {
-  ASSERT_TRUE(test_server()->Start());
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
   ASSERT_TRUE(RunExtensionTest("script_badge/basics")) << message_;
   const Extension* extension = GetSingleLoadedExtension();
   ASSERT_TRUE(extension) << message_;
@@ -88,8 +88,8 @@
     ResultCatcher catcher;
     // Visit a non-extension page so the extension can run a content script and
     // cause the script badge to be animated in.
-    ui_test_utils::NavigateToURL(browser(),
-                                 test_server()->GetURL(std::string()));
+    ui_test_utils::NavigateToURL(
+        browser(), embedded_test_server()->GetURL("/title1.html"));
     ASSERT_TRUE(catcher.GetNextResult());
   }
   EXPECT_TRUE(script_badge->GetIsVisible(tab_id));
diff --git a/chrome/browser/extensions/api/file_system/file_system_api.cc b/chrome/browser/extensions/api/file_system/file_system_api.cc
index a2a5182..a441157 100644
--- a/chrome/browser/extensions/api/file_system/file_system_api.cc
+++ b/chrome/browser/extensions/api/file_system/file_system_api.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/extensions/api/file_system/file_system_api.h"
 
 #include "apps/saved_files_service.h"
+#include "apps/shell_window.h"
 #include "base/bind.h"
 #include "base/file_util.h"
 #include "base/files/file_path.h"
@@ -13,13 +14,14 @@
 #include "base/strings/string_util.h"
 #include "base/strings/sys_string_conversions.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/value_conversions.h"
+#include "base/values.h"
 #include "chrome/browser/extensions/api/file_handlers/app_file_handler_util.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/extension_system.h"
 #include "chrome/browser/extensions/shell_window_registry.h"
 #include "chrome/browser/platform_util.h"
 #include "chrome/browser/ui/chrome_select_file_policy.h"
-#include "chrome/browser/ui/extensions/shell_window.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/extensions/api/file_system.h"
 #include "chrome/common/extensions/permissions/api_permission.h"
@@ -50,6 +52,7 @@
 
 using apps::SavedFileEntry;
 using apps::SavedFilesService;
+using apps::ShellWindow;
 using fileapi::IsolatedContext;
 
 const char kInvalidParameters[] = "Invalid parameters";
@@ -85,12 +88,8 @@
 // Retrieves the localized display name for the base name of the given path.
 // If the path is not localized, this will just return the base name.
 std::string GetDisplayBaseName(const base::FilePath& path) {
-  base::mac::ScopedCFTypeRef<CFURLRef> url(
-      CFURLCreateFromFileSystemRepresentation(
-          NULL,
-          (const UInt8*)path.value().c_str(),
-          path.value().length(),
-          true));
+  base::ScopedCFTypeRef<CFURLRef> url(CFURLCreateFromFileSystemRepresentation(
+      NULL, (const UInt8*)path.value().c_str(), path.value().length(), true));
   if (!url)
     return path.BaseName().value();
 
@@ -338,10 +337,40 @@
   return true;
 }
 
+// Key for the path of the directory of the file last chosen by the user in
+// response to a chrome.fileSystem.chooseEntry() call.
+const char kLastChooseEntryDirectory[] = "last_choose_file_directory";
+
 }  // namespace
 
 namespace extensions {
 
+namespace file_system_api {
+
+bool GetLastChooseEntryDirectory(const ExtensionPrefs* prefs,
+                                 const std::string& extension_id,
+                                 base::FilePath* path) {
+  std::string string_path;
+  if (!prefs->ReadPrefAsString(extension_id,
+                               kLastChooseEntryDirectory,
+                               &string_path)) {
+    return false;
+  }
+
+  *path = base::FilePath::FromUTF8Unsafe(string_path);
+  return true;
+}
+
+void SetLastChooseEntryDirectory(ExtensionPrefs* prefs,
+                                 const std::string& extension_id,
+                                 const base::FilePath& path) {
+  prefs->UpdateExtensionPref(extension_id,
+                             kLastChooseEntryDirectory,
+                             base::CreateFilePathValue(path));
+}
+
+}  // namespace file_system_api
+
 bool FileSystemGetDisplayPathFunction::RunImpl() {
   std::string filesystem_name;
   std::string filesystem_path;
@@ -405,7 +434,7 @@
           GetExtension()->id(), render_view_host_->GetProcess()->GetID(), path,
           writable);
 
-  DictionaryValue* dict = new DictionaryValue();
+  base::DictionaryValue* dict = new base::DictionaryValue();
   SetResult(dict);
   dict->SetString("fileSystemId", file_entry.filesystem_id);
   dict->SetString("baseName", file_entry.registered_name);
@@ -643,9 +672,10 @@
 
 void FileSystemChooseEntryFunction::FileSelected(const base::FilePath& path,
                                                  EntryType entry_type) {
-  extensions::ExtensionSystem::Get(profile())->extension_service()->
-      extension_prefs()->SetLastChooseEntryDirectory(
-          GetExtension()->id(), path.DirName());
+  file_system_api::SetLastChooseEntryDirectory(
+      ExtensionPrefs::Get(profile()),
+      GetExtension()->id(),
+      path.DirName());
   if (entry_type == WRITABLE) {
     CheckWritableFile(path);
     return;
@@ -755,9 +785,10 @@
   file_type_info.support_drive = true;
 
   base::FilePath previous_path;
-  extensions::ExtensionSystem::Get(profile())->extension_service()->
-      extension_prefs()->GetLastChooseEntryDirectory(
-          GetExtension()->id(), &previous_path);
+  file_system_api::GetLastChooseEntryDirectory(
+      ExtensionPrefs::Get(profile()),
+      GetExtension()->id(),
+      &previous_path);
 
   content::BrowserThread::PostTaskAndReply(
       content::BrowserThread::FILE,
diff --git a/chrome/browser/extensions/api/file_system/file_system_api.h b/chrome/browser/extensions/api/file_system/file_system_api.h
index 9793e57..97b8dd1 100644
--- a/chrome/browser/extensions/api/file_system/file_system_api.h
+++ b/chrome/browser/extensions/api/file_system/file_system_api.h
@@ -9,7 +9,29 @@
 #include "chrome/common/extensions/api/file_system.h"
 #include "ui/shell_dialogs/select_file_dialog.h"
 
+namespace base {
+class FilePath;
+}
+
 namespace extensions {
+class ExtensionPrefs;
+
+namespace file_system_api {
+
+// Methods to get and set the path of the directory containing the last file
+// chosen by the user in response to a chrome.fileSystem.chooseEntry() call for
+// the given extension.
+
+// Returns true and populates result on success; false on failure.
+bool GetLastChooseEntryDirectory(const ExtensionPrefs* prefs,
+                                 const std::string& extension_id,
+                                 base::FilePath* path);
+
+void SetLastChooseEntryDirectory(ExtensionPrefs* prefs,
+                                 const std::string& extension_id,
+                                 const base::FilePath& path);
+
+}  // namespace file_system_api
 
 class FileSystemGetDisplayPathFunction : public SyncExtensionFunction {
  public:
diff --git a/chrome/browser/extensions/api/file_system/file_system_apitest.cc b/chrome/browser/extensions/api/file_system/file_system_apitest.cc
index 11f5823..ab7c4d5 100644
--- a/chrome/browser/extensions/api/file_system/file_system_apitest.cc
+++ b/chrome/browser/extensions/api/file_system/file_system_apitest.cc
@@ -7,22 +7,21 @@
 #include "base/path_service.h"
 #include "build/build_config.h"
 #include "chrome/browser/extensions/api/file_system/file_system_api.h"
-#include "chrome/browser/extensions/extension_service.h"
-#include "chrome/browser/extensions/extension_system.h"
+#include "chrome/browser/extensions/extension_prefs.h"
 #include "chrome/browser/extensions/platform_app_browsertest_util.h"
 #include "chrome/common/chrome_notification_types.h"
 #include "chrome/common/chrome_paths.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_service.h"
 
-using extensions::FileSystemChooseEntryFunction;
+namespace extensions {
 
 namespace {
 
 class AppInstallObserver : public content::NotificationObserver {
  public:
   AppInstallObserver(
-      base::Callback<void(const extensions::Extension*)> callback)
+      base::Callback<void(const Extension*)> callback)
       : callback_(callback) {
     registrar_.Add(this,
                    chrome::NOTIFICATION_EXTENSION_LOADED,
@@ -33,40 +32,42 @@
                        const content::NotificationSource& source,
                        const content::NotificationDetails& details) OVERRIDE {
     EXPECT_EQ(chrome::NOTIFICATION_EXTENSION_LOADED, type);
-    callback_.Run(content::Details<const extensions::Extension>(details).ptr());
+    callback_.Run(content::Details<const Extension>(details).ptr());
   }
 
  private:
   content::NotificationRegistrar registrar_;
-  base::Callback<void(const extensions::Extension*)> callback_;
+  base::Callback<void(const Extension*)> callback_;
   DISALLOW_COPY_AND_ASSIGN(AppInstallObserver);
 };
 
 void SetLastChooseEntryDirectory(const base::FilePath& choose_entry_directory,
-                                 extensions::ExtensionPrefs* prefs,
-                                 const extensions::Extension* extension) {
-  prefs->SetLastChooseEntryDirectory(extension->id(), choose_entry_directory);
+                                 ExtensionPrefs* prefs,
+                                 const Extension* extension) {
+  file_system_api::SetLastChooseEntryDirectory(
+      prefs, extension->id(), choose_entry_directory);
 }
 
 void SetLastChooseEntryDirectoryToAppDirectory(
-    extensions::ExtensionPrefs* prefs,
-    const extensions::Extension* extension) {
-  prefs->SetLastChooseEntryDirectory(extension->id(), extension->path());
+    ExtensionPrefs* prefs,
+    const Extension* extension) {
+  file_system_api::SetLastChooseEntryDirectory(
+      prefs, extension->id(), extension->path());
 }
 
 void AddSavedEntry(const base::FilePath& path_to_save,
                    apps::SavedFilesService* service,
-                   const extensions::Extension* extension) {
+                   const Extension* extension) {
   service->RegisterFileEntry(
       extension->id(), "magic id", path_to_save, /* writable */ true);
 }
 
 }  // namespace
 
-class FileSystemApiTest : public extensions::PlatformAppBrowserTest {
+class FileSystemApiTest : public PlatformAppBrowserTest {
  public:
   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
-    extensions::PlatformAppBrowserTest::SetUpCommandLine(command_line);
+    PlatformAppBrowserTest::SetUpCommandLine(command_line);
     test_root_folder_ = test_data_dir_.AppendASCII("api_test")
         .AppendASCII("file_system");
     FileSystemChooseEntryFunction::RegisterTempExternalFileSystemForTest(
@@ -75,7 +76,7 @@
 
   virtual void TearDown() OVERRIDE {
     FileSystemChooseEntryFunction::StopSkippingPickerForTest();
-    extensions::PlatformAppBrowserTest::TearDown();
+    PlatformAppBrowserTest::TearDown();
   };
 
  protected:
@@ -97,18 +98,17 @@
   }
 
   void CheckStoredDirectoryMatches(const base::FilePath& filename) {
-    const extensions::Extension* extension = GetSingleLoadedExtension();
+    const Extension* extension = GetSingleLoadedExtension();
     ASSERT_TRUE(extension);
     std::string extension_id = extension->id();
-    extensions::ExtensionPrefs* prefs = extensions::ExtensionSystem::Get(
-        profile())->extension_service()->extension_prefs();
+    ExtensionPrefs* prefs = ExtensionPrefs::Get(profile());
     base::FilePath stored_value;
     if (filename.empty()) {
-      EXPECT_FALSE(prefs->GetLastChooseEntryDirectory(extension_id,
-                                                      &stored_value));
+      EXPECT_FALSE(file_system_api::GetLastChooseEntryDirectory(
+          prefs, extension_id, &stored_value));
     } else {
-      EXPECT_TRUE(prefs->GetLastChooseEntryDirectory(extension_id,
-                                                     &stored_value));
+      EXPECT_TRUE(file_system_api::GetLastChooseEntryDirectory(
+          prefs, extension_id, &stored_value));
       EXPECT_EQ(base::MakeAbsoluteFilePath(filename.DirName()),
                 base::MakeAbsoluteFilePath(stored_value));
     }
@@ -182,8 +182,7 @@
     AppInstallObserver observer(
         base::Bind(SetLastChooseEntryDirectory,
                    test_file.DirName(),
-                   extensions::ExtensionSystem::Get(
-                       profile())->extension_service()->extension_prefs()));
+                   ExtensionPrefs::Get(profile())));
     ASSERT_TRUE(RunPlatformAppTest("api_test/file_system/open_existing"))
         << message_;
   }
@@ -203,8 +202,7 @@
         SetLastChooseEntryDirectory,
         test_file.DirName().Append(
             base::FilePath::FromUTF8Unsafe("fake_directory_does_not_exist")),
-        extensions::ExtensionSystem::Get(
-            profile())->extension_service()->extension_prefs()));
+        ExtensionPrefs::Get(profile())));
     ASSERT_TRUE(RunPlatformAppTest("api_test/file_system/open_existing"))
         << message_;
   }
@@ -392,8 +390,7 @@
   {
     AppInstallObserver observer(
         base::Bind(SetLastChooseEntryDirectoryToAppDirectory,
-                   extensions::ExtensionSystem::Get(
-                       profile())->extension_service()->extension_prefs()));
+                   ExtensionPrefs::Get(profile())));
     ASSERT_TRUE(RunPlatformAppTest(
         "api_test/file_system/get_writable_file_entry_non_writable_file"))
         << message_;
@@ -499,10 +496,11 @@
   {
     AppInstallObserver observer(
         base::Bind(SetLastChooseEntryDirectoryToAppDirectory,
-                   extensions::ExtensionSystem::Get(
-                       profile())->extension_service()->extension_prefs()));
+                   ExtensionPrefs::Get(profile())));
     ASSERT_TRUE(RunPlatformAppTest(
         "api_test/file_system/open_writable_existing_non_writable"))
         << message_;
   }
 }
+
+}  // namespace extensions
diff --git a/chrome/browser/extensions/api/font_settings/font_settings_api.cc b/chrome/browser/extensions/api/font_settings/font_settings_api.cc
index 7ec693d..722172a 100644
--- a/chrome/browser/extensions/api/font_settings/font_settings_api.cc
+++ b/chrome/browser/extensions/api/font_settings/font_settings_api.cc
@@ -174,8 +174,8 @@
   }
   font_name = MaybeGetLocalizedFontName(font_name);
 
-  ListValue args;
-  DictionaryValue* dict = new DictionaryValue();
+  base::ListValue args;
+  base::DictionaryValue* dict = new base::DictionaryValue();
   args.Append(dict);
   dict->SetString(kFontIdKey, font_name);
   dict->SetString(kGenericFamilyKey, generic_family);
@@ -198,8 +198,8 @@
       pref_name.c_str());
   CHECK(pref);
 
-  ListValue args;
-  DictionaryValue* dict = new DictionaryValue();
+  base::ListValue args;
+  base::DictionaryValue* dict = new base::DictionaryValue();
   args.Append(dict);
   dict->Set(key, pref->GetValue()->DeepCopy());
 
@@ -275,7 +275,7 @@
                                                         pref_path,
                                                         kIncognito);
 
-  DictionaryValue* result = new DictionaryValue();
+  base::DictionaryValue* result = new base::DictionaryValue();
   result->SetString(kFontIdKey, font_name);
   result->SetString(kLevelOfControlKey, level_of_control);
   SetResult(result);
@@ -314,15 +314,17 @@
 }
 
 void FontSettingsGetFontListFunction::FontListHasLoaded(
-    scoped_ptr<ListValue> list) {
+    scoped_ptr<base::ListValue> list) {
   bool success = CopyFontsToResult(list.get());
   SendResponse(success);
 }
 
-bool FontSettingsGetFontListFunction::CopyFontsToResult(ListValue* fonts) {
-  scoped_ptr<ListValue> result(new ListValue());
-  for (ListValue::iterator it = fonts->begin(); it != fonts->end(); ++it) {
-    ListValue* font_list_value;
+bool FontSettingsGetFontListFunction::CopyFontsToResult(
+    base::ListValue* fonts) {
+  scoped_ptr<base::ListValue> result(new base::ListValue());
+  for (base::ListValue::iterator it = fonts->begin();
+       it != fonts->end(); ++it) {
+    base::ListValue* font_list_value;
     if (!(*it)->GetAsList(&font_list_value)) {
       NOTREACHED();
       return false;
@@ -340,7 +342,7 @@
       return false;
     }
 
-    DictionaryValue* font_name = new DictionaryValue();
+    base::DictionaryValue* font_name = new base::DictionaryValue();
     font_name->Set(kFontIdKey, Value::CreateStringValue(name));
     font_name->Set(kDisplayNameKey, Value::CreateStringValue(localized_name));
     result->Append(font_name);
@@ -376,7 +378,7 @@
                                                         GetPrefName(),
                                                         kIncognito);
 
-  DictionaryValue* result = new DictionaryValue();
+  base::DictionaryValue* result = new base::DictionaryValue();
   result->Set(GetKey(), pref->GetValue()->DeepCopy());
   result->SetString(kLevelOfControlKey, level_of_control);
   SetResult(result);
@@ -389,7 +391,7 @@
     return false;
   }
 
-  DictionaryValue* details = NULL;
+  base::DictionaryValue* details = NULL;
   EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &details));
 
   Value* value;
diff --git a/chrome/browser/extensions/api/history/history_api.cc b/chrome/browser/extensions/api/history/history_api.cc
index 474db65..e45e94b 100644
--- a/chrome/browser/extensions/api/history/history_api.cc
+++ b/chrome/browser/extensions/api/history/history_api.cc
@@ -14,7 +14,7 @@
 #include "base/prefs/pref_service.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "base/values.h"
 #include "chrome/browser/extensions/event_router.h"
 #include "chrome/browser/extensions/extension_system.h"
@@ -168,7 +168,7 @@
     Profile* profile,
     const history::URLVisitedDetails* details) {
   scoped_ptr<HistoryItem> history_item = GetHistoryItem(details->row);
-  scoped_ptr<ListValue> args = OnVisited::Create(*history_item);
+  scoped_ptr<base::ListValue> args = OnVisited::Create(*history_item);
 
   DispatchEvent(profile, kOnVisited, args.Pass());
 }
@@ -186,14 +186,14 @@
   }
   removed.urls.reset(urls);
 
-  scoped_ptr<ListValue> args = OnVisitRemoved::Create(removed);
+  scoped_ptr<base::ListValue> args = OnVisitRemoved::Create(removed);
   DispatchEvent(profile, kOnVisitRemoved, args.Pass());
 }
 
 void HistoryEventRouter::DispatchEvent(
     Profile* profile,
     const char* event_name,
-    scoped_ptr<ListValue> event_args) {
+    scoped_ptr<base::ListValue> event_args) {
   if (profile && extensions::ExtensionSystem::Get(profile)->event_router()) {
     scoped_ptr<extensions::Event> event(new extensions::Event(
         event_name, event_args.Pass()));
diff --git a/chrome/browser/extensions/api/history/history_apitest.cc b/chrome/browser/extensions/api/history/history_apitest.cc
index b690e0c..f2394e0 100644
--- a/chrome/browser/extensions/api/history/history_apitest.cc
+++ b/chrome/browser/extensions/api/history/history_apitest.cc
@@ -26,8 +26,6 @@
 
     host_resolver()->AddRule("www.a.com", "127.0.0.1");
     host_resolver()->AddRule("www.b.com", "127.0.0.1");
-
-    ASSERT_TRUE(StartTestServer());
   }
 
   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
@@ -38,11 +36,13 @@
 
 // Full text search indexing sometimes exceeds a timeout. (http://crbug/119505)
 IN_PROC_BROWSER_TEST_F(HistoryApiTest, DISABLED_MiscSearch) {
+  ASSERT_TRUE(StartEmbeddedTestServer());
   ASSERT_TRUE(RunExtensionSubtest("history", "misc_search.html")) << message_;
 }
 
 // Same could happen here without the FTS (http://crbug/119505)
 IN_PROC_BROWSER_TEST_F(HistoryApiTest, DISABLED_TimedSearch) {
+  ASSERT_TRUE(StartEmbeddedTestServer());
   ASSERT_TRUE(RunExtensionSubtest("history", "timed_search.html")) << message_;
 }
 
@@ -53,18 +53,21 @@
 #define MAYBE_Delete Delete
 #endif
 IN_PROC_BROWSER_TEST_F(HistoryApiTest, MAYBE_Delete) {
+  ASSERT_TRUE(StartEmbeddedTestServer());
   ASSERT_TRUE(RunExtensionSubtest("history", "delete.html")) << message_;
 }
 
 IN_PROC_BROWSER_TEST_F(HistoryApiTest, DeleteProhibited) {
   browser()->profile()->GetPrefs()->
       SetBoolean(prefs::kAllowDeletingBrowserHistory, false);
+  ASSERT_TRUE(StartEmbeddedTestServer());
   ASSERT_TRUE(RunExtensionSubtest("history", "delete_prohibited.html")) <<
       message_;
 }
 
 // See crbug.com/79074
 IN_PROC_BROWSER_TEST_F(HistoryApiTest, DISABLED_GetVisits) {
+  ASSERT_TRUE(StartEmbeddedTestServer());
   ASSERT_TRUE(RunExtensionSubtest("history", "get_visits.html")) << message_;
 }
 
@@ -77,11 +80,14 @@
 #endif
 
 IN_PROC_BROWSER_TEST_F(HistoryApiTest, MAYBE_SearchAfterAdd) {
+  ASSERT_TRUE(StartEmbeddedTestServer());
   ASSERT_TRUE(RunExtensionSubtest("history", "search_after_add.html"))
       << message_;
 }
 
 IN_PROC_BROWSER_TEST_F(HistoryApiTest, MostVisited) {
+  ASSERT_TRUE(StartEmbeddedTestServer());
+
   // Add entries to the history database that we can query for (using the
   // extension history API for this doesn't work as it only adds URLs with
   // LINK transition type).
diff --git a/chrome/browser/extensions/api/i18n/i18n_apitest.cc b/chrome/browser/extensions/api/i18n/i18n_apitest.cc
index a255d1f..12c7142 100644
--- a/chrome/browser/extensions/api/i18n/i18n_apitest.cc
+++ b/chrome/browser/extensions/api/i18n/i18n_apitest.cc
@@ -10,15 +10,15 @@
 #include "chrome/browser/ui/browser.h"
 #include "chrome/common/extensions/extension.h"
 #include "chrome/test/base/ui_test_utils.h"
-#include "net/test/spawned_test_server/spawned_test_server.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
 
 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, I18N) {
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
   ASSERT_TRUE(RunExtensionTest("i18n")) << message_;
 }
 
 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, I18NUpdate) {
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
   // Create an Extension whose messages.json file will be updated.
   base::ScopedTempDir extension_dir;
   ASSERT_TRUE(extension_dir.CreateUniqueTempDir());
@@ -42,7 +42,8 @@
 
   // Test that the messages.json file is loaded and the i18n message is loaded.
   ui_test_utils::NavigateToURL(
-      browser(), test_server()->GetURL("file/extensions/test_file.html"));
+      browser(),
+      embedded_test_server()->GetURL("/extensions/test_file.html"));
   EXPECT_TRUE(catcher.GetNextResult());
 
   string16 title;
@@ -58,7 +59,8 @@
 
   // Check that the i18n message is also changed.
   ui_test_utils::NavigateToURL(
-      browser(), test_server()->GetURL("file/extensions/test_file.html"));
+      browser(),
+      embedded_test_server()->GetURL("/extensions/test_file.html"));
   EXPECT_TRUE(catcher.GetNextResult());
 
   ui_test_utils::GetCurrentTabTitle(browser(), &title);
diff --git a/chrome/browser/extensions/api/identity/identity_api.cc b/chrome/browser/extensions/api/identity/identity_api.cc
index cdcd4dc..3191610 100644
--- a/chrome/browser/extensions/api/identity/identity_api.cc
+++ b/chrome/browser/extensions/api/identity/identity_api.cc
@@ -18,6 +18,7 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/extensions/extension_function_dispatcher.h"
 #include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/policy/browser_policy_connector.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/signin/signin_manager.h"
 #include "chrome/browser/signin/signin_manager_factory.h"
@@ -31,10 +32,13 @@
 #include "chrome/common/pref_names.h"
 #include "chrome/common/url_constants.h"
 #include "google_apis/gaia/gaia_constants.h"
+#include "google_apis/gaia/gaia_urls.h"
 #include "googleurl/src/gurl.h"
 
 #if defined(OS_CHROMEOS)
 #include "chrome/browser/chromeos/login/user_manager.h"
+#include "chrome/browser/chromeos/settings/device_oauth2_token_service.h"
+#include "chrome/browser/chromeos/settings/device_oauth2_token_service_factory.h"
 #endif
 
 namespace extensions {
@@ -88,7 +92,8 @@
   const OAuth2Info& oauth2_info = OAuth2Info::GetOAuth2Info(GetExtension());
 
   // Check that the necessary information is present in the manifest.
-  if (oauth2_info.client_id.empty()) {
+  oauth2_client_id_ = GetOAuth2ClientId();
+  if (oauth2_client_id_.empty()) {
     error_ = identity_constants::kInvalidClientId;
     return false;
   }
@@ -101,6 +106,14 @@
   // Balanced in CompleteFunctionWithResult|CompleteFunctionWithError
   AddRef();
 
+#if defined(OS_CHROMEOS)
+  if (chromeos::UserManager::Get()->IsLoggedInAsKioskApp() &&
+      g_browser_process->browser_policy_connector()->IsEnterpriseManaged()) {
+    StartMintTokenFlow(IdentityMintRequestQueue::MINT_TYPE_NONINTERACTIVE);
+    return true;
+  }
+#endif
+
   if (!HasLoginToken()) {
     if (!should_prompt_for_signin_) {
       error_ = identity_constants::kUserNotSignedIn;
@@ -206,11 +219,21 @@
       case IdentityTokenCacheValue::CACHE_STATUS_NOTFOUND:
 #if defined(OS_CHROMEOS)
         // Always force minting token for ChromeOS kiosk app.
-        if (chrome::IsRunningInForcedAppMode()) {
-          StartGaiaRequest(OAuth2MintTokenFlow::MODE_MINT_TOKEN_FORCE);
+        if (chromeos::UserManager::Get()->IsLoggedInAsKioskApp()) {
+          if (g_browser_process->browser_policy_connector()->
+                  IsEnterpriseManaged()) {
+            OAuth2TokenService::ScopeSet scope_set(oauth2_info.scopes.begin(),
+                                                   oauth2_info.scopes.end());
+            device_token_request_ =
+                chromeos::DeviceOAuth2TokenServiceFactory::Get()->StartRequest(
+                    scope_set, this);
+          } else {
+            StartGaiaRequest(OAuth2MintTokenFlow::MODE_MINT_TOKEN_FORCE);
+          }
           return;
         }
 #endif
+
         if (oauth2_info.auto_approve)
           // oauth2_info.auto_approve is protected by a whitelist in
           // _manifest_features.json hence only selected extensions take
@@ -330,8 +353,6 @@
       error = MapOAuth2ErrorToDescription(oauth_error);
       break;
 
-      // TODO(courage): load failure tests
-
     case GaiaWebAuthFlow::LOAD_FAILED:
       error = identity_constants::kPageLoadFailure;
       break;
@@ -362,6 +383,32 @@
   CompleteFunctionWithResult(access_token);
 }
 
+void IdentityGetAuthTokenFunction::OnGetTokenSuccess(
+    const OAuth2TokenService::Request* request,
+    const std::string& access_token,
+    const base::Time& expiration_time) {
+  DCHECK_EQ(device_token_request_.get(), request);
+  device_token_request_.reset();
+
+  const OAuth2Info& oauth2_info = OAuth2Info::GetOAuth2Info(GetExtension());
+  IdentityTokenCacheValue token(access_token,
+                                expiration_time - base::Time::Now());
+  IdentityAPI::GetFactoryInstance()->GetForProfile(profile())->SetCachedToken(
+      GetExtension()->id(), oauth2_info.scopes, token);
+
+  CompleteMintTokenFlow();
+  CompleteFunctionWithResult(access_token);
+}
+
+void IdentityGetAuthTokenFunction::OnGetTokenFailure(
+    const OAuth2TokenService::Request* request,
+    const GoogleServiceAuthError& error) {
+  DCHECK_EQ(device_token_request_.get(), request);
+  device_token_request_.reset();
+
+  OnGaiaFlowFailure(GaiaWebAuthFlow::SERVICE_AUTH_ERROR, error, std::string());
+}
+
 void IdentityGetAuthTokenFunction::StartGaiaRequest(
     OAuth2MintTokenFlow::Mode mode) {
   mint_token_flow_.reset(CreateMintTokenFlow(mode));
@@ -387,6 +434,7 @@
 OAuth2MintTokenFlow* IdentityGetAuthTokenFunction::CreateMintTokenFlow(
     OAuth2MintTokenFlow::Mode mode) {
   const OAuth2Info& oauth2_info = OAuth2Info::GetOAuth2Info(GetExtension());
+
   OAuth2MintTokenFlow* mint_token_flow =
       new OAuth2MintTokenFlow(
           profile()->GetRequestContext(),
@@ -394,7 +442,7 @@
           OAuth2MintTokenFlow::Parameters(
               refresh_token_,
               GetExtension()->id(),
-              oauth2_info.client_id,
+              oauth2_client_id_,
               oauth2_info.scopes,
               mode));
 #if defined(OS_CHROMEOS)
@@ -429,6 +477,19 @@
     return std::string(identity_constants::kAuthFailure) + error;
 }
 
+std::string IdentityGetAuthTokenFunction::GetOAuth2ClientId() const {
+  const OAuth2Info& oauth2_info = OAuth2Info::GetOAuth2Info(GetExtension());
+  std::string client_id = oauth2_info.client_id;
+
+  // Component apps using auto_approve may use Chrome's client ID by
+  // omitting the field.
+  if (client_id.empty() && GetExtension()->location() == Manifest::COMPONENT &&
+      oauth2_info.auto_approve) {
+    client_id = GaiaUrls::GetInstance()->oauth2_chrome_client_id();
+  }
+  return client_id;
+}
+
 IdentityRemoveCachedAuthTokenFunction::IdentityRemoveCachedAuthTokenFunction() {
 }
 
diff --git a/chrome/browser/extensions/api/identity/identity_api.h b/chrome/browser/extensions/api/identity/identity_api.h
index b2b85c3..a04a01d 100644
--- a/chrome/browser/extensions/api/identity/identity_api.h
+++ b/chrome/browser/extensions/api/identity/identity_api.h
@@ -19,10 +19,12 @@
 #include "chrome/browser/extensions/api/identity/web_auth_flow.h"
 #include "chrome/browser/extensions/api/profile_keyed_api_factory.h"
 #include "chrome/browser/extensions/extension_function.h"
+#include "chrome/browser/signin/oauth2_token_service.h"
 #include "chrome/browser/signin/signin_global_error.h"
 #include "google_apis/gaia/oauth2_mint_token_flow.h"
 
 class GoogleServiceAuthError;
+class MockGetAuthTokenFunction;
 class Profile;
 class SigninManagerBase;
 
@@ -65,7 +67,8 @@
                                      public GaiaWebAuthFlow::Delegate,
                                      public IdentityMintRequestQueue::Request,
                                      public OAuth2MintTokenFlow::Delegate,
-                                     public IdentitySigninFlow::Delegate {
+                                     public IdentitySigninFlow::Delegate,
+                                     public OAuth2TokenService::Consumer {
  public:
   DECLARE_EXTENSION_FUNCTION("identity.getAuthToken",
                              EXPERIMENTAL_IDENTITY_GETAUTHTOKEN);
@@ -76,7 +79,10 @@
   virtual ~IdentityGetAuthTokenFunction();
 
  private:
-  friend class GetAuthTokenFunctionTest;
+  FRIEND_TEST_ALL_PREFIXES(GetAuthTokenFunctionTest,
+                           ComponentWithChromeClientId);
+  FRIEND_TEST_ALL_PREFIXES(GetAuthTokenFunctionTest,
+                           ComponentWithNormalClientId);
   friend class MockGetAuthTokenFunction;
 
   // ExtensionFunction:
@@ -113,6 +119,13 @@
   virtual void OnGaiaFlowCompleted(const std::string& access_token,
                                    const std::string& expiration) OVERRIDE;
 
+  // OAuth2TokenService::Consumer implementation:
+  virtual void OnGetTokenSuccess(const OAuth2TokenService::Request* request,
+                                 const std::string& access_token,
+                                 const base::Time& expiration_time) OVERRIDE;
+  virtual void OnGetTokenFailure(const OAuth2TokenService::Request* request,
+                                 const GoogleServiceAuthError& error) OVERRIDE;
+
   // Starts a mint token request to GAIA.
   void StartGaiaRequest(OAuth2MintTokenFlow::Mode mode);
 
@@ -130,17 +143,21 @@
   // developer in chrome.runtime.lastError.
   std::string MapOAuth2ErrorToDescription(const std::string& error);
 
+  std::string GetOAuth2ClientId() const;
+
   bool should_prompt_for_scopes_;
   IdentityMintRequestQueue::MintType mint_token_flow_type_;
   scoped_ptr<OAuth2MintTokenFlow> mint_token_flow_;
   std::string refresh_token_;
   bool should_prompt_for_signin_;
 
+  std::string oauth2_client_id_;
   // When launched in interactive mode, and if there is no existing grant,
   // a permissions prompt will be popped up to the user.
   IssueAdviceInfo issue_advice_;
   scoped_ptr<GaiaWebAuthFlow> gaia_web_auth_flow_;
   scoped_ptr<IdentitySigninFlow> signin_flow_;
+  scoped_ptr<OAuth2TokenService::Request> device_token_request_;
 };
 
 class IdentityRemoveCachedAuthTokenFunction : public SyncExtensionFunction {
diff --git a/chrome/browser/extensions/api/identity/identity_apitest.cc b/chrome/browser/extensions/api/identity/identity_apitest.cc
index 73e871d..8659114 100644
--- a/chrome/browser/extensions/api/identity/identity_apitest.cc
+++ b/chrome/browser/extensions/api/identity/identity_apitest.cc
@@ -315,7 +315,8 @@
   enum OAuth2Fields {
     NONE = 0,
     CLIENT_ID = 1,
-    SCOPES = 2
+    SCOPES = 2,
+    AS_COMPONENT = 4
   };
 
   virtual ~GetAuthTokenFunctionTest() {}
@@ -323,10 +324,17 @@
   // Helper to create an extension with specific OAuth2Info fields set.
   // |fields_to_set| should be computed by using fields of Oauth2Fields enum.
   const Extension* CreateExtension(int fields_to_set) {
-    const Extension* ext = LoadExtension(
-        test_data_dir_.AppendASCII("platform_apps/oauth2"));
-    OAuth2Info& oauth2_info = const_cast<OAuth2Info&>(
-        OAuth2Info::GetOAuth2Info(ext));
+    const Extension* ext;
+    base::FilePath manifest_path =
+        test_data_dir_.AppendASCII("platform_apps/oauth2");
+    base::FilePath component_manifest_path =
+        test_data_dir_.AppendASCII("packaged_app/component_oauth2");
+    if ((fields_to_set & AS_COMPONENT) == 0)
+      ext = LoadExtension(manifest_path);
+    else
+      ext = LoadExtensionAsComponent(component_manifest_path);
+    OAuth2Info& oauth2_info =
+        const_cast<OAuth2Info&>(OAuth2Info::GetOAuth2Info(ext));
     if ((fields_to_set & CLIENT_ID) != 0)
       oauth2_info.client_id = "client1";
     if ((fields_to_set & SCOPES) != 0) {
@@ -934,6 +942,25 @@
                                      oauth2_info.scopes).status());
 }
 
+IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, ComponentWithChromeClientId) {
+  scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
+  scoped_refptr<const Extension> extension(
+      CreateExtension(SCOPES | AS_COMPONENT));
+  func->set_extension(extension.get());
+  const OAuth2Info& oauth2_info = OAuth2Info::GetOAuth2Info(extension.get());
+  EXPECT_TRUE(oauth2_info.client_id.empty());
+  EXPECT_FALSE(func->GetOAuth2ClientId().empty());
+  EXPECT_NE("client1", func->GetOAuth2ClientId());
+}
+
+IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, ComponentWithNormalClientId) {
+  scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
+  scoped_refptr<const Extension> extension(
+      CreateExtension(CLIENT_ID | SCOPES | AS_COMPONENT));
+  func->set_extension(extension.get());
+  EXPECT_EQ("client1", func->GetOAuth2ClientId());
+}
+
 class RemoveCachedAuthTokenFunctionTest : public ExtensionBrowserTest {
  protected:
   bool InvalidateDefaultToken() {
diff --git a/chrome/browser/extensions/api/identity/web_auth_flow.cc b/chrome/browser/extensions/api/identity/web_auth_flow.cc
index b0ad761..4a8f2ad 100644
--- a/chrome/browser/extensions/api/identity/web_auth_flow.cc
+++ b/chrome/browser/extensions/api/identity/web_auth_flow.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/extensions/api/identity/web_auth_flow.h"
 
+#include "apps/shell_window.h"
 #include "base/base64.h"
 #include "base/location.h"
 #include "base/message_loop.h"
@@ -15,7 +16,6 @@
 #include "chrome/browser/extensions/extension_system.h"
 #include "chrome/browser/extensions/extension_system.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/extensions/shell_window.h"
 #include "chrome/common/extensions/extension_constants.h"
 #include "content/public/browser/navigation_details.h"
 #include "content/public/browser/navigation_entry.h"
@@ -30,6 +30,7 @@
 #include "googleurl/src/gurl.h"
 #include "grit/browser_resources.h"
 
+using apps::ShellWindow;
 using content::RenderViewHost;
 using content::ResourceRedirectDetails;
 using content::WebContents;
@@ -77,7 +78,7 @@
   DCHECK(success);
 
   // identityPrivate.onWebFlowRequest(shell_window_key, provider_url_, mode_)
-  scoped_ptr<ListValue> args(new ListValue());
+  scoped_ptr<base::ListValue> args(new base::ListValue());
   args->AppendString(shell_window_key_);
   args->AppendString(provider_url_.spec());
   if (mode_ == WebAuthFlow::INTERACTIVE)
@@ -124,6 +125,8 @@
   }
 }
 
+void WebAuthFlow::OnShellWindowIconChanged(ShellWindow* shell_window) {}
+
 void WebAuthFlow::OnShellWindowRemoved(ShellWindow* shell_window) {
   if (shell_window->window_key() == shell_window_key_ &&
       shell_window->extension()->id() == extension_misc::kIdentityApiUiAppId) {
diff --git a/chrome/browser/extensions/api/identity/web_auth_flow.h b/chrome/browser/extensions/api/identity/web_auth_flow.h
index df6c0f9..cbe42c6 100644
--- a/chrome/browser/extensions/api/identity/web_auth_flow.h
+++ b/chrome/browser/extensions/api/identity/web_auth_flow.h
@@ -92,9 +92,10 @@
   friend class ::WebAuthFlowTest;
 
   // ShellWindowRegistry::Observer implementation.
-  virtual void OnShellWindowAdded(ShellWindow* shell_window) OVERRIDE;
-  virtual void OnShellWindowIconChanged(ShellWindow* shell_window) OVERRIDE {}
-  virtual void OnShellWindowRemoved(ShellWindow* shell_window) OVERRIDE;
+  virtual void OnShellWindowAdded(apps::ShellWindow* shell_window) OVERRIDE;
+  virtual void OnShellWindowIconChanged(apps::ShellWindow* shell_window)
+      OVERRIDE;
+  virtual void OnShellWindowRemoved(apps::ShellWindow* shell_window) OVERRIDE;
 
   // NotificationObserver implementation.
   virtual void Observe(int type,
@@ -132,7 +133,7 @@
   GURL provider_url_;
   Mode mode_;
 
-  ShellWindow* shell_window_;
+  apps::ShellWindow* shell_window_;
   std::string shell_window_key_;
   bool embedded_window_created_;
 
diff --git a/chrome/browser/extensions/api/identity_private/identity_private_api.cc b/chrome/browser/extensions/api/identity_private/identity_private_api.cc
index 0d2d52c..d1e3270 100644
--- a/chrome/browser/extensions/api/identity_private/identity_private_api.cc
+++ b/chrome/browser/extensions/api/identity_private/identity_private_api.cc
@@ -19,7 +19,7 @@
 IdentityPrivateGetResourcesFunction::~IdentityPrivateGetResourcesFunction() {}
 
 bool IdentityPrivateGetResourcesFunction::RunImpl() {
-  DictionaryValue* result = new DictionaryValue;
+  base::DictionaryValue* result = new base::DictionaryValue;
 
   result->SetString("IDR_CLOSE_DIALOG",
                     webui::GetBitmapDataUrlFromResource(IDR_CLOSE_DIALOG));
diff --git a/chrome/browser/extensions/api/idle/idle_manager.cc b/chrome/browser/extensions/api/idle/idle_manager.cc
index c907b81..bf02c33 100644
--- a/chrome/browser/extensions/api/idle/idle_manager.cc
+++ b/chrome/browser/extensions/api/idle/idle_manager.cc
@@ -49,7 +49,7 @@
 
 void DefaultEventDelegate::OnStateChanged(const std::string& extension_id,
                                           IdleState new_state) {
-  scoped_ptr<ListValue> args(new ListValue());
+  scoped_ptr<base::ListValue> args(new base::ListValue());
   args->Append(IdleManager::CreateIdleValue(new_state));
   scoped_ptr<Event> event(new Event(keys::kOnStateChanged, args.Pass()));
   event->restrict_to_profile = profile_;
diff --git a/chrome/browser/extensions/api/idle/idle_manager.h b/chrome/browser/extensions/api/idle/idle_manager.h
index 96d8723..91108c2 100644
--- a/chrome/browser/extensions/api/idle/idle_manager.h
+++ b/chrome/browser/extensions/api/idle/idle_manager.h
@@ -12,7 +12,7 @@
 #include "base/gtest_prod_util.h"
 #include "base/memory/weak_ptr.h"
 #include "base/threading/thread_checker.h"
-#include "base/timer.h"
+#include "base/timer/timer.h"
 #include "chrome/browser/extensions/event_router.h"
 #include "chrome/browser/idle.h"
 #include "components/browser_context_keyed_service/browser_context_keyed_service.h"
diff --git a/chrome/browser/extensions/api/idltest/idltest_api.cc b/chrome/browser/extensions/api/idltest/idltest_api.cc
index 744aa79..98ef9b3 100644
--- a/chrome/browser/extensions/api/idltest/idltest_api.cc
+++ b/chrome/browser/extensions/api/idltest/idltest_api.cc
@@ -10,8 +10,8 @@
 
 namespace {
 
-ListValue* CopyBinaryValueToIntegerList(const BinaryValue* input) {
-  ListValue* output = new ListValue();
+base::ListValue* CopyBinaryValueToIntegerList(const BinaryValue* input) {
+  base::ListValue* output = new base::ListValue();
   const char* input_buffer = input->GetBuffer();
   for (size_t i = 0; i < input->GetSize(); i++) {
     output->Append(Value::CreateIntegerValue(input_buffer[i]));
diff --git a/chrome/browser/extensions/api/input/input.cc b/chrome/browser/extensions/api/input/input.cc
index f0eecbe..b4d264f 100644
--- a/chrome/browser/extensions/api/input/input.cc
+++ b/chrome/browser/extensions/api/input/input.cc
@@ -4,17 +4,15 @@
 
 #include "chrome/browser/extensions/api/input/input.h"
 
-#include <string>
-
 #include "base/lazy_instance.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/strings/string16.h"
 #include "chrome/browser/extensions/extension_function_registry.h"
 #include "content/public/browser/browser_thread.h"
 #include "ui/base/events/event.h"
 
 #if defined(USE_ASH)
 #include "ash/shell.h"
-#include "ui/aura/root_window.h"
 #include "ui/keyboard/keyboard_util.h"
 #endif
 
@@ -27,19 +25,14 @@
 
 namespace extensions {
 
-bool SendKeyboardEventInputFunction::RunImpl() {
+bool InsertTextInputFunction::RunImpl() {
 #if defined(USE_ASH)
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
 
-  scoped_ptr<ui::KeyEvent> event(
-      keyboard::KeyEventFromArgs(args_.get(), &error_));
-  if (!event)
-    return false;
+  string16 text;
+  EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &text));
 
-  ash::Shell::GetActiveRootWindow()->AsRootWindowHostDelegate()->OnHostKeyEvent(
-      event.get());
-
-  return true;
+  return keyboard::InsertText(text, ash::Shell::GetPrimaryRootWindow());
 #endif
   error_ = kNotYetImplementedError;
   return false;
@@ -48,7 +41,7 @@
 InputAPI::InputAPI(Profile* profile) {
   ExtensionFunctionRegistry* registry =
       ExtensionFunctionRegistry::GetInstance();
-  registry->RegisterFunction<SendKeyboardEventInputFunction>();
+  registry->RegisterFunction<InsertTextInputFunction>();
 }
 
 InputAPI::~InputAPI() {
diff --git a/chrome/browser/extensions/api/input/input.h b/chrome/browser/extensions/api/input/input.h
index 51cae3a..4cdf3fa 100644
--- a/chrome/browser/extensions/api/input/input.h
+++ b/chrome/browser/extensions/api/input/input.h
@@ -13,14 +13,14 @@
 
 namespace extensions {
 
-class SendKeyboardEventInputFunction : public SyncExtensionFunction {
+class InsertTextInputFunction : public SyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION(
-      "experimental.input.virtualKeyboard.sendKeyboardEvent",
-      EXPERIMENTAL_INPUT_VIRTUALKEYBOARD_SENDKEYBOARDEVENT);
+      "experimental.input.virtualKeyboard.insertText",
+      EXPERIMENTAL_INPUT_VIRTUALKEYBOARD_INSERTTEXT);
 
  protected:
-  virtual ~SendKeyboardEventInputFunction() {}
+  virtual ~InsertTextInputFunction() {}
 
   // ExtensionFunction:
   virtual bool RunImpl() OVERRIDE;
diff --git a/chrome/browser/extensions/api/input/input_apitest.cc b/chrome/browser/extensions/api/input/input_apitest.cc
deleted file mode 100644
index cb15dcf..0000000
--- a/chrome/browser/extensions/api/input/input_apitest.cc
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/extensions/extension_apitest.h"
-#include "chrome/common/chrome_switches.h"
-
-// Fails on Windows, but we're not really supporting windows yet.
-#if defined(USE_ASH) && defined(USE_AURA) && !defined(OS_WIN)
-IN_PROC_BROWSER_TEST_F(ExtensionApiTest, Input) {
-  CommandLine::ForCurrentProcess()->AppendSwitch(
-      switches::kEnableExperimentalExtensionApis);
-
-  ASSERT_TRUE(RunExtensionTest("input")) << message_;
-}
-#endif
diff --git a/chrome/browser/extensions/api/input_ime/input_ime_api.cc b/chrome/browser/extensions/api/input_ime/input_ime_api.cc
index c33eff7..0e4845b 100644
--- a/chrome/browser/extensions/api/input_ime/input_ime_api.cc
+++ b/chrome/browser/extensions/api/input_ime/input_ime_api.cc
@@ -36,10 +36,10 @@
 const char kErrorUpdateMenuItemsFail[] = "Could not update menu Items";
 
 bool ReadMenuItems(
-    ListValue* menu_items,
+    base::ListValue* menu_items,
     std::vector<chromeos::InputMethodEngine::MenuItem>* output) {
   for (size_t i = 0; i < menu_items->GetSize(); ++i) {
-    DictionaryValue* item_dict;
+    base::DictionaryValue* item_dict;
     if (!menu_items->GetDictionary(i, &item_dict)) {
       return false;
     }
@@ -118,7 +118,7 @@
     output->back().modified = modified;
 
     if (item_dict->HasKey(keys::kItemsKey)) {
-      ListValue* sub_list;
+      base::ListValue* sub_list;
       if (!item_dict->GetList(keys::kItemsKey, &sub_list)) {
         return false;
       }
@@ -135,7 +135,7 @@
 static void DispatchEventToExtension(Profile* profile,
                                      const std::string& extension_id,
                                      const std::string& event_name,
-                                     scoped_ptr<ListValue> args) {
+                                     scoped_ptr<base::ListValue> args) {
   scoped_ptr<extensions::Event> event(new extensions::Event(
       event_name, args.Pass()));
   event->restrict_to_profile = profile;
@@ -176,7 +176,7 @@
     if (profile_ == NULL || extension_id_.empty())
       return;
 
-    scoped_ptr<base::ListValue> args(new ListValue());
+    scoped_ptr<base::ListValue> args(new base::ListValue());
     args->Append(Value::CreateStringValue(engine_id));
 
     DispatchEventToExtension(profile_, extension_id_,
@@ -187,7 +187,7 @@
     if (profile_ == NULL || extension_id_.empty())
       return;
 
-    scoped_ptr<base::ListValue> args(new ListValue());
+    scoped_ptr<base::ListValue> args(new base::ListValue());
     args->Append(Value::CreateStringValue(engine_id));
 
     DispatchEventToExtension(profile_, extension_id_,
@@ -199,11 +199,11 @@
     if (profile_ == NULL || extension_id_.empty())
       return;
 
-    DictionaryValue* dict = new DictionaryValue();
+    base::DictionaryValue* dict = new base::DictionaryValue();
     dict->SetInteger("contextID", context.id);
     dict->SetString("type", context.type);
 
-    scoped_ptr<base::ListValue> args(new ListValue());
+    scoped_ptr<base::ListValue> args(new base::ListValue());
     args->Append(dict);
 
     DispatchEventToExtension(profile_, extension_id_,
@@ -214,7 +214,7 @@
     if (profile_ == NULL || extension_id_.empty())
       return;
 
-    scoped_ptr<base::ListValue> args(new ListValue());
+    scoped_ptr<base::ListValue> args(new base::ListValue());
     args->Append(Value::CreateIntegerValue(context_id));
 
     DispatchEventToExtension(profile_, extension_id_,
@@ -226,11 +226,11 @@
     if (profile_ == NULL || extension_id_.empty())
       return;
 
-    DictionaryValue* dict = new DictionaryValue();
+    base::DictionaryValue* dict = new base::DictionaryValue();
     dict->SetInteger("contextID", context.id);
     dict->SetString("type", context.type);
 
-    scoped_ptr<base::ListValue> args(new ListValue());
+    scoped_ptr<base::ListValue> args(new base::ListValue());
     args->Append(dict);
 
     DispatchEventToExtension(profile_, extension_id_,
@@ -248,7 +248,7 @@
         extensions::InputImeEventRouter::GetInstance()->AddRequest(engine_id,
                                                                    key_data);
 
-    DictionaryValue* dict = new DictionaryValue();
+    base::DictionaryValue* dict = new base::DictionaryValue();
     dict->SetString("type", event.type);
     dict->SetString("requestId", request_id);
     dict->SetString("key", event.key);
@@ -258,7 +258,7 @@
     dict->SetBoolean("shiftKey", event.shift_key);
     dict->SetBoolean("capsLock", event.caps_lock);
 
-    scoped_ptr<base::ListValue> args(new ListValue());
+    scoped_ptr<base::ListValue> args(new base::ListValue());
     args->Append(Value::CreateStringValue(engine_id));
     args->Append(dict);
 
@@ -273,7 +273,7 @@
     if (profile_ == NULL || extension_id_.empty())
       return;
 
-    scoped_ptr<base::ListValue> args(new ListValue());
+    scoped_ptr<base::ListValue> args(new base::ListValue());
     args->Append(Value::CreateStringValue(engine_id));
     args->Append(Value::CreateIntegerValue(candidate_id));
     switch (button) {
@@ -301,7 +301,7 @@
     if (profile_ == NULL || extension_id_.empty())
       return;
 
-    scoped_ptr<base::ListValue> args(new ListValue());
+    scoped_ptr<base::ListValue> args(new base::ListValue());
     args->Append(Value::CreateStringValue(engine_id));
     args->Append(Value::CreateStringValue(menu_id));
 
@@ -315,12 +315,12 @@
                                         int anchor_pos) OVERRIDE {
     if (profile_ == NULL || extension_id_.empty())
       return;
-    DictionaryValue* dict = new DictionaryValue();
+    base::DictionaryValue* dict = new base::DictionaryValue();
     dict->SetString("text", text);
     dict->SetInteger("focus", cursor_pos);
     dict->SetInteger("anchor", anchor_pos);
 
-    scoped_ptr<ListValue> args(new ListValue);
+    scoped_ptr<ListValue> args(new base::ListValue);
     args->Append(Value::CreateStringValue(engine_id));
     args->Append(dict);
 
@@ -331,7 +331,7 @@
   virtual void OnReset(const std::string& engine_id) OVERRIDE {
     if (profile_ == NULL || extension_id_.empty())
       return;
-    scoped_ptr<base::ListValue> args(new ListValue());
+    scoped_ptr<base::ListValue> args(new base::ListValue());
     args->Append(Value::CreateStringValue(engine_id));
 
     DispatchEventToExtension(profile_, extension_id_,
@@ -506,7 +506,7 @@
     return true;
   }
 
-  DictionaryValue* args;
+  base::DictionaryValue* args;
   EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &args));
   int context_id;
   std::string text;
@@ -533,12 +533,12 @@
   }
 
   if (args->HasKey(keys::kSegmentsKey)) {
-    ListValue* segment_list = NULL;
+    base::ListValue* segment_list = NULL;
     EXTENSION_FUNCTION_VALIDATE(args->GetList(keys::kSegmentsKey,
                                               &segment_list));
 
     for (size_t i = 0; i < segment_list->GetSize(); ++i) {
-      DictionaryValue* segment = NULL;
+      base::DictionaryValue* segment = NULL;
       if (!segment_list->GetDictionary(i, &segment))
         continue;
 
@@ -581,7 +581,7 @@
     return true;
   }
 
-  DictionaryValue* args;
+  base::DictionaryValue* args;
   EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &args));
   int context_id;
 
@@ -605,7 +605,7 @@
     return true;
   }
 
-  DictionaryValue* args;
+  base::DictionaryValue* args;
   EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &args));
   int context_id;
   std::string text;
@@ -623,7 +623,7 @@
 }
 
 bool SetCandidateWindowPropertiesFunction::RunImpl() {
-  DictionaryValue* args;
+  base::DictionaryValue* args;
   EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &args));
 
   std::string engine_id;
@@ -636,7 +636,7 @@
     return true;
   }
 
-  DictionaryValue* properties;
+  base::DictionaryValue* properties;
   EXTENSION_FUNCTION_VALIDATE(args->GetDictionary(keys::kPropertiesKey,
                                                   &properties));
 
@@ -707,10 +707,10 @@
 
 #if defined(OS_CHROMEOS)
 bool SetCandidatesFunction::ReadCandidates(
-    ListValue* candidates,
+    base::ListValue* candidates,
     std::vector<chromeos::InputMethodEngine::Candidate>* output) {
   for (size_t i = 0; i < candidates->GetSize(); ++i) {
-    DictionaryValue* candidate_dict;
+    base::DictionaryValue* candidate_dict;
     EXTENSION_FUNCTION_VALIDATE(candidates->GetDictionary(i, &candidate_dict));
 
     std::string candidate;
@@ -734,7 +734,7 @@
     }
 
     if (candidate_dict->HasKey(keys::kUsageKey)) {
-      DictionaryValue* usage_dict;
+      base::DictionaryValue* usage_dict;
       EXTENSION_FUNCTION_VALIDATE(candidate_dict->GetDictionary(keys::kUsageKey,
                                                                 &usage_dict));
       EXTENSION_FUNCTION_VALIDATE(usage_dict->GetString(keys::kUsageTitleKey,
@@ -751,7 +751,7 @@
     output->back().usage = usage_entry;
 
     if (candidate_dict->HasKey(keys::kCandidatesKey)) {
-      ListValue* sub_list;
+      base::ListValue* sub_list;
       EXTENSION_FUNCTION_VALIDATE(candidate_dict->GetList(keys::kCandidatesKey,
                                                           &sub_list));
       if (!ReadCandidates(sub_list, &(output->back().candidates))) {
@@ -772,7 +772,7 @@
     return true;
   }
 
-  DictionaryValue* args;
+  base::DictionaryValue* args;
   EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &args));
 
   int context_id;
@@ -781,7 +781,7 @@
   EXTENSION_FUNCTION_VALIDATE(args->GetInteger(keys::kContextIdKey,
                                                      &context_id));
 
-  ListValue* candidate_list;
+  base::ListValue* candidate_list;
   EXTENSION_FUNCTION_VALIDATE(args->GetList(keys::kCandidatesKey,
                                             &candidate_list));
   if (!ReadCandidates(candidate_list, &candidates)) {
@@ -806,7 +806,7 @@
     return true;
   }
 
-  DictionaryValue* args;
+  base::DictionaryValue* args;
   EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &args));
   int context_id;
   int candidate_id;
@@ -825,7 +825,7 @@
 }
 
 bool SetMenuItemsFunction::RunImpl() {
-  DictionaryValue* args;
+  base::DictionaryValue* args;
   EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &args));
 
   std::string engine_id;
@@ -838,7 +838,7 @@
     return false;
   }
 
-  ListValue* items;
+  base::ListValue* items;
   EXTENSION_FUNCTION_VALIDATE(args->GetList(keys::kItemsKey, &items));
 
   std::vector<chromeos::InputMethodEngine::MenuItem> menu_items;
@@ -851,7 +851,7 @@
 }
 
 bool UpdateMenuItemsFunction::RunImpl() {
-  DictionaryValue* args;
+  base::DictionaryValue* args;
   EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &args));
 
   std::string engine_id;
@@ -864,7 +864,7 @@
     return false;
   }
 
-  ListValue* items;
+  base::ListValue* items;
   EXTENSION_FUNCTION_VALIDATE(args->GetList(keys::kItemsKey, &items));
 
   std::vector<chromeos::InputMethodEngine::MenuItem> menu_items;
@@ -877,7 +877,7 @@
 }
 
 bool DeleteSurroundingTextFunction::RunImpl() {
-  DictionaryValue* args;
+  base::DictionaryValue* args;
   EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &args));
 
   std::string engine_id;
diff --git a/chrome/browser/extensions/api/input_ime/input_ime_api.h b/chrome/browser/extensions/api/input_ime/input_ime_api.h
index aee6111..e744195 100644
--- a/chrome/browser/extensions/api/input_ime/input_ime_api.h
+++ b/chrome/browser/extensions/api/input_ime/input_ime_api.h
@@ -128,7 +128,7 @@
 
  private:
   bool ReadCandidates(
-      ListValue* candidates,
+      base::ListValue* candidates,
       std::vector<chromeos::InputMethodEngine::Candidate>* output);
 };
 
diff --git a/chrome/browser/extensions/api/location/location_api.cc b/chrome/browser/extensions/api/location/location_api.cc
index d547879..41a9917 100644
--- a/chrome/browser/extensions/api/location/location_api.cc
+++ b/chrome/browser/extensions/api/location/location_api.cc
@@ -6,6 +6,7 @@
 
 #include "chrome/browser/extensions/api/location/location_manager.h"
 #include "chrome/common/extensions/api/location.h"
+#include "extensions/common/error_utils.h"
 
 // TODO(vadimt): add tests.
 
@@ -15,14 +16,43 @@
 
 namespace extensions {
 
+const char kMustBePositive[] = "'*' must be 0 or greater.";
+const char kMinDistanceInMeters[] = "minDistanceInMeters";
+const char kMinTimeInMilliseconds[] = "minTimeInMilliseconds";
+
+bool IsNegative(double* value) {
+  return value && *value < 0.0;
+}
+
 bool LocationWatchLocationFunction::RunImpl() {
   scoped_ptr<WatchLocation::Params> params(
       WatchLocation::Params::Create(*args_));
   EXTENSION_FUNCTION_VALIDATE(params.get());
 
-  // TODO(vadimt): validate and use params->request_info.
+  double* min_distance_in_meters =
+      params->request_info.min_distance_in_meters.get();
+  if (IsNegative(min_distance_in_meters)) {
+    error_ = ErrorUtils::FormatErrorMessage(
+        kMustBePositive,
+        kMinDistanceInMeters);
+    return false;
+  }
+
+  double* min_time_in_milliseconds =
+      params->request_info.min_time_in_milliseconds.get();
+  if (IsNegative(min_time_in_milliseconds)) {
+    error_ = ErrorUtils::FormatErrorMessage(
+        kMustBePositive,
+        kMinTimeInMilliseconds);
+    return false;
+  }
+
+  // TODO(vadimt): validate and use params->request_info.maximumAge
   LocationManager::Get(profile())->AddLocationRequest(
-      extension_id(), params->name);
+      extension_id(),
+      params->name,
+      min_distance_in_meters,
+      min_time_in_milliseconds);
 
   return true;
 }
diff --git a/chrome/browser/extensions/api/location/location_manager.cc b/chrome/browser/extensions/api/location/location_manager.cc
index 509494e..173a44a 100644
--- a/chrome/browser/extensions/api/location/location_manager.cc
+++ b/chrome/browser/extensions/api/location/location_manager.cc
@@ -4,8 +4,12 @@
 
 #include "chrome/browser/extensions/api/location/location_manager.h"
 
+#include <math.h>
+#include <vector>
+
 #include "base/bind.h"
 #include "base/lazy_instance.h"
+#include "base/time/time.h"
 #include "chrome/browser/extensions/event_router.h"
 #include "chrome/browser/extensions/extension_system.h"
 #include "chrome/common/chrome_notification_types.h"
@@ -25,6 +29,115 @@
 
 namespace location = api::location;
 
+namespace updatepolicy {
+
+// Base class for all update policies for sending a location.
+class UpdatePolicy : public base::RefCounted<UpdatePolicy> {
+ public:
+  explicit UpdatePolicy() {}
+
+  // True if the caller should send an update based off of this policy.
+  virtual bool ShouldSendUpdate(const content::Geoposition&) const = 0;
+
+  // Updates any policy state on reporting a position.
+  virtual void OnPositionReported(const content::Geoposition&) = 0;
+
+ protected:
+  virtual ~UpdatePolicy() {}
+
+ private:
+  friend class base::RefCounted<UpdatePolicy>;
+  DISALLOW_COPY_AND_ASSIGN(UpdatePolicy);
+};
+
+// A policy that controls sending an update below a distance threshold.
+class DistanceBasedUpdatePolicy : public UpdatePolicy {
+ public:
+  explicit DistanceBasedUpdatePolicy(double distance_update_threshold_meters) :
+      distance_update_threshold_meters_(distance_update_threshold_meters)
+  {}
+
+  // UpdatePolicy Implementation
+  virtual bool ShouldSendUpdate(const content::Geoposition& position) const
+      OVERRIDE {
+    return !last_updated_position_.Validate() ||
+        Distance(position.latitude,
+                 position.longitude,
+                 last_updated_position_.latitude,
+                 last_updated_position_.longitude) >
+            distance_update_threshold_meters_;
+  }
+
+  virtual void OnPositionReported(const content::Geoposition& position)
+      OVERRIDE {
+    last_updated_position_ = position;
+  }
+
+ private:
+  virtual ~DistanceBasedUpdatePolicy() {}
+
+  // Calculates the distance between two latitude and longitude points.
+  static double Distance(const double latitude1,
+                         const double longitude1,
+                         const double latitude2,
+                         const double longitude2) {
+    // The earth has a radius of about 6371 km.
+    const double kRadius = 6371000;
+    const double kPi = 3.14159265358979323846;
+    const double kDegreesToRadians = kPi / 180.0;
+
+    // Conversions
+    const double latitude1Rad = latitude1 * kDegreesToRadians;
+    const double latitude2Rad = latitude2 * kDegreesToRadians;
+    const double latitudeDistRad = latitude2Rad - latitude1Rad;
+    const double longitudeDistRad = (longitude2 - longitude1) *
+                                    kDegreesToRadians;
+
+    // The Haversine Formula determines the great circle distance
+    // between two points on a sphere.
+    const double chordLengthSquared = pow(sin(latitudeDistRad / 2.0), 2) +
+                                      (pow(sin(longitudeDistRad / 2.0), 2) *
+                                       cos(latitude1Rad) *
+                                       cos(latitude2Rad));
+    const double angularDistance = 2.0 * atan2(sqrt(chordLengthSquared),
+                                               sqrt(1.0 - chordLengthSquared));
+    return kRadius * angularDistance;
+  }
+
+  const double distance_update_threshold_meters_;
+  content::Geoposition last_updated_position_;
+
+  DISALLOW_COPY_AND_ASSIGN(DistanceBasedUpdatePolicy);
+};
+
+// A policy that controls sending an update above a time threshold.
+class TimeBasedUpdatePolicy : public UpdatePolicy {
+ public:
+  explicit TimeBasedUpdatePolicy(double time_between_updates_ms) :
+      time_between_updates_ms_(time_between_updates_ms)
+  {}
+
+  // UpdatePolicy Implementation
+  virtual bool ShouldSendUpdate(const content::Geoposition&) const OVERRIDE {
+    return (base::Time::Now() - last_update_time_).InMilliseconds() >
+        time_between_updates_ms_;
+  }
+
+  virtual void OnPositionReported(const content::Geoposition&) OVERRIDE {
+    last_update_time_ = base::Time::Now();
+  }
+
+ private:
+  virtual ~TimeBasedUpdatePolicy() {}
+
+  base::Time last_update_time_;
+  const double time_between_updates_ms_;
+
+  DISALLOW_COPY_AND_ASSIGN(TimeBasedUpdatePolicy);
+};
+
+} // namespace updatepolicy
+
 // Request created by chrome.location.watchLocation() call.
 // Lives in the IO thread, except for the constructor.
 class LocationRequest
@@ -34,7 +147,9 @@
   LocationRequest(
       const base::WeakPtr<LocationManager>& location_manager,
       const std::string& extension_id,
-      const std::string& request_name);
+      const std::string& request_name,
+      const double* distance_update_threshold_meters,
+      const double* time_between_updates_ms);
 
   // Finishes the necessary setup for this object.
   // Call this method immediately after taking a strong reference
@@ -61,6 +176,13 @@
 
   void OnLocationUpdate(const content::Geoposition& position);
 
+  // Determines if all policies say to send a position update.
+  // If there are no policies, this always says yes.
+  bool ShouldSendUpdate(const content::Geoposition& position);
+
+  // Updates the policies on sending a position update.
+  void OnPositionReported(const content::Geoposition& position);
+
   // Request name.
   const std::string request_name_;
 
@@ -70,6 +192,11 @@
   // Owning location manager.
   const base::WeakPtr<LocationManager> location_manager_;
 
+  // Holds Update Policies.
+  typedef std::vector<scoped_refptr<updatepolicy::UpdatePolicy> >
+      UpdatePolicyVector;
+  UpdatePolicyVector update_policies_;
+
   content::GeolocationProvider::LocationUpdateCallback callback_;
 
   DISALLOW_COPY_AND_ASSIGN(LocationRequest);
@@ -78,12 +205,26 @@
 LocationRequest::LocationRequest(
     const base::WeakPtr<LocationManager>& location_manager,
     const std::string& extension_id,
-    const std::string& request_name)
+    const std::string& request_name,
+    const double* distance_update_threshold_meters,
+    const double* time_between_updates_ms)
     : request_name_(request_name),
       extension_id_(extension_id),
       location_manager_(location_manager) {
   // TODO(vadimt): use request_info.
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+  if (time_between_updates_ms) {
+    update_policies_.push_back(
+        new updatepolicy::TimeBasedUpdatePolicy(
+            *time_between_updates_ms));
+  }
+
+  if (distance_update_threshold_meters) {
+    update_policies_.push_back(
+        new updatepolicy::DistanceBasedUpdatePolicy(
+              *distance_update_threshold_meters));
+  }
 }
 
 void LocationRequest::Initialize() {
@@ -121,15 +262,38 @@
 
 void LocationRequest::OnLocationUpdate(const content::Geoposition& position) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+  if (ShouldSendUpdate(position)) {
+    OnPositionReported(position);
+    BrowserThread::PostTask(
+        BrowserThread::UI,
+        FROM_HERE,
+        base::Bind(&LocationManager::SendLocationUpdate,
+                   location_manager_,
+                   extension_id_,
+                   request_name_,
+                   position));
+  }
+}
 
-  BrowserThread::PostTask(
-      BrowserThread::UI,
-      FROM_HERE,
-      base::Bind(&LocationManager::SendLocationUpdate,
-                 location_manager_,
-                 extension_id_,
-                 request_name_,
-                 position));
+bool LocationRequest::ShouldSendUpdate(const content::Geoposition& position) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+  for (UpdatePolicyVector::iterator it = update_policies_.begin();
+       it != update_policies_.end();
+       ++it) {
+    if (!((*it)->ShouldSendUpdate(position))) {
+      return false;
+    }
+  }
+  return true;
+}
+
+void LocationRequest::OnPositionReported(const content::Geoposition& position) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+  for (UpdatePolicyVector::iterator it = update_policies_.begin();
+       it != update_policies_.end();
+       ++it) {
+    (*it)->OnPositionReported(position);
+  }
 }
 
 LocationManager::LocationManager(Profile* profile)
@@ -140,17 +304,23 @@
                  content::Source<Profile>(profile_));
 }
 
-void LocationManager::AddLocationRequest(const std::string& extension_id,
-                                         const std::string& request_name) {
+void LocationManager::AddLocationRequest(
+    const std::string& extension_id,
+    const std::string& request_name,
+    const double* distance_update_threshold_meters,
+    const double* time_between_updates_ms) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   // TODO(vadimt): Consider resuming requests after restarting the browser.
 
   // Override any old request with the same name.
   RemoveLocationRequest(extension_id, request_name);
 
-  LocationRequestPointer location_request = new LocationRequest(AsWeakPtr(),
-                                                                extension_id,
-                                                                request_name);
+  LocationRequestPointer location_request =
+      new LocationRequest(AsWeakPtr(),
+                          extension_id,
+                          request_name,
+                          distance_update_threshold_meters,
+                          time_between_updates_ms);
   location_request->Initialize();
   location_requests_.insert(
       LocationRequestMap::value_type(extension_id, location_request));
@@ -200,7 +370,7 @@
     const content::Geoposition& position) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
 
-  scoped_ptr<ListValue> args(new ListValue());
+  scoped_ptr<base::ListValue> args(new base::ListValue());
   std::string event_name;
 
   if (position.Validate() &&
diff --git a/chrome/browser/extensions/api/location/location_manager.h b/chrome/browser/extensions/api/location/location_manager.h
index 5b24685..6983b17 100644
--- a/chrome/browser/extensions/api/location/location_manager.h
+++ b/chrome/browser/extensions/api/location/location_manager.h
@@ -43,8 +43,11 @@
 
   // Adds location request for the given extension, and starts the location
   // tracking.
-  void AddLocationRequest(const std::string& extension_id,
-                          const std::string& request_name);
+  void AddLocationRequest(
+      const std::string& extension_id,
+      const std::string& request_name,
+      const double* distance_update_threshold_meters,
+      const double* time_between_updates_ms);
 
   // Cancels and removes the request with the given |name| for the given
   // extension.
diff --git a/chrome/browser/extensions/api/management/management_api.cc b/chrome/browser/extensions/api/management/management_api.cc
index c855b83..7f98037 100644
--- a/chrome/browser/extensions/api/management/management_api.cc
+++ b/chrome/browser/extensions/api/management/management_api.cc
@@ -315,13 +315,13 @@
     return handled;
   }
 
-  void OnJSONParseSucceeded(const ListValue& wrapper) {
+  void OnJSONParseSucceeded(const base::ListValue& wrapper) {
     CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
     const Value* value = NULL;
     CHECK(wrapper.Get(0, &value));
     if (value->IsType(Value::TYPE_DICTIONARY))
       parsed_manifest_.reset(
-          static_cast<const DictionaryValue*>(value)->DeepCopy());
+          static_cast<const base::DictionaryValue*>(value)->DeepCopy());
     else
       error_ = keys::kManifestParseError;
 
@@ -358,7 +358,7 @@
   std::string manifest_;
 
   // Results of parsing.
-  scoped_ptr<DictionaryValue> parsed_manifest_;
+  scoped_ptr<base::DictionaryValue> parsed_manifest_;
 
   std::string error_;
 };
@@ -382,7 +382,7 @@
 }
 
 void ManagementGetPermissionWarningsByManifestFunction::OnParseSuccess(
-    DictionaryValue* parsed_manifest) {
+    base::DictionaryValue* parsed_manifest) {
   CHECK(parsed_manifest);
 
   scoped_refptr<Extension> extension = Extension::Create(
@@ -676,7 +676,7 @@
   DCHECK(event_name);
   DCHECK(extension);
 
-  scoped_ptr<ListValue> args(new ListValue());
+  scoped_ptr<base::ListValue> args(new base::ListValue());
   if (event_name == events::kOnExtensionUninstalled) {
     args->Append(Value::CreateStringValue(extension->id()));
   } else {
diff --git a/chrome/browser/extensions/api/management/management_browsertest.cc b/chrome/browser/extensions/api/management/management_browsertest.cc
index 8457eea..ae05985 100644
--- a/chrome/browser/extensions/api/management/management_browsertest.cc
+++ b/chrome/browser/extensions/api/management/management_browsertest.cc
@@ -511,14 +511,14 @@
   ASSERT_TRUE(service->disabled_extensions()->is_empty());
 
   PrefService* prefs = browser()->profile()->GetPrefs();
-  const DictionaryValue* forcelist =
+  const base::DictionaryValue* forcelist =
       prefs->GetDictionary(prefs::kExtensionInstallForceList);
   ASSERT_TRUE(forcelist->empty()) << kForceInstallNotEmptyHelp;
 
   {
     // Set the policy as a user preference and fire notification observers.
     DictionaryPrefUpdate pref_update(prefs, prefs::kExtensionInstallForceList);
-    DictionaryValue* forcelist = pref_update.Get();
+    base::DictionaryValue* forcelist = pref_update.Get();
     extensions::ExternalPolicyLoader::AddExtension(
         forcelist, kExtensionId, "http://localhost/autoupdate/manifest");
   }
@@ -584,7 +584,7 @@
 
   // Check that the policy is initially empty.
   PrefService* prefs = browser()->profile()->GetPrefs();
-  const DictionaryValue* forcelist =
+  const base::DictionaryValue* forcelist =
       prefs->GetDictionary(prefs::kExtensionInstallForceList);
   ASSERT_TRUE(forcelist->empty()) << kForceInstallNotEmptyHelp;
 
@@ -638,7 +638,7 @@
   // and force enable it too.
   {
     DictionaryPrefUpdate pref_update(prefs, prefs::kExtensionInstallForceList);
-    DictionaryValue* forcelist = pref_update.Get();
+    base::DictionaryValue* forcelist = pref_update.Get();
     extensions::ExternalPolicyLoader::AddExtension(
         forcelist, kExtensionId, "http://localhost/autoupdate/manifest");
   }
diff --git a/chrome/browser/extensions/api/media_galleries/media_galleries_api.cc b/chrome/browser/extensions/api/media_galleries/media_galleries_api.cc
index 4fbc75b..49d55f0 100644
--- a/chrome/browser/extensions/api/media_galleries/media_galleries_api.cc
+++ b/chrome/browser/extensions/api/media_galleries/media_galleries_api.cc
@@ -10,6 +10,7 @@
 #include <string>
 #include <vector>
 
+#include "apps/shell_window.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/platform_file.h"
 #include "base/stl_util.h"
@@ -21,7 +22,6 @@
 #include "chrome/browser/media_galleries/media_galleries_dialog_controller.h"
 #include "chrome/browser/storage_monitor/storage_monitor.h"
 #include "chrome/browser/ui/chrome_select_file_policy.h"
-#include "chrome/browser/ui/extensions/shell_window.h"
 #include "chrome/common/extensions/api/experimental_media_galleries.h"
 #include "chrome/common/extensions/api/media_galleries.h"
 #include "chrome/common/extensions/extension.h"
@@ -39,6 +39,7 @@
 #include "base/strings/sys_string_conversions.h"
 #endif
 
+using apps::ShellWindow;
 using chrome::MediaFileSystemInfo;
 using chrome::MediaFileSystemRegistry;
 using chrome::MediaFileSystemsCallback;
@@ -93,7 +94,7 @@
     interactive = params->details->interactive;
   }
 
-  chrome::StorageMonitor::GetInstance()->Initialize(base::Bind(
+  chrome::StorageMonitor::GetInstance()->EnsureInitialized(base::Bind(
       &MediaGalleriesGetMediaFileSystemsFunction::OnStorageMonitorInit,
       this,
       interactive));
@@ -205,6 +206,13 @@
   WebContents* contents = WebContents::FromRenderViewHost(render_view_host());
   WebContentsModalDialogManager* web_contents_modal_dialog_manager =
       WebContentsModalDialogManager::FromWebContents(contents);
+  // If there's no user gesture associated with the API call, do not show
+  // the dialog.
+  if (!user_gesture()) {
+    GetAndReturnGalleries();
+    return;
+  }
+
   if (!web_contents_modal_dialog_manager) {
     // If there is no WebContentsModalDialogManager, then this contents is
     // probably the background page for an app. Try to find a shell window to
diff --git a/chrome/browser/extensions/api/media_galleries_private/gallery_watch_manager.cc b/chrome/browser/extensions/api/media_galleries_private/gallery_watch_manager.cc
index c2cbfe1..c12d9d7 100644
--- a/chrome/browser/extensions/api/media_galleries_private/gallery_watch_manager.cc
+++ b/chrome/browser/extensions/api/media_galleries_private/gallery_watch_manager.cc
@@ -16,7 +16,7 @@
 #include "base/location.h"
 #include "base/memory/ref_counted.h"
 #include "base/stl_util.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/extensions/api/media_galleries_private/media_galleries_private_event_router.h"
 #include "content/public/browser/browser_thread.h"
 
diff --git a/chrome/browser/extensions/api/media_galleries_private/gallery_watch_state_tracker.cc b/chrome/browser/extensions/api/media_galleries_private/gallery_watch_state_tracker.cc
index bcd2ff5..309b008 100644
--- a/chrome/browser/extensions/api/media_galleries_private/gallery_watch_state_tracker.cc
+++ b/chrome/browser/extensions/api/media_galleries_private/gallery_watch_state_tracker.cc
@@ -55,7 +55,7 @@
 scoped_ptr<base::ListValue> WatchedGalleryIdsToValue(
     const chrome::MediaGalleryPrefIdSet gallery_ids) {
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
-  scoped_ptr<base::ListValue> list(new ListValue());
+  scoped_ptr<base::ListValue> list(new base::ListValue());
   for (chrome::MediaGalleryPrefIdSet::const_iterator id_iter =
            gallery_ids.begin();
        id_iter != gallery_ids.end(); ++id_iter)
diff --git a/chrome/browser/extensions/api/media_galleries_private/media_galleries_private_api.cc b/chrome/browser/extensions/api/media_galleries_private/media_galleries_private_api.cc
index fa1246b..86a414a 100644
--- a/chrome/browser/extensions/api/media_galleries_private/media_galleries_private_api.cc
+++ b/chrome/browser/extensions/api/media_galleries_private/media_galleries_private_api.cc
@@ -128,7 +128,7 @@
   // This method is called synchronously with the message handler for the
   // JS invocation.
 
-  chrome::StorageMonitor::GetInstance()->Initialize(base::Bind(
+  chrome::StorageMonitor::GetInstance()->EnsureInitialized(base::Bind(
       &MediaGalleriesPrivateAPI::MaybeInitializeEventRouterAndTracker,
       weak_ptr_factory_.GetWeakPtr()));
 }
@@ -171,7 +171,7 @@
       AddGalleryWatch::Params::Create(*args_));
   EXTENSION_FUNCTION_VALIDATE(params.get());
 
-  chrome::StorageMonitor::GetInstance()->Initialize(base::Bind(
+  chrome::StorageMonitor::GetInstance()->EnsureInitialized(base::Bind(
       &MediaGalleriesPrivateAddGalleryWatchFunction::OnStorageMonitorInit,
       this,
       params->gallery_id));
@@ -251,7 +251,7 @@
       RemoveGalleryWatch::Params::Create(*args_));
   EXTENSION_FUNCTION_VALIDATE(params.get());
 
-  chrome::StorageMonitor::GetInstance()->Initialize(base::Bind(
+  chrome::StorageMonitor::GetInstance()->EnsureInitialized(base::Bind(
       &MediaGalleriesPrivateRemoveGalleryWatchFunction::OnStorageMonitorInit,
       this,
       params->gallery_id));
@@ -298,7 +298,7 @@
   if (!render_view_host() || !render_view_host()->GetProcess())
     return false;
 
-  chrome::StorageMonitor::GetInstance()->Initialize(base::Bind(
+  chrome::StorageMonitor::GetInstance()->EnsureInitialized(base::Bind(
       &MediaGalleriesPrivateGetAllGalleryWatchFunction::OnStorageMonitorInit,
       this));
   return true;
@@ -335,7 +335,7 @@
   if (!render_view_host() || !render_view_host()->GetProcess())
     return false;
 
-  chrome::StorageMonitor::GetInstance()->Initialize(base::Bind(
+  chrome::StorageMonitor::GetInstance()->EnsureInitialized(base::Bind(
       &MediaGalleriesPrivateRemoveAllGalleryWatchFunction::OnStorageMonitorInit,
       this));
   return true;
@@ -371,7 +371,7 @@
   scoped_ptr<EjectDevice::Params> params(EjectDevice::Params::Create(*args_));
   EXTENSION_FUNCTION_VALIDATE(params.get());
 
-  chrome::StorageMonitor::GetInstance()->Initialize(base::Bind(
+  chrome::StorageMonitor::GetInstance()->EnsureInitialized(base::Bind(
       &MediaGalleriesPrivateEjectDeviceFunction::OnStorageMonitorInit,
       this,
       params->device_id));
diff --git a/chrome/browser/extensions/api/media_galleries_private/media_galleries_private_apitest.cc b/chrome/browser/extensions/api/media_galleries_private/media_galleries_private_apitest.cc
index 197a01e..c85d58a 100644
--- a/chrome/browser/extensions/api/media_galleries_private/media_galleries_private_apitest.cc
+++ b/chrome/browser/extensions/api/media_galleries_private/media_galleries_private_apitest.cc
@@ -11,6 +11,7 @@
 #include "chrome/browser/extensions/extension_test_message_listener.h"
 #include "chrome/browser/storage_monitor/storage_info.h"
 #include "chrome/browser/storage_monitor/storage_monitor.h"
+#include "chrome/browser/storage_monitor/test_storage_monitor.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/extensions/extension.h"
@@ -86,37 +87,32 @@
   }
 
   void Attach() {
+    DCHECK(chrome::StorageMonitor::GetInstance()->IsInitialized());
     chrome::StorageInfo info(device_id_, ASCIIToUTF16(kDeviceName), kDevicePath,
                              string16(), string16(), string16(), 0);
     chrome::StorageMonitor::GetInstance()->receiver()->ProcessAttach(info);
-    WaitForDeviceEvents();
-  }
-
-  void Detach() {
-    chrome::StorageMonitor::GetInstance()->receiver()->ProcessDetach(
-        device_id_);
-    WaitForDeviceEvents();
-  }
-
- private:
-  void WaitForDeviceEvents() {
     content::RunAllPendingInMessageLoop();
   }
 
+  void Detach() {
+    DCHECK(chrome::StorageMonitor::GetInstance()->IsInitialized());
+    chrome::StorageMonitor::GetInstance()->receiver()->ProcessDetach(
+        device_id_);
+    content::RunAllPendingInMessageLoop();
+  }
+
+ private:
   std::string device_id_;
 
   DISALLOW_COPY_AND_ASSIGN(MediaGalleriesPrivateApiTest);
 };
 
-// TODO(jschuh): Flaky on Win64 & Linux Aura build. crbug.com/247336
-#if (defined(OS_WIN) && defined(ARCH_CPU_X86_64)) || \
-    (defined(OS_LINUX) && defined(USE_AURA))
-#define MAYBE_DeviceAttachDetachEvents DISABLED_DeviceAttachDetachEvents
-#else
-#define MAYBE_DeviceAttachDetachEvents DeviceAttachDetachEvents
-#endif
-IN_PROC_BROWSER_TEST_F(MediaGalleriesPrivateApiTest,
-                       MAYBE_DeviceAttachDetachEvents) {
+IN_PROC_BROWSER_TEST_F(MediaGalleriesPrivateApiTest, DeviceAttachDetachEvents) {
+  scoped_ptr<chrome::test::TestStorageMonitor> monitor(
+      chrome::test::TestStorageMonitor::CreateForBrowserTests());
+  monitor->Init();
+  monitor->MarkInitialized();
+
   // Setup.
   const extensions::Extension* extension =
       LoadExtension(test_data_dir_.AppendASCII(kTestExtensionPath));
diff --git a/chrome/browser/extensions/api/media_galleries_private/media_galleries_private_event_router.cc b/chrome/browser/extensions/api/media_galleries_private/media_galleries_private_event_router.cc
index 2d7bb43..8a2070a 100644
--- a/chrome/browser/extensions/api/media_galleries_private/media_galleries_private_event_router.cc
+++ b/chrome/browser/extensions/api/media_galleries_private/media_galleries_private_event_router.cc
@@ -62,7 +62,7 @@
        it != extension_ids.end(); ++it) {
     GalleryChangeDetails details;
     details.gallery_id = gallery_id;
-    scoped_ptr<ListValue> args(new ListValue());
+    scoped_ptr<base::ListValue> args(new base::ListValue());
     args->Append(details.ToValue().release());
     scoped_ptr<extensions::Event> event(new extensions::Event(
         event_names::kOnGalleryChangedEventName,
@@ -106,7 +106,7 @@
   DeviceDetachmentDetails details;
   details.device_id = GetTransientIdForDeviceId(info.device_id());
 
-  scoped_ptr<base::ListValue> args(new ListValue());
+  scoped_ptr<base::ListValue> args(new base::ListValue());
   args->Append(details.ToValue().release());
   DispatchEvent(event_names::kOnDetachEventName, args.Pass());
 }
diff --git a/chrome/browser/extensions/api/messaging/extension_message_port.cc b/chrome/browser/extensions/api/messaging/extension_message_port.cc
index a3bba97..e4782c7 100644
--- a/chrome/browser/extensions/api/messaging/extension_message_port.cc
+++ b/chrome/browser/extensions/api/messaging/extension_message_port.cc
@@ -4,7 +4,6 @@
 
 #include "chrome/browser/extensions/api/messaging/extension_message_port.h"
 
-#include "base/values.h"
 #include "chrome/browser/extensions/extension_host.h"
 #include "chrome/browser/extensions/extension_process_manager.h"
 #include "chrome/browser/extensions/extension_system.h"
@@ -46,11 +45,10 @@
       routing_id_, source_port_id, error_message));
 }
 
-void ExtensionMessagePort::DispatchOnMessage(
-    scoped_ptr<base::ListValue> message,
-    int target_port_id) {
-  process_->Send(new ExtensionMsg_DeliverMessage(
-      routing_id_, target_port_id, *message));
+void ExtensionMessagePort::DispatchOnMessage(const std::string& message,
+                                             int target_port_id) {
+    process_->Send(new ExtensionMsg_DeliverMessage(
+        routing_id_, target_port_id, message));
 }
 
 void ExtensionMessagePort::IncrementLazyKeepaliveCount() {
diff --git a/chrome/browser/extensions/api/messaging/extension_message_port.h b/chrome/browser/extensions/api/messaging/extension_message_port.h
index 7cc386a..ccf9b69 100644
--- a/chrome/browser/extensions/api/messaging/extension_message_port.h
+++ b/chrome/browser/extensions/api/messaging/extension_message_port.h
@@ -9,10 +9,6 @@
 
 class GURL;
 
-namespace base {
-class ListValue;
-}
-
 namespace content {
 class RenderProcessHost;
 }  // namespace content
@@ -34,7 +30,7 @@
       const GURL& source_url) OVERRIDE;
   virtual void DispatchOnDisconnect(int source_port_id,
                                     const std::string& error_message) OVERRIDE;
-  virtual void DispatchOnMessage(scoped_ptr<base::ListValue> message,
+  virtual void DispatchOnMessage(const std::string& message,
                                  int target_port_id) OVERRIDE;
   virtual void IncrementLazyKeepaliveCount() OVERRIDE;
   virtual void DecrementLazyKeepaliveCount() OVERRIDE;
diff --git a/chrome/browser/extensions/api/messaging/message_service.cc b/chrome/browser/extensions/api/messaging/message_service.cc
index 3188a7f..6ef2531 100644
--- a/chrome/browser/extensions/api/messaging/message_service.cc
+++ b/chrome/browser/extensions/api/messaging/message_service.cc
@@ -6,7 +6,6 @@
 
 #include "base/atomic_sequence_num.h"
 #include "base/bind.h"
-#include "base/bind_helpers.h"
 #include "base/callback.h"
 #include "base/json/json_writer.h"
 #include "base/lazy_instance.h"
@@ -71,7 +70,7 @@
 
 struct MessageService::OpenChannelParams {
   content::RenderProcessHost* source;
-  DictionaryValue source_tab;
+  base::DictionaryValue source_tab;
   scoped_ptr<MessagePort> receiver;
   int receiver_port_id;
   std::string source_extension_id;
@@ -81,7 +80,7 @@
 
   // Takes ownership of receiver.
   OpenChannelParams(content::RenderProcessHost* source,
-                    scoped_ptr<DictionaryValue> source_tab,
+                    scoped_ptr<base::DictionaryValue> source_tab,
                     MessagePort* receiver,
                     int receiver_port_id,
                     const std::string& source_extension_id,
@@ -241,7 +240,7 @@
       source_process_id, source_routing_id);
 
   // Include info about the opener's tab (if it was a tab).
-  scoped_ptr<DictionaryValue> source_tab;
+  scoped_ptr<base::DictionaryValue> source_tab;
   GURL source_url_for_tab;
 
   if (source_contents && ExtensionTabUtil::GetTabId(source_contents) >= 0) {
@@ -356,8 +355,8 @@
 
   scoped_ptr<OpenChannelParams> params(new OpenChannelParams(
         source,
-        scoped_ptr<DictionaryValue>(),  // Source tab doesn't make sense for
-                                        // opening to tabs.
+        scoped_ptr<base::DictionaryValue>(),  // Source tab doesn't make sense
+                                              // for opening to tabs.
         receiver.release(),
         receiver_port_id,
         extension_id,
@@ -458,7 +457,7 @@
 }
 
 void MessageService::PostMessage(
-    int source_port_id, scoped_ptr<base::ListValue> message) {
+    int source_port_id, const std::string& message) {
   int channel_id = GET_CHANNEL_ID(source_port_id);
   MessageChannelMap::iterator iter = channels_.find(channel_id);
   if (iter == channels_.end()) {
@@ -469,9 +468,7 @@
       lazy_background_task_queue_->AddPendingTask(
           pending->second.first, pending->second.second,
           base::Bind(&MessageService::PendingPostMessage,
-                     weak_factory_.GetWeakPtr(),
-                     source_port_id,
-                     base::Passed(&message)));
+                     weak_factory_.GetWeakPtr(), source_port_id, message));
     }
     return;
   }
@@ -481,13 +478,12 @@
   MessagePort* port = IS_OPENER_PORT_ID(dest_port_id) ?
       iter->second->opener.get() : iter->second->receiver.get();
 
-  port->DispatchOnMessage(message.Pass(), dest_port_id);
+  port->DispatchOnMessage(message, dest_port_id);
 }
 
-void MessageService::PostMessageFromNativeProcess(
-    int port_id,
-    scoped_ptr<base::ListValue> message) {
-  PostMessage(port_id, message.Pass());
+void MessageService::PostMessageFromNativeProcess(int port_id,
+                                                  const std::string& message) {
+  PostMessage(port_id, message);
 }
 
 void MessageService::Observe(int type,
diff --git a/chrome/browser/extensions/api/messaging/message_service.h b/chrome/browser/extensions/api/messaging/message_service.h
index 59ba6ff..6de5a74 100644
--- a/chrome/browser/extensions/api/messaging/message_service.h
+++ b/chrome/browser/extensions/api/messaging/message_service.h
@@ -22,7 +22,6 @@
 
 namespace base {
 class DictionaryValue;
-class ListValue;
 }
 
 namespace content {
@@ -83,7 +82,7 @@
                                       const std::string& error_message) {}
 
     // Dispatch a message to this end of the communication.
-    virtual void DispatchOnMessage(scoped_ptr<base::ListValue> message,
+    virtual void DispatchOnMessage(const std::string& message,
                                    int target_port_id) = 0;
 
     // MessagPorts that target extensions will need to adjust their keepalive
@@ -145,12 +144,12 @@
                             const std::string& error_message) OVERRIDE;
 
   // Sends a message to the given port.
-  void PostMessage(int port_id, scoped_ptr<base::ListValue> message);
+  void PostMessage(int port_id, const std::string& message);
 
   // NativeMessageProcessHost::Client
   virtual void PostMessageFromNativeProcess(
       int port_id,
-      scoped_ptr<base::ListValue> message) OVERRIDE;
+      const std::string& message) OVERRIDE;
 
  private:
   friend class MockMessageService;
@@ -206,10 +205,10 @@
       CloseChannel(port_id, error_message);
   }
   void PendingPostMessage(int port_id,
-                          scoped_ptr<base::ListValue> message,
+                          const std::string& message,
                           extensions::ExtensionHost* host) {
     if (host)
-      PostMessage(port_id, message.Pass());
+      PostMessage(port_id, message);
   }
 
   // Immediate dispatches a disconnect to |source| for |port_id|. Sets source's
diff --git a/chrome/browser/extensions/api/messaging/native_message_port.cc b/chrome/browser/extensions/api/messaging/native_message_port.cc
index 7ca7bea..e746e29 100644
--- a/chrome/browser/extensions/api/messaging/native_message_port.cc
+++ b/chrome/browser/extensions/api/messaging/native_message_port.cc
@@ -5,8 +5,6 @@
 #include "chrome/browser/extensions/api/messaging/native_message_port.h"
 
 #include "base/bind.h"
-#include "base/json/json_writer.h"
-#include "base/values.h"
 #include "chrome/browser/extensions/api/messaging/native_message_process_host.h"
 #include "content/public/browser/browser_thread.h"
 
@@ -21,20 +19,12 @@
       content::BrowserThread::IO, FROM_HERE, native_process_);
 }
 
-void NativeMessagePort::DispatchOnMessage(scoped_ptr<base::ListValue> message,
+void NativeMessagePort::DispatchOnMessage(const std::string& message,
                                           int target_port_id) {
-  std::string message_as_json;
-  if (!message->empty()) {
-    DCHECK_EQ(1u, message->GetSize());
-    base::Value* value = NULL;
-    message->Get(0, &value);
-    base::JSONWriter::Write(value, &message_as_json);
-  }
   content::BrowserThread::PostTask(
       content::BrowserThread::IO, FROM_HERE,
       base::Bind(&NativeMessageProcessHost::Send,
-                 base::Unretained(native_process_),
-                 message_as_json));
+                 base::Unretained(native_process_), message));
 }
 
 }  // namespace extensions
diff --git a/chrome/browser/extensions/api/messaging/native_message_port.h b/chrome/browser/extensions/api/messaging/native_message_port.h
index 4c88445..6afce8a 100644
--- a/chrome/browser/extensions/api/messaging/native_message_port.h
+++ b/chrome/browser/extensions/api/messaging/native_message_port.h
@@ -16,7 +16,7 @@
   // Takes ownership of |native_process|.
   explicit NativeMessagePort(NativeMessageProcessHost* native_process);
   virtual ~NativeMessagePort();
-  virtual void DispatchOnMessage(scoped_ptr<base::ListValue> message,
+  virtual void DispatchOnMessage(const std::string& message,
                                  int target_port_id) OVERRIDE;
 
  private:
diff --git a/chrome/browser/extensions/api/messaging/native_message_process_host.cc b/chrome/browser/extensions/api/messaging/native_message_process_host.cc
index 9f8c50b..9187a08 100644
--- a/chrome/browser/extensions/api/messaging/native_message_process_host.cc
+++ b/chrome/browser/extensions/api/messaging/native_message_process_host.cc
@@ -5,9 +5,7 @@
 #include "chrome/browser/extensions/api/messaging/native_message_process_host.h"
 
 #include "base/bind.h"
-#include "base/bind_helpers.h"
 #include "base/files/file_path.h"
-#include "base/json/json_reader.h"
 #include "base/logging.h"
 #include "base/platform_file.h"
 #include "base/process_util.h"
@@ -44,8 +42,6 @@
     "Access to the specified native messaging host is forbidden.";
 const char kHostInputOuputError[] =
     "Error when communicating with the native messaging host.";
-const char kInvalidJsonError[] =
-    "Message must be valid JSON";
 
 }  // namespace
 
@@ -272,35 +268,10 @@
     if (incoming_data_.size() < message_size + kMessageHeaderSize)
       return;
 
-    scoped_ptr<base::ListValue> message(new base::ListValue());
-    {
-      std::string message_as_json =
-          incoming_data_.substr(kMessageHeaderSize, message_size);
-      int error_code;
-      std::string error_message;
-      scoped_ptr<base::Value> message_as_value(
-          base::JSONReader::ReadAndReturnError(message_as_json,
-                                               0,  // no flags
-                                               &error_code,
-                                               &error_message));
-      if (!message_as_value) {
-        base::JSONReader::JsonParseError parse_error =
-            static_cast<base::JSONReader::JsonParseError>(error_code);
-        LOG(ERROR) << "Native Messaging host sent message with invalid JSON \""
-                   << message_as_json << "\": " << error_message << " ("
-                   << base::JSONReader::ErrorCodeToString(parse_error) << "), "
-                   << "message size " << message_size << ", "
-                   << "incoming data size " << incoming_data_.size() << ".";
-        Close(kInvalidJsonError);
-        return;
-      }
-      message->Append(message_as_value.release());
-    }
-
     content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
         base::Bind(&Client::PostMessageFromNativeProcess, weak_client_ui_,
             destination_port_,
-            base::Passed(&message)));
+            incoming_data_.substr(kMessageHeaderSize, message_size)));
 
     incoming_data_.erase(0, kMessageHeaderSize + message_size);
   }
diff --git a/chrome/browser/extensions/api/messaging/native_message_process_host.h b/chrome/browser/extensions/api/messaging/native_message_process_host.h
index ef339b2..987055f 100644
--- a/chrome/browser/extensions/api/messaging/native_message_process_host.h
+++ b/chrome/browser/extensions/api/messaging/native_message_process_host.h
@@ -15,15 +15,13 @@
 #include "chrome/browser/extensions/api/messaging/native_process_launcher.h"
 #include "content/public/browser/browser_thread.h"
 
-namespace base {
-class ListValue;
-}
-
 namespace net {
+
 class DrainableIOBuffer;
 class FileStream;
 class IOBuffer;
 class IOBufferWithSize;
+
 }  // namespace net
 
 namespace extensions {
@@ -45,9 +43,8 @@
    public:
     virtual ~Client() {}
     // Called on the UI thread.
-    virtual void PostMessageFromNativeProcess(
-        int port_id,
-        scoped_ptr<base::ListValue> message) = 0;
+    virtual void PostMessageFromNativeProcess(int port_id,
+                                              const std::string& message) = 0;
     virtual void CloseChannel(int port_id,
                               const std::string& error_message) = 0;
   };
diff --git a/chrome/browser/extensions/api/messaging/native_message_process_host_unittest.cc b/chrome/browser/extensions/api/messaging/native_message_process_host_unittest.cc
index d8fe2c4..5b7f0c8 100644
--- a/chrome/browser/extensions/api/messaging/native_message_process_host_unittest.cc
+++ b/chrome/browser/extensions/api/messaging/native_message_process_host_unittest.cc
@@ -19,7 +19,7 @@
 #include "base/test/test_timeouts.h"
 #include "base/threading/platform_thread.h"
 #include "base/threading/sequenced_worker_pool.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/extensions/api/messaging/native_message_process_host.h"
 #include "chrome/browser/extensions/api/messaging/native_messaging_test_util.h"
 #include "chrome/browser/extensions/api/messaging/native_process_launcher.h"
@@ -104,15 +104,19 @@
 
   virtual void PostMessageFromNativeProcess(
       int port_id,
-      scoped_ptr<base::ListValue> message_as_list) OVERRIDE  {
-    // |message_as_list| should contain a single DictionaryValue. Extract it
-    // into |last_message_|.
-    ASSERT_EQ(1u, message_as_list->GetSize());
-    base::Value* last_message_value = NULL;
-    message_as_list->Remove(0, &last_message_value);
-    ASSERT_EQ(base::Value::TYPE_DICTIONARY, last_message_value->GetType());
-    last_message_.reset(
-        static_cast<base::DictionaryValue*>(last_message_value));
+      const std::string& message) OVERRIDE  {
+    last_message_ = message;
+
+    // Parse the message.
+    base::Value* parsed = base::JSONReader::Read(message);
+    base::DictionaryValue* dict_value;
+    if (parsed && parsed->GetAsDictionary(&dict_value)) {
+      last_message_parsed_.reset(dict_value);
+    } else {
+      LOG(ERROR) << "Failed to parse " << message;
+      last_message_parsed_.reset();
+      delete parsed;
+    }
 
     if (read_message_run_loop_)
       read_message_run_loop_->Quit();
@@ -146,7 +150,8 @@
   base::FilePath user_data_dir_;
   scoped_ptr<base::RunLoop> read_message_run_loop_;
   content::TestBrowserThreadBundle thread_bundle_;
-  scoped_ptr<DictionaryValue> last_message_;
+  std::string last_message_;
+  scoped_ptr<base::DictionaryValue> last_message_parsed_;
 };
 
 // Read a single message from a local file.
@@ -163,26 +168,19 @@
   read_message_run_loop_.reset(new base::RunLoop());
   read_message_run_loop_->RunUntilIdle();
 
-  if (!last_message_) {
+  if (last_message_.empty()) {
     read_message_run_loop_.reset(new base::RunLoop());
     native_message_process_host_->ReadNowForTesting();
     read_message_run_loop_->Run();
   }
-  ASSERT_TRUE(last_message_);
-
-  scoped_ptr<base::Value> kTestMessageAsValue(
-      base::JSONReader::Read(kTestMessage));
-  ASSERT_TRUE(kTestMessageAsValue);
-  EXPECT_TRUE(base::Value::Equals(kTestMessageAsValue.get(),
-                                  last_message_.get()))
-      << "Expected " << *kTestMessageAsValue << " got " << *last_message_;
+  EXPECT_EQ(kTestMessage, last_message_);
 }
 
 // Tests sending a single message. The message should get written to
 // |temp_file| and should match the contents of single_message_request.msg.
 TEST_F(NativeMessagingTest, SingleSendMessageWrite) {
   base::FilePath temp_output_file = temp_dir_.path().AppendASCII("output");
-  base::FilePath temp_input_file = CreateTempFileWithMessage("{}");
+  base::FilePath temp_input_file = CreateTempFileWithMessage(std::string());
 
   scoped_ptr<NativeProcessLauncher> launcher(
       new FakeLauncher(temp_input_file, temp_output_file));
@@ -228,29 +226,30 @@
   native_message_process_host_->Send("{\"text\": \"Hello.\"}");
   read_message_run_loop_.reset(new base::RunLoop());
   read_message_run_loop_->Run();
-  ASSERT_TRUE(last_message_);
+  ASSERT_FALSE(last_message_.empty());
+  ASSERT_TRUE(last_message_parsed_);
 
   std::string expected_url = std::string("chrome-extension://") +
       kTestNativeMessagingExtensionId + "/";
   int id;
-  EXPECT_TRUE(last_message_->GetInteger("id", &id));
+  EXPECT_TRUE(last_message_parsed_->GetInteger("id", &id));
   EXPECT_EQ(1, id);
   std::string text;
-  EXPECT_TRUE(last_message_->GetString("echo.text", &text));
+  EXPECT_TRUE(last_message_parsed_->GetString("echo.text", &text));
   EXPECT_EQ("Hello.", text);
   std::string url;
-  EXPECT_TRUE(last_message_->GetString("caller_url", &url));
+  EXPECT_TRUE(last_message_parsed_->GetString("caller_url", &url));
   EXPECT_EQ(expected_url, url);
 
 
   native_message_process_host_->Send("{\"foo\": \"bar\"}");
   read_message_run_loop_.reset(new base::RunLoop());
   read_message_run_loop_->Run();
-  EXPECT_TRUE(last_message_->GetInteger("id", &id));
+  EXPECT_TRUE(last_message_parsed_->GetInteger("id", &id));
   EXPECT_EQ(2, id);
-  EXPECT_TRUE(last_message_->GetString("echo.foo", &text));
+  EXPECT_TRUE(last_message_parsed_->GetString("echo.foo", &text));
   EXPECT_EQ("bar", text);
-  EXPECT_TRUE(last_message_->GetString("caller_url", &url));
+  EXPECT_TRUE(last_message_parsed_->GetString("caller_url", &url));
   EXPECT_EQ(expected_url, url);
 }
 
diff --git a/chrome/browser/extensions/api/messaging/native_process_launcher_win.cc b/chrome/browser/extensions/api/messaging/native_process_launcher_win.cc
index 6dd0769..70d0fd6 100644
--- a/chrome/browser/extensions/api/messaging/native_process_launcher_win.cc
+++ b/chrome/browser/extensions/api/messaging/native_process_launcher_win.cc
@@ -23,36 +23,41 @@
 const wchar_t kNativeMessagingRegistryKey[] =
     L"SOFTWARE\\Google\\Chrome\\NativeMessagingHosts";
 
+namespace {
+
+// Reads path to the native messaging host manifest from the registry. Returns
+// empty string if the path isn't found.
+string16 GetManifestPath(const string16& native_host_name, DWORD flags) {
+  base::win::RegKey key;
+  string16 result;
+
+  if (key.Open(HKEY_LOCAL_MACHINE, kNativeMessagingRegistryKey,
+               KEY_QUERY_VALUE | flags) != ERROR_SUCCESS ||
+      key.OpenKey(native_host_name.c_str(),
+                  KEY_QUERY_VALUE | flags) != ERROR_SUCCESS ||
+      key.ReadValue(NULL, &result) != ERROR_SUCCESS) {
+    return string16();
+  }
+
+  return result;
+}
+
+}  // namespace
+
 // static
 scoped_ptr<NativeMessagingHostManifest>
 NativeProcessLauncher::FindAndLoadManifest(
     const std::string& native_host_name,
     std::string* error_message) {
-  base::win::RegKey key;
-
-  string16 manifest_path;
   string16 native_host_name_wide = UTF8ToUTF16(native_host_name);
 
-  bool found = false;
-
   // First check 32-bit registry and then try 64-bit.
-  if (key.Open(HKEY_LOCAL_MACHINE, kNativeMessagingRegistryKey,
-               KEY_QUERY_VALUE | KEY_WOW64_32KEY) == ERROR_SUCCESS) {
-    if (key.ReadValue(native_host_name_wide.c_str(), &manifest_path) ==
-        ERROR_SUCCESS) {
-      found = true;
-    }
-  }
+  string16 manifest_path =
+      GetManifestPath(native_host_name_wide, KEY_WOW64_32KEY);
+  if (manifest_path.empty())
+    manifest_path = GetManifestPath(native_host_name_wide, KEY_WOW64_64KEY);
 
-  if (!found && key.Open(HKEY_LOCAL_MACHINE, kNativeMessagingRegistryKey,
-                         KEY_QUERY_VALUE | KEY_WOW64_64KEY) == ERROR_SUCCESS) {
-    if (key.ReadValue(native_host_name_wide.c_str(), &manifest_path) ==
-        ERROR_SUCCESS) {
-      found = true;
-    }
-  }
-
-  if (!found) {
+  if (manifest_path.empty()) {
     *error_message = "Native messaging host " + native_host_name +
         " is not registered";
     return scoped_ptr<NativeMessagingHostManifest>();
diff --git a/chrome/browser/extensions/api/metrics_private/metrics_apitest.cc b/chrome/browser/extensions/api/metrics_private/metrics_apitest.cc
index 655670f..1794fc2 100644
--- a/chrome/browser/extensions/api/metrics_private/metrics_apitest.cc
+++ b/chrome/browser/extensions/api/metrics_private/metrics_apitest.cc
@@ -4,6 +4,7 @@
 
 #include <map>
 
+#include "base/metrics/field_trial.h"
 #include "base/metrics/histogram.h"
 #include "base/metrics/statistics_recorder.h"
 #include "chrome/browser/extensions/extension_apitest.h"
@@ -126,6 +127,8 @@
 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, Metrics) {
   UserActionObserver observer;
 
+  base::FieldTrialList::CreateFieldTrial("apitestfieldtrial2", "group1");
+
   ASSERT_TRUE(RunComponentExtensionTest("metrics")) << message_;
 
   observer.ValidateUserActions(g_user_actions, arraysize(g_user_actions));
diff --git a/chrome/browser/extensions/api/metrics_private/metrics_private_api.cc b/chrome/browser/extensions/api/metrics_private/metrics_private_api.cc
index 08ac6f3..f65d80e 100644
--- a/chrome/browser/extensions/api/metrics_private/metrics_private_api.cc
+++ b/chrome/browser/extensions/api/metrics_private/metrics_private_api.cc
@@ -6,6 +6,7 @@
 
 #include <algorithm>
 
+#include "base/metrics/field_trial.h"
 #include "base/metrics/histogram.h"
 #include "base/prefs/pref_service.h"
 #include "chrome/browser/browser_process.h"
@@ -22,6 +23,7 @@
 
 namespace GetIsCrashReportingEnabled =
     api::metrics_private::GetIsCrashReportingEnabled;
+namespace GetFieldTrial = api::metrics_private::GetFieldTrial;
 namespace RecordUserAction = api::metrics_private::RecordUserAction;
 namespace RecordValue = api::metrics_private::RecordValue;
 namespace RecordPercentage = api::metrics_private::RecordPercentage;
@@ -66,6 +68,14 @@
   return true;
 }
 
+bool MetricsPrivateGetFieldTrialFunction::RunImpl() {
+  std::string name;
+  EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &name));
+
+  SetResult(new base::StringValue(base::FieldTrialList::FindFullName(name)));
+  return true;
+}
+
 bool MetricsPrivateRecordUserActionFunction::RunImpl() {
   scoped_ptr<RecordUserAction::Params> params(
       RecordUserAction::Params::Create(*args_));
diff --git a/chrome/browser/extensions/api/metrics_private/metrics_private_api.h b/chrome/browser/extensions/api/metrics_private/metrics_private_api.h
index f3307c3..7679aa2 100644
--- a/chrome/browser/extensions/api/metrics_private/metrics_private_api.h
+++ b/chrome/browser/extensions/api/metrics_private/metrics_private_api.h
@@ -25,6 +25,18 @@
   virtual bool RunImpl() OVERRIDE;
 };
 
+class MetricsPrivateGetFieldTrialFunction : public SyncExtensionFunction {
+ public:
+  DECLARE_EXTENSION_FUNCTION("metricsPrivate.getFieldTrial",
+                             METRICSPRIVATE_GETFIELDTRIAL)
+
+ protected:
+  virtual ~MetricsPrivateGetFieldTrialFunction() {}
+
+  // ExtensionFunction:
+  virtual bool RunImpl() OVERRIDE;
+};
+
 class MetricsPrivateRecordUserActionFunction : public SyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("metricsPrivate.recordUserAction",
diff --git a/chrome/browser/extensions/api/music_manager_private/device_id_mac.cc b/chrome/browser/extensions/api/music_manager_private/device_id_mac.cc
index d768167..e66c0e2 100644
--- a/chrome/browser/extensions/api/music_manager_private/device_id_mac.cc
+++ b/chrome/browser/extensions/api/music_manager_private/device_id_mac.cc
@@ -46,20 +46,20 @@
 std::string GetVolumeUUIDFromBSDName(const std::string& bsd_name) {
   const CFAllocatorRef allocator = NULL;
 
-  base::mac::ScopedCFTypeRef<DASessionRef> session(DASessionCreate(allocator));
+  base::ScopedCFTypeRef<DASessionRef> session(DASessionCreate(allocator));
   if (session.get() == NULL) {
     VLOG(1) << "Error creating DA Session.";
     return std::string();
   }
 
-  base::mac::ScopedCFTypeRef<DADiskRef> disk(
+  base::ScopedCFTypeRef<DADiskRef> disk(
       DADiskCreateFromBSDName(allocator, session, bsd_name.c_str()));
   if (disk.get() == NULL) {
     VLOG(1) << "Error creating DA disk from BSD disk name.";
     return std::string();
   }
 
-  base::mac::ScopedCFTypeRef<CFDictionaryRef> disk_description(
+  base::ScopedCFTypeRef<CFDictionaryRef> disk_description(
       DADiskCopyDescription(disk));
   if (disk_description.get() == NULL) {
     VLOG(1) << "Error getting disk description.";
@@ -74,7 +74,7 @@
     return std::string();
   }
 
-  base::mac::ScopedCFTypeRef<CFStringRef> volume_uuid_string(
+  base::ScopedCFTypeRef<CFStringRef> volume_uuid_string(
       CFUUIDCreateString(allocator, volume_uuid));
   if (volume_uuid_string.get() == NULL) {
     VLOG(1) << "Error creating string from CSStringRef.";
diff --git a/chrome/browser/extensions/api/notifications/notifications_api.cc b/chrome/browser/extensions/api/notifications/notifications_api.cc
index 7365649..b5f9600 100644
--- a/chrome/browser/extensions/api/notifications/notifications_api.cc
+++ b/chrome/browser/extensions/api/notifications/notifications_api.cc
@@ -7,7 +7,7 @@
 #include "base/callback.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/extensions/event_names.h"
 #include "chrome/browser/extensions/event_router.h"
@@ -135,18 +135,18 @@
   virtual void Display() OVERRIDE { }
 
   virtual void Error() OVERRIDE {
-    scoped_ptr<ListValue> args(CreateBaseEventArgs());
+    scoped_ptr<base::ListValue> args(CreateBaseEventArgs());
     SendEvent(event_names::kOnNotificationError, args.Pass());
   }
 
   virtual void Close(bool by_user) OVERRIDE {
-    scoped_ptr<ListValue> args(CreateBaseEventArgs());
+    scoped_ptr<base::ListValue> args(CreateBaseEventArgs());
     args->Append(Value::CreateBooleanValue(by_user));
     SendEvent(event_names::kOnNotificationClosed, args.Pass());
   }
 
   virtual void Click() OVERRIDE {
-    scoped_ptr<ListValue> args(CreateBaseEventArgs());
+    scoped_ptr<base::ListValue> args(CreateBaseEventArgs());
     SendEvent(event_names::kOnNotificationClicked, args.Pass());
   }
 
@@ -156,7 +156,7 @@
   }
 
   virtual void ButtonClick(int index) OVERRIDE {
-    scoped_ptr<ListValue> args(CreateBaseEventArgs());
+    scoped_ptr<base::ListValue> args(CreateBaseEventArgs());
     args->Append(Value::CreateIntegerValue(index));
     SendEvent(event_names::kOnNotificationButtonClicked, args.Pass());
   }
@@ -186,14 +186,14 @@
  private:
   virtual ~NotificationsApiDelegate() {}
 
-  void SendEvent(const std::string& name, scoped_ptr<ListValue> args) {
+  void SendEvent(const std::string& name, scoped_ptr<base::ListValue> args) {
     scoped_ptr<Event> event(new Event(name, args.Pass()));
     ExtensionSystem::Get(profile_)->event_router()->DispatchEventToExtension(
         extension_id_, event.Pass());
   }
 
-  scoped_ptr<ListValue> CreateBaseEventArgs() {
-    scoped_ptr<ListValue> args(new ListValue());
+  scoped_ptr<base::ListValue> CreateBaseEventArgs() {
+    scoped_ptr<base::ListValue> args(new base::ListValue());
     args->Append(Value::CreateStringValue(id_));
     return args.Pass();
   }
@@ -442,7 +442,7 @@
       notification_ui_manager->GetAllIdsByProfileAndSourceOrigin(
           profile_, extension_->url());
 
-  scoped_ptr<DictionaryValue> result(new DictionaryValue());
+  scoped_ptr<base::DictionaryValue> result(new base::DictionaryValue());
 
   for (std::set<std::string>::iterator iter = notification_ids.begin();
        iter != notification_ids.end(); iter++) {
diff --git a/chrome/browser/extensions/api/omnibox/omnibox_api.cc b/chrome/browser/extensions/api/omnibox/omnibox_api.cc
index 774055f..400fc32 100644
--- a/chrome/browser/extensions/api/omnibox/omnibox_api.cc
+++ b/chrome/browser/extensions/api/omnibox/omnibox_api.cc
@@ -74,7 +74,7 @@
       ExtensionSystem::Get(profile)->extension_service()->extension_prefs();
 
   scoped_ptr<omnibox::SuggestResult> suggestion;
-  const DictionaryValue* dict = NULL;
+  const base::DictionaryValue* dict = NULL;
   if (prefs && prefs->ReadPrefAsDictionary(extension_id,
                                            kOmniboxDefaultSuggestion,
                                            &dict)) {
@@ -112,7 +112,7 @@
 void ExtensionOmniboxEventRouter::OnInputStarted(
     Profile* profile, const std::string& extension_id) {
   scoped_ptr<Event> event(new Event(
-      events::kOnInputStarted, make_scoped_ptr(new ListValue())));
+      events::kOnInputStarted, make_scoped_ptr(new base::ListValue())));
   event->restrict_to_profile = profile;
   ExtensionSystem::Get(profile)->event_router()->
       DispatchEventToExtension(extension_id, event.Pass());
@@ -126,7 +126,7 @@
           ExtensionHasEventListener(extension_id, events::kOnInputChanged))
     return false;
 
-  scoped_ptr<ListValue> args(new ListValue());
+  scoped_ptr<base::ListValue> args(new base::ListValue());
   args->Set(0, Value::CreateStringValue(input));
   args->Set(1, Value::CreateIntegerValue(suggest_id));
 
@@ -153,7 +153,7 @@
   extensions::TabHelper::FromWebContents(web_contents)->
       active_tab_permission_granter()->GrantIfRequested(extension);
 
-  scoped_ptr<ListValue> args(new ListValue());
+  scoped_ptr<base::ListValue> args(new base::ListValue());
   args->Set(0, Value::CreateStringValue(input));
   if (disposition == NEW_FOREGROUND_TAB)
     args->Set(1, Value::CreateStringValue(kForegroundTabDisposition));
@@ -177,7 +177,7 @@
 void ExtensionOmniboxEventRouter::OnInputCancelled(
     Profile* profile, const std::string& extension_id) {
   scoped_ptr<Event> event(new Event(
-      events::kOnInputCancelled, make_scoped_ptr(new ListValue())));
+      events::kOnInputCancelled, make_scoped_ptr(new base::ListValue())));
   event->restrict_to_profile = profile;
   ExtensionSystem::Get(profile)->event_router()->
       DispatchEventToExtension(extension_id, event.Pass());
diff --git a/chrome/browser/extensions/api/omnibox/omnibox_unittest.cc b/chrome/browser/extensions/api/omnibox/omnibox_unittest.cc
index f1ab1ed..549367f 100644
--- a/chrome/browser/extensions/api/omnibox/omnibox_unittest.cc
+++ b/chrome/browser/extensions/api/omnibox/omnibox_unittest.cc
@@ -41,7 +41,7 @@
 // +       ddd
 // = nmmmmndddn
 TEST(ExtensionOmniboxTest, DescriptionStylesSimple) {
-  scoped_ptr<ListValue> list = ListBuilder()
+  scoped_ptr<base::ListValue> list = ListBuilder()
       .Append(42)
       .Append(ListBuilder()
         .Append(DictionaryBuilder()
@@ -72,7 +72,7 @@
       *params->suggest_results[0]));
 
   // Same input, but swap the order. Ensure it still works.
-  scoped_ptr<ListValue> swap_list = ListBuilder()
+  scoped_ptr<base::ListValue> swap_list = ListBuilder()
       .Append(42)
       .Append(ListBuilder()
         .Append(DictionaryBuilder()
@@ -104,7 +104,7 @@
 // +  dd
 // = 3773unnnn66
 TEST(ExtensionOmniboxTest, DescriptionStylesCombine) {
-  scoped_ptr<ListValue> list = ListBuilder()
+  scoped_ptr<base::ListValue> list = ListBuilder()
       .Append(42)
       .Append(ListBuilder()
         .Append(DictionaryBuilder()
@@ -149,7 +149,7 @@
 
   // Try moving the "dim/match" style pair at offset 9. Output should be the
   // same.
-  scoped_ptr<ListValue> moved_list = ListBuilder()
+  scoped_ptr<base::ListValue> moved_list = ListBuilder()
       .Append(42)
       .Append(ListBuilder()
         .Append(DictionaryBuilder()
@@ -193,7 +193,7 @@
 // + ddd
 // = 77777nnnnn
 TEST(ExtensionOmniboxTest, DescriptionStylesCombine2) {
-  scoped_ptr<ListValue> list = ListBuilder()
+  scoped_ptr<base::ListValue> list = ListBuilder()
       .Append(42)
       .Append(ListBuilder()
         .Append(DictionaryBuilder()
@@ -242,7 +242,7 @@
 // = 77777nnnnn
 TEST(ExtensionOmniboxTest, DefaultSuggestResult) {
   // Default suggestions should not have a content parameter.
-  scoped_ptr<ListValue> list = ListBuilder()
+  scoped_ptr<base::ListValue> list = ListBuilder()
       .Append(DictionaryBuilder()
         .Set("description", "description")
         .Set("descriptionStyles", ListBuilder()
diff --git a/chrome/browser/extensions/api/page_capture/page_capture_api.cc b/chrome/browser/extensions/api/page_capture/page_capture_api.cc
index 62a800e..1fe87c7 100644
--- a/chrome/browser/extensions/api/page_capture/page_capture_api.cc
+++ b/chrome/browser/extensions/api/page_capture/page_capture_api.cc
@@ -175,7 +175,7 @@
   ChildProcessSecurityPolicy::GetInstance()->GrantReadFile(
       child_id, mhtml_path_);
 
-  DictionaryValue* dict = new DictionaryValue();
+  base::DictionaryValue* dict = new base::DictionaryValue();
   SetResult(dict);
   dict->SetString("mhtmlFilePath", mhtml_path_.value());
   dict->SetInteger("mhtmlFileLength", file_size);
diff --git a/chrome/browser/extensions/api/page_capture/page_capture_apitest.cc b/chrome/browser/extensions/api/page_capture/page_capture_apitest.cc
index 34e7654..a2bb28b 100644
--- a/chrome/browser/extensions/api/page_capture/page_capture_apitest.cc
+++ b/chrome/browser/extensions/api/page_capture/page_capture_apitest.cc
@@ -18,23 +18,8 @@
     ExtensionApiTest::SetUpCommandLine(command_line);
     command_line->AppendSwitchASCII(switches::kJavaScriptFlags, "--expose-gc");
   }
-
-  virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
-    ExtensionApiTest::SetUpInProcessBrowserTestFixture();
-
-    host_resolver()->AddRule("www.a.com", "127.0.0.1");
-
-    ASSERT_TRUE(StartTestServer());
-  }
 };
 
-// Disabled on Linux http://crbug.com/98194
-#if defined(OS_LINUX)
-#define MAYBE_SaveAsMHTML DISABLED_SaveAsMHTML
-#else
-#define MAYBE_SaveAsMHTML SaveAsMHTML
-#endif  // defined(OS_LINUX)
-
 class PageCaptureSaveAsMHTMLDelegate
     : public PageCaptureSaveAsMHTMLFunction::TestDelegate {
  public:
@@ -54,7 +39,9 @@
   base::FilePath temp_file_;
 };
 
-IN_PROC_BROWSER_TEST_F(ExtensionPageCaptureApiTest, MAYBE_SaveAsMHTML) {
+IN_PROC_BROWSER_TEST_F(ExtensionPageCaptureApiTest, SaveAsMHTML) {
+  host_resolver()->AddRule("www.a.com", "127.0.0.1");
+  ASSERT_TRUE(StartEmbeddedTestServer());
   PageCaptureSaveAsMHTMLDelegate delegate;
   ASSERT_TRUE(RunExtensionTest("page_capture")) << message_;
   ASSERT_FALSE(delegate.temp_file_.empty());
diff --git a/chrome/browser/extensions/api/permissions/permissions_api_helpers.cc b/chrome/browser/extensions/api/permissions/permissions_api_helpers.cc
index dff6acb..9a610c0 100644
--- a/chrome/browser/extensions/api/permissions/permissions_api_helpers.cc
+++ b/chrome/browser/extensions/api/permissions/permissions_api_helpers.cc
@@ -9,7 +9,6 @@
 #include "base/values.h"
 #include "chrome/common/extensions/api/permissions.h"
 #include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/permissions/bluetooth_device_permission.h"
 #include "chrome/common/extensions/permissions/permission_set.h"
 #include "chrome/common/extensions/permissions/permissions_info.h"
 #include "chrome/common/extensions/permissions/usb_device_permission.h"
@@ -36,7 +35,7 @@
 const char kUnknownPermissionError[] =
     "'*' is not a recognized permission.";
 const char kUnsupportedPermissionId[] =
-    "Only the bluetoothDevices and usbDevices permissions support arguments.";
+    "Only the usbDevices permission supports arguments.";
 
 }  // namespace
 
@@ -95,14 +94,9 @@
 
         // Explicitly check the permissions that accept arguments until the bug
         // referenced above is fixed.
-        const APIPermissionInfo* bluetooth_device_permission_info =
-            info->GetByID(APIPermission::kBluetoothDevice);
         const APIPermissionInfo* usb_device_permission_info =
             info->GetByID(APIPermission::kUsbDevice);
-        if (permission_name == bluetooth_device_permission_info->name()) {
-          permission = new BluetoothDevicePermission(
-              bluetooth_device_permission_info);
-        } else if (permission_name == usb_device_permission_info->name()) {
+        if (permission_name == usb_device_permission_info->name()) {
           permission = new UsbDevicePermission(usb_device_permission_info);
         } else {
           *error = kUnsupportedPermissionId;
diff --git a/chrome/browser/extensions/api/permissions/permissions_api_helpers_unittest.cc b/chrome/browser/extensions/api/permissions/permissions_api_helpers_unittest.cc
index 429ee70..3ec4abc 100644
--- a/chrome/browser/extensions/api/permissions/permissions_api_helpers_unittest.cc
+++ b/chrome/browser/extensions/api/permissions/permissions_api_helpers_unittest.cc
@@ -41,9 +41,9 @@
 
   // Pack the permission set to value and verify its contents.
   scoped_ptr<Permissions> permissions(PackPermissionSet(permission_set.get()));
-  scoped_ptr<DictionaryValue> value(permissions->ToValue());
-  ListValue* api_list = NULL;
-  ListValue* origin_list = NULL;
+  scoped_ptr<base::DictionaryValue> value(permissions->ToValue());
+  base::ListValue* api_list = NULL;
+  base::ListValue* origin_list = NULL;
   EXPECT_TRUE(value->GetList("permissions", &api_list));
   EXPECT_TRUE(value->GetList("origins", &origin_list));
 
@@ -77,12 +77,12 @@
 // Tests various error conditions and edge cases when unpacking values
 // into PermissionSets.
 TEST(ExtensionPermissionsAPIHelpers, Unpack) {
-  scoped_ptr<ListValue> apis(new ListValue());
+  scoped_ptr<base::ListValue> apis(new base::ListValue());
   apis->Append(Value::CreateStringValue("tabs"));
-  scoped_ptr<ListValue> origins(new ListValue());
+  scoped_ptr<base::ListValue> origins(new base::ListValue());
   origins->Append(Value::CreateStringValue("http://a.com/*"));
 
-  scoped_ptr<DictionaryValue> value(new DictionaryValue());
+  scoped_ptr<base::DictionaryValue> value(new base::DictionaryValue());
   scoped_refptr<PermissionSet> permissions;
   std::string error;
 
@@ -113,7 +113,7 @@
   {
     Permissions permissions_object;
     value->Clear();
-    scoped_ptr<ListValue> invalid_apis(apis->DeepCopy());
+    scoped_ptr<base::ListValue> invalid_apis(apis->DeepCopy());
     invalid_apis->Append(Value::CreateIntegerValue(3));
     value->Set("permissions", invalid_apis->DeepCopy());
     EXPECT_FALSE(Permissions::Populate(*value, &permissions_object));
@@ -123,7 +123,7 @@
   {
     Permissions permissions_object;
     value->Clear();
-    scoped_ptr<ListValue> invalid_origins(origins->DeepCopy());
+    scoped_ptr<base::ListValue> invalid_origins(origins->DeepCopy());
     invalid_origins->Append(Value::CreateIntegerValue(3));
     value->Set("origins", invalid_origins->DeepCopy());
     EXPECT_FALSE(Permissions::Populate(*value, &permissions_object));
@@ -161,7 +161,7 @@
   {
     Permissions permissions_object;
     value->Clear();
-    scoped_ptr<ListValue> invalid_apis(apis->DeepCopy());
+    scoped_ptr<base::ListValue> invalid_apis(apis->DeepCopy());
     invalid_apis->Append(Value::CreateStringValue("unknown_permission"));
     value->Set("permissions", invalid_apis->DeepCopy());
     EXPECT_TRUE(Permissions::Populate(*value, &permissions_object));
diff --git a/chrome/browser/extensions/api/permissions/permissions_apitest.cc b/chrome/browser/extensions/api/permissions/permissions_apitest.cc
index ef20085..1bfea06 100644
--- a/chrome/browser/extensions/api/permissions/permissions_apitest.cc
+++ b/chrome/browser/extensions/api/permissions/permissions_apitest.cc
@@ -84,7 +84,7 @@
 
   PermissionsRequestFunction::SetIgnoreUserGestureForTests(true);
   host_resolver()->AddRule("*.com", "127.0.0.1");
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
   EXPECT_TRUE(RunExtensionTest("permissions/optional")) << message_;
 }
 
@@ -95,26 +95,16 @@
   PermissionsRequestFunction::SetAutoConfirmForTests(true);
   PermissionsRequestFunction::SetIgnoreUserGestureForTests(true);
   host_resolver()->AddRule("*.com", "127.0.0.1");
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
   EXPECT_TRUE(RunExtensionTest("permissions/optional")) << message_;
 }
 
-// Tests that the optional permissions API works correctly with complex
-// permissions.
-IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ComplexOptionalPermissions) {
-  // Rather than setting the granted permissions, set the UI autoconfirm flag
-  // and run the same tests.
-  PermissionsRequestFunction::SetAutoConfirmForTests(true);
-  PermissionsRequestFunction::SetIgnoreUserGestureForTests(true);
-  EXPECT_TRUE(RunExtensionTest("permissions/complex_optional")) << message_;
-}
-
 // Test that denying the optional permissions confirmation dialog works.
 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, OptionalPermissionsDeny) {
   PermissionsRequestFunction::SetAutoConfirmForTests(false);
   PermissionsRequestFunction::SetIgnoreUserGestureForTests(true);
   host_resolver()->AddRule("*.com", "127.0.0.1");
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
   EXPECT_TRUE(RunExtensionTest("permissions/optional_deny")) << message_;
 }
 
@@ -123,7 +113,7 @@
 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, OptionalPermissionsGesture) {
   PermissionsRequestFunction::SetIgnoreUserGestureForTests(false);
   host_resolver()->AddRule("*.com", "127.0.0.1");
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
   EXPECT_TRUE(RunExtensionTest("permissions/optional_gesture")) << message_;
 }
 
diff --git a/chrome/browser/extensions/api/preference/preference_helpers.cc b/chrome/browser/extensions/api/preference/preference_helpers.cc
index c8f1f6b..e4192dd 100644
--- a/chrome/browser/extensions/api/preference/preference_helpers.cc
+++ b/chrome/browser/extensions/api/preference/preference_helpers.cc
@@ -88,7 +88,7 @@
 void DispatchEventToExtensions(
     Profile* profile,
     const std::string& event_name,
-    ListValue* args,
+    base::ListValue* args,
     APIPermission::ID permission,
     bool incognito,
     const std::string& browser_pref) {
@@ -108,7 +108,7 @@
         (!incognito || IncognitoInfo::IsSplitMode(it->get()) ||
          extension_service->CanCrossIncognito(it->get()))) {
       // Inject level of control key-value.
-      DictionaryValue* dict;
+      base::DictionaryValue* dict;
       bool rv = args->GetDictionary(0, &dict);
       DCHECK(rv);
       std::string level_of_control =
@@ -134,7 +134,7 @@
         }
       }
 
-      scoped_ptr<ListValue> args_copy(args->DeepCopy());
+      scoped_ptr<base::ListValue> args_copy(args->DeepCopy());
       scoped_ptr<Event> event(new Event(event_name, args_copy.Pass()));
       event->restrict_to_profile = restrict_to_profile;
       router->DispatchEventToExtension(extension_id, event.Pass());
diff --git a/chrome/browser/extensions/api/processes/processes_api.cc b/chrome/browser/extensions/api/processes/processes_api.cc
index adcd39d..5472844 100644
--- a/chrome/browser/extensions/api/processes/processes_api.cc
+++ b/chrome/browser/extensions/api/processes/processes_api.cc
@@ -44,16 +44,16 @@
 
 #if defined(ENABLE_TASK_MANAGER)
 
-DictionaryValue* CreateCacheData(
+base::DictionaryValue* CreateCacheData(
     const WebKit::WebCache::ResourceTypeStat& stat) {
 
-  DictionaryValue* cache = new DictionaryValue();
+  base::DictionaryValue* cache = new base::DictionaryValue();
   cache->SetDouble(keys::kCacheSize, static_cast<double>(stat.size));
   cache->SetDouble(keys::kCacheLiveSize, static_cast<double>(stat.liveSize));
   return cache;
 }
 
-void SetProcessType(DictionaryValue* result,
+void SetProcessType(base::DictionaryValue* result,
                     TaskManagerModel* model,
                     int index) {
   // Determine process type.
@@ -87,7 +87,6 @@
     case task_manager::Resource::GPU:
       type = keys::kProcessTypeGPU;
       break;
-    case task_manager::Resource::PROFILE_IMPORT:
     case task_manager::Resource::ZYGOTE:
     case task_manager::Resource::SANDBOX_HELPER:
     case task_manager::Resource::UNKNOWN:
@@ -99,8 +98,8 @@
   result->SetString(keys::kTypeKey, type);
 }
 
-ListValue* GetTabsForProcess(int process_id) {
-  ListValue* tabs_list = new ListValue();
+base::ListValue* GetTabsForProcess(int process_id) {
+  base::ListValue* tabs_list = new base::ListValue();
 
   // The tabs list only makes sense for render processes, so if we don't find
   // one, just return the empty list.
@@ -112,16 +111,15 @@
   int tab_id = -1;
   // We need to loop through all the RVHs to ensure we collect the set of all
   // tabs using this renderer process.
-  content::RenderProcessHost::RenderWidgetHostsIterator iter(
-      rph->GetRenderWidgetHostsIterator());
-  for (; !iter.IsAtEnd(); iter.Advance()) {
-    const content::RenderWidgetHost* widget = iter.GetCurrentValue();
-    DCHECK(widget);
-    if (!widget || !widget->IsRenderView())
+  content::RenderWidgetHost::List widgets =
+      content::RenderWidgetHost::GetRenderWidgetHosts();
+  for (size_t i = 0; i < widgets.size(); ++i) {
+    if (widgets[i]->GetProcess()->GetID() != process_id)
+      continue;
+    if (!widgets[i]->IsRenderView())
       continue;
 
-    content::RenderViewHost* host = content::RenderViewHost::From(
-        const_cast<content::RenderWidgetHost*>(widget));
+    content::RenderViewHost* host = content::RenderViewHost::From(widgets[i]);
     content::WebContents* contents =
         content::WebContents::FromRenderViewHost(host);
     if (contents) {
@@ -137,11 +135,11 @@
 // This function creates a Process object to be returned to the extensions
 // using these APIs. For memory details, which are not added by this function,
 // the callers need to use AddMemoryDetails.
-DictionaryValue* CreateProcessFromModel(int process_id,
-                                        TaskManagerModel* model,
-                                        int index,
-                                        bool include_optional) {
-  DictionaryValue* result = new DictionaryValue();
+base::DictionaryValue* CreateProcessFromModel(int process_id,
+                                              TaskManagerModel* model,
+                                              int index,
+                                              bool include_optional) {
+  base::DictionaryValue* result = new base::DictionaryValue();
   size_t mem;
 
   result->SetInteger(keys::kIdKey, process_id);
@@ -200,7 +198,7 @@
 // Since memory details are expensive to gather, we don't do it by default.
 // This function is a helper to add memory details data to an existing
 // Process object representation.
-void AddMemoryDetails(DictionaryValue* result,
+void AddMemoryDetails(base::DictionaryValue* result,
                       TaskManagerModel* model,
                       int index) {
   size_t mem;
@@ -307,8 +305,8 @@
     index = model_->GetGroupIndexForResource(start);
   }
 
-  scoped_ptr<ListValue> args(new ListValue());
-  DictionaryValue* process = CreateProcessFromModel(
+  scoped_ptr<base::ListValue> args(new base::ListValue());
+  base::DictionaryValue* process = CreateProcessFromModel(
       model_->GetUniqueChildProcessId(index), model_, index, false);
   DCHECK(process != NULL);
 
@@ -339,21 +337,21 @@
 
   DCHECK(updated || updated_memory);
 
-  IDMap<DictionaryValue> processes_map;
+  IDMap<base::DictionaryValue> processes_map;
   for (int i = start; i < start + length; i++) {
     if (model_->IsResourceFirstInGroup(i)) {
       int id = model_->GetUniqueChildProcessId(i);
-      DictionaryValue* process = CreateProcessFromModel(id, model_, i, true);
+      base::DictionaryValue* process = CreateProcessFromModel(id, model_, i, true);
       processes_map.AddWithID(process, i);
     }
   }
 
   int id;
   std::string idkey(keys::kIdKey);
-  DictionaryValue* processes = new DictionaryValue();
+  base::DictionaryValue* processes = new base::DictionaryValue();
 
   if (updated) {
-    IDMap<DictionaryValue>::iterator it(&processes_map);
+    IDMap<base::DictionaryValue>::iterator it(&processes_map);
     for (; !it.IsAtEnd(); it.Advance()) {
       if (!it.GetCurrentValue()->GetInteger(idkey, &id))
         continue;
@@ -362,13 +360,13 @@
       processes->Set(base::IntToString(id), it.GetCurrentValue());
     }
 
-    scoped_ptr<ListValue> args(new ListValue());
+    scoped_ptr<base::ListValue> args(new base::ListValue());
     args->Append(processes);
     DispatchEvent(keys::kOnUpdated, args.Pass());
   }
 
   if (updated_memory) {
-    IDMap<DictionaryValue>::iterator it(&processes_map);
+    IDMap<base::DictionaryValue>::iterator it(&processes_map);
     for (; !it.IsAtEnd(); it.Advance()) {
       if (!it.GetCurrentValue()->GetInteger(idkey, &id))
         continue;
@@ -381,7 +379,7 @@
         processes->Set(base::IntToString(id), it.GetCurrentValue());
     }
 
-    scoped_ptr<ListValue> args(new ListValue());
+    scoped_ptr<base::ListValue> args(new base::ListValue());
     args->Append(processes);
     DispatchEvent(keys::kOnUpdatedWithMemory, args.Pass());
   }
@@ -400,7 +398,7 @@
     return;
 
   // The callback function parameters.
-  scoped_ptr<ListValue> args(new ListValue());
+  scoped_ptr<base::ListValue> args(new base::ListValue());
 
   // First arg: The id of the process that was closed.
   args->Append(Value::CreateIntegerValue(
@@ -422,7 +420,7 @@
   if (!HasEventListeners(event))
     return;
 
-  DictionaryValue* process = NULL;
+  base::DictionaryValue* process = NULL;
   int count = model_->ResourceCount();
   int id = widget->GetProcess()->GetID();
 
@@ -439,7 +437,7 @@
   if (process == NULL)
     return;
 
-  scoped_ptr<ListValue> args(new ListValue());
+  scoped_ptr<base::ListValue> args(new base::ListValue());
   args->Append(process);
 
   DispatchEvent(keys::kOnUnresponsive, args.Pass());
@@ -451,7 +449,7 @@
     content::RenderProcessHost::RendererClosedDetails* details) {
 #if defined(ENABLE_TASK_MANAGER)
   // The callback function parameters.
-  scoped_ptr<ListValue> args(new ListValue());
+  scoped_ptr<base::ListValue> args(new base::ListValue());
 
   // First arg: The id of the process that was closed.
   args->Append(Value::CreateIntegerValue(rph->GetID()));
@@ -466,8 +464,9 @@
 #endif  // defined(ENABLE_TASK_MANAGER)
 }
 
-void ProcessesEventRouter::DispatchEvent(const char* event_name,
-                                         scoped_ptr<ListValue> event_args) {
+void ProcessesEventRouter::DispatchEvent(
+    const char* event_name,
+    scoped_ptr<base::ListValue> event_args) {
   if (extensions::ExtensionSystem::Get(profile_)->event_router()) {
     scoped_ptr<extensions::Event> event(new extensions::Event(
         event_name, event_args.Pass()));
@@ -732,7 +731,7 @@
 void GetProcessInfoFunction::GatherProcessInfo() {
 #if defined(ENABLE_TASK_MANAGER)
   TaskManagerModel* model = TaskManager::GetInstance()->model();
-  DictionaryValue* processes = new DictionaryValue();
+  base::DictionaryValue* processes = new base::DictionaryValue();
 
   // If there are no process IDs specified, it means we need to return all of
   // the ones we know of.
@@ -741,7 +740,7 @@
     for (int i = 0; i < resources; ++i) {
       if (model->IsResourceFirstInGroup(i)) {
         int id = model->GetUniqueChildProcessId(i);
-        DictionaryValue* d = CreateProcessFromModel(id, model, i, false);
+        base::DictionaryValue* d = CreateProcessFromModel(id, model, i, false);
         if (memory_)
           AddMemoryDetails(d, model, i);
         processes->Set(base::IntToString(id), d);
@@ -755,7 +754,8 @@
         std::vector<int>::iterator proc_id = std::find(process_ids_.begin(),
                                                        process_ids_.end(), id);
         if (proc_id != process_ids_.end()) {
-          DictionaryValue* d = CreateProcessFromModel(id, model, i, false);
+          base::DictionaryValue* d =
+              CreateProcessFromModel(id, model, i, false);
           if (memory_)
             AddMemoryDetails(d, model, i);
           processes->Set(base::IntToString(id), d);
diff --git a/chrome/browser/extensions/api/processes/processes_apitest.cc b/chrome/browser/extensions/api/processes/processes_apitest.cc
index af7c08b..d38a683 100644
--- a/chrome/browser/extensions/api/processes/processes_apitest.cc
+++ b/chrome/browser/extensions/api/processes/processes_apitest.cc
@@ -50,7 +50,7 @@
   EXPECT_EQ(TaskManagerModel::TASK_PENDING, model->update_state_);
 
   // Now show the task manager and wait for it to be ready
-  chrome::ShowTaskManager(browser(), false);
+  chrome::ShowTaskManager(browser());
 
   EXPECT_EQ(2, model->update_requests_);
   EXPECT_EQ(TaskManagerModel::TASK_PENDING, model->update_state_);
diff --git a/chrome/browser/extensions/api/proxy/proxy_api.cc b/chrome/browser/extensions/api/proxy/proxy_api.cc
index 054cab6..a115a1b 100644
--- a/chrome/browser/extensions/api/proxy/proxy_api.cc
+++ b/chrome/browser/extensions/api/proxy/proxy_api.cc
@@ -37,8 +37,8 @@
     EventRouterForwarder* event_router,
     void* profile,
     int error_code) {
-  scoped_ptr<ListValue> args(new ListValue());
-  DictionaryValue* dict = new DictionaryValue();
+  scoped_ptr<base::ListValue> args(new base::ListValue());
+  base::DictionaryValue* dict = new base::DictionaryValue();
   dict->SetBoolean(keys::kProxyEventFatal, true);
   dict->SetString(keys::kProxyEventError, net::ErrorToString(error_code));
   dict->SetString(keys::kProxyEventDetails, std::string());
@@ -58,8 +58,8 @@
     void* profile,
     int line_number,
     const string16& error) {
-  scoped_ptr<ListValue> args(new ListValue());
-  DictionaryValue* dict = new DictionaryValue();
+  scoped_ptr<base::ListValue> args(new base::ListValue());
+  base::DictionaryValue* dict = new base::DictionaryValue();
   dict->SetBoolean(keys::kProxyEventFatal, false);
   dict->SetString(keys::kProxyEventError,
                   net::ErrorToString(net::ERR_PAC_SCRIPT_FAILED));
@@ -95,8 +95,8 @@
   // has been verified already by the extension API to match the schema
   // defined in the extension API JSON.
   CHECK(extension_pref->IsType(Value::TYPE_DICTIONARY));
-  const DictionaryValue* config =
-      static_cast<const DictionaryValue*>(extension_pref);
+  const base::DictionaryValue* config =
+      static_cast<const base::DictionaryValue*>(extension_pref);
 
   // Extract the various pieces of information passed to
   // chrome.proxy.settings.set(). Several of these strings will
@@ -135,7 +135,7 @@
   // This is a dictionary wrapper that exposes the proxy configuration stored in
   // the browser preferences.
   ProxyConfigDictionary config(
-      static_cast<const DictionaryValue*>(browser_pref));
+      static_cast<const base::DictionaryValue*>(browser_pref));
 
   ProxyPrefs::ProxyMode mode;
   if (!config.GetMode(&mode)) {
@@ -144,7 +144,7 @@
   }
 
   // Build a new ProxyConfig instance as defined in the extension API.
-  scoped_ptr<DictionaryValue> extension_pref(new DictionaryValue);
+  scoped_ptr<base::DictionaryValue> extension_pref(new base::DictionaryValue);
 
   extension_pref->SetString(keys::kProxyConfigMode,
                             ProxyPrefs::ProxyModeToString(mode));
@@ -159,7 +159,7 @@
       // A PAC URL either point to a PAC script or contain a base64 encoded
       // PAC script. In either case we build a PacScript dictionary as defined
       // in the extension API.
-      DictionaryValue* pac_dict = helpers::CreatePacScriptDict(config);
+      base::DictionaryValue* pac_dict = helpers::CreatePacScriptDict(config);
       if (!pac_dict)
         return NULL;
       extension_pref->Set(keys::kProxyConfigPacScript, pac_dict);
@@ -167,7 +167,8 @@
     }
     case ProxyPrefs::MODE_FIXED_SERVERS: {
       // Build ProxyRules dictionary according to the extension API.
-      DictionaryValue* proxy_rules_dict = helpers::CreateProxyRulesDict(config);
+      base::DictionaryValue* proxy_rules_dict =
+          helpers::CreateProxyRulesDict(config);
       if (!proxy_rules_dict)
         return NULL;
       extension_pref->Set(keys::kProxyConfigRules, proxy_rules_dict);
diff --git a/chrome/browser/extensions/api/proxy/proxy_api_helpers.cc b/chrome/browser/extensions/api/proxy/proxy_api_helpers.cc
index 8dcd291..f0fc389 100644
--- a/chrome/browser/extensions/api/proxy/proxy_api_helpers.cc
+++ b/chrome/browser/extensions/api/proxy/proxy_api_helpers.cc
@@ -58,7 +58,7 @@
 
 // Extension Pref -> Browser Pref conversion.
 
-bool GetProxyModeFromExtensionPref(const DictionaryValue* proxy_config,
+bool GetProxyModeFromExtensionPref(const base::DictionaryValue* proxy_config,
                                    ProxyPrefs::ProxyMode* out,
                                    std::string* error,
                                    bool* bad_message) {
@@ -75,11 +75,11 @@
   return true;
 }
 
-bool GetPacMandatoryFromExtensionPref(const DictionaryValue* proxy_config,
+bool GetPacMandatoryFromExtensionPref(const base::DictionaryValue* proxy_config,
                                       bool* out,
                                       std::string* error,
                                       bool* bad_message){
-  const DictionaryValue* pac_dict = NULL;
+  const base::DictionaryValue* pac_dict = NULL;
   proxy_config->GetDictionary(keys::kProxyConfigPacScript, &pac_dict);
   if (!pac_dict)
     return true;
@@ -96,11 +96,11 @@
   return true;
 }
 
-bool GetPacUrlFromExtensionPref(const DictionaryValue* proxy_config,
+bool GetPacUrlFromExtensionPref(const base::DictionaryValue* proxy_config,
                                 std::string* out,
                                 std::string* error,
                                 bool* bad_message) {
-  const DictionaryValue* pac_dict = NULL;
+  const base::DictionaryValue* pac_dict = NULL;
   proxy_config->GetDictionary(keys::kProxyConfigPacScript, &pac_dict);
   if (!pac_dict)
     return true;
@@ -122,11 +122,11 @@
   return true;
 }
 
-bool GetPacDataFromExtensionPref(const DictionaryValue* proxy_config,
+bool GetPacDataFromExtensionPref(const base::DictionaryValue* proxy_config,
                                  std::string* out,
                                  std::string* error,
                                  bool* bad_message) {
-  const DictionaryValue* pac_dict = NULL;
+  const base::DictionaryValue* pac_dict = NULL;
   proxy_config->GetDictionary(keys::kProxyConfigPacScript, &pac_dict);
   if (!pac_dict)
     return true;
@@ -147,7 +147,7 @@
   return true;
 }
 
-bool GetProxyServer(const DictionaryValue* proxy_server,
+bool GetProxyServer(const base::DictionaryValue* proxy_server,
                     net::ProxyServer::Scheme default_scheme,
                     net::ProxyServer* out,
                     std::string* error,
@@ -188,11 +188,12 @@
   return true;
 }
 
-bool GetProxyRulesStringFromExtensionPref(const DictionaryValue* proxy_config,
-                                          std::string* out,
-                                          std::string* error,
-                                          bool* bad_message) {
-  const DictionaryValue* proxy_rules = NULL;
+bool GetProxyRulesStringFromExtensionPref(
+    const base::DictionaryValue* proxy_config,
+    std::string* out,
+    std::string* error,
+    bool* bad_message) {
+  const base::DictionaryValue* proxy_rules = NULL;
   proxy_config->GetDictionary(keys::kProxyConfigRules, &proxy_rules);
   if (!proxy_rules)
     return true;
@@ -207,7 +208,7 @@
   // singleProxy that will supersede per-URL proxies, but it's worth it to keep
   // the code simple and extensible.
   for (size_t i = 0; i <= keys::SCHEME_MAX; ++i) {
-    const DictionaryValue* proxy_dict = NULL;
+    const base::DictionaryValue* proxy_dict = NULL;
     has_proxy[i] = proxy_rules->GetDictionary(keys::field_name[i],
                                               &proxy_dict);
     if (has_proxy[i]) {
@@ -255,7 +256,7 @@
   return true;
 }
 
-bool JoinUrlList(const ListValue* list,
+bool JoinUrlList(const base::ListValue* list,
                  const std::string& joiner,
                  std::string* out,
                  std::string* error,
@@ -283,11 +284,11 @@
   return true;
 }
 
-bool GetBypassListFromExtensionPref(const DictionaryValue* proxy_config,
+bool GetBypassListFromExtensionPref(const base::DictionaryValue* proxy_config,
                                     std::string* out,
                                     std::string* error,
                                     bool* bad_message) {
-  const DictionaryValue* proxy_rules = NULL;
+  const base::DictionaryValue* proxy_rules = NULL;
   proxy_config->GetDictionary(keys::kProxyConfigRules, &proxy_rules);
   if (!proxy_rules)
     return true;
@@ -296,7 +297,7 @@
     *out = "";
     return true;
   }
-  const ListValue* bypass_list = NULL;
+  const base::ListValue* bypass_list = NULL;
   if (!proxy_rules->GetList(keys::kProxyConfigBypassList, &bypass_list)) {
     LOG(ERROR) << "'rules.bypassList' could not be parsed.";
     *bad_message = true;
@@ -306,14 +307,15 @@
   return JoinUrlList(bypass_list, ",", out, error, bad_message);
 }
 
-DictionaryValue* CreateProxyConfigDict(ProxyPrefs::ProxyMode mode_enum,
-                                       bool pac_mandatory,
-                                       const std::string& pac_url,
-                                       const std::string& pac_data,
-                                       const std::string& proxy_rules_string,
-                                       const std::string& bypass_list,
-                                       std::string* error) {
-  DictionaryValue* result_proxy_config = NULL;
+base::DictionaryValue* CreateProxyConfigDict(
+    ProxyPrefs::ProxyMode mode_enum,
+    bool pac_mandatory,
+    const std::string& pac_url,
+    const std::string& pac_data,
+    const std::string& proxy_rules_string,
+    const std::string& bypass_list,
+    std::string* error) {
+  base::DictionaryValue* result_proxy_config = NULL;
   switch (mode_enum) {
     case ProxyPrefs::MODE_DIRECT:
       result_proxy_config = ProxyConfigDictionary::CreateDirect();
@@ -357,12 +359,13 @@
   return result_proxy_config;
 }
 
-DictionaryValue* CreateProxyRulesDict(
+base::DictionaryValue* CreateProxyRulesDict(
     const ProxyConfigDictionary& proxy_config) {
   ProxyPrefs::ProxyMode mode;
   CHECK(proxy_config.GetMode(&mode) && mode == ProxyPrefs::MODE_FIXED_SERVERS);
 
-  scoped_ptr<DictionaryValue> extension_proxy_rules(new DictionaryValue);
+  scoped_ptr<base::DictionaryValue> extension_proxy_rules(
+      new base::DictionaryValue);
 
   std::string proxy_servers;
   if (!proxy_config.GetProxyServer(&proxy_servers)) {
@@ -417,15 +420,16 @@
       LOG(ERROR) << "Invalid bypassList in configuration.";
       return NULL;
     }
-    ListValue* bypass_list = TokenizeToStringList(bypass_list_string, ",;");
+    base::ListValue* bypass_list =
+        TokenizeToStringList(bypass_list_string, ",;");
     extension_proxy_rules->Set(keys::kProxyConfigBypassList, bypass_list);
   }
 
   return extension_proxy_rules.release();
 }
 
-DictionaryValue* CreateProxyServerDict(const net::ProxyServer& proxy) {
-  scoped_ptr<DictionaryValue> out(new DictionaryValue);
+base::DictionaryValue* CreateProxyServerDict(const net::ProxyServer& proxy) {
+  scoped_ptr<base::DictionaryValue> out(new base::DictionaryValue);
   switch (proxy.scheme()) {
     case net::ProxyServer::SCHEME_HTTP:
       out->SetString(keys::kProxyConfigRuleScheme, "http");
@@ -449,12 +453,12 @@
   return out.release();
 }
 
-DictionaryValue* CreatePacScriptDict(
+base::DictionaryValue* CreatePacScriptDict(
     const ProxyConfigDictionary& proxy_config) {
   ProxyPrefs::ProxyMode mode;
   CHECK(proxy_config.GetMode(&mode) && mode == ProxyPrefs::MODE_PAC_SCRIPT);
 
-  scoped_ptr<DictionaryValue> pac_script_dict(new DictionaryValue);
+  scoped_ptr<base::DictionaryValue> pac_script_dict(new base::DictionaryValue);
   std::string pac_url;
   if (!proxy_config.GetPacUrl(&pac_url)) {
     LOG(ERROR) << "Invalid proxy configuration. Missing PAC URL.";
@@ -481,9 +485,9 @@
   return pac_script_dict.release();
 }
 
-ListValue* TokenizeToStringList(const std::string& in,
+base::ListValue* TokenizeToStringList(const std::string& in,
                                 const std::string& delims) {
-  ListValue* out = new ListValue;
+  base::ListValue* out = new base::ListValue;
   base::StringTokenizer entries(in, delims);
   while (entries.GetNext())
     out->Append(Value::CreateStringValue(entries.token()));
diff --git a/chrome/browser/extensions/api/proxy/proxy_api_helpers_unittest.cc b/chrome/browser/extensions/api/proxy/proxy_api_helpers_unittest.cc
index ff3cd32..f830710 100644
--- a/chrome/browser/extensions/api/proxy/proxy_api_helpers_unittest.cc
+++ b/chrome/browser/extensions/api/proxy/proxy_api_helpers_unittest.cc
@@ -27,18 +27,18 @@
 
 // Helper function to create a ProxyServer dictionary as defined in the
 // extension API.
-DictionaryValue* CreateTestProxyServerDict(const std::string& host) {
-  DictionaryValue* dict = new DictionaryValue;
+base::DictionaryValue* CreateTestProxyServerDict(const std::string& host) {
+  base::DictionaryValue* dict = new base::DictionaryValue;
   dict->SetString(keys::kProxyConfigRuleHost, host);
   return dict;
 }
 
 // Helper function to create a ProxyServer dictionary as defined in the
 // extension API.
-DictionaryValue* CreateTestProxyServerDict(const std::string& schema,
-                                           const std::string& host,
-                                           int port) {
-  DictionaryValue* dict = new DictionaryValue;
+base::DictionaryValue* CreateTestProxyServerDict(const std::string& schema,
+                                                 const std::string& host,
+                                                 int port) {
+  base::DictionaryValue* dict = new base::DictionaryValue;
   dict->SetString(keys::kProxyConfigRuleScheme, schema);
   dict->SetString(keys::kProxyConfigRuleHost, host);
   dict->SetInteger(keys::kProxyConfigRulePort, port);
@@ -69,7 +69,7 @@
 }
 
 TEST(ExtensionProxyApiHelpers, GetProxyModeFromExtensionPref) {
-  DictionaryValue proxy_config;
+  base::DictionaryValue proxy_config;
   ProxyPrefs::ProxyMode mode;
   std::string error;
   bool bad_message = false;
@@ -99,7 +99,7 @@
   std::string error;
   bool bad_message = false;
 
-  DictionaryValue proxy_config;
+  base::DictionaryValue proxy_config;
   proxy_config.SetString(
       keys::kProxyConfigMode,
       ProxyPrefs::ProxyModeToString(ProxyPrefs::MODE_PAC_SCRIPT));
@@ -113,7 +113,7 @@
   EXPECT_FALSE(bad_message);
 
   // Set up a pac script.
-  DictionaryValue* pacScriptDict = new DictionaryValue;
+  base::DictionaryValue* pacScriptDict = new base::DictionaryValue;
   pacScriptDict->SetString(keys::kProxyConfigPacScriptUrl, kSamplePacScriptUrl);
   proxy_config.Set(keys::kProxyConfigPacScript, pacScriptDict);
 
@@ -129,7 +129,7 @@
   std::string error;
   bool bad_message = false;
 
-  DictionaryValue proxy_config;
+  base::DictionaryValue proxy_config;
   proxy_config.SetString(
       keys::kProxyConfigMode,
       ProxyPrefs::ProxyModeToString(ProxyPrefs::MODE_PAC_SCRIPT));
@@ -142,7 +142,7 @@
   EXPECT_FALSE(bad_message);
 
   // Set up a PAC script.
-  DictionaryValue* pacScriptDict = new DictionaryValue;
+  base::DictionaryValue* pacScriptDict = new base::DictionaryValue;
   pacScriptDict->SetString(keys::kProxyConfigPacScriptData, kSamplePacScript);
   proxy_config.Set(keys::kProxyConfigPacScript, pacScriptDict);
 
@@ -158,7 +158,7 @@
   std::string error;
   bool bad_message = false;
 
-  DictionaryValue proxy_config;
+  base::DictionaryValue proxy_config;
   proxy_config.SetString(
       keys::kProxyConfigMode,
       ProxyPrefs::ProxyModeToString(ProxyPrefs::MODE_FIXED_SERVERS));
@@ -171,7 +171,7 @@
   EXPECT_EQ(std::string(), out);
   EXPECT_EQ(std::string(), error);
 
-  DictionaryValue* proxy_rules = new DictionaryValue;
+  base::DictionaryValue* proxy_rules = new base::DictionaryValue;
   proxy_rules->Set(keys::field_name[1], CreateTestProxyServerDict("proxy1"));
   proxy_rules->Set(keys::field_name[2], CreateTestProxyServerDict("proxy2"));
   proxy_config.Set(keys::kProxyConfigRules, proxy_rules);
@@ -189,7 +189,7 @@
   std::string error;
   bool bad_message = false;
 
-  DictionaryValue proxy_config;
+  base::DictionaryValue proxy_config;
   proxy_config.SetString(
       keys::kProxyConfigMode,
       ProxyPrefs::ProxyModeToString(ProxyPrefs::MODE_FIXED_SERVERS));
@@ -203,10 +203,10 @@
   EXPECT_EQ(std::string(), error);
   EXPECT_FALSE(bad_message);
 
-  ListValue* bypass_list = new ListValue;
+  base::ListValue* bypass_list = new base::ListValue;
   bypass_list->Append(Value::CreateStringValue("host1"));
   bypass_list->Append(Value::CreateStringValue("host2"));
-  DictionaryValue* proxy_rules = new DictionaryValue;
+  base::DictionaryValue* proxy_rules = new base::DictionaryValue;
   proxy_rules->Set(keys::kProxyConfigBypassList, bypass_list);
   proxy_config.Set(keys::kProxyConfigRules, proxy_rules);
 
@@ -220,8 +220,9 @@
 
 TEST(ExtensionProxyApiHelpers, CreateProxyConfigDict) {
   std::string error;
-  scoped_ptr<DictionaryValue> exp_direct(ProxyConfigDictionary::CreateDirect());
-  scoped_ptr<DictionaryValue> out_direct(
+  scoped_ptr<base::DictionaryValue> exp_direct(
+      ProxyConfigDictionary::CreateDirect());
+  scoped_ptr<base::DictionaryValue> out_direct(
       CreateProxyConfigDict(ProxyPrefs::MODE_DIRECT,
                             false,
                             std::string(),
@@ -231,9 +232,9 @@
                             &error));
   EXPECT_TRUE(Value::Equals(exp_direct.get(), out_direct.get()));
 
-  scoped_ptr<DictionaryValue> exp_auto(
+  scoped_ptr<base::DictionaryValue> exp_auto(
       ProxyConfigDictionary::CreateAutoDetect());
-  scoped_ptr<DictionaryValue> out_auto(
+  scoped_ptr<base::DictionaryValue> out_auto(
       CreateProxyConfigDict(ProxyPrefs::MODE_AUTO_DETECT,
                             false,
                             std::string(),
@@ -243,9 +244,9 @@
                             &error));
   EXPECT_TRUE(Value::Equals(exp_auto.get(), out_auto.get()));
 
-  scoped_ptr<DictionaryValue> exp_pac_url(
+  scoped_ptr<base::DictionaryValue> exp_pac_url(
       ProxyConfigDictionary::CreatePacScript(kSamplePacScriptUrl, false));
-  scoped_ptr<DictionaryValue> out_pac_url(
+  scoped_ptr<base::DictionaryValue> out_pac_url(
       CreateProxyConfigDict(ProxyPrefs::MODE_PAC_SCRIPT,
                             false,
                             kSamplePacScriptUrl,
@@ -255,9 +256,9 @@
                             &error));
   EXPECT_TRUE(Value::Equals(exp_pac_url.get(), out_pac_url.get()));
 
-  scoped_ptr<DictionaryValue> exp_pac_data(
+  scoped_ptr<base::DictionaryValue> exp_pac_data(
       ProxyConfigDictionary::CreatePacScript(kSamplePacScriptAsDataUrl, false));
-  scoped_ptr<DictionaryValue> out_pac_data(
+  scoped_ptr<base::DictionaryValue> out_pac_data(
       CreateProxyConfigDict(ProxyPrefs::MODE_PAC_SCRIPT,
                             false,
                             std::string(),
@@ -267,9 +268,9 @@
                             &error));
   EXPECT_TRUE(Value::Equals(exp_pac_data.get(), out_pac_data.get()));
 
-  scoped_ptr<DictionaryValue> exp_fixed(
+  scoped_ptr<base::DictionaryValue> exp_fixed(
       ProxyConfigDictionary::CreateFixedServers("foo:80", "localhost"));
-  scoped_ptr<DictionaryValue> out_fixed(
+  scoped_ptr<base::DictionaryValue> out_fixed(
       CreateProxyConfigDict(ProxyPrefs::MODE_FIXED_SERVERS,
                             false,
                             std::string(),
@@ -279,8 +280,9 @@
                             &error));
   EXPECT_TRUE(Value::Equals(exp_fixed.get(), out_fixed.get()));
 
-  scoped_ptr<DictionaryValue> exp_system(ProxyConfigDictionary::CreateSystem());
-  scoped_ptr<DictionaryValue> out_system(
+  scoped_ptr<base::DictionaryValue> exp_system(
+      ProxyConfigDictionary::CreateSystem());
+  scoped_ptr<base::DictionaryValue> out_system(
       CreateProxyConfigDict(ProxyPrefs::MODE_SYSTEM,
                             false,
                             std::string(),
@@ -295,7 +297,7 @@
 }
 
 TEST(ExtensionProxyApiHelpers, GetProxyServer) {
-  DictionaryValue proxy_server_dict;
+  base::DictionaryValue proxy_server_dict;
   net::ProxyServer created;
   std::string error;
   bool bad_message = false;
@@ -320,7 +322,7 @@
 
 TEST(ExtensionProxyApiHelpers, JoinUrlList) {
   bool bad_message = false;
-  ListValue list;
+  base::ListValue list;
   list.Append(Value::CreateStringValue("s1"));
   list.Append(Value::CreateStringValue("s2"));
   list.Append(Value::CreateStringValue("s3"));
@@ -334,15 +336,16 @@
 
 // This tests CreateProxyServerDict as well.
 TEST(ExtensionProxyApiHelpers, CreateProxyRulesDict) {
-  scoped_ptr<DictionaryValue> browser_pref(
+  scoped_ptr<base::DictionaryValue> browser_pref(
       ProxyConfigDictionary::CreateFixedServers(
           "http=proxy1:80;https=proxy2:80;ftp=proxy3:80;socks=proxy4:80",
           "localhost"));
   ProxyConfigDictionary config(browser_pref.get());
-  scoped_ptr<DictionaryValue> extension_pref(CreateProxyRulesDict(config));
+  scoped_ptr<base::DictionaryValue> extension_pref(
+      CreateProxyRulesDict(config));
   ASSERT_TRUE(extension_pref.get());
 
-  scoped_ptr<DictionaryValue> expected(new DictionaryValue);
+  scoped_ptr<base::DictionaryValue> expected(new base::DictionaryValue);
   expected->Set("proxyForHttp",
                 CreateTestProxyServerDict("http", "proxy1", 80));
   expected->Set("proxyForHttps",
@@ -351,7 +354,7 @@
                 CreateTestProxyServerDict("http", "proxy3", 80));
   expected->Set("fallbackProxy",
                 CreateTestProxyServerDict("socks4", "proxy4", 80));
-  ListValue* bypass_list = new ListValue;
+  base::ListValue* bypass_list = new base::ListValue;
   bypass_list->Append(Value::CreateStringValue("localhost"));
   expected->Set(keys::kProxyConfigBypassList, bypass_list);
 
@@ -360,16 +363,17 @@
 
 // Test multiple proxies per scheme -- expect that only the first is returned.
 TEST(ExtensionProxyApiHelpers, CreateProxyRulesDictMultipleProxies) {
-  scoped_ptr<DictionaryValue> browser_pref(
+  scoped_ptr<base::DictionaryValue> browser_pref(
       ProxyConfigDictionary::CreateFixedServers(
           "http=proxy1:80,default://;https=proxy2:80,proxy1:80;ftp=proxy3:80,"
           "https://proxy5:443;socks=proxy4:80,proxy1:80",
           "localhost"));
   ProxyConfigDictionary config(browser_pref.get());
-  scoped_ptr<DictionaryValue> extension_pref(CreateProxyRulesDict(config));
+  scoped_ptr<base::DictionaryValue> extension_pref(
+      CreateProxyRulesDict(config));
   ASSERT_TRUE(extension_pref.get());
 
-  scoped_ptr<DictionaryValue> expected(new DictionaryValue);
+  scoped_ptr<base::DictionaryValue> expected(new base::DictionaryValue);
   expected->Set("proxyForHttp",
                 CreateTestProxyServerDict("http", "proxy1", 80));
   expected->Set("proxyForHttps",
@@ -378,7 +382,7 @@
                 CreateTestProxyServerDict("http", "proxy3", 80));
   expected->Set("fallbackProxy",
                 CreateTestProxyServerDict("socks4", "proxy4", 80));
-  ListValue* bypass_list = new ListValue;
+  base::ListValue* bypass_list = new base::ListValue;
   bypass_list->Append(Value::CreateStringValue("localhost"));
   expected->Set(keys::kProxyConfigBypassList, bypass_list);
 
@@ -387,13 +391,13 @@
 
 // Test if a PAC script URL is specified.
 TEST(ExtensionProxyApiHelpers, CreatePacScriptDictWithUrl) {
-  scoped_ptr<DictionaryValue> browser_pref(
+  scoped_ptr<base::DictionaryValue> browser_pref(
       ProxyConfigDictionary::CreatePacScript(kSamplePacScriptUrl, false));
   ProxyConfigDictionary config(browser_pref.get());
-  scoped_ptr<DictionaryValue> extension_pref(CreatePacScriptDict(config));
+  scoped_ptr<base::DictionaryValue> extension_pref(CreatePacScriptDict(config));
   ASSERT_TRUE(extension_pref.get());
 
-  scoped_ptr<DictionaryValue> expected(new DictionaryValue);
+  scoped_ptr<base::DictionaryValue> expected(new base::DictionaryValue);
   expected->SetString(keys::kProxyConfigPacScriptUrl, kSamplePacScriptUrl);
   expected->SetBoolean(keys::kProxyConfigPacScriptMandatory, false);
 
@@ -402,13 +406,13 @@
 
 // Test if a PAC script is encoded in a data URL.
 TEST(ExtensionProxyApiHelpers, CreatePacScriptDictWidthData) {
-  scoped_ptr<DictionaryValue> browser_pref(
+  scoped_ptr<base::DictionaryValue> browser_pref(
       ProxyConfigDictionary::CreatePacScript(kSamplePacScriptAsDataUrl, false));
   ProxyConfigDictionary config(browser_pref.get());
-  scoped_ptr<DictionaryValue> extension_pref(CreatePacScriptDict(config));
+  scoped_ptr<base::DictionaryValue> extension_pref(CreatePacScriptDict(config));
   ASSERT_TRUE(extension_pref.get());
 
-  scoped_ptr<DictionaryValue> expected(new DictionaryValue);
+  scoped_ptr<base::DictionaryValue> expected(new base::DictionaryValue);
   expected->SetString(keys::kProxyConfigPacScriptData, kSamplePacScript);
   expected->SetBoolean(keys::kProxyConfigPacScriptMandatory, false);
 
@@ -416,12 +420,12 @@
 }
 
 TEST(ExtensionProxyApiHelpers, TokenizeToStringList) {
-  ListValue expected;
+  base::ListValue expected;
   expected.Append(Value::CreateStringValue("s1"));
   expected.Append(Value::CreateStringValue("s2"));
   expected.Append(Value::CreateStringValue("s3"));
 
-  scoped_ptr<ListValue> out(TokenizeToStringList("s1;s2;s3", ";"));
+  scoped_ptr<base::ListValue> out(TokenizeToStringList("s1;s2;s3", ";"));
   EXPECT_TRUE(Value::Equals(&expected, out.get()));
 }
 
diff --git a/chrome/browser/extensions/api/proxy/proxy_apitest.cc b/chrome/browser/extensions/api/proxy/proxy_apitest.cc
index be76c40..a05e71a 100644
--- a/chrome/browser/extensions/api/proxy/proxy_apitest.cc
+++ b/chrome/browser/extensions/api/proxy/proxy_apitest.cc
@@ -283,7 +283,7 @@
 
 // Tests error events: invalid proxy
 IN_PROC_BROWSER_TEST_F(ProxySettingsApiTest, MAYBE_ProxyEventsInvalidProxy) {
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
   ASSERT_TRUE(
       RunExtensionSubtest("proxy/events", "invalid_proxy.html")) << message_;
 }
diff --git a/chrome/browser/extensions/api/push_messaging/obfuscated_gaia_id_fetcher.cc b/chrome/browser/extensions/api/push_messaging/obfuscated_gaia_id_fetcher.cc
index 3dc1267..6063b1f 100644
--- a/chrome/browser/extensions/api/push_messaging/obfuscated_gaia_id_fetcher.cc
+++ b/chrome/browser/extensions/api/push_messaging/obfuscated_gaia_id_fetcher.cc
@@ -127,7 +127,7 @@
   if (!value.get())
     return false;
 
-  DictionaryValue* dict = NULL;
+  base::DictionaryValue* dict = NULL;
   if (!value->GetAsDictionary(&dict))
     return false;
 
diff --git a/chrome/browser/extensions/api/push_messaging/push_messaging_api.cc b/chrome/browser/extensions/api/push_messaging/push_messaging_api.cc
index c84a393..9d89f17 100644
--- a/chrome/browser/extensions/api/push_messaging/push_messaging_api.cc
+++ b/chrome/browser/extensions/api/push_messaging/push_messaging_api.cc
@@ -19,11 +19,11 @@
 #include "chrome/browser/extensions/extension_system_factory.h"
 #include "chrome/browser/extensions/token_cache/token_cache_service.h"
 #include "chrome/browser/extensions/token_cache/token_cache_service_factory.h"
+#include "chrome/browser/invalidation/invalidation_service.h"
+#include "chrome/browser/invalidation/invalidation_service_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/signin/token_service.h"
 #include "chrome/browser/signin/token_service_factory.h"
-#include "chrome/browser/sync/profile_sync_service.h"
-#include "chrome/browser/sync/profile_sync_service_factory.h"
 #include "chrome/browser/ui/webui/signin/login_ui_service_factory.h"
 #include "chrome/common/chrome_notification_types.h"
 #include "chrome/common/extensions/api/push_messaging.h"
@@ -302,17 +302,18 @@
 void PushMessagingAPI::Observe(int type,
                                const content::NotificationSource& source,
                                const content::NotificationDetails& details) {
-  ProfileSyncService* pss = ProfileSyncServiceFactory::GetForProfile(profile_);
+  invalidation::InvalidationService* invalidation_service =
+      invalidation::InvalidationServiceFactory::GetForProfile(profile_);
   // This may be NULL; for example, for the ChromeOS guest user. In these cases,
   // just return without setting up anything, since it won't work anyway.
-  if (!pss)
+  if (!invalidation_service)
     return;
 
   if (!event_router_)
     event_router_.reset(new PushMessagingEventRouter(profile_));
   if (!handler_) {
     handler_.reset(new PushMessagingInvalidationHandler(
-        pss, event_router_.get()));
+        invalidation_service, event_router_.get()));
   }
   switch (type) {
     case chrome::NOTIFICATION_EXTENSION_INSTALLED: {
@@ -351,7 +352,7 @@
 template <>
 void ProfileKeyedAPIFactory<PushMessagingAPI>::DeclareFactoryDependencies() {
   DependsOn(ExtensionSystemFactory::GetInstance());
-  DependsOn(ProfileSyncServiceFactory::GetInstance());
+  DependsOn(invalidation::InvalidationServiceFactory::GetInstance());
 }
 
 }  // 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 6960205..6a38470 100644
--- a/chrome/browser/extensions/api/push_messaging/push_messaging_apitest.cc
+++ b/chrome/browser/extensions/api/push_messaging/push_messaging_apitest.cc
@@ -10,19 +10,23 @@
 #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"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/sync/profile_sync_service.h"
-#include "chrome/browser/sync/profile_sync_service_factory.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "google/cacheinvalidation/types.pb.h"
+#include "sync/notifier/fake_invalidator.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
 using ::testing::_;
 using ::testing::SaveArg;
 using ::testing::StrictMock;
 
+using invalidation::InvalidationServiceFactory;
+
 namespace extensions {
 
 namespace {
@@ -52,10 +56,34 @@
 
 class PushMessagingApiTest : public ExtensionApiTest {
  public:
+  PushMessagingApiTest()
+      : fake_invalidation_service_(NULL) {
+  }
+
   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
     ExtensionApiTest::SetUpCommandLine(command_line);
   }
 
+  virtual void SetUp() OVERRIDE {
+    InvalidationServiceFactory::GetInstance()->
+        SetBuildOnlyFakeInvalidatorsForTest(true);
+    ExtensionApiTest::SetUp();
+  }
+
+  virtual void SetUpOnMainThread() OVERRIDE {
+    ExtensionApiTest::SetUpOnMainThread();
+    fake_invalidation_service_ =
+        static_cast<invalidation::FakeInvalidationService*>(
+            InvalidationServiceFactory::GetInstance()->GetForProfile(
+                profile()));
+  }
+
+  void EmitInvalidation(
+      const invalidation::ObjectId& object_id,
+      const std::string& payload) {
+    fake_invalidation_service_->EmitInvalidationForTest(object_id, payload);
+  }
+
   PushMessagingAPI* GetAPI() {
     return PushMessagingAPI::Get(profile());
   }
@@ -63,6 +91,8 @@
   PushMessagingEventRouter* GetEventRouter() {
     return PushMessagingAPI::Get(profile())->GetEventRouterForTest();
   }
+
+  invalidation::FakeInvalidationService* fake_invalidation_service_;
 };
 
 IN_PROC_BROWSER_TEST_F(PushMessagingApiTest, EventDispatch) {
@@ -92,18 +122,14 @@
   ui_test_utils::NavigateToURL(
       browser(), extension->GetResourceURL("event_dispatch.html"));
 
-  ProfileSyncService* pss =
-      ProfileSyncServiceFactory::GetForProfile(profile());
-  ASSERT_TRUE(pss);
-
   // PushMessagingInvalidationHandler suppresses the initial invalidation on
   // each subchannel at install, so trigger the suppressions first.
   for (int i = 0; i < 3; ++i) {
-    pss->EmitInvalidationForTest(
+    EmitInvalidation(
         ExtensionAndSubchannelToObjectId(extension->id(), i), std::string());
   }
 
-  pss->EmitInvalidationForTest(
+  EmitInvalidation(
       ExtensionAndSubchannelToObjectId(extension->id(), 1), "payload");
   EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
 }
diff --git a/chrome/browser/extensions/api/push_messaging/push_messaging_invalidation_handler.cc b/chrome/browser/extensions/api/push_messaging/push_messaging_invalidation_handler.cc
index 95eb4e7..f9208e5 100644
--- a/chrome/browser/extensions/api/push_messaging/push_messaging_invalidation_handler.cc
+++ b/chrome/browser/extensions/api/push_messaging/push_messaging_invalidation_handler.cc
@@ -10,7 +10,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
 #include "chrome/browser/extensions/api/push_messaging/push_messaging_invalidation_handler_delegate.h"
-#include "chrome/browser/invalidation/invalidation_frontend.h"
+#include "chrome/browser/invalidation/invalidation_service.h"
 #include "chrome/common/extensions/extension.h"
 #include "google/cacheinvalidation/types.pb.h"
 
@@ -78,7 +78,7 @@
 }  // namespace
 
 PushMessagingInvalidationHandler::PushMessagingInvalidationHandler(
-    invalidation::InvalidationFrontend* service,
+    invalidation::InvalidationService* service,
     PushMessagingInvalidationHandlerDelegate* delegate)
     : service_(service),
       delegate_(delegate) {
diff --git a/chrome/browser/extensions/api/push_messaging/push_messaging_invalidation_handler.h b/chrome/browser/extensions/api/push_messaging/push_messaging_invalidation_handler.h
index ef40b76..4f7d9e3 100644
--- a/chrome/browser/extensions/api/push_messaging/push_messaging_invalidation_handler.h
+++ b/chrome/browser/extensions/api/push_messaging/push_messaging_invalidation_handler.h
@@ -15,7 +15,7 @@
 #include "sync/notifier/invalidation_handler.h"
 
 namespace invalidation {
-class InvalidationFrontend;
+class InvalidationService;
 }
 
 namespace extensions {
@@ -32,7 +32,7 @@
   // |extension_ids| is the set of extension IDs for which push messaging is
   // enabled.
   PushMessagingInvalidationHandler(
-      invalidation::InvalidationFrontend* service,
+      invalidation::InvalidationService* service,
       PushMessagingInvalidationHandlerDelegate* delegate);
   virtual ~PushMessagingInvalidationHandler();
 
@@ -56,7 +56,7 @@
   void UpdateRegistrations();
 
   base::ThreadChecker thread_checker_;
-  invalidation::InvalidationFrontend* const service_;
+  invalidation::InvalidationService* const service_;
   std::set<std::string> registered_extensions_;
   syncer::ObjectIdSet suppressed_ids_;
   PushMessagingInvalidationHandlerDelegate* const delegate_;
diff --git a/chrome/browser/extensions/api/push_messaging/push_messaging_invalidation_handler_unittest.cc b/chrome/browser/extensions/api/push_messaging/push_messaging_invalidation_handler_unittest.cc
index 9ab280b..9db3b46 100644
--- a/chrome/browser/extensions/api/push_messaging/push_messaging_invalidation_handler_unittest.cc
+++ b/chrome/browser/extensions/api/push_messaging/push_messaging_invalidation_handler_unittest.cc
@@ -7,7 +7,7 @@
 #include "base/basictypes.h"
 #include "base/memory/scoped_ptr.h"
 #include "chrome/browser/extensions/api/push_messaging/push_messaging_invalidation_handler_delegate.h"
-#include "chrome/browser/invalidation/invalidation_frontend.h"
+#include "chrome/browser/invalidation/invalidation_service.h"
 #include "google/cacheinvalidation/types.pb.h"
 #include "sync/internal_api/public/base/invalidation_test_util.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -22,10 +22,10 @@
 
 namespace {
 
-class MockInvalidationFrontend : public invalidation::InvalidationFrontend {
+class MockInvalidationService : public invalidation::InvalidationService {
  public:
-  MockInvalidationFrontend();
-  ~MockInvalidationFrontend();
+  MockInvalidationService();
+  ~MockInvalidationService();
   MOCK_METHOD1(RegisterInvalidationHandler,
                void(syncer::InvalidationHandler*));
   MOCK_METHOD2(UpdateRegisteredInvalidationIds,
@@ -35,13 +35,14 @@
   MOCK_METHOD2(AcknowledgeInvalidation, void(const invalidation::ObjectId&,
                                              const syncer::AckHandle&));
   MOCK_CONST_METHOD0(GetInvalidatorState, syncer::InvalidatorState());
+  MOCK_CONST_METHOD0(GetInvalidatorClientId, std::string());
 
  private:
-  DISALLOW_COPY_AND_ASSIGN(MockInvalidationFrontend);
+  DISALLOW_COPY_AND_ASSIGN(MockInvalidationService);
 };
 
-MockInvalidationFrontend::MockInvalidationFrontend() {}
-MockInvalidationFrontend::~MockInvalidationFrontend() {}
+MockInvalidationService::MockInvalidationService() {}
+MockInvalidationService::~MockInvalidationService() {}
 
 class MockInvalidationHandlerDelegate
     : public PushMessagingInvalidationHandlerDelegate {
@@ -74,7 +75,7 @@
     EXPECT_CALL(service_, UnregisterInvalidationHandler(handler_.get()));
     handler_.reset();
   }
-  StrictMock<MockInvalidationFrontend> service_;
+  StrictMock<MockInvalidationService> service_;
   StrictMock<MockInvalidationHandlerDelegate> delegate_;
   scoped_ptr<PushMessagingInvalidationHandler> handler_;
 };
diff --git a/chrome/browser/extensions/api/push_messaging/sync_setup_helper.cc b/chrome/browser/extensions/api/push_messaging/sync_setup_helper.cc
index b0292d9..f4dffc3 100644
--- a/chrome/browser/extensions/api/push_messaging/sync_setup_helper.cc
+++ b/chrome/browser/extensions/api/push_messaging/sync_setup_helper.cc
@@ -29,7 +29,8 @@
 
 bool SyncSetupHelper::InitializeSync(Profile* profile) {
   profile_ = profile;
-  client_.reset(new ProfileSyncServiceHarness(profile_, username_, password_));
+  client_.reset(
+      ProfileSyncServiceHarness::Create(profile_, username_, password_));
 
   if (client_->service()->IsSyncEnabledAndLoggedIn())
     return true;
diff --git a/chrome/browser/extensions/api/record/record_api.h b/chrome/browser/extensions/api/record/record_api.h
index e5c6189..d0ea960 100644
--- a/chrome/browser/extensions/api/record/record_api.h
+++ b/chrome/browser/extensions/api/record/record_api.h
@@ -7,7 +7,7 @@
 
 #include "base/command_line.h"
 #include "base/files/file_path.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/extensions/extension_function.h"
 
 namespace {
diff --git a/chrome/browser/extensions/api/record/record_api_test.cc b/chrome/browser/extensions/api/record/record_api_test.cc
index c276ba3..4548501 100644
--- a/chrome/browser/extensions/api/record/record_api_test.cc
+++ b/chrome/browser/extensions/api/record/record_api_test.cc
@@ -188,7 +188,7 @@
     InProcessBrowserTest::CleanUpOnMainThread();
     for (std::vector<base::FilePath>::const_iterator it = temp_files_.begin();
         it != temp_files_.end(); ++it) {
-      if (!file_util::Delete(*it, false))
+      if (!base::Delete(*it, false))
         NOTREACHED();
     }
   }
@@ -241,7 +241,7 @@
 
   // Verify that the URL list of good and bad URLs was properly handled.
   // Needed by several tests.
-  bool VerifyURLHandling(const ListValue* result,
+  bool VerifyURLHandling(const base::ListValue* result,
       const TestProcessStrategy& strategy) {
 
     // Check that the two bad URLs are returned.
@@ -345,7 +345,7 @@
    // Check for return value with proper stats.
   EXPECT_EQ(kTestStatistics, utils::GetString(result.get(), kStatsKey));
 
-  ListValue* errors = NULL;
+  base::ListValue* errors = NULL;
   EXPECT_TRUE(result->GetList(kErrorsKey, &errors));
   EXPECT_TRUE(VerifyURLHandling(errors, strategy));
 }
diff --git a/chrome/browser/extensions/api/rtc_private/rtc_private_api.cc b/chrome/browser/extensions/api/rtc_private/rtc_private_api.cc
index 6018a81..5a0a120 100644
--- a/chrome/browser/extensions/api/rtc_private/rtc_private_api.cc
+++ b/chrome/browser/extensions/api/rtc_private/rtc_private_api.cc
@@ -8,7 +8,7 @@
 #include "base/message_loop.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "base/value_conversions.h"
 #include "base/values.h"
 #include "chrome/browser/chromeos/contacts/contact.pb.h"
diff --git a/chrome/browser/extensions/api/runtime/runtime_api.cc b/chrome/browser/extensions/api/runtime/runtime_api.cc
index d00ab43..c04d181 100644
--- a/chrome/browser/extensions/api/runtime/runtime_api.cc
+++ b/chrome/browser/extensions/api/runtime/runtime_api.cc
@@ -4,7 +4,11 @@
 
 #include "chrome/browser/extensions/api/runtime/runtime_api.h"
 
+#include <utility>
+
+#include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/values.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/extensions/event_router.h"
 #include "chrome/browser/extensions/extension_host.h"
@@ -19,7 +23,6 @@
 #include "chrome/browser/ui/browser_navigator.h"
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/common/chrome_notification_types.h"
-#include "chrome/common/extensions/api/runtime.h"
 #include "chrome/common/extensions/background_info.h"
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/omaha_query_params/omaha_query_params.h"
@@ -42,6 +45,7 @@
 const char kOnUpdateAvailableEvent[] = "runtime.onUpdateAvailable";
 const char kOnBrowserUpdateAvailableEvent[] =
     "runtime.onBrowserUpdateAvailable";
+const char kOnRestartRequiredEvent[] = "runtime.onRestartRequired";
 const char kNoBackgroundPageError[] = "You do not have a background page.";
 const char kPageLoadError[] = "Background page failed to load.";
 const char kInstallReason[] = "reason";
@@ -100,7 +104,7 @@
     return;
   }
 
-  scoped_ptr<base::ListValue> event_args(new ListValue());
+  scoped_ptr<base::ListValue> event_args(new base::ListValue());
   scoped_ptr<Event> event(new Event(kOnStartupEvent, event_args.Pass()));
   system->event_router()->DispatchEventToExtension(extension_id, event.Pass());
 }
@@ -143,7 +147,7 @@
   // chance to register for events. So we register on its behalf. If the
   // extension does not actually have a listener, the event will just be
   // ignored.
-  scoped_ptr<base::ListValue> event_args(new ListValue());
+  scoped_ptr<base::ListValue> event_args(new base::ListValue());
   base::DictionaryValue* info = new base::DictionaryValue();
   event_args->Append(info);
   if (old_version.IsValid()) {
@@ -166,12 +170,12 @@
 void RuntimeEventRouter::DispatchOnUpdateAvailableEvent(
     Profile* profile,
     const std::string& extension_id,
-    const DictionaryValue* manifest) {
+    const base::DictionaryValue* manifest) {
   ExtensionSystem* system = ExtensionSystem::Get(profile);
   if (!system)
     return;
 
-  scoped_ptr<ListValue> args(new ListValue);
+  scoped_ptr<base::ListValue> args(new base::ListValue);
   args->Append(manifest->DeepCopy());
   DCHECK(system->event_router());
   scoped_ptr<Event> event(new Event(kOnUpdateAvailableEvent, args.Pass()));
@@ -185,7 +189,7 @@
   if (!system)
     return;
 
-  scoped_ptr<ListValue> args(new ListValue);
+  scoped_ptr<base::ListValue> args(new base::ListValue);
   DCHECK(system->event_router());
   scoped_ptr<Event> event(new Event(kOnBrowserUpdateAvailableEvent,
                                     args.Pass()));
@@ -193,8 +197,25 @@
 }
 
 // static
+void RuntimeEventRouter::DispatchOnRestartRequiredEvent(
+    Profile* profile,
+    const std::string& app_id,
+    api::runtime::OnRestartRequired::Reason reason) {
+  ExtensionSystem* system = ExtensionSystem::Get(profile);
+  if (!system)
+    return;
+
+  scoped_ptr<Event> event(
+      new Event(kOnRestartRequiredEvent,
+                api::runtime::OnRestartRequired::Create(reason)));
+
+  DCHECK(system->event_router());
+  system->event_router()->DispatchEventToExtension(app_id, event.Pass());
+}
+
+// static
 void RuntimeEventRouter::OnExtensionUninstalled(
-    Profile *profile,
+    Profile* profile,
     const std::string& extension_id) {
 #if defined(ENABLE_EXTENSIONS)
   GURL uninstall_url(GetUninstallUrl(ExtensionPrefs::Get(profile),
@@ -409,7 +430,7 @@
   if (!policy->CanReadFile(renderer_id, path))
     policy->GrantReadFile(renderer_id, path);
 
-  DictionaryValue* dict = new DictionaryValue();
+  base::DictionaryValue* dict = new base::DictionaryValue();
   SetResult(dict);
   dict->SetString("fileSystemId", filesystem_id);
   dict->SetString("baseName", relative_path);
diff --git a/chrome/browser/extensions/api/runtime/runtime_api.h b/chrome/browser/extensions/api/runtime/runtime_api.h
index c21255e..d936945 100644
--- a/chrome/browser/extensions/api/runtime/runtime_api.h
+++ b/chrome/browser/extensions/api/runtime/runtime_api.h
@@ -5,7 +5,10 @@
 #ifndef CHROME_BROWSER_EXTENSIONS_API_RUNTIME_RUNTIME_API_H_
 #define CHROME_BROWSER_EXTENSIONS_API_RUNTIME_RUNTIME_API_H_
 
+#include <string>
+
 #include "chrome/browser/extensions/extension_function.h"
+#include "chrome/common/extensions/api/runtime.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
 
@@ -40,6 +43,12 @@
   // Dispatches the onBrowserUpdateAvailable event to all extensions.
   static void DispatchOnBrowserUpdateAvailableEvent(Profile* profile);
 
+  // Dispatches the onRestartRequired event to the given app.
+  static void DispatchOnRestartRequiredEvent(
+      Profile* profile,
+      const std::string& app_id,
+      api::runtime::OnRestartRequired::Reason reason);
+
   // Does any work needed at extension uninstall (e.g. load uninstall url).
   static void OnExtensionUninstalled(Profile* profile,
                                      const std::string& extension_id);
diff --git a/chrome/browser/extensions/api/runtime/runtime_apitest.cc b/chrome/browser/extensions/api/runtime/runtime_apitest.cc
index 55f0d2a..c2c17be 100644
--- a/chrome/browser/extensions/api/runtime/runtime_apitest.cc
+++ b/chrome/browser/extensions/api/runtime/runtime_apitest.cc
@@ -6,6 +6,7 @@
 #include "chrome/browser/extensions/extension_apitest.h"
 #include "chrome/browser/extensions/extension_function_test_utils.h"
 #include "chrome/test/base/ui_test_utils.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
 
 // Tests the privileged components of chrome.runtime.
 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ChromeRuntimePrivileged) {
@@ -14,14 +15,14 @@
 
 // Tests the unprivileged components of chrome.runtime.
 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ChromeRuntimeUnprivileged) {
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
   ASSERT_TRUE(
       LoadExtension(test_data_dir_.AppendASCII("runtime/content_script")));
 
   // The content script runs on webpage.html.
   ResultCatcher catcher;
   ui_test_utils::NavigateToURL(browser(),
-                               test_server()->GetURL("webpage.html"));
+                               embedded_test_server()->GetURL("/webpage.html"));
   EXPECT_TRUE(catcher.GetNextResult()) << message_;
 }
 
diff --git a/chrome/browser/extensions/api/serial/serial_api.cc b/chrome/browser/extensions/api/serial/serial_api.cc
index 1a36453..b0e7925 100644
--- a/chrome/browser/extensions/api/serial/serial_api.cc
+++ b/chrome/browser/extensions/api/serial/serial_api.cc
@@ -60,7 +60,7 @@
 void SerialGetPortsFunction::Work() {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
 
-  ListValue* ports = new ListValue();
+  base::ListValue* ports = new base::ListValue();
   SerialPortEnumerator::StringSet port_names =
       SerialPortEnumerator::GenerateValidSerialPortNames();
   SerialPortEnumerator::StringSet::const_iterator i = port_names.begin();
@@ -96,7 +96,7 @@
   EXTENSION_FUNCTION_VALIDATE(params_.get());
 
   if (params_->options.get()) {
-    scoped_ptr<DictionaryValue> options = params_->options->ToValue();
+    scoped_ptr<base::DictionaryValue> options = params_->options->ToValue();
     if (options->HasKey(kBitrateKey))
       EXTENSION_FUNCTION_VALIDATE(options->GetInteger(kBitrateKey, &bitrate_));
   }
@@ -128,12 +128,12 @@
       id = -1;
     }
 
-    DictionaryValue* result = new DictionaryValue();
+    base::DictionaryValue* result = new base::DictionaryValue();
     result->SetInteger(kConnectionIdKey, id);
     SetResult(result);
     AsyncWorkCompleted();
   } else {
-    DictionaryValue* result = new DictionaryValue();
+    base::DictionaryValue* result = new base::DictionaryValue();
     result->SetInteger(kConnectionIdKey, -1);
     SetResult(result);
     AsyncWorkCompleted();
@@ -218,7 +218,7 @@
   if (serial_connection)
     bytes_read = serial_connection->Read(io_buffer);
 
-  DictionaryValue* result = new DictionaryValue();
+  base::DictionaryValue* result = new base::DictionaryValue();
 
   // The API is defined to require a 'data' value, so we will always
   // create a BinaryValue, even if it's zero-length.
@@ -262,7 +262,7 @@
   else
     error_ = kSerialConnectionNotFoundError;
 
-  DictionaryValue* result = new DictionaryValue();
+  base::DictionaryValue* result = new base::DictionaryValue();
   result->SetInteger(kBytesWrittenKey, bytes_written);
   SetResult(result);
 }
@@ -318,7 +318,7 @@
 }
 
 void SerialGetControlSignalsFunction::Work() {
-  DictionaryValue *result = new DictionaryValue();
+  base::DictionaryValue *result = new base::DictionaryValue();
   SerialConnection* serial_connection = GetSerialConnection(
       params_->connection_id);
   if (serial_connection) {
diff --git a/chrome/browser/extensions/api/serial/serial_apitest.cc b/chrome/browser/extensions/api/serial/serial_apitest.cc
index 9b1d8dd..646dfd1 100644
--- a/chrome/browser/extensions/api/serial/serial_apitest.cc
+++ b/chrome/browser/extensions/api/serial/serial_apitest.cc
@@ -36,7 +36,7 @@
 class FakeSerialGetPortsFunction : public AsyncExtensionFunction {
  public:
   virtual bool RunImpl() OVERRIDE {
-    ListValue* ports = new ListValue();
+    base::ListValue* ports = new base::ListValue();
     ports->Append(Value::CreateStringValue("/dev/fakeserial"));
     ports->Append(Value::CreateStringValue("\\\\COM800\\"));
     SetResult(ports);
diff --git a/chrome/browser/extensions/api/socket/socket_api.cc b/chrome/browser/extensions/api/socket/socket_api.cc
index b21769f..6a43ce7 100644
--- a/chrome/browser/extensions/api/socket/socket_api.cc
+++ b/chrome/browser/extensions/api/socket/socket_api.cc
@@ -151,7 +151,7 @@
   }
   DCHECK(socket);
 
-  DictionaryValue* result = new DictionaryValue();
+  base::DictionaryValue* result = new base::DictionaryValue();
   result->SetInteger(kSocketIdKey, manager_->Add(socket));
   SetResult(result);
 }
@@ -348,7 +348,7 @@
 
 void SocketAcceptFunction::OnAccept(int result_code,
                                     net::TCPClientSocket *socket) {
-  DictionaryValue* result = new DictionaryValue();
+  base::DictionaryValue* result = new base::DictionaryValue();
   result->SetInteger(kResultCodeKey, result_code);
   if (socket) {
     Socket *client_socket = new TCPSocket(socket, extension_id(), true);
@@ -383,7 +383,7 @@
 
 void SocketReadFunction::OnCompleted(int bytes_read,
                                      scoped_refptr<net::IOBuffer> io_buffer) {
-  DictionaryValue* result = new DictionaryValue();
+  base::DictionaryValue* result = new base::DictionaryValue();
   result->SetInteger(kResultCodeKey, bytes_read);
   if (bytes_read > 0) {
     result->Set(kDataKey,
@@ -429,7 +429,7 @@
 }
 
 void SocketWriteFunction::OnCompleted(int bytes_written) {
-  DictionaryValue* result = new DictionaryValue();
+  base::DictionaryValue* result = new base::DictionaryValue();
   result->SetInteger(kBytesWrittenKey, bytes_written);
   SetResult(result);
 
@@ -462,7 +462,7 @@
                                          scoped_refptr<net::IOBuffer> io_buffer,
                                          const std::string& address,
                                          int port) {
-  DictionaryValue* result = new DictionaryValue();
+  base::DictionaryValue* result = new base::DictionaryValue();
   result->SetInteger(kResultCodeKey, bytes_read);
   if (bytes_read > 0) {
     result->Set(kDataKey,
@@ -541,7 +541,7 @@
 }
 
 void SocketSendToFunction::OnCompleted(int bytes_written) {
-  DictionaryValue* result = new DictionaryValue();
+  base::DictionaryValue* result = new base::DictionaryValue();
   result->SetInteger(kBytesWrittenKey, bytes_written);
   SetResult(result);
 
diff --git a/chrome/browser/extensions/api/socket/socket_apitest.cc b/chrome/browser/extensions/api/socket/socket_apitest.cc
index 970c922..0d0f8c8 100644
--- a/chrome/browser/extensions/api/socket/socket_apitest.cc
+++ b/chrome/browser/extensions/api/socket/socket_apitest.cc
@@ -125,7 +125,8 @@
   scoped_ptr<base::Value> result(utils::RunFunctionAndReturnSingleResult(
       socket_create_function.get(), "[\"udp\"]", browser(), utils::NONE));
   ASSERT_EQ(base::Value::TYPE_DICTIONARY, result->GetType());
-  DictionaryValue *value = static_cast<DictionaryValue*>(result.get());
+  base::DictionaryValue *value =
+      static_cast<base::DictionaryValue*>(result.get());
   int socketId = -1;
   EXPECT_TRUE(value->GetInteger("socketId", &socketId));
   EXPECT_TRUE(socketId > 0);
@@ -142,7 +143,8 @@
   scoped_ptr<base::Value> result(utils::RunFunctionAndReturnSingleResult(
       socket_create_function.get(), "[\"tcp\"]", browser(), utils::NONE));
   ASSERT_EQ(base::Value::TYPE_DICTIONARY, result->GetType());
-  DictionaryValue *value = static_cast<DictionaryValue*>(result.get());
+  base::DictionaryValue *value =
+      static_cast<base::DictionaryValue*>(result.get());
   int socketId = -1;
   EXPECT_TRUE(value->GetInteger("socketId", &socketId));
   ASSERT_TRUE(socketId > 0);
@@ -162,7 +164,7 @@
 
   // If we're invoking socket tests, all we can confirm is that we have at
   // least one address, but not what it is.
-  ListValue *value = static_cast<ListValue*>(result.get());
+  base::ListValue *value = static_cast<base::ListValue*>(result.get());
   ASSERT_TRUE(value->GetSize() > 0);
 }
 
diff --git a/chrome/browser/extensions/api/storage/setting_sync_data.cc b/chrome/browser/extensions/api/storage/setting_sync_data.cc
index cb4fe79..42f72f2 100644
--- a/chrome/browser/extensions/api/storage/setting_sync_data.cc
+++ b/chrome/browser/extensions/api/storage/setting_sync_data.cc
@@ -51,7 +51,7 @@
   if (!value.get()) {
     LOG(WARNING) << "Specifics for " << specifics.extension_id() << "/" <<
         specifics.key() << " had bad JSON for value: " << specifics.value();
-    value.reset(new DictionaryValue());
+    value.reset(new base::DictionaryValue());
   }
   internal_ = new Internal(
       change_type,
diff --git a/chrome/browser/extensions/api/storage/settings_apitest.cc b/chrome/browser/extensions/api/storage/settings_apitest.cc
index 433f69c..45e3386 100644
--- a/chrome/browser/extensions/api/storage/settings_apitest.cc
+++ b/chrome/browser/extensions/api/storage/settings_apitest.cc
@@ -196,7 +196,7 @@
       Namespace settings_namespace,
       const std::string& action,
       bool is_final_action) {
-    scoped_ptr<DictionaryValue> message(new DictionaryValue());
+    scoped_ptr<base::DictionaryValue> message(new base::DictionaryValue());
     message->SetString("namespace", ToString(settings_namespace));
     message->SetString("action", action);
     message->SetBoolean("isFinalAction", is_final_action);
@@ -454,7 +454,7 @@
   policy::PolicyService* service = connector->policy_service();
   scoped_refptr<const policy::PolicyDomainDescriptor> descriptor =
       service->GetPolicyDomainDescriptor(policy::POLICY_DOMAIN_EXTENSIONS);
-  EXPECT_TRUE(descriptor);
+  EXPECT_TRUE(descriptor.get());
 }
 
 IN_PROC_BROWSER_TEST_F(ExtensionSettingsApiTest, ManagedStorage) {
diff --git a/chrome/browser/extensions/api/storage/settings_backend.cc b/chrome/browser/extensions/api/storage/settings_backend.cc
index e1a5d37..cd4976a 100644
--- a/chrome/browser/extensions/api/storage/settings_backend.cc
+++ b/chrome/browser/extensions/api/storage/settings_backend.cc
@@ -41,12 +41,13 @@
 ValueStore* SettingsBackend::GetStorage(
     const std::string& extension_id) const {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
-  DictionaryValue empty;
+  base::DictionaryValue empty;
   return GetOrCreateStorageWithSyncData(extension_id, empty);
 }
 
 SyncableSettingsStorage* SettingsBackend::GetOrCreateStorageWithSyncData(
-    const std::string& extension_id, const DictionaryValue& sync_data) const {
+    const std::string& extension_id,
+    const base::DictionaryValue& sync_data) const {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
 
   StorageObjMap::iterator maybe_storage = storage_objs_.find(extension_id);
@@ -132,10 +133,10 @@
 
 static void AddAllSyncData(
     const std::string& extension_id,
-    const DictionaryValue& src,
+    const base::DictionaryValue& src,
     syncer::ModelType type,
     syncer::SyncDataList* dst) {
-  for (DictionaryValue::Iterator it(src); !it.IsAtEnd(); it.Advance()) {
+  for (base::DictionaryValue::Iterator it(src); !it.IsAtEnd(); it.Advance()) {
     dst->push_back(settings_sync_util::CreateData(
         extension_id, it.key(), it.value(), type));
   }
@@ -184,14 +185,15 @@
   sync_error_factory_ = sync_error_factory.Pass();
 
   // Group the initial sync data by extension id.
-  std::map<std::string, linked_ptr<DictionaryValue> > grouped_sync_data;
+  std::map<std::string, linked_ptr<base::DictionaryValue> > grouped_sync_data;
   for (syncer::SyncDataList::const_iterator it = initial_sync_data.begin();
       it != initial_sync_data.end(); ++it) {
     SettingSyncData data(*it);
-    linked_ptr<DictionaryValue> sync_data =
+    linked_ptr<base::DictionaryValue> sync_data =
         grouped_sync_data[data.extension_id()];
     if (!sync_data.get()) {
-      sync_data = linked_ptr<DictionaryValue>(new DictionaryValue());
+      sync_data = linked_ptr<base::DictionaryValue>(
+          new base::DictionaryValue());
       grouped_sync_data[data.extension_id()] = sync_data;
     }
     DCHECK(!sync_data->HasKey(data.key())) <<
@@ -203,7 +205,7 @@
   // the future will start being synced as part of the creation process.
   for (StorageObjMap::iterator it = storage_objs_.begin();
       it != storage_objs_.end(); ++it) {
-    std::map<std::string, linked_ptr<DictionaryValue> >::iterator
+    std::map<std::string, linked_ptr<base::DictionaryValue> >::iterator
         maybe_sync_data = grouped_sync_data.find(it->first);
     syncer::SyncError error;
     if (maybe_sync_data != grouped_sync_data.end()) {
@@ -212,7 +214,7 @@
           CreateSettingsSyncProcessor(it->first).Pass());
       grouped_sync_data.erase(it->first);
     } else {
-      DictionaryValue empty;
+      base::DictionaryValue empty;
       error = it->second->StartSyncing(
           empty,
           CreateSettingsSyncProcessor(it->first).Pass());
@@ -224,7 +226,7 @@
   // Eagerly create and init the rest of the storage areas that have sync data.
   // Under normal circumstances (i.e. not first-time sync) this will be all of
   // them.
-  for (std::map<std::string, linked_ptr<DictionaryValue> >::iterator it =
+  for (std::map<std::string, linked_ptr<base::DictionaryValue> >::iterator it =
       grouped_sync_data.begin(); it != grouped_sync_data.end(); ++it) {
     GetOrCreateStorageWithSyncData(it->first, *it->second);
   }
@@ -247,7 +249,7 @@
   }
 
   // Create any storage areas that don't exist yet but have sync data.
-  DictionaryValue empty;
+  base::DictionaryValue empty;
   for (std::map<std::string, SettingSyncDataList>::iterator
       it = grouped_sync_data.begin(); it != grouped_sync_data.end(); ++it) {
     SyncableSettingsStorage* storage =
diff --git a/chrome/browser/extensions/api/storage/settings_backend.h b/chrome/browser/extensions/api/storage/settings_backend.h
index 9de4f0e..0882b68 100644
--- a/chrome/browser/extensions/api/storage/settings_backend.h
+++ b/chrome/browser/extensions/api/storage/settings_backend.h
@@ -72,7 +72,7 @@
   // initializing sync with some initial data if sync enabled.
   SyncableSettingsStorage* GetOrCreateStorageWithSyncData(
       const std::string& extension_id,
-      const DictionaryValue& sync_data) const;
+      const base::DictionaryValue& sync_data) const;
 
   // Gets all extension IDs known to extension settings.  This may not be all
   // installed extensions.
diff --git a/chrome/browser/extensions/api/storage/settings_frontend.cc b/chrome/browser/extensions/api/storage/settings_frontend.cc
index dece669..a14ed69 100644
--- a/chrome/browser/extensions/api/storage/settings_frontend.cc
+++ b/chrome/browser/extensions/api/storage/settings_frontend.cc
@@ -44,7 +44,7 @@
       const std::string& change_json) OVERRIDE {
     // TODO(gdk): This is a temporary hack while the refactoring for
     // string-based event payloads is removed. http://crbug.com/136045
-    scoped_ptr<ListValue> args(new ListValue());
+    scoped_ptr<base::ListValue> args(new base::ListValue());
     args->Append(base::JSONReader::Read(change_json));
     args->Append(Value::CreateStringValue(settings_namespace::ToString(
         settings_namespace)));
diff --git a/chrome/browser/extensions/api/storage/settings_frontend_unittest.cc b/chrome/browser/extensions/api/storage/settings_frontend_unittest.cc
index 28015a8..9705531 100644
--- a/chrome/browser/extensions/api/storage/settings_frontend_unittest.cc
+++ b/chrome/browser/extensions/api/storage/settings_frontend_unittest.cc
@@ -40,7 +40,7 @@
 
 // Creates a megabyte of data.
 scoped_ptr<Value> CreateMegabyte() {
-  ListValue* megabyte = new ListValue();
+  base::ListValue* megabyte = new base::ListValue();
   for (int i = 0; i < 1000; ++i) {
     megabyte->Append(CreateKilobyte().release());
   }
diff --git a/chrome/browser/extensions/api/storage/settings_quota_unittest.cc b/chrome/browser/extensions/api/storage/settings_quota_unittest.cc
index 8ed71e8..0e4ea79 100644
--- a/chrome/browser/extensions/api/storage/settings_quota_unittest.cc
+++ b/chrome/browser/extensions/api/storage/settings_quota_unittest.cc
@@ -11,6 +11,10 @@
 #include "chrome/browser/value_store/testing_value_store.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+using base::DictionaryValue;
+using base::ListValue;
+using base::Value;
+
 namespace extensions {
 
 // To save typing ValueStore::DEFAULTS/IGNORE_QUOTA everywhere.
diff --git a/chrome/browser/extensions/api/storage/settings_storage_quota_enforcer.cc b/chrome/browser/extensions/api/storage/settings_storage_quota_enforcer.cc
index ffe05ab..c64dd6c 100644
--- a/chrome/browser/extensions/api/storage/settings_storage_quota_enforcer.cc
+++ b/chrome/browser/extensions/api/storage/settings_storage_quota_enforcer.cc
@@ -91,7 +91,7 @@
     return;
   }
 
-  for (DictionaryValue::Iterator it(*maybe_settings->settings().get());
+  for (base::DictionaryValue::Iterator it(*maybe_settings->settings().get());
        !it.IsAtEnd(); it.Advance()) {
     Allocate(it.key(), it.value(), &used_total_, &used_per_setting_);
   }
@@ -164,10 +164,11 @@
 }
 
 ValueStore::WriteResult SettingsStorageQuotaEnforcer::Set(
-    WriteOptions options, const DictionaryValue& values) {
+    WriteOptions options, const base::DictionaryValue& values) {
   size_t new_used_total = used_total_;
   std::map<std::string, size_t> new_used_per_setting = used_per_setting_;
-  for (DictionaryValue::Iterator it(values); !it.IsAtEnd(); it.Advance()) {
+  for (base::DictionaryValue::Iterator it(values); !it.IsAtEnd();
+       it.Advance()) {
     Allocate(it.key(), it.value(), &new_used_total, &new_used_per_setting);
 
     if (!(options & IGNORE_QUOTA) &&
diff --git a/chrome/browser/extensions/api/storage/settings_storage_quota_enforcer.h b/chrome/browser/extensions/api/storage/settings_storage_quota_enforcer.h
index 537ee33..7db793e 100644
--- a/chrome/browser/extensions/api/storage/settings_storage_quota_enforcer.h
+++ b/chrome/browser/extensions/api/storage/settings_storage_quota_enforcer.h
@@ -42,7 +42,7 @@
       const std::string& key,
       const Value& value) OVERRIDE;
   virtual WriteResult Set(
-      WriteOptions options, const DictionaryValue& values) OVERRIDE;
+      WriteOptions options, const base::DictionaryValue& values) OVERRIDE;
   virtual WriteResult Remove(const std::string& key) OVERRIDE;
   virtual WriteResult Remove(const std::vector<std::string>& keys) OVERRIDE;
   virtual WriteResult Clear() OVERRIDE;
diff --git a/chrome/browser/extensions/api/storage/settings_sync_processor.cc b/chrome/browser/extensions/api/storage/settings_sync_processor.cc
index 06b4ee8..b016e9e 100644
--- a/chrome/browser/extensions/api/storage/settings_sync_processor.cc
+++ b/chrome/browser/extensions/api/storage/settings_sync_processor.cc
@@ -31,11 +31,12 @@
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
 }
 
-void SettingsSyncProcessor::Init(const DictionaryValue& initial_state) {
+void SettingsSyncProcessor::Init(const base::DictionaryValue& initial_state) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
   CHECK(!initialized_) << "Init called multiple times";
 
-  for (DictionaryValue::Iterator i(initial_state); !i.IsAtEnd(); i.Advance())
+  for (base::DictionaryValue::Iterator i(initial_state); !i.IsAtEnd();
+       i.Advance())
     synced_keys_.insert(i.key());
 
   initialized_ = true;
diff --git a/chrome/browser/extensions/api/storage/settings_sync_processor.h b/chrome/browser/extensions/api/storage/settings_sync_processor.h
index 834e026..acc836f 100644
--- a/chrome/browser/extensions/api/storage/settings_sync_processor.h
+++ b/chrome/browser/extensions/api/storage/settings_sync_processor.h
@@ -31,7 +31,7 @@
   ~SettingsSyncProcessor();
 
   // Initializes this with the initial state of sync.
-  void Init(const DictionaryValue& initial_state);
+  void Init(const base::DictionaryValue& initial_state);
 
   // Sends |changes| to sync.
   syncer::SyncError SendChanges(const ValueStoreChangeList& changes);
diff --git a/chrome/browser/extensions/api/storage/settings_sync_unittest.cc b/chrome/browser/extensions/api/storage/settings_sync_unittest.cc
index ae4a353..b1b22a9 100644
--- a/chrome/browser/extensions/api/storage/settings_sync_unittest.cc
+++ b/chrome/browser/extensions/api/storage/settings_sync_unittest.cc
@@ -24,6 +24,9 @@
 #include "sync/api/sync_error_factory_mock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+using base::DictionaryValue;
+using base::ListValue;
+using base::Value;
 using content::BrowserThread;
 
 namespace extensions {
@@ -94,6 +97,7 @@
     if (fail_all_requests_) {
       return syncer::SyncError(
           FROM_HERE,
+          syncer::SyncError::DATATYPE_ERROR,
           "MockSyncChangeProcessor: configured to fail",
           change_list[0].sync_data().GetDataType());
     }
diff --git a/chrome/browser/extensions/api/storage/settings_sync_util.cc b/chrome/browser/extensions/api/storage/settings_sync_util.cc
index b9246e0..4509ee9 100644
--- a/chrome/browser/extensions/api/storage/settings_sync_util.cc
+++ b/chrome/browser/extensions/api/storage/settings_sync_util.cc
@@ -98,7 +98,7 @@
     const std::string& extension_id,
     const std::string& key,
     syncer::ModelType type) {
-  DictionaryValue no_value;
+  base::DictionaryValue no_value;
   return syncer::SyncChange(
       FROM_HERE,
       syncer::SyncChange::ACTION_DELETE,
diff --git a/chrome/browser/extensions/api/storage/settings_test_util.cc b/chrome/browser/extensions/api/storage/settings_test_util.cc
index 30bf92b..3d8d110 100644
--- a/chrome/browser/extensions/api/storage/settings_test_util.cc
+++ b/chrome/browser/extensions/api/storage/settings_test_util.cc
@@ -60,11 +60,11 @@
     const std::string& id,
     Manifest::Type type,
     const std::set<std::string>& permissions_set) {
-  DictionaryValue manifest;
+  base::DictionaryValue manifest;
   manifest.SetString("name", std::string("Test extension ") + id);
   manifest.SetString("version", "1.0");
 
-  scoped_ptr<ListValue> permissions(new ListValue());
+  scoped_ptr<base::ListValue> permissions(new base::ListValue());
   for (std::set<std::string>::const_iterator it = permissions_set.begin();
       it != permissions_set.end(); ++it) {
     permissions->Append(Value::CreateStringValue(*it));
@@ -76,8 +76,8 @@
       break;
 
     case Manifest::TYPE_LEGACY_PACKAGED_APP: {
-      DictionaryValue* app = new DictionaryValue();
-      DictionaryValue* app_launch = new DictionaryValue();
+      base::DictionaryValue* app = new base::DictionaryValue();
+      base::DictionaryValue* app_launch = new base::DictionaryValue();
       app_launch->SetString("local_path", "fake.html");
       app->Set("launch", app_launch);
       manifest.Set("app", app);
diff --git a/chrome/browser/extensions/api/storage/storage_api.cc b/chrome/browser/extensions/api/storage/storage_api.cc
index bfc41a5..d86b763 100644
--- a/chrome/browser/extensions/api/storage/storage_api.cc
+++ b/chrome/browser/extensions/api/storage/storage_api.cc
@@ -113,10 +113,12 @@
 namespace {
 
 // Adds all StringValues from a ListValue to a vector of strings.
-void AddAllStringValues(const ListValue& from, std::vector<std::string>* to) {
+void AddAllStringValues(const base::ListValue& from,
+                        std::vector<std::string>* to) {
   DCHECK(to->empty());
   std::string as_string;
-  for (ListValue::const_iterator it = from.begin(); it != from.end(); ++it) {
+  for (base::ListValue::const_iterator it = from.begin();
+       it != from.end(); ++it) {
     if ((*it)->GetAsString(&as_string)) {
       to->push_back(as_string);
     }
@@ -124,9 +126,9 @@
 }
 
 // Gets the keys of a DictionaryValue.
-std::vector<std::string> GetKeys(const DictionaryValue& dict) {
+std::vector<std::string> GetKeys(const base::DictionaryValue& dict) {
   std::vector<std::string> keys;
-  for (DictionaryValue::Iterator it(dict); !it.IsAtEnd(); it.Advance()) {
+  for (base::DictionaryValue::Iterator it(dict); !it.IsAtEnd(); it.Advance()) {
     keys.push_back(it.key());
   }
   return keys;
@@ -162,33 +164,34 @@
 }  // namespace
 
 bool StorageStorageAreaGetFunction::RunWithStorage(ValueStore* storage) {
-  Value* input = NULL;
+  base::Value* input = NULL;
   EXTENSION_FUNCTION_VALIDATE(args_->Get(0, &input));
 
   switch (input->GetType()) {
-    case Value::TYPE_NULL:
+    case base::Value::TYPE_NULL:
       return UseReadResult(storage->Get());
 
-    case Value::TYPE_STRING: {
+    case base::Value::TYPE_STRING: {
       std::string as_string;
       input->GetAsString(&as_string);
       return UseReadResult(storage->Get(as_string));
     }
 
-    case Value::TYPE_LIST: {
+    case base::Value::TYPE_LIST: {
       std::vector<std::string> as_string_list;
-      AddAllStringValues(*static_cast<ListValue*>(input), &as_string_list);
+      AddAllStringValues(*static_cast<base::ListValue*>(input),
+                         &as_string_list);
       return UseReadResult(storage->Get(as_string_list));
     }
 
-    case Value::TYPE_DICTIONARY: {
-      DictionaryValue* as_dict = static_cast<DictionaryValue*>(input);
+    case base::Value::TYPE_DICTIONARY: {
+      base::DictionaryValue* as_dict = static_cast<base::DictionaryValue*>(input);
       ValueStore::ReadResult result = storage->Get(GetKeys(*as_dict));
       if (result->HasError()) {
         return UseReadResult(result.Pass());
       }
 
-      DictionaryValue* with_default_values = as_dict->DeepCopy();
+      base::DictionaryValue* with_default_values = as_dict->DeepCopy();
       with_default_values->MergeDictionary(result->settings().get());
       return UseReadResult(
           ValueStore::MakeReadResult(with_default_values));
@@ -202,26 +205,27 @@
 
 bool StorageStorageAreaGetBytesInUseFunction::RunWithStorage(
     ValueStore* storage) {
-  Value* input = NULL;
+  base::Value* input = NULL;
   EXTENSION_FUNCTION_VALIDATE(args_->Get(0, &input));
 
   size_t bytes_in_use = 0;
 
   switch (input->GetType()) {
-    case Value::TYPE_NULL:
+    case base::Value::TYPE_NULL:
       bytes_in_use = storage->GetBytesInUse();
       break;
 
-    case Value::TYPE_STRING: {
+    case base::Value::TYPE_STRING: {
       std::string as_string;
       input->GetAsString(&as_string);
       bytes_in_use = storage->GetBytesInUse(as_string);
       break;
     }
 
-    case Value::TYPE_LIST: {
+    case base::Value::TYPE_LIST: {
       std::vector<std::string> as_string_list;
-      AddAllStringValues(*static_cast<ListValue*>(input), &as_string_list);
+      AddAllStringValues(*static_cast<base::ListValue*>(input),
+                         &as_string_list);
       bytes_in_use = storage->GetBytesInUse(as_string_list);
       break;
     }
@@ -231,12 +235,12 @@
       return false;
   }
 
-  SetResult(Value::CreateIntegerValue(bytes_in_use));
+  SetResult(base::Value::CreateIntegerValue(bytes_in_use));
   return true;
 }
 
 bool StorageStorageAreaSetFunction::RunWithStorage(ValueStore* storage) {
-  DictionaryValue* input = NULL;
+  base::DictionaryValue* input = NULL;
   EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &input));
   return UseWriteResult(storage->Set(ValueStore::DEFAULTS, *input));
 }
@@ -247,19 +251,20 @@
 }
 
 bool StorageStorageAreaRemoveFunction::RunWithStorage(ValueStore* storage) {
-  Value* input = NULL;
+  base::Value* input = NULL;
   EXTENSION_FUNCTION_VALIDATE(args_->Get(0, &input));
 
   switch (input->GetType()) {
-    case Value::TYPE_STRING: {
+    case base::Value::TYPE_STRING: {
       std::string as_string;
       input->GetAsString(&as_string);
       return UseWriteResult(storage->Remove(as_string));
     }
 
-    case Value::TYPE_LIST: {
+    case base::Value::TYPE_LIST: {
       std::vector<std::string> as_string_list;
-      AddAllStringValues(*static_cast<ListValue*>(input), &as_string_list);
+      AddAllStringValues(*static_cast<base::ListValue*>(input),
+                         &as_string_list);
       return UseWriteResult(storage->Remove(as_string_list));
     }
 
diff --git a/chrome/browser/extensions/api/storage/storage_schema_manifest_handler_unittest.cc b/chrome/browser/extensions/api/storage/storage_schema_manifest_handler_unittest.cc
index 1d0a7bb..a7fd429 100644
--- a/chrome/browser/extensions/api/storage/storage_schema_manifest_handler_unittest.cc
+++ b/chrome/browser/extensions/api/storage/storage_schema_manifest_handler_unittest.cc
@@ -48,7 +48,7 @@
       return NULL;
     base::FilePath schema_path = temp_dir_.path().AppendASCII("schema.json");
     if (schema.empty()) {
-      file_util::Delete(schema_path, false);
+      base::Delete(schema_path, false);
     } else {
       if (file_util::WriteFile(schema_path, schema.data(), schema.size()) !=
           static_cast<int>(schema.size())) {
diff --git a/chrome/browser/extensions/api/storage/syncable_settings_storage.cc b/chrome/browser/extensions/api/storage/syncable_settings_storage.cc
index 221ebeb..66fd94f 100644
--- a/chrome/browser/extensions/api/storage/syncable_settings_storage.cc
+++ b/chrome/browser/extensions/api/storage/syncable_settings_storage.cc
@@ -75,7 +75,7 @@
 }
 
 ValueStore::WriteResult SyncableSettingsStorage::Set(
-    WriteOptions options, const DictionaryValue& values) {
+    WriteOptions options, const base::DictionaryValue& values) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
   WriteResult result = delegate_->Set(options, values);
   if (result->HasError()) {
@@ -129,7 +129,7 @@
 // Sync-related methods.
 
 syncer::SyncError SyncableSettingsStorage::StartSyncing(
-    const DictionaryValue& sync_state,
+    const base::DictionaryValue& sync_state,
     scoped_ptr<SettingsSyncProcessor> sync_processor) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
   DCHECK(!sync_processor_.get());
@@ -141,11 +141,12 @@
   if (maybe_settings->HasError()) {
     return syncer::SyncError(
         FROM_HERE,
+        syncer::SyncError::DATATYPE_ERROR,
         std::string("Failed to get settings: ") + maybe_settings->error(),
         sync_processor_->type());
   }
 
-  const DictionaryValue& settings = *maybe_settings->settings().get();
+  const base::DictionaryValue& settings = *maybe_settings->settings().get();
   if (sync_state.empty())
     return SendLocalSettingsToSync(settings);
   else
@@ -153,11 +154,11 @@
 }
 
 syncer::SyncError SyncableSettingsStorage::SendLocalSettingsToSync(
-    const DictionaryValue& settings) {
+    const base::DictionaryValue& settings) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
 
   ValueStoreChangeList changes;
-  for (DictionaryValue::Iterator i(settings); !i.IsAtEnd(); i.Advance()) {
+  for (base::DictionaryValue::Iterator i(settings); !i.IsAtEnd(); i.Advance()) {
     changes.push_back(ValueStoreChange(i.key(), NULL, i.value().DeepCopy()));
   }
 
@@ -172,14 +173,15 @@
 }
 
 syncer::SyncError SyncableSettingsStorage::OverwriteLocalSettingsWithSync(
-    const DictionaryValue& sync_state, const DictionaryValue& settings) {
+    const base::DictionaryValue& sync_state,
+    const base::DictionaryValue& settings) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
   // Treat this as a list of changes to sync and use ProcessSyncChanges.
   // This gives notifications etc for free.
-  scoped_ptr<DictionaryValue> new_sync_state(sync_state.DeepCopy());
+  scoped_ptr<base::DictionaryValue> new_sync_state(sync_state.DeepCopy());
 
   SettingSyncDataList changes;
-  for (DictionaryValue::Iterator it(settings); !it.IsAtEnd(); it.Advance()) {
+  for (base::DictionaryValue::Iterator it(settings); !it.IsAtEnd(); it.Advance()) {
     Value* orphaned_sync_value = NULL;
     if (new_sync_state->RemoveWithoutPathExpansion(
           it.key(), &orphaned_sync_value)) {
@@ -202,13 +204,13 @@
               syncer::SyncChange::ACTION_DELETE,
               extension_id_,
               it.key(),
-              scoped_ptr<Value>(new DictionaryValue())));
+              scoped_ptr<Value>(new base::DictionaryValue())));
     }
   }
 
   // Add all new settings to local settings.
   while (!new_sync_state->empty()) {
-    DictionaryValue::Iterator first_entry(*new_sync_state);
+    base::DictionaryValue::Iterator first_entry(*new_sync_state);
     std::string key = first_entry.key();
     Value* value = NULL;
     CHECK(new_sync_state->RemoveWithoutPathExpansion(key, &value));
@@ -239,6 +241,7 @@
   if (!sync_processor_.get()) {
     return syncer::SyncError(
         FROM_HERE,
+        syncer::SyncError::DATATYPE_ERROR,
         std::string("Sync is inactive for ") + extension_id_,
         syncer::UNSPECIFIED);
   }
@@ -259,6 +262,7 @@
       if (maybe_settings->HasError()) {
         errors.push_back(syncer::SyncError(
             FROM_HERE,
+            syncer::SyncError::DATATYPE_ERROR,
             std::string("Error getting current sync state for ") +
                 extension_id_ + "/" + key + ": " + maybe_settings->error(),
             sync_processor_->type()));
@@ -338,6 +342,7 @@
   if (result->HasError()) {
     return syncer::SyncError(
         FROM_HERE,
+        syncer::SyncError::DATATYPE_ERROR,
         std::string("Error pushing sync add to local settings: ") +
             result->error(),
         sync_processor_->type());
@@ -357,6 +362,7 @@
   if (result->HasError()) {
     return syncer::SyncError(
         FROM_HERE,
+        syncer::SyncError::DATATYPE_ERROR,
         std::string("Error pushing sync update to local settings: ") +
             result->error(),
         sync_processor_->type());
@@ -374,6 +380,7 @@
   if (result->HasError()) {
     return syncer::SyncError(
         FROM_HERE,
+        syncer::SyncError::DATATYPE_ERROR,
         std::string("Error pushing sync remove to local settings: ") +
             result->error(),
         sync_processor_->type());
diff --git a/chrome/browser/extensions/api/storage/syncable_settings_storage.h b/chrome/browser/extensions/api/storage/syncable_settings_storage.h
index ec57f83..d971ef0 100644
--- a/chrome/browser/extensions/api/storage/syncable_settings_storage.h
+++ b/chrome/browser/extensions/api/storage/syncable_settings_storage.h
@@ -43,7 +43,7 @@
       const std::string& key,
       const Value& value) OVERRIDE;
   virtual WriteResult Set(
-      WriteOptions options, const DictionaryValue& values) OVERRIDE;
+      WriteOptions options, const base::DictionaryValue& values) OVERRIDE;
   virtual WriteResult Remove(const std::string& key) OVERRIDE;
   virtual WriteResult Remove(const std::vector<std::string>& keys) OVERRIDE;
   virtual WriteResult Clear() OVERRIDE;
@@ -54,7 +54,7 @@
 
   // Must only be called if sync isn't already active.
   syncer::SyncError StartSyncing(
-      const DictionaryValue& sync_state,
+      const base::DictionaryValue& sync_state,
       scoped_ptr<SettingsSyncProcessor> sync_processor);
 
   // May be called at any time (idempotent).
@@ -69,11 +69,12 @@
 
   // Sends all local settings to sync (synced settings assumed to be empty).
   syncer::SyncError SendLocalSettingsToSync(
-      const DictionaryValue& settings);
+      const base::DictionaryValue& settings);
 
   // Overwrites local state with sync state.
   syncer::SyncError OverwriteLocalSettingsWithSync(
-      const DictionaryValue& sync_state, const DictionaryValue& settings);
+      const base::DictionaryValue& sync_state,
+      const base::DictionaryValue& settings);
 
   // Called when an Add/Update/Remove comes from sync.  Ownership of Value*s
   // are taken.
diff --git a/chrome/browser/extensions/api/storage/weak_unlimited_settings_storage.cc b/chrome/browser/extensions/api/storage/weak_unlimited_settings_storage.cc
index 7adf5f4..241ae2f 100644
--- a/chrome/browser/extensions/api/storage/weak_unlimited_settings_storage.cc
+++ b/chrome/browser/extensions/api/storage/weak_unlimited_settings_storage.cc
@@ -41,12 +41,12 @@
 }
 
 ValueStore::WriteResult WeakUnlimitedSettingsStorage::Set(
-    WriteOptions options, const std::string& key, const Value& value) {
+    WriteOptions options, const std::string& key, const base::Value& value) {
   return delegate_->Set(IGNORE_QUOTA, key, value);
 }
 
 ValueStore::WriteResult WeakUnlimitedSettingsStorage::Set(
-    WriteOptions options, const DictionaryValue& values) {
+    WriteOptions options, const base::DictionaryValue& values) {
   return delegate_->Set(IGNORE_QUOTA, values);
 }
 
diff --git a/chrome/browser/extensions/api/storage/weak_unlimited_settings_storage.h b/chrome/browser/extensions/api/storage/weak_unlimited_settings_storage.h
index c74d57c..66a4002 100644
--- a/chrome/browser/extensions/api/storage/weak_unlimited_settings_storage.h
+++ b/chrome/browser/extensions/api/storage/weak_unlimited_settings_storage.h
@@ -32,7 +32,7 @@
       const std::string& key,
       const Value& value) OVERRIDE;
   virtual WriteResult Set(
-      WriteOptions options, const DictionaryValue& values) OVERRIDE;
+      WriteOptions options, const base::DictionaryValue& values) OVERRIDE;
   virtual WriteResult Remove(const std::string& key) OVERRIDE;
   virtual WriteResult Remove(const std::vector<std::string>& keys) OVERRIDE;
   virtual WriteResult Clear() OVERRIDE;
diff --git a/chrome/browser/extensions/api/streams_private/streams_private_api.cc b/chrome/browser/extensions/api/streams_private/streams_private_api.cc
index d87c9a0..dc1fb07 100644
--- a/chrome/browser/extensions/api/streams_private/streams_private_api.cc
+++ b/chrome/browser/extensions/api/streams_private/streams_private_api.cc
@@ -52,7 +52,7 @@
     scoped_ptr<content::StreamHandle> stream,
     int64 expected_content_size) {
   // Create the event's arguments value.
-  scoped_ptr<ListValue> event_args(new ListValue());
+  scoped_ptr<base::ListValue> event_args(new base::ListValue());
   event_args->Append(new base::StringValue(stream->GetMimeType()));
   event_args->Append(new base::StringValue(stream->GetOriginalURL().spec()));
   event_args->Append(new base::StringValue(stream->GetURL().spec()));
diff --git a/chrome/browser/extensions/api/streams_private/streams_private_apitest.cc b/chrome/browser/extensions/api/streams_private/streams_private_apitest.cc
index 7fd3672..3139336 100644
--- a/chrome/browser/extensions/api/streams_private/streams_private_apitest.cc
+++ b/chrome/browser/extensions/api/streams_private/streams_private_apitest.cc
@@ -51,7 +51,7 @@
   // For relative path "/doc_path.doc", return success response with MIME type
   // "application/msword".
   if (request.relative_url == "/doc_path.doc") {
-    response->set_code(net::test_server::SUCCESS);
+    response->set_code(net::HTTP_OK);
     response->set_content_type("application/msword");
     return response.PassAs<HttpResponse>();
   }
@@ -60,7 +60,7 @@
   // MIME type "plain/text" and content "txt content". Also, set content
   // disposition to be attachment.
   if (request.relative_url == "/text_path_attch.txt") {
-    response->set_code(net::test_server::SUCCESS);
+    response->set_code(net::HTTP_OK);
     response->set_content("txt content");
     response->set_content_type("plain/text");
     response->AddCustomHeader("Content-Disposition",
@@ -70,7 +70,7 @@
   // For relative path "/test_path_attch.txt", return success response with
   // MIME type "plain/text" and content "txt content".
   if (request.relative_url == "/text_path.txt") {
-    response->set_code(net::test_server::SUCCESS);
+    response->set_code(net::HTTP_OK);
     response->set_content("txt content");
     response->set_content_type("plain/text");
     return response.PassAs<HttpResponse>();
@@ -78,7 +78,7 @@
 
   // No other requests should be handled in the tests.
   EXPECT_TRUE(false) << "NOTREACHED!";
-  response->set_code(net::test_server::NOT_FOUND);
+  response->set_code(net::HTTP_NOT_FOUND);
   return response.PassAs<HttpResponse>();
 }
 
@@ -134,7 +134,7 @@
   // event with the "test/done" MIME type (unless the 'chrome.test.notifyFail'
   // has already been called).
   void SendDoneEvent() {
-    scoped_ptr<ListValue> event_args(new ListValue());
+    scoped_ptr<base::ListValue> event_args(new base::ListValue());
     event_args->Append(new base::StringValue("test/done"));
     event_args->Append(new base::StringValue("http://foo"));
     event_args->Append(new base::StringValue("blob://bar"));
diff --git a/chrome/browser/extensions/api/sync_file_system/extension_sync_event_observer.cc b/chrome/browser/extensions/api/sync_file_system/extension_sync_event_observer.cc
index e856033..3b76078 100644
--- a/chrome/browser/extensions/api/sync_file_system/extension_sync_event_observer.cc
+++ b/chrome/browser/extensions/api/sync_file_system/extension_sync_event_observer.cc
@@ -75,7 +75,7 @@
     sync_file_system::SyncFileStatus status,
     sync_file_system::SyncAction action,
     sync_file_system::SyncDirection direction) {
-  scoped_ptr<base::ListValue> params(new ListValue());
+  scoped_ptr<base::ListValue> params(new base::ListValue());
 
   // For now we always assume events come only for files (not directories).
   params->Append(CreateDictionaryValueForFileSystemEntry(
diff --git a/chrome/browser/extensions/api/sync_file_system/sync_file_system_api.cc b/chrome/browser/extensions/api/sync_file_system/sync_file_system_api.cc
index cb0c0fd..640ad9e 100644
--- a/chrome/browser/extensions/api/sync_file_system/sync_file_system_api.cc
+++ b/chrome/browser/extensions/api/sync_file_system/sync_file_system_api.cc
@@ -142,7 +142,7 @@
 
   BrowserThread::PostTask(
       BrowserThread::IO, FROM_HERE,
-      Bind(&fileapi::FileSystemContext::OpenSyncableFileSystem,
+      Bind(&fileapi::FileSystemContext::OpenFileSystem,
            GetFileSystemContext(),
            source_url().GetOrigin(),
            fileapi::kFileSystemTypeSyncable,
@@ -171,7 +171,7 @@
     return;
   }
 
-  DictionaryValue* dict = new DictionaryValue();
+  base::DictionaryValue* dict = new base::DictionaryValue();
   SetResult(dict);
   dict->SetString("name", file_system_name);
   dict->SetString("root", root_url.spec());
@@ -220,7 +220,7 @@
 
 bool SyncFileSystemGetFileStatusesFunction::RunImpl() {
   // All FileEntries converted into array of URL Strings in JS custom bindings.
-  ListValue* file_entry_urls = NULL;
+  base::ListValue* file_entry_urls = NULL;
   EXTENSION_FUNCTION_VALIDATE(args_->GetList(0, &file_entry_urls));
 
   scoped_refptr<fileapi::FileSystemContext> file_system_context =
@@ -274,7 +274,7 @@
   base::ListValue* status_array = new base::ListValue();
   for (URLToStatusMap::iterator it = file_sync_statuses_.begin();
        it != file_sync_statuses_.end(); ++it) {
-    DictionaryValue* dict = new DictionaryValue();
+    base::DictionaryValue* dict = new base::DictionaryValue();
     status_array->Append(dict);
 
     fileapi::FileSystemURL url = it->first;
@@ -357,7 +357,7 @@
   EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &policy_string));
   ConflictResolutionPolicy policy = ExtensionEnumToConflictResolutionPolicy(
       api::sync_file_system::ParseConflictResolutionPolicy(policy_string));
-  if (policy == sync_file_system::CONFLICT_RESOLUTION_UNKNOWN) {
+  if (policy == sync_file_system::CONFLICT_RESOLUTION_POLICY_UNKNOWN) {
     SetError(base::StringPrintf(kUnsupportedConflictResolutionPolicy,
                                 policy_string.c_str()));
     return false;
diff --git a/chrome/browser/extensions/api/sync_file_system/sync_file_system_api_helpers.cc b/chrome/browser/extensions/api/sync_file_system/sync_file_system_api_helpers.cc
index 0adc20b..7398440 100644
--- a/chrome/browser/extensions/api/sync_file_system/sync_file_system_api_helpers.cc
+++ b/chrome/browser/extensions/api/sync_file_system/sync_file_system_api_helpers.cc
@@ -77,25 +77,25 @@
     api::sync_file_system::ConflictResolutionPolicy policy) {
   switch (policy) {
     case api::sync_file_system::CONFLICT_RESOLUTION_POLICY_NONE:
-      return sync_file_system::CONFLICT_RESOLUTION_UNKNOWN;
+      return sync_file_system::CONFLICT_RESOLUTION_POLICY_UNKNOWN;
     case api::sync_file_system::CONFLICT_RESOLUTION_POLICY_LAST_WRITE_WIN:
-      return sync_file_system::CONFLICT_RESOLUTION_LAST_WRITE_WIN;
+      return sync_file_system::CONFLICT_RESOLUTION_POLICY_LAST_WRITE_WIN;
     case api::sync_file_system::CONFLICT_RESOLUTION_POLICY_MANUAL:
-      return sync_file_system::CONFLICT_RESOLUTION_MANUAL;
+      return sync_file_system::CONFLICT_RESOLUTION_POLICY_MANUAL;
   }
   NOTREACHED() << "Invalid conflict resolution policy: " << policy;
-  return sync_file_system::CONFLICT_RESOLUTION_UNKNOWN;
+  return sync_file_system::CONFLICT_RESOLUTION_POLICY_UNKNOWN;
 }
 
 api::sync_file_system::ConflictResolutionPolicy
 ConflictResolutionPolicyToExtensionEnum(
     sync_file_system::ConflictResolutionPolicy policy) {
   switch (policy) {
-    case sync_file_system::CONFLICT_RESOLUTION_UNKNOWN:
+    case sync_file_system::CONFLICT_RESOLUTION_POLICY_UNKNOWN:
       return api::sync_file_system::CONFLICT_RESOLUTION_POLICY_NONE;
-    case sync_file_system::CONFLICT_RESOLUTION_LAST_WRITE_WIN:
+    case sync_file_system::CONFLICT_RESOLUTION_POLICY_LAST_WRITE_WIN:
         return api::sync_file_system::CONFLICT_RESOLUTION_POLICY_LAST_WRITE_WIN;
-    case sync_file_system::CONFLICT_RESOLUTION_MANUAL:
+    case sync_file_system::CONFLICT_RESOLUTION_POLICY_MANUAL:
       return api::sync_file_system::CONFLICT_RESOLUTION_POLICY_MANUAL;
   }
   NOTREACHED() << "Invalid conflict resolution policy: " << policy;
diff --git a/chrome/browser/extensions/api/sync_file_system/sync_file_system_api_helpers.h b/chrome/browser/extensions/api/sync_file_system/sync_file_system_api_helpers.h
index 16bb547..a08b701 100644
--- a/chrome/browser/extensions/api/sync_file_system/sync_file_system_api_helpers.h
+++ b/chrome/browser/extensions/api/sync_file_system/sync_file_system_api_helpers.h
@@ -6,10 +6,10 @@
 #define CHROME_BROWSER_EXTENSIONS_API_SYNC_FILE_SYSTEM_SYNC_FILE_SYSTEM_API_HELPERS_H_
 
 #include "chrome/browser/sync_file_system/conflict_resolution_policy.h"
+#include "chrome/browser/sync_file_system/sync_action.h"
+#include "chrome/browser/sync_file_system/sync_direction.h"
 #include "chrome/browser/sync_file_system/sync_service_state.h"
 #include "chrome/common/extensions/api/sync_file_system.h"
-#include "webkit/browser/fileapi/syncable/sync_action.h"
-#include "webkit/browser/fileapi/syncable/sync_direction.h"
 #include "webkit/browser/fileapi/syncable/sync_file_status.h"
 #include "webkit/browser/fileapi/syncable/sync_file_type.h"
 
diff --git a/chrome/browser/extensions/api/system_info_cpu/cpu_info_provider.h b/chrome/browser/extensions/api/system_info_cpu/cpu_info_provider.h
index e84db05..df7d77c 100644
--- a/chrome/browser/extensions/api/system_info_cpu/cpu_info_provider.h
+++ b/chrome/browser/extensions/api/system_info_cpu/cpu_info_provider.h
@@ -6,7 +6,7 @@
 
 #include <vector>
 
-#include "base/timer.h"
+#include "base/timer/timer.h"
 #include "chrome/browser/extensions/api/system_info/system_info_provider.h"
 #include "chrome/common/extensions/api/system_info_cpu.h"
 
diff --git a/chrome/browser/extensions/api/system_info_display/display_info_provider_chromeos.cc b/chrome/browser/extensions/api/system_info_display/display_info_provider_chromeos.cc
index 5fb380b..7ce7621 100644
--- a/chrome/browser/extensions/api/system_info_display/display_info_provider_chromeos.cc
+++ b/chrome/browser/extensions/api/system_info_display/display_info_provider_chromeos.cc
@@ -7,7 +7,7 @@
 #include "ash/display/display_controller.h"
 #include "ash/display/display_manager.h"
 #include "ash/shell.h"
-#include "base/message_loop_proxy.h"
+#include "base/message_loop/message_loop_proxy.h"
 #include "base/strings/string_number_conversions.h"
 #include "content/public/browser/browser_thread.h"
 #include "ui/gfx/display.h"
diff --git a/chrome/browser/extensions/api/system_info_storage/storage_info_provider.h b/chrome/browser/extensions/api/system_info_storage/storage_info_provider.h
index 5ed7b5a..88c147b 100644
--- a/chrome/browser/extensions/api/system_info_storage/storage_info_provider.h
+++ b/chrome/browser/extensions/api/system_info_storage/storage_info_provider.h
@@ -8,7 +8,7 @@
 
 #include "base/memory/ref_counted.h"
 #include "base/observer_list_threadsafe.h"
-#include "base/timer.h"
+#include "base/timer/timer.h"
 #include "chrome/browser/extensions/api/system_info/system_info_provider.h"
 #include "chrome/browser/extensions/api/system_info_storage/storage_info_observer.h"
 #include "chrome/browser/storage_monitor/removable_storage_observer.h"
diff --git a/chrome/browser/extensions/api/system_info_storage/storage_info_provider_linux_unittest.cc b/chrome/browser/extensions/api/system_info_storage/storage_info_provider_linux_unittest.cc
index 24bd8d8..46a013d 100644
--- a/chrome/browser/extensions/api/system_info_storage/storage_info_provider_linux_unittest.cc
+++ b/chrome/browser/extensions/api/system_info_storage/storage_info_provider_linux_unittest.cc
@@ -109,7 +109,7 @@
   }
 
   virtual void TearDown() OVERRIDE {
-    file_util::Delete(mtab_file_, false);
+    base::Delete(mtab_file_, false);
   }
 
   scoped_refptr<StorageInfoProviderLinuxWrapper> storage_info_provider_;
diff --git a/chrome/browser/extensions/api/system_info_storage/storage_info_provider_mac.cc b/chrome/browser/extensions/api/system_info_storage/storage_info_provider_mac.cc
index 125152b..0041224 100644
--- a/chrome/browser/extensions/api/system_info_storage/storage_info_provider_mac.cc
+++ b/chrome/browser/extensions/api/system_info_storage/storage_info_provider_mac.cc
@@ -105,11 +105,9 @@
   for (base::mac::ScopedIOObject<io_service_t> media(IOIteratorNext(iterator));
        media;
        media.reset(IOIteratorNext(iterator))) {
-    base::mac::ScopedCFTypeRef<CFTypeRef> dev_path_cf(
-        IORegistryEntryCreateCFProperty(media,
-                                        CFSTR(kIOBSDNameKey),
-                                        kCFAllocatorDefault,
-                                        0));
+    base::ScopedCFTypeRef<CFTypeRef> dev_path_cf(
+        IORegistryEntryCreateCFProperty(
+            media, CFSTR(kIOBSDNameKey), kCFAllocatorDefault, 0));
 
     if (!dev_path_cf)
       continue;
@@ -119,11 +117,9 @@
         base::SysCFStringRefToUTF8(
             base::mac::CFCast<CFStringRef>(dev_path_cf)));
 
-    base::mac::ScopedCFTypeRef<CFTypeRef> removable_cf(
-        IORegistryEntryCreateCFProperty(media,
-                                        CFSTR(kIOMediaEjectableKey),
-                                        kCFAllocatorDefault,
-                                        0));
+    base::ScopedCFTypeRef<CFTypeRef> removable_cf(
+        IORegistryEntryCreateCFProperty(
+            media, CFSTR(kIOMediaEjectableKey), kCFAllocatorDefault, 0));
     if (!removable_cf)
       dev_path_to_type_map_[dev_path] = systeminfo::kStorageTypeUnknown;
     else if (CFBooleanGetValue(base::mac::CFCast<CFBooleanRef>(removable_cf)))
diff --git a/chrome/browser/extensions/api/system_info_storage/system_info_storage_apitest.cc b/chrome/browser/extensions/api/system_info_storage/system_info_storage_apitest.cc
index 7374342..b4ca0fe 100644
--- a/chrome/browser/extensions/api/system_info_storage/system_info_storage_apitest.cc
+++ b/chrome/browser/extensions/api/system_info_storage/system_info_storage_apitest.cc
@@ -4,7 +4,7 @@
 #include "base/command_line.h"
 #include "base/message_loop.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/timer.h"
+#include "base/timer/timer.h"
 #include "chrome/browser/extensions/api/system_info_storage/storage_info_provider.h"
 #include "chrome/browser/extensions/extension_apitest.h"
 #include "chrome/browser/extensions/extension_test_message_listener.h"
diff --git a/chrome/browser/extensions/api/system_private/system_private_api.cc b/chrome/browser/extensions/api/system_private/system_private_api.cc
index bab2503..55296e3 100644
--- a/chrome/browser/extensions/api/system_private/system_private_api.cc
+++ b/chrome/browser/extensions/api/system_private/system_private_api.cc
@@ -124,7 +124,7 @@
     state = kNotAvailableState;
   }
 #endif
-  DictionaryValue* dict = new DictionaryValue();
+  base::DictionaryValue* dict = new base::DictionaryValue();
   dict->SetString(kStateKey, state);
   dict->SetDouble(kDownloadProgressKey, download_progress);
   SetResult(dict);
@@ -133,14 +133,14 @@
 }
 
 void DispatchVolumeChangedEvent(double volume, bool is_volume_muted) {
-  DictionaryValue* dict = new DictionaryValue();
+  base::DictionaryValue* dict = new base::DictionaryValue();
   dict->SetDouble(kVolumeKey, volume);
   dict->SetBoolean(kIsVolumeMutedKey, is_volume_muted);
   DispatchEvent(kOnVolumeChanged, dict);
 }
 
 void DispatchBrightnessChangedEvent(int brightness, bool user_initiated) {
-  DictionaryValue* dict = new DictionaryValue();
+  base::DictionaryValue* dict = new base::DictionaryValue();
   dict->SetInteger(kBrightnessKey, brightness);
   dict->SetBoolean(kUserInitiatedKey, user_initiated);
   DispatchEvent(kOnBrightnessChanged, dict);
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 ebb9bfc..cfef6e3 100644
--- a/chrome/browser/extensions/api/tab_capture/tab_capture_apitest.cc
+++ b/chrome/browser/extensions/api/tab_capture/tab_capture_apitest.cc
@@ -13,6 +13,7 @@
 #include "chrome/browser/extensions/extension_test_message_listener.h"
 #include "chrome/browser/extensions/tab_helper.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/fullscreen/fullscreen_controller.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/chrome_version_info.h"
 #include "chrome/common/extensions/feature_switch.h"
@@ -185,4 +186,55 @@
   EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
 }
 
+// http://crbug.com/177163
+#if defined(OS_WIN) && !defined(NDEBUG)
+#define MAYBE_FullscreenEvents DISABLED_FullscreenEvents
+#elif defined(USE_AURA) || defined(OS_MACOSX)
+// These don't always fire fullscreen events when run in tests. Tested manually.
+#define MAYBE_FullscreenEvents DISABLED_FullscreenEvents
+#elif defined(OS_LINUX)
+// Flaky to get out of fullscreen in tests. Tested manually.
+#define MAYBE_FullscreenEvents DISABLED_FullscreenEvents
+#else
+#define MAYBE_FullscreenEvents FullscreenEvents
+#endif
+IN_PROC_BROWSER_TEST_F(TabCaptureApiTest, MAYBE_FullscreenEvents) {
+#if defined(OS_WIN)
+  // TODO(justinlin): Disabled for WinXP due to timeout issues.
+  if (base::win::GetVersion() < base::win::VERSION_VISTA) {
+    return;
+  }
+#endif
+
+  AddExtensionToCommandLineWhitelist();
+
+  content::OpenURLParams params(GURL("chrome://version"),
+                                content::Referrer(),
+                                CURRENT_TAB,
+                                content::PAGE_TRANSITION_LINK, false);
+  content::WebContents* web_contents = browser()->OpenURL(params);
+
+  ExtensionTestMessageListener listeners_setup("ready1", true);
+  ExtensionTestMessageListener fullscreen_entered("ready2", true);
+
+  ASSERT_TRUE(RunExtensionSubtest("tab_capture/experimental",
+                                  "fullscreen_test.html")) << message_;
+  EXPECT_TRUE(listeners_setup.WaitUntilSatisfied());
+
+  // Toggle fullscreen after setting up listeners.
+  browser()->fullscreen_controller()->ToggleFullscreenModeForTab(web_contents,
+                                                                 true);
+  listeners_setup.Reply("");
+
+  // Toggle again after JS should have the event.
+  EXPECT_TRUE(fullscreen_entered.WaitUntilSatisfied());
+  browser()->fullscreen_controller()->ToggleFullscreenModeForTab(web_contents,
+                                                                 false);
+  fullscreen_entered.Reply("");
+
+  ResultCatcher catcher;
+  catcher.RestrictToProfile(browser()->profile());
+  EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
+}
+
 }  // namespace chrome
diff --git a/chrome/browser/extensions/api/tab_capture/tab_capture_registry.cc b/chrome/browser/extensions/api/tab_capture/tab_capture_registry.cc
index 406d9de..88d37be 100644
--- a/chrome/browser/extensions/api/tab_capture/tab_capture_registry.cc
+++ b/chrome/browser/extensions/api/tab_capture/tab_capture_registry.cc
@@ -10,11 +10,13 @@
 #include "chrome/browser/extensions/event_router.h"
 #include "chrome/browser/extensions/extension_system.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/fullscreen/fullscreen_controller.h"
 #include "chrome/common/chrome_notification_types.h"
 #include "chrome/common/extensions/extension.h"
 #include "components/browser_context_keyed_service/browser_context_dependency_manager.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/notification_details.h"
+#include "content/public/browser/notification_service.h"
 #include "content/public/browser/notification_source.h"
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/web_contents.h"
@@ -109,7 +111,9 @@
   registrar_.Add(this,
                  chrome::NOTIFICATION_EXTENSION_UNLOADED,
                  content::Source<Profile>(profile_));
-  // TODO(justinlin): Hook up HTML5 fullscreen.
+  registrar_.Add(this,
+                 chrome::NOTIFICATION_FULLSCREEN_CHANGED,
+                 content::NotificationService::AllSources());
 }
 
 TabCaptureRegistry::~TabCaptureRegistry() {
@@ -132,6 +136,7 @@
 void TabCaptureRegistry::Observe(int type,
                                  const content::NotificationSource& source,
                                  const content::NotificationDetails& details) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   switch (type) {
     case chrome::NOTIFICATION_EXTENSION_UNLOADED: {
       // Cleanup all the requested media streams for this extension.
@@ -149,7 +154,36 @@
       break;
     }
     case chrome::NOTIFICATION_FULLSCREEN_CHANGED: {
-      // TODO(justinlin): Hook up HTML5 fullscreen.
+      FullscreenController* fullscreen_controller =
+          content::Source<FullscreenController>(source).ptr();
+      const bool is_fullscreen = *content::Details<bool>(details).ptr();
+      for (ScopedVector<TabCaptureRequest>::iterator it = requests_.begin();
+           it != requests_.end(); ++it) {
+        // If we are exiting fullscreen mode, we only need to check if any of
+        // the requests had the fullscreen flag toggled previously. The
+        // fullscreen controller no longer has the reference to the fullscreen
+        // web_contents here.
+        if (!is_fullscreen) {
+          if ((*it)->fullscreen) {
+            (*it)->fullscreen = false;
+            DispatchStatusChangeEvent(*it);
+            break;
+          }
+          continue;
+        }
+
+        // If we are entering fullscreen mode, find whether the web_contents we
+        // are capturing entered fullscreen mode.
+        content::RenderViewHost* const rvh =
+            content::RenderViewHost::FromID((*it)->render_process_id,
+                                            (*it)->render_view_id);
+        if (rvh && fullscreen_controller->IsFullscreenForTabOrPending(
+                content::WebContents::FromRenderViewHost(rvh))) {
+          (*it)->fullscreen = true;
+          DispatchStatusChangeEvent(*it);
+          break;
+        }
+      }
       break;
     }
   }
@@ -278,7 +312,7 @@
   info->status = request->status;
   info->fullscreen = request->fullscreen;
 
-  scoped_ptr<base::ListValue> args(new ListValue());
+  scoped_ptr<base::ListValue> args(new base::ListValue());
   args->Append(info->ToValue().release());
   scoped_ptr<Event> event(new Event(
       extensions::event_names::kOnTabCaptureStatusChanged, args.Pass()));
diff --git a/chrome/browser/extensions/api/tabs/ash_panel_contents.cc b/chrome/browser/extensions/api/tabs/ash_panel_contents.cc
index 059847b..27b7d5e 100644
--- a/chrome/browser/extensions/api/tabs/ash_panel_contents.cc
+++ b/chrome/browser/extensions/api/tabs/ash_panel_contents.cc
@@ -13,7 +13,6 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/sessions/session_tab_helper.h"
 #include "chrome/browser/ui/extensions/native_app_window.h"
-#include "chrome/browser/ui/extensions/shell_window.h"
 #include "chrome/common/chrome_notification_types.h"
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/extension_messages.h"
@@ -21,6 +20,8 @@
 #include "content/public/browser/web_contents.h"
 #include "ui/gfx/image/image.h"
 
+using apps::ShellWindow;
+
 // AshPanelWindowController ----------------------------------------------------
 
 // This class enables a ShellWindow instance to be accessed (to a limited
@@ -78,9 +79,9 @@
     const extensions::Extension* extension) const {
   DCHECK(IsVisibleToExtension(extension));
   base::DictionaryValue* result = CreateWindowValue();
-  DictionaryValue* tab_value = CreateTabValue(extension, 0);
+  base::DictionaryValue* tab_value = CreateTabValue(extension, 0);
   if (tab_value) {
-    base::ListValue* tab_list = new ListValue();
+    base::ListValue* tab_list = new base::ListValue();
     tab_list->Append(tab_value);
     result->Set(extensions::tabs_constants::kTabsKey, tab_list);
   }
@@ -97,7 +98,7 @@
   if (!web_contents)
     return NULL;
 
-  DictionaryValue* tab_value = new DictionaryValue();
+  base::DictionaryValue* tab_value = new base::DictionaryValue();
   tab_value->SetInteger(extensions::tabs_constants::kIdKey,
                         SessionID::IdForTab(web_contents));
   tab_value->SetInteger(extensions::tabs_constants::kIndexKey, 0);
diff --git a/chrome/browser/extensions/api/tabs/ash_panel_contents.h b/chrome/browser/extensions/api/tabs/ash_panel_contents.h
index 5aa0c46..4f79971 100644
--- a/chrome/browser/extensions/api/tabs/ash_panel_contents.h
+++ b/chrome/browser/extensions/api/tabs/ash_panel_contents.h
@@ -7,11 +7,11 @@
 
 #include <vector>
 
+#include "apps/shell_window.h"
 #include "base/basictypes.h"
 #include "base/memory/scoped_ptr.h"
 #include "chrome/browser/extensions/extension_function_dispatcher.h"
 #include "chrome/browser/ui/ash/launcher/launcher_favicon_loader.h"
-#include "chrome/browser/ui/extensions/shell_window.h"
 #include "content/public/browser/web_contents_observer.h"
 
 class AshPanelWindowController;
@@ -25,20 +25,20 @@
 struct DraggableRegion;
 }
 
-// ShellWindowContents class specific to panel windows created by v1
+// apps::ShellWindowContents class specific to panel windows created by v1
 // extenstions. This class maintains a WebContents instance and observes it for
 // the purpose of passing messages to the extensions system. It also creates
 // an extensions::WindowController instance for interfacing with the v1
 // extensions API.
-class AshPanelContents : public ShellWindowContents,
+class AshPanelContents : public apps::ShellWindowContents,
                          public content::WebContentsObserver,
                          public LauncherFaviconLoader::Delegate,
                          public ExtensionFunctionDispatcher::Delegate {
  public:
-  explicit AshPanelContents(ShellWindow* host);
+  explicit AshPanelContents(apps::ShellWindow* host);
   virtual ~AshPanelContents();
 
-  // ShellWindowContents
+  // apps::ShellWindowContents
   virtual void Initialize(Profile* profile, const GURL& url) OVERRIDE;
   virtual void LoadContents(int32 creator_process_id) OVERRIDE;
   virtual void NativeWindowChanged(NativeAppWindow* native_app_window) OVERRIDE;
@@ -63,7 +63,7 @@
 
   void OnRequest(const ExtensionHostMsg_Request_Params& params);
 
-  ShellWindow* host_;
+  apps::ShellWindow* host_;
   GURL url_;
   scoped_ptr<content::WebContents> web_contents_;
   scoped_ptr<ExtensionFunctionDispatcher> extension_function_dispatcher_;
diff --git a/chrome/browser/extensions/api/tabs/tabs_api.cc b/chrome/browser/extensions/api/tabs/tabs_api.cc
index 81d938e..1a7027e 100644
--- a/chrome/browser/extensions/api/tabs/tabs_api.cc
+++ b/chrome/browser/extensions/api/tabs/tabs_api.cc
@@ -8,6 +8,7 @@
 #include <limits>
 #include <vector>
 
+#include "apps/shell_window.h"
 #include "base/base64.h"
 #include "base/bind.h"
 #include "base/command_line.h"
@@ -34,6 +35,7 @@
 #include "chrome/browser/prefs/incognito_mode_prefs.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/translate/translate_tab_helper.h"
+#include "chrome/browser/ui/apps/chrome_shell_window_delegate.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_commands.h"
 #include "chrome/browser/ui/browser_finder.h"
@@ -41,7 +43,6 @@
 #include "chrome/browser/ui/browser_navigator.h"
 #include "chrome/browser/ui/browser_tabstrip.h"
 #include "chrome/browser/ui/browser_window.h"
-#include "chrome/browser/ui/extensions/shell_window.h"
 #include "chrome/browser/ui/host_desktop.h"
 #include "chrome/browser/ui/panels/panel_manager.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
@@ -97,6 +98,7 @@
 #include "chrome/browser/extensions/shell_window_registry.h"
 #endif
 
+using apps::ShellWindow;
 using content::BrowserThread;
 using content::NavigationController;
 using content::NavigationEntry;
@@ -328,7 +330,7 @@
   if (params->get_info.get() && params->get_info->populate.get())
     populate_tabs = *params->get_info->populate;
 
-  ListValue* window_list = new ListValue();
+  base::ListValue* window_list = new base::ListValue();
   const WindowControllerList::ControllerList& windows =
       WindowControllerList::GetInstance()->windows();
   for (WindowControllerList::ControllerList::const_iterator iter =
@@ -396,7 +398,7 @@
 }
 
 bool WindowsCreateFunction::RunImpl() {
-  DictionaryValue* args = NULL;
+  base::DictionaryValue* args = NULL;
   std::vector<GURL> urls;
   TabStripModel* source_tab_strip = NULL;
   int tab_index = -1;
@@ -417,7 +419,8 @@
         url_value->GetAsString(&url_string);
         url_strings.push_back(url_string);
       } else if (url_value->IsType(Value::TYPE_LIST)) {
-        const ListValue* url_list = static_cast<const ListValue*>(url_value);
+        const base::ListValue* url_list =
+            static_cast<const base::ListValue*>(url_value);
         for (size_t i = 0; i < url_list->GetSize(); ++i) {
           std::string url_string;
           EXTENSION_FUNCTION_VALIDATE(url_list->GetString(i, &url_string));
@@ -584,8 +587,9 @@
       create_params.window_type = ShellWindow::WINDOW_TYPE_V1_PANEL;
       create_params.bounds = window_bounds;
       create_params.focused = saw_focus_key && focused;
-      ShellWindow* shell_window =
-          new ShellWindow(window_profile, GetExtension());
+      ShellWindow* shell_window = new ShellWindow(
+          window_profile, new chrome::ChromeShellWindowDelegate(),
+          GetExtension());
       AshPanelContents* ash_panel_contents = new AshPanelContents(shell_window);
       shell_window->Init(urls[0], ash_panel_contents, create_params);
       SetResult(ash_panel_contents->GetExtensionWindowController()->
@@ -689,7 +693,7 @@
 bool WindowsUpdateFunction::RunImpl() {
   int window_id = extension_misc::kUnknownWindowId;
   EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &window_id));
-  DictionaryValue* update_props;
+  base::DictionaryValue* update_props;
   EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &update_props));
 
   WindowController* controller;
@@ -795,6 +799,8 @@
       error_ = keys::kInvalidWindowStateError;
       return false;
     }
+    // TODO(varkha): Updating bounds during a drag can cause problems and a more
+    // general solution is needed. See http://crbug.com/251813 .
     controller->window()->SetBounds(bounds);
   }
 
@@ -937,7 +943,7 @@
         params->query_info.window_type);
   }
 
-  ListValue* result = new ListValue();
+  base::ListValue* result = new base::ListValue();
   for (chrome::BrowserIterator it; !it.done(); it.Next()) {
     Browser* browser = *it;
     if (!profile()->IsSameProfile(browser->profile()))
@@ -1114,7 +1120,8 @@
 
   index = std::min(std::max(index, -1), tab_strip->count());
 
-  int add_types = active ? TabStripModel::ADD_ACTIVE : TabStripModel::ADD_NONE;
+  int add_types = active ? TabStripModel::ADD_ACTIVE :
+                             TabStripModel::ADD_NONE;
   add_types |= TabStripModel::ADD_FORCE_INDEX;
   if (pinned)
     add_types |= TabStripModel::ADD_PINNED;
@@ -1134,10 +1141,8 @@
   if (opener)
     tab_strip->SetOpenerOfWebContentsAt(new_index, opener);
 
-  if (active) {
-    navigate_params.target_contents->GetDelegate()->ActivateContents(
-        navigate_params.target_contents);
-  }
+  if (active)
+    navigate_params.target_contents->GetView()->SetInitialFocus();
 
   // Return data about the newly created tab.
   if (has_callback()) {
@@ -1345,7 +1350,6 @@
       tab_strip->ActivateTabAt(tab_index, false);
       DCHECK_EQ(contents, tab_strip->GetActiveWebContents());
     }
-    web_contents_->GetDelegate()->ActivateContents(web_contents_);
   }
 
   if (params->update_properties.highlighted.get()) {
@@ -1447,10 +1451,11 @@
   SetResult(ExtensionTabUtil::CreateTabValue(web_contents_, GetExtension()));
 }
 
-void TabsUpdateFunction::OnExecuteCodeFinished(const std::string& error,
-                                              int32 on_page_id,
-                                              const GURL& url,
-                                              const ListValue& script_result) {
+void TabsUpdateFunction::OnExecuteCodeFinished(
+    const std::string& error,
+    int32 on_page_id,
+    const GURL& url,
+    const base::ListValue& script_result) {
   if (error.empty())
     PopulateResult();
   else
@@ -1464,7 +1469,7 @@
 
   int new_index = params->move_properties.index;
   int* window_id = params->move_properties.window_id.get();
-  ListValue tab_values;
+  base::ListValue tab_values;
 
   std::vector<int> tab_ids;
   if (params->tab_ids.as_array.get()) {
@@ -1503,7 +1508,7 @@
 bool TabsMoveFunction::MoveTab(int tab_id,
                                int *new_index,
                                int iteration,
-                               ListValue* tab_values,
+                               base::ListValue* tab_values,
                                int* window_id) {
   Browser* source_browser = NULL;
   TabStripModel* source_tab_strip = NULL;
@@ -1730,8 +1735,8 @@
   image_quality_ = kDefaultQuality;  // Default quality setting.
 
   if (params->options.get()) {
-    image_format_ = params->options->format;
-    EXTENSION_FUNCTION_VALIDATE(image_format_ != FormatEnum::FORMAT_NONE);
+    if (params->options->format != FormatEnum::FORMAT_NONE)
+      image_format_ = params->options->format;
 
     if (params->options->quality.get())
       image_quality_ = *params->options->quality;
@@ -2026,10 +2031,11 @@
   return false;
 }
 
-void TabsExecuteScriptFunction::OnExecuteCodeFinished(const std::string& error,
-                                                      int32 on_page_id,
-                                                      const GURL& on_url,
-                                                      const ListValue& result) {
+void TabsExecuteScriptFunction::OnExecuteCodeFinished(
+    const std::string& error,
+    int32 on_page_id,
+    const GURL& on_url,
+    const base::ListValue& result) {
   if (error.empty())
     SetResult(result.DeepCopy());
   ExecuteCodeInTabFunction::OnExecuteCodeFinished(error, on_page_id, on_url,
@@ -2046,7 +2052,7 @@
     EXTENSION_FUNCTION_VALIDATE(tab_id >= 0);
 
   // |details| are not optional.
-  DictionaryValue* details_value = NULL;
+  base::DictionaryValue* details_value = NULL;
   if (!args_->GetDictionary(1, &details_value))
     return false;
   scoped_ptr<InjectDetails> details(new InjectDetails());
diff --git a/chrome/browser/extensions/api/tabs/tabs_api.h b/chrome/browser/extensions/api/tabs/tabs_api.h
index 3b61e62..80e47a6 100644
--- a/chrome/browser/extensions/api/tabs/tabs_api.h
+++ b/chrome/browser/extensions/api/tabs/tabs_api.h
@@ -150,7 +150,7 @@
   void OnExecuteCodeFinished(const std::string& error,
                              int32 on_page_id,
                              const GURL& on_url,
-                             const ListValue& script_result);
+                             const base::ListValue& script_result);
 
   DECLARE_EXTENSION_FUNCTION("tabs.update", TABS_UPDATE)
 };
@@ -160,7 +160,7 @@
   bool MoveTab(int tab_id,
                int* new_index,
                int iteration,
-               ListValue* tab_values,
+               base::ListValue* tab_values,
                int* window_id);
   DECLARE_EXTENSION_FUNCTION("tabs.move", TABS_MOVE)
 };
@@ -253,10 +253,11 @@
  private:
   virtual ~TabsExecuteScriptFunction() {}
 
-  virtual void OnExecuteCodeFinished(const std::string& error,
-                                     int32 on_page_id,
-                                     const GURL& on_url,
-                                     const ListValue& script_result) OVERRIDE;
+  virtual void OnExecuteCodeFinished(
+      const std::string& error,
+      int32 on_page_id,
+      const GURL& on_url,
+      const base::ListValue& script_result) OVERRIDE;
 
   DECLARE_EXTENSION_FUNCTION("tabs.executeScript", TABS_EXECUTESCRIPT)
 };
diff --git a/chrome/browser/extensions/api/tabs/tabs_interactive_test.cc b/chrome/browser/extensions/api/tabs/tabs_interactive_test.cc
index 7af0c97..293f076 100644
--- a/chrome/browser/extensions/api/tabs/tabs_interactive_test.cc
+++ b/chrome/browser/extensions/api/tabs/tabs_interactive_test.cc
@@ -45,7 +45,7 @@
   // The id should always match the last focused window and does not depend
   // on what was passed to RunFunctionAndReturnSingleResult.
   EXPECT_EQ(focused_window_id, utils::GetInteger(result.get(), "id"));
-  ListValue* tabs = NULL;
+  base::ListValue* tabs = NULL;
   EXPECT_FALSE(result.get()->GetList(keys::kTabsKey, &tabs));
 
   function = new extensions::WindowsGetLastFocusedFunction();
@@ -91,11 +91,11 @@
                                               "[{\"lastFocusedWindow\":true}]",
                                               browser())));
 
-  ListValue* result_tabs = result.get();
+  base::ListValue* result_tabs = result.get();
   // We should have one initial tab and one added tab.
   EXPECT_EQ(2u, result_tabs->GetSize());
   for (size_t i = 0; i < result_tabs->GetSize(); ++i) {
-    DictionaryValue* result_tab = NULL;
+    base::DictionaryValue* result_tab = NULL;
     EXPECT_TRUE(result_tabs->GetDictionary(i, &result_tab));
     EXPECT_EQ(focused_window_id, utils::GetInteger(result_tab,
                                                    keys::kWindowIdKey));
@@ -112,7 +112,7 @@
   // We should get one tab for each extra window and one for the initial window.
   EXPECT_EQ(kExtraWindows + 1, result_tabs->GetSize());
   for (size_t i = 0; i < result_tabs->GetSize(); ++i) {
-    DictionaryValue* result_tab = NULL;
+    base::DictionaryValue* result_tab = NULL;
     EXPECT_TRUE(result_tabs->GetDictionary(i, &result_tab));
     EXPECT_NE(focused_window_id, utils::GetInteger(result_tab,
                                                    keys::kWindowIdKey));
diff --git a/chrome/browser/extensions/api/tabs/tabs_test.cc b/chrome/browser/extensions/api/tabs/tabs_test.cc
index 821d254..0ce9e1f 100644
--- a/chrome/browser/extensions/api/tabs/tabs_test.cc
+++ b/chrome/browser/extensions/api/tabs/tabs_test.cc
@@ -83,7 +83,7 @@
 
   EXPECT_EQ(window_id, utils::GetInteger(result.get(), "id"));
   // "populate" was enabled so tabs should be populated.
-  ListValue* tabs = NULL;
+  base::ListValue* tabs = NULL;
   EXPECT_TRUE(result.get()->GetList(keys::kTabsKey, &tabs));
 
   // TODO(aa): Can't assume window is focused. On mac, calling Activate() from a
@@ -153,7 +153,7 @@
   // The id should match the window id of the browser instance that was passed
   // to RunFunctionAndReturnSingleResult.
   EXPECT_EQ(new_id, utils::GetInteger(result.get(), "id"));
-  ListValue* tabs = NULL;
+  base::ListValue* tabs = NULL;
   EXPECT_FALSE(result.get()->GetList(keys::kTabsKey, &tabs));
 
   // Get the current window using the old window and make the tabs populated.
@@ -190,15 +190,15 @@
                                               "[]",
                                               browser())));
 
-  ListValue* windows = result.get();
+  base::ListValue* windows = result.get();
   EXPECT_EQ(NUM_WINDOWS, windows->GetSize());
   for (size_t i = 0; i < NUM_WINDOWS; ++i) {
-    DictionaryValue* result_window = NULL;
+    base::DictionaryValue* result_window = NULL;
     EXPECT_TRUE(windows->GetDictionary(i, &result_window));
     result_ids.insert(utils::GetInteger(result_window, "id"));
 
     // "populate" was not passed in so tabs are not populated.
-    ListValue* tabs = NULL;
+    base::ListValue* tabs = NULL;
     EXPECT_FALSE(result_window->GetList(keys::kTabsKey, &tabs));
   }
   // The returned ids should contain all the current browser instance ids.
@@ -215,12 +215,12 @@
   windows = result.get();
   EXPECT_EQ(NUM_WINDOWS, windows->GetSize());
   for (size_t i = 0; i < windows->GetSize(); ++i) {
-    DictionaryValue* result_window = NULL;
+    base::DictionaryValue* result_window = NULL;
     EXPECT_TRUE(windows->GetDictionary(i, &result_window));
     result_ids.insert(utils::GetInteger(result_window, "id"));
 
     // "populate" was enabled so tabs should be populated.
-    ListValue* tabs = NULL;
+    base::ListValue* tabs = NULL;
     EXPECT_TRUE(result_window->GetList(keys::kTabsKey, &tabs));
   }
   // The returned ids should contain all the current browser instance ids.
@@ -404,11 +404,11 @@
                                               "[{\"currentWindow\":true}]",
                                               browser())));
 
-  ListValue* result_tabs = result.get();
+  base::ListValue* result_tabs = result.get();
   // We should have one initial tab and one added tab.
   EXPECT_EQ(2u, result_tabs->GetSize());
   for (size_t i = 0; i < result_tabs->GetSize(); ++i) {
-    DictionaryValue* result_tab = NULL;
+    base::DictionaryValue* result_tab = NULL;
     EXPECT_TRUE(result_tabs->GetDictionary(i, &result_tab));
     EXPECT_EQ(window_id, utils::GetInteger(result_tab, keys::kWindowIdKey));
   }
@@ -425,7 +425,7 @@
   // We should have one tab for each extra window.
   EXPECT_EQ(kExtraWindows, result_tabs->GetSize());
   for (size_t i = 0; i < kExtraWindows; ++i) {
-    DictionaryValue* result_tab = NULL;
+    base::DictionaryValue* result_tab = NULL;
     EXPECT_TRUE(result_tabs->GetDictionary(i, &result_tab));
     EXPECT_NE(window_id, utils::GetInteger(result_tab, keys::kWindowIdKey));
   }
diff --git a/chrome/browser/extensions/api/tabs/windows_event_router.cc b/chrome/browser/extensions/api/tabs/windows_event_router.cc
index 2880c3a..54d9b2d 100644
--- a/chrome/browser/extensions/api/tabs/windows_event_router.cc
+++ b/chrome/browser/extensions/api/tabs/windows_event_router.cc
@@ -57,8 +57,9 @@
   if (!profile_->IsSameProfile(window_controller->profile()))
     return;
 
-  scoped_ptr<base::ListValue> args(new ListValue());
-  DictionaryValue* window_dictionary = window_controller->CreateWindowValue();
+  scoped_ptr<base::ListValue> args(new base::ListValue());
+  base::DictionaryValue* window_dictionary =
+      window_controller->CreateWindowValue();
   args->Append(window_dictionary);
   DispatchEvent(event_names::kOnWindowCreated, window_controller->profile(),
                 args.Pass());
@@ -70,7 +71,7 @@
     return;
 
   int window_id = window_controller->GetWindowId();
-  scoped_ptr<base::ListValue> args(new ListValue());
+  scoped_ptr<base::ListValue> args(new base::ListValue());
   args->Append(Value::CreateIntegerValue(window_id));
   DispatchEvent(event_names::kOnWindowRemoved, window_controller->profile(),
                 args.Pass());
@@ -107,7 +108,7 @@
                                            int window_id,
                                            Profile* profile,
                                            const Extension* extension,
-                                           ListValue* event_args) {
+                                           base::ListValue* event_args) {
   // When switching between windows in the default and incognito profiles,
   // dispatch WINDOW_ID_NONE to extensions whose profile lost focus that
   // can't see the new focused window across the incognito boundary.
@@ -143,7 +144,7 @@
   focused_window_id_ = window_id;
 
   scoped_ptr<Event> event(new Event(event_names::kOnWindowFocusedChanged,
-                                    make_scoped_ptr(new ListValue())));
+                                    make_scoped_ptr(new base::ListValue())));
   event->will_dispatch_callback =
       base::Bind(&WillDispatchWindowFocusedEvent, window_profile, window_id);
   ExtensionSystem::Get(profile_)->event_router()->BroadcastEvent(event.Pass());
diff --git a/chrome/browser/extensions/api/test/test_api.cc b/chrome/browser/extensions/api/test/test_api.cc
index 207cc91..c6efce0 100644
--- a/chrome/browser/extensions/api/test/test_api.cc
+++ b/chrome/browser/extensions/api/test/test_api.cc
@@ -98,7 +98,7 @@
       CreateIncognitoTab::Params::Create(*args_));
   EXTENSION_FUNCTION_VALIDATE(params.get());
   chrome::OpenURLOffTheRecord(profile(), GURL(params->url),
-                              chrome::HOST_DESKTOP_TYPE_NATIVE);
+                              chrome::GetActiveDesktop());
   return true;
 }
 
@@ -124,7 +124,7 @@
 
 // static
 void TestGetConfigFunction::set_test_config_state(
-    DictionaryValue* value) {
+    base::DictionaryValue* value) {
   TestConfigState* test_config_state = TestConfigState::GetInstance();
   test_config_state->set_config_state(value);
 }
diff --git a/chrome/browser/extensions/api/test/test_api.h b/chrome/browser/extensions/api/test/test_api.h
index 5c0df7d..fa0c2ab 100644
--- a/chrome/browser/extensions/api/test/test_api.h
+++ b/chrome/browser/extensions/api/test/test_api.h
@@ -98,7 +98,7 @@
 
   // Set the dictionary returned by chrome.test.getConfig().
   // Does not take ownership of |value|.
-  static void set_test_config_state(DictionaryValue* value);
+  static void set_test_config_state(base::DictionaryValue* value);
 
  protected:
   // Tests that set configuration state do so by calling
@@ -109,11 +109,11 @@
    public:
     static TestConfigState* GetInstance();
 
-    void set_config_state(DictionaryValue* config_state) {
+    void set_config_state(base::DictionaryValue* config_state) {
       config_state_ = config_state;
     }
 
-    const DictionaryValue* config_state() {
+    const base::DictionaryValue* config_state() {
       return config_state_;
     }
 
@@ -121,7 +121,7 @@
     friend struct DefaultSingletonTraits<TestConfigState>;
     TestConfigState();
 
-    DictionaryValue* config_state_;
+    base::DictionaryValue* config_state_;
 
     DISALLOW_COPY_AND_ASSIGN(TestConfigState);
   };
diff --git a/chrome/browser/extensions/api/top_sites/top_sites_api.cc b/chrome/browser/extensions/api/top_sites/top_sites_api.cc
index 84d31a3..77d5a93 100644
--- a/chrome/browser/extensions/api/top_sites/top_sites_api.cc
+++ b/chrome/browser/extensions/api/top_sites/top_sites_api.cc
@@ -30,11 +30,11 @@
 
 void TopSitesGetFunction::OnMostVisitedURLsAvailable(
     const history::MostVisitedURLList& data) {
-  scoped_ptr<base::ListValue> pages_value(new ListValue);
+  scoped_ptr<base::ListValue> pages_value(new base::ListValue);
   for (size_t i = 0; i < data.size(); i++) {
     const history::MostVisitedURL& url = data[i];
     if (!url.url.is_empty()) {
-      DictionaryValue* page_value = new DictionaryValue();
+      base::DictionaryValue* page_value = new base::DictionaryValue();
       page_value->SetString("url", url.url.spec());
       if (url.title.empty())
         page_value->SetString("title", url.url.spec());
diff --git a/chrome/browser/extensions/api/usb/usb_api.cc b/chrome/browser/extensions/api/usb/usb_api.cc
index 29aa7c3..c4bb050 100644
--- a/chrome/browser/extensions/api/usb/usb_api.cc
+++ b/chrome/browser/extensions/api/usb/usb_api.cc
@@ -321,7 +321,7 @@
   descriptor.alternate_setting = alternate_setting;
   descriptor.interface_class = interface_class;
   descriptor.interface_subclass = interface_subclass;
-  descriptor.interface_protocol = interface_subclass;
+  descriptor.interface_protocol = interface_protocol;
   descriptor.endpoints = *endpoints;
   return descriptor.ToValue().release();
 }
diff --git a/chrome/browser/extensions/api/web_navigation/web_navigation_api_helpers.cc b/chrome/browser/extensions/api/web_navigation/web_navigation_api_helpers.cc
index 84b94cc..86213ee 100644
--- a/chrome/browser/extensions/api/web_navigation/web_navigation_api_helpers.cc
+++ b/chrome/browser/extensions/api/web_navigation/web_navigation_api_helpers.cc
@@ -8,7 +8,7 @@
 
 #include "base/json/json_writer.h"
 #include "base/strings/string_number_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "base/values.h"
 #include "chrome/browser/extensions/api/web_navigation/web_navigation_api_constants.h"
 #include "chrome/browser/extensions/event_router.h"
@@ -37,7 +37,7 @@
 // Dispatches events to the extension message service.
 void DispatchEvent(content::BrowserContext* browser_context,
                    const char* event_name,
-                   scoped_ptr<ListValue> args,
+                   scoped_ptr<base::ListValue> args,
                    const GURL& url) {
   EventFilteringInfo info;
   info.SetURL(url);
@@ -65,8 +65,8 @@
                               int64 parent_frame_id,
                               bool parent_is_main_frame,
                               const GURL& validated_url) {
-  scoped_ptr<ListValue> args(new ListValue());
-  DictionaryValue* dict = new DictionaryValue();
+  scoped_ptr<base::ListValue> args(new base::ListValue());
+  base::DictionaryValue* dict = new base::DictionaryValue();
   dict->SetInteger(keys::kTabIdKey, ExtensionTabUtil::GetTabId(web_contents));
   dict->SetString(keys::kUrlKey, validated_url.spec());
   dict->SetInteger(keys::kProcessIdKey, render_process_id);
@@ -90,8 +90,8 @@
                          bool is_main_frame,
                          const GURL& url,
                          content::PageTransition transition_type) {
-  scoped_ptr<ListValue> args(new ListValue());
-  DictionaryValue* dict = new DictionaryValue();
+  scoped_ptr<base::ListValue> args(new base::ListValue());
+  base::DictionaryValue* dict = new base::DictionaryValue();
   dict->SetInteger(keys::kTabIdKey, ExtensionTabUtil::GetTabId(web_contents));
   dict->SetString(keys::kUrlKey, url.spec());
   dict->SetInteger(keys::kProcessIdKey,
@@ -100,7 +100,7 @@
   dict->SetString(
       keys::kTransitionTypeKey,
       content::PageTransitionGetCoreTransitionString(transition_type));
-  ListValue* qualifiers = new ListValue();
+  base::ListValue* qualifiers = new base::ListValue();
   if (transition_type & content::PAGE_TRANSITION_CLIENT_REDIRECT)
     qualifiers->Append(Value::CreateStringValue("client_redirect"));
   if (transition_type & content::PAGE_TRANSITION_SERVER_REDIRECT)
@@ -122,8 +122,8 @@
                                 const GURL& url,
                                 bool is_main_frame,
                                 int64 frame_id) {
-  scoped_ptr<ListValue> args(new ListValue());
-  DictionaryValue* dict = new DictionaryValue();
+  scoped_ptr<base::ListValue> args(new base::ListValue());
+  base::DictionaryValue* dict = new base::DictionaryValue();
   dict->SetInteger(keys::kTabIdKey,
                    ExtensionTabUtil::GetTabId(web_contents));
   dict->SetString(keys::kUrlKey, url.spec());
@@ -144,8 +144,8 @@
                          const GURL& url,
                          bool is_main_frame,
                          int64 frame_id) {
-  scoped_ptr<ListValue> args(new ListValue());
-  DictionaryValue* dict = new DictionaryValue();
+  scoped_ptr<base::ListValue> args(new base::ListValue());
+  base::DictionaryValue* dict = new base::DictionaryValue();
   dict->SetInteger(keys::kTabIdKey,
                    ExtensionTabUtil::GetTabId(web_contents));
   dict->SetString(keys::kUrlKey, url.spec());
@@ -174,8 +174,8 @@
       Profile::FromBrowserContext(target_web_contents->GetBrowserContext()),
       false, NULL, NULL, NULL, NULL));
 
-  scoped_ptr<ListValue> args(new ListValue());
-  DictionaryValue* dict = new DictionaryValue();
+  scoped_ptr<base::ListValue> args(new base::ListValue());
+  base::DictionaryValue* dict = new base::DictionaryValue();
   dict->SetInteger(keys::kSourceTabIdKey,
                    ExtensionTabUtil::GetTabId(web_contents));
   dict->SetInteger(keys::kSourceProcessIdKey,
@@ -199,8 +199,8 @@
                              int64 frame_id,
                              bool is_main_frame,
                              int error_code) {
-  scoped_ptr<ListValue> args(new ListValue());
-  DictionaryValue* dict = new DictionaryValue();
+  scoped_ptr<base::ListValue> args(new base::ListValue());
+  base::DictionaryValue* dict = new base::DictionaryValue();
   dict->SetInteger(keys::kTabIdKey, ExtensionTabUtil::GetTabId(web_contents));
   dict->SetString(keys::kUrlKey, url.spec());
   dict->SetInteger(keys::kProcessIdKey, render_process_id);
@@ -218,8 +218,8 @@
     content::WebContents* old_web_contents,
     content::BrowserContext* browser_context,
     content::WebContents* new_web_contents) {
-  scoped_ptr<ListValue> args(new ListValue());
-  DictionaryValue* dict = new DictionaryValue();
+  scoped_ptr<base::ListValue> args(new base::ListValue());
+  base::DictionaryValue* dict = new base::DictionaryValue();
   dict->SetInteger(keys::kReplacedTabIdKey,
                    ExtensionTabUtil::GetTabId(old_web_contents));
   dict->SetInteger(keys::kTabIdKey,
diff --git a/chrome/browser/extensions/api/web_navigation/web_navigation_apitest.cc b/chrome/browser/extensions/api/web_navigation/web_navigation_apitest.cc
index d0b3aeb..d57a78e 100644
--- a/chrome/browser/extensions/api/web_navigation/web_navigation_apitest.cc
+++ b/chrome/browser/extensions/api/web_navigation/web_navigation_apitest.cc
@@ -37,6 +37,7 @@
 #include "content/public/common/url_constants.h"
 #include "content/public/test/browser_test_utils.h"
 #include "net/dns/mock_host_resolver.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
 #include "third_party/WebKit/public/web/WebContextMenuData.h"
 #include "third_party/WebKit/public/web/WebInputEvent.h"
 #include "webkit/glue/resource_type.h"
@@ -360,7 +361,6 @@
         switches::kAllowLegacyExtensionManifests);
 
     host_resolver()->AddRule("*", "127.0.0.1");
-    ASSERT_TRUE(StartTestServer());
   }
 
   virtual void TearDownInProcessBrowserTestFixture() OVERRIDE {
@@ -387,6 +387,7 @@
 #define MAYBE_Api Api
 #endif  // defined(OS_WIN)
 IN_PROC_BROWSER_TEST_F(WebNavigationApiTest, MAYBE_Api) {
+  ASSERT_TRUE(StartEmbeddedTestServer());
   ASSERT_TRUE(
       RunExtensionSubtest("webnavigation", "test_api.html")) << message_;
 }
@@ -398,17 +399,20 @@
 #define MAYBE_GetFrame GetFrame
 #endif  // defined(OS_WIN)
 IN_PROC_BROWSER_TEST_F(WebNavigationApiTest, MAYBE_GetFrame) {
+  ASSERT_TRUE(StartEmbeddedTestServer());
   ASSERT_TRUE(
       RunExtensionSubtest("webnavigation", "test_getFrame.html")) << message_;
 }
 
 IN_PROC_BROWSER_TEST_F(WebNavigationApiTest, ClientRedirect) {
+  ASSERT_TRUE(StartEmbeddedTestServer());
   ASSERT_TRUE(
       RunExtensionSubtest("webnavigation", "test_clientRedirect.html"))
           << message_;
 }
 
 IN_PROC_BROWSER_TEST_F(WebNavigationApiTest, ServerRedirect) {
+  ASSERT_TRUE(StartEmbeddedTestServer());
   ASSERT_TRUE(
       RunExtensionSubtest("webnavigation", "test_serverRedirect.html"))
           << message_;
@@ -423,6 +427,8 @@
 #endif
 IN_PROC_BROWSER_TEST_F(WebNavigationApiTest,
                        MAYBE_ServerRedirectSingleProcess) {
+  ASSERT_TRUE(StartEmbeddedTestServer());
+
   // Set max renderers to 1 to force running out of processes.
   content::RenderProcessHost::SetMaxRendererProcessCount(1);
 
@@ -437,15 +443,15 @@
   ResultCatcher catcher;
   GURL url(base::StringPrintf(
       "http://www.a.com:%d/"
-          "files/extensions/api_test/webnavigation/serverRedirect/a.html",
-      test_server()->host_port_pair().port()));
+          "extensions/api_test/webnavigation/serverRedirect/a.html",
+      embedded_test_server()->port()));
 
   ui_test_utils::NavigateToURL(browser(), url);
 
   url = GURL(base::StringPrintf(
       "http://www.b.com:%d/server-redirect?http://www.b.com:%d/",
-      test_server()->host_port_pair().port(),
-      test_server()->host_port_pair().port()));
+      embedded_test_server()->port(),
+      embedded_test_server()->port()));
 
   ui_test_utils::NavigateToURL(browser(), url);
 
@@ -453,33 +459,39 @@
 }
 
 IN_PROC_BROWSER_TEST_F(WebNavigationApiTest, ForwardBack) {
+  ASSERT_TRUE(StartEmbeddedTestServer());
   ASSERT_TRUE(
       RunExtensionSubtest("webnavigation", "test_forwardBack.html"))
           << message_;
 }
 
 IN_PROC_BROWSER_TEST_F(WebNavigationApiTest, IFrame) {
+  ASSERT_TRUE(StartEmbeddedTestServer());
   ASSERT_TRUE(
       RunExtensionSubtest("webnavigation", "test_iframe.html")) << message_;
 }
 
 IN_PROC_BROWSER_TEST_F(WebNavigationApiTest, SrcDoc) {
+  ASSERT_TRUE(StartEmbeddedTestServer());
   ASSERT_TRUE(
       RunExtensionSubtest("webnavigation", "test_srcdoc.html")) << message_;
 }
 
 IN_PROC_BROWSER_TEST_F(WebNavigationApiTest, OpenTab) {
+  ASSERT_TRUE(StartEmbeddedTestServer());
   ASSERT_TRUE(
       RunExtensionSubtest("webnavigation", "test_openTab.html")) << message_;
 }
 
 IN_PROC_BROWSER_TEST_F(WebNavigationApiTest, ReferenceFragment) {
+  ASSERT_TRUE(StartEmbeddedTestServer());
   ASSERT_TRUE(
       RunExtensionSubtest("webnavigation", "test_referenceFragment.html"))
           << message_;
 }
 
 IN_PROC_BROWSER_TEST_F(WebNavigationApiTest, SimpleLoad) {
+  ASSERT_TRUE(StartEmbeddedTestServer());
   ASSERT_TRUE(
       RunExtensionSubtest("webnavigation", "test_simpleLoad.html")) << message_;
 }
@@ -491,11 +503,13 @@
 #define MAYBE_Failures Failures
 #endif  // defined(OS_WIN)
 IN_PROC_BROWSER_TEST_F(WebNavigationApiTest, MAYBE_Failures) {
+  ASSERT_TRUE(StartEmbeddedTestServer());
   ASSERT_TRUE(
       RunExtensionSubtest("webnavigation", "test_failures.html")) << message_;
 }
 
 IN_PROC_BROWSER_TEST_F(WebNavigationApiTest, FilteredTest) {
+  ASSERT_TRUE(StartEmbeddedTestServer());
   ASSERT_TRUE(
       RunExtensionSubtest("webnavigation", "test_filtered.html")) << message_;
 }
@@ -507,6 +521,8 @@
 #define MAYBE_UserAction UserAction
 #endif  // defined(OS_WIN)
 IN_PROC_BROWSER_TEST_F(WebNavigationApiTest, MAYBE_UserAction) {
+  ASSERT_TRUE(StartEmbeddedTestServer());
+
   // Wait for the extension to set itself up and return control to us.
   ASSERT_TRUE(
       RunExtensionSubtest("webnavigation", "test_userAction.html")) << message_;
@@ -547,6 +563,8 @@
 #define MAYBE_RequestOpenTab RequestOpenTab
 #endif
 IN_PROC_BROWSER_TEST_F(WebNavigationApiTest, MAYBE_RequestOpenTab) {
+  ASSERT_TRUE(StartEmbeddedTestServer());
+
   // Wait for the extension to set itself up and return control to us.
   ASSERT_TRUE(RunExtensionSubtest("webnavigation", "test_requestOpenTab.html"))
       << message_;
@@ -585,6 +603,8 @@
 #define MAYBE_TargetBlank TargetBlank
 #endif  // defined(OS_WIN)
 IN_PROC_BROWSER_TEST_F(WebNavigationApiTest, MAYBE_TargetBlank) {
+  ASSERT_TRUE(StartEmbeddedTestServer());
+
   // Wait for the extension to set itself up and return control to us.
   ASSERT_TRUE(RunExtensionSubtest("webnavigation", "test_targetBlank.html"))
       << message_;
@@ -594,8 +614,8 @@
 
   ResultCatcher catcher;
 
-  GURL url = test_server()->GetURL(
-      "files/extensions/api_test/webnavigation/targetBlank/a.html");
+  GURL url = embedded_test_server()->GetURL(
+      "/extensions/api_test/webnavigation/targetBlank/a.html");
 
   chrome::NavigateParams params(browser(), url, content::PAGE_TRANSITION_LINK);
   ui_test_utils::NavigateToURL(&params);
@@ -622,6 +642,8 @@
 #define MAYBE_TargetBlankIncognito TargetBlankIncognito
 #endif
 IN_PROC_BROWSER_TEST_F(WebNavigationApiTest, MAYBE_TargetBlankIncognito) {
+  ASSERT_TRUE(StartEmbeddedTestServer());
+
   // Wait for the extension to set itself up and return control to us.
   ASSERT_TRUE(RunExtensionSubtest(
       "webnavigation", "test_targetBlank.html",
@@ -629,8 +651,8 @@
 
   ResultCatcher catcher;
 
-  GURL url = test_server()->GetURL(
-      "files/extensions/api_test/webnavigation/targetBlank/a.html");
+  GURL url = embedded_test_server()->GetURL(
+      "/extensions/api_test/webnavigation/targetBlank/a.html");
 
   Browser* otr_browser = ui_test_utils::OpenURLOffTheRecord(
       browser()->profile(), url);
@@ -652,12 +674,15 @@
 }
 
 IN_PROC_BROWSER_TEST_F(WebNavigationApiTest, History) {
+  ASSERT_TRUE(StartEmbeddedTestServer());
   ASSERT_TRUE(
       RunExtensionSubtest("webnavigation", "test_history.html"))
           << message_;
 }
 
 IN_PROC_BROWSER_TEST_F(WebNavigationApiTest, CrossProcess) {
+  ASSERT_TRUE(StartEmbeddedTestServer());
+
   LoadExtension(test_data_dir_.AppendASCII("webnavigation").AppendASCII("app"));
   LoadExtension(test_data_dir_.AppendASCII("webnavigation"));
 
@@ -669,7 +694,7 @@
   // See crossProcess/d.html.
   DelayLoadStartAndExecuteJavascript call_script(
       test_navigation_listener(),
-      test_server()->GetURL("test1"),
+      embedded_test_server()->GetURL("/test1"),
       "navigate2()",
       extension->GetResourceURL("crossProcess/empty.html"));
 
@@ -679,6 +704,8 @@
 }
 
 IN_PROC_BROWSER_TEST_F(WebNavigationApiTest, CrossProcessFragment) {
+  ASSERT_TRUE(StartEmbeddedTestServer());
+
   LoadExtension(test_data_dir_.AppendASCII("webnavigation"));
 
   ExtensionService* service = extensions::ExtensionSystem::Get(
@@ -689,20 +716,20 @@
   // See crossProcess/f.html.
   DelayLoadStartAndExecuteJavascript call_script3(
       test_navigation_listener(),
-      test_server()->GetURL("test3"),
+      embedded_test_server()->GetURL("/test3"),
       "updateFragment()",
       extension->GetResourceURL(base::StringPrintf(
           "crossProcess/f.html?%d#foo",
-          test_server()->host_port_pair().port())));
+          embedded_test_server()->port())));
 
   // See crossProcess/g.html.
   DelayLoadStartAndExecuteJavascript call_script4(
       test_navigation_listener(),
-      test_server()->GetURL("test4"),
+      embedded_test_server()->GetURL("/test4"),
       "updateFragment()",
       extension->GetResourceURL(base::StringPrintf(
           "crossProcess/g.html?%d#foo",
-          test_server()->host_port_pair().port())));
+          embedded_test_server()->port())));
 
   ASSERT_TRUE(RunPageTest(
       extension->GetResourceURL("test_crossProcessFragment.html").spec()))
@@ -710,6 +737,8 @@
 }
 
 IN_PROC_BROWSER_TEST_F(WebNavigationApiTest, CrossProcessHistory) {
+  ASSERT_TRUE(StartEmbeddedTestServer());
+
   LoadExtension(test_data_dir_.AppendASCII("webnavigation"));
 
   ExtensionService* service = extensions::ExtensionSystem::Get(
@@ -720,21 +749,21 @@
   // See crossProcess/e.html.
   DelayLoadStartAndExecuteJavascript call_script2(
       test_navigation_listener(),
-      test_server()->GetURL("test2"),
+      embedded_test_server()->GetURL("/test2"),
       "updateHistory()",
       extension->GetResourceURL("crossProcess/empty.html"));
 
   // See crossProcess/h.html.
   DelayLoadStartAndExecuteJavascript call_script5(
       test_navigation_listener(),
-      test_server()->GetURL("test5"),
+      embedded_test_server()->GetURL("/test5"),
       "updateHistory()",
       extension->GetResourceURL("crossProcess/empty.html"));
 
   // See crossProcess/i.html.
   DelayLoadStartAndExecuteJavascript call_script6(
       test_navigation_listener(),
-      test_server()->GetURL("test6"),
+      embedded_test_server()->GetURL("/test6"),
       "updateHistory()",
       extension->GetResourceURL("crossProcess/empty.html"));
 
@@ -750,6 +779,8 @@
 #define MAYBE_Crash Crash
 #endif
 IN_PROC_BROWSER_TEST_F(WebNavigationApiTest, MAYBE_Crash) {
+  ASSERT_TRUE(StartEmbeddedTestServer());
+
   // Wait for the extension to set itself up and return control to us.
   ASSERT_TRUE(RunExtensionSubtest("webnavigation", "test_crash.html"))
       << message_;
@@ -761,16 +792,16 @@
 
   GURL url(base::StringPrintf(
       "http://www.a.com:%d/"
-          "files/extensions/api_test/webnavigation/crash/a.html",
-      test_server()->host_port_pair().port()));
+          "extensions/api_test/webnavigation/crash/a.html",
+      embedded_test_server()->port()));
   ui_test_utils::NavigateToURL(browser(), url);
 
   ui_test_utils::NavigateToURL(browser(), GURL(content::kChromeUICrashURL));
 
   url = GURL(base::StringPrintf(
       "http://www.a.com:%d/"
-          "files/extensions/api_test/webnavigation/crash/b.html",
-      test_server()->host_port_pair().port()));
+          "extensions/api_test/webnavigation/crash/b.html",
+      embedded_test_server()->port()));
   ui_test_utils::NavigateToURL(browser(), url);
 
   ASSERT_TRUE(catcher.GetNextResult()) << catcher.message();
diff --git a/chrome/browser/extensions/api/web_request/upload_data_presenter_unittest.cc b/chrome/browser/extensions/api/web_request/upload_data_presenter_unittest.cc
index 5e06660..c445982 100644
--- a/chrome/browser/extensions/api/web_request/upload_data_presenter_unittest.cc
+++ b/chrome/browser/extensions/api/web_request/upload_data_presenter_unittest.cc
@@ -9,11 +9,6 @@
 #include "net/base/upload_bytes_element_reader.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-using base::BinaryValue;
-using base::ListValue;
-using base::StringValue;
-using base::Value;
-
 namespace keys = extension_web_request_api_constants;
 
 namespace extensions {
@@ -27,9 +22,9 @@
   net::UploadBytesElementReader element(block, sizeof(block) - 1);
 
   // Expected output.
-  scoped_ptr<ListValue> values(new ListValue);
-  values->Append(Value::CreateStringValue("value"));
-  DictionaryValue expected_form;
+  scoped_ptr<base::ListValue> values(new base::ListValue);
+  values->Append(base::Value::CreateStringValue("value"));
+  base::DictionaryValue expected_form;
   expected_form.SetWithoutPathExpansion("key.with.dots", values.release());
 
   // Real output.
@@ -38,7 +33,7 @@
   ASSERT_TRUE(parsed_data_presenter.get() != NULL);
   parsed_data_presenter->FeedNext(element);
   EXPECT_TRUE(parsed_data_presenter->Succeeded());
-  scoped_ptr<Value> result = parsed_data_presenter->Result();
+  scoped_ptr<base::Value> result = parsed_data_presenter->Result();
   ASSERT_TRUE(result.get() != NULL);
 
   EXPECT_TRUE(result->Equals(&expected_form));
@@ -53,16 +48,17 @@
   const size_t block2_size = sizeof(block2) - 1;
 
   // Expected output.
-  scoped_ptr<BinaryValue> expected_a(
-      BinaryValue::CreateWithCopiedBuffer(block1, block1_size));
+  scoped_ptr<base::BinaryValue> expected_a(
+      base::BinaryValue::CreateWithCopiedBuffer(block1, block1_size));
   ASSERT_TRUE(expected_a.get() != NULL);
-  scoped_ptr<StringValue> expected_b(Value::CreateStringValue(kFilename));
+  scoped_ptr<base::StringValue> expected_b(
+      base::Value::CreateStringValue(kFilename));
   ASSERT_TRUE(expected_b.get() != NULL);
-  scoped_ptr<BinaryValue> expected_c(
-      BinaryValue::CreateWithCopiedBuffer(block2, block2_size));
+  scoped_ptr<base::BinaryValue> expected_c(
+      base::BinaryValue::CreateWithCopiedBuffer(block2, block2_size));
   ASSERT_TRUE(expected_c.get() != NULL);
 
-  ListValue expected_list;
+  base::ListValue expected_list;
   subtle::AppendKeyValuePair(
       keys::kRequestBodyRawBytesKey, expected_a.release(), &expected_list);
   subtle::AppendKeyValuePair(
@@ -76,7 +72,7 @@
   raw_presenter.FeedNextFile(kFilename);
   raw_presenter.FeedNextBytes(block2, block2_size);
   EXPECT_TRUE(raw_presenter.Succeeded());
-  scoped_ptr<Value> result = raw_presenter.Result();
+  scoped_ptr<base::Value> result = raw_presenter.Result();
   ASSERT_TRUE(result.get() != NULL);
 
   EXPECT_TRUE(result->Equals(&expected_list));
diff --git a/chrome/browser/extensions/api/web_request/web_request_api.cc b/chrome/browser/extensions/api/web_request/web_request_api.cc
index 06b9cb4..38e35f3 100644
--- a/chrome/browser/extensions/api/web_request/web_request_api.cc
+++ b/chrome/browser/extensions/api/web_request/web_request_api.cc
@@ -13,7 +13,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chrome_content_browser_client.h"
diff --git a/chrome/browser/extensions/api/web_request/web_request_api.h b/chrome/browser/extensions/api/web_request/web_request_api.h
index 3a0d43e..1f717f4 100644
--- a/chrome/browser/extensions/api/web_request/web_request_api.h
+++ b/chrome/browser/extensions/api/web_request/web_request_api.h
@@ -13,7 +13,7 @@
 
 #include "base/memory/singleton.h"
 #include "base/memory/weak_ptr.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/extensions/api/declarative_webrequest/request_stage.h"
 #include "chrome/browser/extensions/api/web_request/web_request_api_helpers.h"
 #include "chrome/browser/extensions/api/web_request/web_request_permissions.h"
diff --git a/chrome/browser/extensions/api/web_request/web_request_api_helpers.cc b/chrome/browser/extensions/api/web_request/web_request_api_helpers.cc
index f083906..058f122 100644
--- a/chrome/browser/extensions/api/web_request/web_request_api_helpers.cc
+++ b/chrome/browser/extensions/api/web_request/web_request_api_helpers.cc
@@ -10,7 +10,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/extensions/api/web_request/web_request_api.h"
@@ -216,10 +216,10 @@
 Value* NetLogModificationCallback(
     const EventResponseDelta* delta,
     net::NetLog::LogLevel log_level) {
-  DictionaryValue* dict = new DictionaryValue();
+  base::DictionaryValue* dict = new base::DictionaryValue();
   dict->SetString("extension_id", delta->extension_id);
 
-  ListValue* modified_headers = new ListValue();
+  base::ListValue* modified_headers = new base::ListValue();
   net::HttpRequestHeaders::Iterator modification(
       delta->modified_request_headers);
   while (modification.GetNext()) {
@@ -228,7 +228,7 @@
   }
   dict->Set("modified_headers", modified_headers);
 
-  ListValue* deleted_headers = new ListValue();
+  base::ListValue* deleted_headers = new base::ListValue();
   for (std::vector<std::string>::const_iterator key =
            delta->deleted_request_headers.begin();
        key != delta->deleted_request_headers.end();
@@ -245,8 +245,8 @@
   return a->extension_install_time > b->extension_install_time;
 }
 
-ListValue* StringToCharList(const std::string& s) {
-  ListValue* result = new ListValue;
+base::ListValue* StringToCharList(const std::string& s) {
+  base::ListValue* result = new base::ListValue;
   for (size_t i = 0, n = s.size(); i < n; ++i) {
     result->Append(
         Value::CreateIntegerValue(
@@ -255,7 +255,7 @@
   return result;
 }
 
-bool CharListToString(const ListValue* list, std::string* out) {
+bool CharListToString(const base::ListValue* list, std::string* out) {
   if (!list)
     return false;
   const size_t list_length = list->GetSize();
diff --git a/chrome/browser/extensions/api/web_request/web_request_api_helpers.h b/chrome/browser/extensions/api/web_request/web_request_api_helpers.h
index d14f5ca..76325b3 100644
--- a/chrome/browser/extensions/api/web_request/web_request_api_helpers.h
+++ b/chrome/browser/extensions/api/web_request/web_request_api_helpers.h
@@ -11,10 +11,10 @@
 #include <set>
 #include <string>
 
-#include "base/memory/ref_counted.h"
 #include "base/memory/linked_ptr.h"
+#include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/extensions/extension_warning_set.h"
 #include "googleurl/src/gurl.h"
 #include "net/base/auth.h"
diff --git a/chrome/browser/extensions/api/web_request/web_request_api_unittest.cc b/chrome/browser/extensions/api/web_request/web_request_api_unittest.cc
index 0e58bdc..408ed01 100644
--- a/chrome/browser/extensions/api/web_request/web_request_api_unittest.cc
+++ b/chrome/browser/extensions/api/web_request/web_request_api_unittest.cc
@@ -19,7 +19,7 @@
 #include "base/strings/string_piece.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/content_settings/cookie_settings.h"
 #include "chrome/browser/extensions/api/web_request/upload_data_presenter.h"
 #include "chrome/browser/extensions/api/web_request/web_request_api.h"
diff --git a/chrome/browser/extensions/api/web_request/web_request_apitest.cc b/chrome/browser/extensions/api/web_request/web_request_apitest.cc
index 767eeec..0cca09d 100644
--- a/chrome/browser/extensions/api/web_request/web_request_apitest.cc
+++ b/chrome/browser/extensions/api/web_request/web_request_apitest.cc
@@ -22,6 +22,7 @@
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/browser_test_utils.h"
 #include "net/dns/mock_host_resolver.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
 #include "third_party/WebKit/public/web/WebInputEvent.h"
 
 using content::WebContents;
@@ -64,7 +65,6 @@
 
     ExtensionApiTest::SetUpInProcessBrowserTestFixture();
     host_resolver()->AddRule("*", "127.0.0.1");
-    ASSERT_TRUE(StartTestServer());
   }
 
   void RunPermissionTest(
@@ -76,6 +76,7 @@
 };
 
 IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest, WebRequestApi) {
+  ASSERT_TRUE(StartEmbeddedTestServer());
   ASSERT_TRUE(RunExtensionSubtest("webrequest", "test_api.html")) << message_;
 }
 
@@ -86,11 +87,13 @@
 #define MAYBE_WebRequestSimple WebRequestSimple
 #endif  // defined(OS_WIN)
 IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest, MAYBE_WebRequestSimple) {
+  ASSERT_TRUE(StartEmbeddedTestServer());
   ASSERT_TRUE(RunExtensionSubtest("webrequest", "test_simple.html")) <<
       message_;
 }
 
 IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest, WebRequestComplex) {
+  ASSERT_TRUE(StartEmbeddedTestServer());
   ASSERT_TRUE(RunExtensionSubtest("webrequest", "test_complex.html")) <<
       message_;
 }
@@ -100,6 +103,7 @@
                        DISABLED_WebRequestAuthRequired) {
   CancelLoginDialog login_dialog_helper;
 
+  ASSERT_TRUE(StartEmbeddedTestServer());
   ASSERT_TRUE(RunExtensionSubtest("webrequest", "test_auth_required.html")) <<
       message_;
 }
@@ -111,6 +115,7 @@
 #define MAYBE_WebRequestBlocking WebRequestBlocking
 #endif
 IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest, MAYBE_WebRequestBlocking) {
+  ASSERT_TRUE(StartEmbeddedTestServer());
   ASSERT_TRUE(RunExtensionSubtest("webrequest", "test_blocking.html")) <<
       message_;
 }
@@ -122,6 +127,7 @@
 #define MAYBE_WebRequestNewTab WebRequestNewTab
 #endif  // defined(OS_WIN)
 IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest, MAYBE_WebRequestNewTab) {
+  ASSERT_TRUE(StartEmbeddedTestServer());
   // Wait for the extension to set itself up and return control to us.
   ASSERT_TRUE(RunExtensionSubtest("webrequest", "test_newTab.html"))
       << message_;
@@ -155,6 +161,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest, WebRequestDeclarative1) {
+  ASSERT_TRUE(StartEmbeddedTestServer());
   ASSERT_TRUE(RunExtensionSubtest("webrequest", "test_declarative1.html"))
       << message_;
 }
@@ -167,6 +174,7 @@
 #endif
 IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest,
                        MAYBE_WebRequestDeclarative2) {
+  ASSERT_TRUE(StartEmbeddedTestServer());
   ASSERT_TRUE(RunExtensionSubtest("webrequest", "test_declarative2.html"))
       << message_;
 }
@@ -200,7 +208,7 @@
   // This navigation should be redirected.
   ui_test_utils::NavigateToURL(
       browser(),
-      test_server()->GetURL("files/extensions/test_file.html"));
+      embedded_test_server()->GetURL("/extensions/test_file.html"));
 
   std::string body;
   WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents();
@@ -221,7 +229,7 @@
   // load_extension_with_incognito_permission is true.
   ui_test_utils::NavigateToURL(
       otr_browser,
-      test_server()->GetURL("files/extensions/test_file.html"));
+      embedded_test_server()->GetURL("/extensions/test_file.html"));
 
   body.clear();
   WebContents* otr_tab = otr_browser->tab_strip_model()->GetActiveWebContents();
@@ -235,12 +243,14 @@
 IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest,
                        WebRequestDeclarativePermissionSpanning1) {
   // Test spanning with incognito permission.
+  ASSERT_TRUE(StartEmbeddedTestServer());
   RunPermissionTest("spanning", true, false, "redirected1", "redirected1");
 }
 
 IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest,
                        WebRequestDeclarativePermissionSpanning2) {
   // Test spanning without incognito permission.
+  ASSERT_TRUE(StartEmbeddedTestServer());
   RunPermissionTest("spanning", false, false, "redirected1", "");
 }
 
@@ -248,12 +258,14 @@
 IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest,
                        WebRequestDeclarativePermissionSplit1) {
   // Test split with incognito permission.
+  ASSERT_TRUE(StartEmbeddedTestServer());
   RunPermissionTest("split", true, true, "redirected1", "redirected2");
 }
 
 IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest,
                        WebRequestDeclarativePermissionSplit2) {
   // Test split without incognito permission.
+  ASSERT_TRUE(StartEmbeddedTestServer());
   RunPermissionTest("split", false, false, "redirected1", "");
 }
 
@@ -267,18 +279,21 @@
 #endif
 IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest, MAYBE_PostData1) {
   // Test HTML form POST data access with the default and "url" encoding.
+  ASSERT_TRUE(StartEmbeddedTestServer());
   ASSERT_TRUE(RunExtensionSubtest("webrequest", "test_post1.html")) <<
       message_;
 }
 
 IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest, MAYBE_PostData2) {
   // Test HTML form POST data access with the multipart and plaintext encoding.
+  ASSERT_TRUE(StartEmbeddedTestServer());
   ASSERT_TRUE(RunExtensionSubtest("webrequest", "test_post2.html")) <<
       message_;
 }
 
 IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest,
                        DeclarativeSendMessage) {
+  ASSERT_TRUE(StartEmbeddedTestServer());
   ASSERT_TRUE(RunExtensionTest("webrequest_sendmessage")) << message_;
 }
 
@@ -286,6 +301,7 @@
 // has two active background pages with registered events does not crash the
 // browser. Regression test for http://crbug.com/224094
 IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest, IncognitoSplitModeReload) {
+  ASSERT_TRUE(StartEmbeddedTestServer());
   // Wait for rules to be set up.
   ExtensionTestMessageListener listener("done", true);
   ExtensionTestMessageListener listener_incognito("done_incognito", true);
diff --git a/chrome/browser/extensions/api/web_request/web_request_time_tracker.h b/chrome/browser/extensions/api/web_request/web_request_time_tracker.h
index fc58aa0..ff33e70 100644
--- a/chrome/browser/extensions/api/web_request/web_request_time_tracker.h
+++ b/chrome/browser/extensions/api/web_request/web_request_time_tracker.h
@@ -12,7 +12,7 @@
 
 #include "base/gtest_prod_util.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "googleurl/src/gurl.h"
 
 namespace base {
diff --git a/chrome/browser/extensions/api/web_socket_proxy_private/web_socket_proxy_private_api.cc b/chrome/browser/extensions/api/web_socket_proxy_private/web_socket_proxy_private_api.cc
index 91483c5..3e551a3 100644
--- a/chrome/browser/extensions/api/web_socket_proxy_private/web_socket_proxy_private_api.cc
+++ b/chrome/browser/extensions/api/web_socket_proxy_private/web_socket_proxy_private_api.cc
@@ -171,7 +171,7 @@
 
 bool WebSocketProxyPrivateGetURLForTCPFunction::RunImpl() {
 #if defined(OS_CHROMEOS)
-  DictionaryValue* qualification = NULL;
+  base::DictionaryValue* qualification = NULL;
   if (args_->GetDictionary(2, &qualification)) {
     const char kTlsOption[] = "tls";
     if (qualification->HasKey(kTlsOption)) {
diff --git a/chrome/browser/extensions/api/web_socket_proxy_private/web_socket_proxy_private_api.h b/chrome/browser/extensions/api/web_socket_proxy_private/web_socket_proxy_private_api.h
index 29677a6..bec791e 100644
--- a/chrome/browser/extensions/api/web_socket_proxy_private/web_socket_proxy_private_api.h
+++ b/chrome/browser/extensions/api/web_socket_proxy_private/web_socket_proxy_private_api.h
@@ -5,7 +5,7 @@
 #ifndef CHROME_BROWSER_EXTENSIONS_API_WEB_SOCKET_PROXY_PRIVATE_WEB_SOCKET_PROXY_PRIVATE_API_H_
 #define CHROME_BROWSER_EXTENSIONS_API_WEB_SOCKET_PROXY_PRIVATE_WEB_SOCKET_PROXY_PRIVATE_API_H_
 
-#include "base/timer.h"
+#include "base/timer/timer.h"
 #include "chrome/browser/extensions/extension_function.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
diff --git a/chrome/browser/extensions/api/web_socket_proxy_private/web_socket_proxy_private_apitest.cc b/chrome/browser/extensions/api/web_socket_proxy_private/web_socket_proxy_private_apitest.cc
index d75832c..c417921 100644
--- a/chrome/browser/extensions/api/web_socket_proxy_private/web_socket_proxy_private_apitest.cc
+++ b/chrome/browser/extensions/api/web_socket_proxy_private/web_socket_proxy_private_apitest.cc
@@ -18,7 +18,7 @@
 IN_PROC_BROWSER_TEST_F(ExtensionWebSocketProxyPrivateApiTest, Pass) {
   // Currently WebSocket-to-TCP proxy is operational only on ChromeOS platform.
 #if defined(OS_CHROMEOS)
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
   ASSERT_TRUE(RunExtensionTest("web_socket_proxy_private")) << message_;
   // Check if API still works on subsequent calls.
   ASSERT_TRUE(RunExtensionTest("web_socket_proxy_private")) << message_;
diff --git a/chrome/browser/extensions/api/webstore_private/webstore_private_api.cc b/chrome/browser/extensions/api/webstore_private/webstore_private_api.cc
index 9d25844..2f398b5 100644
--- a/chrome/browser/extensions/api/webstore_private/webstore_private_api.cc
+++ b/chrome/browser/extensions/api/webstore_private/webstore_private_api.cc
@@ -20,8 +20,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/install_tracker.h"
-#include "chrome/browser/extensions/install_tracker_factory.h"
 #include "chrome/browser/extensions/webstore_installer.h"
 #include "chrome/browser/gpu/gpu_feature_checker.h"
 #include "chrome/browser/profiles/profile_manager.h"
@@ -168,8 +166,8 @@
 
 // Helper to create a dictionary with login properties set from the appropriate
 // values in the passed-in |profile|.
-DictionaryValue* CreateLoginResult(Profile* profile) {
-  DictionaryValue* dictionary = new DictionaryValue();
+base::DictionaryValue* CreateLoginResult(Profile* profile) {
+  base::DictionaryValue* dictionary = new base::DictionaryValue();
   std::string username = profile->GetPrefs()->GetString(
       prefs::kGoogleServicesUsername);
   dictionary->SetString(kLoginKey, username);
@@ -222,7 +220,7 @@
 InstallBundleFunction::~InstallBundleFunction() {}
 
 bool InstallBundleFunction::RunImpl() {
-  ListValue* extensions = NULL;
+  base::ListValue* extensions = NULL;
   EXTENSION_FUNCTION_VALIDATE(args_->GetList(0, &extensions));
 
   BundleInstaller::ItemList items;
@@ -237,10 +235,10 @@
   return true;
 }
 
-bool InstallBundleFunction::ReadBundleInfo(ListValue* extensions,
+bool InstallBundleFunction::ReadBundleInfo(base::ListValue* extensions,
                                            BundleInstaller::ItemList* items) {
   for (size_t i = 0; i < extensions->GetSize(); ++i) {
-    DictionaryValue* details = NULL;
+    base::DictionaryValue* details = NULL;
     EXTENSION_FUNCTION_VALIDATE(extensions->GetDictionary(i, &details));
 
     BundleInstaller::Item item;
@@ -286,7 +284,7 @@
 BeginInstallWithManifestFunction::~BeginInstallWithManifestFunction() {}
 
 bool BeginInstallWithManifestFunction::RunImpl() {
-  DictionaryValue* details = NULL;
+  base::DictionaryValue* details = NULL;
   EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &details));
   CHECK(details);
 
@@ -401,7 +399,7 @@
 void BeginInstallWithManifestFunction::OnWebstoreParseSuccess(
     const std::string& id,
     const SkBitmap& icon,
-    DictionaryValue* parsed_manifest) {
+    base::DictionaryValue* parsed_manifest) {
   CHECK_EQ(id_, id);
   CHECK(parsed_manifest);
   icon_ = icon;
@@ -584,20 +582,9 @@
     LOG(ERROR) << "Error installing app launcher";
   std::string id = approval_->extension_id;
   if (apps::IsAppLauncherEnabled()) {
-    std::string name;
-    if (!approval_->manifest->value()->GetString(extension_manifest_keys::kName,
-                                                 &name)) {
-      NOTREACHED();
-    }
     // Show the app list so it receives install progress notifications.
     if (approval_->manifest->is_app())
       AppListService::Get()->ShowAppList(profile());
-
-    extensions::InstallTracker* tracker =
-        extensions::InstallTrackerFactory::GetForProfile(profile());
-    tracker->OnBeginExtensionInstall(
-        id, name, approval_->installing_icon, approval_->manifest->is_app(),
-        approval_->manifest->is_platform_app());
   }
 
   // The extension will install through the normal extension install flow, but
@@ -626,9 +613,6 @@
     const std::string& id,
     const std::string& error,
     WebstoreInstaller::FailureReason reason) {
-  extensions::InstallTracker* tracker =
-      extensions::InstallTrackerFactory::GetForProfile(profile());
-  tracker->OnInstallFailure(id);
   if (test_webstore_installer_delegate) {
     test_webstore_installer_delegate->OnExtensionInstallFailure(
         id, error, reason);
@@ -643,14 +627,6 @@
   Release();
 }
 
-void CompleteInstallFunction::OnExtensionDownloadProgress(
-    const std::string& id,
-    content::DownloadItem* item) {
-  extensions::InstallTracker* tracker =
-      extensions::InstallTrackerFactory::GetForProfile(profile());
-  tracker->OnDownloadProgress(id, item->PercentComplete());
-}
-
 EnableAppLauncherFunction::EnableAppLauncherFunction() {}
 
 EnableAppLauncherFunction::~EnableAppLauncherFunction() {}
@@ -714,4 +690,11 @@
   return true;
 }
 
+bool IsInIncognitoModeFunction::RunImpl() {
+  SetResult(
+      Value::CreateBooleanValue(profile_ != profile_->GetOriginalProfile()));
+  SendResponse(true);
+  return true;
+}
+
 }  // namespace extensions
diff --git a/chrome/browser/extensions/api/webstore_private/webstore_private_api.h b/chrome/browser/extensions/api/webstore_private/webstore_private_api.h
index 18ef67f..5866259 100644
--- a/chrome/browser/extensions/api/webstore_private/webstore_private_api.h
+++ b/chrome/browser/extensions/api/webstore_private/webstore_private_api.h
@@ -182,9 +182,6 @@
       const std::string& id,
       const std::string& error,
       WebstoreInstaller::FailureReason reason) OVERRIDE;
-  virtual void OnExtensionDownloadProgress(
-      const std::string& id,
-      content::DownloadItem* item) OVERRIDE;
 
  protected:
   virtual ~CompleteInstallFunction();
@@ -290,6 +287,20 @@
   void OnIsLauncherCheckCompleted(bool is_enabled);
 };
 
+class IsInIncognitoModeFunction : public AsyncExtensionFunction {
+ public:
+  DECLARE_EXTENSION_FUNCTION("webstorePrivate.isInIncognitoMode",
+                             WEBSTOREPRIVATE_ISININCOGNITOMODEFUNCTION)
+
+  IsInIncognitoModeFunction() {}
+
+ protected:
+  virtual ~IsInIncognitoModeFunction() {}
+
+  // ExtensionFunction:
+  virtual bool RunImpl() OVERRIDE;
+};
+
 }  // namespace extensions
 
 #endif  // CHROME_BROWSER_EXTENSIONS_API_WEBSTORE_PRIVATE_WEBSTORE_PRIVATE_API_H_
diff --git a/chrome/browser/extensions/api/webstore_private/webstore_private_apitest.cc b/chrome/browser/extensions/api/webstore_private/webstore_private_apitest.cc
index 40ddd5b..ad7dfbe 100644
--- a/chrome/browser/extensions/api/webstore_private/webstore_private_apitest.cc
+++ b/chrome/browser/extensions/api/webstore_private/webstore_private_apitest.cc
@@ -191,7 +191,7 @@
   base::ScopedTempDir temp_dir;
   EXPECT_TRUE(temp_dir.CreateUniqueTempDir());
   base::FilePath missing_directory = temp_dir.Take();
-  EXPECT_TRUE(file_util::Delete(missing_directory, true));
+  EXPECT_TRUE(base::Delete(missing_directory, true));
   WebstoreInstaller::SetDownloadDirectoryForTests(&missing_directory);
 
   // Now run the install test, which should succeed.
@@ -199,7 +199,7 @@
 
   // Cleanup.
   if (file_util::DirectoryExists(missing_directory))
-    EXPECT_TRUE(file_util::Delete(missing_directory, true));
+    EXPECT_TRUE(base::Delete(missing_directory, true));
 }
 
 // Tests passing a localized name.
@@ -241,6 +241,17 @@
   ASSERT_EQ("iladmdjkfniedhfhcfoefgojhgaiaccc", listener.id());
 }
 
+IN_PROC_BROWSER_TEST_F(ExtensionWebstorePrivateApiTest, IsInIncognitoMode) {
+  GURL page_url = GetTestServerURL("incognito.html");
+  ASSERT_TRUE(
+      RunPageTest(page_url.spec(), ExtensionApiTest::kFlagUseIncognito));
+}
+
+IN_PROC_BROWSER_TEST_F(ExtensionWebstorePrivateApiTest, IsNotInIncognitoMode) {
+  GURL page_url = GetTestServerURL("not_incognito.html");
+  ASSERT_TRUE(RunPageTest(page_url.spec()));
+}
+
 // Fails often on Windows dbg bots. http://crbug.com/177163.
 #if defined(OS_WIN)
 #define MAYBE_IconUrl DISABLED_IconUrl
diff --git a/chrome/browser/extensions/api/webview/webview_api.cc b/chrome/browser/extensions/api/webview/webview_api.cc
index a5be9df..c342072 100644
--- a/chrome/browser/extensions/api/webview/webview_api.cc
+++ b/chrome/browser/extensions/api/webview/webview_api.cc
@@ -5,7 +5,7 @@
 #include "chrome/browser/extensions/api/webview/webview_api.h"
 
 #include "chrome/browser/extensions/tab_helper.h"
-#include "chrome/browser/webview/webview_guest.h"
+#include "chrome/browser/guestview/webview/webview_guest.h"
 #include "chrome/common/extensions/api/webview.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_view_host.h"
@@ -32,7 +32,7 @@
   if (!guest_instance_id_)
     return false;
 
-  DictionaryValue* details_value = NULL;
+  base::DictionaryValue* details_value = NULL;
   if (!args_->GetDictionary(1, &details_value))
     return false;
   scoped_ptr<InjectDetails> details(new InjectDetails());
@@ -52,7 +52,7 @@
 }
 
 extensions::ScriptExecutor* WebviewExecuteCodeFunction::GetScriptExecutor() {
-  chrome::WebViewGuest* guest = chrome::WebViewGuest::From(
+  WebViewGuest* guest = WebViewGuest::From(
       render_view_host()->GetProcess()->GetID(), guest_instance_id_);
   if (!guest)
     return NULL;
@@ -64,11 +64,14 @@
   return true;
 }
 
+WebviewExecuteScriptFunction::WebviewExecuteScriptFunction() {
+}
+
 void WebviewExecuteScriptFunction::OnExecuteCodeFinished(
     const std::string& error,
     int32 on_page_id,
     const GURL& on_url,
-    const ListValue& result) {
+    const base::ListValue& result) {
   content::RecordAction(content::UserMetricsAction("WebView.ExecuteScript"));
   if (error.empty())
     SetResult(result.DeepCopy());
@@ -76,7 +79,31 @@
                                                     result);
 }
 
+WebviewInsertCSSFunction::WebviewInsertCSSFunction() {
+}
+
 bool WebviewInsertCSSFunction::ShouldInsertCSS() const {
   return true;
 }
 
+WebviewGoFunction::WebviewGoFunction() {
+}
+
+WebviewGoFunction::~WebviewGoFunction() {
+}
+
+bool WebviewGoFunction::RunImpl() {
+  int instance_id = 0;
+  EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &instance_id));
+
+  int relative_index = 0;
+  EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(1, &relative_index));
+
+  WebViewGuest* guest = WebViewGuest::From(
+      render_view_host()->GetProcess()->GetID(), instance_id);
+  if (!guest)
+    return false;
+
+  guest->Go(relative_index);
+  return true;
+}
diff --git a/chrome/browser/extensions/api/webview/webview_api.h b/chrome/browser/extensions/api/webview/webview_api.h
index c525e2c..a015119 100644
--- a/chrome/browser/extensions/api/webview/webview_api.h
+++ b/chrome/browser/extensions/api/webview/webview_api.h
@@ -27,26 +27,57 @@
   extensions::ExtensionResource resource_;
 
   int guest_instance_id_;
+
+  DISALLOW_COPY_AND_ASSIGN(WebviewExecuteCodeFunction);
 };
 
 class WebviewExecuteScriptFunction : public WebviewExecuteCodeFunction {
+ public:
+  WebviewExecuteScriptFunction();
+
  protected:
   virtual ~WebviewExecuteScriptFunction() {}
 
   virtual void OnExecuteCodeFinished(const std::string& error,
                                      int32 on_page_id,
                                      const GURL& on_url,
-                                     const ListValue& result) OVERRIDE;
+                                     const base::ListValue& result) OVERRIDE;
 
   DECLARE_EXTENSION_FUNCTION("webview.executeScript", WEBVIEW_EXECUTESCRIPT)
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(WebviewExecuteScriptFunction);
 };
 
 class WebviewInsertCSSFunction : public WebviewExecuteCodeFunction {
+ public:
+  WebviewInsertCSSFunction();
+
  protected:
   virtual ~WebviewInsertCSSFunction() {}
 
   virtual bool ShouldInsertCSS() const OVERRIDE;
 
   DECLARE_EXTENSION_FUNCTION("webview.insertCSS", WEBVIEW_INSERTCSS)
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(WebviewInsertCSSFunction);
 };
+
+class WebviewGoFunction : public AsyncExtensionFunction {
+ public:
+  DECLARE_EXTENSION_FUNCTION("webview.go", WEBVIEW_GO);
+
+  WebviewGoFunction();
+
+ protected:
+  virtual ~WebviewGoFunction();
+
+  // ExtensionFunction implementation.
+  virtual bool RunImpl() OVERRIDE;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(WebviewGoFunction);
+};
+
 #endif  // CHROME_BROWSER_EXTENSIONS_API_WEBVIEW_WEBVIEW_API_H_
diff --git a/chrome/browser/extensions/app_background_page_apitest.cc b/chrome/browser/extensions/app_background_page_apitest.cc
index 773c528..75fe6cf 100644
--- a/chrome/browser/extensions/app_background_page_apitest.cc
+++ b/chrome/browser/extensions/app_background_page_apitest.cc
@@ -20,6 +20,7 @@
 #include "content/public/test/test_notification_tracker.h"
 #include "content/public/test/test_utils.h"
 #include "net/dns/mock_host_resolver.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
 
 #if defined(OS_MACOSX)
 #include "base/mac/scoped_nsautorelease_pool.h"
@@ -114,7 +115,7 @@
 
 IN_PROC_BROWSER_TEST_F(AppBackgroundPageApiTest, MAYBE_Basic) {
   host_resolver()->AddRule("a.com", "127.0.0.1");
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
 
   std::string app_manifest = base::StringPrintf(
       "{"
@@ -131,7 +132,7 @@
       "  },"
       "  \"permissions\": [\"background\"]"
       "}",
-      test_server()->host_port_pair().port());
+      embedded_test_server()->port());
 
   base::FilePath app_dir;
   ASSERT_TRUE(CreateApp(app_manifest, &app_dir));
@@ -147,7 +148,7 @@
 // Crashy, http://crbug.com/69215.
 IN_PROC_BROWSER_TEST_F(AppBackgroundPageApiTest, DISABLED_LacksPermission) {
   host_resolver()->AddRule("a.com", "127.0.0.1");
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
 
   std::string app_manifest = base::StringPrintf(
       "{"
@@ -163,7 +164,7 @@
       "    }"
       "  }"
       "}",
-      test_server()->host_port_pair().port());
+      embedded_test_server()->port());
 
   base::FilePath app_dir;
   ASSERT_TRUE(CreateApp(app_manifest, &app_dir));
@@ -175,7 +176,7 @@
 
 IN_PROC_BROWSER_TEST_F(AppBackgroundPageApiTest, ManifestBackgroundPage) {
   host_resolver()->AddRule("a.com", "127.0.0.1");
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
 
   std::string app_manifest = base::StringPrintf(
       "{"
@@ -195,8 +196,8 @@
       "    \"page\": \"http://a.com:%d/test.html\""
       "  }"
       "}",
-      test_server()->host_port_pair().port(),
-      test_server()->host_port_pair().port());
+      embedded_test_server()->port(),
+      embedded_test_server()->port());
 
   base::FilePath app_dir;
   ASSERT_TRUE(CreateApp(app_manifest, &app_dir));
@@ -223,7 +224,7 @@
       content::Source<Profile>(browser()->profile()));
 
   host_resolver()->AddRule("a.com", "127.0.0.1");
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
 
   std::string app_manifest = base::StringPrintf(
       "{"
@@ -243,7 +244,7 @@
       "    \"allow_js_access\": false"
       "  }"
       "}",
-      test_server()->host_port_pair().port());
+      embedded_test_server()->port());
 
   base::FilePath app_dir;
   ASSERT_TRUE(CreateApp(app_manifest, &app_dir));
@@ -267,7 +268,7 @@
 
 IN_PROC_BROWSER_TEST_F(AppBackgroundPageApiTest, NoJsManifestBackgroundPage) {
   host_resolver()->AddRule("a.com", "127.0.0.1");
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
 
   std::string app_manifest = base::StringPrintf(
       "{"
@@ -288,8 +289,8 @@
       "    \"allow_js_access\": false"
       "  }"
       "}",
-      test_server()->host_port_pair().port(),
-      test_server()->host_port_pair().port());
+      embedded_test_server()->port(),
+      embedded_test_server()->port());
 
   base::FilePath app_dir;
   ASSERT_TRUE(CreateApp(app_manifest, &app_dir));
@@ -307,7 +308,7 @@
 
 IN_PROC_BROWSER_TEST_F(AppBackgroundPageApiTest, OpenTwoBackgroundPages) {
   host_resolver()->AddRule("a.com", "127.0.0.1");
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
 
   std::string app_manifest = base::StringPrintf(
       "{"
@@ -324,7 +325,7 @@
       "  },"
       "  \"permissions\": [\"background\"]"
       "}",
-      test_server()->host_port_pair().port());
+      embedded_test_server()->port());
 
   base::FilePath app_dir;
   ASSERT_TRUE(CreateApp(app_manifest, &app_dir));
@@ -336,7 +337,7 @@
 
 IN_PROC_BROWSER_TEST_F(AppBackgroundPageApiTest, OpenTwoPagesWithManifest) {
   host_resolver()->AddRule("a.com", "127.0.0.1");
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
 
   std::string app_manifest = base::StringPrintf(
       "{"
@@ -356,8 +357,8 @@
       "  },"
       "  \"permissions\": [\"background\"]"
       "}",
-      test_server()->host_port_pair().port(),
-      test_server()->host_port_pair().port());
+      embedded_test_server()->port(),
+      embedded_test_server()->port());
 
   base::FilePath app_dir;
   ASSERT_TRUE(CreateApp(app_manifest, &app_dir));
@@ -371,7 +372,7 @@
 // Times out occasionally -- see crbug.com/108493
 IN_PROC_BROWSER_TEST_F(AppBackgroundPageApiTest, DISABLED_OpenPopupFromBGPage) {
   host_resolver()->AddRule("a.com", "127.0.0.1");
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
 
   std::string app_manifest = base::StringPrintf(
       "{"
@@ -386,12 +387,12 @@
       "      \"web_url\": \"http://a.com:%d/\""
       "    }"
       "  },"
-      "  \"background\": { \"page\": \"http://a.com:%d/files/extensions/api_test/"
+      "  \"background\": { \"page\": \"http://a.com:%d/extensions/api_test/"
       "app_background_page/bg_open/bg_open_bg.html\" },"
       "  \"permissions\": [\"background\"]"
       "}",
-      test_server()->host_port_pair().port(),
-      test_server()->host_port_pair().port());
+      embedded_test_server()->port(),
+      embedded_test_server()->port());
 
   base::FilePath app_dir;
   ASSERT_TRUE(CreateApp(app_manifest, &app_dir));
@@ -401,7 +402,7 @@
 
 IN_PROC_BROWSER_TEST_F(AppBackgroundPageApiTest, DISABLED_OpenThenClose) {
   host_resolver()->AddRule("a.com", "127.0.0.1");
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
 
   std::string app_manifest = base::StringPrintf(
       "{"
@@ -418,7 +419,7 @@
       "  },"
       "  \"permissions\": [\"background\"]"
       "}",
-      test_server()->host_port_pair().port());
+      embedded_test_server()->port());
 
   base::FilePath app_dir;
   ASSERT_TRUE(CreateApp(app_manifest, &app_dir));
@@ -447,7 +448,7 @@
 
 IN_PROC_BROWSER_TEST_F(AppBackgroundPageApiTest, UnloadExtensionWhileHidden) {
   host_resolver()->AddRule("a.com", "127.0.0.1");
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
 
   std::string app_manifest = base::StringPrintf(
       "{"
@@ -467,8 +468,8 @@
       "    \"page\": \"http://a.com:%d/test.html\""
       "  }"
       "}",
-      test_server()->host_port_pair().port(),
-      test_server()->host_port_pair().port());
+      embedded_test_server()->port(),
+      embedded_test_server()->port());
 
   base::FilePath app_dir;
   ASSERT_TRUE(CreateApp(app_manifest, &app_dir));
diff --git a/chrome/browser/extensions/app_process_apitest.cc b/chrome/browser/extensions/app_process_apitest.cc
index f47eb7b..e48b29d 100644
--- a/chrome/browser/extensions/app_process_apitest.cc
+++ b/chrome/browser/extensions/app_process_apitest.cc
@@ -28,6 +28,7 @@
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/test_navigation_observer.h"
 #include "net/dns/mock_host_resolver.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
 #include "sync/api/string_ordinal.h"
 
 using content::NavigationController;
@@ -44,8 +45,8 @@
     GURL::Replacements replace_host;
     std::string host_str("localhost");  // must stay in scope with replace_host
     replace_host.SetHostStr(host_str);
-    GURL base_url = test_server()->GetURL(
-        "files/extensions/api_test/" + test_directory + "/");
+    GURL base_url = embedded_test_server()->GetURL(
+        "/extensions/api_test/" + test_directory + "/");
     return base_url.ReplaceComponents(replace_host);
   }
 
@@ -67,7 +68,7 @@
         browser()->profile())->extension_service()->process_map();
 
     host_resolver()->AddRule("*", "127.0.0.1");
-    ASSERT_TRUE(test_server()->Start());
+    ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
 
     ASSERT_TRUE(LoadExtension(
         test_data_dir_.AppendASCII(app_name)));
@@ -144,7 +145,7 @@
       browser()->profile())->extension_service()->process_map();
 
   host_resolver()->AddRule("*", "127.0.0.1");
-  ASSERT_TRUE(test_server()->Start());
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
 
   ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("app_process")));
 
@@ -291,7 +292,7 @@
   extensions::ProcessMap* process_map = service->process_map();
 
   host_resolver()->AddRule("*", "127.0.0.1");
-  ASSERT_TRUE(test_server()->Start());
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
   GURL base_url = GetTestBaseURL("app_process");
 
   // Load an app as a bookmark app.
@@ -371,7 +372,7 @@
 // See http://crbug.com/61757
 IN_PROC_BROWSER_TEST_F(AppApiTest, AppProcessRedirectBack) {
   host_resolver()->AddRule("*", "127.0.0.1");
-  ASSERT_TRUE(test_server()->Start());
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
 
   ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("app_process")));
 
@@ -397,7 +398,7 @@
   // 3 tabs, including the initial about:blank. The last 2 should be the same
   // process.
   ASSERT_EQ(3, browser()->tab_strip_model()->count());
-  EXPECT_EQ("/files/extensions/api_test/app_process/path1/empty.html",
+  EXPECT_EQ("/extensions/api_test/app_process/path1/empty.html",
             browser()->tab_strip_model()->GetWebContentsAt(2)->
                 GetController().GetLastCommittedEntry()->GetURL().path());
   EXPECT_EQ(browser()->tab_strip_model()->GetWebContentsAt(1)->
@@ -416,7 +417,7 @@
       browser()->profile())->extension_service()->process_map();
 
   host_resolver()->AddRule("*", "127.0.0.1");
-  ASSERT_TRUE(test_server()->Start());
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
 
   // The app under test acts on URLs whose host is "localhost",
   // so the URLs we navigate to must have host "localhost".
@@ -463,7 +464,7 @@
       browser()->profile())->extension_service()->process_map();
 
   host_resolver()->AddRule("*", "127.0.0.1");
-  ASSERT_TRUE(test_server()->Start());
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
 
   // The app under test acts on URLs whose host is "localhost",
   // so the URLs we navigate to must have host "localhost".
@@ -528,7 +529,7 @@
       browser()->profile())->extension_service()->process_map();
 
   host_resolver()->AddRule("*", "127.0.0.1");
-  ASSERT_TRUE(test_server()->Start());
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
 
   // The app under test acts on URLs whose host is "localhost",
   // so the URLs we navigate to must have host "localhost".
@@ -602,7 +603,7 @@
       browser()->profile())->extension_service()->process_map();
 
   host_resolver()->AddRule("*", "127.0.0.1");
-  ASSERT_TRUE(test_server()->Start());
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
 
   GURL base_url = GetTestBaseURL("app_process");
 
@@ -638,7 +639,7 @@
 #endif
 IN_PROC_BROWSER_TEST_F(BlockedAppApiTest, MAYBE_OpenAppFromIframe) {
   host_resolver()->AddRule("*", "127.0.0.1");
-  ASSERT_TRUE(test_server()->Start());
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
 
   // Load app and start URL (not in the app).
   const Extension* app =
@@ -666,7 +667,7 @@
 // up with an app process. See http://crbug.com/99349 for more details.
 IN_PROC_BROWSER_TEST_F(AppApiTest, ServerRedirectToAppFromExtension) {
   host_resolver()->AddRule("*", "127.0.0.1");
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
 
   LoadExtension(test_data_dir_.AppendASCII("app_process"));
   const Extension* launcher =
@@ -708,7 +709,7 @@
 // up with an app process.
 IN_PROC_BROWSER_TEST_F(AppApiTest, ClientRedirectToAppFromExtension) {
   host_resolver()->AddRule("*", "127.0.0.1");
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
 
   LoadExtension(test_data_dir_.AppendASCII("app_process"));
   const Extension* launcher =
@@ -757,7 +758,7 @@
       browser()->profile())->extension_service()->process_map();
 
   host_resolver()->AddRule("*", "127.0.0.1");
-  ASSERT_TRUE(test_server()->Start());
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
 
   GURL base_url = GetTestBaseURL("app_process");
 
@@ -794,7 +795,7 @@
       browser()->profile())->extension_service()->process_map();
 
   host_resolver()->AddRule("*", "127.0.0.1");
-  ASSERT_TRUE(test_server()->Start());
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
 
   ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("app_process")));
 
diff --git a/chrome/browser/extensions/app_window_contents.cc b/chrome/browser/extensions/app_window_contents.cc
index f515fc8..5c6ff07 100644
--- a/chrome/browser/extensions/app_window_contents.cc
+++ b/chrome/browser/extensions/app_window_contents.cc
@@ -4,6 +4,8 @@
 
 #include "chrome/browser/extensions/app_window_contents.h"
 
+#include "chrome/browser/printing/print_preview_message_handler.h"
+#include "chrome/browser/printing/print_view_manager.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/extensions/native_app_window.h"
 #include "chrome/common/chrome_notification_types.h"
@@ -19,6 +21,8 @@
 
 namespace app_window = extensions::api::app_window;
 
+using apps::ShellWindow;
+
 AppWindowContents::AppWindowContents(ShellWindow* host)
     : host_(host) {
 }
@@ -40,6 +44,12 @@
   web_contents_->GetMutableRendererPrefs()->
       browser_handles_all_top_level_requests = true;
   web_contents_->GetRenderViewHost()->SyncRendererPrefs();
+
+#if defined(ENABLE_PRINTING)
+  printing::PrintPreviewMessageHandler::CreateForWebContents(
+      web_contents_.get());
+  printing::PrintViewManager::CreateForWebContents(web_contents_.get());
+#endif
 }
 
 void AppWindowContents::LoadContents(int32 creator_process_id) {
@@ -76,7 +86,7 @@
 
 void AppWindowContents::NativeWindowChanged(
     NativeAppWindow* native_app_window) {
-  ListValue args;
+  base::ListValue args;
   DictionaryValue* dictionary = new DictionaryValue();
   args.Append(dictionary);
 
diff --git a/chrome/browser/extensions/app_window_contents.h b/chrome/browser/extensions/app_window_contents.h
index 3cf2a32..bb37787 100644
--- a/chrome/browser/extensions/app_window_contents.h
+++ b/chrome/browser/extensions/app_window_contents.h
@@ -7,10 +7,10 @@
 
 #include <vector>
 
+#include "apps/shell_window.h"
 #include "base/basictypes.h"
 #include "base/memory/scoped_ptr.h"
 #include "chrome/browser/extensions/extension_function_dispatcher.h"
-#include "chrome/browser/ui/extensions/shell_window.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/web_contents_observer.h"
 
@@ -24,18 +24,18 @@
 struct DraggableRegion;
 }
 
-// ShellWindowContents class specific to app windows. It maintains a
+// apps::ShellWindowContents class specific to app windows. It maintains a
 // WebContents instance and observes it for the purpose of passing
 // messages to the extensions system.
-class AppWindowContents : public ShellWindowContents,
+class AppWindowContents : public apps::ShellWindowContents,
                           public content::NotificationObserver,
                           public content::WebContentsObserver,
                           public ExtensionFunctionDispatcher::Delegate {
  public:
-  explicit AppWindowContents(ShellWindow* host);
+  explicit AppWindowContents(apps::ShellWindow* host);
   virtual ~AppWindowContents();
 
-  // ShellWindowContents
+  // apps::ShellWindowContents
   virtual void Initialize(Profile* profile, const GURL& url) OVERRIDE;
   virtual void LoadContents(int32 creator_process_id) OVERRIDE;
   virtual void NativeWindowChanged(NativeAppWindow* native_app_window) OVERRIDE;
@@ -61,7 +61,7 @@
       const std::vector<extensions::DraggableRegion>& regions);
   void SuspendRenderViewHost(content::RenderViewHost* rvh);
 
-  ShellWindow* host_;  // This class is owned by |host_|
+  apps::ShellWindow* host_;  // This class is owned by |host_|
   GURL url_;
   content::NotificationRegistrar registrar_;
   scoped_ptr<content::WebContents> web_contents_;
diff --git a/chrome/browser/extensions/background_app_browsertest.cc b/chrome/browser/extensions/background_app_browsertest.cc
new file mode 100644
index 0000000..7951e40
--- /dev/null
+++ b/chrome/browser/extensions/background_app_browsertest.cc
@@ -0,0 +1,78 @@
+// 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/background/background_mode_manager.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/extensions/extension_browsertest.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/test/base/ui_test_utils.h"
+
+class TestBackgroundModeManager : public BackgroundModeManager {
+ public:
+  TestBackgroundModeManager(CommandLine* command_line,
+                            ProfileInfoCache* profile_cache)
+      : BackgroundModeManager(command_line, profile_cache),
+        showed_background_app_installed_notification_for_test_(false) {}
+
+  virtual ~TestBackgroundModeManager() {}
+
+  virtual void DisplayAppInstalledNotification(
+      const extensions::Extension* extension) OVERRIDE {
+    showed_background_app_installed_notification_for_test_ = true;
+  }
+
+  bool showed_background_app_installed_notification_for_test() {
+    return showed_background_app_installed_notification_for_test_;
+  }
+
+  void set_showed_background_app_installed_notification_for_test(
+      bool showed) {
+    showed_background_app_installed_notification_for_test_ = showed;
+  }
+
+ private:
+  // Tracks if we have shown a "Background App Installed" notification to the
+  // user.  Used for unit tests only.
+  bool showed_background_app_installed_notification_for_test_;
+
+  FRIEND_TEST_ALL_PREFIXES(BackgroundAppBrowserTest,
+                           ReloadBackgroundApp);
+
+  DISALLOW_COPY_AND_ASSIGN(TestBackgroundModeManager);
+};
+
+class BackgroundAppBrowserTest: public ExtensionBrowserTest {};
+
+// Tests that if we reload a background app, we don't get a popup bubble
+// telling us that a new background app has been installed.
+IN_PROC_BROWSER_TEST_F(BackgroundAppBrowserTest, ReloadBackgroundApp) {
+
+  // Pass this in to the browser test.
+  scoped_ptr<BackgroundModeManager> test_background_mode_manager(
+      new TestBackgroundModeManager(
+          CommandLine::ForCurrentProcess(),
+          &(g_browser_process->profile_manager()->GetProfileInfoCache())));
+  g_browser_process->set_background_mode_manager_for_test(
+      test_background_mode_manager.Pass());
+  TestBackgroundModeManager* manager =
+      reinterpret_cast<TestBackgroundModeManager*>(
+          g_browser_process->background_mode_manager());
+
+  // Load our background extension
+  ASSERT_FALSE(
+      manager->showed_background_app_installed_notification_for_test());
+  const extensions::Extension* extension = LoadExtension(
+      test_data_dir_.AppendASCII("background_app"));
+  ASSERT_FALSE(extension == NULL);
+
+  // Set the test flag to not shown.
+  manager->set_showed_background_app_installed_notification_for_test(false);
+
+  // Reload our background extension
+  ReloadExtension(extension->id());
+
+  // Ensure that we did not see a "Background extension loaded" dialog.
+  EXPECT_FALSE(
+      manager->showed_background_app_installed_notification_for_test());
+}
diff --git a/chrome/browser/extensions/browser_event_router.cc b/chrome/browser/extensions/browser_event_router.cc
index d2c8b5d..3f85d96 100644
--- a/chrome/browser/extensions/browser_event_router.cc
+++ b/chrome/browser/extensions/browser_event_router.cc
@@ -165,7 +165,7 @@
                                         bool active,
                                         Profile* profile,
                                         const Extension* extension,
-                                        ListValue* event_args) {
+                                        base::ListValue* event_args) {
   DictionaryValue* tab_value = ExtensionTabUtil::CreateTabValue(
       contents, extension);
   event_args->Clear();
@@ -177,7 +177,7 @@
                                       int index,
                                       bool active) {
   Profile* profile = Profile::FromBrowserContext(contents->GetBrowserContext());
-  scoped_ptr<ListValue> args(new ListValue());
+  scoped_ptr<base::ListValue> args(new base::ListValue());
   scoped_ptr<Event> event(new Event(events::kOnTabCreated, args.Pass()));
   event->restrict_to_profile = profile;
   event->user_gesture = EventRouter::USER_GESTURE_NOT_ENABLED;
@@ -200,7 +200,7 @@
     return;
   }
 
-  scoped_ptr<ListValue> args(new ListValue());
+  scoped_ptr<base::ListValue> args(new base::ListValue());
   args->Append(Value::CreateIntegerValue(tab_id));
 
   DictionaryValue* object_args = new DictionaryValue();
@@ -221,7 +221,7 @@
     return;
   }
 
-  scoped_ptr<ListValue> args(new ListValue());
+  scoped_ptr<base::ListValue> args(new base::ListValue());
   args->Append(Value::CreateIntegerValue(ExtensionTabUtil::GetTabId(contents)));
 
   DictionaryValue* object_args = new DictionaryValue();
@@ -241,7 +241,7 @@
                                       int index) {
   int tab_id = ExtensionTabUtil::GetTabId(contents);
 
-  scoped_ptr<ListValue> args(new ListValue());
+  scoped_ptr<base::ListValue> args(new base::ListValue());
   args->Append(Value::CreateIntegerValue(tab_id));
 
   DictionaryValue* object_args = new DictionaryValue();
@@ -265,7 +265,7 @@
                                           WebContents* new_contents,
                                           int index,
                                           int reason) {
-  scoped_ptr<ListValue> args(new ListValue());
+  scoped_ptr<base::ListValue> args(new base::ListValue());
   int tab_id = ExtensionTabUtil::GetTabId(new_contents);
   args->Append(Value::CreateIntegerValue(tab_id));
 
@@ -283,9 +283,9 @@
       ? EventRouter::USER_GESTURE_ENABLED
       : EventRouter::USER_GESTURE_NOT_ENABLED;
   DispatchEvent(profile, events::kOnTabSelectionChanged,
-                scoped_ptr<ListValue>(args->DeepCopy()), gesture);
+                scoped_ptr<base::ListValue>(args->DeepCopy()), gesture);
   DispatchEvent(profile, events::kOnTabActiveChanged,
-                scoped_ptr<ListValue>(args->DeepCopy()), gesture);
+                scoped_ptr<base::ListValue>(args->DeepCopy()), gesture);
 
   // The onActivated event takes one argument: {windowId, tabId}.
   args->Remove(0, NULL);
@@ -298,7 +298,7 @@
     const ui::ListSelectionModel& old_model) {
   ui::ListSelectionModel::SelectedIndices new_selection =
       tab_strip_model->selection_model().selected_indices();
-  ListValue* all = new ListValue();
+  base::ListValue* all = new base::ListValue();
 
   for (size_t i = 0; i < new_selection.size(); ++i) {
     int index = new_selection[i];
@@ -309,7 +309,7 @@
     all->Append(Value::CreateIntegerValue(tab_id));
   }
 
-  scoped_ptr<ListValue> args(new ListValue());
+  scoped_ptr<base::ListValue> args(new base::ListValue());
   DictionaryValue* select_info = new DictionaryValue();
 
   select_info->Set(tab_keys::kWindowIdKey, Value::CreateIntegerValue(
@@ -321,7 +321,7 @@
   // The onHighlighted event replaced onHighlightChanged.
   Profile* profile = tab_strip_model->profile();
   DispatchEvent(profile, events::kOnTabHighlightChanged,
-                scoped_ptr<ListValue>(args->DeepCopy()),
+                scoped_ptr<base::ListValue>(args->DeepCopy()),
                 EventRouter::USER_GESTURE_UNKNOWN);
   DispatchEvent(profile, events::kOnTabHighlighted, args.Pass(),
                 EventRouter::USER_GESTURE_UNKNOWN);
@@ -330,7 +330,7 @@
 void BrowserEventRouter::TabMoved(WebContents* contents,
                                   int from_index,
                                   int to_index) {
-  scoped_ptr<ListValue> args(new ListValue());
+  scoped_ptr<base::ListValue> args(new base::ListValue());
   args->Append(Value::CreateIntegerValue(ExtensionTabUtil::GetTabId(contents)));
 
   DictionaryValue* object_args = new DictionaryValue();
@@ -380,7 +380,7 @@
 void BrowserEventRouter::DispatchEvent(
     Profile* profile,
     const char* event_name,
-    scoped_ptr<ListValue> args,
+    scoped_ptr<base::ListValue> args,
     EventRouter::UserGestureState user_gesture) {
   if (!profile_->IsSameProfile(profile) ||
       !extensions::ExtensionSystem::Get(profile)->event_router())
@@ -396,7 +396,7 @@
     Profile* profile,
     const std::string& extension_id,
     const char* event_name,
-    scoped_ptr<ListValue> event_args,
+    scoped_ptr<base::ListValue> event_args,
     EventRouter::UserGestureState user_gesture) {
   if (!profile_->IsSameProfile(profile) ||
       !extensions::ExtensionSystem::Get(profile)->event_router())
@@ -414,7 +414,7 @@
   if (!profile_->IsSameProfile(profile))
     return;
 
-  scoped_ptr<ListValue> args(new ListValue());
+  scoped_ptr<base::ListValue> args(new base::ListValue());
   args->Append(Value::CreateIntegerValue(window_id));
 
   DispatchEvent(profile, event_name, args.Pass(),
@@ -426,7 +426,7 @@
     const DictionaryValue* changed_properties,
     Profile* profile,
     const Extension* extension,
-    ListValue* event_args) {
+    base::ListValue* event_args) {
   // Overwrite the second argument with the appropriate properties dictionary,
   // depending on extension permissions.
   DictionaryValue* properties_value = changed_properties->DeepCopy();
@@ -447,7 +447,7 @@
 
   // The state of the tab (as seen from the extension point of view) has
   // changed.  Send a notification to the extension.
-  scoped_ptr<ListValue> args_base(new ListValue());
+  scoped_ptr<base::ListValue> args_base(new base::ListValue());
 
   // First arg: The id of the tab that changed.
   args_base->AppendInteger(ExtensionTabUtil::GetTabId(contents));
@@ -517,7 +517,7 @@
   // WebContents being swapped.
   const int new_tab_id = ExtensionTabUtil::GetTabId(new_contents);
   const int old_tab_id = ExtensionTabUtil::GetTabId(old_contents);
-  scoped_ptr<ListValue> args(new ListValue());
+  scoped_ptr<base::ListValue> args(new base::ListValue());
   args->Append(Value::CreateIntegerValue(new_tab_id));
   args->Append(Value::CreateIntegerValue(old_tab_id));
 
@@ -559,7 +559,7 @@
     int tab_id,
     const std::string& url,
     int button) {
-  scoped_ptr<ListValue> args(new ListValue());
+  scoped_ptr<base::ListValue> args(new base::ListValue());
   args->Append(Value::CreateStringValue(page_action_id));
 
   DictionaryValue* data = new DictionaryValue();
@@ -632,7 +632,7 @@
   }
 
   if (event_name) {
-    scoped_ptr<ListValue> args(new ListValue());
+    scoped_ptr<base::ListValue> args(new base::ListValue());
     DictionaryValue* tab_value = ExtensionTabUtil::CreateTabValue(
         web_contents);
     args->Append(tab_value);
diff --git a/chrome/browser/extensions/component_loader.cc b/chrome/browser/extensions/component_loader.cc
index 370ae71..b2b10b6 100644
--- a/chrome/browser/extensions/component_loader.cc
+++ b/chrome/browser/extensions/component_loader.cc
@@ -27,6 +27,7 @@
 
 #if defined(USE_AURA)
 #include "grit/keyboard_resources.h"
+#include "ui/keyboard/keyboard_util.h"
 #endif
 
 #if defined(GOOGLE_CHROME_BUILD)
@@ -289,7 +290,8 @@
 
 void ComponentLoader::AddKeyboardApp() {
 #if defined(USE_AURA)
-  Add(IDR_KEYBOARD_MANIFEST, base::FilePath(FILE_PATH_LITERAL("keyboard")));
+  if (keyboard::IsKeyboardEnabled())
+    Add(IDR_KEYBOARD_MANIFEST, base::FilePath(FILE_PATH_LITERAL("keyboard")));
 #endif
 }
 
@@ -394,9 +396,7 @@
         fileapi::FileSystemContext* context =
             content::BrowserContext::GetStoragePartitionForSite(profile, site)->
                 GetFileSystemContext();
-        fileapi::SandboxMountPointProvider* provider =
-            context->sandbox_provider();
-        provider->set_enable_temporary_file_system_in_incognito(true);
+        context->EnableTemporaryFileSystemInIncognito();
       }
     }
 #endif  // defined(GOOGLE_CHROME_BUILD)
diff --git a/chrome/browser/extensions/content_script_apitest.cc b/chrome/browser/extensions/content_script_apitest.cc
index 1bd0dce..48f6cc6 100644
--- a/chrome/browser/extensions/content_script_apitest.cc
+++ b/chrome/browser/extensions/content_script_apitest.cc
@@ -16,31 +16,32 @@
 #include "content/public/test/browser_test_utils.h"
 #include "googleurl/src/gurl.h"
 #include "net/dns/mock_host_resolver.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
 
 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ContentScriptAllFrames) {
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
   ASSERT_TRUE(RunExtensionTest("content_scripts/all_frames")) << message_;
 }
 
 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ContentScriptAboutBlankIframes) {
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
   ASSERT_TRUE(
       RunExtensionTest("content_scripts/about_blank_iframes")) << message_;
 }
 
 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ContentScriptExtensionIframe) {
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
   ASSERT_TRUE(RunExtensionTest("content_scripts/extension_iframe")) << message_;
 }
 
 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ContentScriptExtensionProcess) {
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
   ASSERT_TRUE(
       RunExtensionTest("content_scripts/extension_process")) << message_;
 }
 
 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ContentScriptFragmentNavigation) {
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
   const char* extension_name = "content_scripts/fragment";
   ASSERT_TRUE(RunExtensionTest(extension_name)) << message_;
 }
@@ -54,7 +55,7 @@
 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, MAYBE_ContentScriptIsolatedWorlds) {
   // This extension runs various bits of script and tests that they all run in
   // the same isolated world.
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
   ASSERT_TRUE(RunExtensionTest("content_scripts/isolated_world1")) << message_;
 
   // Now load a different extension, inject into same page, verify worlds aren't
@@ -65,14 +66,14 @@
 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ContentScriptIgnoreHostPermissions) {
   host_resolver()->AddRule("a.com", "127.0.0.1");
   host_resolver()->AddRule("b.com", "127.0.0.1");
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
   ASSERT_TRUE(RunExtensionTest(
       "content_scripts/dont_match_host_permissions")) << message_;
 }
 
 // crbug.com/39249 -- content scripts js should not run on view source.
 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ContentScriptViewSource) {
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
   ASSERT_TRUE(RunExtensionTest("content_scripts/view_source")) << message_;
 }
 
@@ -80,7 +81,7 @@
 // extensions.
 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ContentScriptOtherExtensions) {
   host_resolver()->AddRule("a.com", "127.0.0.1");
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
   // First, load extension that sets up content script.
   ASSERT_TRUE(RunExtensionTest("content_scripts/other_extensions/injector"))
       << message_;
@@ -93,7 +94,7 @@
 IN_PROC_BROWSER_TEST_F(
     ExtensionApiTest,
     DISABLED_ContentScriptStylesInjectedIntoExistingRenderers) {
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
 
   content::WindowedNotificationObserver signal(
       chrome::NOTIFICATION_USER_SCRIPTS_UPDATED,
@@ -121,25 +122,29 @@
 
 IN_PROC_BROWSER_TEST_F(ExtensionApiTest,
                        ContentScriptCSSLocalization) {
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
   ASSERT_TRUE(RunExtensionTest("content_scripts/css_l10n")) << message_;
 }
 
 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ContentScriptExtensionAPIs) {
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
 
   const extensions::Extension* extension = LoadExtension(
       test_data_dir_.AppendASCII("content_scripts/extension_api"));
 
   ResultCatcher catcher;
   ui_test_utils::NavigateToURL(
-      browser(), test_server()->GetURL("functions.html"));
+      browser(),
+      embedded_test_server()->GetURL(
+          "/extensions/api_test/content_scripts/extension_api/functions.html"));
   EXPECT_TRUE(catcher.GetNextResult());
 
   // Navigate to a page that will cause a content script to run that starts
   // listening for an extension event.
   ui_test_utils::NavigateToURL(
-      browser(), test_server()->GetURL("events.html"));
+      browser(),
+      embedded_test_server()->GetURL(
+          "/extensions/api_test/content_scripts/extension_api/events.html"));
 
   // Navigate to an extension page that will fire the event events.js is
   // listening for.
@@ -159,11 +164,11 @@
   extensions::PermissionsRequestFunction::SetIgnoreUserGestureForTests(true);
   extensions::PermissionsRequestFunction::SetAutoConfirmForTests(true);
   host_resolver()->AddRule("*.com", "127.0.0.1");
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
   ASSERT_TRUE(RunExtensionTest("content_scripts/permissions")) << message_;
 }
 
 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ContentScriptBypassPageCSP) {
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
   ASSERT_TRUE(RunExtensionTest("content_scripts/bypass_page_csp")) << message_;
 }
diff --git a/chrome/browser/extensions/content_security_policy_apitest.cc b/chrome/browser/extensions/content_security_policy_apitest.cc
index d2a4969..cbf104d 100644
--- a/chrome/browser/extensions/content_security_policy_apitest.cc
+++ b/chrome/browser/extensions/content_security_policy_apitest.cc
@@ -7,12 +7,12 @@
 #include "net/dns/mock_host_resolver.h"
 
 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ContentSecurityPolicy) {
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
   ASSERT_TRUE(RunExtensionTest("content_security_policy")) << message_;
 }
 
 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, DefaultContentSecurityPolicy) {
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
   ASSERT_TRUE(RunExtensionTest("default_content_security_policy")) <<
       message_;
 }
diff --git a/chrome/browser/extensions/convert_user_script.cc b/chrome/browser/extensions/convert_user_script.cc
index 752e6a3..e823819 100644
--- a/chrome/browser/extensions/convert_user_script.cc
+++ b/chrome/browser/extensions/convert_user_script.cc
@@ -101,12 +101,12 @@
   root->SetString(keys::kPublicKey, key);
   root->SetBoolean(keys::kConvertedFromUserScript, true);
 
-  ListValue* js_files = new ListValue();
+  base::ListValue* js_files = new base::ListValue();
   js_files->Append(Value::CreateStringValue("script.js"));
 
   // If the script provides its own match patterns, we use those. Otherwise, we
   // generate some using the include globs.
-  ListValue* matches = new ListValue();
+  base::ListValue* matches = new base::ListValue();
   if (!script.url_patterns().is_empty()) {
     for (URLPatternSet::const_iterator i = script.url_patterns().begin();
          i != script.url_patterns().end(); ++i) {
@@ -119,7 +119,7 @@
   }
 
   // Read the exclude matches, if any are present.
-  ListValue* exclude_matches = new ListValue();
+  base::ListValue* exclude_matches = new base::ListValue();
   if (!script.exclude_url_patterns().is_empty()) {
     for (URLPatternSet::const_iterator i =
          script.exclude_url_patterns().begin();
@@ -128,11 +128,11 @@
     }
   }
 
-  ListValue* includes = new ListValue();
+  base::ListValue* includes = new base::ListValue();
   for (size_t i = 0; i < script.globs().size(); ++i)
     includes->Append(Value::CreateStringValue(script.globs().at(i)));
 
-  ListValue* excludes = new ListValue();
+  base::ListValue* excludes = new base::ListValue();
   for (size_t i = 0; i < script.exclude_globs().size(); ++i)
     excludes->Append(Value::CreateStringValue(script.exclude_globs().at(i)));
 
@@ -151,7 +151,7 @@
     // This is the default, but store it just in case we change that.
     content_script->SetString(keys::kRunAt, values::kRunAtDocumentIdle);
 
-  ListValue* content_scripts = new ListValue();
+  base::ListValue* content_scripts = new base::ListValue();
   content_scripts->Append(content_script);
 
   root->Set(keys::kContentScripts, content_scripts);
diff --git a/chrome/browser/extensions/convert_web_app.cc b/chrome/browser/extensions/convert_web_app.cc
index 9d61a86..e1dcf8e 100644
--- a/chrome/browser/extensions/convert_web_app.cc
+++ b/chrome/browser/extensions/convert_web_app.cc
@@ -18,7 +18,7 @@
 #include "base/path_service.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/extension_file_util.h"
@@ -130,14 +130,14 @@
   }
 
   // Add the permissions.
-  ListValue* permissions = new ListValue();
+  base::ListValue* permissions = new base::ListValue();
   root->Set(keys::kPermissions, permissions);
   for (size_t i = 0; i < web_app.permissions.size(); ++i) {
     permissions->Append(Value::CreateStringValue(web_app.permissions[i]));
   }
 
   // Add the URLs.
-  ListValue* urls = new ListValue();
+  base::ListValue* urls = new base::ListValue();
   root->Set(keys::kWebURLs, urls);
   for (size_t i = 0; i < web_app.urls.size(); ++i) {
     urls->Append(Value::CreateStringValue(web_app.urls[i].spec()));
diff --git a/chrome/browser/extensions/convert_web_app_unittest.cc b/chrome/browser/extensions/convert_web_app_unittest.cc
index c6805be..cea76d4 100644
--- a/chrome/browser/extensions/convert_web_app_unittest.cc
+++ b/chrome/browser/extensions/convert_web_app_unittest.cc
@@ -13,7 +13,7 @@
 #include "base/path_service.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "base/version.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/extensions/extension.h"
diff --git a/chrome/browser/extensions/cross_origin_xhr_apitest.cc b/chrome/browser/extensions/cross_origin_xhr_apitest.cc
index 4198b7d..eae682f 100644
--- a/chrome/browser/extensions/cross_origin_xhr_apitest.cc
+++ b/chrome/browser/extensions/cross_origin_xhr_apitest.cc
@@ -7,19 +7,19 @@
 
 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, CrossOriginXHRBackgroundPage) {
   host_resolver()->AddRule("*.com", "127.0.0.1");
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
   ASSERT_TRUE(RunExtensionTest("cross_origin_xhr/background_page")) << message_;
 }
 
 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, CrossOriginXHRAllURLs) {
   host_resolver()->AddRule("*.com", "127.0.0.1");
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
   ASSERT_TRUE(RunExtensionTest("cross_origin_xhr/all_urls")) << message_;
 }
 
 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, CrossOriginXHRContentScript) {
   host_resolver()->AddRule("*.com", "127.0.0.1");
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
   ASSERT_TRUE(RunExtensionTest("cross_origin_xhr/content_script")) << message_;
 }
 
diff --git a/chrome/browser/extensions/crx_installer.cc b/chrome/browser/extensions/crx_installer.cc
index 424ef62..4f15cb9 100644
--- a/chrome/browser/extensions/crx_installer.cc
+++ b/chrome/browser/extensions/crx_installer.cc
@@ -19,7 +19,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/sequenced_worker_pool.h"
 #include "base/threading/thread_restrictions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "base/version.h"
 #include "chrome/browser/extensions/convert_user_script.h"
 #include "chrome/browser/extensions/convert_web_app.h"
@@ -412,17 +412,8 @@
       Version version_required(i->minimum_version);
       const Extension* imported_module =
           service->GetExtensionById(i->extension_id, true);
-      if (!imported_module ||
-          (version_required.IsValid() &&
-           imported_module->version()->CompareTo(version_required) < 0)) {
-        ReportFailureFromUIThread(
-            CrxInstallerError(l10n_util::GetStringFUTF16(
-                IDS_EXTENSION_INSTALL_DEPENDENCY_NOT_FOUND,
-                ASCIIToUTF16(i->extension_id),
-                ASCIIToUTF16(i->minimum_version))));
-        return;
-      }
-      if (!SharedModuleInfo::IsSharedModule(imported_module)) {
+      if (imported_module &&
+          !SharedModuleInfo::IsSharedModule(imported_module)) {
         ReportFailureFromUIThread(
             CrxInstallerError(l10n_util::GetStringFUTF16(
                 IDS_EXTENSION_INSTALL_DEPENDENCY_NOT_SHARED_MODULE,
@@ -457,6 +448,11 @@
 
   string16 error = installer_.CheckManagementPolicy();
   if (!error.empty()) {
+    // We don't want to show the error infobar for installs from the WebStore,
+    // because the WebStore already shows an error dialog itself.
+    // Note: |client_| can be NULL in unit_tests!
+    if (extension()->from_webstore() && client_)
+      client_->install_ui()->SetSkipPostInstallUI(true);
     ReportFailureFromUIThread(CrxInstallerError(error));
     return;
   }
diff --git a/chrome/browser/extensions/event_listener_map.cc b/chrome/browser/extensions/event_listener_map.cc
index 5843714..2ea49e9 100644
--- a/chrome/browser/extensions/event_listener_map.cc
+++ b/chrome/browser/extensions/event_listener_map.cc
@@ -168,7 +168,7 @@
     const DictionaryValue& filtered) {
   for (DictionaryValue::Iterator it(filtered); !it.IsAtEnd(); it.Advance()) {
     // We skip entries if they are malformed.
-    const ListValue* filter_list = NULL;
+    const base::ListValue* filter_list = NULL;
     if (!it.value().GetAsList(&filter_list))
       continue;
     for (size_t i = 0; i < filter_list->GetSize(); i++) {
diff --git a/chrome/browser/extensions/event_listener_map_unittest.cc b/chrome/browser/extensions/event_listener_map_unittest.cc
index da4eb24..d1b657f 100644
--- a/chrome/browser/extensions/event_listener_map_unittest.cc
+++ b/chrome/browser/extensions/event_listener_map_unittest.cc
@@ -9,6 +9,10 @@
 #include "content/public/test/mock_render_process_host.h"
 #include "content/public/test/test_browser_context.h"
 
+using base::DictionaryValue;
+using base::ListValue;
+using base::StringValue;
+
 namespace extensions {
 
 namespace {
diff --git a/chrome/browser/extensions/event_names.cc b/chrome/browser/extensions/event_names.cc
index deb5d58..3270043 100644
--- a/chrome/browser/extensions/event_names.cc
+++ b/chrome/browser/extensions/event_names.cc
@@ -103,6 +103,9 @@
 
 const char kOnFeedbackRequested[] = "feedbackPrivate.onFeedbackRequested";
 
+const char kDeveloperPrivateOnItemStateChanged[] =
+    "developerPrivate.onItemStateChanged";
+
 }  // namespace event_names
 
 }  // namespace extensions
diff --git a/chrome/browser/extensions/event_names.h b/chrome/browser/extensions/event_names.h
index bf81d6b..0428921 100644
--- a/chrome/browser/extensions/event_names.h
+++ b/chrome/browser/extensions/event_names.h
@@ -122,6 +122,9 @@
 // FeedbackPrivate
 extern const char kOnFeedbackRequested[];
 
+// DeveloperPrivate.
+extern const char kDeveloperPrivateOnItemStateChanged[];
+
 }  // namespace event_names
 
 }  // namespace extensions
diff --git a/chrome/browser/extensions/event_router.h b/chrome/browser/extensions/event_router.h
index ad8b72b..32a079c 100644
--- a/chrome/browser/extensions/event_router.h
+++ b/chrome/browser/extensions/event_router.h
@@ -165,7 +165,7 @@
   static void LogExtensionEventMessage(void* profile_id,
                                        const std::string& extension_id,
                                        const std::string& event_name,
-                                       scoped_ptr<ListValue> event_args);
+                                       scoped_ptr<base::ListValue> event_args);
 
   // TODO(gdk): Document this.
   static void DispatchExtensionMessage(
diff --git a/chrome/browser/extensions/event_router_forwarder.cc b/chrome/browser/extensions/event_router_forwarder.cc
index 50b0d8f..f04c16e 100644
--- a/chrome/browser/extensions/event_router_forwarder.cc
+++ b/chrome/browser/extensions/event_router_forwarder.cc
@@ -69,7 +69,7 @@
 
 void EventRouterForwarder::HandleEvent(const std::string& extension_id,
                                        const std::string& event_name,
-                                       scoped_ptr<ListValue> event_args,
+                                       scoped_ptr<base::ListValue> event_args,
                                        void* profile_ptr,
                                        bool use_profile_to_restrict_events,
                                        const GURL& event_url) {
@@ -98,7 +98,8 @@
   } else {
     std::vector<Profile*> profiles(profile_manager->GetLoadedProfiles());
     for (size_t i = 0; i < profiles.size(); ++i) {
-      scoped_ptr<ListValue> per_profile_event_args(event_args->DeepCopy());
+      scoped_ptr<base::ListValue> per_profile_event_args(
+          event_args->DeepCopy());
       CallEventRouter(
           profiles[i], extension_id, event_name, per_profile_event_args.Pass(),
           use_profile_to_restrict_events ? profiles[i] : NULL, event_url);
@@ -106,12 +107,13 @@
   }
 }
 
-void EventRouterForwarder::CallEventRouter(Profile* profile,
-                                           const std::string& extension_id,
-                                           const std::string& event_name,
-                                           scoped_ptr<ListValue> event_args,
-                                           Profile* restrict_to_profile,
-                                           const GURL& event_url) {
+void EventRouterForwarder::CallEventRouter(
+    Profile* profile,
+    const std::string& extension_id,
+    const std::string& event_name,
+    scoped_ptr<base::ListValue> event_args,
+    Profile* restrict_to_profile,
+    const GURL& event_url) {
   // We may not have an extension in cases like chromeos login
   // (crosbug.com/12856), chrome_frame_net_tests.exe which reuses the chrome
   // browser single process framework.
diff --git a/chrome/browser/extensions/event_router_forwarder_unittest.cc b/chrome/browser/extensions/event_router_forwarder_unittest.cc
index ee2bf3e..c3c1056 100644
--- a/chrome/browser/extensions/event_router_forwarder_unittest.cc
+++ b/chrome/browser/extensions/event_router_forwarder_unittest.cc
@@ -47,7 +47,7 @@
 static void BroadcastEventToRenderers(EventRouterForwarder* event_router,
                                       const std::string& event_name,
                                       const GURL& url) {
-  scoped_ptr<ListValue> args(new ListValue());
+  scoped_ptr<base::ListValue> args(new base::ListValue());
   event_router->BroadcastEventToRenderers(event_name, args.Pass(), url);
 }
 
@@ -56,7 +56,7 @@
                                      void* profile,
                                      bool use_profile_to_restrict_events,
                                      const GURL& url) {
-  scoped_ptr<ListValue> args(new ListValue());
+  scoped_ptr<base::ListValue> args(new base::ListValue());
   event_router->DispatchEventToRenderers(event_name, args.Pass(), profile,
                                          use_profile_to_restrict_events, url);
 }
@@ -65,7 +65,7 @@
                                       const std::string& extension,
                                       const std::string& event_name,
                                       const GURL& url) {
-  scoped_ptr<ListValue> args(new ListValue());
+  scoped_ptr<base::ListValue> args(new base::ListValue());
   event_router->BroadcastEventToExtension(extension, event_name, args.Pass(),
                                           url);
 }
@@ -76,7 +76,7 @@
                                      void* profile,
                                      bool use_profile_to_restrict_events,
                                      const GURL& url) {
-  scoped_ptr<ListValue> args(new ListValue());
+  scoped_ptr<base::ListValue> args(new base::ListValue());
   event_router->DispatchEventToExtension(
       extension, event_name, args.Pass(), profile,
       use_profile_to_restrict_events, url);
diff --git a/chrome/browser/extensions/execute_script_apitest.cc b/chrome/browser/extensions/execute_script_apitest.cc
index c2d96d7..f28ba8c 100644
--- a/chrome/browser/extensions/execute_script_apitest.cc
+++ b/chrome/browser/extensions/execute_script_apitest.cc
@@ -18,14 +18,14 @@
 // If failing, mark disabled and update http://crbug.com/92105.
 IN_PROC_BROWSER_TEST_F(ExecuteScriptApiTest, ExecuteScriptBasic) {
   SetupDelayedHostResolver();
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
   ASSERT_TRUE(RunExtensionTest("executescript/basic")) << message_;
 }
 
 // If failing, mark disabled and update http://crbug.com/92105.
 IN_PROC_BROWSER_TEST_F(ExecuteScriptApiTest, ExecuteScriptInFrame) {
   SetupDelayedHostResolver();
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
   ASSERT_TRUE(RunExtensionTest("executescript/in_frame")) << message_;
 }
 
@@ -39,20 +39,20 @@
 
 IN_PROC_BROWSER_TEST_F(ExecuteScriptApiTest, MAYBE_ExecuteScriptPermissions) {
   SetupDelayedHostResolver();
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
   ASSERT_TRUE(RunExtensionTest("executescript/permissions")) << message_;
 }
 
 // If failing, mark disabled and update http://crbug.com/84760.
 IN_PROC_BROWSER_TEST_F(ExecuteScriptApiTest, ExecuteScriptFileAfterClose) {
   host_resolver()->AddRule("b.com", "127.0.0.1");
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
   ASSERT_TRUE(RunExtensionTest("executescript/file_after_close")) << message_;
 }
 
 // If crashing, mark disabled and update http://crbug.com/67774.
 IN_PROC_BROWSER_TEST_F(ExecuteScriptApiTest, ExecuteScriptFragmentNavigation) {
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
   const char* extension_name = "executescript/fragment";
   ASSERT_TRUE(RunExtensionTest(extension_name)) << message_;
 }
@@ -67,7 +67,7 @@
                        MAYBE_NavigationRaceExecuteScript) {
   host_resolver()->AddRule("a.com", "127.0.0.1");
   host_resolver()->AddRule("b.com", "127.0.0.1");
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
   ASSERT_TRUE(RunExtensionSubtest("executescript/navigation_race",
                                   "execute_script.html")) << message_;
 }
@@ -75,7 +75,7 @@
 IN_PROC_BROWSER_TEST_F(ExecuteScriptApiTest, NavigationRaceJavaScriptURL) {
   host_resolver()->AddRule("a.com", "127.0.0.1");
   host_resolver()->AddRule("b.com", "127.0.0.1");
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
   ASSERT_TRUE(RunExtensionSubtest("executescript/navigation_race",
                                   "javascript_url.html")) << message_;
 }
@@ -83,18 +83,18 @@
 // If failing, mark disabled and update http://crbug.com/92105.
 IN_PROC_BROWSER_TEST_F(ExecuteScriptApiTest, ExecuteScriptFrameAfterLoad) {
   SetupDelayedHostResolver();
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
   ASSERT_TRUE(RunExtensionTest("executescript/frame_after_load")) << message_;
 }
 
 IN_PROC_BROWSER_TEST_F(ExecuteScriptApiTest, ExecuteScriptRunAt) {
   SetupDelayedHostResolver();
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
   ASSERT_TRUE(RunExtensionTest("executescript/run_at")) << message_;
 }
 
 IN_PROC_BROWSER_TEST_F(ExecuteScriptApiTest, ExecuteScriptCallback) {
   SetupDelayedHostResolver();
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
   ASSERT_TRUE(RunExtensionTest("executescript/callback")) << message_;
 }
diff --git a/chrome/browser/extensions/extension_apitest.cc b/chrome/browser/extensions/extension_apitest.cc
index c14182b..ed6d644 100644
--- a/chrome/browser/extensions/extension_apitest.cc
+++ b/chrome/browser/extensions/extension_apitest.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/extensions/extension_apitest.h"
 
+#include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "chrome/browser/extensions/api/test/test_api.h"
@@ -18,7 +19,11 @@
 #include "chrome/test/base/ui_test_utils.h"
 #include "content/public/browser/notification_registrar.h"
 #include "content/public/browser/notification_service.h"
+#include "net/base/escape.h"
 #include "net/base/net_util.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+#include "net/test/embedded_test_server/http_response.h"
+#include "net/test/embedded_test_server/http_request.h"
 #include "net/test/spawned_test_server/spawned_test_server.h"
 
 namespace {
@@ -28,9 +33,108 @@
 const char kTestDataDirectory[] = "testDataDirectory";
 const char kTestWebSocketPort[] = "testWebSocketPort";
 
+scoped_ptr<net::test_server::HttpResponse> HandleServerRedirectRequest(
+    const net::test_server::HttpRequest& request) {
+  if (!StartsWithASCII(request.relative_url, "/server-redirect?", true))
+    return scoped_ptr<net::test_server::HttpResponse>();
+
+  size_t query_string_pos = request.relative_url.find('?');
+  std::string redirect_target =
+      request.relative_url.substr(query_string_pos + 1);
+
+  scoped_ptr<net::test_server::BasicHttpResponse> http_response(
+      new net::test_server::BasicHttpResponse);
+  http_response->set_code(net::HTTP_MOVED_PERMANENTLY);
+  http_response->AddCustomHeader("Location", redirect_target);
+  return http_response.PassAs<net::test_server::HttpResponse>();
+}
+
+scoped_ptr<net::test_server::HttpResponse> HandleEchoHeaderRequest(
+    const net::test_server::HttpRequest& request) {
+  if (!StartsWithASCII(request.relative_url, "/echoheader?", true))
+    return scoped_ptr<net::test_server::HttpResponse>();
+
+  size_t query_string_pos = request.relative_url.find('?');
+  std::string header_name =
+      request.relative_url.substr(query_string_pos + 1);
+
+  std::string header_value;
+  std::map<std::string, std::string>::const_iterator it = request.headers.find(
+      header_name);
+  if (it != request.headers.end())
+    header_value = it->second;
+
+  scoped_ptr<net::test_server::BasicHttpResponse> http_response(
+      new net::test_server::BasicHttpResponse);
+  http_response->set_code(net::HTTP_OK);
+  http_response->set_content(header_value);
+  return http_response.PassAs<net::test_server::HttpResponse>();
+}
+
+scoped_ptr<net::test_server::HttpResponse> HandleSetCookieRequest(
+    const net::test_server::HttpRequest& request) {
+  if (!StartsWithASCII(request.relative_url, "/set-cookie?", true))
+    return scoped_ptr<net::test_server::HttpResponse>();
+
+  scoped_ptr<net::test_server::BasicHttpResponse> http_response(
+      new net::test_server::BasicHttpResponse);
+  http_response->set_code(net::HTTP_OK);
+
+  size_t query_string_pos = request.relative_url.find('?');
+  std::string cookie_value =
+      request.relative_url.substr(query_string_pos + 1);
+
+  std::vector<std::string> cookies;
+  base::SplitString(cookie_value, '&', &cookies);
+
+  for (size_t i = 0; i < cookies.size(); i++)
+    http_response->AddCustomHeader("Set-Cookie", cookies[i]);
+
+  return http_response.PassAs<net::test_server::HttpResponse>();
+}
+
+scoped_ptr<net::test_server::HttpResponse> HandleSetHeaderRequest(
+    const net::test_server::HttpRequest& request) {
+  if (!StartsWithASCII(request.relative_url, "/set-header?", true))
+    return scoped_ptr<net::test_server::HttpResponse>();
+
+  size_t query_string_pos = request.relative_url.find('?');
+  std::string escaped_header =
+      request.relative_url.substr(query_string_pos + 1);
+
+  std::string header =
+      net::UnescapeURLComponent(escaped_header,
+                                net::UnescapeRule::NORMAL |
+                                net::UnescapeRule::SPACES |
+                                net::UnescapeRule::URL_SPECIAL_CHARS);
+
+  size_t colon_pos = header.find(':');
+  if (colon_pos == std::string::npos)
+    return scoped_ptr<net::test_server::HttpResponse>();
+
+  std::string header_name = header.substr(0, colon_pos);
+  // Skip space after colon.
+  std::string header_value = header.substr(colon_pos + 2);
+
+  scoped_ptr<net::test_server::BasicHttpResponse> http_response(
+      new net::test_server::BasicHttpResponse);
+  http_response->set_code(net::HTTP_OK);
+  http_response->AddCustomHeader(header_name, header_value);
+  return http_response.PassAs<net::test_server::HttpResponse>();
+}
+
 };  // namespace
 
-ExtensionApiTest::ExtensionApiTest() {}
+ExtensionApiTest::ExtensionApiTest() {
+  embedded_test_server()->RegisterRequestHandler(
+      base::Bind(&HandleServerRedirectRequest));
+  embedded_test_server()->RegisterRequestHandler(
+      base::Bind(&HandleEchoHeaderRequest));
+  embedded_test_server()->RegisterRequestHandler(
+      base::Bind(&HandleSetCookieRequest));
+  embedded_test_server()->RegisterRequestHandler(
+      base::Bind(&HandleSetHeaderRequest));
+}
 
 ExtensionApiTest::~ExtensionApiTest() {}
 
@@ -305,15 +409,15 @@
   return extension;
 }
 
-bool ExtensionApiTest::StartTestServer() {
-  if (!test_server()->Start())
+bool ExtensionApiTest::StartEmbeddedTestServer() {
+  if (!embedded_test_server()->InitializeAndWaitUntilReady())
     return false;
 
   // Build a dictionary of values that tests can use to build URLs that
   // access the test server and local file system.  Tests can see these values
   // using the extension API function chrome.test.getConfig().
   test_config_->SetInteger(kTestServerPort,
-                           test_server()->host_port_pair().port());
+                           embedded_test_server()->port());
 
   return true;
 }
diff --git a/chrome/browser/extensions/extension_apitest.h b/chrome/browser/extensions/extension_apitest.h
index 9d6cf0c..12827ad 100644
--- a/chrome/browser/extensions/extension_apitest.h
+++ b/chrome/browser/extensions/extension_apitest.h
@@ -158,7 +158,7 @@
 
   // Start the test server, and store details of its state.  Those details
   // will be available to javascript tests using chrome.test.getConfig().
-  bool StartTestServer();
+  bool StartEmbeddedTestServer();
 
   // Start the test WebSocket server, and store details of its state. Those
   // details will be available to javascript tests using
diff --git a/chrome/browser/extensions/extension_browsertest.cc b/chrome/browser/extensions/extension_browsertest.cc
index c2ec75b..07fb324 100644
--- a/chrome/browser/extensions/extension_browsertest.cc
+++ b/chrome/browser/extensions/extension_browsertest.cc
@@ -239,7 +239,7 @@
 base::FilePath ExtensionBrowserTest::PackExtension(
     const base::FilePath& dir_path) {
   base::FilePath crx_path = temp_dir_.path().AppendASCII("temp.crx");
-  if (!file_util::Delete(crx_path, false)) {
+  if (!base::Delete(crx_path, false)) {
     ADD_FAILURE() << "Failed to delete crx: " << crx_path.value();
     return base::FilePath();
   }
@@ -252,7 +252,7 @@
   if (!file_util::PathExists(pem_path)) {
     pem_path = base::FilePath();
     pem_path_out = crx_path.DirName().AppendASCII("temp.pem");
-    if (!file_util::Delete(pem_path_out, false)) {
+    if (!base::Delete(pem_path_out, false)) {
       ADD_FAILURE() << "Failed to delete pem: " << pem_path_out.value();
       return base::FilePath();
     }
@@ -452,7 +452,7 @@
   return service->GetExtensionById(last_loaded_extension_id_, false);
 }
 
-void ExtensionBrowserTest::ReloadExtension(const std::string& extension_id) {
+void ExtensionBrowserTest::ReloadExtension(const std::string extension_id) {
   ExtensionService* service = extensions::ExtensionSystem::Get(
       profile())->extension_service();
   service->ReloadExtension(extension_id);
diff --git a/chrome/browser/extensions/extension_browsertest.h b/chrome/browser/extensions/extension_browsertest.h
index ef2b4c8..2b750c3 100644
--- a/chrome/browser/extensions/extension_browsertest.h
+++ b/chrome/browser/extensions/extension_browsertest.h
@@ -170,7 +170,7 @@
         std::string(), path, INSTALL_UI_TYPE_CANCEL, 0);
   }
 
-  void ReloadExtension(const std::string& extension_id);
+  void ReloadExtension(const std::string extension_id);
 
   void UnloadExtension(const std::string& extension_id);
 
diff --git a/chrome/browser/extensions/extension_context_menu_model_unittest.cc b/chrome/browser/extensions/extension_context_menu_model_unittest.cc
index 9aa6929..6abe35c 100644
--- a/chrome/browser/extensions/extension_context_menu_model_unittest.cc
+++ b/chrome/browser/extensions/extension_context_menu_model_unittest.cc
@@ -39,8 +39,7 @@
   service_->AddExtension(extension.get());
 
   // Create a Browser for the ExtensionContextMenuModel to use.
-  Browser::CreateParams params(profile_.get(),
-                               chrome::HOST_DESKTOP_TYPE_NATIVE);
+  Browser::CreateParams params(profile_.get(), chrome::GetActiveDesktop());
   TestBrowserWindow test_window;
   params.window = &test_window;
   Browser browser(params);
diff --git a/chrome/browser/extensions/extension_creator.cc b/chrome/browser/extensions/extension_creator.cc
index 8aa0301..cedc048 100644
--- a/chrome/browser/extensions/extension_creator.cc
+++ b/chrome/browser/extensions/extension_creator.cc
@@ -237,7 +237,7 @@
                                 const std::vector<uint8>& signature,
                                 const base::FilePath& crx_path) {
   if (file_util::PathExists(crx_path))
-    file_util::Delete(crx_path, false);
+    base::Delete(crx_path, false);
   ScopedStdioHandle crx_handle(file_util::OpenFile(crx_path, "wb"));
   if (!crx_handle.get()) {
     error_message_ = l10n_util::GetStringUTF8(IDS_EXTENSION_SHARING_VIOLATION);
@@ -322,7 +322,7 @@
     result = true;
   }
 
-  file_util::Delete(zip_path, false);
+  base::Delete(zip_path, false);
   return result;
 }
 
diff --git a/chrome/browser/extensions/extension_creator_filter_unittest.cc b/chrome/browser/extensions/extension_creator_filter_unittest.cc
index 45e9941..48f5806 100644
--- a/chrome/browser/extensions/extension_creator_filter_unittest.cc
+++ b/chrome/browser/extensions/extension_creator_filter_unittest.cc
@@ -26,7 +26,7 @@
     base::FilePath test_file(test_dir_.Append(file_path));
     base::FilePath temp_file;
     EXPECT_TRUE(file_util::CreateTemporaryFileInDir(test_dir_, &temp_file));
-    EXPECT_TRUE(file_util::Move(temp_file, test_file));
+    EXPECT_TRUE(base::Move(temp_file, test_file));
     return test_file;
   }
 
diff --git a/chrome/browser/extensions/extension_dom_clipboard_apitest.cc b/chrome/browser/extensions/extension_dom_clipboard_apitest.cc
index 0d63acb..0d2e6a1 100644
--- a/chrome/browser/extensions/extension_dom_clipboard_apitest.cc
+++ b/chrome/browser/extensions/extension_dom_clipboard_apitest.cc
@@ -11,6 +11,7 @@
 #include "content/public/test/browser_test_utils.h"
 #include "googleurl/src/gurl.h"
 #include "net/dns/mock_host_resolver.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
 
 namespace {
 
@@ -29,7 +30,7 @@
                                      const std::string& launch_page) {
   host_resolver()->AddRule("*", "127.0.0.1");
 
-  if (!StartTestServer()) {
+  if (!StartEmbeddedTestServer()) {
     message_ = "Failed to start test server.";
     return false;
   }
@@ -40,7 +41,8 @@
     return false;
   }
 
-  GURL base_url = test_server()->GetURL("files/extensions/api_test/clipboard/");
+  GURL base_url = embedded_test_server()->GetURL(
+      "/extensions/api_test/clipboard/");
   GURL::Replacements replace_host;
   std::string host_str("localhost");  // Must stay in scope with replace_host.
   replace_host.SetHostStr(host_str);
@@ -80,12 +82,12 @@
 }  // namespace
 
 IN_PROC_BROWSER_TEST_F(ClipboardApiTest, Extension) {
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
   ASSERT_TRUE(RunExtensionTest("clipboard/extension")) << message_;
 }
 
 IN_PROC_BROWSER_TEST_F(ClipboardApiTest, ExtensionNoPermission) {
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
   ASSERT_TRUE(RunExtensionTest("clipboard/extension_no_permission"))
       << message_;
 }
diff --git a/chrome/browser/extensions/extension_function.cc b/chrome/browser/extensions/extension_function.cc
index 484abd7..3e6a397 100644
--- a/chrome/browser/extensions/extension_function.cc
+++ b/chrome/browser/extensions/extension_function.cc
@@ -88,7 +88,7 @@
   results_->Append(result);
 }
 
-const ListValue* ExtensionFunction::GetResultList() {
+const base::ListValue* ExtensionFunction::GetResultList() {
   return results_.get();
 }
 
@@ -128,7 +128,7 @@
 
   // If results were never set, we send an empty argument list.
   if (!results_)
-    results_.reset(new ListValue());
+    results_.reset(new base::ListValue());
 
   response_callback_.Run(type, *results_, GetError());
 }
diff --git a/chrome/browser/extensions/extension_function_dispatcher.cc b/chrome/browser/extensions/extension_function_dispatcher.cc
index a7ff244..daa25d2 100644
--- a/chrome/browser/extensions/extension_function_dispatcher.cc
+++ b/chrome/browser/extensions/extension_function_dispatcher.cc
@@ -48,7 +48,7 @@
 
 void LogSuccess(const std::string& extension_id,
                 const std::string& api_name,
-                scoped_ptr<ListValue> args,
+                scoped_ptr<base::ListValue> args,
                 Profile* profile) {
   // The ActivityLog can only be accessed from the main (UI) thread.  If we're
   // running on the wrong thread, re-dispatch from the main thread.
@@ -70,7 +70,7 @@
 
 void LogFailure(const std::string& extension_id,
                 const std::string& api_name,
-                scoped_ptr<ListValue> args,
+                scoped_ptr<base::ListValue> args,
                 extensions::BlockedAction::Reason reason,
                 Profile* profile) {
   // The ActivityLog can only be accessed from the main (UI) thread.  If we're
@@ -226,6 +226,11 @@
   return NULL;
 }
 
+content::WebContents*
+ExtensionFunctionDispatcher::Delegate::GetVisibleWebContents() const {
+  return GetAssociatedWebContents();
+}
+
 void ExtensionFunctionDispatcher::GetAllFunctionNames(
     std::vector<std::string>* names) {
   ExtensionFunctionRegistry::GetInstance()->GetAllNames(names);
diff --git a/chrome/browser/extensions/extension_function_dispatcher.h b/chrome/browser/extensions/extension_function_dispatcher.h
index b6cebd6..85f15ef 100644
--- a/chrome/browser/extensions/extension_function_dispatcher.h
+++ b/chrome/browser/extensions/extension_function_dispatcher.h
@@ -57,11 +57,16 @@
     virtual extensions::WindowController* GetExtensionWindowController() const;
 
     // Asks the delegate for any relevant WebContents associated with this
-    // context. For example, the WebbContents in which an infobar or
+    // context. For example, the WebContents in which an infobar or
     // chrome-extension://<id> URL are being shown. Callers must check for a
     // NULL return value (as in the case of a background page).
     virtual content::WebContents* GetAssociatedWebContents() const;
 
+    // If the associated web contents is not null, returns that. Otherwise,
+    // returns the next most relevant visible web contents. Callers must check
+    // for a NULL return value (as in the case of a background page).
+    virtual content::WebContents* GetVisibleWebContents() const;
+
    protected:
     virtual ~Delegate() {}
   };
diff --git a/chrome/browser/extensions/extension_function_histogram_value.h b/chrome/browser/extensions/extension_function_histogram_value.h
index 6b1a5d4..9a8ef6d 100644
--- a/chrome/browser/extensions/extension_function_histogram_value.h
+++ b/chrome/browser/extensions/extension_function_histogram_value.h
@@ -484,7 +484,7 @@
   DEVELOPERPRIVATE_RESTART,
   DEVELOPERPRIVATE_ALLOWINCOGNITO,
   INPUT_IME_DELETESURROUNDINGTEXT,
-  FILEBROWSERPRIVATE_OPENNEWWINDOW,
+  DELETED_FILEBROWSERPRIVATE_OPENNEWWINDOW,
   CLOUDPRINTPRIVATE_GETCLIENTID,
   ECHOPRIVATE_GETUSERCONSENT,
   SYNCFILESYSTEM_SETCONFLICTRESOLUTIONPOLICY,
@@ -552,6 +552,12 @@
   FEEDBACKPRIVATE_GETUSEREMAIL,
   FEEDBACKPRIVATE_GETSYSTEMINFORMATION,
   FEEDBACKPRIVATE_SENDFEEDBACK,
+  EXPERIMENTAL_INPUT_VIRTUALKEYBOARD_INSERTTEXT,
+  DIAGNOSTICS_SENDPACKET,
+  METRICSPRIVATE_GETFIELDTRIAL,
+  FILEBROWSERPRIVATE_ZOOM,
+  WEBVIEW_GO,
+  WEBSTOREPRIVATE_ISININCOGNITOMODEFUNCTION,
   ENUM_BOUNDARY // Last entry: Add new entries above.
 };
 
diff --git a/chrome/browser/extensions/extension_function_registry.cc b/chrome/browser/extensions/extension_function_registry.cc
index 23d3a70..c6b3d4d 100644
--- a/chrome/browser/extensions/extension_function_registry.cc
+++ b/chrome/browser/extensions/extension_function_registry.cc
@@ -73,6 +73,7 @@
   RegisterFunction<extensions::EnableAppLauncherFunction>();
   RegisterFunction<extensions::GetWebGLStatusFunction>();
   RegisterFunction<extensions::GetIsLauncherEnabledFunction>();
+  RegisterFunction<extensions::IsInIncognitoModeFunction>();
 
   // Runtime
   RegisterFunction<extensions::RuntimeGetBackgroundPageFunction>();
diff --git a/chrome/browser/extensions/extension_host.cc b/chrome/browser/extensions/extension_host.cc
index 74c14f6..5668535 100644
--- a/chrome/browser/extensions/extension_host.cc
+++ b/chrome/browser/extensions/extension_host.cc
@@ -55,6 +55,10 @@
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/resource/resource_bundle.h"
 
+#if !defined(OS_ANDROID)
+#include "components/web_modal/web_contents_modal_dialog_manager.h"
+#endif
+
 using WebKit::WebDragOperation;
 using WebKit::WebDragOperationsMask;
 using content::NativeWebKeyboardEvent;
@@ -191,6 +195,15 @@
   return associated_web_contents_;
 }
 
+WebContents* ExtensionHost::GetVisibleWebContents() const {
+  if (associated_web_contents_)
+    return associated_web_contents_;
+  if ((extension_host_type_ == VIEW_TYPE_EXTENSION_POPUP) ||
+      (extension_host_type_ == VIEW_TYPE_PANEL))
+    return host_contents_.get();
+  return NULL;
+}
+
 void ExtensionHost::SetAssociatedWebContents(
     content::WebContents* web_contents) {
   associated_web_contents_ = web_contents;
@@ -252,6 +265,16 @@
     return;
   }
 
+#if !defined(OS_ANDROID)
+  if ((extension_host_type_ == VIEW_TYPE_EXTENSION_POPUP) ||
+      (extension_host_type_ == VIEW_TYPE_PANEL)) {
+    web_modal::WebContentsModalDialogManager::CreateForWebContents(
+        host_contents_.get());
+    web_modal::WebContentsModalDialogManager::FromWebContents(
+        host_contents_.get())->set_delegate(this);
+  }
+#endif
+
   host_contents_->GetController().LoadURL(
       initial_url_, content::Referrer(), content::PAGE_TRANSITION_LINK,
       std::string());
diff --git a/chrome/browser/extensions/extension_host.h b/chrome/browser/extensions/extension_host.h
index 9433037..b9a9972 100644
--- a/chrome/browser/extensions/extension_host.h
+++ b/chrome/browser/extensions/extension_host.h
@@ -29,6 +29,10 @@
 #include "chrome/browser/ui/android/extensions/extension_view_android.h"
 #endif
 
+#if !defined(OS_ANDROID)
+#include "chrome/browser/ui/chrome_web_modal_dialog_manager_delegate.h"
+#endif
+
 class Browser;
 class PrefsTabHelper;
 
@@ -47,6 +51,9 @@
 // privileges available to extensions.  It may have a view to be shown in the
 // browser UI, or it may be hidden.
 class ExtensionHost : public content::WebContentsDelegate,
+#if !defined(OS_ANDROID)
+                      public ChromeWebModalDialogManagerDelegate,
+#endif
                       public content::WebContentsObserver,
                       public ExtensionFunctionDispatcher::Delegate,
                       public content::NotificationObserver {
@@ -110,6 +117,7 @@
 
   // ExtensionFunctionDispatcher::Delegate
   virtual content::WebContents* GetAssociatedWebContents() const OVERRIDE;
+  virtual content::WebContents* GetVisibleWebContents() const OVERRIDE;
   void SetAssociatedWebContents(content::WebContents* web_contents);
 
   // Returns true if the render view is initialized and didn't crash.
diff --git a/chrome/browser/extensions/extension_incognito_apitest.cc b/chrome/browser/extensions/extension_incognito_apitest.cc
index dbf7033..c122733 100644
--- a/chrome/browser/extensions/extension_incognito_apitest.cc
+++ b/chrome/browser/extensions/extension_incognito_apitest.cc
@@ -16,11 +16,12 @@
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/browser_test_utils.h"
 #include "net/dns/mock_host_resolver.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
 
 using content::WebContents;
 
 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, IncognitoNoScript) {
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
 
   // Loads a simple extension which attempts to change the title of every page
   // that loads to "modified".
@@ -30,7 +31,7 @@
   // Open incognito window and navigate to test page.
   Browser* otr_browser = ui_test_utils::OpenURLOffTheRecord(
       browser()->profile(),
-      test_server()->GetURL("files/extensions/test_file.html"));
+      embedded_test_server()->GetURL("/extensions/test_file.html"));
 
   WebContents* tab = otr_browser->tab_strip_model()->GetActiveWebContents();
 
@@ -52,7 +53,7 @@
 
 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, MAYBE_IncognitoYesScript) {
   host_resolver()->AddRule("*", "127.0.0.1");
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
 
   // Load a dummy extension. This just tests that we don't regress a
   // crash fix when multiple incognito- and non-incognito-enabled extensions
@@ -72,7 +73,7 @@
   // Open incognito window and navigate to test page.
   Browser* otr_browser = ui_test_utils::OpenURLOffTheRecord(
       browser()->profile(),
-      test_server()->GetURL("files/extensions/test_file.html"));
+      embedded_test_server()->GetURL("/extensions/test_file.html"));
 
   WebContents* tab = otr_browser->tab_strip_model()->GetActiveWebContents();
 
@@ -102,14 +103,14 @@
 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, Incognito) {
 #endif
   host_resolver()->AddRule("*", "127.0.0.1");
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
 
   ResultCatcher catcher;
 
   // Open incognito window and navigate to test page.
   ui_test_utils::OpenURLOffTheRecord(
       browser()->profile(),
-      test_server()->GetURL("files/extensions/test_file.html"));
+      embedded_test_server()->GetURL("/extensions/test_file.html"));
 
   ASSERT_TRUE(LoadExtensionIncognito(test_data_dir_
       .AppendASCII("incognito").AppendASCII("apis")));
@@ -126,7 +127,7 @@
 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, IncognitoSplitMode) {
 #endif
   host_resolver()->AddRule("*", "127.0.0.1");
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
 
   // We need 2 ResultCatchers because we'll be running the same test in both
   // regular and incognito mode.
@@ -142,7 +143,7 @@
   // Open incognito window and navigate to test page.
   ui_test_utils::OpenURLOffTheRecord(
       browser()->profile(),
-      test_server()->GetURL("files/extensions/test_file.html"));
+      embedded_test_server()->GetURL("/extensions/test_file.html"));
 
   ASSERT_TRUE(LoadExtensionIncognito(test_data_dir_
       .AppendASCII("incognito").AppendASCII("split")));
@@ -166,14 +167,14 @@
 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, IncognitoDisabled) {
 #endif
   host_resolver()->AddRule("*", "127.0.0.1");
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
 
   ResultCatcher catcher;
 
   // Open incognito window and navigate to test page.
   ui_test_utils::OpenURLOffTheRecord(
       browser()->profile(),
-      test_server()->GetURL("files/extensions/test_file.html"));
+      embedded_test_server()->GetURL("/extensions/test_file.html"));
 
   ASSERT_TRUE(LoadExtension(test_data_dir_
       .AppendASCII("incognito").AppendASCII("apis_disabled")));
@@ -190,7 +191,7 @@
 // Test that opening a popup from an incognito browser window works properly.
 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, MAYBE_IncognitoPopup) {
   host_resolver()->AddRule("*", "127.0.0.1");
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
 
   ResultCatcher catcher;
 
@@ -200,7 +201,7 @@
   // Open incognito window and navigate to test page.
   Browser* incognito_browser = ui_test_utils::OpenURLOffTheRecord(
       browser()->profile(),
-      test_server()->GetURL("files/extensions/test_file.html"));
+      embedded_test_server()->GetURL("/extensions/test_file.html"));
 
   // Simulate the incognito's browser action being clicked.
   BrowserActionTestUtil(incognito_browser).Press(0);
diff --git a/chrome/browser/extensions/extension_info_map.h b/chrome/browser/extensions/extension_info_map.h
index a5f1b14..cfbf6c6 100644
--- a/chrome/browser/extensions/extension_info_map.h
+++ b/chrome/browser/extensions/extension_info_map.h
@@ -8,9 +8,9 @@
 #include <string>
 
 #include "base/basictypes.h"
-#include "base/time.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/time/time.h"
 #include "chrome/browser/extensions/extensions_quota_service.h"
 #include "chrome/browser/extensions/process_map.h"
 #include "chrome/common/extensions/extension_constants.h"
diff --git a/chrome/browser/extensions/extension_javascript_url_apitest.cc b/chrome/browser/extensions/extension_javascript_url_apitest.cc
index 4076c14..9e7fca1 100644
--- a/chrome/browser/extensions/extension_javascript_url_apitest.cc
+++ b/chrome/browser/extensions/extension_javascript_url_apitest.cc
@@ -9,7 +9,7 @@
 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, JavaScriptURLPermissions) {
   host_resolver()->AddRule("a.com", "127.0.0.1");
   host_resolver()->AddRule("b.com", "127.0.0.1");
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
 
   ASSERT_TRUE(RunExtensionTest("tabs/javascript_url_permissions")) << message_;
 }
diff --git a/chrome/browser/extensions/extension_keybinding_registry.cc b/chrome/browser/extensions/extension_keybinding_registry.cc
index e5cf544..9cc3cfb 100644
--- a/chrome/browser/extensions/extension_keybinding_registry.cc
+++ b/chrome/browser/extensions/extension_keybinding_registry.cc
@@ -70,7 +70,7 @@
   if (granter)
     granter->GrantIfRequested(extension);
 
-  scoped_ptr<ListValue> args(new ListValue());
+  scoped_ptr<base::ListValue> args(new base::ListValue());
   args->Append(Value::CreateStringValue(command));
 
   scoped_ptr<Event> event(new Event("commands.onCommand", args.Pass()));
diff --git a/chrome/browser/extensions/extension_messages_apitest.cc b/chrome/browser/extensions/extension_messages_apitest.cc
index e2a605c..2b9d995 100644
--- a/chrome/browser/extensions/extension_messages_apitest.cc
+++ b/chrome/browser/extensions/extension_messages_apitest.cc
@@ -36,18 +36,19 @@
   }
 
  private:
-  static scoped_ptr<ListValue> BuildEventArguments(const bool last_message,
-                                                   const std::string& data) {
+  static scoped_ptr<base::ListValue> BuildEventArguments(
+      const bool last_message,
+      const std::string& data) {
     DictionaryValue* event = new DictionaryValue();
     event->SetBoolean("lastMessage", last_message);
     event->SetString("data", data);
-    scoped_ptr<ListValue> arguments(new ListValue());
+    scoped_ptr<base::ListValue> arguments(new base::ListValue());
     arguments->Append(event);
     return arguments.Pass();
   }
 
   static scoped_ptr<extensions::Event> BuildEvent(
-      scoped_ptr<ListValue> event_args,
+      scoped_ptr<base::ListValue> event_args,
       Profile* profile,
       GURL event_url) {
     scoped_ptr<extensions::Event> event(new extensions::Event(
@@ -91,7 +92,7 @@
 
 // Tests that message passing between extensions and content scripts works.
 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, Messaging) {
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
   ASSERT_TRUE(RunExtensionTest("messaging/connect")) << message_;
 }
 
@@ -174,6 +175,7 @@
         "onConnectExternal",
         "onMessage",
         "onMessageExternal",
+        "onRestartRequired",
         "id",
     };
 
diff --git a/chrome/browser/extensions/extension_override_apitest.cc b/chrome/browser/extensions/extension_override_apitest.cc
index d0989a6..dcaa3cd 100644
--- a/chrome/browser/extensions/extension_override_apitest.cc
+++ b/chrome/browser/extensions/extension_override_apitest.cc
@@ -27,7 +27,7 @@
         browser()->profile()->GetPrefs()->GetDictionary(
             ExtensionWebUI::kExtensionURLOverrides);
 
-    const ListValue* values = NULL;
+    const base::ListValue* values = NULL;
     if (!overrides->GetList("history", &values))
       return false;
 
@@ -125,7 +125,7 @@
   // a preferences file without corresponding UnloadExtension() calls. This is
   // the same as the above test, except for that it is testing the case where
   // the file already contains dupes when an extension is loaded.
-  ListValue* list = new ListValue();
+  base::ListValue* list = new base::ListValue();
   for (size_t i = 0; i < 3; ++i)
     list->Append(Value::CreateStringValue("http://www.google.com/"));
 
diff --git a/chrome/browser/extensions/extension_pref_value_map.h b/chrome/browser/extensions/extension_pref_value_map.h
index a0120f9..9f8e3b2 100644
--- a/chrome/browser/extensions/extension_pref_value_map.h
+++ b/chrome/browser/extensions/extension_pref_value_map.h
@@ -11,7 +11,7 @@
 
 #include "base/observer_list.h"
 #include "base/prefs/pref_value_map.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "base/values.h"
 #include "components/browser_context_keyed_service/browser_context_keyed_service.h"
 #include "extensions/browser/extension_prefs_scope.h"
diff --git a/chrome/browser/extensions/extension_prefs.cc b/chrome/browser/extensions/extension_prefs.cc
index c7f5bbf..5dea347 100644
--- a/chrome/browser/extensions/extension_prefs.cc
+++ b/chrome/browser/extensions/extension_prefs.cc
@@ -121,6 +121,9 @@
 // updates that were waiting for idle.
 const char kDelayedInstallInfo[] = "idle_install_info";
 
+// Reason why the extension's install was delayed.
+const char kDelayedInstallReason[] = "delay_install_reason";
+
 // Path for the suggested page ordinal of a delayed extension install.
 const char kPrefSuggestedPageOrdinal[] = "suggested_page_ordinal";
 
@@ -182,10 +185,6 @@
 // Key for Geometry Cache preference.
 const char kPrefGeometryCache[] = "geometry_cache";
 
-// Key for the path of the directory of the file last chosen by the user in
-// response to a chrome.fileSystem.chooseEntry() call.
-const char kLastChooseEntryDirectory[] = "last_choose_file_directory";
-
 // Provider of write access to a dictionary storing extension prefs.
 class ScopedExtensionPrefUpdate : public DictionaryPrefUpdate {
  public:
@@ -1328,6 +1327,7 @@
 void ExtensionPrefs::SetDelayedInstallInfo(
     const Extension* extension,
     Extension::State initial_state,
+    DelayReason delay_reason,
     const syncer::StringOrdinal& page_ordinal) {
   DictionaryValue* extension_dict = new DictionaryValue();
   PopulateExtensionInfoPrefs(extension, time_provider_->GetCurrentTime(),
@@ -1342,6 +1342,8 @@
         page_ordinal.IsValid() ? page_ordinal.ToInternalValue()
                                : std::string());
   }
+  extension_dict->SetInteger(kDelayedInstallReason,
+                             static_cast<int>(delay_reason));
 
   UpdateExtensionPref(extension->id(), kDelayedInstallInfo, extension_dict);
 }
@@ -1377,6 +1379,7 @@
     needs_sort_ordinal = true;
     pending_install_dict->Remove(kPrefSuggestedPageOrdinal, NULL);
   }
+  pending_install_dict->Remove(kDelayedInstallReason, NULL);
 
   const base::Time install_time = time_provider_->GetCurrentTime();
   pending_install_dict->Set(
@@ -1405,6 +1408,24 @@
   return GetInstalledInfoHelper(extension_id, ext);
 }
 
+ExtensionPrefs::DelayReason ExtensionPrefs::GetDelayedInstallReason(
+    const std::string& extension_id) const {
+  const DictionaryValue* extension_prefs =
+      GetExtensionPref(extension_id);
+  if (!extension_prefs)
+    return DELAY_REASON_NONE;
+
+  const DictionaryValue* ext = NULL;
+  if (!extension_prefs->GetDictionary(kDelayedInstallInfo, &ext))
+    return DELAY_REASON_NONE;
+
+  int delay_reason;
+  if (!ext->GetInteger(kDelayedInstallReason, &delay_reason))
+    return DELAY_REASON_NONE;
+
+  return static_cast<DelayReason>(delay_reason);
+}
+
 scoped_ptr<ExtensionPrefs::ExtensionsInfo> ExtensionPrefs::
     GetAllDelayedInstallInfo() const {
   scoped_ptr<ExtensionsInfo> extensions_info(new ExtensionsInfo);
@@ -1465,6 +1486,16 @@
   return creation_flags;
 }
 
+int ExtensionPrefs::GetDelayedInstallCreationFlags(
+    const std::string& extension_id) const {
+  int creation_flags = Extension::NO_FLAGS;
+  const DictionaryValue* delayed_info = NULL;
+  if (ReadPrefAsDictionary(extension_id, kDelayedInstallInfo, &delayed_info)) {
+    delayed_info->GetInteger(kPrefCreationFlags, &creation_flags);
+  }
+  return creation_flags;
+}
+
 bool ExtensionPrefs::WasInstalledByDefault(
     const std::string& extension_id) const {
   const DictionaryValue* dictionary = GetExtensionPref(extension_id);
@@ -1624,25 +1655,6 @@
   UpdateExtensionPref(extension_id, kPrefGeometryCache, cache.release());
 }
 
-bool ExtensionPrefs::GetLastChooseEntryDirectory(
-    const std::string& extension_id, base::FilePath* result) const {
-  const DictionaryValue* dictionary = GetExtensionPref(extension_id);
-  if (!dictionary)
-    return false;
-
-  const Value* value;
-  if (!dictionary->Get(kLastChooseEntryDirectory, &value))
-    return false;
-
-  return base::GetValueAsFilePath(*value, result);
-}
-
-void ExtensionPrefs::SetLastChooseEntryDirectory(
-    const std::string& extension_id, const base::FilePath& value) {
-  UpdateExtensionPref(extension_id, kLastChooseEntryDirectory,
-                      base::CreateFilePathValue(value));
-}
-
 ExtensionPrefs::ExtensionPrefs(
     PrefService* prefs,
     const base::FilePath& root_dir,
diff --git a/chrome/browser/extensions/extension_prefs.h b/chrome/browser/extensions/extension_prefs.h
index a0eb1ec..d721375 100644
--- a/chrome/browser/extensions/extension_prefs.h
+++ b/chrome/browser/extensions/extension_prefs.h
@@ -11,7 +11,7 @@
 
 #include "base/memory/linked_ptr.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "base/values.h"
 #include "chrome/browser/extensions/extension_scoped_prefs.h"
 #include "chrome/browser/prefs/scoped_user_pref_update.h"
@@ -81,6 +81,17 @@
     LAUNCH_DEFAULT = LAUNCH_REGULAR
   };
 
+  // This enum is used to store the reason an extension's install has been
+  // delayed.  Do not remove items or re-order this enum as it is used in
+  // preferences.
+  enum DelayReason {
+    DELAY_REASON_NONE = 0,
+    DELAY_REASON_GC = 1,
+    DELAY_REASON_WAIT_FOR_IDLE = 2,
+    DELAY_REASON_WAIT_FOR_IMPORTS = 3,
+  };
+
+
   // Creates base::Time classes. The default implementation is just to return
   // the current time, but tests can inject alternative implementations.
   class TimeProvider {
@@ -394,9 +405,10 @@
       const std::string& extension_id) const;
 
   // We've downloaded an updated .crx file for the extension, but are waiting
-  // for idle time to install it.
+  // to install it.
   void SetDelayedInstallInfo(const Extension* extension,
                              Extension::State initial_state,
+                             DelayReason delay_reason,
                              const syncer::StringOrdinal& page_ordinal);
 
   // Removes any delayed install information we have for the given
@@ -411,6 +423,8 @@
   scoped_ptr<ExtensionInfo> GetDelayedInstallInfo(
       const std::string& extension_id) const;
 
+  DelayReason GetDelayedInstallReason(const std::string& extension_id) const;
+
   // Returns information about all the extensions that have delayed install
   // information.
   scoped_ptr<ExtensionsInfo> GetAllDelayedInstallInfo() const;
@@ -430,6 +444,9 @@
   // Returns the creation flags mask for the extension.
   int GetCreationFlags(const std::string& extension_id) const;
 
+  // Returns the creation flags mask for a delayed install extension.
+  int GetDelayedInstallCreationFlags(const std::string& extension_id) const;
+
   // Returns true if the extension was installed from the Chrome Web Store.
   bool IsFromWebStore(const std::string& extension_id) const;
 
@@ -478,13 +495,6 @@
   void SetGeometryCache(const std::string& extension_id,
                         scoped_ptr<base::DictionaryValue> cache);
 
-  // The path of the directory containing the last file chosen by the user in
-  // response to a chrome.fileSystem.chooseEntry() call for this extension.
-  bool GetLastChooseEntryDirectory(const std::string& extension_id,
-                                   base::FilePath* result) const;
-  void SetLastChooseEntryDirectory(const std::string& extension_id,
-                                   const base::FilePath& value);
-
  private:
   friend class ExtensionPrefsBlacklistedExtensions;  // Unit test.
   friend class ExtensionPrefsUninstallExtension;     // Unit test.
diff --git a/chrome/browser/extensions/extension_prefs_unittest.cc b/chrome/browser/extensions/extension_prefs_unittest.cc
index 5fc8484..08d07d6 100644
--- a/chrome/browser/extensions/extension_prefs_unittest.cc
+++ b/chrome/browser/extensions/extension_prefs_unittest.cc
@@ -168,7 +168,7 @@
     scoped_ptr<APIPermission> permission(
         permission_info->CreateAPIPermission());
     {
-      scoped_ptr<ListValue> value(new ListValue());
+      scoped_ptr<base::ListValue> value(new base::ListValue());
       value->Append(Value::CreateStringValue("tcp-connect:*.example.com:80"));
       value->Append(Value::CreateStringValue("udp-bind::8080"));
       value->Append(Value::CreateStringValue("udp-send-to::8888"));
@@ -452,6 +452,7 @@
     ASSERT_TRUE(extension.get()) << errors;
     ASSERT_EQ(id, extension->id());
     prefs()->SetDelayedInstallInfo(extension.get(), Extension::ENABLED,
+                                   ExtensionPrefs::DELAY_REASON_WAIT_FOR_IDLE,
                                    syncer::StringOrdinal());
   }
 
diff --git a/chrome/browser/extensions/extension_process_manager.cc b/chrome/browser/extensions/extension_process_manager.cc
index 4ef475d..7346c25 100644
--- a/chrome/browser/extensions/extension_process_manager.cc
+++ b/chrome/browser/extensions/extension_process_manager.cc
@@ -12,7 +12,7 @@
 #include "base/metrics/histogram.h"
 #include "base/stl_util.h"
 #include "base/strings/string_number_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/extensions/api/runtime/runtime_api.h"
 #include "chrome/browser/extensions/extension_host.h"
diff --git a/chrome/browser/extensions/extension_process_manager.h b/chrome/browser/extensions/extension_process_manager.h
index 75cdb40..12fdf4a 100644
--- a/chrome/browser/extensions/extension_process_manager.h
+++ b/chrome/browser/extensions/extension_process_manager.h
@@ -13,7 +13,7 @@
 #include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
 #include "extensions/common/view_type.h"
diff --git a/chrome/browser/extensions/extension_protocols_unittest.cc b/chrome/browser/extensions/extension_protocols_unittest.cc
index acffeeb..b096d98 100644
--- a/chrome/browser/extensions/extension_protocols_unittest.cc
+++ b/chrome/browser/extensions/extension_protocols_unittest.cc
@@ -67,7 +67,7 @@
   manifest.SetString("name", "An extension with web-accessible resources");
   manifest.SetString("version", "2");
 
-  ListValue* web_accessible_list = new ListValue();
+  base::ListValue* web_accessible_list = new base::ListValue();
   web_accessible_list->AppendString("test.dat");
   manifest.Set("web_accessible_resources", web_accessible_list);
 
diff --git a/chrome/browser/extensions/extension_renderer_state.cc b/chrome/browser/extensions/extension_renderer_state.cc
index c43c690..551d895 100644
--- a/chrome/browser/extensions/extension_renderer_state.cc
+++ b/chrome/browser/extensions/extension_renderer_state.cc
@@ -8,7 +8,6 @@
 #include "base/bind_helpers.h"
 #include "chrome/browser/sessions/session_tab_helper.h"
 #include "chrome/browser/tab_contents/retargeting_details.h"
-#include "chrome/browser/webview/webview_guest.h"
 #include "chrome/common/chrome_notification_types.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/navigation_details.h"
diff --git a/chrome/browser/extensions/extension_renderer_state.h b/chrome/browser/extensions/extension_renderer_state.h
index 8118585..1ce2dde 100644
--- a/chrome/browser/extensions/extension_renderer_state.h
+++ b/chrome/browser/extensions/extension_renderer_state.h
@@ -12,9 +12,7 @@
 #include "base/basictypes.h"
 #include "base/memory/singleton.h"
 
-namespace chrome {
 class WebViewGuest;
-}  // namespace chrome
 
 // This class keeps track of renderer state for use on the IO thread. All
 // methods should be called on the IO thread except for Init and Shutdown.
@@ -48,7 +46,7 @@
   class RenderViewHostObserver;
   class TabObserver;
   friend class TabObserver;
-  friend class chrome::WebViewGuest;
+  friend class WebViewGuest;
   friend struct DefaultSingletonTraits<ExtensionRendererState>;
 
   typedef std::pair<int, int> RenderId;
diff --git a/chrome/browser/extensions/extension_service.cc b/chrome/browser/extensions/extension_service.cc
index c08866d..2458305 100644
--- a/chrome/browser/extensions/extension_service.cc
+++ b/chrome/browser/extensions/extension_service.cc
@@ -23,7 +23,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/sequenced_worker_pool.h"
 #include "base/threading/thread_restrictions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "base/values.h"
 #include "base/version.h"
 #include "chrome/browser/app_mode/app_mode_utils.h"
@@ -76,6 +76,7 @@
 #include "chrome/common/chrome_version_info.h"
 #include "chrome/common/extensions/background_info.h"
 #include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/extension_constants.h"
 #include "chrome/common/extensions/extension_file_util.h"
 #include "chrome/common/extensions/extension_manifest_constants.h"
 #include "chrome/common/extensions/extension_messages.h"
@@ -85,6 +86,7 @@
 #include "chrome/common/extensions/manifest.h"
 #include "chrome/common/extensions/manifest_handlers/app_isolation_info.h"
 #include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
+#include "chrome/common/extensions/manifest_handlers/shared_module_info.h"
 #include "chrome/common/extensions/manifest_url_handler.h"
 #include "chrome/common/extensions/permissions/permissions_data.h"
 #include "chrome/common/extensions/sync_helper.h"
@@ -128,6 +130,7 @@
 using extensions::PermissionMessage;
 using extensions::PermissionMessages;
 using extensions::PermissionSet;
+using extensions::SharedModuleInfo;
 using extensions::UnloadedExtensionInfo;
 
 namespace errors = extension_manifest_errors;
@@ -157,6 +160,10 @@
 // which can be garbage collected.
 static const int kGarbageCollectStartupDelay = 30;
 
+static bool IsSharedModule(const Extension* extension) {
+  return SharedModuleInfo::IsSharedModule(extension);
+}
+
 }  // namespace
 
 ExtensionService::ExtensionRuntimeData::ExtensionRuntimeData()
@@ -340,7 +347,7 @@
       event_routers_initialized_(false),
       update_once_all_providers_are_ready_(false),
       browser_terminating_(false),
-      installs_delayed_(false),
+      installs_delayed_for_gc_(false),
       is_first_run_(false),
       app_sync_bundle_(this),
       extension_sync_bundle_(this) {
@@ -457,33 +464,6 @@
   }
 }
 
-void ExtensionService::InitEventRoutersAfterImport() {
-  RegisterForImportFinished();
-}
-
-void ExtensionService::RegisterForImportFinished() {
-  if (!registrar_.IsRegistered(this, chrome::NOTIFICATION_IMPORT_FINISHED,
-                               content::Source<Profile>(profile_))) {
-    registrar_.Add(this, chrome::NOTIFICATION_IMPORT_FINISHED,
-                   content::Source<Profile>(profile_));
-  }
-}
-
-void ExtensionService::InitAfterImport() {
-  startup_metric_utils::ScopedSlowStartupUMA
-      scoped_timer("Startup.SlowStartupExtensionServiceInitAfterImport");
-  component_loader_->LoadAll();
-
-  CheckForExternalUpdates();
-
-  GarbageCollectExtensions();
-
-  // Idempotent, so although there is a possible race if the import
-  // process finished sometime in the middle of ProfileImpl::InitExtensions,
-  // it cannot happen twice.
-  InitEventRouters();
-}
-
 void ExtensionService::InitEventRouters() {
   if (event_routers_initialized_)
     return;
@@ -557,31 +537,48 @@
     // extension listens to onStartup and opens a window).
     SetReadyAndNotifyListeners();
   } else {
-    // TODO(mek): It might be cleaner to do the FinishDelayedInstallInfo stuff
-    // here instead of in installedloader.
-    if (g_browser_process->profile_manager() &&
-        g_browser_process->profile_manager()->will_import()) {
-      // Do not load any component extensions, since they may conflict with the
-      // import process.
+    // LoadAllExtensions() calls OnLoadedInstalledExtensions().
+    component_loader_->LoadAll();
+    extensions::InstalledLoader(this).LoadAllExtensions();
 
-      extensions::InstalledLoader(this).LoadAllExtensions();
-      SetReadyAndNotifyListeners();
-      RegisterForImportFinished();
-    } else {
-      // In this case, LoadAllExtensions() calls OnLoadedInstalledExtensions().
-      component_loader_->LoadAll();
-      extensions::InstalledLoader(this).LoadAllExtensions();
-      SetReadyAndNotifyListeners();
-
-      // TODO(erikkay) this should probably be deferred to a future point
-      // rather than running immediately at startup.
-      CheckForExternalUpdates();
-
-      base::MessageLoop::current()->PostDelayedTask(
-          FROM_HERE,
-          base::Bind(&ExtensionService::GarbageCollectExtensions, AsWeakPtr()),
-          base::TimeDelta::FromSeconds(kGarbageCollectStartupDelay));
+    // Finish install (if possible) of extensions that were still delayed while
+    // the browser was shut down.
+    scoped_ptr<extensions::ExtensionPrefs::ExtensionsInfo> delayed_info(
+        extension_prefs_->GetAllDelayedInstallInfo());
+    for (size_t i = 0; i < delayed_info->size(); ++i) {
+      ExtensionInfo* info = delayed_info->at(i).get();
+      scoped_refptr<const Extension> extension(NULL);
+      if (info->extension_manifest) {
+        std::string error;
+        extension = Extension::Create(
+            info->extension_path,
+            info->extension_location,
+            *info->extension_manifest,
+            extension_prefs_->GetDelayedInstallCreationFlags(
+                info->extension_id),
+            info->extension_id,
+            &error);
+        if (extension.get())
+          delayed_installs_.Insert(extension);
+      }
     }
+    MaybeFinishDelayedInstallations();
+
+    scoped_ptr<extensions::ExtensionPrefs::ExtensionsInfo> delayed_info2(
+        extension_prefs_->GetAllDelayedInstallInfo());
+    UMA_HISTOGRAM_COUNTS_100("Extensions.UpdateOnLoad",
+                             delayed_info2->size() - delayed_info->size());
+
+    SetReadyAndNotifyListeners();
+
+    // TODO(erikkay) this should probably be deferred to a future point
+    // rather than running immediately at startup.
+    CheckForExternalUpdates();
+
+    base::MessageLoop::current()->PostDelayedTask(
+        FROM_HERE,
+        base::Bind(&ExtensionService::GarbageCollectExtensions, AsWeakPtr()),
+        base::TimeDelta::FromSeconds(kGarbageCollectStartupDelay));
 
     if (extension_prefs_->NeedsStorageGarbageCollection()) {
       GarbageCollectIsolatedStorage();
@@ -672,7 +669,7 @@
   return true;
 }
 
-void ExtensionService::ReloadExtension(const std::string& extension_id) {
+void ExtensionService::ReloadExtension(const std::string extension_id) {
   CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
 
   // If the extension is already reloading, don't reload again.
@@ -708,7 +705,7 @@
     path = unloaded_extension_paths_[extension_id];
   }
 
-  if (delayed_updates_for_idle_.Contains(extension_id)) {
+  if (delayed_installs_.Contains(extension_id)) {
     FinishDelayedInstallation(extension_id);
     return;
   }
@@ -716,12 +713,15 @@
   // If we're reloading a component extension, use the component extension
   // loader's reloader.
   if (component_loader_->Exists(extension_id)) {
+    SetBeingReloaded(extension_id, true);
     component_loader_->Reload(extension_id);
+    SetBeingReloaded(extension_id, false);
     return;
   }
 
   // Check the installed extensions to see if what we're reloading was already
   // installed.
+  SetBeingReloaded(extension_id, true);
   scoped_ptr<ExtensionInfo> installed_extension(
       extension_prefs_->GetInstalledExtensionInfo(extension_id));
   if (installed_extension.get() &&
@@ -734,6 +734,8 @@
     CHECK(!path.empty());
     extensions::UnpackedInstaller::Create(this)->Load(path);
   }
+  // When reloading is done, mark this extension as done reloading.
+  SetBeingReloaded(extension_id, false);
 }
 
 bool ExtensionService::UninstallExtension(
@@ -836,9 +838,10 @@
     extension_sync_bundle_.ProcessDeletion(extension_id, sync_change);
   }
 
-  delayed_updates_for_idle_.Remove(extension_id);
   delayed_installs_.Remove(extension_id);
 
+  PruneSharedModulesOnUninstall(extension.get());
+
   // Track the uninstallation.
   UMA_HISTOGRAM_ENUMERATION("Extensions.ExtensionUninstalled", 1, 2);
 
@@ -924,6 +927,7 @@
   // |extension| can be NULL if sync disables an extension that is not
   // installed yet.
   if (extension &&
+      disable_reason != Extension::DISABLE_RELOAD &&
       !system_->management_policy()->UserMayModifySettings(extension, NULL)) {
     return;
   }
@@ -960,12 +964,12 @@
 
   for (ExtensionSet::const_iterator extension = extensions_.begin();
       extension != extensions_.end(); ++extension) {
-    if (management_policy->UserMayModifySettings(*extension, NULL))
+    if (management_policy->UserMayModifySettings(extension->get(), NULL))
       to_disable.push_back(*extension);
   }
   for (ExtensionSet::const_iterator extension = terminated_extensions_.begin();
       extension != terminated_extensions_.end(); ++extension) {
-    if (management_policy->UserMayModifySettings(*extension, NULL))
+    if (management_policy->UserMayModifySettings(extension->get(), NULL))
       to_disable.push_back(*extension);
   }
 
@@ -2205,6 +2209,92 @@
   child_process_logging::SetActiveExtensions(extension_ids);
 }
 
+ExtensionService::ImportStatus ExtensionService::SatisfyImports(
+    const Extension* extension) {
+  ImportStatus status = IMPORT_STATUS_OK;
+  std::vector<std::string> pending;
+  // TODO(elijahtaylor): Message the user if there is a failure that is
+  // unrecoverable.
+  if (SharedModuleInfo::ImportsModules(extension)) {
+    const std::vector<SharedModuleInfo::ImportInfo>& imports =
+        SharedModuleInfo::GetImports(extension);
+    std::vector<SharedModuleInfo::ImportInfo>::const_iterator i;
+    for (i = imports.begin(); i != imports.end(); ++i) {
+      Version version_required(i->minimum_version);
+      const Extension* imported_module =
+          GetExtensionById(i->extension_id, true);
+      if (!imported_module) {
+        if (extension->from_webstore()) {
+          status = IMPORT_STATUS_UNSATISFIED;
+          pending.push_back(i->extension_id);
+        } else {
+          return IMPORT_STATUS_UNRECOVERABLE;
+        }
+      } else if (!SharedModuleInfo::IsSharedModule(imported_module)) {
+        return IMPORT_STATUS_UNRECOVERABLE;
+      } else if (version_required.IsValid() &&
+                 imported_module->version()->CompareTo(version_required) < 0) {
+        if (imported_module->from_webstore()) {
+          status = IMPORT_STATUS_UNSATISFIED;
+        } else {
+          return IMPORT_STATUS_UNRECOVERABLE;
+        }
+      }
+    }
+  }
+  if (status == IMPORT_STATUS_UNSATISFIED) {
+    for (std::vector<std::string>::const_iterator iter = pending.begin();
+         iter != pending.end();
+         ++iter) {
+      pending_extension_manager()->AddFromExtensionImport(
+          *iter,
+          extension_urls::GetWebstoreUpdateUrl(),
+          IsSharedModule);
+    }
+    CheckForUpdatesSoon();
+  }
+  return status;
+}
+
+scoped_ptr<const ExtensionSet>
+    ExtensionService::GetDependentExtensions(const Extension* extension) {
+  scoped_ptr<ExtensionSet> dependents(new ExtensionSet());
+  scoped_ptr<ExtensionSet> set_to_check(new ExtensionSet());
+  if (SharedModuleInfo::IsSharedModule(extension)) {
+    set_to_check->InsertAll(disabled_extensions_);
+    set_to_check->InsertAll(delayed_installs_);
+    set_to_check->InsertAll(extensions_);
+    for (ExtensionSet::const_iterator iter = set_to_check->begin();
+         iter != set_to_check->end(); ++iter) {
+      if (SharedModuleInfo::ImportsExtensionById(iter->get(),
+                                                 extension->id())) {
+        dependents->Insert(*iter);
+      }
+    }
+  }
+  return dependents.PassAs<const ExtensionSet>();
+}
+
+void ExtensionService::PruneSharedModulesOnUninstall(
+    const Extension* extension) {
+  if (SharedModuleInfo::ImportsModules(extension)) {
+    const std::vector<SharedModuleInfo::ImportInfo>& imports =
+        SharedModuleInfo::GetImports(extension);
+    std::vector<SharedModuleInfo::ImportInfo>::const_iterator i;
+    for (i = imports.begin(); i != imports.end(); ++i) {
+      const Extension* imported_module =
+          GetExtensionById(i->extension_id, true);
+      if (imported_module && imported_module->from_webstore()) {
+        scoped_ptr<const ExtensionSet> dependents =
+            GetDependentExtensions(imported_module);
+        if (dependents->size() == 0) {
+          UninstallExtension(i->extension_id, false, NULL);
+        }
+      }
+    }
+  }
+}
+
 void ExtensionService::OnExtensionInstalled(
     const Extension* extension,
     const syncer::StringOrdinal& page_ordinal,
@@ -2287,10 +2377,10 @@
       initial_enable ? Extension::ENABLED : Extension::DISABLED;
   if (ShouldDelayExtensionUpdate(id, wait_for_idle)) {
     extension_prefs_->SetDelayedInstallInfo(extension, initial_state,
-                                            page_ordinal);
+        extensions::ExtensionPrefs::DELAY_REASON_WAIT_FOR_IDLE, page_ordinal);
 
     // Transfer ownership of |extension|.
-    delayed_updates_for_idle_.Insert(extension);
+    delayed_installs_.Insert(extension);
 
     // Notify extension of available update.
     extensions::RuntimeEventRouter::DispatchOnUpdateAvailableEvent(
@@ -2302,10 +2392,18 @@
     return;
   }
 
-  if (installs_delayed()) {
+  ImportStatus status = SatisfyImports(extension);
+  if (installs_delayed_for_gc()) {
     extension_prefs_->SetDelayedInstallInfo(extension, initial_state,
-                                            page_ordinal);
+        extensions::ExtensionPrefs::DELAY_REASON_GC, page_ordinal);
     delayed_installs_.Insert(extension);
+  } else if (status != IMPORT_STATUS_OK) {
+    if (status == IMPORT_STATUS_UNSATISFIED) {
+      extension_prefs_->SetDelayedInstallInfo(extension, initial_state,
+          extensions::ExtensionPrefs::DELAY_REASON_WAIT_FOR_IMPORTS,
+          page_ordinal);
+      delayed_installs_.Insert(extension);
+    }
   } else {
     AddNewOrUpdatedExtension(extension, initial_state, page_ordinal);
   }
@@ -2327,13 +2425,35 @@
 
 void ExtensionService::MaybeFinishDelayedInstallation(
     const std::string& extension_id) {
-  // Check if the extension already got updated.
-  if (!delayed_updates_for_idle_.Contains(extension_id))
+  // Check if the extension already got installed.
+  if (!delayed_installs_.Contains(extension_id))
     return;
-  // Check if the extension is idle.
-  if (!IsExtensionIdle(extension_id))
+  extensions::ExtensionPrefs::DelayReason reason =
+      extension_prefs_->GetDelayedInstallReason(extension_id);
+
+  // Check if the extension is idle. DELAY_REASON_NONE is used for older
+  // preferences files that will not have set this field but it was previously
+  // only used for idle updates.
+  if ((reason == extensions::ExtensionPrefs::DELAY_REASON_WAIT_FOR_IDLE ||
+       reason == extensions::ExtensionPrefs::DELAY_REASON_NONE) &&
+       is_ready() && !IsExtensionIdle(extension_id))
     return;
 
+  const Extension* extension = delayed_installs_.GetByID(extension_id);
+  if (reason == extensions::ExtensionPrefs::DELAY_REASON_WAIT_FOR_IMPORTS) {
+    ImportStatus status = SatisfyImports(extension);
+    if (status != IMPORT_STATUS_OK) {
+      if (status == IMPORT_STATUS_UNRECOVERABLE) {
+        delayed_installs_.Remove(extension_id);
+        // Make sure no version of the extension is actually installed, (i.e.,
+        // that this delayed install was not an update).
+        CHECK(!extension_prefs_->GetInstalledExtensionInfo(extension_id).get());
+        extension_prefs_->DeleteExtensionPrefs(extension_id);
+      }
+      return;
+    }
+  }
+
   FinishDelayedInstallation(extension_id);
 }
 
@@ -2342,7 +2462,7 @@
   scoped_refptr<const Extension> extension(
       GetPendingExtensionUpdate(extension_id));
   CHECK(extension.get());
-  delayed_updates_for_idle_.Remove(extension_id);
+  delayed_installs_.Remove(extension_id);
 
   if (!extension_prefs_->FinishDelayedInstallInfo(extension_id))
     NOTREACHED();
@@ -2399,11 +2519,17 @@
                               EXTERNAL_EXTENSION_INSTALLED,
                               EXTERNAL_EXTENSION_BUCKET_BOUNDARY);
   }
+
+  // Check extensions that may have been delayed only because this shared module
+  // was not available.
+  if (SharedModuleInfo::IsSharedModule(extension)) {
+    MaybeFinishDelayedInstallations();
+  }
 }
 
 const Extension* ExtensionService::GetPendingExtensionUpdate(
     const std::string& id) const {
-  return delayed_updates_for_idle_.GetByID(id);
+  return delayed_installs_.GetByID(id);
 }
 
 void ExtensionService::TrackTerminatedExtension(const Extension* extension) {
@@ -2642,15 +2768,11 @@
                      process->GetID()));
       break;
     }
-    case chrome::NOTIFICATION_IMPORT_FINISHED: {
-      InitAfterImport();
-      break;
-    }
     case chrome::NOTIFICATION_EXTENSION_HOST_DESTROYED: {
       extensions::ExtensionHost* host =
           content::Details<extensions::ExtensionHost>(details).ptr();
       std::string extension_id = host->extension_id();
-      if (delayed_updates_for_idle_.Contains(extension_id)) {
+      if (delayed_installs_.Contains(extension_id)) {
         // We were waiting for this extension to become idle, it now might have,
         // so maybe finish installation.
         base::MessageLoop::current()->PostDelayedTask(
@@ -2746,6 +2868,27 @@
   extension_runtime_data_[extension->id()].being_upgraded = value;
 }
 
+bool ExtensionService::IsBeingReloaded(
+    const std::string& extension_id) const {
+  return ContainsKey(extensions_being_reloaded_, extension_id);
+}
+
+void ExtensionService::SetBeingReloaded(const std::string& extension_id,
+                                         bool isBeingReloaded) {
+  LOG(INFO) << "****** " << __FUNCTION__;
+  LOG(INFO) << "****** " << __FUNCTION__ << " extension_id is: "
+            << extension_id << " and isBeingReloaded is " << isBeingReloaded;
+  LOG(INFO) << "****** " << __FUNCTION__ << " Set size is "
+            << extensions_being_reloaded_.size();
+  if (isBeingReloaded) {
+    extensions_being_reloaded_.insert(extension_id);
+    LOG(INFO) << "****** " << __FUNCTION__ << " insert succeeded.";
+  } else {
+    extensions_being_reloaded_.erase(extension_id);
+    LOG(INFO) << "****** " << __FUNCTION__ << " erase succeeded.";
+  }
+}
+
 bool ExtensionService::HasUsedWebRequest(const Extension* extension) const {
   ExtensionRuntimeDataMap::const_iterator it =
       extension_runtime_data_.find(extension->id());
@@ -2834,8 +2977,8 @@
     }
   }
 
-  DCHECK(!installs_delayed());
-  set_installs_delayed(true);
+  DCHECK(!installs_delayed_for_gc());
+  set_installs_delayed_for_gc(true);
   BrowserContext::GarbageCollectStoragePartitions(
       profile_, active_paths.Pass(),
       base::Bind(&ExtensionService::OnGarbageCollectIsolatedStorageFinished,
@@ -2843,18 +2986,22 @@
 }
 
 void ExtensionService::OnGarbageCollectIsolatedStorageFinished() {
-  set_installs_delayed(false);
+  set_installs_delayed_for_gc(false);
+  MaybeFinishDelayedInstallations();
+}
+
+void ExtensionService::MaybeFinishDelayedInstallations() {
+  std::vector<std::string> to_be_installed;
   for (ExtensionSet::const_iterator it = delayed_installs_.begin();
        it != delayed_installs_.end();
        ++it) {
-    FinishDelayedInstallation((*it)->id());
+    to_be_installed.push_back((*it)->id());
   }
-  for (ExtensionSet::const_iterator it = delayed_updates_for_idle_.begin();
-       it != delayed_updates_for_idle_.end();
+  for (std::vector<std::string>::const_iterator it = to_be_installed.begin();
+       it != to_be_installed.end();
        ++it) {
-    MaybeFinishDelayedInstallation((*it)->id());
+    MaybeFinishDelayedInstallation(*it);
   }
-  delayed_installs_.Clear();
 }
 
 void ExtensionService::OnNeedsToGarbageCollectIsolatedStorage() {
diff --git a/chrome/browser/extensions/extension_service.h b/chrome/browser/extensions/extension_service.h
index e83a3a6..8d0c6c3 100644
--- a/chrome/browser/extensions/extension_service.h
+++ b/chrome/browser/extensions/extension_service.h
@@ -66,7 +66,7 @@
 class ExtensionUpdater;
 class PendingExtensionManager;
 class SettingsFrontend;
-} // namespace extensions
+}  // namespace extensions
 
 namespace syncer {
 class SyncErrorFactory;
@@ -249,6 +249,11 @@
   bool IsBeingUpgraded(const extensions::Extension* extension) const;
   void SetBeingUpgraded(const extensions::Extension* extension, bool value);
 
+  // Getter and setter for the flag that specifies whether the extension is
+  // being reloaded.
+  bool IsBeingReloaded(const std::string& extension_name) const;
+  void SetBeingReloaded(const std::string& extension_id, bool value);
+
   // Getter and setter for the flag that specifies if the extension has used
   // the webrequest API.
   // TODO(mpcomplete): remove. http://crbug.com/100411
@@ -258,15 +263,6 @@
   // Initialize and start all installed extensions.
   void Init();
 
-  // To delay some initialization until after import has finished, register
-  // for the notification.
-  // TODO(yoz): remove InitEventRoutersAterImport.
-  void InitEventRoutersAfterImport();
-  void RegisterForImportFinished();
-
-  // Complete some initialization after being notified that import has finished.
-  void InitAfterImport();
-
   // Start up the extension event routers.
   void InitEventRouters();
 
@@ -320,7 +316,7 @@
 
   // Reloads the specified extension, sending the onLaunched() event to it if it
   // currently has any window showing.
-  void ReloadExtension(const std::string& extension_id);
+  void ReloadExtension(const std::string extension_id);
 
   // Uninstalls the specified extension. Callers should only call this method
   // with extensions that exist. |external_uninstall| is a magical parameter
@@ -413,6 +409,24 @@
   virtual void AddComponentExtension(const extensions::Extension* extension)
       OVERRIDE;
 
+  enum ImportStatus {
+   IMPORT_STATUS_OK,
+   IMPORT_STATUS_UNSATISFIED,
+   IMPORT_STATUS_UNRECOVERABLE
+  };
+
+  // Checks an extension's shared module imports to see if they are satisfied.
+  // If they are not, this function adds the dependencies to the pending install
+  // list if |extension| came from the webstore.
+  ImportStatus SatisfyImports(const extensions::Extension* extension);
+
+  // Returns a set of extensions that import a given extension.
+  scoped_ptr<const ExtensionSet> GetDependentExtensions(
+      const extensions::Extension* extension);
+
+  // Uninstalls shared modules that were only referenced by |extension|.
+  void PruneSharedModulesOnUninstall(const extensions::Extension* extension);
+
   // Informs the service that an extension's files are in place for loading.
   //
   // Please make sure the Blacklist is checked some time before calling this
@@ -423,6 +437,9 @@
       bool has_requirement_errors,
       bool wait_for_idle);
 
+  // Checks for delayed installation for all pending installs.
+  void MaybeFinishDelayedInstallations();
+
   // Similar to FinishInstallation, but first checks if there still is an update
   // pending for the extension, and makes sure the extension is still idle.
   void MaybeFinishDelayedInstallation(const std::string& extension_id);
@@ -770,9 +787,12 @@
   void ManageBlacklist(const std::set<std::string>& old_blacklisted_ids,
                        const std::set<std::string>& new_blacklisted_ids);
 
-  // Controls if installs are delayed. See comment for |installs_delayed_|.
-  void set_installs_delayed(bool value) { installs_delayed_ = value; }
-  bool installs_delayed() const { return installs_delayed_; }
+  // Controls if installs are delayed. See comment for
+  // |installs_delayed_for_gc_|.
+  void set_installs_delayed_for_gc(bool value) {
+    installs_delayed_for_gc_ = value;
+  }
+  bool installs_delayed_for_gc() const { return installs_delayed_for_gc_; }
 
   // The normal profile associated with this ExtensionService.
   Profile* profile_;
@@ -804,13 +824,8 @@
   // they can easily be un-blacklisted.
   ExtensionSet blacklisted_extensions_;
 
-  // The list of extension updates that have had their installs delayed because
-  // they are waiting for idle.
-  ExtensionSet delayed_updates_for_idle_;
-
-  // The list of extension installs delayed by |installs_delayed_|.
-  // This is a disjoint set from |delayed_updates_for_idle_|. Extensions in
-  // the |delayed_installs_| do not need to wait for idle.
+  // The list of extension installs delayed for various reasons.  The reason
+  // for delayed install is stored in ExtensionPrefs.
   ExtensionSet delayed_installs_;
 
   // Hold the set of pending extensions.
@@ -891,11 +906,11 @@
   // decide to abort.
   bool browser_terminating_;
 
-  // Set to true to delay all new extension installations. Acts as a lock
-  // to allow background processing of tasks such as garbage collection of
-  // on-disk state without needing to worry about race conditions caused
-  // by extension installation and reinstallation.
-  bool installs_delayed_;
+  // Set to true to delay all new extension installations. Acts as a lock to
+  // allow background processing of garbage collection of on-disk state without
+  // needing to worry about race conditions caused by extension installation and
+  // reinstallation.
+  bool installs_delayed_for_gc_;
 
   // Set to true if this is the first time this ExtensionService has run.
   // Used for specially handling external extensions that are installed the
@@ -907,6 +922,10 @@
 
   extensions::ProcessMap process_map_;
 
+  // A set of the extension ids currently being reloaded.  We use this to
+  // avoid showing a "new install" notice for an extension reinstall.
+  std::set<std::string> extensions_being_reloaded_;
+
   scoped_ptr<ExtensionErrorUI> extension_error_ui_;
   // Sequenced task runner for extension related file operations.
   scoped_refptr<base::SequencedTaskRunner> file_task_runner_;
diff --git a/chrome/browser/extensions/extension_service_unittest.cc b/chrome/browser/extensions/extension_service_unittest.cc
index 7d9aca1..9297723 100644
--- a/chrome/browser/extensions/extension_service_unittest.cc
+++ b/chrome/browser/extensions/extension_service_unittest.cc
@@ -116,6 +116,9 @@
 #include "chrome/browser/chromeos/settings/device_settings_service.h"
 #endif
 
+using base::DictionaryValue;
+using base::ListValue;
+using base::Value;
 using content::BrowserContext;
 using content::BrowserThread;
 using content::DOMStorageContext;
@@ -155,7 +158,8 @@
 const char* const updates_from_webstore = "akjooamlhcgeopfifcmlggaebeocgokj";
 
 struct ExtensionsOrder {
-  bool operator()(const Extension* a, const Extension* b) {
+  bool operator()(const scoped_refptr<const Extension>& a,
+                  const scoped_refptr<const Extension>& b) {
     return a->name() < b->name();
   }
 };
@@ -506,13 +510,13 @@
   ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
   base::FilePath path = temp_dir_.path();
   path = path.Append(FILE_PATH_LITERAL("TestingExtensionsPath"));
-  file_util::Delete(path, true);
+  base::Delete(path, true);
   file_util::CreateDirectory(path);
   base::FilePath temp_prefs = path.Append(FILE_PATH_LITERAL("Preferences"));
   file_util::CopyFile(prefs_file, temp_prefs);
 
   extensions_install_dir_ = path.Append(FILE_PATH_LITERAL("Extensions"));
-  file_util::Delete(extensions_install_dir_, true);
+  base::Delete(extensions_install_dir_, true);
   file_util::CopyDirectory(source_install_dir, extensions_install_dir_, true);
 
   ExtensionServiceInitParams params;
@@ -542,12 +546,12 @@
   ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
   base::FilePath path = temp_dir_.path();
   path = path.Append(FILE_PATH_LITERAL("TestingExtensionsPath"));
-  file_util::Delete(path, true);
+  base::Delete(path, true);
   file_util::CreateDirectory(path);
   base::FilePath prefs_filename =
       path.Append(FILE_PATH_LITERAL("TestPreferences"));
   extensions_install_dir_ = path.Append(FILE_PATH_LITERAL("Extensions"));
-  file_util::Delete(extensions_install_dir_, true);
+  base::Delete(extensions_install_dir_, true);
   file_util::CreateDirectory(extensions_install_dir_);
 
   ExtensionServiceInitParams params;
@@ -654,7 +658,7 @@
       ASSERT_TRUE(file_util::PathExists(pem_path));
     }
 
-    ASSERT_TRUE(file_util::Delete(crx_path, false));
+    ASSERT_TRUE(base::Delete(crx_path, false));
 
     scoped_ptr<ExtensionCreator> creator(new ExtensionCreator());
     ASSERT_TRUE(creator->Run(dir_path,
@@ -1450,6 +1454,66 @@
       prefs->GetDelayedInstallInfo("bjafgdebaacbbbecmhlhpofkepfkgcpa"));
 }
 
+// Test various cases for delayed install because of missing imports.
+TEST_F(ExtensionServiceTest, PendingImports) {
+  InitPluginService();
+
+  base::FilePath source_install_dir = data_dir_
+      .AppendASCII("pending_updates_with_imports")
+      .AppendASCII("Extensions");
+  base::FilePath pref_path = source_install_dir
+      .DirName()
+      .AppendASCII("Preferences");
+
+  InitializeInstalledExtensionService(pref_path, source_install_dir);
+
+  // Verify there are no pending extensions initially.
+  EXPECT_FALSE(service_->pending_extension_manager()->HasPendingExtensions());
+
+  service_->Init();
+  // Wait for GarbageCollectExtensions task to complete.
+  loop_.RunUntilIdle();
+
+  // These extensions are used by the extensions we test below, they must be
+  // installed.
+  EXPECT_TRUE(file_util::PathExists(extensions_install_dir_.AppendASCII(
+      "bjafgdebaacbbbecmhlhpofkepfkgcpa/1.0")));
+  EXPECT_TRUE(file_util::PathExists(extensions_install_dir_.AppendASCII(
+      "hpiknbiabeeppbpihjehijgoemciehgk/2")));
+
+  // Each of these extensions should have been rejected because of dependencies
+  // that cannot be satisfied.
+  ExtensionPrefs* prefs = service_->extension_prefs();
+  EXPECT_FALSE(
+      prefs->GetDelayedInstallInfo("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"));
+  EXPECT_FALSE(
+      prefs->GetInstalledExtensionInfo("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"));
+  EXPECT_FALSE(
+      prefs->GetDelayedInstallInfo("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"));
+  EXPECT_FALSE(
+      prefs->GetInstalledExtensionInfo("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"));
+  EXPECT_FALSE(
+      prefs->GetDelayedInstallInfo("cccccccccccccccccccccccccccccccc"));
+  EXPECT_FALSE(
+      prefs->GetInstalledExtensionInfo("cccccccccccccccccccccccccccccccc"));
+
+  // Make sure the import started for the extension with a dependency.
+  EXPECT_TRUE(
+      prefs->GetDelayedInstallInfo("behllobkkfkfnphdnhnkndlbkcpglgmj"));
+  EXPECT_EQ(ExtensionPrefs::DELAY_REASON_WAIT_FOR_IMPORTS,
+      prefs->GetDelayedInstallReason("behllobkkfkfnphdnhnkndlbkcpglgmj"));
+
+  EXPECT_FALSE(file_util::PathExists(extensions_install_dir_.AppendASCII(
+      "behllobkkfkfnphdnhnkndlbkcpglgmj/1.0.0.0")));
+
+  EXPECT_TRUE(service_->pending_extension_manager()->HasPendingExtensions());
+  std::string pending_id("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee");
+  EXPECT_TRUE(service_->pending_extension_manager()->IsIdPending(pending_id));
+  // Remove it because we are not testing the pending extension manager's
+  // ability to download and install extensions.
+  EXPECT_TRUE(service_->pending_extension_manager()->Remove(pending_id));
+}
+
 // Test installing extensions. This test tries to install few extensions using
 // crx files. If you need to change those crx files, feel free to repackage
 // them, throw away the key used and change the id's above.
@@ -1974,7 +2038,7 @@
 
   // Repeat the run with the pem file gone, and no special flags
   // Should refuse to overwrite the existing crx.
-  file_util::Delete(privkey_path, false);
+  base::Delete(privkey_path, false);
   ASSERT_FALSE(creator->Run(input_directory, crx_path, base::FilePath(),
       privkey_path, ExtensionCreator::kNoRunFlags));
 
@@ -2111,9 +2175,9 @@
   ASSERT_TRUE(file_util::PathExists(crx_path));
   ASSERT_TRUE(file_util::PathExists(privkey_path));
 
-  file_util::Delete(crx_path, false);
+  base::Delete(crx_path, false);
   // Move the pem file into the extension.
-  file_util::Move(privkey_path,
+  base::Move(privkey_path,
                   input_directory.AppendASCII("privkey.pem"));
 
   // This pack should fail because of the contained private key.
@@ -2214,7 +2278,7 @@
   // directory, and we don't want to copy the whole extension for a unittest.
   base::FilePath theme_file = extension_path.Append(chrome::kThemePackFilename);
   ASSERT_TRUE(file_util::PathExists(theme_file));
-  ASSERT_TRUE(file_util::Delete(theme_file, false));  // Not recursive.
+  ASSERT_TRUE(base::Delete(theme_file, false));  // Not recursive.
 }
 
 // Tests that we can change the ID of an unpacked extension by adding a key
@@ -3944,6 +4008,8 @@
   IndexedDBContext* idb_context =
       BrowserContext::GetDefaultStoragePartition(profile_.get())->
           GetIndexedDBContext();
+  idb_context->SetTaskRunnerForTesting(
+      base::MessageLoop::current()->message_loop_proxy().get());
   base::FilePath idb_path = idb_context->GetFilePathForTesting(origin_id);
   EXPECT_TRUE(file_util::CreateDirectory(idb_path));
   EXPECT_TRUE(file_util::DirectoryExists(idb_path));
@@ -4059,6 +4125,8 @@
   IndexedDBContext* idb_context =
       BrowserContext::GetDefaultStoragePartition(profile_.get())->
           GetIndexedDBContext();
+  idb_context->SetTaskRunnerForTesting(
+      base::MessageLoop::current()->message_loop_proxy().get());
   base::FilePath idb_path = idb_context->GetFilePathForTesting(origin_id);
   EXPECT_TRUE(file_util::CreateDirectory(idb_path));
   EXPECT_TRUE(file_util::DirectoryExists(idb_path));
diff --git a/chrome/browser/extensions/extension_sorting.cc b/chrome/browser/extensions/extension_sorting.cc
index dc92c4c..ec2ba25 100644
--- a/chrome/browser/extensions/extension_sorting.cc
+++ b/chrome/browser/extensions/extension_sorting.cc
@@ -467,6 +467,7 @@
     // Ensure that the web store app still isn't found in this list, since
     // it is added after this loop.
     DCHECK(*ext_it != extension_misc::kWebStoreAppId);
+    DCHECK(*ext_it != extension_misc::kChromeAppId);
   }
 
   // Include the Web Store App since it is displayed on the NTP.
@@ -477,6 +478,14 @@
                       web_store_app_page,
                       GetAppLaunchOrdinal(extension_misc::kWebStoreAppId));
   }
+  // Include the Chrome App since it is displayed in the app launcher.
+  syncer::StringOrdinal chrome_app_page =
+      GetPageOrdinal(extension_misc::kChromeAppId);
+  if (chrome_app_page.IsValid()) {
+    AddOrdinalMapping(extension_misc::kChromeAppId,
+                      chrome_app_page,
+                      GetAppLaunchOrdinal(extension_misc::kChromeAppId));
+  }
 }
 
 void ExtensionSorting::AddOrdinalMapping(
@@ -540,6 +549,7 @@
   chromeos::default_app_order::Get(&app_ids);
 #else
   const char* kDefaultAppOrder[] = {
+    extension_misc::kChromeAppId,
     extension_misc::kWebStoreAppId,
   };
   const std::vector<const char*> app_ids(
diff --git a/chrome/browser/extensions/extension_special_storage_policy_unittest.cc b/chrome/browser/extensions/extension_special_storage_policy_unittest.cc
index 3ae4143..7e07052 100644
--- a/chrome/browser/extensions/extension_special_storage_policy_unittest.cc
+++ b/chrome/browser/extensions/extension_special_storage_policy_unittest.cc
@@ -104,7 +104,7 @@
     manifest.SetString(keys::kName, "Protected");
     manifest.SetString(keys::kVersion, "1");
     manifest.SetString(keys::kLaunchWebURL, "http://explicit/protected/start");
-    ListValue* list = new ListValue();
+    base::ListValue* list = new base::ListValue();
     list->Append(Value::CreateStringValue("http://explicit/protected"));
     list->Append(Value::CreateStringValue("*://*.wildcards/protected"));
     manifest.Set(keys::kWebURLs, list);
@@ -126,10 +126,10 @@
     manifest.SetString(keys::kName, "Unlimited");
     manifest.SetString(keys::kVersion, "1");
     manifest.SetString(keys::kLaunchWebURL, "http://explicit/unlimited/start");
-    ListValue* list = new ListValue();
+    base::ListValue* list = new base::ListValue();
     list->Append(Value::CreateStringValue("unlimitedStorage"));
     manifest.Set(keys::kPermissions, list);
-    list = new ListValue();
+    list = new base::ListValue();
     list->Append(Value::CreateStringValue("http://explicit/unlimited"));
     list->Append(Value::CreateStringValue("*://*.wildcards/unlimited"));
     manifest.Set(keys::kWebURLs, list);
diff --git a/chrome/browser/extensions/extension_startup_browsertest.cc b/chrome/browser/extensions/extension_startup_browsertest.cc
index ada7f89..43519a9 100644
--- a/chrome/browser/extensions/extension_startup_browsertest.cc
+++ b/chrome/browser/extensions/extension_startup_browsertest.cc
@@ -79,11 +79,11 @@
   }
 
   virtual void TearDown() {
-    EXPECT_TRUE(file_util::Delete(preferences_file_, false));
+    EXPECT_TRUE(base::Delete(preferences_file_, false));
 
     // TODO(phajdan.jr): Check return values of the functions below, carefully.
-    file_util::Delete(user_scripts_dir_, true);
-    file_util::Delete(extensions_dir_, true);
+    base::Delete(user_scripts_dir_, true);
+    base::Delete(extensions_dir_, true);
 
     InProcessBrowserTest::TearDown();
   }
diff --git a/chrome/browser/extensions/extension_system.cc b/chrome/browser/extensions/extension_system.cc
index a2ae1f3..c65ec53 100644
--- a/chrome/browser/extensions/extension_system.cc
+++ b/chrome/browser/extensions/extension_system.cc
@@ -204,14 +204,7 @@
   // initialized (see issue 40144). Now that bookmarks aren't imported and
   // the event routers need to be initialized for every profile individually,
   // initialize them with the extension service.
-  // If import is going to run in a separate process (the profile itself is on
-  // the main process), wait for import to finish before initializing the
-  // routers.
-  if (g_browser_process->profile_manager()->will_import()) {
-    extension_service_->InitEventRoutersAfterImport();
-  } else {
-    extension_service_->InitEventRouters();
-  }
+  extension_service_->InitEventRouters();
 
   extension_warning_service_.reset(new ExtensionWarningService(profile_));
   extension_warning_badge_service_.reset(
diff --git a/chrome/browser/extensions/extension_tab_util.cc b/chrome/browser/extensions/extension_tab_util.cc
index e86607f..e8e50b0 100644
--- a/chrome/browser/extensions/extension_tab_util.cc
+++ b/chrome/browser/extensions/extension_tab_util.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/extensions/extension_tab_util.h"
 
+#include "apps/shell_window.h"
 #include "chrome/browser/extensions/api/tabs/tabs_constants.h"
 #include "chrome/browser/extensions/shell_window_registry.h"
 #include "chrome/browser/extensions/tab_helper.h"
@@ -16,7 +17,6 @@
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/browser_iterator.h"
 #include "chrome/browser/ui/browser_window.h"
-#include "chrome/browser/ui/extensions/shell_window.h"
 #include "chrome/browser/ui/tab_contents/tab_contents_iterator.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/common/extensions/extension.h"
@@ -33,6 +33,7 @@
 namespace keys = extensions::tabs_constants;
 namespace tabs = extensions::api::tabs;
 
+using apps::ShellWindow;
 using content::NavigationEntry;
 using content::WebContents;
 using extensions::APIPermission;
@@ -99,10 +100,10 @@
   return result;
 }
 
-ListValue* ExtensionTabUtil::CreateTabList(
+base::ListValue* ExtensionTabUtil::CreateTabList(
     const Browser* browser,
     const Extension* extension) {
-  ListValue* tab_list = new ListValue();
+  base::ListValue* tab_list = new base::ListValue();
   TabStripModel* tab_strip = browser->tab_strip_model();
   for (int i = 0; i < tab_strip->count(); ++i) {
     tab_list->Append(CreateTabValue(tab_strip->GetWebContentsAt(i),
diff --git a/chrome/browser/extensions/extension_tabs_apitest.cc b/chrome/browser/extensions/extension_tabs_apitest.cc
index 128e0b3..7a654a5 100644
--- a/chrome/browser/extensions/extension_tabs_apitest.cc
+++ b/chrome/browser/extensions/extension_tabs_apitest.cc
@@ -22,15 +22,14 @@
 #define MAYBE_UpdateWindowShowState DISABLED_UpdateWindowShowState
 #else
 
-#if defined(USE_AURA) || defined(OS_MACOSX) || defined(OS_WIN)
+#if defined(USE_AURA) || defined(OS_MACOSX)
 // Maximizing/fullscreen popup window doesn't work on aura's managed mode.
 // See bug crbug.com/116305.
 // Mac: http://crbug.com/103912
-// Failing on Win7: http://crbug.com/176683
 #define MAYBE_UpdateWindowShowState DISABLED_UpdateWindowShowState
 #else
 #define MAYBE_UpdateWindowShowState UpdateWindowShowState
-#endif  // defined(USE_AURA) || defined(OS_MACOSX) || defined(OS_WIN)
+#endif  // defined(USE_AURA) || defined(OS_MACOSX)
 
 #define MAYBE_UpdateWindowResize UpdateWindowResize
 #endif  // defined(OS_LINUX) && !defined(USE_AURA)
@@ -140,7 +139,7 @@
 
 // Flaky on the trybots. See http://crbug.com/96725.
 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, DISABLED_TabConnect) {
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
   ASSERT_TRUE(RunExtensionTest("tabs/connect")) << message_;
 }
 
@@ -156,7 +155,7 @@
 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, DISABLED_CaptureVisibleTabJpeg) {
   host_resolver()->AddRule("a.com", "127.0.0.1");
   host_resolver()->AddRule("b.com", "127.0.0.1");
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
   ASSERT_TRUE(RunExtensionSubtest("tabs/capture_visible_tab",
                                   "test_jpeg.html")) << message_;
 }
@@ -164,7 +163,7 @@
 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, DISABLED_CaptureVisibleTabPng) {
   host_resolver()->AddRule("a.com", "127.0.0.1");
   host_resolver()->AddRule("b.com", "127.0.0.1");
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
   ASSERT_TRUE(RunExtensionSubtest("tabs/capture_visible_tab",
                                   "test_png.html")) << message_;
 }
diff --git a/chrome/browser/extensions/extension_web_ui.cc b/chrome/browser/extensions/extension_web_ui.cc
index fc851b9..b62af29 100644
--- a/chrome/browser/extensions/extension_web_ui.cc
+++ b/chrome/browser/extensions/extension_web_ui.cc
@@ -45,7 +45,7 @@
 namespace {
 
 // De-dupes the items in |list|. Assumes the values are strings.
-void CleanUpDuplicates(ListValue* list) {
+void CleanUpDuplicates(base::ListValue* list) {
   std::set<std::string> seen_values;
 
   // Loop backwards as we may be removing items.
@@ -178,10 +178,10 @@
     return false;
 
   Profile* profile = Profile::FromBrowserContext(browser_context);
-  const DictionaryValue* overrides =
+  const base::DictionaryValue* overrides =
       profile->GetPrefs()->GetDictionary(kExtensionURLOverrides);
   std::string page = url->host();
-  const ListValue* url_list = NULL;
+  const base::ListValue* url_list = NULL;
   if (!overrides || !overrides->GetList(page, &url_list))
     return false;
 
@@ -244,7 +244,7 @@
 bool ExtensionWebUI::HandleChromeURLOverrideReverse(
     GURL* url, content::BrowserContext* browser_context) {
   Profile* profile = Profile::FromBrowserContext(browser_context);
-  const DictionaryValue* overrides =
+  const base::DictionaryValue* overrides =
       profile->GetPrefs()->GetDictionary(kExtensionURLOverrides);
   if (!overrides)
     return false;
@@ -253,12 +253,13 @@
   // internal URL
   // chrome-extension://eemcgdkfndhakfknompkggombfjjjeno/main.html#1 to
   // chrome://bookmarks/#1 for display in the omnibox.
-  for (DictionaryValue::Iterator it(*overrides); !it.IsAtEnd(); it.Advance()) {
-    const ListValue* url_list = NULL;
+  for (base::DictionaryValue::Iterator it(*overrides); !it.IsAtEnd();
+       it.Advance()) {
+    const base::ListValue* url_list = NULL;
     if (!it.value().GetAsList(&url_list))
       continue;
 
-    for (ListValue::const_iterator it2 = url_list->begin();
+    for (base::ListValue::const_iterator it2 = url_list->begin();
          it2 != url_list->end(); ++it2) {
       std::string override;
       if (!(*it2)->GetAsString(&override))
@@ -283,22 +284,22 @@
 
   PrefService* prefs = profile->GetPrefs();
   DictionaryPrefUpdate update(prefs, kExtensionURLOverrides);
-  DictionaryValue* all_overrides = update.Get();
+  base::DictionaryValue* all_overrides = update.Get();
 
   // For each override provided by the extension, add it to the front of
   // the override list if it's not already in the list.
   URLOverrides::URLOverrideMap::const_iterator iter = overrides.begin();
   for (; iter != overrides.end(); ++iter) {
     const std::string& key = iter->first;
-    ListValue* page_overrides = NULL;
+    base::ListValue* page_overrides = NULL;
     if (!all_overrides->GetList(key, &page_overrides)) {
-      page_overrides = new ListValue();
+      page_overrides = new base::ListValue();
       all_overrides->Set(key, page_overrides);
     } else {
       CleanUpDuplicates(page_overrides);
 
       // Verify that the override isn't already in the list.
-      ListValue::iterator i = page_overrides->begin();
+      base::ListValue::iterator i = page_overrides->begin();
       for (; i != page_overrides->end(); ++i) {
         std::string override_val;
         if (!(*i)->GetAsString(&override_val)) {
@@ -321,7 +322,7 @@
 // static
 void ExtensionWebUI::UnregisterAndReplaceOverride(const std::string& page,
                                                   Profile* profile,
-                                                  ListValue* list,
+                                                  base::ListValue* list,
                                                   const Value* override) {
   size_t index = 0;
   bool found = list->Remove(*override, &index);
@@ -342,8 +343,8 @@
     return;
   PrefService* prefs = profile->GetPrefs();
   DictionaryPrefUpdate update(prefs, kExtensionURLOverrides);
-  DictionaryValue* all_overrides = update.Get();
-  ListValue* page_overrides = NULL;
+  base::DictionaryValue* all_overrides = update.Get();
+  base::ListValue* page_overrides = NULL;
   if (!all_overrides->GetList(page, &page_overrides)) {
     // If it's being unregistered, it should already be in the list.
     NOTREACHED();
@@ -360,11 +361,11 @@
     return;
   PrefService* prefs = profile->GetPrefs();
   DictionaryPrefUpdate update(prefs, kExtensionURLOverrides);
-  DictionaryValue* all_overrides = update.Get();
+  base::DictionaryValue* all_overrides = update.Get();
   URLOverrides::URLOverrideMap::const_iterator iter = overrides.begin();
   for (; iter != overrides.end(); ++iter) {
     const std::string& page = iter->first;
-    ListValue* page_overrides = NULL;
+    base::ListValue* page_overrides = NULL;
     if (!all_overrides->GetList(page, &page_overrides)) {
       // If it's being unregistered, it should already be in the list.
       NOTREACHED();
diff --git a/chrome/browser/extensions/extensions_quota_service.cc b/chrome/browser/extensions/extensions_quota_service.cc
index bd34b1f..f776c40 100644
--- a/chrome/browser/extensions/extensions_quota_service.cc
+++ b/chrome/browser/extensions/extensions_quota_service.cc
@@ -37,7 +37,7 @@
 std::string ExtensionsQuotaService::Assess(
     const std::string& extension_id,
     ExtensionFunction* function,
-    const ListValue* args,
+    const base::ListValue* args,
     const base::TimeTicks& event_time) {
   DCHECK(CalledOnValidThread());
 
@@ -106,7 +106,7 @@
 }
 
 void QuotaLimitHeuristic::SingletonBucketMapper::GetBucketsForArgs(
-    const ListValue* args,
+    const base::ListValue* args,
     BucketList* buckets) {
   buckets->push_back(&bucket_);
 }
@@ -119,7 +119,7 @@
 
 QuotaLimitHeuristic::~QuotaLimitHeuristic() {}
 
-bool QuotaLimitHeuristic::ApplyToArgs(const ListValue* args,
+bool QuotaLimitHeuristic::ApplyToArgs(const base::ListValue* args,
     const base::TimeTicks& event_time) {
   BucketList buckets;
   bucket_mapper_->GetBucketsForArgs(args, &buckets);
diff --git a/chrome/browser/extensions/extensions_quota_service.h b/chrome/browser/extensions/extensions_quota_service.h
index e29300e..5644397 100644
--- a/chrome/browser/extensions/extensions_quota_service.h
+++ b/chrome/browser/extensions/extensions_quota_service.h
@@ -22,8 +22,8 @@
 #include "base/containers/hash_tables.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/threading/non_thread_safe.h"
-#include "base/time.h"
-#include "base/timer.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
 #include "base/values.h"
 
 class ExtensionFunction;
@@ -56,7 +56,7 @@
   // or empty-string if the request is fine and can proceed.
   std::string Assess(const std::string& extension_id,
                      ExtensionFunction* function,
-                     const ListValue* args,
+                     const base::ListValue* args,
                      const base::TimeTicks& event_time);
 
  private:
@@ -152,7 +152,7 @@
     // occurs while parsing |args|, the function aborts - buckets may be non-
     // empty). The expectation is that invalid args and associated errors are
     // handled by the ExtensionFunction itself so we don't concern ourselves.
-    virtual void GetBucketsForArgs(const ListValue* args,
+    virtual void GetBucketsForArgs(const base::ListValue* args,
                                    BucketList* buckets) = 0;
   };
 
@@ -162,7 +162,7 @@
    public:
     SingletonBucketMapper() {}
     virtual ~SingletonBucketMapper() {}
-    virtual void GetBucketsForArgs(const ListValue* args,
+    virtual void GetBucketsForArgs(const base::ListValue* args,
                                    BucketList* buckets) OVERRIDE;
 
    private:
@@ -180,7 +180,8 @@
   // implementation of a derived class) to perform an operation with |args|,
   // based on the history of similar operations with similar arguments (which
   // is retrieved using the BucketMapper).
-  bool ApplyToArgs(const ListValue* args, const base::TimeTicks& event_time);
+  bool ApplyToArgs(const base::ListValue* args,
+                   const base::TimeTicks& event_time);
 
   // Returns an error formatted according to this heuristic.
   std::string GetError() const;
diff --git a/chrome/browser/extensions/extensions_quota_service_unittest.cc b/chrome/browser/extensions/extensions_quota_service_unittest.cc
index e8eefd0..4ebbf5a 100644
--- a/chrome/browser/extensions/extensions_quota_service_unittest.cc
+++ b/chrome/browser/extensions/extensions_quota_service_unittest.cc
@@ -34,7 +34,7 @@
  public:
   Mapper() {}
   virtual ~Mapper() { STLDeleteValues(&buckets_); }
-  virtual void GetBucketsForArgs(const ListValue* args,
+  virtual void GetBucketsForArgs(const base::ListValue* args,
                                  BucketList* buckets) OVERRIDE {
     for (size_t i = 0; i < args->GetSize(); i++) {
       int id;
@@ -52,7 +52,7 @@
 
 class MockMapper : public QuotaLimitHeuristic::BucketMapper {
  public:
-  virtual void GetBucketsForArgs(const ListValue* args,
+  virtual void GetBucketsForArgs(const base::ListValue* args,
                                  BucketList* buckets) OVERRIDE {
   }
 };
@@ -61,7 +61,7 @@
  public:
   explicit MockFunction(const std::string& name) { set_name(name); }
 
-  virtual void SetArgs(const ListValue* args) OVERRIDE {}
+  virtual void SetArgs(const base::ListValue* args) OVERRIDE {}
   virtual const std::string GetError() OVERRIDE { return std::string(); }
   virtual void SetError(const std::string& error) OVERRIDE {}
   virtual void Run() OVERRIDE {}
@@ -217,20 +217,20 @@
 
 TEST_F(ExtensionsQuotaServiceTest, NoHeuristic) {
   scoped_refptr<MockFunction> f(new MockFunction("foo"));
-  ListValue args;
+  base::ListValue args;
   EXPECT_EQ("", service_->Assess(extension_a_, f.get(), &args, kStartTime));
 }
 
 TEST_F(ExtensionsQuotaServiceTest, FrozenHeuristic) {
   scoped_refptr<MockFunction> f(new FrozenMockFunction("foo"));
-  ListValue args;
+  base::ListValue args;
   args.Append(new base::FundamentalValue(1));
   EXPECT_NE("", service_->Assess(extension_a_, f.get(), &args, kStartTime));
 }
 
 TEST_F(ExtensionsQuotaServiceTest, SingleHeuristic) {
   scoped_refptr<MockFunction> f(new TimedLimitMockFunction("foo"));
-  ListValue args;
+  base::ListValue args;
   args.Append(new base::FundamentalValue(1));
   EXPECT_EQ("", service_->Assess(extension_a_, f.get(), &args, kStartTime));
   EXPECT_EQ("",
@@ -244,7 +244,7 @@
                              &args,
                              kStartTime + TimeDelta::FromSeconds(15)));
 
-  ListValue args2;
+  base::ListValue args2;
   args2.Append(new base::FundamentalValue(1));
   args2.Append(new base::FundamentalValue(2));
   EXPECT_EQ("", service_->Assess(extension_b_, f.get(), &args2, kStartTime));
@@ -269,7 +269,7 @@
                              kStartTime + peace + TimeDelta::FromSeconds(15)));
 
   // Test that items are independent.
-  ListValue args3;
+  base::ListValue args3;
   args3.Append(new base::FundamentalValue(3));
   EXPECT_EQ("", service_->Assess(extension_c_, f.get(), &args, kStartTime));
   EXPECT_EQ("",
@@ -301,7 +301,7 @@
 
 TEST_F(ExtensionsQuotaServiceTest, ChainedHeuristics) {
   scoped_refptr<MockFunction> f(new ChainedLimitsMockFunction("foo"));
-  ListValue args;
+  base::ListValue args;
   args.Append(new base::FundamentalValue(1));
 
   // First, test that the low limit can be avoided but the higher one is hit.
@@ -356,8 +356,8 @@
   scoped_refptr<MockFunction> f(new TimedLimitMockFunction("foo"));
   scoped_refptr<MockFunction> g(new TimedLimitMockFunction("bar"));
 
-  ListValue args_f;
-  ListValue args_g;
+  base::ListValue args_f;
+  base::ListValue args_g;
   args_f.Append(new base::FundamentalValue(1));
   args_g.Append(new base::FundamentalValue(2));
 
@@ -388,7 +388,7 @@
 TEST_F(ExtensionsQuotaServiceTest, ViolatorsWillBeViolators) {
   scoped_refptr<MockFunction> f(new TimedLimitMockFunction("foo"));
   scoped_refptr<MockFunction> g(new TimedLimitMockFunction("bar"));
-  ListValue arg;
+  base::ListValue arg;
   arg.Append(new base::FundamentalValue(1));
   EXPECT_EQ("", service_->Assess(extension_a_, f.get(), &arg, kStartTime));
   EXPECT_EQ("",
diff --git a/chrome/browser/extensions/external_provider_impl.cc b/chrome/browser/extensions/external_provider_impl.cc
index 08efd2e..b5f3dc5 100644
--- a/chrome/browser/extensions/external_provider_impl.cc
+++ b/chrome/browser/extensions/external_provider_impl.cc
@@ -90,7 +90,7 @@
   loader_->StartLoading();
 }
 
-void ExternalProviderImpl::SetPrefs(DictionaryValue* prefs) {
+void ExternalProviderImpl::SetPrefs(base::DictionaryValue* prefs) {
   CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
 
   // Check if the service is still alive. It is possible that it went
@@ -104,9 +104,9 @@
   std::set<std::string> unsupported_extensions;
 
   // Notify ExtensionService about all the extensions this provider has.
-  for (DictionaryValue::Iterator i(*prefs_); !i.IsAtEnd(); i.Advance()) {
+  for (base::DictionaryValue::Iterator i(*prefs_); !i.IsAtEnd(); i.Advance()) {
     const std::string& extension_id = i.key();
-    const DictionaryValue* extension = NULL;
+    const base::DictionaryValue* extension = NULL;
 
     if (!Extension::IdIsValid(extension_id)) {
       LOG(WARNING) << "Malformed extension dictionary: key "
@@ -159,7 +159,7 @@
     }
 
     // Check that extension supports current browser locale.
-    const ListValue* supported_locales = NULL;
+    const base::ListValue* supported_locales = NULL;
     if (extension->GetList(kSupportedLocales, &supported_locales)) {
       std::vector<std::string> browser_locales;
       l10n_util::GetParentLocales(g_browser_process->GetApplicationLocale(),
@@ -307,7 +307,7 @@
   CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   CHECK(prefs_.get());
   CHECK(ready_);
-  DictionaryValue* extension = NULL;
+  base::DictionaryValue* extension = NULL;
   if (!prefs_->GetDictionary(id, &extension))
     return false;
 
diff --git a/chrome/browser/extensions/external_registry_loader_win.cc b/chrome/browser/extensions/external_registry_loader_win.cc
index 05498fb..47cf902 100644
--- a/chrome/browser/extensions/external_registry_loader_win.cc
+++ b/chrome/browser/extensions/external_registry_loader_win.cc
@@ -11,7 +11,7 @@
 #include "base/metrics/histogram.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "base/values.h"
 #include "base/version.h"
 #include "base/win/registry.h"
diff --git a/chrome/browser/extensions/image_loader.cc b/chrome/browser/extensions/image_loader.cc
index a941e23..9d775dd 100644
--- a/chrome/browser/extensions/image_loader.cc
+++ b/chrome/browser/extensions/image_loader.cc
@@ -174,19 +174,24 @@
 #endif
 #if defined(USE_AURA)
     {"keyboard/api_adapter.js", IDR_KEYBOARD_API_ADAPTER_JS},
-    {"keyboard/common.js", IDR_KEYBOARD_COMMON_JS},
-    {"keyboard/images/chevron.svg", IDR_KEYBOARD_IMAGES_CHEVRON},
-    {"keyboard/images/del.svg", IDR_KEYBOARD_IMAGES_DEL},
+    {"keyboard/constants.js", IDR_KEYBOARD_CONSTANTS_JS},
+    {"keyboard/elements/kb-accent-container.html",
+        IDR_KEYBOARD_ELEMENTS_ACCENT_CONTAINER},
+    {"keyboard/elements/kb-accent-key.html", IDR_KEYBOARD_ELEMENTS_ACCENT_KEY},
+    {"keyboard/elements/kb-accent-set.html", IDR_KEYBOARD_ELEMENTS_ACCENT_SET},
+    {"keyboard/elements/kb-key.html", IDR_KEYBOARD_ELEMENTS_KEY},
+    {"keyboard/elements/kb-keyboard.html", IDR_KEYBOARD_ELEMENTS_KEYBOARD},
+    {"keyboard/elements/kb-keyset.html", IDR_KEYBOARD_ELEMENTS_KEYSET},
+    {"keyboard/elements/kb-row.html", IDR_KEYBOARD_ELEMENTS_ROW},
     {"keyboard/images/keyboard.svg", IDR_KEYBOARD_IMAGES_KEYBOARD},
     {"keyboard/images/mic.svg", IDR_KEYBOARD_IMAGES_MIC},
-    {"keyboard/images/ret.svg", IDR_KEYBOARD_IMAGES_RET},
-    {"keyboard/images/shift.svg", IDR_KEYBOARD_IMAGES_SHIFT},
-    {"keyboard/images/shift_down.svg", IDR_KEYBOARD_IMAGES_SHIFT_DOWN},
-    {"keyboard/images/tab.svg", IDR_KEYBOARD_IMAGES_TAB},
+    {"keyboard/images/mic-green.svg", IDR_KEYBOARD_IMAGES_MIC_GREEN},
     {"keyboard/index.html", IDR_KEYBOARD_INDEX},
-    {"keyboard/layout_us.js", IDR_KEYBOARD_LAYOUT_US_JS},
+    {"keyboard/keysets.html", IDR_KEYBOARD_KEYSETS},
     {"keyboard/main.css", IDR_KEYBOARD_MAIN_CSS},
     {"keyboard/main.js", IDR_KEYBOARD_MAIN_JS},
+    {"keyboard/polymer.min.js", IDR_KEYBOARD_POLYMER},
+    {"keyboard/voice_input.js", IDR_KEYBOARD_VOICE_INPUT_JS},
 #endif
   };
   static const size_t kExtraComponentExtensionResourcesSize =
diff --git a/chrome/browser/extensions/installed_loader.cc b/chrome/browser/extensions/installed_loader.cc
index 2fc4b46..ee65eda 100644
--- a/chrome/browser/extensions/installed_loader.cc
+++ b/chrome/browser/extensions/installed_loader.cc
@@ -164,7 +164,6 @@
 
   std::vector<int> reload_reason_counts(NUM_MANIFEST_RELOAD_REASONS, 0);
   bool should_write_prefs = false;
-  int update_count = 0;
 
   for (size_t i = 0; i < extensions_info->size(); ++i) {
     ExtensionInfo* info = extensions_info->at(i).get();
@@ -174,31 +173,6 @@
     if (info->extension_location == Manifest::COMMAND_LINE)
       continue;
 
-    scoped_ptr<ExtensionInfo> pending_update(
-        extension_prefs_->GetDelayedInstallInfo(info->extension_id));
-    if (pending_update) {
-      if (!extension_prefs_->FinishDelayedInstallInfo(info->extension_id))
-        NOTREACHED();
-
-      Version old_version;
-      if (info->extension_manifest) {
-        std::string version_str;
-        if (info->extension_manifest->GetString(
-            extension_manifest_keys::kVersion, &version_str)) {
-          old_version = Version(version_str);
-        }
-      }
-      base::MessageLoop::current()->PostTask(FROM_HERE,
-          base::Bind(&DispatchOnInstalledEvent, extension_service_->profile(),
-                     info->extension_id, old_version, false));
-
-      info = extension_prefs_->GetInstalledExtensionInfo(
-          info->extension_id).release();
-      extensions_info->at(i).reset(info);
-
-      update_count++;
-    }
-
     ManifestReloadReason reload_reason = ShouldReloadExtensionManifest(*info);
     ++reload_reason_counts[reload_reason];
     UMA_HISTOGRAM_ENUMERATION("Extensions.ManifestReloadEnumValue",
@@ -255,8 +229,6 @@
                            extension_service_->extensions()->size());
   UMA_HISTOGRAM_COUNTS_100("Extensions.Disabled",
                            extension_service_->disabled_extensions()->size());
-  UMA_HISTOGRAM_COUNTS_100("Extensions.UpdateOnLoad",
-                           update_count);
 
   UMA_HISTOGRAM_TIMES("Extensions.LoadAllTime",
                       base::TimeTicks::Now() - start_time);
diff --git a/chrome/browser/extensions/isolated_app_browsertest.cc b/chrome/browser/extensions/isolated_app_browsertest.cc
index ca84974..0dcdfa7 100644
--- a/chrome/browser/extensions/isolated_app_browsertest.cc
+++ b/chrome/browser/extensions/isolated_app_browsertest.cc
@@ -21,6 +21,9 @@
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/browser_test_utils.h"
 #include "net/dns/mock_host_resolver.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+#include "net/test/embedded_test_server/http_response.h"
+#include "net/test/embedded_test_server/http_request.h"
 
 using content::ExecuteScript;
 using content::ExecuteScriptAndExtractString;
@@ -35,6 +38,64 @@
       javascript_expression + ")";
 }
 
+scoped_ptr<net::test_server::HttpResponse> HandleExpectAndSetCookieRequest(
+    const net::test_server::EmbeddedTestServer* test_server,
+    const net::test_server::HttpRequest& request) {
+  if (!StartsWithASCII(request.relative_url, "/expect-and-set-cookie?", true))
+    return scoped_ptr<net::test_server::HttpResponse>();
+
+  scoped_ptr<net::test_server::BasicHttpResponse> http_response(
+      new net::test_server::BasicHttpResponse);
+  http_response->set_code(net::HTTP_OK);
+
+  std::string request_cookies;
+  std::map<std::string, std::string>::const_iterator it =
+      request.headers.find("Cookie");
+  if (it != request.headers.end())
+    request_cookies = it->second;
+
+  size_t query_string_pos = request.relative_url.find('?');
+  std::string query_string =
+      request.relative_url.substr(query_string_pos + 1);
+  url_parse::Component query(0, query_string.length()), key_pos, value_pos;
+  bool expectations_satisfied = true;
+  std::vector<std::string> cookies_to_set;
+  while (url_parse::ExtractQueryKeyValue(
+             query_string.c_str(), &query, &key_pos, &value_pos)) {
+    std::string escaped_key(query_string.substr(key_pos.begin, key_pos.len));
+    std::string escaped_value(
+        query_string.substr(value_pos.begin, value_pos.len));
+
+    std::string key =
+        net::UnescapeURLComponent(escaped_key,
+                                  net::UnescapeRule::NORMAL |
+                                  net::UnescapeRule::SPACES |
+                                  net::UnescapeRule::URL_SPECIAL_CHARS);
+
+    std::string value =
+        net::UnescapeURLComponent(escaped_value,
+                                  net::UnescapeRule::NORMAL |
+                                  net::UnescapeRule::SPACES |
+                                  net::UnescapeRule::URL_SPECIAL_CHARS);
+
+    if (key == "expect") {
+      if (request_cookies.find(value) == std::string::npos)
+        expectations_satisfied = false;
+    } else if (key == "set") {
+      cookies_to_set.push_back(value);
+    } else {
+      return scoped_ptr<net::test_server::HttpResponse>();
+    }
+  }
+
+  if (expectations_satisfied) {
+    for (size_t i = 0; i < cookies_to_set.size(); i++)
+      http_response->AddCustomHeader("Set-Cookie", cookies_to_set[i]);
+  }
+
+  return http_response.PassAs<net::test_server::HttpResponse>();
+}
+
 class IsolatedAppTest : public ExtensionBrowserTest {
  public:
   // Returns whether the given tab's current URL has the given cookie.
@@ -76,12 +137,12 @@
 
 IN_PROC_BROWSER_TEST_F(IsolatedAppTest, CrossProcessClientRedirect) {
   host_resolver()->AddRule("*", "127.0.0.1");
-  ASSERT_TRUE(test_server()->Start());
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
 
   ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("isolated_apps/app1")));
   ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("isolated_apps/app2")));
 
-  GURL base_url = test_server()->GetURL("files/extensions/isolated_apps/");
+  GURL base_url = embedded_test_server()->GetURL("/extensions/isolated_apps/");
   GURL::Replacements replace_host;
   std::string host_str("localhost");  // Must stay in scope with replace_host.
   replace_host.SetHostStr(host_str);
@@ -91,8 +152,8 @@
       CURRENT_TAB, ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
 
   // Redirect to app2.
-  GURL redirect_url(test_server()->GetURL(
-      "client-redirect?files/extensions/isolated_apps/app2/main.html"));
+  GURL redirect_url(embedded_test_server()->GetURL(
+      "/extensions/isolated_apps/app2/redirect.html"));
   ui_test_utils::NavigateToURLWithDisposition(
       browser(), redirect_url,
       CURRENT_TAB, ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
@@ -143,14 +204,14 @@
 // separation as you would expect.
 IN_PROC_BROWSER_TEST_F(IsolatedAppTest, CookieIsolation) {
   host_resolver()->AddRule("*", "127.0.0.1");
-  ASSERT_TRUE(test_server()->Start());
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
 
   ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("isolated_apps/app1")));
   ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("isolated_apps/app2")));
 
   // The app under test acts on URLs whose host is "localhost",
   // so the URLs we navigate to must have host "localhost".
-  GURL base_url = test_server()->GetURL("files/extensions/isolated_apps/");
+  GURL base_url = embedded_test_server()->GetURL("/extensions/isolated_apps/");
   GURL::Replacements replace_host;
   std::string host_str("localhost");  // Must stay in scope with replace_host.
   replace_host.SetHostStr(host_str);
@@ -242,11 +303,11 @@
 // Ensure that cookies are not isolated if the isolated apps are not installed.
 IN_PROC_BROWSER_TEST_F(IsolatedAppTest, DISABLED_NoCookieIsolationWithoutApp) {
   host_resolver()->AddRule("*", "127.0.0.1");
-  ASSERT_TRUE(test_server()->Start());
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
 
   // The app under test acts on URLs whose host is "localhost",
   // so the URLs we navigate to must have host "localhost".
-  GURL base_url = test_server()->GetURL("files/extensions/isolated_apps/");
+  GURL base_url = embedded_test_server()->GetURL("/extensions/isolated_apps/");
   GURL::Replacements replace_host;
   std::string host_str("localhost");  // Must stay in scope with replace_host.
   replace_host.SetHostStr(host_str);
@@ -321,15 +382,18 @@
 // Tests that subresource and media requests use the app's cookie store.
 // See http://crbug.com/141172.
 IN_PROC_BROWSER_TEST_F(IsolatedAppTest, MAYBE_SubresourceCookieIsolation) {
+  embedded_test_server()->RegisterRequestHandler(
+      base::Bind(&HandleExpectAndSetCookieRequest, embedded_test_server()));
+
   host_resolver()->AddRule("*", "127.0.0.1");
-  ASSERT_TRUE(test_server()->Start());
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
 
   ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("isolated_apps/app1")));
 
   // The app under test acts on URLs whose host is "localhost",
   // so the URLs we navigate to must have host "localhost".
-  GURL root_url = test_server()->GetURL(std::string());
-  GURL base_url = test_server()->GetURL("files/extensions/isolated_apps/");
+  GURL root_url = embedded_test_server()->GetURL("/");
+  GURL base_url = embedded_test_server()->GetURL("/extensions/isolated_apps/");
   GURL::Replacements replace_host;
   std::string host_str("localhost");  // Must stay in scope with replace_host.
   replace_host.SetHostStr(host_str);
@@ -338,7 +402,7 @@
 
   // First set cookies inside and outside the app.
   ui_test_utils::NavigateToURLWithDisposition(
-      browser(), root_url.Resolve("set-cookie?nonApp=1"),
+      browser(), root_url.Resolve("expect-and-set-cookie?set=nonApp%3d1"),
       CURRENT_TAB, ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
   WebContents* tab0 = browser()->tab_strip_model()->GetWebContentsAt(0);
   ASSERT_FALSE(GetInstalledApp(tab0));
@@ -397,13 +461,13 @@
 // where non-app popups may be kept in the hosted app process.
 IN_PROC_BROWSER_TEST_F(IsolatedAppTest, MAYBE_IsolatedAppProcessModel) {
   host_resolver()->AddRule("*", "127.0.0.1");
-  ASSERT_TRUE(test_server()->Start());
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
 
   ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("isolated_apps/app1")));
 
   // The app under test acts on URLs whose host is "localhost",
   // so the URLs we navigate to must have host "localhost".
-  GURL base_url = test_server()->GetURL("files/extensions/isolated_apps/");
+  GURL base_url = embedded_test_server()->GetURL("/extensions/isolated_apps/");
   GURL::Replacements replace_host;
   std::string host_str("localhost");  // Must stay in scope with replace_host.
   replace_host.SetHostStr(host_str);
@@ -457,14 +521,14 @@
 // removed. http://crbug.com/159932
 IN_PROC_BROWSER_TEST_F(IsolatedAppTest, DISABLED_SessionStorage) {
   host_resolver()->AddRule("*", "127.0.0.1");
-  ASSERT_TRUE(test_server()->Start());
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
 
   ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("isolated_apps/app1")));
   ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("isolated_apps/app2")));
 
   // The app under test acts on URLs whose host is "localhost",
   // so the URLs we navigate to must have host "localhost".
-  GURL base_url = test_server()->GetURL("files/extensions/isolated_apps/");
+  GURL base_url = embedded_test_server()->GetURL("/extensions/isolated_apps/");
   GURL::Replacements replace_host;
   std::string host_str("localhost");  // Must stay in scope with replace_host.
   replace_host.SetHostStr(host_str);
diff --git a/chrome/browser/extensions/lazy_background_page_apitest.cc b/chrome/browser/extensions/lazy_background_page_apitest.cc
index 8bb4b11..ba6f7de 100644
--- a/chrome/browser/extensions/lazy_background_page_apitest.cc
+++ b/chrome/browser/extensions/lazy_background_page_apitest.cc
@@ -30,6 +30,7 @@
 #include "content/public/test/browser_test_utils.h"
 #include "googleurl/src/gurl.h"
 #include "net/dns/mock_host_resolver.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
 
 using extensions::Extension;
 
@@ -141,7 +142,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(LazyBackgroundPageApiTest, BroadcastEvent) {
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
 
   const Extension* extension = LoadExtensionAndWait("broadcast_event");
   ASSERT_TRUE(extension);
@@ -159,7 +160,7 @@
         chrome::NOTIFICATION_EXTENSION_PAGE_ACTION_VISIBILITY_CHANGED,
         content::NotificationService::AllSources());
   ui_test_utils::NavigateToURL(
-      browser(), test_server()->GetURL("files/extensions/test_file.html"));
+      browser(), embedded_test_server()->GetURL("/extensions/test_file.html"));
   page_complete.Wait();
 
   EXPECT_FALSE(pm->GetBackgroundHostForExtension(last_loaded_extension_id_));
@@ -183,7 +184,7 @@
   // Open a tab to a URL that will fire a webNavigation event.
   LazyBackgroundObserver page_complete;
   ui_test_utils::NavigateToURL(
-      browser(), test_server()->GetURL("files/extensions/test_file.html"));
+      browser(), embedded_test_server()->GetURL("/extensions/test_file.html"));
   page_complete.Wait();
 }
 
@@ -235,7 +236,7 @@
 // are complete.
 IN_PROC_BROWSER_TEST_F(LazyBackgroundPageApiTest, WaitForRequest) {
   host_resolver()->AddRule("*", "127.0.0.1");
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
 
   LazyBackgroundObserver page_complete;
   ResultCatcher catcher;
@@ -376,7 +377,7 @@
 // Tests that messages from the content script activate the lazy background
 // page, and keep it alive until all channels are closed.
 IN_PROC_BROWSER_TEST_F(LazyBackgroundPageApiTest, Messaging) {
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
   ASSERT_TRUE(LoadExtensionAndWait("messaging"));
 
   // Lazy Background Page doesn't exist yet.
@@ -389,7 +390,7 @@
   ResultCatcher catcher;
   LazyBackgroundObserver lazybg;
   ui_test_utils::NavigateToURL(
-      browser(), test_server()->GetURL("files/extensions/test_file.html"));
+      browser(), embedded_test_server()->GetURL("/extensions/test_file.html"));
   lazybg.WaitUntilLoaded();
 
   // Background page got the content script's message and is still loaded
diff --git a/chrome/browser/extensions/media_galleries_handler.cc b/chrome/browser/extensions/media_galleries_handler.cc
index d2349a8..a1a361a 100644
--- a/chrome/browser/extensions/media_galleries_handler.cc
+++ b/chrome/browser/extensions/media_galleries_handler.cc
@@ -78,10 +78,10 @@
 // |result|.
 bool LoadMediaGalleriesHandlers(
     const std::string& extension_id,
-    const ListValue* extension_actions,
+    const base::ListValue* extension_actions,
     MediaGalleriesHandler::List* result,
     string16* error) {
-  for (ListValue::const_iterator iter = extension_actions->begin();
+  for (base::ListValue::const_iterator iter = extension_actions->begin();
        iter != extension_actions->end();
        ++iter) {
     if (!(*iter)->IsType(Value::TYPE_DICTIONARY)) {
@@ -124,7 +124,7 @@
 
 bool MediaGalleriesHandlerParser::Parse(extensions::Extension* extension,
                                         string16* error) {
-  const ListValue* media_galleries_handlers_value = NULL;
+  const base::ListValue* media_galleries_handlers_value = NULL;
   if (!extension->manifest()->GetList(keys::kMediaGalleriesHandlers,
                                       &media_galleries_handlers_value)) {
     *error = ASCIIToUTF16(errors::kInvalidMediaGalleriesHandler);
diff --git a/chrome/browser/extensions/menu_manager.cc b/chrome/browser/extensions/menu_manager.cc
index b11b3e5..cb2ce0e 100644
--- a/chrome/browser/extensions/menu_manager.cc
+++ b/chrome/browser/extensions/menu_manager.cc
@@ -82,7 +82,7 @@
 }
 
 scoped_ptr<base::Value> MenuItemsToValue(const MenuItem::List& items) {
-  scoped_ptr<base::ListValue> list(new ListValue());
+  scoped_ptr<base::ListValue> list(new base::ListValue());
   for (size_t i = 0; i < items.size(); ++i)
     list->Append(items[i]->ToValue().release());
   return scoped_ptr<Value>(list.release());
@@ -94,7 +94,7 @@
   if (!dict.HasKey(key))
     return true;
 
-  const ListValue* list = NULL;
+  const base::ListValue* list = NULL;
   if (!dict.GetListWithoutPathExpansion(key, &list))
     return false;
 
@@ -606,7 +606,7 @@
   if (item->type() == MenuItem::RADIO)
     RadioItemSelected(item);
 
-  scoped_ptr<ListValue> args(new ListValue());
+  scoped_ptr<base::ListValue> args(new base::ListValue());
 
   DictionaryValue* properties = new DictionaryValue();
   SetIdKeyValue(properties, "menuItemId", item->id());
@@ -673,8 +673,9 @@
   }
 
   {
-    scoped_ptr<Event> event(new Event(event_names::kOnContextMenus,
-                                      scoped_ptr<ListValue>(args->DeepCopy())));
+    scoped_ptr<Event> event(new Event(
+        event_names::kOnContextMenus,
+        scoped_ptr<base::ListValue>(args->DeepCopy())));
     event->restrict_to_profile = profile;
     event->user_gesture = EventRouter::USER_GESTURE_ENABLED;
     event_router->DispatchEventToExtension(item->extension_id(), event.Pass());
diff --git a/chrome/browser/extensions/menu_manager.h b/chrome/browser/extensions/menu_manager.h
index c4e56ac..764e861 100644
--- a/chrome/browser/extensions/menu_manager.h
+++ b/chrome/browser/extensions/menu_manager.h
@@ -109,11 +109,11 @@
       value_ |= context;
     }
 
-    scoped_ptr<Value> ToValue() const {
-      return scoped_ptr<Value>(Value::CreateIntegerValue(value_));
+    scoped_ptr<base::Value> ToValue() const {
+      return scoped_ptr<base::Value>(base::Value::CreateIntegerValue(value_));
     }
 
-    bool Populate(const Value& value) {
+    bool Populate(const base::Value& value) {
       int int_value;
       if (!value.GetAsInteger(&int_value) || int_value < 0)
         return false;
@@ -178,7 +178,7 @@
   // Returns a new MenuItem created from |value|, or NULL if there is
   // an error. The caller takes ownership of the MenuItem.
   static MenuItem* Populate(const std::string& extension_id,
-                            const DictionaryValue& value,
+                            const base::DictionaryValue& value,
                             std::string* error);
 
   // Sets any document and target URL patterns from |properties|.
diff --git a/chrome/browser/extensions/menu_manager_unittest.cc b/chrome/browser/extensions/menu_manager_unittest.cc
index f9adbd9..73c8357 100644
--- a/chrome/browser/extensions/menu_manager_unittest.cc
+++ b/chrome/browser/extensions/menu_manager_unittest.cc
@@ -214,13 +214,13 @@
   int contexts_value = 0;
   ASSERT_TRUE(contexts.ToValue()->GetAsInteger(&contexts_value));
 
-  ListValue* document_url_patterns(new ListValue());
+  base::ListValue* document_url_patterns(new base::ListValue());
   document_url_patterns->Append(
       Value::CreateStringValue("http://www.google.com/*"));
   document_url_patterns->Append(
       Value::CreateStringValue("http://www.reddit.com/*"));
 
-  ListValue* target_url_patterns(new ListValue());
+  base::ListValue* target_url_patterns(new base::ListValue());
   target_url_patterns->Append(
       Value::CreateStringValue("http://www.yahoo.com/*"));
   target_url_patterns->Append(
diff --git a/chrome/browser/extensions/message_handler.cc b/chrome/browser/extensions/message_handler.cc
index f0576e5..8389b9a 100644
--- a/chrome/browser/extensions/message_handler.cc
+++ b/chrome/browser/extensions/message_handler.cc
@@ -4,7 +4,6 @@
 
 #include "chrome/browser/extensions/message_handler.h"
 
-#include "base/values.h"
 #include "chrome/browser/extensions/api/messaging/message_service.h"
 #include "chrome/browser/extensions/extension_system.h"
 #include "chrome/browser/profiles/profile.h"
@@ -44,12 +43,12 @@
 }
 
 void MessageHandler::OnPostMessage(int port_id,
-                                   const base::ListValue& message) {
+                                   const std::string& message) {
   Profile* profile = Profile::FromBrowserContext(
       render_view_host()->GetProcess()->GetBrowserContext());
   MessageService* message_service = MessageService::Get(profile);
   if (message_service) {
-    message_service->PostMessage(port_id, make_scoped_ptr(message.DeepCopy()));
+    message_service->PostMessage(port_id, message);
   }
 }
 
diff --git a/chrome/browser/extensions/message_handler.h b/chrome/browser/extensions/message_handler.h
index 7142682..140105d 100644
--- a/chrome/browser/extensions/message_handler.h
+++ b/chrome/browser/extensions/message_handler.h
@@ -9,10 +9,6 @@
 
 #include "content/public/browser/render_view_host_observer.h"
 
-namespace base {
-class ListValue;
-}
-
 namespace extensions {
 
 // Filters and dispatches extension-related IPC messages that arrive from
@@ -37,7 +33,7 @@
 
  private:
   // Message handlers.
-  void OnPostMessage(int port_id, const base::ListValue& message);
+  void OnPostMessage(int port_id, const std::string& message);
 
   DISALLOW_COPY_AND_ASSIGN(MessageHandler);
 };
diff --git a/chrome/browser/extensions/pending_extension_manager.cc b/chrome/browser/extensions/pending_extension_manager.cc
index 15aac52..fcf1660 100644
--- a/chrome/browser/extensions/pending_extension_manager.cc
+++ b/chrome/browser/extensions/pending_extension_manager.cc
@@ -119,6 +119,26 @@
                           kIsFromSync, install_silently, kSyncLocation);
 }
 
+bool PendingExtensionManager::AddFromExtensionImport(
+    const std::string& id,
+    const GURL& update_url,
+    PendingExtensionInfo::ShouldAllowInstallPredicate should_allow_install) {
+  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+  if (service_.GetInstalledExtension(id)) {
+    LOG(ERROR) << "Trying to add pending extension " << id
+               << " which already exists";
+    return false;
+  }
+
+  const bool kIsFromSync = false;
+  const bool kInstallSilently = true;
+  const Manifest::Location kManifestLocation = Manifest::INTERNAL;
+
+  return AddExtensionImpl(id, update_url, Version(), should_allow_install,
+                          kIsFromSync, kInstallSilently, kManifestLocation);
+}
+
 bool PendingExtensionManager::AddFromExternalUpdateUrl(
     const std::string& id,
     const GURL& update_url,
diff --git a/chrome/browser/extensions/pending_extension_manager.h b/chrome/browser/extensions/pending_extension_manager.h
index d275adf..41bf30c 100644
--- a/chrome/browser/extensions/pending_extension_manager.h
+++ b/chrome/browser/extensions/pending_extension_manager.h
@@ -80,6 +80,12 @@
       PendingExtensionInfo::ShouldAllowInstallPredicate should_allow_install,
       bool install_silently);
 
+  // Adds an extension that was depended on by another extension.
+  bool AddFromExtensionImport(
+      const std::string& id,
+      const GURL& update_url,
+      PendingExtensionInfo::ShouldAllowInstallPredicate should_allow_install);
+
   // Given an extension id and an update URL, schedule the extension
   // to be fetched, installed, and activated.
   bool AddFromExternalUpdateUrl(const std::string& id,
diff --git a/chrome/browser/extensions/permissions_updater.cc b/chrome/browser/extensions/permissions_updater.cc
index 46bb60f..a985332 100644
--- a/chrome/browser/extensions/permissions_updater.cc
+++ b/chrome/browser/extensions/permissions_updater.cc
@@ -101,7 +101,7 @@
       !ExtensionSystem::Get(profile_)->event_router())
     return;
 
-  scoped_ptr<ListValue> value(new ListValue());
+  scoped_ptr<base::ListValue> value(new base::ListValue());
   scoped_ptr<api::permissions::Permissions> permissions =
       PackPermissionSet(changed_permissions);
   value->Append(permissions->ToValue().release());
diff --git a/chrome/browser/extensions/platform_app_browsertest.cc b/chrome/browser/extensions/platform_app_browsertest.cc
index 2b88475..28168bb 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/shell_window.h"
 #include "base/bind.h"
 #include "base/file_util.h"
 #include "base/files/scoped_temp_dir.h"
@@ -29,7 +30,6 @@
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/extensions/application_launch.h"
 #include "chrome/browser/ui/extensions/native_app_window.h"
-#include "chrome/browser/ui/extensions/shell_window.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/common/chrome_notification_types.h"
 #include "chrome/common/chrome_switches.h"
@@ -42,8 +42,10 @@
 #include "content/public/browser/render_widget_host_view.h"
 #include "content/public/browser/web_contents_view.h"
 #include "content/public/test/test_utils.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
 #include "googleurl/src/gurl.h"
 
+using apps::ShellWindow;
 using content::WebContents;
 using web_modal::WebContentsModalDialogManager;
 
@@ -303,7 +305,7 @@
 IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, DisallowNavigation) {
   TabsAddedNotificationObserver observer(2);
 
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
   ASSERT_TRUE(RunPlatformAppTest("platform_apps/navigation")) << message_;
 
   observer.Wait();
@@ -315,7 +317,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, Iframes) {
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
   ASSERT_TRUE(RunPlatformAppTest("platform_apps/iframes")) << message_;
 }
 
@@ -342,11 +344,11 @@
 
 // Tests that platform apps have isolated storage by default.
 IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, Isolation) {
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
 
   // Load a (non-app) page under the "localhost" origin that sets a cookie.
-  GURL set_cookie_url = test_server()->GetURL(
-      "files/extensions/platform_apps/isolation/set_cookie.html");
+  GURL set_cookie_url = embedded_test_server()->GetURL(
+      "/extensions/platform_apps/isolation/set_cookie.html");
   GURL::Replacements replace_host;
   std::string host_str("localhost");  // Must stay in scope with replace_host.
   replace_host.SetHostStr(host_str);
@@ -607,7 +609,7 @@
 #endif  // defined(OS_CHROMEOS)
 
 IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, OpenLink) {
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
   content::WindowedNotificationObserver observer(
       chrome::NOTIFICATION_TAB_ADDED,
       content::Source<content::WebContentsDelegate>(browser()));
@@ -646,6 +648,82 @@
   ASSERT_TRUE(RunPlatformAppTest("platform_apps/restore_state"));
 }
 
+IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest,
+                       ShellWindowAdjustBoundsToBeVisibleOnScreen) {
+  const Extension* extension = LoadAndLaunchPlatformApp("minimal");
+  ShellWindow* window = CreateShellWindow(extension);
+
+  // The screen bounds didn't change, the cached bounds didn't need to adjust.
+  gfx::Rect cached_bounds(80, 100, 400, 400);
+  gfx::Rect cached_screen_bounds(0, 0, 1600, 900);
+  gfx::Rect current_screen_bounds(0, 0, 1600, 900);
+  gfx::Size minimum_size(200, 200);
+  gfx::Rect bounds;
+  CallAdjustBoundsToBeVisibleOnScreenForShellWindow(window,
+                                                    cached_bounds,
+                                                    cached_screen_bounds,
+                                                    current_screen_bounds,
+                                                    minimum_size,
+                                                    &bounds);
+  EXPECT_EQ(bounds, cached_bounds);
+
+  // We have an empty screen bounds, the cached bounds didn't need to adjust.
+  gfx::Rect empty_screen_bounds;
+  CallAdjustBoundsToBeVisibleOnScreenForShellWindow(window,
+                                                    cached_bounds,
+                                                    empty_screen_bounds,
+                                                    current_screen_bounds,
+                                                    minimum_size,
+                                                    &bounds);
+  EXPECT_EQ(bounds, cached_bounds);
+
+  // Cached bounds is completely off the new screen bounds in horizontal
+  // locations. Expect to reposition the bounds.
+  gfx::Rect horizontal_out_of_screen_bounds(-800, 100, 400, 400);
+  CallAdjustBoundsToBeVisibleOnScreenForShellWindow(
+      window,
+      horizontal_out_of_screen_bounds,
+      gfx::Rect(-1366, 0, 1600, 900),
+      current_screen_bounds,
+      minimum_size,
+      &bounds);
+  EXPECT_EQ(bounds, gfx::Rect(0, 100, 400, 400));
+
+  // Cached bounds is completely off the new screen bounds in vertical
+  // locations. Expect to reposition the bounds.
+  gfx::Rect vertical_out_of_screen_bounds(10, 1000, 400, 400);
+  CallAdjustBoundsToBeVisibleOnScreenForShellWindow(
+      window,
+      vertical_out_of_screen_bounds,
+      gfx::Rect(-1366, 0, 1600, 900),
+      current_screen_bounds,
+      minimum_size,
+      &bounds);
+  EXPECT_EQ(bounds, gfx::Rect(10, 500, 400, 400));
+
+  // From a large screen resulotion to a small one. Expect it fit on screen.
+  gfx::Rect big_cache_bounds(10, 10, 1000, 1000);
+  CallAdjustBoundsToBeVisibleOnScreenForShellWindow(
+      window,
+      big_cache_bounds,
+      gfx::Rect(0, 0, 1600, 1000),
+      gfx::Rect(0, 0, 800, 600),
+      minimum_size,
+      &bounds);
+  EXPECT_EQ(bounds, gfx::Rect(0, 0, 800, 600));
+
+  // Don't resize the bounds smaller than minimum size, when the minimum size is
+  // larger than the screen.
+  CallAdjustBoundsToBeVisibleOnScreenForShellWindow(
+      window,
+      big_cache_bounds,
+      gfx::Rect(0, 0, 1600, 1000),
+      gfx::Rect(0, 0, 800, 600),
+      gfx::Size(900, 900),
+      &bounds);
+  EXPECT_EQ(bounds, gfx::Rect(0, 0, 900, 900));
+}
+
 namespace {
 
 class PlatformAppDevToolsBrowserTest : public PlatformAppBrowserTest {
diff --git a/chrome/browser/extensions/platform_app_browsertest_util.cc b/chrome/browser/extensions/platform_app_browsertest_util.cc
index a815326..2d1cdd0 100644
--- a/chrome/browser/extensions/platform_app_browsertest_util.cc
+++ b/chrome/browser/extensions/platform_app_browsertest_util.cc
@@ -9,6 +9,7 @@
 #include "chrome/browser/extensions/api/tabs/tabs_api.h"
 #include "chrome/browser/extensions/extension_function_test_utils.h"
 #include "chrome/browser/extensions/shell_window_registry.h"
+#include "chrome/browser/ui/apps/chrome_shell_window_delegate.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/extensions/application_launch.h"
 #include "chrome/browser/ui/extensions/native_app_window.h"
@@ -16,6 +17,7 @@
 #include "content/public/browser/notification_service.h"
 #include "content/public/test/test_utils.h"
 
+using apps::ShellWindow;
 using content::WebContents;
 
 namespace utils = extension_function_test_utils;
@@ -23,7 +25,7 @@
 namespace extensions {
 
 PlatformAppBrowserTest::PlatformAppBrowserTest() {
-  ShellWindow::DisableExternalOpenForTesting();
+  chrome::ChromeShellWindowDelegate::DisableExternalOpenForTesting();
 }
 
 void PlatformAppBrowserTest::SetUpCommandLine(CommandLine* command_line) {
@@ -146,13 +148,15 @@
     const Extension* extension) {
   ShellWindow::CreateParams params;
   return ShellWindow::Create(
-      browser()->profile(), extension, GURL(std::string()), params);
+      browser()->profile(), new chrome::ChromeShellWindowDelegate(),
+      extension, GURL(std::string()), params);
 }
 
 ShellWindow* PlatformAppBrowserTest::CreateShellWindowFromParams(
     const Extension* extension, const ShellWindow::CreateParams& params) {
   return ShellWindow::Create(
-      browser()->profile(), extension, GURL(std::string()), params);
+      browser()->profile(), new chrome::ChromeShellWindowDelegate(),
+      extension, GURL(std::string()), params);
 }
 
 void PlatformAppBrowserTest::CloseShellWindow(ShellWindow* window) {
@@ -163,6 +167,20 @@
   destroyed_observer.Wait();
 }
 
+void PlatformAppBrowserTest::CallAdjustBoundsToBeVisibleOnScreenForShellWindow(
+    ShellWindow* window,
+    const gfx::Rect& cached_bounds,
+    const gfx::Rect& cached_screen_bounds,
+    const gfx::Rect& current_screen_bounds,
+    const gfx::Size& minimum_size,
+    gfx::Rect* bounds) {
+  window->AdjustBoundsToBeVisibleOnScreen(cached_bounds,
+                                          cached_screen_bounds,
+                                          current_screen_bounds,
+                                          minimum_size,
+                                          bounds);
+}
+
 void ExperimentalPlatformAppBrowserTest::SetUpCommandLine(
     CommandLine* command_line) {
   PlatformAppBrowserTest::SetUpCommandLine(command_line);
diff --git a/chrome/browser/extensions/platform_app_browsertest_util.h b/chrome/browser/extensions/platform_app_browsertest_util.h
index d484909..6cc179b 100644
--- a/chrome/browser/extensions/platform_app_browsertest_util.h
+++ b/chrome/browser/extensions/platform_app_browsertest_util.h
@@ -6,15 +6,14 @@
 #define CHROME_BROWSER_EXTENSIONS_PLATFORM_APP_BROWSERTEST_UTIL_H_
 
 
+#include "apps/shell_window.h"
 #include "chrome/browser/extensions/extension_apitest.h"
-#include "chrome/browser/ui/extensions/shell_window.h"
 
 namespace content {
 class WebContents;
 }
 
 class CommandLine;
-class ShellWindow;
 
 namespace extensions {
 class Extension;
@@ -41,7 +40,7 @@
 
   // Gets the first shell window that is found (most tests only deal with one
   // platform app window, so this is good enough).
-  ShellWindow* GetFirstShellWindow();
+  apps::ShellWindow* GetFirstShellWindow();
 
   // Runs chrome.windows.getAll for the given extension and returns the number
   // of windows that the function returns.
@@ -64,13 +63,23 @@
   void SetCommandLineArg(const std::string& test_file);
 
   // Creates an empty shell window for |extension|.
-  ShellWindow* CreateShellWindow(const Extension* extension);
+  apps::ShellWindow* CreateShellWindow(const Extension* extension);
 
-  ShellWindow* CreateShellWindowFromParams(
-      const Extension* extension, const ShellWindow::CreateParams& params);
+  apps::ShellWindow* CreateShellWindowFromParams(
+      const Extension* extension,
+      const apps::ShellWindow::CreateParams& params);
 
   // Closes |window| and waits until it's gone.
-  void CloseShellWindow(ShellWindow* window);
+  void CloseShellWindow(apps::ShellWindow* window);
+
+  // Call AdjustBoundsToBeVisibleOnScreen of |window|.
+  void CallAdjustBoundsToBeVisibleOnScreenForShellWindow(
+      apps::ShellWindow* window,
+      const gfx::Rect& cached_bounds,
+      const gfx::Rect& cached_screen_bounds,
+      const gfx::Rect& current_screen_bounds,
+      const gfx::Size& minimum_size,
+      gfx::Rect* bounds);
 };
 
 class ExperimentalPlatformAppBrowserTest : public PlatformAppBrowserTest {
@@ -78,6 +87,6 @@
   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE;
 };
 
-}
+}  // namespace extensions
 
 #endif  // CHROME_BROWSER_EXTENSIONS_PLATFORM_APP_BROWSERTEST_UTIL_H_
diff --git a/chrome/browser/extensions/process_management_browsertest.cc b/chrome/browser/extensions/process_management_browsertest.cc
index d6ea919..bb54aeb 100644
--- a/chrome/browser/extensions/process_management_browsertest.cc
+++ b/chrome/browser/extensions/process_management_browsertest.cc
@@ -20,6 +20,7 @@
 #include "content/public/browser/site_instance.h"
 #include "content/public/browser/web_contents.h"
 #include "net/dns/mock_host_resolver.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
 
 using content::NavigationController;
 using content::WebContents;
@@ -53,7 +54,7 @@
   content::RenderProcessHost::SetMaxRendererProcessCount(1);
 
   host_resolver()->AddRule("*", "127.0.0.1");
-  ASSERT_TRUE(test_server()->Start());
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
 
   ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("isolated_apps/app1")));
   ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("isolated_apps/app2")));
@@ -63,8 +64,8 @@
 
   // The app under test acts on URLs whose host is "localhost",
   // so the URLs we navigate to must have host "localhost".
-  GURL base_url = test_server()->GetURL(
-      "files/extensions/");
+  GURL base_url = embedded_test_server()->GetURL(
+      "/extensions/");
   GURL::Replacements replace_host;
   std::string host_str("localhost");  // Must stay in scope with replace_host.
   replace_host.SetHostStr(host_str);
@@ -194,12 +195,12 @@
   content::RenderProcessHost::SetMaxRendererProcessCount(6);
 
   host_resolver()->AddRule("*", "127.0.0.1");
-  ASSERT_TRUE(test_server()->Start());
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
 
   // The app under test acts on URLs whose host is "localhost",
   // so the URLs we navigate to must have host "localhost".
-  GURL base_url = test_server()->GetURL(
-      "files/extensions/");
+  GURL base_url = embedded_test_server()->GetURL(
+      "/extensions/");
   GURL::Replacements replace_host;
   std::string host_str("localhost");  // Must stay in scope with replace_host.
   replace_host.SetHostStr(host_str);
diff --git a/chrome/browser/extensions/sandboxed_unpacker.cc b/chrome/browser/extensions/sandboxed_unpacker.cc
index 80241b7..91b4cbc 100644
--- a/chrome/browser/extensions/sandboxed_unpacker.cc
+++ b/chrome/browser/extensions/sandboxed_unpacker.cc
@@ -141,7 +141,7 @@
     *temp_dir = normalized_temp_file.DirName();
   }
   // Clean up the temp file.
-  file_util::Delete(temp_file, false);
+  base::Delete(temp_file, false);
 
   return normalized;
 }
@@ -661,7 +661,7 @@
               ASCIIToUTF16("INVALID_PATH_FOR_BROWSER_IMAGE")));
       return false;
     }
-    if (!file_util::Delete(extension_root_.Append(path), false)) {
+    if (!base::Delete(extension_root_.Append(path), false)) {
       // Error removing old image file.
       ReportFailure(
           ERROR_REMOVING_OLD_IMAGE_FILE,
diff --git a/chrome/browser/extensions/sandboxed_unpacker.h b/chrome/browser/extensions/sandboxed_unpacker.h
index d4ef975..4a694c8 100644
--- a/chrome/browser/extensions/sandboxed_unpacker.h
+++ b/chrome/browser/extensions/sandboxed_unpacker.h
@@ -10,7 +10,7 @@
 #include "base/files/file_path.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/memory/ref_counted.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/common/extensions/manifest.h"
 #include "content/public/browser/utility_process_host_client.h"
 
diff --git a/chrome/browser/extensions/scoped_gaia_auth_extension.cc b/chrome/browser/extensions/scoped_gaia_auth_extension.cc
index 33464fa..57e160e 100644
--- a/chrome/browser/extensions/scoped_gaia_auth_extension.cc
+++ b/chrome/browser/extensions/scoped_gaia_auth_extension.cc
@@ -34,7 +34,7 @@
   if (command_line->HasSwitch(switches::kAuthExtensionPath)) {
     base::FilePath auth_extension_path =
         command_line->GetSwitchValuePath(switches::kAuthExtensionPath);
-    component_loader->Add(IDR_GAIA_TEST_AUTH_MANIFEST, auth_extension_path);
+    component_loader->Add(IDR_GAIA_AUTH_MANIFEST, auth_extension_path);
     return;
   }
 
@@ -42,7 +42,7 @@
 #if defined(OS_CHROMEOS)
   chromeos::system::StatisticsProvider* provider =
       chromeos::system::StatisticsProvider::GetInstance();
-  provider->GetMachineFlag(chromeos::kOemKeyboardDrivenOobeKey,
+  provider->GetMachineFlag(chromeos::system::kOemKeyboardDrivenOobeKey,
                            &force_keyboard_oobe);
 #endif // OS_CHROMEOS
   if (force_keyboard_oobe) {
diff --git a/chrome/browser/extensions/shell_window_registry.cc b/chrome/browser/extensions/shell_window_registry.cc
index 4e4c02a..38a8d38 100644
--- a/chrome/browser/extensions/shell_window_registry.cc
+++ b/chrome/browser/extensions/shell_window_registry.cc
@@ -2,12 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "apps/shell_window.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/extensions/shell_window_registry.h"
 #include "chrome/browser/profiles/incognito_helpers.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/extensions/native_app_window.h"
-#include "chrome/browser/ui/extensions/shell_window.h"
 #include "chrome/common/extensions/extension.h"
 #include "components/browser_context_keyed_service/browser_context_dependency_manager.h"
 #include "content/public/browser/devtools_agent_host.h"
@@ -17,6 +17,8 @@
 #include "content/public/browser/site_instance.h"
 #include "content/public/browser/web_contents.h"
 
+using apps::ShellWindow;
+
 namespace {
 
 // Create a key that identifies a ShellWindow in a RenderViewHost across App
@@ -41,7 +43,7 @@
   return key;
 }
 
-}
+}  // namespace
 
 namespace extensions {
 
diff --git a/chrome/browser/extensions/shell_window_registry.h b/chrome/browser/extensions/shell_window_registry.h
index ba3dd76..da1072c 100644
--- a/chrome/browser/extensions/shell_window_registry.h
+++ b/chrome/browser/extensions/shell_window_registry.h
@@ -16,7 +16,10 @@
 #include "ui/gfx/native_widget_types.h"
 
 class Profile;
+
+namespace apps {
 class ShellWindow;
+}
 
 namespace content {
 class DevToolsAgentHost;
@@ -37,17 +40,17 @@
   class Observer {
    public:
     // Called just after a shell window was added.
-    virtual void OnShellWindowAdded(ShellWindow* shell_window) = 0;
+    virtual void OnShellWindowAdded(apps::ShellWindow* shell_window) = 0;
     // Called when the window icon changes.
-    virtual void OnShellWindowIconChanged(ShellWindow* shell_window) = 0;
+    virtual void OnShellWindowIconChanged(apps::ShellWindow* shell_window) = 0;
     // Called just after a shell window was removed.
-    virtual void OnShellWindowRemoved(ShellWindow* shell_window) = 0;
+    virtual void OnShellWindowRemoved(apps::ShellWindow* shell_window) = 0;
 
    protected:
     virtual ~Observer() {}
   };
 
-  typedef std::list<ShellWindow*> ShellWindowList;
+  typedef std::list<apps::ShellWindow*> ShellWindowList;
   typedef ShellWindowList::const_iterator const_iterator;
   typedef std::set<std::string> InspectedWindowSet;
 
@@ -58,11 +61,11 @@
   // a convenience wrapper around ShellWindowRegistry::Factory::GetForProfile.
   static ShellWindowRegistry* Get(Profile* profile);
 
-  void AddShellWindow(ShellWindow* shell_window);
-  void ShellWindowIconChanged(ShellWindow* shell_window);
+  void AddShellWindow(apps::ShellWindow* shell_window);
+  void ShellWindowIconChanged(apps::ShellWindow* shell_window);
   // Called by |shell_window| when it is activated.
-  void ShellWindowActivated(ShellWindow* shell_window);
-  void RemoveShellWindow(ShellWindow* shell_window);
+  void ShellWindowActivated(apps::ShellWindow* shell_window);
+  void RemoveShellWindow(apps::ShellWindow* shell_window);
 
   void AddObserver(Observer* observer);
   void RemoveObserver(Observer* observer);
@@ -72,19 +75,22 @@
   const ShellWindowList& shell_windows() const { return shell_windows_; }
 
   // Helper functions to find shell windows with particular attributes.
-  ShellWindow* GetShellWindowForRenderViewHost(
+  apps::ShellWindow* GetShellWindowForRenderViewHost(
       content::RenderViewHost* render_view_host) const;
-  ShellWindow* GetShellWindowForNativeWindow(gfx::NativeWindow window) const;
+  apps::ShellWindow* GetShellWindowForNativeWindow(
+      gfx::NativeWindow window) const;
   // Returns an app window for the given app, or NULL if no shell windows are
   // open. If there is a window for the given app that is active, that one will
   // be returned, otherwise an arbitrary window will be returned.
-  ShellWindow* GetCurrentShellWindowForApp(const std::string& app_id) const;
+  apps::ShellWindow* GetCurrentShellWindowForApp(
+      const std::string& app_id) const;
   // Returns an app window for the given app and window key, or NULL if no shell
   // window with the key are open. If there is a window for the given app and
   // key that is active, that one will be returned, otherwise an arbitrary
   // window will be returned.
-  ShellWindow* GetShellWindowForAppAndKey(const std::string& app_id,
-                                          const std::string& window_key) const;
+  apps::ShellWindow* GetShellWindowForAppAndKey(
+      const std::string& app_id,
+      const std::string& window_key) const;
 
   // Returns whether a ShellWindow's ID was last known to have a DevToolsAgent
   // attached to it, which should be restored during a reload of a corresponding
@@ -92,7 +98,7 @@
   bool HadDevToolsAttached(content::RenderViewHost* render_view_host) const;
 
   // Returns the shell window for |window|, looking in all profiles.
-  static ShellWindow* GetShellWindowForNativeWindowAnyProfile(
+  static apps::ShellWindow* GetShellWindowForNativeWindowAnyProfile(
       gfx::NativeWindow window);
 
   // Returns true if the number of shell windows registered across all profiles
@@ -126,11 +132,11 @@
  private:
   // Ensures the specified |shell_window| is included in |shell_windows_|.
   // Otherwise adds |shell_window| to the back of |shell_windows_|.
-  void AddShellWindowToList(ShellWindow* shell_window);
+  void AddShellWindowToList(apps::ShellWindow* shell_window);
 
   // Bring |shell_window| to the front of |shell_windows_|. If it is not in the
   // list, add it first.
-  void BringToFront(ShellWindow* shell_window);
+  void BringToFront(apps::ShellWindow* shell_window);
 
   Profile* profile_;
   ShellWindowList shell_windows_;
diff --git a/chrome/browser/extensions/stubs_apitest.cc b/chrome/browser/extensions/stubs_apitest.cc
index 7a5a407..982d317 100644
--- a/chrome/browser/extensions/stubs_apitest.cc
+++ b/chrome/browser/extensions/stubs_apitest.cc
@@ -6,7 +6,7 @@
 #include "chrome/common/chrome_paths.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "googleurl/src/gurl.h"
-#include "net/test/spawned_test_server/spawned_test_server.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
 
 // Tests that we throw errors when you try using extension APIs that aren't
 // supported in content scripts.
@@ -17,13 +17,13 @@
 #define MAYBE_Stubs Stubs
 #endif
 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, MAYBE_Stubs) {
-  ASSERT_TRUE(test_server()->Start());
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
 
   ASSERT_TRUE(RunExtensionTest("stubs")) << message_;
 
   // Navigate to a simple http:// page, which should get the content script
   // injected and run the rest of the test.
-  GURL url(test_server()->GetURL("file/extensions/test_file.html"));
+  GURL url(embedded_test_server()->GetURL("/extensions/test_file.html"));
   ui_test_utils::NavigateToURL(browser(), url);
 
   ResultCatcher catcher;
diff --git a/chrome/browser/extensions/token_cache/token_cache_service.h b/chrome/browser/extensions/token_cache/token_cache_service.h
index 70ee415..bab555e 100644
--- a/chrome/browser/extensions/token_cache/token_cache_service.h
+++ b/chrome/browser/extensions/token_cache/token_cache_service.h
@@ -10,7 +10,7 @@
 
 #include "base/basictypes.h"
 #include "base/compiler_specific.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "components/browser_context_keyed_service/browser_context_keyed_service.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
diff --git a/chrome/browser/extensions/token_cache/token_cache_service_unittest.cc b/chrome/browser/extensions/token_cache/token_cache_service_unittest.cc
index 83ffaaf..fb42678 100644
--- a/chrome/browser/extensions/token_cache/token_cache_service_unittest.cc
+++ b/chrome/browser/extensions/token_cache/token_cache_service_unittest.cc
@@ -4,7 +4,7 @@
 
 #include "base/basictypes.h"
 #include "base/compiler_specific.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/extensions/token_cache/token_cache_service.h"
 #include "chrome/common/chrome_notification_types.h"
 #include "content/public/browser/notification_details.h"
diff --git a/chrome/browser/extensions/updater/extension_downloader.cc b/chrome/browser/extensions/updater/extension_downloader.cc
index 30ef6d6..0af857d 100644
--- a/chrome/browser/extensions/updater/extension_downloader.cc
+++ b/chrome/browser/extensions/updater/extension_downloader.cc
@@ -17,7 +17,7 @@
 #include "base/platform_file.h"
 #include "base/stl_util.h"
 #include "base/strings/string_util.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "base/version.h"
 #include "chrome/browser/extensions/updater/request_queue_impl.h"
 #include "chrome/browser/extensions/updater/safe_manifest_parser.h"
diff --git a/chrome/browser/extensions/updater/extension_downloader_delegate.h b/chrome/browser/extensions/updater/extension_downloader_delegate.h
index 58e0dc9..99f5d6e 100644
--- a/chrome/browser/extensions/updater/extension_downloader_delegate.h
+++ b/chrome/browser/extensions/updater/extension_downloader_delegate.h
@@ -8,7 +8,7 @@
 #include <set>
 #include <string>
 
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/extensions/updater/manifest_fetch_data.h"
 
 class GURL;
diff --git a/chrome/browser/extensions/updater/extension_updater.h b/chrome/browser/extensions/updater/extension_updater.h
index ffb40e9..94e0176 100644
--- a/chrome/browser/extensions/updater/extension_updater.h
+++ b/chrome/browser/extensions/updater/extension_updater.h
@@ -17,8 +17,8 @@
 #include "base/gtest_prod_util.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
-#include "base/time.h"
-#include "base/timer.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
 #include "chrome/browser/extensions/updater/extension_downloader_delegate.h"
 #include "chrome/browser/extensions/updater/manifest_fetch_data.h"
 #include "content/public/browser/notification_observer.h"
diff --git a/chrome/browser/extensions/updater/request_queue.h b/chrome/browser/extensions/updater/request_queue.h
index 2ec72f5..c147881 100644
--- a/chrome/browser/extensions/updater/request_queue.h
+++ b/chrome/browser/extensions/updater/request_queue.h
@@ -11,8 +11,8 @@
 #include "base/callback.h"
 #include "base/memory/linked_ptr.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/time.h"
-#include "base/timer.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
 #include "net/base/backoff_entry.h"
 
 namespace extensions {
diff --git a/chrome/browser/extensions/web_view_browsertest.cc b/chrome/browser/extensions/web_view_browsertest.cc
index bfe49c3..d3400ae 100644
--- a/chrome/browser/extensions/web_view_browsertest.cc
+++ b/chrome/browser/extensions/web_view_browsertest.cc
@@ -20,12 +20,21 @@
 #include "content/public/browser/web_contents_delegate.h"
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/fake_speech_recognition_manager.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+#include "net/test/embedded_test_server/http_request.h"
+#include "net/test/embedded_test_server/http_response.h"
 #include "ui/compositor/compositor_setup.h"
 #include "ui/gl/gl_switches.h"
 
 using prerender::PrerenderLinkManager;
 using prerender::PrerenderLinkManagerFactory;
 
+namespace {
+  const char kRedirectResponsePath[] = "/server-redirect";
+  const char kRedirectResponseFullPath[] =
+      "/extensions/platform_apps/web_view/shim/guest_redirect.html";
+}  // namespace
+
 // This class intercepts media access request from the embedder. The request
 // should be triggered only if the embedder API (from tests) allows the request
 // in Javascript.
@@ -204,26 +213,26 @@
 
     navigate_to_url = navigate_to_url.ReplaceComponents(replace_host);
 
-    GURL tag_url1 = test_server()->GetURL(
-        "files/extensions/platform_apps/web_view/isolation/cookie.html");
+    GURL tag_url1 = embedded_test_server()->GetURL(
+        "/extensions/platform_apps/web_view/isolation/cookie.html");
     tag_url1 = tag_url1.ReplaceComponents(replace_host);
-    GURL tag_url2 = test_server()->GetURL(
-        "files/extensions/platform_apps/web_view/isolation/cookie2.html");
+    GURL tag_url2 = embedded_test_server()->GetURL(
+        "/extensions/platform_apps/web_view/isolation/cookie2.html");
     tag_url2 = tag_url2.ReplaceComponents(replace_host);
-    GURL tag_url3 = test_server()->GetURL(
-        "files/extensions/platform_apps/web_view/isolation/storage1.html");
+    GURL tag_url3 = embedded_test_server()->GetURL(
+        "/extensions/platform_apps/web_view/isolation/storage1.html");
     tag_url3 = tag_url3.ReplaceComponents(replace_host);
-    GURL tag_url4 = test_server()->GetURL(
-        "files/extensions/platform_apps/web_view/isolation/storage2.html");
+    GURL tag_url4 = embedded_test_server()->GetURL(
+        "/extensions/platform_apps/web_view/isolation/storage2.html");
     tag_url4 = tag_url4.ReplaceComponents(replace_host);
-    GURL tag_url5 = test_server()->GetURL(
-        "files/extensions/platform_apps/web_view/isolation/storage1.html#p1");
+    GURL tag_url5 = embedded_test_server()->GetURL(
+        "/extensions/platform_apps/web_view/isolation/storage1.html#p1");
     tag_url5 = tag_url5.ReplaceComponents(replace_host);
-    GURL tag_url6 = test_server()->GetURL(
-        "files/extensions/platform_apps/web_view/isolation/storage1.html#p2");
+    GURL tag_url6 = embedded_test_server()->GetURL(
+        "/extensions/platform_apps/web_view/isolation/storage1.html#p2");
     tag_url6 = tag_url6.ReplaceComponents(replace_host);
-    GURL tag_url7 = test_server()->GetURL(
-        "files/extensions/platform_apps/web_view/isolation/storage1.html#p3");
+    GURL tag_url7 = embedded_test_server()->GetURL(
+        "/extensions/platform_apps/web_view/isolation/storage1.html#p3");
     tag_url7 = tag_url7.ReplaceComponents(replace_host);
 
     ui_test_utils::NavigateToURLWithDisposition(
@@ -352,24 +361,44 @@
     EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle());
   }
 
-  void GeolocationTestHelper(const std::string& test_name,
-                             const std::string& app_location) {
-    ASSERT_TRUE(StartTestServer());  // For serving guest pages.
+  // Handles |request| by serving a redirect response.
+  static scoped_ptr<net::test_server::HttpResponse> RedirectResponseHandler(
+      const std::string& path,
+      const GURL& redirect_target,
+      const net::test_server::HttpRequest& request) {
+    if (!StartsWithASCII(path, request.relative_url, true))
+      return scoped_ptr<net::test_server::HttpResponse>();
+
+    scoped_ptr<net::test_server::BasicHttpResponse> http_response(
+        new net::test_server::BasicHttpResponse);
+    http_response->set_code(net::HTTP_MOVED_PERMANENTLY);
+    http_response->AddCustomHeader("Location", redirect_target.spec());
+    return http_response.PassAs<net::test_server::HttpResponse>();
+  }
+
+  void TestHelper(const std::string& test_name,
+                  const std::string& test_passed_msg,
+                  const std::string& test_failed_msg,
+                  const std::string& app_location) {
+    ASSERT_TRUE(StartEmbeddedTestServer());  // For serving guest pages.
     ExtensionTestMessageListener launched_listener("Launched", false);
     LoadAndLaunchPlatformApp(app_location.c_str());
     ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
 
+    embedded_test_server()->RegisterRequestHandler(
+        base::Bind(&WebViewTest::RedirectResponseHandler,
+                   kRedirectResponsePath,
+                   embedded_test_server()->GetURL(kRedirectResponseFullPath)));
+
     content::WebContents* embedder_web_contents =
         GetFirstShellWindowWebContents();
     ASSERT_TRUE(embedder_web_contents);
 
-    ExtensionTestMessageListener done_listener("DoneGeolocationTest.PASSED",
-                                               false);
-    done_listener.AlsoListenForFailureMessage("DoneGeolocationTest.FAILED");
+    ExtensionTestMessageListener done_listener(test_passed_msg, false);
+    done_listener.AlsoListenForFailureMessage(test_failed_msg);
     EXPECT_TRUE(content::ExecuteScript(
                     embedder_web_contents,
-                    base::StringPrintf("runGeolocationTest('%s')",
-                                       test_name.c_str())));
+                    base::StringPrintf("runTest('%s')", test_name.c_str())));
     ASSERT_TRUE(done_listener.WaitUntilSatisfied());
   }
 
@@ -379,7 +408,7 @@
     std::string host_str("localhost");  // Must stay in scope with replace_host.
     replace_host.SetHostStr(host_str);
 
-    GURL guest_url = test_server()->GetURL(guest_path);
+    GURL guest_url = embedded_test_server()->GetURL(guest_path);
     guest_url = guest_url.ReplaceComponents(replace_host);
 
     ui_test_utils::UrlLoadObserver guest_observer(
@@ -407,7 +436,7 @@
   // Runs media_access/deny tests, each of them are run separately otherwise
   // they timeout (mostly on Windows).
   void MediaAccessAPIDenyTestHelper(const std::string& test_name) {
-    ASSERT_TRUE(StartTestServer());  // For serving guest pages.
+    ASSERT_TRUE(StartEmbeddedTestServer());  // For serving guest pages.
     ExtensionTestMessageListener loaded_listener("loaded", false);
     LoadAndLaunchPlatformApp("web_view/media_access/deny");
     ASSERT_TRUE(loaded_listener.WaitUntilSatisfied());
@@ -430,17 +459,146 @@
       fake_speech_recognition_manager_;
 };
 
-// This test is flaky on Windows, Chrome OS, and Mac (all platforms that
-// have threaded compositing enabled).
-// http://crbug.com/176122
-#if defined(OS_WIN) || defined(OS_CHROMEOS) || defined(OS_MACOSX)
-#define MAYBE_Shim DISABLED_Shim
-#else
-#define MAYBE_Shim Shim
-#endif
-IN_PROC_BROWSER_TEST_F(WebViewTest, MAYBE_Shim) {
-  ASSERT_TRUE(StartTestServer());
-  ASSERT_TRUE(RunPlatformAppTest("platform_apps/web_view/shim")) << message_;
+IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_TestSize) {
+  TestHelper("testSize",
+             "DoneShimTest.PASSED",
+             "DoneShimTest.FAILED",
+             "web_view/shim");
+}
+
+IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_TestAPIMethodExistence) {
+  TestHelper("testAPIMethodExistence",
+             "DoneShimTest.PASSED",
+             "DoneShimTest.FAILED",
+             "web_view/shim");
+}
+
+IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_TestEventName) {
+  TestHelper("testEventName",
+             "DoneShimTest.PASSED",
+             "DoneShimTest.FAILED",
+             "web_view/shim");
+}
+
+// WebViewTest.Shim_TestDestroyOnEventListener is flaky, so disable it.
+// http://crbug.com/255106
+IN_PROC_BROWSER_TEST_F(WebViewTest, DISABLED_Shim_TestDestroyOnEventListener) {
+  TestHelper("testDestroyOnEventListener",
+             "DoneShimTest.PASSED",
+             "DoneShimTest.FAILED",
+             "web_view/shim");
+}
+
+IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_TestCannotMutateEventName) {
+  TestHelper("testCannotMutateEventName",
+             "DoneShimTest.PASSED",
+             "DoneShimTest.FAILED",
+             "web_view/shim");
+}
+
+IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_TestPartitionRaisesException) {
+  TestHelper("testPartitionRaisesException",
+             "DoneShimTest.PASSED",
+             "DoneShimTest.FAILED",
+             "web_view/shim");
+}
+
+IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_TestExecuteScriptFail) {
+  TestHelper("testExecuteScriptFail",
+             "DoneShimTest.PASSED",
+             "DoneShimTest.FAILED",
+             "web_view/shim");
+}
+
+IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_TestExecuteScript) {
+  TestHelper("testExecuteScript",
+             "DoneShimTest.PASSED",
+             "DoneShimTest.FAILED",
+             "web_view/shim");
+}
+
+IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_TestTerminateAfterExit) {
+  TestHelper("testTerminateAfterExit",
+             "DoneShimTest.PASSED",
+             "DoneShimTest.FAILED",
+             "web_view/shim");
+}
+
+IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_TestAssignSrcAfterCrash) {
+  TestHelper("testAssignSrcAfterCrash",
+             "DoneShimTest.PASSED",
+             "DoneShimTest.FAILED",
+             "web_view/shim");
+}
+
+IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_TestRemoveSrcAttribute) {
+  TestHelper("testRemoveSrcAttribute",
+             "DoneShimTest.PASSED",
+             "DoneShimTest.FAILED",
+             "web_view/shim");
+}
+
+IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_TestBrowserPluginNotAllowed) {
+  TestHelper("testBrowserPluginNotAllowed",
+             "DoneShimTest.PASSED",
+             "DoneShimTest.FAILED",
+             "web_view/shim");
+}
+
+IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_TestNewWindow) {
+  TestHelper("testNewWindow",
+             "DoneShimTest.PASSED",
+             "DoneShimTest.FAILED",
+             "web_view/shim");
+}
+
+IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_TestNewWindowTwoListeners) {
+  TestHelper("testNewWindowTwoListeners",
+             "DoneShimTest.PASSED",
+             "DoneShimTest.FAILED",
+             "web_view/shim");
+}
+
+IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_TestNewWindowNoPreventDefault) {
+  TestHelper("testNewWindowNoPreventDefault",
+             "DoneShimTest.PASSED",
+             "DoneShimTest.FAILED",
+             "web_view/shim");
+}
+
+IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_TestNewWindowNoReferrerLink) {
+  TestHelper("testNewWindowNoReferrerLink",
+             "DoneShimTest.PASSED",
+             "DoneShimTest.FAILED",
+             "web_view/shim");
+}
+
+IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_TestContentLoadEvent) {
+  TestHelper("testContentLoadEvent",
+             "DoneShimTest.PASSED",
+             "DoneShimTest.FAILED",
+             "web_view/shim");
+}
+
+IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_TestWebRequestAPI) {
+  TestHelper("testWebRequestAPI",
+             "DoneShimTest.PASSED",
+             "DoneShimTest.FAILED",
+             "web_view/shim");
+}
+
+IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_TestLoadStartLoadRedirect) {
+  TestHelper("testLoadStartLoadRedirect",
+             "DoneShimTest.PASSED",
+             "DoneShimTest.FAILED",
+             "web_view/shim");
+}
+
+IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_TestGetProcessId) {
+  TestHelper("testGetProcessId",
+             "DoneShimTest.PASSED",
+             "DoneShimTest.FAILED",
+             "web_view/shim");
 }
 
 IN_PROC_BROWSER_TEST_F(WebViewTest, ShimSrcAttribute) {
@@ -452,10 +610,10 @@
 // This test is here rather than in PrerenderBrowserTest for testing convenience
 // only. If it breaks then this is a bug in the prerenderer.
 IN_PROC_BROWSER_TEST_F(WebViewTest, NoPrerenderer) {
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
   content::WebContents* guest_web_contents =
       LoadGuest(
-          "files/extensions/platform_apps/web_view/noprerenderer/guest.html",
+          "/extensions/platform_apps/web_view/noprerenderer/guest.html",
           "web_view/noprerenderer");
   ASSERT_TRUE(guest_web_contents != NULL);
 
@@ -471,7 +629,7 @@
 // multiple webview tags. Each tag sets a cookie and the test checks the proper
 // storage isolation is enforced.
 IN_PROC_BROWSER_TEST_F(WebViewTest, CookieIsolation) {
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
   const std::string kExpire =
       "var expire = new Date(Date.now() + 24 * 60 * 60 * 1000);";
   std::string cookie_script1(kExpire);
@@ -485,8 +643,8 @@
   std::string host_str("localhost");  // Must stay in scope with replace_host.
   replace_host.SetHostStr(host_str);
 
-  GURL set_cookie_url = test_server()->GetURL(
-      "files/extensions/platform_apps/isolation/set_cookie.html");
+  GURL set_cookie_url = embedded_test_server()->GetURL(
+      "/extensions/platform_apps/isolation/set_cookie.html");
   set_cookie_url = set_cookie_url.ReplaceComponents(replace_host);
 
   // The first two partitions will be used to set cookies and ensure they are
@@ -537,7 +695,7 @@
 // This tests that in-memory storage partitions are reset on browser restart,
 // but persistent ones maintain state for cookies and HTML5 storage.
 IN_PROC_BROWSER_TEST_F(WebViewTest, PRE_StoragePersistence) {
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
   const std::string kExpire =
       "var expire = new Date(Date.now() + 24 * 60 * 60 * 1000);";
   std::string cookie_script1(kExpire);
@@ -622,7 +780,7 @@
 // This is the post-reset portion of the StoragePersistence test.  See
 // PRE_StoragePersistence for main comment.
 IN_PROC_BROWSER_TEST_F(WebViewTest, DISABLED_StoragePersistence) {
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
 
   // We don't care where the main browser is on this test.
   GURL blank_url("about:blank");
@@ -692,8 +850,8 @@
 // entries, which the test checks to ensure proper storage isolation is
 // enforced.
 IN_PROC_BROWSER_TEST_F(WebViewTest, MAYBE_DOMStorageIsolation) {
-  ASSERT_TRUE(StartTestServer());
-  GURL regular_url = test_server()->GetURL("files/title1.html");
+  ASSERT_TRUE(StartEmbeddedTestServer());
+  GURL regular_url = embedded_test_server()->GetURL("/title1.html");
 
   std::string output;
   std::string get_local_storage("window.domAutomationController.send("
@@ -786,8 +944,8 @@
 // an app with multiple webview tags and each tag creates an IndexedDB record,
 // which the test checks to ensure proper storage isolation is enforced.
 IN_PROC_BROWSER_TEST_F(WebViewTest, MAYBE_IndexedDBIsolation) {
-  ASSERT_TRUE(StartTestServer());
-  GURL regular_url = test_server()->GetURL("files/title1.html");
+  ASSERT_TRUE(StartEmbeddedTestServer());
+  GURL regular_url = embedded_test_server()->GetURL("/title1.html");
 
   content::WebContents* default_tag_contents1;
   content::WebContents* default_tag_contents2;
@@ -899,7 +1057,7 @@
 }
 
 void WebViewTest::MediaAccessAPIAllowTestHelper(const std::string& test_name) {
-  ASSERT_TRUE(StartTestServer());  // For serving guest pages.
+  ASSERT_TRUE(StartEmbeddedTestServer());  // For serving guest pages.
   ExtensionTestMessageListener launched_listener("Launched", false);
   LoadAndLaunchPlatformApp("web_view/media_access/allow");
   ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
@@ -941,16 +1099,16 @@
 // Checks that window.screenX/screenY/screenLeft/screenTop works correctly for
 // guests.
 IN_PROC_BROWSER_TEST_F(WebViewTest, ScreenCoordinates) {
-  ASSERT_TRUE(StartTestServer());  // For serving guest pages.
+  ASSERT_TRUE(StartEmbeddedTestServer());  // For serving guest pages.
   ASSERT_TRUE(RunPlatformAppTestWithArg(
       "platform_apps/web_view/common", "screen_coordinates"))
           << message_;
 }
 
 IN_PROC_BROWSER_TEST_F(WebViewTest, SpeechRecognition) {
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
   content::WebContents* guest_web_contents = LoadGuest(
-      "files/extensions/platform_apps/web_view/speech/guest.html",
+      "/extensions/platform_apps/web_view/speech/guest.html",
       "web_view/speech");
   ASSERT_TRUE(guest_web_contents);
 
@@ -970,7 +1128,7 @@
   const extensions::Extension* extension =
       LoadAndLaunchPlatformApp("web_view/teardown");
   ASSERT_TRUE(first_loaded_listener.WaitUntilSatisfied());
-  ShellWindow* window = NULL;
+  apps::ShellWindow* window = NULL;
   if (!GetShellWindowCount())
     window = CreateShellWindow(extension);
   else
@@ -988,13 +1146,17 @@
 // No matter what the API does, geolocation permission would be denied.
 // Note that the test name prefix must be "GeolocationAPI".
 IN_PROC_BROWSER_TEST_F(WebViewTest, GeolocationAPIEmbedderHasNoAccessAllow) {
-  GeolocationTestHelper("testDenyDenies",
-                        "web_view/geolocation/embedder_has_no_permission");
+  TestHelper("testDenyDenies",
+             "DoneGeolocationTest.PASSED",
+             "DoneGeolocationTest.FAILED",
+             "web_view/geolocation/embedder_has_no_permission");
 }
 
 IN_PROC_BROWSER_TEST_F(WebViewTest, GeolocationAPIEmbedderHasNoAccessDeny) {
-  GeolocationTestHelper("testDenyDenies",
-                        "web_view/geolocation/embedder_has_no_permission");
+  TestHelper("testDenyDenies",
+             "DoneGeolocationTest.PASSED",
+             "DoneGeolocationTest.FAILED",
+             "web_view/geolocation/embedder_has_no_permission");
 }
 
 // In following GeolocationAPIEmbedderHasAccess* tests, embedder (i.e. the
@@ -1008,43 +1170,56 @@
 // the tests become flaky.
 // GeolocationAPI* test 1 of 3.
 IN_PROC_BROWSER_TEST_F(WebViewTest, GeolocationAPIEmbedderHasAccessAllow) {
-  GeolocationTestHelper("testAllow",
-                        "web_view/geolocation/embedder_has_permission");
+  TestHelper("testAllow",
+             "DoneGeolocationTest.PASSED",
+             "DoneGeolocationTest.FAILED",
+             "web_view/geolocation/embedder_has_permission");
 }
 
 // GeolocationAPI* test 2 of 3.
 IN_PROC_BROWSER_TEST_F(WebViewTest, GeolocationAPIEmbedderHasAccessDeny) {
-  GeolocationTestHelper("testDeny",
-                        "web_view/geolocation/embedder_has_permission");
+  TestHelper("testDeny",
+             "DoneGeolocationTest.PASSED",
+             "DoneGeolocationTest.FAILED",
+             "web_view/geolocation/embedder_has_permission");
 }
 
 // GeolocationAPI* test 3 of 3.
 IN_PROC_BROWSER_TEST_F(WebViewTest,
                        GeolocationAPIEmbedderHasAccessMultipleBridgeIdAllow) {
-  GeolocationTestHelper("testMultipleBridgeIdAllow",
-                        "web_view/geolocation/embedder_has_permission");
+  TestHelper("testMultipleBridgeIdAllow",
+             "DoneGeolocationTest.PASSED",
+             "DoneGeolocationTest.FAILED",
+             "web_view/geolocation/embedder_has_permission");
 }
 
 // Tests that
 // BrowserPluginGeolocationPermissionContext::CancelGeolocationPermissionRequest
 // is handled correctly (and does not crash).
 IN_PROC_BROWSER_TEST_F(WebViewTest, GeolocationAPICancelGeolocation) {
-  ASSERT_TRUE(StartTestServer());  // For serving guest pages.
+  ASSERT_TRUE(StartEmbeddedTestServer());  // For serving guest pages.
   ASSERT_TRUE(RunPlatformAppTest(
         "platform_apps/web_view/geolocation/cancel_request")) << message_;
 }
 
+IN_PROC_BROWSER_TEST_F(WebViewTest, Navigation) {
+  TestHelper("testNavigation",
+             "DoneNavigationTest.PASSED",
+             "DoneNavigationTest.FAILED",
+             "web_view/navigation");
+}
+
 IN_PROC_BROWSER_TEST_F(WebViewTest, ConsoleMessage) {
-  ASSERT_TRUE(StartTestServer());  // For serving guest pages.
+  ASSERT_TRUE(StartEmbeddedTestServer());  // For serving guest pages.
   ASSERT_TRUE(RunPlatformAppTestWithArg(
       "platform_apps/web_view/common", "console_messages"))
           << message_;
 }
 
 IN_PROC_BROWSER_TEST_F(WebViewTest, DownloadPermission) {
-  ASSERT_TRUE(StartTestServer());  // For serving guest pages.
+  ASSERT_TRUE(StartEmbeddedTestServer());  // For serving guest pages.
   content::WebContents* guest_web_contents =
-      LoadGuest("files/extensions/platform_apps/web_view/download/guest.html",
+      LoadGuest("/extensions/platform_apps/web_view/download/guest.html",
                 "web_view/download");
   ASSERT_TRUE(guest_web_contents);
 
diff --git a/chrome/browser/extensions/web_view_interactive_browsertest.cc b/chrome/browser/extensions/web_view_interactive_browsertest.cc
index 5d854bd..69b5cbc 100644
--- a/chrome/browser/extensions/web_view_interactive_browsertest.cc
+++ b/chrome/browser/extensions/web_view_interactive_browsertest.cc
@@ -1,13 +1,13 @@
-// Copyright (c) 2013 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/stringprintf.h"
+#include "apps/shell_window.h"
+#include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/extensions/extension_test_message_listener.h"
 #include "chrome/browser/extensions/platform_app_browsertest_util.h"
 #include "chrome/browser/extensions/shell_window_registry.h"
-#include "chrome/browser/ui/extensions/shell_window.h"
 #include "chrome/test/base/interactive_test_utils.h"
 #include "chrome/test/base/test_launcher_utils.h"
 #include "chrome/test/base/ui_test_utils.h"
@@ -18,9 +18,12 @@
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_view.h"
 #include "content/public/test/browser_test_utils.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
 #include "ui/base/keycodes/keyboard_codes.h"
 #include "ui/base/test/ui_controls.h"
 
+using apps::ShellWindow;
+
 class WebViewInteractiveTest
     : public extensions::PlatformAppBrowserTest {
  public:
@@ -101,7 +104,7 @@
 
   void NewWindowTestHelper(const std::string& test_name,
                            const std::string& app_location) {
-    ASSERT_TRUE(StartTestServer());  // For serving guest pages.
+    ASSERT_TRUE(StartEmbeddedTestServer());  // For serving guest pages.
     ExtensionTestMessageListener launched_listener("Launched", false);
     LoadAndLaunchPlatformApp(app_location.c_str());
     ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
@@ -122,12 +125,12 @@
 
   void SetupTest(const std::string& app_name,
                  const std::string& guest_url_spec) {
-    ASSERT_TRUE(StartTestServer());
+    ASSERT_TRUE(StartEmbeddedTestServer());
     GURL::Replacements replace_host;
     std::string host_str("localhost");  // Must stay in scope with replace_host.
     replace_host.SetHostStr(host_str);
 
-    GURL guest_url = test_server()->GetURL(guest_url_spec);
+    GURL guest_url = embedded_test_server()->GetURL(guest_url_spec);
     guest_url = guest_url.ReplaceComponents(replace_host);
 
     ui_test_utils::UrlLoadObserver guest_observer(
@@ -290,7 +293,7 @@
 
 IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, PointerLock) {
   SetupTest("web_view/pointer_lock",
-            "files/extensions/platform_apps/web_view/pointer_lock/guest.html");
+            "/extensions/platform_apps/web_view/pointer_lock/guest.html");
 
   // Move the mouse over the Lock Pointer button.
   ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(
@@ -364,7 +367,7 @@
 
 // Tests that setting focus on the <webview> sets focus on the guest.
 IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, DISABLED_Focus) {
-  ASSERT_TRUE(StartTestServer());  // For serving guest pages.
+  ASSERT_TRUE(StartEmbeddedTestServer());  // For serving guest pages.
   ASSERT_TRUE(RunPlatformAppTest("platform_apps/web_view/focus"))
       << message_;
 }
@@ -372,7 +375,7 @@
 // Tests that guests receive edit commands and respond appropriately.
 IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, EditCommands) {
   SetupTest("web_view/edit_commands",
-            "files/extensions/platform_apps/web_view/edit_commands/guest.html");
+            "/extensions/platform_apps/web_view/edit_commands/guest.html");
 
   ASSERT_TRUE(ui_test_utils::ShowAndFocusNativeWindow(
       GetPlatformAppWindow()));
@@ -390,7 +393,7 @@
 // Tests that guests receive edit commands and respond appropriately.
 IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, EditCommandsNoMenu) {
   SetupTest("web_view/edit_commands_no_menu",
-      "files/extensions/platform_apps/web_view/edit_commands_no_menu/"
+      "/extensions/platform_apps/web_view/edit_commands_no_menu/"
       "guest.html");
 
   ASSERT_TRUE(ui_test_utils::ShowAndFocusNativeWindow(
@@ -436,7 +439,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, ExecuteCode) {
-  ASSERT_TRUE(StartTestServer());  // For serving guest pages.
+  ASSERT_TRUE(StartEmbeddedTestServer());  // For serving guest pages.
   ASSERT_TRUE(RunPlatformAppTestWithArg(
       "platform_apps/web_view/common", "execute_code")) << message_;
 }
@@ -444,7 +447,7 @@
 IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, PopupPositioning) {
   SetupTest(
       "web_view/popup_positioning",
-      "files/extensions/platform_apps/web_view/popup_positioning/guest.html");
+      "/extensions/platform_apps/web_view/popup_positioning/guest.html");
   ASSERT_TRUE(guest_web_contents());
 
   PopupTestHelper(gfx::Point());
@@ -461,7 +464,7 @@
 IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, DISABLED_PopupPositioningMoved) {
   SetupTest(
       "web_view/popup_positioning_moved",
-      "files/extensions/platform_apps/web_view/popup_positioning_moved"
+      "/extensions/platform_apps/web_view/popup_positioning_moved"
       "/guest.html");
   ASSERT_TRUE(guest_web_contents());
 
diff --git a/chrome/browser/extensions/webstore_install_helper.cc b/chrome/browser/extensions/webstore_install_helper.cc
index 67bbbf1..323cba4 100644
--- a/chrome/browser/extensions/webstore_install_helper.cc
+++ b/chrome/browser/extensions/webstore_install_helper.cc
@@ -149,7 +149,8 @@
   ReportResultsIfComplete();
 }
 
-void WebstoreInstallHelper::OnJSONParseSucceeded(const ListValue& wrapper) {
+void WebstoreInstallHelper::OnJSONParseSucceeded(
+    const base::ListValue& wrapper) {
   CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
   manifest_parse_complete_ = true;
   const Value* value = NULL;
diff --git a/chrome/browser/extensions/webstore_installer.cc b/chrome/browser/extensions/webstore_installer.cc
index b0573eb..bd40ef5 100644
--- a/chrome/browser/extensions/webstore_installer.cc
+++ b/chrome/browser/extensions/webstore_installer.cc
@@ -18,6 +18,8 @@
 #include "chrome/browser/download/download_prefs.h"
 #include "chrome/browser/download/download_util.h"
 #include "chrome/browser/extensions/crx_installer.h"
+#include "chrome/browser/extensions/install_tracker.h"
+#include "chrome/browser/extensions/install_tracker_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser_list.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
@@ -25,6 +27,7 @@
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/extension_constants.h"
+#include "chrome/common/extensions/extension_manifest_constants.h"
 #include "chrome/common/omaha_query_params/omaha_query_params.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/download_manager.h"
@@ -66,7 +69,7 @@
 const char kDownloadInterruptedError[] = "Download interrupted";
 const char kInvalidDownloadError[] = "Download was not a CRX";
 const char kInlineInstallSource[] = "inline";
-const char kDefaultInstallSource[] = "";
+const char kDefaultInstallSource[] = "ondemand";
 
 base::FilePath* g_download_directory_for_tests = NULL;
 
@@ -230,6 +233,17 @@
       BrowserThread::FILE, FROM_HERE,
       base::Bind(&GetDownloadFilePath, download_path, id_,
                  base::Bind(&WebstoreInstaller::StartDownload, this)));
+
+  std::string name;
+  if (!approval_->manifest->value()->GetString(extension_manifest_keys::kName,
+                                               &name)) {
+    NOTREACHED();
+  }
+  extensions::InstallTracker* tracker =
+      extensions::InstallTrackerFactory::GetForProfile(profile_);
+  tracker->OnBeginExtensionInstall(
+      id_, name, approval_->installing_icon, approval_->manifest->is_app(),
+      approval_->manifest->is_platform_app());
 }
 
 void WebstoreInstaller::Observe(int type,
@@ -323,15 +337,27 @@
       break;
     case DownloadItem::COMPLETE:
       // Wait for other notifications if the download is really an extension.
-      if (!download_crx_util::IsExtensionDownload(*download))
+      if (!download_crx_util::IsExtensionDownload(*download)) {
         ReportFailure(kInvalidDownloadError, FAILURE_REASON_OTHER);
-      else if (delegate_)
-        delegate_->OnExtensionDownloadProgress(id_, download);
+      } else {
+        if (delegate_)
+          delegate_->OnExtensionDownloadProgress(id_, download);
+
+        extensions::InstallTracker* tracker =
+            extensions::InstallTrackerFactory::GetForProfile(profile_);
+        tracker->OnDownloadProgress(id_, 100);
+      }
       break;
-    case DownloadItem::IN_PROGRESS:
+    case DownloadItem::IN_PROGRESS: {
       if (delegate_)
         delegate_->OnExtensionDownloadProgress(id_, download);
+
+      extensions::InstallTracker* tracker =
+          extensions::InstallTrackerFactory::GetForProfile(profile_);
+      tracker->OnDownloadProgress(id_, download->PercentComplete());
+
       break;
+    }
     default:
       // Continue listening if the download is not in one of the above states.
       break;
@@ -422,6 +448,10 @@
     delegate_ = NULL;
   }
 
+  extensions::InstallTracker* tracker =
+      extensions::InstallTrackerFactory::GetForProfile(profile_);
+  tracker->OnInstallFailure(id_);
+
   Release();  // Balanced in Start().
 }
 
diff --git a/chrome/browser/extensions/webstore_standalone_installer.cc b/chrome/browser/extensions/webstore_standalone_installer.cc
index 8508281..70e61ce 100644
--- a/chrome/browser/extensions/webstore_standalone_installer.cc
+++ b/chrome/browser/extensions/webstore_standalone_installer.cc
@@ -73,6 +73,11 @@
   webstore_data_fetcher_->Start();
 }
 
+scoped_ptr<ExtensionInstallPrompt>
+WebstoreStandaloneInstaller::CreateInstallUI() {
+  return make_scoped_ptr(new ExtensionInstallPrompt(GetWebContents()));
+}
+
 void WebstoreStandaloneInstaller::OnWebstoreRequestFailure() {
   CompleteInstall(kWebstoreRequestError);
 }
@@ -174,7 +179,7 @@
 
   install_prompt_ = CreateInstallPrompt();
   if (install_prompt_) {
-    CreateInstallUI();
+    ShowInstallUI();
     // Control flow finishes up in InstallUIProceed or InstallUIAbort.
   } else {
     InstallUIProceed();
@@ -251,7 +256,7 @@
 }
 
 void
-WebstoreStandaloneInstaller::CreateInstallUI() {
+WebstoreStandaloneInstaller::ShowInstallUI() {
   std::string error;
   localized_extension_for_display_ =
       ExtensionInstallPrompt::GetLocalizedExtensionForDisplay(
@@ -266,7 +271,7 @@
     return;
   }
 
-  install_ui_.reset(new ExtensionInstallPrompt(GetWebContents()));
+  install_ui_ = CreateInstallUI();
   install_ui_->ConfirmStandaloneInstall(
       this, localized_extension_for_display_.get(), &icon_, *install_prompt_);
 }
diff --git a/chrome/browser/extensions/webstore_standalone_installer.h b/chrome/browser/extensions/webstore_standalone_installer.h
index fb4c02b..a49a868 100644
--- a/chrome/browser/extensions/webstore_standalone_installer.h
+++ b/chrome/browser/extensions/webstore_standalone_installer.h
@@ -107,6 +107,10 @@
       const base::DictionaryValue& webstore_data,
       std::string* error) const = 0;
 
+  // Returns an install UI to be shown. By default, this returns an install UI
+  // that is a transient child of the host window for GetWebContents().
+  virtual scoped_ptr<ExtensionInstallPrompt> CreateInstallUI();
+
   // Accessors to be used by subclasses.
   const std::string& localized_user_count() const {
     return localized_user_count_;
@@ -161,7 +165,7 @@
       const std::string& error,
       WebstoreInstaller::FailureReason reason) OVERRIDE;
 
-  void CreateInstallUI();
+  void ShowInstallUI();
 
   // Input configuration.
   std::string id_;
@@ -185,7 +189,7 @@
   scoped_ptr<DictionaryValue> manifest_;
   SkBitmap icon_;
 
-  // Created by CreateInstallUI() when a prompt is shown (if
+  // Created by ShowInstallUI() when a prompt is shown (if
   // the implementor returns a non-NULL in CreateInstallPrompt()).
   scoped_refptr<Extension> localized_extension_for_display_;
 
diff --git a/chrome/browser/extensions/webstore_startup_installer_browsertest.cc b/chrome/browser/extensions/webstore_startup_installer_browsertest.cc
index b1febf4..019acee 100644
--- a/chrome/browser/extensions/webstore_startup_installer_browsertest.cc
+++ b/chrome/browser/extensions/webstore_startup_installer_browsertest.cc
@@ -11,6 +11,9 @@
 #include "chrome/browser/extensions/extension_system.h"
 #include "chrome/browser/extensions/startup_helper.h"
 #include "chrome/browser/extensions/webstore_standalone_installer.h"
+#include "chrome/browser/infobars/infobar_service.h"
+#include "chrome/browser/managed_mode/managed_user_service.h"
+#include "chrome/browser/managed_mode/managed_user_service_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
@@ -18,6 +21,7 @@
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/extensions/extension_builder.h"
 #include "chrome/common/extensions/value_builder.h"
+#include "chrome/common/pref_names.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "content/public/browser/notification_registrar.h"
@@ -235,6 +239,28 @@
   EXPECT_TRUE(extension_service->extensions()->Contains(kTestExtensionId));
 }
 
+IN_PROC_BROWSER_TEST_F(WebstoreStartupInstallerTest,
+                       InstallProhibitedForManagedUsers) {
+  CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+      switches::kAppsGalleryInstallAutoConfirmForTests, "accept");
+
+  // Make the profile managed such that no extension installs are allowed.
+  browser()->profile()->GetPrefs()->SetBoolean(prefs::kProfileIsManaged, true);
+  ManagedUserService* service =
+      ManagedUserServiceFactory::GetForProfile(browser()->profile());
+  service->Init();
+
+  ui_test_utils::NavigateToURL(
+      browser(), GenerateTestServerUrl(kAppDomain, "install_prohibited.html"));
+
+  RunTest("runTest");
+
+  // No error infobar should show up.
+  WebContents* contents = browser()->tab_strip_model()->GetActiveWebContents();
+  InfoBarService* info_bar_service = InfoBarService::FromWebContents(contents);
+  EXPECT_EQ(info_bar_service->infobar_count(), 0u);
+}
+
 // The unpack failure test needs to use a different install .crx, which is
 // specified via a command-line flag, so it needs its own test subclass.
 class WebstoreStartupInstallUnpackFailureTest
diff --git a/chrome/browser/extensions/window_controls_browsertest.cc b/chrome/browser/extensions/window_controls_browsertest.cc
new file mode 100644
index 0000000..a8bc465
--- /dev/null
+++ b/chrome/browser/extensions/window_controls_browsertest.cc
@@ -0,0 +1,80 @@
+// 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/extension_process_manager.h"
+#include "chrome/browser/extensions/extension_test_message_listener.h"
+#include "chrome/browser/extensions/platform_app_browsertest_util.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/common/chrome_switches.h"
+#include "content/public/browser/web_contents_view.h"
+#include "content/public/test/browser_test_utils.h"
+
+class WindowControlsTest : public extensions::PlatformAppBrowserTest {
+ protected:
+  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
+    extensions::PlatformAppBrowserTest::SetUpCommandLine(command_line);
+    command_line->AppendSwitch(switches::kEnableAppWindowControls);
+  }
+  content::WebContents* GetWebContentsForExtensionWindow(
+      const extensions::Extension* extension);
+};
+
+content::WebContents* WindowControlsTest::GetWebContentsForExtensionWindow(
+    const extensions::Extension* extension) {
+  ExtensionProcessManager* process_manager =
+      extensions::ExtensionSystem::Get(profile())->process_manager();
+
+  // Lookup render view host for background page.
+  const extensions::ExtensionHost* extension_host =
+      process_manager->GetBackgroundHostForExtension(extension->id());
+  content::RenderViewHost* background_view_host =
+      extension_host->render_view_host();
+
+  // Go through all active views, looking for the first window of the extension
+  const ExtensionProcessManager::ViewSet all_views =
+      process_manager->GetAllViews();
+  ExtensionProcessManager::ViewSet::const_iterator it = all_views.begin();
+  for (; it != all_views.end(); ++it) {
+    content::RenderViewHost* host = *it;
+
+    // Filter out views not part of this extension
+    if (process_manager->GetExtensionForRenderViewHost(host) == extension) {
+      // Filter out the background page view
+      if (host != background_view_host) {
+        content::WebContents* web_contents =
+            content::WebContents::FromRenderViewHost(host);
+        return web_contents;
+      }
+    }
+  }
+  return NULL;
+}
+
+IN_PROC_BROWSER_TEST_F(WindowControlsTest, CloseControlWorks) {
+  // Launch app and wait for window to show up
+  ExtensionTestMessageListener window_opened("window-opened", false);
+  const extensions::Extension* extension =
+      LoadAndLaunchPlatformApp("window_controls/buttons");
+  ASSERT_TRUE(window_opened.WaitUntilSatisfied());
+
+  // Find WebContents of window
+  content::WebContents* web_contents =
+      GetWebContentsForExtensionWindow(extension);
+  ASSERT_TRUE(web_contents != NULL);
+
+  // Send a left click on the "Close" button and wait for the close action
+  // to happen.
+  ExtensionTestMessageListener window_closed("window-closed", false);
+
+  // Send mouse click somewhere inside the [x] button
+  const int controlOffset = 25;
+  int x = web_contents->GetView()->GetContainerSize().width() - controlOffset;
+  int y = controlOffset;
+  content::SimulateMouseClickAt(web_contents,
+                                0,
+                                WebKit::WebMouseEvent::ButtonLeft,
+                                gfx::Point(x, y));
+
+  ASSERT_TRUE(window_closed.WaitUntilSatisfied());
+}
diff --git a/chrome/browser/extensions/window_open_apitest.cc b/chrome/browser/extensions/window_open_apitest.cc
index fe79889..840ff58 100644
--- a/chrome/browser/extensions/window_open_apitest.cc
+++ b/chrome/browser/extensions/window_open_apitest.cc
@@ -107,7 +107,7 @@
 
 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, BrowserIsApp) {
   host_resolver()->AddRule("a.com", "127.0.0.1");
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
   ASSERT_TRUE(LoadExtension(
       test_data_dir_.AppendASCII("window_open").AppendASCII("browser_is_app")));
 
@@ -122,7 +122,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, WindowOpenPopupDefault) {
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
   ASSERT_TRUE(LoadExtension(
       test_data_dir_.AppendASCII("window_open").AppendASCII("popup")));
 
@@ -132,7 +132,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, WindowOpenPopupLarge) {
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
   ASSERT_TRUE(LoadExtension(
       test_data_dir_.AppendASCII("window_open").AppendASCII("popup_large")));
 
@@ -143,7 +143,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, WindowOpenPopupSmall) {
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
   ASSERT_TRUE(LoadExtension(
       test_data_dir_.AppendASCII("window_open").AppendASCII("popup_small")));
 
@@ -162,7 +162,7 @@
 #endif
 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, MAYBE_PopupBlockingExtension) {
   host_resolver()->AddRule("*", "127.0.0.1");
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
 
   ASSERT_TRUE(LoadExtension(
       test_data_dir_.AppendASCII("window_open").AppendASCII("popup_blocking")
@@ -241,10 +241,14 @@
   ASSERT_TRUE(RunExtensionTest("window_open/panel")) << message_;
 }
 
+#if defined(USE_ASH_PANELS)
 // On Ash, this currently fails because we're currently opening new panel
 // windows as popup windows instead.
-// This is also flakey on Windows, ASan and Mac builds: crbug.com/179251
-IN_PROC_BROWSER_TEST_F(WindowOpenPanelTest, DISABLED_WindowOpenPanelDetached) {
+#define MAYBE_WindowOpenPanelDetached DISABLED_WindowOpenPanelDetached
+#else
+#define MAYBE_WindowOpenPanelDetached WindowOpenPanelDetached
+#endif
+IN_PROC_BROWSER_TEST_F(WindowOpenPanelTest, MAYBE_WindowOpenPanelDetached) {
   ASSERT_TRUE(RunExtensionTest("window_open/panel_detached")) << message_;
 }
 
@@ -264,7 +268,7 @@
   int num_popups = 2;
   int num_panels = 2;
 #endif
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
 
   // Setup listeners to wait on strings we expect the extension pages to send.
   std::vector<std::string> test_strings;
@@ -331,7 +335,7 @@
   int num_popups = 2;
   int num_panels = 2;
 #endif
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
 
   // Setup listeners to wait on strings we expect the extension pages to send.
   std::vector<std::string> test_strings;
@@ -381,7 +385,7 @@
 #define MAYBE_WindowOpenFromPanel WindowOpenFromPanel
 #endif
 IN_PROC_BROWSER_TEST_F(WindowOpenPanelTest, MAYBE_WindowOpenFromPanel) {
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
 
   // Load the extension that will open a panel which then calls window.open.
   ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("window_open").
diff --git a/chrome/browser/extensions/window_open_interactive_apitest.cc b/chrome/browser/extensions/window_open_interactive_apitest.cc
index 75384ab..7cf4f66 100644
--- a/chrome/browser/extensions/window_open_interactive_apitest.cc
+++ b/chrome/browser/extensions/window_open_interactive_apitest.cc
@@ -13,7 +13,9 @@
   }
 };
 
-#if defined(OS_MACOSX)  // http://crbug.com/162912 || defined(OS_WIN)
+// http://crbug.com/162912 || defined(OS_WIN)
+// http://crbug.com/253417 for NDEBUG
+#if defined(OS_MACOSX) && defined(NDEBUG)
 // Focus test fails if there is no window manager on Linux.
 IN_PROC_BROWSER_TEST_F(WindowOpenPanelTest, WindowOpenFocus) {
   ASSERT_TRUE(RunExtensionTest("window_open/focus")) << message_;
diff --git a/chrome/browser/external_protocol/external_protocol_handler.cc b/chrome/browser/external_protocol/external_protocol_handler.cc
index 580d261..04d59e8 100644
--- a/chrome/browser/external_protocol/external_protocol_handler.cc
+++ b/chrome/browser/external_protocol/external_protocol_handler.cc
@@ -19,8 +19,8 @@
 #include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/common/pref_names.h"
 #include "content/public/browser/browser_thread.h"
-#include "googleurl/src/gurl.h"
 #include "net/base/escape.h"
+#include "url/gurl.h"
 
 using content::BrowserThread;
 
diff --git a/chrome/browser/favicon/favicon_changed_details.h b/chrome/browser/favicon/favicon_changed_details.h
index 921513a..ec1277c 100644
--- a/chrome/browser/favicon/favicon_changed_details.h
+++ b/chrome/browser/favicon/favicon_changed_details.h
@@ -8,7 +8,7 @@
 #include <set>
 
 #include "chrome/browser/history/history_details.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 // Details for chrome::NOTIFICATION_FAVICON_CHANGED.
 struct FaviconChangedDetails : public history::HistoryDetails {
diff --git a/chrome/browser/favicon/favicon_handler.cc b/chrome/browser/favicon/favicon_handler.cc
index 4771790..881008d 100644
--- a/chrome/browser/favicon/favicon_handler.cc
+++ b/chrome/browser/favicon/favicon_handler.cc
@@ -30,6 +30,10 @@
 
 namespace {
 
+// Size (along each axis) of a touch icon. This currently corresponds to
+// the apple touch icon for iPad.
+const int kTouchIconSize = 72;
+
 // Returns chrome::IconType the given icon_type corresponds to.
 chrome::IconType ToHistoryIconType(FaviconURL::IconType icon_type) {
   switch (icon_type) {
@@ -47,6 +51,25 @@
   return chrome::INVALID_ICON;
 }
 
+// Get the maximal icon size in pixels for a icon of type |icon_type| for the
+// current platform.
+int GetMaximalIconSize(chrome::IconType icon_type) {
+  int base_size = 0;
+  switch (icon_type) {
+    case chrome::FAVICON:
+      base_size = gfx::kFaviconSize;
+      break;
+    case chrome::TOUCH_ICON:
+    case chrome::TOUCH_PRECOMPOSED_ICON:
+      base_size = kTouchIconSize;
+      break;
+    case chrome::INVALID_ICON:
+      base_size = 0;
+      break;
+  }
+  return ui::GetScaleFactorScale(ui::GetMaxScaleFactor()) * base_size;
+}
+
 bool DoUrlAndIconMatch(const FaviconURL& favicon_url,
                        const GURL& url,
                        chrome::IconType icon_type) {
@@ -300,7 +323,10 @@
   if (image.IsEmpty())
     return;
 
-  entry->GetFavicon().image = image;
+  gfx::Image image_with_adjusted_colorspace = image;
+  FaviconUtil::SetFaviconColorSpace(&image_with_adjusted_colorspace);
+
+  entry->GetFavicon().image = image_with_adjusted_colorspace;
   delegate_->NotifyFaviconUpdated(icon_url_changed);
 }
 
@@ -406,12 +432,15 @@
   return NULL;
 }
 
-int FaviconHandler::DownloadFavicon(const GURL& image_url, int image_size) {
+int FaviconHandler::DownloadFavicon(const GURL& image_url,
+                                    int image_size,
+                                    chrome::IconType icon_type) {
   if (!image_url.is_valid()) {
     NOTREACHED();
     return 0;
   }
-  int id = delegate_->StartDownload(image_url, image_size);
+  int id = delegate_->StartDownload(
+      image_url, image_size, GetMaximalIconSize(icon_type));
   return id;
 }
 
@@ -590,7 +619,7 @@
     const GURL& image_url,
     int image_size,
     chrome::IconType icon_type) {
-  const int download_id = DownloadFavicon(image_url, image_size);
+  const int download_id = DownloadFavicon(image_url, image_size, icon_type);
   if (download_id) {
     // Download ids should be unique.
     DCHECK(download_requests_.find(download_id) == download_requests_.end());
diff --git a/chrome/browser/favicon/favicon_handler.h b/chrome/browser/favicon/favicon_handler.h
index 8d23a79..2d62d5b 100644
--- a/chrome/browser/favicon/favicon_handler.h
+++ b/chrome/browser/favicon/favicon_handler.h
@@ -15,9 +15,9 @@
 #include "chrome/common/cancelable_task_tracker.h"
 #include "chrome/common/ref_counted_util.h"
 #include "content/public/common/favicon_url.h"
-#include "googleurl/src/gurl.h"
 #include "ui/gfx/favicon_size.h"
 #include "ui/gfx/image/image.h"
+#include "url/gurl.h"
 
 class FaviconHandlerDelegate;
 class Profile;
@@ -122,7 +122,9 @@
   virtual content::NavigationEntry* GetEntry();
 
   // Asks the render to download favicon, returns the request id.
-  virtual int DownloadFavicon(const GURL& image_url, int image_size);
+  virtual int DownloadFavicon(const GURL& image_url,
+                              int image_size,
+                              chrome::IconType icon_type);
 
   // Ask the favicon from history
   virtual void UpdateFaviconMappingAndFetch(
diff --git a/chrome/browser/favicon/favicon_handler_delegate.h b/chrome/browser/favicon/favicon_handler_delegate.h
index 0fc1749..b7664fd 100644
--- a/chrome/browser/favicon/favicon_handler_delegate.h
+++ b/chrome/browser/favicon/favicon_handler_delegate.h
@@ -23,7 +23,13 @@
   // will call OnDidDownloadFavicon() with the results.
   // Returns the unique id of the download request. The id will be passed
   // in OnDidDownloadFavicon().
-  virtual int StartDownload(const GURL& url, int image_size) = 0;
+  // |preferred_image_size| is used to select the size of the returned image if
+  // the |url| is a multi resolution image.
+  // |max_image_size| is the maximal size of the image. If the image at |url| is
+  // bigger than this, it will be resized. 0 means unlimited.
+  virtual int StartDownload(const GURL& url,
+                            int preferred_image_size,
+                            int max_image_size) = 0;
 
   // Notifies the delegate that the favicon for the active entry was updated.
   // |icon_url_changed| is true if a favicon with a different icon URL has
diff --git a/chrome/browser/favicon/favicon_handler_unittest.cc b/chrome/browser/favicon/favicon_handler_unittest.cc
index 52dbb7a..c74cb86 100644
--- a/chrome/browser/favicon/favicon_handler_unittest.cc
+++ b/chrome/browser/favicon/favicon_handler_unittest.cc
@@ -178,7 +178,9 @@
     return NULL;
   }
 
-  virtual int StartDownload(const GURL& url, int image_size) OVERRIDE {
+  virtual int StartDownload(const GURL& url,
+                            int preferred_image_size,
+                            int max_image_size) OVERRIDE {
     ADD_FAILURE() << "TestFaviconHandlerDelegate::StartDownload() "
                   << "should never be called in tests.";
     return -1;
@@ -270,7 +272,9 @@
                                                      icon_types, callback));
   }
 
-  virtual int DownloadFavicon(const GURL& image_url, int image_size) OVERRIDE {
+  virtual int DownloadFavicon(const GURL& image_url,
+                              int image_size,
+                              chrome::IconType icon_type) OVERRIDE {
     download_id_++;
     download_handler_->AddDownload(download_id_, image_url, image_size);
     return download_id_;
@@ -1056,7 +1060,7 @@
   int download_id = 0;
 
   // Try to download missing icon.
-  download_id = favicon_tab_helper->StartDownload(missing_icon_url, 0);
+  download_id = favicon_tab_helper->StartDownload(missing_icon_url, 0, 0);
   EXPECT_NE(0, download_id);
   EXPECT_FALSE(favicon_service->WasUnableToDownloadFavicon(missing_icon_url));
 
@@ -1067,7 +1071,7 @@
   EXPECT_FALSE(favicon_service->WasUnableToDownloadFavicon(missing_icon_url));
 
   // Try to download again.
-  download_id = favicon_tab_helper->StartDownload(missing_icon_url, 0);
+  download_id = favicon_tab_helper->StartDownload(missing_icon_url, 0, 0);
   EXPECT_NE(0, download_id);
   EXPECT_FALSE(favicon_service->WasUnableToDownloadFavicon(missing_icon_url));
 
@@ -1078,13 +1082,13 @@
   EXPECT_TRUE(favicon_service->WasUnableToDownloadFavicon(missing_icon_url));
 
   // Try to download again.
-  download_id = favicon_tab_helper->StartDownload(missing_icon_url, 0);
+  download_id = favicon_tab_helper->StartDownload(missing_icon_url, 0, 0);
   // Download is not started and Icon is still marked as UnableToDownload.
   EXPECT_EQ(0, download_id);
   EXPECT_TRUE(favicon_service->WasUnableToDownloadFavicon(missing_icon_url));
 
   // Try to download another icon.
-  download_id = favicon_tab_helper->StartDownload(another_icon_url, 0);
+  download_id = favicon_tab_helper->StartDownload(another_icon_url, 0, 0);
   // Download is started as another icon URL is not same as missing_icon_url.
   EXPECT_NE(0, download_id);
   EXPECT_FALSE(favicon_service->WasUnableToDownloadFavicon(another_icon_url));
@@ -1095,7 +1099,7 @@
   EXPECT_FALSE(favicon_service->WasUnableToDownloadFavicon(another_icon_url));
 
   // Try to download again.
-  download_id = favicon_tab_helper->StartDownload(missing_icon_url, 0);
+  download_id = favicon_tab_helper->StartDownload(missing_icon_url, 0, 0);
   EXPECT_NE(0, download_id);
   // Report download success with HTTP 200 status.
   favicon_tab_helper->DidDownloadFavicon(download_id, 200, missing_icon_url,
diff --git a/chrome/browser/favicon/favicon_service.cc b/chrome/browser/favicon/favicon_service.cc
index 37d691a..dc4cab9 100644
--- a/chrome/browser/favicon/favicon_service.cc
+++ b/chrome/browser/favicon/favicon_service.cc
@@ -8,12 +8,12 @@
 #include "base/message_loop/message_loop_proxy.h"
 #include "chrome/browser/favicon/favicon_types.h"
 #include "chrome/browser/favicon/favicon_util.h"
-#include "chrome/browser/favicon/imported_favicon_usage.h"
 #include "chrome/browser/history/history_backend.h"
 #include "chrome/browser/history/history_service.h"
 #include "chrome/browser/history/history_service_factory.h"
 #include "chrome/browser/history/select_favicon_frames.h"
 #include "chrome/browser/ui/webui/chrome_web_ui_controller_factory.h"
+#include "chrome/common/importer/imported_favicon_usage.h"
 #include "chrome/common/url_constants.h"
 #include "extensions/common/constants.h"
 #include "third_party/skia/include/core/SkBitmap.h"
@@ -314,6 +314,8 @@
       favicon_bitmap_results,
       FaviconUtil::GetFaviconScaleFactors(),
       desired_size_in_dip);
+  FaviconUtil::SetFaviconColorSpace(&image_result.image);
+
   image_result.icon_url = image_result.image.IsEmpty() ?
       GURL() : favicon_bitmap_results[0].icon_url;
   callback.Run(image_result);
diff --git a/chrome/browser/favicon/favicon_tab_helper.cc b/chrome/browser/favicon/favicon_tab_helper.cc
index 7be0450..93af404 100644
--- a/chrome/browser/favicon/favicon_tab_helper.cc
+++ b/chrome/browser/favicon/favicon_tab_helper.cc
@@ -134,7 +134,9 @@
   return web_contents()->GetController().GetActiveEntry();
 }
 
-int FaviconTabHelper::StartDownload(const GURL& url, int image_size) {
+int FaviconTabHelper::StartDownload(const GURL& url,
+                                    int preferred_image_size,
+                                    int max_image_size) {
   FaviconService* favicon_service = FaviconServiceFactory::GetForProfile(
       profile_->GetOriginalProfile(), Profile::IMPLICIT_ACCESS);
   if (favicon_service && favicon_service->WasUnableToDownloadFavicon(url)) {
@@ -145,7 +147,8 @@
   return web_contents()->DownloadImage(
       url,
       true,
-      image_size,
+      preferred_image_size,
+      max_image_size,
       base::Bind(&FaviconTabHelper::DidDownloadFavicon,base::Unretained(this)));
 }
 
diff --git a/chrome/browser/favicon/favicon_tab_helper.h b/chrome/browser/favicon/favicon_tab_helper.h
index 6f0f4ad..fad95a8 100644
--- a/chrome/browser/favicon/favicon_tab_helper.h
+++ b/chrome/browser/favicon/favicon_tab_helper.h
@@ -68,7 +68,9 @@
 
   // FaviconHandlerDelegate methods.
   virtual content::NavigationEntry* GetActiveEntry() OVERRIDE;
-  virtual int StartDownload(const GURL& url, int image_size) OVERRIDE;
+  virtual int StartDownload(const GURL& url,
+                            int preferred_image_size,
+                            int max_image_size) OVERRIDE;
   virtual void NotifyFaviconUpdated(bool icon_url_changed) OVERRIDE;
 
   // Favicon download callback.
diff --git a/chrome/browser/favicon/favicon_types.h b/chrome/browser/favicon/favicon_types.h
index f48ec4b..16724e0 100644
--- a/chrome/browser/favicon/favicon_types.h
+++ b/chrome/browser/favicon/favicon_types.h
@@ -6,9 +6,9 @@
 #define CHROME_BROWSER_FAVICON_FAVICON_TYPES_H_
 
 #include "base/memory/ref_counted_memory.h"
-#include "googleurl/src/gurl.h"
 #include "ui/gfx/image/image.h"
 #include "ui/gfx/size.h"
+#include "url/gurl.h"
 
 namespace chrome {
 
diff --git a/chrome/browser/favicon/favicon_util.cc b/chrome/browser/favicon/favicon_util.cc
index df96a47..21c9d75 100644
--- a/chrome/browser/favicon/favicon_util.cc
+++ b/chrome/browser/favicon/favicon_util.cc
@@ -7,14 +7,19 @@
 #include "chrome/browser/favicon/favicon_types.h"
 #include "chrome/browser/history/select_favicon_frames.h"
 #include "content/public/browser/render_view_host.h"
-#include "googleurl/src/gurl.h"
+#include "content/public/child/image_decoder_utils.h"
 #include "skia/ext/image_operations.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/gfx/codec/png_codec.h"
 #include "ui/gfx/favicon_size.h"
 #include "ui/gfx/image/image_png_rep.h"
 #include "ui/gfx/image/image_skia.h"
-#include "webkit/glue/image_decoder.h"
+#include "ui/gfx/size.h"
+#include "url/gurl.h"
+
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+#include "base/mac/mac_util.h"
+#endif  // defined(OS_MACOSX) && !defined(OS_IOS)
 
 namespace {
 
@@ -105,6 +110,13 @@
 }
 
 // static
+void FaviconUtil::SetFaviconColorSpace(gfx::Image* image) {
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+  image->SetSourceColorSpace(base::mac::GetSystemColorSpace());
+#endif  // defined(OS_MACOSX) && !defined(OS_IOS)
+}
+
+// static
 gfx::Image FaviconUtil::SelectFaviconFramesFromPNGs(
       const std::vector<chrome::FaviconBitmapResult>& png_data,
       const std::vector<ui::ScaleFactor>& scale_factors,
@@ -194,9 +206,10 @@
                                   size_t src_len,
                                   std::vector<unsigned char>* png_data) {
   // Decode the favicon using WebKit's image decoder.
-  webkit_glue::ImageDecoder decoder(
-      gfx::Size(gfx::kFaviconSize, gfx::kFaviconSize));
-  SkBitmap decoded = decoder.Decode(src_data, src_len);
+  SkBitmap decoded = content::DecodeImage(
+      src_data,
+      gfx::Size(gfx::kFaviconSize, gfx::kFaviconSize),
+      src_len);
   if (decoded.empty())
     return false;  // Unable to decode.
 
diff --git a/chrome/browser/favicon/favicon_util.h b/chrome/browser/favicon/favicon_util.h
index 32dc6e0..89474e9 100644
--- a/chrome/browser/favicon/favicon_util.h
+++ b/chrome/browser/favicon/favicon_util.h
@@ -34,6 +34,11 @@
   // the default favicon.
   static std::vector<ui::ScaleFactor> GetFaviconScaleFactors();
 
+  // Sets the color space used for converting |image| to an NSImage to the
+  // system colorspace. This makes the favicon look the same in the browser UI
+  // as it does in the renderer.
+  static void SetFaviconColorSpace(gfx::Image* image);
+
   // Takes a vector of png-encoded frames, decodes them, and converts them to
   // a favicon of size favicon_size (in DIPs) at the desired ui scale factors.
   static gfx::Image SelectFaviconFramesFromPNGs(
diff --git a/chrome/browser/favicon/imported_favicon_usage.cc b/chrome/browser/favicon/imported_favicon_usage.cc
deleted file mode 100644
index 42da286..0000000
--- a/chrome/browser/favicon/imported_favicon_usage.cc
+++ /dev/null
@@ -1,11 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/favicon/imported_favicon_usage.h"
-
-ImportedFaviconUsage::ImportedFaviconUsage() {
-}
-
-ImportedFaviconUsage::~ImportedFaviconUsage() {
-}
diff --git a/chrome/browser/favicon/imported_favicon_usage.h b/chrome/browser/favicon/imported_favicon_usage.h
deleted file mode 100644
index ec7957d..0000000
--- a/chrome/browser/favicon/imported_favicon_usage.h
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_FAVICON_IMPORTED_FAVICON_USAGE_H_
-#define CHROME_BROWSER_FAVICON_IMPORTED_FAVICON_USAGE_H_
-
-#include <set>
-#include <vector>
-
-#include "googleurl/src/gurl.h"
-
-// Used to correlate favicons to imported bookmarks.
-struct ImportedFaviconUsage {
-  ImportedFaviconUsage();
-  ~ImportedFaviconUsage();
-
-  // The URL of the favicon.
-  GURL favicon_url;
-
-  // The raw png-encoded data.
-  std::vector<unsigned char> png_data;
-
-  // The list of URLs using this favicon.
-  std::set<GURL> urls;
-};
-
-#endif  // CHROME_BROWSER_FAVICON_IMPORTED_FAVICON_USAGE_H_
diff --git a/chrome/browser/feedback/feedback_data.h b/chrome/browser/feedback/feedback_data.h
index 14217cc..111721b 100644
--- a/chrome/browser/feedback/feedback_data.h
+++ b/chrome/browser/feedback/feedback_data.h
@@ -10,7 +10,7 @@
 
 #include "base/memory/ref_counted.h"
 #include "chrome/browser/ui/webui/screenshot_source.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 #if defined(OS_CHROMEOS)
 #include "chrome/browser/chromeos/system_logs/system_logs_fetcher.h"
diff --git a/chrome/browser/feedback/feedback_util.cc b/chrome/browser/feedback/feedback_util.cc
index 2ed8930..c16691c 100644
--- a/chrome/browser/feedback/feedback_util.cc
+++ b/chrome/browser/feedback/feedback_util.cc
@@ -28,7 +28,6 @@
 #include "content/public/browser/navigation_controller.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/content_client.h"
-#include "googleurl/src/gurl.h"
 #include "grit/generated_resources.h"
 #include "grit/locale_settings.h"
 #include "grit/theme_resources.h"
@@ -39,6 +38,7 @@
 #include "net/url_request/url_request_status.h"
 #include "third_party/icu/public/common/unicode/locid.h"
 #include "ui/base/l10n/l10n_util.h"
+#include "url/gurl.h"
 
 using content::WebContents;
 
diff --git a/chrome/browser/first_run/first_run.cc b/chrome/browser/first_run/first_run.cc
index a6c9080..4216528 100644
--- a/chrome/browser/first_run/first_run.cc
+++ b/chrome/browser/first_run/first_run.cc
@@ -23,10 +23,9 @@
 #include "chrome/browser/first_run/first_run_internal.h"
 #include "chrome/browser/google/google_util.h"
 #include "chrome/browser/importer/external_process_importer_host.h"
-#include "chrome/browser/importer/importer_host.h"
+#include "chrome/browser/importer/importer_creator.h"
 #include "chrome/browser/importer/importer_list.h"
 #include "chrome/browser/importer/importer_progress_observer.h"
-#include "chrome/browser/importer/importer_type.h"
 #include "chrome/browser/importer/profile_writer.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/search_engines/template_url_service.h"
@@ -39,9 +38,9 @@
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/global_error/global_error_service.h"
 #include "chrome/browser/ui/global_error/global_error_service_factory.h"
+#include "chrome/browser/ui/sync/sync_promo_ui.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/webui/ntp/new_tab_ui.h"
-#include "chrome/browser/ui/webui/sync_promo/sync_promo_ui.h"
 #include "chrome/common/chrome_notification_types.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/chrome_switches.h"
@@ -56,7 +55,7 @@
 #include "content/public/browser/user_metrics.h"
 #include "content/public/browser/web_contents.h"
 #include "google_apis/gaia/gaia_auth_util.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 using content::UserMetricsAction;
 
@@ -231,12 +230,12 @@
 // |target_profile| for the items specified in the |items_to_import| bitfield.
 // This may be done in a separate process depending on the platform, but it will
 // always block until done.
-void ImportFromSourceProfile(ImporterHost* importer_host,
+void ImportFromSourceProfile(ExternalProcessImporterHost* importer_host,
                              const importer::SourceProfile& source_profile,
                              Profile* target_profile,
                              uint16 items_to_import) {
   ImportEndedObserver observer;
-  importer_host->SetObserver(&observer);
+  importer_host->set_observer(&observer);
   importer_host->StartImportSettings(source_profile,
                                      target_profile,
                                      items_to_import,
@@ -251,7 +250,7 @@
 // Imports bookmarks from an html file whose path is provided by
 // |import_bookmarks_path|.
 void ImportFromFile(Profile* profile,
-                    ImporterHost* file_importer_host,
+                    ExternalProcessImporterHost* file_importer_host,
                     const std::string& import_bookmarks_path) {
   importer::SourceProfile source_profile;
   source_profile.importer_type = importer::TYPE_BOOKMARKS_FILE;
@@ -271,7 +270,7 @@
 
 // Imports settings from the first profile in |importer_list|.
 void ImportSettings(Profile* profile,
-                    ImporterHost* importer_host,
+                    ExternalProcessImporterHost* importer_host,
                     scoped_refptr<ImporterList> importer_list,
                     int items_to_import) {
   const importer::SourceProfile& source_profile =
@@ -453,9 +452,6 @@
 #endif
 
 }  // namespace internal
-}  // namespace first_run
-
-namespace first_run {
 
 MasterPrefs::MasterPrefs()
     : ping_delay(0),
@@ -506,7 +502,7 @@
   base::FilePath first_run_sentinel;
   if (!internal::GetFirstRunSentinelFilePath(&first_run_sentinel))
     return false;
-  return file_util::Delete(first_run_sentinel, false);
+  return base::Delete(first_run_sentinel, false);
 }
 
 bool SetShowFirstRunBubblePref(FirstRunBubbleOptions show_bubble_option) {
@@ -676,24 +672,16 @@
     int import_items,
     int dont_import_items,
     const std::string& import_bookmarks_path) {
-#if !defined(USE_AURA)
   // Deletes itself.
-  ImporterHost* importer_host;
-  // TODO(csilv,mirandac): Out-of-process import has only been qualified on
-  // MacOS X and Windows, so we will only use it on those platforms.
-  // Linux still uses the in-process import (http://crbug.com/56816).
-#if defined(OS_MACOSX) || defined(OS_WIN)
-  importer_host = new ExternalProcessImporterHost;
-#else
-  importer_host = new ImporterHost;
-#endif
+  ExternalProcessImporterHost* importer_host = new ExternalProcessImporterHost;
 
   base::FilePath local_state_path;
   PathService::Get(chrome::FILE_LOCAL_STATE, &local_state_path);
   bool local_state_file_exists = file_util::PathExists(local_state_path);
 
-  scoped_refptr<ImporterList> importer_list(new ImporterList(NULL));
-  importer_list->DetectSourceProfilesHack();
+  scoped_refptr<ImporterList> importer_list(new ImporterList());
+  importer_list->DetectSourceProfilesHack(
+      g_browser_process->GetApplicationLocale());
 
   // Do import if there is an available profile for us to import.
   if (importer_list->count() > 0) {
@@ -753,14 +741,8 @@
 
   if (!import_bookmarks_path.empty()) {
     // Deletes itself.
-    ImporterHost* file_importer_host;
-    // TODO(gab): Make Linux use OOP import as well (http://crbug.com/56816) and
-    // get rid of these ugly ifdefs.
-#if defined(OS_MACOSX) || defined(OS_WIN)
-    file_importer_host = new ExternalProcessImporterHost;
-#else
-    file_importer_host = new ImporterHost;
-#endif
+    ExternalProcessImporterHost* file_importer_host =
+        new ExternalProcessImporterHost;
     file_importer_host->set_headless();
 
     ImportFromFile(profile, file_importer_host, import_bookmarks_path);
@@ -768,7 +750,6 @@
 
   content::RecordAction(UserMetricsAction("FirstRunDef_Accept"));
 
-#endif  // !defined(USE_AURA)
   g_auto_import_state |= AUTO_IMPORT_CALLED;
 }
 
diff --git a/chrome/browser/first_run/first_run_browsertest.cc b/chrome/browser/first_run/first_run_browsertest.cc
index 6f1cf93..437f691 100644
--- a/chrome/browser/first_run/first_run_browsertest.cc
+++ b/chrome/browser/first_run/first_run_browsertest.cc
@@ -4,12 +4,14 @@
 
 #include "base/command_line.h"
 #include "base/files/file_path.h"
+#include "base/memory/ref_counted.h"
 #include "base/prefs/pref_service.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/extensions/component_loader.h"
 #include "chrome/browser/first_run/first_run.h"
+#include "chrome/browser/importer/importer_list.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
@@ -91,7 +93,7 @@
   }
 
   virtual void TearDown() OVERRIDE {
-    EXPECT_TRUE(file_util::Delete(prefs_file_, false));
+    EXPECT_TRUE(base::Delete(prefs_file_, false));
     InProcessBrowserTest::TearDown();
   }
 
@@ -130,45 +132,40 @@
   DISALLOW_COPY_AND_ASSIGN(FirstRunMasterPrefsBrowserTestT);
 };
 
-}  // namespace
-
-// TODO(tapted): Investigate why this fails on Linux bots but does not
-// reproduce locally. See http://crbug.com/178062 .
-// TODO(tapted): Investigate why this fails on mac_asan flakily
-// http://crbug.com/181499 .
-#if defined(OS_LINUX) || (defined(OS_MACOSX) && defined(ADDRESS_SANITIZER))
-#define MAYBE_ImportDefault DISABLED_ImportDefault
-#else
-#define MAYBE_ImportDefault ImportDefault
+// Returns the true expected import state, derived from the original
+// |expected_import_state|, for the current test machine's configuration. Some
+// bot configurations do not have another profile (browser) to import from and
+// thus the import must not be expected to have occurred.
+int MaskExpectedImportState(int expected_import_state) {
+  scoped_refptr<ImporterList> importer_list(new ImporterList());
+  importer_list->DetectSourceProfilesHack(
+      g_browser_process->GetApplicationLocale());
+  int source_profile_count = importer_list->count();
+#if defined(OS_WIN)
+  // On Windows, the importer's DetectIEProfiles() will always add to the count.
+  // Internet Explorer always exists and always has something to import.
+  EXPECT_GT(source_profile_count, 0);
 #endif
+  if (source_profile_count == 0)
+    return expected_import_state & ~first_run::AUTO_IMPORT_PROFILE_IMPORTED;
+
+  return expected_import_state;
+}
+
+}  // namespace
 
 extern const char kImportDefault[] =
     "{\n"
     "}\n";
 typedef FirstRunMasterPrefsBrowserTestT<kImportDefault>
     FirstRunMasterPrefsImportDefault;
-IN_PROC_BROWSER_TEST_F(FirstRunMasterPrefsImportDefault, MAYBE_ImportDefault) {
+IN_PROC_BROWSER_TEST_F(FirstRunMasterPrefsImportDefault, ImportDefault) {
   int auto_import_state = first_run::auto_import_state();
-  // Aura builds skip over the import process.
-#if defined(USE_AURA)
-  EXPECT_EQ(first_run::AUTO_IMPORT_CALLED, auto_import_state);
-#else
-  EXPECT_EQ(first_run::AUTO_IMPORT_CALLED |
-                first_run::AUTO_IMPORT_PROFILE_IMPORTED,
+  EXPECT_EQ(MaskExpectedImportState(first_run::AUTO_IMPORT_CALLED |
+                                    first_run::AUTO_IMPORT_PROFILE_IMPORTED),
             auto_import_state);
-#endif
 }
 
-// TODO(tapted): Investigate why this fails on Linux bots but does not
-// reproduce locally. See http://crbug.com/178062 .
-// TODO(tapted): Investigate why this fails on mac_asan flakily
-// http://crbug.com/181499 .
-#if defined(OS_LINUX) || (defined(OS_MACOSX) && defined(ADDRESS_SANITIZER))
-#define MAYBE_ImportBookmarksFile DISABLED_ImportBookmarksFile
-#else
-#define MAYBE_ImportBookmarksFile ImportBookmarksFile
-#endif
-
 // The bookmarks file doesn't actually need to exist for this integration test
 // to trigger the interaction being tested.
 extern const char kImportBookmarksFile[] =
@@ -180,17 +177,13 @@
 typedef FirstRunMasterPrefsBrowserTestT<kImportBookmarksFile>
     FirstRunMasterPrefsImportBookmarksFile;
 IN_PROC_BROWSER_TEST_F(FirstRunMasterPrefsImportBookmarksFile,
-                       MAYBE_ImportBookmarksFile) {
+                       ImportBookmarksFile) {
   int auto_import_state = first_run::auto_import_state();
-  // Aura builds skip over the import process.
-#if defined(USE_AURA)
-  EXPECT_EQ(first_run::AUTO_IMPORT_CALLED, auto_import_state);
-#else
-  EXPECT_EQ(first_run::AUTO_IMPORT_CALLED |
-                first_run::AUTO_IMPORT_PROFILE_IMPORTED |
-                first_run::AUTO_IMPORT_BOOKMARKS_FILE_IMPORTED,
-            auto_import_state);
-#endif
+  EXPECT_EQ(
+      MaskExpectedImportState(first_run::AUTO_IMPORT_CALLED |
+                              first_run::AUTO_IMPORT_PROFILE_IMPORTED |
+                              first_run::AUTO_IMPORT_BOOKMARKS_FILE_IMPORTED),
+      auto_import_state);
 }
 
 // Test an import with all import options disabled. This is a regression test
diff --git a/chrome/browser/first_run/first_run_internal.h b/chrome/browser/first_run/first_run_internal.h
index ae6f152..eec3cf8 100644
--- a/chrome/browser/first_run/first_run_internal.h
+++ b/chrome/browser/first_run/first_run_internal.h
@@ -5,21 +5,8 @@
 #ifndef CHROME_BROWSER_FIRST_RUN_FIRST_RUN_INTERNAL_H_
 #define CHROME_BROWSER_FIRST_RUN_FIRST_RUN_INTERNAL_H_
 
-#include <vector>
-
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "base/gtest_prod_util.h"
-#include "base/memory/ref_counted.h"
-#include "ui/gfx/native_widget_types.h"
-
-class CommandLine;
-class GURL;
-class ImporterHost;
-class ImporterList;
+class MasterPrefs;
 class Profile;
-class ProcessSingleton;
-class TemplateURLService;
 
 namespace base {
 class FilePath;
diff --git a/chrome/browser/first_run/first_run_internal_linux.cc b/chrome/browser/first_run/first_run_internal_linux.cc
new file mode 100644
index 0000000..f2441e2
--- /dev/null
+++ b/chrome/browser/first_run/first_run_internal_linux.cc
@@ -0,0 +1,29 @@
+// 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/first_run/first_run_internal.h"
+
+#include "base/base_paths.h"
+#include "base/files/file_path.h"
+#include "base/path_service.h"
+#include "chrome/installer/util/master_preferences.h"
+
+namespace first_run {
+namespace internal {
+
+bool IsOrganicFirstRun() {
+  // We treat all installs as organic.
+  return true;
+}
+
+base::FilePath MasterPrefsPath() {
+  // The standard location of the master prefs is next to the chrome binary.
+  base::FilePath master_prefs;
+  if (!PathService::Get(base::DIR_EXE, &master_prefs))
+    return base::FilePath();
+  return master_prefs.AppendASCII(installer::kDefaultMasterPrefs);
+}
+
+}  // namespace internal
+}  // namespace first_run
diff --git a/chrome/browser/first_run/first_run_internal_mac.mm b/chrome/browser/first_run/first_run_internal_mac.mm
new file mode 100644
index 0000000..38efc78
--- /dev/null
+++ b/chrome/browser/first_run/first_run_internal_mac.mm
@@ -0,0 +1,17 @@
+// 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/first_run/first_run_internal.h"
+
+#include "chrome/browser/mac/master_prefs.h"
+
+namespace first_run {
+namespace internal {
+
+base::FilePath MasterPrefsPath() {
+  return master_prefs::MasterPrefsPath();
+}
+
+}  // namespace internal
+}  // namespace first_run
diff --git a/chrome/browser/first_run/first_run_internal_posix.cc b/chrome/browser/first_run/first_run_internal_posix.cc
new file mode 100644
index 0000000..ce26df8
--- /dev/null
+++ b/chrome/browser/first_run/first_run_internal_posix.cc
@@ -0,0 +1,66 @@
+// 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/first_run/first_run_internal.h"
+
+#include "base/file_util.h"
+#include "base/files/file_path.h"
+#include "base/path_service.h"
+#include "base/prefs/pref_service.h"
+#include "build/build_config.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/first_run/first_run_dialog.h"
+#include "chrome/common/chrome_constants.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/common/startup_metric_utils.h"
+#include "chrome/installer/util/google_update_settings.h"
+#include "chrome/installer/util/master_preferences.h"
+
+namespace first_run {
+namespace internal {
+
+void DoPostImportPlatformSpecificTasks(Profile* profile) {
+#if !defined(OS_CHROMEOS)
+  // Aura needs a views implementation of the first run dialog for Linux.
+  // http://crbug.com/234637
+#if !defined(USE_AURA)
+  base::FilePath local_state_path;
+  PathService::Get(chrome::FILE_LOCAL_STATE, &local_state_path);
+  bool local_state_file_exists = file_util::PathExists(local_state_path);
+  // Launch the first run dialog only for certain builds, and only if the user
+  // has not already set preferences.
+  if (internal::IsOrganicFirstRun() && !local_state_file_exists) {
+    if (ShowFirstRunDialog(profile))
+      startup_metric_utils::SetNonBrowserUIDisplayed();
+  }
+#endif
+
+  // If stats reporting was turned on by the first run dialog then toggle
+  // the pref (on Windows, the download is tagged with enable/disable stats so
+  // this is POSIX-specific).
+  if (GoogleUpdateSettings::GetCollectStatsConsent()) {
+    g_browser_process->local_state()->SetBoolean(
+        prefs::kMetricsReportingEnabled, true);
+  }
+#endif
+}
+
+bool GetFirstRunSentinelFilePath(base::FilePath* path) {
+  base::FilePath first_run_sentinel;
+
+  if (!PathService::Get(chrome::DIR_USER_DATA, &first_run_sentinel))
+    return false;
+
+  *path = first_run_sentinel.Append(chrome::kFirstRunSentinel);
+  return true;
+}
+
+bool ShowPostInstallEULAIfNeeded(installer::MasterPreferences* install_prefs) {
+  // The EULA is only handled on Windows.
+  return true;
+}
+
+}  // namespace internal
+}  // namespace first_run
diff --git a/chrome/browser/first_run/first_run_internal_win.cc b/chrome/browser/first_run/first_run_internal_win.cc
new file mode 100644
index 0000000..6004248
--- /dev/null
+++ b/chrome/browser/first_run/first_run_internal_win.cc
@@ -0,0 +1,217 @@
+// 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/first_run/first_run_internal.h"
+
+#include <windows.h>
+#include <shellapi.h>
+
+#include "base/base_paths.h"
+#include "base/callback.h"
+#include "base/file_util.h"
+#include "base/files/file_path.h"
+#include "base/path_service.h"
+#include "base/prefs/pref_service.h"
+#include "base/process.h"
+#include "base/process_util.h"
+#include "base/threading/sequenced_worker_pool.h"
+#include "base/time/time.h"
+#include "base/win/metro.h"
+#include "chrome/common/chrome_constants.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/installer/util/google_update_settings.h"
+#include "chrome/installer/util/install_util.h"
+#include "chrome/installer/util/master_preferences.h"
+#include "chrome/installer/util/master_preferences_constants.h"
+#include "chrome/installer/util/util_constants.h"
+#include "content/public/browser/browser_thread.h"
+#include "google_update/google_update_idl.h"
+#include "grit/locale_settings.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/win/shell.h"
+
+namespace {
+
+// Launches the setup exe with the given parameter/value on the command-line.
+// For non-metro Windows, it waits for its termination, returns its exit code
+// in |*ret_code|, and returns true if the exit code is valid.
+// For metro Windows, it launches setup via ShellExecuteEx and returns in order
+// to bounce the user back to the desktop, then returns immediately.
+bool LaunchSetupForEula(const base::FilePath::StringType& value,
+                        int* ret_code) {
+  base::FilePath exe_dir;
+  if (!PathService::Get(base::DIR_MODULE, &exe_dir))
+    return false;
+  exe_dir = exe_dir.Append(installer::kInstallerDir);
+  base::FilePath exe_path = exe_dir.Append(installer::kSetupExe);
+  base::ProcessHandle ph;
+
+  CommandLine cl(CommandLine::NO_PROGRAM);
+  cl.AppendSwitchNative(installer::switches::kShowEula, value);
+
+  CommandLine* browser_command_line = CommandLine::ForCurrentProcess();
+  if (browser_command_line->HasSwitch(switches::kChromeFrame)) {
+    cl.AppendSwitch(switches::kChromeFrame);
+  }
+
+  if (base::win::IsMetroProcess()) {
+    cl.AppendSwitch(installer::switches::kShowEulaForMetro);
+
+    // This obscure use of the 'log usage' mask for windows 8 is documented here
+    // http://go.microsoft.com/fwlink/?LinkID=243079. It causes the desktop
+    // process to receive focus. Pass SEE_MASK_FLAG_NO_UI to avoid hangs if an
+    // error occurs since the UI can't be shown from a metro process.
+    ui::win::OpenAnyViaShell(exe_path.value(),
+                             exe_dir.value(),
+                             cl.GetCommandLineString(),
+                             SEE_MASK_FLAG_LOG_USAGE | SEE_MASK_FLAG_NO_UI);
+    return false;
+  } else {
+    base::LaunchOptions launch_options;
+    launch_options.wait = true;
+    CommandLine setup_path(exe_path);
+    setup_path.AppendArguments(cl, false);
+
+    DWORD exit_code = 0;
+    if (!base::LaunchProcess(setup_path, launch_options, &ph) ||
+        !::GetExitCodeProcess(ph, &exit_code)) {
+      return false;
+    }
+
+    *ret_code = exit_code;
+    return true;
+  }
+}
+
+// Populates |path| with the path to |file| in the sentinel directory. This is
+// the application directory for user-level installs, and the default user data
+// dir for system-level installs. Returns false on error.
+bool GetSentinelFilePath(const wchar_t* file, base::FilePath* path) {
+  base::FilePath exe_path;
+  if (!PathService::Get(base::DIR_EXE, &exe_path))
+    return false;
+  if (InstallUtil::IsPerUserInstall(exe_path.value().c_str()))
+    *path = exe_path;
+  else if (!PathService::Get(chrome::DIR_USER_DATA, path))
+    return false;
+  *path = path->Append(file);
+  return true;
+}
+
+bool GetEULASentinelFilePath(base::FilePath* path) {
+  return GetSentinelFilePath(installer::kEULASentinelFile, path);
+}
+
+// Returns true if the EULA is required but has not been accepted by this user.
+// The EULA is considered having been accepted if the user has gotten past
+// first run in the "other" environment (desktop or metro).
+bool IsEULANotAccepted(installer::MasterPreferences* install_prefs) {
+  bool value = false;
+  if (install_prefs->GetBool(installer::master_preferences::kRequireEula,
+          &value) && value) {
+    base::FilePath eula_sentinel;
+    // Be conservative and show the EULA if the path to the sentinel can't be
+    // determined.
+    if (!GetEULASentinelFilePath(&eula_sentinel) ||
+        !file_util::PathExists(eula_sentinel)) {
+      return true;
+    }
+  }
+  return false;
+}
+
+// Writes the EULA to a temporary file, returned in |*eula_path|, and returns
+// true if successful.
+bool WriteEULAtoTempFile(base::FilePath* eula_path) {
+  std::string terms = l10n_util::GetStringUTF8(IDS_TERMS_HTML);
+  if (terms.empty())
+    return false;
+  FILE *file = file_util::CreateAndOpenTemporaryFile(eula_path);
+  if (!file)
+    return false;
+  bool good = fwrite(terms.data(), terms.size(), 1, file) == 1;
+  fclose(file);
+  return good;
+}
+
+// Creates the sentinel indicating that the EULA was required and has been
+// accepted.
+bool CreateEULASentinel() {
+  base::FilePath eula_sentinel;
+  if (!GetEULASentinelFilePath(&eula_sentinel))
+    return false;
+
+  return (file_util::CreateDirectory(eula_sentinel.DirName()) &&
+          file_util::WriteFile(eula_sentinel, "", 0) != -1);
+}
+
+}  // namespace
+
+namespace first_run {
+namespace internal {
+
+void DoPostImportPlatformSpecificTasks(Profile* /* profile */) {
+  // Trigger the Active Setup command for system-level Chromes to finish
+  // configuring this user's install (e.g. per-user shortcuts).
+  // Delay the task slightly to give Chrome launch I/O priority while also
+  // making sure shortcuts are created promptly to avoid annoying the user by
+  // re-creating shortcuts he previously deleted.
+  static const int64 kTiggerActiveSetupDelaySeconds = 5;
+  base::FilePath chrome_exe;
+  if (!PathService::Get(base::FILE_EXE, &chrome_exe)) {
+    NOTREACHED();
+  } else if (!InstallUtil::IsPerUserInstall(chrome_exe.value().c_str())) {
+    content::BrowserThread::GetBlockingPool()->PostDelayedTask(
+        FROM_HERE,
+        base::Bind(&InstallUtil::TriggerActiveSetupCommand),
+        base::TimeDelta::FromSeconds(kTiggerActiveSetupDelaySeconds));
+  }
+}
+
+bool GetFirstRunSentinelFilePath(base::FilePath* path) {
+  return GetSentinelFilePath(chrome::kFirstRunSentinel, path);
+}
+
+bool ShowPostInstallEULAIfNeeded(installer::MasterPreferences* install_prefs) {
+  if (IsEULANotAccepted(install_prefs)) {
+    // Show the post-installation EULA. This is done by setup.exe and the
+    // result determines if we continue or not. We wait here until the user
+    // dismisses the dialog.
+
+    // The actual eula text is in a resource in chrome. We extract it to
+    // a text file so setup.exe can use it as an inner frame.
+    base::FilePath inner_html;
+    if (WriteEULAtoTempFile(&inner_html)) {
+      int retcode = 0;
+      if (!LaunchSetupForEula(inner_html.value(), &retcode) ||
+          (retcode != installer::EULA_ACCEPTED &&
+           retcode != installer::EULA_ACCEPTED_OPT_IN)) {
+        LOG(WARNING) << "EULA flow requires fast exit.";
+        return false;
+      }
+      CreateEULASentinel();
+
+      if (retcode == installer::EULA_ACCEPTED) {
+        VLOG(1) << "EULA : no collection";
+        GoogleUpdateSettings::SetCollectStatsConsent(false);
+      } else if (retcode == installer::EULA_ACCEPTED_OPT_IN) {
+        VLOG(1) << "EULA : collection consent";
+        GoogleUpdateSettings::SetCollectStatsConsent(true);
+      }
+    }
+  }
+  return true;
+}
+
+base::FilePath MasterPrefsPath() {
+  // The standard location of the master prefs is next to the chrome binary.
+  base::FilePath master_prefs;
+  if (!PathService::Get(base::DIR_EXE, &master_prefs))
+    return base::FilePath();
+  return master_prefs.AppendASCII(installer::kDefaultMasterPrefs);
+}
+
+}  // namespace internal
+}  // namespace first_run
diff --git a/chrome/browser/first_run/first_run_linux.cc b/chrome/browser/first_run/first_run_linux.cc
deleted file mode 100644
index 4d4d084..0000000
--- a/chrome/browser/first_run/first_run_linux.cc
+++ /dev/null
@@ -1,43 +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/first_run/first_run.h"
-
-#include "base/command_line.h"
-#include "base/files/file_path.h"
-#include "base/path_service.h"
-#include "base/process_util.h"
-#include "base/strings/string_piece.h"
-#include "base/strings/string_util.h"
-#include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/first_run/first_run_internal.h"
-#include "chrome/browser/importer/importer_host.h"
-#include "chrome/browser/process_singleton.h"
-#include "chrome/browser/shell_integration.h"
-#include "chrome/common/chrome_switches.h"
-#include "chrome/installer/util/google_update_settings.h"
-#include "chrome/installer/util/master_preferences.h"
-#include "content/public/common/result_codes.h"
-#include "googleurl/src/gurl.h"
-#include "ui/base/ui_base_switches.h"
-
-namespace first_run {
-namespace internal {
-
-bool IsOrganicFirstRun() {
-  // We treat all installs as organic.
-  return true;
-}
-
-base::FilePath MasterPrefsPath() {
-  // The standard location of the master prefs is next to the chrome binary.
-  base::FilePath master_prefs;
-  if (!PathService::Get(base::DIR_EXE, &master_prefs))
-    return base::FilePath();
-  return master_prefs.AppendASCII(installer::kDefaultMasterPrefs);
-}
-
-}  // namespace internal
-}  // namespace first_run
diff --git a/chrome/browser/first_run/first_run_mac.mm b/chrome/browser/first_run/first_run_mac.mm
deleted file mode 100644
index 85a43d2..0000000
--- a/chrome/browser/first_run/first_run_mac.mm
+++ /dev/null
@@ -1,23 +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/first_run/first_run.h"
-
-#include "base/files/file_path.h"
-#include "base/strings/string_util.h"
-#include "chrome/browser/first_run/first_run_internal.h"
-#include "chrome/browser/importer/external_process_importer_host.h"
-#include "chrome/browser/importer/importer_host.h"
-#include "chrome/browser/mac/master_prefs.h"
-#include "chrome/browser/process_singleton.h"
-
-namespace first_run {
-namespace internal {
-
-base::FilePath MasterPrefsPath() {
-  return master_prefs::MasterPrefsPath();
-}
-
-}  // namespace internal
-}  // namespace first_run
diff --git a/chrome/browser/first_run/first_run_posix.cc b/chrome/browser/first_run/first_run_posix.cc
deleted file mode 100644
index 7498a90..0000000
--- a/chrome/browser/first_run/first_run_posix.cc
+++ /dev/null
@@ -1,67 +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/first_run/first_run.h"
-
-#include "base/file_util.h"
-#include "base/files/file_path.h"
-#include "base/path_service.h"
-#include "base/prefs/pref_service.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/first_run/first_run_dialog.h"
-#include "chrome/browser/first_run/first_run_internal.h"
-#include "chrome/browser/profiles/profile_manager.h"
-#include "chrome/common/chrome_constants.h"
-#include "chrome/common/chrome_paths.h"
-#include "chrome/common/pref_names.h"
-#include "chrome/common/startup_metric_utils.h"
-#include "chrome/installer/util/google_update_settings.h"
-#include "chrome/installer/util/master_preferences.h"
-
-namespace first_run {
-namespace internal {
-
-void DoPostImportPlatformSpecificTasks(Profile* profile) {
-#if !defined(OS_CHROMEOS)
-  // Aura needs a views implementation of the first run dialog for Linux.
-  // http://crbug.com/234637
-#if !defined(USE_AURA)
-  base::FilePath local_state_path;
-  PathService::Get(chrome::FILE_LOCAL_STATE, &local_state_path);
-  bool local_state_file_exists = file_util::PathExists(local_state_path);
-  // Launch the first run dialog only for certain builds, and only if the user
-  // has not already set preferences.
-  if (internal::IsOrganicFirstRun() && !local_state_file_exists) {
-    if (ShowFirstRunDialog(profile))
-      startup_metric_utils::SetNonBrowserUIDisplayed();
-  }
-#endif
-
-  // If stats reporting was turned on by the first run dialog then toggle
-  // the pref (on Windows, the download is tagged with enable/disable stats so
-  // this is POSIX-specific).
-  if (GoogleUpdateSettings::GetCollectStatsConsent()) {
-    g_browser_process->local_state()->SetBoolean(
-        prefs::kMetricsReportingEnabled, true);
-  }
-#endif
-}
-
-bool GetFirstRunSentinelFilePath(base::FilePath* path) {
-  base::FilePath first_run_sentinel;
-
-  if (!PathService::Get(chrome::DIR_USER_DATA, &first_run_sentinel))
-    return false;
-
-  *path = first_run_sentinel.Append(chrome::kFirstRunSentinel);
-  return true;
-}
-
-bool ShowPostInstallEULAIfNeeded(installer::MasterPreferences* install_prefs) {
-  // The EULA is only handled on Windows.
-  return true;
-}
-
-}  // namespace internal
-}  // namespace first_run
diff --git a/chrome/browser/first_run/first_run_win.cc b/chrome/browser/first_run/first_run_win.cc
deleted file mode 100644
index 7aa0e5d..0000000
--- a/chrome/browser/first_run/first_run_win.cc
+++ /dev/null
@@ -1,217 +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/first_run/first_run.h"
-
-#include <shellapi.h>
-
-#include "base/base_paths.h"
-#include "base/callback.h"
-#include "base/file_util.h"
-#include "base/files/file_path.h"
-#include "base/path_service.h"
-#include "base/prefs/pref_service.h"
-#include "base/process.h"
-#include "base/process_util.h"
-#include "base/threading/sequenced_worker_pool.h"
-#include "base/time.h"
-#include "base/win/metro.h"
-#include "chrome/browser/first_run/first_run_internal.h"
-#include "chrome/common/chrome_constants.h"
-#include "chrome/common/chrome_paths.h"
-#include "chrome/common/chrome_switches.h"
-#include "chrome/installer/util/google_update_settings.h"
-#include "chrome/installer/util/install_util.h"
-#include "chrome/installer/util/master_preferences.h"
-#include "chrome/installer/util/master_preferences_constants.h"
-#include "chrome/installer/util/util_constants.h"
-#include "content/public/browser/browser_thread.h"
-#include "google_update/google_update_idl.h"
-#include "grit/locale_settings.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "ui/base/win/shell.h"
-
-namespace {
-
-// Launches the setup exe with the given parameter/value on the command-line.
-// For non-metro Windows, it waits for its termination, returns its exit code
-// in |*ret_code|, and returns true if the exit code is valid.
-// For metro Windows, it launches setup via ShellExecuteEx and returns in order
-// to bounce the user back to the desktop, then returns immediately.
-bool LaunchSetupForEula(const base::FilePath::StringType& value,
-                        int* ret_code) {
-  base::FilePath exe_dir;
-  if (!PathService::Get(base::DIR_MODULE, &exe_dir))
-    return false;
-  exe_dir = exe_dir.Append(installer::kInstallerDir);
-  base::FilePath exe_path = exe_dir.Append(installer::kSetupExe);
-  base::ProcessHandle ph;
-
-  CommandLine cl(CommandLine::NO_PROGRAM);
-  cl.AppendSwitchNative(installer::switches::kShowEula, value);
-
-  CommandLine* browser_command_line = CommandLine::ForCurrentProcess();
-  if (browser_command_line->HasSwitch(switches::kChromeFrame)) {
-    cl.AppendSwitch(switches::kChromeFrame);
-  }
-
-  if (base::win::IsMetroProcess()) {
-    cl.AppendSwitch(installer::switches::kShowEulaForMetro);
-
-    // This obscure use of the 'log usage' mask for windows 8 is documented here
-    // http://go.microsoft.com/fwlink/?LinkID=243079. It causes the desktop
-    // process to receive focus. Pass SEE_MASK_FLAG_NO_UI to avoid hangs if an
-    // error occurs since the UI can't be shown from a metro process.
-    ui::win::OpenAnyViaShell(exe_path.value(),
-                             exe_dir.value(),
-                             cl.GetCommandLineString(),
-                             SEE_MASK_FLAG_LOG_USAGE | SEE_MASK_FLAG_NO_UI);
-    return false;
-  } else {
-    base::LaunchOptions launch_options;
-    launch_options.wait = true;
-    CommandLine setup_path(exe_path);
-    setup_path.AppendArguments(cl, false);
-
-    DWORD exit_code = 0;
-    if (!base::LaunchProcess(setup_path, launch_options, &ph) ||
-        !::GetExitCodeProcess(ph, &exit_code)) {
-      return false;
-    }
-
-    *ret_code = exit_code;
-    return true;
-  }
-}
-
-// Populates |path| with the path to |file| in the sentinel directory. This is
-// the application directory for user-level installs, and the default user data
-// dir for system-level installs. Returns false on error.
-bool GetSentinelFilePath(const wchar_t* file, base::FilePath* path) {
-  base::FilePath exe_path;
-  if (!PathService::Get(base::DIR_EXE, &exe_path))
-    return false;
-  if (InstallUtil::IsPerUserInstall(exe_path.value().c_str()))
-    *path = exe_path;
-  else if (!PathService::Get(chrome::DIR_USER_DATA, path))
-    return false;
-  *path = path->Append(file);
-  return true;
-}
-
-bool GetEULASentinelFilePath(base::FilePath* path) {
-  return GetSentinelFilePath(installer::kEULASentinelFile, path);
-}
-
-// Returns true if the EULA is required but has not been accepted by this user.
-// The EULA is considered having been accepted if the user has gotten past
-// first run in the "other" environment (desktop or metro).
-bool IsEULANotAccepted(installer::MasterPreferences* install_prefs) {
-  bool value = false;
-  if (install_prefs->GetBool(installer::master_preferences::kRequireEula,
-          &value) && value) {
-    base::FilePath eula_sentinel;
-    // Be conservative and show the EULA if the path to the sentinel can't be
-    // determined.
-    if (!GetEULASentinelFilePath(&eula_sentinel) ||
-        !file_util::PathExists(eula_sentinel)) {
-      return true;
-    }
-  }
-  return false;
-}
-
-// Writes the EULA to a temporary file, returned in |*eula_path|, and returns
-// true if successful.
-bool WriteEULAtoTempFile(base::FilePath* eula_path) {
-  std::string terms = l10n_util::GetStringUTF8(IDS_TERMS_HTML);
-  if (terms.empty())
-    return false;
-  FILE *file = file_util::CreateAndOpenTemporaryFile(eula_path);
-  if (!file)
-    return false;
-  bool good = fwrite(terms.data(), terms.size(), 1, file) == 1;
-  fclose(file);
-  return good;
-}
-
-// Creates the sentinel indicating that the EULA was required and has been
-// accepted.
-bool CreateEULASentinel() {
-  base::FilePath eula_sentinel;
-  if (!GetEULASentinelFilePath(&eula_sentinel))
-    return false;
-
-  return (file_util::CreateDirectory(eula_sentinel.DirName()) &&
-          file_util::WriteFile(eula_sentinel, "", 0) != -1);
-}
-
-}  // namespace
-
-namespace first_run {
-namespace internal {
-
-void DoPostImportPlatformSpecificTasks(Profile* /* profile */) {
-  // Trigger the Active Setup command for system-level Chromes to finish
-  // configuring this user's install (e.g. per-user shortcuts).
-  // Delay the task slightly to give Chrome launch I/O priority while also
-  // making sure shortcuts are created promptly to avoid annoying the user by
-  // re-creating shortcuts he previously deleted.
-  static const int64 kTiggerActiveSetupDelaySeconds = 5;
-  base::FilePath chrome_exe;
-  if (!PathService::Get(base::FILE_EXE, &chrome_exe)) {
-    NOTREACHED();
-  } else if (!InstallUtil::IsPerUserInstall(chrome_exe.value().c_str())) {
-    content::BrowserThread::GetBlockingPool()->PostDelayedTask(
-        FROM_HERE,
-        base::Bind(&InstallUtil::TriggerActiveSetupCommand),
-        base::TimeDelta::FromSeconds(kTiggerActiveSetupDelaySeconds));
-  }
-}
-
-bool GetFirstRunSentinelFilePath(base::FilePath* path) {
-  return GetSentinelFilePath(chrome::kFirstRunSentinel, path);
-}
-
-bool ShowPostInstallEULAIfNeeded(installer::MasterPreferences* install_prefs) {
-  if (IsEULANotAccepted(install_prefs)) {
-    // Show the post-installation EULA. This is done by setup.exe and the
-    // result determines if we continue or not. We wait here until the user
-    // dismisses the dialog.
-
-    // The actual eula text is in a resource in chrome. We extract it to
-    // a text file so setup.exe can use it as an inner frame.
-    base::FilePath inner_html;
-    if (WriteEULAtoTempFile(&inner_html)) {
-      int retcode = 0;
-      if (!LaunchSetupForEula(inner_html.value(), &retcode) ||
-          (retcode != installer::EULA_ACCEPTED &&
-           retcode != installer::EULA_ACCEPTED_OPT_IN)) {
-        LOG(WARNING) << "EULA flow requires fast exit.";
-        return false;
-      }
-      CreateEULASentinel();
-
-      if (retcode == installer::EULA_ACCEPTED) {
-        VLOG(1) << "EULA : no collection";
-        GoogleUpdateSettings::SetCollectStatsConsent(false);
-      } else if (retcode == installer::EULA_ACCEPTED_OPT_IN) {
-        VLOG(1) << "EULA : collection consent";
-        GoogleUpdateSettings::SetCollectStatsConsent(true);
-      }
-    }
-  }
-  return true;
-}
-
-base::FilePath MasterPrefsPath() {
-  // The standard location of the master prefs is next to the chrome binary.
-  base::FilePath master_prefs;
-  if (!PathService::Get(base::DIR_EXE, &master_prefs))
-    return base::FilePath();
-  return master_prefs.AppendASCII(installer::kDefaultMasterPrefs);
-}
-
-}  // namespace internal
-}  // namespace first_run
diff --git a/chrome/browser/geolocation/chrome_access_token_store.cc b/chrome/browser/geolocation/chrome_access_token_store.cc
index 9bf2b9f..cefb644 100644
--- a/chrome/browser/geolocation/chrome_access_token_store.cc
+++ b/chrome/browser/geolocation/chrome_access_token_store.cc
@@ -14,7 +14,7 @@
 #include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/common/pref_names.h"
 #include "content/public/browser/browser_thread.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 using content::AccessTokenStore;
 using content::BrowserThread;
diff --git a/chrome/browser/geolocation/geolocation_browsertest.cc b/chrome/browser/geolocation/geolocation_browsertest.cc
index 9ffc81a..597ce45 100644
--- a/chrome/browser/geolocation/geolocation_browsertest.cc
+++ b/chrome/browser/geolocation/geolocation_browsertest.cc
@@ -31,7 +31,7 @@
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/browser_test_utils.h"
 #include "net/base/net_util.h"
-#include "net/test/spawned_test_server/spawned_test_server.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
 
 using content::DomOperationNotificationDetails;
 using content::NavigationController;
@@ -274,9 +274,6 @@
   double fake_latitude_;
   double fake_longitude_;
 
-  // TODO(phajdan.jr): Remove after we can ask TestServer whether it is started.
-  bool started_test_server_;
-
  private:
   DISALLOW_COPY_AND_ASSIGN(GeolocationBrowserTest);
 };
@@ -284,10 +281,10 @@
 GeolocationBrowserTest::GeolocationBrowserTest()
   : infobar_(NULL),
     current_browser_(NULL),
-    html_for_tests_("files/geolocation/simple.html"),
+    html_for_tests_("/geolocation/simple.html"),
     fake_latitude_(1.23),
-    fake_longitude_(4.56),
-    started_test_server_(false) {}
+    fake_longitude_(4.56) {
+}
 
 void GeolocationBrowserTest::SetUpOnMainThread() {
   ui_test_utils::OverrideGeolocation(fake_latitude_, fake_longitude_);
@@ -298,13 +295,13 @@
 }
 
 bool GeolocationBrowserTest::Initialize(InitializationOptions options) {
-  if (!started_test_server_)
-    started_test_server_ = test_server()->Start();
-  EXPECT_TRUE(started_test_server_);
-  if (!started_test_server_)
+  if (!embedded_test_server()->Started() &&
+      !embedded_test_server()->InitializeAndWaitUntilReady()) {
+    ADD_FAILURE() << "Test server failed to start.";
     return false;
+  }
 
-  current_url_ = test_server()->GetURL(html_for_tests_);
+  current_url_ = embedded_test_server()->GetURL(html_for_tests_);
   LOG(WARNING) << "before navigate";
   if (options == INITIALIZATION_OFFTHERECORD) {
     current_browser_ = ui_test_utils::OpenURLOffTheRecord(
@@ -540,7 +537,7 @@
 // crbug.com/176291
 IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest,
                        DISABLED_IFramesWithFreshPosition) {
-  html_for_tests_ = "files/geolocation/iframes_different_origin.html";
+  html_for_tests_ = "/geolocation/iframes_different_origin.html";
   ASSERT_TRUE(Initialize(INITIALIZATION_IFRAMES));
   LoadIFrames(2);
   LOG(WARNING) << "frames loaded";
@@ -585,7 +582,7 @@
 
 IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest,
                        IFramesWithCachedPosition) {
-  html_for_tests_ = "files/geolocation/iframes_different_origin.html";
+  html_for_tests_ = "/geolocation/iframes_different_origin.html";
   ASSERT_TRUE(Initialize(INITIALIZATION_IFRAMES));
   LoadIFrames(2);
 
@@ -624,7 +621,7 @@
 // crbug.com/176291
 IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest,
                        DISABLED_CancelPermissionForFrame) {
-  html_for_tests_ = "files/geolocation/iframes_different_origin.html";
+  html_for_tests_ = "/geolocation/iframes_different_origin.html";
   ASSERT_TRUE(Initialize(INITIALIZATION_IFRAMES));
   LoadIFrames(2);
   LOG(WARNING) << "frames loaded";
@@ -653,7 +650,7 @@
 IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, InvalidUrlRequest) {
   // Tests that an invalid URL (e.g. from a popup window) is rejected
   // correctly. Also acts as a regression test for http://crbug.com/40478
-  html_for_tests_ = "files/geolocation/invalid_request_url.html";
+  html_for_tests_ = "/geolocation/invalid_request_url.html";
   ASSERT_TRUE(Initialize(INITIALIZATION_NONE));
   WebContents* original_tab =
       current_browser_->tab_strip_model()->GetActiveWebContents();
@@ -663,7 +660,7 @@
 
 IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, NoInfoBarBeforeStart) {
   // See http://crbug.com/42789
-  html_for_tests_ = "files/geolocation/iframes_different_origin.html";
+  html_for_tests_ = "/geolocation/iframes_different_origin.html";
   ASSERT_TRUE(Initialize(INITIALIZATION_IFRAMES));
   LoadIFrames(2);
   LOG(WARNING) << "frames loaded";
@@ -686,7 +683,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, TwoWatchesInOneFrame) {
-  html_for_tests_ = "files/geolocation/two_watches.html";
+  html_for_tests_ = "/geolocation/two_watches.html";
   ASSERT_TRUE(Initialize(INITIALIZATION_NONE));
   // First, set the JavaScript to navigate when it receives |final_position|.
   double final_position_latitude = 3.17;
@@ -720,7 +717,7 @@
 
 // crbug.com/176291
 IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, DISABLED_TabDestroyed) {
-  html_for_tests_ = "files/geolocation/tab_destroyed.html";
+  html_for_tests_ = "/geolocation/tab_destroyed.html";
   ASSERT_TRUE(Initialize(INITIALIZATION_IFRAMES));
   LoadIFrames(3);
 
diff --git a/chrome/browser/geolocation/geolocation_infobar_delegate.h b/chrome/browser/geolocation/geolocation_infobar_delegate.h
index 64e2f2b..d149836 100644
--- a/chrome/browser/geolocation/geolocation_infobar_delegate.h
+++ b/chrome/browser/geolocation/geolocation_infobar_delegate.h
@@ -5,11 +5,11 @@
 #ifndef CHROME_BROWSER_GEOLOCATION_GEOLOCATION_INFOBAR_DELEGATE_H_
 #define CHROME_BROWSER_GEOLOCATION_GEOLOCATION_INFOBAR_DELEGATE_H_
 
+#include <string>
+
 #include "chrome/browser/geolocation/geolocation_permission_request_id.h"
 #include "chrome/browser/infobars/confirm_infobar_delegate.h"
-#include "googleurl/src/gurl.h"
-
-#include <string>
+#include "url/gurl.h"
 
 class GeolocationInfoBarQueueController;
 class InfoBarService;
diff --git a/chrome/browser/geolocation/geolocation_settings_state.h b/chrome/browser/geolocation/geolocation_settings_state.h
index e927626..c5f9948 100644
--- a/chrome/browser/geolocation/geolocation_settings_state.h
+++ b/chrome/browser/geolocation/geolocation_settings_state.h
@@ -9,7 +9,7 @@
 #include <set>
 
 #include "chrome/common/content_settings.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 class Profile;
 
diff --git a/chrome/browser/google/google_search_counter.cc b/chrome/browser/google/google_search_counter.cc
index e15da72..ecf670c8 100644
--- a/chrome/browser/google/google_search_counter.cc
+++ b/chrome/browser/google/google_search_counter.cc
@@ -20,7 +20,7 @@
 bool IsOmniboxGoogleSearchNavigation(const content::NavigationEntry& entry) {
   const content::PageTransition stripped_transition =
       PageTransitionStripQualifier(entry.GetTransitionType());
-  DCHECK(google_util::IsGoogleSearchUrl(entry.GetURL().spec()));
+  DCHECK(google_util::IsGoogleSearchUrl(entry.GetURL()));
   return stripped_transition == content::PAGE_TRANSITION_GENERATED;
 }
 
@@ -28,7 +28,7 @@
 // App. This method assumes that we have already verified that |entry|'s URL is
 // a Google search URL.
 bool IsSearchAppGoogleSearchNavigation(const content::NavigationEntry& entry) {
-  DCHECK(google_util::IsGoogleSearchUrl(entry.GetURL().spec()));
+  DCHECK(google_util::IsGoogleSearchUrl(entry.GetURL()));
   return entry.GetURL().query().find("source=search_app") !=
          std::string::npos;
 }
@@ -60,7 +60,7 @@
   const content::NavigationEntry& entry = *commit->entry;
 
   // First see if this is a Google search URL at all.
-  if (!google_util::IsGoogleSearchUrl(entry.GetURL().spec()))
+  if (!google_util::IsGoogleSearchUrl(entry.GetURL()))
     return;
 
   // If the commit is a GENERATED commit with a Google search URL, we know it's
diff --git a/chrome/browser/google/google_update_settings_posix.cc b/chrome/browser/google/google_update_settings_posix.cc
index 0bced14..c4bd2cd 100644
--- a/chrome/browser/google/google_update_settings_posix.cc
+++ b/chrome/browser/google/google_update_settings_posix.cc
@@ -51,7 +51,7 @@
     }
   } else {
     google_update::posix_guid().clear();
-    return file_util::Delete(consent_file, false);
+    return base::Delete(consent_file, false);
   }
   return true;
 }
diff --git a/chrome/browser/google/google_update_win.cc b/chrome/browser/google/google_update_win.cc
index 8192412..5b9dd1b 100644
--- a/chrome/browser/google/google_update_win.cc
+++ b/chrome/browser/google/google_update_win.cc
@@ -60,10 +60,15 @@
       !InstallUtil::IsPerUserInstall(chrome_exe_path.value().c_str()));
   DCHECK(!app_guid.empty());
 
-  if (GoogleUpdateSettings::GetAppUpdatePolicy(app_guid, NULL) ==
-      GoogleUpdateSettings::UPDATES_DISABLED)
+  GoogleUpdateSettings::UpdatePolicy update_policy =
+      GoogleUpdateSettings::GetAppUpdatePolicy(app_guid, NULL);
+
+  if (update_policy == GoogleUpdateSettings::UPDATES_DISABLED)
     return GOOGLE_UPDATE_DISABLED_BY_POLICY;
 
+  if (update_policy == GoogleUpdateSettings::AUTO_UPDATES_ONLY)
+    return GOOGLE_UPDATE_DISABLED_BY_POLICY_AUTO_ONLY;
+
   return GOOGLE_UPDATE_NO_ERROR;
 #endif
 }
diff --git a/chrome/browser/google/google_update_win.h b/chrome/browser/google/google_update_win.h
index d9b8951..06e5fe2 100644
--- a/chrome/browser/google/google_update_win.h
+++ b/chrome/browser/google/google_update_win.h
@@ -56,8 +56,12 @@
   // An error occurred while upgrading (or while checking for update).
   // Check the Google Update log in %TEMP% for more details.
   GOOGLE_UPDATE_ERROR_UPDATING,
-  // Updates can not be downloaded because the administrator has disabled them.
+  // Updates can not be downloaded because the administrator has disabled all
+  // types of updating.
   GOOGLE_UPDATE_DISABLED_BY_POLICY,
+  // Updates can not be downloaded because the administrator has disabled
+  // manual (on-demand) updates.  Automatic background updates are allowed.
+  GOOGLE_UPDATE_DISABLED_BY_POLICY_AUTO_ONLY,
 };
 
 // The GoogleUpdateStatusListener interface is used by components to receive
diff --git a/chrome/browser/google/google_url_tracker.cc b/chrome/browser/google/google_url_tracker.cc
index 0f78cfb..2472417 100644
--- a/chrome/browser/google/google_url_tracker.cc
+++ b/chrome/browser/google/google_url_tracker.cc
@@ -139,8 +139,7 @@
   GURL url(url_str);
   if (!url.is_valid() || (url.path().length() > 1) || url.has_query() ||
       url.has_ref() ||
-      !google_util::IsGoogleDomainUrl(url.spec(),
-                                      google_util::DISALLOW_SUBDOMAIN,
+      !google_util::IsGoogleDomainUrl(url, google_util::DISALLOW_SUBDOMAIN,
                                       google_util::DISALLOW_NON_STANDARD_PORTS))
     return;
 
diff --git a/chrome/browser/google/google_url_tracker.h b/chrome/browser/google/google_url_tracker.h
index 2784179..d71e7e7 100644
--- a/chrome/browser/google/google_url_tracker.h
+++ b/chrome/browser/google/google_url_tracker.h
@@ -15,10 +15,10 @@
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/google/google_url_tracker_map_entry.h"
 #include "components/browser_context_keyed_service/browser_context_keyed_service.h"
-#include "googleurl/src/gurl.h"
 #include "net/base/network_change_notifier.h"
 #include "net/url_request/url_fetcher.h"
 #include "net/url_request/url_fetcher_delegate.h"
+#include "url/gurl.h"
 
 class GoogleURLTrackerNavigationHelper;
 class PrefService;
diff --git a/chrome/browser/google/google_url_tracker_infobar_delegate.h b/chrome/browser/google/google_url_tracker_infobar_delegate.h
index 694d6ba..7e01655 100644
--- a/chrome/browser/google/google_url_tracker_infobar_delegate.h
+++ b/chrome/browser/google/google_url_tracker_infobar_delegate.h
@@ -6,7 +6,7 @@
 #define CHROME_BROWSER_GOOGLE_GOOGLE_URL_TRACKER_INFOBAR_DELEGATE_H_
 
 #include "chrome/browser/infobars/confirm_infobar_delegate.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 class GoogleURLTracker;
 
diff --git a/chrome/browser/google/google_url_tracker_navigation_helper_impl.cc b/chrome/browser/google/google_url_tracker_navigation_helper_impl.cc
index 8a1cb14..867a84f 100644
--- a/chrome/browser/google/google_url_tracker_navigation_helper_impl.cc
+++ b/chrome/browser/google/google_url_tracker_navigation_helper_impl.cc
@@ -31,13 +31,9 @@
   if (listen) {
     registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_PENDING,
         content::NotificationService::AllBrowserContextsAndSources());
-    registrar_.Add(this, chrome::NOTIFICATION_INSTANT_COMMITTED,
-        content::NotificationService::AllBrowserContextsAndSources());
   } else {
     registrar_.Remove(this, content::NOTIFICATION_NAV_ENTRY_PENDING,
         content::NotificationService::AllBrowserContextsAndSources());
-    registrar_.Remove(this, chrome::NOTIFICATION_INSTANT_COMMITTED,
-        content::NotificationService::AllBrowserContextsAndSources());
   }
 }
 
@@ -148,33 +144,7 @@
       break;
     }
 
-    case chrome::NOTIFICATION_INSTANT_COMMITTED: {
-      content::WebContents* web_contents =
-          content::Source<content::WebContents>(source).ptr();
-      content::NavigationController* nav_controller =
-          &web_contents->GetController();
-      const GURL& search_url = web_contents->GetURL();
-      if (!search_url.is_valid())  // Not clear if this can happen.
-        tracker_->OnTabClosed(nav_controller);
-      OnInstantCommitted(nav_controller,
-                         InfoBarService::FromWebContents(web_contents),
-                         search_url);
-      break;
-    }
-
     default:
       NOTREACHED() << "Unknown notification received:" << type;
   }
 }
-
-void GoogleURLTrackerNavigationHelperImpl::OnInstantCommitted(
-    content::NavigationController* nav_controller,
-    InfoBarService* infobar_service,
-    const GURL& search_url) {
-  // Call OnNavigationPending, giving |tracker_| the option to register for
-  // navigation commit messages for this navigation controller. If it does
-  // register for them, simulate the commit as well.
-  tracker_->OnNavigationPending(nav_controller, infobar_service, 0);
-  if (IsListeningForNavigationCommit(nav_controller))
-    tracker_->OnNavigationCommitted(infobar_service, search_url);
-}
diff --git a/chrome/browser/google/google_url_tracker_navigation_helper_impl.h b/chrome/browser/google/google_url_tracker_navigation_helper_impl.h
index a710b5e..2900590 100644
--- a/chrome/browser/google/google_url_tracker_navigation_helper_impl.h
+++ b/chrome/browser/google/google_url_tracker_navigation_helper_impl.h
@@ -8,7 +8,7 @@
 #include "chrome/browser/google/google_url_tracker_navigation_helper.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 class GoogleURLTrackerNavigationHelperImpl
     : public GoogleURLTrackerNavigationHelper,
@@ -40,12 +40,6 @@
                        const content::NotificationSource& source,
                        const content::NotificationDetails& details) OVERRIDE;
 
-  // Handles instant commit notifications by simulating the relevant navigation
-  // callbacks.
-  void OnInstantCommitted(content::NavigationController* nav_controller,
-                          InfoBarService* infobar_service,
-                          const GURL& search_url);
-
   // Returns a WebContents NavigationSource for the WebContents corresponding to
   // the given NavigationController NotificationSource.
   virtual content::NotificationSource GetWebContentsSource(
diff --git a/chrome/browser/google/google_util.cc b/chrome/browser/google/google_util.cc
index e2c09ec..d14ec5a 100644
--- a/chrome/browser/google/google_util.cc
+++ b/chrome/browser/google/google_util.cc
@@ -17,9 +17,9 @@
 #include "chrome/browser/google/google_url_tracker.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/installer/util/google_update_settings.h"
-#include "googleurl/src/gurl.h"
 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
 #include "net/base/url_util.h"
+#include "url/gurl.h"
 
 #if defined(OS_MACOSX)
 #include "chrome/browser/mac/keystone_glue.h"
@@ -35,16 +35,25 @@
 #define LINKDOCTOR_SERVER_REQUEST_URL std::string()
 #endif
 
+
+// Helpers --------------------------------------------------------------------
+
 namespace {
 
 const char* brand_for_testing = NULL;
-
 bool gUseMockLinkDoctorBaseURLForTesting = false;
 
-}  // anonymous namespace
+bool IsPathHomePageBase(const std::string& path) {
+  return (path == "/") || (path == "/webhp");
+}
+
+}  // namespace
+
 
 namespace google_util {
 
+// Global functions -----------------------------------------------------------
+
 bool HasGoogleSearchQueryParam(const std::string& str) {
   url_parse::Component query(0, str.length()), key, value;
   while (url_parse::ExtractQueryKeyValue(str.c_str(), &query, &key,
@@ -65,15 +74,6 @@
   gUseMockLinkDoctorBaseURLForTesting = true;
 }
 
-BrandForTesting::BrandForTesting(const std::string& brand) : brand_(brand) {
-  DCHECK(brand_for_testing == NULL);
-  brand_for_testing = brand_.c_str();
-}
-
-BrandForTesting::~BrandForTesting() {
-  brand_for_testing = NULL;
-}
-
 GURL AppendGoogleLocaleParam(const GURL& url) {
   // Google does not yet recognize 'nb' for Norwegian Bokmal, but it uses
   // 'no' for that.
@@ -152,32 +152,23 @@
 
 #endif
 
-bool IsGoogleDomainUrl(const std::string& url,
-                       SubdomainPermission subdomain_permission,
-                       PortPermission port_permission) {
-  GURL original_url(url);
-  if (!original_url.is_valid() ||
-      !(original_url.SchemeIs("http") || original_url.SchemeIs("https")))
-    return false;
-
-  // If we have the Instant URL overridden with a command line flag, accept
-  // its domain/port combination as well.
-  const CommandLine& command_line = *CommandLine::ForCurrentProcess();
-  if (command_line.HasSwitch(switches::kInstantURL)) {
-    GURL custom_instant_url(
-        command_line.GetSwitchValueASCII(switches::kInstantURL));
-    if (original_url.host() == custom_instant_url.host() &&
-        original_url.port() == custom_instant_url.port())
-      return true;
-  }
-
-  return (original_url.port().empty() ||
-      port_permission == ALLOW_NON_STANDARD_PORTS) &&
-      google_util::IsGoogleHostname(original_url.host(), subdomain_permission);
+bool StartsWithCommandLineGoogleBaseURL(const GURL& url) {
+  const std::string base_url(CommandLine::ForCurrentProcess()->
+      GetSwitchValueASCII(switches::kGoogleBaseURL));
+  return !base_url.empty() &&
+      StartsWithASCII(url.possibly_invalid_spec(), base_url, true);
 }
 
 bool IsGoogleHostname(const std::string& host,
                       SubdomainPermission subdomain_permission) {
+  const std::string base_url(CommandLine::ForCurrentProcess()->
+      GetSwitchValueASCII(switches::kGoogleBaseURL));
+  if (!base_url.empty()) {
+    GURL base_gurl(base_url);
+    if (base_gurl.is_valid() && (host == base_gurl.host()))
+      return true;
+  }
+
   size_t tld_length = net::registry_controlled_domains::GetRegistryLength(
       host,
       net::registry_controlled_domains::EXCLUDE_UNKNOWN_REGISTRIES,
@@ -192,51 +183,39 @@
   return LowerCaseEqualsASCII(host_minus_tld, "www.google.");
 }
 
-bool IsGoogleHomePageUrl(const std::string& url) {
-  GURL original_url(url);
+bool IsGoogleDomainUrl(const GURL& url,
+                       SubdomainPermission subdomain_permission,
+                       PortPermission port_permission) {
+  return url.is_valid() && (url.SchemeIs("http") || url.SchemeIs("https")) &&
+      (url.port().empty() || (port_permission == ALLOW_NON_STANDARD_PORTS)) &&
+      google_util::IsGoogleHostname(url.host(), subdomain_permission);
+}
 
+bool IsGoogleHomePageUrl(const GURL& url) {
   // First check to see if this has a Google domain.
   if (!IsGoogleDomainUrl(url, DISALLOW_SUBDOMAIN, DISALLOW_NON_STANDARD_PORTS))
     return false;
 
   // Make sure the path is a known home page path.
-  std::string path(original_url.path());
-  if (path != "/" && path != "/webhp" &&
-      !StartsWithASCII(path, "/ig", false)) {
-    return false;
-  }
-
-  return true;
+  std::string path(url.path());
+  return IsPathHomePageBase(path) || StartsWithASCII(path, "/ig", false);
 }
 
-bool IsGoogleSearchUrl(const std::string& url) {
-  GURL original_url(url);
-
+bool IsGoogleSearchUrl(const GURL& url) {
   // First check to see if this has a Google domain.
   if (!IsGoogleDomainUrl(url, DISALLOW_SUBDOMAIN, DISALLOW_NON_STANDARD_PORTS))
     return false;
 
   // Make sure the path is a known search path.
-  std::string path(original_url.path());
-  bool has_valid_path = false;
-  bool is_home_page_base = false;
-  if (path == "/search") {
-    has_valid_path = true;
-  } else if (path == "/webhp" || path == "/") {
-    // Note that we allow both "/" and "" paths, but GURL spits them
-    // both out as just "/".
-    has_valid_path = true;
-    is_home_page_base = true;
-  }
-  if (!has_valid_path)
+  std::string path(url.path());
+  bool is_home_page_base = IsPathHomePageBase(path);
+  if (!is_home_page_base && (path != "/search"))
     return false;
 
   // Check for query parameter in URL parameter and hash fragment, depending on
   // the path type.
-  std::string query(original_url.query());
-  std::string ref(original_url.ref());
-  return HasGoogleSearchQueryParam(ref) ||
-      (!is_home_page_base && HasGoogleSearchQueryParam(query));
+  return HasGoogleSearchQueryParam(url.ref()) ||
+      (!is_home_page_base && HasGoogleSearchQueryParam(url.query()));
 }
 
 bool IsOrganic(const std::string& brand) {
@@ -300,4 +279,17 @@
   return found != end;
 }
 
+
+// BrandForTesting ------------------------------------------------------------
+
+BrandForTesting::BrandForTesting(const std::string& brand) : brand_(brand) {
+  DCHECK(brand_for_testing == NULL);
+  brand_for_testing = brand_.c_str();
+}
+
+BrandForTesting::~BrandForTesting() {
+  brand_for_testing = NULL;
+}
+
+
 }  // namespace google_util
diff --git a/chrome/browser/google/google_util.h b/chrome/browser/google/google_util.h
index ea49f36..f3da3b4 100644
--- a/chrome/browser/google/google_util.h
+++ b/chrome/browser/google/google_util.h
@@ -69,22 +69,31 @@
   DISALLOW_NON_STANDARD_PORTS,
 };
 
-// True if |url| is an HTTP[S] request with host "[www.]google.<TLD>". If
-// |subdomain_permission| is ALLOW_SUBDOMAIN, this checks against host
-// "*.google.<TLD>" instead. If |port_permission| is ALLOW_NON_STANDARD_PORTS,
-// this also allows ports other than 80 for http or 443 for https.
-bool IsGoogleDomainUrl(const std::string& url,
-                       SubdomainPermission subdomain_permission,
-                       PortPermission port_permission);
+// Returns true if a Google base URL was specified on the command line and |url|
+// begins with that base URL.  This uses a simple string equality check.
+bool StartsWithCommandLineGoogleBaseURL(const GURL& url);
+
 // True if |host| is "[www.]google.<TLD>" with a valid TLD. If
 // |subdomain_permission| is ALLOW_SUBDOMAIN, we check against host
 // "*.google.<TLD>" instead.
+//
+// If the Google base URL has been overridden on the command line, this function
+// will also return true for any URL whose hostname exactly matches the hostname
+// of the URL specified on the command line.  In this case,
+// |subdomain_permission| is ignored.
 bool IsGoogleHostname(const std::string& host,
                       SubdomainPermission subdomain_permission);
+// True if |url| is a valid URL with a host that returns true for
+// IsGoogleHostname(), and an HTTP or HTTPS scheme.  If |port_permission| is
+// DISALLOW_NON_STANDARD_PORTS, this also requires |url| to use the standard
+// port for its scheme (80 for HTTP, 443 for HTTPS).
+bool IsGoogleDomainUrl(const GURL& url,
+                       SubdomainPermission subdomain_permission,
+                       PortPermission port_permission);
 // True if |url| represents a valid Google home page URL.
-bool IsGoogleHomePageUrl(const std::string& url);
+bool IsGoogleHomePageUrl(const GURL& url);
 // True if |url| represents a valid Google search URL.
-bool IsGoogleSearchUrl(const std::string& url);
+bool IsGoogleSearchUrl(const GURL& url);
 
 // True if a build is strictly organic, according to its brand code.
 bool IsOrganic(const std::string& brand);
diff --git a/chrome/browser/google/google_util_unittest.cc b/chrome/browser/google/google_util_unittest.cc
index 719c9b4..3701758 100644
--- a/chrome/browser/google/google_util_unittest.cc
+++ b/chrome/browser/google/google_util_unittest.cc
@@ -3,346 +3,334 @@
 // found in the LICENSE file.
 
 #include "base/command_line.h"
-#include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/google/google_url_tracker.h"
 #include "chrome/browser/google/google_util.h"
 #include "chrome/common/chrome_switches.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 using google_util::IsGoogleDomainUrl;
-using google_util::IsGoogleHomePageUrl;
-using google_util::IsGoogleSearchUrl;
+
+
+// Helpers --------------------------------------------------------------------
+
+namespace {
+
+// These functions merely provide brevity in the callers.
+
+bool IsHomePage(const std::string& url) {
+  return google_util::IsGoogleHomePageUrl(GURL(url));
+}
+
+bool IsSearch(const std::string& url) {
+  return google_util::IsGoogleSearchUrl(GURL(url));
+}
+
+bool StartsWithBaseURL(const std::string& url) {
+  return google_util::StartsWithCommandLineGoogleBaseURL(GURL(url));
+}
+
+}  // namespace
+
+
+// Actual tests ---------------------------------------------------------------
 
 TEST(GoogleUtilTest, GoodHomePagesNonSecure) {
   // Valid home page hosts.
-  EXPECT_TRUE(IsGoogleHomePageUrl(GoogleURLTracker::kDefaultGoogleHomepage));
-  EXPECT_TRUE(IsGoogleHomePageUrl("http://google.com"));
-  EXPECT_TRUE(IsGoogleHomePageUrl("http://www.google.com"));
-  EXPECT_TRUE(IsGoogleHomePageUrl("http://www.google.ca"));
-  EXPECT_TRUE(IsGoogleHomePageUrl("http://www.google.co.uk"));
-  EXPECT_TRUE(IsGoogleHomePageUrl("http://www.google.com:80/"));
+  EXPECT_TRUE(IsHomePage(GoogleURLTracker::kDefaultGoogleHomepage));
+  EXPECT_TRUE(IsHomePage("http://google.com"));
+  EXPECT_TRUE(IsHomePage("http://www.google.com"));
+  EXPECT_TRUE(IsHomePage("http://www.google.ca"));
+  EXPECT_TRUE(IsHomePage("http://www.google.co.uk"));
+  EXPECT_TRUE(IsHomePage("http://www.google.com:80/"));
 
   // Only the paths /, /webhp, and /ig.* are valid.  Query parameters are
   // ignored.
-  EXPECT_TRUE(IsGoogleHomePageUrl("http://www.google.com/"));
-  EXPECT_TRUE(IsGoogleHomePageUrl("http://www.google.com/webhp"));
-  EXPECT_TRUE(IsGoogleHomePageUrl("http://www.google.com/webhp?rlz=TEST"));
-  EXPECT_TRUE(IsGoogleHomePageUrl("http://www.google.com/ig"));
-  EXPECT_TRUE(IsGoogleHomePageUrl("http://www.google.com/ig/foo"));
-  EXPECT_TRUE(IsGoogleHomePageUrl("http://www.google.com/ig?rlz=TEST"));
-  EXPECT_TRUE(IsGoogleHomePageUrl("http://www.google.com/ig/foo?rlz=TEST"));
+  EXPECT_TRUE(IsHomePage("http://www.google.com/"));
+  EXPECT_TRUE(IsHomePage("http://www.google.com/webhp"));
+  EXPECT_TRUE(IsHomePage("http://www.google.com/webhp?rlz=TEST"));
+  EXPECT_TRUE(IsHomePage("http://www.google.com/ig"));
+  EXPECT_TRUE(IsHomePage("http://www.google.com/ig/foo"));
+  EXPECT_TRUE(IsHomePage("http://www.google.com/ig?rlz=TEST"));
+  EXPECT_TRUE(IsHomePage("http://www.google.com/ig/foo?rlz=TEST"));
 }
 
 TEST(GoogleUtilTest, GoodHomePagesSecure) {
   // Valid home page hosts.
-  EXPECT_TRUE(IsGoogleHomePageUrl("https://google.com"));
-  EXPECT_TRUE(IsGoogleHomePageUrl("https://www.google.com"));
-  EXPECT_TRUE(IsGoogleHomePageUrl("https://www.google.ca"));
-  EXPECT_TRUE(IsGoogleHomePageUrl("https://www.google.co.uk"));
-  EXPECT_TRUE(IsGoogleHomePageUrl("https://www.google.com:443/"));
+  EXPECT_TRUE(IsHomePage("https://google.com"));
+  EXPECT_TRUE(IsHomePage("https://www.google.com"));
+  EXPECT_TRUE(IsHomePage("https://www.google.ca"));
+  EXPECT_TRUE(IsHomePage("https://www.google.co.uk"));
+  EXPECT_TRUE(IsHomePage("https://www.google.com:443/"));
 
   // Only the paths /, /webhp, and /ig.* are valid.  Query parameters are
   // ignored.
-  EXPECT_TRUE(IsGoogleHomePageUrl("https://www.google.com/"));
-  EXPECT_TRUE(IsGoogleHomePageUrl("https://www.google.com/webhp"));
-  EXPECT_TRUE(IsGoogleHomePageUrl("https://www.google.com/webhp?rlz=TEST"));
-  EXPECT_TRUE(IsGoogleHomePageUrl("https://www.google.com/ig"));
-  EXPECT_TRUE(IsGoogleHomePageUrl("https://www.google.com/ig/foo"));
-  EXPECT_TRUE(IsGoogleHomePageUrl("https://www.google.com/ig?rlz=TEST"));
-  EXPECT_TRUE(IsGoogleHomePageUrl("https://www.google.com/ig/foo?rlz=TEST"));
+  EXPECT_TRUE(IsHomePage("https://www.google.com/"));
+  EXPECT_TRUE(IsHomePage("https://www.google.com/webhp"));
+  EXPECT_TRUE(IsHomePage("https://www.google.com/webhp?rlz=TEST"));
+  EXPECT_TRUE(IsHomePage("https://www.google.com/ig"));
+  EXPECT_TRUE(IsHomePage("https://www.google.com/ig/foo"));
+  EXPECT_TRUE(IsHomePage("https://www.google.com/ig?rlz=TEST"));
+  EXPECT_TRUE(IsHomePage("https://www.google.com/ig/foo?rlz=TEST"));
 }
 
 TEST(GoogleUtilTest, BadHomePages) {
-  EXPECT_FALSE(IsGoogleHomePageUrl(std::string()));
+  EXPECT_FALSE(IsHomePage(std::string()));
 
   // If specified, only the "www" subdomain is OK.
-  EXPECT_FALSE(IsGoogleHomePageUrl("http://maps.google.com"));
-  EXPECT_FALSE(IsGoogleHomePageUrl("http://foo.google.com"));
+  EXPECT_FALSE(IsHomePage("http://maps.google.com"));
+  EXPECT_FALSE(IsHomePage("http://foo.google.com"));
 
   // No non-standard port numbers.
-  EXPECT_FALSE(IsGoogleHomePageUrl("http://www.google.com:1234"));
-  EXPECT_FALSE(IsGoogleHomePageUrl("https://www.google.com:5678"));
+  EXPECT_FALSE(IsHomePage("http://www.google.com:1234"));
+  EXPECT_FALSE(IsHomePage("https://www.google.com:5678"));
 
   // Invalid TLDs.
-  EXPECT_FALSE(IsGoogleHomePageUrl("http://www.google.abc"));
-  EXPECT_FALSE(IsGoogleHomePageUrl("http://www.google.com.abc"));
-  EXPECT_FALSE(IsGoogleHomePageUrl("http://www.google.abc.com"));
-  EXPECT_FALSE(IsGoogleHomePageUrl("http://www.google.ab.cd"));
-  EXPECT_FALSE(IsGoogleHomePageUrl("http://www.google.uk.qq"));
+  EXPECT_FALSE(IsHomePage("http://www.google.abc"));
+  EXPECT_FALSE(IsHomePage("http://www.google.com.abc"));
+  EXPECT_FALSE(IsHomePage("http://www.google.abc.com"));
+  EXPECT_FALSE(IsHomePage("http://www.google.ab.cd"));
+  EXPECT_FALSE(IsHomePage("http://www.google.uk.qq"));
 
   // Must be http or https.
-  EXPECT_FALSE(IsGoogleHomePageUrl("ftp://www.google.com"));
-  EXPECT_FALSE(IsGoogleHomePageUrl("file://does/not/exist"));
-  EXPECT_FALSE(IsGoogleHomePageUrl("bad://www.google.com"));
-  EXPECT_FALSE(IsGoogleHomePageUrl("www.google.com"));
+  EXPECT_FALSE(IsHomePage("ftp://www.google.com"));
+  EXPECT_FALSE(IsHomePage("file://does/not/exist"));
+  EXPECT_FALSE(IsHomePage("bad://www.google.com"));
+  EXPECT_FALSE(IsHomePage("www.google.com"));
 
   // Only the paths /, /webhp, and /ig.* are valid.
-  EXPECT_FALSE(IsGoogleHomePageUrl("http://www.google.com/abc"));
-  EXPECT_FALSE(IsGoogleHomePageUrl("http://www.google.com/webhpabc"));
-  EXPECT_FALSE(IsGoogleHomePageUrl("http://www.google.com/webhp/abc"));
-  EXPECT_FALSE(IsGoogleHomePageUrl("http://www.google.com/abcig"));
-  EXPECT_FALSE(IsGoogleHomePageUrl("http://www.google.com/webhp/ig"));
+  EXPECT_FALSE(IsHomePage("http://www.google.com/abc"));
+  EXPECT_FALSE(IsHomePage("http://www.google.com/webhpabc"));
+  EXPECT_FALSE(IsHomePage("http://www.google.com/webhp/abc"));
+  EXPECT_FALSE(IsHomePage("http://www.google.com/abcig"));
+  EXPECT_FALSE(IsHomePage("http://www.google.com/webhp/ig"));
 
   // A search URL should not be identified as a home page URL.
-  EXPECT_FALSE(IsGoogleHomePageUrl("http://www.google.com/search?q=something"));
+  EXPECT_FALSE(IsHomePage("http://www.google.com/search?q=something"));
 
   // Path is case sensitive.
-  EXPECT_FALSE(IsGoogleHomePageUrl("https://www.google.com/WEBHP"));
+  EXPECT_FALSE(IsHomePage("https://www.google.com/WEBHP"));
 }
 
 TEST(GoogleUtilTest, GoodSearchPagesNonSecure) {
   // Queries with path "/search" need to have the query parameter in either
   // the url parameter or the hash fragment.
-  EXPECT_TRUE(IsGoogleSearchUrl(
-      "http://www.google.com/search?q=something"));
-  EXPECT_TRUE(IsGoogleSearchUrl(
-      "http://www.google.com/search#q=something"));
-  EXPECT_TRUE(IsGoogleSearchUrl(
-      "http://www.google.com/search?name=bob&q=something"));
-  EXPECT_TRUE(IsGoogleSearchUrl(
-      "http://www.google.com/search?name=bob#q=something"));
-  EXPECT_TRUE(IsGoogleSearchUrl(
-      "http://www.google.com/search?name=bob#age=24&q=something"));
-  EXPECT_TRUE(IsGoogleSearchUrl(
-      "http://www.google.co.uk/search?q=something"));
+  EXPECT_TRUE(IsSearch("http://www.google.com/search?q=something"));
+  EXPECT_TRUE(IsSearch("http://www.google.com/search#q=something"));
+  EXPECT_TRUE(IsSearch("http://www.google.com/search?name=bob&q=something"));
+  EXPECT_TRUE(IsSearch("http://www.google.com/search?name=bob#q=something"));
+  EXPECT_TRUE(IsSearch("http://www.google.com/search?name=bob#age=24&q=thing"));
+  EXPECT_TRUE(IsSearch("http://www.google.co.uk/search?q=something"));
   // It's actually valid for both to have the query parameter.
-  EXPECT_TRUE(IsGoogleSearchUrl(
-      "http://www.google.com/search?q=something#q=other"));
+  EXPECT_TRUE(IsSearch("http://www.google.com/search?q=something#q=other"));
 
   // Queries with path "/webhp", "/" or "" need to have the query parameter in
   // the hash fragment.
-  EXPECT_TRUE(IsGoogleSearchUrl(
-      "http://www.google.com/webhp#q=something"));
-  EXPECT_TRUE(IsGoogleSearchUrl(
-      "http://www.google.com/webhp#name=bob&q=something"));
-  EXPECT_TRUE(IsGoogleSearchUrl(
-      "http://www.google.com/webhp?name=bob#q=something"));
-  EXPECT_TRUE(IsGoogleSearchUrl(
-      "http://www.google.com/webhp?name=bob#age=24&q=something"));
+  EXPECT_TRUE(IsSearch("http://www.google.com/webhp#q=something"));
+  EXPECT_TRUE(IsSearch("http://www.google.com/webhp#name=bob&q=something"));
+  EXPECT_TRUE(IsSearch("http://www.google.com/webhp?name=bob#q=something"));
+  EXPECT_TRUE(IsSearch("http://www.google.com/webhp?name=bob#age=24&q=thing"));
 
-  EXPECT_TRUE(IsGoogleSearchUrl(
-      "http://www.google.com/#q=something"));
-  EXPECT_TRUE(IsGoogleSearchUrl(
-      "http://www.google.com/#name=bob&q=something"));
-  EXPECT_TRUE(IsGoogleSearchUrl(
-      "http://www.google.com/?name=bob#q=something"));
-  EXPECT_TRUE(IsGoogleSearchUrl(
-      "http://www.google.com/?name=bob#age=24&q=something"));
+  EXPECT_TRUE(IsSearch("http://www.google.com/#q=something"));
+  EXPECT_TRUE(IsSearch("http://www.google.com/#name=bob&q=something"));
+  EXPECT_TRUE(IsSearch("http://www.google.com/?name=bob#q=something"));
+  EXPECT_TRUE(IsSearch("http://www.google.com/?name=bob#age=24&q=something"));
 
-  EXPECT_TRUE(IsGoogleSearchUrl(
-      "http://www.google.com#q=something"));
-  EXPECT_TRUE(IsGoogleSearchUrl(
-      "http://www.google.com#name=bob&q=something"));
-  EXPECT_TRUE(IsGoogleSearchUrl(
-      "http://www.google.com?name=bob#q=something"));
-  EXPECT_TRUE(IsGoogleSearchUrl(
-      "http://www.google.com?name=bob#age=24&q=something"));
+  EXPECT_TRUE(IsSearch("http://www.google.com#q=something"));
+  EXPECT_TRUE(IsSearch("http://www.google.com#name=bob&q=something"));
+  EXPECT_TRUE(IsSearch("http://www.google.com?name=bob#q=something"));
+  EXPECT_TRUE(IsSearch("http://www.google.com?name=bob#age=24&q=something"));
 }
 
 TEST(GoogleUtilTest, GoodSearchPagesSecure) {
   // Queries with path "/search" need to have the query parameter in either
   // the url parameter or the hash fragment.
-  EXPECT_TRUE(IsGoogleSearchUrl(
-      "https://www.google.com/search?q=something"));
-  EXPECT_TRUE(IsGoogleSearchUrl(
-      "https://www.google.com/search#q=something"));
-  EXPECT_TRUE(IsGoogleSearchUrl(
-      "https://www.google.com/search?name=bob&q=something"));
-  EXPECT_TRUE(IsGoogleSearchUrl(
-      "https://www.google.com/search?name=bob#q=something"));
-  EXPECT_TRUE(IsGoogleSearchUrl(
-      "https://www.google.com/search?name=bob#age=24&q=something"));
-  EXPECT_TRUE(IsGoogleSearchUrl(
-      "https://www.google.co.uk/search?q=something"));
+  EXPECT_TRUE(IsSearch("https://www.google.com/search?q=something"));
+  EXPECT_TRUE(IsSearch("https://www.google.com/search#q=something"));
+  EXPECT_TRUE(IsSearch("https://www.google.com/search?name=bob&q=something"));
+  EXPECT_TRUE(IsSearch("https://www.google.com/search?name=bob#q=something"));
+  EXPECT_TRUE(IsSearch("https://www.google.com/search?name=bob#age=24&q=q"));
+  EXPECT_TRUE(IsSearch("https://www.google.co.uk/search?q=something"));
   // It's actually valid for both to have the query parameter.
-  EXPECT_TRUE(IsGoogleSearchUrl(
-      "https://www.google.com/search?q=something#q=other"));
+  EXPECT_TRUE(IsSearch("https://www.google.com/search?q=something#q=other"));
 
   // Queries with path "/webhp", "/" or "" need to have the query parameter in
   // the hash fragment.
-  EXPECT_TRUE(IsGoogleSearchUrl(
-      "https://www.google.com/webhp#q=something"));
-  EXPECT_TRUE(IsGoogleSearchUrl(
-      "https://www.google.com/webhp#name=bob&q=something"));
-  EXPECT_TRUE(IsGoogleSearchUrl(
-      "https://www.google.com/webhp?name=bob#q=something"));
-  EXPECT_TRUE(IsGoogleSearchUrl(
-      "https://www.google.com/webhp?name=bob#age=24&q=something"));
+  EXPECT_TRUE(IsSearch("https://www.google.com/webhp#q=something"));
+  EXPECT_TRUE(IsSearch("https://www.google.com/webhp#name=bob&q=something"));
+  EXPECT_TRUE(IsSearch("https://www.google.com/webhp?name=bob#q=something"));
+  EXPECT_TRUE(IsSearch("https://www.google.com/webhp?name=bob#age=24&q=thing"));
 
-  EXPECT_TRUE(IsGoogleSearchUrl(
-      "https://www.google.com/#q=something"));
-  EXPECT_TRUE(IsGoogleSearchUrl(
-      "https://www.google.com/#name=bob&q=something"));
-  EXPECT_TRUE(IsGoogleSearchUrl(
-      "https://www.google.com/?name=bob#q=something"));
-  EXPECT_TRUE(IsGoogleSearchUrl(
-      "https://www.google.com/?name=bob#age=24&q=something"));
+  EXPECT_TRUE(IsSearch("https://www.google.com/#q=something"));
+  EXPECT_TRUE(IsSearch("https://www.google.com/#name=bob&q=something"));
+  EXPECT_TRUE(IsSearch("https://www.google.com/?name=bob#q=something"));
+  EXPECT_TRUE(IsSearch("https://www.google.com/?name=bob#age=24&q=something"));
 
-  EXPECT_TRUE(IsGoogleSearchUrl(
-      "https://www.google.com#q=something"));
-  EXPECT_TRUE(IsGoogleSearchUrl(
-      "https://www.google.com#name=bob&q=something"));
-  EXPECT_TRUE(IsGoogleSearchUrl(
-      "https://www.google.com?name=bob#q=something"));
-  EXPECT_TRUE(IsGoogleSearchUrl(
-      "https://www.google.com?name=bob#age=24&q=something"));
+  EXPECT_TRUE(IsSearch("https://www.google.com#q=something"));
+  EXPECT_TRUE(IsSearch("https://www.google.com#name=bob&q=something"));
+  EXPECT_TRUE(IsSearch("https://www.google.com?name=bob#q=something"));
+  EXPECT_TRUE(IsSearch("https://www.google.com?name=bob#age=24&q=something"));
 }
 
 TEST(GoogleUtilTest, BadSearches) {
   // A home page URL should not be identified as a search URL.
-  EXPECT_FALSE(IsGoogleSearchUrl(GoogleURLTracker::kDefaultGoogleHomepage));
-  EXPECT_FALSE(IsGoogleSearchUrl("http://google.com"));
-  EXPECT_FALSE(IsGoogleSearchUrl("http://www.google.com"));
-  EXPECT_FALSE(IsGoogleSearchUrl("http://www.google.com/search"));
-  EXPECT_FALSE(IsGoogleSearchUrl("http://www.google.com/search?"));
+  EXPECT_FALSE(IsSearch(GoogleURLTracker::kDefaultGoogleHomepage));
+  EXPECT_FALSE(IsSearch("http://google.com"));
+  EXPECT_FALSE(IsSearch("http://www.google.com"));
+  EXPECT_FALSE(IsSearch("http://www.google.com/search"));
+  EXPECT_FALSE(IsSearch("http://www.google.com/search?"));
 
   // Must be http or https
-  EXPECT_FALSE(IsGoogleSearchUrl(
-      "ftp://www.google.com/search?q=something"));
-  EXPECT_FALSE(IsGoogleSearchUrl(
-      "file://does/not/exist/search?q=something"));
-  EXPECT_FALSE(IsGoogleSearchUrl(
-      "bad://www.google.com/search?q=something"));
-  EXPECT_FALSE(IsGoogleSearchUrl(
-      "www.google.com/search?q=something"));
+  EXPECT_FALSE(IsSearch("ftp://www.google.com/search?q=something"));
+  EXPECT_FALSE(IsSearch("file://does/not/exist/search?q=something"));
+  EXPECT_FALSE(IsSearch("bad://www.google.com/search?q=something"));
+  EXPECT_FALSE(IsSearch("www.google.com/search?q=something"));
 
   // Can't have an empty query parameter.
-  EXPECT_FALSE(IsGoogleSearchUrl(
-      "http://www.google.com/search?q="));
-  EXPECT_FALSE(IsGoogleSearchUrl(
-      "http://www.google.com/search?name=bob&q="));
-  EXPECT_FALSE(IsGoogleSearchUrl(
-      "http://www.google.com/webhp#q="));
-  EXPECT_FALSE(IsGoogleSearchUrl(
-      "http://www.google.com/webhp#name=bob&q="));
+  EXPECT_FALSE(IsSearch("http://www.google.com/search?q="));
+  EXPECT_FALSE(IsSearch("http://www.google.com/search?name=bob&q="));
+  EXPECT_FALSE(IsSearch("http://www.google.com/webhp#q="));
+  EXPECT_FALSE(IsSearch("http://www.google.com/webhp#name=bob&q="));
 
   // Home page searches without a hash fragment query parameter are invalid.
-  EXPECT_FALSE(IsGoogleSearchUrl(
-      "http://www.google.com/webhp?q=something"));
-  EXPECT_FALSE(IsGoogleSearchUrl(
-      "http://www.google.com/webhp?q=something#no=good"));
-  EXPECT_FALSE(IsGoogleSearchUrl(
-      "http://www.google.com/webhp?name=bob&q=something"));
-  EXPECT_FALSE(IsGoogleSearchUrl(
-      "http://www.google.com/?q=something"));
-  EXPECT_FALSE(IsGoogleSearchUrl(
-      "http://www.google.com?q=something"));
+  EXPECT_FALSE(IsSearch("http://www.google.com/webhp?q=something"));
+  EXPECT_FALSE(IsSearch("http://www.google.com/webhp?q=something#no=good"));
+  EXPECT_FALSE(IsSearch("http://www.google.com/webhp?name=bob&q=something"));
+  EXPECT_FALSE(IsSearch("http://www.google.com/?q=something"));
+  EXPECT_FALSE(IsSearch("http://www.google.com?q=something"));
 
   // Some paths are outright invalid as searches.
-  EXPECT_FALSE(IsGoogleSearchUrl(
-      "http://www.google.com/notreal?q=something"));
-  EXPECT_FALSE(IsGoogleSearchUrl(
-      "http://www.google.com/chrome?q=something"));
-  EXPECT_FALSE(IsGoogleSearchUrl(
-      "http://www.google.com/search/nogood?q=something"));
-  EXPECT_FALSE(IsGoogleSearchUrl(
-      "http://www.google.com/webhp/nogood#q=something"));
-  EXPECT_FALSE(IsGoogleSearchUrl(std::string()));
+  EXPECT_FALSE(IsSearch("http://www.google.com/notreal?q=something"));
+  EXPECT_FALSE(IsSearch("http://www.google.com/chrome?q=something"));
+  EXPECT_FALSE(IsSearch("http://www.google.com/search/nogood?q=something"));
+  EXPECT_FALSE(IsSearch("http://www.google.com/webhp/nogood#q=something"));
+  EXPECT_FALSE(IsSearch(std::string()));
 
   // Case sensitive paths.
-  EXPECT_FALSE(IsGoogleSearchUrl(
-      "http://www.google.com/SEARCH?q=something"));
-  EXPECT_FALSE(IsGoogleSearchUrl(
-      "http://www.google.com/WEBHP#q=something"));
+  EXPECT_FALSE(IsSearch("http://www.google.com/SEARCH?q=something"));
+  EXPECT_FALSE(IsSearch("http://www.google.com/WEBHP#q=something"));
 }
 
 TEST(GoogleUtilTest, GoogleDomains) {
   // Test some good Google domains (valid TLDs).
-  EXPECT_TRUE(IsGoogleDomainUrl("http://www.google.com",
+  EXPECT_TRUE(IsGoogleDomainUrl(GURL("http://www.google.com"),
                                 google_util::ALLOW_SUBDOMAIN,
                                 google_util::DISALLOW_NON_STANDARD_PORTS));
-  EXPECT_TRUE(IsGoogleDomainUrl("http://google.com",
+  EXPECT_TRUE(IsGoogleDomainUrl(GURL("http://google.com"),
                                 google_util::ALLOW_SUBDOMAIN,
                                 google_util::DISALLOW_NON_STANDARD_PORTS));
-  EXPECT_TRUE(IsGoogleDomainUrl("http://www.google.ca",
+  EXPECT_TRUE(IsGoogleDomainUrl(GURL("http://www.google.ca"),
                                 google_util::ALLOW_SUBDOMAIN,
                                 google_util::DISALLOW_NON_STANDARD_PORTS));
-  EXPECT_TRUE(IsGoogleDomainUrl("http://www.google.biz.tj",
+  EXPECT_TRUE(IsGoogleDomainUrl(GURL("http://www.google.biz.tj"),
                                 google_util::ALLOW_SUBDOMAIN,
                                 google_util::DISALLOW_NON_STANDARD_PORTS));
-  EXPECT_TRUE(IsGoogleDomainUrl("http://www.google.com/search?q=something",
+  EXPECT_TRUE(IsGoogleDomainUrl(GURL("http://www.google.com/search?q=thing"),
                                 google_util::ALLOW_SUBDOMAIN,
                                 google_util::DISALLOW_NON_STANDARD_PORTS));
-  EXPECT_TRUE(IsGoogleDomainUrl("http://www.google.com/webhp",
+  EXPECT_TRUE(IsGoogleDomainUrl(GURL("http://www.google.com/webhp"),
                                 google_util::ALLOW_SUBDOMAIN,
                                 google_util::DISALLOW_NON_STANDARD_PORTS));
 
   // Test some bad Google domains (invalid TLDs).
-  EXPECT_FALSE(IsGoogleDomainUrl("http://www.google.notrealtld",
+  EXPECT_FALSE(IsGoogleDomainUrl(GURL("http://www.google.notrealtld"),
                                  google_util::ALLOW_SUBDOMAIN,
                                  google_util::DISALLOW_NON_STANDARD_PORTS));
-  EXPECT_FALSE(IsGoogleDomainUrl("http://www.google.faketld/search?q=something",
+  EXPECT_FALSE(IsGoogleDomainUrl(GURL("http://www.google.faketld/search?q=q"),
                                  google_util::ALLOW_SUBDOMAIN,
                                  google_util::DISALLOW_NON_STANDARD_PORTS));
-  EXPECT_FALSE(IsGoogleDomainUrl("http://www.yahoo.com",
+  EXPECT_FALSE(IsGoogleDomainUrl(GURL("http://www.yahoo.com"),
                                  google_util::ALLOW_SUBDOMAIN,
                                  google_util::DISALLOW_NON_STANDARD_PORTS));
 
   // Test subdomain checks.
-  EXPECT_TRUE(IsGoogleDomainUrl("http://images.google.com",
+  EXPECT_TRUE(IsGoogleDomainUrl(GURL("http://images.google.com"),
                                 google_util::ALLOW_SUBDOMAIN,
                                 google_util::DISALLOW_NON_STANDARD_PORTS));
-  EXPECT_FALSE(IsGoogleDomainUrl("http://images.google.com",
+  EXPECT_FALSE(IsGoogleDomainUrl(GURL("http://images.google.com"),
                                  google_util::DISALLOW_SUBDOMAIN,
                                  google_util::DISALLOW_NON_STANDARD_PORTS));
-  EXPECT_TRUE(IsGoogleDomainUrl("http://google.com",
+  EXPECT_TRUE(IsGoogleDomainUrl(GURL("http://google.com"),
                                 google_util::DISALLOW_SUBDOMAIN,
                                 google_util::DISALLOW_NON_STANDARD_PORTS));
-  EXPECT_TRUE(IsGoogleDomainUrl("http://www.google.com",
+  EXPECT_TRUE(IsGoogleDomainUrl(GURL("http://www.google.com"),
                                 google_util::DISALLOW_SUBDOMAIN,
                                 google_util::DISALLOW_NON_STANDARD_PORTS));
 
   // Port and scheme checks.
-  EXPECT_TRUE(IsGoogleDomainUrl("http://www.google.com:80",
+  EXPECT_TRUE(IsGoogleDomainUrl(GURL("http://www.google.com:80"),
                                 google_util::DISALLOW_SUBDOMAIN,
                                 google_util::DISALLOW_NON_STANDARD_PORTS));
-  EXPECT_FALSE(IsGoogleDomainUrl("http://www.google.com:123",
+  EXPECT_FALSE(IsGoogleDomainUrl(GURL("http://www.google.com:123"),
                                  google_util::DISALLOW_SUBDOMAIN,
                                  google_util::DISALLOW_NON_STANDARD_PORTS));
-  EXPECT_TRUE(IsGoogleDomainUrl("https://www.google.com:443",
+  EXPECT_TRUE(IsGoogleDomainUrl(GURL("https://www.google.com:443"),
                                 google_util::DISALLOW_SUBDOMAIN,
                                 google_util::DISALLOW_NON_STANDARD_PORTS));
-  EXPECT_FALSE(IsGoogleDomainUrl("http://www.google.com:123",
+  EXPECT_FALSE(IsGoogleDomainUrl(GURL("http://www.google.com:123"),
                                  google_util::DISALLOW_SUBDOMAIN,
                                  google_util::DISALLOW_NON_STANDARD_PORTS));
-  EXPECT_TRUE(IsGoogleDomainUrl("http://www.google.com:123",
+  EXPECT_TRUE(IsGoogleDomainUrl(GURL("http://www.google.com:123"),
                                 google_util::DISALLOW_SUBDOMAIN,
                                 google_util::ALLOW_NON_STANDARD_PORTS));
-  EXPECT_TRUE(IsGoogleDomainUrl("https://www.google.com:123",
+  EXPECT_TRUE(IsGoogleDomainUrl(GURL("https://www.google.com:123"),
                                 google_util::DISALLOW_SUBDOMAIN,
                                 google_util::ALLOW_NON_STANDARD_PORTS));
-  EXPECT_TRUE(IsGoogleDomainUrl("http://www.google.com:80",
+  EXPECT_TRUE(IsGoogleDomainUrl(GURL("http://www.google.com:80"),
                                 google_util::DISALLOW_SUBDOMAIN,
                                 google_util::ALLOW_NON_STANDARD_PORTS));
-  EXPECT_TRUE(IsGoogleDomainUrl("https://www.google.com:443",
+  EXPECT_TRUE(IsGoogleDomainUrl(GURL("https://www.google.com:443"),
                                 google_util::DISALLOW_SUBDOMAIN,
                                 google_util::ALLOW_NON_STANDARD_PORTS));
-  EXPECT_FALSE(IsGoogleDomainUrl("file://www.google.com",
+  EXPECT_FALSE(IsGoogleDomainUrl(GURL("file://www.google.com"),
                                  google_util::DISALLOW_SUBDOMAIN,
                                  google_util::DISALLOW_NON_STANDARD_PORTS));
-  EXPECT_FALSE(IsGoogleDomainUrl("doesnotexist://www.google.com",
+  EXPECT_FALSE(IsGoogleDomainUrl(GURL("doesnotexist://www.google.com"),
                                  google_util::DISALLOW_SUBDOMAIN,
                                  google_util::DISALLOW_NON_STANDARD_PORTS));
+}
 
-  // Test overriding with --instant-url works.
-  EXPECT_FALSE(IsGoogleDomainUrl("http://test.foo.com",
+TEST(GoogleUtilTest, GoogleBaseURL) {
+  // When no command-line flag is specified, no input to
+  // StartsWithCommandLineGoogleBaseURL() should return true.
+  EXPECT_FALSE(StartsWithBaseURL(std::string()));
+  EXPECT_FALSE(StartsWithBaseURL("http://www.foo.com/"));
+  EXPECT_FALSE(StartsWithBaseURL("http://www.google.com/"));
+
+  // By default, none of the IsGoogleXXX functions should return true for a
+  // "foo.com" URL.
+  EXPECT_FALSE(IsGoogleHostname("www.foo.com",
+                                google_util::DISALLOW_SUBDOMAIN));
+  EXPECT_FALSE(IsGoogleDomainUrl(GURL("http://www.foo.com/xyz"),
                                  google_util::DISALLOW_SUBDOMAIN,
                                  google_util::DISALLOW_NON_STANDARD_PORTS));
-  EXPECT_FALSE(IsGoogleDomainUrl("http://test.foo.com:1234",
+  EXPECT_FALSE(IsGoogleDomainUrl(GURL("https://www.foo.com/"),
                                  google_util::DISALLOW_SUBDOMAIN,
                                  google_util::DISALLOW_NON_STANDARD_PORTS));
-  CommandLine::ForCurrentProcess()->AppendSwitchASCII(
-      switches::kInstantURL, "http://test.foo.com:1234/bar");
-  EXPECT_FALSE(IsGoogleDomainUrl("http://test.foo.com",
-                                 google_util::DISALLOW_SUBDOMAIN,
-                                 google_util::DISALLOW_NON_STANDARD_PORTS));
-  EXPECT_TRUE(IsGoogleDomainUrl("http://test.foo.com:1234",
+  EXPECT_FALSE(IsHomePage("https://www.foo.com/webhp"));
+  EXPECT_FALSE(IsSearch("http://www.foo.com/search?q=a"));
+
+  // Override the Google base URL on the command line.
+  CommandLine::ForCurrentProcess()->AppendSwitchASCII(switches::kGoogleBaseURL,
+                                                      "http://www.foo.com/");
+
+  // Only URLs which start with exactly the string on the command line should
+  // cause StartsWithCommandLineGoogleBaseURL() to return true.
+  EXPECT_FALSE(StartsWithBaseURL(std::string()));
+  EXPECT_TRUE(StartsWithBaseURL("http://www.foo.com/"));
+  EXPECT_TRUE(StartsWithBaseURL("http://www.foo.com/abc"));
+  EXPECT_FALSE(StartsWithBaseURL("https://www.foo.com/"));
+  EXPECT_FALSE(StartsWithBaseURL("http://www.google.com/"));
+
+  // The various IsGoogleXXX functions should respect the command-line flag.
+  EXPECT_TRUE(IsGoogleHostname("www.foo.com", google_util::DISALLOW_SUBDOMAIN));
+  EXPECT_FALSE(IsGoogleHostname("foo.com", google_util::ALLOW_SUBDOMAIN));
+  EXPECT_TRUE(IsGoogleDomainUrl(GURL("http://www.foo.com/xyz"),
                                 google_util::DISALLOW_SUBDOMAIN,
                                 google_util::DISALLOW_NON_STANDARD_PORTS));
-  EXPECT_FALSE(IsGoogleDomainUrl("file://test.foo.com:1234",
-                                 google_util::DISALLOW_SUBDOMAIN,
-                                 google_util::DISALLOW_NON_STANDARD_PORTS));
-  EXPECT_TRUE(IsGoogleDomainUrl("http://www.google.com",
+  EXPECT_TRUE(IsGoogleDomainUrl(GURL("https://www.foo.com/"),
                                 google_util::DISALLOW_SUBDOMAIN,
                                 google_util::DISALLOW_NON_STANDARD_PORTS));
+  EXPECT_TRUE(IsHomePage("https://www.foo.com/webhp"));
+  EXPECT_FALSE(IsHomePage("http://www.foo.com/xyz"));
+  EXPECT_TRUE(IsSearch("http://www.foo.com/search?q=a"));
 }
diff --git a/chrome/browser/google_apis/DEPS b/chrome/browser/google_apis/DEPS
index d24803e..3fc08f4 100644
--- a/chrome/browser/google_apis/DEPS
+++ b/chrome/browser/google_apis/DEPS
@@ -3,17 +3,19 @@
   "-content",
   "+chrome/browser/google_apis",
 
-  # Temporarily needed, see http://crbug.com/146989
+  # BrowserThread should be gone: crbug.com/256112
   "!content/public/browser/browser_thread.h",
 ]
 
+# Exceptions are temporarily needed. crbug.com/146989
 specific_include_rules = {
-  ".*_[a-z]+test\.cc": [
-    # Temporarily needed, see http://crbug.com/146989
-    "!chrome/browser/chromeos/system/timezone_settings.h",
+  ".*requests.*unittest\.cc": [
+    # This is necessary for AuthService. See below.
     "!chrome/test/base/testing_profile.h",
+    # TestBrowserThreadBundle should be gone: crbug.com/256109
     "!content/public/test/test_browser_thread_bundle.h",
   ],
+  # AuthService should be gone. crbug.com/162157
   "auth_service\.(h|cc)": [
     "!chrome/browser/profiles/profile.h",
     "!chrome/browser/signin/token_service_factory.h",
diff --git a/chrome/browser/google_apis/auth_service.cc b/chrome/browser/google_apis/auth_service.cc
index 3f019ae..10377f1 100644
--- a/chrome/browser/google_apis/auth_service.cc
+++ b/chrome/browser/google_apis/auth_service.cc
@@ -15,7 +15,6 @@
 #include "chrome/browser/signin/token_service.h"
 #include "chrome/browser/signin/token_service_factory.h"
 #include "chrome/common/chrome_notification_types.h"
-#include "content/public/browser/browser_thread.h"
 #include "content/public/browser/notification_details.h"
 #include "content/public/browser/notification_source.h"
 #include "content/public/browser/notification_types.h"
@@ -28,8 +27,6 @@
 #include "chromeos/login/login_state.h"
 #endif  // OS_CHROMEOS
 
-using content::BrowserThread;
-
 namespace google_apis {
 
 namespace {
@@ -65,6 +62,7 @@
   AuthStatusCallback callback_;
   std::vector<std::string> scopes_;
   scoped_ptr<OAuth2AccessTokenFetcher> oauth2_access_token_fetcher_;
+  base::ThreadChecker thread_checker_;
 
   DISALLOW_COPY_AND_ASSIGN(AuthRequest);
 };
@@ -98,7 +96,7 @@
 // used to start fetching user data.
 void AuthRequest::OnGetTokenSuccess(const std::string& access_token,
                                     const base::Time& expiration_time) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  DCHECK(thread_checker_.CalledOnValidThread());
 
   UMA_HISTOGRAM_ENUMERATION("GData.AuthSuccess",
                             kSuccessRatioHistogramSuccess,
@@ -110,7 +108,7 @@
 
 // Callback for OAuth2AccessTokenFetcher on failure.
 void AuthRequest::OnGetTokenFailure(const GoogleServiceAuthError& error) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  DCHECK(thread_checker_.CalledOnValidThread());
 
   LOG(WARNING) << "AuthRequest: token request using refresh token failed: "
                << error.ToString();
@@ -164,14 +162,14 @@
       url_request_context_getter_(url_request_context_getter),
       scopes_(scopes),
       weak_ptr_factory_(this) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  DCHECK(thread_checker_.CalledOnValidThread());
 }
 
 AuthService::~AuthService() {
 }
 
 void AuthService::StartAuthentication(const AuthStatusCallback& callback) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  DCHECK(thread_checker_.CalledOnValidThread());
   scoped_refptr<base::MessageLoopProxy> relay_proxy(
       base::MessageLoopProxy::current());
 
@@ -220,7 +218,7 @@
 void AuthService::OnAuthCompleted(const AuthStatusCallback& callback,
                                   GDataErrorCode error,
                                   const std::string& access_token) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   if (error == HTTP_SUCCESS) {
diff --git a/chrome/browser/google_apis/auth_service.h b/chrome/browser/google_apis/auth_service.h
index 2ebbc05..8f47ecd 100644
--- a/chrome/browser/google_apis/auth_service.h
+++ b/chrome/browser/google_apis/auth_service.h
@@ -10,6 +10,7 @@
 
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
+#include "base/threading/thread_checker.h"
 #include "chrome/browser/google_apis/auth_service_interface.h"
 #include "chrome/browser/google_apis/gdata_errorcode.h"
 #include "content/public/browser/notification_observer.h"
@@ -79,6 +80,7 @@
   std::string access_token_;
   std::vector<std::string> scopes_;
   ObserverList<AuthServiceObserver> observers_;
+  base::ThreadChecker thread_checker_;
 
   content::NotificationRegistrar registrar_;
 
diff --git a/chrome/browser/google_apis/base_requests.cc b/chrome/browser/google_apis/base_requests.cc
index 0f3dfce..49a5f07 100644
--- a/chrome/browser/google_apis/base_requests.cc
+++ b/chrome/browser/google_apis/base_requests.cc
@@ -44,8 +44,6 @@
 
 // Parse JSON string to base::Value object.
 scoped_ptr<base::Value> ParseJsonOnBlockingPool(const std::string& json) {
-  DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
-
   int error_code = -1;
   std::string error_message;
   scoped_ptr<base::Value> value(base::JSONReader::ReadAndReturnError(
@@ -92,29 +90,10 @@
 
 //============================ UrlFetchRequestBase ===========================
 
-UrlFetchRequestBase::UrlFetchRequestBase(
-    RequestSender* runner,
-    net::URLRequestContextGetter* url_request_context_getter)
-    : RequestRegistry::Request(runner->request_registry()),
-      url_request_context_getter_(url_request_context_getter),
-      re_authenticate_count_(0),
-      started_(false),
-      save_temp_file_(false),
+UrlFetchRequestBase::UrlFetchRequestBase(RequestSender* sender)
+    : re_authenticate_count_(0),
+      sender_(sender),
       weak_ptr_factory_(this) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-}
-
-UrlFetchRequestBase::UrlFetchRequestBase(
-    RequestSender* runner,
-    net::URLRequestContextGetter* url_request_context_getter,
-    const base::FilePath& path)
-    : RequestRegistry::Request(runner->request_registry(), path),
-      url_request_context_getter_(url_request_context_getter),
-      re_authenticate_count_(0),
-      started_(false),
-      save_temp_file_(false),
-      weak_ptr_factory_(this) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
 }
 
 UrlFetchRequestBase::~UrlFetchRequestBase() {}
@@ -122,8 +101,7 @@
 void UrlFetchRequestBase::Start(const std::string& access_token,
                                 const std::string& custom_user_agent,
                                 const ReAuthenticateCallback& callback) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  DCHECK(url_request_context_getter_);
+  DCHECK(CalledOnValidThread());
   DCHECK(!access_token.empty());
   DCHECK(!callback.is_null());
   DCHECK(re_authenticate_callback_.is_null());
@@ -143,17 +121,16 @@
   URLFetcher::RequestType request_type = GetRequestType();
   url_fetcher_.reset(
       URLFetcher::Create(url, request_type, this));
-  url_fetcher_->SetRequestContext(url_request_context_getter_);
+  url_fetcher_->SetRequestContext(sender_->url_request_context_getter());
   // Always set flags to neither send nor save cookies.
   url_fetcher_->SetLoadFlags(
       net::LOAD_DO_NOT_SEND_COOKIES | net::LOAD_DO_NOT_SAVE_COOKIES |
       net::LOAD_DISABLE_CACHE);
-  if (save_temp_file_) {
-    url_fetcher_->SaveResponseToTemporaryFile(
-        BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE));
-  } else if (!output_file_path_.empty()) {
+
+  base::FilePath output_file_path;
+  if (GetOutputFilePath(&output_file_path)) {
     url_fetcher_->SaveResponseToFileAtPath(
-        output_file_path_,
+        output_file_path,
         BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE));
   }
 
@@ -204,11 +181,7 @@
     }
   }
 
-  // Register to request registry.
-  NotifyStart();
-
   url_fetcher_->Start();
-  started_ = true;
 }
 
 URLFetcher::RequestType UrlFetchRequestBase::GetRequestType() const {
@@ -231,9 +204,14 @@
   return false;
 }
 
-void UrlFetchRequestBase::DoCancel() {
+bool UrlFetchRequestBase::GetOutputFilePath(base::FilePath* local_file_path) {
+  return false;
+}
+
+void UrlFetchRequestBase::Cancel() {
   url_fetcher_.reset(NULL);
   RunCallbackOnPrematureFailure(GDATA_CANCELLED);
+  sender_->RequestFinished(this);
 }
 
 // static
@@ -251,8 +229,12 @@
   return code;
 }
 
+bool UrlFetchRequestBase::CalledOnValidThread() {
+  return thread_checker_.CalledOnValidThread();
+}
+
 void UrlFetchRequestBase::OnProcessURLFetchResultsComplete(bool result) {
-  NotifyFinish(result ? REQUEST_COMPLETED : REQUEST_FAILED);
+  sender_->RequestFinished(this);
 }
 
 void UrlFetchRequestBase::OnURLFetchComplete(const URLFetcher* source) {
@@ -278,20 +260,7 @@
 
 void UrlFetchRequestBase::OnAuthFailed(GDataErrorCode code) {
   RunCallbackOnPrematureFailure(code);
-
-  // Check if this failed before we even started fetching. If so, register
-  // for start so we can properly unregister with finish.
-  if (!started_)
-    NotifyStart();
-
-  // Note: NotifyFinish() must be invoked at the end, after all other callbacks
-  // and notifications. Once NotifyFinish() is called, the current instance of
-  // request will be deleted from the RequestRegistry and become invalid.
-  NotifyFinish(REQUEST_FAILED);
-}
-
-RequestRegistry::Request* UrlFetchRequestBase::AsRequestRegistryRequest() {
-  return this;
+  sender_->RequestFinished(this);
 }
 
 base::WeakPtr<AuthenticatedRequestInterface>
@@ -301,11 +270,9 @@
 
 //============================ EntryActionRequest ============================
 
-EntryActionRequest::EntryActionRequest(
-    RequestSender* runner,
-    net::URLRequestContextGetter* url_request_context_getter,
-    const EntryActionCallback& callback)
-    : UrlFetchRequestBase(runner, url_request_context_getter),
+EntryActionRequest::EntryActionRequest(RequestSender* sender,
+                                       const EntryActionCallback& callback)
+    : UrlFetchRequestBase(sender),
       callback_(callback) {
   DCHECK(!callback_.is_null());
 }
@@ -325,11 +292,9 @@
 
 //============================== GetDataRequest ==============================
 
-GetDataRequest::GetDataRequest(
-    RequestSender* runner,
-    net::URLRequestContextGetter* url_request_context_getter,
-    const GetDataCallback& callback)
-    : UrlFetchRequestBase(runner, url_request_context_getter),
+GetDataRequest::GetDataRequest(RequestSender* sender,
+                               const GetDataCallback& callback)
+    : UrlFetchRequestBase(sender),
       callback_(callback),
       weak_ptr_factory_(this) {
   DCHECK(!callback_.is_null());
@@ -339,7 +304,7 @@
 
 void GetDataRequest::ParseResponse(GDataErrorCode fetch_error_code,
                                    const std::string& data) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  DCHECK(CalledOnValidThread());
 
   VLOG(1) << "JSON received from " << GetURL().spec() << ": "
           << data.size() << " bytes";
@@ -373,10 +338,9 @@
   callback_.Run(fetch_error_code, scoped_ptr<base::Value>());
 }
 
-void GetDataRequest::OnDataParsed(
-    GDataErrorCode fetch_error_code,
-    scoped_ptr<base::Value> value) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+void GetDataRequest::OnDataParsed(GDataErrorCode fetch_error_code,
+                                  scoped_ptr<base::Value> value) {
+  DCHECK(CalledOnValidThread());
 
   bool success = true;
   if (!value.get()) {
@@ -392,24 +356,19 @@
 
 void GetDataRequest::RunCallbackOnSuccess(GDataErrorCode fetch_error_code,
                                           scoped_ptr<base::Value> value) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  DCHECK(CalledOnValidThread());
   callback_.Run(fetch_error_code, value.Pass());
 }
 
 //========================= InitiateUploadRequestBase ========================
 
 InitiateUploadRequestBase::InitiateUploadRequestBase(
-    RequestSender* runner,
-    net::URLRequestContextGetter* url_request_context_getter,
+    RequestSender* sender,
     const InitiateUploadCallback& callback,
-    const base::FilePath& drive_file_path,
     const std::string& content_type,
     int64 content_length)
-    : UrlFetchRequestBase(runner,
-                          url_request_context_getter,
-                          drive_file_path),
+    : UrlFetchRequestBase(sender),
       callback_(callback),
-      drive_file_path_(drive_file_path),
       content_type_(content_type),
       content_length_(content_length) {
   DCHECK(!callback_.is_null());
@@ -430,9 +389,6 @@
                                                   kUploadResponseLocation,
                                                   &upload_location);
   }
-  VLOG(1) << "Got response for [" << drive_file_path_.value()
-          << "]: code=" << code
-          << ", location=[" << upload_location << "]";
 
   callback_.Run(code, GURL(upload_location));
   OnProcessURLFetchResultsComplete(code == HTTP_SUCCESS);
@@ -473,15 +429,9 @@
 
 //========================== UploadRangeRequestBase ==========================
 
-UploadRangeRequestBase::UploadRangeRequestBase(
-    RequestSender* runner,
-    net::URLRequestContextGetter* url_request_context_getter,
-    const base::FilePath& drive_file_path,
-    const GURL& upload_url)
-    : UrlFetchRequestBase(runner,
-                          url_request_context_getter,
-                          drive_file_path),
-      drive_file_path_(drive_file_path),
+UploadRangeRequestBase::UploadRangeRequestBase(RequestSender* sender,
+                                               const GURL& upload_url)
+    : UrlFetchRequestBase(sender),
       upload_url_(upload_url),
       weak_ptr_factory_(this) {
 }
@@ -528,11 +478,6 @@
     // The Range header has the received data range, so the start position
     // should be always 0.
     DCHECK_EQ(start_position_received, 0);
-    DVLOG(1) << "Got response for [" << drive_file_path_.value()
-             << "]: code=" << code
-             << ", range_hdr=[" << range_received
-             << "], range_parsed=" << start_position_received
-             << "," << end_position_received;
 
     OnRangeRequestComplete(UploadRangeResponse(code,
                                                start_position_received,
@@ -544,9 +489,6 @@
     // There might be explanation of unexpected error code in response.
     std::string response_content;
     source->GetResponseAsString(&response_content);
-    DVLOG(1) << "Got response for [" << drive_file_path_.value()
-             << "]: code=" << code
-             << ", content=[\n" << response_content << "\n]";
 
     ParseJson(response_content,
               base::Bind(&UploadRangeRequestBase::OnDataParsed,
@@ -557,7 +499,7 @@
 
 void UploadRangeRequestBase::OnDataParsed(GDataErrorCode code,
                                           scoped_ptr<base::Value> value) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  DCHECK(CalledOnValidThread());
 
   OnRangeRequestComplete(UploadRangeResponse(code, -1, -1), value.Pass());
   OnProcessURLFetchResultsComplete(
@@ -573,19 +515,14 @@
 //========================== ResumeUploadRequestBase =========================
 
 ResumeUploadRequestBase::ResumeUploadRequestBase(
-    RequestSender* runner,
-    net::URLRequestContextGetter* url_request_context_getter,
-    const base::FilePath& drive_file_path,
+    RequestSender* sender,
     const GURL& upload_location,
     int64 start_position,
     int64 end_position,
     int64 content_length,
     const std::string& content_type,
     const base::FilePath& local_file_path)
-    : UploadRangeRequestBase(runner,
-                             url_request_context_getter,
-                             drive_file_path,
-                             upload_location),
+    : UploadRangeRequestBase(sender, upload_location),
       start_position_(start_position),
       end_position_(end_position),
       content_length_(content_length),
@@ -642,16 +579,10 @@
 
 //======================== GetUploadStatusRequestBase ========================
 
-GetUploadStatusRequestBase::GetUploadStatusRequestBase(
-    RequestSender* runner,
-    net::URLRequestContextGetter* url_request_context_getter,
-    const base::FilePath& drive_file_path,
-    const GURL& upload_url,
-    int64 content_length)
-    : UploadRangeRequestBase(runner,
-                             url_request_context_getter,
-                             drive_file_path,
-                             upload_url),
+GetUploadStatusRequestBase::GetUploadStatusRequestBase(RequestSender* sender,
+                                                       const GURL& upload_url,
+                                                       int64 content_length)
+    : UploadRangeRequestBase(sender, upload_url),
       content_length_(content_length) {}
 
 GetUploadStatusRequestBase::~GetUploadStatusRequestBase() {}
@@ -671,60 +602,60 @@
   return headers;
 }
 
-//============================ DownloadFileRequest ===========================
+//============================ DownloadFileRequestBase =========================
 
-DownloadFileRequest::DownloadFileRequest(
-    RequestSender* runner,
-    net::URLRequestContextGetter* url_request_context_getter,
+DownloadFileRequestBase::DownloadFileRequestBase(
+    RequestSender* sender,
     const DownloadActionCallback& download_action_callback,
     const GetContentCallback& get_content_callback,
     const ProgressCallback& progress_callback,
     const GURL& download_url,
-    const base::FilePath& drive_file_path,
     const base::FilePath& output_file_path)
-    : UrlFetchRequestBase(runner,
-                          url_request_context_getter,
-                          drive_file_path),
+    : UrlFetchRequestBase(sender),
       download_action_callback_(download_action_callback),
       get_content_callback_(get_content_callback),
       progress_callback_(progress_callback),
-      download_url_(download_url) {
+      download_url_(download_url),
+      output_file_path_(output_file_path) {
   DCHECK(!download_action_callback_.is_null());
+  DCHECK(!output_file_path_.empty());
   // get_content_callback may be null.
-
-  // Make sure we download the content into a temp file.
-  if (output_file_path.empty())
-    set_save_temp_file(true);
-  else
-    set_output_file_path(output_file_path);
 }
 
-DownloadFileRequest::~DownloadFileRequest() {}
+DownloadFileRequestBase::~DownloadFileRequestBase() {}
 
 // Overridden from UrlFetchRequestBase.
-GURL DownloadFileRequest::GetURL() const {
+GURL DownloadFileRequestBase::GetURL() const {
   return download_url_;
 }
 
-void DownloadFileRequest::OnURLFetchDownloadProgress(const URLFetcher* source,
-                                                     int64 current,
-                                                     int64 total) {
+bool DownloadFileRequestBase::GetOutputFilePath(
+    base::FilePath* local_file_path) {
+  // Configure so that the downloaded content is saved to |output_file_path_|.
+  *local_file_path = output_file_path_;
+  return true;
+}
+
+void DownloadFileRequestBase::OnURLFetchDownloadProgress(
+    const URLFetcher* source,
+    int64 current,
+    int64 total) {
   if (!progress_callback_.is_null())
     progress_callback_.Run(current, total);
 }
 
-bool DownloadFileRequest::ShouldSendDownloadData() {
+bool DownloadFileRequestBase::ShouldSendDownloadData() {
   return !get_content_callback_.is_null();
 }
 
-void DownloadFileRequest::OnURLFetchDownloadData(
+void DownloadFileRequestBase::OnURLFetchDownloadData(
     const URLFetcher* source,
     scoped_ptr<std::string> download_data) {
   if (!get_content_callback_.is_null())
     get_content_callback_.Run(HTTP_SUCCESS, download_data.Pass());
 }
 
-void DownloadFileRequest::ProcessURLFetchResults(const URLFetcher* source) {
+void DownloadFileRequestBase::ProcessURLFetchResults(const URLFetcher* source) {
   GDataErrorCode code = GetErrorCode(source);
 
   // Take over the ownership of the the downloaded temp file.
@@ -739,7 +670,8 @@
   OnProcessURLFetchResultsComplete(code == HTTP_SUCCESS);
 }
 
-void DownloadFileRequest::RunCallbackOnPrematureFailure(GDataErrorCode code) {
+void DownloadFileRequestBase::RunCallbackOnPrematureFailure(
+    GDataErrorCode code) {
   download_action_callback_.Run(code, base::FilePath());
 }
 
diff --git a/chrome/browser/google_apis/base_requests.h b/chrome/browser/google_apis/base_requests.h
index f187b15..d57a6c6 100644
--- a/chrome/browser/google_apis/base_requests.h
+++ b/chrome/browser/google_apis/base_requests.h
@@ -12,21 +12,18 @@
 #include <vector>
 
 #include "base/callback.h"
+#include "base/files/file_path.h"
 #include "base/memory/weak_ptr.h"
+#include "base/threading/thread_checker.h"
 #include "chrome/browser/google_apis/gdata_errorcode.h"
-#include "chrome/browser/google_apis/request_registry.h"
-#include "googleurl/src/gurl.h"
 #include "net/url_request/url_fetcher.h"
 #include "net/url_request/url_fetcher_delegate.h"
+#include "url/gurl.h"
 
 namespace base {
 class Value;
 }  // namespace base
 
-namespace net {
-class URLRequestContextGetter;
-}  // namespace net
-
 namespace google_apis {
 
 class RequestSender;
@@ -74,20 +71,18 @@
   // deleted when it is canceled by user action, for posting asynchronous tasks
   // on the authentication request object, weak pointers have to be used.
   // TODO(kinaba): crbug.com/134814 use more clean life time management than
-  // using weak pointers, while deprecating RequestRegistry.
+  // using weak pointers.
   virtual base::WeakPtr<AuthenticatedRequestInterface> GetWeakPtr() = 0;
 
-  // TODO(kinaba): crbug.com/{164089, 231209} This is temporarily added during
-  // migration of cancellation from RequestRegistry to JobScheduler. It should
-  // go away *very soon*.
-  virtual RequestRegistry::Request* AsRequestRegistryRequest() = 0;
+  // Cancels the request. It will invoke the callback object passed in
+  // each request's constructor with error code GDATA_CANCELLED.
+  virtual void Cancel() = 0;
 };
 
 //============================ UrlFetchRequestBase ===========================
 
 // Base class for requests that are fetching URLs.
 class UrlFetchRequestBase : public AuthenticatedRequestInterface,
-                            public RequestRegistry::Request,
                             public net::URLFetcherDelegate {
  public:
   // AuthenticatedRequestInterface overrides.
@@ -95,19 +90,10 @@
                      const std::string& custom_user_agent,
                      const ReAuthenticateCallback& callback) OVERRIDE;
   virtual base::WeakPtr<AuthenticatedRequestInterface> GetWeakPtr() OVERRIDE;
+  virtual void Cancel() OVERRIDE;
 
  protected:
-  UrlFetchRequestBase(
-      RequestSender* runner,
-      net::URLRequestContextGetter* url_request_context_getter);
-  // Use this constructor when you need to implement requests that take a
-  // drive file path (ex. for downloading and uploading).
-  // |url_request_context_getter| is used to initialize URLFetcher.
-  // TODO(satorux): Remove the drive file path hack. crbug.com/163296
-  UrlFetchRequestBase(
-      RequestSender* runner,
-      net::URLRequestContextGetter* url_request_context_getter,
-      const base::FilePath& drive_file_path);
+  explicit UrlFetchRequestBase(RequestSender* sender);
   virtual ~UrlFetchRequestBase();
 
   // Gets URL for the request.
@@ -138,6 +124,10 @@
                               int64* range_length,
                               std::string* upload_content_type);
 
+  // Used by a derived class to set an output file path if they want to save
+  // the downloaded content to a file at a specific path.
+  virtual bool GetOutputFilePath(base::FilePath* local_file_path);
+
   // Invoked by OnURLFetchComplete when the request completes without an
   // authentication error. Must be implemented by a derived class.
   virtual void ProcessURLFetchResults(const net::URLFetcher* source) = 0;
@@ -153,44 +143,28 @@
   // the status of the URLFetcher.
   static GDataErrorCode GetErrorCode(const net::URLFetcher* source);
 
-  // By default, no temporary file will be saved. Derived classes can set
-  // this to true in their constructors, if they want to save the downloaded
-  // content to a temporary file.
-  void set_save_temp_file(bool save_temp_file) {
-    save_temp_file_ = save_temp_file;
-  }
-
-  // By default, no file will be saved. Derived classes can set an output
-  // file path in their constructors, if they want to save the downloaded
-  // content to a file at a specific path.
-  void set_output_file_path(const base::FilePath& output_file_path) {
-    output_file_path_ = output_file_path;
-  }
+  // Returns true if called on the thread where the constructor was called.
+  bool CalledOnValidThread();
 
  private:
-  // RequestRegistry::Request overrides.
-  virtual void DoCancel() OVERRIDE;
-
   // URLFetcherDelegate overrides.
   virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE;
 
   // AuthenticatedRequestInterface overrides.
   virtual void OnAuthFailed(GDataErrorCode code) OVERRIDE;
-  virtual RequestRegistry::Request* AsRequestRegistryRequest() OVERRIDE;
 
-  net::URLRequestContextGetter* url_request_context_getter_;
   ReAuthenticateCallback re_authenticate_callback_;
   int re_authenticate_count_;
   scoped_ptr<net::URLFetcher> url_fetcher_;
-  bool started_;
+  RequestSender* sender_;
 
-  bool save_temp_file_;
-  base::FilePath output_file_path_;
+  base::ThreadChecker thread_checker_;
 
-  // WeakPtrFactory bound to the UI thread.
   // Note: This should remain the last member so it'll be destroyed and
   // invalidate its weak pointers before any other members are destroyed.
   base::WeakPtrFactory<UrlFetchRequestBase> weak_ptr_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(UrlFetchRequestBase);
 };
 
 //============================ EntryActionRequest ============================
@@ -204,10 +178,8 @@
  public:
   // |url_request_context_getter| is used to initialize URLFetcher.
   // |callback| must not be null.
-  EntryActionRequest(
-      RequestSender* runner,
-      net::URLRequestContextGetter* url_request_context_getter,
-      const EntryActionCallback& callback);
+  EntryActionRequest(RequestSender* sender,
+                     const EntryActionCallback& callback);
   virtual ~EntryActionRequest();
 
  protected:
@@ -234,9 +206,7 @@
 class GetDataRequest : public UrlFetchRequestBase {
  public:
   // |callback| must not be null.
-  GetDataRequest(RequestSender* runner,
-                 net::URLRequestContextGetter* url_request_context_getter,
-                 const GetDataCallback& callback);
+  GetDataRequest(RequestSender* sender, const GetDataCallback& callback);
   virtual ~GetDataRequest();
 
   // Parses JSON response.
@@ -263,6 +233,7 @@
   // Note: This should remain the last member so it'll be destroyed and
   // invalidate its weak pointers before any other members are destroyed.
   base::WeakPtrFactory<GetDataRequest> weak_ptr_factory_;
+
   DISALLOW_COPY_AND_ASSIGN(GetDataRequest);
 };
 
@@ -291,13 +262,10 @@
   // |callback| must not be null.
   // |content_type| and |content_length| should be the attributes of the
   // uploading file.
-  InitiateUploadRequestBase(
-      RequestSender* runner,
-      net::URLRequestContextGetter* url_request_context_getter,
-      const InitiateUploadCallback& callback,
-      const base::FilePath& drive_file_path,
-      const std::string& content_type,
-      int64 content_length);
+  InitiateUploadRequestBase(RequestSender* sender,
+                            const InitiateUploadCallback& callback,
+                            const std::string& content_type,
+                            int64 content_length);
   virtual ~InitiateUploadRequestBase();
 
   // UrlFetchRequestBase overrides.
@@ -307,7 +275,6 @@
 
  private:
   const InitiateUploadCallback callback_;
-  const base::FilePath drive_file_path_;
   const std::string content_type_;
   const int64 content_length_;
 
@@ -341,14 +308,7 @@
 class UploadRangeRequestBase : public UrlFetchRequestBase {
  protected:
   // |upload_location| is the URL of where to upload the file to.
-  // |drive_file_path| is the path to the file seen in the UI. Not necessary
-  // for resuming an upload, but used for adding an entry to RequestRegistry.
-  // TODO(satorux): Remove the drive file path hack. crbug.com/163296
-  UploadRangeRequestBase(
-      RequestSender* runner,
-      net::URLRequestContextGetter* url_request_context_getter,
-      const base::FilePath& drive_file_path,
-      const GURL& upload_url);
+  UploadRangeRequestBase(RequestSender* sender, const GURL& upload_url);
   virtual ~UploadRangeRequestBase();
 
   // UrlFetchRequestBase overrides.
@@ -380,12 +340,12 @@
   // Called when ParseJson() is completed.
   void OnDataParsed(GDataErrorCode code, scoped_ptr<base::Value> value);
 
-  const base::FilePath drive_file_path_;
   const GURL upload_url_;
 
   // Note: This should remain the last member so it'll be destroyed and
   // invalidate its weak pointers before any other members are destroyed.
   base::WeakPtrFactory<UploadRangeRequestBase> weak_ptr_factory_;
+
   DISALLOW_COPY_AND_ASSIGN(UploadRangeRequestBase);
 };
 
@@ -408,17 +368,14 @@
   // file content to be uploaded respectively.
   // |buf| holds current content to be uploaded.
   // See also UploadRangeRequestBase's comment for remaining parameters
-  // meaining.
-  ResumeUploadRequestBase(
-      RequestSender* runner,
-      net::URLRequestContextGetter* url_request_context_getter,
-      const base::FilePath& drive_file_path,
-      const GURL& upload_location,
-      int64 start_position,
-      int64 end_position,
-      int64 content_length,
-      const std::string& content_type,
-      const base::FilePath& local_file_path);
+  // meaning.
+  ResumeUploadRequestBase(RequestSender* sender,
+                          const GURL& upload_location,
+                          int64 start_position,
+                          int64 end_position,
+                          int64 content_length,
+                          const std::string& content_type,
+                          const base::FilePath& local_file_path);
   virtual ~ResumeUploadRequestBase();
 
   // UrlFetchRequestBase overrides.
@@ -454,12 +411,9 @@
   // |content_length| is the whole data size to be uploaded.
   // See also UploadRangeRequestBase's constructor comment for other
   // parameters.
-  GetUploadStatusRequestBase(
-      RequestSender* runner,
-      net::URLRequestContextGetter* url_request_context_getter,
-      const base::FilePath& drive_file_path,
-      const GURL& upload_url,
-      int64 content_length);
+  GetUploadStatusRequestBase(RequestSender* sender,
+                             const GURL& upload_url,
+                             int64 content_length);
   virtual ~GetUploadStatusRequestBase();
 
  protected:
@@ -484,8 +438,8 @@
                             const base::FilePath& temp_file)>
     DownloadActionCallback;
 
-// This class performs the request for downloading of a given document/file.
-class DownloadFileRequest : public UrlFetchRequestBase {
+// This is a base class for performing the request for downloading a file.
+class DownloadFileRequestBase : public UrlFetchRequestBase {
  public:
   // download_action_callback:
   //   This callback is called when the download is complete. Must not be null.
@@ -501,27 +455,22 @@
   // download_url:
   //   Specifies the target file to download.
   //
-  // drive_file_path:
-  //   Specifies the drive path of the target file. Shown in UI.
-  //   TODO(satorux): Remove the drive file path hack. crbug.com/163296
-  //
   // output_file_path:
   //   Specifies the file path to save the downloaded file.
   //
-  DownloadFileRequest(
-      RequestSender* runner,
-      net::URLRequestContextGetter* url_request_context_getter,
+  DownloadFileRequestBase(
+      RequestSender* sender,
       const DownloadActionCallback& download_action_callback,
       const GetContentCallback& get_content_callback,
       const ProgressCallback& progress_callback,
       const GURL& download_url,
-      const base::FilePath& drive_file_path,
       const base::FilePath& output_file_path);
-  virtual ~DownloadFileRequest();
+  virtual ~DownloadFileRequestBase();
 
  protected:
   // UrlFetchRequestBase overrides.
   virtual GURL GetURL() const OVERRIDE;
+  virtual bool GetOutputFilePath(base::FilePath* local_file_path) OVERRIDE;
   virtual void ProcessURLFetchResults(const net::URLFetcher* source) OVERRIDE;
   virtual void RunCallbackOnPrematureFailure(GDataErrorCode code) OVERRIDE;
 
@@ -538,8 +487,9 @@
   const GetContentCallback get_content_callback_;
   const ProgressCallback progress_callback_;
   const GURL download_url_;
+  const base::FilePath output_file_path_;
 
-  DISALLOW_COPY_AND_ASSIGN(DownloadFileRequest);
+  DISALLOW_COPY_AND_ASSIGN(DownloadFileRequestBase);
 };
 
 }  // namespace google_apis
diff --git a/chrome/browser/google_apis/base_requests_server_unittest.cc b/chrome/browser/google_apis/base_requests_server_unittest.cc
index 539f1ad..58f8941 100644
--- a/chrome/browser/google_apis/base_requests_server_unittest.cc
+++ b/chrome/browser/google_apis/base_requests_server_unittest.cc
@@ -7,8 +7,7 @@
 #include "base/bind.h"
 #include "base/file_util.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/message_loop.h"
-#include "base/values.h"
+#include "base/run_loop.h"
 #include "chrome/browser/google_apis/auth_service.h"
 #include "chrome/browser/google_apis/request_sender.h"
 #include "chrome/browser/google_apis/task_util.h"
@@ -60,11 +59,6 @@
                    base::Unretained(&http_request_)));
   }
 
-  virtual void TearDown() OVERRIDE {
-    EXPECT_TRUE(test_server_.ShutdownAndWaitUntilComplete());
-    request_context_getter_ = NULL;
-  }
-
   // Returns a temporary file path suitable for storing the cache file.
   base::FilePath GetTestCachedFilePath(const base::FilePath& file_name) {
     return profile_->GetPath().Append(file_name);
@@ -85,31 +79,32 @@
 TEST_F(BaseRequestsServerTest, DownloadFileRequest_ValidFile) {
   GDataErrorCode result_code = GDATA_OTHER_ERROR;
   base::FilePath temp_file;
-  DownloadFileRequest* request = new DownloadFileRequest(
-      request_sender_.get(),
-      request_context_getter_.get(),
-      CreateComposedCallback(
-          base::Bind(&test_util::RunAndQuit),
-          test_util::CreateCopyResultCallback(&result_code, &temp_file)),
-      GetContentCallback(),
-      ProgressCallback(),
-      test_server_.GetURL("/files/chromeos/gdata/testfile.txt"),
-      base::FilePath::FromUTF8Unsafe("/dummy/gdata/testfile.txt"),
-      GetTestCachedFilePath(
-          base::FilePath::FromUTF8Unsafe("cached_testfile.txt")));
-  request_sender_->StartRequestWithRetry(request);
-  base::MessageLoop::current()->Run();
+  {
+    base::RunLoop run_loop;
+    DownloadFileRequestBase* request = new DownloadFileRequestBase(
+        request_sender_.get(),
+        test_util::CreateQuitCallback(
+            &run_loop,
+            test_util::CreateCopyResultCallback(&result_code, &temp_file)),
+        GetContentCallback(),
+        ProgressCallback(),
+        test_server_.GetURL("/files/gdata/testfile.txt"),
+        GetTestCachedFilePath(
+            base::FilePath::FromUTF8Unsafe("cached_testfile.txt")));
+    request_sender_->StartRequestWithRetry(request);
+    run_loop.Run();
+  }
 
   std::string contents;
   file_util::ReadFileToString(temp_file, &contents);
-  file_util::Delete(temp_file, false);
+  base::Delete(temp_file, false);
 
   EXPECT_EQ(HTTP_SUCCESS, result_code);
   EXPECT_EQ(net::test_server::METHOD_GET, http_request_.method);
-  EXPECT_EQ("/files/chromeos/gdata/testfile.txt", http_request_.relative_url);
+  EXPECT_EQ("/files/gdata/testfile.txt", http_request_.relative_url);
 
   const base::FilePath expected_path =
-      test_util::GetTestFilePath("chromeos/gdata/testfile.txt");
+      test_util::GetTestFilePath("gdata/testfile.txt");
   std::string expected_contents;
   file_util::ReadFileToString(expected_path, &expected_contents);
   EXPECT_EQ(expected_contents, contents);
@@ -118,24 +113,24 @@
 TEST_F(BaseRequestsServerTest, DownloadFileRequest_NonExistentFile) {
   GDataErrorCode result_code = GDATA_OTHER_ERROR;
   base::FilePath temp_file;
-  DownloadFileRequest* request = new DownloadFileRequest(
-      request_sender_.get(),
-      request_context_getter_.get(),
-      CreateComposedCallback(
-          base::Bind(&test_util::RunAndQuit),
-          test_util::CreateCopyResultCallback(&result_code, &temp_file)),
-      GetContentCallback(),
-      ProgressCallback(),
-      test_server_.GetURL("/files/chromeos/gdata/no-such-file.txt"),
-      base::FilePath::FromUTF8Unsafe("/dummy/gdata/no-such-file.txt"),
-      GetTestCachedFilePath(
-          base::FilePath::FromUTF8Unsafe("cache_no-such-file.txt")));
-  request_sender_->StartRequestWithRetry(request);
-  base::MessageLoop::current()->Run();
-
+  {
+    base::RunLoop run_loop;
+    DownloadFileRequestBase* request = new DownloadFileRequestBase(
+        request_sender_.get(),
+        test_util::CreateQuitCallback(
+            &run_loop,
+            test_util::CreateCopyResultCallback(&result_code, &temp_file)),
+        GetContentCallback(),
+        ProgressCallback(),
+        test_server_.GetURL("/files/gdata/no-such-file.txt"),
+        GetTestCachedFilePath(
+            base::FilePath::FromUTF8Unsafe("cache_no-such-file.txt")));
+    request_sender_->StartRequestWithRetry(request);
+    run_loop.Run();
+  }
   EXPECT_EQ(HTTP_NOT_FOUND, result_code);
   EXPECT_EQ(net::test_server::METHOD_GET, http_request_.method);
-  EXPECT_EQ("/files/chromeos/gdata/no-such-file.txt",
+  EXPECT_EQ("/files/gdata/no-such-file.txt",
             http_request_.relative_url);
   // Do not verify the not found message.
 }
diff --git a/chrome/browser/google_apis/base_requests_unittest.cc b/chrome/browser/google_apis/base_requests_unittest.cc
index a0a3f36..a4eb9f0 100644
--- a/chrome/browser/google_apis/base_requests_unittest.cc
+++ b/chrome/browser/google_apis/base_requests_unittest.cc
@@ -22,16 +22,14 @@
 
 class FakeGetDataRequest : public GetDataRequest {
  public:
-  explicit FakeGetDataRequest(RequestSender* runner,
+  explicit FakeGetDataRequest(RequestSender* sender,
                               const GetDataCallback& callback)
-      : GetDataRequest(runner, NULL, callback) {
+      : GetDataRequest(sender, callback) {
   }
 
   virtual ~FakeGetDataRequest() {
   }
 
-  using RequestRegistry::Request::NotifyStart;
-
  protected:
   virtual GURL GetURL() const OVERRIDE {
     NOTREACHED();  // This method is not called in tests.
@@ -43,58 +41,31 @@
 
 class BaseRequestsTest : public testing::Test {
  public:
-  BaseRequestsTest()
-      : parse_json_callback_called_(false),
-        get_data_callback_called_(false) {
-  }
-
-  void ParseJsonCallback(scoped_ptr<base::Value> value) {
-    parse_json_result_ = value.Pass();;
-    parse_json_callback_called_ = true;
-  }
-
-  void GetDataCallback(GDataErrorCode error, scoped_ptr<base::Value> value) {
-    get_data_result_error_ = error;
-    get_data_result_value_ = value.Pass();
-    get_data_callback_called_ = true;
-  }
-
   virtual void SetUp() OVERRIDE {
     profile_.reset(new TestingProfile);
-    runner_.reset(new RequestSender(profile_.get(),
+    sender_.reset(new RequestSender(profile_.get(),
                                     NULL /* url_request_context_getter */,
                                     std::vector<std::string>() /* scopes */,
                                     std::string() /* custom user agent */));
-    runner_->Initialize();
-    LOG(ERROR) << "Initialized.";
+    sender_->Initialize();
   }
 
   content::TestBrowserThreadBundle thread_bundle_;
   scoped_ptr<TestingProfile> profile_;
-  scoped_ptr<RequestSender> runner_;
-
-  // Following members stores data returned with callbacks to be verified
-  // by tests.
-  scoped_ptr<base::Value> parse_json_result_;
-  bool parse_json_callback_called_;
-  GDataErrorCode get_data_result_error_;
-  scoped_ptr<base::Value> get_data_result_value_;
-  bool get_data_callback_called_;
+  scoped_ptr<RequestSender> sender_;
 };
 
 TEST_F(BaseRequestsTest, ParseValidJson) {
+  scoped_ptr<base::Value> json;
   ParseJson(kValidJsonString,
-            base::Bind(&BaseRequestsTest::ParseJsonCallback,
-                       base::Unretained(this)));
+            base::Bind(test_util::CreateCopyResultCallback(&json)));
   // Should wait for a blocking pool task, as the JSON parsing is done in the
   // blocking pool.
   test_util::RunBlockingPoolTask();
 
-  ASSERT_TRUE(parse_json_callback_called_);
-  ASSERT_TRUE(parse_json_result_.get());
-
   DictionaryValue* root_dict = NULL;
-  ASSERT_TRUE(parse_json_result_->GetAsDictionary(&root_dict));
+  ASSERT_TRUE(json);
+  ASSERT_TRUE(json->GetAsDictionary(&root_dict));
 
   int int_value = 0;
   ASSERT_TRUE(root_dict->GetInteger("test", &int_value));
@@ -102,51 +73,49 @@
 }
 
 TEST_F(BaseRequestsTest, ParseInvalidJson) {
+  // Initialize with a valid pointer to verify that null is indeed assigned.
+  scoped_ptr<base::Value> json(base::Value::CreateNullValue());
   ParseJson(kInvalidJsonString,
-            base::Bind(&BaseRequestsTest::ParseJsonCallback,
-                       base::Unretained(this)));
+            base::Bind(test_util::CreateCopyResultCallback(&json)));
   // Should wait for a blocking pool task, as the JSON parsing is done in the
   // blocking pool.
   test_util::RunBlockingPoolTask();
 
-  ASSERT_TRUE(parse_json_callback_called_);
-  ASSERT_FALSE(parse_json_result_.get());
+  EXPECT_FALSE(json);
 }
 
 TEST_F(BaseRequestsTest, GetDataRequestParseValidResponse) {
+  GDataErrorCode error = GDATA_OTHER_ERROR;
+  scoped_ptr<base::Value> value;
   FakeGetDataRequest* get_data_request =
       new FakeGetDataRequest(
-          runner_.get(),
-          base::Bind(&BaseRequestsTest::GetDataCallback,
-                     base::Unretained(this)));
-  get_data_request->NotifyStart();
+          sender_.get(),
+          base::Bind(test_util::CreateCopyResultCallback(&error, &value)));
 
   get_data_request->ParseResponse(HTTP_SUCCESS, kValidJsonString);
   // Should wait for a blocking pool task, as the JSON parsing is done in the
   // blocking pool.
   test_util::RunBlockingPoolTask();
 
-  ASSERT_TRUE(get_data_callback_called_);
-  ASSERT_EQ(HTTP_SUCCESS, get_data_result_error_);
-  ASSERT_TRUE(get_data_result_value_.get());
+  EXPECT_EQ(HTTP_SUCCESS, error);
+  EXPECT_TRUE(value);
 }
 
 TEST_F(BaseRequestsTest, GetDataRequestParseInvalidResponse) {
+  GDataErrorCode error = GDATA_OTHER_ERROR;
+  scoped_ptr<base::Value> value;
   FakeGetDataRequest* get_data_request =
       new FakeGetDataRequest(
-          runner_.get(),
-          base::Bind(&BaseRequestsTest::GetDataCallback,
-                     base::Unretained(this)));
-  get_data_request->NotifyStart();
+          sender_.get(),
+          base::Bind(test_util::CreateCopyResultCallback(&error, &value)));
 
   get_data_request->ParseResponse(HTTP_SUCCESS, kInvalidJsonString);
   // Should wait for a blocking pool task, as the JSON parsing is done in the
   // blocking pool.
   test_util::RunBlockingPoolTask();
 
-  ASSERT_TRUE(get_data_callback_called_);
-  ASSERT_EQ(GDATA_PARSE_ERROR, get_data_result_error_);
-  ASSERT_FALSE(get_data_result_value_.get());
+  EXPECT_EQ(GDATA_PARSE_ERROR, error);
+  EXPECT_FALSE(value);
 }
 
 }  // namespace google_apis
diff --git a/chrome/browser/google_apis/drive_api_parser.h b/chrome/browser/google_apis/drive_api_parser.h
index f8d001d..7042320 100644
--- a/chrome/browser/google_apis/drive_api_parser.h
+++ b/chrome/browser/google_apis/drive_api_parser.h
@@ -12,8 +12,8 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/scoped_vector.h"
 #include "base/strings/string_piece.h"
-#include "base/time.h"
-#include "googleurl/src/gurl.h"
+#include "base/time/time.h"
+#include "url/gurl.h"
 // TODO(kochi): Eliminate this dependency once dependency to EntryKind is gone.
 // http://crbug.com/142293
 #include "chrome/browser/google_apis/gdata_wapi_parser.h"
diff --git a/chrome/browser/google_apis/drive_api_parser_unittest.cc b/chrome/browser/google_apis/drive_api_parser_unittest.cc
index 8fa6197..60d4f35 100644
--- a/chrome/browser/google_apis/drive_api_parser_unittest.cc
+++ b/chrome/browser/google_apis/drive_api_parser_unittest.cc
@@ -4,7 +4,7 @@
 
 #include "chrome/browser/google_apis/drive_api_parser.h"
 
-#include "base/time.h"
+#include "base/time/time.h"
 #include "base/values.h"
 #include "chrome/browser/google_apis/gdata_wapi_parser.h"
 #include "chrome/browser/google_apis/test_util.h"
@@ -20,7 +20,7 @@
 TEST(DriveAPIParserTest, AboutResourceParser) {
   std::string error;
   scoped_ptr<base::Value> document = test_util::LoadJSONFile(
-      "chromeos/drive/about.json");
+      "drive/about.json");
   ASSERT_TRUE(document.get());
 
   ASSERT_EQ(base::Value::TYPE_DICTIONARY, document->GetType());
@@ -56,7 +56,7 @@
 TEST(DriveAPIParserTest, AppListParser) {
   std::string error;
   scoped_ptr<base::Value> document = test_util::LoadJSONFile(
-      "chromeos/drive/applist.json");
+      "drive/applist.json");
   ASSERT_TRUE(document.get());
 
   ASSERT_EQ(base::Value::TYPE_DICTIONARY, document->GetType());
@@ -234,7 +234,7 @@
 TEST(DriveAPIParserTest, FileListParser) {
   std::string error;
   scoped_ptr<base::Value> document = test_util::LoadJSONFile(
-      "chromeos/drive/filelist.json");
+      "drive/filelist.json");
   ASSERT_TRUE(document.get());
 
   ASSERT_EQ(base::Value::TYPE_DICTIONARY, document->GetType());
@@ -350,7 +350,7 @@
 TEST(DriveAPIParserTest, ChangeListParser) {
   std::string error;
   scoped_ptr<base::Value> document =
-      test_util::LoadJSONFile("chromeos/drive/changelist.json");
+      test_util::LoadJSONFile("drive/changelist.json");
   ASSERT_TRUE(document.get());
 
   ASSERT_EQ(base::Value::TYPE_DICTIONARY, document->GetType());
@@ -413,9 +413,9 @@
 
 TEST(DriveAPIParserTest, HasKind) {
   scoped_ptr<base::Value> change_list_json(
-      test_util::LoadJSONFile("chromeos/drive/changelist.json"));
+      test_util::LoadJSONFile("drive/changelist.json"));
   scoped_ptr<base::Value> file_list_json(
-      test_util::LoadJSONFile("chromeos/drive/filelist.json"));
+      test_util::LoadJSONFile("drive/filelist.json"));
 
   EXPECT_TRUE(ChangeList::HasChangeListKind(*change_list_json));
   EXPECT_FALSE(ChangeList::HasChangeListKind(*file_list_json));
diff --git a/chrome/browser/google_apis/drive_api_requests.cc b/chrome/browser/google_apis/drive_api_requests.cc
index 555ff22..04e163e 100644
--- a/chrome/browser/google_apis/drive_api_requests.cc
+++ b/chrome/browser/google_apis/drive_api_requests.cc
@@ -11,9 +11,6 @@
 #include "chrome/browser/google_apis/drive_api_parser.h"
 #include "chrome/browser/google_apis/request_util.h"
 #include "chrome/browser/google_apis/time_util.h"
-#include "content/public/browser/browser_thread.h"
-
-using content::BrowserThread;
 
 namespace google_apis {
 namespace {
@@ -29,7 +26,6 @@
     const base::Callback<void(GDataErrorCode, scoped_ptr<T>)>& callback,
     GDataErrorCode error,
     scoped_ptr<base::Value> value) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   DCHECK(!callback.is_null());
 
   scoped_ptr<T> resource;
@@ -53,7 +49,6 @@
     const drive::UploadRangeCallback& callback,
     const UploadRangeResponse& response,
     scoped_ptr<base::Value> value) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   DCHECK(!callback.is_null());
 
   scoped_ptr<FileResource> file_resource;
@@ -77,11 +72,10 @@
 //============================== GetAboutRequest =============================
 
 GetAboutRequest::GetAboutRequest(
-    RequestSender* runner,
-    net::URLRequestContextGetter* url_request_context_getter,
+    RequestSender* sender,
     const DriveApiUrlGenerator& url_generator,
     const GetAboutResourceCallback& callback)
-    : GetDataRequest(runner, url_request_context_getter,
+    : GetDataRequest(sender,
                      base::Bind(&ParseJsonAndRun<AboutResource>, callback)),
       url_generator_(url_generator) {
   DCHECK(!callback.is_null());
@@ -96,11 +90,10 @@
 //============================== GetApplistRequest ===========================
 
 GetApplistRequest::GetApplistRequest(
-    RequestSender* runner,
-    net::URLRequestContextGetter* url_request_context_getter,
+    RequestSender* sender,
     const DriveApiUrlGenerator& url_generator,
     const GetDataCallback& callback)
-    : GetDataRequest(runner, url_request_context_getter, callback),
+    : GetDataRequest(sender, callback),
       url_generator_(url_generator) {
   DCHECK(!callback.is_null());
 }
@@ -114,14 +107,13 @@
 //============================ GetChangelistRequest ==========================
 
 GetChangelistRequest::GetChangelistRequest(
-    RequestSender* runner,
-    net::URLRequestContextGetter* url_request_context_getter,
+    RequestSender* sender,
     const DriveApiUrlGenerator& url_generator,
     bool include_deleted,
     int64 start_changestamp,
     int max_results,
     const GetDataCallback& callback)
-    : GetDataRequest(runner, url_request_context_getter, callback),
+    : GetDataRequest(sender, callback),
       url_generator_(url_generator),
       include_deleted_(include_deleted),
       start_changestamp_(start_changestamp),
@@ -139,13 +131,12 @@
 //============================= GetFilelistRequest ===========================
 
 GetFilelistRequest::GetFilelistRequest(
-    RequestSender* runner,
-    net::URLRequestContextGetter* url_request_context_getter,
+    RequestSender* sender,
     const DriveApiUrlGenerator& url_generator,
     const std::string& search_string,
     int max_results,
     const GetDataCallback& callback)
-    : GetDataRequest(runner, url_request_context_getter, callback),
+    : GetDataRequest(sender, callback),
       url_generator_(url_generator),
       search_string_(search_string),
       max_results_(max_results) {
@@ -161,12 +152,11 @@
 //=============================== GetFileRequest =============================
 
 GetFileRequest::GetFileRequest(
-    RequestSender* runner,
-    net::URLRequestContextGetter* url_request_context_getter,
+    RequestSender* sender,
     const DriveApiUrlGenerator& url_generator,
     const std::string& file_id,
     const FileResourceCallback& callback)
-    : GetDataRequest(runner, url_request_context_getter,
+    : GetDataRequest(sender,
                      base::Bind(&ParseJsonAndRun<FileResource>, callback)),
       url_generator_(url_generator),
       file_id_(file_id) {
@@ -184,11 +174,10 @@
 //======================= ContinueGetFileListRequest =========================
 
 ContinueGetFileListRequest::ContinueGetFileListRequest(
-    RequestSender* runner,
-    net::URLRequestContextGetter* url_request_context_getter,
+    RequestSender* sender,
     const GURL& url,
     const GetDataCallback& callback)
-    : GetDataRequest(runner, url_request_context_getter, callback),
+    : GetDataRequest(sender, callback),
       url_(url) {
   DCHECK(!callback.is_null());
 }
@@ -202,13 +191,12 @@
 //========================== CreateDirectoryRequest ==========================
 
 CreateDirectoryRequest::CreateDirectoryRequest(
-    RequestSender* runner,
-    net::URLRequestContextGetter* url_request_context_getter,
+    RequestSender* sender,
     const DriveApiUrlGenerator& url_generator,
     const std::string& parent_resource_id,
     const std::string& directory_name,
     const FileResourceCallback& callback)
-    : GetDataRequest(runner, url_request_context_getter,
+    : GetDataRequest(sender,
                      base::Bind(&ParseJsonAndRun<FileResource>, callback)),
       url_generator_(url_generator),
       parent_resource_id_(parent_resource_id),
@@ -253,13 +241,12 @@
 //=========================== RenameResourceRequest ==========================
 
 RenameResourceRequest::RenameResourceRequest(
-    RequestSender* runner,
-    net::URLRequestContextGetter* url_request_context_getter,
+    RequestSender* sender,
     const DriveApiUrlGenerator& url_generator,
     const std::string& resource_id,
     const std::string& new_name,
     const EntryActionCallback& callback)
-    : EntryActionRequest(runner, url_request_context_getter, callback),
+    : EntryActionRequest(sender, callback),
       url_generator_(url_generator),
       resource_id_(resource_id),
       new_name_(new_name) {
@@ -299,14 +286,13 @@
 //=========================== TouchResourceRequest ===========================
 
 TouchResourceRequest::TouchResourceRequest(
-    RequestSender* runner,
-    net::URLRequestContextGetter* url_request_context_getter,
+    RequestSender* sender,
     const DriveApiUrlGenerator& url_generator,
     const std::string& resource_id,
     const base::Time& modified_date,
     const base::Time& last_viewed_by_me_date,
     const FileResourceCallback& callback)
-    : GetDataRequest(runner, url_request_context_getter,
+    : GetDataRequest(sender,
                      base::Bind(&ParseJsonAndRun<FileResource>, callback)),
       url_generator_(url_generator),
       resource_id_(resource_id),
@@ -352,14 +338,13 @@
 //=========================== CopyResourceRequest ============================
 
 CopyResourceRequest::CopyResourceRequest(
-    RequestSender* runner,
-    net::URLRequestContextGetter* url_request_context_getter,
+    RequestSender* sender,
     const DriveApiUrlGenerator& url_generator,
     const std::string& resource_id,
     const std::string& parent_resource_id,
     const std::string& new_name,
     const FileResourceCallback& callback)
-    : GetDataRequest(runner, url_request_context_getter,
+    : GetDataRequest(sender,
                      base::Bind(&ParseJsonAndRun<FileResource>, callback)),
       url_generator_(url_generator),
       resource_id_(resource_id),
@@ -405,12 +390,11 @@
 //=========================== TrashResourceRequest ===========================
 
 TrashResourceRequest::TrashResourceRequest(
-    RequestSender* runner,
-    net::URLRequestContextGetter* url_request_context_getter,
+    RequestSender* sender,
     const DriveApiUrlGenerator& url_generator,
     const std::string& resource_id,
     const EntryActionCallback& callback)
-    : EntryActionRequest(runner, url_request_context_getter, callback),
+    : EntryActionRequest(sender, callback),
       url_generator_(url_generator),
       resource_id_(resource_id) {
   DCHECK(!callback.is_null());
@@ -429,13 +413,12 @@
 //========================== InsertResourceRequest ===========================
 
 InsertResourceRequest::InsertResourceRequest(
-    RequestSender* runner,
-    net::URLRequestContextGetter* url_request_context_getter,
+    RequestSender* sender,
     const DriveApiUrlGenerator& url_generator,
     const std::string& parent_resource_id,
     const std::string& resource_id,
     const EntryActionCallback& callback)
-    : EntryActionRequest(runner, url_request_context_getter, callback),
+    : EntryActionRequest(sender, callback),
       url_generator_(url_generator),
       parent_resource_id_(parent_resource_id),
       resource_id_(resource_id) {
@@ -468,13 +451,12 @@
 //========================== DeleteResourceRequest ===========================
 
 DeleteResourceRequest::DeleteResourceRequest(
-    RequestSender* runner,
-    net::URLRequestContextGetter* url_request_context_getter,
+    RequestSender* sender,
     const DriveApiUrlGenerator& url_generator,
     const std::string& parent_resource_id,
     const std::string& resource_id,
     const EntryActionCallback& callback)
-    : EntryActionRequest(runner, url_request_context_getter, callback),
+    : EntryActionRequest(sender, callback),
       url_generator_(url_generator),
       parent_resource_id_(parent_resource_id),
       resource_id_(resource_id) {
@@ -495,19 +477,15 @@
 //======================= InitiateUploadNewFileRequest =======================
 
 InitiateUploadNewFileRequest::InitiateUploadNewFileRequest(
-    RequestSender* runner,
-    net::URLRequestContextGetter* url_request_context_getter,
+    RequestSender* sender,
     const DriveApiUrlGenerator& url_generator,
-    const base::FilePath& drive_file_path,
     const std::string& content_type,
     int64 content_length,
     const std::string& parent_resource_id,
     const std::string& title,
     const InitiateUploadCallback& callback)
-    : InitiateUploadRequestBase(runner,
-                                url_request_context_getter,
+    : InitiateUploadRequestBase(sender,
                                 callback,
-                                drive_file_path,
                                 content_type,
                                 content_length),
       url_generator_(url_generator),
@@ -556,19 +534,15 @@
 //===================== InitiateUploadExistingFileRequest ====================
 
 InitiateUploadExistingFileRequest::InitiateUploadExistingFileRequest(
-    RequestSender* runner,
-    net::URLRequestContextGetter* url_request_context_getter,
+    RequestSender* sender,
     const DriveApiUrlGenerator& url_generator,
-    const base::FilePath& drive_file_path,
     const std::string& content_type,
     int64 content_length,
     const std::string& resource_id,
     const std::string& etag,
     const InitiateUploadCallback& callback)
-    : InitiateUploadRequestBase(runner,
-                                url_request_context_getter,
+    : InitiateUploadRequestBase(sender,
                                 callback,
-                                drive_file_path,
                                 content_type,
                                 content_length),
       url_generator_(url_generator),
@@ -598,9 +572,7 @@
 //============================ ResumeUploadRequest ===========================
 
 ResumeUploadRequest::ResumeUploadRequest(
-    RequestSender* runner,
-    net::URLRequestContextGetter* url_request_context_getter,
-    const base::FilePath& drive_file_path,
+    RequestSender* sender,
     const GURL& upload_location,
     int64 start_position,
     int64 end_position,
@@ -609,9 +581,7 @@
     const base::FilePath& local_file_path,
     const UploadRangeCallback& callback,
     const ProgressCallback& progress_callback)
-    : ResumeUploadRequestBase(runner,
-                              url_request_context_getter,
-                              drive_file_path,
+    : ResumeUploadRequestBase(sender,
                               upload_location,
                               start_position,
                               end_position,
@@ -626,7 +596,9 @@
 ResumeUploadRequest::~ResumeUploadRequest() {}
 
 void ResumeUploadRequest::OnRangeRequestComplete(
-    const UploadRangeResponse& response, scoped_ptr<base::Value> value) {
+    const UploadRangeResponse& response,
+    scoped_ptr<base::Value> value) {
+  DCHECK(CalledOnValidThread());
   ParseFileResourceWithUploadRangeAndRun(callback_, response, value.Pass());
 }
 
@@ -639,15 +611,11 @@
 //========================== GetUploadStatusRequest ==========================
 
 GetUploadStatusRequest::GetUploadStatusRequest(
-    RequestSender* runner,
-    net::URLRequestContextGetter* url_request_context_getter,
-    const base::FilePath& drive_file_path,
+    RequestSender* sender,
     const GURL& upload_url,
     int64 content_length,
     const UploadRangeCallback& callback)
-    : GetUploadStatusRequestBase(runner,
-                                 url_request_context_getter,
-                                 drive_file_path,
+    : GetUploadStatusRequestBase(sender,
                                  upload_url,
                                  content_length),
       callback_(callback) {
@@ -657,9 +625,33 @@
 GetUploadStatusRequest::~GetUploadStatusRequest() {}
 
 void GetUploadStatusRequest::OnRangeRequestComplete(
-    const UploadRangeResponse& response, scoped_ptr<base::Value> value) {
+    const UploadRangeResponse& response,
+    scoped_ptr<base::Value> value) {
+  DCHECK(CalledOnValidThread());
   ParseFileResourceWithUploadRangeAndRun(callback_, response, value.Pass());
 }
 
+//========================== DownloadFileRequest ==========================
+
+DownloadFileRequest::DownloadFileRequest(
+    RequestSender* sender,
+    const DriveApiUrlGenerator& url_generator,
+    const std::string& resource_id,
+    const base::FilePath& output_file_path,
+    const DownloadActionCallback& download_action_callback,
+    const GetContentCallback& get_content_callback,
+    const ProgressCallback& progress_callback)
+    : DownloadFileRequestBase(
+          sender,
+          download_action_callback,
+          get_content_callback,
+          progress_callback,
+          url_generator.GenerateDownloadFileUrl(resource_id),
+          output_file_path) {
+}
+
+DownloadFileRequest::~DownloadFileRequest() {
+}
+
 }  // namespace drive
 }  // namespace google_apis
diff --git a/chrome/browser/google_apis/drive_api_requests.h b/chrome/browser/google_apis/drive_api_requests.h
index f48513e..0fa5a79 100644
--- a/chrome/browser/google_apis/drive_api_requests.h
+++ b/chrome/browser/google_apis/drive_api_requests.h
@@ -12,10 +12,6 @@
 #include "chrome/browser/google_apis/drive_api_url_generator.h"
 #include "chrome/browser/google_apis/drive_common_callbacks.h"
 
-namespace net {
-class URLRequestContextGetter;
-}  // namespace net
-
 namespace google_apis {
 
 class FileResource;
@@ -32,8 +28,7 @@
 // This class performs the request for fetching About data.
 class GetAboutRequest : public GetDataRequest {
  public:
-  GetAboutRequest(RequestSender* runner,
-                  net::URLRequestContextGetter* url_request_context_getter,
+  GetAboutRequest(RequestSender* sender,
                   const DriveApiUrlGenerator& url_generator,
                   const GetAboutResourceCallback& callback);
   virtual ~GetAboutRequest();
@@ -53,8 +48,7 @@
 // This class performs the request for fetching Applist.
 class GetApplistRequest : public GetDataRequest {
  public:
-  GetApplistRequest(RequestSender* runner,
-                    net::URLRequestContextGetter* url_request_context_getter,
+  GetApplistRequest(RequestSender* sender,
                     const DriveApiUrlGenerator& url_generator,
                     const GetDataCallback& callback);
   virtual ~GetApplistRequest();
@@ -82,14 +76,12 @@
   // all changes are necessary.
   // |max_results| specifies the max of the number of files resource in the
   // response.
-  GetChangelistRequest(
-      RequestSender* runner,
-      net::URLRequestContextGetter* url_request_context_getter,
-      const DriveApiUrlGenerator& url_generator,
-      bool include_deleted,
-      int64 start_changestamp,
-      int max_results,
-      const GetDataCallback& callback);
+  GetChangelistRequest(RequestSender* sender,
+                       const DriveApiUrlGenerator& url_generator,
+                       bool include_deleted,
+                       int64 start_changestamp,
+                       int max_results,
+                       const GetDataCallback& callback);
   virtual ~GetChangelistRequest();
 
  protected:
@@ -112,13 +104,11 @@
 // should be able to be fetched by ContinueGetFileListRequest defined below.
 class GetFilelistRequest : public GetDataRequest {
  public:
-  GetFilelistRequest(
-      RequestSender* runner,
-      net::URLRequestContextGetter* url_request_context_getter,
-      const DriveApiUrlGenerator& url_generator,
-      const std::string& search_string,
-      int max_results,
-      const GetDataCallback& callback);
+  GetFilelistRequest(RequestSender* sender,
+                     const DriveApiUrlGenerator& url_generator,
+                     const std::string& search_string,
+                     int max_results,
+                     const GetDataCallback& callback);
   virtual ~GetFilelistRequest();
 
  protected:
@@ -138,8 +128,7 @@
 // This class performs the request for fetching a file.
 class GetFileRequest : public GetDataRequest {
  public:
-  GetFileRequest(RequestSender* runner,
-                 net::URLRequestContextGetter* url_request_context_getter,
+  GetFileRequest(RequestSender* sender,
                  const DriveApiUrlGenerator& url_generator,
                  const std::string& file_id,
                  const FileResourceCallback& callback);
@@ -169,11 +158,9 @@
 // This class performs the request to fetch remaining Filelist result.
 class ContinueGetFileListRequest : public GetDataRequest {
  public:
-  ContinueGetFileListRequest(
-      RequestSender* runner,
-      net::URLRequestContextGetter* url_request_context_getter,
-      const GURL& url,
-      const GetDataCallback& callback);
+  ContinueGetFileListRequest(RequestSender* sender,
+                             const GURL& url,
+                             const GetDataCallback& callback);
   virtual ~ContinueGetFileListRequest();
 
  protected:
@@ -190,13 +177,11 @@
 // This class performs the request for creating a directory.
 class CreateDirectoryRequest : public GetDataRequest {
  public:
-  CreateDirectoryRequest(
-      RequestSender* runner,
-      net::URLRequestContextGetter* url_request_context_getter,
-      const DriveApiUrlGenerator& url_generator,
-      const std::string& parent_resource_id,
-      const std::string& directory_name,
-      const FileResourceCallback& callback);
+  CreateDirectoryRequest(RequestSender* sender,
+                         const DriveApiUrlGenerator& url_generator,
+                         const std::string& parent_resource_id,
+                         const std::string& directory_name,
+                         const FileResourceCallback& callback);
   virtual ~CreateDirectoryRequest();
 
  protected:
@@ -220,13 +205,11 @@
 class RenameResourceRequest : public EntryActionRequest {
  public:
   // |callback| must not be null.
-  RenameResourceRequest(
-      RequestSender* runner,
-      net::URLRequestContextGetter* url_request_context_getter,
-      const DriveApiUrlGenerator& url_generator,
-      const std::string& resource_id,
-      const std::string& new_name,
-      const EntryActionCallback& callback);
+  RenameResourceRequest(RequestSender* sender,
+                        const DriveApiUrlGenerator& url_generator,
+                        const std::string& resource_id,
+                        const std::string& new_name,
+                        const EntryActionCallback& callback);
   virtual ~RenameResourceRequest();
 
  protected:
@@ -255,14 +238,12 @@
 class TouchResourceRequest : public GetDataRequest {
  public:
   // |callback| must not be null.
-  TouchResourceRequest(
-      RequestSender* runner,
-      net::URLRequestContextGetter* url_request_context_getter,
-      const DriveApiUrlGenerator& url_generator,
-      const std::string& resource_id,
-      const base::Time& modified_date,
-      const base::Time& last_viewed_by_me_date,
-      const FileResourceCallback& callback);
+  TouchResourceRequest(RequestSender* sender,
+                       const DriveApiUrlGenerator& url_generator,
+                       const std::string& resource_id,
+                       const base::Time& modified_date,
+                       const base::Time& last_viewed_by_me_date,
+                       const FileResourceCallback& callback);
   virtual ~TouchResourceRequest();
 
  protected:
@@ -298,14 +279,12 @@
 class CopyResourceRequest : public GetDataRequest {
  public:
   // Upon completion, |callback| will be called. |callback| must not be null.
-  CopyResourceRequest(
-      RequestSender* runner,
-      net::URLRequestContextGetter* url_request_context_getter,
-      const DriveApiUrlGenerator& url_generator,
-      const std::string& resource_id,
-      const std::string& parent_resource_id,
-      const std::string& new_name,
-      const FileResourceCallback& callback);
+  CopyResourceRequest(RequestSender* sender,
+                      const DriveApiUrlGenerator& url_generator,
+                      const std::string& resource_id,
+                      const std::string& parent_resource_id,
+                      const std::string& new_name,
+                      const FileResourceCallback& callback);
   virtual ~CopyResourceRequest();
 
  protected:
@@ -338,12 +317,10 @@
 class TrashResourceRequest : public EntryActionRequest {
  public:
   // |callback| must not be null.
-  TrashResourceRequest(
-      RequestSender* runner,
-      net::URLRequestContextGetter* url_request_context_getter,
-      const DriveApiUrlGenerator& url_generator,
-      const std::string& resource_id,
-      const EntryActionCallback& callback);
+  TrashResourceRequest(RequestSender* sender,
+                       const DriveApiUrlGenerator& url_generator,
+                       const std::string& resource_id,
+                       const EntryActionCallback& callback);
   virtual ~TrashResourceRequest();
 
  protected:
@@ -366,13 +343,11 @@
 class InsertResourceRequest : public EntryActionRequest {
  public:
   // |callback| must not be null.
-  InsertResourceRequest(
-      RequestSender* runner,
-      net::URLRequestContextGetter* url_request_context_getter,
-      const DriveApiUrlGenerator& url_generator,
-      const std::string& parent_resource_id,
-      const std::string& resource_id,
-      const EntryActionCallback& callback);
+  InsertResourceRequest(RequestSender* sender,
+                        const DriveApiUrlGenerator& url_generator,
+                        const std::string& parent_resource_id,
+                        const std::string& resource_id,
+                        const EntryActionCallback& callback);
   virtual ~InsertResourceRequest();
 
  protected:
@@ -401,13 +376,11 @@
 class DeleteResourceRequest : public EntryActionRequest {
  public:
   // |callback| must not be null.
-  DeleteResourceRequest(
-      RequestSender* runner,
-      net::URLRequestContextGetter* url_request_context_getter,
-      const DriveApiUrlGenerator& url_generator,
-      const std::string& parent_resource_id,
-      const std::string& resource_id,
-      const EntryActionCallback& callback);
+  DeleteResourceRequest(RequestSender* sender,
+                        const DriveApiUrlGenerator& url_generator,
+                        const std::string& parent_resource_id,
+                        const std::string& resource_id,
+                        const EntryActionCallback& callback);
   virtual ~DeleteResourceRequest();
 
  protected:
@@ -432,16 +405,13 @@
   // |title| should be set.
   // See also the comments of InitiateUploadRequestBase for more details
   // about the other parameters.
-  InitiateUploadNewFileRequest(
-      RequestSender* runner,
-      net::URLRequestContextGetter* url_request_context_getter,
-      const DriveApiUrlGenerator& url_generator,
-      const base::FilePath& drive_file_path,
-      const std::string& content_type,
-      int64 content_length,
-      const std::string& parent_resource_id,
-      const std::string& title,
-      const InitiateUploadCallback& callback);
+  InitiateUploadNewFileRequest(RequestSender* sender,
+                               const DriveApiUrlGenerator& url_generator,
+                               const std::string& content_type,
+                               int64 content_length,
+                               const std::string& parent_resource_id,
+                               const std::string& title,
+                               const InitiateUploadCallback& callback);
   virtual ~InitiateUploadNewFileRequest();
 
  protected:
@@ -471,16 +441,13 @@
   // |etag| should be set if it is available to detect the upload confliction.
   // See also the comments of InitiateUploadRequestBase for more details
   // about the other parameters.
-  InitiateUploadExistingFileRequest(
-      RequestSender* runner,
-      net::URLRequestContextGetter* url_request_context_getter,
-      const DriveApiUrlGenerator& url_generator,
-      const base::FilePath& drive_file_path,
-      const std::string& content_type,
-      int64 content_length,
-      const std::string& resource_id,
-      const std::string& etag,
-      const InitiateUploadCallback& callback);
+  InitiateUploadExistingFileRequest(RequestSender* sender,
+                                    const DriveApiUrlGenerator& url_generator,
+                                    const std::string& content_type,
+                                    int64 content_length,
+                                    const std::string& resource_id,
+                                    const std::string& etag,
+                                    const InitiateUploadCallback& callback);
   virtual ~InitiateUploadExistingFileRequest();
 
  protected:
@@ -509,18 +476,15 @@
  public:
   // See also ResumeUploadRequestBase's comment for parameters meaning.
   // |callback| must not be null. |progress_callback| may be null.
-  ResumeUploadRequest(
-      RequestSender* runner,
-      net::URLRequestContextGetter* url_request_context_getter,
-      const base::FilePath& drive_file_path,
-      const GURL& upload_location,
-      int64 start_position,
-      int64 end_position,
-      int64 content_length,
-      const std::string& content_type,
-      const base::FilePath& local_file_path,
-      const UploadRangeCallback& callback,
-      const ProgressCallback& progress_callback);
+  ResumeUploadRequest(RequestSender* sender,
+                      const GURL& upload_location,
+                      int64 start_position,
+                      int64 end_position,
+                      int64 content_length,
+                      const std::string& content_type,
+                      const base::FilePath& local_file_path,
+                      const UploadRangeCallback& callback,
+                      const ProgressCallback& progress_callback);
   virtual ~ResumeUploadRequest();
 
  protected:
@@ -546,13 +510,10 @@
  public:
   // See also GetUploadStatusRequestBase's comment for parameters meaning.
   // |callback| must not be null.
-  GetUploadStatusRequest(
-      RequestSender* runner,
-      net::URLRequestContextGetter* url_request_context_getter,
-      const base::FilePath& drive_file_path,
-      const GURL& upload_url,
-      int64 content_length,
-      const UploadRangeCallback& callback);
+  GetUploadStatusRequest(RequestSender* sender,
+                         const GURL& upload_url,
+                         int64 content_length,
+                         const UploadRangeCallback& callback);
   virtual ~GetUploadStatusRequest();
 
  protected:
@@ -567,6 +528,23 @@
   DISALLOW_COPY_AND_ASSIGN(GetUploadStatusRequest);
 };
 
+//========================== DownloadFileRequest ==========================
+
+// This class performs the request for downloading of a specified file.
+class DownloadFileRequest : public DownloadFileRequestBase {
+ public:
+  // See also DownloadFileRequestBase's comment for parameters meaning.
+  DownloadFileRequest(RequestSender* sender,
+                      const DriveApiUrlGenerator& url_generator,
+                      const std::string& resource_id,
+                      const base::FilePath& output_file_path,
+                      const DownloadActionCallback& download_action_callback,
+                      const GetContentCallback& get_content_callback,
+                      const ProgressCallback& progress_callback);
+  virtual ~DownloadFileRequest();
+
+  DISALLOW_COPY_AND_ASSIGN(DownloadFileRequest);
+};
 
 }  // namespace drive
 }  // namespace google_apis
diff --git a/chrome/browser/google_apis/drive_api_requests_unittest.cc b/chrome/browser/google_apis/drive_api_requests_unittest.cc
index ce6de2b..903e2df 100644
--- a/chrome/browser/google_apis/drive_api_requests_unittest.cc
+++ b/chrome/browser/google_apis/drive_api_requests_unittest.cc
@@ -3,9 +3,10 @@
 // found in the LICENSE file.
 
 #include "base/bind.h"
+#include "base/file_util.h"
 #include "base/files/file_path.h"
 #include "base/files/scoped_temp_dir.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/run_loop.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/values.h"
 #include "chrome/browser/google_apis/auth_service.h"
@@ -13,7 +14,6 @@
 #include "chrome/browser/google_apis/drive_api_requests.h"
 #include "chrome/browser/google_apis/drive_api_url_generator.h"
 #include "chrome/browser/google_apis/request_sender.h"
-#include "chrome/browser/google_apis/task_util.h"
 #include "chrome/browser/google_apis/test_util.h"
 #include "chrome/test/base/testing_profile.h"
 #include "content/public/browser/browser_thread.h"
@@ -42,6 +42,7 @@
 
 const char kTestUploadExistingFilePath[] = "/upload/existingfile/path";
 const char kTestUploadNewFilePath[] = "/upload/newfile/path";
+const char kTestDownloadPathPrefix[] = "/download/";
 
 }  // namespace
 
@@ -85,9 +86,13 @@
     test_server_.RegisterRequestHandler(
         base::Bind(&DriveApiRequestsTest::HandleContentResponse,
                    base::Unretained(this)));
+    test_server_.RegisterRequestHandler(
+        base::Bind(&DriveApiRequestsTest::HandleDownloadRequest,
+                   base::Unretained(this)));
 
+    GURL test_base_url = test_util::GetBaseUrlForTesting(test_server_.port());
     url_generator_.reset(new DriveApiUrlGenerator(
-        test_util::GetBaseUrlForTesting(test_server_.port())));
+        test_base_url, test_base_url.Resolve(kTestDownloadPathPrefix)));
 
     // Reset the server's expected behavior just in case.
     ResetExpectedResponse();
@@ -95,12 +100,6 @@
     content_length_ = 0;
   }
 
-  virtual void TearDown() OVERRIDE {
-    EXPECT_TRUE(test_server_.ShutdownAndWaitUntilComplete());
-    request_context_getter_ = NULL;
-    ResetExpectedResponse();
-  }
-
   content::TestBrowserThreadBundle thread_bundle_;
   net::test_server::EmbeddedTestServer test_server_;
   scoped_ptr<TestingProfile> profile_;
@@ -151,7 +150,7 @@
     // Return the response with just "204 No Content" status code.
     scoped_ptr<net::test_server::BasicHttpResponse> http_response(
         new net::test_server::BasicHttpResponse);
-    http_response->set_code(net::test_server::NO_CONTENT);
+    http_response->set_code(net::HTTP_NO_CONTENT);
     return http_response.PassAs<net::test_server::HttpResponse>();
   }
 
@@ -199,7 +198,7 @@
     if (found != request.headers.end() &&
         found->second != "*" &&
         found->second != kTestETag) {
-      response->set_code(net::test_server::PRECONDITION);
+      response->set_code(net::HTTP_PRECONDITION_FAILED);
       return response.PassAs<net::test_server::HttpResponse>();
     }
 
@@ -212,7 +211,7 @@
     }
     received_bytes_ = 0;
 
-    response->set_code(net::test_server::SUCCESS);
+    response->set_code(net::HTTP_OK);
     response->AddCustomHeader(
         "Location",
         test_server_.base_url().Resolve(expected_upload_path_).spec());
@@ -257,7 +256,7 @@
       scoped_ptr<net::test_server::BasicHttpResponse> response(
           new net::test_server::BasicHttpResponse);
       // Set RESUME INCOMPLETE (308) status code.
-      response->set_code(net::test_server::RESUME_INCOMPLETE);
+      response->set_code(static_cast<net::HttpStatusCode>(308));
 
       // Add Range header to the response, based on the values of
       // Content-Range header in the request.
@@ -274,11 +273,11 @@
     // (dummy) metadata.
     scoped_ptr<net::test_server::BasicHttpResponse> response =
         test_util::CreateHttpResponseFromFile(
-            test_util::GetTestFilePath("chromeos/drive/file_entry.json"));
+            test_util::GetTestFilePath("drive/file_entry.json"));
 
     // The response code is CREATED if it is new file uploading.
     if (http_request_.relative_url == kTestUploadNewFilePath) {
-      response->set_code(net::test_server::CREATED);
+      response->set_code(net::HTTP_CREATED);
     }
 
     return response.PassAs<net::test_server::HttpResponse>();
@@ -299,12 +298,34 @@
 
     scoped_ptr<net::test_server::BasicHttpResponse> response(
         new net::test_server::BasicHttpResponse);
-    response->set_code(net::test_server::SUCCESS);
+    response->set_code(net::HTTP_OK);
     response->set_content_type(expected_content_type_);
     response->set_content(expected_content_);
     return response.PassAs<net::test_server::HttpResponse>();
   }
 
+  // Handles a request for downloading a file.
+  scoped_ptr<net::test_server::HttpResponse> HandleDownloadRequest(
+      const net::test_server::HttpRequest& request) {
+    http_request_ = request;
+
+    const GURL absolute_url = test_server_.GetURL(request.relative_url);
+    std::string id;
+    if (!test_util::RemovePrefix(absolute_url.path(),
+                                 kTestDownloadPathPrefix,
+                                 &id)) {
+      return scoped_ptr<net::test_server::HttpResponse>();
+    }
+
+    // For testing, returns a text with |id| repeated 3 times.
+    scoped_ptr<net::test_server::BasicHttpResponse> response(
+        new net::test_server::BasicHttpResponse);
+    response->set_code(net::HTTP_OK);
+    response->set_content(id + id + id);
+    response->set_content_type("text/plain");
+    return response.PassAs<net::test_server::HttpResponse>();
+  }
+
   // These are for the current upload file status.
   int64 received_bytes_;
   int64 content_length_;
@@ -313,20 +334,22 @@
 TEST_F(DriveApiRequestsTest, GetAboutRequest_ValidJson) {
   // Set an expected data file containing valid result.
   expected_data_file_path_ = test_util::GetTestFilePath(
-      "chromeos/drive/about.json");
+      "drive/about.json");
 
   GDataErrorCode error = GDATA_OTHER_ERROR;
   scoped_ptr<AboutResource> about_resource;
 
-  GetAboutRequest* request = new GetAboutRequest(
-      request_sender_.get(),
-      request_context_getter_.get(),
-      *url_generator_,
-      CreateComposedCallback(
-          base::Bind(&test_util::RunAndQuit),
-          test_util::CreateCopyResultCallback(&error, &about_resource)));
-  request_sender_->StartRequestWithRetry(request);
-  base::MessageLoop::current()->Run();
+  {
+    base::RunLoop run_loop;
+    GetAboutRequest* request = new GetAboutRequest(
+        request_sender_.get(),
+        *url_generator_,
+        test_util::CreateQuitCallback(
+            &run_loop,
+            test_util::CreateCopyResultCallback(&error, &about_resource)));
+    request_sender_->StartRequestWithRetry(request);
+    run_loop.Run();
+  }
 
   EXPECT_EQ(HTTP_SUCCESS, error);
   EXPECT_EQ(net::test_server::METHOD_GET, http_request_.method);
@@ -334,7 +357,7 @@
 
   scoped_ptr<AboutResource> expected(
       AboutResource::CreateFrom(
-          *test_util::LoadJSONFile("chromeos/drive/about.json")));
+          *test_util::LoadJSONFile("drive/about.json")));
   ASSERT_TRUE(about_resource.get());
   EXPECT_EQ(expected->largest_change_id(), about_resource->largest_change_id());
   EXPECT_EQ(expected->quota_bytes_total(), about_resource->quota_bytes_total());
@@ -345,20 +368,22 @@
 TEST_F(DriveApiRequestsTest, GetAboutRequest_InvalidJson) {
   // Set an expected data file containing invalid result.
   expected_data_file_path_ = test_util::GetTestFilePath(
-      "chromeos/gdata/testfile.txt");
+      "gdata/testfile.txt");
 
   GDataErrorCode error = GDATA_OTHER_ERROR;
   scoped_ptr<AboutResource> about_resource;
 
-  GetAboutRequest* request = new GetAboutRequest(
-      request_sender_.get(),
-      request_context_getter_.get(),
-      *url_generator_,
-      CreateComposedCallback(
-          base::Bind(&test_util::RunAndQuit),
-          test_util::CreateCopyResultCallback(&error, &about_resource)));
-  request_sender_->StartRequestWithRetry(request);
-  base::MessageLoop::current()->Run();
+  {
+    base::RunLoop run_loop;
+    GetAboutRequest* request = new GetAboutRequest(
+        request_sender_.get(),
+        *url_generator_,
+        test_util::CreateQuitCallback(
+            &run_loop,
+            test_util::CreateCopyResultCallback(&error, &about_resource)));
+    request_sender_->StartRequestWithRetry(request);
+    run_loop.Run();
+  }
 
   // "parse error" should be returned, and the about resource should be NULL.
   EXPECT_EQ(GDATA_PARSE_ERROR, error);
@@ -370,20 +395,22 @@
 TEST_F(DriveApiRequestsTest, GetApplistRequest) {
   // Set an expected data file containing valid result.
   expected_data_file_path_ = test_util::GetTestFilePath(
-      "chromeos/drive/applist.json");
+      "drive/applist.json");
 
   GDataErrorCode error = GDATA_OTHER_ERROR;
   scoped_ptr<base::Value> result;
 
-  GetApplistRequest* request = new GetApplistRequest(
-      request_sender_.get(),
-      request_context_getter_.get(),
-      *url_generator_,
-      CreateComposedCallback(
-          base::Bind(&test_util::RunAndQuit),
-          test_util::CreateCopyResultCallback(&error, &result)));
-  request_sender_->StartRequestWithRetry(request);
-  base::MessageLoop::current()->Run();
+  {
+    base::RunLoop run_loop;
+    GetApplistRequest* request = new GetApplistRequest(
+        request_sender_.get(),
+        *url_generator_,
+        test_util::CreateQuitCallback(
+            &run_loop,
+            test_util::CreateCopyResultCallback(&error, &result)));
+    request_sender_->StartRequestWithRetry(request);
+    run_loop.Run();
+  }
 
   EXPECT_EQ(HTTP_SUCCESS, error);
   EXPECT_EQ(net::test_server::METHOD_GET, http_request_.method);
@@ -394,23 +421,25 @@
 TEST_F(DriveApiRequestsTest, GetChangelistRequest) {
   // Set an expected data file containing valid result.
   expected_data_file_path_ = test_util::GetTestFilePath(
-      "chromeos/drive/changelist.json");
+      "drive/changelist.json");
 
   GDataErrorCode error = GDATA_OTHER_ERROR;
   scoped_ptr<base::Value> result;
 
-  GetChangelistRequest* request = new GetChangelistRequest(
-      request_sender_.get(),
-      request_context_getter_.get(),
-      *url_generator_,
-      true,  // include deleted
-      100,  // start changestamp
-      500,  // max results
-      CreateComposedCallback(
-          base::Bind(&test_util::RunAndQuit),
-          test_util::CreateCopyResultCallback(&error, &result)));
-  request_sender_->StartRequestWithRetry(request);
-  base::MessageLoop::current()->Run();
+  {
+    base::RunLoop run_loop;
+    GetChangelistRequest* request = new GetChangelistRequest(
+        request_sender_.get(),
+        *url_generator_,
+        true,  // include deleted
+        100,  // start changestamp
+        500,  // max results
+        test_util::CreateQuitCallback(
+            &run_loop,
+            test_util::CreateCopyResultCallback(&error, &result)));
+    request_sender_->StartRequestWithRetry(request);
+    run_loop.Run();
+  }
 
   EXPECT_EQ(HTTP_SUCCESS, error);
   EXPECT_EQ(net::test_server::METHOD_GET, http_request_.method);
@@ -422,22 +451,24 @@
 TEST_F(DriveApiRequestsTest, GetFilelistRequest) {
   // Set an expected data file containing valid result.
   expected_data_file_path_ = test_util::GetTestFilePath(
-      "chromeos/drive/filelist.json");
+      "drive/filelist.json");
 
   GDataErrorCode error = GDATA_OTHER_ERROR;
   scoped_ptr<base::Value> result;
 
-  GetFilelistRequest* request = new GetFilelistRequest(
-      request_sender_.get(),
-      request_context_getter_.get(),
-      *url_generator_,
-      "\"abcde\" in parents",
-      50,  // max results
-      CreateComposedCallback(
-          base::Bind(&test_util::RunAndQuit),
-          test_util::CreateCopyResultCallback(&error, &result)));
-  request_sender_->StartRequestWithRetry(request);
-  base::MessageLoop::current()->Run();
+  {
+    base::RunLoop run_loop;
+    GetFilelistRequest* request = new GetFilelistRequest(
+        request_sender_.get(),
+        *url_generator_,
+        "\"abcde\" in parents",
+        50,  // max results
+        test_util::CreateQuitCallback(
+            &run_loop,
+            test_util::CreateCopyResultCallback(&error, &result)));
+    request_sender_->StartRequestWithRetry(request);
+    run_loop.Run();
+  }
 
   EXPECT_EQ(HTTP_SUCCESS, error);
   EXPECT_EQ(net::test_server::METHOD_GET, http_request_.method);
@@ -449,21 +480,23 @@
 TEST_F(DriveApiRequestsTest, ContinueGetFileListRequest) {
   // Set an expected data file containing valid result.
   expected_data_file_path_ = test_util::GetTestFilePath(
-      "chromeos/drive/filelist.json");
+      "drive/filelist.json");
 
   GDataErrorCode error = GDATA_OTHER_ERROR;
   scoped_ptr<base::Value> result;
 
-  drive::ContinueGetFileListRequest* request =
-      new drive::ContinueGetFileListRequest(
-          request_sender_.get(),
-          request_context_getter_.get(),
-          test_server_.GetURL("/continue/get/file/list"),
-          CreateComposedCallback(
-              base::Bind(&test_util::RunAndQuit),
-              test_util::CreateCopyResultCallback(&error, &result)));
-  request_sender_->StartRequestWithRetry(request);
-  base::MessageLoop::current()->Run();
+  {
+    base::RunLoop run_loop;
+    drive::ContinueGetFileListRequest* request =
+        new drive::ContinueGetFileListRequest(
+            request_sender_.get(),
+            test_server_.GetURL("/continue/get/file/list"),
+            test_util::CreateQuitCallback(
+                &run_loop,
+                test_util::CreateCopyResultCallback(&error, &result)));
+    request_sender_->StartRequestWithRetry(request);
+    run_loop.Run();
+  }
 
   EXPECT_EQ(HTTP_SUCCESS, error);
   EXPECT_EQ(net::test_server::METHOD_GET, http_request_.method);
@@ -474,24 +507,26 @@
 TEST_F(DriveApiRequestsTest, CreateDirectoryRequest) {
   // Set an expected data file containing the directory's entry data.
   expected_data_file_path_ =
-      test_util::GetTestFilePath("chromeos/drive/directory_entry.json");
+      test_util::GetTestFilePath("drive/directory_entry.json");
 
   GDataErrorCode error = GDATA_OTHER_ERROR;
   scoped_ptr<FileResource> file_resource;
 
   // Create "new directory" in the root directory.
-  drive::CreateDirectoryRequest* request =
-      new drive::CreateDirectoryRequest(
-          request_sender_.get(),
-          request_context_getter_.get(),
-          *url_generator_,
-          "root",
-          "new directory",
-          CreateComposedCallback(
-              base::Bind(&test_util::RunAndQuit),
-              test_util::CreateCopyResultCallback(&error, &file_resource)));
-  request_sender_->StartRequestWithRetry(request);
-  base::MessageLoop::current()->Run();
+  {
+    base::RunLoop run_loop;
+    drive::CreateDirectoryRequest* request =
+        new drive::CreateDirectoryRequest(
+            request_sender_.get(),
+            *url_generator_,
+            "root",
+            "new directory",
+            test_util::CreateQuitCallback(
+                &run_loop,
+                test_util::CreateCopyResultCallback(&error, &file_resource)));
+    request_sender_->StartRequestWithRetry(request);
+    run_loop.Run();
+  }
 
   EXPECT_EQ(HTTP_SUCCESS, error);
   EXPECT_EQ(net::test_server::METHOD_POST, http_request_.method);
@@ -502,7 +537,7 @@
 
   scoped_ptr<FileResource> expected(
       FileResource::CreateFrom(
-          *test_util::LoadJSONFile("chromeos/drive/directory_entry.json")));
+          *test_util::LoadJSONFile("drive/directory_entry.json")));
 
   // Sanity check.
   ASSERT_TRUE(file_resource.get());
@@ -517,23 +552,25 @@
   // Set an expected data file containing the directory's entry data.
   // It'd be returned if we rename a directory.
   expected_data_file_path_ =
-      test_util::GetTestFilePath("chromeos/drive/directory_entry.json");
+      test_util::GetTestFilePath("drive/directory_entry.json");
 
   GDataErrorCode error = GDATA_OTHER_ERROR;
 
   // Create "new directory" in the root directory.
-  drive::RenameResourceRequest* request =
-      new drive::RenameResourceRequest(
-          request_sender_.get(),
-          request_context_getter_.get(),
-          *url_generator_,
-          "resource_id",
-          "new name",
-          CreateComposedCallback(
-              base::Bind(&test_util::RunAndQuit),
-              test_util::CreateCopyResultCallback(&error)));
-  request_sender_->StartRequestWithRetry(request);
-  base::MessageLoop::current()->Run();
+  {
+    base::RunLoop run_loop;
+    drive::RenameResourceRequest* request =
+        new drive::RenameResourceRequest(
+            request_sender_.get(),
+            *url_generator_,
+            "resource_id",
+            "new name",
+            test_util::CreateQuitCallback(
+                &run_loop,
+                test_util::CreateCopyResultCallback(&error)));
+    request_sender_->StartRequestWithRetry(request);
+    run_loop.Run();
+  }
 
   EXPECT_EQ(HTTP_SUCCESS, error);
   EXPECT_EQ(net::test_server::METHOD_PATCH, http_request_.method);
@@ -548,7 +585,7 @@
   // Set an expected data file containing the directory's entry data.
   // It'd be returned if we rename a directory.
   expected_data_file_path_ =
-      test_util::GetTestFilePath("chromeos/drive/directory_entry.json");
+      test_util::GetTestFilePath("drive/directory_entry.json");
 
   GDataErrorCode error = GDATA_OTHER_ERROR;
   scoped_ptr<FileResource> file_resource;
@@ -557,18 +594,20 @@
       {2013, 7, 0, 19, 15, 59, 13, 123};
 
   // Touch a file with |resource_id|.
-  drive::TouchResourceRequest* request = new drive::TouchResourceRequest(
-      request_sender_.get(),
-      request_context_getter_.get(),
-      *url_generator_,
-      "resource_id",
-      base::Time::FromUTCExploded(kModifiedDate),
-      base::Time::FromUTCExploded(kLastViewedByMeDate),
-      CreateComposedCallback(
-          base::Bind(&test_util::RunAndQuit),
-          test_util::CreateCopyResultCallback(&error, &file_resource)));
-  request_sender_->StartRequestWithRetry(request);
-  base::MessageLoop::current()->Run();
+  {
+    base::RunLoop run_loop;
+    drive::TouchResourceRequest* request = new drive::TouchResourceRequest(
+        request_sender_.get(),
+        *url_generator_,
+        "resource_id",
+        base::Time::FromUTCExploded(kModifiedDate),
+        base::Time::FromUTCExploded(kLastViewedByMeDate),
+        test_util::CreateQuitCallback(
+            &run_loop,
+            test_util::CreateCopyResultCallback(&error, &file_resource)));
+    request_sender_->StartRequestWithRetry(request);
+    run_loop.Run();
+  }
 
   EXPECT_EQ(HTTP_SUCCESS, error);
   EXPECT_EQ(net::test_server::METHOD_PATCH, http_request_.method);
@@ -587,25 +626,27 @@
   // Set an expected data file containing the dummy file entry data.
   // It'd be returned if we copy a file.
   expected_data_file_path_ =
-      test_util::GetTestFilePath("chromeos/drive/file_entry.json");
+      test_util::GetTestFilePath("drive/file_entry.json");
 
   GDataErrorCode error = GDATA_OTHER_ERROR;
   scoped_ptr<FileResource> file_resource;
 
   // Copy the file to a new file named "new name".
-  drive::CopyResourceRequest* request =
-      new drive::CopyResourceRequest(
-          request_sender_.get(),
-          request_context_getter_.get(),
-          *url_generator_,
-          "resource_id",
-          "parent_resource_id",
-          "new name",
-          CreateComposedCallback(
-              base::Bind(&test_util::RunAndQuit),
-              test_util::CreateCopyResultCallback(&error, &file_resource)));
-  request_sender_->StartRequestWithRetry(request);
-  base::MessageLoop::current()->Run();
+  {
+    base::RunLoop run_loop;
+    drive::CopyResourceRequest* request =
+        new drive::CopyResourceRequest(
+            request_sender_.get(),
+            *url_generator_,
+            "resource_id",
+            "parent_resource_id",
+            "new name",
+            test_util::CreateQuitCallback(
+                &run_loop,
+                test_util::CreateCopyResultCallback(&error, &file_resource)));
+    request_sender_->StartRequestWithRetry(request);
+    run_loop.Run();
+  }
 
   EXPECT_EQ(HTTP_SUCCESS, error);
   EXPECT_EQ(net::test_server::METHOD_POST, http_request_.method);
@@ -623,25 +664,27 @@
   // Set an expected data file containing the dummy file entry data.
   // It'd be returned if we copy a file.
   expected_data_file_path_ =
-      test_util::GetTestFilePath("chromeos/drive/file_entry.json");
+      test_util::GetTestFilePath("drive/file_entry.json");
 
   GDataErrorCode error = GDATA_OTHER_ERROR;
   scoped_ptr<FileResource> file_resource;
 
   // Copy the file to a new file named "new name".
-  drive::CopyResourceRequest* request =
-      new drive::CopyResourceRequest(
-          request_sender_.get(),
-          request_context_getter_.get(),
-          *url_generator_,
-          "resource_id",
-          std::string(),  // parent resource id.
-          "new name",
-          CreateComposedCallback(
-              base::Bind(&test_util::RunAndQuit),
-              test_util::CreateCopyResultCallback(&error, &file_resource)));
-  request_sender_->StartRequestWithRetry(request);
-  base::MessageLoop::current()->Run();
+  {
+    base::RunLoop run_loop;
+    drive::CopyResourceRequest* request =
+        new drive::CopyResourceRequest(
+            request_sender_.get(),
+            *url_generator_,
+            "resource_id",
+            std::string(),  // parent resource id.
+            "new name",
+            test_util::CreateQuitCallback(
+                &run_loop,
+                test_util::CreateCopyResultCallback(&error, &file_resource)));
+    request_sender_->StartRequestWithRetry(request);
+    run_loop.Run();
+  }
 
   EXPECT_EQ(HTTP_SUCCESS, error);
   EXPECT_EQ(net::test_server::METHOD_POST, http_request_.method);
@@ -657,22 +700,24 @@
   // Set data for the expected result. Directory entry should be returned
   // if the trashing entry is a directory, so using it here should be fine.
   expected_data_file_path_ =
-      test_util::GetTestFilePath("chromeos/drive/directory_entry.json");
+      test_util::GetTestFilePath("drive/directory_entry.json");
 
   GDataErrorCode error = GDATA_OTHER_ERROR;
 
   // Trash a resource with the given resource id.
-  drive::TrashResourceRequest* request =
-      new drive::TrashResourceRequest(
-          request_sender_.get(),
-          request_context_getter_.get(),
-          *url_generator_,
-          "resource_id",
-          CreateComposedCallback(
-              base::Bind(&test_util::RunAndQuit),
-              test_util::CreateCopyResultCallback(&error)));
-  request_sender_->StartRequestWithRetry(request);
-  base::MessageLoop::current()->Run();
+  {
+    base::RunLoop run_loop;
+    drive::TrashResourceRequest* request =
+        new drive::TrashResourceRequest(
+            request_sender_.get(),
+            *url_generator_,
+            "resource_id",
+            test_util::CreateQuitCallback(
+                &run_loop,
+                test_util::CreateCopyResultCallback(&error)));
+    request_sender_->StartRequestWithRetry(request);
+    run_loop.Run();
+  }
 
   EXPECT_EQ(HTTP_SUCCESS, error);
   EXPECT_EQ(net::test_server::METHOD_POST, http_request_.method);
@@ -690,18 +735,20 @@
 
   // Add a resource with "resource_id" to a directory with
   // "parent_resource_id".
-  drive::InsertResourceRequest* request =
-      new drive::InsertResourceRequest(
-          request_sender_.get(),
-          request_context_getter_.get(),
-          *url_generator_,
-          "parent_resource_id",
-          "resource_id",
-          CreateComposedCallback(
-              base::Bind(&test_util::RunAndQuit),
-              test_util::CreateCopyResultCallback(&error)));
-  request_sender_->StartRequestWithRetry(request);
-  base::MessageLoop::current()->Run();
+  {
+    base::RunLoop run_loop;
+    drive::InsertResourceRequest* request =
+        new drive::InsertResourceRequest(
+            request_sender_.get(),
+            *url_generator_,
+            "parent_resource_id",
+            "resource_id",
+            test_util::CreateQuitCallback(
+                &run_loop,
+                test_util::CreateCopyResultCallback(&error)));
+    request_sender_->StartRequestWithRetry(request);
+    run_loop.Run();
+  }
 
   EXPECT_EQ(HTTP_SUCCESS, error);
   EXPECT_EQ(net::test_server::METHOD_POST, http_request_.method);
@@ -718,18 +765,20 @@
 
   // Remove a resource with "resource_id" from a directory with
   // "parent_resource_id".
-  drive::DeleteResourceRequest* request =
-      new drive::DeleteResourceRequest(
-          request_sender_.get(),
-          request_context_getter_.get(),
-          *url_generator_,
-          "parent_resource_id",
-          "resource_id",
-          CreateComposedCallback(
-              base::Bind(&test_util::RunAndQuit),
-              test_util::CreateCopyResultCallback(&error)));
-  request_sender_->StartRequestWithRetry(request);
-  base::MessageLoop::current()->Run();
+  {
+    base::RunLoop run_loop;
+    drive::DeleteResourceRequest* request =
+        new drive::DeleteResourceRequest(
+            request_sender_.get(),
+            *url_generator_,
+            "parent_resource_id",
+            "resource_id",
+            test_util::CreateQuitCallback(
+                &run_loop,
+                test_util::CreateCopyResultCallback(&error)));
+    request_sender_->StartRequestWithRetry(request);
+    run_loop.Run();
+  }
 
   EXPECT_EQ(HTTP_NO_CONTENT, error);
   EXPECT_EQ(net::test_server::METHOD_DELETE, http_request_.method);
@@ -753,21 +802,22 @@
 
   // Initiate uploading a new file to the directory with
   // "parent_resource_id".
-  drive::InitiateUploadNewFileRequest* request =
-      new drive::InitiateUploadNewFileRequest(
-          request_sender_.get(),
-          request_context_getter_.get(),
-          *url_generator_,
-          base::FilePath(FILE_PATH_LITERAL("drive/file/path")),
-          kTestContentType,
-          kTestContent.size(),
-          "parent_resource_id",  // The resource id of the parent directory.
-          "new file title",  // The title of the file being uploaded.
-          CreateComposedCallback(
-              base::Bind(&test_util::RunAndQuit),
-              test_util::CreateCopyResultCallback(&error, &upload_url)));
-  request_sender_->StartRequestWithRetry(request);
-  base::MessageLoop::current()->Run();
+  {
+    base::RunLoop run_loop;
+    drive::InitiateUploadNewFileRequest* request =
+        new drive::InitiateUploadNewFileRequest(
+            request_sender_.get(),
+            *url_generator_,
+            kTestContentType,
+            kTestContent.size(),
+            "parent_resource_id",  // The resource id of the parent directory.
+            "new file title",  // The title of the file being uploaded.
+            test_util::CreateQuitCallback(
+                &run_loop,
+                test_util::CreateCopyResultCallback(&error, &upload_url)));
+    request_sender_->StartRequestWithRetry(request);
+    run_loop.Run();
+  }
 
   EXPECT_EQ(HTTP_SUCCESS, error);
   EXPECT_EQ(kTestUploadNewFilePath, upload_url.path());
@@ -791,23 +841,24 @@
   UploadRangeResponse response;
   scoped_ptr<FileResource> new_entry;
 
-  drive::ResumeUploadRequest* resume_request =
-      new drive::ResumeUploadRequest(
-          request_sender_.get(),
-          request_context_getter_.get(),
-          base::FilePath(FILE_PATH_LITERAL("drive/file/path")),
-          upload_url,
-          0,  // start_position
-          kTestContent.size(),  // end_position (exclusive)
-          kTestContent.size(),  // content_length,
-          kTestContentType,
-          kTestFilePath,
-          CreateComposedCallback(
-              base::Bind(&test_util::RunAndQuit),
-              test_util::CreateCopyResultCallback(&response, &new_entry)),
-          ProgressCallback());
-  request_sender_->StartRequestWithRetry(resume_request);
-  base::MessageLoop::current()->Run();
+  {
+    base::RunLoop run_loop;
+    drive::ResumeUploadRequest* resume_request =
+        new drive::ResumeUploadRequest(
+            request_sender_.get(),
+            upload_url,
+            0,  // start_position
+            kTestContent.size(),  // end_position (exclusive)
+            kTestContent.size(),  // content_length,
+            kTestContentType,
+            kTestFilePath,
+            test_util::CreateQuitCallback(
+                &run_loop,
+                test_util::CreateCopyResultCallback(&response, &new_entry)),
+            ProgressCallback());
+    request_sender_->StartRequestWithRetry(resume_request);
+    run_loop.Run();
+  }
 
   // METHOD_PUT should be used to upload data.
   EXPECT_EQ(net::test_server::METHOD_PUT, http_request_.method);
@@ -843,21 +894,22 @@
   GURL upload_url;
 
   // Initiate uploading a new file to the directory with "parent_resource_id".
-  drive::InitiateUploadNewFileRequest* request =
-      new drive::InitiateUploadNewFileRequest(
-          request_sender_.get(),
-          request_context_getter_.get(),
-          *url_generator_,
-          base::FilePath(FILE_PATH_LITERAL("drive/file/path")),
-          kTestContentType,
-          0,
-          "parent_resource_id",  // The resource id of the parent directory.
-          "new file title",  // The title of the file being uploaded.
-          CreateComposedCallback(
-              base::Bind(&test_util::RunAndQuit),
-              test_util::CreateCopyResultCallback(&error, &upload_url)));
-  request_sender_->StartRequestWithRetry(request);
-  base::MessageLoop::current()->Run();
+  {
+    base::RunLoop run_loop;
+    drive::InitiateUploadNewFileRequest* request =
+        new drive::InitiateUploadNewFileRequest(
+            request_sender_.get(),
+            *url_generator_,
+            kTestContentType,
+            0,
+            "parent_resource_id",  // The resource id of the parent directory.
+            "new file title",  // The title of the file being uploaded.
+            test_util::CreateQuitCallback(
+                &run_loop,
+                test_util::CreateCopyResultCallback(&error, &upload_url)));
+    request_sender_->StartRequestWithRetry(request);
+    run_loop.Run();
+  }
 
   EXPECT_EQ(HTTP_SUCCESS, error);
   EXPECT_EQ(kTestUploadNewFilePath, upload_url.path());
@@ -880,23 +932,24 @@
   UploadRangeResponse response;
   scoped_ptr<FileResource> new_entry;
 
-  drive::ResumeUploadRequest* resume_request =
-      new drive::ResumeUploadRequest(
-          request_sender_.get(),
-          request_context_getter_.get(),
-          base::FilePath(FILE_PATH_LITERAL("drive/file/path")),
-          upload_url,
-          0,  // start_position
-          0,  // end_position (exclusive)
-          0,  // content_length,
-          kTestContentType,
-          kTestFilePath,
-          CreateComposedCallback(
-              base::Bind(&test_util::RunAndQuit),
-              test_util::CreateCopyResultCallback(&response, &new_entry)),
-          ProgressCallback());
-  request_sender_->StartRequestWithRetry(resume_request);
-  base::MessageLoop::current()->Run();
+  {
+    base::RunLoop run_loop;
+    drive::ResumeUploadRequest* resume_request =
+        new drive::ResumeUploadRequest(
+            request_sender_.get(),
+            upload_url,
+            0,  // start_position
+            0,  // end_position (exclusive)
+            0,  // content_length,
+            kTestContentType,
+            kTestFilePath,
+            test_util::CreateQuitCallback(
+                &run_loop,
+                test_util::CreateCopyResultCallback(&response, &new_entry)),
+            ProgressCallback());
+    request_sender_->StartRequestWithRetry(resume_request);
+    run_loop.Run();
+  }
 
   // METHOD_PUT should be used to upload data.
   EXPECT_EQ(net::test_server::METHOD_PUT, http_request_.method);
@@ -915,9 +968,6 @@
   EXPECT_EQ(-1, response.end_position_received);
 }
 
-// TODO(kinaba): crbug.com/{241241,164098} Re-enable the test.
-#define NO_GET_UPLOAD_STATUS_TEST
-
 TEST_F(DriveApiRequestsTest, UploadNewLargeFileRequest) {
   // Set an expected url for uploading.
   expected_upload_path_ = kTestUploadNewFilePath;
@@ -933,21 +983,22 @@
   GURL upload_url;
 
   // Initiate uploading a new file to the directory with "parent_resource_id".
-  drive::InitiateUploadNewFileRequest* request =
-      new drive::InitiateUploadNewFileRequest(
-          request_sender_.get(),
-          request_context_getter_.get(),
-          *url_generator_,
-          base::FilePath(FILE_PATH_LITERAL("drive/file/path")),
-          kTestContentType,
-          kTestContent.size(),
-          "parent_resource_id",  // The resource id of the parent directory.
-          "new file title",  // The title of the file being uploaded.
-          CreateComposedCallback(
-              base::Bind(&test_util::RunAndQuit),
-              test_util::CreateCopyResultCallback(&error, &upload_url)));
-  request_sender_->StartRequestWithRetry(request);
-  base::MessageLoop::current()->Run();
+  {
+    base::RunLoop run_loop;
+    drive::InitiateUploadNewFileRequest* request =
+        new drive::InitiateUploadNewFileRequest(
+            request_sender_.get(),
+            *url_generator_,
+            kTestContentType,
+            kTestContent.size(),
+            "parent_resource_id",  // The resource id of the parent directory.
+            "new file title",  // The title of the file being uploaded.
+            test_util::CreateQuitCallback(
+                &run_loop,
+                test_util::CreateCopyResultCallback(&error, &upload_url)));
+    request_sender_->StartRequestWithRetry(request);
+    run_loop.Run();
+  }
 
   EXPECT_EQ(HTTP_SUCCESS, error);
   EXPECT_EQ(kTestUploadNewFilePath, upload_url.path());
@@ -967,7 +1018,6 @@
             "\"title\":\"new file title\"}",
             http_request_.content);
 
-#if !defined(NO_GET_UPLOAD_STATUS_TEST)
   // Before sending any data, check the current status.
   // This is an edge case test for GetUploadStatusRequest.
   {
@@ -975,18 +1025,19 @@
     scoped_ptr<FileResource> new_entry;
 
     // Check the response by GetUploadStatusRequest.
-    drive::GetUploadStatusRequest* get_upload_status_request =
-        new drive::GetUploadStatusRequest(
-            request_sender_.get(),
-            request_context_getter_.get(),
-            base::FilePath(FILE_PATH_LITERAL("drive/file/path")),
-            upload_url,
-            kTestContent.size(),
-            CreateComposedCallback(
-                base::Bind(&test_util::RunAndQuit),
-                test_util::CreateCopyResultCallback(&response, &new_entry)));
-    request_sender_->StartRequestWithRetry(get_upload_status_request);
-    base::MessageLoop::current()->Run();
+    {
+      base::RunLoop run_loop;
+      drive::GetUploadStatusRequest* get_upload_status_request =
+          new drive::GetUploadStatusRequest(
+              request_sender_.get(),
+              upload_url,
+              kTestContent.size(),
+              test_util::CreateQuitCallback(
+                  &run_loop,
+                  test_util::CreateCopyResultCallback(&response, &new_entry)));
+      request_sender_->StartRequestWithRetry(get_upload_status_request);
+      run_loop.Run();
+    }
 
     // METHOD_PUT should be used to upload data.
     EXPECT_EQ(net::test_server::METHOD_PUT, http_request_.method);
@@ -1003,7 +1054,6 @@
     EXPECT_EQ(0, response.start_position_received);
     EXPECT_EQ(0, response.end_position_received);
   }
-#endif  // NO_GET_UPLOAD_STATUS_TEST
 
   // Upload the content to the upload URL.
   for (size_t start_position = 0; start_position < kTestContent.size();
@@ -1016,23 +1066,24 @@
     UploadRangeResponse response;
     scoped_ptr<FileResource> new_entry;
 
-    drive::ResumeUploadRequest* resume_request =
-        new drive::ResumeUploadRequest(
-            request_sender_.get(),
-            request_context_getter_.get(),
-            base::FilePath(FILE_PATH_LITERAL("drive/file/path")),
-            upload_url,
-            start_position,
-            end_position,
-            kTestContent.size(),  // content_length,
-            kTestContentType,
-            kTestFilePath,
-            CreateComposedCallback(
-                base::Bind(&test_util::RunAndQuit),
-                test_util::CreateCopyResultCallback(&response, &new_entry)),
-            ProgressCallback());
-    request_sender_->StartRequestWithRetry(resume_request);
-    base::MessageLoop::current()->Run();
+    {
+      base::RunLoop run_loop;
+      drive::ResumeUploadRequest* resume_request =
+          new drive::ResumeUploadRequest(
+              request_sender_.get(),
+              upload_url,
+              start_position,
+              end_position,
+              kTestContent.size(),  // content_length,
+              kTestContentType,
+              kTestFilePath,
+              test_util::CreateQuitCallback(
+                  &run_loop,
+                  test_util::CreateCopyResultCallback(&response, &new_entry)),
+              ProgressCallback());
+      request_sender_->StartRequestWithRetry(resume_request);
+      run_loop.Run();
+    }
 
     // METHOD_PUT should be used to upload data.
     EXPECT_EQ(net::test_server::METHOD_PUT, http_request_.method);
@@ -1063,20 +1114,20 @@
     EXPECT_EQ(0, response.start_position_received);
     EXPECT_EQ(static_cast<int64>(end_position), response.end_position_received);
 
-#if !defined(NO_GET_UPLOAD_STATUS_TEST)
     // Check the response by GetUploadStatusRequest.
-    drive::GetUploadStatusRequest* get_upload_status_request =
-        new drive::GetUploadStatusRequest(
-            request_sender_.get(),
-            request_context_getter_.get(),
-            base::FilePath(FILE_PATH_LITERAL("drive/file/path")),
-            upload_url,
-            kTestContent.size(),
-            CreateComposedCallback(
-                base::Bind(&test_util::RunAndQuit),
-                test_util::CreateCopyResultCallback(&response, &new_entry)));
-    request_sender_->StartRequestWithRetry(get_upload_status_request);
-    base::MessageLoop::current()->Run();
+    {
+      base::RunLoop run_loop;
+      drive::GetUploadStatusRequest* get_upload_status_request =
+          new drive::GetUploadStatusRequest(
+              request_sender_.get(),
+              upload_url,
+              kTestContent.size(),
+              test_util::CreateQuitCallback(
+                  &run_loop,
+                  test_util::CreateCopyResultCallback(&response, &new_entry)));
+      request_sender_->StartRequestWithRetry(get_upload_status_request);
+      run_loop.Run();
+    }
 
     // METHOD_PUT should be used to upload data.
     EXPECT_EQ(net::test_server::METHOD_PUT, http_request_.method);
@@ -1093,7 +1144,6 @@
     EXPECT_EQ(0, response.start_position_received);
     EXPECT_EQ(static_cast<int64>(end_position),
               response.end_position_received);
-#endif  // NO_GET_UPLOAD_STATUS_TEST
   }
 }
 
@@ -1111,21 +1161,22 @@
   GURL upload_url;
 
   // Initiate uploading a new file to the directory with "parent_resource_id".
-  drive::InitiateUploadExistingFileRequest* request =
-      new drive::InitiateUploadExistingFileRequest(
-          request_sender_.get(),
-          request_context_getter_.get(),
-          *url_generator_,
-          base::FilePath(FILE_PATH_LITERAL("drive/file/path")),
-          kTestContentType,
-          kTestContent.size(),
-          "resource_id",  // The resource id of the file to be overwritten.
-          std::string(),  // No etag.
-          CreateComposedCallback(
-              base::Bind(&test_util::RunAndQuit),
-              test_util::CreateCopyResultCallback(&error, &upload_url)));
-  request_sender_->StartRequestWithRetry(request);
-  base::MessageLoop::current()->Run();
+  {
+    base::RunLoop run_loop;
+    drive::InitiateUploadExistingFileRequest* request =
+        new drive::InitiateUploadExistingFileRequest(
+            request_sender_.get(),
+            *url_generator_,
+            kTestContentType,
+            kTestContent.size(),
+            "resource_id",  // The resource id of the file to be overwritten.
+            std::string(),  // No etag.
+            test_util::CreateQuitCallback(
+                &run_loop,
+                test_util::CreateCopyResultCallback(&error, &upload_url)));
+    request_sender_->StartRequestWithRetry(request);
+    run_loop.Run();
+  }
 
   EXPECT_EQ(HTTP_SUCCESS, error);
   EXPECT_EQ(kTestUploadExistingFilePath, upload_url.path());
@@ -1144,23 +1195,24 @@
   UploadRangeResponse response;
   scoped_ptr<FileResource> new_entry;
 
-  drive::ResumeUploadRequest* resume_request =
-      new drive::ResumeUploadRequest(
-          request_sender_.get(),
-          request_context_getter_.get(),
-          base::FilePath(FILE_PATH_LITERAL("drive/file/path")),
-          upload_url,
-          0,  // start_position
-          kTestContent.size(),  // end_position (exclusive)
-          kTestContent.size(),  // content_length,
-          kTestContentType,
-          kTestFilePath,
-          CreateComposedCallback(
-              base::Bind(&test_util::RunAndQuit),
-              test_util::CreateCopyResultCallback(&response, &new_entry)),
-          ProgressCallback());
-  request_sender_->StartRequestWithRetry(resume_request);
-  base::MessageLoop::current()->Run();
+  {
+    base::RunLoop run_loop;
+    drive::ResumeUploadRequest* resume_request =
+        new drive::ResumeUploadRequest(
+            request_sender_.get(),
+            upload_url,
+            0,  // start_position
+            kTestContent.size(),  // end_position (exclusive)
+            kTestContent.size(),  // content_length,
+            kTestContentType,
+            kTestFilePath,
+            test_util::CreateQuitCallback(
+                &run_loop,
+                test_util::CreateCopyResultCallback(&response, &new_entry)),
+            ProgressCallback());
+    request_sender_->StartRequestWithRetry(resume_request);
+    run_loop.Run();
+  }
 
   // METHOD_PUT should be used to upload data.
   EXPECT_EQ(net::test_server::METHOD_PUT, http_request_.method);
@@ -1196,21 +1248,22 @@
   GURL upload_url;
 
   // Initiate uploading a new file to the directory with "parent_resource_id".
-  drive::InitiateUploadExistingFileRequest* request =
-      new drive::InitiateUploadExistingFileRequest(
-          request_sender_.get(),
-          request_context_getter_.get(),
-          *url_generator_,
-          base::FilePath(FILE_PATH_LITERAL("drive/file/path")),
-          kTestContentType,
-          kTestContent.size(),
-          "resource_id",  // The resource id of the file to be overwritten.
-          kTestETag,
-          CreateComposedCallback(
-              base::Bind(&test_util::RunAndQuit),
-              test_util::CreateCopyResultCallback(&error, &upload_url)));
-  request_sender_->StartRequestWithRetry(request);
-  base::MessageLoop::current()->Run();
+  {
+    base::RunLoop run_loop;
+    drive::InitiateUploadExistingFileRequest* request =
+        new drive::InitiateUploadExistingFileRequest(
+            request_sender_.get(),
+            *url_generator_,
+            kTestContentType,
+            kTestContent.size(),
+            "resource_id",  // The resource id of the file to be overwritten.
+            kTestETag,
+            test_util::CreateQuitCallback(
+                &run_loop,
+                test_util::CreateCopyResultCallback(&error, &upload_url)));
+    request_sender_->StartRequestWithRetry(request);
+    run_loop.Run();
+  }
 
   EXPECT_EQ(HTTP_SUCCESS, error);
   EXPECT_EQ(kTestUploadExistingFilePath, upload_url.path());
@@ -1229,23 +1282,24 @@
   UploadRangeResponse response;
   scoped_ptr<FileResource> new_entry;
 
-  drive::ResumeUploadRequest* resume_request =
-      new drive::ResumeUploadRequest(
-          request_sender_.get(),
-          request_context_getter_.get(),
-          base::FilePath(FILE_PATH_LITERAL("drive/file/path")),
-          upload_url,
-          0,  // start_position
-          kTestContent.size(),  // end_position (exclusive)
-          kTestContent.size(),  // content_length,
-          kTestContentType,
-          kTestFilePath,
-          CreateComposedCallback(
-              base::Bind(&test_util::RunAndQuit),
-              test_util::CreateCopyResultCallback(&response, &new_entry)),
-          ProgressCallback());
-  request_sender_->StartRequestWithRetry(resume_request);
-  base::MessageLoop::current()->Run();
+  {
+    base::RunLoop run_loop;
+    drive::ResumeUploadRequest* resume_request =
+        new drive::ResumeUploadRequest(
+            request_sender_.get(),
+            upload_url,
+            0,  // start_position
+            kTestContent.size(),  // end_position (exclusive)
+            kTestContent.size(),  // content_length,
+            kTestContentType,
+            kTestFilePath,
+            test_util::CreateQuitCallback(
+                &run_loop,
+                test_util::CreateCopyResultCallback(&response, &new_entry)),
+            ProgressCallback());
+    request_sender_->StartRequestWithRetry(resume_request);
+    run_loop.Run();
+  }
 
   // METHOD_PUT should be used to upload data.
   EXPECT_EQ(net::test_server::METHOD_PUT, http_request_.method);
@@ -1278,21 +1332,22 @@
   GURL upload_url;
 
   // Initiate uploading a new file to the directory with "parent_resource_id".
-  drive::InitiateUploadExistingFileRequest* request =
-      new drive::InitiateUploadExistingFileRequest(
-          request_sender_.get(),
-          request_context_getter_.get(),
-          *url_generator_,
-          base::FilePath(FILE_PATH_LITERAL("drive/file/path")),
-          kTestContentType,
-          kTestContent.size(),
-          "resource_id",  // The resource id of the file to be overwritten.
-          "Conflicting-etag",
-          CreateComposedCallback(
-              base::Bind(&test_util::RunAndQuit),
-              test_util::CreateCopyResultCallback(&error, &upload_url)));
-  request_sender_->StartRequestWithRetry(request);
-  base::MessageLoop::current()->Run();
+  {
+    base::RunLoop run_loop;
+    drive::InitiateUploadExistingFileRequest* request =
+        new drive::InitiateUploadExistingFileRequest(
+            request_sender_.get(),
+            *url_generator_,
+            kTestContentType,
+            kTestContent.size(),
+            "resource_id",  // The resource id of the file to be overwritten.
+            "Conflicting-etag",
+            test_util::CreateQuitCallback(
+                &run_loop,
+                test_util::CreateCopyResultCallback(&error, &upload_url)));
+    request_sender_->StartRequestWithRetry(request);
+    run_loop.Run();
+  }
 
   EXPECT_EQ(HTTP_PRECONDITION, error);
   EXPECT_EQ(kTestContentType, http_request_.headers["X-Upload-Content-Type"]);
@@ -1307,4 +1362,40 @@
   EXPECT_TRUE(http_request_.content.empty());
 }
 
+TEST_F(DriveApiRequestsTest, DownloadFileRequest) {
+  const base::FilePath kDownloadedFilePath =
+      temp_dir_.path().AppendASCII("cache_file");
+  const std::string kTestId("dummyId");
+
+  GDataErrorCode result_code = GDATA_OTHER_ERROR;
+  base::FilePath temp_file;
+  {
+    base::RunLoop run_loop;
+    drive::DownloadFileRequest* request = new drive::DownloadFileRequest(
+        request_sender_.get(),
+        *url_generator_,
+        kTestId,
+        kDownloadedFilePath,
+        test_util::CreateQuitCallback(
+            &run_loop,
+            test_util::CreateCopyResultCallback(&result_code, &temp_file)),
+        GetContentCallback(),
+        ProgressCallback());
+    request_sender_->StartRequestWithRetry(request);
+    run_loop.Run();
+  }
+
+  std::string contents;
+  file_util::ReadFileToString(temp_file, &contents);
+  base::Delete(temp_file, false);
+
+  EXPECT_EQ(HTTP_SUCCESS, result_code);
+  EXPECT_EQ(net::test_server::METHOD_GET, http_request_.method);
+  EXPECT_EQ(kTestDownloadPathPrefix + kTestId, http_request_.relative_url);
+  EXPECT_EQ(kDownloadedFilePath, temp_file);
+
+  const std::string expected_contents = kTestId + kTestId + kTestId;
+  EXPECT_EQ(expected_contents, contents);
+}
+
 }  // namespace google_apis
diff --git a/chrome/browser/google_apis/drive_api_url_generator.cc b/chrome/browser/google_apis/drive_api_url_generator.cc
index 1de3704..53a6200 100644
--- a/chrome/browser/google_apis/drive_api_url_generator.cc
+++ b/chrome/browser/google_apis/drive_api_url_generator.cc
@@ -41,8 +41,10 @@
 
 }  // namespace
 
-DriveApiUrlGenerator::DriveApiUrlGenerator(const GURL& base_url)
-    : base_url_(base_url) {
+DriveApiUrlGenerator::DriveApiUrlGenerator(const GURL& base_url,
+                                           const GURL& base_download_url)
+    : base_url_(base_url),
+      base_download_url_(base_download_url) {
   // Do nothing.
 }
 
@@ -52,6 +54,8 @@
 
 const char DriveApiUrlGenerator::kBaseUrlForProduction[] =
     "https://www.googleapis.com";
+const char DriveApiUrlGenerator::kBaseDownloadUrlForProduction[] =
+    "https://www.googledrive.com/host/";
 
 GURL DriveApiUrlGenerator::GetAboutUrl() const {
   return base_url_.Resolve(kDriveV2AboutUrl);
@@ -153,4 +157,9 @@
   return AddResumableUploadParam(url);
 }
 
+GURL DriveApiUrlGenerator::GenerateDownloadFileUrl(
+    const std::string& resource_id) const {
+  return base_download_url_.Resolve(net::EscapePath(resource_id));
+}
+
 }  // namespace google_apis
diff --git a/chrome/browser/google_apis/drive_api_url_generator.h b/chrome/browser/google_apis/drive_api_url_generator.h
index 84f35f4..f121969 100644
--- a/chrome/browser/google_apis/drive_api_url_generator.h
+++ b/chrome/browser/google_apis/drive_api_url_generator.h
@@ -7,7 +7,7 @@
 
 #include <string>
 
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 namespace google_apis {
 
@@ -17,12 +17,15 @@
  public:
   // |base_url| is the path to the target drive api server.
   // Note that this is an injecting point for a testing server.
-  explicit DriveApiUrlGenerator(const GURL& base_url);
+  DriveApiUrlGenerator(const GURL& base_url, const GURL& base_download_url);
   ~DriveApiUrlGenerator();
 
   // The base URL for communicating with the production drive api server.
   static const char kBaseUrlForProduction[];
 
+  // The base URL for the file download server for production.
+  static const char kBaseDownloadUrlForProduction[];
+
   // Returns a URL to fetch "about" data.
   GURL GetAboutUrl() const;
 
@@ -86,8 +89,12 @@
   // |resource_id|.
   GURL GetInitiateUploadExistingFileUrl(const std::string& resource_id) const;
 
+  // Generates a URL for downloading a file.
+  GURL GenerateDownloadFileUrl(const std::string& resource_id) const;
+
  private:
   const GURL base_url_;
+  const GURL base_download_url_;
 
   // This class is copyable hence no DISALLOW_COPY_AND_ASSIGN here.
 };
diff --git a/chrome/browser/google_apis/drive_api_url_generator_unittest.cc b/chrome/browser/google_apis/drive_api_url_generator_unittest.cc
index 6729105..cb6212d 100644
--- a/chrome/browser/google_apis/drive_api_url_generator_unittest.cc
+++ b/chrome/browser/google_apis/drive_api_url_generator_unittest.cc
@@ -5,16 +5,20 @@
 #include "chrome/browser/google_apis/drive_api_url_generator.h"
 
 #include "chrome/browser/google_apis/test_util.h"
-#include "googleurl/src/gurl.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
 
 namespace google_apis {
 
 class DriveApiUrlGeneratorTest : public testing::Test {
  public:
   DriveApiUrlGeneratorTest()
-      : url_generator_(GURL(DriveApiUrlGenerator::kBaseUrlForProduction)),
-        test_url_generator_(test_util::GetBaseUrlForTesting(12345)) {
+      : url_generator_(
+            GURL(DriveApiUrlGenerator::kBaseUrlForProduction),
+            GURL(DriveApiUrlGenerator::kBaseDownloadUrlForProduction)),
+        test_url_generator_(
+            test_util::GetBaseUrlForTesting(12345),
+            test_util::GetBaseUrlForTesting(12345).Resolve("download/")) {
   }
 
  protected:
@@ -256,4 +260,16 @@
           "file:file_id").spec());
 }
 
+TEST_F(DriveApiUrlGeneratorTest, GenerateDownloadFileUrl) {
+  EXPECT_EQ(
+      "https://www.googledrive.com/host/resourceId",
+      url_generator_.GenerateDownloadFileUrl("resourceId").spec());
+  EXPECT_EQ(
+      "https://www.googledrive.com/host/file%3AresourceId",
+      url_generator_.GenerateDownloadFileUrl("file:resourceId").spec());
+  EXPECT_EQ(
+      "http://127.0.0.1:12345/download/resourceId",
+      test_url_generator_.GenerateDownloadFileUrl("resourceId").spec());
+}
+
 }  // namespace google_apis
diff --git a/chrome/browser/google_apis/drive_api_util.cc b/chrome/browser/google_apis/drive_api_util.cc
deleted file mode 100644
index 7f96bf6..0000000
--- a/chrome/browser/google_apis/drive_api_util.cc
+++ /dev/null
@@ -1,138 +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/google_apis/drive_api_util.h"
-
-#include <string>
-
-#include "base/command_line.h"
-#include "base/logging.h"
-#include "base/strings/string16.h"
-#include "base/strings/string_util.h"
-#include "base/strings/stringprintf.h"
-#include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/google_apis/drive_switches.h"
-#include "googleurl/src/gurl.h"
-#include "net/base/escape.h"
-#include "third_party/re2/re2/re2.h"
-
-namespace google_apis {
-namespace util {
-
-bool IsDriveV2ApiEnabled() {
-  const CommandLine* command_line = CommandLine::ForCurrentProcess();
-
-  // Disable Drive API v2 by default.
-  if (!command_line->HasSwitch(switches::kEnableDriveV2Api))
-    return false;
-
-  std::string value =
-      command_line->GetSwitchValueASCII(switches::kEnableDriveV2Api);
-  StringToLowerASCII(&value);
-  // The value must be "" or "true" for true, or "false" for false.
-  DCHECK(value.empty() || value == "true" || value == "false");
-  return value != "false";
-}
-
-}  // namespace util
-
-namespace drive {
-namespace util {
-
-std::string EscapeQueryStringValue(const std::string& str) {
-  std::string result;
-  result.reserve(str.size());
-  for (size_t i = 0; i < str.size(); ++i) {
-    if (str[i] == '\\' || str[i] == '\'') {
-      result.push_back('\\');
-    }
-    result.push_back(str[i]);
-  }
-  return result;
-}
-
-std::string TranslateQuery(const std::string& original_query) {
-  // In order to handle non-ascii white spaces correctly, convert to UTF16.
-  base::string16 query = UTF8ToUTF16(original_query);
-  const base::string16 kDelimiter(
-      kWhitespaceUTF16 + base::string16(1, static_cast<char16>('"')));
-
-  std::string result;
-  for (size_t index = query.find_first_not_of(kWhitespaceUTF16);
-       index != base::string16::npos;
-       index = query.find_first_not_of(kWhitespaceUTF16, index)) {
-    bool is_exclusion = (query[index] == '-');
-    if (is_exclusion)
-      ++index;
-    if (index == query.length()) {
-      // Here, the token is '-' and it should be ignored.
-      continue;
-    }
-
-    size_t begin_token = index;
-    base::string16 token;
-    if (query[begin_token] == '"') {
-      // Quoted query.
-      ++begin_token;
-      size_t end_token = query.find('"', begin_token);
-      if (end_token == base::string16::npos) {
-        // This is kind of syntax error, since quoted string isn't finished.
-        // However, the query is built by user manually, so here we treat
-        // whole remaining string as a token as a fallback, by appending
-        // a missing double-quote character.
-        end_token = query.length();
-        query.push_back('"');
-      }
-
-      token = query.substr(begin_token, end_token - begin_token);
-      index = end_token + 1;  // Consume last '"', too.
-    } else {
-      size_t end_token = query.find_first_of(kDelimiter, begin_token);
-      if (end_token == base::string16::npos) {
-        end_token = query.length();
-      }
-
-      token = query.substr(begin_token, end_token - begin_token);
-      index = end_token;
-    }
-
-    if (token.empty()) {
-      // Just ignore an empty token.
-      continue;
-    }
-
-    if (!result.empty()) {
-      // If there are two or more tokens, need to connect with "and".
-      result.append(" and ");
-    }
-
-    // The meaning of "fullText" should include title, description and content.
-    base::StringAppendF(
-        &result,
-        "%sfullText contains \'%s\'",
-        is_exclusion ? "not " : "",
-        EscapeQueryStringValue(UTF16ToUTF8(token)).c_str());
-  }
-
-  return result;
-}
-
-std::string ExtractResourceIdFromUrl(const GURL& url) {
-  return net::UnescapeURLComponent(url.ExtractFileName(),
-                                   net::UnescapeRule::URL_SPECIAL_CHARS);
-}
-
-std::string CanonicalizeResourceId(const std::string& resource_id) {
-  // If resource ID is in the old WAPI format starting with a prefix like
-  // "document:", strip it and return the remaining part.
-  std::string stripped_resource_id;
-  if (RE2::FullMatch(resource_id, "^[a-z-]+(?::|%3A)([\\w-]+)$",
-                     &stripped_resource_id))
-    return stripped_resource_id;
-  return resource_id;
-}
-
-}  // namespace util
-}  // namespace drive
-}  // namespace google_apis
diff --git a/chrome/browser/google_apis/drive_api_util.h b/chrome/browser/google_apis/drive_api_util.h
deleted file mode 100644
index e0f9c05..0000000
--- a/chrome/browser/google_apis/drive_api_util.h
+++ /dev/null
@@ -1,49 +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_GOOGLE_APIS_DRIVE_API_UTIL_H_
-#define CHROME_BROWSER_GOOGLE_APIS_DRIVE_API_UTIL_H_
-
-#include <string>
-
-class GURL;
-
-namespace google_apis {
-namespace util {
-
-// Returns true if Drive v2 API is enabled via commandline switch.
-bool IsDriveV2ApiEnabled();
-
-}  // namespace util
-
-namespace drive {
-namespace util {
-
-// Escapes ' to \' in the |str|. This is designed to use for string value of
-// search parameter on Drive API v2.
-// See also: https://developers.google.com/drive/search-parameters
-std::string EscapeQueryStringValue(const std::string& str);
-
-// Parses the query, and builds a search query for Drive API v2.
-// This only supports:
-//   Regular query (e.g. dog => fullText contains 'dog')
-//   Conjunctions
-//     (e.g. dog cat => fullText contains 'dog' and fullText contains 'cat')
-//   Exclusion query (e.g. -cat => not fullText contains 'cat').
-//   Quoted query (e.g. "dog cat" => fullText contains 'dog cat').
-// See also: https://developers.google.com/drive/search-parameters
-std::string TranslateQuery(const std::string& original_query);
-
-// Extracts resource_id out of edit url.
-std::string ExtractResourceIdFromUrl(const GURL& url);
-
-// If |resource_id| is in the old resource ID format used by WAPI, converts it
-// into the new format.
-std::string CanonicalizeResourceId(const std::string& resource_id);
-
-}  // namespace util
-}  // namespace drive
-}  // namespace google_apis
-
-#endif  // CHROME_BROWSER_GOOGLE_APIS_DRIVE_API_UTIL_H_
diff --git a/chrome/browser/google_apis/drive_api_util_unittest.cc b/chrome/browser/google_apis/drive_api_util_unittest.cc
deleted file mode 100644
index a301362..0000000
--- a/chrome/browser/google_apis/drive_api_util_unittest.cc
+++ /dev/null
@@ -1,80 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/google_apis/drive_api_util.h"
-
-#include "googleurl/src/gurl.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace google_apis {
-namespace drive {
-namespace util {
-
-TEST(DriveApiUtilTest, EscapeQueryStringValue) {
-  EXPECT_EQ("abcde", EscapeQueryStringValue("abcde"));
-  EXPECT_EQ("\\'", EscapeQueryStringValue("'"));
-  EXPECT_EQ("\\'abcde\\'", EscapeQueryStringValue("'abcde'"));
-  EXPECT_EQ("\\\\", EscapeQueryStringValue("\\"));
-  EXPECT_EQ("\\\\\\'", EscapeQueryStringValue("\\'"));
-}
-
-TEST(DriveApiUtilTest, TranslateQuery) {
-  EXPECT_EQ("", TranslateQuery(""));
-  EXPECT_EQ("fullText contains 'dog'", TranslateQuery("dog"));
-  EXPECT_EQ("fullText contains 'dog' and fullText contains 'cat'",
-            TranslateQuery("dog cat"));
-  EXPECT_EQ("not fullText contains 'cat'", TranslateQuery("-cat"));
-  EXPECT_EQ("fullText contains 'dog cat'", TranslateQuery("\"dog cat\""));
-
-  // Should handles full-width white space correctly.
-  // Note: \xE3\x80\x80 (\u3000) is Ideographic Space (a.k.a. Japanese
-  //   full-width whitespace).
-  EXPECT_EQ("fullText contains 'dog' and fullText contains 'cat'",
-            TranslateQuery("dog" "\xE3\x80\x80" "cat"));
-
-  // If the quoted token is not closed (i.e. the last '"' is missing),
-  // we handle the remaining string is one token, as a fallback.
-  EXPECT_EQ("fullText contains 'dog cat'", TranslateQuery("\"dog cat"));
-
-  // For quoted text with leading '-'.
-  EXPECT_EQ("not fullText contains 'dog cat'", TranslateQuery("-\"dog cat\""));
-
-  // Empty tokens should be simply ignored.
-  EXPECT_EQ("", TranslateQuery("-"));
-  EXPECT_EQ("", TranslateQuery("\"\""));
-  EXPECT_EQ("", TranslateQuery("-\"\""));
-  EXPECT_EQ("", TranslateQuery("\"\"\"\""));
-  EXPECT_EQ("", TranslateQuery("\"\" \"\""));
-  EXPECT_EQ("fullText contains 'dog'", TranslateQuery("\"\" dog \"\""));
-}
-
-TEST(FileSystemUtilTest, ExtractResourceIdFromUrl) {
-  EXPECT_EQ("file:2_file_resource_id", ExtractResourceIdFromUrl(
-      GURL("https://file1_link_self/file:2_file_resource_id")));
-  // %3A should be unescaped.
-  EXPECT_EQ("file:2_file_resource_id", ExtractResourceIdFromUrl(
-      GURL("https://file1_link_self/file%3A2_file_resource_id")));
-
-  // The resource ID cannot be extracted, hence empty.
-  EXPECT_EQ("", ExtractResourceIdFromUrl(GURL("https://www.example.com/")));
-}
-
-TEST(FileSystemUtilTest, CanonicalizeResourceId) {
-  std::string resource_id("1YsCnrMxxgp7LDdtlFDt-WdtEIth89vA9inrILtvK-Ug");
-
-  // New style ID is unchanged.
-  EXPECT_EQ(resource_id, CanonicalizeResourceId(resource_id));
-
-  // Drop prefixes from old style IDs.
-  EXPECT_EQ(resource_id, CanonicalizeResourceId("document:" + resource_id));
-  EXPECT_EQ(resource_id, CanonicalizeResourceId("spreadsheet:" + resource_id));
-  EXPECT_EQ(resource_id, CanonicalizeResourceId("presentation:" + resource_id));
-  EXPECT_EQ(resource_id, CanonicalizeResourceId("drawing:" + resource_id));
-  EXPECT_EQ(resource_id, CanonicalizeResourceId("table:" + resource_id));
-  EXPECT_EQ(resource_id, CanonicalizeResourceId("externalapp:" + resource_id));
-}
-
-}  // namespace util
-}  // namespace drive
-}  // namespace google_apis
diff --git a/chrome/browser/google_apis/drive_notification_observer.h b/chrome/browser/google_apis/drive_notification_observer.h
deleted file mode 100644
index 5aadf14..0000000
--- a/chrome/browser/google_apis/drive_notification_observer.h
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_GOOGLE_APIS_DRIVE_NOTIFICATION_OBSERVER_H_
-#define CHROME_BROWSER_GOOGLE_APIS_DRIVE_NOTIFICATION_OBSERVER_H_
-
-namespace google_apis {
-
-// Interface for classes which need to know when to check Google Drive for
-// updates.
-class DriveNotificationObserver {
- public:
-  // Called when a notification from Google Drive is received.
-  virtual void OnNotificationReceived() = 0;
-
-  // Called when XMPP-based push notification is enabled or disabled.
-  virtual void OnPushNotificationEnabled(bool enabled) {}
-
- protected:
-  virtual ~DriveNotificationObserver() {}
-};
-
-}  // namespace google_apis
-
-#endif  // CHROME_BROWSER_GOOGLE_APIS_DRIVE_NOTIFICATION_OBSERVER_H_
diff --git a/chrome/browser/google_apis/drive_switches.cc b/chrome/browser/google_apis/drive_switches.cc
deleted file mode 100644
index e90dd19..0000000
--- a/chrome/browser/google_apis/drive_switches.cc
+++ /dev/null
@@ -1,14 +0,0 @@
-// Copyright 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/google_apis/drive_switches.h"
-
-namespace google_apis {
-namespace switches {
-
-// Enables Drive v2 API instead of Google Documents List API.
-const char kEnableDriveV2Api[] = "enable-drive-v2-api";
-
-}  // namespace switches
-}  // namespace google_apis
diff --git a/chrome/browser/google_apis/drive_switches.h b/chrome/browser/google_apis/drive_switches.h
deleted file mode 100644
index 67f270d..0000000
--- a/chrome/browser/google_apis/drive_switches.h
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright 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_GOOGLE_APIS_DRIVE_SWITCHES_H_
-#define CHROME_BROWSER_GOOGLE_APIS_DRIVE_SWITCHES_H_
-
-namespace google_apis {
-namespace switches {
-
-extern const char kEnableDriveV2Api[];
-
-}  // namespace switches
-}  // namespace google_apis
-
-#endif  // CHROME_BROWSER_GOOGLE_APIS_DRIVE_SWITCHES_H_
diff --git a/chrome/browser/google_apis/event_logger.cc b/chrome/browser/google_apis/event_logger.cc
deleted file mode 100644
index c853b74..0000000
--- a/chrome/browser/google_apis/event_logger.cc
+++ /dev/null
@@ -1,54 +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/google_apis/event_logger.h"
-
-#include "base/strings/stringprintf.h"
-
-namespace google_apis {
-
-EventLogger::Event::Event(int id, const std::string& what)
-    : id(id),
-      when(base::Time::Now()),
-      what(what) {
-}
-
-EventLogger::EventLogger()
-    : history_size_(kDefaultHistorySize),
-      next_event_id_(0) {
-}
-
-EventLogger::~EventLogger() {
-}
-
-void EventLogger::Log(const char* format, ...) {
-  std::string what;
-
-  va_list args;
-  va_start(args, format);
-  base::StringAppendV(&what, format, args);
-  va_end(args);
-
-  base::AutoLock auto_lock(lock_);
-  history_.push_back(Event(next_event_id_, what));
-  ++next_event_id_;
-  if (history_.size() > history_size_)
-    history_.pop_front();
-}
-
-void EventLogger::SetHistorySize(size_t history_size) {
-  base::AutoLock auto_lock(lock_);
-  history_.clear();
-  history_size_ = history_size;
-}
-
-std::vector<EventLogger::Event> EventLogger::GetHistory() {
-  base::AutoLock auto_lock(lock_);
-  std::vector<Event> output;
-  output.assign(history_.begin(), history_.end());
-  return output;
-}
-
-
-}  // namespace google_apis
diff --git a/chrome/browser/google_apis/event_logger.h b/chrome/browser/google_apis/event_logger.h
deleted file mode 100644
index 3828b17..0000000
--- a/chrome/browser/google_apis/event_logger.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 CHROME_BROWSER_GOOGLE_APIS_EVENT_LOGGER_H_
-#define CHROME_BROWSER_GOOGLE_APIS_EVENT_LOGGER_H_
-
-#include <stdarg.h>   // va_list
-#include <deque>
-#include <string>
-#include <vector>
-
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "base/synchronization/lock.h"
-#include "base/time.h"
-
-namespace google_apis {
-
-// The default history size used by EventLogger.
-const int kDefaultHistorySize = 1000;
-
-// EventLogger is used to collect and expose text messages for diagnosing
-// behaviors of Google APIs stuff. For instance, the collected messages are
-// exposed to chrome:drive-internals.
-class EventLogger {
- public:
-  // Represents a single event log.
-  struct Event {
-    Event(int id, const std::string& what);
-    int id;  // Monotonically increasing ID starting from 0.
-    base::Time when;  // When the event occurred.
-    std::string what;  // What happened.
-  };
-
-  // Creates an event logger that keeps the latest kDefaultHistorySize events.
-  EventLogger();
-  ~EventLogger();
-
-  // Logs a message using printf format.
-  // Can be called from any thread as long as the object is alive.
-  // Note that PRINTF_FORMAT should be (2, 3) instead of (1, 2) as this is a
-  // C++ member function.
-  void Log(const char* format, ...) PRINTF_FORMAT(2, 3);
-
-  // Sets the history size. The existing history is cleared.
-  // Can be called from any thread as long as the object is alive.
-  void SetHistorySize(size_t history_size);
-
-  // Gets the list of latest events (the oldest event comes first).
-  // Can be called from any thread as long as the object is alive.
-  std::vector<Event> GetHistory();
-
- private:
-  std::deque<Event> history_;  // guarded by lock_.
-  size_t history_size_;  // guarded by lock_.
-  int next_event_id_;  // guarded by lock_.
-  base::Lock lock_;
-
-  DISALLOW_COPY_AND_ASSIGN(EventLogger);
-};
-
-}  // namespace google_apis
-
-#endif  // CHROME_BROWSER_GOOGLE_APIS_EVENT_LOGGER_H_
diff --git a/chrome/browser/google_apis/event_logger_unittest.cc b/chrome/browser/google_apis/event_logger_unittest.cc
deleted file mode 100644
index e4c5308..0000000
--- a/chrome/browser/google_apis/event_logger_unittest.cc
+++ /dev/null
@@ -1,43 +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/google_apis/event_logger.h"
-
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace google_apis {
-
-TEST(EventLoggerTest, BasicLogging) {
-  EventLogger logger;
-  logger.SetHistorySize(3);  // At most 3 events are kept.
-  EXPECT_EQ(0U, logger.GetHistory().size());
-
-  logger.Log("first");
-  logger.Log("%dnd", 2);
-  logger.Log("third");
-
-  // Events are recorded in the chronological order with sequential IDs.
-  std::vector<EventLogger::Event> history = logger.GetHistory();
-  ASSERT_EQ(3U, history.size());
-  EXPECT_EQ(0, history[0].id);
-  EXPECT_EQ("first", history[0].what);
-  EXPECT_EQ(1, history[1].id);
-  EXPECT_EQ("2nd", history[1].what);
-  EXPECT_EQ(2, history[2].id);
-  EXPECT_EQ("third", history[2].what);
-
-  logger.Log("fourth");
-  // It does not log events beyond the specified.
-  history = logger.GetHistory();
-  ASSERT_EQ(3U, history.size());
-  // The oldest events is pushed out.
-  EXPECT_EQ(1, history[0].id);
-  EXPECT_EQ("2nd", history[0].what);
-  EXPECT_EQ(2, history[1].id);
-  EXPECT_EQ("third", history[1].what);
-  EXPECT_EQ(3, history[2].id);
-  EXPECT_EQ("fourth", history[2].what);
-}
-
-}   // namespace google_apis
diff --git a/chrome/browser/google_apis/gdata_contacts_requests.cc b/chrome/browser/google_apis/gdata_contacts_requests.cc
index f864bd2..74c547d 100644
--- a/chrome/browser/google_apis/gdata_contacts_requests.cc
+++ b/chrome/browser/google_apis/gdata_contacts_requests.cc
@@ -5,8 +5,8 @@
 #include "chrome/browser/google_apis/gdata_contacts_requests.h"
 
 #include "chrome/browser/google_apis/time_util.h"
-#include "googleurl/src/gurl.h"
 #include "net/base/url_util.h"
+#include "url/gurl.h"
 
 namespace google_apis {
 
@@ -38,9 +38,8 @@
 
 GetContactGroupsRequest::GetContactGroupsRequest(
     RequestSender* runner,
-    net::URLRequestContextGetter* url_request_context_getter,
     const GetDataCallback& callback)
-    : GetDataRequest(runner, url_request_context_getter, callback) {
+    : GetDataRequest(runner, callback) {
 }
 
 GetContactGroupsRequest::~GetContactGroupsRequest() {}
@@ -55,11 +54,10 @@
 
 GetContactsRequest::GetContactsRequest(
     RequestSender* runner,
-    net::URLRequestContextGetter* url_request_context_getter,
     const std::string& group_id,
     const base::Time& min_update_time,
     const GetDataCallback& callback)
-    : GetDataRequest(runner, url_request_context_getter, callback),
+    : GetDataRequest(runner, callback),
       group_id_(group_id),
       min_update_time_(min_update_time) {
 }
@@ -87,10 +85,9 @@
 
 GetContactPhotoRequest::GetContactPhotoRequest(
     RequestSender* runner,
-    net::URLRequestContextGetter* url_request_context_getter,
     const GURL& photo_url,
     const GetContentCallback& callback)
-    : UrlFetchRequestBase(runner, url_request_context_getter),
+    : UrlFetchRequestBase(runner),
       photo_url_(photo_url),
       callback_(callback) {
 }
diff --git a/chrome/browser/google_apis/gdata_contacts_requests.h b/chrome/browser/google_apis/gdata_contacts_requests.h
index 08fcb06..67861e3 100644
--- a/chrome/browser/google_apis/gdata_contacts_requests.h
+++ b/chrome/browser/google_apis/gdata_contacts_requests.h
@@ -9,10 +9,6 @@
 
 #include "chrome/browser/google_apis/base_requests.h"
 
-namespace net {
-class URLRequestContextGetter;
-}  // namespace net
-
 namespace google_apis {
 
 //========================== GetContactGroupsRequest =========================
@@ -20,10 +16,8 @@
 // This class fetches a JSON feed containing a user's contact groups.
 class GetContactGroupsRequest : public GetDataRequest {
  public:
-  GetContactGroupsRequest(
-      RequestSender* runner,
-      net::URLRequestContextGetter* url_request_context_getter,
-      const GetDataCallback& callback);
+  GetContactGroupsRequest(RequestSender* runner,
+                          const GetDataCallback& callback);
   virtual ~GetContactGroupsRequest();
 
   void set_feed_url_for_testing(const GURL& url) {
@@ -46,12 +40,10 @@
 // This class fetches a JSON feed containing a user's contacts.
 class GetContactsRequest : public GetDataRequest {
  public:
-  GetContactsRequest(
-      RequestSender* runner,
-      net::URLRequestContextGetter* url_request_context_getter,
-      const std::string& group_id,
-      const base::Time& min_update_time,
-      const GetDataCallback& callback);
+  GetContactsRequest(RequestSender* runner,
+                     const std::string& group_id,
+                     const base::Time& min_update_time,
+                     const GetDataCallback& callback);
   virtual ~GetContactsRequest();
 
   void set_feed_url_for_testing(const GURL& url) {
@@ -83,11 +75,9 @@
 // This class fetches a contact's photo.
 class GetContactPhotoRequest : public UrlFetchRequestBase {
  public:
-  GetContactPhotoRequest(
-      RequestSender* runner,
-      net::URLRequestContextGetter* url_request_context_getter,
-      const GURL& photo_url,
-      const GetContentCallback& callback);
+  GetContactPhotoRequest(RequestSender* runner,
+                         const GURL& photo_url,
+                         const GetContentCallback& callback);
   virtual ~GetContactPhotoRequest();
 
  protected:
diff --git a/chrome/browser/google_apis/gdata_wapi_parser.h b/chrome/browser/google_apis/gdata_wapi_parser.h
index 1cf4a30..332e8d6 100644
--- a/chrome/browser/google_apis/gdata_wapi_parser.h
+++ b/chrome/browser/google_apis/gdata_wapi_parser.h
@@ -13,9 +13,9 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/scoped_vector.h"
 #include "base/strings/string_piece.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/google_apis/drive_entry_kinds.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 namespace base {
 class FilePath;
diff --git a/chrome/browser/google_apis/gdata_wapi_parser_unittest.cc b/chrome/browser/google_apis/gdata_wapi_parser_unittest.cc
index 217bdde..f4f564d 100644
--- a/chrome/browser/google_apis/gdata_wapi_parser_unittest.cc
+++ b/chrome/browser/google_apis/gdata_wapi_parser_unittest.cc
@@ -9,7 +9,7 @@
 #include "base/files/file_path.h"
 #include "base/json/json_file_value_serializer.h"
 #include "base/logging.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "base/values.h"
 #include "chrome/browser/google_apis/test_util.h"
 #include "chrome/browser/google_apis/time_util.h"
@@ -23,7 +23,7 @@
 TEST(GDataWAPIParserTest, ResourceListJsonParser) {
   std::string error;
   scoped_ptr<base::Value> document =
-      test_util::LoadJSONFile("chromeos/gdata/basic_feed.json");
+      test_util::LoadJSONFile("gdata/basic_feed.json");
   ASSERT_TRUE(document.get());
   ASSERT_EQ(base::Value::TYPE_DICTIONARY, document->GetType());
   scoped_ptr<ResourceList> feed(ResourceList::ExtractAndParse(*document));
@@ -152,7 +152,7 @@
 TEST(GDataWAPIParserTest, ResourceEntryJsonParser) {
   std::string error;
   scoped_ptr<base::Value> document =
-      test_util::LoadJSONFile("chromeos/gdata/file_entry.json");
+      test_util::LoadJSONFile("gdata/file_entry.json");
   ASSERT_TRUE(document.get());
   ASSERT_EQ(base::Value::TYPE_DICTIONARY, document->GetType());
   scoped_ptr<ResourceEntry> entry(ResourceEntry::ExtractAndParse(*document));
@@ -233,7 +233,7 @@
 
 TEST(GDataWAPIParserTest, AccountMetadataParser) {
   scoped_ptr<base::Value> document =
-      test_util::LoadJSONFile("chromeos/gdata/account_metadata.json");
+      test_util::LoadJSONFile("gdata/account_metadata.json");
   ASSERT_TRUE(document.get());
   base::DictionaryValue* document_dict = NULL;
   base::DictionaryValue* entry_value = NULL;
diff --git a/chrome/browser/google_apis/gdata_wapi_requests.cc b/chrome/browser/google_apis/gdata_wapi_requests.cc
index d479f14..187ee2b 100644
--- a/chrome/browser/google_apis/gdata_wapi_requests.cc
+++ b/chrome/browser/google_apis/gdata_wapi_requests.cc
@@ -25,7 +25,6 @@
 
 namespace {
 
-
 const char kUploadContentRange[] = "Content-Range: bytes ";
 
 const char kFeedField[] = "feed";
@@ -36,7 +35,6 @@
 // Parses the JSON value to ResourceList.
 scoped_ptr<ResourceList> ParseResourceListOnBlockingPool(
     scoped_ptr<base::Value> value) {
-  DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
   DCHECK(value);
 
   return ResourceList::ExtractAndParse(*value);
@@ -48,7 +46,6 @@
     const GetResourceListCallback& callback,
     GDataErrorCode error,
     scoped_ptr<ResourceList> resource_list) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   DCHECK(!callback.is_null());
 
   // resource_list being NULL indicates there was a parsing error.
@@ -63,7 +60,6 @@
 void ParseResourceListAndRun(const GetResourceListCallback& callback,
                              GDataErrorCode error,
                              scoped_ptr<base::Value> value) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   DCHECK(!callback.is_null());
 
   if (!value) {
@@ -83,7 +79,6 @@
 void ParseAccounetMetadataAndRun(const GetAccountMetadataCallback& callback,
                                  GDataErrorCode error,
                                  scoped_ptr<base::Value> value) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   DCHECK(!callback.is_null());
 
   if (!value) {
@@ -124,7 +119,6 @@
                          const AuthorizeAppCallback& callback,
                          GDataErrorCode error,
                          scoped_ptr<base::Value> value) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   DCHECK(!callback.is_null());
 
   if (!value) {
@@ -161,15 +155,14 @@
 //============================ GetResourceListRequest ========================
 
 GetResourceListRequest::GetResourceListRequest(
-    RequestSender* runner,
-    net::URLRequestContextGetter* url_request_context_getter,
+    RequestSender* sender,
     const GDataWapiUrlGenerator& url_generator,
     const GURL& override_url,
     int64 start_changestamp,
     const std::string& search_string,
     const std::string& directory_resource_id,
     const GetResourceListCallback& callback)
-    : GetDataRequest(runner, url_request_context_getter,
+    : GetDataRequest(sender,
                      base::Bind(&ParseResourceListAndRun, callback)),
       url_generator_(url_generator),
       override_url_(override_url),
@@ -191,13 +184,12 @@
 //============================ SearchByTitleRequest ==========================
 
 SearchByTitleRequest::SearchByTitleRequest(
-    RequestSender* runner,
-    net::URLRequestContextGetter* url_request_context_getter,
+    RequestSender* sender,
     const GDataWapiUrlGenerator& url_generator,
     const std::string& title,
     const std::string& directory_resource_id,
     const GetResourceListCallback& callback)
-    : GetDataRequest(runner, url_request_context_getter,
+    : GetDataRequest(sender,
                      base::Bind(&ParseResourceListAndRun, callback)),
       url_generator_(url_generator),
       title_(title),
@@ -215,12 +207,11 @@
 //============================ GetResourceEntryRequest =======================
 
 GetResourceEntryRequest::GetResourceEntryRequest(
-    RequestSender* runner,
-    net::URLRequestContextGetter* url_request_context_getter,
+    RequestSender* sender,
     const GDataWapiUrlGenerator& url_generator,
     const std::string& resource_id,
     const GetDataCallback& callback)
-    : GetDataRequest(runner, url_request_context_getter, callback),
+    : GetDataRequest(sender, callback),
       url_generator_(url_generator),
       resource_id_(resource_id) {
   DCHECK(!callback.is_null());
@@ -235,12 +226,11 @@
 //========================= GetAccountMetadataRequest ========================
 
 GetAccountMetadataRequest::GetAccountMetadataRequest(
-    RequestSender* runner,
-    net::URLRequestContextGetter* url_request_context_getter,
+    RequestSender* sender,
     const GDataWapiUrlGenerator& url_generator,
     const GetAccountMetadataCallback& callback,
     bool include_installed_apps)
-    : GetDataRequest(runner, url_request_context_getter,
+    : GetDataRequest(sender,
                      base::Bind(&ParseAccounetMetadataAndRun, callback)),
       url_generator_(url_generator),
       include_installed_apps_(include_installed_apps) {
@@ -256,13 +246,12 @@
 //=========================== DeleteResourceRequest ==========================
 
 DeleteResourceRequest::DeleteResourceRequest(
-    RequestSender* runner,
-    net::URLRequestContextGetter* url_request_context_getter,
+    RequestSender* sender,
     const GDataWapiUrlGenerator& url_generator,
     const EntryActionCallback& callback,
     const std::string& resource_id,
     const std::string& etag)
-    : EntryActionRequest(runner, url_request_context_getter, callback),
+    : EntryActionRequest(sender, callback),
       url_generator_(url_generator),
       resource_id_(resource_id),
       etag_(etag) {
@@ -289,13 +278,12 @@
 //========================== CreateDirectoryRequest ==========================
 
 CreateDirectoryRequest::CreateDirectoryRequest(
-    RequestSender* runner,
-    net::URLRequestContextGetter* url_request_context_getter,
+    RequestSender* sender,
     const GDataWapiUrlGenerator& url_generator,
     const GetDataCallback& callback,
     const std::string& parent_resource_id,
     const std::string& directory_name)
-    : GetDataRequest(runner, url_request_context_getter, callback),
+    : GetDataRequest(sender, callback),
       url_generator_(url_generator),
       parent_resource_id_(parent_resource_id),
       directory_name_(directory_name) {
@@ -341,13 +329,12 @@
 //============================ CopyHostedDocumentRequest =====================
 
 CopyHostedDocumentRequest::CopyHostedDocumentRequest(
-    RequestSender* runner,
-    net::URLRequestContextGetter* url_request_context_getter,
+    RequestSender* sender,
     const GDataWapiUrlGenerator& url_generator,
     const GetDataCallback& callback,
     const std::string& resource_id,
     const std::string& new_name)
-    : GetDataRequest(runner, url_request_context_getter, callback),
+    : GetDataRequest(sender, callback),
       url_generator_(url_generator),
       resource_id_(resource_id),
       new_name_(new_name) {
@@ -387,13 +374,12 @@
 //=========================== RenameResourceRequest ==========================
 
 RenameResourceRequest::RenameResourceRequest(
-    RequestSender* runner,
-    net::URLRequestContextGetter* url_request_context_getter,
+    RequestSender* sender,
     const GDataWapiUrlGenerator& url_generator,
     const EntryActionCallback& callback,
     const std::string& resource_id,
     const std::string& new_name)
-    : EntryActionRequest(runner, url_request_context_getter, callback),
+    : EntryActionRequest(sender, callback),
       url_generator_(url_generator),
       resource_id_(resource_id),
       new_name_(new_name) {
@@ -438,13 +424,12 @@
 //=========================== AuthorizeAppRequest ==========================
 
 AuthorizeAppRequest::AuthorizeAppRequest(
-    RequestSender* runner,
-    net::URLRequestContextGetter* url_request_context_getter,
+    RequestSender* sender,
     const GDataWapiUrlGenerator& url_generator,
     const AuthorizeAppCallback& callback,
     const std::string& resource_id,
     const std::string& app_id)
-    : GetDataRequest(runner, url_request_context_getter,
+    : GetDataRequest(sender,
                      base::Bind(&ParseOpenLinkAndRun, app_id, callback)),
       url_generator_(url_generator),
       resource_id_(resource_id),
@@ -490,13 +475,12 @@
 //======================= AddResourceToDirectoryRequest ======================
 
 AddResourceToDirectoryRequest::AddResourceToDirectoryRequest(
-    RequestSender* runner,
-    net::URLRequestContextGetter* url_request_context_getter,
+    RequestSender* sender,
     const GDataWapiUrlGenerator& url_generator,
     const EntryActionCallback& callback,
     const std::string& parent_resource_id,
     const std::string& resource_id)
-    : EntryActionRequest(runner, url_request_context_getter, callback),
+    : EntryActionRequest(sender, callback),
       url_generator_(url_generator),
       parent_resource_id_(parent_resource_id),
       resource_id_(resource_id) {
@@ -536,13 +520,12 @@
 //==================== RemoveResourceFromDirectoryRequest ====================
 
 RemoveResourceFromDirectoryRequest::RemoveResourceFromDirectoryRequest(
-    RequestSender* runner,
-    net::URLRequestContextGetter* url_request_context_getter,
+    RequestSender* sender,
     const GDataWapiUrlGenerator& url_generator,
     const EntryActionCallback& callback,
     const std::string& parent_resource_id,
     const std::string& document_resource_id)
-    : EntryActionRequest(runner, url_request_context_getter, callback),
+    : EntryActionRequest(sender, callback),
       url_generator_(url_generator),
       resource_id_(document_resource_id),
       parent_resource_id_(parent_resource_id) {
@@ -572,19 +555,15 @@
 //======================= InitiateUploadNewFileRequest =======================
 
 InitiateUploadNewFileRequest::InitiateUploadNewFileRequest(
-    RequestSender* runner,
-    net::URLRequestContextGetter* url_request_context_getter,
+    RequestSender* sender,
     const GDataWapiUrlGenerator& url_generator,
     const InitiateUploadCallback& callback,
-    const base::FilePath& drive_file_path,
     const std::string& content_type,
     int64 content_length,
     const std::string& parent_resource_id,
     const std::string& title)
-    : InitiateUploadRequestBase(runner,
-                                url_request_context_getter,
+    : InitiateUploadRequestBase(sender,
                                 callback,
-                                drive_file_path,
                                 content_type,
                                 content_length),
       url_generator_(url_generator),
@@ -625,19 +604,15 @@
 //===================== InitiateUploadExistingFileRequest ====================
 
 InitiateUploadExistingFileRequest::InitiateUploadExistingFileRequest(
-    RequestSender* runner,
-    net::URLRequestContextGetter* url_request_context_getter,
+    RequestSender* sender,
     const GDataWapiUrlGenerator& url_generator,
     const InitiateUploadCallback& callback,
-    const base::FilePath& drive_file_path,
     const std::string& content_type,
     int64 content_length,
     const std::string& resource_id,
     const std::string& etag)
-    : InitiateUploadRequestBase(runner,
-                                url_request_context_getter,
+    : InitiateUploadRequestBase(sender,
                                 callback,
-                                drive_file_path,
                                 content_type,
                                 content_length),
       url_generator_(url_generator),
@@ -679,20 +654,16 @@
 //============================ ResumeUploadRequest ===========================
 
 ResumeUploadRequest::ResumeUploadRequest(
-    RequestSender* runner,
-    net::URLRequestContextGetter* url_request_context_getter,
+    RequestSender* sender,
     const UploadRangeCallback& callback,
     const ProgressCallback& progress_callback,
-    const base::FilePath& drive_file_path,
     const GURL& upload_location,
     int64 start_position,
     int64 end_position,
     int64 content_length,
     const std::string& content_type,
     const base::FilePath& local_file_path)
-    : ResumeUploadRequestBase(runner,
-                              url_request_context_getter,
-                              drive_file_path,
+    : ResumeUploadRequestBase(sender,
                               upload_location,
                               start_position,
                               end_position,
@@ -720,17 +691,11 @@
 //========================== GetUploadStatusRequest ==========================
 
 GetUploadStatusRequest::GetUploadStatusRequest(
-    RequestSender* runner,
-    net::URLRequestContextGetter* url_request_context_getter,
+    RequestSender* sender,
     const UploadRangeCallback& callback,
-    const base::FilePath& drive_file_path,
     const GURL& upload_url,
     int64 content_length)
-    : GetUploadStatusRequestBase(runner,
-                                 url_request_context_getter,
-                                 drive_file_path,
-                                 upload_url,
-                                 content_length),
+    : GetUploadStatusRequestBase(sender, upload_url, content_length),
       callback_(callback) {
   DCHECK(!callback.is_null());
 }
@@ -742,4 +707,27 @@
   callback_.Run(response, ParseResourceEntry(value.Pass()));
 }
 
+
+//========================== DownloadFileRequest ==========================
+
+DownloadFileRequest::DownloadFileRequest(
+    RequestSender* sender,
+    const GDataWapiUrlGenerator& url_generator,
+    const DownloadActionCallback& download_action_callback,
+    const GetContentCallback& get_content_callback,
+    const ProgressCallback& progress_callback,
+    const std::string& resource_id,
+    const base::FilePath& output_file_path)
+    : DownloadFileRequestBase(
+          sender,
+          download_action_callback,
+          get_content_callback,
+          progress_callback,
+          url_generator.GenerateDownloadFileUrl(resource_id),
+          output_file_path) {
+}
+
+DownloadFileRequest::~DownloadFileRequest() {
+}
+
 }  // namespace google_apis
diff --git a/chrome/browser/google_apis/gdata_wapi_requests.h b/chrome/browser/google_apis/gdata_wapi_requests.h
index 2c9d37c..ba6f774 100644
--- a/chrome/browser/google_apis/gdata_wapi_requests.h
+++ b/chrome/browser/google_apis/gdata_wapi_requests.h
@@ -12,10 +12,6 @@
 #include "chrome/browser/google_apis/drive_common_callbacks.h"
 #include "chrome/browser/google_apis/gdata_wapi_url_generator.h"
 
-namespace net {
-class URLRequestContextGetter;
-}  // namespace net
-
 namespace google_apis {
 
 class AccountMetadata;
@@ -45,15 +41,13 @@
   //
   // callback:
   //   Called once the feed is fetched. Must not be null.
-  GetResourceListRequest(
-      RequestSender* runner,
-      net::URLRequestContextGetter* url_request_context_getter,
-      const GDataWapiUrlGenerator& url_generator,
-      const GURL& override_url,
-      int64 start_changestamp,
-      const std::string& search_string,
-      const std::string& directory_resource_id,
-      const GetResourceListCallback& callback);
+  GetResourceListRequest(RequestSender* sender,
+                         const GDataWapiUrlGenerator& url_generator,
+                         const GURL& override_url,
+                         int64 start_changestamp,
+                         const std::string& search_string,
+                         const std::string& directory_resource_id,
+                         const GetResourceListCallback& callback);
   virtual ~GetResourceListRequest();
 
  protected:
@@ -83,13 +77,11 @@
   //
   // callback:
   //   Called once the feed is fetched. Must not be null.
-  SearchByTitleRequest(
-      RequestSender* runner,
-      net::URLRequestContextGetter* url_request_context_getter,
-      const GDataWapiUrlGenerator& url_generator,
-      const std::string& title,
-      const std::string& directory_resource_id,
-      const GetResourceListCallback& callback);
+  SearchByTitleRequest(RequestSender* sender,
+                       const GDataWapiUrlGenerator& url_generator,
+                       const std::string& title,
+                       const std::string& directory_resource_id,
+                       const GetResourceListCallback& callback);
   virtual ~SearchByTitleRequest();
 
  protected:
@@ -110,12 +102,10 @@
 class GetResourceEntryRequest : public GetDataRequest {
  public:
   // |callback| must not be null.
-  GetResourceEntryRequest(
-      RequestSender* runner,
-      net::URLRequestContextGetter* url_request_context_getter,
-      const GDataWapiUrlGenerator& url_generator,
-      const std::string& resource_id,
-      const GetDataCallback& callback);
+  GetResourceEntryRequest(RequestSender* sender,
+                          const GDataWapiUrlGenerator& url_generator,
+                          const std::string& resource_id,
+                          const GetDataCallback& callback);
   virtual ~GetResourceEntryRequest();
 
  protected:
@@ -143,12 +133,10 @@
   // If |include_installed_apps| is set to true, the result should include
   // the list of installed third party applications.
   // |callback| must not be null.
-  GetAccountMetadataRequest(
-      RequestSender* runner,
-      net::URLRequestContextGetter* url_request_context_getter,
-      const GDataWapiUrlGenerator& url_generator,
-      const GetAccountMetadataCallback& callback,
-      bool include_installed_apps);
+  GetAccountMetadataRequest(RequestSender* sender,
+                            const GDataWapiUrlGenerator& url_generator,
+                            const GetAccountMetadataCallback& callback,
+                            bool include_installed_apps);
   virtual ~GetAccountMetadataRequest();
 
  protected:
@@ -173,13 +161,11 @@
 class DeleteResourceRequest : public EntryActionRequest {
  public:
   // |callback| must not be null.
-  DeleteResourceRequest(
-      RequestSender* runner,
-      net::URLRequestContextGetter* url_request_context_getter,
-      const GDataWapiUrlGenerator& url_generator,
-      const EntryActionCallback& callback,
-      const std::string& resource_id,
-      const std::string& etag);
+  DeleteResourceRequest(RequestSender* sender,
+                        const GDataWapiUrlGenerator& url_generator,
+                        const EntryActionCallback& callback,
+                        const std::string& resource_id,
+                        const std::string& etag);
   virtual ~DeleteResourceRequest();
 
  protected:
@@ -205,13 +191,11 @@
   // |parent_resource_id|. If this parameter is empty, a new directory will
   // be created in the root directory.
   // |callback| must not be null.
-  CreateDirectoryRequest(
-      RequestSender* runner,
-      net::URLRequestContextGetter* url_request_context_getter,
-      const GDataWapiUrlGenerator& url_generator,
-      const GetDataCallback& callback,
-      const std::string& parent_resource_id,
-      const std::string& directory_name);
+  CreateDirectoryRequest(RequestSender* sender,
+                         const GDataWapiUrlGenerator& url_generator,
+                         const GetDataCallback& callback,
+                         const std::string& parent_resource_id,
+                         const std::string& directory_name);
   virtual ~CreateDirectoryRequest();
 
  protected:
@@ -237,13 +221,11 @@
 class CopyHostedDocumentRequest : public GetDataRequest {
  public:
   // |callback| must not be null.
-  CopyHostedDocumentRequest(
-      RequestSender* runner,
-      net::URLRequestContextGetter* url_request_context_getter,
-      const GDataWapiUrlGenerator& url_generator,
-      const GetDataCallback& callback,
-      const std::string& resource_id,
-      const std::string& new_name);
+  CopyHostedDocumentRequest(RequestSender* sender,
+                            const GDataWapiUrlGenerator& url_generator,
+                            const GetDataCallback& callback,
+                            const std::string& resource_id,
+                            const std::string& new_name);
   virtual ~CopyHostedDocumentRequest();
 
  protected:
@@ -267,13 +249,11 @@
 class RenameResourceRequest : public EntryActionRequest {
  public:
   // |callback| must not be null.
-  RenameResourceRequest(
-      RequestSender* runner,
-      net::URLRequestContextGetter* url_request_context_getter,
-      const GDataWapiUrlGenerator& url_generator,
-      const EntryActionCallback& callback,
-      const std::string& resource_id,
-      const std::string& new_name);
+  RenameResourceRequest(RequestSender* sender,
+                        const GDataWapiUrlGenerator& url_generator,
+                        const EntryActionCallback& callback,
+                        const std::string& resource_id,
+                        const std::string& new_name);
   virtual ~RenameResourceRequest();
 
  protected:
@@ -299,13 +279,11 @@
 class AuthorizeAppRequest : public GetDataRequest {
  public:
   // |callback| must not be null.
-  AuthorizeAppRequest(
-      RequestSender* runner,
-      net::URLRequestContextGetter* url_request_context_getter,
-      const GDataWapiUrlGenerator& url_generator,
-      const AuthorizeAppCallback& callback,
-      const std::string& resource_id,
-      const std::string& app_id);
+  AuthorizeAppRequest(RequestSender* sender,
+                      const GDataWapiUrlGenerator& url_generator,
+                      const AuthorizeAppCallback& callback,
+                      const std::string& resource_id,
+                      const std::string& app_id);
   virtual ~AuthorizeAppRequest();
 
  protected:
@@ -331,13 +309,11 @@
 class AddResourceToDirectoryRequest : public EntryActionRequest {
  public:
   // |callback| must not be null.
-  AddResourceToDirectoryRequest(
-      RequestSender* runner,
-      net::URLRequestContextGetter* url_request_context_getter,
-      const GDataWapiUrlGenerator& url_generator,
-      const EntryActionCallback& callback,
-      const std::string& parent_resource_id,
-      const std::string& resource_id);
+  AddResourceToDirectoryRequest(RequestSender* sender,
+                                const GDataWapiUrlGenerator& url_generator,
+                                const EntryActionCallback& callback,
+                                const std::string& parent_resource_id,
+                                const std::string& resource_id);
   virtual ~AddResourceToDirectoryRequest();
 
  protected:
@@ -362,13 +338,11 @@
 class RemoveResourceFromDirectoryRequest : public EntryActionRequest {
  public:
   // |callback| must not be null.
-  RemoveResourceFromDirectoryRequest(
-      RequestSender* runner,
-      net::URLRequestContextGetter* url_request_context_getter,
-      const GDataWapiUrlGenerator& url_generator,
-      const EntryActionCallback& callback,
-      const std::string& parent_resource_id,
-      const std::string& resource_id);
+  RemoveResourceFromDirectoryRequest(RequestSender* sender,
+                                     const GDataWapiUrlGenerator& url_generator,
+                                     const EntryActionCallback& callback,
+                                     const std::string& parent_resource_id,
+                                     const std::string& resource_id);
   virtual ~RemoveResourceFromDirectoryRequest();
 
  protected:
@@ -395,16 +369,13 @@
   //   (resumable-create-media URL)
   // See also the comments of InitiateUploadRequestBase for more details
   // about the other parameters.
-  InitiateUploadNewFileRequest(
-      RequestSender* runner,
-      net::URLRequestContextGetter* url_request_context_getter,
-      const GDataWapiUrlGenerator& url_generator,
-      const InitiateUploadCallback& callback,
-      const base::FilePath& drive_file_path,
-      const std::string& content_type,
-      int64 content_length,
-      const std::string& parent_resource_id,
-      const std::string& title);
+  InitiateUploadNewFileRequest(RequestSender* sender,
+                               const GDataWapiUrlGenerator& url_generator,
+                               const InitiateUploadCallback& callback,
+                               const std::string& content_type,
+                               int64 content_length,
+                               const std::string& parent_resource_id,
+                               const std::string& title);
   virtual ~InitiateUploadNewFileRequest();
 
  protected:
@@ -434,16 +405,13 @@
   // |etag| should be set if it is available to detect the upload confliction.
   // See also the comments of InitiateUploadRequestBase for more details
   // about the other parameters.
-  InitiateUploadExistingFileRequest(
-      RequestSender* runner,
-      net::URLRequestContextGetter* url_request_context_getter,
-      const GDataWapiUrlGenerator& url_generator,
-      const InitiateUploadCallback& callback,
-      const base::FilePath& drive_file_path,
-      const std::string& content_type,
-      int64 content_length,
-      const std::string& resource_id,
-      const std::string& etag);
+  InitiateUploadExistingFileRequest(RequestSender* sender,
+                                    const GDataWapiUrlGenerator& url_generator,
+                                    const InitiateUploadCallback& callback,
+                                    const std::string& content_type,
+                                    int64 content_length,
+                                    const std::string& resource_id,
+                                    const std::string& etag);
   virtual ~InitiateUploadExistingFileRequest();
 
  protected:
@@ -467,20 +435,17 @@
 // Performs the request for resuming the upload of a file.
 class ResumeUploadRequest : public ResumeUploadRequestBase {
  public:
-  // See also ResumeUploadRequestBase's comment for parameters meaining.
+  // See also ResumeUploadRequestBase's comment for parameters meaning.
   // |callback| must not be null.
-  ResumeUploadRequest(
-      RequestSender* runner,
-      net::URLRequestContextGetter* url_request_context_getter,
-      const UploadRangeCallback& callback,
-      const ProgressCallback& progress_callback,
-      const base::FilePath& drive_file_path,
-      const GURL& upload_location,
-      int64 start_position,
-      int64 end_position,
-      int64 content_length,
-      const std::string& content_type,
-      const base::FilePath& local_file_path);
+  ResumeUploadRequest(RequestSender* sender,
+                      const UploadRangeCallback& callback,
+                      const ProgressCallback& progress_callback,
+                      const GURL& upload_location,
+                      int64 start_position,
+                      int64 end_position,
+                      int64 content_length,
+                      const std::string& content_type,
+                      const base::FilePath& local_file_path);
   virtual ~ResumeUploadRequest();
 
  protected:
@@ -506,13 +471,10 @@
  public:
   // See also GetUploadStatusRequestBase's comment for parameters meaning.
   // |callback| must not be null.
-  GetUploadStatusRequest(
-      RequestSender* runner,
-      net::URLRequestContextGetter* url_request_context_getter,
-      const UploadRangeCallback& callback,
-      const base::FilePath& drive_file_path,
-      const GURL& upload_url,
-      int64 content_length);
+  GetUploadStatusRequest(RequestSender* sender,
+                         const UploadRangeCallback& callback,
+                         const GURL& upload_url,
+                         int64 content_length);
   virtual ~GetUploadStatusRequest();
 
  protected:
@@ -527,6 +489,25 @@
   DISALLOW_COPY_AND_ASSIGN(GetUploadStatusRequest);
 };
 
+
+//========================== DownloadFileRequest ==========================
+
+// This class performs the request for downloading of a specified file.
+class DownloadFileRequest : public DownloadFileRequestBase {
+ public:
+  // See also DownloadFileRequestBase's comment for parameters meaning.
+  DownloadFileRequest(RequestSender* sender,
+                      const GDataWapiUrlGenerator& url_generator,
+                      const DownloadActionCallback& download_action_callback,
+                      const GetContentCallback& get_content_callback,
+                      const ProgressCallback& progress_callback,
+                      const std::string& resource_id,
+                      const base::FilePath& output_file_path);
+  virtual ~DownloadFileRequest();
+
+  DISALLOW_COPY_AND_ASSIGN(DownloadFileRequest);
+};
+
 }  // namespace google_apis
 
 #endif  // CHROME_BROWSER_GOOGLE_APIS_GDATA_WAPI_REQUESTS_H_
diff --git a/chrome/browser/google_apis/gdata_wapi_requests_unittest.cc b/chrome/browser/google_apis/gdata_wapi_requests_unittest.cc
index 4406039..39302ac 100644
--- a/chrome/browser/google_apis/gdata_wapi_requests_unittest.cc
+++ b/chrome/browser/google_apis/gdata_wapi_requests_unittest.cc
@@ -6,11 +6,12 @@
 #include <map>
 
 #include "base/bind.h"
+#include "base/file_util.h"
 #include "base/files/file_path.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/json/json_reader.h"
 #include "base/json/json_writer.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/run_loop.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
 #include "base/values.h"
@@ -19,7 +20,6 @@
 #include "chrome/browser/google_apis/gdata_wapi_requests.h"
 #include "chrome/browser/google_apis/gdata_wapi_url_generator.h"
 #include "chrome/browser/google_apis/request_sender.h"
-#include "chrome/browser/google_apis/task_util.h"
 #include "chrome/browser/google_apis/test_util.h"
 #include "chrome/test/base/testing_profile.h"
 #include "content/public/browser/browser_thread.h"
@@ -38,6 +38,7 @@
 const char kTestGDataAuthToken[] = "testtoken";
 const char kTestUserAgent[] = "test-user-agent";
 const char kTestETag[] = "test_etag";
+const char kTestDownloadPathPrefix[] = "/download/";
 
 class GDataWapiRequestsTest : public testing::Test {
  public:
@@ -80,19 +81,18 @@
     test_server_.RegisterRequestHandler(
         base::Bind(&GDataWapiRequestsTest::HandleUploadRequest,
                    base::Unretained(this)));
+    test_server_.RegisterRequestHandler(
+        base::Bind(&GDataWapiRequestsTest::HandleDownloadRequest,
+                   base::Unretained(this)));
 
+    GURL test_base_url = test_util::GetBaseUrlForTesting(test_server_.port());
     url_generator_.reset(new GDataWapiUrlGenerator(
-        test_util::GetBaseUrlForTesting(test_server_.port())));
+        test_base_url, test_base_url.Resolve(kTestDownloadPathPrefix)));
 
     received_bytes_ = 0;
     content_length_ = 0;
   }
 
-  virtual void TearDown() OVERRIDE {
-    EXPECT_TRUE(test_server_.ShutdownAndWaitUntilComplete());
-    request_context_getter_ = NULL;
-  }
-
  protected:
   // Handles a request for fetching a resource feed.
   scoped_ptr<net::test_server::HttpResponse> HandleResourceFeedRequest(
@@ -108,7 +108,7 @@
       // copied document but for now, just return "file_entry.json"
       scoped_ptr<net::test_server::BasicHttpResponse> result(
           test_util::CreateHttpResponseFromFile(
-              test_util::GetTestFilePath("chromeos/gdata/file_entry.json")));
+              test_util::GetTestFilePath("gdata/file_entry.json")));
       return result.PassAs<net::test_server::HttpResponse>();
     }
 
@@ -122,7 +122,7 @@
       // Process the default feed.
       scoped_ptr<net::test_server::BasicHttpResponse> result(
           test_util::CreateHttpResponseFromFile(
-              test_util::GetTestFilePath("chromeos/gdata/root_feed.json")));
+              test_util::GetTestFilePath("gdata/root_feed.json")));
       return result.PassAs<net::test_server::HttpResponse>();
     } else {
       // Process a feed for a single resource ID.
@@ -131,7 +131,7 @@
       if (resource_id == "file:2_file_resource_id") {
         scoped_ptr<net::test_server::BasicHttpResponse> result(
             test_util::CreateHttpResponseFromFile(
-                test_util::GetTestFilePath("chromeos/gdata/file_entry.json")));
+                test_util::GetTestFilePath("gdata/file_entry.json")));
         return result.PassAs<net::test_server::HttpResponse>();
       } else if (resource_id == "folder:root/contents" &&
                  request.method == net::test_server::METHOD_POST) {
@@ -141,7 +141,7 @@
         scoped_ptr<net::test_server::BasicHttpResponse> result(
             test_util::CreateHttpResponseFromFile(
                 test_util::GetTestFilePath(
-                    "chromeos/gdata/directory_entry.json")));
+                    "gdata/directory_entry.json")));
         return result.PassAs<net::test_server::HttpResponse>();
       } else if (resource_id ==
                  "folder:root/contents/file:2_file_resource_id" &&
@@ -152,7 +152,7 @@
         // matter.
         scoped_ptr<net::test_server::BasicHttpResponse> result(
             test_util::CreateHttpResponseFromFile(
-                test_util::GetTestFilePath("chromeos/gdata/testfile.txt")));
+                test_util::GetTestFilePath("gdata/testfile.txt")));
         return result.PassAs<net::test_server::HttpResponse>();
       } else if (resource_id == "invalid_resource_id") {
         // Check if this is an authorization request for an app.
@@ -161,7 +161,7 @@
             request.content.find("<docs:authorizedApp>") != std::string::npos) {
           scoped_ptr<net::test_server::BasicHttpResponse> result(
               test_util::CreateHttpResponseFromFile(
-                  test_util::GetTestFilePath("chromeos/gdata/testfile.txt")));
+                  test_util::GetTestFilePath("gdata/testfile.txt")));
           return result.PassAs<net::test_server::HttpResponse>();
         }
       }
@@ -182,7 +182,7 @@
     scoped_ptr<net::test_server::BasicHttpResponse> result(
         test_util::CreateHttpResponseFromFile(
             test_util::GetTestFilePath(
-                "chromeos/gdata/account_metadata.json")));
+                "gdata/account_metadata.json")));
     if (absolute_url.query().find("include-installed-apps=true") ==
         string::npos) {
       // Exclude the list of installed apps.
@@ -223,7 +223,7 @@
       if (found != request.headers.end() &&
           found->second != "*" &&
           found->second != kTestETag) {
-        http_response->set_code(net::test_server::PRECONDITION);
+        http_response->set_code(net::HTTP_PRECONDITION_FAILED);
         return http_response.PassAs<net::test_server::HttpResponse>();
       }
 
@@ -236,7 +236,7 @@
       }
       received_bytes_ = 0;
 
-      http_response->set_code(net::test_server::SUCCESS);
+      http_response->set_code(net::HTTP_OK);
       GURL upload_url;
       // POST is used for a new file, and PUT is used for an existing file.
       if (request.method == net::test_server::METHOD_POST) {
@@ -268,11 +268,11 @@
     // file, but for now, just return file_entry.json.
     scoped_ptr<net::test_server::BasicHttpResponse> response =
         test_util::CreateHttpResponseFromFile(
-            test_util::GetTestFilePath("chromeos/gdata/file_entry.json"));
+            test_util::GetTestFilePath("gdata/file_entry.json"));
     // response.code() is set to SUCCESS. Change it to CREATED if it's a new
     // file.
     if (absolute_url.path() == "/upload_new_file")
-      response->set_code(net::test_server::CREATED);
+      response->set_code(net::HTTP_CREATED);
 
     // Check if the Content-Range header is present. This must be present if
     // the request body is not empty.
@@ -307,11 +307,33 @@
 
     // Change the code to RESUME_INCOMPLETE if upload is not complete.
     if (received_bytes_ < content_length_)
-      response->set_code(net::test_server::RESUME_INCOMPLETE);
+      response->set_code(static_cast<net::HttpStatusCode>(308));
 
     return response.PassAs<net::test_server::HttpResponse>();
   }
 
+  // Handles a request for downloading a file.
+  scoped_ptr<net::test_server::HttpResponse> HandleDownloadRequest(
+      const net::test_server::HttpRequest& request) {
+    http_request_ = request;
+
+    const GURL absolute_url = test_server_.GetURL(request.relative_url);
+    std::string id;
+    if (!test_util::RemovePrefix(absolute_url.path(),
+                                 kTestDownloadPathPrefix,
+                                 &id)) {
+      return scoped_ptr<net::test_server::HttpResponse>();
+    }
+
+    // For testing, returns a text with |id| repeated 3 times.
+    scoped_ptr<net::test_server::BasicHttpResponse> response(
+        new net::test_server::BasicHttpResponse);
+    response->set_code(net::HTTP_OK);
+    response->set_content(id + id + id);
+    response->set_content_type("text/plain");
+    return response.PassAs<net::test_server::HttpResponse>();
+  }
+
   content::TestBrowserThreadBundle thread_bundle_;
   net::test_server::EmbeddedTestServer test_server_;
   scoped_ptr<TestingProfile> profile_;
@@ -340,19 +362,21 @@
   GDataErrorCode result_code = GDATA_OTHER_ERROR;
   scoped_ptr<ResourceList> result_data;
 
-  GetResourceListRequest* request = new GetResourceListRequest(
-      request_sender_.get(),
-      request_context_getter_.get(),
-      *url_generator_,
-      GURL(),         // Pass an empty URL to use the default feed
-      0,              // start changestamp
-      std::string(),  // search string
-      std::string(),  // directory resource ID
-      CreateComposedCallback(
-          base::Bind(&test_util::RunAndQuit),
-          test_util::CreateCopyResultCallback(&result_code, &result_data)));
-  request_sender_->StartRequestWithRetry(request);
-  base::MessageLoop::current()->Run();
+  {
+    base::RunLoop run_loop;
+    GetResourceListRequest* request = new GetResourceListRequest(
+        request_sender_.get(),
+        *url_generator_,
+        GURL(),         // Pass an empty URL to use the default feed
+        0,              // start changestamp
+        std::string(),  // search string
+        std::string(),  // directory resource ID
+        test_util::CreateQuitCallback(
+            &run_loop,
+            test_util::CreateCopyResultCallback(&result_code, &result_data)));
+    request_sender_->StartRequestWithRetry(request);
+    run_loop.Run();
+  }
 
   EXPECT_EQ(HTTP_SUCCESS, result_code);
   EXPECT_EQ(net::test_server::METHOD_GET, http_request_.method);
@@ -363,7 +387,7 @@
   // Sanity check of the result.
   scoped_ptr<ResourceList> expected(
       ResourceList::ExtractAndParse(
-          *test_util::LoadJSONFile("chromeos/gdata/root_feed.json")));
+          *test_util::LoadJSONFile("gdata/root_feed.json")));
   ASSERT_TRUE(result_data);
   EXPECT_EQ(expected->title(), result_data->title());
 }
@@ -372,29 +396,31 @@
   GDataErrorCode result_code = GDATA_OTHER_ERROR;
   scoped_ptr<ResourceList> result_data;
 
-  GetResourceListRequest* request = new GetResourceListRequest(
-      request_sender_.get(),
-      request_context_getter_.get(),
-      *url_generator_,
-      test_server_.GetURL("/files/chromeos/gdata/root_feed.json"),
-      0,              // start changestamp
-      std::string(),  // search string
-      std::string(),  // directory resource ID
-      CreateComposedCallback(
-          base::Bind(&test_util::RunAndQuit),
-          test_util::CreateCopyResultCallback(&result_code, &result_data)));
-  request_sender_->StartRequestWithRetry(request);
-  base::MessageLoop::current()->Run();
+  {
+    base::RunLoop run_loop;
+    GetResourceListRequest* request = new GetResourceListRequest(
+        request_sender_.get(),
+        *url_generator_,
+        test_server_.GetURL("/files/gdata/root_feed.json"),
+        0,              // start changestamp
+        std::string(),  // search string
+        std::string(),  // directory resource ID
+        test_util::CreateQuitCallback(
+            &run_loop,
+            test_util::CreateCopyResultCallback(&result_code, &result_data)));
+    request_sender_->StartRequestWithRetry(request);
+    run_loop.Run();
+  }
 
   EXPECT_EQ(HTTP_SUCCESS, result_code);
   EXPECT_EQ(net::test_server::METHOD_GET, http_request_.method);
-  EXPECT_EQ("/files/chromeos/gdata/root_feed.json?v=3&alt=json&showroot=true&"
+  EXPECT_EQ("/files/gdata/root_feed.json?v=3&alt=json&showroot=true&"
             "showfolders=true&include-shared=true&max-results=500",
             http_request_.relative_url);
 
   scoped_ptr<ResourceList> expected(
       ResourceList::ExtractAndParse(
-          *test_util::LoadJSONFile("chromeos/gdata/root_feed.json")));
+          *test_util::LoadJSONFile("gdata/root_feed.json")));
   ASSERT_TRUE(result_data);
   EXPECT_EQ(expected->title(), result_data->title());
 }
@@ -405,23 +431,25 @@
   GDataErrorCode result_code = GDATA_OTHER_ERROR;
   scoped_ptr<ResourceList> result_data;
 
-  GetResourceListRequest* request = new GetResourceListRequest(
-      request_sender_.get(),
-      request_context_getter_.get(),
-      *url_generator_,
-      test_server_.GetURL("/files/chromeos/gdata/testfile.txt"),
-      0,              // start changestamp
-      std::string(),  // search string
-      std::string(),  // directory resource ID
-      CreateComposedCallback(
-          base::Bind(&test_util::RunAndQuit),
-          test_util::CreateCopyResultCallback(&result_code, &result_data)));
-  request_sender_->StartRequestWithRetry(request);
-  base::MessageLoop::current()->Run();
+  {
+    base::RunLoop run_loop;
+    GetResourceListRequest* request = new GetResourceListRequest(
+        request_sender_.get(),
+        *url_generator_,
+        test_server_.GetURL("/files/gdata/testfile.txt"),
+        0,              // start changestamp
+        std::string(),  // search string
+        std::string(),  // directory resource ID
+        test_util::CreateQuitCallback(
+            &run_loop,
+            test_util::CreateCopyResultCallback(&result_code, &result_data)));
+    request_sender_->StartRequestWithRetry(request);
+    run_loop.Run();
+  }
 
   EXPECT_EQ(GDATA_PARSE_ERROR, result_code);
   EXPECT_EQ(net::test_server::METHOD_GET, http_request_.method);
-  EXPECT_EQ("/files/chromeos/gdata/testfile.txt?v=3&alt=json&showroot=true&"
+  EXPECT_EQ("/files/gdata/testfile.txt?v=3&alt=json&showroot=true&"
             "showfolders=true&include-shared=true&max-results=500",
             http_request_.relative_url);
   EXPECT_FALSE(result_data);
@@ -431,17 +459,19 @@
   GDataErrorCode result_code = GDATA_OTHER_ERROR;
   scoped_ptr<ResourceList> result_data;
 
-  SearchByTitleRequest* request = new SearchByTitleRequest(
-      request_sender_.get(),
-      request_context_getter_.get(),
-      *url_generator_,
-      "search-title",
-      std::string(),  // directory resource id
-      CreateComposedCallback(
-          base::Bind(&test_util::RunAndQuit),
-          test_util::CreateCopyResultCallback(&result_code, &result_data)));
-  request_sender_->StartRequestWithRetry(request);
-  base::MessageLoop::current()->Run();
+  {
+    base::RunLoop run_loop;
+    SearchByTitleRequest* request = new SearchByTitleRequest(
+        request_sender_.get(),
+        *url_generator_,
+        "search-title",
+        std::string(),  // directory resource id
+        test_util::CreateQuitCallback(
+            &run_loop,
+            test_util::CreateCopyResultCallback(&result_code, &result_data)));
+    request_sender_->StartRequestWithRetry(request);
+    run_loop.Run();
+  }
 
   EXPECT_EQ(HTTP_SUCCESS, result_code);
   EXPECT_EQ(net::test_server::METHOD_GET, http_request_.method);
@@ -456,16 +486,18 @@
   GDataErrorCode result_code = GDATA_OTHER_ERROR;
   scoped_ptr<base::Value> result_data;
 
-  GetResourceEntryRequest* request = new GetResourceEntryRequest(
-      request_sender_.get(),
-      request_context_getter_.get(),
-      *url_generator_,
-      "file:2_file_resource_id",  // resource ID
-      CreateComposedCallback(
-          base::Bind(&test_util::RunAndQuit),
-          test_util::CreateCopyResultCallback(&result_code, &result_data)));
-  request_sender_->StartRequestWithRetry(request);
-  base::MessageLoop::current()->Run();
+  {
+    base::RunLoop run_loop;
+    GetResourceEntryRequest* request = new GetResourceEntryRequest(
+        request_sender_.get(),
+        *url_generator_,
+        "file:2_file_resource_id",  // resource ID
+        test_util::CreateQuitCallback(
+            &run_loop,
+            test_util::CreateCopyResultCallback(&result_code, &result_data)));
+    request_sender_->StartRequestWithRetry(request);
+    run_loop.Run();
+  }
 
   EXPECT_EQ(HTTP_SUCCESS, result_code);
   EXPECT_EQ(net::test_server::METHOD_GET, http_request_.method);
@@ -473,7 +505,7 @@
             "?v=3&alt=json&showroot=true",
             http_request_.relative_url);
   EXPECT_TRUE(test_util::VerifyJsonData(
-      test_util::GetTestFilePath("chromeos/gdata/file_entry.json"),
+      test_util::GetTestFilePath("gdata/file_entry.json"),
       result_data.get()));
 }
 
@@ -481,16 +513,18 @@
   GDataErrorCode result_code = GDATA_OTHER_ERROR;
   scoped_ptr<base::Value> result_data;
 
-  GetResourceEntryRequest* request = new GetResourceEntryRequest(
-      request_sender_.get(),
-      request_context_getter_.get(),
-      *url_generator_,
-      "<invalid>",  // resource ID
-      CreateComposedCallback(
-          base::Bind(&test_util::RunAndQuit),
-          test_util::CreateCopyResultCallback(&result_code, &result_data)));
-  request_sender_->StartRequestWithRetry(request);
-  base::MessageLoop::current()->Run();
+  {
+    base::RunLoop run_loop;
+    GetResourceEntryRequest* request = new GetResourceEntryRequest(
+        request_sender_.get(),
+        *url_generator_,
+        "<invalid>",  // resource ID
+        test_util::CreateQuitCallback(
+            &run_loop,
+            test_util::CreateCopyResultCallback(&result_code, &result_data)));
+    request_sender_->StartRequestWithRetry(request);
+    run_loop.Run();
+  }
 
   EXPECT_EQ(HTTP_NOT_FOUND, result_code);
   EXPECT_EQ(net::test_server::METHOD_GET, http_request_.method);
@@ -504,16 +538,18 @@
   GDataErrorCode result_code = GDATA_OTHER_ERROR;
   scoped_ptr<AccountMetadata> result_data;
 
-  GetAccountMetadataRequest* request = new GetAccountMetadataRequest(
-      request_sender_.get(),
-      request_context_getter_.get(),
-      *url_generator_,
-      CreateComposedCallback(
-          base::Bind(&test_util::RunAndQuit),
-          test_util::CreateCopyResultCallback(&result_code, &result_data)),
-      true);  // Include installed apps.
-  request_sender_->StartRequestWithRetry(request);
-  base::MessageLoop::current()->Run();
+  {
+    base::RunLoop run_loop;
+    GetAccountMetadataRequest* request = new GetAccountMetadataRequest(
+        request_sender_.get(),
+        *url_generator_,
+        test_util::CreateQuitCallback(
+            &run_loop,
+            test_util::CreateCopyResultCallback(&result_code, &result_data)),
+        true);  // Include installed apps.
+    request_sender_->StartRequestWithRetry(request);
+    run_loop.Run();
+  }
 
   EXPECT_EQ(HTTP_SUCCESS, result_code);
   EXPECT_EQ(net::test_server::METHOD_GET, http_request_.method);
@@ -523,7 +559,7 @@
 
   scoped_ptr<AccountMetadata> expected(
       AccountMetadata::CreateFrom(
-          *test_util::LoadJSONFile("chromeos/gdata/account_metadata.json")));
+          *test_util::LoadJSONFile("gdata/account_metadata.json")));
 
   ASSERT_TRUE(result_data.get());
   EXPECT_EQ(expected->largest_changestamp(),
@@ -543,16 +579,18 @@
   GDataErrorCode result_code = GDATA_OTHER_ERROR;
   scoped_ptr<AccountMetadata> result_data;
 
-  GetAccountMetadataRequest* request = new GetAccountMetadataRequest(
-      request_sender_.get(),
-      request_context_getter_.get(),
-      *url_generator_,
-      CreateComposedCallback(
-          base::Bind(&test_util::RunAndQuit),
-          test_util::CreateCopyResultCallback(&result_code, &result_data)),
-      false);  // Exclude installed apps.
-  request_sender_->StartRequestWithRetry(request);
-  base::MessageLoop::current()->Run();
+  {
+    base::RunLoop run_loop;
+    GetAccountMetadataRequest* request = new GetAccountMetadataRequest(
+        request_sender_.get(),
+        *url_generator_,
+        test_util::CreateQuitCallback(
+            &run_loop,
+            test_util::CreateCopyResultCallback(&result_code, &result_data)),
+        false);  // Exclude installed apps.
+    request_sender_->StartRequestWithRetry(request);
+    run_loop.Run();
+  }
 
   EXPECT_EQ(HTTP_SUCCESS, result_code);
   EXPECT_EQ(net::test_server::METHOD_GET, http_request_.method);
@@ -561,7 +599,7 @@
 
   scoped_ptr<AccountMetadata> expected(
       AccountMetadata::CreateFrom(
-          *test_util::LoadJSONFile("chromeos/gdata/account_metadata.json")));
+          *test_util::LoadJSONFile("gdata/account_metadata.json")));
 
   ASSERT_TRUE(result_data.get());
   EXPECT_EQ(expected->largest_changestamp(),
@@ -578,17 +616,20 @@
 TEST_F(GDataWapiRequestsTest, DeleteResourceRequest) {
   GDataErrorCode result_code = GDATA_OTHER_ERROR;
 
-  DeleteResourceRequest* request = new DeleteResourceRequest(
-      request_sender_.get(),
-      request_context_getter_.get(),
-      *url_generator_,
-      CreateComposedCallback(base::Bind(&test_util::RunAndQuit),
-                             test_util::CreateCopyResultCallback(&result_code)),
-      "file:2_file_resource_id",
-      std::string());
+  {
+    base::RunLoop run_loop;
+    DeleteResourceRequest* request = new DeleteResourceRequest(
+        request_sender_.get(),
+        *url_generator_,
+        test_util::CreateQuitCallback(
+            &run_loop,
+            test_util::CreateCopyResultCallback(&result_code)),
+        "file:2_file_resource_id",
+        std::string());
 
-  request_sender_->StartRequestWithRetry(request);
-  base::MessageLoop::current()->Run();
+    request_sender_->StartRequestWithRetry(request);
+    run_loop.Run();
+  }
 
   EXPECT_EQ(HTTP_SUCCESS, result_code);
   EXPECT_EQ(net::test_server::METHOD_DELETE, http_request_.method);
@@ -602,18 +643,20 @@
 TEST_F(GDataWapiRequestsTest, DeleteResourceRequestWithETag) {
   GDataErrorCode result_code = GDATA_OTHER_ERROR;
 
-  DeleteResourceRequest* request = new DeleteResourceRequest(
-      request_sender_.get(),
-      request_context_getter_.get(),
-      *url_generator_,
-      CreateComposedCallback(
-          base::Bind(&test_util::RunAndQuit),
-          test_util::CreateCopyResultCallback(&result_code)),
-      "file:2_file_resource_id",
-      "etag");
+  {
+    base::RunLoop run_loop;
+    DeleteResourceRequest* request = new DeleteResourceRequest(
+        request_sender_.get(),
+        *url_generator_,
+        test_util::CreateQuitCallback(
+            &run_loop,
+            test_util::CreateCopyResultCallback(&result_code)),
+        "file:2_file_resource_id",
+        "etag");
 
-  request_sender_->StartRequestWithRetry(request);
-  base::MessageLoop::current()->Run();
+    request_sender_->StartRequestWithRetry(request);
+    run_loop.Run();
+  }
 
   EXPECT_EQ(HTTP_SUCCESS, result_code);
   EXPECT_EQ(net::test_server::METHOD_DELETE, http_request_.method);
@@ -629,18 +672,20 @@
   scoped_ptr<base::Value> result_data;
 
   // Create "new directory" in the root directory.
-  CreateDirectoryRequest* request = new CreateDirectoryRequest(
-      request_sender_.get(),
-      request_context_getter_.get(),
-      *url_generator_,
-      CreateComposedCallback(
-          base::Bind(&test_util::RunAndQuit),
-          test_util::CreateCopyResultCallback(&result_code, &result_data)),
-      "folder:root",
-      "new directory");
+  {
+    base::RunLoop run_loop;
+    CreateDirectoryRequest* request = new CreateDirectoryRequest(
+        request_sender_.get(),
+        *url_generator_,
+        test_util::CreateQuitCallback(
+            &run_loop,
+            test_util::CreateCopyResultCallback(&result_code, &result_data)),
+        "folder:root",
+        "new directory");
 
-  request_sender_->StartRequestWithRetry(request);
-  base::MessageLoop::current()->Run();
+    request_sender_->StartRequestWithRetry(request);
+    run_loop.Run();
+  }
 
   EXPECT_EQ(HTTP_SUCCESS, result_code);
   EXPECT_EQ(net::test_server::METHOD_POST, http_request_.method);
@@ -664,18 +709,20 @@
   scoped_ptr<base::Value> result_data;
 
   // Copy a document with a new name "New Document".
-  CopyHostedDocumentRequest* request = new CopyHostedDocumentRequest(
-      request_sender_.get(),
-      request_context_getter_.get(),
-      *url_generator_,
-      CreateComposedCallback(
-          base::Bind(&test_util::RunAndQuit),
-          test_util::CreateCopyResultCallback(&result_code, &result_data)),
-      "document:5_document_resource_id",  // source resource ID
-      "New Document");
+  {
+    base::RunLoop run_loop;
+    CopyHostedDocumentRequest* request = new CopyHostedDocumentRequest(
+        request_sender_.get(),
+        *url_generator_,
+        test_util::CreateQuitCallback(
+            &run_loop,
+            test_util::CreateCopyResultCallback(&result_code, &result_data)),
+        "document:5_document_resource_id",  // source resource ID
+        "New Document");
 
-  request_sender_->StartRequestWithRetry(request);
-  base::MessageLoop::current()->Run();
+    request_sender_->StartRequestWithRetry(request);
+    run_loop.Run();
+  }
 
   EXPECT_EQ(HTTP_SUCCESS, result_code);
   EXPECT_EQ(net::test_server::METHOD_POST, http_request_.method);
@@ -696,18 +743,20 @@
   GDataErrorCode result_code = GDATA_OTHER_ERROR;
 
   // Rename a file with a new name "New File".
-  RenameResourceRequest* request = new RenameResourceRequest(
-      request_sender_.get(),
-      request_context_getter_.get(),
-      *url_generator_,
-      CreateComposedCallback(
-          base::Bind(&test_util::RunAndQuit),
-          test_util::CreateCopyResultCallback(&result_code)),
-      "file:2_file_resource_id",
-      "New File");
+  {
+    base::RunLoop run_loop;
+    RenameResourceRequest* request = new RenameResourceRequest(
+        request_sender_.get(),
+        *url_generator_,
+        test_util::CreateQuitCallback(
+            &run_loop,
+            test_util::CreateCopyResultCallback(&result_code)),
+        "file:2_file_resource_id",
+        "New File");
 
-  request_sender_->StartRequestWithRetry(request);
-  base::MessageLoop::current()->Run();
+    request_sender_->StartRequestWithRetry(request);
+    run_loop.Run();
+  }
 
   EXPECT_EQ(HTTP_SUCCESS, result_code);
   EXPECT_EQ(net::test_server::METHOD_PUT, http_request_.method);
@@ -731,18 +780,20 @@
   GURL result_data;
 
   // Authorize an app with APP_ID to access to a document.
-  AuthorizeAppRequest* request = new AuthorizeAppRequest(
-      request_sender_.get(),
-      request_context_getter_.get(),
-      *url_generator_,
-      CreateComposedCallback(
-          base::Bind(&test_util::RunAndQuit),
-          test_util::CreateCopyResultCallback(&result_code, &result_data)),
-      "file:2_file_resource_id",
-      "the_app_id");
+  {
+    base::RunLoop run_loop;
+    AuthorizeAppRequest* request = new AuthorizeAppRequest(
+        request_sender_.get(),
+        *url_generator_,
+        test_util::CreateQuitCallback(
+            &run_loop,
+            test_util::CreateCopyResultCallback(&result_code, &result_data)),
+        "file:2_file_resource_id",
+        "the_app_id");
 
-  request_sender_->StartRequestWithRetry(request);
-  base::MessageLoop::current()->Run();
+    request_sender_->StartRequestWithRetry(request);
+    run_loop.Run();
+  }
 
   EXPECT_EQ(HTTP_SUCCESS, result_code);
   EXPECT_EQ(GURL("https://entry1_open_with_link/"), result_data);
@@ -768,18 +819,20 @@
   GURL result_data;
 
   // Authorize an app with APP_ID to access to a document.
-  AuthorizeAppRequest* request = new AuthorizeAppRequest(
-      request_sender_.get(),
-      request_context_getter_.get(),
-      *url_generator_,
-      CreateComposedCallback(
-          base::Bind(&test_util::RunAndQuit),
-          test_util::CreateCopyResultCallback(&result_code, &result_data)),
-      "file:2_file_resource_id",
-      "unauthorized_app_id");
+  {
+    base::RunLoop run_loop;
+    AuthorizeAppRequest* request = new AuthorizeAppRequest(
+        request_sender_.get(),
+        *url_generator_,
+        test_util::CreateQuitCallback(
+            &run_loop,
+            test_util::CreateCopyResultCallback(&result_code, &result_data)),
+        "file:2_file_resource_id",
+        "unauthorized_app_id");
 
-  request_sender_->StartRequestWithRetry(request);
-  base::MessageLoop::current()->Run();
+    request_sender_->StartRequestWithRetry(request);
+    run_loop.Run();
+  }
 
   EXPECT_EQ(GDATA_OTHER_ERROR, result_code);
   EXPECT_EQ(net::test_server::METHOD_PUT, http_request_.method);
@@ -803,18 +856,20 @@
   GURL result_data;
 
   // Authorize an app with APP_ID to access to a document but an invalid feed.
-  AuthorizeAppRequest* request = new AuthorizeAppRequest(
-      request_sender_.get(),
-      request_context_getter_.get(),
-      *url_generator_,
-      CreateComposedCallback(
-          base::Bind(&test_util::RunAndQuit),
-          test_util::CreateCopyResultCallback(&result_code, &result_data)),
-      "invalid_resource_id",
-      "APP_ID");
+  {
+    base::RunLoop run_loop;
+    AuthorizeAppRequest* request = new AuthorizeAppRequest(
+        request_sender_.get(),
+        *url_generator_,
+        test_util::CreateQuitCallback(
+            &run_loop,
+            test_util::CreateCopyResultCallback(&result_code, &result_data)),
+        "invalid_resource_id",
+        "APP_ID");
 
-  request_sender_->StartRequestWithRetry(request);
-  base::MessageLoop::current()->Run();
+    request_sender_->StartRequestWithRetry(request);
+    run_loop.Run();
+  }
 
   EXPECT_EQ(GDATA_PARSE_ERROR, result_code);
   EXPECT_EQ(net::test_server::METHOD_PUT, http_request_.method);
@@ -837,19 +892,21 @@
   GDataErrorCode result_code = GDATA_OTHER_ERROR;
 
   // Add a file to the root directory.
-  AddResourceToDirectoryRequest* request =
-      new AddResourceToDirectoryRequest(
-          request_sender_.get(),
-          request_context_getter_.get(),
-          *url_generator_,
-          CreateComposedCallback(
-              base::Bind(&test_util::RunAndQuit),
-              test_util::CreateCopyResultCallback(&result_code)),
-          "folder:root",
-          "file:2_file_resource_id");
+  {
+    base::RunLoop run_loop;
+    AddResourceToDirectoryRequest* request =
+        new AddResourceToDirectoryRequest(
+            request_sender_.get(),
+            *url_generator_,
+            test_util::CreateQuitCallback(
+                &run_loop,
+                test_util::CreateCopyResultCallback(&result_code)),
+            "folder:root",
+            "file:2_file_resource_id");
 
-  request_sender_->StartRequestWithRetry(request);
-  base::MessageLoop::current()->Run();
+    request_sender_->StartRequestWithRetry(request);
+    run_loop.Run();
+  }
 
   EXPECT_EQ(HTTP_SUCCESS, result_code);
   EXPECT_EQ(net::test_server::METHOD_POST, http_request_.method);
@@ -872,19 +929,21 @@
   GDataErrorCode result_code = GDATA_OTHER_ERROR;
 
   // Remove a file from the root directory.
-  RemoveResourceFromDirectoryRequest* request =
-      new RemoveResourceFromDirectoryRequest(
-          request_sender_.get(),
-          request_context_getter_.get(),
-          *url_generator_,
-          CreateComposedCallback(
-              base::Bind(&test_util::RunAndQuit),
-              test_util::CreateCopyResultCallback(&result_code)),
-          "folder:root",
-          "file:2_file_resource_id");
+  {
+    base::RunLoop run_loop;
+    RemoveResourceFromDirectoryRequest* request =
+        new RemoveResourceFromDirectoryRequest(
+            request_sender_.get(),
+            *url_generator_,
+            test_util::CreateQuitCallback(
+                &run_loop,
+                test_util::CreateCopyResultCallback(&result_code)),
+            "folder:root",
+            "file:2_file_resource_id");
 
-  request_sender_->StartRequestWithRetry(request);
-  base::MessageLoop::current()->Run();
+    request_sender_->StartRequestWithRetry(request);
+    run_loop.Run();
+  }
 
   EXPECT_EQ(HTTP_SUCCESS, result_code);
   // DELETE method should be used, without the body content.
@@ -908,22 +967,22 @@
   GURL upload_url;
 
   // 1) Get the upload URL for uploading a new file.
-  InitiateUploadNewFileRequest* initiate_request =
-      new InitiateUploadNewFileRequest(
-          request_sender_.get(),
-          request_context_getter_.get(),
-          *url_generator_,
-          CreateComposedCallback(
-              base::Bind(&test_util::RunAndQuit),
-              test_util::CreateCopyResultCallback(&result_code, &upload_url)),
-          base::FilePath::FromUTF8Unsafe("drive/newfile.txt"),
-          "text/plain",
-          kUploadContent.size(),
-          "folder:id",
-          "New file");
-
-  request_sender_->StartRequestWithRetry(initiate_request);
-  base::MessageLoop::current()->Run();
+  {
+    base::RunLoop run_loop;
+    InitiateUploadNewFileRequest* initiate_request =
+        new InitiateUploadNewFileRequest(
+            request_sender_.get(),
+            *url_generator_,
+            test_util::CreateQuitCallback(
+                &run_loop,
+                test_util::CreateCopyResultCallback(&result_code, &upload_url)),
+            "text/plain",
+            kUploadContent.size(),
+            "folder:id",
+            "New file");
+    request_sender_->StartRequestWithRetry(initiate_request);
+    run_loop.Run();
+  }
 
   EXPECT_EQ(HTTP_SUCCESS, result_code);
   EXPECT_EQ(test_server_.GetURL("/upload_new_file"), upload_url);
@@ -950,23 +1009,24 @@
   UploadRangeResponse response;
   scoped_ptr<ResourceEntry> new_entry;
 
-  ResumeUploadRequest* resume_request = new ResumeUploadRequest(
-      request_sender_.get(),
-      request_context_getter_.get(),
-      CreateComposedCallback(
-          base::Bind(&test_util::RunAndQuit),
-          test_util::CreateCopyResultCallback(&response, &new_entry)),
-      ProgressCallback(),
-      base::FilePath::FromUTF8Unsafe("drive/newfile.txt"),
-      upload_url,
-      0,  // start_position
-      kUploadContent.size(),  // end_position (exclusive)
-      kUploadContent.size(),  // content_length,
-      "text/plain",  // content_type
-      kTestFilePath);
+  {
+    base::RunLoop run_loop;
+    ResumeUploadRequest* resume_request = new ResumeUploadRequest(
+        request_sender_.get(),
+        test_util::CreateQuitCallback(
+            &run_loop,
+            test_util::CreateCopyResultCallback(&response, &new_entry)),
+        ProgressCallback(),
+        upload_url,
+        0,  // start_position
+        kUploadContent.size(),  // end_position (exclusive)
+        kUploadContent.size(),  // content_length,
+        "text/plain",  // content_type
+        kTestFilePath);
 
-  request_sender_->StartRequestWithRetry(resume_request);
-  base::MessageLoop::current()->Run();
+    request_sender_->StartRequestWithRetry(resume_request);
+    run_loop.Run();
+  }
 
   // METHOD_PUT should be used to upload data.
   EXPECT_EQ(net::test_server::METHOD_PUT, http_request_.method);
@@ -988,9 +1048,6 @@
   EXPECT_EQ(-1, response.end_position_received);
 }
 
-// TODO(kinaba): crbug.com/{241241,164098} Re-enable the test.
-#define NO_GET_UPLOAD_STATUS_TEST
-
 // This test exercises InitiateUploadNewFileRequest and ResumeUploadRequest
 // for a scenario of uploading a new *large* file, which requires multiple
 // requests of ResumeUploadRequest. GetUploadRequest is also tested in this
@@ -1010,22 +1067,22 @@
   GURL upload_url;
 
   // 1) Get the upload URL for uploading a new file.
-  InitiateUploadNewFileRequest* initiate_request =
-      new InitiateUploadNewFileRequest(
-          request_sender_.get(),
-          request_context_getter_.get(),
-          *url_generator_,
-          CreateComposedCallback(
-              base::Bind(&test_util::RunAndQuit),
-              test_util::CreateCopyResultCallback(&result_code, &upload_url)),
-          base::FilePath::FromUTF8Unsafe("drive/newfile.txt"),
-          "text/plain",
-          kUploadContent.size(),
-          "folder:id",
-          "New file");
-
-  request_sender_->StartRequestWithRetry(initiate_request);
-  base::MessageLoop::current()->Run();
+  {
+    base::RunLoop run_loop;
+    InitiateUploadNewFileRequest* initiate_request =
+        new InitiateUploadNewFileRequest(
+            request_sender_.get(),
+            *url_generator_,
+            test_util::CreateQuitCallback(
+                &run_loop,
+                test_util::CreateCopyResultCallback(&result_code, &upload_url)),
+            "text/plain",
+            kUploadContent.size(),
+            "folder:id",
+            "New file");
+    request_sender_->StartRequestWithRetry(initiate_request);
+    run_loop.Run();
+  }
 
   EXPECT_EQ(HTTP_SUCCESS, result_code);
   EXPECT_EQ(test_server_.GetURL("/upload_new_file"), upload_url);
@@ -1048,7 +1105,6 @@
             "</entry>\n",
             http_request_.content);
 
-#if !defined(NO_GET_UPLOAD_STATUS_TEST)
   // 2) Before sending any data, check the current status.
   // This is an edge case test for GetUploadStatusRequest
   // (UploadRangeRequestBase).
@@ -1057,18 +1113,19 @@
     scoped_ptr<ResourceEntry> new_entry;
 
     // Check the response by GetUploadStatusRequest.
-    GetUploadStatusRequest* get_upload_status_request =
-        new GetUploadStatusRequest(
-            request_sender_.get(),
-            request_context_getter_.get(),
-            CreateComposedCallback(
-                base::Bind(&test_util::RunAndQuit),
-                test_util::CreateCopyResultCallback(&response, &new_entry)),
-            base::FilePath::FromUTF8Unsafe("drive/newfile.txt"),
-            upload_url,
-            kUploadContent.size());
-    request_sender_->StartRequestWithRetry(get_upload_status_request);
-    base::MessageLoop::current()->Run();
+    {
+      base::RunLoop run_loop;
+      GetUploadStatusRequest* get_upload_status_request =
+          new GetUploadStatusRequest(
+              request_sender_.get(),
+              test_util::CreateQuitCallback(
+                  &run_loop,
+                  test_util::CreateCopyResultCallback(&response, &new_entry)),
+              upload_url,
+              kUploadContent.size());
+      request_sender_->StartRequestWithRetry(get_upload_status_request);
+      run_loop.Run();
+    }
 
     // METHOD_PUT should be used to upload data.
     EXPECT_EQ(net::test_server::METHOD_PUT, http_request_.method);
@@ -1085,7 +1142,6 @@
     EXPECT_EQ(0, response.start_position_received);
     EXPECT_EQ(0, response.end_position_received);
   }
-#endif  // NO_GET_UPLOAD_STATUS_TEST
 
   // 3) Upload the content to the upload URL with multiple requests.
   size_t num_bytes_consumed = 0;
@@ -1104,23 +1160,23 @@
     UploadRangeResponse response;
     scoped_ptr<ResourceEntry> new_entry;
 
-    ResumeUploadRequest* resume_request = new ResumeUploadRequest(
-        request_sender_.get(),
-        request_context_getter_.get(),
-        CreateComposedCallback(
-            base::Bind(&test_util::RunAndQuit),
-            test_util::CreateCopyResultCallback(&response, &new_entry)),
-        ProgressCallback(),
-        base::FilePath::FromUTF8Unsafe("drive/newfile.txt"),
-        upload_url,
-        start_position,
-        end_position,
-        kUploadContent.size(),  // content_length,
-        "text/plain",  // content_type
-        kTestFilePath);
-
-    request_sender_->StartRequestWithRetry(resume_request);
-    base::MessageLoop::current()->Run();
+    {
+      base::RunLoop run_loop;
+      ResumeUploadRequest* resume_request = new ResumeUploadRequest(
+          request_sender_.get(),
+          test_util::CreateQuitCallback(
+              &run_loop,
+              test_util::CreateCopyResultCallback(&response, &new_entry)),
+          ProgressCallback(),
+          upload_url,
+          start_position,
+          end_position,
+          kUploadContent.size(),  // content_length,
+          "text/plain",  // content_type
+          kTestFilePath);
+      request_sender_->StartRequestWithRetry(resume_request);
+      run_loop.Run();
+    }
 
     // METHOD_PUT should be used to upload data.
     EXPECT_EQ(net::test_server::METHOD_PUT, http_request_.method);
@@ -1152,20 +1208,20 @@
     EXPECT_EQ(static_cast<int64>(end_position),
               response.end_position_received);
 
-#if !defined(NO_GET_UPLOAD_STATUS_TEST)
     // Check the response by GetUploadStatusRequest.
-    GetUploadStatusRequest* get_upload_status_request =
-        new GetUploadStatusRequest(
-            request_sender_.get(),
-            request_context_getter_.get(),
-            CreateComposedCallback(
-                base::Bind(&test_util::RunAndQuit),
-                test_util::CreateCopyResultCallback(&response, &new_entry)),
-            base::FilePath::FromUTF8Unsafe("drive/newfile.txt"),
-            upload_url,
-            kUploadContent.size());
-    request_sender_->StartRequestWithRetry(get_upload_request);
-    base::MessageLoop::current()->Run();
+    {
+      base::RunLoop run_loop;
+      GetUploadStatusRequest* get_upload_status_request =
+          new GetUploadStatusRequest(
+              request_sender_.get(),
+              test_util::CreateQuitCallback(
+                  &run_loop,
+                  test_util::CreateCopyResultCallback(&response, &new_entry)),
+              upload_url,
+              kUploadContent.size());
+      request_sender_->StartRequestWithRetry(get_upload_status_request);
+      run_loop.Run();
+    }
 
     // METHOD_PUT should be used to upload data.
     EXPECT_EQ(net::test_server::METHOD_PUT, http_request_.method);
@@ -1182,7 +1238,6 @@
     EXPECT_EQ(0, response.start_position_received);
     EXPECT_EQ(static_cast<int64>(end_position),
               response.end_position_received);
-#endif  // NO_GET_UPLOAD_STATUS_TEST
   }
 
   EXPECT_EQ(kUploadContent.size(), num_bytes_consumed);
@@ -1203,22 +1258,22 @@
   GURL upload_url;
 
   // 1) Get the upload URL for uploading a new file.
-  InitiateUploadNewFileRequest* initiate_request =
-      new InitiateUploadNewFileRequest(
-          request_sender_.get(),
-          request_context_getter_.get(),
-          *url_generator_,
-          CreateComposedCallback(
-              base::Bind(&test_util::RunAndQuit),
-              test_util::CreateCopyResultCallback(&result_code, &upload_url)),
-          base::FilePath::FromUTF8Unsafe("drive/newfile.txt"),
-          "text/plain",
-          kUploadContent.size(),
-          "folder:id",
-          "New file");
-
-  request_sender_->StartRequestWithRetry(initiate_request);
-  base::MessageLoop::current()->Run();
+  {
+    base::RunLoop run_loop;
+    InitiateUploadNewFileRequest* initiate_request =
+        new InitiateUploadNewFileRequest(
+            request_sender_.get(),
+            *url_generator_,
+            test_util::CreateQuitCallback(
+                &run_loop,
+                test_util::CreateCopyResultCallback(&result_code, &upload_url)),
+            "text/plain",
+            kUploadContent.size(),
+            "folder:id",
+            "New file");
+    request_sender_->StartRequestWithRetry(initiate_request);
+    run_loop.Run();
+  }
 
   EXPECT_EQ(HTTP_SUCCESS, result_code);
   EXPECT_EQ(test_server_.GetURL("/upload_new_file"), upload_url);
@@ -1245,23 +1300,23 @@
   UploadRangeResponse response;
   scoped_ptr<ResourceEntry> new_entry;
 
-  ResumeUploadRequest* resume_request = new ResumeUploadRequest(
-      request_sender_.get(),
-      request_context_getter_.get(),
-      CreateComposedCallback(
-          base::Bind(&test_util::RunAndQuit),
-          test_util::CreateCopyResultCallback(&response, &new_entry)),
-      ProgressCallback(),
-      base::FilePath::FromUTF8Unsafe("drive/newfile.txt"),
-      upload_url,
-      0,  // start_position
-      kUploadContent.size(),  // end_position (exclusive)
-      kUploadContent.size(),  // content_length,
-      "text/plain",  // content_type
-      kTestFilePath);
-
-  request_sender_->StartRequestWithRetry(resume_request);
-  base::MessageLoop::current()->Run();
+  {
+    base::RunLoop run_loop;
+    ResumeUploadRequest* resume_request = new ResumeUploadRequest(
+        request_sender_.get(),
+        test_util::CreateQuitCallback(
+            &run_loop,
+            test_util::CreateCopyResultCallback(&response, &new_entry)),
+        ProgressCallback(),
+        upload_url,
+        0,  // start_position
+        kUploadContent.size(),  // end_position (exclusive)
+        kUploadContent.size(),  // content_length,
+        "text/plain",  // content_type
+        kTestFilePath);
+    request_sender_->StartRequestWithRetry(resume_request);
+    run_loop.Run();
+  }
 
   // METHOD_PUT should be used to upload data.
   EXPECT_EQ(net::test_server::METHOD_PUT, http_request_.method);
@@ -1293,22 +1348,22 @@
   GURL upload_url;
 
   // 1) Get the upload URL for uploading an existing file.
-  InitiateUploadExistingFileRequest* initiate_request =
-      new InitiateUploadExistingFileRequest(
-          request_sender_.get(),
-          request_context_getter_.get(),
-          *url_generator_,
-          CreateComposedCallback(
-              base::Bind(&test_util::RunAndQuit),
-              test_util::CreateCopyResultCallback(&result_code, &upload_url)),
-          base::FilePath::FromUTF8Unsafe("drive/existingfile.txt"),
-          "text/plain",
-          kUploadContent.size(),
-          "file:foo",
-          std::string() /* etag */);
-
-  request_sender_->StartRequestWithRetry(initiate_request);
-  base::MessageLoop::current()->Run();
+  {
+    base::RunLoop run_loop;
+    InitiateUploadExistingFileRequest* initiate_request =
+        new InitiateUploadExistingFileRequest(
+            request_sender_.get(),
+            *url_generator_,
+            test_util::CreateQuitCallback(
+                &run_loop,
+                test_util::CreateCopyResultCallback(&result_code, &upload_url)),
+            "text/plain",
+            kUploadContent.size(),
+            "file:foo",
+            std::string() /* etag */);
+    request_sender_->StartRequestWithRetry(initiate_request);
+    run_loop.Run();
+  }
 
   EXPECT_EQ(HTTP_SUCCESS, result_code);
   EXPECT_EQ(test_server_.GetURL("/upload_existing_file"), upload_url);
@@ -1334,23 +1389,24 @@
   UploadRangeResponse response;
   scoped_ptr<ResourceEntry> new_entry;
 
-  ResumeUploadRequest* resume_request = new ResumeUploadRequest(
-      request_sender_.get(),
-      request_context_getter_.get(),
-      CreateComposedCallback(
-          base::Bind(&test_util::RunAndQuit),
-          test_util::CreateCopyResultCallback(&response, &new_entry)),
-      ProgressCallback(),
-      base::FilePath::FromUTF8Unsafe("drive/existingfile.txt"),
-      upload_url,
-      0,  // start_position
-      kUploadContent.size(),  // end_position (exclusive)
-      kUploadContent.size(),  // content_length,
-      "text/plain",  // content_type
-      kTestFilePath);
+  {
+    base::RunLoop run_loop;
+    ResumeUploadRequest* resume_request = new ResumeUploadRequest(
+        request_sender_.get(),
+        test_util::CreateQuitCallback(
+            &run_loop,
+            test_util::CreateCopyResultCallback(&response, &new_entry)),
+        ProgressCallback(),
+        upload_url,
+        0,  // start_position
+        kUploadContent.size(),  // end_position (exclusive)
+        kUploadContent.size(),  // content_length,
+        "text/plain",  // content_type
+        kTestFilePath);
 
-  request_sender_->StartRequestWithRetry(resume_request);
-  base::MessageLoop::current()->Run();
+    request_sender_->StartRequestWithRetry(resume_request);
+    run_loop.Run();
+  }
 
   // METHOD_PUT should be used to upload data.
   EXPECT_EQ(net::test_server::METHOD_PUT, http_request_.method);
@@ -1384,22 +1440,22 @@
   GURL upload_url;
 
   // 1) Get the upload URL for uploading an existing file.
-  InitiateUploadExistingFileRequest* initiate_request =
-      new InitiateUploadExistingFileRequest(
-          request_sender_.get(),
-          request_context_getter_.get(),
-          *url_generator_,
-          CreateComposedCallback(
-              base::Bind(&test_util::RunAndQuit),
-              test_util::CreateCopyResultCallback(&result_code, &upload_url)),
-          base::FilePath::FromUTF8Unsafe("drive/existingfile.txt"),
-          "text/plain",
-          kUploadContent.size(),
-          "file:foo",
-          kTestETag);
-
-  request_sender_->StartRequestWithRetry(initiate_request);
-  base::MessageLoop::current()->Run();
+  {
+    base::RunLoop run_loop;
+    InitiateUploadExistingFileRequest* initiate_request =
+        new InitiateUploadExistingFileRequest(
+            request_sender_.get(),
+            *url_generator_,
+            test_util::CreateQuitCallback(
+                &run_loop,
+                test_util::CreateCopyResultCallback(&result_code, &upload_url)),
+            "text/plain",
+            kUploadContent.size(),
+            "file:foo",
+            kTestETag);
+    request_sender_->StartRequestWithRetry(initiate_request);
+    run_loop.Run();
+  }
 
   EXPECT_EQ(HTTP_SUCCESS, result_code);
   EXPECT_EQ(test_server_.GetURL("/upload_existing_file"), upload_url);
@@ -1425,23 +1481,23 @@
   UploadRangeResponse response;
   scoped_ptr<ResourceEntry> new_entry;
 
-  ResumeUploadRequest* resume_request = new ResumeUploadRequest(
-      request_sender_.get(),
-      request_context_getter_.get(),
-      CreateComposedCallback(
-          base::Bind(&test_util::RunAndQuit),
-          test_util::CreateCopyResultCallback(&response, &new_entry)),
-      ProgressCallback(),
-      base::FilePath::FromUTF8Unsafe("drive/existingfile.txt"),
-      upload_url,
-      0,  // start_position
-      kUploadContent.size(),  // end_position (exclusive)
-      kUploadContent.size(),  // content_length,
-      "text/plain",  // content_type
-      kTestFilePath);
-
-  request_sender_->StartRequestWithRetry(resume_request);
-  base::MessageLoop::current()->Run();
+  {
+    base::RunLoop run_loop;
+    ResumeUploadRequest* resume_request = new ResumeUploadRequest(
+        request_sender_.get(),
+        test_util::CreateQuitCallback(
+            &run_loop,
+            test_util::CreateCopyResultCallback(&response, &new_entry)),
+        ProgressCallback(),
+        upload_url,
+        0,  // start_position
+        kUploadContent.size(),  // end_position (exclusive)
+        kUploadContent.size(),  // content_length,
+        "text/plain",  // content_type
+        kTestFilePath);
+    request_sender_->StartRequestWithRetry(resume_request);
+    run_loop.Run();
+  }
 
   // METHOD_PUT should be used to upload data.
   EXPECT_EQ(net::test_server::METHOD_PUT, http_request_.method);
@@ -1471,22 +1527,22 @@
   GDataErrorCode result_code = GDATA_OTHER_ERROR;
   GURL upload_url;
 
-  InitiateUploadExistingFileRequest* initiate_request =
-      new InitiateUploadExistingFileRequest(
-          request_sender_.get(),
-          request_context_getter_.get(),
-          *url_generator_,
-          CreateComposedCallback(
-              base::Bind(&test_util::RunAndQuit),
-              test_util::CreateCopyResultCallback(&result_code, &upload_url)),
-          base::FilePath::FromUTF8Unsafe("drive/existingfile.txt"),
-          "text/plain",
-          kUploadContent.size(),
-          "file:foo",
-          kWrongETag);
-
-  request_sender_->StartRequestWithRetry(initiate_request);
-  base::MessageLoop::current()->Run();
+  {
+    base::RunLoop run_loop;
+    InitiateUploadExistingFileRequest* initiate_request =
+        new InitiateUploadExistingFileRequest(
+            request_sender_.get(),
+            *url_generator_,
+            test_util::CreateQuitCallback(
+                &run_loop,
+                test_util::CreateCopyResultCallback(&result_code, &upload_url)),
+            "text/plain",
+            kUploadContent.size(),
+            "file:foo",
+            kWrongETag);
+    request_sender_->StartRequestWithRetry(initiate_request);
+    run_loop.Run();
+  }
 
   EXPECT_EQ(HTTP_PRECONDITION, result_code);
   // For updating an existing file, METHOD_PUT should be used.
@@ -1508,4 +1564,41 @@
   EXPECT_EQ(kWrongETag, http_request_.headers["If-Match"]);
 }
 
+TEST_F(GDataWapiRequestsTest, DownloadFileRequest) {
+  const base::FilePath kDownloadedFilePath =
+      temp_dir_.path().AppendASCII("cache_file");
+  const std::string kTestIdWithTypeLabel("file:dummyId");
+  const std::string kTestId("dummyId");
+
+  GDataErrorCode result_code = GDATA_OTHER_ERROR;
+  base::FilePath temp_file;
+  {
+    base::RunLoop run_loop;
+    DownloadFileRequest* request = new DownloadFileRequest(
+        request_sender_.get(),
+        *url_generator_,
+        test_util::CreateQuitCallback(
+            &run_loop,
+            test_util::CreateCopyResultCallback(&result_code, &temp_file)),
+        GetContentCallback(),
+        ProgressCallback(),
+        kTestIdWithTypeLabel,
+        kDownloadedFilePath);
+    request_sender_->StartRequestWithRetry(request);
+    run_loop.Run();
+  }
+
+  std::string contents;
+  file_util::ReadFileToString(temp_file, &contents);
+  base::Delete(temp_file, false);
+
+  EXPECT_EQ(HTTP_SUCCESS, result_code);
+  EXPECT_EQ(net::test_server::METHOD_GET, http_request_.method);
+  EXPECT_EQ(kTestDownloadPathPrefix + kTestId, http_request_.relative_url);
+  EXPECT_EQ(kDownloadedFilePath, temp_file);
+
+  const std::string expected_contents = kTestId + kTestId + kTestId;
+  EXPECT_EQ(expected_contents, contents);
+}
+
 }  // namespace google_apis
diff --git a/chrome/browser/google_apis/gdata_wapi_url_generator.cc b/chrome/browser/google_apis/gdata_wapi_url_generator.cc
index 85e4517..f4956a8 100644
--- a/chrome/browser/google_apis/gdata_wapi_url_generator.cc
+++ b/chrome/browser/google_apis/gdata_wapi_url_generator.cc
@@ -7,9 +7,9 @@
 #include "base/logging.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
-#include "googleurl/src/gurl.h"
 #include "net/base/escape.h"
 #include "net/base/url_util.h"
+#include "url/gurl.h"
 
 namespace google_apis {
 namespace {
@@ -57,6 +57,9 @@
 const char GDataWapiUrlGenerator::kBaseUrlForProduction[] =
     "https://docs.google.com/";
 
+const char GDataWapiUrlGenerator::kBaseDownloadUrlForProduction[] =
+    "https://www.googledrive.com/host/";
+
 // static
 GURL GDataWapiUrlGenerator::AddStandardUrlParams(const GURL& url) {
   GURL result = net::AppendOrReplaceQueryParameter(url, "v", "3");
@@ -83,8 +86,10 @@
   return result;
 }
 
-GDataWapiUrlGenerator::GDataWapiUrlGenerator(const GURL& base_url)
-    : base_url_(GURL(base_url)) {
+GDataWapiUrlGenerator::GDataWapiUrlGenerator(const GURL& base_url,
+                                             const GURL& base_download_url)
+    : base_url_(base_url),
+      base_download_url_(base_download_url) {
 }
 
 GDataWapiUrlGenerator::~GDataWapiUrlGenerator() {
@@ -215,4 +220,13 @@
   return result;
 }
 
+GURL GDataWapiUrlGenerator::GenerateDownloadFileUrl(
+    const std::string& resource_id) const {
+  // Strip the file type prefix before the colon character.
+  size_t colon = resource_id.find(':');
+  return base_download_url_.Resolve(net::EscapePath(
+      colon == std::string::npos ? resource_id
+                                 : resource_id.substr(colon + 1)));
+}
+
 }  // namespace google_apis
diff --git a/chrome/browser/google_apis/gdata_wapi_url_generator.h b/chrome/browser/google_apis/gdata_wapi_url_generator.h
index e071f8c..31d17f9 100644
--- a/chrome/browser/google_apis/gdata_wapi_url_generator.h
+++ b/chrome/browser/google_apis/gdata_wapi_url_generator.h
@@ -9,7 +9,7 @@
 
 #include <string>
 
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 namespace google_apis {
 
@@ -17,12 +17,16 @@
 // for production, and the local server for testing.
 class GDataWapiUrlGenerator {
  public:
-  explicit GDataWapiUrlGenerator(const GURL& base_url);
+  // The
+  GDataWapiUrlGenerator(const GURL& base_url, const GURL& base_download_url);
   ~GDataWapiUrlGenerator();
 
   // The base URL for communicating with the WAPI server for production.
   static const char kBaseUrlForProduction[];
 
+  // The base URL for the file download server for production.
+  static const char kBaseDownloadUrlForProduction[];
+
   // Adds additional parameters for API version, output content type and to
   // show folders in the feed are added to document feed URLs.
   static GURL AddStandardUrlParams(const GURL& url);
@@ -119,8 +123,12 @@
   // list of installed third party applications.
   GURL GenerateAccountMetadataUrl(bool include_installed_apps) const;
 
+  // Generates a URL for downloading a file.
+  GURL GenerateDownloadFileUrl(const std::string& resource_id) const;
+
  private:
   const GURL base_url_;
+  const GURL base_download_url_;
 };
 
 }  // namespace google_apis
diff --git a/chrome/browser/google_apis/gdata_wapi_url_generator_unittest.cc b/chrome/browser/google_apis/gdata_wapi_url_generator_unittest.cc
index 94a518a..ef8f1da 100644
--- a/chrome/browser/google_apis/gdata_wapi_url_generator_unittest.cc
+++ b/chrome/browser/google_apis/gdata_wapi_url_generator_unittest.cc
@@ -4,15 +4,17 @@
 
 #include "chrome/browser/google_apis/gdata_wapi_url_generator.h"
 
-#include "googleurl/src/gurl.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
 
 namespace google_apis {
 
 class GDataWapiUrlGeneratorTest : public testing::Test {
  public:
   GDataWapiUrlGeneratorTest()
-      : url_generator_(GURL(GDataWapiUrlGenerator::kBaseUrlForProduction)) {
+      : url_generator_(
+          GURL(GDataWapiUrlGenerator::kBaseUrlForProduction),
+          GURL(GDataWapiUrlGenerator::kBaseDownloadUrlForProduction)) {
   }
 
  protected:
@@ -196,4 +198,10 @@
       url_generator_.GenerateAccountMetadataUrl(false).spec());
 }
 
+TEST_F(GDataWapiUrlGeneratorTest, GenerateDownloadFileUrl) {
+  EXPECT_EQ(
+      "https://www.googledrive.com/host/resourceId",
+      url_generator_.GenerateDownloadFileUrl("file:resourceId").spec());
+}
+
 }  // namespace google_apis
diff --git a/chrome/browser/google_apis/request_registry.cc b/chrome/browser/google_apis/request_registry.cc
deleted file mode 100644
index 240b388..0000000
--- a/chrome/browser/google_apis/request_registry.cc
+++ /dev/null
@@ -1,88 +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/google_apis/request_registry.h"
-
-#include "content/public/browser/browser_thread.h"
-
-using content::BrowserThread;
-
-namespace google_apis {
-
-RequestProgressStatus::RequestProgressStatus(const base::FilePath& path)
-    : request_id(-1),
-      file_path(path),
-      transfer_state(REQUEST_NOT_STARTED) {
-}
-
-RequestRegistry::Request::Request(RequestRegistry* registry)
-    : registry_(registry),
-      progress_status_(base::FilePath()) {
-}
-
-RequestRegistry::Request::Request(RequestRegistry* registry,
-                                        const base::FilePath& path)
-    : registry_(registry),
-      progress_status_(path) {
-}
-
-RequestRegistry::Request::~Request() {
-  DCHECK(progress_status_.transfer_state == REQUEST_COMPLETED ||
-         progress_status_.transfer_state == REQUEST_FAILED);
-}
-
-void RequestRegistry::Request::Cancel() {
-  DoCancel();
-  NotifyFinish(REQUEST_FAILED);
-}
-
-void RequestRegistry::Request::NotifyStart() {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  // Some request_ids may be restarted. Report only the first "start".
-  if (progress_status_.transfer_state == REQUEST_NOT_STARTED) {
-    progress_status_.transfer_state = REQUEST_STARTED;
-    registry_->OnRequestStart(this, &progress_status_.request_id);
-  }
-}
-
-void RequestRegistry::Request::NotifyFinish(
-    RequestTransferState status) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  DCHECK(progress_status_.transfer_state >= REQUEST_STARTED);
-  DCHECK(status == REQUEST_COMPLETED || status == REQUEST_FAILED);
-  progress_status_.transfer_state = status;
-  registry_->OnRequestFinish(progress_status().request_id);
-}
-
-RequestRegistry::RequestRegistry() {
-  in_flight_requests_.set_check_on_null_data(true);
-}
-
-RequestRegistry::~RequestRegistry() {
-}
-
-void RequestRegistry::CancelRequest(Request* request) {
-  request->Cancel();
-}
-
-void RequestRegistry::OnRequestStart(
-    RequestRegistry::Request* request,
-    RequestID* id) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
-  *id = in_flight_requests_.Add(request);
-  DVLOG(1) << "Request[" << *id << "] started.";
-}
-
-void RequestRegistry::OnRequestFinish(RequestID id) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
-  Request* request = in_flight_requests_.Lookup(id);
-  DCHECK(request);
-
-  DVLOG(1) << "Request[" << id << "] finished.";
-  in_flight_requests_.Remove(id);
-}
-
-}  // namespace google_apis
diff --git a/chrome/browser/google_apis/request_registry.h b/chrome/browser/google_apis/request_registry.h
deleted file mode 100644
index 0c034a7..0000000
--- a/chrome/browser/google_apis/request_registry.h
+++ /dev/null
@@ -1,100 +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_GOOGLE_APIS_REQUEST_REGISTRY_H_
-#define CHROME_BROWSER_GOOGLE_APIS_REQUEST_REGISTRY_H_
-
-#include "base/basictypes.h"
-#include "base/files/file_path.h"
-#include "base/id_map.h"
-#include "chrome/browser/google_apis/gdata_errorcode.h"
-
-namespace google_apis {
-
-// Unique ID to identify each request.
-typedef int32 RequestID;
-
-// Enumeration type for indicating the state of the transfer.
-enum RequestTransferState {
-  REQUEST_NOT_STARTED,
-  REQUEST_STARTED,
-  REQUEST_IN_PROGRESS,
-  REQUEST_COMPLETED,
-  REQUEST_FAILED,
-};
-
-// Returns string representations of the request state.
-std::string RequestTransferStateToString(RequestTransferState state);
-
-// Structure that packs progress information of each request.
-struct RequestProgressStatus {
-  explicit RequestProgressStatus(const base::FilePath& file_path);
-
-  RequestID request_id;
-
-  // Drive path of the file dealt with the current request.
-  base::FilePath file_path;
-  // Current state of the transfer;
-  RequestTransferState transfer_state;
-};
-
-// This class tracks all the in-flight Google API requests and manage
-// their lifetime.
-class RequestRegistry {
- public:
-  RequestRegistry();
-  ~RequestRegistry();
-
-  // Base class for requests that this registry class can maintain.
-  // NotifyStart() passes the ownership of the Request object to the registry.
-  // In particular, calling NotifyFinish() causes the registry to delete the
-  // Request object itself.
-  class Request {
-   public:
-    explicit Request(RequestRegistry* registry);
-    Request(RequestRegistry* registry, const base::FilePath& file_path);
-    virtual ~Request();
-
-    // Cancels the ongoing request. NotifyFinish() is called and the Request
-    // object is deleted once the cancellation is done in DoCancel().
-    void Cancel();
-
-    // Retrieves the current progress status of the request.
-    const RequestProgressStatus& progress_status() const {
-      return progress_status_;
-    }
-
-   protected:
-    // Notifies the registry about current status.
-    void NotifyStart();
-    void NotifyFinish(RequestTransferState status);
-
-   private:
-    // Does the cancellation.
-    virtual void DoCancel() = 0;
-
-    RequestRegistry* const registry_;
-    RequestProgressStatus progress_status_;
-  };
-
-  // Cancels the specified request.
-  void CancelRequest(Request* request);
-
- private:
-  // Handlers for notifications from Requests.
-  friend class Request;
-  // Notifies that an request has started. This method passes the ownership of
-  // the request to the registry. A fresh request ID is returned to *id.
-  void OnRequestStart(Request* request, RequestID* id);
-  void OnRequestFinish(RequestID request_id);
-
-  typedef IDMap<Request, IDMapOwnPointer> RequestIDMap;
-  RequestIDMap in_flight_requests_;
-
-  DISALLOW_COPY_AND_ASSIGN(RequestRegistry);
-};
-
-}  // namespace google_apis
-
-#endif  // CHROME_BROWSER_GOOGLE_APIS_REQUEST_REGISTRY_H_
diff --git a/chrome/browser/google_apis/request_sender.cc b/chrome/browser/google_apis/request_sender.cc
index f4eae24..b2709dc 100644
--- a/chrome/browser/google_apis/request_sender.cc
+++ b/chrome/browser/google_apis/request_sender.cc
@@ -5,11 +5,9 @@
 #include "chrome/browser/google_apis/request_sender.h"
 
 #include "base/bind.h"
+#include "base/stl_util.h"
 #include "chrome/browser/google_apis/auth_service.h"
 #include "chrome/browser/google_apis/base_requests.h"
-#include "content/public/browser/browser_thread.h"
-
-using content::BrowserThread;
 
 namespace google_apis {
 
@@ -19,25 +17,29 @@
     const std::vector<std::string>& scopes,
     const std::string& custom_user_agent)
     : profile_(profile),
+      url_request_context_getter_(url_request_context_getter),
       auth_service_(new AuthService(url_request_context_getter, scopes)),
-      request_registry_(new RequestRegistry()),
       custom_user_agent_(custom_user_agent),
       weak_ptr_factory_(this) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  DCHECK(thread_checker_.CalledOnValidThread());
 }
 
 RequestSender::~RequestSender() {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  DCHECK(thread_checker_.CalledOnValidThread());
+  STLDeleteContainerPointers(in_flight_requests_.begin(),
+                             in_flight_requests_.end());
 }
 
 void RequestSender::Initialize() {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  DCHECK(thread_checker_.CalledOnValidThread());
   auth_service_->Initialize(profile_);
 }
 
 base::Closure RequestSender::StartRequestWithRetry(
     AuthenticatedRequestInterface* request) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  in_flight_requests_.insert(request);
 
   // TODO(kinaba): Stop relying on weak pointers. Move lifetime management
   // of the requests to request sender.
@@ -66,7 +68,7 @@
     const base::WeakPtr<AuthenticatedRequestInterface>& request,
     GDataErrorCode code,
     const std::string& /* access_token */) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  DCHECK(thread_checker_.CalledOnValidThread());
 
   // Do nothing if the request is canceled during authentication.
   if (!request.get())
@@ -81,7 +83,7 @@
 }
 
 void RequestSender::RetryRequest(AuthenticatedRequestInterface* request) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  DCHECK(thread_checker_.CalledOnValidThread());
 
   auth_service_->ClearAccessToken();
   // User authentication might have expired - rerun the request to force
@@ -91,12 +93,17 @@
 
 void RequestSender::CancelRequest(
     const base::WeakPtr<AuthenticatedRequestInterface>& request) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  DCHECK(thread_checker_.CalledOnValidThread());
 
   // Do nothing if the request is already finished.
   if (!request.get())
     return;
-  request_registry_->CancelRequest(request->AsRequestRegistryRequest());
+  request->Cancel();
+}
+
+void RequestSender::RequestFinished(AuthenticatedRequestInterface* request) {
+  in_flight_requests_.erase(request);
+  delete request;
 }
 
 }  // namespace google_apis
diff --git a/chrome/browser/google_apis/request_sender.h b/chrome/browser/google_apis/request_sender.h
index 5b9b8dc..f20c394 100644
--- a/chrome/browser/google_apis/request_sender.h
+++ b/chrome/browser/google_apis/request_sender.h
@@ -5,6 +5,7 @@
 #ifndef CHROME_BROWSER_GOOGLE_APIS_REQUEST_SENDER_H_
 #define CHROME_BROWSER_GOOGLE_APIS_REQUEST_SENDER_H_
 
+#include <set>
 #include <string>
 #include <vector>
 
@@ -12,6 +13,7 @@
 #include "base/callback_forward.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
+#include "base/threading/thread_checker.h"
 #include "chrome/browser/google_apis/gdata_errorcode.h"
 
 class Profile;
@@ -24,7 +26,6 @@
 
 class AuthenticatedRequestInterface;
 class AuthService;
-class RequestRegistry;
 
 // Helper class that sends requests implementing
 // AuthenticatedRequestInterface and handles retries and authentication.
@@ -44,8 +45,9 @@
   virtual ~RequestSender();
 
   AuthService* auth_service() { return auth_service_.get(); }
-  RequestRegistry* request_registry() {
-    return request_registry_.get();
+
+  net::URLRequestContextGetter* url_request_context_getter() const {
+    return url_request_context_getter_;
   }
 
   // Prepares the object for use.
@@ -53,12 +55,18 @@
 
   // Starts a request implementing the AuthenticatedRequestInterface
   // interface, and makes the request retry upon authentication failures by
-  // calling back to RetryRequest.
+  // calling back to RetryRequest. The |request| object is owned by this
+  // RequestSender. It will be deleted in RequestSender's destructor or
+  // in RequestFinished().
   //
   // Returns a closure to cancel the request. The closure cancels the request
   // if it is in-flight, and does nothing if it is already terminated.
   base::Closure StartRequestWithRetry(AuthenticatedRequestInterface* request);
 
+  // Notifies to this RequestSender that |request| has finished.
+  // TODO(kinaba): refactor the life time management and make this at private.
+  void RequestFinished(AuthenticatedRequestInterface* request);
+
  private:
   // Called when the access token is fetched.
   void OnAccessTokenFetched(
@@ -76,11 +84,14 @@
       const base::WeakPtr<AuthenticatedRequestInterface>& request);
 
   Profile* profile_;  // Not owned.
+  net::URLRequestContextGetter* url_request_context_getter_;  // Not owned.
 
   scoped_ptr<AuthService> auth_service_;
-  scoped_ptr<RequestRegistry> request_registry_;
+  std::set<AuthenticatedRequestInterface*> in_flight_requests_;
   const std::string custom_user_agent_;
 
+  base::ThreadChecker thread_checker_;
+
   // Note: This should remain the last member so it'll be destroyed and
   // invalidate its weak pointers before any other members are destroyed.
   base::WeakPtrFactory<RequestSender> weak_ptr_factory_;
diff --git a/chrome/browser/google_apis/task_util.cc b/chrome/browser/google_apis/task_util.cc
index 7d048ee..eb175d8 100644
--- a/chrome/browser/google_apis/task_util.cc
+++ b/chrome/browser/google_apis/task_util.cc
@@ -5,9 +5,6 @@
 #include "chrome/browser/google_apis/task_util.h"
 
 #include "base/location.h"
-#include "content/public/browser/browser_thread.h"
-
-using content::BrowserThread;
 
 namespace google_apis {
 
@@ -21,9 +18,4 @@
   }
 }
 
-void RunTaskOnUIThread(const base::Closure& task) {
-  RunTaskOnThread(
-      BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI), task);
-}
-
 }  // namespace google_apis
diff --git a/chrome/browser/google_apis/task_util.h b/chrome/browser/google_apis/task_util.h
index d4fd59b..f6e874b 100644
--- a/chrome/browser/google_apis/task_util.h
+++ b/chrome/browser/google_apis/task_util.h
@@ -14,9 +14,6 @@
 void RunTaskOnThread(scoped_refptr<base::MessageLoopProxy> relay_proxy,
                      const base::Closure& task);
 
-// Runs task on UI thread.
-void RunTaskOnUIThread(const base::Closure& task);
-
 namespace internal {
 
 // Implementation of the composed callback, whose signature is |Sig|.
diff --git a/chrome/browser/google_apis/test_util.cc b/chrome/browser/google_apis/test_util.cc
index 84dab6c..30c2d35 100644
--- a/chrome/browser/google_apis/test_util.cc
+++ b/chrome/browser/google_apis/test_util.cc
@@ -11,6 +11,7 @@
 #include "base/path_service.h"
 #include "base/pending_task.h"
 #include "base/rand_util.h"
+#include "base/run_loop.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
@@ -20,9 +21,9 @@
 #include "chrome/browser/google_apis/gdata_wapi_parser.h"
 #include "chrome/browser/google_apis/gdata_wapi_requests.h"
 #include "content/public/browser/browser_thread.h"
-#include "googleurl/src/gurl.h"
 #include "net/test/embedded_test_server/http_request.h"
 #include "net/test/embedded_test_server/http_response.h"
+#include "url/gurl.h"
 
 namespace google_apis {
 namespace test_util {
@@ -79,16 +80,16 @@
 
     TaskObserver task_observer;
     base::MessageLoop::current()->AddTaskObserver(&task_observer);
-    base::MessageLoop::current()->RunUntilIdle();
+    base::RunLoop().RunUntilIdle();
     base::MessageLoop::current()->RemoveTaskObserver(&task_observer);
     if (!task_observer.posted())
       break;
   }
 }
 
-void RunAndQuit(const base::Closure& closure) {
+void RunAndQuit(base::RunLoop* run_loop, const base::Closure& closure) {
   closure.Run();
-  base::MessageLoop::current()->Quit();
+  run_loop->Quit();
 }
 
 bool WriteStringToFile(const base::FilePath& file_path,
@@ -138,7 +139,7 @@
 
   scoped_ptr<net::test_server::BasicHttpResponse> http_response(
       new net::test_server::BasicHttpResponse);
-  http_response->set_code(net::test_server::SUCCESS);
+  http_response->set_code(net::HTTP_OK);
   http_response->set_content(content);
   http_response->set_content_type(content_type);
   return http_response.Pass();
diff --git a/chrome/browser/google_apis/test_util.h b/chrome/browser/google_apis/test_util.h
index 0e770bd..173674d 100644
--- a/chrome/browser/google_apis/test_util.h
+++ b/chrome/browser/google_apis/test_util.h
@@ -16,11 +16,13 @@
 #include "base/template_util.h"
 #include "chrome/browser/google_apis/base_requests.h"
 #include "chrome/browser/google_apis/gdata_errorcode.h"
+#include "chrome/browser/google_apis/task_util.h"
 
 class GURL;
 
 namespace base {
 class FilePath;
+class RunLoop;
 class Value;
 }
 
@@ -33,15 +35,6 @@
 }
 
 namespace google_apis {
-
-class AboutResource;
-class AccountMetadata;
-class AppList;
-class AuthenticatedRequestInterface;
-class ResourceEntry;
-class ResourceList;
-struct UploadRangeResponse;
-
 namespace test_util {
 
 // Runs a task posted to the blocking pool, including subsequent tasks posted
@@ -53,8 +46,15 @@
 // repeatedly.
 void RunBlockingPoolTask();
 
-// Runs the closure, and then quits the current MessageLoop.
-void RunAndQuit(const base::Closure& closure);
+// Runs the closure, and then quits the |run_loop|.
+void RunAndQuit(base::RunLoop* run_loop, const base::Closure& closure);
+
+// Returns callback which runs the given |callback| and then quits |run_loop|.
+template<typename CallbackType>
+CallbackType CreateQuitCallback(base::RunLoop* run_loop,
+                                const CallbackType& callback) {
+  return CreateComposedCallback(base::Bind(&RunAndQuit, run_loop), callback);
+}
 
 // Removes |prefix| from |input| and stores the result in |output|. Returns
 // true if the prefix is removed.
diff --git a/chrome/browser/google_apis/time_util.cc b/chrome/browser/google_apis/time_util.cc
index 01a40dd..3c274b5 100644
--- a/chrome/browser/google_apis/time_util.cc
+++ b/chrome/browser/google_apis/time_util.cc
@@ -10,7 +10,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
-#include "base/time.h"
+#include "base/time/time.h"
 
 namespace google_apis {
 namespace util {
diff --git a/chrome/browser/google_apis/time_util_unittest.cc b/chrome/browser/google_apis/time_util_unittest.cc
index af7eec9..14c8c3c 100644
--- a/chrome/browser/google_apis/time_util_unittest.cc
+++ b/chrome/browser/google_apis/time_util_unittest.cc
@@ -6,52 +6,27 @@
 
 #include "base/i18n/time_formatting.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-#if defined(OS_CHROMEOS)
-#include "chrome/browser/chromeos/system/timezone_settings.h"
-#endif  // OS_CHROMEOS
-
 namespace google_apis {
 namespace util {
 namespace {
 
 std::string FormatTime(const base::Time& time) {
-  return UTF16ToUTF8(TimeFormatShortDateAndTime(time));
+  return base::UTF16ToUTF8(base::TimeFormatShortDateAndTime(time));
 }
 
 }  // namespace
 
-#if defined(OS_CHROMEOS)
-// ChromeOS can test utilities using ICU library.
-TEST(TimeUtilTest, GetTimeFromStringLocalTimezoneForChromeOs) {
-  // Creates time object GMT.
-  base::Time::Exploded exploded = {2012, 7, 0, 14, 1, 3, 21, 151};
-  base::Time target_time = base::Time::FromUTCExploded(exploded);
-
-  // Creates time object as the local time.
-  base::Time test_time;
-  ASSERT_TRUE(GetTimeFromString("2012-07-14T01:03:21.151", &test_time));
-
-  // Gets the offset between the local time and GMT.
-  const icu::TimeZone& tz =
-      chromeos::system::TimezoneSettings::GetInstance()->GetTimezone();
-  UErrorCode status = U_ZERO_ERROR;
-  int millisecond_in_day = ((1 * 60 + 3) * 60 + 21) * 1000 + 151;
-  int offset = tz.getOffset(1, 2012, 7, 14, 1, millisecond_in_day, status);
-  ASSERT_TRUE(U_SUCCESS(status));
-
-  EXPECT_EQ((target_time - test_time).InMilliseconds(), offset);
-}
-#endif  // OS_CHROMEOS
-
 TEST(TimeUtilTest, GetTimeFromStringLocalTimezone) {
   // Creates local time objects from exploded structure.
   base::Time::Exploded exploded = {2013, 1, 0, 15, 17, 11, 35, 374};
   base::Time local_time = base::Time::FromLocalExploded(exploded);
 
-  // Creates local time object, parsing time string.
+  // Creates local time object, parsing time string. Note that if there is
+  // not timezone suffix, GetTimeFromString() will handle this as local time
+  // with FromLocalExploded().
   base::Time test_time;
   ASSERT_TRUE(GetTimeFromString("2013-01-15T17:11:35.374", &test_time));
 
@@ -59,7 +34,7 @@
   EXPECT_EQ(local_time, test_time);
 }
 
-TEST(TimeUtilTest, GetTimeFromStringTimezone) {
+TEST(TimeUtilTest, GetTimeFromStringNonTrivialTimezones) {
   base::Time target_time;
   base::Time test_time;
   // Creates the target time.
@@ -78,19 +53,23 @@
   EXPECT_EQ(FormatTime(target_time), FormatTime(test_time));
 }
 
-TEST(TimeUtilTest, GetTimeFromString) {
+TEST(TimeUtilTest, GetTimeFromStringBasic) {
   base::Time test_time;
 
+  // Test that the special timezone "Z" (UTC) is handled.
   base::Time::Exploded target_time1 = {2005, 1, 0, 7, 8, 2, 0, 0};
   EXPECT_TRUE(GetTimeFromString("2005-01-07T08:02:00Z", &test_time));
   EXPECT_EQ(FormatTime(base::Time::FromUTCExploded(target_time1)),
             FormatTime(test_time));
 
+  // Test that a simple timezone "-08:00" is handled
+  // 17:57 - 8 hours = 09:57
   base::Time::Exploded target_time2 = {2005, 8, 0, 9, 17, 57, 0, 0};
   EXPECT_TRUE(GetTimeFromString("2005-08-09T09:57:00-08:00", &test_time));
   EXPECT_EQ(FormatTime(base::Time::FromUTCExploded(target_time2)),
             FormatTime(test_time));
 
+  // Test that milliseconds (.123) are handled.
   base::Time::Exploded target_time3 = {2005, 1, 0, 7, 8, 2, 0, 123};
   EXPECT_TRUE(GetTimeFromString("2005-01-07T08:02:00.123Z", &test_time));
   EXPECT_EQ(FormatTime(base::Time::FromUTCExploded(target_time3)),
diff --git a/chrome/browser/gpu/OWNERS b/chrome/browser/gpu/OWNERS
index fed3782..92ac858 100644
--- a/chrome/browser/gpu/OWNERS
+++ b/chrome/browser/gpu/OWNERS
@@ -1,5 +1,4 @@
 apatrick@chromium.org
 kbr@chromium.org
-gman@chromium.org
 piman@chromium.org
 zmo@chromium.org
diff --git a/chrome/browser/webview/OWNERS b/chrome/browser/guestview/OWNERS
similarity index 100%
rename from chrome/browser/webview/OWNERS
rename to chrome/browser/guestview/OWNERS
diff --git a/chrome/browser/guestview/adview/adview_constants.cc b/chrome/browser/guestview/adview/adview_constants.cc
new file mode 100644
index 0000000..98790ea
--- /dev/null
+++ b/chrome/browser/guestview/adview/adview_constants.cc
@@ -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.
+
+#include "chrome/browser/guestview/adview/adview_constants.h"
+
+namespace adview {
+
+// Events.
+const char kEventLoadCommit[] = "adview.onLoadCommit";
+
+}  // namespace adview
diff --git a/chrome/browser/guestview/adview/adview_constants.h b/chrome/browser/guestview/adview/adview_constants.h
new file mode 100644
index 0000000..480bc5c
--- /dev/null
+++ b/chrome/browser/guestview/adview/adview_constants.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.
+
+// Constants used for the adview API.
+
+#ifndef CHROME_BROWSER_GUESTVIEW_ADVIEW_ADVIEW_CONSTANTS_H_
+#define CHROME_BROWSER_GUESTVIEW_ADVIEW_ADVIEW_CONSTANTS_H_
+
+namespace adview {
+
+// Events.
+extern const char kEventLoadCommit[];
+
+}  // namespace adview
+
+#endif  // CHROME_BROWSER_GUESTVIEW_ADVIEW_ADVIEW_CONSTANTS_H_
+
diff --git a/chrome/browser/guestview/adview/adview_guest.cc b/chrome/browser/guestview/adview/adview_guest.cc
new file mode 100644
index 0000000..1f20a21
--- /dev/null
+++ b/chrome/browser/guestview/adview/adview_guest.cc
@@ -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.
+
+#include "chrome/browser/guestview/adview/adview_guest.h"
+
+#include "chrome/browser/guestview/adview/adview_constants.h"
+#include "chrome/browser/guestview/guestview_constants.h"
+#include "content/public/browser/web_contents.h"
+
+using content::WebContents;
+
+AdViewGuest::AdViewGuest(WebContents* guest_web_contents)
+    : GuestView(guest_web_contents),
+      WebContentsObserver(guest_web_contents) {
+}
+
+// static
+AdViewGuest* AdViewGuest::From(int embedder_process_id,
+                               int guest_instance_id) {
+  GuestView* guest = GuestView::From(embedder_process_id, guest_instance_id);
+  if (!guest)
+    return NULL;
+  return guest->AsAdView();
+}
+
+GuestView::Type AdViewGuest::GetViewType() const {
+  return GuestView::ADVIEW;
+}
+
+WebViewGuest* AdViewGuest::AsWebView() {
+  return NULL;
+}
+
+AdViewGuest* AdViewGuest::AsAdView() {
+  return this;
+}
+
+AdViewGuest::~AdViewGuest() {
+}
+
+void AdViewGuest::DidCommitProvisionalLoadForFrame(
+    int64 frame_id,
+    bool is_main_frame,
+    const GURL& url,
+    content::PageTransition transition_type,
+    content::RenderViewHost* render_view_host) {
+  scoped_ptr<DictionaryValue> args(new DictionaryValue());
+  args->SetString(guestview::kUrl, url.spec());
+  args->SetBoolean(guestview::kIsTopLevel, is_main_frame);
+  DispatchEvent(new GuestView::Event(adview::kEventLoadCommit, args.Pass()));
+}
+
+void AdViewGuest::WebContentsDestroyed(WebContents* web_contents) {
+  delete this;
+}
diff --git a/chrome/browser/guestview/adview/adview_guest.h b/chrome/browser/guestview/adview/adview_guest.h
new file mode 100644
index 0000000..35db3c3
--- /dev/null
+++ b/chrome/browser/guestview/adview/adview_guest.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_GUESTVIEW_ADVIEW_ADVIEW_GUEST_H_
+#define CHROME_BROWSER_GUESTVIEW_ADVIEW_ADVIEW_GUEST_H_
+
+#include "base/values.h"
+#include "chrome/browser/guestview/guestview.h"
+#include "content/public/browser/web_contents_observer.h"
+
+// An AdViewGuest is a WebContentsObserver on the guest WebContents of a
+// <adview> tag. It provides the browser-side implementation of the <adview>
+// API and manages the lifetime of <adview> extension events. AdViewGuest is
+// created on attachment. When a guest WebContents is associated with
+// a particular embedder WebContents, we call this "attachment".
+// TODO(fsamuel): There might be an opportunity here to refactor and reuse code
+// between AdViewGuest and WebViewGuest.
+class AdViewGuest : public GuestView,
+                    public content::WebContentsObserver {
+ public:
+  explicit AdViewGuest(content::WebContents* guest_web_contents);
+
+  static AdViewGuest* From(int embedder_process_id, int instance_id);
+
+  // GuestView implementation.
+  virtual GuestView::Type GetViewType() const OVERRIDE;
+  virtual WebViewGuest* AsWebView() OVERRIDE;
+  virtual AdViewGuest* AsAdView() OVERRIDE;
+
+ private:
+  virtual ~AdViewGuest();
+
+  virtual void DidCommitProvisionalLoadForFrame(
+      int64 frame_id,
+      bool is_main_frame,
+      const GURL& url,
+      content::PageTransition transition_type,
+      content::RenderViewHost* render_view_host) OVERRIDE;
+  virtual void WebContentsDestroyed(
+      content::WebContents* web_contents) OVERRIDE;
+
+  DISALLOW_COPY_AND_ASSIGN(AdViewGuest);
+};
+
+#endif  // CHROME_BROWSER_GUESTVIEW_ADVIEW_ADVIEW_GUEST_H_
diff --git a/chrome/browser/guestview/guestview.cc b/chrome/browser/guestview/guestview.cc
new file mode 100644
index 0000000..502f6db
--- /dev/null
+++ b/chrome/browser/guestview/guestview.cc
@@ -0,0 +1,149 @@
+// 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/guestview/guestview.h"
+
+#include "base/lazy_instance.h"
+#include "chrome/browser/extensions/event_router.h"
+#include "chrome/browser/guestview/guestview_constants.h"
+#include "chrome/browser/profiles/profile.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/browser/web_contents.h"
+
+using content::WebContents;
+
+namespace {
+
+// <embedder_process_id, guest_instance_id> => GuestView*
+typedef std::map<std::pair<int, int>, GuestView*> EmbedderGuestViewMap;
+static base::LazyInstance<EmbedderGuestViewMap> embedder_guestview_map =
+    LAZY_INSTANCE_INITIALIZER;
+
+typedef std::map<WebContents*, GuestView*> WebContentsGuestViewMap;
+static base::LazyInstance<WebContentsGuestViewMap> webcontents_guestview_map =
+    LAZY_INSTANCE_INITIALIZER;
+
+}  // namespace
+
+GuestView::Event::Event(const std::string& event_name,
+                        scoped_ptr<DictionaryValue> args)
+    : event_name_(event_name),
+      args_(args.Pass()) {
+}
+
+GuestView::Event::~Event() {
+}
+
+scoped_ptr<DictionaryValue> GuestView::Event::GetArguments() {
+  return args_.Pass();
+}
+
+GuestView::GuestView(WebContents* guest_web_contents)
+    : guest_web_contents_(guest_web_contents),
+      embedder_web_contents_(NULL),
+      embedder_render_process_id_(0),
+      browser_context_(guest_web_contents->GetBrowserContext()),
+      guest_instance_id_(guest_web_contents->GetEmbeddedInstanceID()),
+      view_instance_id_(guestview::kInstanceIDNone) {
+  webcontents_guestview_map.Get().insert(
+      std::make_pair(guest_web_contents, this));
+}
+
+// static
+GuestView* GuestView::FromWebContents(WebContents* web_contents) {
+  WebContentsGuestViewMap* guest_map = webcontents_guestview_map.Pointer();
+  WebContentsGuestViewMap::iterator it = guest_map->find(web_contents);
+  return it == guest_map->end() ? NULL : it->second;
+}
+
+// static
+GuestView* GuestView::From(int embedder_process_id, int guest_instance_id) {
+  EmbedderGuestViewMap* guest_map = embedder_guestview_map.Pointer();
+  EmbedderGuestViewMap::iterator it = guest_map->find(
+      std::make_pair(embedder_process_id, guest_instance_id));
+  return it == guest_map->end() ? NULL : it->second;
+}
+
+void GuestView::Attach(content::WebContents* embedder_web_contents,
+                       const std::string& extension_id,
+                       int view_instance_id,
+                       const base::DictionaryValue& args) {
+  embedder_web_contents_ = embedder_web_contents;
+  embedder_render_process_id_ =
+      embedder_web_contents->GetRenderProcessHost()->GetID();
+  extension_id_ = extension_id;
+  view_instance_id_ = view_instance_id;
+
+  std::pair<int, int> key(embedder_render_process_id_, guest_instance_id_);
+  embedder_guestview_map.Get().insert(std::make_pair(key, this));
+
+  // GuestView::Attach is called prior to initialization (and initial
+  // navigation) of the guest in the content layer in order to permit mapping
+  // the necessary associations between the <*view> element and its guest. This
+  // is needed by the <webview> WebRequest API to allow intercepting resource
+  // requests during navigation. However, queued events should be fired after
+  // content layer initialization in order to ensure that load events (such as
+  // 'loadstop') fire in embedder after the contentWindow is available.
+  base::MessageLoop::current()->PostTask(
+      FROM_HERE,
+      base::Bind(&GuestView::SendQueuedEvents,
+                  base::Unretained(this)));
+}
+
+GuestView::Type GuestView::GetViewType() const {
+  return GuestView::UNKNOWN;
+}
+
+WebViewGuest* GuestView::AsWebView() {
+  return NULL;
+}
+
+AdViewGuest* GuestView::AsAdView() {
+  return NULL;
+}
+
+GuestView::~GuestView() {
+  std::pair<int, int> key(embedder_render_process_id_, guest_instance_id_);
+  embedder_guestview_map.Get().erase(key);
+
+  webcontents_guestview_map.Get().erase(guest_web_contents());
+
+  while (!pending_events_.empty()) {
+    delete pending_events_.front();
+    pending_events_.pop();
+  }
+}
+
+void GuestView::DispatchEvent(Event* event) {
+  if (!attached()) {
+    pending_events_.push(event);
+    return;
+  }
+
+  Profile* profile = Profile::FromBrowserContext(browser_context_);
+
+  extensions::EventFilteringInfo info;
+  info.SetURL(GURL());
+  info.SetInstanceID(guest_instance_id_);
+  scoped_ptr<ListValue> args(new ListValue());
+  args->Append(event->GetArguments().release());
+
+  extensions::EventRouter::DispatchEvent(
+      embedder_web_contents_, profile, extension_id_,
+      event->event_name(), args.Pass(),
+      extensions::EventRouter::USER_GESTURE_UNKNOWN, info);
+
+  delete event;
+}
+
+void GuestView::SendQueuedEvents() {
+  if (!attached())
+    return;
+
+  while (!pending_events_.empty()) {
+    Event* event = pending_events_.front();
+    pending_events_.pop();
+    DispatchEvent(event);
+  }
+}
diff --git a/chrome/browser/guestview/guestview.h b/chrome/browser/guestview/guestview.h
new file mode 100644
index 0000000..4a0570b
--- /dev/null
+++ b/chrome/browser/guestview/guestview.h
@@ -0,0 +1,116 @@
+// 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_GUESTVIEW_GUESTVIEW_H_
+#define CHROME_BROWSER_GUESTVIEW_GUESTVIEW_H_
+
+#include <queue>
+
+#include "base/values.h"
+#include "content/public/browser/web_contents.h"
+
+class AdViewGuest;
+class WebViewGuest;
+
+// A GuestView is the base class browser-side API implementation for a <*view>
+// tag. GuestView maintains an association between a guest WebContents and an
+// embedder WebContents. It receives events issued from the guest and relays
+// them to the embedder.
+class GuestView {
+ public:
+  enum Type {
+    WEBVIEW,
+    ADVIEW,
+    UNKNOWN
+  };
+
+  class Event {
+   public:
+     Event(const std::string& event_name, scoped_ptr<DictionaryValue> args);
+     ~Event();
+
+    const std::string& event_name() const { return event_name_; }
+
+    scoped_ptr<DictionaryValue> GetArguments();
+
+   private:
+    const std::string event_name_;
+    scoped_ptr<DictionaryValue> args_;
+  };
+
+  explicit GuestView(content::WebContents* guest_web_contents);
+
+  static GuestView* FromWebContents(content::WebContents* web_contents);
+
+  static GuestView* From(int embedder_process_id, int instance_id);
+
+  virtual void Attach(content::WebContents* embedder_web_contents,
+                      const std::string& extension_id,
+                      int view_instance_id,
+                      const base::DictionaryValue& args);
+
+  content::WebContents* embedder_web_contents() const {
+    return embedder_web_contents_;
+  }
+
+  // Returns the guest WebContents.
+  content::WebContents* guest_web_contents() const {
+    return guest_web_contents_;
+  }
+
+  virtual Type GetViewType() const;
+
+  // Returns a WebViewGuest if this GuestView belongs to a <webview>.
+  virtual WebViewGuest* AsWebView() = 0;
+
+  // Returns an AdViewGuest if the GuestView belongs to an <adview>.
+  virtual AdViewGuest* AsAdView() = 0;
+
+  // Returns whether this guest has an associated embedder.
+  bool attached() const { return !!embedder_web_contents_; }
+
+  // Returns the instance ID of the <*view> element.
+  int view_instance_id() const { return view_instance_id_; }
+
+  // Returns the instance ID of the guest WebContents.
+  int guest_instance_id() const { return guest_instance_id_; }
+
+  // Returns the extension ID of the embedder.
+  const std::string& extension_id() const { return extension_id_; }
+
+  // Returns the user browser context of the embedder.
+  content::BrowserContext* browser_context() const { return browser_context_; }
+
+  // Returns the embedder's process ID.
+  int embedder_render_process_id() const { return embedder_render_process_id_; }
+
+ protected:
+  virtual ~GuestView();
+
+  // Dispatches an event |event_name| to the embedder with the |event| fields.
+  void DispatchEvent(Event* event);
+
+ private:
+  void SendQueuedEvents();
+
+  content::WebContents* guest_web_contents_;
+  content::WebContents* embedder_web_contents_;
+  std::string extension_id_;
+  int embedder_render_process_id_;
+  content::BrowserContext* browser_context_;
+  // |guest_instance_id_| is a profile-wide unique identifier for a guest
+  // WebContents.
+  const int guest_instance_id_;
+  // |view_instance_id_| is an identifier that's unique within a particular
+  // embedder RenderViewHost for a particular <*view> instance.
+  int view_instance_id_;
+
+  // This is a queue of Events that are destined to be sent to the embedder once
+  // the guest is attached to a particular embedder.
+  std::queue<Event*> pending_events_;
+
+  DISALLOW_COPY_AND_ASSIGN(GuestView);
+};
+
+#endif  // CHROME_BROWSER_GUESTVIEW_GUESTVIEW_H_
diff --git a/chrome/browser/guestview/guestview_constants.cc b/chrome/browser/guestview/guestview_constants.cc
new file mode 100644
index 0000000..3659bec
--- /dev/null
+++ b/chrome/browser/guestview/guestview_constants.cc
@@ -0,0 +1,19 @@
+// 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/guestview/guestview_constants.h"
+
+namespace guestview {
+
+// Parameters/properties on events.
+const char kIsTopLevel[] = "isTopLevel";
+const char kUrl[] = "url";
+
+// Attributes.
+const char kAttributeApi[] = "api";
+
+// Other.
+const int kInstanceIDNone = 0;
+
+}  // namespace guestview
diff --git a/chrome/browser/guestview/guestview_constants.h b/chrome/browser/guestview/guestview_constants.h
new file mode 100644
index 0000000..70a09a5
--- /dev/null
+++ b/chrome/browser/guestview/guestview_constants.h
@@ -0,0 +1,25 @@
+// 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.
+
+// Constants used for the WebView API.
+
+#ifndef CHROME_BROWSER_GUESTVIEW_GUESTVIEW_CONSTANTS_H_
+#define CHROME_BROWSER_GUESTVIEW_GUESTVIEW_CONSTANTS_H_
+
+namespace guestview {
+
+// Parameters/properties on events.
+extern const char kIsTopLevel[];
+extern const char kUrl[];
+
+// Attributes.
+extern const char kAttributeApi[];
+
+// Other.
+extern const int kInstanceIDNone;
+
+}  // namespace guestview
+
+#endif  // CHROME_BROWSER_GUESTVIEW_GUESTVIEW_CONSTANTS_H_
+
diff --git a/chrome/browser/guestview/webview/webview_constants.cc b/chrome/browser/guestview/webview/webview_constants.cc
new file mode 100644
index 0000000..dd4c8f4
--- /dev/null
+++ b/chrome/browser/guestview/webview/webview_constants.cc
@@ -0,0 +1,25 @@
+// 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/guestview/webview/webview_constants.h"
+
+namespace webview {
+
+// Events.
+const char kEventContentLoad[] = "webview.onContentLoad";
+const char kEventLoadCommit[] = "webview.onLoadCommit";
+const char kEventLoadRedirect[] = "webview.onLoadRedirect";
+const char kEventLoadStart[] = "webview.onLoadStart";
+const char kEventLoadStop[] = "webview.onLoadStop";
+
+// Internal parameters/properties on events.
+const char kInternalCurrentEntryIndex[] = "currentEntryIndex";
+const char kInternalEntryCount[] = "entryCount";
+const char kInternalProcessId[] = "processId";
+
+// Parameters/properties on events.
+extern const char kNewURL[];
+extern const char kOldURL[];
+
+}  // namespace webview
diff --git a/chrome/browser/guestview/webview/webview_constants.h b/chrome/browser/guestview/webview/webview_constants.h
new file mode 100644
index 0000000..01cec96
--- /dev/null
+++ b/chrome/browser/guestview/webview/webview_constants.h
@@ -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.
+
+// Constants used for the WebView API.
+
+#ifndef CHROME_BROWSER_GUESTVIEW_WEBVIEW_WEBVIEW_CONSTANTS_H_
+#define CHROME_BROWSER_GUESTVIEW_WEBVIEW_WEBVIEW_CONSTANTS_H_
+
+namespace webview {
+
+// Events.
+extern const char kEventContentLoad[];
+extern const char kEventLoadCommit[];
+extern const char kEventLoadRedirect[];
+extern const char kEventLoadStart[];
+extern const char kEventLoadStop[];
+
+// Internal parameters/properties on events.
+extern const char kInternalCurrentEntryIndex[];
+extern const char kInternalEntryCount[];
+extern const char kInternalProcessId[];
+
+// Parameters/properties on events.
+const char kNewURL[] = "newUrl";
+const char kOldURL[] = "oldUrl";
+
+}  // namespace webview
+
+#endif  // CHROME_BROWSER_GUESTVIEW_WEBVIEW_WEBVIEW_CONSTANTS_H_
+
diff --git a/chrome/browser/guestview/webview/webview_guest.cc b/chrome/browser/guestview/webview/webview_guest.cc
new file mode 100644
index 0000000..5c15a6f
--- /dev/null
+++ b/chrome/browser/guestview/webview/webview_guest.cc
@@ -0,0 +1,209 @@
+// 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/guestview/webview/webview_guest.h"
+
+#include "chrome/browser/extensions/api/web_request/web_request_api.h"
+#include "chrome/browser/extensions/extension_renderer_state.h"
+#include "chrome/browser/extensions/script_executor.h"
+#include "chrome/browser/guestview/guestview_constants.h"
+#include "chrome/browser/guestview/webview/webview_constants.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/notification_details.h"
+#include "content/public/browser/notification_source.h"
+#include "content/public/browser/notification_types.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/browser/resource_request_details.h"
+#include "content/public/browser/web_contents.h"
+
+using content::WebContents;
+
+namespace {
+
+void RemoveWebViewEventListenersOnIOThread(
+    void* profile,
+    const std::string& extension_id,
+    int embedder_process_id,
+    int guest_instance_id) {
+  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
+  ExtensionWebRequestEventRouter::GetInstance()->RemoveWebViewEventListeners(
+      profile, extension_id, embedder_process_id, guest_instance_id);
+}
+
+}  // namespace
+
+WebViewGuest::WebViewGuest(WebContents* guest_web_contents)
+    : GuestView(guest_web_contents),
+      WebContentsObserver(guest_web_contents),
+      script_executor_(new extensions::ScriptExecutor(guest_web_contents,
+                                                      &script_observers_)) {
+  notification_registrar_.Add(
+      this, content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
+      content::Source<WebContents>(guest_web_contents));
+
+  notification_registrar_.Add(
+      this, content::NOTIFICATION_RESOURCE_RECEIVED_REDIRECT,
+      content::Source<WebContents>(guest_web_contents));
+}
+
+// static
+WebViewGuest* WebViewGuest::From(int embedder_process_id,
+                                 int guest_instance_id) {
+  GuestView* guest = GuestView::From(embedder_process_id, guest_instance_id);
+  if (!guest)
+    return NULL;
+  return guest->AsWebView();
+}
+
+void WebViewGuest::Attach(WebContents* embedder_web_contents,
+                          const std::string& extension_id,
+                          int view_instance_id,
+                          const base::DictionaryValue& args) {
+  GuestView::Attach(
+      embedder_web_contents, extension_id, view_instance_id, args);
+
+  AddWebViewToExtensionRendererState();
+}
+
+GuestView::Type WebViewGuest::GetViewType() const {
+  return GuestView::WEBVIEW;
+}
+
+WebViewGuest* WebViewGuest::AsWebView() {
+  return this;
+}
+
+AdViewGuest* WebViewGuest::AsAdView() {
+  return NULL;
+}
+
+void WebViewGuest::Observe(int type,
+                           const content::NotificationSource& source,
+                           const content::NotificationDetails& details) {
+  switch (type) {
+    case content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME: {
+      DCHECK_EQ(content::Source<WebContents>(source).ptr(),
+                guest_web_contents());
+      if (content::Source<WebContents>(source).ptr() == guest_web_contents())
+        LoadHandlerCalled();
+      break;
+    }
+    case content::NOTIFICATION_RESOURCE_RECEIVED_REDIRECT: {
+      DCHECK_EQ(content::Source<WebContents>(source).ptr(),
+                guest_web_contents());
+      content::ResourceRedirectDetails* resource_redirect_details =
+          content::Details<content::ResourceRedirectDetails>(details).ptr();
+      bool is_top_level =
+          resource_redirect_details->resource_type == ResourceType::MAIN_FRAME;
+      LoadRedirect(resource_redirect_details->url,
+                   resource_redirect_details->new_url,
+                   is_top_level);
+      break;
+    }
+    default:
+      NOTREACHED() << "Unexpected notification sent.";
+      break;
+  }
+}
+
+void WebViewGuest::Go(int relative_index) {
+  guest_web_contents()->GetController().GoToOffset(relative_index);
+}
+
+WebViewGuest::~WebViewGuest() {
+}
+
+void WebViewGuest::DidCommitProvisionalLoadForFrame(
+    int64 frame_id,
+    bool is_main_frame,
+    const GURL& url,
+    content::PageTransition transition_type,
+    content::RenderViewHost* render_view_host) {
+  scoped_ptr<DictionaryValue> args(new DictionaryValue());
+  args->SetString(guestview::kUrl, url.spec());
+  args->SetBoolean(guestview::kIsTopLevel, is_main_frame);
+  args->SetInteger(webview::kInternalCurrentEntryIndex,
+      web_contents()->GetController().GetCurrentEntryIndex());
+  args->SetInteger(webview::kInternalEntryCount,
+      web_contents()->GetController().GetEntryCount());
+  args->SetInteger(webview::kInternalProcessId,
+      web_contents()->GetRenderProcessHost()->GetID());
+  DispatchEvent(new GuestView::Event(webview::kEventLoadCommit, args.Pass()));
+}
+
+void WebViewGuest::DidStartProvisionalLoadForFrame(
+    int64 frame_id,
+    int64 parent_frame_id,
+    bool is_main_frame,
+    const GURL& validated_url,
+    bool is_error_page,
+    bool is_iframe_srcdoc,
+    content::RenderViewHost* render_view_host) {
+  scoped_ptr<DictionaryValue> args(new DictionaryValue());
+  args->SetString(guestview::kUrl, validated_url.spec());
+  args->SetBoolean(guestview::kIsTopLevel, is_main_frame);
+  DispatchEvent(new GuestView::Event(webview::kEventLoadStart, args.Pass()));
+}
+
+void WebViewGuest::DidStopLoading(content::RenderViewHost* render_view_host) {
+  scoped_ptr<DictionaryValue> args(new DictionaryValue());
+  DispatchEvent(new GuestView::Event(webview::kEventLoadStop, args.Pass()));
+}
+
+void WebViewGuest::WebContentsDestroyed(WebContents* web_contents) {
+  RemoveWebViewFromExtensionRendererState(web_contents);
+  content::BrowserThread::PostTask(
+      content::BrowserThread::IO,
+      FROM_HERE,
+      base::Bind(
+          &RemoveWebViewEventListenersOnIOThread,
+          browser_context(), extension_id(),
+          embedder_render_process_id(),
+          view_instance_id()));
+  delete this;
+}
+
+void WebViewGuest::LoadHandlerCalled() {
+  scoped_ptr<DictionaryValue> args(new DictionaryValue());
+  DispatchEvent(new GuestView::Event(webview::kEventContentLoad, args.Pass()));
+}
+
+void WebViewGuest::LoadRedirect(const GURL& old_url,
+                                const GURL& new_url,
+                                bool is_top_level) {
+  scoped_ptr<DictionaryValue> args(new DictionaryValue());
+  args->SetBoolean(guestview::kIsTopLevel, is_top_level);
+  args->SetString(webview::kNewURL, new_url.spec());
+  args->SetString(webview::kOldURL, old_url.spec());
+  DispatchEvent(new GuestView::Event(webview::kEventLoadRedirect, args.Pass()));
+}
+
+void WebViewGuest::AddWebViewToExtensionRendererState() {
+  ExtensionRendererState::WebViewInfo webview_info;
+  webview_info.embedder_process_id = embedder_render_process_id();
+  webview_info.embedder_routing_id = embedder_web_contents()->GetRoutingID();
+  webview_info.guest_instance_id = guest_instance_id();
+  webview_info.instance_id = view_instance_id();
+
+  content::BrowserThread::PostTask(
+      content::BrowserThread::IO, FROM_HERE,
+      base::Bind(
+          &ExtensionRendererState::AddWebView,
+          base::Unretained(ExtensionRendererState::GetInstance()),
+          guest_web_contents()->GetRenderProcessHost()->GetID(),
+          guest_web_contents()->GetRoutingID(),
+          webview_info));
+}
+
+// static
+void WebViewGuest::RemoveWebViewFromExtensionRendererState(
+    WebContents* web_contents) {
+  content::BrowserThread::PostTask(
+      content::BrowserThread::IO, FROM_HERE,
+      base::Bind(
+          &ExtensionRendererState::RemoveWebView,
+          base::Unretained(ExtensionRendererState::GetInstance()),
+          web_contents->GetRenderProcessHost()->GetID(),
+          web_contents->GetRoutingID()));
+}
diff --git a/chrome/browser/guestview/webview/webview_guest.h b/chrome/browser/guestview/webview/webview_guest.h
new file mode 100644
index 0000000..905d346
--- /dev/null
+++ b/chrome/browser/guestview/webview/webview_guest.h
@@ -0,0 +1,99 @@
+// 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_GUESTVIEW_WEBVIEW_WEBVIEW_GUEST_H_
+#define CHROME_BROWSER_GUESTVIEW_WEBVIEW_WEBVIEW_GUEST_H_
+
+#include "base/observer_list.h"
+#include "chrome/browser/extensions/tab_helper.h"
+#include "chrome/browser/guestview/guestview.h"
+#include "content/public/browser/notification_registrar.h"
+#include "content/public/browser/web_contents_observer.h"
+
+namespace extensions {
+class ScriptExecutor;
+}  // namespace extensions
+
+// A WebViewGuest is a WebContentsObserver on the guest WebContents of a
+// <webview> tag. It provides the browser-side implementation of the <webview>
+// API and manages the lifetime of <webview> extension events. WebViewGuest is
+// created on attachment. That is, when a guest WebContents is associated with
+// a particular embedder WebContents. This happens on either initial navigation
+// or through the use of the New Window API, when a new window is attached to
+// a particular <webview>.
+class WebViewGuest : public GuestView,
+                     public content::NotificationObserver,
+                     public content::WebContentsObserver {
+ public:
+  explicit WebViewGuest(content::WebContents* guest_web_contents);
+
+  static WebViewGuest* From(int embedder_process_id, int instance_id);
+
+  // GuestView implementation.
+  virtual void Attach(content::WebContents* embedder_web_contents,
+                      const std::string& extension_id,
+                      int view_instance_id,
+                      const base::DictionaryValue& args) OVERRIDE;
+  virtual GuestView::Type GetViewType() const OVERRIDE;
+  virtual WebViewGuest* AsWebView() OVERRIDE;
+  virtual AdViewGuest* AsAdView() OVERRIDE;
+
+  // NotificationObserver implementation.
+  virtual void Observe(int type,
+                       const content::NotificationSource& source,
+                       const content::NotificationDetails& details) OVERRIDE;
+
+  // If possible, navigate the guest to |relative_index| entries away from the
+  // current navigation entry.
+  void Go(int relative_index);
+
+  extensions::ScriptExecutor* script_executor() {
+    return script_executor_.get();
+  }
+
+ private:
+  virtual ~WebViewGuest();
+
+  // WebContentsObserver implementation.
+  virtual void DidCommitProvisionalLoadForFrame(
+      int64 frame_id,
+      bool is_main_frame,
+      const GURL& url,
+      content::PageTransition transition_type,
+      content::RenderViewHost* render_view_host) OVERRIDE;
+  virtual void DidStartProvisionalLoadForFrame(
+      int64 frame_id,
+      int64 parent_frame_id,
+      bool is_main_frame,
+      const GURL& validated_url,
+      bool is_error_page,
+      bool is_iframe_srcdoc,
+      content::RenderViewHost* render_view_host) OVERRIDE;
+  virtual void DidStopLoading(
+      content::RenderViewHost* render_view_host) OVERRIDE;
+  virtual void WebContentsDestroyed(
+      content::WebContents* web_contents) OVERRIDE;
+
+  // Called after the load handler is called in the guest's main frame.
+  void LoadHandlerCalled();
+
+  // Called when a redirect notification occurs.
+  void LoadRedirect(const GURL& old_url,
+                    const GURL& new_url,
+                    bool is_top_level);
+
+  void AddWebViewToExtensionRendererState();
+  static void RemoveWebViewFromExtensionRendererState(
+      content::WebContents* web_contents);
+
+  ObserverList<extensions::TabHelper::ScriptExecutionObserver>
+      script_observers_;
+  scoped_ptr<extensions::ScriptExecutor> script_executor_;
+
+  content::NotificationRegistrar notification_registrar_;
+
+  DISALLOW_COPY_AND_ASSIGN(WebViewGuest);
+};
+
+#endif  // CHROME_BROWSER_GUESTVIEW_WEBVIEW_WEBVIEW_GUEST_H_
diff --git a/chrome/browser/history/android/android_cache_database.cc b/chrome/browser/history/android/android_cache_database.cc
index 52a0d40..1fdd981 100644
--- a/chrome/browser/history/android/android_cache_database.cc
+++ b/chrome/browser/history/android/android_cache_database.cc
@@ -174,8 +174,7 @@
 
 bool AndroidCacheDatabase::CreateDatabase(const base::FilePath& db_name) {
   db_name_ = db_name;
-  if (file_util::PathExists(db_name_))
-    file_util::Delete(db_name_, false);
+  sql::Connection::Delete(db_name_);
 
   // Using a new connection, otherwise we can not create the database.
   sql::Connection connection;
diff --git a/chrome/browser/history/android/android_cache_database.h b/chrome/browser/history/android/android_cache_database.h
index ac6d1c4..4f4dd19 100644
--- a/chrome/browser/history/android/android_cache_database.h
+++ b/chrome/browser/history/android/android_cache_database.h
@@ -7,7 +7,7 @@
 
 #include "base/files/file_path.h"
 #include "base/gtest_prod_util.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/history/android/android_history_types.h"
 #include "sql/connection.h"
 #include "sql/init_status.h"
diff --git a/chrome/browser/history/android/android_history_provider_service_unittest.cc b/chrome/browser/history/android/android_history_provider_service_unittest.cc
index 626bf8a..7919849 100644
--- a/chrome/browser/history/android/android_history_provider_service_unittest.cc
+++ b/chrome/browser/history/android/android_history_provider_service_unittest.cc
@@ -5,7 +5,7 @@
 #include "chrome/browser/history/android/android_history_provider_service.h"
 
 #include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/history/android/android_history_types.h"
 #include "chrome/common/chrome_constants.h"
 #include "chrome/test/base/testing_browser_process.h"
diff --git a/chrome/browser/history/android/android_time.h b/chrome/browser/history/android/android_time.h
index f9499fa..a2f3fee 100644
--- a/chrome/browser/history/android/android_time.h
+++ b/chrome/browser/history/android/android_time.h
@@ -5,7 +5,7 @@
 #ifndef CHROME_BROWSER_HISTORY_ANDROID_ANDROID_TIME_H_
 #define CHROME_BROWSER_HISTORY_ANDROID_ANDROID_TIME_H_
 
-#include "base/time.h"
+#include "base/time/time.h"
 
 namespace history {
 
diff --git a/chrome/browser/history/android/favicon_sql_handler.cc b/chrome/browser/history/android/favicon_sql_handler.cc
index 0028184..6c0c3d7 100644
--- a/chrome/browser/history/android/favicon_sql_handler.cc
+++ b/chrome/browser/history/android/favicon_sql_handler.cc
@@ -40,7 +40,6 @@
   chrome::FaviconID favicon_id = thumbnail_db_->AddFavicon(
       GURL(),
       chrome::FAVICON,
-      history::GetDefaultFaviconSizes(),
       row.favicon(),
       Time::Now(),
       gfx::Size());
@@ -110,7 +109,6 @@
   chrome::FaviconID id = thumbnail_db_->AddFavicon(
       GURL(),
       chrome::FAVICON,
-      history::GetDefaultFaviconSizes(),
       row->favicon(),
       Time::Now(),
       gfx::Size());
diff --git a/chrome/browser/history/android/sqlite_cursor_unittest.cc b/chrome/browser/history/android/sqlite_cursor_unittest.cc
index ac97f2f..7491cd1 100644
--- a/chrome/browser/history/android/sqlite_cursor_unittest.cc
+++ b/chrome/browser/history/android/sqlite_cursor_unittest.cc
@@ -10,7 +10,7 @@
 #include "base/android/jni_array.h"
 #include "base/android/jni_string.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/history/android/android_history_provider_service.h"
 #include "chrome/browser/history/android/android_history_types.h"
 #include "chrome/browser/history/android/android_time.h"
diff --git a/chrome/browser/history/delete_directive_handler.cc b/chrome/browser/history/delete_directive_handler.cc
index f87ac9c..c08bf77 100644
--- a/chrome/browser/history/delete_directive_handler.cc
+++ b/chrome/browser/history/delete_directive_handler.cc
@@ -6,7 +6,7 @@
 
 #include "base/json/json_writer.h"
 #include "base/rand_util.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "base/values.h"
 #include "chrome/browser/history/history_backend.h"
 #include "chrome/browser/history/history_db_task.h"
@@ -344,6 +344,7 @@
   if (!sync_processor_) {
     return syncer::SyncError(
         FROM_HERE,
+        syncer::SyncError::DATATYPE_ERROR,
         "Cannot send local delete directive to sync",
         syncer::HISTORY_DELETE_DIRECTIVES);
   }
@@ -372,7 +373,10 @@
   DCHECK(thread_checker_.CalledOnValidThread());
   if (!sync_processor_) {
     return syncer::SyncError(
-        FROM_HERE, "Sync is disabled.", syncer::HISTORY_DELETE_DIRECTIVES);
+        FROM_HERE,
+        syncer::SyncError::DATATYPE_ERROR,
+        "Sync is disabled.",
+        syncer::HISTORY_DELETE_DIRECTIVES);
   }
 
   syncer::SyncDataList delete_directives;
diff --git a/chrome/browser/history/download_database.cc b/chrome/browser/history/download_database.cc
index c21734d..4d1d70e 100644
--- a/chrome/browser/history/download_database.cc
+++ b/chrome/browser/history/download_database.cc
@@ -15,7 +15,7 @@
 #include "base/stl_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "build/build_config.h"
 #include "chrome/browser/history/download_row.h"
 #include "chrome/browser/history/history_types.h"
@@ -37,18 +37,19 @@
 };
 
 static const char kSchema[] =
-  "CREATE TABLE downloads ("
-  "id INTEGER PRIMARY KEY,"           // Primary key.
-  "current_path LONGVARCHAR NOT NULL,"  // Current disk location of the download
-  "target_path LONGVARCHAR NOT NULL,"  // Final disk location of the download
-  "start_time INTEGER NOT NULL,"      // When the download was started.
-  "received_bytes INTEGER NOT NULL,"  // Total size downloaded.
-  "total_bytes INTEGER NOT NULL,"     // Total size of the download.
-  "state INTEGER NOT NULL,"           // 1=complete, 4=interrupted
-  "danger_type INTEGER NOT NULL, "    // Not dangerous, danger type, validated.
-  "interrupt_reason INTEGER NOT NULL,"  // Reason the download was interrupted.
-  "end_time INTEGER NOT NULL,"        // When the download completed.
-  "opened INTEGER NOT NULL)";         // 1 if it has ever been opened else 0
+    "CREATE TABLE downloads ("
+    "id INTEGER PRIMARY KEY,"  // Primary key.
+    "current_path LONGVARCHAR NOT NULL,"  // Current disk location
+    "target_path LONGVARCHAR NOT NULL,"  // Final disk location
+    "start_time INTEGER NOT NULL,"  // When the download was started.
+    "received_bytes INTEGER NOT NULL,"  // Total size downloaded.
+    "total_bytes INTEGER NOT NULL,"  // Total size of the download.
+    "state INTEGER NOT NULL,"  // 1=complete, 4=interrupted
+    "danger_type INTEGER NOT NULL, "  // Not dangerous, danger type, validated.
+    "interrupt_reason INTEGER NOT NULL,"
+    "end_time INTEGER NOT NULL,"  // When the download completed.
+    "opened INTEGER NOT NULL,"  // 1 if it has ever been opened else 0
+    "referrer VARCHAR NOT NULL)";  // HTTP Referrer
 
 static const char kUrlChainSchema[] =
     "CREATE TABLE downloads_url_chains ("
@@ -234,7 +235,7 @@
   sql::Statement statement_populate(GetDB().GetUniqueStatement(
     "INSERT INTO downloads "
     "( id, current_path, target_path, start_time, received_bytes, total_bytes, "
-    "  state, danger_type, interrupt_reason, end_time, opened ) "
+    "  state, danger_type, interrupt_reason, end_time, opened, referrer ) "
     "SELECT id, full_path, full_path, "
     "       CASE start_time WHEN 0 THEN 0 ELSE "
     "            (start_time + 11644473600) * 1000000 END, "
@@ -242,7 +243,7 @@
     "       state, ?, ?, "
     "       CASE end_time WHEN 0 THEN 0 ELSE "
     "            (end_time + 11644473600) * 1000000 END, "
-    "       opened "
+    "       opened, \"\" "
     "FROM downloads_tmp"));
   statement_populate.BindInt(0, content::DOWNLOAD_INTERRUPT_REASON_NONE);
   statement_populate.BindInt(1, kDangerTypeNotDangerous);
@@ -265,6 +266,10 @@
   return true;
 }
 
+bool DownloadDatabase::MigrateReferrer() {
+  return EnsureColumnExists("referrer", "VARCHAR NOT NULL DEFAULT \"\"");
+}
+
 bool DownloadDatabase::InitDownloadTable() {
   GetMetaTable().GetValue(kNextDownloadId, &next_id_);
   if (GetDB().DoesTableExist("downloads")) {
@@ -295,9 +300,9 @@
 
   sql::Statement statement_main(GetDB().GetCachedStatement(SQL_FROM_HERE,
       "SELECT id, current_path, target_path, start_time, received_bytes, "
-        "total_bytes, state, danger_type, interrupt_reason, end_time, opened "
-      "FROM downloads "
-      "ORDER BY start_time"));
+      "total_bytes, state, danger_type, interrupt_reason, end_time, opened, "
+      "referrer "
+      "FROM downloads ORDER BY start_time"));
 
   while (statement_main.Step()) {
     scoped_ptr<DownloadRow> info(new DownloadRow());
@@ -321,6 +326,7 @@
     info->end_time = base::Time::FromInternalValue(
         statement_main.ColumnInt64(column++));
     info->opened = statement_main.ColumnInt(column++) != 0;
+    info->referrer_url = GURL(statement_main.ColumnString(column++));
     if (info->db_handle >= next_db_handle_)
       next_db_handle_ = info->db_handle + 1;
     if (!db_handles.insert(info->db_handle).second) {
@@ -482,8 +488,8 @@
         "INSERT INTO downloads "
         "(id, current_path, target_path, start_time, "
         " received_bytes, total_bytes, state, danger_type, interrupt_reason, "
-        " end_time, opened) "
-        "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"));
+        " end_time, opened, referrer) "
+        "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"));
 
     int column = 0;
     statement_insert.BindInt64(column++, db_handle);
@@ -497,6 +503,7 @@
     statement_insert.BindInt(column++, info.interrupt_reason);
     statement_insert.BindInt64(column++, info.end_time.ToInternalValue());
     statement_insert.BindInt(column++, info.opened ? 1 : 0);
+    statement_insert.BindString(column++, info.referrer_url.spec());
     if (!statement_insert.Run()) {
       // GetErrorCode() returns a bitmask where the lower byte is a more general
       // code and the upper byte is a more specific code. In order to save
diff --git a/chrome/browser/history/download_database.h b/chrome/browser/history/download_database.h
index afb5fd0..ef85279 100644
--- a/chrome/browser/history/download_database.h
+++ b/chrome/browser/history/download_database.h
@@ -67,6 +67,10 @@
   // two target paths to downloads.
   bool MigrateDownloadsReasonPathsAndDangerType();
 
+  // Returns true if able to successfully add the referrer column to the
+  // downloads table.
+  bool MigrateReferrer();
+
   // Creates the downloads table if needed.
   bool InitDownloadTable();
 
diff --git a/chrome/browser/history/download_row.h b/chrome/browser/history/download_row.h
index 2f8b63b..7e91655 100644
--- a/chrome/browser/history/download_row.h
+++ b/chrome/browser/history/download_row.h
@@ -8,11 +8,11 @@
 #include <vector>
 
 #include "base/files/file_path.h"
-#include "base/time.h"
+#include "base/time/time.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 "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 namespace history {
 
diff --git a/chrome/browser/history/expire_history_backend.cc b/chrome/browser/history/expire_history_backend.cc
index 6652aca..4e46a2e 100644
--- a/chrome/browser/history/expire_history_backend.cc
+++ b/chrome/browser/history/expire_history_backend.cc
@@ -382,11 +382,9 @@
     if (!thumb_db_->HasMappingFor(*i)) {
       GURL icon_url;
       chrome::IconType icon_type;
-      FaviconSizes favicon_sizes;
       if (thumb_db_->GetFaviconHeader(*i,
                                       &icon_url,
-                                      &icon_type,
-                                      &favicon_sizes) &&
+                                      &icon_type) &&
           thumb_db_->DeleteFavicon(*i)) {
         expired_favicons->insert(icon_url);
       }
@@ -762,7 +760,7 @@
        file = file_enumerator.Next()) {
     TextDatabase::DBIdent file_id = TextDatabase::FileNameToID(file);
     if (file_id < cutoff_id)
-      file_util::Delete(file, false);
+      sql::Connection::Delete(file);
   }
 }
 
diff --git a/chrome/browser/history/expire_history_backend.h b/chrome/browser/history/expire_history_backend.h
index a7e8cdd..626ad12 100644
--- a/chrome/browser/history/expire_history_backend.h
+++ b/chrome/browser/history/expire_history_backend.h
@@ -13,7 +13,7 @@
 #include "base/gtest_prod_util.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/history/history_types.h"
 
 class BookmarkService;
diff --git a/chrome/browser/history/expire_history_backend_unittest.cc b/chrome/browser/history/expire_history_backend_unittest.cc
index 37155bb..415d6b2 100644
--- a/chrome/browser/history/expire_history_backend_unittest.cc
+++ b/chrome/browser/history/expire_history_backend_unittest.cc
@@ -211,9 +211,9 @@
   // Two favicons. The first two URLs will share the same one, while the last
   // one will have a unique favicon.
   chrome::FaviconID favicon1 = thumb_db_->AddFavicon(
-      GURL("http://favicon/url1"), chrome::FAVICON, GetDefaultFaviconSizes());
+      GURL("http://favicon/url1"), chrome::FAVICON);
   chrome::FaviconID favicon2 = thumb_db_->AddFavicon(
-      GURL("http://favicon/url2"), chrome::FAVICON, GetDefaultFaviconSizes());
+      GURL("http://favicon/url2"), chrome::FAVICON);
 
   // Three URLs.
   URLRow url_row1(GURL("http://www.google.com/1"));
@@ -325,7 +325,7 @@
 bool ExpireHistoryTest::HasFavicon(chrome::FaviconID favicon_id) {
   if (!thumb_db_.get() || favicon_id == 0)
     return false;
-  return thumb_db_->GetFaviconHeader(favicon_id, NULL, NULL, NULL);
+  return thumb_db_->GetFaviconHeader(favicon_id, NULL, NULL);
 }
 
 chrome::FaviconID ExpireHistoryTest::GetFavicon(const GURL& page_url,
@@ -410,7 +410,7 @@
   // Add a favicon record.
   const GURL favicon_url("http://www.google.com/favicon.ico");
   chrome::FaviconID icon_id = thumb_db_->AddFavicon(
-      favicon_url, chrome::FAVICON, GetDefaultFaviconSizes());
+      favicon_url, chrome::FAVICON);
   EXPECT_TRUE(icon_id);
   EXPECT_TRUE(HasFavicon(icon_id));
 
@@ -425,7 +425,7 @@
 
   // Add back the favicon.
   icon_id = thumb_db_->AddFavicon(
-      favicon_url, chrome::TOUCH_ICON, GetDefaultFaviconSizes());
+      favicon_url, chrome::TOUCH_ICON);
   EXPECT_TRUE(icon_id);
   EXPECT_TRUE(HasFavicon(icon_id));
 
diff --git a/chrome/browser/history/history_backend.cc b/chrome/browser/history/history_backend.cc
index 614d93a..ed1419c 100644
--- a/chrome/browser/history/history_backend.cc
+++ b/chrome/browser/history/history_backend.cc
@@ -14,7 +14,6 @@
 #include "base/basictypes.h"
 #include "base/bind.h"
 #include "base/compiler_specific.h"
-#include "base/file_util.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/scoped_vector.h"
 #include "base/message_loop.h"
@@ -22,11 +21,10 @@
 #include "base/rand_util.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/autocomplete/history_url_provider.h"
 #include "chrome/browser/bookmarks/bookmark_service.h"
 #include "chrome/browser/favicon/favicon_changed_details.h"
-#include "chrome/browser/favicon/imported_favicon_usage.h"
 #include "chrome/browser/history/download_row.h"
 #include "chrome/browser/history/history_db_task.h"
 #include "chrome/browser/history/history_notifications.h"
@@ -39,12 +37,13 @@
 #include "chrome/browser/history/visit_filter.h"
 #include "chrome/common/chrome_constants.h"
 #include "chrome/common/chrome_notification_types.h"
+#include "chrome/common/importer/imported_favicon_usage.h"
 #include "chrome/common/url_constants.h"
-#include "googleurl/src/gurl.h"
 #include "grit/chromium_strings.h"
 #include "grit/generated_resources.h"
 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
 #include "sql/error_delegate_util.h"
+#include "url/gurl.h"
 
 #if defined(OS_ANDROID)
 #include "chrome/browser/history/android/android_provider_backend.h"
@@ -103,6 +102,11 @@
 // and is archived.
 static const int kArchiveDaysThreshold = 90;
 
+#if defined(OS_ANDROID)
+// The maximum number of top sites to track when recording top page visit stats.
+static const size_t kPageVisitStatsMaxTopSites = 50;
+#endif
+
 // Converts from PageUsageData to MostVisitedURL. |redirects| is a
 // list of redirects for this URL. Empty list means no redirects.
 MostVisitedURL MakeMostVisitedURL(const PageUsageData& page_data,
@@ -247,7 +251,7 @@
   }
 
 #if defined(OS_ANDROID)
-  file_util::Delete(GetAndroidCacheFileName(), false);
+  sql::Connection::Delete(GetAndroidCacheFileName());
 #endif
 }
 
@@ -256,6 +260,9 @@
     InitImpl(languages);
   delegate_->DBLoaded(id_);
   typed_url_syncable_service_.reset(new TypedUrlSyncableService(this));
+#if defined(OS_ANDROID)
+  PopulateMostVisitedURLMap();
+#endif
 }
 
 void HistoryBackend::SetOnBackendDestroyTask(base::MessageLoop* message_loop,
@@ -706,7 +713,7 @@
     // See needs_version_17_migration() decl for more. In this case, we want
     // to delete the archived database and need to do so before we try to
     // open the file. We can ignore any error (maybe the file doesn't exist).
-    file_util::Delete(archived_name, false);
+    sql::Connection::Delete(archived_name);
   }
   archived_db_.reset(new ArchivedDatabase());
   if (!archived_db_->Init(archived_name)) {
@@ -800,6 +807,15 @@
       transition_type == content::PAGE_TRANSITION_KEYWORD_GENERATED)
     typed_increment = 1;
 
+#if defined(OS_ANDROID)
+  // Only count the page visit if it came from user browsing and only count it
+  // once when cycling through a redirect chain.
+  if (visit_source == SOURCE_BROWSED &&
+      (transition & content::PAGE_TRANSITION_CHAIN_END) != 0) {
+    RecordTopPageVisitStats(url);
+  }
+#endif
+
   // See if this URL is already in the DB.
   URLRow url_info(url);
   URLID url_id = db_->GetRowForURL(url, &url_info);
@@ -1358,8 +1374,14 @@
       // if (archived_db_.get() &&
       //     expirer_.GetCurrentArchiveTime() - TimeDelta::FromDays(7)) {
     } else {
-      // Full text history query.
-      QueryHistoryFTS(text_query, options, &request->value);
+      // Text history query.
+      QueryHistoryText(db_.get(), db_.get(), text_query, options,
+                       &request->value);
+      if (archived_db_.get() &&
+          expirer_.GetCurrentArchiveTime() >= options.begin_time) {
+        QueryHistoryText(archived_db_.get(), archived_db_.get(), text_query,
+                         options, &request->value);
+      }
     }
   }
 
@@ -1424,6 +1446,43 @@
     result->set_reached_beginning(true);
 }
 
+// Text-based querying of history.
+void HistoryBackend::QueryHistoryText(URLDatabase* url_db,
+                                      VisitDatabase* visit_db,
+                                      const string16& text_query,
+                                      const QueryOptions& options,
+                                      QueryResults* result) {
+  URLRows text_matches;
+  url_db->GetTextMatches(text_query, &text_matches);
+
+  std::vector<URLResult> matching_visits;
+  VisitVector visits;    // Declare outside loop to prevent re-construction.
+  for (size_t i = 0; i < text_matches.size(); i++) {
+    const URLRow& text_match = text_matches[i];
+    // Get all visits for given URL match.
+    visit_db->GetVisitsForURLWithOptions(text_match.id(), options, &visits);
+    for (size_t j = 0; j < visits.size(); j++) {
+      URLResult url_result(text_match);
+      url_result.set_visit_time(visits[j].visit_time);
+      matching_visits.push_back(url_result);
+    }
+  }
+
+  std::sort(matching_visits.begin(), matching_visits.end(),
+            URLResult::CompareVisitTime);
+
+  size_t max_results = options.max_count == 0 ?
+      std::numeric_limits<size_t>::max() : static_cast<int>(options.max_count);
+  for (std::vector<URLResult>::iterator it = matching_visits.begin();
+       it != matching_visits.end() && result->size() < max_results; ++it) {
+    result->AppendURLBySwapping(&(*it));
+  }
+
+  if (matching_visits.size() == result->size() &&
+      options.begin_time <= first_recorded_time_)
+    result->set_reached_beginning(true);
+}
+
 void HistoryBackend::QueryHistoryFTS(const string16& text_query,
                                      const QueryOptions& options,
                                      QueryResults* result) {
@@ -1923,8 +1982,7 @@
 
   if (!favicon_id) {
     // There is no favicon at |icon_url|, create it.
-    favicon_id = thumbnail_db_->AddFavicon(icon_url, icon_type,
-                                           GetDefaultFaviconSizes());
+    favicon_id = thumbnail_db_->AddFavicon(icon_url, icon_type);
   }
 
   std::vector<FaviconBitmapIDSize> bitmap_id_sizes;
@@ -2083,8 +2141,7 @@
     if (!icon_id) {
       // TODO(pkotwicz): Remove the favicon sizes attribute from
       // ThumbnailDatabase::AddFavicon().
-      icon_id = thumbnail_db_->AddFavicon(icon_url, icon_type,
-                                          GetDefaultFaviconSizes());
+      icon_id = thumbnail_db_->AddFavicon(icon_url, icon_type);
       data_modified = true;
     }
     icon_ids.push_back(icon_id);
@@ -2153,7 +2210,6 @@
       favicon_id = thumbnail_db_->AddFavicon(
           favicon_usage[i].favicon_url,
           chrome::FAVICON,
-          GetDefaultFaviconSizes(),
           new base::RefCountedBytes(favicon_usage[i].png_data),
           now,
           gfx::Size());
@@ -2438,7 +2494,7 @@
   GURL icon_url;
   chrome::IconType icon_type;
   if (!thumbnail_db_->GetFaviconHeader(best_favicon_id, &icon_url,
-                                       &icon_type, NULL)) {
+                                       &icon_type)) {
     return false;
   }
 
@@ -2934,7 +2990,7 @@
     // Close the database and delete the file.
     archived_db_.reset();
     base::FilePath archived_file_name = GetArchivedFileName();
-    file_util::Delete(archived_file_name, false);
+    sql::Connection::Delete(archived_file_name);
 
     // Now re-initialize the database (which may fail).
     archived_db_.reset(new ArchivedDatabase());
@@ -2963,7 +3019,7 @@
     // error opening it. In this case, we just try to blow it away to try to
     // fix the error if it exists. This may fail, in which case either the
     // file doesn't exist or there's no more we can do.
-    file_util::Delete(GetThumbnailFileName(), false);
+    sql::Connection::Delete(GetThumbnailFileName());
     return true;
   }
 
@@ -3074,4 +3130,28 @@
     delegate_->NotifyVisitDBObserversOnAddVisit(info);
 }
 
+#if defined(OS_ANDROID)
+void HistoryBackend::PopulateMostVisitedURLMap() {
+  MostVisitedURLList most_visited_urls;
+  QueryMostVisitedURLsImpl(kPageVisitStatsMaxTopSites, kSegmentDataRetention,
+                           &most_visited_urls);
+
+  DCHECK_LE(most_visited_urls.size(), kPageVisitStatsMaxTopSites);
+  for (size_t i = 0; i < most_visited_urls.size(); ++i) {
+    most_visited_urls_map_[most_visited_urls[i].url] = i;
+    for (size_t j = 0; j < most_visited_urls[i].redirects.size(); ++j)
+      most_visited_urls_map_[most_visited_urls[i].redirects[j]] = i;
+  }
+}
+
+void HistoryBackend::RecordTopPageVisitStats(const GURL& url) {
+  int rank = kPageVisitStatsMaxTopSites;
+  std::map<GURL, int>::const_iterator it = most_visited_urls_map_.find(url);
+  if (it != most_visited_urls_map_.end())
+    rank = (*it).second;
+  UMA_HISTOGRAM_ENUMERATION("History.TopSitesVisitsByRank",
+                            rank, kPageVisitStatsMaxTopSites + 1);
+}
+#endif
+
 }  // namespace history
diff --git a/chrome/browser/history/history_backend.h b/chrome/browser/history/history_backend.h
index a55d6eb..188847b 100644
--- a/chrome/browser/history/history_backend.h
+++ b/chrome/browser/history/history_backend.h
@@ -578,6 +578,18 @@
 #if defined(OS_ANDROID)
   // Returns the name of android cache database.
   base::FilePath GetAndroidCacheFileName() const;
+
+  // Populate a map from a |MostVisitedURLList|. The map assigns a rank to each
+  // top URL and its redirects. This should only be done once at backend
+  // initialization.
+  // This can be removed for M31. (See issue 248761.)
+
+  void PopulateMostVisitedURLMap();
+  // Record counts of page visits by rank. If a url is not ranked, record the
+  // page visit in a slot corresponding to |max_top_url_count|, which should
+  // be one greater than the largest rank of any url in |top_urls|.
+  // This can be removed for M31. (See issue 248761.)
+  void RecordTopPageVisitStats(const GURL& url);
 #endif
 
   class URLQuerier;
@@ -629,12 +641,18 @@
 
   // Querying ------------------------------------------------------------------
 
-  // Backends for QueryHistory. *Basic() handles queries that are not FTS (full
-  // text search) queries and can just be given directly to the history DB).
-  // The FTS version queries the text_database, then merges with the history DB.
+  // Backends for QueryHistory. *Basic() handles queries that are not
+  // text search queries and can just be given directly to the history DB.
+  // The *Text() version performs a brute force query of the history DB to
+  // search for results which match the given text query.
   // Both functions assume QueryHistory already checked the DB for validity.
   void QueryHistoryBasic(URLDatabase* url_db, VisitDatabase* visit_db,
                          const QueryOptions& options, QueryResults* result);
+  void QueryHistoryText(URLDatabase* url_db,
+                        VisitDatabase* visit_db,
+                        const string16& text_query,
+                        const QueryOptions& options,
+                        QueryResults* result);
   void QueryHistoryFTS(const string16& text_query,
                        const QueryOptions& options,
                        QueryResults* result);
@@ -909,6 +927,12 @@
 #if defined(OS_ANDROID)
   // Used to provide the Android ContentProvider APIs.
   scoped_ptr<AndroidProviderBackend> android_provider_backend_;
+
+  // Used to provide UMA on the number of page visits that are to the most
+  // visited URLs. This is here because the backend both has access to this
+  // information and is notified of page visits. The top sites service should
+  // be used instead whenever possible.
+  std::map<GURL, int> most_visited_urls_map_;
 #endif
 
   // Used to manage syncing of the typed urls datatype. This will be NULL
diff --git a/chrome/browser/history/history_backend_unittest.cc b/chrome/browser/history/history_backend_unittest.cc
index faf15f4..75b426b 100644
--- a/chrome/browser/history/history_backend_unittest.cc
+++ b/chrome/browser/history/history_backend_unittest.cc
@@ -21,7 +21,6 @@
 #include "chrome/browser/bookmarks/bookmark_model.h"
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
 #include "chrome/browser/bookmarks/bookmark_utils.h"
-#include "chrome/browser/favicon/imported_favicon_usage.h"
 #include "chrome/browser/history/history_backend.h"
 #include "chrome/browser/history/history_notifications.h"
 #include "chrome/browser/history/history_service.h"
@@ -32,6 +31,7 @@
 #include "chrome/common/chrome_constants.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/chrome_switches.h"
+#include "chrome/common/importer/imported_favicon_usage.h"
 #include "chrome/common/thumbnail_score.h"
 #include "chrome/test/base/testing_profile.h"
 #include "chrome/test/base/ui_test_utils.h"
@@ -39,11 +39,11 @@
 #include "content/public/browser/notification_details.h"
 #include "content/public/browser/notification_source.h"
 #include "content/public/test/test_browser_thread.h"
-#include "googleurl/src/gurl.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/gfx/codec/jpeg_codec.h"
 #include "ui/gfx/image/image.h"
+#include "url/gurl.h"
 
 using base::Time;
 using base::TimeDelta;
@@ -75,7 +75,7 @@
   return a.pixel_size.GetArea() < b.pixel_size.GetArea();
 }
 
-}  // namepace
+}  // namespace
 
 namespace history {
 
@@ -391,7 +391,8 @@
       backend_->Closing();
     backend_ = NULL;
     mem_backend_.reset();
-    file_util::Delete(test_dir_, true);
+    base::Delete(test_dir_, true);
+    base::RunLoop().RunUntilIdle();
   }
 
   void SetInMemoryBackend(int backend_id, InMemoryHistoryBackend* backend) {
@@ -460,9 +461,9 @@
   GURL favicon_url1("http://www.google.com/favicon.ico");
   GURL favicon_url2("http://news.google.com/favicon.ico");
   chrome::FaviconID favicon2 = backend_->thumbnail_db_->AddFavicon(favicon_url2,
-      chrome::FAVICON, GetSizesSmallAndLarge());
+      chrome::FAVICON);
   chrome::FaviconID favicon1 = backend_->thumbnail_db_->AddFavicon(favicon_url1,
-      chrome::FAVICON, GetSizesSmallAndLarge());
+      chrome::FAVICON);
 
   std::vector<unsigned char> data;
   data.push_back('a');
@@ -688,7 +689,6 @@
   chrome::FaviconID favicon1 = backend_->thumbnail_db_->AddFavicon(
       favicon_url1,
       chrome::FAVICON,
-      GetDefaultFaviconSizes(),
       new base::RefCountedBytes(data),
       Time::Now(),
       gfx::Size());
@@ -697,7 +697,6 @@
   chrome::FaviconID favicon2 = backend_->thumbnail_db_->AddFavicon(
       favicon_url2,
       chrome::FAVICON,
-      GetDefaultFaviconSizes(),
       new base::RefCountedBytes(data),
       Time::Now(),
       gfx::Size());
@@ -870,7 +869,6 @@
   chrome::FaviconID favicon1 = backend_->thumbnail_db_->AddFavicon(
       favicon_url1,
       chrome::FAVICON,
-      GetDefaultFaviconSizes(),
       base::RefCountedBytes::TakeVector(&data),
       Time::Now(),
       gfx::Size());
@@ -1277,7 +1275,7 @@
   // Copy history database file to current directory so that it will be deleted
   // in Teardown.
   base::FilePath new_history_path(getTestDir());
-  file_util::Delete(new_history_path, true);
+  base::Delete(new_history_path, true);
   file_util::CreateDirectory(new_history_path);
   base::FilePath new_history_file =
       new_history_path.Append(chrome::kHistoryFilename);
@@ -2072,7 +2070,7 @@
   const GURL icon_url("http://www.google.com/icon1");
 
   chrome::FaviconID icon_id = backend_->thumbnail_db_->AddFavicon(
-      icon_url, chrome::FAVICON, GetSizesSmallAndLarge());
+      icon_url, chrome::FAVICON);
   EXPECT_NE(0, icon_id);
   EXPECT_NE(0, backend_->thumbnail_db_->AddIconMapping(page_url, icon_id));
 
@@ -2197,7 +2195,6 @@
   chrome::FaviconID icon_id =
       backend_->thumbnail_db_->AddFavicon(icon_url,
                                           chrome::FAVICON,
-                                          GetSizesSmallAndLarge(),
                                           bitmap_data,
                                           last_updated,
                                           kSmallSize);
@@ -2517,7 +2514,7 @@
   // Copy history database file to current directory so that it will be deleted
   // in Teardown.
   base::FilePath new_history_path(getTestDir());
-  file_util::Delete(new_history_path, true);
+  base::Delete(new_history_path, true);
   file_util::CreateDirectory(new_history_path);
   base::FilePath new_history_file =
       new_history_path.Append(chrome::kHistoryFilename);
diff --git a/chrome/browser/history/history_browsertest.cc b/chrome/browser/history/history_browsertest.cc
index a7831ff..a563511 100644
--- a/chrome/browser/history/history_browsertest.cc
+++ b/chrome/browser/history/history_browsertest.cc
@@ -25,7 +25,7 @@
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/test_browser_thread.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 using content::BrowserThread;
 
diff --git a/chrome/browser/history/history_database.cc b/chrome/browser/history/history_database.cc
index 9be2f15..4c49ee8 100644
--- a/chrome/browser/history/history_database.cc
+++ b/chrome/browser/history/history_database.cc
@@ -13,7 +13,7 @@
 #include "base/metrics/histogram.h"
 #include "base/rand_util.h"
 #include "base/strings/string_util.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "sql/transaction.h"
 
 #if defined(OS_MACOSX)
@@ -27,7 +27,7 @@
 // Current version number. We write databases at the "current" version number,
 // but any previous version that can read the "compatible" one can make do with
 // or database without *too* many bad effects.
-static const int kCurrentVersionNumber = 25;
+static const int kCurrentVersionNumber = 26;
 static const int kCompatibleVersionNumber = 16;
 static const char kEarlyExpirationThresholdKey[] = "early_expiration_threshold";
 
@@ -56,11 +56,11 @@
   // this is a NOP. Must be a power of 2 and a max of 8192.
   db_.set_page_size(4096);
 
-  // Increase the cache size. The page size, plus a little extra, times this
+  // Set the cache size. The page size, plus a little extra, times this
   // value, tells us how much memory the cache will use maximum.
-  // 6000 * 4MB = 24MB
+  // 1000 * 4kB = 4MB
   // TODO(brettw) scale this value to the amount of available memory.
-  db_.set_cache_size(6000);
+  db_.set_cache_size(1000);
 
   // Note that we don't set exclusive locking here. That's done by
   // BeginExclusiveMode below which is called later (we have to be in shared
@@ -418,6 +418,15 @@
     meta_table_.SetVersionNumber(cur_version);
   }
 
+  if (cur_version == 25) {
+    if (!MigrateReferrer()) {
+      LOG(WARNING) << "Unable to migrate history to version 26";
+      return sql::INIT_FAILURE;
+    }
+    cur_version++;
+    meta_table_.SetVersionNumber(cur_version);
+  }
+
   // When the version is too old, we just try to continue anyway, there should
   // not be a released product that makes a database too old for us to handle.
   LOG_IF(WARNING, cur_version < GetCurrentVersion()) <<
diff --git a/chrome/browser/history/history_database_unittest.cc b/chrome/browser/history/history_database_unittest.cc
index 67f7290..45832d4 100644
--- a/chrome/browser/history/history_database_unittest.cc
+++ b/chrome/browser/history/history_database_unittest.cc
@@ -20,7 +20,7 @@
 
   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
   db_file = temp_dir.path().AppendASCII("DropBookmarks.db");
-  file_util::Delete(db_file, false);
+  sql::Connection::Delete(db_file);
 
   // Copy db file over that contains starred URLs.
   base::FilePath old_history_path;
diff --git a/chrome/browser/history/history_notifications.h b/chrome/browser/history/history_notifications.h
index afe48f1..2f596e8 100644
--- a/chrome/browser/history/history_notifications.h
+++ b/chrome/browser/history/history_notifications.h
@@ -12,7 +12,7 @@
 #include "chrome/browser/history/history_details.h"
 #include "chrome/browser/history/history_types.h"
 #include "chrome/browser/search_engines/template_url_id.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 namespace history {
 
diff --git a/chrome/browser/history/history_publisher_none.cc b/chrome/browser/history/history_publisher_none.cc
index 956f1f5..ddf75fc 100644
--- a/chrome/browser/history/history_publisher_none.cc
+++ b/chrome/browser/history/history_publisher_none.cc
@@ -8,7 +8,7 @@
 
 #include "chrome/browser/history/history_publisher.h"
 
-#include "base/time.h"
+#include "base/time/time.h"
 
 namespace history {
 
diff --git a/chrome/browser/history/history_publisher_win.cc b/chrome/browser/history/history_publisher_win.cc
index 37b32bf..e6178b5 100644
--- a/chrome/browser/history/history_publisher_win.cc
+++ b/chrome/browser/history/history_publisher_win.cc
@@ -10,12 +10,12 @@
 
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "base/win/registry.h"
 #include "base/win/scoped_bstr.h"
 #include "base/win/scoped_comptr.h"
 #include "base/win/scoped_variant.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 namespace {
 
diff --git a/chrome/browser/history/history_querying_unittest.cc b/chrome/browser/history/history_querying_unittest.cc
index 4719b90..aa69fc4 100644
--- a/chrome/browser/history/history_querying_unittest.cc
+++ b/chrome/browser/history/history_querying_unittest.cc
@@ -26,29 +26,25 @@
   const char* url;
   const char* title;
   const int days_ago;
-  const char* body;
   Time time;  // Filled by SetUp.
 } test_entries[] = {
   // This one is visited super long ago so it will be in a different database
   // from the next appearance of it at the end.
-  {"http://example.com/", "Other", 180, "Other"},
+  {"http://example.com/", "Other", 180},
 
   // These are deliberately added out of chronological order. The history
   // service should sort them by visit time when returning query results.
   // The correct index sort order is 4 2 3 1 7 6 5 0.
-  {"http://www.google.com/1", "Title 1", 10,
-   "PAGEONE FOO some body text"},
-  {"http://www.google.com/3", "Title 3", 8,
-   "PAGETHREE BAR some hello world for you"},
-  {"http://www.google.com/2", "Title 2", 9,
-   "PAGETWO FOO some more blah blah blah Title"},
+  {"http://www.google.com/1", "Title PAGEONE FOO some text", 10},
+  {"http://www.google.com/3", "Title PAGETHREE BAR some hello world", 8},
+  {"http://www.google.com/2", "Title PAGETWO FOO some more blah blah blah", 9},
 
   // A more recent visit of the first one.
-  {"http://example.com/", "Other", 6, "Other"},
+  {"http://example.com/", "Other", 6},
 
-  {"http://www.google.com/6", "Title 6", 13, "I'm the second oldest"},
-  {"http://www.google.com/4", "Title 4", 12, "four"},
-  {"http://www.google.com/5", "Title 5", 11, "five"},
+  {"http://www.google.com/6", "Title I'm the second oldest", 13},
+  {"http://www.google.com/4", "Title four", 12},
+  {"http://www.google.com/5", "Title five", 11},
 };
 
 // Returns true if the nth result in the given results set matches. It will
@@ -91,8 +87,8 @@
   }
 
   // Test paging through results, with a fixed number of results per page.
-  // Defined here so code can be shared for the FTS version and the non-FTS
-  // version.
+  // Defined here so code can be shared for the text search and the non-text
+  // seach versions.
   void TestPaging(const std::string& query_text,
                   const int* expected_results,
                   int results_length) {
@@ -125,10 +121,10 @@
     }
 
     // Add a couple of entries with duplicate timestamps. Use |query_text| as
-    // the body of both entries so that they match a full-text query.
+    // the title of both entries so that they match a text query.
     TestEntry duplicates[] = {
-      { "http://www.google.com/x", "", 1, query_text.c_str() },
-      { "http://www.google.com/y", "", 1, query_text.c_str() }
+      { "http://www.google.com/x",  query_text.c_str(), 1, },
+      { "http://www.google.com/y",  query_text.c_str(), 1, }
     };
     AddEntryToHistory(duplicates[0]);
     AddEntryToHistory(duplicates[1]);
@@ -157,7 +153,6 @@
                       history::RedirectList(), content::PAGE_TRANSITION_LINK,
                       history::SOURCE_BROWSED, false);
     history_->SetPageTitle(url, UTF8ToUTF16(entry.title));
-    history_->SetPageContents(url, UTF8ToUTF16(entry.body));
   }
 
  private:
@@ -313,14 +308,13 @@
   EXPECT_TRUE(results.reached_beginning());
   options.max_count = results.size();
   QueryHistory("some", options, &results);
-  // Since the query didn't cover the oldest visit in the database, we
-  // expect false here.
-  EXPECT_FALSE(results.reached_beginning());
+  EXPECT_TRUE(results.reached_beginning());
 }
 
-// This does most of the same tests above, but searches for a FTS string that
-// will match the pages in question. This will trigger a different code path.
-TEST_F(HistoryQueryTest, FTS) {
+// This does most of the same tests above, but performs a text searches for a
+// string that will match the pages in question. This will trigger a
+// different code path.
+TEST_F(HistoryQueryTest, TextSearch) {
   ASSERT_TRUE(history_.get());
 
   QueryOptions options;
@@ -349,33 +343,8 @@
   EXPECT_TRUE(NthResultIs(results, 0, 1));
 }
 
-// Searches titles.
-TEST_F(HistoryQueryTest, FTSTitle) {
-  ASSERT_TRUE(history_.get());
-
-  QueryOptions options;
-  QueryResults results;
-
-  // First execute a body-only query, to ensure that it works and that that
-  // version of the statement is not cached for the next query.
-  options.body_only = true;
-  QueryHistory("Title", options, &results);
-  EXPECT_EQ(1U, results.size());
-  EXPECT_TRUE(NthResultIs(results, 0, 3));
-  options.body_only = false;
-
-  // Query all time but with a limit on the number of entries. We should
-  // get the N most recent entries.
-  options.max_count = 3;
-  QueryHistory("title", options, &results);
-  EXPECT_EQ(3U, results.size());
-  EXPECT_TRUE(NthResultIs(results, 0, 2));
-  EXPECT_TRUE(NthResultIs(results, 1, 3));
-  EXPECT_TRUE(NthResultIs(results, 2, 1));
-}
-
-// Tests prefix searching for Full Text Search queries.
-TEST_F(HistoryQueryTest, FTSPrefix) {
+// Tests prefix searching for text search queries.
+TEST_F(HistoryQueryTest, TextSearchPrefix) {
   ASSERT_TRUE(history_.get());
 
   QueryOptions options;
@@ -389,8 +358,8 @@
   EXPECT_TRUE(NthResultIs(results, 1, 3));
 }
 
-// Tests max_count feature for Full Text Search queries.
-TEST_F(HistoryQueryTest, FTSCount) {
+// Tests max_count feature for text search queries.
+TEST_F(HistoryQueryTest, TextSearchCount) {
   ASSERT_TRUE(history_.get());
 
   QueryOptions options;
@@ -413,21 +382,21 @@
   EXPECT_TRUE(NthResultIs(results, 0, 3));
 }
 
-// Tests that FTS queries can find URLs when they exist only in the archived
-// database. This also tests that imported URLs can be found, since we use
-// AddPageWithDetails just like the importer.
-TEST_F(HistoryQueryTest, FTSArchived) {
+// Tests that text search queries can find URLs when they exist only in the
+// archived database. This also tests that imported URLs can be found, since
+// we use AddPageWithDetails just like the importer.
+TEST_F(HistoryQueryTest, TextSearchArchived) {
   ASSERT_TRUE(history_.get());
 
   URLRows urls_to_add;
 
   URLRow row1(GURL("http://foo.bar/"));
-  row1.set_title(UTF8ToUTF16("archived title"));
+  row1.set_title(UTF8ToUTF16("archived title same"));
   row1.set_last_visit(Time::Now() - TimeDelta::FromDays(365));
   urls_to_add.push_back(row1);
 
   URLRow row2(GURL("http://foo.bar/"));
-  row2.set_title(UTF8ToUTF16("nonarchived title"));
+  row2.set_title(UTF8ToUTF16("nonarchived title same"));
   row2.set_last_visit(Time::Now());
   urls_to_add.push_back(row2);
 
@@ -436,13 +405,22 @@
   QueryOptions options;
   QueryResults results;
 
-  // Query all time. The title we get should be the one in the full text
-  // database and not the most current title (since otherwise highlighting in
+  // Query all time. The title we get should be the one in the archived and
+  // not the most current title (since otherwise highlighting in
   // the title might be wrong).
   QueryHistory("archived", options, &results);
   ASSERT_EQ(1U, results.size());
   EXPECT_TRUE(row1.url() == results[0].url());
   EXPECT_TRUE(row1.title() == results[0].title());
+
+  // Check query is ordered correctly when split between archived and
+  // non-archived database.
+  QueryHistory("same", options, &results);
+  ASSERT_EQ(2U, results.size());
+  EXPECT_TRUE(row2.url() == results[0].url());
+  EXPECT_TRUE(row2.title() == results[0].title());
+  EXPECT_TRUE(row1.url() == results[1].url());
+  EXPECT_TRUE(row1.title() == results[1].title());
 }
 
 /* TODO(brettw) re-enable this. It is commented out because the current history
@@ -451,15 +429,15 @@
    won't get picked up by the deletor and it can happen again. When this is the
    case, we should fix this test to duplicate that situation.
 
-// Tests duplicate collapsing and not in Full Text Search situations.
-TEST_F(HistoryQueryTest, FTSDupes) {
+// Tests duplicate collapsing and not in text search situations.
+TEST_F(HistoryQueryTest, TextSearchDupes) {
   ASSERT_TRUE(history_.get());
 
   QueryOptions options;
   QueryResults results;
 
   QueryHistory("Other", options, &results);
-  EXPECT_EQ(1, results.urls().size());
+  EXPECT_EQ(1U, results.size());
   EXPECT_TRUE(NthResultIs(results, 0, 4));
 }
 */
@@ -472,7 +450,7 @@
   TestPaging(std::string(), expected_results, arraysize(expected_results));
 }
 
-TEST_F(HistoryQueryTest, FTSPaging) {
+TEST_F(HistoryQueryTest, TextSearchPaging) {
   // Since results are fetched 1 and 2 at a time, entry #0 and #6 will not
   // be de-duplicated. Entry #4 does not contain the text "title", so it
   // shouldn't appear.
diff --git a/chrome/browser/history/history_service.cc b/chrome/browser/history/history_service.cc
index 1e4361a..49e4b07 100644
--- a/chrome/browser/history/history_service.cc
+++ b/chrome/browser/history/history_service.cc
@@ -35,12 +35,11 @@
 #include "base/prefs/pref_service.h"
 #include "base/thread_task_runner_handle.h"
 #include "base/threading/thread.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/autocomplete/history_url_provider.h"
 #include "chrome/browser/bookmarks/bookmark_model.h"
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
 #include "chrome/browser/browser_process.h"
-#include "chrome/browser/favicon/imported_favicon_usage.h"
 #include "chrome/browser/history/download_row.h"
 #include "chrome/browser/history/history_backend.h"
 #include "chrome/browser/history/history_notifications.h"
@@ -58,6 +57,7 @@
 #include "chrome/common/chrome_constants.h"
 #include "chrome/common/chrome_notification_types.h"
 #include "chrome/common/chrome_switches.h"
+#include "chrome/common/importer/imported_favicon_usage.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/thumbnail_score.h"
 #include "chrome/common/url_constants.h"
@@ -155,10 +155,11 @@
   virtual void SetInMemoryBackend(int backend_id,
       history::InMemoryHistoryBackend* backend) OVERRIDE {
     // Send the backend to the history service on the main thread.
+    scoped_ptr<history::InMemoryHistoryBackend> in_memory_backend(backend);
     service_task_runner_->PostTask(
         FROM_HERE,
         base::Bind(&HistoryService::SetInMemoryBackend, history_service_,
-                   backend_id, backend));
+                   backend_id, base::Passed(&in_memory_backend)));
   }
 
   virtual void BroadcastNotifications(
@@ -1076,17 +1077,16 @@
       delete_directive);
 }
 
-void HistoryService::SetInMemoryBackend(int backend_id,
-    history::InMemoryHistoryBackend* mem_backend) {
+void HistoryService::SetInMemoryBackend(
+    int backend_id, scoped_ptr<history::InMemoryHistoryBackend> mem_backend) {
   DCHECK(thread_checker_.CalledOnValidThread());
   if (!history_backend_.get() || current_backend_id_ != backend_id) {
     DVLOG(1) << "Message from obsolete backend";
-    // Cleaning up the memory backend.
-    delete mem_backend;
+    // mem_backend is deleted.
     return;
   }
   DCHECK(!in_memory_backend_) << "Setting mem DB twice";
-  in_memory_backend_.reset(mem_backend);
+  in_memory_backend_.reset(mem_backend.release());
 
   // The database requires additional initialization once we own it.
   in_memory_backend_->AttachToHistoryService(profile_);
diff --git a/chrome/browser/history/history_service.h b/chrome/browser/history/history_service.h
index 2a0cb81..885c75c 100644
--- a/chrome/browser/history/history_service.h
+++ b/chrome/browser/history/history_service.h
@@ -19,7 +19,7 @@
 #include "base/observer_list.h"
 #include "base/strings/string16.h"
 #include "base/threading/thread_checker.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/common/cancelable_request.h"
 #include "chrome/browser/favicon/favicon_service.h"
 #include "chrome/browser/history/delete_directive_handler.h"
@@ -831,8 +831,9 @@
 
   // Sets the in-memory URL database. This is called by the backend once the
   // database is loaded to make it available.
-  void SetInMemoryBackend(int backend_id,
-                          history::InMemoryHistoryBackend* mem_backend);
+  void SetInMemoryBackend(
+      int backend_id,
+      scoped_ptr<history::InMemoryHistoryBackend> mem_backend);
 
   // Called by our BackendDelegate when there is a problem reading the database.
   void NotifyProfileError(int backend_id, sql::InitStatus init_status);
diff --git a/chrome/browser/history/history_tab_helper.cc b/chrome/browser/history/history_tab_helper.cc
index 5438b97..f0285ab 100644
--- a/chrome/browser/history/history_tab_helper.cc
+++ b/chrome/browser/history/history_tab_helper.cc
@@ -12,7 +12,6 @@
 #include "chrome/browser/prerender/prerender_manager.h"
 #include "chrome/browser/prerender/prerender_manager_factory.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/search/instant_overlay.h"
 #include "chrome/common/render_messages.h"
 #include "content/public/browser/navigation_details.h"
 #include "content/public/browser/navigation_entry.h"
@@ -128,13 +127,6 @@
     }
   }
 
-  InstantOverlay* instant_overlay =
-      InstantOverlay::FromWebContents(web_contents());
-  if (instant_overlay) {
-    instant_overlay->DidNavigate(add_page_args);
-    return;
-  }
-
 #if !defined(OS_ANDROID)
   // Don't update history if this web contents isn't associatd with a tab.
   Browser* browser = chrome::FindBrowserWithWebContents(web_contents());
diff --git a/chrome/browser/history/history_tab_helper.h b/chrome/browser/history/history_tab_helper.h
index 3615ecb..95c4ee0 100644
--- a/chrome/browser/history/history_tab_helper.h
+++ b/chrome/browser/history/history_tab_helper.h
@@ -6,7 +6,7 @@
 #define CHROME_BROWSER_HISTORY_HISTORY_TAB_HELPER_H_
 
 #include "base/memory/ref_counted.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
 #include "content/public/browser/web_contents_observer.h"
diff --git a/chrome/browser/history/history_types.cc b/chrome/browser/history/history_types.cc
index 09fed81..f0e6439 100644
--- a/chrome/browser/history/history_types.cc
+++ b/chrome/browser/history/history_types.cc
@@ -107,6 +107,10 @@
     : URLRow(url) {
   title_match_positions_ = title_matches;
 }
+URLResult::URLResult(const URLRow& url_row)
+    : URLRow(url_row),
+      blocked_visit_(false) {
+}
 
 URLResult::~URLResult() {
 }
@@ -119,6 +123,11 @@
   std::swap(blocked_visit_, other->blocked_visit_);
 }
 
+// static
+bool URLResult::CompareVisitTime(const URLResult& lhs, const URLResult& rhs) {
+  return lhs.visit_time() > rhs.visit_time();
+}
+
 // QueryResults ----------------------------------------------------------------
 
 QueryResults::QueryResults() : reached_beginning_(false) {
@@ -385,13 +394,6 @@
 
 IconMapping::~IconMapping() {}
 
-// FaviconSizes --------------------------------------------------------------
-
-const FaviconSizes& GetDefaultFaviconSizes() {
-  CR_DEFINE_STATIC_LOCAL(FaviconSizes, kDefaultFaviconSizes, ());
-  return kDefaultFaviconSizes;
-}
-
 // FaviconBitmapIDSize ---------------------------------------------------------
 
 FaviconBitmapIDSize::FaviconBitmapIDSize()
diff --git a/chrome/browser/history/history_types.h b/chrome/browser/history/history_types.h
index c99457d..d78d40f 100644
--- a/chrome/browser/history/history_types.h
+++ b/chrome/browser/history/history_types.h
@@ -16,16 +16,16 @@
 #include "base/memory/ref_counted_memory.h"
 #include "base/memory/scoped_vector.h"
 #include "base/strings/string16.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/favicon/favicon_types.h"
 #include "chrome/browser/history/snippet.h"
 #include "chrome/browser/search_engines/template_url_id.h"
 #include "chrome/common/ref_counted_util.h"
 #include "chrome/common/thumbnail_score.h"
 #include "content/public/common/page_transition_types.h"
-#include "googleurl/src/gurl.h"
 #include "ui/gfx/image/image.h"
 #include "ui/gfx/size.h"
+#include "url/gurl.h"
 
 class PageUsageData;
 
@@ -294,6 +294,7 @@
   // Constructor that create a URLResult from the specified URL and title match
   // positions from title_matches.
   URLResult(const GURL& url, const Snippet::MatchPositions& title_matches);
+  explicit URLResult(const URLRow& url_row);
   virtual ~URLResult();
 
   base::Time visit_time() const { return visit_time_; }
@@ -315,6 +316,8 @@
 
   void SwapResult(URLResult* other);
 
+  static bool CompareVisitTime(const URLResult& lhs, const URLResult& rhs);
+
  private:
   friend class HistoryBackend;
 
@@ -608,8 +611,6 @@
   // scoped_refptr<base::RefCountedBytes> favicon;
 };
 
-typedef std::vector<MostVisitedURL> MostVisitedURLList;
-
 struct MostVisitedURLWithRank {
   MostVisitedURL url;
   int rank;
@@ -697,19 +698,6 @@
   chrome::IconType icon_type;
 };
 
-// FaviconSizes represents the sizes that the thumbnail database knows a
-// favicon is available from the web. FaviconSizes has several entries
-// only if FaviconSizes is for an .ico file. FaviconSizes can be different
-// from the pixel sizes of the entries in the |favicon_bitmaps| table. For
-// instance, if a web page has a .ico favicon with bitmaps of pixel sizes
-// (16x16, 32x32), FaviconSizes will have both sizes regardless of whether
-// either of these bitmaps is cached in the favicon_bitmaps database table.
-typedef std::vector<gfx::Size> FaviconSizes;
-
-// Returns the default FaviconSizes to use if the favicon sizes for a FaviconID
-// are unknown.
-const FaviconSizes& GetDefaultFaviconSizes();
-
 // Defines a favicon bitmap and its associated pixel size.
 struct FaviconBitmapIDSize {
   FaviconBitmapIDSize();
diff --git a/chrome/browser/history/history_unittest.cc b/chrome/browser/history/history_unittest.cc
index d9e8949..ebdf67d 100644
--- a/chrome/browser/history/history_unittest.cc
+++ b/chrome/browser/history/history_unittest.cc
@@ -40,7 +40,7 @@
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/platform_thread.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/history/download_row.h"
 #include "chrome/browser/history/history_backend.h"
 #include "chrome/browser/history/history_database.h"
@@ -165,10 +165,10 @@
     std::vector<GURL> url_chain;
     url_chain.push_back(GURL("foo-url"));
 
-    DownloadRow download(base::FilePath(FILE_PATH_LITERAL("foo-path")),
-                         base::FilePath(FILE_PATH_LITERAL("foo-path")),
+    DownloadRow download(base::FilePath(FILE_PATH_LITERAL("current-path")),
+                         base::FilePath(FILE_PATH_LITERAL("target-path")),
                          url_chain,
-                         GURL(std::string()),
+                         GURL("http://referrer.com/"),
                          time,
                          time,
                          0,
@@ -177,7 +177,7 @@
                          content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
                          content::DOWNLOAD_INTERRUPT_REASON_NONE,
                          0,
-                         0);
+                         false);
     return db_->CreateDownload(download);
   }
 
@@ -221,12 +221,33 @@
   db_->QueryDownloads(&downloads);
   EXPECT_EQ(0U, downloads.size());
 
-  // Add a download, test that it was added, remove it, test that it was
-  // removed.
+  // Add a download, test that it was added correctly, remove it, test that it
+  // was removed.
   DownloadID handle;
-  EXPECT_NE(0, handle = AddDownload(DownloadItem::COMPLETE, Time()));
+  Time now = Time();
+  EXPECT_NE(0, handle = AddDownload(DownloadItem::COMPLETE, now));
   db_->QueryDownloads(&downloads);
   EXPECT_EQ(1U, downloads.size());
+
+  EXPECT_EQ(base::FilePath(FILE_PATH_LITERAL("current-path")),
+            downloads[0].current_path);
+  EXPECT_EQ(base::FilePath(FILE_PATH_LITERAL("target-path")),
+            downloads[0].target_path);
+  EXPECT_EQ(1UL, downloads[0].url_chain.size());
+  EXPECT_EQ(GURL("foo-url"), downloads[0].url_chain[0]);
+  EXPECT_EQ(std::string("http://referrer.com/"),
+            std::string(downloads[0].referrer_url.spec()));
+  EXPECT_EQ(now, downloads[0].start_time);
+  EXPECT_EQ(now, downloads[0].end_time);
+  EXPECT_EQ(0, downloads[0].received_bytes);
+  EXPECT_EQ(512, downloads[0].total_bytes);
+  EXPECT_EQ(DownloadItem::COMPLETE, downloads[0].state);
+  EXPECT_EQ(content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
+            downloads[0].danger_type);
+  EXPECT_EQ(content::DOWNLOAD_INTERRUPT_REASON_NONE,
+            downloads[0].interrupt_reason);
+  EXPECT_FALSE(downloads[0].opened);
+
   db_->RemoveDownload(handle);
   db_->QueryDownloads(&downloads);
   EXPECT_EQ(0U, downloads.size());
@@ -411,6 +432,54 @@
   }
 }
 
+TEST_F(HistoryBackendDBTest, MigrateReferrer) {
+  Time now(base::Time::Now());
+  ASSERT_NO_FATAL_FAILURE(CreateDBVersion(22));
+  {
+    sql::Connection db;
+    ASSERT_TRUE(db.Open(history_dir_.Append(chrome::kHistoryFilename)));
+    sql::Statement s(db.GetUniqueStatement(
+        "INSERT INTO downloads (id, full_path, url, start_time, "
+        "received_bytes, total_bytes, state, end_time, opened) VALUES "
+        "(?, ?, ?, ?, ?, ?, ?, ?, ?)"));
+    int64 db_handle = 0;
+    s.BindInt64(0, ++db_handle);
+    s.BindString(1, "full_path");
+    s.BindString(2, "http://whatever.com/index.html");
+    s.BindInt64(3, now.ToTimeT());
+    s.BindInt64(4, 100);
+    s.BindInt64(5, 100);
+    s.BindInt(6, 1);
+    s.BindInt64(7, now.ToTimeT());
+    s.BindInt(8, 1);
+    ASSERT_TRUE(s.Run());
+  }
+  // Re-open the db using the HistoryDatabase, which should migrate to version
+  // 26, creating the referrer column.
+  CreateBackendAndDatabase();
+  DeleteBackend();
+  {
+    // Re-open the db for manual manipulation.
+    sql::Connection db;
+    ASSERT_TRUE(db.Open(history_dir_.Append(chrome::kHistoryFilename)));
+    // The version should have been updated.
+    int cur_version = HistoryDatabase::GetCurrentVersion();
+    ASSERT_LE(26, cur_version);
+    {
+      sql::Statement s(db.GetUniqueStatement(
+          "SELECT value FROM meta WHERE key = 'version'"));
+      EXPECT_TRUE(s.Step());
+      EXPECT_EQ(cur_version, s.ColumnInt(0));
+    }
+    {
+      sql::Statement s(db.GetUniqueStatement(
+          "SELECT referrer from downloads"));
+      EXPECT_TRUE(s.Step());
+      EXPECT_EQ(std::string(), s.ColumnString(0));
+    }
+  }
+}
+
 TEST_F(HistoryBackendDBTest, ConfirmDownloadRowCreateAndDelete) {
   // Create the DB.
   CreateBackendAndDatabase();
diff --git a/chrome/browser/history/in_memory_database.cc b/chrome/browser/history/in_memory_database.cc
index 40babf5..61e2570 100644
--- a/chrome/browser/history/in_memory_database.cc
+++ b/chrome/browser/history/in_memory_database.cc
@@ -8,7 +8,7 @@
 #include "base/logging.h"
 #include "base/metrics/histogram.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "build/build_config.h"
 
 namespace history {
diff --git a/chrome/browser/history/in_memory_history_backend.cc b/chrome/browser/history/in_memory_history_backend.cc
index 0dc276f..ce9f965 100644
--- a/chrome/browser/history/in_memory_history_backend.cc
+++ b/chrome/browser/history/in_memory_history_backend.cc
@@ -9,7 +9,7 @@
 
 #include "base/command_line.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/history/history_notifications.h"
 #include "chrome/browser/history/in_memory_database.h"
diff --git a/chrome/browser/history/in_memory_url_index.cc b/chrome/browser/history/in_memory_url_index.cc
index 50098cd..e0f4462 100644
--- a/chrome/browser/history/in_memory_url_index.cc
+++ b/chrome/browser/history/in_memory_url_index.cc
@@ -31,7 +31,7 @@
 // there is no private data to save. Runs on the FILE thread.
 void DeleteCacheFile(const base::FilePath& path) {
   DCHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
-  file_util::Delete(path, false);
+  base::Delete(path, false);
 }
 
 // Initializes a whitelist of URL schemes.
diff --git a/chrome/browser/history/in_memory_url_index_types.h b/chrome/browser/history/in_memory_url_index_types.h
index b4f51cf..19547fa 100644
--- a/chrome/browser/history/in_memory_url_index_types.h
+++ b/chrome/browser/history/in_memory_url_index_types.h
@@ -12,7 +12,7 @@
 #include "base/strings/string16.h"
 #include "chrome/browser/autocomplete/history_provider_util.h"
 #include "chrome/browser/history/history_types.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 namespace history {
 
diff --git a/chrome/browser/history/page_usage_data.h b/chrome/browser/history/page_usage_data.h
index 1f27440..07f58dd 100644
--- a/chrome/browser/history/page_usage_data.h
+++ b/chrome/browser/history/page_usage_data.h
@@ -6,9 +6,9 @@
 #define CHROME_BROWSER_HISTORY_PAGE_USAGE_DATA_H__
 
 #include "base/strings/string16.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/history/history_types.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 class SkBitmap;
 
diff --git a/chrome/browser/history/query_parser.cc b/chrome/browser/history/query_parser.cc
index 9fafc9b..322da23 100644
--- a/chrome/browser/history/query_parser.cc
+++ b/chrome/browser/history/query_parser.cc
@@ -11,6 +11,7 @@
 #include "base/i18n/case_conversion.h"
 #include "base/logging.h"
 #include "base/stl_util.h"
+#include "base/strings/utf_string_conversions.h"
 
 namespace {
 
@@ -88,6 +89,8 @@
   virtual bool HasMatchIn(
       const std::vector<QueryWord>& words,
       Snippet::MatchPositions* match_positions) const OVERRIDE;
+  virtual bool HasMatchIn(
+      const std::vector<QueryWord>& words) const OVERRIDE;
   virtual void AppendWords(std::vector<string16>* words) const OVERRIDE;
 
  private:
@@ -138,6 +141,14 @@
   return matched;
 }
 
+bool QueryNodeWord::HasMatchIn(const std::vector<QueryWord>& words) const {
+  for (size_t i = 0; i < words.size(); ++i) {
+    if (Matches(words[i].word, false))
+      return true;
+  }
+  return false;
+}
+
 void QueryNodeWord::AppendWords(std::vector<string16>* words) const {
   words->push_back(word_);
 }
@@ -164,6 +175,8 @@
   virtual bool HasMatchIn(
       const std::vector<QueryWord>& words,
       Snippet::MatchPositions* match_positions) const OVERRIDE;
+  virtual bool HasMatchIn(
+      const std::vector<QueryWord>& words) const OVERRIDE;
   virtual void AppendWords(std::vector<string16>* words) const OVERRIDE;
 
  protected:
@@ -219,6 +232,11 @@
   return false;
 }
 
+bool QueryNodeList::HasMatchIn(const std::vector<QueryWord>& words) const {
+  NOTREACHED();
+  return false;
+}
+
 void QueryNodeList::AppendWords(std::vector<string16>* words) const {
   for (size_t i = 0; i < children_.size(); ++i)
     children_[i]->AppendWords(words);
@@ -246,8 +264,13 @@
   virtual bool HasMatchIn(
       const std::vector<QueryWord>& words,
       Snippet::MatchPositions* match_positions) const OVERRIDE;
+  virtual bool HasMatchIn(
+      const std::vector<QueryWord>& words) const OVERRIDE;
 
  private:
+  bool MatchesAll(const std::vector<QueryWord>& words,
+                  const QueryWord** first_word,
+                  const QueryWord** last_word) const;
   DISALLOW_COPY_AND_ASSIGN(QueryNodePhrase);
 };
 
@@ -262,9 +285,9 @@
   return num_words;
 }
 
-bool QueryNodePhrase::HasMatchIn(
-    const std::vector<QueryWord>& words,
-    Snippet::MatchPositions* match_positions) const {
+bool QueryNodePhrase::MatchesAll(const std::vector<QueryWord>& words,
+                                 const QueryWord** first_word,
+                                 const QueryWord** last_word) const {
   if (words.size() < children_.size())
     return false;
 
@@ -277,16 +300,35 @@
       }
     }
     if (matched_all) {
-      const QueryWord& last_word = words[i + children_.size() - 1];
-      match_positions->push_back(
-          Snippet::MatchPosition(words[i].position,
-                                 last_word.position + last_word.word.length()));
+      *first_word = &words[i];
+      *last_word = &words[i + children_.size() - 1];
       return true;
     }
   }
   return false;
 }
 
+bool QueryNodePhrase::HasMatchIn(
+    const std::vector<QueryWord>& words,
+    Snippet::MatchPositions* match_positions) const {
+  const QueryWord* first_word;
+  const QueryWord* last_word;
+
+  if (MatchesAll(words, &first_word, &last_word)) {
+    match_positions->push_back(
+        Snippet::MatchPosition(first_word->position,
+                               last_word->position + last_word->word.length()));
+      return true;
+  }
+  return false;
+}
+
+bool QueryNodePhrase::HasMatchIn(const std::vector<QueryWord>& words) const {
+  const QueryWord* first_word;
+  const QueryWord* last_word;
+  return MatchesAll(words, &first_word, &last_word);
+}
+
 QueryParser::QueryParser() {}
 
 // static
@@ -354,6 +396,18 @@
   return true;
 }
 
+bool QueryParser::DoesQueryMatch(const std::vector<QueryWord>& query_words,
+                                 const std::vector<QueryNode*>& query_nodes) {
+  if (query_nodes.empty() || query_words.empty())
+    return false;
+
+  for (size_t i = 0; i < query_nodes.size(); ++i) {
+    if (!query_nodes[i]->HasMatchIn(query_words))
+      return false;
+  }
+  return true;
+}
+
 bool QueryParser::ParseQueryImpl(const string16& query, QueryNodeList* root) {
   base::i18n::BreakIterator iter(query, base::i18n::BreakIterator::BREAK_WORD);
   // TODO(evanm): support a locale here
diff --git a/chrome/browser/history/query_parser.h b/chrome/browser/history/query_parser.h
index 6bb0787..fe69e0b 100644
--- a/chrome/browser/history/query_parser.h
+++ b/chrome/browser/history/query_parser.h
@@ -46,6 +46,9 @@
   virtual bool HasMatchIn(const std::vector<QueryWord>& words,
                           Snippet::MatchPositions* match_positions) const = 0;
 
+  // Returns true if this node matches at least one of the words in |words|.
+  virtual bool HasMatchIn(const std::vector<QueryWord>& words) const = 0;
+
   // Appends the words that make up this node in |words|.
   virtual void AppendWords(std::vector<string16>* words) const = 0;
 };
@@ -87,14 +90,19 @@
                       const std::vector<QueryNode*>& nodes,
                       Snippet::MatchPositions* match_positions);
 
+  // Returns true if all of the |words| match the query |nodes| created by a
+  // call to ParseQuery.
+  bool DoesQueryMatch(const std::vector<QueryWord>& words,
+                      const std::vector<QueryNode*>& nodes);
+
+  // Extracts the words from |text|, placing each word into |words|.
+  void ExtractQueryWords(const string16& text, std::vector<QueryWord>* words);
+
  private:
   // Does the work of parsing |query|; creates nodes in |root| as appropriate.
   // This is invoked from both of the ParseQuery methods.
   bool ParseQueryImpl(const string16& query, QueryNodeList* root);
 
-  // Extracts the words from |text|, placing each word into |words|.
-  void ExtractQueryWords(const string16& text, std::vector<QueryWord>* words);
-
   DISALLOW_COPY_AND_ASSIGN(QueryParser);
 };
 
diff --git a/chrome/browser/history/shortcuts_backend.h b/chrome/browser/history/shortcuts_backend.h
index a634c5b..6979271 100644
--- a/chrome/browser/history/shortcuts_backend.h
+++ b/chrome/browser/history/shortcuts_backend.h
@@ -16,12 +16,12 @@
 #include "base/observer_list.h"
 #include "base/strings/string16.h"
 #include "base/synchronization/lock.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/autocomplete/autocomplete_match.h"
 #include "components/browser_context_keyed_service/refcounted_browser_context_keyed_service.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 class Profile;
 
diff --git a/chrome/browser/history/shortcuts_backend_unittest.cc b/chrome/browser/history/shortcuts_backend_unittest.cc
index dbc4e83..804f1df 100644
--- a/chrome/browser/history/shortcuts_backend_unittest.cc
+++ b/chrome/browser/history/shortcuts_backend_unittest.cc
@@ -7,7 +7,7 @@
 #include "base/path_service.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/history/shortcuts_backend.h"
 #include "chrome/browser/history/shortcuts_backend_factory.h"
 #include "chrome/browser/history/shortcuts_database.h"
diff --git a/chrome/browser/history/shortcuts_database.cc b/chrome/browser/history/shortcuts_database.cc
index 69dcd33..f739073 100644
--- a/chrome/browser/history/shortcuts_database.cc
+++ b/chrome/browser/history/shortcuts_database.cc
@@ -11,7 +11,7 @@
 #include "base/guid.h"
 #include "base/logging.h"
 #include "base/strings/stringprintf.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/chrome_constants.h"
 #include "sql/statement.h"
diff --git a/chrome/browser/history/shortcuts_database.h b/chrome/browser/history/shortcuts_database.h
index 36e803d..647b000 100644
--- a/chrome/browser/history/shortcuts_database.h
+++ b/chrome/browser/history/shortcuts_database.h
@@ -14,8 +14,8 @@
 #include "base/memory/ref_counted.h"
 #include "base/strings/string16.h"
 #include "chrome/browser/history/shortcuts_backend.h"
-#include "googleurl/src/gurl.h"
 #include "sql/connection.h"
+#include "url/gurl.h"
 
 class Profile;
 
diff --git a/chrome/browser/history/shortcuts_database_unittest.cc b/chrome/browser/history/shortcuts_database_unittest.cc
index 86040a6..dd3a322 100644
--- a/chrome/browser/history/shortcuts_database_unittest.cc
+++ b/chrome/browser/history/shortcuts_database_unittest.cc
@@ -6,7 +6,7 @@
 #include "base/path_service.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/history/shortcuts_database.h"
 #include "chrome/test/base/testing_profile.h"
 #include "sql/statement.h"
diff --git a/chrome/browser/history/text_database.h b/chrome/browser/history/text_database.h
index efb9563..ddb247b 100644
--- a/chrome/browser/history/text_database.h
+++ b/chrome/browser/history/text_database.h
@@ -12,9 +12,9 @@
 #include "base/files/file_path.h"
 #include "base/strings/string16.h"
 #include "chrome/browser/history/history_types.h"
-#include "googleurl/src/gurl.h"
 #include "sql/connection.h"
 #include "sql/meta_table.h"
+#include "url/gurl.h"
 
 namespace history {
 
diff --git a/chrome/browser/history/text_database_manager.cc b/chrome/browser/history/text_database_manager.cc
index a55b0a0..e0d8484 100644
--- a/chrome/browser/history/text_database_manager.cc
+++ b/chrome/browser/history/text_database_manager.cc
@@ -9,7 +9,6 @@
 
 #include "base/bind.h"
 #include "base/compiler_specific.h"
-#include "base/file_util.h"
 #include "base/files/file_enumerator.h"
 #include "base/logging.h"
 #include "base/message_loop.h"
@@ -415,7 +414,7 @@
   for (DBIdentSet::iterator i = present_databases_.begin();
        i != present_databases_.end(); ++i) {
     base::FilePath file_name = dir_.Append(TextDatabase::IDToFileName(*i));
-    file_util::Delete(file_name, false);
+    sql::Connection::Delete(file_name);
   }
 }
 
diff --git a/chrome/browser/history/text_database_manager_unittest.cc b/chrome/browser/history/text_database_manager_unittest.cc
index eccd7a8..fa5a1f3 100644
--- a/chrome/browser/history/text_database_manager_unittest.cc
+++ b/chrome/browser/history/text_database_manager_unittest.cc
@@ -161,7 +161,7 @@
   }
 
   virtual void TearDown() {
-    file_util::Delete(dir_, true);
+    base::Delete(dir_, true);
   }
 
   base::MessageLoop message_loop_;
diff --git a/chrome/browser/history/text_database_unittest.cc b/chrome/browser/history/text_database_unittest.cc
index 72447f0..25b7d79 100644
--- a/chrome/browser/history/text_database_unittest.cc
+++ b/chrome/browser/history/text_database_unittest.cc
@@ -4,7 +4,6 @@
 
 #include <string>
 
-#include "base/file_util.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/strings/string_util.h"
@@ -106,7 +105,7 @@
     TextDatabase* db = new TextDatabase(temp_dir_.path(), id, allow_create);
 
     if (delete_file)
-      file_util::Delete(db->file_name(), false);
+      sql::Connection::Delete(db->file_name());
 
     if (!db->Init()) {
       delete db;
diff --git a/chrome/browser/history/thumbnail_database.cc b/chrome/browser/history/thumbnail_database.cc
index 9f26548..ef5c439 100644
--- a/chrome/browser/history/thumbnail_database.cc
+++ b/chrome/browser/history/thumbnail_database.cc
@@ -19,7 +19,7 @@
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/diagnostics/sqlite_diagnostics.h"
 #include "chrome/browser/history/history_publisher.h"
 #include "chrome/browser/history/top_sites.h"
@@ -55,22 +55,13 @@
 //   icon_type        The type of the favicon specified in the rel attribute of
 //                    the link tag. The FAVICON type is used for the default
 //                    favicon.ico favicon.
-//   sizes            Sizes is a listing of all the sizes at which the favicon
-//                    at |url| is available from the web. Note that this may
-//                    include sizes for which a bitmap is not stored in the
-//                    favicon_bitmaps table. Each widthxheight pair is
-//                    separated by a space. Width and height are separated by
-//                    a space as well. For instance, if |icon_id| represents a
-//                    .ico file containing 16x16 and 32x32 bitmaps, |sizes|
-//                    would be "16 16 32 32".
 //
 // favicon_bitmaps    This table contains the PNG encoded bitmap data of the
 //                    favicons. There is a separate row for every size in a
 //                    multi resolution bitmap. The bitmap data is associated
 //                    to the favicon via the |icon_id| field which matches
 //                    the |id| field in the appropriate row in the |favicons|
-//                    table. There is not necessarily a row for each size
-//                    specified in the sizes attribute.
+//                    table.
 //
 //  id                Unique ID.
 //  icon_id           The ID of the favicon that the bitmap is associated to.
@@ -288,8 +279,8 @@
 namespace history {
 
 // Version number of the database.
-static const int kCurrentVersionNumber = 6;
-static const int kCompatibleVersionNumber = 6;
+static const int kCurrentVersionNumber = 7;
+static const int kCompatibleVersionNumber = 7;
 
 // Use 90 quality (out of 100) which is pretty high, because we're very
 // sensitive to artifacts for these small sized, highly detailed images.
@@ -391,7 +382,7 @@
       return CantUpgradeToVersion(cur_version);
   }
 
-  if (!db_.DoesColumnExist("favicons", "sizes")) {
+  if (cur_version < 7 && !db_.DoesColumnExist("favicons", "sizes")) {
     LOG(ERROR) << "Raze because of missing favicon.sizes";
     RecordInvalidStructure(STRUCTURE_EVENT_VERSION5);
 
@@ -405,6 +396,12 @@
       return CantUpgradeToVersion(cur_version);
   }
 
+  if (cur_version == 6) {
+    ++cur_version;
+    if (!UpgradeToVersion7())
+      return CantUpgradeToVersion(cur_version);
+  }
+
   LOG_IF(WARNING, cur_version < kCurrentVersionNumber) <<
       "Thumbnail database version " << cur_version << " is too old to handle.";
 
@@ -523,8 +520,7 @@
                "url LONGVARCHAR NOT NULL,"
                // Set the default icon_type as FAVICON to be consistent with
                // table upgrade in UpgradeToVersion4().
-               "icon_type INTEGER DEFAULT 1,"
-               "sizes LONGVARCHAR)");
+               "icon_type INTEGER DEFAULT 1)");
     if (!db->Execute(sql.c_str()))
       return false;
   }
@@ -566,7 +562,7 @@
 }
 
 bool ThumbnailDatabase::IsFaviconDBStructureIncorrect() {
-  return !db_.IsSQLValid("SELECT id, url, icon_type, sizes FROM favicons");
+  return !db_.IsSQLValid("SELECT id, url, icon_type FROM favicons");
 }
 
 void ThumbnailDatabase::BeginTransaction() {
@@ -851,19 +847,6 @@
   return statement.Run();
 }
 
-bool ThumbnailDatabase::SetFaviconSizes(chrome::FaviconID icon_id,
-                                        const FaviconSizes& favicon_sizes) {
-  std::string favicon_sizes_as_string;
-  FaviconSizesToDatabaseString(favicon_sizes, &favicon_sizes_as_string);
-
-  sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE,
-      "UPDATE favicons SET sizes=? WHERE id=?"));
-  statement.BindString(0, favicon_sizes_as_string);
-  statement.BindInt64(1, icon_id);
-
-  return statement.Run();
-}
-
 bool ThumbnailDatabase::SetFaviconOutOfDate(chrome::FaviconID icon_id) {
   sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE,
       "UPDATE favicon_bitmaps SET last_updated=? WHERE icon_id=?"));
@@ -893,12 +876,11 @@
 
 bool ThumbnailDatabase::GetFaviconHeader(chrome::FaviconID icon_id,
                                          GURL* icon_url,
-                                         chrome::IconType* icon_type,
-                                         FaviconSizes* favicon_sizes) {
+                                         chrome::IconType* icon_type) {
   DCHECK(icon_id);
 
   sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE,
-      "SELECT url, icon_type, sizes FROM favicons WHERE id=?"));
+      "SELECT url, icon_type FROM favicons WHERE id=?"));
   statement.BindInt64(0, icon_id);
 
   if (!statement.Step())
@@ -908,24 +890,18 @@
     *icon_url = GURL(statement.ColumnString(0));
   if (icon_type)
     *icon_type = static_cast<chrome::IconType>(statement.ColumnInt(1));
-  if (favicon_sizes)
-    DatabaseStringToFaviconSizes(statement.ColumnString(2), favicon_sizes);
 
   return true;
 }
 
 chrome::FaviconID ThumbnailDatabase::AddFavicon(
     const GURL& icon_url,
-    chrome::IconType icon_type,
-    const FaviconSizes& favicon_sizes) {
-  std::string favicon_sizes_as_string;
-  FaviconSizesToDatabaseString(favicon_sizes, &favicon_sizes_as_string);
+    chrome::IconType icon_type) {
 
   sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE,
-      "INSERT INTO favicons (url, icon_type, sizes) VALUES (?, ?, ?)"));
+      "INSERT INTO favicons (url, icon_type) VALUES (?, ?)"));
   statement.BindString(0, URLDatabase::GURLToDatabaseURL(icon_url));
   statement.BindInt(1, icon_type);
-  statement.BindString(2, favicon_sizes_as_string);
 
   if (!statement.Run())
     return 0;
@@ -935,11 +911,10 @@
 chrome::FaviconID ThumbnailDatabase::AddFavicon(
     const GURL& icon_url,
     chrome::IconType icon_type,
-    const FaviconSizes& favicon_sizes,
     const scoped_refptr<base::RefCountedMemory>& icon_data,
     base::Time time,
     const gfx::Size& pixel_size) {
-  chrome::FaviconID icon_id = AddFavicon(icon_url, icon_type, favicon_sizes);
+  chrome::FaviconID icon_id = AddFavicon(icon_url, icon_type);
   if (!icon_id || !AddFaviconBitmap(icon_id, icon_data, time, pixel_size))
     return 0;
 
@@ -1155,8 +1130,8 @@
     chrome::FaviconID source) {
   sql::Statement statement;
   statement.Assign(db_.GetCachedStatement(SQL_FROM_HERE,
-      "INSERT INTO temp_favicons (url, icon_type, sizes) "
-      "SELECT url, icon_type, sizes FROM favicons WHERE id = ?"));
+      "INSERT INTO temp_favicons (url, icon_type) "
+      "SELECT url, icon_type FROM favicons WHERE id = ?"));
   statement.BindInt64(0, source);
 
   if (!statement.Run())
@@ -1248,7 +1223,7 @@
   if (OpenDatabase(&db_, new_db_file) != sql::INIT_OK)
     return false;
 
-  file_util::Delete(old_db_file, false);
+  sql::Connection::Delete(old_db_file);
 
   meta_table_.Reset();
   if (!meta_table_.Init(&db_, kCurrentVersionNumber, kCompatibleVersionNumber))
@@ -1360,39 +1335,24 @@
   return true;
 }
 
-// static
-void ThumbnailDatabase::FaviconSizesToDatabaseString(
-    const FaviconSizes& favicon_sizes,
-    std::string* favicon_sizes_string) {
-  std::vector<std::string> parts;
-  for (FaviconSizes::const_iterator it = favicon_sizes.begin();
-       it != favicon_sizes.end(); ++it) {
-    parts.push_back(base::IntToString(it->width()));
-    parts.push_back(base::IntToString(it->height()));
-  }
-  *favicon_sizes_string = JoinString(parts, ' ');
-}
+bool ThumbnailDatabase::UpgradeToVersion7() {
+  bool success =
+      db_.Execute("CREATE TABLE temp_favicons ("
+                  "id INTEGER PRIMARY KEY,"
+                  "url LONGVARCHAR NOT NULL,"
+                  "icon_type INTEGER DEFAULT 1)") &&
+      db_.Execute("INSERT INTO temp_favicons (id, url, icon_type) "
+                  "SELECT id, url, icon_type FROM favicons") &&
+      db_.Execute("DROP TABLE favicons") &&
+      db_.Execute("ALTER TABLE temp_favicons RENAME TO favicons") &&
+      db_.Execute("CREATE INDEX IF NOT EXISTS favicons_url ON favicons(url)");
 
-// static
-void ThumbnailDatabase::DatabaseStringToFaviconSizes(
-    const std::string& favicon_sizes_string,
-    FaviconSizes* favicon_sizes) {
-  bool parsing_errors = false;
+  if (!success)
+    return false;
 
-  base::StringTokenizer t(favicon_sizes_string, " ");
-  while (t.GetNext() && !parsing_errors) {
-    int width, height = 0;
-    parsing_errors |= !base::StringToInt(t.token(), &width);
-    if (!t.GetNext()) {
-      parsing_errors = true;
-      break;
-    }
-    parsing_errors |= !base::StringToInt(t.token(), &height);
-    favicon_sizes->push_back(gfx::Size(width, height));
-  }
-
-  if (parsing_errors)
-    favicon_sizes->clear();
+  meta_table_.SetVersionNumber(7);
+  meta_table_.SetCompatibleVersionNumber(std::min(7, kCompatibleVersionNumber));
+  return true;
 }
 
 }  // namespace history
diff --git a/chrome/browser/history/thumbnail_database.h b/chrome/browser/history/thumbnail_database.h
index fc726d6..00931f1 100644
--- a/chrome/browser/history/thumbnail_database.h
+++ b/chrome/browser/history/thumbnail_database.h
@@ -161,11 +161,6 @@
 
   // Favicons ------------------------------------------------------------------
 
-  // Updates the favicon sizes associated with a favicon to |favicon_sizes|.
-  // See comment in history_types.h for description of |favicon_sizes|.
-  bool SetFaviconSizes(chrome::FaviconID icon_id,
-                       const FaviconSizes& favicon_sizes);
-
   // Sets the the favicon as out of date. This will set |last_updated| for all
   // of the bitmaps for |icon_id| to be out of date.
   bool SetFaviconOutOfDate(chrome::FaviconID icon_id);
@@ -184,21 +179,18 @@
   // Gets the icon_url, icon_type and sizes for the specified |icon_id|.
   bool GetFaviconHeader(chrome::FaviconID icon_id,
                         GURL* icon_url,
-                        chrome::IconType* icon_type,
-                        FaviconSizes* favicon_sizes);
+                        chrome::IconType* icon_type);
 
   // Adds favicon with |icon_url|, |icon_type| and |favicon_sizes| to the
   // favicon db, returning its id.
   chrome::FaviconID AddFavicon(const GURL& icon_url,
-                               chrome::IconType icon_type,
-                               const FaviconSizes& favicon_sizes);
+                               chrome::IconType icon_type);
 
   // Adds a favicon with a single bitmap. This call is equivalent to calling
   // AddFavicon and AddFaviconBitmap.
   chrome::FaviconID AddFavicon(
       const GURL& icon_url,
       chrome::IconType icon_type,
-      const FaviconSizes& favicon_sizes,
       const scoped_refptr<base::RefCountedMemory>& icon_data,
       base::Time time,
       const gfx::Size& pixel_size);
@@ -325,7 +317,7 @@
   FRIEND_TEST_ALL_PREFIXES(ThumbnailDatabaseTest, UpgradeToVersion4);
   FRIEND_TEST_ALL_PREFIXES(ThumbnailDatabaseTest, UpgradeToVersion5);
   FRIEND_TEST_ALL_PREFIXES(ThumbnailDatabaseTest, UpgradeToVersion6);
-  FRIEND_TEST_ALL_PREFIXES(ThumbnailDatabaseTest, FaviconSizesToAndFromString);
+  FRIEND_TEST_ALL_PREFIXES(ThumbnailDatabaseTest, UpgradeToVersion7);
   FRIEND_TEST_ALL_PREFIXES(HistoryBackendTest, MigrationIconMapping);
 
   // Creates the thumbnail table, returning true if the table already exists
@@ -344,9 +336,12 @@
   // Adds support for sizes in favicon table.
   bool UpgradeToVersion5();
 
-  // Adds support for size in favicons table and removes sizes column.
+  // Adds support for size in favicons table.
   bool UpgradeToVersion6();
 
+  // Removes sizes column.
+  bool UpgradeToVersion7();
+
   // Migrates the icon mapping data from URL database to Thumbnail database.
   // Return whether the migration succeeds.
   bool MigrateIconMappingData(URLDatabase* url_db);
@@ -401,23 +396,6 @@
   // Returns True if the current database is latest.
   bool IsLatestVersion();
 
-  // Converts the vector representation of favicon sizes as passed into
-  // SetFaviconSizes to a string to store in the |favicons| database table.
-  // Format:
-  //   Each widthxheight pair is separated by a space.
-  //   Width and height are separated by a space.
-  // For instance, if sizes contains pixel sizes (16x16, 32x32), the
-  // string representation is "16 16 32 32".
-  static void FaviconSizesToDatabaseString(const FaviconSizes& favicon_sizes,
-                                           std::string* favicon_sizes_string);
-
-  // Converts the string representation of favicon sizes as stored in the
-  // |favicons| database table to a vector. Returns an empty vector if there
-  // were parsing errors.
-  static void DatabaseStringToFaviconSizes(
-      const std::string& favicon_sizes_string,
-      FaviconSizes* favicon_sizes);
-
   sql::Connection db_;
   sql::MetaTable meta_table_;
 
diff --git a/chrome/browser/history/thumbnail_database_unittest.cc b/chrome/browser/history/thumbnail_database_unittest.cc
index d81ad30..6446fd1 100644
--- a/chrome/browser/history/thumbnail_database_unittest.cc
+++ b/chrome/browser/history/thumbnail_database_unittest.cc
@@ -19,10 +19,10 @@
 #include "chrome/common/thumbnail_score.h"
 #include "chrome/test/base/testing_profile.h"
 #include "chrome/tools/profiles/thumbnail-inl.h"
-#include "googleurl/src/gurl.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/gfx/codec/jpeg_codec.h"
+#include "url/gurl.h"
 
 using base::Time;
 using base::TimeDelta;
@@ -69,13 +69,6 @@
         gfx::JPEGCodec::Decode(kGoogleThumbnail, sizeof(kGoogleThumbnail)));
   }
 
-  const FaviconSizes GetFaviconSizesSmallAndLarge() {
-    FaviconSizes sizes_small_and_large;
-    sizes_small_and_large.push_back(kSmallSize);
-    sizes_small_and_large.push_back(kLargeSize);
-    return sizes_small_and_large;
-  }
-
   scoped_ptr<SkBitmap> google_bitmap_;
 
   base::ScopedTempDir temp_dir_;
@@ -128,8 +121,7 @@
   scoped_refptr<base::RefCountedBytes> favicon(new base::RefCountedBytes(data));
 
   GURL url("http://google.com");
-  chrome::FaviconID icon_id =
-      db.AddFavicon(url, chrome::FAVICON, GetFaviconSizesSmallAndLarge());
+  chrome::FaviconID icon_id = db.AddFavicon(url, chrome::FAVICON);
   base::Time time = base::Time::Now();
   FaviconBitmapID bitmap1_id = db.AddFaviconBitmap(icon_id, favicon, time,
                                                    kSmallSize);
@@ -140,13 +132,10 @@
 
   GURL url_out;
   chrome::IconType icon_type_out;
-  FaviconSizes favicon_sizes_out;
-  EXPECT_TRUE(db.GetFaviconHeader(icon_id, &url_out, &icon_type_out,
-                                  &favicon_sizes_out));
+  EXPECT_TRUE(db.GetFaviconHeader(icon_id, &url_out, &icon_type_out));
 
   EXPECT_EQ(url, url_out);
   EXPECT_EQ(chrome::FAVICON, icon_type_out);
-  EXPECT_EQ(GetFaviconSizesSmallAndLarge(), favicon_sizes_out);
 
   std::vector<FaviconBitmap> favicon_bitmaps_out;
   EXPECT_TRUE(db.GetFaviconBitmaps(icon_id, &favicon_bitmaps_out));
@@ -195,7 +184,6 @@
   base::Time time = base::Time::Now();
   chrome::FaviconID id = db.AddFavicon(url,
                                        chrome::TOUCH_ICON,
-                                       GetDefaultFaviconSizes(),
                                        favicon,
                                        time,
                                        gfx::Size());
@@ -216,7 +204,7 @@
 
   GURL url("http://google.com");
   chrome::FaviconID id =
-      db.AddFavicon(url, chrome::TOUCH_ICON, GetDefaultFaviconSizes());
+      db.AddFavicon(url, chrome::TOUCH_ICON);
 
   EXPECT_LT(0, db.AddIconMapping(url, id));
   std::vector<IconMapping> icon_mapping;
@@ -227,7 +215,7 @@
 
   GURL url1("http://www.google.com/");
   chrome::FaviconID new_id =
-      db.AddFavicon(url1, chrome::TOUCH_ICON, GetDefaultFaviconSizes());
+      db.AddFavicon(url1, chrome::TOUCH_ICON);
   EXPECT_TRUE(db.UpdateIconMapping(icon_mapping.front().mapping_id, new_id));
 
   icon_mapping.clear();
@@ -248,13 +236,13 @@
 
   GURL url("http://google.com");
   chrome::FaviconID id =
-      db.AddFavicon(url, chrome::TOUCH_ICON, GetDefaultFaviconSizes());
+      db.AddFavicon(url, chrome::TOUCH_ICON);
   base::Time time = base::Time::Now();
   db.AddFaviconBitmap(id, favicon, time, gfx::Size());
   EXPECT_LT(0, db.AddIconMapping(url, id));
 
   chrome::FaviconID id2 =
-      db.AddFavicon(url, chrome::FAVICON, GetDefaultFaviconSizes());
+      db.AddFavicon(url, chrome::FAVICON);
   EXPECT_LT(0, db.AddIconMapping(url, id2));
   ASSERT_NE(id, id2);
 
@@ -280,15 +268,13 @@
 
   GURL url("http://google.com");
 
-  chrome::FaviconID id1 =
-      db.AddFavicon(url, chrome::TOUCH_ICON, GetFaviconSizesSmallAndLarge());
+  chrome::FaviconID id1 = db.AddFavicon(url, chrome::TOUCH_ICON);
   base::Time time = base::Time::Now();
   db.AddFaviconBitmap(id1, favicon, time, kSmallSize);
   db.AddFaviconBitmap(id1, favicon, time, kLargeSize);
   EXPECT_LT(0, db.AddIconMapping(url, id1));
 
-  chrome::FaviconID id2 =
-      db.AddFavicon(url, chrome::FAVICON, GetFaviconSizesSmallAndLarge());
+  chrome::FaviconID id2 = db.AddFavicon(url, chrome::FAVICON);
   EXPECT_NE(id1, id2);
   db.AddFaviconBitmap(id2, favicon, time, kSmallSize);
   EXPECT_LT(0, db.AddIconMapping(url, id2));
@@ -437,6 +423,53 @@
   EXPECT_EQ(0, statement.ColumnInt(4));
 }
 
+// Test upgrading database to version 7.
+TEST_F(ThumbnailDatabaseTest, UpgradeToVersion7) {
+  ThumbnailDatabase db;
+  ASSERT_EQ(sql::INIT_OK, db.Init(file_name_, NULL, NULL));
+  db.BeginTransaction();
+
+  const char* name = "favicons";
+  std::string sql;
+  sql.append("DROP TABLE IF EXISTS ");
+  sql.append(name);
+  EXPECT_TRUE(db.db_.Execute(sql.c_str()));
+
+  sql.clear();
+  sql.append("CREATE TABLE ");
+  sql.append(name);
+  sql.append("("
+             "id INTEGER PRIMARY KEY,"
+             "url LONGVARCHAR NOT NULL,"
+             "icon_type INTEGER DEFAULT 1,"
+             "sizes LONGVARCHAR)");
+  EXPECT_TRUE(db.db_.Execute(sql.c_str()));
+
+  int favicon_id = 1;
+  GURL url("http://google.com");
+
+  sql::Statement statement;
+  statement.Assign(db.db_.GetCachedStatement(SQL_FROM_HERE,
+      "INSERT INTO favicons (id, url, icon_type, sizes) "
+      "VALUES (?, ?, ?, ?)"));
+  statement.BindInt(0, favicon_id);
+  statement.BindString(1, URLDatabase::GURLToDatabaseURL(url));
+  statement.BindInt(2, chrome::TOUCH_ICON);
+  statement.BindCString(3, "Data which happened to be there");
+  EXPECT_TRUE(statement.Run());
+
+  EXPECT_TRUE(db.UpgradeToVersion7());
+
+  EXPECT_FALSE(db.db_.DoesColumnExist("favicons", "sizes"));
+
+  statement.Assign(db.db_.GetCachedStatement(SQL_FROM_HERE,
+      "SELECT id, url, icon_type FROM favicons"));
+  EXPECT_TRUE(statement.Step());
+  EXPECT_EQ(favicon_id, statement.ColumnInt(0));
+  EXPECT_EQ(url, GURL(statement.ColumnString(1)));
+  EXPECT_EQ(chrome::TOUCH_ICON, statement.ColumnInt(2));
+}
+
 // Test that only data moved to a temporary table is left in the main table
 // once the temporary table is committed.
 TEST_F(ThumbnailDatabaseTest, TemporaryTables) {
@@ -452,13 +485,11 @@
   scoped_refptr<base::RefCountedBytes> favicon(new base::RefCountedBytes(data));
 
   GURL unkept_url("http://google.com/favicon2.ico");
-  chrome::FaviconID unkept_id = db.AddFavicon(
-      unkept_url, chrome::FAVICON, GetFaviconSizesSmallAndLarge());
+  chrome::FaviconID unkept_id = db.AddFavicon(unkept_url, chrome::FAVICON);
   db.AddFaviconBitmap(unkept_id, favicon, base::Time::Now(), kSmallSize);
 
   GURL kept_url("http://google.com/favicon.ico");
-  chrome::FaviconID kept_id =
-      db.AddFavicon(kept_url, chrome::FAVICON, GetFaviconSizesSmallAndLarge());
+  chrome::FaviconID kept_id = db.AddFavicon(kept_url, chrome::FAVICON);
   db.AddFaviconBitmap(kept_id, favicon, base::Time::Now(), kLargeSize);
 
   GURL page_url("http://google.com");
@@ -503,8 +534,7 @@
       new base::RefCountedBytes(data2));
 
   GURL url("http://google.com");
-  chrome::FaviconID id =
-      db.AddFavicon(url, chrome::FAVICON, GetFaviconSizesSmallAndLarge());
+  chrome::FaviconID id = db.AddFavicon(url, chrome::FAVICON);
   base::Time last_updated = base::Time::Now();
   db.AddFaviconBitmap(id, favicon1, last_updated, kSmallSize);
   db.AddFaviconBitmap(id, favicon2, last_updated, kLargeSize);
@@ -530,7 +560,6 @@
 
   chrome::FaviconID id = db.AddFavicon(icon_url,
                                        chrome::FAVICON,
-                                       GetDefaultFaviconSizes(),
                                        favicon,
                                        time,
                                        gfx::Size());
@@ -550,7 +579,6 @@
 
   chrome::FaviconID id2 = db.AddFavicon(icon_url,
                                         chrome::TOUCH_ICON,
-                                        GetDefaultFaviconSizes(),
                                         favicon2,
                                         time,
                                         gfx::Size());
@@ -570,7 +598,6 @@
 
   chrome::FaviconID id3 = db.AddFavicon(icon_url,
                                         chrome::TOUCH_PRECOMPOSED_ICON,
-                                        GetDefaultFaviconSizes(),
                                         favicon3,
                                         time,
                                         gfx::Size());
@@ -598,7 +625,6 @@
 
   chrome::FaviconID id1 = db.AddFavicon(url,
                                         chrome::FAVICON,
-                                        GetDefaultFaviconSizes(),
                                         favicon,
                                         time,
                                         gfx::Size());
@@ -606,7 +632,6 @@
 
   chrome::FaviconID id2 = db.AddFavicon(url,
                                         chrome::TOUCH_ICON,
-                                        GetDefaultFaviconSizes(),
                                         favicon,
                                         time,
                                         gfx::Size());
@@ -614,7 +639,6 @@
 
   chrome::FaviconID id3 = db.AddFavicon(url,
                                         chrome::TOUCH_ICON,
-                                        GetDefaultFaviconSizes(),
                                         favicon,
                                         time,
                                         gfx::Size());
@@ -665,7 +689,6 @@
   base::Time time = base::Time::Now();
   chrome::FaviconID id1 = db.AddFavicon(GURL("http://google.com"),
                                         chrome::FAVICON,
-                                        GetDefaultFaviconSizes(),
                                         favicon,
                                         time,
                                         gfx::Size());
@@ -675,7 +698,6 @@
   time = base::Time::Now();
   chrome::FaviconID id2 = db.AddFavicon(GURL("http://www.google.com/icon"),
                                         chrome::TOUCH_ICON,
-                                        GetDefaultFaviconSizes(),
                                         favicon,
                                         time,
                                         gfx::Size());
@@ -685,7 +707,6 @@
   time = base::Time::Now();
   chrome::FaviconID id3 = db.AddFavicon(GURL("http://www.google.com/icon"),
                                         chrome::TOUCH_ICON,
-                                        GetDefaultFaviconSizes(),
                                         favicon,
                                         time,
                                         gfx::Size());
@@ -717,23 +738,21 @@
 
   // Add a favicon which will have icon_mappings
   chrome::FaviconID id1 = db.AddFavicon(
-      GURL("http://google.com"), chrome::FAVICON, GetDefaultFaviconSizes());
+      GURL("http://google.com"), chrome::FAVICON);
   EXPECT_NE(0, id1);
   base::Time time = base::Time::Now();
   db.AddFaviconBitmap(id1, favicon, time, gfx::Size());
 
   // Add another type of favicon
   chrome::FaviconID id2 = db.AddFavicon(GURL("http://www.google.com/icon"),
-                                        chrome::TOUCH_ICON,
-                                        GetDefaultFaviconSizes());
+                                        chrome::TOUCH_ICON);
   EXPECT_NE(0, id2);
   time = base::Time::Now();
   db.AddFaviconBitmap(id2, favicon, time, gfx::Size());
 
   // Add 3rd favicon
   chrome::FaviconID id3 = db.AddFavicon(GURL("http://www.google.com/icon"),
-                                        chrome::TOUCH_ICON,
-                                        GetDefaultFaviconSizes());
+                                        chrome::TOUCH_ICON);
   EXPECT_NE(0, id3);
   time = base::Time::Now();
   db.AddFaviconBitmap(id3, favicon, time, gfx::Size());
@@ -834,7 +853,6 @@
   GURL icon_url1("http://google.com/favicon.ico");
   chrome::FaviconID touch_icon_id1 = db.AddFavicon(icon_url1,
                                                    chrome::TOUCH_ICON,
-                                                   GetDefaultFaviconSizes(),
                                                    favicon,
                                                    base::Time::Now(),
                                                    gfx::Size());
@@ -844,7 +862,6 @@
 
   chrome::FaviconID favicon_id1 = db.AddFavicon(icon_url1,
                                                 chrome::FAVICON,
-                                                GetDefaultFaviconSizes(),
                                                 favicon,
                                                 base::Time::Now(),
                                                 gfx::Size());
@@ -856,7 +873,6 @@
   GURL icon_url2("http://chromium.org/favicon.ico");
   chrome::FaviconID favicon_id2 = db.AddFavicon(icon_url2,
                                                 chrome::FAVICON,
-                                                GetDefaultFaviconSizes(),
                                                 favicon,
                                                 base::Time::Now(),
                                                 gfx::Size());
@@ -903,38 +919,4 @@
   EXPECT_FALSE(enumerator2.GetNextIconMapping(&icon_mapping));
 }
 
-TEST_F(ThumbnailDatabaseTest, FaviconSizesToAndFromString) {
-  // Invalid input.
-  FaviconSizes sizes_missing_height;
-  ThumbnailDatabase::DatabaseStringToFaviconSizes("0 0 10",
-      &sizes_missing_height);
-  EXPECT_EQ(0u, sizes_missing_height.size());
-
-  FaviconSizes sizes_non_int;
-  ThumbnailDatabase::DatabaseStringToFaviconSizes("0 0 a 10",
-      &sizes_non_int);
-  EXPECT_EQ(0u, sizes_non_int.size());
-
-  // Valid input.
-  FaviconSizes sizes_empty;
-  ThumbnailDatabase::DatabaseStringToFaviconSizes(std::string(), &sizes_empty);
-  EXPECT_EQ(0u, sizes_empty.size());
-
-  FaviconSizes sizes_valid;
-  ThumbnailDatabase::DatabaseStringToFaviconSizes("10 15 20 25", &sizes_valid);
-  EXPECT_EQ(2u, sizes_valid.size());
-  if (sizes_valid[0] == gfx::Size(10, 15)) {
-    EXPECT_EQ(sizes_valid[1], gfx::Size(20, 25));
-  } else {
-    EXPECT_EQ(sizes_valid[0], gfx::Size(20, 25));
-    EXPECT_EQ(sizes_valid[1], gfx::Size(10, 15));
-  }
-
-  std::string sizes_as_string;
-  ThumbnailDatabase::FaviconSizesToDatabaseString(sizes_valid,
-                                                  &sizes_as_string);
-  EXPECT_TRUE(sizes_as_string == "10 15 20 25" ||
-              sizes_as_string == "20 25 10 15");
-}
-
 }  // namespace history
diff --git a/chrome/browser/history/top_sites.h b/chrome/browser/history/top_sites.h
index 47351ad..b55821d 100644
--- a/chrome/browser/history/top_sites.h
+++ b/chrome/browser/history/top_sites.h
@@ -13,9 +13,9 @@
 #include "chrome/browser/history/history_service.h"
 #include "chrome/browser/history/history_types.h"
 #include "chrome/common/thumbnail_score.h"
-#include "googleurl/src/gurl.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "ui/gfx/image/image.h"
+#include "url/gurl.h"
 
 class Profile;
 
diff --git a/chrome/browser/history/top_sites_backend.cc b/chrome/browser/history/top_sites_backend.cc
index bdf589c..58bf38d 100644
--- a/chrome/browser/history/top_sites_backend.cc
+++ b/chrome/browser/history/top_sites_backend.cc
@@ -6,7 +6,6 @@
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
-#include "base/file_util.h"
 #include "base/files/file_path.h"
 #include "base/memory/ref_counted.h"
 #include "chrome/browser/history/top_sites_database.h"
@@ -137,7 +136,7 @@
 void TopSitesBackend::ResetDatabaseOnDBThread(const base::FilePath& file_path) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
   db_.reset(NULL);
-  file_util::Delete(db_path_, false);
+  sql::Connection::Delete(db_path_);
   db_.reset(new TopSitesDatabase());
   InitDBOnDBThread(db_path_);
 }
diff --git a/chrome/browser/history/top_sites_database.cc b/chrome/browser/history/top_sites_database.cc
index f63dc16..ec0e1de 100644
--- a/chrome/browser/history/top_sites_database.cc
+++ b/chrome/browser/history/top_sites_database.cc
@@ -43,9 +43,7 @@
     // the entries as they are no longer applicable, but it's safest to just
     // remove the file and start over.
     db_.reset(NULL);
-    if (!file_util::Delete(db_name, false) &&
-        !file_util::Delete(db_name, false)) {
-      // Try to delete twice. If we can't, fail.
+    if (!sql::Connection::Delete(db_name)) {
       LOG(ERROR) << "unable to delete old TopSites file";
       return false;
     }
diff --git a/chrome/browser/history/top_sites_impl.h b/chrome/browser/history/top_sites_impl.h
index f76aaab..025ac4d 100644
--- a/chrome/browser/history/top_sites_impl.h
+++ b/chrome/browser/history/top_sites_impl.h
@@ -16,8 +16,8 @@
 #include "base/gtest_prod_util.h"
 #include "base/memory/ref_counted.h"
 #include "base/synchronization/lock.h"
-#include "base/time.h"
-#include "base/timer.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
 #include "chrome/browser/common/cancelable_request.h"
 #include "chrome/browser/history/history_service.h"
 #include "chrome/browser/history/history_types.h"
@@ -26,9 +26,9 @@
 #include "chrome/browser/history/top_sites_backend.h"
 #include "chrome/common/cancelable_task_tracker.h"
 #include "chrome/common/thumbnail_score.h"
-#include "googleurl/src/gurl.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "ui/gfx/image/image.h"
+#include "url/gurl.h"
 
 class Profile;
 
diff --git a/chrome/browser/history/top_sites_impl_unittest.cc b/chrome/browser/history/top_sites_impl_unittest.cc
index 5f5179e..566e8e9 100644
--- a/chrome/browser/history/top_sites_impl_unittest.cc
+++ b/chrome/browser/history/top_sites_impl_unittest.cc
@@ -33,7 +33,6 @@
 #include "chrome/tools/profiles/thumbnail-inl.h"
 #include "content/public/test/test_browser_thread.h"
 #include "content/public/test/test_utils.h"
-#include "googleurl/src/gurl.h"
 #include "grit/chromium_strings.h"
 #include "grit/generated_resources.h"
 #include "grit/locale_settings.h"
@@ -41,6 +40,7 @@
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/gfx/codec/jpeg_codec.h"
+#include "url/gurl.h"
 
 using content::BrowserThread;
 
@@ -1198,8 +1198,8 @@
 
   // Remove the TopSites file. This forces TopSites to wait until history loads
   // before TopSites is considered loaded.
-  file_util::Delete(profile()->GetPath().Append(chrome::kTopSitesFilename),
-                    false);
+  sql::Connection::Delete(
+      profile()->GetPath().Append(chrome::kTopSitesFilename));
 
   // Create TopSites, but not History.
   profile()->CreateTopSites();
diff --git a/chrome/browser/history/top_sites_likely_impl.h b/chrome/browser/history/top_sites_likely_impl.h
index 7080f22..89122d4 100644
--- a/chrome/browser/history/top_sites_likely_impl.h
+++ b/chrome/browser/history/top_sites_likely_impl.h
@@ -16,8 +16,8 @@
 #include "base/gtest_prod_util.h"
 #include "base/memory/ref_counted.h"
 #include "base/synchronization/lock.h"
-#include "base/time.h"
-#include "base/timer.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
 #include "chrome/browser/common/cancelable_request.h"
 #include "chrome/browser/history/history_service.h"
 #include "chrome/browser/history/history_types.h"
@@ -26,9 +26,9 @@
 #include "chrome/browser/history/top_sites_backend.h"
 #include "chrome/common/cancelable_task_tracker.h"
 #include "chrome/common/thumbnail_score.h"
-#include "googleurl/src/gurl.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "ui/gfx/image/image.h"
+#include "url/gurl.h"
 
 class Profile;
 
diff --git a/chrome/browser/history/top_sites_likely_impl_unittest.cc b/chrome/browser/history/top_sites_likely_impl_unittest.cc
index 34eb652..14529ca 100644
--- a/chrome/browser/history/top_sites_likely_impl_unittest.cc
+++ b/chrome/browser/history/top_sites_likely_impl_unittest.cc
@@ -33,7 +33,6 @@
 #include "chrome/tools/profiles/thumbnail-inl.h"
 #include "content/public/test/test_browser_thread.h"
 #include "content/public/test/test_utils.h"
-#include "googleurl/src/gurl.h"
 #include "grit/chromium_strings.h"
 #include "grit/generated_resources.h"
 #include "grit/locale_settings.h"
@@ -41,6 +40,7 @@
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/gfx/codec/jpeg_codec.h"
+#include "url/gurl.h"
 
 using content::BrowserThread;
 
@@ -1199,8 +1199,8 @@
 
   // Remove the TopSites file. This forces TopSites to wait until history loads
   // before TopSites is considered loaded.
-  file_util::Delete(profile()->GetPath().Append(chrome::kTopSitesFilename),
-                    false);
+  sql::Connection::Delete(
+      profile()->GetPath().Append(chrome::kTopSitesFilename));
 
   // Create TopSites, but not History.
   profile()->CreateTopSites();
diff --git a/chrome/browser/history/typed_url_syncable_service.cc b/chrome/browser/history/typed_url_syncable_service.cc
index 3b6d57e..fcb3cfa 100644
--- a/chrome/browser/history/typed_url_syncable_service.cc
+++ b/chrome/browser/history/typed_url_syncable_service.cc
@@ -119,6 +119,7 @@
   // TODO(mgist): Add implementation
 
   return syncer::SyncError(FROM_HERE,
+                           syncer::SyncError::DATATYPE_ERROR,
                            "Typed url syncable service is not implemented.",
                            syncer::TYPED_URLS);
 }
diff --git a/chrome/browser/history/url_database.cc b/chrome/browser/history/url_database.cc
index 0856d25..4f5a72d 100644
--- a/chrome/browser/history/url_database.cc
+++ b/chrome/browser/history/url_database.cc
@@ -12,9 +12,9 @@
 #include "base/i18n/case_conversion.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/common/url_constants.h"
-#include "googleurl/src/gurl.h"
 #include "sql/statement.h"
 #include "ui/base/l10n/l10n_util.h"
+#include "url/gurl.h"
 
 namespace history {
 
@@ -358,6 +358,32 @@
   return true;
 }
 
+bool URLDatabase::GetTextMatches(const string16& query,
+                                 URLRows* results) {
+  ScopedVector<QueryNode> query_nodes;
+  query_parser_.ParseQueryNodes(query, &query_nodes.get());
+
+  results->clear();
+  sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
+      "SELECT" HISTORY_URL_ROW_FIELDS "FROM urls WHERE hidden = 0"));
+
+  while (statement.Step()) {
+    std::vector<QueryWord> query_words;
+    string16 url = base::i18n::ToLower(statement.ColumnString16(1));
+    query_parser_.ExtractQueryWords(url, &query_words);
+    string16 title = base::i18n::ToLower(statement.ColumnString16(2));
+    query_parser_.ExtractQueryWords(title, &query_words);
+
+    if (query_parser_.DoesQueryMatch(query_words, query_nodes.get())) {
+      history::URLResult info;
+      FillURLRow(statement, &info);
+      if (info.url().is_valid())
+        results->push_back(info);
+    }
+  }
+  return !results->empty();
+}
+
 bool URLDatabase::InitKeywordSearchTermsTable() {
   has_keyword_search_terms_ = true;
   if (!GetDB().DoesTableExist("keyword_search_terms")) {
diff --git a/chrome/browser/history/url_database.h b/chrome/browser/history/url_database.h
index 5cf44c2..c486560 100644
--- a/chrome/browser/history/url_database.h
+++ b/chrome/browser/history/url_database.h
@@ -7,6 +7,7 @@
 
 #include "base/basictypes.h"
 #include "chrome/browser/history/history_types.h"
+#include "chrome/browser/history/query_parser.h"
 #include "chrome/browser/search_engines/template_url_id.h"
 #include "sql/statement.h"
 
@@ -189,6 +190,12 @@
                                bool allow_base,
                                history::URLRow* info);
 
+  // History search ------------------------------------------------------------
+
+  // Performs a brute force search over the database to find any URLs or titles
+  // which match the |query| string.  Returns any matches in |results|.
+  bool GetTextMatches(const string16& query, URLRows* results);
+
   // Keyword Search Terms ------------------------------------------------------
 
   // Sets the search terms for the specified url/keyword pair.
@@ -289,6 +296,8 @@
   // have keyword search terms.
   bool has_keyword_search_terms_;
 
+  QueryParser query_parser_;
+
   DISALLOW_COPY_AND_ASSIGN(URLDatabase);
 };
 
@@ -303,6 +312,6 @@
     " urls.id, urls.url, urls.title, urls.visit_count, urls.typed_count, " \
     "urls.last_visit_time, urls.hidden "
 
-}  // history
+}  // namespace history
 
 #endif  // CHROME_BROWSER_HISTORY_URL_DATABASE_H_
diff --git a/chrome/browser/history/url_index_private_data.cc b/chrome/browser/history/url_index_private_data.cc
index 9ddd230..3315adb 100644
--- a/chrome/browser/history/url_index_private_data.cc
+++ b/chrome/browser/history/url_index_private_data.cc
@@ -18,7 +18,7 @@
 #include "base/metrics/histogram.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/autocomplete/autocomplete_provider.h"
 #include "chrome/browser/autocomplete/url_prefix.h"
 #include "chrome/browser/bookmarks/bookmark_service.h"
diff --git a/chrome/browser/history/visit_database.cc b/chrome/browser/history/visit_database.cc
index 4ef7f21..883fe6f 100644
--- a/chrome/browser/history/visit_database.cc
+++ b/chrome/browser/history/visit_database.cc
@@ -118,6 +118,39 @@
   return statement.Succeeded();
 }
 
+// static
+bool VisitDatabase::FillVisitVectorWithOptions(sql::Statement& statement,
+                                               const QueryOptions& options,
+                                               VisitVector* visits) {
+  std::set<URLID> found_urls;
+
+  // Keeps track of the day that |found_urls| is holding the URLs for, in order
+  // to handle removing per-day duplicates.
+  base::Time found_urls_midnight;
+
+  while (statement.Step()) {
+    VisitRow visit;
+    FillVisitRow(statement, &visit);
+
+    if (options.duplicate_policy != QueryOptions::KEEP_ALL_DUPLICATES) {
+      if (options.duplicate_policy == QueryOptions::REMOVE_DUPLICATES_PER_DAY &&
+          found_urls_midnight != visit.visit_time.LocalMidnight()) {
+        found_urls.clear();
+        found_urls_midnight = visit.visit_time.LocalMidnight();
+      }
+      // Make sure the URL this visit corresponds to is unique.
+      if (found_urls.find(visit.url_id) != found_urls.end())
+        continue;
+      found_urls.insert(visit.url_id);
+    }
+
+    if (static_cast<int>(visits->size()) >= options.EffectiveMaxCount())
+      return true;
+    visits->push_back(visit);
+  }
+  return false;
+}
+
 VisitID VisitDatabase::AddVisit(VisitRow* visit, VisitSource source) {
   sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
       "INSERT INTO visits "
@@ -245,6 +278,31 @@
   return FillVisitVector(statement, visits);
 }
 
+bool VisitDatabase::GetVisitsForURLWithOptions(URLID url_id,
+                                               const QueryOptions& options,
+                                               VisitVector* visits) {
+  visits->clear();
+
+  if (options.REMOVE_ALL_DUPLICATES) {
+    VisitRow visit_row;
+    VisitID visit_id = GetMostRecentVisitForURL(url_id, &visit_row);
+    if (visit_id && options.EffectiveMaxCount() != 0) {
+      visits->push_back(visit_row);
+    }
+    return options.EffectiveMaxCount() == 0 && visit_id;
+  } else {
+    sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
+        "SELECT" HISTORY_VISIT_ROW_FIELDS
+        "FROM visits "
+        "WHERE url=? AND visit_time >= ? AND visit_time < ? "
+        "ORDER BY visit_time DESC"));
+    statement.BindInt64(0, url_id);
+    statement.BindInt64(1, options.EffectiveBeginTime());
+    statement.BindInt64(2, options.EffectiveEndTime());
+
+    return FillVisitVectorWithOptions(statement, options, visits);
+  }
+}
 
 bool VisitDatabase::GetVisitsForTimes(const std::vector<base::Time>& times,
                                       VisitVector* visits) {
@@ -333,33 +391,7 @@
   statement.BindInt(5, content::PAGE_TRANSITION_MANUAL_SUBFRAME);
   statement.BindInt(6, content::PAGE_TRANSITION_KEYWORD_GENERATED);
 
-  std::set<URLID> found_urls;
-
-  // Keeps track of the day that |found_urls| is holding the URLs for, in order
-  // to handle removing per-day duplicates.
-  base::Time found_urls_midnight;
-
-  while (statement.Step()) {
-    VisitRow visit;
-    FillVisitRow(statement, &visit);
-
-    if (options.duplicate_policy != QueryOptions::KEEP_ALL_DUPLICATES) {
-      if (options.duplicate_policy == QueryOptions::REMOVE_DUPLICATES_PER_DAY &&
-          found_urls_midnight != visit.visit_time.LocalMidnight()) {
-        found_urls.clear();
-        found_urls_midnight = visit.visit_time.LocalMidnight();
-      }
-      // Make sure the URL this visit corresponds to is unique.
-      if (found_urls.find(visit.url_id) != found_urls.end())
-        continue;
-      found_urls.insert(visit.url_id);
-    }
-
-    if (static_cast<int>(visits->size()) >= options.EffectiveMaxCount())
-      return true;
-    visits->push_back(visit);
-  }
-  return false;
+  return FillVisitVectorWithOptions(statement, options, visits);
 }
 
 void VisitDatabase::GetDirectVisitsDuringTimes(const VisitFilter& time_filter,
diff --git a/chrome/browser/history/visit_database.h b/chrome/browser/history/visit_database.h
index 18efc3c..effaa8f 100644
--- a/chrome/browser/history/visit_database.h
+++ b/chrome/browser/history/visit_database.h
@@ -63,6 +63,15 @@
   // Returns true on success (although there may still be no matches).
   bool GetIndexedVisitsForURL(URLID url_id, VisitVector* visits);
 
+  // Fills in the given vector with the visits for the given page ID which
+  // match the set of options passed, sorted in ascending order of date.
+  //
+  // Returns true if there are more results available, i.e. if the number of
+  // results was restricted by |options.max_count|.
+  bool GetVisitsForURLWithOptions(URLID url_id,
+                                  const QueryOptions& options,
+                                  VisitVector* visits);
+
   // Fills the vector with all visits with times in the given list.
   //
   // The results will be in no particular order.  Also, no duplicate
@@ -202,6 +211,14 @@
   // hasn't happened yet.
   static bool FillVisitVector(sql::Statement& statement, VisitVector* visits);
 
+  // Convenience to fill a VisitVector while respecting the set of options.
+  // |statement| should order the query decending by visit_time to ensure
+  // correct duplicate management behavior. Assumes that statement.step()
+  // hasn't happened yet.
+  static bool FillVisitVectorWithOptions(sql::Statement& statement,
+                                         const QueryOptions& options,
+                                         VisitVector* visits);
+
   // Called by the derived classes to migrate the older visits table which
   // don't have visit_duration column yet.
   bool MigrateVisitsWithoutDuration();
@@ -216,6 +233,6 @@
     " id,url,visit_time,from_visit,transition,segment_id,is_indexed," \
     "visit_duration "
 
-}  // history
+}  // namespace history
 
 #endif  // CHROME_BROWSER_HISTORY_VISIT_DATABASE_H_
diff --git a/chrome/browser/history/visit_database_unittest.cc b/chrome/browser/history/visit_database_unittest.cc
index cac1394..a6146b4 100644
--- a/chrome/browser/history/visit_database_unittest.cc
+++ b/chrome/browser/history/visit_database_unittest.cc
@@ -9,7 +9,7 @@
 #include "base/files/scoped_temp_dir.h"
 #include "base/path_service.h"
 #include "base/strings/string_util.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/history/url_database.h"
 #include "chrome/browser/history/visit_database.h"
 #include "sql/connection.h"
diff --git a/chrome/browser/history/visit_filter.cc b/chrome/browser/history/visit_filter.cc
index 32ca426..0a5ab74 100644
--- a/chrome/browser/history/visit_filter.cc
+++ b/chrome/browser/history/visit_filter.cc
@@ -9,7 +9,7 @@
 #include <algorithm>
 
 #include "base/logging.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/history/history_types.h"
 
 namespace history {
diff --git a/chrome/browser/history/visit_filter.h b/chrome/browser/history/visit_filter.h
index ce68f98..deeacf3 100644
--- a/chrome/browser/history/visit_filter.h
+++ b/chrome/browser/history/visit_filter.h
@@ -8,7 +8,7 @@
 #include <vector>
 
 #include "base/gtest_prod_util.h"
-#include "base/time.h"
+#include "base/time/time.h"
 
 namespace history {
 
diff --git a/chrome/browser/history/visit_filter_unittest.cc b/chrome/browser/history/visit_filter_unittest.cc
index bc0b7b2..f100ad7 100644
--- a/chrome/browser/history/visit_filter_unittest.cc
+++ b/chrome/browser/history/visit_filter_unittest.cc
@@ -7,7 +7,7 @@
 #include <math.h>
 
 #include "base/logging.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/history/history_types.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/chrome/browser/history/web_history_service.cc b/chrome/browser/history/web_history_service.cc
index cea7f2f..8e91d69 100644
--- a/chrome/browser/history/web_history_service.cc
+++ b/chrome/browser/history/web_history_service.cc
@@ -16,13 +16,13 @@
 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
 #include "google_apis/gaia/gaia_urls.h"
 #include "google_apis/gaia/google_service_auth_error.h"
-#include "googleurl/src/gurl.h"
 #include "net/base/load_flags.h"
 #include "net/base/url_util.h"
 #include "net/http/http_status_code.h"
 #include "net/http/http_util.h"
 #include "net/url_request/url_fetcher.h"
 #include "net/url_request/url_fetcher_delegate.h"
+#include "url/gurl.h"
 
 namespace history {
 
diff --git a/chrome/browser/icon_loader_linux.cc b/chrome/browser/icon_loader_linux.cc
index 3860ea0..acecd0a 100644
--- a/chrome/browser/icon_loader_linux.cc
+++ b/chrome/browser/icon_loader_linux.cc
@@ -11,9 +11,10 @@
 #include "base/logging.h"
 #include "base/message_loop.h"
 #include "base/nix/mime_util_xdg.h"
+#include "content/public/child/image_decoder_utils.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/gfx/image/image_skia.h"
-#include "webkit/glue/image_decoder.h"
+#include "ui/gfx/size.h"
 
 using std::string;
 
@@ -50,10 +51,10 @@
     string icon_data;
     file_util::ReadFileToString(filename, &icon_data);
 
-    webkit_glue::ImageDecoder decoder;
     SkBitmap bitmap;
-    bitmap = decoder.Decode(
+    bitmap = content::DecodeImage(
         reinterpret_cast<const unsigned char*>(icon_data.data()),
+        gfx::Size(),
         icon_data.length());
     if (!bitmap.empty()) {
       DCHECK_EQ(size_pixels, bitmap.width());
diff --git a/chrome/browser/idle_chromeos.cc b/chrome/browser/idle_chromeos.cc
index 9bb2f12..aa8c221 100644
--- a/chrome/browser/idle_chromeos.cc
+++ b/chrome/browser/idle_chromeos.cc
@@ -7,7 +7,7 @@
 #include "ash/session_state_delegate.h"
 #include "ash/shell.h"
 #include "ash/wm/user_activity_detector.h"
-#include "base/time.h"
+#include "base/time/time.h"
 
 void CalculateIdleTime(IdleTimeCallback notify) {
   base::TimeDelta idle_time = base::TimeTicks::Now() -
diff --git a/chrome/browser/iframe_browsertest.cc b/chrome/browser/iframe_browsertest.cc
index 3f650e3..941cb3f 100644
--- a/chrome/browser/iframe_browsertest.cc
+++ b/chrome/browser/iframe_browsertest.cc
@@ -9,7 +9,7 @@
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "content/public/browser/web_contents.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 class IFrameTest : public InProcessBrowserTest {
  protected:
diff --git a/chrome/browser/importer/bookmark_html_reader.cc b/chrome/browser/importer/bookmark_html_reader.cc
new file mode 100644
index 0000000..e618bad
--- /dev/null
+++ b/chrome/browser/importer/bookmark_html_reader.cc
@@ -0,0 +1,432 @@
+// 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/importer/bookmark_html_reader.h"
+
+#include "base/callback.h"
+#include "base/file_util.h"
+#include "base/i18n/icu_string_conversions.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
+#include "base/time/time.h"
+#include "chrome/browser/favicon/favicon_util.h"
+#include "chrome/common/importer/imported_bookmark_entry.h"
+#include "chrome/common/importer/imported_favicon_usage.h"
+#include "content/public/common/url_constants.h"
+#include "net/base/data_url.h"
+#include "net/base/escape.h"
+#include "url/gurl.h"
+
+namespace {
+
+// Fetches the given |attribute| value from the |attribute_list|. Returns true
+// if successful, and |value| will contain the value.
+bool GetAttribute(const std::string& attribute_list,
+                  const std::string& attribute,
+                  std::string* value) {
+  const char kQuote[] = "\"";
+
+  size_t begin = attribute_list.find(attribute + "=" + kQuote);
+  if (begin == std::string::npos)
+    return false;  // Can't find the attribute.
+
+  begin += attribute.size() + 2;
+  size_t end = begin + 1;
+
+  while (end < attribute_list.size()) {
+    if (attribute_list[end] == '"' &&
+        attribute_list[end - 1] != '\\') {
+      break;
+    }
+    end++;
+  }
+
+  if (end == attribute_list.size())
+    return false;  // The value is not quoted.
+
+  *value = attribute_list.substr(begin, end - begin);
+  return true;
+}
+
+// Given the URL of a page and a favicon data URL, adds an appropriate record
+// to the given favicon usage vector.
+void DataURLToFaviconUsage(
+    const GURL& link_url,
+    const GURL& favicon_data,
+    std::vector<ImportedFaviconUsage>* favicons) {
+  if (!link_url.is_valid() || !favicon_data.is_valid() ||
+      !favicon_data.SchemeIs(chrome::kDataScheme))
+    return;
+
+  // Parse the data URL.
+  std::string mime_type, char_set, data;
+  if (!net::DataURL::Parse(favicon_data, &mime_type, &char_set, &data) ||
+      data.empty())
+    return;
+
+  ImportedFaviconUsage usage;
+  if (!FaviconUtil::ReencodeFavicon(
+          reinterpret_cast<const unsigned char*>(&data[0]),
+          data.size(), &usage.png_data))
+    return;  // Unable to decode.
+
+  // We need to make up a URL for the favicon. We use a version of the page's
+  // URL so that we can be sure it will not collide.
+  usage.favicon_url = GURL(std::string("made-up-favicon:") + link_url.spec());
+
+  // We only have one URL per favicon for Firefox 2 bookmarks.
+  usage.urls.insert(link_url);
+
+  favicons->push_back(usage);
+}
+
+}  // namespace
+
+namespace bookmark_html_reader {
+
+void ImportBookmarksFile(
+      const base::Callback<bool(void)>& cancellation_callback,
+      const base::Callback<bool(const GURL&)>& valid_url_callback,
+      const base::FilePath& file_path,
+      std::vector<ImportedBookmarkEntry>* bookmarks,
+      std::vector<ImportedFaviconUsage>* favicons) {
+  std::string content;
+  file_util::ReadFileToString(file_path, &content);
+  std::vector<std::string> lines;
+  base::SplitString(content, '\n', &lines);
+
+  base::string16 last_folder;
+  bool last_folder_on_toolbar = false;
+  bool last_folder_is_empty = true;
+  bool has_subfolder = false;
+  base::Time last_folder_add_date;
+  std::vector<base::string16> path;
+  size_t toolbar_folder_index = 0;
+  std::string charset;
+  for (size_t i = 0;
+       i < lines.size() &&
+           (cancellation_callback.is_null() || !cancellation_callback.Run());
+       ++i) {
+    std::string line;
+    TrimString(lines[i], " ", &line);
+
+    // Get the encoding of the bookmark file.
+    if (internal::ParseCharsetFromLine(line, &charset))
+      continue;
+
+    // Get the folder name.
+    if (internal::ParseFolderNameFromLine(line,
+                                          charset,
+                                          &last_folder,
+                                          &last_folder_on_toolbar,
+                                          &last_folder_add_date)) {
+      continue;
+    }
+
+    // Get the bookmark entry.
+    base::string16 title;
+    base::string16 shortcut;
+    GURL url, favicon;
+    base::Time add_date;
+    base::string16 post_data;
+    bool is_bookmark;
+    // TODO(jcampan): http://b/issue?id=1196285 we do not support POST based
+    //                keywords yet.
+    is_bookmark =
+        internal::ParseBookmarkFromLine(line, charset, &title,
+                                        &url, &favicon, &shortcut,
+                                        &add_date, &post_data) ||
+        internal::ParseMinimumBookmarkFromLine(line, charset, &title, &url);
+
+    if (is_bookmark)
+      last_folder_is_empty = false;
+
+    if (is_bookmark &&
+        post_data.empty() &&
+        (valid_url_callback.is_null() || valid_url_callback.Run(url))) {
+      if (toolbar_folder_index > path.size() && !path.empty()) {
+        NOTREACHED();  // error in parsing.
+        break;
+      }
+
+      ImportedBookmarkEntry entry;
+      entry.creation_time = add_date;
+      entry.url = url;
+      entry.title = title;
+
+      if (toolbar_folder_index) {
+        // The toolbar folder should be at the top level.
+        entry.in_toolbar = true;
+        entry.path.assign(path.begin() + toolbar_folder_index - 1, path.end());
+      } else {
+        // Add this bookmark to the list of |bookmarks|.
+        if (!has_subfolder && !last_folder.empty()) {
+          path.push_back(last_folder);
+          last_folder.clear();
+        }
+        entry.path.assign(path.begin(), path.end());
+      }
+      bookmarks->push_back(entry);
+
+      // Save the favicon. DataURLToFaviconUsage will handle the case where
+      // there is no favicon.
+      if (favicons)
+        DataURLToFaviconUsage(url, favicon, favicons);
+
+      continue;
+    }
+
+    // Bookmarks in sub-folder are encapsulated with <DL> tag.
+    if (StartsWithASCII(line, "<DL>", false)) {
+      has_subfolder = true;
+      if (!last_folder.empty()) {
+        path.push_back(last_folder);
+        last_folder.clear();
+      }
+      if (last_folder_on_toolbar && !toolbar_folder_index)
+        toolbar_folder_index = path.size();
+
+      // Mark next folder empty as initial state.
+      last_folder_is_empty = true;
+    } else if (StartsWithASCII(line, "</DL>", false)) {
+      if (path.empty())
+        break;  // Mismatch <DL>.
+
+      base::string16 folder_title = path.back();
+      path.pop_back();
+
+      if (last_folder_is_empty) {
+        // Empty folder should be added explicitly.
+        ImportedBookmarkEntry entry;
+        entry.is_folder = true;
+        entry.creation_time = last_folder_add_date;
+        entry.title = folder_title;
+        if (toolbar_folder_index) {
+          // The toolbar folder should be at the top level.
+          // Make sure we don't add the toolbar folder itself if it is empty.
+          if (toolbar_folder_index <= path.size()) {
+            entry.in_toolbar = true;
+            entry.path.assign(path.begin() + toolbar_folder_index - 1,
+                              path.end());
+            bookmarks->push_back(entry);
+          }
+        } else {
+          // Add this folder to the list of |bookmarks|.
+          entry.path.assign(path.begin(), path.end());
+          bookmarks->push_back(entry);
+        }
+
+        // Parent folder include current one, so it's not empty.
+        last_folder_is_empty = false;
+      }
+
+      if (toolbar_folder_index > path.size())
+        toolbar_folder_index = 0;
+    }
+  }
+}
+
+namespace internal {
+
+bool ParseCharsetFromLine(const std::string& line, std::string* charset) {
+  const char kCharset[] = "charset=";
+  if (StartsWithASCII(line, "<META", false) &&
+      (line.find("CONTENT=\"") != std::string::npos ||
+          line.find("content=\"") != std::string::npos)) {
+    size_t begin = line.find(kCharset);
+    if (begin == std::string::npos)
+      return false;
+    begin += std::string(kCharset).size();
+    size_t end = line.find_first_of('\"', begin);
+    *charset = line.substr(begin, end - begin);
+    return true;
+  }
+  return false;
+}
+
+bool ParseFolderNameFromLine(const std::string& line,
+                             const std::string& charset,
+                             base::string16* folder_name,
+                             bool* is_toolbar_folder,
+                             base::Time* add_date) {
+  const char kFolderOpen[] = "<DT><H3";
+  const char kFolderClose[] = "</H3>";
+  const char kToolbarFolderAttribute[] = "PERSONAL_TOOLBAR_FOLDER";
+  const char kAddDateAttribute[] = "ADD_DATE";
+
+  if (!StartsWithASCII(line, kFolderOpen, true))
+    return false;
+
+  size_t end = line.find(kFolderClose);
+  size_t tag_end = line.rfind('>', end) + 1;
+  // If no end tag or start tag is broken, we skip to find the folder name.
+  if (end == std::string::npos || tag_end < arraysize(kFolderOpen))
+    return false;
+
+  base::CodepageToUTF16(line.substr(tag_end, end - tag_end), charset.c_str(),
+                        base::OnStringConversionError::SKIP, folder_name);
+  *folder_name = net::UnescapeForHTML(*folder_name);
+
+  std::string attribute_list = line.substr(arraysize(kFolderOpen),
+      tag_end - arraysize(kFolderOpen) - 1);
+  std::string value;
+
+  // Add date
+  if (GetAttribute(attribute_list, kAddDateAttribute, &value)) {
+    int64 time;
+    base::StringToInt64(value, &time);
+    // Upper bound it at 32 bits.
+    if (0 < time && time < (1LL << 32))
+      *add_date = base::Time::FromTimeT(time);
+  }
+
+  if (GetAttribute(attribute_list, kToolbarFolderAttribute, &value) &&
+      LowerCaseEqualsASCII(value, "true"))
+    *is_toolbar_folder = true;
+  else
+    *is_toolbar_folder = false;
+
+  return true;
+}
+
+bool ParseBookmarkFromLine(const std::string& line,
+                           const std::string& charset,
+                           base::string16* title,
+                           GURL* url,
+                           GURL* favicon,
+                           base::string16* shortcut,
+                           base::Time* add_date,
+                           base::string16* post_data) {
+  const char kItemOpen[] = "<DT><A";
+  const char kItemClose[] = "</A>";
+  const char kFeedURLAttribute[] = "FEEDURL";
+  const char kHrefAttribute[] = "HREF";
+  const char kIconAttribute[] = "ICON";
+  const char kShortcutURLAttribute[] = "SHORTCUTURL";
+  const char kAddDateAttribute[] = "ADD_DATE";
+  const char kPostDataAttribute[] = "POST_DATA";
+
+  title->clear();
+  *url = GURL();
+  *favicon = GURL();
+  shortcut->clear();
+  post_data->clear();
+  *add_date = base::Time();
+
+  if (!StartsWithASCII(line, kItemOpen, true))
+    return false;
+
+  size_t end = line.find(kItemClose);
+  size_t tag_end = line.rfind('>', end) + 1;
+  if (end == std::string::npos || tag_end < arraysize(kItemOpen))
+    return false;  // No end tag or start tag is broken.
+
+  std::string attribute_list = line.substr(arraysize(kItemOpen),
+      tag_end - arraysize(kItemOpen) - 1);
+
+  // We don't import Live Bookmark folders, which is Firefox's RSS reading
+  // feature, since the user never necessarily bookmarked them and we don't
+  // have this feature to update their contents.
+  std::string value;
+  if (GetAttribute(attribute_list, kFeedURLAttribute, &value))
+    return false;
+
+  // Title
+  base::CodepageToUTF16(line.substr(tag_end, end - tag_end), charset.c_str(),
+                        base::OnStringConversionError::SKIP, title);
+  *title = net::UnescapeForHTML(*title);
+
+  // URL
+  if (GetAttribute(attribute_list, kHrefAttribute, &value)) {
+    base::string16 url16;
+    base::CodepageToUTF16(value, charset.c_str(),
+                          base::OnStringConversionError::SKIP, &url16);
+    url16 = net::UnescapeForHTML(url16);
+
+    *url = GURL(url16);
+  }
+
+  // Favicon
+  if (GetAttribute(attribute_list, kIconAttribute, &value))
+    *favicon = GURL(value);
+
+  // Keyword
+  if (GetAttribute(attribute_list, kShortcutURLAttribute, &value)) {
+    base::CodepageToUTF16(value, charset.c_str(),
+                          base::OnStringConversionError::SKIP, shortcut);
+    *shortcut = net::UnescapeForHTML(*shortcut);
+  }
+
+  // Add date
+  if (GetAttribute(attribute_list, kAddDateAttribute, &value)) {
+    int64 time;
+    base::StringToInt64(value, &time);
+    // Upper bound it at 32 bits.
+    if (0 < time && time < (1LL << 32))
+      *add_date = base::Time::FromTimeT(time);
+  }
+
+  // Post data.
+  if (GetAttribute(attribute_list, kPostDataAttribute, &value)) {
+    base::CodepageToUTF16(value, charset.c_str(),
+                          base::OnStringConversionError::SKIP, post_data);
+    *post_data = net::UnescapeForHTML(*post_data);
+  }
+
+  return true;
+}
+
+bool ParseMinimumBookmarkFromLine(const std::string& line,
+                                  const std::string& charset,
+                                  base::string16* title,
+                                  GURL* url) {
+  const char kItemOpen[] = "<DT><A";
+  const char kItemClose[] = "</";
+  const char kHrefAttributeUpper[] = "HREF";
+  const char kHrefAttributeLower[] = "href";
+
+  title->clear();
+  *url = GURL();
+
+  // Case-insensitive check of open tag.
+  if (!StartsWithASCII(line, kItemOpen, false))
+    return false;
+
+  // Find any close tag.
+  size_t end = line.find(kItemClose);
+  size_t tag_end = line.rfind('>', end) + 1;
+  if (end == std::string::npos || tag_end < arraysize(kItemOpen))
+    return false;  // No end tag or start tag is broken.
+
+  std::string attribute_list = line.substr(arraysize(kItemOpen),
+      tag_end - arraysize(kItemOpen) - 1);
+
+  // Title
+  base::CodepageToUTF16(line.substr(tag_end, end - tag_end), charset.c_str(),
+                        base::OnStringConversionError::SKIP, title);
+  *title = net::UnescapeForHTML(*title);
+
+  // URL
+  std::string value;
+  if (GetAttribute(attribute_list, kHrefAttributeUpper, &value) ||
+      GetAttribute(attribute_list, kHrefAttributeLower, &value)) {
+    if (charset.length() != 0) {
+      base::string16 url16;
+      base::CodepageToUTF16(value, charset.c_str(),
+                            base::OnStringConversionError::SKIP, &url16);
+      url16 = net::UnescapeForHTML(url16);
+
+      *url = GURL(url16);
+    } else {
+      *url = GURL(value);
+    }
+  }
+
+  return true;
+}
+
+}  // namespace internal
+
+}  // namespace bookmark_html_reader
diff --git a/chrome/browser/importer/bookmark_html_reader.h b/chrome/browser/importer/bookmark_html_reader.h
new file mode 100644
index 0000000..5d34ab2
--- /dev/null
+++ b/chrome/browser/importer/bookmark_html_reader.h
@@ -0,0 +1,97 @@
+// 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_IMPORTER_BOOKMARK_HTML_READER_H_
+#define CHROME_BROWSER_IMPORTER_BOOKMARK_HTML_READER_H_
+
+#include <string>
+#include <vector>
+
+#include "base/callback_forward.h"
+#include "base/strings/string16.h"
+
+class GURL;
+struct ImportedBookmarkEntry;
+struct ImportedFaviconUsage;
+
+namespace base {
+class FilePath;
+class Time;
+}
+
+namespace bookmark_html_reader {
+
+// Imports the bookmarks from the specified file.
+//
+// |cancellation_callback| is polled to query if the import should be cancelled;
+// if it returns |true| at any time the import will be cancelled. If
+// |cancellation_callback| is a null callback the import will run to completion.
+//
+// |valid_url_callback| is called to determine if a specified URL is valid for
+// import; it returns |true| if it is. If |valid_url_callback| is a null
+// callback, all URLs are considered to be valid.
+//
+// |file_path| is the path of the file on disk to import.
+//
+// |bookmarks| is a pointer to a vector, which is filled with the imported
+// bookmarks. It may not be NULL.
+//
+// |favicons| is a pointer to a vector, which is filled with the favicons of
+// imported bookmarks. It may be NULL, in which case favicons are not imported.
+void ImportBookmarksFile(
+    const base::Callback<bool(void)>& cancellation_callback,
+    const base::Callback<bool(const GURL&)>& valid_url_callback,
+    const base::FilePath& file_path,
+    std::vector<ImportedBookmarkEntry>* bookmarks,
+    std::vector<ImportedFaviconUsage>* favicons);
+
+namespace internal {
+
+// The file format that BookmarkHTMLReader parses starts with a heading
+// tag, which contains its title. All bookmarks and sub-folders follow,
+// bracketed by a <DL> tag:
+//   <DT><H3 PERSONAL_TOOLBAR_FOLDER="true" ...>title</H3>
+//   <DL><p>
+//      ... container ...
+//   </DL><p>
+// And a bookmark is presented by a <A> tag:
+//   <DT><A HREF="url" SHORTCUTURL="shortcut" ADD_DATE="11213014"...>name</A>
+// Reference: http://kb.mozillazine.org/Bookmarks.html
+
+bool ParseCharsetFromLine(const std::string& line,
+                          std::string* charset);
+bool ParseFolderNameFromLine(const std::string& line,
+                             const std::string& charset,
+                             base::string16* folder_name,
+                             bool* is_toolbar_folder,
+                             base::Time* add_date);
+// See above, this will also put the data: URL of the favicon into |*favicon|
+// if there is a favicon given. |post_data| is set for POST base keywords to
+// the contents of the actual POST (with %s for the search term).
+bool ParseBookmarkFromLine(const std::string& line,
+                           const std::string& charset,
+                           base::string16* title,
+                           GURL* url,
+                           GURL* favicon,
+                           base::string16* shortcut,
+                           base::Time* add_date,
+                           base::string16* post_data);
+// Save bookmarks imported from browsers with Firefox 2 compatible bookmark
+// systems such as Epiphany. This bookmark format is the same as that of the
+// basic Firefox 2 bookmark, but it misses additional properties and uses
+// lower-case tag:
+//   ...<h1>Bookmarks</h1><dl>
+//   <dt><a href="url">name</a></dt>
+//   <dt><a href="url">name</a></dt>
+//   </dl>
+bool ParseMinimumBookmarkFromLine(const std::string& line,
+                                  const std::string& charset,
+                                  base::string16* title,
+                                  GURL* url);
+
+}  // namespace internal
+
+}  // namespace bookmark_html_reader
+
+#endif  // CHROME_BROWSER_IMPORTER_BOOKMARK_HTML_READER_H_
diff --git a/chrome/browser/importer/bookmark_html_reader_unittest.cc b/chrome/browser/importer/bookmark_html_reader_unittest.cc
new file mode 100644
index 0000000..8374a12
--- /dev/null
+++ b/chrome/browser/importer/bookmark_html_reader_unittest.cc
@@ -0,0 +1,275 @@
+// 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/importer/bookmark_html_reader.h"
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/callback.h"
+#include "base/files/file_path.h"
+#include "base/path_service.h"
+#include "base/strings/string16.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/common/importer/imported_bookmark_entry.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace bookmark_html_reader {
+
+TEST(BookmarkHTMLReaderTest, ParseTests) {
+  bool result;
+
+  // Tests charset.
+  std::string charset;
+  result = internal::ParseCharsetFromLine(
+      "<META HTTP-EQUIV=\"Content-Type\" "
+      "CONTENT=\"text/html; charset=UTF-8\">",
+      &charset);
+  EXPECT_TRUE(result);
+  EXPECT_EQ("UTF-8", charset);
+
+  // Escaped characters in name.
+  base::string16 folder_name;
+  bool is_toolbar_folder;
+  base::Time folder_add_date;
+  result = internal::ParseFolderNameFromLine(
+      "<DT><H3 ADD_DATE=\"1207558707\" >&lt; &gt;"
+      " &amp; &quot; &#39; \\ /</H3>",
+      charset, &folder_name, &is_toolbar_folder, &folder_add_date);
+  EXPECT_TRUE(result);
+  EXPECT_EQ(ASCIIToUTF16("< > & \" ' \\ /"), folder_name);
+  EXPECT_FALSE(is_toolbar_folder);
+  EXPECT_TRUE(base::Time::FromTimeT(1207558707) == folder_add_date);
+
+  // Empty name and toolbar folder attribute.
+  result = internal::ParseFolderNameFromLine(
+      "<DT><H3 PERSONAL_TOOLBAR_FOLDER=\"true\"></H3>",
+      charset, &folder_name, &is_toolbar_folder, &folder_add_date);
+  EXPECT_TRUE(result);
+  EXPECT_EQ(base::string16(), folder_name);
+  EXPECT_TRUE(is_toolbar_folder);
+
+  // Unicode characters in title and shortcut.
+  base::string16 title;
+  GURL url, favicon;
+  base::string16 shortcut;
+  base::string16 post_data;
+  base::Time add_date;
+  result = internal::ParseBookmarkFromLine(
+      "<DT><A HREF=\"http://chinese.site.cn/path?query=1#ref\" "
+      "SHORTCUTURL=\"\xE4\xB8\xAD\">\xE4\xB8\xAD\xE6\x96\x87</A>",
+      charset, &title, &url, &favicon, &shortcut, &add_date, &post_data);
+  EXPECT_TRUE(result);
+  EXPECT_EQ(L"\x4E2D\x6587", UTF16ToWide(title));
+  EXPECT_EQ("http://chinese.site.cn/path?query=1#ref", url.spec());
+  EXPECT_EQ(L"\x4E2D", UTF16ToWide(shortcut));
+  EXPECT_EQ(base::string16(), post_data);
+  EXPECT_TRUE(base::Time() == add_date);
+
+  // No shortcut, and url contains %22 ('"' character).
+  result = internal::ParseBookmarkFromLine(
+      "<DT><A HREF=\"http://domain.com/?q=%22<>%22\">name</A>",
+      charset, &title, &url, &favicon, &shortcut, &add_date, &post_data);
+  EXPECT_TRUE(result);
+  EXPECT_EQ(ASCIIToUTF16("name"), title);
+  EXPECT_EQ("http://domain.com/?q=%22%3C%3E%22", url.spec());
+  EXPECT_EQ(base::string16(), shortcut);
+  EXPECT_EQ(base::string16(), post_data);
+  EXPECT_TRUE(base::Time() == add_date);
+
+  result = internal::ParseBookmarkFromLine(
+      "<DT><A HREF=\"http://domain.com/?g=&quot;\"\">name</A>",
+      charset, &title, &url, &favicon, &shortcut, &add_date, &post_data);
+  EXPECT_TRUE(result);
+  EXPECT_EQ(ASCIIToUTF16("name"), title);
+  EXPECT_EQ("http://domain.com/?g=%22", url.spec());
+  EXPECT_EQ(base::string16(), shortcut);
+  EXPECT_EQ(base::string16(), post_data);
+  EXPECT_TRUE(base::Time() == add_date);
+
+  // Creation date.
+  result = internal::ParseBookmarkFromLine(
+      "<DT><A HREF=\"http://site/\" ADD_DATE=\"1121301154\">name</A>",
+      charset, &title, &url, &favicon, &shortcut, &add_date, &post_data);
+  EXPECT_TRUE(result);
+  EXPECT_EQ(ASCIIToUTF16("name"), title);
+  EXPECT_EQ(GURL("http://site/"), url);
+  EXPECT_EQ(base::string16(), shortcut);
+  EXPECT_EQ(base::string16(), post_data);
+  EXPECT_TRUE(base::Time::FromTimeT(1121301154) == add_date);
+
+  // Post-data
+  result = internal::ParseBookmarkFromLine(
+      "<DT><A HREF=\"http://localhost:8080/test/hello.html\" ADD_DATE=\""
+      "1212447159\" LAST_VISIT=\"1212447251\" LAST_MODIFIED=\"1212447248\""
+      "SHORTCUTURL=\"post\" ICON=\"data:\" POST_DATA=\"lname%3D%25s\""
+      "LAST_CHARSET=\"UTF-8\" ID=\"rdf:#$weKaR3\">Test Post keyword</A>",
+      charset, &title, &url, &favicon, &shortcut, &add_date, &post_data);
+  EXPECT_TRUE(result);
+  EXPECT_EQ(ASCIIToUTF16("Test Post keyword"), title);
+  EXPECT_EQ("http://localhost:8080/test/hello.html", url.spec());
+  EXPECT_EQ(ASCIIToUTF16("post"), shortcut);
+  EXPECT_EQ(ASCIIToUTF16("lname%3D%25s"), post_data);
+  EXPECT_TRUE(base::Time::FromTimeT(1212447159) == add_date);
+
+  // Invalid case.
+  result = internal::ParseBookmarkFromLine(
+      "<DT><A HREF=\"http://domain.com/?q=%22",
+      charset, &title, &url, &favicon, &shortcut, &add_date, &post_data);
+  EXPECT_FALSE(result);
+  EXPECT_EQ(base::string16(), title);
+  EXPECT_EQ("", url.spec());
+  EXPECT_EQ(base::string16(), shortcut);
+  EXPECT_EQ(base::string16(), post_data);
+  EXPECT_TRUE(base::Time() == add_date);
+
+  // Epiphany format.
+  result = internal::ParseMinimumBookmarkFromLine(
+      "<dt><a href=\"http://www.google.com/\">Google</a></dt>",
+      charset, &title, &url);
+  EXPECT_TRUE(result);
+  EXPECT_EQ(ASCIIToUTF16("Google"), title);
+  EXPECT_EQ("http://www.google.com/", url.spec());
+}
+
+namespace {
+
+void ExpectFirstFirefox2Bookmark(const ImportedBookmarkEntry& entry) {
+  EXPECT_EQ(ASCIIToUTF16("Empty"), entry.title);
+  EXPECT_TRUE(entry.is_folder);
+  EXPECT_EQ(base::Time::FromTimeT(1295938143), entry.creation_time);
+  EXPECT_EQ(1U, entry.path.size());
+  if (entry.path.size() == 1)
+    EXPECT_EQ(ASCIIToUTF16("Empty's Parent"), entry.path.front());
+}
+
+void ExpectSecondFirefox2Bookmark(const ImportedBookmarkEntry& entry) {
+  EXPECT_EQ(ASCIIToUTF16("[Tamura Yukari.com]"), entry.title);
+  EXPECT_FALSE(entry.is_folder);
+  EXPECT_EQ(base::Time::FromTimeT(1234567890), entry.creation_time);
+  EXPECT_EQ(1U, entry.path.size());
+  if (entry.path.size() == 1)
+    EXPECT_EQ(ASCIIToUTF16("Not Empty"), entry.path.front());
+  EXPECT_EQ("http://www.tamurayukari.com/", entry.url.spec());
+}
+
+void ExpectThirdFirefox2Bookmark(const ImportedBookmarkEntry& entry) {
+  EXPECT_EQ(ASCIIToUTF16("Google"), entry.title);
+  EXPECT_FALSE(entry.is_folder);
+  EXPECT_EQ(base::Time::FromTimeT(0000000000), entry.creation_time);
+  EXPECT_EQ(1U, entry.path.size());
+  if (entry.path.size() == 1)
+    EXPECT_EQ(ASCIIToUTF16("Not Empty But Default"), entry.path.front());
+  EXPECT_EQ("http://www.google.com/", entry.url.spec());
+}
+
+void ExpectFirstEpiphanyBookmark(const ImportedBookmarkEntry& entry) {
+  EXPECT_EQ(ASCIIToUTF16("[Tamura Yukari.com]"), entry.title);
+  EXPECT_EQ("http://www.tamurayukari.com/", entry.url.spec());
+  EXPECT_EQ(0U, entry.path.size());
+}
+
+void ExpectSecondEpiphanyBookmark(const ImportedBookmarkEntry& entry) {
+  EXPECT_EQ(ASCIIToUTF16("Google"), entry.title);
+  EXPECT_EQ("http://www.google.com/", entry.url.spec());
+  EXPECT_EQ(0U, entry.path.size());
+}
+
+}  // namespace
+
+TEST(BookmarkHTMLReaderTest, Firefox2BookmarkFileImport) {
+  base::FilePath path;
+  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &path));
+  path = path.AppendASCII("bookmark_html_reader");
+  path = path.AppendASCII("firefox2.html");
+
+  std::vector<ImportedBookmarkEntry> bookmarks;
+  ImportBookmarksFile(base::Callback<bool(void)>(),
+                      base::Callback<bool(const GURL&)>(),
+                      path, &bookmarks, NULL);
+
+  ASSERT_EQ(3U, bookmarks.size());
+  ExpectFirstFirefox2Bookmark(bookmarks[0]);
+  ExpectSecondFirefox2Bookmark(bookmarks[1]);
+  ExpectThirdFirefox2Bookmark(bookmarks[2]);
+}
+
+TEST(BookmarkHTMLReaderTest, EpiphanyBookmarkFileImport) {
+  base::FilePath path;
+  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &path));
+  path = path.AppendASCII("bookmark_html_reader");
+  path = path.AppendASCII("epiphany.html");
+
+  std::vector<ImportedBookmarkEntry> bookmarks;
+  ImportBookmarksFile(base::Callback<bool(void)>(),
+                      base::Callback<bool(const GURL&)>(),
+                      path, &bookmarks, NULL);
+
+  ASSERT_EQ(2U, bookmarks.size());
+  ExpectFirstEpiphanyBookmark(bookmarks[0]);
+  ExpectSecondEpiphanyBookmark(bookmarks[1]);
+}
+
+namespace {
+
+class CancelAfterFifteenCalls {
+  int count;
+ public:
+  CancelAfterFifteenCalls() : count(0) { }
+  bool ShouldCancel() {
+    return ++count > 16;
+  }
+};
+
+}  // namespace
+
+TEST(BookmarkHTMLReaderTest, CancellationCallback) {
+  base::FilePath path;
+  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &path));
+  path = path.AppendASCII("bookmark_html_reader");
+  // Use a file for testing that has multiple bookmarks.
+  path = path.AppendASCII("firefox2.html");
+
+  std::vector<ImportedBookmarkEntry> bookmarks;
+  CancelAfterFifteenCalls cancel_fifteen;
+  ImportBookmarksFile(base::Bind(&CancelAfterFifteenCalls::ShouldCancel,
+                                 base::Unretained(&cancel_fifteen)),
+                      base::Callback<bool(const GURL&)>(),
+                      path, &bookmarks, NULL);
+
+  // The cancellation callback is checked before each line is read, so fifteen
+  // lines are imported. The first fifteen lines of firefox2.html include only
+  // one bookmark.
+  ASSERT_EQ(1U, bookmarks.size());
+  ExpectFirstFirefox2Bookmark(bookmarks[0]);
+}
+
+namespace {
+
+bool IsURLValid(const GURL& url) {
+  // No offense to whomever owns this domain...
+  return !url.DomainIs("tamurayukari.com");
+}
+
+}  // namespace
+
+TEST(BookmarkHTMLReaderTest, ValidURLCallback) {
+  base::FilePath path;
+  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &path));
+  path = path.AppendASCII("bookmark_html_reader");
+  // Use a file for testing that has multiple bookmarks.
+  path = path.AppendASCII("firefox2.html");
+
+  std::vector<ImportedBookmarkEntry> bookmarks;
+  ImportBookmarksFile(base::Callback<bool(void)>(),
+                      base::Bind(&IsURLValid),
+                      path, &bookmarks, NULL);
+
+  ASSERT_EQ(2U, bookmarks.size());
+  ExpectFirstFirefox2Bookmark(bookmarks[0]);
+  ExpectThirdFirefox2Bookmark(bookmarks[1]);
+}
+
+}  // namespace bookmark_html_reader
diff --git a/chrome/browser/importer/bookmark_html_writer_unittest.cc b/chrome/browser/importer/bookmark_html_writer_unittest.cc
new file mode 100644
index 0000000..37beb81
--- /dev/null
+++ b/chrome/browser/importer/bookmark_html_writer_unittest.cc
@@ -0,0 +1,283 @@
+// 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/bookmarks/bookmark_html_writer.h"
+
+#include "base/files/scoped_temp_dir.h"
+#include "base/i18n/time_formatting.h"
+#include "base/path_service.h"
+#include "base/run_loop.h"
+#include "base/strings/string16.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/time/time.h"
+#include "chrome/browser/bookmarks/bookmark_model.h"
+#include "chrome/browser/bookmarks/bookmark_model_factory.h"
+#include "chrome/browser/favicon/favicon_service.h"
+#include "chrome/browser/favicon/favicon_service_factory.h"
+#include "chrome/browser/history/history_service.h"
+#include "chrome/browser/history/history_service_factory.h"
+#include "chrome/browser/importer/bookmark_html_reader.h"
+#include "chrome/common/importer/imported_bookmark_entry.h"
+#include "chrome/common/importer/imported_favicon_usage.h"
+#include "chrome/test/base/testing_profile.h"
+#include "chrome/test/base/ui_test_utils.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "grit/generated_resources.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/gfx/codec/png_codec.h"
+
+using content::BrowserThread;
+
+namespace {
+
+const int kIconWidth = 16;
+const int kIconHeight = 16;
+
+void MakeTestSkBitmap(int w, int h, SkBitmap* bmp) {
+  bmp->setConfig(SkBitmap::kARGB_8888_Config, w, h);
+  bmp->allocPixels();
+
+  uint32_t* src_data = bmp->getAddr32(0, 0);
+  for (int i = 0; i < w * h; i++) {
+    src_data[i] = SkPreMultiplyARGB(i % 255, i % 250, i % 245, i % 240);
+  }
+}
+
+}  // namespace
+
+class BookmarkHTMLWriterTest : public testing::Test {
+ protected:
+  virtual void SetUp() {
+    testing::Test::SetUp();
+    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+    path_ = temp_dir_.path().AppendASCII("bookmarks.html");
+  }
+
+  // Converts an ImportedBookmarkEntry to a string suitable for assertion
+  // testing.
+  string16 BookmarkEntryToString(const ImportedBookmarkEntry& entry) {
+    string16 result;
+    result.append(ASCIIToUTF16("on_toolbar="));
+    if (entry.in_toolbar)
+      result.append(ASCIIToUTF16("true"));
+    else
+      result.append(ASCIIToUTF16("false"));
+
+    result.append(ASCIIToUTF16(" url=") + UTF8ToUTF16(entry.url.spec()));
+
+    result.append(ASCIIToUTF16(" path="));
+    for (size_t i = 0; i < entry.path.size(); ++i) {
+      if (i != 0)
+        result.append(ASCIIToUTF16("/"));
+      result.append(entry.path[i]);
+    }
+
+    result.append(ASCIIToUTF16(" title="));
+    result.append(entry.title);
+
+    result.append(ASCIIToUTF16(" time="));
+    result.append(base::TimeFormatFriendlyDateAndTime(entry.creation_time));
+    return result;
+  }
+
+  // Creates a set of bookmark values to a string for assertion testing.
+  string16 BookmarkValuesToString(bool on_toolbar,
+                                  const GURL& url,
+                                  const string16& title,
+                                  base::Time creation_time,
+                                  const string16& f1,
+                                  const string16& f2,
+                                  const string16& f3) {
+    ImportedBookmarkEntry entry;
+    entry.in_toolbar = on_toolbar;
+    entry.url = url;
+    if (!f1.empty()) {
+      entry.path.push_back(f1);
+      if (!f2.empty()) {
+        entry.path.push_back(f2);
+        if (!f3.empty())
+          entry.path.push_back(f3);
+      }
+    }
+    entry.title = title;
+    entry.creation_time = creation_time;
+    return BookmarkEntryToString(entry);
+  }
+
+  void AssertBookmarkEntryEquals(const ImportedBookmarkEntry& entry,
+                                 bool on_toolbar,
+                                 const GURL& url,
+                                 const string16& title,
+                                 base::Time creation_time,
+                                 const string16& f1,
+                                 const string16& f2,
+                                 const string16& f3) {
+    EXPECT_EQ(BookmarkValuesToString(on_toolbar, url, title, creation_time,
+                                     f1, f2, f3),
+              BookmarkEntryToString(entry));
+  }
+
+  base::ScopedTempDir temp_dir_;
+  base::FilePath path_;
+};
+
+// Class that will notify message loop when file is written.
+class BookmarksObserver : public BookmarksExportObserver {
+ public:
+  explicit BookmarksObserver(base::RunLoop* loop) : loop_(loop) {
+    DCHECK(loop);
+  }
+
+  virtual void OnExportFinished() OVERRIDE {
+    loop_->Quit();
+  }
+
+ private:
+  base::RunLoop* loop_;
+
+  DISALLOW_COPY_AND_ASSIGN(BookmarksObserver);
+};
+
+// Tests bookmark_html_writer by populating a BookmarkModel, writing it out by
+// way of bookmark_html_writer, then using the importer to read it back in.
+TEST_F(BookmarkHTMLWriterTest, Test) {
+  content::TestBrowserThreadBundle thread_bundle;
+
+  TestingProfile profile;
+  profile.CreateHistoryService(true, false);
+  profile.BlockUntilHistoryProcessesPendingRequests();
+  profile.CreateFaviconService();
+  profile.CreateBookmarkModel(true);
+
+  BookmarkModel* model = BookmarkModelFactory::GetForProfile(&profile);
+  ui_test_utils::WaitForBookmarkModelToLoad(model);
+
+  // Create test PNG representing favicon for url1.
+  SkBitmap bitmap;
+  MakeTestSkBitmap(kIconWidth, kIconHeight, &bitmap);
+  std::vector<unsigned char> icon_data;
+  gfx::PNGCodec::EncodeBGRASkBitmap(bitmap, false, &icon_data);
+
+  // Populate the BookmarkModel. This creates the following bookmark structure:
+  // Bookmarks bar
+  //   F1
+  //     url1
+  //     F2
+  //       url2
+  //   url3
+  //   url4
+  // Other
+  //   url1
+  //   url2
+  //   F3
+  //     F4
+  //       url1
+  // Mobile
+  //   url1
+  //   <bookmark without a title.>
+  string16 f1_title = ASCIIToUTF16("F\"&;<1\"");
+  string16 f2_title = ASCIIToUTF16("F2");
+  string16 f3_title = ASCIIToUTF16("F 3");
+  string16 f4_title = ASCIIToUTF16("F4");
+  string16 url1_title = ASCIIToUTF16("url 1");
+  string16 url2_title = ASCIIToUTF16("url&2");
+  string16 url3_title = ASCIIToUTF16("url\"3");
+  string16 url4_title = ASCIIToUTF16("url\"&;");
+  string16 unnamed_bookmark_title = ASCIIToUTF16("");
+  GURL url1("http://url1");
+  GURL url1_favicon("http://url1/icon.ico");
+  GURL url2("http://url2");
+  GURL url3("http://url3");
+  GURL url4("javascript:alert(\"Hello!\");");
+  GURL unnamed_bookmark_url("about:blank");
+  base::Time t1(base::Time::Now());
+  base::Time t2(t1 + base::TimeDelta::FromHours(1));
+  base::Time t3(t1 + base::TimeDelta::FromHours(1));
+  base::Time t4(t1 + base::TimeDelta::FromHours(1));
+  const BookmarkNode* f1 = model->AddFolder(
+      model->bookmark_bar_node(), 0, f1_title);
+  model->AddURLWithCreationTime(f1, 0, url1_title, url1, t1);
+  HistoryServiceFactory::GetForProfile(&profile, Profile::EXPLICIT_ACCESS)->
+      AddPage(url1, base::Time::Now(), history::SOURCE_BROWSED);
+  FaviconServiceFactory::GetForProfile(
+      &profile, Profile::EXPLICIT_ACCESS)->SetFavicons(
+          url1, url1_favicon, chrome::FAVICON,
+          gfx::Image::CreateFrom1xBitmap(bitmap));
+  const BookmarkNode* f2 = model->AddFolder(f1, 1, f2_title);
+  model->AddURLWithCreationTime(f2, 0, url2_title, url2, t2);
+  model->AddURLWithCreationTime(model->bookmark_bar_node(),
+                                1, url3_title, url3, t3);
+
+  model->AddURLWithCreationTime(model->other_node(), 0, url1_title, url1, t1);
+  model->AddURLWithCreationTime(model->other_node(), 1, url2_title, url2, t2);
+  const BookmarkNode* f3 = model->AddFolder(model->other_node(), 2, f3_title);
+  const BookmarkNode* f4 = model->AddFolder(f3, 0, f4_title);
+  model->AddURLWithCreationTime(f4, 0, url1_title, url1, t1);
+  model->AddURLWithCreationTime(model->bookmark_bar_node(), 2, url4_title,
+                                url4, t4);
+  model->AddURLWithCreationTime(model->mobile_node(), 0, url1_title, url1, t1);
+  model->AddURLWithCreationTime(model->mobile_node(), 1, unnamed_bookmark_title,
+                                unnamed_bookmark_url, t2);
+
+  base::RunLoop run_loop;
+
+  // Write to a temp file.
+  BookmarksObserver observer(&run_loop);
+  bookmark_html_writer::WriteBookmarks(&profile, path_, &observer);
+  run_loop.Run();
+
+  // Clear favicon so that it would be read from file.
+  FaviconServiceFactory::GetForProfile(
+      &profile, Profile::EXPLICIT_ACCESS)->SetFavicons(
+          url1, url1_favicon, chrome::FAVICON, gfx::Image());
+
+  // Read the bookmarks back in.
+  std::vector<ImportedBookmarkEntry> parsed_bookmarks;
+  std::vector<ImportedFaviconUsage> favicons;
+  bookmark_html_reader::ImportBookmarksFile(base::Callback<bool(void)>(),
+                                            base::Callback<bool(const GURL&)>(),
+                                            path_,
+                                            &parsed_bookmarks,
+                                            &favicons);
+
+  // Check loaded favicon (url1 is represented by 4 separate bookmarks).
+  EXPECT_EQ(4U, favicons.size());
+  for (size_t i = 0; i < favicons.size(); i++) {
+    if (url1_favicon == favicons[i].favicon_url) {
+      EXPECT_EQ(1U, favicons[i].urls.size());
+      std::set<GURL>::const_iterator iter = favicons[i].urls.find(url1);
+      ASSERT_TRUE(iter != favicons[i].urls.end());
+      ASSERT_TRUE(*iter == url1);
+      ASSERT_TRUE(favicons[i].png_data == icon_data);
+    }
+  }
+
+  // Verify we got back what we wrote.
+  ASSERT_EQ(9U, parsed_bookmarks.size());
+  // Windows and ChromeOS builds use Sentence case.
+  string16 bookmark_folder_name =
+      l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_FOLDER_NAME);
+  AssertBookmarkEntryEquals(parsed_bookmarks[0], true, url1, url1_title, t1,
+                            bookmark_folder_name, f1_title, string16());
+  AssertBookmarkEntryEquals(parsed_bookmarks[1], true, url2, url2_title, t2,
+                            bookmark_folder_name, f1_title, f2_title);
+  AssertBookmarkEntryEquals(parsed_bookmarks[2], true, url3, url3_title, t3,
+                            bookmark_folder_name, string16(), string16());
+  AssertBookmarkEntryEquals(parsed_bookmarks[3], true, url4, url4_title, t4,
+                            bookmark_folder_name, string16(), string16());
+  AssertBookmarkEntryEquals(parsed_bookmarks[4], false, url1, url1_title, t1,
+                            string16(), string16(), string16());
+  AssertBookmarkEntryEquals(parsed_bookmarks[5], false, url2, url2_title, t2,
+                            string16(), string16(), string16());
+  AssertBookmarkEntryEquals(parsed_bookmarks[6], false, url1, url1_title, t1,
+                            f3_title, f4_title, string16());
+  AssertBookmarkEntryEquals(parsed_bookmarks[7], false, url1, url1_title, t1,
+                            string16(), string16(), string16());
+  AssertBookmarkEntryEquals(parsed_bookmarks[8], false, unnamed_bookmark_url,
+                            unnamed_bookmark_title, t2,
+                            string16(), string16(), string16());
+}
diff --git a/chrome/browser/importer/bookmarks_file_importer.cc b/chrome/browser/importer/bookmarks_file_importer.cc
index 5a35863..3a1c871 100644
--- a/chrome/browser/importer/bookmarks_file_importer.cc
+++ b/chrome/browser/importer/bookmarks_file_importer.cc
@@ -5,12 +5,12 @@
 #include "chrome/browser/importer/bookmarks_file_importer.h"
 
 #include "base/bind.h"
-#include "chrome/browser/bookmarks/bookmark_html_reader.h"
-#include "chrome/browser/bookmarks/imported_bookmark_entry.h"
-#include "chrome/browser/favicon/imported_favicon_usage.h"
+#include "chrome/browser/importer/bookmark_html_reader.h"
 #include "chrome/browser/importer/firefox_importer_utils.h"
 #include "chrome/browser/importer/importer_bridge.h"
-#include "chrome/browser/importer/importer_data_types.h"
+#include "chrome/common/importer/imported_bookmark_entry.h"
+#include "chrome/common/importer/imported_favicon_usage.h"
+#include "chrome/common/importer/importer_data_types.h"
 #include "grit/generated_resources.h"
 
 namespace {
diff --git a/chrome/browser/importer/external_process_importer_bridge.cc b/chrome/browser/importer/external_process_importer_bridge.cc
index 2395fa0..23cc3bc 100644
--- a/chrome/browser/importer/external_process_importer_bridge.cc
+++ b/chrome/browser/importer/external_process_importer_bridge.cc
@@ -10,9 +10,10 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/task_runner.h"
 #include "base/values.h"
-#include "chrome/browser/bookmarks/imported_bookmark_entry.h"
-#include "chrome/browser/favicon/imported_favicon_usage.h"
-#include "chrome/browser/importer/profile_import_process_messages.h"
+#include "chrome/common/importer/imported_bookmark_entry.h"
+#include "chrome/common/importer/imported_favicon_usage.h"
+#include "chrome/common/importer/importer_data_types.h"
+#include "chrome/common/importer/profile_import_process_messages.h"
 #include "content/public/common/password_form.h"
 #include "ipc/ipc_sender.h"
 
@@ -103,7 +104,7 @@
 }
 
 void ExternalProcessImporterBridge::SetHistoryItems(
-    const history::URLRows& rows,
+    const std::vector<ImporterURLRow>& rows,
     history::VisitSource visit_source) {
   Send(new ProfileImportProcessHostMsg_NotifyHistoryImportStart(rows.size()));
 
@@ -111,9 +112,10 @@
   // Debug bounds-check which prevents pushing an iterator beyond its end()
   // (i.e., |it + 2 < s.end()| crashes in debug mode if |i + 1 == s.end()|).
   int rows_left = rows.end() - rows.begin();
-  for (history::URLRows::const_iterator it = rows.begin(); it < rows.end();) {
-    history::URLRows row_group;
-    history::URLRows::const_iterator end_group =
+  for (std::vector<ImporterURLRow>::const_iterator it = rows.begin();
+       it < rows.end();) {
+    std::vector<ImporterURLRow> row_group;
+    std::vector<ImporterURLRow>::const_iterator end_group =
         it + std::min(rows_left, kNumHistoryRowsToSend);
     row_group.assign(it, end_group);
 
@@ -126,11 +128,16 @@
 }
 
 void ExternalProcessImporterBridge::SetKeywords(
-    const std::vector<TemplateURL*>& template_urls,
+    const std::vector<importer::URLKeywordInfo>& url_keywords,
     bool unique_on_host_and_path) {
-  Send(new ProfileImportProcessHostMsg_NotifyKeywordsReady(template_urls,
-      unique_on_host_and_path));
-  STLDeleteContainerPointers(template_urls.begin(), template_urls.end());
+  Send(new ProfileImportProcessHostMsg_NotifyKeywordsReady(
+      url_keywords, unique_on_host_and_path));
+}
+
+void ExternalProcessImporterBridge::SetFirefoxSearchEnginesXMLData(
+    const std::vector<std::string>& search_engine_data) {
+  Send(new ProfileImportProcessHostMsg_NotifyFirefoxSearchEngData(
+      search_engine_data));
 }
 
 void ExternalProcessImporterBridge::SetPasswordForm(
diff --git a/chrome/browser/importer/external_process_importer_bridge.h b/chrome/browser/importer/external_process_importer_bridge.h
index c5450de..b1cb519 100644
--- a/chrome/browser/importer/external_process_importer_bridge.h
+++ b/chrome/browser/importer/external_process_importer_bridge.h
@@ -5,6 +5,7 @@
 #ifndef CHROME_BROWSER_IMPORTER_EXTERNAL_PROCESS_IMPORTER_BRIDGE_H_
 #define CHROME_BROWSER_IMPORTER_EXTERNAL_PROCESS_IMPORTER_BRIDGE_H_
 
+#include <string>
 #include <vector>
 
 #include "base/basictypes.h"
@@ -20,6 +21,10 @@
 class TaskRunner;
 }
 
+namespace importer {
+struct URLKeywordInfo;
+}
+
 namespace IPC {
 class Message;
 class Sender;
@@ -52,11 +57,15 @@
   virtual void SetFavicons(
       const std::vector<ImportedFaviconUsage>& favicons) OVERRIDE;
 
-  virtual void SetHistoryItems(const history::URLRows& rows,
+  virtual void SetHistoryItems(const std::vector<ImporterURLRow>& rows,
                                history::VisitSource visit_source) OVERRIDE;
 
-  virtual void SetKeywords(const std::vector<TemplateURL*>& template_urls,
-                           bool unique_on_host_and_path) OVERRIDE;
+  virtual void SetKeywords(
+      const std::vector<importer::URLKeywordInfo>& url_keywords,
+      bool unique_on_host_and_path) OVERRIDE;
+
+  virtual void SetFirefoxSearchEnginesXMLData(
+      const std::vector<std::string>& seach_engine_data) OVERRIDE;
 
   virtual void SetPasswordForm(
       const content::PasswordForm& form) OVERRIDE;
diff --git a/chrome/browser/importer/external_process_importer_client.cc b/chrome/browser/importer/external_process_importer_client.cc
index 56ee2e6..d90d9a0 100644
--- a/chrome/browser/importer/external_process_importer_client.cc
+++ b/chrome/browser/importer/external_process_importer_client.cc
@@ -6,15 +6,12 @@
 
 #include "base/bind.h"
 #include "base/strings/string_number_conversions.h"
-#include "chrome/browser/bookmarks/imported_bookmark_entry.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/importer/external_process_importer_host.h"
 #include "chrome/browser/importer/firefox_importer_utils.h"
-#include "chrome/browser/importer/importer_host.h"
 #include "chrome/browser/importer/in_process_importer_bridge.h"
-#include "chrome/browser/importer/profile_import_process_messages.h"
-#include "chrome/browser/search_engines/template_url.h"
-#include "chrome/browser/search_engines/template_url_service.h"
+#include "chrome/common/importer/imported_bookmark_entry.h"
+#include "chrome/common/importer/profile_import_process_messages.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/utility_process_host.h"
 #include "grit/generated_resources.h"
@@ -64,6 +61,7 @@
 }
 
 void ExternalProcessImporterClient::OnProcessCrashed(int exit_code) {
+  DLOG(ERROR) << __FUNCTION__;
   if (cancelled_)
     return;
 
@@ -102,6 +100,8 @@
                         OnPasswordFormImportReady)
     IPC_MESSAGE_HANDLER(ProfileImportProcessHostMsg_NotifyKeywordsReady,
                         OnKeywordsImportReady)
+    IPC_MESSAGE_HANDLER(ProfileImportProcessHostMsg_NotifyFirefoxSearchEngData,
+                        OnFirefoxSearchEngineDataReceived)
     IPC_MESSAGE_UNHANDLED(handled = false)
   IPC_END_MESSAGE_MAP()
   return handled;
@@ -155,7 +155,7 @@
 }
 
 void ExternalProcessImporterClient::OnHistoryImportGroup(
-    const history::URLRows& history_rows_group,
+    const std::vector<ImporterURLRow>& history_rows_group,
     int visit_source) {
   if (cancelled_)
     return;
@@ -228,13 +228,18 @@
 }
 
 void ExternalProcessImporterClient::OnKeywordsImportReady(
-    const std::vector<TemplateURL*>& template_urls,
+    const std::vector<importer::URLKeywordInfo>& url_keywords,
     bool unique_on_host_and_path) {
   if (cancelled_)
     return;
+  bridge_->SetKeywords(url_keywords, unique_on_host_and_path);
+}
 
-  bridge_->SetKeywords(template_urls, unique_on_host_and_path);
-  // The pointers in |template_urls| have now been deleted.
+void ExternalProcessImporterClient::OnFirefoxSearchEngineDataReceived(
+    const std::vector<std::string> search_engine_data) {
+  if (cancelled_)
+    return;
+  bridge_->SetFirefoxSearchEnginesXMLData(search_engine_data);
 }
 
 ExternalProcessImporterClient::~ExternalProcessImporterClient() {}
@@ -287,9 +292,6 @@
       base::IntToString(IDS_IMPORT_FROM_FIREFOX),
       l10n_util::GetStringUTF8(IDS_IMPORT_FROM_FIREFOX));
   localized_strings.SetString(
-      base::IntToString(IDS_IMPORT_FROM_GOOGLE_TOOLBAR),
-      l10n_util::GetStringUTF8(IDS_IMPORT_FROM_GOOGLE_TOOLBAR));
-  localized_strings.SetString(
       base::IntToString(IDS_IMPORT_FROM_SAFARI),
       l10n_util::GetStringUTF8(IDS_IMPORT_FROM_SAFARI));
   localized_strings.SetString(
diff --git a/chrome/browser/importer/external_process_importer_client.h b/chrome/browser/importer/external_process_importer_client.h
index f5a03d7..5af485e 100644
--- a/chrome/browser/importer/external_process_importer_client.h
+++ b/chrome/browser/importer/external_process_importer_client.h
@@ -13,7 +13,8 @@
 #include "base/memory/weak_ptr.h"
 #include "base/strings/string16.h"
 #include "chrome/browser/history/history_types.h"
-#include "chrome/browser/importer/importer_data_types.h"
+#include "chrome/common/importer/importer_data_types.h"
+#include "chrome/common/importer/importer_url_row.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/utility_process_host_client.h"
 
@@ -21,13 +22,16 @@
 struct ImportedBookmarkEntry;
 struct ImportedFaviconUsage;
 class InProcessImporterBridge;
-class TemplateURL;
 
 namespace content {
 struct PasswordForm;
 class UtilityProcessHost;
 }
 
+namespace importer {
+struct URLKeywordInfo;
+}
+
 // This class is the client for the out of process profile importing.  It
 // collects notifications from this process host and feeds data back to the
 // importer host, who actually does the writing.
@@ -54,8 +58,9 @@
   void OnImportItemStart(int item);
   void OnImportItemFinished(int item);
   void OnHistoryImportStart(size_t total_history_rows_count);
-  void OnHistoryImportGroup(const history::URLRows& history_rows_group,
-                            int visit_source);
+  void OnHistoryImportGroup(
+      const std::vector<ImporterURLRow>& history_rows_group,
+      int visit_source);
   void OnHomePageImportReady(const GURL& home_page);
   void OnBookmarksImportStart(const string16& first_folder_name,
                               size_t total_bookmarks_count);
@@ -65,10 +70,11 @@
   void OnFaviconsImportGroup(
       const std::vector<ImportedFaviconUsage>& favicons_group);
   void OnPasswordFormImportReady(const content::PasswordForm& form);
-  // WARNING: This function takes ownership of (and deletes) the pointers in
-  // |template_urls|!
-  void OnKeywordsImportReady(const std::vector<TemplateURL*>& template_urls,
-                             bool unique_on_host_and_path);
+  void OnKeywordsImportReady(
+      const std::vector<importer::URLKeywordInfo>& url_keywords,
+      bool unique_on_host_and_path);
+  void OnFirefoxSearchEngineDataReceived(
+      const std::vector<std::string> search_engine_data);
 
  protected:
   virtual ~ExternalProcessImporterClient();
@@ -88,7 +94,7 @@
 
   // These variables store data being collected from the importer until the
   // entire group has been collected and is ready to be written to the profile.
-  history::URLRows history_rows_;
+  std::vector<ImporterURLRow> history_rows_;
   std::vector<ImportedBookmarkEntry> bookmarks_;
   std::vector<ImportedFaviconUsage> favicons_;
 
@@ -117,7 +123,7 @@
   base::WeakPtr<content::UtilityProcessHost> utility_process_host_;
 
   // Data to be passed from the importer host to the external importer.
-  const importer::SourceProfile& source_profile_;
+  importer::SourceProfile source_profile_;
   uint16 items_;
 
   // Takes import data coming over IPC and delivers it to be written by the
diff --git a/chrome/browser/importer/external_process_importer_host.cc b/chrome/browser/importer/external_process_importer_host.cc
index 1e66b69..a461aac 100644
--- a/chrome/browser/importer/external_process_importer_host.cc
+++ b/chrome/browser/importer/external_process_importer_host.cc
@@ -4,13 +4,34 @@
 
 #include "chrome/browser/importer/external_process_importer_host.h"
 
+#include "base/bind.h"
 #include "chrome/browser/bookmarks/bookmark_model.h"
+#include "chrome/browser/bookmarks/bookmark_model_factory.h"
 #include "chrome/browser/importer/external_process_importer_client.h"
-#include "chrome/browser/importer/importer_type.h"
+#include "chrome/browser/importer/firefox_profile_lock.h"
+#include "chrome/browser/importer/importer.h"
+#include "chrome/browser/importer/importer_creator.h"
+#include "chrome/browser/importer/importer_lock_dialog.h"
+#include "chrome/browser/importer/importer_progress_observer.h"
 #include "chrome/browser/importer/in_process_importer_bridge.h"
+#include "chrome/browser/search_engines/template_url_service.h"
+#include "chrome/browser/search_engines/template_url_service_factory.h"
+#include "chrome/common/chrome_notification_types.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/notification_source.h"
+
+using content::BrowserThread;
 
 ExternalProcessImporterHost::ExternalProcessImporterHost()
-    : client_(NULL),
+    : weak_ptr_factory_(this),
+      headless_(false),
+      parent_window_(NULL),
+      observer_(NULL),
+      profile_(NULL),
+      waiting_for_bookmarkbar_model_(false),
+      installed_bookmark_observer_(false),
+      is_source_readable_(true),
+      client_(NULL),
       source_profile_(NULL),
       items_(0),
       cancelled_(false),
@@ -24,8 +45,6 @@
   NotifyImportEnded();  // Tells the observer that we're done, and deletes us.
 }
 
-ExternalProcessImporterHost::~ExternalProcessImporterHost() {}
-
 void ExternalProcessImporterHost::StartImportSettings(
     const importer::SourceProfile& source_profile,
     Profile* target_profile,
@@ -47,10 +66,42 @@
 
   CheckForLoadedModels(items);
 
-  InvokeTaskIfDone();
+  LaunchImportIfReady();
 }
 
-void ExternalProcessImporterHost::InvokeTaskIfDone() {
+void ExternalProcessImporterHost::NotifyImportStarted() {
+  if (observer_)
+    observer_->ImportStarted();
+}
+
+void ExternalProcessImporterHost::NotifyImportItemStarted(
+    importer::ImportItem item) {
+  if (observer_)
+    observer_->ImportItemStarted(item);
+}
+
+void ExternalProcessImporterHost::NotifyImportItemEnded(
+    importer::ImportItem item) {
+  if (observer_)
+    observer_->ImportItemEnded(item);
+}
+
+void ExternalProcessImporterHost::NotifyImportEnded() {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  firefox_lock_.reset();
+  if (observer_)
+    observer_->ImportEnded();
+  delete this;
+}
+
+ExternalProcessImporterHost::~ExternalProcessImporterHost() {
+  if (installed_bookmark_observer_) {
+    DCHECK(profile_);
+    BookmarkModelFactory::GetForProfile(profile_)->RemoveObserver(this);
+  }
+}
+
+void ExternalProcessImporterHost::LaunchImportIfReady() {
   if (waiting_for_bookmarkbar_model_ || !registrar_.IsEmpty() ||
       !is_source_readable_ || cancelled_)
     return;
@@ -76,5 +127,93 @@
   waiting_for_bookmarkbar_model_ = false;
   installed_bookmark_observer_ = false;
 
-  InvokeTaskIfDone();
+  LaunchImportIfReady();
+}
+
+void ExternalProcessImporterHost::BookmarkModelBeingDeleted(
+    BookmarkModel* model) {
+  installed_bookmark_observer_ = false;
+}
+
+void ExternalProcessImporterHost::BookmarkModelChanged() {
+}
+
+void ExternalProcessImporterHost::Observe(int type,
+                           const content::NotificationSource& source,
+                           const content::NotificationDetails& details) {
+  DCHECK_EQ(type, chrome::NOTIFICATION_TEMPLATE_URL_SERVICE_LOADED);
+  registrar_.RemoveAll();
+  LaunchImportIfReady();
+}
+
+void ExternalProcessImporterHost::ShowWarningDialog() {
+  DCHECK(!headless_);
+  importer::ShowImportLockDialog(
+      parent_window_,
+      base::Bind(&ExternalProcessImporterHost::OnImportLockDialogEnd,
+                 weak_ptr_factory_.GetWeakPtr()));
+}
+
+void ExternalProcessImporterHost::OnImportLockDialogEnd(bool is_continue) {
+  if (is_continue) {
+    // User chose to continue, then we check the lock again to make
+    // sure that Firefox has been closed. Try to import the settings
+    // if successful. Otherwise, show a warning dialog.
+    firefox_lock_->Lock();
+    if (firefox_lock_->HasAcquired()) {
+      is_source_readable_ = true;
+      LaunchImportIfReady();
+    } else {
+      ShowWarningDialog();
+    }
+  } else {
+    NotifyImportEnded();
+  }
+}
+
+bool ExternalProcessImporterHost::CheckForFirefoxLock(
+    const importer::SourceProfile& source_profile) {
+  if (source_profile.importer_type != importer::TYPE_FIREFOX3)
+    return true;
+
+  DCHECK(!firefox_lock_.get());
+  firefox_lock_.reset(new FirefoxProfileLock(source_profile.source_path));
+  if (firefox_lock_->HasAcquired())
+    return true;
+
+  // If fail to acquire the lock, we set the source unreadable and
+  // show a warning dialog, unless running without UI (in which case the import
+  // must be aborted).
+  is_source_readable_ = false;
+  if (headless_)
+    return false;
+
+  ShowWarningDialog();
+  return true;
+}
+
+void ExternalProcessImporterHost::CheckForLoadedModels(uint16 items) {
+  // A target profile must be loaded by StartImportSettings().
+  DCHECK(profile_);
+
+  // BookmarkModel should be loaded before adding IE favorites. So we observe
+  // the BookmarkModel if needed, and start the task after it has been loaded.
+  if ((items & importer::FAVORITES) && !writer_->BookmarkModelIsLoaded()) {
+    BookmarkModelFactory::GetForProfile(profile_)->AddObserver(this);
+    waiting_for_bookmarkbar_model_ = true;
+    installed_bookmark_observer_ = true;
+  }
+
+  // Observes the TemplateURLService if needed to import search engines from the
+  // other browser. We also check to see if we're importing bookmarks because
+  // we can import bookmark keywords from Firefox as search engines.
+  if ((items & importer::SEARCH_ENGINES) || (items & importer::FAVORITES)) {
+    if (!writer_->TemplateURLServiceIsLoaded()) {
+      TemplateURLService* model =
+          TemplateURLServiceFactory::GetForProfile(profile_);
+      registrar_.Add(this, chrome::NOTIFICATION_TEMPLATE_URL_SERVICE_LOADED,
+                     content::Source<TemplateURLService>(model));
+      model->Load();
+    }
+  }
 }
diff --git a/chrome/browser/importer/external_process_importer_host.h b/chrome/browser/importer/external_process_importer_host.h
index 215263e..abf8077 100644
--- a/chrome/browser/importer/external_process_importer_host.h
+++ b/chrome/browser/importer/external_process_importer_host.h
@@ -7,11 +7,21 @@
 
 #include "base/basictypes.h"
 #include "base/compiler_specific.h"
-#include "chrome/browser/importer/importer_host.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "chrome/browser/bookmarks/base_bookmark_model_observer.h"
+#include "chrome/browser/importer/importer_progress_observer.h"
+#include "chrome/browser/importer/profile_writer.h"
+#include "chrome/common/importer/importer_data_types.h"
+#include "content/public/browser/notification_observer.h"
+#include "content/public/browser/notification_registrar.h"
+#include "ui/gfx/native_widget_types.h"
 
 class ExternalProcessImporterClient;
+class FirefoxProfileLock;
+class Importer;
 class Profile;
-class ProfileWriter;
 
 namespace importer {
 struct SourceProfile;
@@ -19,23 +29,124 @@
 
 // This class manages the import process. It creates the in-process half of the
 // importer bridge and the external process importer client.
-class ExternalProcessImporterHost : public ImporterHost {
+class ExternalProcessImporterHost : public BaseBookmarkModelObserver,
+                                    public content::NotificationObserver {
  public:
   ExternalProcessImporterHost();
 
   void Cancel();
 
- private:
-  virtual ~ExternalProcessImporterHost();
-
-  // ImporterHost:
+  // Starts the process of importing the settings and data depending on what the
+  // user selected.
+  // |source_profile| - importer profile to import.
+  // |target_profile| - profile to import into.
+  // |items| - specifies which data to import (bitmask of importer::ImportItem).
+  // |writer| - called to actually write data back to the profile.
   virtual void StartImportSettings(
       const importer::SourceProfile& source_profile,
       Profile* target_profile,
       uint16 items,
-      ProfileWriter* writer) OVERRIDE;
-  virtual void InvokeTaskIfDone() OVERRIDE;
+      ProfileWriter* writer);
+
+  // When in headless mode, the importer will not show any warning dialog if
+  // a user action is required (e.g., Firefox profile is locked and user should
+  // close Firefox to continue) and the outcome is as if the user had canceled
+  // the import operation.
+  void set_headless() { headless_ = true; }
+  bool is_headless() const { return headless_; }
+
+  void set_parent_window(gfx::NativeWindow parent_window) {
+    parent_window_ = parent_window;
+  }
+
+  void set_observer(importer::ImporterProgressObserver* observer) {
+    observer_ = observer;
+  }
+
+  // A series of functions invoked at the start, during and end of the import
+  // process. The middle functions are notifications that the a harvesting of a
+  // particular source of data (specified by |item|) is under way.
+  void NotifyImportStarted();
+  void NotifyImportItemStarted(importer::ImportItem item);
+  void NotifyImportItemEnded(importer::ImportItem item);
+  void NotifyImportEnded();
+
+ private:
+  // ExternalProcessImporterHost deletes itself in OnImportEnded().
+  virtual ~ExternalProcessImporterHost();
+
+  // Launches the utility process that starts the import task, unless bookmark
+  // or template model are not yet loaded. If load is not detected, this method
+  // will be called when the loading observer sees that model loading is
+  // complete.
+  virtual void LaunchImportIfReady();
+
+  // BaseBookmarkModelObserver:
   virtual void Loaded(BookmarkModel* model, bool ids_reassigned) OVERRIDE;
+  virtual void BookmarkModelBeingDeleted(BookmarkModel* model) OVERRIDE;
+  virtual void BookmarkModelChanged() OVERRIDE;
+
+  // content::NotificationObserver:
+  // Called when TemplateURLService has been loaded.
+  virtual void Observe(int type,
+                       const content::NotificationSource& source,
+                       const content::NotificationDetails& details) OVERRIDE;
+
+  // ShowWarningDialog() asks user to close the application that is owning the
+  // lock. They can retry or skip the importing process.
+  // This method should not be called if the importer is in headless mode.
+  void ShowWarningDialog();
+
+  // This is called when when user ends the lock dialog by clicking on either
+  // the "Skip" or "Continue" buttons. |is_continue| is true when user clicked
+  // the "Continue" button.
+  void OnImportLockDialogEnd(bool is_continue);
+
+  // Make sure that Firefox isn't running, if import browser is Firefox. Show
+  // to the user a dialog that notifies that is necessary to close Firefox
+  // prior to continue.
+  // |source_profile| - importer profile to import.
+  // Returns false iff import should be aborted.
+  bool CheckForFirefoxLock(const importer::SourceProfile& source_profile);
+
+  // Make sure BookmarkModel and TemplateURLService are loaded before import
+  // process starts, if bookmarks and/or search engines are among the items
+  // which are to be imported.
+  void CheckForLoadedModels(uint16 items);
+
+  // Vends weak pointers for the importer to call us back.
+  base::WeakPtrFactory<ExternalProcessImporterHost> weak_ptr_factory_;
+
+  // True if UI is not to be shown.
+  bool headless_;
+
+  // Parent window that we pass to the import lock dialog (i.e, the Firefox
+  // warning dialog).
+  gfx::NativeWindow parent_window_;
+
+  // The observer that we need to notify about changes in the import process.
+  importer::ImporterProgressObserver* observer_;
+
+  // Firefox profile lock.
+  scoped_ptr<FirefoxProfileLock> firefox_lock_;
+
+  // Profile we're importing from.
+  Profile* profile_;
+
+  // True if we're waiting for the model to finish loading.
+  bool waiting_for_bookmarkbar_model_;
+
+  // Have we installed a listener on the bookmark model?
+  bool installed_bookmark_observer_;
+
+  // True if source profile is readable.
+  bool is_source_readable_;
+
+  // Receives notification when the TemplateURLService has loaded.
+  content::NotificationRegistrar registrar_;
+
+  // Writes data from the importer back to the profile.
+  scoped_refptr<ProfileWriter> writer_;
 
   // Used to pass notifications from the browser side to the external process.
   ExternalProcessImporterClient* client_;
diff --git a/chrome/browser/importer/firefox3_importer.cc b/chrome/browser/importer/firefox3_importer.cc
index e58fa81..c3ec58d 100644
--- a/chrome/browser/importer/firefox3_importer.cc
+++ b/chrome/browser/importer/firefox3_importer.cc
@@ -13,22 +13,22 @@
 #include "base/stl_util.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/bookmarks/bookmark_html_reader.h"
-#include "chrome/browser/bookmarks/imported_bookmark_entry.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/favicon/favicon_util.h"
-#include "chrome/browser/favicon/imported_favicon_usage.h"
+#include "chrome/browser/importer/bookmark_html_reader.h"
 #include "chrome/browser/importer/firefox_importer_utils.h"
 #include "chrome/browser/importer/importer_bridge.h"
 #include "chrome/browser/importer/nss_decryptor.h"
-#include "chrome/browser/search_engines/template_url.h"
+#include "chrome/common/importer/imported_bookmark_entry.h"
+#include "chrome/common/importer/imported_favicon_usage.h"
+#include "chrome/common/importer/importer_url_row.h"
 #include "chrome/common/time_format.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/common/password_form.h"
-#include "googleurl/src/gurl.h"
 #include "grit/generated_resources.h"
 #include "sql/connection.h"
 #include "sql/statement.h"
+#include "url/gurl.h"
 
 using content::BrowserThread;
 
@@ -43,24 +43,6 @@
   TYPE_DYNAMIC_CONTAINER = 4
 };
 
-// Creates a TemplateURL with the |keyword| and |url|. |title| may be empty.
-// This function transfers ownership of the created TemplateURL to the caller.
-TemplateURL* CreateTemplateURL(const string16& title,
-                               const string16& keyword,
-                               const GURL& url) {
-  // Skip if the keyword or url is invalid.
-  if (keyword.empty() || !url.is_valid())
-    return NULL;
-
-  TemplateURLData data;
-  // We set short name by using the title if it exists.
-  // Otherwise, we use the shortcut.
-  data.short_name = title.empty() ? keyword : title;
-  data.SetKeyword(keyword);
-  data.SetURL(TemplateURLRef::DisplayURLToURLRef(UTF8ToUTF16(url.spec())));
-  return new TemplateURL(NULL, data);
-}
-
 // Loads the default bookmarks in the Firefox installed at |app_path|,
 // and stores their locations in |urls|.
 void LoadDefaultBookmarks(const base::FilePath& app_path,
@@ -95,10 +77,6 @@
 };
 
 Firefox3Importer::Firefox3Importer() {
-#if defined(OS_POSIX) && !defined(OS_MACOSX)
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  locale_ = g_browser_process->GetApplicationLocale();
-#endif
 }
 
 Firefox3Importer::~Firefox3Importer() {
@@ -108,13 +86,14 @@
     const importer::SourceProfile& source_profile,
     uint16 items,
     ImporterBridge* bridge) {
-#if defined(OS_POSIX) && !defined(OS_MACOSX)
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
-#endif
   bridge_ = bridge;
   source_path_ = source_profile.source_path;
   app_path_ = source_profile.app_path;
 
+#if defined(OS_POSIX)
+  locale_ = source_profile.locale;
+#endif
+
   // The order here is important!
   bridge_->NotifyStarted();
   if ((items & importer::HOME_PAGE) && !cancelled())
@@ -169,7 +148,7 @@
 
   sql::Statement s(db.GetUniqueStatement(query));
 
-  history::URLRows rows;
+  std::vector<ImporterURLRow> rows;
   while (s.Step() && !cancelled()) {
     GURL url(s.ColumnString(0));
 
@@ -177,12 +156,12 @@
     if (!CanImportURL(url))
       continue;
 
-    history::URLRow row(url);
-    row.set_title(s.ColumnString16(1));
-    row.set_visit_count(s.ColumnInt(2));
-    row.set_hidden(s.ColumnInt(3) == 1);
-    row.set_typed_count(s.ColumnInt(4));
-    row.set_last_visit(base::Time::FromTimeT(s.ColumnInt64(5)/1000000));
+    ImporterURLRow row(url);
+    row.title = s.ColumnString16(1);
+    row.visit_count = s.ColumnInt(2);
+    row.hidden = s.ColumnInt(3) == 1;
+    row.typed_count = s.ColumnInt(4);
+    row.last_visit = base::Time::FromTimeT(s.ColumnInt64(5)/1000000);
 
     rows.push_back(row);
   }
@@ -223,7 +202,7 @@
     GetWholeBookmarkFolder(&db, &list, i, NULL);
 
   std::vector<ImportedBookmarkEntry> bookmarks;
-  std::vector<TemplateURL*> template_urls;
+  std::vector<importer::URLKeywordInfo> url_keywords;
   FaviconMap favicon_map;
 
   // TODO(jcampan): http://b/issue?id=1196285 we do not support POST based
@@ -311,11 +290,14 @@
       if (item->favicon)
         favicon_map[item->favicon].insert(item->url);
 
-      // This bookmark has a keyword, we import it to our TemplateURL model.
-      TemplateURL* t_url = CreateTemplateURL(
-          item->title, UTF8ToUTF16(item->keyword), item->url);
-      if (t_url)
-        template_urls.push_back(t_url);
+      // This bookmark has a keyword, we should import it.
+      if (!item->keyword.empty() && item->url.is_valid()) {
+        importer::URLKeywordInfo url_keyword_info;
+        url_keyword_info.url = item->url;
+        url_keyword_info.keyword.assign(UTF8ToUTF16(item->keyword));
+        url_keyword_info.display_name = item->title;
+        url_keywords.push_back(url_keyword_info);
+      }
     }
   }
 
@@ -327,10 +309,9 @@
         bridge_->GetLocalizedString(IDS_BOOKMARK_GROUP_FROM_FIREFOX);
     bridge_->AddBookmarks(bookmarks, first_folder_name);
   }
-  if (!template_urls.empty() && !cancelled())
-    bridge_->SetKeywords(template_urls, false);
-  else
-    STLDeleteElements(&template_urls);
+  if (!url_keywords.empty() && !cancelled()) {
+    bridge_->SetKeywords(url_keywords, false);
+  }
   if (!favicon_map.empty() && !cancelled()) {
     std::vector<ImportedFaviconUsage> favicons;
     LoadFavicons(&db, favicon_map, &favicons);
@@ -371,13 +352,10 @@
 }
 
 void Firefox3Importer::ImportSearchEngines() {
-  std::vector<base::FilePath> files;
-  GetSearchEnginesXMLFiles(&files);
+  std::vector<std::string> search_engine_data;
+  GetSearchEnginesXMLData(&search_engine_data);
 
-  std::vector<TemplateURL*> search_engines;
-  ParseSearchEnginesFromXMLFiles(files, &search_engines);
-
-  bridge_->SetKeywords(search_engines, true);
+  bridge_->SetFirefoxSearchEnginesXMLData(search_engine_data);
 }
 
 void Firefox3Importer::ImportHomepage() {
@@ -387,8 +365,8 @@
   }
 }
 
-void Firefox3Importer::GetSearchEnginesXMLFiles(
-    std::vector<base::FilePath>* files) {
+void Firefox3Importer::GetSearchEnginesXMLData(
+    std::vector<std::string>* search_engine_data) {
   base::FilePath file = source_path_.AppendASCII("search.sqlite");
   if (!file_util::PathExists(file))
     return;
@@ -435,16 +413,19 @@
         // Looks like absolute path to the file.
         file = base::FilePath::FromUTF8Unsafe(engine);
       }
-      files->push_back(file);
+      std::string file_data;
+      file_util::ReadFileToString(file, &file_data);
+      search_engine_data->push_back(file_data);
     } while (s.Step() && !cancelled());
   }
 
-#if defined(OS_POSIX) && !defined(OS_MACOSX)
+#if defined(OS_POSIX)
   // Ubuntu-flavored Firefox3 supports locale-specific search engines via
   // locale-named subdirectories. They fall back to en-US.
   // See http://crbug.com/53899
   // TODO(jshin): we need to make sure our locale code matches that of
   // Firefox.
+  DCHECK(!locale_.empty());
   base::FilePath locale_app_path = app_path.AppendASCII(locale_);
   base::FilePath default_locale_app_path = app_path.AppendASCII("en-US");
   if (file_util::DirectoryExists(locale_app_path))
@@ -457,7 +438,9 @@
   base::FileEnumerator engines(app_path, false, base::FileEnumerator::FILES);
   for (base::FilePath engine_path = engines.Next();
        !engine_path.value().empty(); engine_path = engines.Next()) {
-    files->push_back(engine_path);
+    std::string file_data;
+    file_util::ReadFileToString(file, &file_data);
+    search_engine_data->push_back(file_data);
   }
 }
 
diff --git a/chrome/browser/importer/firefox3_importer.h b/chrome/browser/importer/firefox3_importer.h
index bff7eb3..a609f80 100644
--- a/chrome/browser/importer/firefox3_importer.h
+++ b/chrome/browser/importer/firefox3_importer.h
@@ -46,7 +46,7 @@
   // Import the user's home page, unless it is set to default home page as
   // defined in browserconfig.properties.
   void ImportHomepage();
-  void GetSearchEnginesXMLFiles(std::vector<base::FilePath>* files);
+  void GetSearchEnginesXMLData(std::vector<std::string>* search_engine_data);
 
   // The struct stores the information about a bookmark item.
   struct BookmarkItem;
@@ -78,9 +78,8 @@
   base::FilePath source_path_;
   base::FilePath app_path_;
 
-#if defined(OS_POSIX) && !defined(OS_MACOSX)
-  // Stored because we can only access it from the UI thread. Not usable
-  // in Mac because no access from out-of-process import.
+#if defined(OS_POSIX)
+  // Stored because we can only access it from the UI thread.
   std::string locale_;
 #endif
 
diff --git a/chrome/browser/importer/firefox_importer_browsertest.cc b/chrome/browser/importer/firefox_importer_browsertest.cc
index 4042f35..8cde615 100644
--- a/chrome/browser/importer/firefox_importer_browsertest.cc
+++ b/chrome/browser/importer/firefox_importer_browsertest.cc
@@ -11,17 +11,16 @@
 #include "base/strings/string16.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/bookmarks/imported_bookmark_entry.h"
-#include "chrome/browser/favicon/imported_favicon_usage.h"
 #include "chrome/browser/importer/external_process_importer_host.h"
 #include "chrome/browser/importer/firefox_importer_unittest_utils.h"
-#include "chrome/browser/importer/importer_data_types.h"
-#include "chrome/browser/importer/importer_host.h"
 #include "chrome/browser/importer/importer_progress_observer.h"
 #include "chrome/browser/importer/importer_unittest_utils.h"
 #include "chrome/browser/search_engines/template_url.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/common/chrome_paths.h"
+#include "chrome/common/importer/imported_bookmark_entry.h"
+#include "chrome/common/importer/imported_favicon_usage.h"
+#include "chrome/common/importer/importer_data_types.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "content/public/common/password_form.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -220,7 +219,7 @@
     // Creates a new profile in a new subdirectory in the temp directory.
     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
     base::FilePath test_path = temp_dir_.path().AppendASCII("ImporterTest");
-    file_util::Delete(test_path, true);
+    base::Delete(test_path, true);
     file_util::CreateDirectory(test_path);
     profile_path_ = test_path.AppendASCII("profile");
     app_path_ = test_path.AppendASCII("app");
@@ -262,20 +261,15 @@
     source_profile.importer_type = importer::TYPE_FIREFOX3;
     source_profile.app_path = app_path_;
     source_profile.source_path = profile_path_;
+    source_profile.locale = "en-US";
 
     int items = importer::HISTORY | importer::PASSWORDS | importer::FAVORITES;
     if (import_search_plugins)
       items = items | importer::SEARCH_ENGINES;
 
     // Deletes itself.
-    // TODO(gab): Use ExternalProcessImporterHost on Linux as well.
-    ImporterHost* host;
-#if defined(OS_MACOSX) || defined(OS_WIN)
-    host = new ExternalProcessImporterHost;
-#else
-    host = new ImporterHost;
-#endif
-    host->SetObserver(observer);
+    ExternalProcessImporterHost* host = new ExternalProcessImporterHost;
+    host->set_observer(observer);
     host->StartImportSettings(source_profile,
                               browser()->profile(),
                               items,
diff --git a/chrome/browser/importer/firefox_importer_utils.cc b/chrome/browser/importer/firefox_importer_utils.cc
index 4553c11..5610f5b 100644
--- a/chrome/browser/importer/firefox_importer_utils.cc
+++ b/chrome/browser/importer/firefox_importer_utils.cc
@@ -16,38 +16,9 @@
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
-#include "chrome/browser/search_engines/template_url.h"
-#include "chrome/browser/search_engines/template_url_parser.h"
-#include "chrome/browser/search_engines/template_url_prepopulate_data.h"
-#include "chrome/browser/search_engines/template_url_service.h"
-#include "googleurl/src/gurl.h"
 #include "grit/generated_resources.h"
 #include "ui/base/l10n/l10n_util.h"
-
-namespace {
-
-// FirefoxURLParameterFilter is used to remove parameter mentioning Firefox from
-// the search URL when importing search engines.
-class FirefoxURLParameterFilter : public TemplateURLParser::ParameterFilter {
- public:
-  FirefoxURLParameterFilter() {}
-  virtual ~FirefoxURLParameterFilter() {}
-
-  // TemplateURLParser::ParameterFilter method.
-  virtual bool KeepParameter(const std::string& key,
-                             const std::string& value) OVERRIDE {
-    std::string low_value = StringToLowerASCII(value);
-    if (low_value.find("mozilla") != std::string::npos ||
-        low_value.find("firefox") != std::string::npos ||
-        low_value.find("moz:") != std::string::npos )
-      return false;
-    return true;
-  }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(FirefoxURLParameterFilter);
-};
-}  // namespace
+#include "url/gurl.h"
 
 base::FilePath GetFirefoxProfilePath() {
   base::FilePath ini_file = GetProfilesINI();
@@ -149,53 +120,6 @@
   return true;
 }
 
-void ParseSearchEnginesFromXMLFiles(
-    const std::vector<base::FilePath>& xml_files,
-    std::vector<TemplateURL*>* search_engines) {
-  DCHECK(search_engines);
-
-  typedef std::map<std::string, TemplateURL*> SearchEnginesMap;
-  SearchEnginesMap search_engine_for_url;
-  std::string content;
-  // The first XML file represents the default search engine in Firefox 3, so we
-  // need to keep it on top of the list.
-  SearchEnginesMap::const_iterator default_turl = search_engine_for_url.end();
-  for (std::vector<base::FilePath>::const_iterator file_iter =
-           xml_files.begin(); file_iter != xml_files.end(); ++file_iter) {
-    file_util::ReadFileToString(*file_iter, &content);
-    FirefoxURLParameterFilter param_filter;
-    TemplateURL* template_url = TemplateURLParser::Parse(NULL, true,
-        content.data(), content.length(), &param_filter);
-    if (template_url) {
-      SearchEnginesMap::iterator iter =
-          search_engine_for_url.find(template_url->url());
-      if (iter == search_engine_for_url.end()) {
-        iter = search_engine_for_url.insert(
-            std::make_pair(template_url->url(), template_url)).first;
-      } else {
-        // We have already found a search engine with the same URL.  We give
-        // priority to the latest one found, as GetSearchEnginesXMLFiles()
-        // returns a vector with first Firefox default search engines and then
-        // the user's ones.  We want to give priority to the user ones.
-        delete iter->second;
-        iter->second = template_url;
-      }
-      if (default_turl == search_engine_for_url.end())
-        default_turl = iter;
-    }
-    content.clear();
-  }
-
-  // Put the results in the |search_engines| vector.
-  for (SearchEnginesMap::iterator t_iter = search_engine_for_url.begin();
-       t_iter != search_engine_for_url.end(); ++t_iter) {
-    if (t_iter == default_turl)
-      search_engines->insert(search_engines->begin(), default_turl->second);
-    else
-      search_engines->push_back(t_iter->second);
-  }
-}
-
 bool ReadPrefFile(const base::FilePath& path, std::string* content) {
   if (content == NULL)
     return false;
diff --git a/chrome/browser/importer/firefox_importer_utils.h b/chrome/browser/importer/firefox_importer_utils.h
index 54e7162..5446ddf 100644
--- a/chrome/browser/importer/firefox_importer_utils.h
+++ b/chrome/browser/importer/firefox_importer_utils.h
@@ -71,11 +71,6 @@
 // with a unsupported scheme.
 bool CanImportURL(const GURL& url);
 
-// Parses the OpenSearch XML files in |xml_files| and populates |search_engines|
-// with the resulting TemplateURLs.
-void ParseSearchEnginesFromXMLFiles(const std::vector<base::FilePath>& xml_files,
-                                    std::vector<TemplateURL*>* search_engines);
-
 // Returns the home page set in Firefox in a particular profile.
 GURL GetHomepage(const base::FilePath& profile_path);
 
diff --git a/chrome/browser/importer/firefox_profile_lock_posix.cc b/chrome/browser/importer/firefox_profile_lock_posix.cc
index 2b24187..dd00b70 100644
--- a/chrome/browser/importer/firefox_profile_lock_posix.cc
+++ b/chrome/browser/importer/firefox_profile_lock_posix.cc
@@ -78,7 +78,7 @@
     return;
   close(lock_fd_);
   lock_fd_ = -1;
-  file_util::Delete(old_lock_file_, false);
+  base::Delete(old_lock_file_, false);
 }
 
 bool FirefoxProfileLock::HasAcquired() {
diff --git a/chrome/browser/importer/ie_importer.cc b/chrome/browser/importer/ie_importer.cc
index cb6e7a2..b5ad754 100644
--- a/chrome/browser/importer/ie_importer.cc
+++ b/chrome/browser/importer/ie_importer.cc
@@ -22,30 +22,28 @@
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "base/win/registry.h"
 #include "base/win/scoped_co_mem.h"
 #include "base/win/scoped_comptr.h"
 #include "base/win/scoped_handle.h"
 #include "base/win/scoped_propvariant.h"
 #include "base/win/windows_version.h"
-#include "chrome/browser/bookmarks/imported_bookmark_entry.h"
 #include "chrome/browser/favicon/favicon_util.h"
-#include "chrome/browser/favicon/imported_favicon_usage.h"
 #include "chrome/browser/importer/ie_importer_utils_win.h"
 #include "chrome/browser/importer/importer_bridge.h"
-#include "chrome/browser/importer/importer_data_types.h"
 #include "chrome/browser/importer/pstore_declarations.h"
-#include "chrome/browser/search_engines/template_url.h"
-#include "chrome/browser/search_engines/template_url_prepopulate_data.h"
-#include "chrome/browser/search_engines/template_url_service.h"
+#include "chrome/common/importer/imported_bookmark_entry.h"
+#include "chrome/common/importer/imported_favicon_usage.h"
+#include "chrome/common/importer/importer_data_types.h"
+#include "chrome/common/importer/importer_url_row.h"
 #include "chrome/common/time_format.h"
 #include "chrome/common/url_constants.h"
 #include "components/webdata/encryptor/ie7_password.h"
 #include "content/public/common/password_form.h"
-#include "googleurl/src/gurl.h"
 #include "grit/generated_resources.h"
 #include "ui/base/l10n/l10n_util.h"
+#include "url/gurl.h"
 
 namespace {
 
@@ -489,7 +487,7 @@
     return;
   base::win::ScopedComPtr<IEnumSTATURL> enum_url;
   if (SUCCEEDED(result = url_history_stg2->EnumUrls(enum_url.Receive()))) {
-    history::URLRows rows;
+    std::vector<ImporterURLRow> rows;
     STATURL stat_url;
     ULONG fetched;
     while (!cancelled() &&
@@ -512,14 +510,14 @@
            kSchemes + total_schemes))
         continue;
 
-      history::URLRow row(url);
-      row.set_title(title_string);
-      row.set_last_visit(base::Time::FromFileTime(stat_url.ftLastVisited));
+      ImporterURLRow row(url);
+      row.title = title_string;
+      row.last_visit = base::Time::FromFileTime(stat_url.ftLastVisited);
       if (stat_url.dwFlags == STATURL_QUERYFLAG_TOPLEVEL) {
-        row.set_visit_count(1);
-        row.set_hidden(false);
+        row.visit_count = 1;
+        row.hidden = false;
       } else {
-        row.set_hidden(true);
+        row.hidden = true;
       }
 
       rows.push_back(row);
@@ -686,7 +684,7 @@
   // Software\Microsoft\Internet Explorer\SearchScopes
   // Each key represents a search engine. The URL value contains the URL and
   // the DisplayName the name.
-  typedef std::map<std::string, TemplateURL*> SearchEnginesMap;
+  typedef std::map<std::string, string16> SearchEnginesMap;
   SearchEnginesMap search_engines_map;
   for (base::win::RegistryKeyIterator key_iter(HKEY_CURRENT_USER,
        kSearchScopePath); key_iter.Valid(); ++key_iter) {
@@ -719,24 +717,20 @@
       // First time we see that URL.
       GURL gurl(url);
       if (gurl.is_valid()) {
-        TemplateURLData data;
-        data.short_name = name;
-        data.SetKeyword(TemplateURLService::GenerateKeyword(gurl));
-        data.SetURL(url);
-        data.show_in_default_list = true;
-        t_iter = search_engines_map.insert(std::make_pair(url,
-            new TemplateURL(NULL, data))).first;
+        t_iter = search_engines_map.insert(std::make_pair(url, name)).first;
       }
     }
   }
-
   // ProfileWriter::AddKeywords() requires a vector and we have a map.
-  std::vector<TemplateURL*> search_engines;
+  std::vector<importer::URLKeywordInfo> url_keywords;
   for (SearchEnginesMap::iterator i = search_engines_map.begin();
-       i != search_engines_map.end(); ++i)
-    search_engines.push_back(i->second);
-
-  bridge_->SetKeywords(search_engines, true);
+       i != search_engines_map.end(); ++i) {
+    importer::URLKeywordInfo url_keyword_info;
+    url_keyword_info.url = GURL(i->first);
+    url_keyword_info.display_name = i->second;
+    url_keywords.push_back(url_keyword_info);
+  }
+  bridge_->SetKeywords(url_keywords, true);
 }
 
 void IEImporter::ImportHomepage() {
diff --git a/chrome/browser/importer/ie_importer_browsertest_win.cc b/chrome/browser/importer/ie_importer_browsertest_win.cc
index b281b57..d4747d4 100644
--- a/chrome/browser/importer/ie_importer_browsertest_win.cc
+++ b/chrome/browser/importer/ie_importer_browsertest_win.cc
@@ -6,10 +6,10 @@
 #include <windows.h>
 #include <unknwn.h>
 #include <intshcut.h>
-#include <shlguid.h>
-#include <urlhist.h>
-#include <shlobj.h>
 #include <propvarutil.h>
+#include <shlguid.h>
+#include <shlobj.h>
+#include <urlhist.h>
 
 #include <algorithm>
 #include <vector>
@@ -28,21 +28,20 @@
 #include "base/win/scoped_comptr.h"
 #include "base/win/scoped_propvariant.h"
 #include "base/win/windows_version.h"
-#include "chrome/browser/bookmarks/imported_bookmark_entry.h"
-#include "chrome/browser/favicon/imported_favicon_usage.h"
 #include "chrome/browser/importer/external_process_importer_host.h"
 #include "chrome/browser/importer/ie_importer.h"
 #include "chrome/browser/importer/ie_importer_test_registry_overrider_win.h"
 #include "chrome/browser/importer/ie_importer_utils_win.h"
 #include "chrome/browser/importer/importer_bridge.h"
-#include "chrome/browser/importer/importer_data_types.h"
-#include "chrome/browser/importer/importer_host.h"
 #include "chrome/browser/importer/importer_progress_observer.h"
 #include "chrome/browser/importer/importer_unittest_utils.h"
 #include "chrome/browser/importer/pstore_declarations.h"
 #include "chrome/browser/search_engines/template_url.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/common/chrome_paths.h"
+#include "chrome/common/importer/imported_bookmark_entry.h"
+#include "chrome/common/importer/imported_favicon_usage.h"
+#include "chrome/common/importer/importer_data_types.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/testing_profile.h"
 #include "content/public/common/password_form.h"
@@ -485,9 +484,9 @@
 
   // Starts to import the above settings.
   // Deletes itself.
-  ImporterHost* host = new ExternalProcessImporterHost;
+  ExternalProcessImporterHost* host = new ExternalProcessImporterHost;
   TestObserver* observer = new TestObserver();
-  host->SetObserver(observer);
+  host->set_observer(observer);
 
   importer::SourceProfile source_profile;
   source_profile.importer_type = importer::TYPE_IE;
@@ -561,10 +560,10 @@
 
     // Starts to import the above settings.
     // Deletes itself.
-    ImporterHost* host = new ExternalProcessImporterHost;
+    ExternalProcessImporterHost* host = new ExternalProcessImporterHost;
     MalformedFavoritesRegistryTestObserver* observer =
         new MalformedFavoritesRegistryTestObserver();
-    host->SetObserver(observer);
+    host->set_observer(observer);
 
     importer::SourceProfile source_profile;
     source_profile.importer_type = importer::TYPE_IE;
diff --git a/chrome/browser/importer/importer_bridge.h b/chrome/browser/importer/importer_bridge.h
index 76915d3..ac9cfd5 100644
--- a/chrome/browser/importer/importer_bridge.h
+++ b/chrome/browser/importer/importer_bridge.h
@@ -5,6 +5,7 @@
 #ifndef CHROME_BROWSER_IMPORTER_IMPORTER_BRIDGE_H_
 #define CHROME_BROWSER_IMPORTER_IMPORTER_BRIDGE_H_
 
+#include <string>
 #include <vector>
 
 #include "base/basictypes.h"
@@ -12,15 +13,17 @@
 #include "base/strings/string16.h"
 #include "build/build_config.h"
 #include "chrome/browser/history/history_types.h"
-#include "chrome/browser/importer/importer_data_types.h"
+#include "chrome/common/importer/importer_data_types.h"
+#include "chrome/common/importer/importer_url_row.h"
 
 class GURL;
 struct IE7PasswordInfo;
 struct ImportedBookmarkEntry;
 struct ImportedFaviconUsage;
-class TemplateURL;
-// TODO: remove this, see friend declaration in ImporterBridge.
-class Toolbar5Importer;
+
+namespace importer {
+struct URLKeywordInfo;
+}
 
 namespace content {
 struct PasswordForm;
@@ -43,13 +46,17 @@
   virtual void SetFavicons(
       const std::vector<ImportedFaviconUsage>& favicons) = 0;
 
-  virtual void SetHistoryItems(const history::URLRows& rows,
+  virtual void SetHistoryItems(const std::vector<ImporterURLRow>& rows,
                                history::VisitSource visit_source) = 0;
 
-  // WARNING: This function takes ownership of (and deletes) the pointers in
-  // |template_urls|!
-  virtual void SetKeywords(const std::vector<TemplateURL*>& template_urls,
-                           bool unique_on_host_and_path) = 0;
+  virtual void SetKeywords(
+      const std::vector<importer::URLKeywordInfo>& url_keywords,
+      bool unique_on_host_and_path) = 0;
+
+  // The search_engine_data vector contains XML data retrieved from the Firefox
+  // profile and its sqlite db.
+  virtual void SetFirefoxSearchEnginesXMLData(
+      const std::vector<std::string>& search_engine_data) = 0;
 
   virtual void SetPasswordForm(const content::PasswordForm& form) = 0;
 
@@ -75,10 +82,6 @@
 
  protected:
   friend class base::RefCountedThreadSafe<ImporterBridge>;
-  // TODO: In order to run Toolbar5Importer OOP we need to cut this
-  // connection, but as an interim step we allow Toolbar5Import to break
-  // the abstraction here and assume import is in-process.
-  friend class Toolbar5Importer;
 
   virtual ~ImporterBridge();
 
diff --git a/chrome/browser/importer/importer_creator.cc b/chrome/browser/importer/importer_creator.cc
new file mode 100644
index 0000000..7127ed2
--- /dev/null
+++ b/chrome/browser/importer/importer_creator.cc
@@ -0,0 +1,107 @@
+// 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/importer/importer_creator.h"
+
+#include "base/logging.h"
+#include "base/metrics/histogram.h"
+#include "chrome/browser/importer/bookmarks_file_importer.h"
+#include "chrome/browser/importer/firefox3_importer.h"
+
+#if defined(OS_WIN)
+#include "chrome/browser/importer/ie_importer.h"
+#endif
+
+#if defined(OS_MACOSX)
+#include <CoreFoundation/CoreFoundation.h>
+#include "base/mac/foundation_util.h"
+#include "chrome/browser/importer/safari_importer.h"
+#endif
+
+namespace importer {
+
+namespace {
+
+// The enum used to register importer use.
+enum ImporterTypeMetrics {
+  IMPORTER_METRICS_UNKNOWN         = 0,
+#if defined(OS_WIN)
+  IMPORTER_METRICS_IE              = 1,
+#endif
+  IMPORTER_METRICS_FIREFOX2        = 2,  // obsolete
+  IMPORTER_METRICS_FIREFOX3        = 3,
+#if defined(OS_MACOSX)
+  IMPORTER_METRICS_SAFARI          = 4,
+#endif
+  IMPORTER_METRICS_GOOGLE_TOOLBAR5 = 5,  // obsolete
+  IMPORTER_METRICS_BOOKMARKS_FILE  = 6,
+
+  // Insert new values here. Never remove any existing values, as this enum is
+  // used to bucket a UMA histogram, and removing values breaks that.
+  IMPORTER_METRICS_SIZE
+};
+
+
+}  // namespace
+
+Importer* CreateImporterByType(ImporterType type) {
+  switch (type) {
+#if defined(OS_WIN)
+    case TYPE_IE:
+      return new IEImporter();
+#endif
+    case TYPE_BOOKMARKS_FILE:
+      return new BookmarksFileImporter();
+    case TYPE_FIREFOX3:
+      return new Firefox3Importer();
+#if defined(OS_MACOSX)
+    case TYPE_SAFARI:
+      return new SafariImporter(base::mac::GetUserLibraryPath());
+#endif
+    default:
+      NOTREACHED();
+      return NULL;
+  }
+  NOTREACHED();
+  return NULL;
+}
+
+void LogImporterUseToMetrics(const std::string& metric_postfix,
+                             ImporterType type) {
+  ImporterTypeMetrics metrics_type = IMPORTER_METRICS_UNKNOWN;
+  switch (type) {
+    case TYPE_UNKNOWN:
+      metrics_type = IMPORTER_METRICS_UNKNOWN;
+      break;
+#if defined(OS_WIN)
+    case TYPE_IE:
+      metrics_type = IMPORTER_METRICS_IE;
+      break;
+#endif
+    case TYPE_FIREFOX3:
+      metrics_type = IMPORTER_METRICS_FIREFOX3;
+      break;
+#if defined(OS_MACOSX)
+    case TYPE_SAFARI:
+      metrics_type = IMPORTER_METRICS_SAFARI;
+      break;
+#endif
+    case TYPE_BOOKMARKS_FILE:
+      metrics_type = IMPORTER_METRICS_BOOKMARKS_FILE;
+      break;
+  }
+
+  // Note: This leaks memory, which is the expected behavior as the factory
+  // creates and owns the histogram.
+  base::HistogramBase* histogram =
+      base::LinearHistogram::FactoryGet(
+          "Import.ImporterType." + metric_postfix,
+          1,
+          IMPORTER_METRICS_SIZE,
+          IMPORTER_METRICS_SIZE + 1,
+          base::HistogramBase::kUmaTargetedHistogramFlag);
+  histogram->Add(metrics_type);
+}
+
+}  // namespace importer
diff --git a/chrome/browser/importer/importer_creator.h b/chrome/browser/importer/importer_creator.h
new file mode 100644
index 0000000..b3b7465
--- /dev/null
+++ b/chrome/browser/importer/importer_creator.h
@@ -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.
+
+#ifndef CHROME_BROWSER_IMPORTER_IMPORTER_CREATOR_H_
+#define CHROME_BROWSER_IMPORTER_IMPORTER_CREATOR_H_
+
+#include <string>
+
+#include "chrome/common/importer/importer_type.h"
+
+class Importer;
+
+namespace importer {
+
+// Creates an Importer of the specified |type|.
+Importer* CreateImporterByType(ImporterType type);
+
+// Logs to UMA that an Importer of the specified |type| was used. Uses
+// |metric_postfix| to split by entry point. Note: Values passed via
+// |metric_postfix| require a matching "Import.ImporterType.|metric_postfix|"
+// entry in tools/metrics/histograms/histograms.xml.
+void LogImporterUseToMetrics(const std::string& metric_prefix,
+                             ImporterType type);
+
+}  // namespace importer
+
+#endif  // CHROME_BROWSER_IMPORTER_IMPORTER_CREATOR_H_
diff --git a/chrome/browser/importer/importer_data_types.cc b/chrome/browser/importer/importer_data_types.cc
deleted file mode 100644
index a178fc2..0000000
--- a/chrome/browser/importer/importer_data_types.cc
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/importer/importer_data_types.h"
-
-namespace importer {
-
-SourceProfile::SourceProfile()
-    : importer_type(TYPE_UNKNOWN),
-      services_supported(0) {
-}
-
-SourceProfile::~SourceProfile() {
-}
-
-}  // namespace importer
diff --git a/chrome/browser/importer/importer_data_types.h b/chrome/browser/importer/importer_data_types.h
deleted file mode 100644
index 9b44fb2..0000000
--- a/chrome/browser/importer/importer_data_types.h
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_IMPORTER_IMPORTER_DATA_TYPES_H_
-#define CHROME_BROWSER_IMPORTER_IMPORTER_DATA_TYPES_H_
-
-#include <string>
-
-#include "base/basictypes.h"
-#include "base/files/file_path.h"
-#include "base/memory/ref_counted.h"
-#include "base/strings/string16.h"
-#include "chrome/browser/importer/importer_type.h"
-#include "net/url_request/url_request_context_getter.h"
-
-// Types needed for importing data from other browsers and the Google Toolbar.
-namespace importer {
-
-// An enumeration of the type of data that can be imported.
-enum ImportItem {
-  NONE           = 0,
-  HISTORY        = 1 << 0,
-  FAVORITES      = 1 << 1,
-  COOKIES        = 1 << 2,  // Not supported yet.
-  PASSWORDS      = 1 << 3,
-  SEARCH_ENGINES = 1 << 4,
-  HOME_PAGE      = 1 << 5,
-  ALL            = (1 << 6) - 1  // All the bits should be 1, hence the -1.
-};
-
-// Information about a profile needed by an importer to do import work.
-struct SourceProfile {
-  SourceProfile();
-  ~SourceProfile();
-
-  string16 importer_name;
-  ImporterType importer_type;
-  base::FilePath source_path;
-  base::FilePath app_path;
-  uint16 services_supported;  // Bitmask of ImportItem.
-  // The URLRequestContextGetter is only used for Google Toolbar.
-  scoped_refptr<net::URLRequestContextGetter> request_context_getter;
-};
-
-}  // namespace importer
-
-#endif  // CHROME_BROWSER_IMPORTER_IMPORTER_DATA_TYPES_H_
diff --git a/chrome/browser/importer/importer_host.cc b/chrome/browser/importer/importer_host.cc
deleted file mode 100644
index b22f7bc..0000000
--- a/chrome/browser/importer/importer_host.cc
+++ /dev/null
@@ -1,282 +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/importer/importer_host.h"
-
-#include "base/bind.h"
-#include "base/message_loop.h"
-#include "base/metrics/histogram.h"
-#include "base/prefs/pref_service.h"
-#include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/bookmarks/bookmark_model.h"
-#include "chrome/browser/bookmarks/bookmark_model_factory.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/importer/firefox_profile_lock.h"
-#include "chrome/browser/importer/importer.h"
-#include "chrome/browser/importer/importer_lock_dialog.h"
-#include "chrome/browser/importer/importer_progress_observer.h"
-#include "chrome/browser/importer/importer_type.h"
-#include "chrome/browser/importer/in_process_importer_bridge.h"
-#include "chrome/browser/importer/toolbar_importer_utils.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/search_engines/template_url.h"
-#include "chrome/browser/search_engines/template_url_service.h"
-#include "chrome/browser/search_engines/template_url_service_factory.h"
-#include "chrome/browser/ui/browser_list.h"
-#include "chrome/browser/ui/browser_tabstrip.h"
-#include "chrome/browser/ui/simple_message_box.h"
-#include "chrome/common/chrome_notification_types.h"
-#include "chrome/common/pref_names.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/notification_source.h"
-#include "grit/chromium_strings.h"
-#include "grit/generated_resources.h"
-#include "ui/base/l10n/l10n_util.h"
-
-using content::BrowserThread;
-
-ImporterHost::ImporterHost()
-    : weak_ptr_factory_(this),
-      profile_(NULL),
-      waiting_for_bookmarkbar_model_(false),
-      installed_bookmark_observer_(false),
-      is_source_readable_(true),
-      headless_(false),
-      parent_window_(NULL),
-      browser_(NULL),
-      observer_(NULL) {
-  BrowserList::AddObserver(this);
-}
-
-void ImporterHost::ShowWarningDialog() {
-  DCHECK(!headless_);
-  importer::ShowImportLockDialog(
-      parent_window_,
-      base::Bind(&ImporterHost::OnImportLockDialogEnd,
-                 weak_ptr_factory_.GetWeakPtr()));
-}
-
-void ImporterHost::OnImportLockDialogEnd(bool is_continue) {
-  if (is_continue) {
-    // User chose to continue, then we check the lock again to make
-    // sure that Firefox has been closed. Try to import the settings
-    // if successful. Otherwise, show a warning dialog.
-    firefox_lock_->Lock();
-    if (firefox_lock_->HasAcquired()) {
-      is_source_readable_ = true;
-      InvokeTaskIfDone();
-    } else {
-      ShowWarningDialog();
-    }
-  } else {
-    // User chose to skip the import process. We should reset the |task_| and
-    // notify the ImporterHost to finish.
-    task_.Reset();
-    importer_ = NULL;
-    NotifyImportEnded();
-  }
-}
-
-void ImporterHost::SetObserver(importer::ImporterProgressObserver* observer) {
-  observer_ = observer;
-}
-
-void ImporterHost::NotifyImportStarted() {
-  if (observer_)
-    observer_->ImportStarted();
-}
-
-void ImporterHost::NotifyImportItemStarted(importer::ImportItem item) {
-  if (observer_)
-    observer_->ImportItemStarted(item);
-}
-
-void ImporterHost::NotifyImportItemEnded(importer::ImportItem item) {
-  if (observer_)
-    observer_->ImportItemEnded(item);
-}
-
-void ImporterHost::NotifyImportEnded() {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  firefox_lock_.reset();  // Release the Firefox profile lock.
-  if (observer_)
-    observer_->ImportEnded();
-  delete this;
-}
-
-void ImporterHost::StartImportSettings(
-    const importer::SourceProfile& source_profile,
-    Profile* target_profile,
-    uint16 items,
-    ProfileWriter* writer) {
-  // We really only support importing from one host at a time.
-  DCHECK(!profile_);
-  DCHECK(target_profile);
-
-  profile_ = target_profile;
-  PrefService* user_prefs = profile_->GetPrefs();
-
-  // Make sure only items that were not disabled by policy are imported.
-  if (!user_prefs->GetBoolean(prefs::kImportHistory))
-    items &= ~importer::HISTORY;
-  if (!user_prefs->GetBoolean(prefs::kImportSearchEngine))
-    items &= ~importer::SEARCH_ENGINES;
-  if (!user_prefs->GetBoolean(prefs::kImportBookmarks))
-    items &= ~importer::FAVORITES;
-  if (!user_prefs->GetBoolean(prefs::kImportSavedPasswords))
-    items &= ~importer::PASSWORDS;
-
-  // Preserves the observer and creates a task, since we do async import so that
-  // it doesn't block the UI. When the import is complete, observer will be
-  // notified.
-  writer_ = writer;
-  importer_ = importer::CreateImporterByType(source_profile.importer_type);
-  // If we fail to create the Importer, exit, as we cannot do anything.
-  if (!importer_.get()) {
-    NotifyImportEnded();
-    return;
-  }
-
-  scoped_refptr<InProcessImporterBridge> bridge(
-      new InProcessImporterBridge(writer_.get(),
-                                  weak_ptr_factory_.GetWeakPtr()));
-  task_ = base::Bind(
-      &Importer::StartImport, importer_, source_profile, items, bridge);
-
-  if (!CheckForFirefoxLock(source_profile)) {
-    NotifyImportEnded();
-    return;
-  }
-
-#if defined(OS_WIN)
-  // For google toolbar import, we need the user to log in and store their GAIA
-  // credentials.
-  if (source_profile.importer_type == importer::TYPE_GOOGLE_TOOLBAR5) {
-    toolbar_importer_utils::IsGoogleGAIACookieInstalled(
-        base::Bind(&ImporterHost::OnGoogleGAIACookieChecked,
-                   weak_ptr_factory_.GetWeakPtr()),
-        profile_);
-    is_source_readable_ = false;
-  }
-#endif
-
-  CheckForLoadedModels(items);
-  InvokeTaskIfDone();
-}
-
-void ImporterHost::OnGoogleGAIACookieChecked(bool result) {
-#if defined(OS_WIN)
-  if (!result) {
-    chrome::ShowMessageBox(
-        NULL,
-        l10n_util::GetStringUTF16(IDS_PRODUCT_NAME),
-        l10n_util::GetStringUTF16(IDS_IMPORTER_GOOGLE_LOGIN_TEXT),
-        chrome::MESSAGE_BOX_TYPE_INFORMATION);
-
-    GURL url("https://accounts.google.com/ServiceLogin");
-    if (browser_)
-      chrome::AddSelectedTabWithURL(browser_, url,
-                                    content::PAGE_TRANSITION_TYPED);
-
-    base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
-        &ImporterHost::OnImportLockDialogEnd,
-        weak_ptr_factory_.GetWeakPtr(), false));
-  } else {
-    is_source_readable_ = true;
-    InvokeTaskIfDone();
-  }
-#endif
-}
-
-ImporterHost::~ImporterHost() {
-  BrowserList::RemoveObserver(this);
-
-  if (installed_bookmark_observer_) {
-    DCHECK(profile_);
-    BookmarkModelFactory::GetForProfile(profile_)->RemoveObserver(this);
-  }
-}
-
-bool ImporterHost::CheckForFirefoxLock(
-    const importer::SourceProfile& source_profile) {
-  if (source_profile.importer_type != importer::TYPE_FIREFOX3)
-    return true;
-
-  DCHECK(!firefox_lock_.get());
-  firefox_lock_.reset(new FirefoxProfileLock(source_profile.source_path));
-  if (firefox_lock_->HasAcquired())
-    return true;
-
-  // If fail to acquire the lock, we set the source unreadable and
-  // show a warning dialog, unless running without UI (in which case the import
-  // must be aborted).
-  is_source_readable_ = false;
-  if (headless_)
-    return false;
-
-  ShowWarningDialog();
-  return true;
-}
-
-void ImporterHost::CheckForLoadedModels(uint16 items) {
-  // A target profile must be loaded by StartImportSettings().
-  DCHECK(profile_);
-
-  // BookmarkModel should be loaded before adding IE favorites. So we observe
-  // the BookmarkModel if needed, and start the task after it has been loaded.
-  if ((items & importer::FAVORITES) && !writer_->BookmarkModelIsLoaded()) {
-    BookmarkModelFactory::GetForProfile(profile_)->AddObserver(this);
-    waiting_for_bookmarkbar_model_ = true;
-    installed_bookmark_observer_ = true;
-  }
-
-  // Observes the TemplateURLService if needed to import search engines from the
-  // other browser. We also check to see if we're importing bookmarks because
-  // we can import bookmark keywords from Firefox as search engines.
-  if ((items & importer::SEARCH_ENGINES) || (items & importer::FAVORITES)) {
-    if (!writer_->TemplateURLServiceIsLoaded()) {
-      TemplateURLService* model =
-          TemplateURLServiceFactory::GetForProfile(profile_);
-      registrar_.Add(this, chrome::NOTIFICATION_TEMPLATE_URL_SERVICE_LOADED,
-                     content::Source<TemplateURLService>(model));
-      model->Load();
-    }
-  }
-}
-
-void ImporterHost::InvokeTaskIfDone() {
-  if (waiting_for_bookmarkbar_model_ || !registrar_.IsEmpty() ||
-      !is_source_readable_)
-    return;
-  BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, task_);
-}
-
-void ImporterHost::Loaded(BookmarkModel* model, bool ids_reassigned) {
-  DCHECK(model->loaded());
-  model->RemoveObserver(this);
-  waiting_for_bookmarkbar_model_ = false;
-  installed_bookmark_observer_ = false;
-
-  InvokeTaskIfDone();
-}
-
-void ImporterHost::BookmarkModelBeingDeleted(BookmarkModel* model) {
-  installed_bookmark_observer_ = false;
-}
-
-void ImporterHost::BookmarkModelChanged() {
-}
-
-void ImporterHost::Observe(int type,
-                           const content::NotificationSource& source,
-                           const content::NotificationDetails& details) {
-  DCHECK(type == chrome::NOTIFICATION_TEMPLATE_URL_SERVICE_LOADED);
-  registrar_.RemoveAll();
-  InvokeTaskIfDone();
-}
-
-void ImporterHost::OnBrowserRemoved(Browser* browser) {
-  if (browser_ == browser)
-    browser_ = NULL;
-}
diff --git a/chrome/browser/importer/importer_host.h b/chrome/browser/importer/importer_host.h
deleted file mode 100644
index ecfe9e6..0000000
--- a/chrome/browser/importer/importer_host.h
+++ /dev/null
@@ -1,171 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_IMPORTER_IMPORTER_HOST_H_
-#define CHROME_BROWSER_IMPORTER_IMPORTER_HOST_H_
-
-#include "base/basictypes.h"
-#include "base/callback.h"
-#include "base/compiler_specific.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/memory/weak_ptr.h"
-#include "chrome/browser/bookmarks/base_bookmark_model_observer.h"
-#include "chrome/browser/importer/importer_data_types.h"
-#include "chrome/browser/importer/profile_writer.h"
-#include "chrome/browser/ui/browser_list_observer.h"
-#include "content/public/browser/notification_observer.h"
-#include "content/public/browser/notification_registrar.h"
-#include "ui/gfx/native_widget_types.h"
-
-class FirefoxProfileLock;
-class Importer;
-class Profile;
-
-namespace importer {
-class ImporterProgressObserver;
-}
-
-// This class hosts the importers. It enumerates profiles from other
-// browsers dynamically, and controls the process of importing. When
-// the import process is done, ImporterHost deletes itself.
-class ImporterHost : public BaseBookmarkModelObserver,
-                     public content::NotificationObserver,
-                     public chrome::BrowserListObserver {
- public:
-  ImporterHost();
-
-  void SetObserver(importer::ImporterProgressObserver* observer);
-
-  // A series of functions invoked at the start, during and end of the import
-  // process. The middle functions are notifications that the a harvesting of a
-  // particular source of data (specified by |item|) is under way.
-  void NotifyImportStarted();
-  void NotifyImportItemStarted(importer::ImportItem item);
-  void NotifyImportItemEnded(importer::ImportItem item);
-  void NotifyImportEnded();
-
-  // When in headless mode, the importer will not show any warning dialog if
-  // a user action is required (e.g., Firefox profile is locked and user should
-  // close Firefox to continue) and the outcome is as if the user had canceled
-  // the import operation.
-  void set_headless() { headless_ = true; }
-  bool is_headless() const { return headless_; }
-
-  void set_parent_window(gfx::NativeWindow parent_window) {
-    parent_window_ = parent_window;
-  }
-
-  void set_browser(Browser* browser) { browser_ = browser; }
-
-  // Starts the process of importing the settings and data depending on what the
-  // user selected.
-  // |source_profile| - importer profile to import.
-  // |target_profile| - profile to import into.
-  // |items| - specifies which data to import (bitmask of importer::ImportItem).
-  // |writer| - called to actually write data back to the profile.
-  virtual void StartImportSettings(
-      const importer::SourceProfile& source_profile,
-      Profile* target_profile,
-      uint16 items,
-      ProfileWriter* writer);
-
- protected:
-  virtual ~ImporterHost();
-
-  // ShowWarningDialog() asks user to close the application that is owning the
-  // lock. They can retry or skip the importing process.
-  // This method should not be called if the importer is in headless mode.
-  void ShowWarningDialog();
-
-  // This is called when when user ends the lock dialog by clicking on either
-  // the "Skip" or "Continue" buttons. |is_continue| is true when user clicked
-  // the "Continue" button.
-  void OnImportLockDialogEnd(bool is_continue);
-
-  // Make sure that Firefox isn't running, if import browser is Firefox. Show
-  // to the user a dialog that notifies that is necessary to close Firefox
-  // prior to continue.
-  // |source_profile| - importer profile to import.
-  // Returns false iff import should be aborted.
-  bool CheckForFirefoxLock(const importer::SourceProfile& source_profile);
-
-  // Make sure BookmarkModel and TemplateURLService are loaded before import
-  // process starts, if bookmarks and/or search engines are among the items
-  // which are to be imported.
-  void CheckForLoadedModels(uint16 items);
-
-  // Vends weak pointers for the importer to call us back.
-  base::WeakPtrFactory<ImporterHost> weak_ptr_factory_;
-
-  // Profile we're importing from.
-  Profile* profile_;
-
-  // True if we're waiting for the model to finish loading.
-  bool waiting_for_bookmarkbar_model_;
-
-  // Have we installed a listener on the bookmark model?
-  bool installed_bookmark_observer_;
-
-  // True if source profile is readable.
-  bool is_source_readable_;
-
-  // Receives notification when the TemplateURLService has loaded.
-  content::NotificationRegistrar registrar_;
-
-  // Writes data from the importer back to the profile.
-  scoped_refptr<ProfileWriter> writer_;
-
- private:
-  friend class base::RefCountedThreadSafe<ImporterHost>;
-
-  // Launches the thread that starts the import task, unless bookmark or
-  // template model are not yet loaded. If load is not detected, this method
-  // will be called when the loading observer sees that model loading is
-  // complete.
-  virtual void InvokeTaskIfDone();
-
-  // Called when IsGoogleGAIACookieInstalled is done.
-  void OnGoogleGAIACookieChecked(bool result);
-
-  // BaseBookmarkModelObserver:
-  virtual void Loaded(BookmarkModel* model, bool ids_reassigned) OVERRIDE;
-  virtual void BookmarkModelBeingDeleted(BookmarkModel* model) OVERRIDE;
-  virtual void BookmarkModelChanged() OVERRIDE;
-
-  // content::NotificationObserver:
-  // Called when TemplateURLService has been loaded.
-  virtual void Observe(int type,
-                       const content::NotificationSource& source,
-                       const content::NotificationDetails& details) OVERRIDE;
-
-  // chrome::BrowserListObserver
-  virtual void OnBrowserRemoved(Browser* browser) OVERRIDE;
-
-  // The task is the process of importing settings from other browsers.
-  base::Closure task_;
-
-  // The importer used in the task.
-  scoped_refptr<Importer> importer_;
-
-  // True if UI is not to be shown.
-  bool headless_;
-
-  // Parent window that we pass to the import lock dialog (i.e, the Firefox
-  // warning dialog).
-  gfx::NativeWindow parent_window_;
-
-  // Used to add a new tab if we need the user to sign in.
-  Browser* browser_;
-
-  // The observer that we need to notify about changes in the import process.
-  importer::ImporterProgressObserver* observer_;
-
-  // Firefox profile lock.
-  scoped_ptr<FirefoxProfileLock> firefox_lock_;
-
-  DISALLOW_COPY_AND_ASSIGN(ImporterHost);
-};
-
-#endif  // CHROME_BROWSER_IMPORTER_IMPORTER_HOST_H_
diff --git a/chrome/browser/importer/importer_list.cc b/chrome/browser/importer/importer_list.cc
index 04fddc9..7c9df71 100644
--- a/chrome/browser/importer/importer_list.cc
+++ b/chrome/browser/importer/importer_list.cc
@@ -5,12 +5,11 @@
 #include "chrome/browser/importer/importer_list.h"
 
 #include "base/bind.h"
-#include "chrome/browser/first_run/first_run.h"
 #include "chrome/browser/importer/firefox_importer_utils.h"
 #include "chrome/browser/importer/importer_bridge.h"
-#include "chrome/browser/importer/importer_data_types.h"
 #include "chrome/browser/importer/importer_list_observer.h"
 #include "chrome/browser/shell_integration.h"
+#include "chrome/common/importer/importer_data_types.h"
 #include "grit/generated_resources.h"
 #include "ui/base/l10n/l10n_util.h"
 
@@ -55,7 +54,11 @@
 }
 #endif  // defined(OS_MACOSX)
 
-void DetectFirefoxProfiles(std::vector<importer::SourceProfile*>* profiles) {
+// |locale|: The application locale used for lookups in Firefox's
+// locale-specific search engines feature (see firefox3_importer.cc for
+// details).
+void DetectFirefoxProfiles(const std::string locale,
+                           std::vector<importer::SourceProfile*>* profiles) {
   base::FilePath profile_path = GetFirefoxProfilePath();
   if (profile_path.empty())
     return;
@@ -88,40 +91,21 @@
     firefox->app_path = app_path;
   firefox->services_supported = importer::HISTORY | importer::FAVORITES |
       importer::PASSWORDS | importer::SEARCH_ENGINES;
+  firefox->locale = locale;
   profiles->push_back(firefox);
 }
 
-#if defined(OS_WIN)
-void DetectGoogleToolbarProfiles(
-    std::vector<importer::SourceProfile*>* profiles,
-    scoped_refptr<net::URLRequestContextGetter> request_context_getter) {
-  if (first_run::IsChromeFirstRun())
-    return;
-
-  importer::SourceProfile* google_toolbar = new importer::SourceProfile;
-  google_toolbar->importer_name =
-      l10n_util::GetStringUTF16(IDS_IMPORT_FROM_GOOGLE_TOOLBAR);
-  google_toolbar->importer_type = importer::TYPE_GOOGLE_TOOLBAR5;
-  google_toolbar->source_path.clear();
-  google_toolbar->app_path.clear();
-  google_toolbar->services_supported = importer::FAVORITES;
-  google_toolbar->request_context_getter = request_context_getter;
-  profiles->push_back(google_toolbar);
-}
-#endif
-
 }  // namespace
 
-ImporterList::ImporterList(
-    net::URLRequestContextGetter* request_context_getter)
+ImporterList::ImporterList()
     : source_thread_id_(BrowserThread::UI),
       observer_(NULL),
       is_observed_(false),
       source_profiles_loaded_(false) {
- request_context_getter_ = make_scoped_refptr(request_context_getter);
 }
 
 void ImporterList::DetectSourceProfiles(
+    const std::string& locale,
     importer::ImporterListObserver* observer) {
   DCHECK(observer);
   observer_ = observer;
@@ -133,15 +117,11 @@
   BrowserThread::PostTask(
       BrowserThread::FILE,
       FROM_HERE,
-      base::Bind(&ImporterList::DetectSourceProfilesWorker, this));
+      base::Bind(&ImporterList::DetectSourceProfilesWorker, this, locale));
 }
 
-void ImporterList::SetObserver(importer::ImporterListObserver* observer) {
-  observer_ = observer;
-}
-
-void ImporterList::DetectSourceProfilesHack() {
-  DetectSourceProfilesWorker();
+void ImporterList::DetectSourceProfilesHack(const std::string& locale) {
+  DetectSourceProfilesWorker(locale);
 }
 
 const importer::SourceProfile& ImporterList::GetSourceProfileAt(
@@ -166,7 +146,7 @@
 ImporterList::~ImporterList() {
 }
 
-void ImporterList::DetectSourceProfilesWorker() {
+void ImporterList::DetectSourceProfilesWorker(const std::string& locale) {
   // TODO(jhawkins): Remove this condition once DetectSourceProfilesHack is
   // removed.
   if (is_observed_)
@@ -178,24 +158,22 @@
   // profile detected, which should be the user's current default.
 #if defined(OS_WIN)
   if (ShellIntegration::IsFirefoxDefaultBrowser()) {
-    DetectFirefoxProfiles(&profiles);
+    DetectFirefoxProfiles(locale, &profiles);
     DetectIEProfiles(&profiles);
   } else {
     DetectIEProfiles(&profiles);
-    DetectFirefoxProfiles(&profiles);
+    DetectFirefoxProfiles(locale, &profiles);
   }
-  // TODO(brg) : Current UI requires win_util.
-  DetectGoogleToolbarProfiles(&profiles, request_context_getter_);
 #elif defined(OS_MACOSX)
   if (ShellIntegration::IsFirefoxDefaultBrowser()) {
-    DetectFirefoxProfiles(&profiles);
+    DetectFirefoxProfiles(locale, &profiles);
     DetectSafariProfiles(&profiles);
   } else {
     DetectSafariProfiles(&profiles);
-    DetectFirefoxProfiles(&profiles);
+    DetectFirefoxProfiles(locale, &profiles);
   }
 #else
-  DetectFirefoxProfiles(&profiles);
+  DetectFirefoxProfiles(locale, &profiles);
 #endif
 
   // TODO(jhawkins): Remove this condition once DetectSourceProfilesHack is
diff --git a/chrome/browser/importer/importer_list.h b/chrome/browser/importer/importer_list.h
index b31e82d..9a18a82 100644
--- a/chrome/browser/importer/importer_list.h
+++ b/chrome/browser/importer/importer_list.h
@@ -5,6 +5,7 @@
 #ifndef CHROME_BROWSER_IMPORTER_IMPORTER_LIST_H_
 #define CHROME_BROWSER_IMPORTER_IMPORTER_LIST_H_
 
+#include <string>
 #include <vector>
 
 #include "base/basictypes.h"
@@ -12,7 +13,6 @@
 #include "base/memory/scoped_vector.h"
 #include "base/strings/string16.h"
 #include "content/public/browser/browser_thread.h"
-#include "net/url_request/url_request_context_getter.h"
 
 namespace importer {
 class ImporterListObserver;
@@ -21,22 +21,27 @@
 
 class ImporterList : public base::RefCountedThreadSafe<ImporterList> {
  public:
-  explicit ImporterList(net::URLRequestContextGetter* request_context_getter);
+  ImporterList();
 
   // Detects the installed browsers and their associated profiles, then stores
   // their information in a list. It returns the list of description of all
   // profiles. Calls into DetectSourceProfilesWorker() on the FILE thread to do
   // the real work of detecting source profiles. |observer| must be non-NULL.
-  void DetectSourceProfiles(importer::ImporterListObserver* observer);
+  // |locale|: As in DetectSourceProfilesWorker().
+  void DetectSourceProfiles(const std::string& locale,
+                            importer::ImporterListObserver* observer);
 
   // Sets the observer of this object. When the current observer is destroyed,
   // this method should be called with a NULL |observer| so it is not notified
   // after destruction.
-  void SetObserver(importer::ImporterListObserver* observer);
+  void set_observer(importer::ImporterListObserver* observer) {
+    observer_ = observer;
+  }
 
   // DEPRECATED: This method is synchronous and performs file operations which
   // may end up blocking the current thread, which is usually the UI thread.
-  void DetectSourceProfilesHack();
+  // |locale|: As in DetectSourceProfilesWorker().
+  void DetectSourceProfilesHack(const std::string& locale);
 
   // Returns the number of different source profiles you can import from.
   size_t count() const { return source_profiles_.size(); }
@@ -59,8 +64,10 @@
   ~ImporterList();
 
   // The worker method for DetectSourceProfiles(). Must be called on the FILE
-  // thread.
-  void DetectSourceProfilesWorker();
+  // thread. |locale|:The application locale (it must be taken as an argument
+  // since this code runs on the FILE thread where GetApplicationLocale() isn't
+  // available).
+  void DetectSourceProfilesWorker(const std::string& locale);
 
   // Called by DetectSourceProfilesWorker() on the source thread. This method
   // notifies |observer_| that the source profiles are loaded. |profiles| is
@@ -71,9 +78,6 @@
   // The list of profiles with the default one first.
   ScopedVector<importer::SourceProfile> source_profiles_;
 
-  // Needed for Google Toolbar Import to connect to Toolbar server.
-  scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
-
   // The ID of the thread DetectSourceProfiles() is called on. Only valid after
   // DetectSourceProfiles() is called and until SourceProfilesLoaded() has
   // returned.
diff --git a/chrome/browser/importer/importer_progress_observer.h b/chrome/browser/importer/importer_progress_observer.h
index 92bca81..b033af8 100644
--- a/chrome/browser/importer/importer_progress_observer.h
+++ b/chrome/browser/importer/importer_progress_observer.h
@@ -5,7 +5,7 @@
 #ifndef CHROME_BROWSER_IMPORTER_IMPORTER_PROGRESS_OBSERVER_H_
 #define CHROME_BROWSER_IMPORTER_IMPORTER_PROGRESS_OBSERVER_H_
 
-#include "chrome/browser/importer/importer_data_types.h"
+#include "chrome/common/importer/importer_data_types.h"
 
 namespace importer {
 
diff --git a/chrome/browser/importer/importer_type.cc b/chrome/browser/importer/importer_type.cc
deleted file mode 100644
index 59e5123..0000000
--- a/chrome/browser/importer/importer_type.cc
+++ /dev/null
@@ -1,113 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/importer/importer_type.h"
-
-#include "base/logging.h"
-#include "base/metrics/histogram.h"
-#include "chrome/browser/importer/bookmarks_file_importer.h"
-#include "chrome/browser/importer/firefox3_importer.h"
-#include "chrome/browser/importer/toolbar_importer.h"
-
-#if defined(OS_WIN)
-#include "chrome/browser/importer/ie_importer.h"
-#endif
-
-#if defined(OS_MACOSX)
-#include <CoreFoundation/CoreFoundation.h>
-#include "base/mac/foundation_util.h"
-#include "chrome/browser/importer/safari_importer.h"
-#endif
-
-namespace importer {
-
-namespace {
-
-// The enum used to register importer use.
-enum ImporterTypeMetrics {
-  IMPORTER_METRICS_UNKNOWN         = 0,
-#if defined(OS_WIN)
-  IMPORTER_METRICS_IE              = 1,
-#endif
-  IMPORTER_METRICS_FIREFOX2        = 2,  // obsolete
-  IMPORTER_METRICS_FIREFOX3        = 3,
-#if defined(OS_MACOSX)
-  IMPORTER_METRICS_SAFARI          = 4,
-#endif
-  IMPORTER_METRICS_GOOGLE_TOOLBAR5 = 5,
-  IMPORTER_METRICS_BOOKMARKS_FILE  = 6,
-
-  // Insert new values here. Never remove any existing values, as this enum is
-  // used to bucket a UMA histogram, and removing values breaks that.
-  IMPORTER_METRICS_SIZE
-};
-
-
-}  // namespace
-
-Importer* CreateImporterByType(ImporterType type) {
-  switch (type) {
-#if defined(OS_WIN)
-    case TYPE_IE:
-      return new IEImporter();
-#endif
-    case TYPE_BOOKMARKS_FILE:
-      return new BookmarksFileImporter();
-    case TYPE_FIREFOX3:
-      return new Firefox3Importer();
-#if defined(OS_MACOSX)
-    case TYPE_SAFARI:
-      return new SafariImporter(base::mac::GetUserLibraryPath());
-#endif
-    case TYPE_GOOGLE_TOOLBAR5:
-      return new Toolbar5Importer();
-    default:
-      NOTREACHED();
-      return NULL;
-  }
-  NOTREACHED();
-  return NULL;
-}
-
-void LogImporterUseToMetrics(const std::string& metric_postfix,
-                             ImporterType type) {
-  ImporterTypeMetrics metrics_type = IMPORTER_METRICS_UNKNOWN;
-  switch (type) {
-    case TYPE_UNKNOWN:
-      metrics_type = IMPORTER_METRICS_UNKNOWN;
-      break;
-#if defined(OS_WIN)
-    case TYPE_IE:
-      metrics_type = IMPORTER_METRICS_IE;
-      break;
-#endif
-    case TYPE_FIREFOX3:
-      metrics_type = IMPORTER_METRICS_FIREFOX3;
-      break;
-#if defined(OS_MACOSX)
-    case TYPE_SAFARI:
-      metrics_type = IMPORTER_METRICS_SAFARI;
-      break;
-#endif
-    case TYPE_GOOGLE_TOOLBAR5:
-      metrics_type = IMPORTER_METRICS_GOOGLE_TOOLBAR5;
-      break;
-    case TYPE_BOOKMARKS_FILE:
-      metrics_type = IMPORTER_METRICS_BOOKMARKS_FILE;
-      break;
-  }
-
-  // Note: This leaks memory, which is the expected behavior as the factory
-  // creates and owns the histogram.
-  base::HistogramBase* histogram =
-      base::LinearHistogram::FactoryGet(
-          "Import.ImporterType." + metric_postfix,
-          1,
-          IMPORTER_METRICS_SIZE,
-          IMPORTER_METRICS_SIZE + 1,
-          base::HistogramBase::kUmaTargetedHistogramFlag);
-  histogram->Add(metrics_type);
-}
-
-}  // namespace importer
diff --git a/chrome/browser/importer/importer_type.h b/chrome/browser/importer/importer_type.h
deleted file mode 100644
index 6705dd8..0000000
--- a/chrome/browser/importer/importer_type.h
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_IMPORTER_IMPORTER_TYPE_H_
-#define CHROME_BROWSER_IMPORTER_IMPORTER_TYPE_H_
-
-#include <string>
-
-#include "build/build_config.h"
-
-class Importer;
-
-namespace importer {
-
-// An enumeration of the type of importers that we support to import
-// settings and data from (browsers, google toolbar and a bookmarks html file).
-// NOTE: Numbers added so that data can be reliably cast to ints and passed
-// across IPC.
-enum ImporterType {
-  TYPE_UNKNOWN         = -1,
-#if defined(OS_WIN)
-  TYPE_IE              = 0,
-#endif
-  // Value 1 was the (now deleted) Firefox 2 profile importer.
-  TYPE_FIREFOX3        = 2,
-#if defined(OS_MACOSX)
-  TYPE_SAFARI          = 3,
-#endif
-  TYPE_GOOGLE_TOOLBAR5 = 4,
-  // Identifies a 'bookmarks.html' file.
-  TYPE_BOOKMARKS_FILE  = 5
-};
-
-// Creates an Importer of the specified |type|.
-Importer* CreateImporterByType(ImporterType type);
-
-// Logs to UMA that an Importer of the specified |type| was used. Uses
-// |metric_postfix| to split by entry point. Note: Values passed via
-// |metric_postfix| require a matching "Import.ImporterType.|metric_postfix|"
-// entry in tools/metrics/histograms/histograms.xml.
-void LogImporterUseToMetrics(const std::string& metric_prefix,
-                             ImporterType type);
-
-}  // namespace importer
-
-#endif  // CHROME_BROWSER_IMPORTER_IMPORTER_TYPE_H_
diff --git a/chrome/browser/importer/importer_unittest_utils.cc b/chrome/browser/importer/importer_unittest_utils.cc
index c96cf81..d0ff6eb 100644
--- a/chrome/browser/importer/importer_unittest_utils.cc
+++ b/chrome/browser/importer/importer_unittest_utils.cc
@@ -5,7 +5,7 @@
 #include "chrome/browser/importer/importer_unittest_utils.h"
 
 #include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/bookmarks/imported_bookmark_entry.h"
+#include "chrome/common/importer/imported_bookmark_entry.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 void TestEqualBookmarkEntry(const ImportedBookmarkEntry& entry,
diff --git a/chrome/browser/importer/in_process_importer_bridge.cc b/chrome/browser/importer/in_process_importer_bridge.cc
index 6d1dc1d..14c1593 100644
--- a/chrome/browser/importer/in_process_importer_bridge.cc
+++ b/chrome/browser/importer/in_process_importer_bridge.cc
@@ -5,11 +5,15 @@
 #include "chrome/browser/importer/in_process_importer_bridge.h"
 
 #include "base/bind.h"
+#include "base/file_util.h"
 #include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/bookmarks/imported_bookmark_entry.h"
-#include "chrome/browser/favicon/imported_favicon_usage.h"
-#include "chrome/browser/importer/importer_host.h"
+#include "chrome/browser/importer/external_process_importer_host.h"
 #include "chrome/browser/search_engines/template_url.h"
+#include "chrome/browser/search_engines/template_url_parser.h"
+#include "chrome/browser/search_engines/template_url_prepopulate_data.h"
+#include "chrome/browser/search_engines/template_url_service.h"
+#include "chrome/common/importer/imported_bookmark_entry.h"
+#include "chrome/common/importer/imported_favicon_usage.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/common/password_form.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -20,12 +24,128 @@
 
 #include <iterator>
 
+namespace {
+
+history::URLRows ConvertImporterURLRowsToHistoryURLRows(
+    const std::vector<ImporterURLRow>& rows) {
+  history::URLRows converted;
+  converted.reserve(rows.size());
+  for (std::vector<ImporterURLRow>::const_iterator it = rows.begin();
+       it != rows.end(); ++it) {
+    history::URLRow row(it->url);
+    row.set_title(it->title);
+    row.set_visit_count(it->visit_count);
+    row.set_typed_count(it->typed_count);
+    row.set_last_visit(it->last_visit);
+    row.set_hidden(it->hidden);
+    converted.push_back(row);
+  }
+  return converted;
+}
+
+}  // namespace
+
 using content::BrowserThread;
 
+namespace {
+
+// FirefoxURLParameterFilter is used to remove parameter mentioning Firefox from
+// the search URL when importing search engines.
+class FirefoxURLParameterFilter : public TemplateURLParser::ParameterFilter {
+ public:
+  FirefoxURLParameterFilter() {}
+  virtual ~FirefoxURLParameterFilter() {}
+
+  // TemplateURLParser::ParameterFilter method.
+  virtual bool KeepParameter(const std::string& key,
+                             const std::string& value) OVERRIDE {
+    std::string low_value = StringToLowerASCII(value);
+    if (low_value.find("mozilla") != std::string::npos ||
+        low_value.find("firefox") != std::string::npos ||
+        low_value.find("moz:") != std::string::npos) {
+      return false;
+    }
+    return true;
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(FirefoxURLParameterFilter);
+};
+
+// Creates a TemplateURL with the |keyword| and |url|. |title| may be empty.
+// This function transfers ownership of the created TemplateURL to the caller.
+TemplateURL* CreateTemplateURL(const string16& title,
+                               const string16& keyword,
+                               const GURL& url) {
+  // Skip if the url is invalid.
+  if (!url.is_valid())
+    return NULL;
+
+  TemplateURLData data;
+  if (keyword.empty())
+    data.SetKeyword(TemplateURLService::GenerateKeyword(url));
+  else
+    data.SetKeyword(keyword);
+  // We set short name by using the title if it exists.
+  // Otherwise, we use the shortcut.
+  data.short_name = title.empty() ? keyword : title;
+  data.SetURL(TemplateURLRef::DisplayURLToURLRef(UTF8ToUTF16(url.spec())));
+  return new TemplateURL(NULL, data);
+}
+
+// Parses the OpenSearch XML files in |xml_files| and populates |search_engines|
+// with the resulting TemplateURLs.
+void ParseSearchEnginesFromFirefoxXMLData(
+    const std::vector<std::string>& xml_data,
+    std::vector<TemplateURL*>* search_engines) {
+  DCHECK(search_engines);
+
+  typedef std::map<std::string, TemplateURL*> SearchEnginesMap;
+  SearchEnginesMap search_engine_for_url;
+  std::string content;
+  FirefoxURLParameterFilter param_filter;
+  // The first XML file represents the default search engine in Firefox 3, so we
+  // need to keep it on top of the list.
+  SearchEnginesMap::const_iterator default_turl = search_engine_for_url.end();
+  for (std::vector<std::string>::const_iterator xml_iter =
+           xml_data.begin(); xml_iter != xml_data.end(); ++xml_iter) {
+    TemplateURL* template_url = TemplateURLParser::Parse(NULL, true,
+        xml_iter->data(), xml_iter->length(), &param_filter);
+    if (template_url) {
+      SearchEnginesMap::iterator iter =
+          search_engine_for_url.find(template_url->url());
+      if (iter == search_engine_for_url.end()) {
+        iter = search_engine_for_url.insert(
+            std::make_pair(template_url->url(), template_url)).first;
+      } else {
+        // We have already found a search engine with the same URL.  We give
+        // priority to the latest one found, as GetSearchEnginesXMLFiles()
+        // returns a vector with first Firefox default search engines and then
+        // the user's ones.  We want to give priority to the user ones.
+        delete iter->second;
+        iter->second = template_url;
+      }
+      if (default_turl == search_engine_for_url.end())
+        default_turl = iter;
+    }
+  }
+
+  // Put the results in the |search_engines| vector.
+  for (SearchEnginesMap::iterator t_iter = search_engine_for_url.begin();
+       t_iter != search_engine_for_url.end(); ++t_iter) {
+    if (t_iter == default_turl)
+      search_engines->insert(search_engines->begin(), default_turl->second);
+    else
+      search_engines->push_back(t_iter->second);
+  }
+}
+
+}  // namespace
+
 InProcessImporterBridge::InProcessImporterBridge(
     ProfileWriter* writer,
-    base::WeakPtr<ImporterHost> host) : writer_(writer),
-                                        host_(host) {
+    base::WeakPtr<ExternalProcessImporterHost> host) : writer_(writer),
+                                                       host_(host) {
 }
 
 void InProcessImporterBridge::AddBookmarks(
@@ -60,24 +180,45 @@
 }
 
 void InProcessImporterBridge::SetHistoryItems(
-    const history::URLRows &rows,
+    const std::vector<ImporterURLRow>& rows,
     history::VisitSource visit_source) {
+  history::URLRows converted = ConvertImporterURLRowsToHistoryURLRows(rows);
   BrowserThread::PostTask(
-      BrowserThread::UI, FROM_HERE,
-      base::Bind(&ProfileWriter::AddHistoryPage, writer_, rows, visit_source));
+      BrowserThread::UI,
+      FROM_HERE,
+      base::Bind(
+          &ProfileWriter::AddHistoryPage, writer_, converted, visit_source));
 }
 
 void InProcessImporterBridge::SetKeywords(
-    const std::vector<TemplateURL*>& template_urls,
+    const std::vector<importer::URLKeywordInfo>& url_keywords,
     bool unique_on_host_and_path) {
   ScopedVector<TemplateURL> owned_template_urls;
-  std::copy(template_urls.begin(), template_urls.end(),
-            std::back_inserter(owned_template_urls));
+  for (size_t i = 0; i < url_keywords.size(); ++i) {
+    owned_template_urls.push_back(
+        CreateTemplateURL(url_keywords[i].display_name,
+                          url_keywords[i].keyword,
+                          url_keywords[i].url));
+  }
   BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
       base::Bind(&ProfileWriter::AddKeywords, writer_,
                  base::Passed(&owned_template_urls), unique_on_host_and_path));
 }
 
+void InProcessImporterBridge::SetFirefoxSearchEnginesXMLData(
+    const std::vector<std::string>& search_engine_data) {
+  std::vector<TemplateURL*> search_engines;
+  ParseSearchEnginesFromFirefoxXMLData(search_engine_data, &search_engines);
+
+  ScopedVector<TemplateURL> owned_template_urls;
+  std::copy(search_engines.begin(), search_engines.end(),
+            std::back_inserter(owned_template_urls));
+
+  BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+      base::Bind(&ProfileWriter::AddKeywords, writer_,
+                 base::Passed(&owned_template_urls), true));
+}
+
 void InProcessImporterBridge::SetPasswordForm(
     const content::PasswordForm& form) {
   BrowserThread::PostTask(
@@ -88,25 +229,27 @@
 void InProcessImporterBridge::NotifyStarted() {
   BrowserThread::PostTask(
       BrowserThread::UI, FROM_HERE,
-      base::Bind(&ImporterHost::NotifyImportStarted, host_));
+      base::Bind(&ExternalProcessImporterHost::NotifyImportStarted, host_));
 }
 
 void InProcessImporterBridge::NotifyItemStarted(importer::ImportItem item) {
   BrowserThread::PostTask(
       BrowserThread::UI, FROM_HERE,
-      base::Bind(&ImporterHost::NotifyImportItemStarted, host_, item));
+      base::Bind(&ExternalProcessImporterHost::NotifyImportItemStarted,
+                 host_, item));
 }
 
 void InProcessImporterBridge::NotifyItemEnded(importer::ImportItem item) {
   BrowserThread::PostTask(
       BrowserThread::UI, FROM_HERE,
-      base::Bind(&ImporterHost::NotifyImportItemEnded, host_, item));
+      base::Bind(&ExternalProcessImporterHost::NotifyImportItemEnded,
+                 host_, item));
 }
 
 void InProcessImporterBridge::NotifyEnded() {
   BrowserThread::PostTask(
       BrowserThread::UI, FROM_HERE,
-      base::Bind(&ImporterHost::NotifyImportEnded, host_));
+      base::Bind(&ExternalProcessImporterHost::NotifyImportEnded, host_));
 }
 
 string16 InProcessImporterBridge::GetLocalizedString(int message_id) {
diff --git a/chrome/browser/importer/in_process_importer_bridge.h b/chrome/browser/importer/in_process_importer_bridge.h
index 2b439c4..89786d4 100644
--- a/chrome/browser/importer/in_process_importer_bridge.h
+++ b/chrome/browser/importer/in_process_importer_bridge.h
@@ -18,12 +18,16 @@
 class GURL;
 struct ImportedBookmarkEntry;
 struct ImportedFaviconUsage;
-class ImporterHost;
+class ExternalProcessImporterHost;
+
+namespace importer {
+struct URLKeywordInfo;
+}
 
 class InProcessImporterBridge : public ImporterBridge {
  public:
   InProcessImporterBridge(ProfileWriter* writer,
-                          base::WeakPtr<ImporterHost> host);
+                          base::WeakPtr<ExternalProcessImporterHost> host);
 
   // Begin ImporterBridge implementation:
   virtual void AddBookmarks(
@@ -40,11 +44,15 @@
   virtual void SetFavicons(
       const std::vector<ImportedFaviconUsage>& favicons) OVERRIDE;
 
-  virtual void SetHistoryItems(const history::URLRows& rows,
+  virtual void SetHistoryItems(const std::vector<ImporterURLRow>& rows,
                                history::VisitSource visit_source) OVERRIDE;
 
-  virtual void SetKeywords(const std::vector<TemplateURL*>& template_urls,
-                           bool unique_on_host_and_path) OVERRIDE;
+  virtual void SetKeywords(
+      const std::vector<importer::URLKeywordInfo>& url_keywords,
+      bool unique_on_host_and_path) OVERRIDE;
+
+  virtual void SetFirefoxSearchEnginesXMLData(
+      const std::vector<std::string>& search_engine_data) OVERRIDE;
 
   virtual void SetPasswordForm(
       const content::PasswordForm& form) OVERRIDE;
@@ -61,7 +69,7 @@
   virtual ~InProcessImporterBridge();
 
   ProfileWriter* const writer_;  // weak
-  const base::WeakPtr<ImporterHost> host_;
+  const base::WeakPtr<ExternalProcessImporterHost> host_;
 
   DISALLOW_COPY_AND_ASSIGN(InProcessImporterBridge);
 };
diff --git a/chrome/browser/importer/profile_import_process_messages.cc b/chrome/browser/importer/profile_import_process_messages.cc
deleted file mode 100644
index 68603e4..0000000
--- a/chrome/browser/importer/profile_import_process_messages.cc
+++ /dev/null
@@ -1,33 +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.
-
-// Get basic type definitions.
-#define IPC_MESSAGE_IMPL
-#include "chrome/browser/importer/profile_import_process_messages.h"
-
-// Generate constructors.
-#include "ipc/struct_constructor_macros.h"
-#include "chrome/browser/importer/profile_import_process_messages.h"
-
-// Generate destructors.
-#include "ipc/struct_destructor_macros.h"
-#include "chrome/browser/importer/profile_import_process_messages.h"
-
-// Generate param traits write methods.
-#include "ipc/param_traits_write_macros.h"
-namespace IPC {
-#include "chrome/browser/importer/profile_import_process_messages.h"
-}  // namespace IPC
-
-// Generate param traits read methods.
-#include "ipc/param_traits_read_macros.h"
-namespace IPC {
-#include "chrome/browser/importer/profile_import_process_messages.h"
-}  // namespace IPC
-
-// Generate param traits log methods.
-#include "ipc/param_traits_log_macros.h"
-namespace IPC {
-#include "chrome/browser/importer/profile_import_process_messages.h"
-}  // namespace IPC
diff --git a/chrome/browser/importer/profile_import_process_messages.h b/chrome/browser/importer/profile_import_process_messages.h
deleted file mode 100644
index ba2d1ab..0000000
--- a/chrome/browser/importer/profile_import_process_messages.h
+++ /dev/null
@@ -1,342 +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.
-
-// Multiply-included message file, no traditonal include guard.
-#include <string>
-#include <vector>
-
-#include "base/basictypes.h"
-#include "base/strings/string16.h"
-#include "base/values.h"
-#include "chrome/browser/bookmarks/imported_bookmark_entry.h"
-#include "chrome/browser/favicon/imported_favicon_usage.h"
-#include "chrome/browser/history/history_types.h"
-#include "chrome/browser/importer/importer_data_types.h"
-#include "chrome/browser/search_engines/template_url.h"
-#include "chrome/common/common_param_traits_macros.h"
-#include "content/public/common/common_param_traits.h"
-#include "content/public/common/password_form.h"
-#include "ipc/ipc_message_macros.h"
-#include "ipc/ipc_message_utils.h"
-
-#ifndef CHROME_BROWSER_IMPORTER_PROFILE_IMPORT_PROCESS_MESSAGES_H_
-#define CHROME_BROWSER_IMPORTER_PROFILE_IMPORT_PROCESS_MESSAGES_H_
-
-namespace IPC {
-
-// Traits for importer::SourceProfile struct to pack/unpack.
-template <>
-struct ParamTraits<importer::SourceProfile> {
-  typedef importer::SourceProfile param_type;
-  static void Write(Message* m, const param_type& p) {
-    WriteParam(m, p.importer_name);
-    WriteParam(m, static_cast<int>(p.importer_type));
-    WriteParam(m, p.source_path);
-    WriteParam(m, p.app_path);
-    WriteParam(m, static_cast<int>(p.services_supported));
-  }
-  static bool Read(const Message* m, PickleIterator* iter, param_type* p) {
-    if (!ReadParam(m, iter, &p->importer_name))
-      return false;
-
-    int importer_type = 0;
-    if (!ReadParam(m, iter, &importer_type))
-      return false;
-    p->importer_type = static_cast<importer::ImporterType>(importer_type);
-
-    if (!ReadParam(m, iter, &p->source_path) ||
-        !ReadParam(m, iter, &p->app_path))
-        return false;
-
-    int services_supported = 0;
-    if (!ReadParam(m, iter, &services_supported))
-      return false;
-    p->services_supported = static_cast<uint16>(services_supported);
-
-    return true;
-  }
-  static void Log(const param_type& p, std::string* l) {
-    l->append("(");
-    LogParam(p.importer_name, l);
-    l->append(", ");
-    LogParam(static_cast<int>(p.importer_type), l);
-    l->append(", ");
-    LogParam(p.source_path, l);
-    l->append(", ");
-    LogParam(p.app_path, l);
-    l->append(", ");
-    LogParam(static_cast<int>(p.services_supported), l);
-    l->append(")");
-  }
-};  // ParamTraits<importer::SourceProfile>
-
-// Traits for history::URLRow to pack/unpack.
-template <>
-struct ParamTraits<history::URLRow> {
-  typedef history::URLRow param_type;
-  static void Write(Message* m, const param_type& p) {
-    WriteParam(m, p.id());
-    WriteParam(m, p.url());
-    WriteParam(m, p.title());
-    WriteParam(m, p.visit_count());
-    WriteParam(m, p.typed_count());
-    WriteParam(m, p.last_visit());
-    WriteParam(m, p.hidden());
-  }
-  static bool Read(const Message* m, PickleIterator* iter, param_type* p) {
-    history::URLID id;
-    GURL url;
-    string16 title;
-    int visit_count, typed_count;
-    base::Time last_visit;
-    bool hidden;
-    if (!ReadParam(m, iter, &id) ||
-        !ReadParam(m, iter, &url) ||
-        !ReadParam(m, iter, &title) ||
-        !ReadParam(m, iter, &visit_count) ||
-        !ReadParam(m, iter, &typed_count) ||
-        !ReadParam(m, iter, &last_visit) ||
-        !ReadParam(m, iter, &hidden))
-      return false;
-    *p = history::URLRow(url, id);
-    p->set_title(title);
-    p->set_visit_count(visit_count);
-    p->set_typed_count(typed_count);
-    p->set_last_visit(last_visit);
-    p->set_hidden(hidden);
-    return true;
-  }
-  static void Log(const param_type& p, std::string* l) {
-    l->append("(");
-    LogParam(p.id(), l);
-    l->append(", ");
-    LogParam(p.url(), l);
-    l->append(", ");
-    LogParam(p.title(), l);
-    l->append(", ");
-    LogParam(p.visit_count(), l);
-    l->append(", ");
-    LogParam(p.typed_count(), l);
-    l->append(", ");
-    LogParam(p.last_visit(), l);
-    l->append(", ");
-    LogParam(p.hidden(), l);
-    l->append(")");
-  }
-};  // ParamTraits<history::URLRow>
-
-// Traits for ImportedBookmarkEntry to pack/unpack.
-template <>
-struct ParamTraits<ImportedBookmarkEntry> {
-  typedef ImportedBookmarkEntry param_type;
-  static void Write(Message* m, const param_type& p) {
-    WriteParam(m, p.in_toolbar);
-    WriteParam(m, p.is_folder);
-    WriteParam(m, p.url);
-    WriteParam(m, p.path);
-    WriteParam(m, p.title);
-    WriteParam(m, p.creation_time);
-  }
-  static bool Read(const Message* m, PickleIterator* iter, param_type* p) {
-    return
-        (ReadParam(m, iter, &p->in_toolbar)) &&
-        (ReadParam(m, iter, &p->is_folder)) &&
-        (ReadParam(m, iter, &p->url)) &&
-        (ReadParam(m, iter, &p->path)) &&
-        (ReadParam(m, iter, &p->title)) &&
-        (ReadParam(m, iter, &p->creation_time));
-  }
-  static void Log(const param_type& p, std::string* l) {
-    l->append("(");
-    LogParam(p.in_toolbar, l);
-    l->append(", ");
-    LogParam(p.is_folder, l);
-    l->append(", ");
-    LogParam(p.url, l);
-    l->append(", ");
-    LogParam(p.path, l);
-    l->append(", ");
-    LogParam(p.title, l);
-    l->append(", ");
-    LogParam(p.creation_time, l);
-    l->append(")");
-  }
-};  // ParamTraits<ImportedBookmarkEntry>
-
-// Traits for ImportedFaviconUsage.
-template <>
-struct ParamTraits<ImportedFaviconUsage> {
-  typedef ImportedFaviconUsage param_type;
-  static void Write(Message* m, const param_type& p) {
-    WriteParam(m, p.favicon_url);
-    WriteParam(m, p.png_data);
-    WriteParam(m, p.urls);
-  }
-  static bool Read(const Message* m, PickleIterator* iter, param_type* p) {
-    return
-        ReadParam(m, iter, &p->favicon_url) &&
-        ReadParam(m, iter, &p->png_data) &&
-        ReadParam(m, iter, &p->urls);
-  }
-  static void Log(const param_type& p, std::string* l) {
-    l->append("(");
-    LogParam(p.favicon_url, l);
-    l->append(", ");
-    LogParam(p.png_data, l);
-    l->append(", ");
-    LogParam(p.urls, l);
-    l->append(")");
-  }
-};  // ParamTraits<ImportedFaviconUsage>
-
-// Traits for TemplateURLData
-template <>
-struct ParamTraits<TemplateURLData> {
-  typedef TemplateURLData param_type;
-  static void Write(Message* m, const param_type& p) {
-    WriteParam(m, p.short_name);
-    WriteParam(m, p.keyword());
-    WriteParam(m, p.url());
-    WriteParam(m, p.suggestions_url);
-    WriteParam(m, p.instant_url);
-    WriteParam(m, p.favicon_url);
-    WriteParam(m, p.originating_url);
-    WriteParam(m, p.show_in_default_list);
-    WriteParam(m, p.safe_for_autoreplace);
-    WriteParam(m, p.input_encodings);
-    WriteParam(m, p.id);
-    WriteParam(m, p.date_created);
-    WriteParam(m, p.last_modified);
-    WriteParam(m, p.created_by_policy);
-    WriteParam(m, p.usage_count);
-    WriteParam(m, p.prepopulate_id);
-    WriteParam(m, p.sync_guid);
-  }
-  static bool Read(const Message* m, PickleIterator* iter, param_type* p) {
-    string16 keyword;
-    std::string url;
-    if (!ReadParam(m, iter, &p->short_name) ||
-        !ReadParam(m, iter, &keyword) ||
-        !ReadParam(m, iter, &url) ||
-        !ReadParam(m, iter, &p->suggestions_url) ||
-        !ReadParam(m, iter, &p->instant_url) ||
-        !ReadParam(m, iter, &p->favicon_url) ||
-        !ReadParam(m, iter, &p->originating_url) ||
-        !ReadParam(m, iter, &p->show_in_default_list) ||
-        !ReadParam(m, iter, &p->safe_for_autoreplace) ||
-        !ReadParam(m, iter, &p->input_encodings) ||
-        !ReadParam(m, iter, &p->id) ||
-        !ReadParam(m, iter, &p->date_created) ||
-        !ReadParam(m, iter, &p->last_modified) ||
-        !ReadParam(m, iter, &p->created_by_policy) ||
-        !ReadParam(m, iter, &p->usage_count) ||
-        !ReadParam(m, iter, &p->prepopulate_id) ||
-        !ReadParam(m, iter, &p->sync_guid))
-      return false;
-    p->SetKeyword(keyword);
-    p->SetURL(url);
-    return true;
-  }
-  static void Log(const param_type& p, std::string* l) {
-    l->append("<TemplateURLData>");
-  }
-};
-
-// Traits for TemplateURL*.
-// WARNING: These will cause us to allocate a new TemplateURL on the heap on the
-// receiver side.  Any messages using this type must have handlers that are
-// careful to properly take ownership and avoid leaks!  See warning below on
-// ProfileImportProcessHostMsg_NotifyKeywordsReady.
-template <>
-struct ParamTraits<TemplateURL*> {
-  typedef TemplateURL* param_type;
-  static void Write(Message* m, const param_type& p) {
-    WriteParam(m, p->data());
-  }
-  static bool Read(const Message* m, PickleIterator* iter, param_type* p) {
-    TemplateURLData data;
-    if (!ReadParam(m, iter, &data))
-      return false;
-    // Since we don't have access to a Profile*, just supply NULL.  The caller
-    // can create a new TemplateURL or modify this one (e.g. via
-    // TemplateURLService::AddAndSetProfile()) to correct this later.
-    *p = new TemplateURL(NULL, data);
-    return true;
-  }
-  static void Log(const param_type& p, std::string* l) {
-    l->append("<TemplateURL*>");
-  }
-};
-
-}  // namespace IPC
-
-#endif  // CHROME_BROWSER_IMPORTER_PROFILE_IMPORT_PROCESS_MESSAGES_H_
-
-#define IPC_MESSAGE_START ProfileImportMsgStart
-
-//-----------------------------------------------------------------------------
-// ProfileImportProcess messages
-// These are messages sent from the browser to the profile import process.
-IPC_MESSAGE_CONTROL3(ProfileImportProcessMsg_StartImport,
-                     importer::SourceProfile,
-                     int                     /* Bitmask of items to import. */,
-                     DictionaryValue         /* Localized strings. */)
-
-IPC_MESSAGE_CONTROL0(ProfileImportProcessMsg_CancelImport)
-
-IPC_MESSAGE_CONTROL1(ProfileImportProcessMsg_ReportImportItemFinished,
-                     int  /* ImportItem */)
-
-//---------------------------------------------------------------------------
-// ProfileImportProcessHost messages
-// These are messages sent from the profile import process to the browser.
-// These messages send information about the status of the import and
-// individual import tasks.
-IPC_MESSAGE_CONTROL0(ProfileImportProcessHostMsg_Import_Started)
-
-IPC_MESSAGE_CONTROL2(ProfileImportProcessHostMsg_Import_Finished,
-                     bool         /* was import successful? */,
-                     std::string  /* error message, if any */)
-
-IPC_MESSAGE_CONTROL1(ProfileImportProcessHostMsg_ImportItem_Started,
-                     int  /* ImportItem */)
-
-IPC_MESSAGE_CONTROL1(ProfileImportProcessHostMsg_ImportItem_Finished,
-                     int  /* ImportItem */)
-
-// These messages send data from the external importer process back to
-// the process host so it can be written to the profile.
-IPC_MESSAGE_CONTROL1(ProfileImportProcessHostMsg_NotifyHistoryImportStart,
-                     int  /* total number of history::URLRow items */)
-
-IPC_MESSAGE_CONTROL2(ProfileImportProcessHostMsg_NotifyHistoryImportGroup,
-                     history::URLRows,
-                     int  /* the source of URLs as in history::VisitSource.*/
-                          /* To simplify IPC call, pass as an integer */)
-
-IPC_MESSAGE_CONTROL1(ProfileImportProcessHostMsg_NotifyHomePageImportReady,
-                     GURL  /* GURL of home page */)
-
-IPC_MESSAGE_CONTROL2(ProfileImportProcessHostMsg_NotifyBookmarksImportStart,
-                     string16  /* first folder name */,
-                     int       /* total number of bookmarks */)
-
-IPC_MESSAGE_CONTROL1(ProfileImportProcessHostMsg_NotifyBookmarksImportGroup,
-                     std::vector<ImportedBookmarkEntry>)
-
-IPC_MESSAGE_CONTROL1(ProfileImportProcessHostMsg_NotifyFaviconsImportStart,
-                     int  /* total number of favicons */)
-
-IPC_MESSAGE_CONTROL1(ProfileImportProcessHostMsg_NotifyFaviconsImportGroup,
-                     std::vector<ImportedFaviconUsage>)
-
-IPC_MESSAGE_CONTROL1(ProfileImportProcessHostMsg_NotifyPasswordFormReady,
-                     content::PasswordForm)
-
-// WARNING: The TemplateURL*s in the following message get heap-allocated on the
-// receiving end.  The message handler for this message MUST take ownership of
-// these pointers and ensure they're properly freed!
-IPC_MESSAGE_CONTROL2(ProfileImportProcessHostMsg_NotifyKeywordsReady,
-                     std::vector<TemplateURL*>,
-                     bool  /* unique on host and path */)
diff --git a/chrome/browser/importer/profile_writer.cc b/chrome/browser/importer/profile_writer.cc
index 5430313..ce85351 100644
--- a/chrome/browser/importer/profile_writer.cc
+++ b/chrome/browser/importer/profile_writer.cc
@@ -15,10 +15,8 @@
 #include "base/threading/thread.h"
 #include "chrome/browser/bookmarks/bookmark_model.h"
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
-#include "chrome/browser/bookmarks/imported_bookmark_entry.h"
 #include "chrome/browser/favicon/favicon_service.h"
 #include "chrome/browser/favicon/favicon_service_factory.h"
-#include "chrome/browser/favicon/imported_favicon_usage.h"
 #include "chrome/browser/history/history_service.h"
 #include "chrome/browser/history/history_service_factory.h"
 #include "chrome/browser/password_manager/password_store.h"
@@ -29,6 +27,8 @@
 #include "chrome/browser/search_engines/template_url_service_factory.h"
 #include "chrome/browser/webdata/web_data_service.h"
 #include "chrome/common/chrome_notification_types.h"
+#include "chrome/common/importer/imported_bookmark_entry.h"
+#include "chrome/common/importer/imported_favicon_usage.h"
 #include "chrome/common/pref_names.h"
 
 namespace {
diff --git a/chrome/browser/importer/profile_writer.h b/chrome/browser/importer/profile_writer.h
index cc47044..2d7b6db 100644
--- a/chrome/browser/importer/profile_writer.h
+++ b/chrome/browser/importer/profile_writer.h
@@ -11,10 +11,10 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_vector.h"
 #include "base/strings/string16.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "build/build_config.h"
 #include "chrome/browser/history/history_types.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 struct ImportedBookmarkEntry;
 struct ImportedFaviconUsage;
diff --git a/chrome/browser/importer/profile_writer_unittest.cc b/chrome/browser/importer/profile_writer_unittest.cc
index 072b327..f61b6c8 100644
--- a/chrome/browser/importer/profile_writer_unittest.cc
+++ b/chrome/browser/importer/profile_writer_unittest.cc
@@ -10,11 +10,11 @@
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
 #include "chrome/browser/bookmarks/bookmark_title_match.h"
 #include "chrome/browser/bookmarks/bookmark_utils.h"
-#include "chrome/browser/bookmarks/imported_bookmark_entry.h"
 #include "chrome/browser/history/history_service_factory.h"
 #include "chrome/browser/history/history_types.h"
 #include "chrome/browser/importer/importer_unittest_utils.h"
 #include "chrome/browser/importer/profile_writer.h"
+#include "chrome/common/importer/imported_bookmark_entry.h"
 #include "chrome/test/base/testing_profile.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "content/public/test/test_browser_thread.h"
diff --git a/chrome/browser/importer/safari_importer.h b/chrome/browser/importer/safari_importer.h
index cc7d721..fd83083 100644
--- a/chrome/browser/importer/safari_importer.h
+++ b/chrome/browser/importer/safari_importer.h
@@ -15,6 +15,7 @@
 #include "base/gtest_prod_util.h"
 #include "chrome/browser/history/history_types.h"
 #include "chrome/browser/importer/importer.h"
+#include "chrome/common/importer/importer_url_row.h"
 
 #if __OBJC__
 @class NSDictionary;
@@ -93,7 +94,7 @@
   double HistoryTimeToEpochTime(NSString* history_time);
 
   // Parses Safari's history and loads it into the input array.
-  void ParseHistoryItems(history::URLRows* history_items);
+  void ParseHistoryItems(std::vector<ImporterURLRow>* history_items);
 
   // Opens the favicon database file.
   bool OpenDatabase(sql::Connection* db);
diff --git a/chrome/browser/importer/safari_importer.mm b/chrome/browser/importer/safari_importer.mm
index 422cc68..4a61298 100644
--- a/chrome/browser/importer/safari_importer.mm
+++ b/chrome/browser/importer/safari_importer.mm
@@ -11,20 +11,19 @@
 
 #include "base/file_util.h"
 #include "base/mac/mac_util.h"
-#include "base/memory/scoped_nsobject.h"
 #include "base/strings/string16.h"
 #include "base/strings/sys_string_conversions.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
-#include "chrome/browser/bookmarks/imported_bookmark_entry.h"
+#include "base/time/time.h"
 #include "chrome/browser/favicon/favicon_util.h"
-#include "chrome/browser/favicon/imported_favicon_usage.h"
 #include "chrome/browser/importer/importer_bridge.h"
+#include "chrome/common/importer/imported_bookmark_entry.h"
+#include "chrome/common/importer/imported_favicon_usage.h"
 #include "chrome/common/url_constants.h"
-#include "googleurl/src/gurl.h"
 #include "grit/generated_resources.h"
 #include "net/base/data_url.h"
 #include "sql/statement.h"
+#include "url/gurl.h"
 
 namespace {
 
@@ -319,7 +318,7 @@
 }
 
 void SafariImporter::ImportHistory() {
-  history::URLRows rows;
+  std::vector<ImporterURLRow> rows;
   ParseHistoryItems(&rows);
 
   if (!rows.empty() && !cancelled()) {
@@ -336,7 +335,8 @@
       kCFAbsoluteTimeIntervalSince1970;
 }
 
-void SafariImporter::ParseHistoryItems(history::URLRows* history_items) {
+void SafariImporter::ParseHistoryItems(
+    std::vector<ImporterURLRow>* history_items) {
   DCHECK(history_items);
 
   // Construct ~/Library/Safari/History.plist path
@@ -366,7 +366,7 @@
     if (!CanImportSafariURL(url))
       continue;
 
-    history::URLRow row(url);
+    ImporterURLRow row(url);
     NSString* title_ns = [history_item objectForKey:@"title"];
 
     // Sometimes items don't have a title, in which case we just substitue
@@ -374,14 +374,14 @@
     if (!title_ns)
       title_ns = url_ns;
 
-    row.set_title(base::SysNSStringToUTF16(title_ns));
+    row.title = base::SysNSStringToUTF16(title_ns);
     int visit_count = [[history_item objectForKey:@"visitCount"]
                           intValue];
-    row.set_visit_count(visit_count);
+    row.visit_count = visit_count;
     // Include imported URLs in autocompletion - don't hide them.
-    row.set_hidden(0);
+    row.hidden = 0;
     // Item was never typed before in the omnibox.
-    row.set_typed_count(0);
+    row.typed_count = 0;
 
     NSString* last_visit_str = [history_item objectForKey:@"lastVisitedDate"];
     // The last visit time should always be in the history item, but if not
@@ -392,7 +392,7 @@
 
     // Convert Safari's last visit time to Unix Epoch time.
     double seconds_since_unix_epoch = HistoryTimeToEpochTime(last_visit_str);
-    row.set_last_visit(base::Time::FromDoubleT(seconds_since_unix_epoch));
+    row.last_visit = base::Time::FromDoubleT(seconds_since_unix_epoch);
 
     history_items->push_back(row);
   }
diff --git a/chrome/browser/importer/safari_importer_unittest.mm b/chrome/browser/importer/safari_importer_unittest.mm
index 6725b75..93e110c 100644
--- a/chrome/browser/importer/safari_importer_unittest.mm
+++ b/chrome/browser/importer/safari_importer_unittest.mm
@@ -13,10 +13,10 @@
 #include "base/strings/string_util.h"
 #include "base/strings/sys_string_conversions.h"
 #include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/bookmarks/imported_bookmark_entry.h"
-#include "chrome/browser/favicon/imported_favicon_usage.h"
 #include "chrome/browser/importer/importer_bridge.h"
 #include "chrome/common/chrome_paths.h"
+#include "chrome/common/importer/imported_bookmark_entry.h"
+#include "chrome/common/importer/imported_favicon_usage.h"
 #include "sql/connection.h"
 #include "testing/platform_test.h"
 
@@ -47,30 +47,30 @@
 TEST_F(SafariImporterTest, HistoryImport) {
   scoped_refptr<SafariImporter> importer(GetSafariImporter());
 
-  history::URLRows history_items;
+  std::vector<ImporterURLRow> history_items;
   importer->ParseHistoryItems(&history_items);
 
   // Should be 2 history items.
   ASSERT_EQ(history_items.size(), 2U);
 
-  history::URLRow& it1 = history_items[0];
-  EXPECT_EQ(it1.url(), GURL("http://www.firsthistoryitem.com/"));
-  EXPECT_EQ(it1.title(), UTF8ToUTF16("First History Item Title"));
-  EXPECT_EQ(it1.visit_count(), 1);
-  EXPECT_EQ(it1.hidden(), 0);
-  EXPECT_EQ(it1.typed_count(), 0);
-  EXPECT_EQ(it1.last_visit().ToDoubleT(),
+  ImporterURLRow& it1 = history_items[0];
+  EXPECT_EQ(it1.url, GURL("http://www.firsthistoryitem.com/"));
+  EXPECT_EQ(it1.title, UTF8ToUTF16("First History Item Title"));
+  EXPECT_EQ(it1.visit_count, 1);
+  EXPECT_EQ(it1.hidden, 0);
+  EXPECT_EQ(it1.typed_count, 0);
+  EXPECT_EQ(it1.last_visit.ToDoubleT(),
       importer->HistoryTimeToEpochTime(@"270598264.4"));
 
-  history::URLRow& it2 = history_items[1];
+  ImporterURLRow& it2 = history_items[1];
   std::string second_item_title("http://www.secondhistoryitem.com/");
-  EXPECT_EQ(it2.url(), GURL(second_item_title));
+  EXPECT_EQ(it2.url, GURL(second_item_title));
   // The second item lacks a title so we expect the URL to be substituted.
-  EXPECT_EQ(UTF16ToUTF8(it2.title()), second_item_title.c_str());
-  EXPECT_EQ(it2.visit_count(), 55);
-  EXPECT_EQ(it2.hidden(), 0);
-  EXPECT_EQ(it2.typed_count(), 0);
-  EXPECT_EQ(it2.last_visit().ToDoubleT(),
+  EXPECT_EQ(UTF16ToUTF8(it2.title), second_item_title.c_str());
+  EXPECT_EQ(it2.visit_count, 55);
+  EXPECT_EQ(it2.hidden, 0);
+  EXPECT_EQ(it2.typed_count, 0);
+  EXPECT_EQ(it2.last_visit.ToDoubleT(),
       importer->HistoryTimeToEpochTime(@"270598231.4"));
 }
 
diff --git a/chrome/browser/importer/toolbar_importer.cc b/chrome/browser/importer/toolbar_importer.cc
deleted file mode 100644
index dea1d61..0000000
--- a/chrome/browser/importer/toolbar_importer.cc
+++ /dev/null
@@ -1,573 +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/importer/toolbar_importer.h"
-
-#include <limits>
-
-#include "base/bind.h"
-#include "base/rand_util.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_split.h"
-#include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/bookmarks/imported_bookmark_entry.h"
-#include "chrome/browser/first_run/first_run.h"
-#include "chrome/browser/importer/importer_bridge.h"
-#include "chrome/browser/importer/importer_data_types.h"
-#include "chrome/browser/profiles/profile.h"
-#include "content/public/browser/browser_thread.h"
-#include "grit/generated_resources.h"
-#include "net/base/load_flags.h"
-#include "net/url_request/url_fetcher.h"
-#include "third_party/libxml/chromium/libxml_utils.h"
-
-using content::BrowserThread;
-
-// Toolbar5Importer
-const char Toolbar5Importer::kXmlApiReplyXmlTag[] = "xml_api_reply";
-const char Toolbar5Importer::kBookmarksXmlTag[] = "bookmarks";
-const char Toolbar5Importer::kBookmarkXmlTag[] = "bookmark";
-const char Toolbar5Importer::kTitleXmlTag[] = "title";
-const char Toolbar5Importer::kUrlXmlTag[] = "url";
-const char Toolbar5Importer::kTimestampXmlTag[] = "timestamp";
-const char Toolbar5Importer::kLabelsXmlTag[] = "labels";
-const char Toolbar5Importer::kLabelsXmlCloseTag[] = "/labels";
-const char Toolbar5Importer::kLabelXmlTag[] = "label";
-const char Toolbar5Importer::kAttributesXmlTag[] = "attributes";
-
-const char Toolbar5Importer::kRandomNumberToken[] = "{random_number}";
-const char Toolbar5Importer::kAuthorizationToken[] = "{auth_token}";
-const char Toolbar5Importer::kAuthorizationTokenPrefix[] = "/*";
-const char Toolbar5Importer::kAuthorizationTokenSuffix[] = "*/";
-const char Toolbar5Importer::kMaxNumToken[] = "{max_num}";
-const char Toolbar5Importer::kMaxTimestampToken[] = "{max_timestamp}";
-
-const char Toolbar5Importer::kT5AuthorizationTokenUrl[] =
-    "http://www.google.com/notebook/token?zx={random_number}";
-const char Toolbar5Importer::kT5FrontEndUrlTemplate[] =
-    "http://www.google.com/notebook/toolbar?cmd=list&tok={auth_token}&"
-    "num={max_num}&min={max_timestamp}&all=0&zx={random_number}";
-
-// Importer methods.
-
-// The constructor should set the initial state to NOT_USED.
-Toolbar5Importer::Toolbar5Importer()
-    : state_(NOT_USED),
-      items_to_import_(importer::NONE),
-      token_fetcher_(NULL),
-      data_fetcher_(NULL) {
-}
-
-// The destructor insures that the fetchers are currently not being used, as
-// their thread-safe implementation requires that they are cancelled from the
-// thread in which they were constructed.
-Toolbar5Importer::~Toolbar5Importer() {
-  DCHECK(!token_fetcher_);
-  DCHECK(!data_fetcher_);
-}
-
-void Toolbar5Importer::StartImport(
-    const importer::SourceProfile& source_profile,
-    uint16 items,
-    ImporterBridge* bridge) {
-  DCHECK(bridge);
-
-  bridge_ = bridge;
-  items_to_import_ = items;
-  DCHECK(source_profile.request_context_getter.get());
-  request_context_getter_ = source_profile.request_context_getter;
-  state_ = INITIALIZED;
-
-  bridge_->NotifyStarted();
-  ContinueImport();
-}
-
-// The public cancel method serves two functions, as a callback from the UI
-// as well as an internal callback in case of cancel.  An internal callback
-// is required since the URLFetcher must be destroyed from the thread it was
-// created.
-void Toolbar5Importer::Cancel() {
-  // In the case when the thread is not importing messages we are to
-  // cancel as soon as possible.
-  Importer::Cancel();
-
-  // If we are conducting network operations, post a message to the importer
-  // thread for synchronization.
-  if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
-    EndImport();
-  } else {
-    BrowserThread::PostTask(
-        BrowserThread::UI, FROM_HERE,
-        base::Bind(&Toolbar5Importer::Cancel, this));
-  }
-}
-
-void Toolbar5Importer::OnURLFetchComplete(const net::URLFetcher* source) {
-  if (cancelled()) {
-    EndImport();
-    return;
-  }
-
-  if (200 != source->GetResponseCode()) {  // HTTP/Ok
-    // Cancelling here will update the UI and bypass the rest of bookmark
-    // import.
-    EndImportBookmarks();
-    return;
-  }
-
-  std::string data;
-  source->GetResponseAsString(&data);
-  switch (state_) {
-    case GET_AUTHORIZATION_TOKEN:
-      GetBookmarkDataFromServer(data);
-      break;
-    case GET_BOOKMARKS:
-      GetBookmarksFromServerDataResponse(data);
-      break;
-    default:
-      NOTREACHED() << "Invalid state.";
-      EndImportBookmarks();
-      break;
-  }
-}
-
-void Toolbar5Importer::ContinueImport() {
-  DCHECK((items_to_import_ == importer::FAVORITES) ||
-         (items_to_import_ == importer::NONE)) <<
-      "The items requested are not supported";
-
-  // The order here is important.  Each Begin... will clear the flag
-  // of its item before its task finishes and re-enters this method.
-  if (importer::NONE == items_to_import_) {
-    EndImport();
-    return;
-  }
-  if ((items_to_import_ & importer::FAVORITES) && !cancelled()) {
-    items_to_import_ &= ~importer::FAVORITES;
-    BeginImportBookmarks();
-    return;
-  }
-  // TODO(brg): Import history, autocomplete, other toolbar information
-  // in a future release.
-
-  // This code should not be reached, but gracefully handles the possibility
-  // that StartImport was called with unsupported items_to_import.
-  if (!cancelled())
-    EndImport();
-}
-
-void Toolbar5Importer::EndImport() {
-  if (state_ != DONE) {
-    state_ = DONE;
-    // By spec the fetchers must be destroyed within the same
-    // thread they are created.  The importer is destroyed in the ui_thread
-    // so when we complete in the file_thread we destroy them first.
-    if (NULL != token_fetcher_) {
-      delete token_fetcher_;
-      token_fetcher_ = NULL;
-    }
-
-    if (NULL != data_fetcher_) {
-      delete data_fetcher_;
-      data_fetcher_ = NULL;
-    }
-
-    if (bridge_.get())
-      bridge_->NotifyEnded();
-  }
-}
-
-void Toolbar5Importer::BeginImportBookmarks() {
-  bridge_->NotifyItemStarted(importer::FAVORITES);
-  GetAuthenticationFromServer();
-}
-
-void Toolbar5Importer::EndImportBookmarks() {
-  bridge_->NotifyItemEnded(importer::FAVORITES);
-  ContinueImport();
-}
-
-
-// Notebook front-end connection manager implementation follows.
-void Toolbar5Importer::GetAuthenticationFromServer() {
-  if (cancelled()) {
-    EndImport();
-    return;
-  }
-
-  // Authentication is a token string retrieved from the authentication server
-  // To access it we call the url below with a random number replacing the
-  // value in the string.
-  state_ = GET_AUTHORIZATION_TOKEN;
-
-  // Random number construction.
-  int random = base::RandInt(0, std::numeric_limits<int>::max());
-  std::string random_string = base::UintToString(random);
-
-  // Retrieve authorization token from the network.
-  std::string url_string(kT5AuthorizationTokenUrl);
-  url_string.replace(url_string.find(kRandomNumberToken),
-                     arraysize(kRandomNumberToken) - 1,
-                     random_string);
-  GURL url(url_string);
-
-  // Because the importer is started as the result of a user action which
-  // explicitly requires authentication, sending cookies here is reasonable.
-  token_fetcher_ = net::URLFetcher::Create(
-      url, net::URLFetcher::GET, this);
-  token_fetcher_->SetRequestContext(request_context_getter_.get());
-  token_fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SAVE_COOKIES);
-  token_fetcher_->Start();
-}
-
-void Toolbar5Importer::GetBookmarkDataFromServer(const std::string& response) {
-  if (cancelled()) {
-    EndImport();
-    return;
-  }
-
-  state_ = GET_BOOKMARKS;
-
-  // Parse and verify the authorization token from the response.
-  std::string token;
-  if (!ParseAuthenticationTokenResponse(response, &token)) {
-    EndImportBookmarks();
-    return;
-  }
-
-  // Build the Toolbar FE connection string, and call the server for
-  // the xml blob.  We must tag the connection string with a random number.
-  std::string conn_string = kT5FrontEndUrlTemplate;
-  int random = base::RandInt(0, std::numeric_limits<int>::max());
-  std::string random_string = base::UintToString(random);
-  conn_string.replace(conn_string.find(kRandomNumberToken),
-                      arraysize(kRandomNumberToken) - 1,
-                      random_string);
-  conn_string.replace(conn_string.find(kAuthorizationToken),
-                      arraysize(kAuthorizationToken) - 1,
-                      token);
-  GURL url(conn_string);
-
-  // Because the importer is started as the result of a user action which
-  // explicitly requires authentication, sending cookies here is reasonable.
-  data_fetcher_ = net::URLFetcher::Create(
-      url, net::URLFetcher::GET, this);
-  data_fetcher_->SetRequestContext(request_context_getter_.get());
-  data_fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SAVE_COOKIES);
-  data_fetcher_->Start();
-}
-
-void Toolbar5Importer::GetBookmarksFromServerDataResponse(
-    const std::string& response) {
-  if (cancelled()) {
-    EndImport();
-    return;
-  }
-
-  state_ = PARSE_BOOKMARKS;
-
-  XmlReader reader;
-  if (reader.Load(response) && !cancelled()) {
-    // Construct Bookmarks
-    std::vector<ImportedBookmarkEntry> bookmarks;
-    if (ParseBookmarksFromReader(&reader, &bookmarks,
-        bridge_->GetLocalizedString(IDS_BOOKMARK_GROUP_FROM_GOOGLE_TOOLBAR)))
-      AddBookmarksToChrome(bookmarks);
-  }
-  EndImportBookmarks();
-}
-
-bool Toolbar5Importer::ParseAuthenticationTokenResponse(
-    const std::string& response,
-    std::string* token) {
-  DCHECK(token);
-
-  *token = response;
-  size_t position = token->find(kAuthorizationTokenPrefix);
-  if (0 != position)
-    return false;
-  token->replace(position, arraysize(kAuthorizationTokenPrefix) - 1, "");
-
-  position = token->find(kAuthorizationTokenSuffix);
-  if (token->size() != (position + (arraysize(kAuthorizationTokenSuffix) - 1)))
-    return false;
-  token->replace(position, arraysize(kAuthorizationTokenSuffix) - 1, "");
-
-  return true;
-}
-
-// Parsing
-bool Toolbar5Importer::ParseBookmarksFromReader(
-    XmlReader* reader,
-    std::vector<ImportedBookmarkEntry>* bookmarks,
-    const string16& bookmark_group_string) {
-  DCHECK(reader);
-  DCHECK(bookmarks);
-
-  // The XML blob returned from the server is described in the
-  // Toolbar-Notebook/Bookmarks Protocol document located at
-  // https://docs.google.com/a/google.com/Doc?docid=cgt3m7dr_24djt62m&hl=en
-  // We are searching for the section with structure
-  // <bookmarks><bookmark>...</bookmark><bookmark>...</bookmark></bookmarks>
-
-  // Locate the |bookmarks| blob.
-  if (!reader->SkipToElement())
-    return false;
-
-  if (!LocateNextTagByName(reader, kBookmarksXmlTag))
-    return false;
-
-  // Parse each |bookmark| blob
-  while (LocateNextTagWithStopByName(reader, kBookmarkXmlTag,
-                                     kBookmarksXmlTag)) {
-    ImportedBookmarkEntry bookmark_entry;
-    std::vector<BookmarkFolderType> folders;
-    if (ExtractBookmarkInformation(reader, &bookmark_entry, &folders,
-                                   bookmark_group_string)) {
-      // For each folder we create a new bookmark entry.  Duplicates will
-      // be detected when we attempt to create the bookmark in the profile.
-      for (std::vector<BookmarkFolderType>::iterator folder = folders.begin();
-          folder != folders.end();
-          ++folder) {
-        bookmark_entry.path = *folder;
-        bookmarks->push_back(bookmark_entry);
-      }
-    }
-  }
-
-  if (0 == bookmarks->size())
-    return false;
-
-  return true;
-}
-
-bool Toolbar5Importer::LocateNextOpenTag(XmlReader* reader) {
-  DCHECK(reader);
-
-  while (!reader->SkipToElement()) {
-    if (!reader->Read())
-      return false;
-  }
-  return true;
-}
-
-bool Toolbar5Importer::LocateNextTagByName(XmlReader* reader,
-                                           const std::string& tag) {
-  DCHECK(reader);
-
-  // Locate the |tag| blob.
-  while (tag != reader->NodeName()) {
-    if (!reader->Read() || !LocateNextOpenTag(reader))
-      return false;
-  }
-  return true;
-}
-
-bool Toolbar5Importer::LocateNextTagWithStopByName(XmlReader* reader,
-                                                   const std::string& tag,
-                                                   const std::string& stop) {
-  DCHECK(reader);
-
-  DCHECK_NE(tag, stop);
-  // Locate the |tag| blob.
-  while (tag != reader->NodeName()) {
-    // Move to the next open tag.
-    if (!reader->Read() || !LocateNextOpenTag(reader))
-      return false;
-    // If we encounter the stop word return false.
-    if (stop == reader->NodeName())
-      return false;
-  }
-  return true;
-}
-
-bool Toolbar5Importer::ExtractBookmarkInformation(
-    XmlReader* reader,
-    ImportedBookmarkEntry* bookmark_entry,
-    std::vector<BookmarkFolderType>* bookmark_folders,
-    const string16& bookmark_group_string) {
-  DCHECK(reader);
-  DCHECK(bookmark_entry);
-  DCHECK(bookmark_folders);
-
-  // The following is a typical bookmark entry.
-  // The reader should be pointing to the <title> tag at the moment.
-  //
-  // <bookmark>
-  // <title>MyTitle</title>
-  // <url>http://www.sohu.com/</url>
-  // <timestamp>1153328691085181</timestamp>
-  // <id>N123nasdf239</id>
-  // <notebook_id>Bxxxxxxx</notebook_id> (for bookmarks, a special id is used)
-  // <section_id>Sxxxxxx</section_id>
-  // <has_highlight>0</has_highlight>
-  // <labels>
-  // <label>China</label>
-  // <label>^k</label> (if this special label is present, the note is deleted)
-  // </labels>
-  // <attributes>
-  // <attribute>
-  // <name>favicon_url</name>
-  // <value>http://www.sohu.com/favicon.ico</value>
-  // </attribute>
-  // <attribute>
-  // <name>favicon_timestamp</name>
-  // <value>1153328653</value>
-  // </attribute>
-  // <attribute>
-  // <name>notebook_name</name>
-  // <value>My notebook 0</value>
-  // </attribute>
-  // <attribute>
-  // <name>section_name</name>
-  // <value>My section 0</value>
-  // </attribute>
-  // </attributes>
-  // </bookmark>
-  //
-  // We parse the blob in order, title->url->timestamp etc.  Any failure
-  // causes us to skip this bookmark.
-
-  if (!ExtractTitleFromXmlReader(reader, bookmark_entry))
-    return false;
-  if (!ExtractUrlFromXmlReader(reader, bookmark_entry))
-    return false;
-  if (!ExtractTimeFromXmlReader(reader, bookmark_entry))
-    return false;
-  if (!ExtractFoldersFromXmlReader(reader, bookmark_folders,
-                                   bookmark_group_string))
-    return false;
-
-  return true;
-}
-
-bool Toolbar5Importer::ExtractNamedValueFromXmlReader(XmlReader* reader,
-                                                      const std::string& name,
-                                                      std::string* buffer) {
-  DCHECK(reader);
-  DCHECK(buffer);
-
-  if (name != reader->NodeName())
-    return false;
-  if (!reader->ReadElementContent(buffer))
-    return false;
-  return true;
-}
-
-bool Toolbar5Importer::ExtractTitleFromXmlReader(
-    XmlReader* reader,
-    ImportedBookmarkEntry* entry) {
-  DCHECK(reader);
-  DCHECK(entry);
-
-  if (!LocateNextTagWithStopByName(reader, kTitleXmlTag, kUrlXmlTag))
-    return false;
-  std::string buffer;
-  if (!ExtractNamedValueFromXmlReader(reader, kTitleXmlTag, &buffer)) {
-    return false;
-  }
-  entry->title = UTF8ToUTF16(buffer);
-  return true;
-}
-
-bool Toolbar5Importer::ExtractUrlFromXmlReader(
-    XmlReader* reader,
-    ImportedBookmarkEntry* entry) {
-  DCHECK(reader);
-  DCHECK(entry);
-
-  if (!LocateNextTagWithStopByName(reader, kUrlXmlTag, kTimestampXmlTag))
-    return false;
-  std::string buffer;
-  if (!ExtractNamedValueFromXmlReader(reader, kUrlXmlTag, &buffer)) {
-    return false;
-  }
-  entry->url = GURL(buffer);
-  return true;
-}
-
-bool Toolbar5Importer::ExtractTimeFromXmlReader(
-    XmlReader* reader,
-    ImportedBookmarkEntry* entry) {
-  DCHECK(reader);
-  DCHECK(entry);
-  if (!LocateNextTagWithStopByName(reader, kTimestampXmlTag, kLabelsXmlTag))
-    return false;
-  std::string buffer;
-  if (!ExtractNamedValueFromXmlReader(reader, kTimestampXmlTag, &buffer)) {
-    return false;
-  }
-  int64 timestamp;
-  if (!base::StringToInt64(buffer, &timestamp)) {
-    return false;
-  }
-  entry->creation_time = base::Time::FromTimeT(timestamp);
-  return true;
-}
-
-bool Toolbar5Importer::ExtractFoldersFromXmlReader(
-    XmlReader* reader,
-    std::vector<BookmarkFolderType>* bookmark_folders,
-    const string16& bookmark_group_string) {
-  DCHECK(reader);
-  DCHECK(bookmark_folders);
-
-  // Read in the labels for this bookmark from the xml.  There may be many
-  // labels for any one bookmark.
-  if (!LocateNextTagWithStopByName(reader, kLabelsXmlTag, kAttributesXmlTag))
-    return false;
-
-  // It is within scope to have an empty labels section, so we do not
-  // return false if the labels are empty.
-  if (!reader->Read() || !LocateNextOpenTag(reader))
-    return false;
-
-  std::vector<string16> label_vector;
-  while (kLabelXmlTag == reader->NodeName()) {
-    std::string label_buffer;
-    if (!reader->ReadElementContent(&label_buffer)) {
-      label_buffer = "";
-    }
-    label_vector.push_back(UTF8ToUTF16(label_buffer));
-    LocateNextOpenTag(reader);
-  }
-
-  if (0 == label_vector.size()) {
-    if (!first_run::IsChromeFirstRun()) {
-      bookmark_folders->resize(1);
-      (*bookmark_folders)[0].push_back(bookmark_group_string);
-    }
-    return true;
-  }
-
-  // We will be making one bookmark folder for each label.
-  bookmark_folders->resize(label_vector.size());
-
-  for (size_t index = 0; index < label_vector.size(); ++index) {
-    // If this is the first run then we place favorites with no labels
-    // in the title bar.  Else they are placed in the "Google Toolbar" folder.
-    if (!first_run::IsChromeFirstRun() || !label_vector[index].empty()) {
-      (*bookmark_folders)[index].push_back(bookmark_group_string);
-    }
-
-    // If the label and is in the form "xxx:yyy:zzz" this was created from an
-    // IE or Firefox folder.  We undo the label creation and recreate the
-    // correct folder.
-    std::vector<string16> folder_names;
-    base::SplitString(label_vector[index], ':', &folder_names);
-    (*bookmark_folders)[index].insert((*bookmark_folders)[index].end(),
-        folder_names.begin(), folder_names.end());
-  }
-
-  return true;
-}
-
-void  Toolbar5Importer::AddBookmarksToChrome(
-    const std::vector<ImportedBookmarkEntry>& bookmarks) {
-  if (!bookmarks.empty() && !cancelled()) {
-    const string16& first_folder_name =
-        bridge_->GetLocalizedString(IDS_BOOKMARK_GROUP_FROM_GOOGLE_TOOLBAR);
-    bridge_->AddBookmarks(bookmarks, first_folder_name);
-  }
-}
diff --git a/chrome/browser/importer/toolbar_importer.h b/chrome/browser/importer/toolbar_importer.h
deleted file mode 100644
index 961b67f..0000000
--- a/chrome/browser/importer/toolbar_importer.h
+++ /dev/null
@@ -1,170 +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.
-
-// The functionality provided here allows the user to import their bookmarks
-// (favorites) from Google Toolbar.
-
-#ifndef CHROME_BROWSER_IMPORTER_TOOLBAR_IMPORTER_H_
-#define CHROME_BROWSER_IMPORTER_TOOLBAR_IMPORTER_H_
-
-#include <string>
-#include <vector>
-
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "base/gtest_prod_util.h"
-#include "base/memory/ref_counted.h"
-#include "base/strings/string16.h"
-#include "chrome/browser/importer/importer.h"
-#include "net/url_request/url_fetcher_delegate.h"
-#include "net/url_request/url_request_context_getter.h"
-
-struct ImportedBookmarkEntry;
-class ImporterBridge;
-class XmlReader;
-
-namespace net {
-class URLFetcher;
-}  // namespace net
-
-// Toolbar5Importer is a class which exposes the functionality needed to
-// communicate with the Google Toolbar v5 front-end, negotiate the download of
-// Toolbar bookmarks, parse them, and install them on the client.
-// Toolbar5Importer should not have StartImport called more than once. Futher
-// if StartImport is called, then the class must not be destroyed until it has
-// either completed or Toolbar5Importer->Cancel() has been called.
-class Toolbar5Importer : public net::URLFetcherDelegate, public Importer {
- public:
-  Toolbar5Importer();
-
-  // Importer:
-  // The importer view calls this method to begin the process. |items| should
-  // only either be NONE or FAVORITES, since as of right now these are the only
-  // items this importer supports.
-  virtual void StartImport(const importer::SourceProfile& source_profile,
-                           uint16 items,
-                           ImporterBridge* bridge) OVERRIDE;
-
-  // Importer view call this method when the user clicks the cancel button
-  // in the tabbed options UI.  We need to post a message to our loop
-  // to cancel network retrieval.
-  virtual void Cancel() OVERRIDE;
-
-  // net::URLFetcherDelegate method called back from the URLFetcher object.
-  virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE;
-
- private:
-  FRIEND_TEST_ALL_PREFIXES(Toolbar5ImporterTest, BookmarkParse);
-
-  virtual ~Toolbar5Importer();
-
-  // Internal states of the toolbar importer.
-  enum InternalStateEnum {
-    NOT_USED = -1,
-    INITIALIZED,
-    GET_AUTHORIZATION_TOKEN,
-    GET_BOOKMARKS,
-    PARSE_BOOKMARKS,
-    DONE
-  };
-
-  typedef std::vector<string16> BookmarkFolderType;
-
-  // URLs for connecting to the toolbar front end are defined below.
-  static const char kT5AuthorizationTokenUrl[];
-  static const char kT5FrontEndUrlTemplate[];
-
-  // Token replacement tags are defined below.
-  static const char kRandomNumberToken[];
-  static const char kAuthorizationToken[];
-  static const char kAuthorizationTokenPrefix[];
-  static const char kAuthorizationTokenSuffix[];
-  static const char kMaxNumToken[];
-  static const char kMaxTimestampToken[];
-
-  // XML tag names are defined below.
-  static const char kXmlApiReplyXmlTag[];
-  static const char kBookmarksXmlTag[];
-  static const char kBookmarkXmlTag[];
-  static const char kTitleXmlTag[];
-  static const char kUrlXmlTag[];
-  static const char kTimestampXmlTag[];
-  static const char kLabelsXmlTag[];
-  static const char kLabelsXmlCloseTag[];
-  static const char kLabelXmlTag[];
-  static const char kAttributesXmlTag[];
-
-  // Flow control for asynchronous import is controlled by the methods below.
-  // ContinueImport is called back by each import action taken.  BeginXXX
-  // and EndXXX are responsible for updating the state of the asynchronous
-  // import.  EndImport is responsible for state cleanup and notifying the
-  // caller that import has completed.
-  void ContinueImport();
-  void EndImport();
-  void BeginImportBookmarks();
-  void EndImportBookmarks();
-
-  // Network I/O is done by the methods below.  These three methods are called
-  // in the order provided.  The last two are called back with the HTML
-  // response provided by the Toolbar server.
-  void GetAuthenticationFromServer();
-  void GetBookmarkDataFromServer(const std::string& response);
-  void GetBookmarksFromServerDataResponse(const std::string& response);
-
-  // XML Parsing is implemented with the methods below.
-  bool ParseAuthenticationTokenResponse(const std::string& response,
-                                        std::string* token);
-
-  static bool ParseBookmarksFromReader(
-      XmlReader* reader,
-      std::vector<ImportedBookmarkEntry>* bookmarks,
-      const string16& bookmark_group_string);
-
-  static bool LocateNextOpenTag(XmlReader* reader);
-  static bool LocateNextTagByName(XmlReader* reader, const std::string& tag);
-  static bool LocateNextTagWithStopByName(
-      XmlReader* reader,
-      const std::string& tag,
-      const std::string& stop);
-
-  static bool ExtractBookmarkInformation(
-      XmlReader* reader,
-      ImportedBookmarkEntry* bookmark_entry,
-      std::vector<BookmarkFolderType>* bookmark_folders,
-      const string16& bookmark_group_string);
-  static bool ExtractNamedValueFromXmlReader(XmlReader* reader,
-                                             const std::string& name,
-                                             std::string* buffer);
-  static bool ExtractTitleFromXmlReader(XmlReader* reader,
-                                        ImportedBookmarkEntry* entry);
-  static bool ExtractUrlFromXmlReader(XmlReader* reader,
-                                      ImportedBookmarkEntry* entry);
-  static bool ExtractTimeFromXmlReader(XmlReader* reader,
-                                       ImportedBookmarkEntry* entry);
-  static bool ExtractFoldersFromXmlReader(
-      XmlReader* reader,
-      std::vector<BookmarkFolderType>* bookmark_folders,
-      const string16& bookmark_group_string);
-
-  // Bookmark creation is done by the method below.
-  void AddBookmarksToChrome(
-      const std::vector<ImportedBookmarkEntry>& bookmarks);
-
-  InternalStateEnum state_;
-
-  // Bitmask of Importer::ImportItem.
-  uint16 items_to_import_;
-
-  // The fetchers need to be available to cancel the network call on user cancel
-  // hence they are stored as member variables.
-  net::URLFetcher* token_fetcher_;
-  net::URLFetcher* data_fetcher_;
-
-  // Used to get correct login data for the toolbar server.
-  scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
-
-  DISALLOW_COPY_AND_ASSIGN(Toolbar5Importer);
-};
-
-#endif  // CHROME_BROWSER_IMPORTER_TOOLBAR_IMPORTER_H_
diff --git a/chrome/browser/importer/toolbar_importer_unittest.cc b/chrome/browser/importer/toolbar_importer_unittest.cc
deleted file mode 100644
index f8c89dc..0000000
--- a/chrome/browser/importer/toolbar_importer_unittest.cc
+++ /dev/null
@@ -1,488 +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 "testing/gtest/include/gtest/gtest.h"
-
-#include <string>
-#include <vector>
-
-#include "base/strings/string16.h"
-#include "base/strings/string_util.h"
-#include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/bookmarks/imported_bookmark_entry.h"
-#include "chrome/browser/first_run/first_run.h"
-#include "chrome/browser/first_run/first_run_internal.h"
-#include "chrome/browser/importer/toolbar_importer.h"
-#include "googleurl/src/gurl.h"
-#include "third_party/libxml/chromium/libxml_utils.h"
-
-// See http://crbug.com/11838
-TEST(Toolbar5ImporterTest, BookmarkParse) {
-static const string16 kTitle = ASCIIToUTF16("MyTitle");
-static const char kUrl[] = "http://www.google.com/";
-static const string16 kFolder = ASCIIToUTF16("Google");
-static const string16 kFolder2 = ASCIIToUTF16("Homepage");
-static const string16 kFolderArray[3] = {
-  ASCIIToUTF16("Google"),
-  ASCIIToUTF16("Search"),
-  ASCIIToUTF16("Page")
-};
-static const string16 kOtherTitle = ASCIIToUTF16("MyOtherTitle");
-static const char* kOtherUrl = "http://www.google.com/mail";
-static const string16 kOtherFolder = ASCIIToUTF16("Mail");
-
-static const string16 kBookmarkGroupTitle = ASCIIToUTF16("BookmarkGroupTitle");
-
-// Since the following is very dense to read I enumerate the test cases here.
-// 1. Correct bookmark structure with one label.
-// 2. Correct bookmark structure with no labels.
-// 3. Correct bookmark structure with two labels.
-// 4. Correct bookmark structure with a folder->label translation by toolbar.
-// 5. Correct bookmark structure with no favicon.
-// 6. Two correct bookmarks.
-// The following are error cases by removing sections from the xml:
-// 7. Empty string passed as xml.
-// 8. No <bookmarks> section in the xml.
-// 9. No <bookmark> section below the <bookmarks> section.
-// 10. No <title> in a <bookmark> section.
-// 11. No <url> in a <bookmark> section.
-// 12. No <timestamp> in a <bookmark> section.
-// 13. No <labels> in a <bookmark> section.
-static const char* kGoodBookmark =
-    "<?xml version=\"1.0\" ?> <xml_api_reply version=\"1\"> <bookmarks>"
-    " <bookmark> "
-    "<title>MyTitle</title> "
-    "<url>http://www.google.com/</url> "
-    "<timestamp>1153328691085181</timestamp> "
-    "<id>N123nasdf239</id> <notebook_id>Bxxxxxxx</notebook_id> "
-    "<section_id>Sxxxxxx</section_id> <has_highlight>0</has_highlight>"
-    "<labels> <label>Google</label> </labels> "
-    "<attributes> "
-    "<attribute> "
-    "<name>favicon_url</name> <value>http://www.google.com/favicon.ico</value> "
-    "</attribute> "
-    "<attribute> "
-    "<name>favicon_timestamp</name> <value>1153328653</value> "
-    "</attribute> "
-    "<attribute> <name>notebook_name</name> <value>My notebook 0</value> "
-    "</attribute> "
-    "<attribute> <name>section_name</name> <value>My section 0 "
-    "</value> </attribute> </attributes> "
-    "</bookmark> </bookmarks>";
-static const char* kGoodBookmarkNoLabel =
-    "<?xml version=\"1.0\" ?> <xml_api_reply version=\"1\"> <bookmarks>"
-    " <bookmark> "
-    "<title>MyTitle</title> "
-    "<url>http://www.google.com/</url> "
-    "<timestamp>1153328691085181</timestamp> "
-    "<id>N123nasdf239</id> <notebook_id>Bxxxxxxx</notebook_id> "
-    "<section_id>Sxxxxxx</section_id> <has_highlight>0</has_highlight>"
-    "<labels> </labels> "
-    "<attributes> "
-    "<attribute> "
-    "<name>favicon_url</name> <value>http://www.google.com/favicon.ico</value> "
-    "</attribute> "
-    "<attribute> "
-    "<name>favicon_timestamp</name> <value>1153328653</value> "
-    "</attribute> "
-    "<attribute> <name>notebook_name</name> <value>My notebook 0</value> "
-    "</attribute> "
-    "<attribute> <name>section_name</name> <value>My section 0 "
-    "</value> </attribute> </attributes> "
-    "</bookmark> </bookmarks>";
-static const char* kGoodBookmarkTwoLabels =
-    "<?xml version=\"1.0\" ?> <xml_api_reply version=\"1\"> <bookmarks>"
-    " <bookmark> "
-    "<title>MyTitle</title> "
-    "<url>http://www.google.com/</url> "
-    "<timestamp>1153328691085181</timestamp> "
-    "<id>N123nasdf239</id> <notebook_id>Bxxxxxxx</notebook_id> "
-    "<section_id>Sxxxxxx</section_id> <has_highlight>0</has_highlight>"
-    "<labels> <label>Google</label> <label>Homepage</label> </labels> "
-    "<attributes> "
-    "<attribute> "
-    "<name>favicon_url</name> <value>http://www.google.com/favicon.ico</value> "
-    "</attribute> "
-    "<attribute> "
-    "<name>favicon_timestamp</name> <value>1153328653</value> "
-    "</attribute> "
-    "<attribute> <name>notebook_name</name> <value>My notebook 0</value> "
-    "</attribute> "
-    "<attribute> <name>section_name</name> <value>My section 0 "
-    "</value> </attribute> </attributes> "
-    "</bookmark> </bookmarks>";
-static const char* kGoodBookmarkFolderLabel =
-    "<?xml version=\"1.0\" ?> <xml_api_reply version=\"1\"> <bookmarks>"
-    " <bookmark> "
-    "<title>MyTitle</title> "
-    "<url>http://www.google.com/</url> "
-    "<timestamp>1153328691085181</timestamp> "
-    "<id>N123nasdf239</id> <notebook_id>Bxxxxxxx</notebook_id> "
-    "<section_id>Sxxxxxx</section_id> <has_highlight>0</has_highlight>"
-    "<labels> <label>Google:Search:Page</label> </labels> "
-    "<attributes> "
-    "<attribute> "
-    "<name>favicon_url</name> <value>http://www.google.com/favicon.ico</value> "
-    "</attribute> "
-    "<attribute> "
-    "<name>favicon_timestamp</name> <value>1153328653</value> "
-    "</attribute> "
-    "<attribute> <name>notebook_name</name> <value>My notebook 0</value> "
-    "</attribute> "
-    "<attribute> <name>section_name</name> <value>My section 0 "
-    "</value> </attribute> </attributes> "
-    "</bookmark> </bookmarks>";
-static const char* kGoodBookmarkNoFavicon =
-    "<?xml version=\"1.0\" ?> <xml_api_reply version=\"1\"> <bookmarks>"
-    " <bookmark> "
-    "<title>MyTitle</title> "
-    "<url>http://www.google.com/</url> "
-    "<timestamp>1153328691085181</timestamp> "
-    "<id>N123nasdf239</id> <notebook_id>Bxxxxxxx</notebook_id> "
-    "<section_id>Sxxxxxx</section_id> <has_highlight>0</has_highlight>"
-    "<labels> <label>Google</label> </labels> "
-    "<attributes> "
-    "<attribute> "
-    "<name>favicon_timestamp</name> <value>1153328653</value> "
-    "</attribute> "
-    "<attribute> <name>notebook_name</name> <value>My notebook 0</value> "
-    "</attribute> "
-    "<attribute> <name>section_name</name> <value>My section 0 "
-    "</value> </attribute> </attributes> "
-    "</bookmark> </bookmarks>";
-static const char* kGoodBookmark2Items =
-    "<?xml version=\"1.0\" ?> <xml_api_reply version=\"1\"> <bookmarks>"
-    " <bookmark> "
-    "<title>MyTitle</title> "
-    "<url>http://www.google.com/</url> "
-    "<timestamp>1153328691085181</timestamp> "
-    "<id>N123nasdf239</id> <notebook_id>Bxxxxxxx</notebook_id> "
-    "<section_id>Sxxxxxx</section_id> <has_highlight>0</has_highlight>"
-    "<labels> <label>Google</label> </labels> "
-    "<attributes> "
-    "<attribute> "
-    "<name>favicon_url</name> <value>http://www.google.com/favicon.ico</value> "
-    "</attribute> "
-    "<attribute> "
-    "<name>favicon_timestamp</name> <value>1153328653</value> "
-    "</attribute> "
-    "<attribute> <name>notebook_name</name> <value>My notebook 0</value> "
-    "</attribute> "
-    "<attribute> <name>section_name</name> <value>My section 0 "
-    "</value> </attribute> </attributes> "
-    "</bookmark>"
-    " <bookmark> "
-    "<title>MyOtherTitle</title> "
-    "<url>http://www.google.com/mail</url> "
-    "<timestamp>1153328691085181</timestamp> "
-    "<id>N123nasdf239</id> <notebook_id>Bxxxxxxx</notebook_id> "
-    "<section_id>Sxxxxxx</section_id> <has_highlight>0</has_highlight>"
-    "<labels> <label>Mail</label> </labels> "
-    "<attributes> "
-    "<attribute> "
-    "<name>favicon_url</name>"
-    "<value>http://www.google.com/mail/favicon.ico</value> "
-    "</attribute> "
-    "<attribute> "
-    "<name>favicon_timestamp</name> <value>1253328653</value> "
-    "</attribute> "
-    "<attribute> <name>notebook_name</name> <value>My notebook 0</value> "
-    "</attribute> "
-    "<attribute> <name>section_name</name> <value>My section 0 "
-    "</value> </attribute> </attributes> "
-    "</bookmark>"
-    "</bookmarks>";
-static const char* kEmptyString = "";
-static const char* kBadBookmarkNoBookmarks =
-    " <bookmark> "
-    "<title>MyTitle</title> "
-    "<url>http://www.google.com/</url> "
-    "<timestamp>1153328691085181</timestamp> "
-    "<id>N123nasdf239</id> <notebook_id>Bxxxxxxx</notebook_id> "
-    "<section_id>Sxxxxxx</section_id> <has_highlight>0</has_highlight>"
-    "<labels> <label>Google</label> </labels> "
-    "<attributes> "
-    "<attribute> "
-    "<name>favicon_url</name> <value>http://www.google.com/favicon.ico</value> "
-    "</attribute> "
-    "<attribute> "
-    "<name>favicon_timestamp</name> <value>1153328653</value> "
-    "</attribute> "
-    "<attribute> <name>notebook_name</name> <value>My notebook 0</value> "
-    "</attribute> "
-    "<attribute> <name>section_name</name> <value>My section 0 "
-    "</value> </attribute> </attributes> "
-    "</bookmark> </bookmarks>";
-static const char* kBadBookmarkNoBookmark =
-    "<?xml version=\"1.0\" ?> <xml_api_reply version=\"1\"> <bookmarks>"
-    "<title>MyTitle</title> "
-    "<url>http://www.google.com/</url> "
-    "<timestamp>1153328691085181</timestamp> "
-    "<id>N123nasdf239</id> <notebook_id>Bxxxxxxx</notebook_id> "
-    "<section_id>Sxxxxxx</section_id> <has_highlight>0</has_highlight>"
-    "<labels> <label>Google</label> </labels> "
-    "<attributes> "
-    "<attribute> "
-    "<name>favicon_url</name> <value>http://www.google.com/favicon.ico</value> "
-    "</attribute> "
-    "<attribute> "
-    "<name>favicon_timestamp</name> <value>1153328653</value> "
-    "</attribute> "
-    "<attribute> <name>notebook_name</name> <value>My notebook 0</value> "
-    "</attribute> "
-    "<attribute> <name>section_name</name> <value>My section 0 "
-    "</value> </attribute> </attributes> "
-    "</bookmark> </bookmarks>";
-static const char* kBadBookmarkNoTitle =
-    "<?xml version=\"1.0\" ?> <xml_api_reply version=\"1\"> <bookmarks>"
-    " <bookmark> "
-    "<url>http://www.google.com/</url> "
-    "<timestamp>1153328691085181</timestamp> "
-    "<id>N123nasdf239</id> <notebook_id>Bxxxxxxx</notebook_id> "
-    "<section_id>Sxxxxxx</section_id> <has_highlight>0</has_highlight>"
-    "<labels> <label>Google</label> </labels> "
-    "<attributes> "
-    "<attribute> "
-    "<name>favicon_url</name> <value>http://www.google.com/favicon.ico</value> "
-    "</attribute> "
-    "<attribute> "
-    "<name>favicon_timestamp</name> <value>1153328653</value> "
-    "</attribute> "
-    "<attribute> <name>notebook_name</name> <value>My notebook 0</value> "
-    "</attribute> "
-    "<attribute> <name>section_name</name> <value>My section 0 "
-    "</value> </attribute> </attributes> "
-    "</bookmark> </bookmarks>";
-static const char* kBadBookmarkNoUrl =
-    "<?xml version=\"1.0\" ?> <xml_api_reply version=\"1\"> <bookmarks>"
-    " <bookmark> "
-    "<title>MyTitle</title> "
-    "<timestamp>1153328691085181</timestamp> "
-    "<id>N123nasdf239</id> <notebook_id>Bxxxxxxx</notebook_id> "
-    "<section_id>Sxxxxxx</section_id> <has_highlight>0</has_highlight>"
-    "<labels> <label>Google</label> </labels> "
-    "<attributes> "
-    "<attribute> "
-    "<name>favicon_url</name> <value>http://www.google.com/favicon.ico</value> "
-    "</attribute> "
-    "<attribute> "
-    "<name>favicon_timestamp</name> <value>1153328653</value> "
-    "</attribute> "
-    "<attribute> <name>notebook_name</name> <value>My notebook 0</value> "
-    "</attribute> "
-    "<attribute> <name>section_name</name> <value>My section 0 "
-    "</value> </attribute> </attributes> "
-    "</bookmark> </bookmarks>";
-static const char* kBadBookmarkNoTimestamp =
-    "<?xml version=\"1.0\" ?> <xml_api_reply version=\"1\"> <bookmarks>"
-    " <bookmark> "
-    "<title>MyTitle</title> "
-    "<url>http://www.google.com/</url> "
-    "<id>N123nasdf239</id> <notebook_id>Bxxxxxxx</notebook_id> "
-    "<section_id>Sxxxxxx</section_id> <has_highlight>0</has_highlight>"
-    "<labels> <label>Google</label> </labels> "
-    "<attributes> "
-    "<attribute> "
-    "<name>favicon_url</name> <value>http://www.google.com/favicon.ico</value> "
-    "</attribute> "
-    "<attribute> "
-    "<name>favicon_timestamp</name> <value>1153328653</value> "
-    "</attribute> "
-    "<attribute> <name>notebook_name</name> <value>My notebook 0</value> "
-    "</attribute> "
-    "<attribute> <name>section_name</name> <value>My section 0 "
-    "</value> </attribute> </attributes> "
-    "</bookmark> </bookmarks>";
-static const char* kBadBookmarkNoLabels =
-    "<?xml version=\"1.0\" ?> <xml_api_reply version=\"1\"> <bookmarks>"
-    " <bookmark> "
-    "<title>MyTitle</title> "
-    "<url>http://www.google.com/</url> "
-    "<timestamp>1153328691085181</timestamp> "
-    "<id>N123nasdf239</id> <notebook_id>Bxxxxxxx</notebook_id> "
-    "<section_id>Sxxxxxx</section_id> <has_highlight>0</has_highlight>"
-    "<attributes> "
-    "<attribute> "
-    "<name>favicon_url</name> <value>http://www.google.com/favicon.ico</value> "
-    "</attribute> "
-    "<attribute> "
-    "<name>favicon_timestamp</name> <value>1153328653</value> "
-    "</attribute> "
-    "<attribute> <name>notebook_name</name> <value>My notebook 0</value> "
-    "</attribute> "
-    "<attribute> <name>section_name</name> <value>My section 0 "
-    "</value> </attribute> </attributes> "
-    "</bookmark> </bookmarks>";
-
-  XmlReader reader;
-  std::string bookmark_xml;
-  std::vector<ImportedBookmarkEntry> bookmarks;
-
-  const GURL url(kUrl);
-  const GURL other_url(kOtherUrl);
-
-  // Test doesn't work if the importer thinks this is the first run of Chromium.
-  // Mark this as a subsequent run of the browser.
-  first_run::internal::first_run_ = first_run::internal::FIRST_RUN_FALSE;
-
-  // Test case 1 is parsing a basic bookmark with a single label.
-  bookmark_xml = kGoodBookmark;
-  bookmarks.clear();
-  XmlReader reader1;
-  EXPECT_TRUE(reader1.Load(bookmark_xml));
-  EXPECT_TRUE(Toolbar5Importer::ParseBookmarksFromReader(&reader1, &bookmarks,
-      kBookmarkGroupTitle));
-
-  ASSERT_EQ(1U, bookmarks.size());
-  EXPECT_FALSE(bookmarks[0].in_toolbar);
-  EXPECT_EQ(kTitle, bookmarks[0].title);
-  EXPECT_EQ(url, bookmarks[0].url);
-  ASSERT_EQ(2U, bookmarks[0].path.size());
-  EXPECT_EQ(kFolder, bookmarks[0].path[1]);
-
-  // Test case 2 is parsing a single bookmark with no label.
-  bookmark_xml = kGoodBookmarkNoLabel;
-  bookmarks.clear();
-  XmlReader reader2;
-  EXPECT_TRUE(reader2.Load(bookmark_xml));
-  EXPECT_TRUE(Toolbar5Importer::ParseBookmarksFromReader(&reader2, &bookmarks,
-      kBookmarkGroupTitle));
-
-  ASSERT_EQ(1U, bookmarks.size());
-  EXPECT_FALSE(bookmarks[0].in_toolbar);
-  EXPECT_EQ(kTitle, bookmarks[0].title);
-  EXPECT_EQ(url, bookmarks[0].url);
-  EXPECT_EQ(1U, bookmarks[0].path.size());
-
-  // Test case 3 is parsing a single bookmark with two labels.
-  bookmark_xml = kGoodBookmarkTwoLabels;
-  bookmarks.clear();
-  XmlReader reader3;
-  EXPECT_TRUE(reader3.Load(bookmark_xml));
-  EXPECT_TRUE(Toolbar5Importer::ParseBookmarksFromReader(&reader3, &bookmarks,
-      kBookmarkGroupTitle));
-
-  ASSERT_EQ(2U, bookmarks.size());
-  EXPECT_FALSE(bookmarks[0].in_toolbar);
-  EXPECT_FALSE(bookmarks[1].in_toolbar);
-  EXPECT_EQ(kTitle, bookmarks[0].title);
-  EXPECT_EQ(kTitle, bookmarks[1].title);
-  EXPECT_EQ(url, bookmarks[0].url);
-  EXPECT_EQ(url, bookmarks[1].url);
-  ASSERT_EQ(2U, bookmarks[0].path.size());
-  EXPECT_EQ(kFolder, bookmarks[0].path[1]);
-  ASSERT_EQ(2U, bookmarks[1].path.size());
-  EXPECT_EQ(kFolder2, bookmarks[1].path[1]);
-
-  // Test case 4 is parsing a single bookmark which has a label with a colon,
-  // this test file name translation between Toolbar and Chrome.
-  bookmark_xml = kGoodBookmarkFolderLabel;
-  bookmarks.clear();
-  XmlReader reader4;
-  EXPECT_TRUE(reader4.Load(bookmark_xml));
-  EXPECT_TRUE(Toolbar5Importer::ParseBookmarksFromReader(&reader4, &bookmarks,
-      kBookmarkGroupTitle));
-
-  ASSERT_EQ(1U, bookmarks.size());
-  EXPECT_FALSE(bookmarks[0].in_toolbar);
-  EXPECT_EQ(kTitle, bookmarks[0].title);
-  EXPECT_EQ(url, bookmarks[0].url);
-  ASSERT_EQ(4U, bookmarks[0].path.size());
-  EXPECT_EQ(string16(kFolderArray[0]),
-            bookmarks[0].path[1]);
-  EXPECT_EQ(string16(kFolderArray[1]),
-            bookmarks[0].path[2]);
-  EXPECT_EQ(string16(kFolderArray[2]),
-            bookmarks[0].path[3]);
-
-  // Test case 5 is parsing a single bookmark without a favicon URL.
-  bookmark_xml = kGoodBookmarkNoFavicon;
-  bookmarks.clear();
-  XmlReader reader5;
-  EXPECT_TRUE(reader5.Load(bookmark_xml));
-  EXPECT_TRUE(Toolbar5Importer::ParseBookmarksFromReader(&reader5, &bookmarks,
-      kBookmarkGroupTitle));
-
-  ASSERT_EQ(1U, bookmarks.size());
-  EXPECT_FALSE(bookmarks[0].in_toolbar);
-  EXPECT_EQ(kTitle, bookmarks[0].title);
-  EXPECT_EQ(url, bookmarks[0].url);
-  ASSERT_EQ(2U, bookmarks[0].path.size());
-  EXPECT_EQ(kFolder, bookmarks[0].path[1]);
-
-  // Test case 6 is parsing two bookmarks.
-  bookmark_xml = kGoodBookmark2Items;
-  bookmarks.clear();
-  XmlReader reader6;
-  EXPECT_TRUE(reader6.Load(bookmark_xml));
-  EXPECT_TRUE(Toolbar5Importer::ParseBookmarksFromReader(&reader6, &bookmarks,
-      kBookmarkGroupTitle));
-
-  ASSERT_EQ(2U, bookmarks.size());
-  EXPECT_FALSE(bookmarks[0].in_toolbar);
-  EXPECT_FALSE(bookmarks[1].in_toolbar);
-  EXPECT_EQ(kTitle, bookmarks[0].title);
-  EXPECT_EQ(kOtherTitle, bookmarks[1].title);
-  EXPECT_EQ(url, bookmarks[0].url);
-  EXPECT_EQ(other_url, bookmarks[1].url);
-  ASSERT_EQ(2U, bookmarks[0].path.size());
-  EXPECT_EQ(kFolder, bookmarks[0].path[1]);
-  ASSERT_EQ(2U, bookmarks[1].path.size());
-  EXPECT_EQ(kOtherFolder, bookmarks[1].path[1]);
-
-  // Test case 7 is parsing an empty string for bookmarks.
-  bookmark_xml = kEmptyString;
-  bookmarks.clear();
-  XmlReader reader7;
-  EXPECT_FALSE(reader7.Load(bookmark_xml));
-
-  // Test case 8 is testing the error when no <bookmarks> section is present.
-  bookmark_xml = kBadBookmarkNoBookmarks;
-  bookmarks.clear();
-  XmlReader reader8;
-  EXPECT_TRUE(reader8.Load(bookmark_xml));
-  EXPECT_FALSE(Toolbar5Importer::ParseBookmarksFromReader(&reader8,
-      &bookmarks, kBookmarkGroupTitle));
-
-  // Test case 9 tests when no <bookmark> section is present.
-  bookmark_xml = kBadBookmarkNoBookmark;
-  bookmarks.clear();
-  XmlReader reader9;
-  EXPECT_TRUE(reader9.Load(bookmark_xml));
-  EXPECT_FALSE(Toolbar5Importer::ParseBookmarksFromReader(&reader9,
-      &bookmarks, kBookmarkGroupTitle));
-
-
-  // Test case 10 tests when a bookmark has no <title> section.
-  bookmark_xml = kBadBookmarkNoTitle;
-  bookmarks.clear();
-  XmlReader reader10;
-  EXPECT_TRUE(reader10.Load(bookmark_xml));
-  EXPECT_FALSE(Toolbar5Importer::ParseBookmarksFromReader(&reader10,
-      &bookmarks, kBookmarkGroupTitle));
-
-  // Test case 11 tests when a bookmark has no <url> section.
-  bookmark_xml = kBadBookmarkNoUrl;
-  bookmarks.clear();
-  XmlReader reader11;
-  EXPECT_TRUE(reader11.Load(bookmark_xml));
-  EXPECT_FALSE(Toolbar5Importer::ParseBookmarksFromReader(&reader11,
-      &bookmarks, kBookmarkGroupTitle));
-
-  // Test case 12 tests when a bookmark has no <timestamp> section.
-  bookmark_xml = kBadBookmarkNoTimestamp;
-  bookmarks.clear();
-  XmlReader reader12;
-  EXPECT_TRUE(reader12.Load(bookmark_xml));
-  EXPECT_FALSE(Toolbar5Importer::ParseBookmarksFromReader(&reader12,
-      &bookmarks, kBookmarkGroupTitle));
-
-  // Test case 13 tests when a bookmark has no <labels> section.
-  bookmark_xml = kBadBookmarkNoLabels;
-  bookmarks.clear();
-  XmlReader reader13;
-  EXPECT_TRUE(reader13.Load(bookmark_xml));
-  EXPECT_FALSE(Toolbar5Importer::ParseBookmarksFromReader(&reader13,
-      &bookmarks, kBookmarkGroupTitle));
-}
diff --git a/chrome/browser/importer/toolbar_importer_utils.cc b/chrome/browser/importer/toolbar_importer_utils.cc
deleted file mode 100644
index 81f2854..0000000
--- a/chrome/browser/importer/toolbar_importer_utils.cc
+++ /dev/null
@@ -1,79 +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/importer/toolbar_importer_utils.h"
-
-#include <string>
-#include <vector>
-
-#include "base/bind.h"
-#include "base/strings/string_split.h"
-#include "chrome/browser/profiles/profile.h"
-#include "content/public/browser/browser_thread.h"
-#include "googleurl/src/gurl.h"
-#include "net/cookies/cookie_store.h"
-#include "net/url_request/url_request_context.h"
-#include "net/url_request/url_request_context_getter.h"
-
-using content::BrowserThread;
-
-namespace {
-const char kGoogleDomainUrl[] = "http://.google.com/";
-const char kGoogleDomainSecureCookieId[] = "SID=";
-const char kSplitStringToken = ';';
-}
-
-namespace toolbar_importer_utils {
-
-void OnGetCookies(const base::Callback<void(bool)>& callback,
-                  const std::string& cookies) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  std::vector<std::string> cookie_list;
-  base::SplitString(cookies, kSplitStringToken, &cookie_list);
-  for (std::vector<std::string>::iterator current = cookie_list.begin();
-       current != cookie_list.end();
-       ++current) {
-    size_t position = (*current).find(kGoogleDomainSecureCookieId);
-    if (position == 0) {
-      callback.Run(true);
-      return;
-    }
-  }
-  callback.Run(false);
-}
-
-void OnFetchComplete(const base::Callback<void(bool)>& callback,
-                     const std::string& cookies) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-  BrowserThread::PostTask(
-      BrowserThread::UI, FROM_HERE,
-      base::Bind(&OnGetCookies, callback, cookies));
-}
-
-void FetchCookiesOnIOThread(
-    const base::Callback<void(bool)>& callback,
-    net::URLRequestContextGetter* context_getter) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-  net::CookieStore* store = context_getter->
-      GetURLRequestContext()->cookie_store();
-  GURL url(kGoogleDomainUrl);
-  net::CookieOptions options;
-  options.set_include_httponly();  // The SID cookie might be httponly.
-  store->GetCookiesWithOptionsAsync(
-      url, options,
-      base::Bind(&toolbar_importer_utils::OnFetchComplete, callback));
-}
-
-void IsGoogleGAIACookieInstalled(const base::Callback<void(bool)>& callback,
-                                 Profile* profile) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  if (!callback.is_null()) {
-    BrowserThread::PostTask(
-        BrowserThread::IO, FROM_HERE,
-        base::Bind(&FetchCookiesOnIOThread,
-                   callback, base::Unretained(profile->GetRequestContext())));
-  }
-}
-
-}  // namespace toolbar_importer_utils
diff --git a/chrome/browser/importer/toolbar_importer_utils.h b/chrome/browser/importer/toolbar_importer_utils.h
deleted file mode 100644
index ca89363..0000000
--- a/chrome/browser/importer/toolbar_importer_utils.h
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_IMPORTER_TOOLBAR_IMPORTER_UTILS_H_
-#define CHROME_BROWSER_IMPORTER_TOOLBAR_IMPORTER_UTILS_H_
-
-#include "base/callback_forward.h"
-
-class Profile;
-
-namespace toolbar_importer_utils {
-
-// Currently the only configuration information we need is to check whether or
-// not the user currently has their GAIA cookie.  This is done by the function
-// exposed through the ToolbarImportUtils namespace.
-void IsGoogleGAIACookieInstalled(const base::Callback<void(bool)>& callback,
-                                 Profile* profile);
-
-}  // namespace toolbar_importer_utils
-
-#endif  // CHROME_BROWSER_IMPORTER_TOOLBAR_IMPORTER_UTILS_H_
diff --git a/chrome/browser/importer/toolbar_importer_utils_browsertest.cc b/chrome/browser/importer/toolbar_importer_utils_browsertest.cc
deleted file mode 100644
index 1d71fca..0000000
--- a/chrome/browser/importer/toolbar_importer_utils_browsertest.cc
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/bind.h"
-#include "base/message_loop.h"
-#include "chrome/browser/importer/toolbar_importer_utils.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/test/base/in_process_browser_test.h"
-#include "chrome/test/base/ui_test_utils.h"
-
-namespace {
-
-class ToolbarImporterUtilsTest : public InProcessBrowserTest {
- public:
-  ToolbarImporterUtilsTest() : did_run_(false) {
-  }
-
-  void Callback(bool result) {
-    DCHECK(!result);
-    did_run_ = true;
-    base::MessageLoop::current()->Quit();
-  }
-
- protected:
-  bool did_run_;
-};
-
-IN_PROC_BROWSER_TEST_F(ToolbarImporterUtilsTest, NoCrash) {
-  // Regression test for http://crbug.com/89752
-  toolbar_importer_utils::IsGoogleGAIACookieInstalled(
-      base::Bind(&ToolbarImporterUtilsTest::Callback,
-                 base::Unretained(this)),
-      browser()->profile());
-  if (!did_run_) {
-    content::RunMessageLoop();
-  }
-  ASSERT_TRUE(did_run_);
-}
-
-}  // namespace
diff --git a/chrome/browser/infobars/infobar.cc b/chrome/browser/infobars/infobar.cc
index 8a37ced..079b571 100644
--- a/chrome/browser/infobars/infobar.cc
+++ b/chrome/browser/infobars/infobar.cc
@@ -37,7 +37,7 @@
 }
 
 // TODO(pkasting): Port Mac to use this.
-#if defined(TOOLKIT_VIEWS) || defined(TOOLKIT_GTK)
+#if defined(TOOLKIT_VIEWS) || defined(TOOLKIT_GTK) || defined(OS_ANDROID)
 
 InfoBar::InfoBar(InfoBarService* owner, InfoBarDelegate* delegate)
     : owner_(owner),
@@ -188,4 +188,4 @@
   }
 }
 
-#endif  // TOOLKIT_VIEWS || TOOLKIT_GTK
+#endif  // TOOLKIT_VIEWS || TOOLKIT_GTK || OS_ANDROID
diff --git a/chrome/browser/infobars/infobar.h b/chrome/browser/infobars/infobar.h
index eab823e..1c0fbb9 100644
--- a/chrome/browser/infobars/infobar.h
+++ b/chrome/browser/infobars/infobar.h
@@ -27,7 +27,7 @@
 typedef std::pair<InfoBarDelegate*, InfoBarDelegate*> InfoBarReplacedDetails;
 
 // TODO(pkasting): Port Mac to use this.
-#if defined(TOOLKIT_VIEWS) || defined(TOOLKIT_GTK)
+#if defined(TOOLKIT_VIEWS) || defined(TOOLKIT_GTK) || defined(OS_ANDROID)
 
 class InfoBarContainer;
 class InfoBarService;
diff --git a/chrome/browser/infobars/infobar_container.cc b/chrome/browser/infobars/infobar_container.cc
index bb13a07..9b8ce11 100644
--- a/chrome/browser/infobars/infobar_container.cc
+++ b/chrome/browser/infobars/infobar_container.cc
@@ -5,7 +5,7 @@
 #include "build/build_config.h"
 
 // TODO(pkasting): Port Mac to use this.
-#if defined(TOOLKIT_VIEWS) || defined(TOOLKIT_GTK)
+#if defined(TOOLKIT_VIEWS) || defined(TOOLKIT_GTK) || defined(OS_ANDROID)
 
 #include "chrome/browser/infobars/infobar_container.h"
 
@@ -265,4 +265,4 @@
           first_infobar_animation.GetCurrentValue());
 }
 
-#endif  // TOOLKIT_VIEWS || defined(TOOLKIT_GTK)
+#endif  // TOOLKIT_VIEWS || defined(TOOLKIT_GTK) || defined(OS_ANDROID)
diff --git a/chrome/browser/infobars/infobar_container.h b/chrome/browser/infobars/infobar_container.h
index c9d9ce2..0f2b241 100644
--- a/chrome/browser/infobars/infobar_container.h
+++ b/chrome/browser/infobars/infobar_container.h
@@ -8,7 +8,7 @@
 #include <vector>
 
 #include "base/compiler_specific.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/ui/search/search_model_observer.h"
 #include "chrome/common/search_types.h"
 #include "content/public/browser/notification_observer.h"
diff --git a/chrome/browser/infobars/infobars_browsertest.cc b/chrome/browser/infobars/infobars_browsertest.cc
index a9baaba..6b2c481 100644
--- a/chrome/browser/infobars/infobars_browsertest.cc
+++ b/chrome/browser/infobars/infobars_browsertest.cc
@@ -17,7 +17,7 @@
 #include "chrome/test/base/ui_test_utils.h"
 #include "chrome/test/ui/ui_test.h"
 #include "content/public/browser/notification_service.h"
-#include "net/test/spawned_test_server/spawned_test_server.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
 
 class InfoBarsTest : public InProcessBrowserTest {
  public:
@@ -51,10 +51,10 @@
 };
 
 IN_PROC_BROWSER_TEST_F(InfoBarsTest, TestInfoBarsCloseOnNewTheme) {
-  ASSERT_TRUE(test_server()->Start());
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
 
   ui_test_utils::NavigateToURL(
-      browser(), test_server()->GetURL("files/simple.html"));
+      browser(), embedded_test_server()->GetURL("/simple.html"));
 
   content::WindowedNotificationObserver infobar_added_1(
         chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_ADDED,
@@ -63,7 +63,7 @@
   infobar_added_1.Wait();
 
   ui_test_utils::NavigateToURLWithDisposition(
-      browser(), test_server()->GetURL("files/simple.html"),
+      browser(), embedded_test_server()->GetURL("/simple.html"),
       NEW_FOREGROUND_TAB, ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
   content::WindowedNotificationObserver infobar_added_2(
         chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_ADDED,
diff --git a/chrome/browser/internal_auth.cc b/chrome/browser/internal_auth.cc
index 0c4fad0..ed8ff26 100644
--- a/chrome/browser/internal_auth.cc
+++ b/chrome/browser/internal_auth.cc
@@ -15,7 +15,7 @@
 #include "base/strings/string_util.h"
 #include "base/synchronization/lock.h"
 #include "base/threading/thread_checker.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "base/values.h"
 #include "crypto/hmac.h"
 
diff --git a/chrome/browser/internal_auth_unittest.cc b/chrome/browser/internal_auth_unittest.cc
index 143b151..c504bd9 100644
--- a/chrome/browser/internal_auth_unittest.cc
+++ b/chrome/browser/internal_auth_unittest.cc
@@ -8,7 +8,7 @@
 
 #include "base/lazy_instance.h"
 #include "base/message_loop.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace chrome {
diff --git a/chrome/browser/intranet_redirect_detector.h b/chrome/browser/intranet_redirect_detector.h
index 68ef522..2a84791 100644
--- a/chrome/browser/intranet_redirect_detector.h
+++ b/chrome/browser/intranet_redirect_detector.h
@@ -12,10 +12,10 @@
 #include "base/memory/weak_ptr.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
-#include "googleurl/src/gurl.h"
 #include "net/base/network_change_notifier.h"
 #include "net/dns/host_resolver_proc.h"
 #include "net/url_request/url_fetcher_delegate.h"
+#include "url/gurl.h"
 
 class PrefRegistrySimple;
 
diff --git a/chrome/browser/invalidation/fake_invalidation_service.cc b/chrome/browser/invalidation/fake_invalidation_service.cc
new file mode 100644
index 0000000..a54a581
--- /dev/null
+++ b/chrome/browser/invalidation/fake_invalidation_service.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 "chrome/browser/invalidation/fake_invalidation_service.h"
+
+#include "chrome/browser/invalidation/invalidation_service_util.h"
+
+namespace invalidation {
+
+FakeInvalidationService::FakeInvalidationService()
+    : client_id_(GenerateInvalidatorClientId()) {
+}
+
+FakeInvalidationService::~FakeInvalidationService() {
+}
+
+void FakeInvalidationService::RegisterInvalidationHandler(
+      syncer::InvalidationHandler* handler) {
+  invalidator_registrar_.RegisterHandler(handler);
+}
+
+void FakeInvalidationService::UpdateRegisteredInvalidationIds(
+      syncer::InvalidationHandler* handler,
+      const syncer::ObjectIdSet& ids) {
+  invalidator_registrar_.UpdateRegisteredIds(handler, ids);
+}
+
+void FakeInvalidationService::UnregisterInvalidationHandler(
+      syncer::InvalidationHandler* handler) {
+  invalidator_registrar_.UnregisterHandler(handler);
+}
+
+void FakeInvalidationService::AcknowledgeInvalidation(
+      const invalidation::ObjectId& id,
+      const syncer::AckHandle& ack_handle) {
+  // TODO(sync): Use assertions to ensure this function is invoked correctly.
+}
+
+syncer::InvalidatorState FakeInvalidationService::GetInvalidatorState() const {
+  return syncer::INVALIDATIONS_ENABLED;
+}
+
+std::string FakeInvalidationService::GetInvalidatorClientId() const {
+  return client_id_;
+}
+
+void FakeInvalidationService::EmitInvalidationForTest(
+      const invalidation::ObjectId& object_id,
+      const std::string& payload) {
+  syncer::ObjectIdInvalidationMap invalidation_map;
+
+  syncer::Invalidation inv;
+  inv.payload = payload;
+  inv.ack_handle = syncer::AckHandle::CreateUnique();
+
+  invalidation_map.insert(std::make_pair(object_id, inv));
+
+  invalidator_registrar_.DispatchInvalidationsToHandlers(invalidation_map);
+}
+
+}  // namespace invalidation
diff --git a/chrome/browser/invalidation/fake_invalidation_service.h b/chrome/browser/invalidation/fake_invalidation_service.h
new file mode 100644
index 0000000..50aa619
--- /dev/null
+++ b/chrome/browser/invalidation/fake_invalidation_service.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 CHROME_BROWSER_INVALIDATION_FAKE_INVALIDATION_SERVICE_H_
+#define CHROME_BROWSER_INVALIDATION_FAKE_INVALIDATION_SERVICE_H_
+
+#include "chrome/browser/invalidation/invalidation_service.h"
+#include "sync/notifier/invalidator_registrar.h"
+
+namespace invalidation {
+
+// An InvalidationService that emits invalidations only when
+// its EmitInvalidationForTest method is called.
+class FakeInvalidationService : public InvalidationService {
+ public:
+  FakeInvalidationService();
+  virtual ~FakeInvalidationService();
+
+  virtual void RegisterInvalidationHandler(
+      syncer::InvalidationHandler* handler) OVERRIDE;
+  virtual void UpdateRegisteredInvalidationIds(
+      syncer::InvalidationHandler* handler,
+      const syncer::ObjectIdSet& ids) OVERRIDE;
+  virtual void UnregisterInvalidationHandler(
+      syncer::InvalidationHandler* handler) OVERRIDE;
+
+  virtual void AcknowledgeInvalidation(
+      const invalidation::ObjectId& id,
+      const syncer::AckHandle& ack_handle) OVERRIDE;
+
+  virtual syncer::InvalidatorState GetInvalidatorState() const OVERRIDE;
+  virtual std::string GetInvalidatorClientId() const OVERRIDE;
+
+  void EmitInvalidationForTest(
+      const invalidation::ObjectId& object_id,
+      const std::string& payload);
+
+ private:
+  std::string client_id_;
+  syncer::InvalidatorRegistrar invalidator_registrar_;
+
+  DISALLOW_COPY_AND_ASSIGN(FakeInvalidationService);
+};
+
+}  // namespace invalidation
+
+#endif  // CHROME_BROWSER_INVALIDATION_FAKE_INVALIDATION_SERVICE_H_
diff --git a/chrome/browser/invalidation/invalidation_frontend.h b/chrome/browser/invalidation/invalidation_frontend.h
deleted file mode 100644
index f8b61a5..0000000
--- a/chrome/browser/invalidation/invalidation_frontend.h
+++ /dev/null
@@ -1,95 +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_INVALIDATION_INVALIDATION_FRONTEND_H_
-#define CHROME_BROWSER_INVALIDATION_INVALIDATION_FRONTEND_H_
-
-#include "sync/notifier/invalidation_util.h"
-#include "sync/notifier/invalidator_state.h"
-
-namespace syncer {
-class InvalidationHandler;
-class AckHandle;
-}  // namespace syncer
-
-namespace invalidation {
-
-// Interface for classes that handle invalidation registrations and send out
-// invalidations to register handlers.
-//
-// Invalidation clients should follow the pattern below:
-//
-// When starting the client:
-//
-//   frontend->RegisterInvalidationHandler(client_handler);
-//
-// When the set of IDs to register changes for the client during its lifetime
-// (i.e., between calls to RegisterInvalidationHandler(client_handler) and
-// UnregisterInvalidationHandler(client_handler):
-//
-//   frontend->UpdateRegisteredInvalidationIds(client_handler, client_ids);
-//
-// To unregister for all invalidations:
-//
-//   frontend->UnregisterInvalidationHandler(client_handler);
-//
-// If an invalidation handler cares about the invalidator state, it should also
-// do the following when starting the client:
-//
-//   invalidator_state = frontend->GetInvalidatorState();
-//
-// It can also do the above in OnInvalidatorStateChange(), or it can use the
-// argument to OnInvalidatorStateChange().
-//
-// It is an error to have registered handlers when an InvalidationFrontend is
-// shut down; clients must ensure that they unregister themselves before then.
-//
-// TODO(rlarocque): This class should extend BrowserContextKeyedService.
-//
-// NOTE(akalin): Invalidations that come in during browser shutdown may get
-// dropped.  This won't matter once we have an Acknowledge API, though: see
-// http://crbug.com/78462 and http://crbug.com/124149.
-class InvalidationFrontend {
- public:
-  // Starts sending notifications to |handler|.  |handler| must not be NULL,
-  // and it must not already be registered.
-  //
-  // Handler registrations are persisted across restarts of sync.
-  virtual void RegisterInvalidationHandler(
-      syncer::InvalidationHandler* handler) = 0;
-
-  // Updates the set of ObjectIds associated with |handler|.  |handler| must
-  // not be NULL, and must already be registered.  An ID must be registered for
-  // at most one handler.
-  //
-  // Registered IDs are persisted across restarts of sync.
-  virtual void UpdateRegisteredInvalidationIds(
-      syncer::InvalidationHandler* handler,
-      const syncer::ObjectIdSet& ids) = 0;
-
-  // Stops sending notifications to |handler|.  |handler| must not be NULL, and
-  // it must already be registered.  Note that this doesn't unregister the IDs
-  // associated with |handler|.
-  //
-  // Handler registrations are persisted across restarts of sync.
-  virtual void UnregisterInvalidationHandler(
-      syncer::InvalidationHandler* handler) = 0;
-
-  // Sends an acknowledgement that an invalidation for |id| was successfully
-  // handled.
-  virtual void AcknowledgeInvalidation(const invalidation::ObjectId& id,
-                                       const syncer::AckHandle& ack_handle) = 0;
-
-  // Returns the current invalidator state.  When called from within
-  // InvalidationHandler::OnInvalidatorStateChange(), this must return
-  // the updated state.
-  virtual syncer::InvalidatorState GetInvalidatorState() const = 0;
-
- protected:
-  virtual ~InvalidationFrontend() { }
-};
-
-}  // namespace invalidation
-
-#endif  // CHROME_BROWSER_INVALIDATION_INVALIDATION_FRONTEND_H_
diff --git a/chrome/browser/invalidation/invalidation_frontend_test_template.cc b/chrome/browser/invalidation/invalidation_frontend_test_template.cc
deleted file mode 100644
index b454623..0000000
--- a/chrome/browser/invalidation/invalidation_frontend_test_template.cc
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/invalidation/invalidation_frontend_test_template.h"
-
-namespace internal {
-
-BoundFakeInvalidationHandler::BoundFakeInvalidationHandler(
-    const invalidation::InvalidationFrontend& invalidator)
-    : invalidator_(invalidator),
-      last_retrieved_state_(syncer::DEFAULT_INVALIDATION_ERROR) {}
-
-BoundFakeInvalidationHandler::~BoundFakeInvalidationHandler() {}
-
-syncer::InvalidatorState
-BoundFakeInvalidationHandler::GetLastRetrievedState() const {
-  return last_retrieved_state_;
-}
-
-void BoundFakeInvalidationHandler::OnInvalidatorStateChange(
-    syncer::InvalidatorState state) {
-  FakeInvalidationHandler::OnInvalidatorStateChange(state);
-  last_retrieved_state_ = invalidator_.GetInvalidatorState();
-}
-
-}
diff --git a/chrome/browser/invalidation/invalidation_frontend_test_template.h b/chrome/browser/invalidation/invalidation_frontend_test_template.h
deleted file mode 100644
index 9643504..0000000
--- a/chrome/browser/invalidation/invalidation_frontend_test_template.h
+++ /dev/null
@@ -1,384 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// This class defines tests that implementations of InvalidationFrontend should
-// pass in order to be conformant.  Here's how you use it to test your
-// implementation.
-//
-// Say your class is called MyInvalidationFrontend.  Then you need to define a
-// class called MyInvalidationFrontendTestDelegate in
-// my_invalidation_frontend_unittest.cc like this:
-//
-//   class MyInvalidationFrontendTestDelegate {
-//    public:
-//     MyInvalidationFrontendTestDelegate() ...
-//
-//     ~MyInvalidationFrontendTestDelegate() {
-//       // DestroyInvalidator() may not be explicitly called by tests.
-//       DestroyInvalidator();
-//     }
-//
-//     // Create the InvalidationFrontend implementation with the given params.
-//     void CreateInvalidationFrontend() {
-//       ...
-//     }
-//
-//     // Should return the InvalidationFrontend implementation.  Only called
-//     // after CreateInvalidator and before DestroyInvalidator.
-//     MyInvalidationFrontend* GetInvalidationFrontend() {
-//       ...
-//     }
-//
-//     // Destroy the InvalidationFrontend implementation.
-//     void DestroyInvalidationFrontend() {
-//       ...
-//     }
-//
-//     // The Trigger* functions below should block until the effects of
-//     // the call are visible on the current thread.
-//
-//     // Should cause OnInvalidatorStateChange() to be called on all
-//     // observers of the InvalidationFrontend implementation with the given
-//     // parameters.
-//     void TriggerOnInvalidatorStateChange(InvalidatorState state) {
-//       ...
-//     }
-//
-//     // Should cause OnIncomingInvalidation() to be called on all
-//     // observers of the InvalidationFrontend implementation with the given
-//     // parameters.
-//     void TriggerOnIncomingInvalidation(
-//         const ObjectIdInvalidationMap& invalidation_map) {
-//       ...
-//     }
-//   };
-//
-// The InvalidationFrontendTest test harness will have a member variable of
-// this delegate type and will call its functions in the various
-// tests.
-//
-// Then you simply #include this file as well as gtest.h and add the
-// following statement to my_sync_notifier_unittest.cc:
-//
-//   INSTANTIATE_TYPED_TEST_CASE_P(
-//       MyInvalidationFrontend,
-//       InvalidationFrontendTest,
-//       MyInvalidatorTestDelegate);
-//
-// Easy!
-
-#ifndef CHROME_BROWSER_INVALIDATION_INVALIDATION_FRONTEND_TEST_TEMPLATE_H_
-#define CHROME_BROWSER_INVALIDATION_INVALIDATION_FRONTEND_TEST_TEMPLATE_H_
-
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "chrome/browser/invalidation/invalidation_frontend.h"
-#include "google/cacheinvalidation/include/types.h"
-#include "google/cacheinvalidation/types.pb.h"
-#include "sync/notifier/fake_invalidation_handler.h"
-#include "sync/notifier/object_id_invalidation_map.h"
-#include "sync/notifier/object_id_invalidation_map_test_util.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-template <typename InvalidatorTestDelegate>
-class InvalidationFrontendTest : public testing::Test {
- protected:
-  // Note: The IDs defined below must be valid.  Otherwise they won't make it
-  // through the round-trip to ModelTypeInvalidationMap and back that the
-  // AndroidInvalidation test requires.
-  InvalidationFrontendTest()
-      : id1(ipc::invalidation::ObjectSource::CHROME_SYNC, "BOOKMARK"),
-        id2(ipc::invalidation::ObjectSource::CHROME_SYNC, "PREFERENCE"),
-        id3(ipc::invalidation::ObjectSource::CHROME_SYNC, "AUTOFILL"),
-        id4(ipc::invalidation::ObjectSource::CHROME_SYNC, "EXPERIMENTS") {
-  }
-
-  invalidation::InvalidationFrontend*
-  CreateAndInitializeInvalidationFrontend() {
-    this->delegate_.CreateInvalidationFrontend();
-    return this->delegate_.GetInvalidationFrontend();
-  }
-
-  InvalidatorTestDelegate delegate_;
-
-  const invalidation::ObjectId id1;
-  const invalidation::ObjectId id2;
-  const invalidation::ObjectId id3;
-  const invalidation::ObjectId id4;
-};
-
-TYPED_TEST_CASE_P(InvalidationFrontendTest);
-
-// Initialize the invalidator, register a handler, register some IDs for that
-// handler, and then unregister the handler, dispatching invalidations in
-// between.  The handler should only see invalidations when its registered and
-// its IDs are registered.
-TYPED_TEST_P(InvalidationFrontendTest, Basic) {
-  invalidation::InvalidationFrontend* const invalidator =
-      this->CreateAndInitializeInvalidationFrontend();
-
-  syncer::FakeInvalidationHandler handler;
-
-  invalidator->RegisterInvalidationHandler(&handler);
-
-  syncer::ObjectIdInvalidationMap states;
-  states[this->id1].payload = "1";
-  states[this->id2].payload = "2";
-  states[this->id3].payload = "3";
-
-  // Should be ignored since no IDs are registered to |handler|.
-  this->delegate_.TriggerOnIncomingInvalidation(states);
-  EXPECT_EQ(0, handler.GetInvalidationCount());
-
-  syncer::ObjectIdSet ids;
-  ids.insert(this->id1);
-  ids.insert(this->id2);
-  invalidator->UpdateRegisteredInvalidationIds(&handler, ids);
-
-  this->delegate_.TriggerOnInvalidatorStateChange(
-      syncer::INVALIDATIONS_ENABLED);
-  EXPECT_EQ(syncer::INVALIDATIONS_ENABLED, handler.GetInvalidatorState());
-
-  syncer::ObjectIdInvalidationMap expected_states;
-  expected_states[this->id1].payload = "1";
-  expected_states[this->id2].payload = "2";
-
-  this->delegate_.TriggerOnIncomingInvalidation(states);
-  EXPECT_EQ(1, handler.GetInvalidationCount());
-  EXPECT_THAT(expected_states, Eq(handler.GetLastInvalidationMap()));
-
-  ids.erase(this->id1);
-  ids.insert(this->id3);
-  invalidator->UpdateRegisteredInvalidationIds(&handler, ids);
-
-  expected_states.erase(this->id1);
-  expected_states[this->id3].payload = "3";
-
-  // Removed object IDs should not be notified, newly-added ones should.
-  this->delegate_.TriggerOnIncomingInvalidation(states);
-  EXPECT_EQ(2, handler.GetInvalidationCount());
-  EXPECT_THAT(expected_states, Eq(handler.GetLastInvalidationMap()));
-
-  this->delegate_.TriggerOnInvalidatorStateChange(
-      syncer::TRANSIENT_INVALIDATION_ERROR);
-  EXPECT_EQ(syncer::TRANSIENT_INVALIDATION_ERROR,
-            handler.GetInvalidatorState());
-
-  this->delegate_.TriggerOnInvalidatorStateChange(
-      syncer::INVALIDATION_CREDENTIALS_REJECTED);
-  EXPECT_EQ(syncer::INVALIDATION_CREDENTIALS_REJECTED,
-            handler.GetInvalidatorState());
-
-  invalidator->UnregisterInvalidationHandler(&handler);
-
-  // Should be ignored since |handler| isn't registered anymore.
-  this->delegate_.TriggerOnIncomingInvalidation(states);
-  EXPECT_EQ(2, handler.GetInvalidationCount());
-}
-
-// Register handlers and some IDs for those handlers, register a handler with
-// no IDs, and register a handler with some IDs but unregister it.  Then,
-// dispatch some invalidations and invalidations.  Handlers that are registered
-// should get invalidations, and the ones that have registered IDs should
-// receive invalidations for those IDs.
-TYPED_TEST_P(InvalidationFrontendTest, MultipleHandlers) {
-  invalidation::InvalidationFrontend* const invalidator =
-      this->CreateAndInitializeInvalidationFrontend();
-
-  syncer::FakeInvalidationHandler handler1;
-  syncer::FakeInvalidationHandler handler2;
-  syncer::FakeInvalidationHandler handler3;
-  syncer::FakeInvalidationHandler handler4;
-
-  invalidator->RegisterInvalidationHandler(&handler1);
-  invalidator->RegisterInvalidationHandler(&handler2);
-  invalidator->RegisterInvalidationHandler(&handler3);
-  invalidator->RegisterInvalidationHandler(&handler4);
-
-  {
-    syncer::ObjectIdSet ids;
-    ids.insert(this->id1);
-    ids.insert(this->id2);
-    invalidator->UpdateRegisteredInvalidationIds(&handler1, ids);
-  }
-
-  {
-    syncer::ObjectIdSet ids;
-    ids.insert(this->id3);
-    invalidator->UpdateRegisteredInvalidationIds(&handler2, ids);
-  }
-
-  // Don't register any IDs for handler3.
-
-  {
-    syncer::ObjectIdSet ids;
-    ids.insert(this->id4);
-    invalidator->UpdateRegisteredInvalidationIds(&handler4, ids);
-  }
-
-  invalidator->UnregisterInvalidationHandler(&handler4);
-
-  this->delegate_.TriggerOnInvalidatorStateChange(
-      syncer::INVALIDATIONS_ENABLED);
-  EXPECT_EQ(syncer::INVALIDATIONS_ENABLED, handler1.GetInvalidatorState());
-  EXPECT_EQ(syncer::INVALIDATIONS_ENABLED, handler2.GetInvalidatorState());
-  EXPECT_EQ(syncer::INVALIDATIONS_ENABLED, handler3.GetInvalidatorState());
-  EXPECT_EQ(syncer::TRANSIENT_INVALIDATION_ERROR,
-            handler4.GetInvalidatorState());
-
-  {
-    syncer::ObjectIdInvalidationMap states;
-    states[this->id1].payload = "1";
-    states[this->id2].payload = "2";
-    states[this->id3].payload = "3";
-    states[this->id4].payload = "4";
-    this->delegate_.TriggerOnIncomingInvalidation(states);
-
-    syncer::ObjectIdInvalidationMap expected_states;
-    expected_states[this->id1].payload = "1";
-    expected_states[this->id2].payload = "2";
-
-    EXPECT_EQ(1, handler1.GetInvalidationCount());
-    EXPECT_THAT(expected_states, Eq(handler1.GetLastInvalidationMap()));
-
-    expected_states.clear();
-    expected_states[this->id3].payload = "3";
-
-    EXPECT_EQ(1, handler2.GetInvalidationCount());
-    EXPECT_THAT(expected_states, Eq(handler2.GetLastInvalidationMap()));
-
-    EXPECT_EQ(0, handler3.GetInvalidationCount());
-    EXPECT_EQ(0, handler4.GetInvalidationCount());
-  }
-
-  this->delegate_.TriggerOnInvalidatorStateChange(
-      syncer::TRANSIENT_INVALIDATION_ERROR);
-  EXPECT_EQ(syncer::TRANSIENT_INVALIDATION_ERROR,
-            handler1.GetInvalidatorState());
-  EXPECT_EQ(syncer::TRANSIENT_INVALIDATION_ERROR,
-            handler2.GetInvalidatorState());
-  EXPECT_EQ(syncer::TRANSIENT_INVALIDATION_ERROR,
-            handler3.GetInvalidatorState());
-  EXPECT_EQ(syncer::TRANSIENT_INVALIDATION_ERROR,
-            handler4.GetInvalidatorState());
-
-  invalidator->UnregisterInvalidationHandler(&handler3);
-  invalidator->UnregisterInvalidationHandler(&handler2);
-  invalidator->UnregisterInvalidationHandler(&handler1);
-}
-
-// Make sure that passing an empty set to UpdateRegisteredInvalidationIds clears
-// the corresponding entries for the handler.
-TYPED_TEST_P(InvalidationFrontendTest, EmptySetUnregisters) {
-  invalidation::InvalidationFrontend* const invalidator =
-      this->CreateAndInitializeInvalidationFrontend();
-
-  syncer::FakeInvalidationHandler handler1;
-
-  // Control observer.
-  syncer::FakeInvalidationHandler handler2;
-
-  invalidator->RegisterInvalidationHandler(&handler1);
-  invalidator->RegisterInvalidationHandler(&handler2);
-
-  {
-    syncer::ObjectIdSet ids;
-    ids.insert(this->id1);
-    ids.insert(this->id2);
-    invalidator->UpdateRegisteredInvalidationIds(&handler1, ids);
-  }
-
-  {
-    syncer::ObjectIdSet ids;
-    ids.insert(this->id3);
-    invalidator->UpdateRegisteredInvalidationIds(&handler2, ids);
-  }
-
-  // Unregister the IDs for the first observer. It should not receive any
-  // further invalidations.
-  invalidator->UpdateRegisteredInvalidationIds(&handler1,
-                                               syncer::ObjectIdSet());
-
-  this->delegate_.TriggerOnInvalidatorStateChange(
-      syncer::INVALIDATIONS_ENABLED);
-  EXPECT_EQ(syncer::INVALIDATIONS_ENABLED, handler1.GetInvalidatorState());
-  EXPECT_EQ(syncer::INVALIDATIONS_ENABLED, handler2.GetInvalidatorState());
-
-  {
-    syncer::ObjectIdInvalidationMap states;
-    states[this->id1].payload = "1";
-    states[this->id2].payload = "2";
-    states[this->id3].payload = "3";
-    this->delegate_.TriggerOnIncomingInvalidation(states);
-    EXPECT_EQ(0, handler1.GetInvalidationCount());
-    EXPECT_EQ(1, handler2.GetInvalidationCount());
-  }
-
-  this->delegate_.TriggerOnInvalidatorStateChange(
-      syncer::TRANSIENT_INVALIDATION_ERROR);
-  EXPECT_EQ(syncer::TRANSIENT_INVALIDATION_ERROR,
-            handler1.GetInvalidatorState());
-  EXPECT_EQ(syncer::TRANSIENT_INVALIDATION_ERROR,
-            handler2.GetInvalidatorState());
-
-  invalidator->UnregisterInvalidationHandler(&handler2);
-  invalidator->UnregisterInvalidationHandler(&handler1);
-}
-
-namespace internal {
-
-// A FakeInvalidationHandler that is "bound" to a specific
-// InvalidationFrontend.  This is for cross-referencing state information with
-// the bound InvalidationFrontend.
-class BoundFakeInvalidationHandler : public syncer::FakeInvalidationHandler {
- public:
-  explicit BoundFakeInvalidationHandler(
-      const invalidation::InvalidationFrontend& invalidator);
-  virtual ~BoundFakeInvalidationHandler();
-
-  // Returns the last return value of GetInvalidatorState() on the
-  // bound invalidator from the last time the invalidator state
-  // changed.
-  syncer::InvalidatorState GetLastRetrievedState() const;
-
-  // InvalidationHandler implementation.
-  virtual void OnInvalidatorStateChange(
-      syncer::InvalidatorState state) OVERRIDE;
-
- private:
-  const invalidation::InvalidationFrontend& invalidator_;
-  syncer::InvalidatorState last_retrieved_state_;
-
-  DISALLOW_COPY_AND_ASSIGN(BoundFakeInvalidationHandler);
-};
-
-}  // namespace internal
-
-TYPED_TEST_P(InvalidationFrontendTest, GetInvalidatorStateAlwaysCurrent) {
-  invalidation::InvalidationFrontend* const invalidator =
-      this->CreateAndInitializeInvalidationFrontend();
-
-  internal::BoundFakeInvalidationHandler handler(*invalidator);
-  invalidator->RegisterInvalidationHandler(&handler);
-
-  this->delegate_.TriggerOnInvalidatorStateChange(
-      syncer::INVALIDATIONS_ENABLED);
-  EXPECT_EQ(syncer::INVALIDATIONS_ENABLED, handler.GetInvalidatorState());
-  EXPECT_EQ(syncer::INVALIDATIONS_ENABLED, handler.GetLastRetrievedState());
-
-  this->delegate_.TriggerOnInvalidatorStateChange(
-      syncer::TRANSIENT_INVALIDATION_ERROR);
-  EXPECT_EQ(syncer::TRANSIENT_INVALIDATION_ERROR,
-            handler.GetInvalidatorState());
-  EXPECT_EQ(syncer::TRANSIENT_INVALIDATION_ERROR,
-            handler.GetLastRetrievedState());
-
-  invalidator->UnregisterInvalidationHandler(&handler);
-}
-
-REGISTER_TYPED_TEST_CASE_P(InvalidationFrontendTest,
-                           Basic, MultipleHandlers, EmptySetUnregisters,
-                           GetInvalidatorStateAlwaysCurrent);
-
-#endif  // CHROME_BROWSER_INVALIDATION_INVALIDATION_FRONTEND_TEST_TEMPLATE_H_
diff --git a/chrome/browser/invalidation/invalidation_service.h b/chrome/browser/invalidation/invalidation_service.h
new file mode 100644
index 0000000..7ee0b73
--- /dev/null
+++ b/chrome/browser/invalidation/invalidation_service.h
@@ -0,0 +1,114 @@
+// 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_INVALIDATION_INVALIDATION_SERVICE_H_
+#define CHROME_BROWSER_INVALIDATION_INVALIDATION_SERVICE_H_
+
+#include "components/browser_context_keyed_service/browser_context_keyed_service.h"
+#include "sync/notifier/invalidation_util.h"
+#include "sync/notifier/invalidator_state.h"
+
+namespace syncer {
+class InvalidationHandler;
+class AckHandle;
+}  // namespace syncer
+
+namespace invalidation {
+
+// Interface for classes that handle invalidation registrations and send out
+// invalidations to register handlers.
+//
+// Invalidation clients should follow the pattern below:
+//
+// When starting the client:
+//
+//   frontend->RegisterInvalidationHandler(client_handler);
+//
+// When the set of IDs to register changes for the client during its lifetime
+// (i.e., between calls to RegisterInvalidationHandler(client_handler) and
+// UnregisterInvalidationHandler(client_handler):
+//
+//   frontend->UpdateRegisteredInvalidationIds(client_handler, client_ids);
+//
+// When shutting down the client for browser shutdown:
+//
+//   frontend->UnregisterInvalidationHandler(client_handler);
+//
+// Note that there's no call to UpdateRegisteredIds() -- this is because the
+// invalidation API persists registrations across browser restarts.
+//
+// When permanently shutting down the client, e.g. when disabling the related
+// feature:
+//
+//   frontend->UpdateRegisteredInvalidationIds(client_handler, ObjectIdSet());
+//   frontend->UnregisterInvalidationHandler(client_handler);
+//
+// If an invalidation handler cares about the invalidator state, it should also
+// do the following when starting the client:
+//
+//   invalidator_state = frontend->GetInvalidatorState();
+//
+// It can also do the above in OnInvalidatorStateChange(), or it can use the
+// argument to OnInvalidatorStateChange().
+//
+// It is an error to have registered handlers when an
+// InvalidationFrontend is shut down; clients must ensure that they
+// unregister themselves before then. (Depending on the
+// InvalidationFrontend, shutdown may be equivalent to destruction, or
+// a separate function call like Shutdown()).
+//
+// NOTE(akalin): Invalidations that come in during browser shutdown may get
+// dropped.  This won't matter once we have an Acknowledge API, though: see
+// http://crbug.com/78462 and http://crbug.com/124149.
+//
+// This class inherits from ProfileKeyedService to make it possible to correctly
+// cast from various InvalidationService implementations to ProfileKeyedService
+// in InvalidationServiceFactory.
+class InvalidationService : public BrowserContextKeyedService {
+ public:
+  // Starts sending notifications to |handler|.  |handler| must not be NULL,
+  // and it must not already be registered.
+  //
+  // Handler registrations are persisted across restarts of sync.
+  virtual void RegisterInvalidationHandler(
+      syncer::InvalidationHandler* handler) = 0;
+
+  // Updates the set of ObjectIds associated with |handler|.  |handler| must
+  // not be NULL, and must already be registered.  An ID must be registered for
+  // at most one handler.
+  //
+  // Registered IDs are persisted across restarts of sync.
+  virtual void UpdateRegisteredInvalidationIds(
+      syncer::InvalidationHandler* handler,
+      const syncer::ObjectIdSet& ids) = 0;
+
+  // Stops sending notifications to |handler|.  |handler| must not be NULL, and
+  // it must already be registered.  Note that this doesn't unregister the IDs
+  // associated with |handler|.
+  //
+  // Handler registrations are persisted across restarts of sync.
+  virtual void UnregisterInvalidationHandler(
+      syncer::InvalidationHandler* handler) = 0;
+
+  // Sends an acknowledgement that an invalidation for |id| was successfully
+  // handled.
+  virtual void AcknowledgeInvalidation(const invalidation::ObjectId& id,
+                                       const syncer::AckHandle& ack_handle) = 0;
+
+  // Returns the current invalidator state.  When called from within
+  // InvalidationHandler::OnInvalidatorStateChange(), this must return
+  // the updated state.
+  virtual syncer::InvalidatorState GetInvalidatorState() const = 0;
+
+  // Returns the ID belonging to this invalidation client.  Can be used to
+  // prevent the receipt of notifications of our own changes.
+  virtual std::string GetInvalidatorClientId() const = 0;
+
+ protected:
+  virtual ~InvalidationService() { }
+};
+
+}  // namespace invalidation
+
+#endif  // CHROME_BROWSER_INVALIDATION_INVALIDATION_SERVICE_H_
diff --git a/chrome/browser/invalidation/invalidation_service_android.h b/chrome/browser/invalidation/invalidation_service_android.h
index 6daef6a..244b1e7 100644
--- a/chrome/browser/invalidation/invalidation_service_android.h
+++ b/chrome/browser/invalidation/invalidation_service_android.h
@@ -8,7 +8,7 @@
 #include "base/basictypes.h"
 #include "base/compiler_specific.h"
 #include "base/threading/non_thread_safe.h"
-#include "chrome/browser/invalidation/invalidation_frontend.h"
+#include "chrome/browser/invalidation/invalidation_service.h"
 #include "components/browser_context_keyed_service/browser_context_keyed_service.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
@@ -24,8 +24,7 @@
 // around Android's invalidations service.
 class InvalidationServiceAndroid
     : public base::NonThreadSafe,
-      public BrowserContextKeyedService,
-      public InvalidationFrontend,
+      public InvalidationService,
       public content::NotificationObserver {
  public:
   explicit InvalidationServiceAndroid(Profile* profile);
@@ -47,7 +46,7 @@
       const invalidation::ObjectId& id,
       const syncer::AckHandle& ack_handle) OVERRIDE;
   virtual syncer::InvalidatorState GetInvalidatorState() const OVERRIDE;
-  virtual std::string GetInvalidatorClientId() const;
+  virtual std::string GetInvalidatorClientId() const OVERRIDE;
 
   // content::NotificationObserver implementation.
   virtual void Observe(int type,
diff --git a/chrome/browser/invalidation/invalidation_service_android_unittest.cc b/chrome/browser/invalidation/invalidation_service_android_unittest.cc
index feadf24..9e332b2 100644
--- a/chrome/browser/invalidation/invalidation_service_android_unittest.cc
+++ b/chrome/browser/invalidation/invalidation_service_android_unittest.cc
@@ -4,8 +4,8 @@
 
 #include "chrome/browser/invalidation/invalidation_service_android.h"
 
-#include "chrome/browser/invalidation/invalidation_frontend_test_template.h"
 #include "chrome/browser/invalidation/invalidation_service_factory.h"
+#include "chrome/browser/invalidation/invalidation_service_test_template.h"
 #include "chrome/common/chrome_notification_types.h"
 #include "chrome/test/base/testing_profile.h"
 #include "content/public/browser/notification_service.h"
@@ -18,20 +18,20 @@
   InvalidationServiceAndroidTestDelegate() { }
 
   ~InvalidationServiceAndroidTestDelegate() {
-    DestroyInvalidationFrontend();
+    DestroyInvalidationService();
   }
 
-  void CreateInvalidationFrontend() {
+  void CreateInvalidationService() {
     profile_.reset(new TestingProfile());
     invalidation_service_android_.reset(
         new InvalidationServiceAndroid(profile_.get()));
   }
 
-  InvalidationFrontend* GetInvalidationFrontend() {
+  InvalidationService* GetInvalidationService() {
     return invalidation_service_android_.get();
   }
 
-  void DestroyInvalidationFrontend() {
+  void DestroyInvalidationService() {
     invalidation_service_android_->Shutdown();
   }
 
@@ -55,7 +55,7 @@
 };
 
 INSTANTIATE_TYPED_TEST_CASE_P(
-    AndroidInvalidationServiceTest, InvalidationFrontendTest,
+    AndroidInvalidationServiceTest, InvalidationServiceTest,
     InvalidationServiceAndroidTestDelegate);
 
 }  // namespace invalidation
diff --git a/chrome/browser/invalidation/invalidation_service_factory.cc b/chrome/browser/invalidation/invalidation_service_factory.cc
index 0fa857b..2085417 100644
--- a/chrome/browser/invalidation/invalidation_service_factory.cc
+++ b/chrome/browser/invalidation/invalidation_service_factory.cc
@@ -4,13 +4,19 @@
 
 #include "chrome/browser/invalidation/invalidation_service_factory.h"
 
-#include "chrome/browser/invalidation/invalidation_frontend.h"
+#include "base/prefs/pref_registry.h"
+#include "chrome/browser/invalidation/fake_invalidation_service.h"
+#include "chrome/browser/invalidation/invalidation_service.h"
 #include "chrome/browser/invalidation/invalidation_service_android.h"
+#include "chrome/browser/invalidation/invalidator_storage.h"
 #include "chrome/browser/invalidation/p2p_invalidation_service.h"
 #include "chrome/browser/invalidation/ticl_invalidation_service.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/signin/profile_oauth2_token_service.h"
+#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
 #include "chrome/browser/signin/signin_manager.h"
 #include "chrome/browser/signin/signin_manager_factory.h"
+#include "chrome/browser/signin/token_service.h"
 #include "chrome/browser/signin/token_service_factory.h"
 #include "components/browser_context_keyed_service/browser_context_dependency_manager.h"
 
@@ -18,14 +24,12 @@
 
 namespace invalidation {
 
-// TODO(rlarocque): Re-enable this once InvalidationFrontend can
-// extend BrowserContextKeyedService.
-// // static
-// InvalidationFrontend* InvalidationServiceFactory::GetForProfile(
-//     Profile* profile) {
-//   return static_cast<InvalidationFrontend*>(
-//       GetInstance()->GetServiceForBrowserContext(profile, true));
-// }
+// static
+InvalidationService* InvalidationServiceFactory::GetForProfile(
+    Profile* profile) {
+  return static_cast<InvalidationService*>(
+      GetInstance()->GetServiceForBrowserContext(profile, true));
+}
 
 // static
 InvalidationServiceFactory* InvalidationServiceFactory::GetInstance() {
@@ -35,24 +39,52 @@
 InvalidationServiceFactory::InvalidationServiceFactory()
     : BrowserContextKeyedServiceFactory(
         "InvalidationService",
-        BrowserContextDependencyManager::GetInstance()) {
+        BrowserContextDependencyManager::GetInstance()),
+      build_fake_invalidators_(false) {
 #if !defined(OS_ANDROID)
   DependsOn(SigninManagerFactory::GetInstance());
-  DependsOn(TokenServiceFactory::GetInstance());
+  DependsOn(ProfileOAuth2TokenServiceFactory::GetInstance());
 #endif
 }
 
 InvalidationServiceFactory::~InvalidationServiceFactory() {}
 
-// static
-BrowserContextKeyedService*
-InvalidationServiceFactory::BuildP2PInvalidationServiceFor(Profile* profile) {
+namespace {
+
+BrowserContextKeyedService* BuildP2PInvalidationService(
+    content::BrowserContext* context) {
+  Profile* profile = static_cast<Profile*>(context);
   return new P2PInvalidationService(profile);
 }
 
+BrowserContextKeyedService* BuildFakeInvalidationService(
+    content::BrowserContext* context) {
+  return new FakeInvalidationService();
+}
+
+}  // namespace
+
+void InvalidationServiceFactory::SetBuildOnlyFakeInvalidatorsForTest(
+    bool test_mode_enabled) {
+  build_fake_invalidators_ = test_mode_enabled;
+}
+
+P2PInvalidationService*
+InvalidationServiceFactory::BuildAndUseP2PInvalidationServiceForTest(
+    content::BrowserContext* context) {
+  BrowserContextKeyedService* service =
+      SetTestingFactoryAndUse(context, BuildP2PInvalidationService);
+  return static_cast<P2PInvalidationService*>(service);
+}
+
 BrowserContextKeyedService* InvalidationServiceFactory::BuildServiceInstanceFor(
     content::BrowserContext* context) const {
   Profile* profile = static_cast<Profile*>(context);
+
+  if (build_fake_invalidators_) {
+    return BuildFakeInvalidationService(context);
+  }
+
 #if defined(OS_ANDROID)
   InvalidationServiceAndroid* service = new InvalidationServiceAndroid(profile);
   return service;
@@ -60,12 +92,22 @@
   SigninManagerBase* signin_manager =
       SigninManagerFactory::GetForProfile(profile);
   TokenService* token_service = TokenServiceFactory::GetForProfile(profile);
+  OAuth2TokenService* oauth2_token_service =
+      ProfileOAuth2TokenServiceFactory::GetForProfile(profile);
 
   TiclInvalidationService* service = new TiclInvalidationService(
-      signin_manager, token_service, profile);
+      signin_manager,
+      token_service,
+      oauth2_token_service,
+      profile);
   service->Init();
   return service;
 #endif
 }
 
+void InvalidationServiceFactory::RegisterUserPrefs(
+    user_prefs::PrefRegistrySyncable* registry) {
+  InvalidatorStorage::RegisterUserPrefs(registry);
+}
+
 }  // namespace invalidation
diff --git a/chrome/browser/invalidation/invalidation_service_factory.h b/chrome/browser/invalidation/invalidation_service_factory.h
index da6900a..fa2828a 100644
--- a/chrome/browser/invalidation/invalidation_service_factory.h
+++ b/chrome/browser/invalidation/invalidation_service_factory.h
@@ -9,15 +9,22 @@
 #include "base/memory/singleton.h"
 #include "components/browser_context_keyed_service/browser_context_keyed_service_factory.h"
 
+namespace user_prefs {
+class PrefRegistrySyncable;
+}
+
 namespace syncer {
 class Invalidator;
 }
 
-class InvalidationFrontend;
 class Profile;
 
 namespace invalidation {
 
+class InvalidationService;
+class P2PInvalidationService;
+class FakeInvalidationService;
+
 // A BrowserContextKeyedServiceFactory to construct InvalidationServices.  The
 // implementation of the InvalidationService may be completely different on
 // different platforms; this class should help to hide this complexity.  It also
@@ -25,16 +32,18 @@
 // on invalidations.
 class InvalidationServiceFactory : public BrowserContextKeyedServiceFactory {
  public:
-  // TODO(rlarocque): Re-enable this once InvalidationFrontend can extend
-  // BrowserContextKeyedService.
-  // static InvalidationFrontend* GetForProfile(Profile* profile);
+  static InvalidationService* GetForProfile(Profile* profile);
 
   static InvalidationServiceFactory* GetInstance();
 
-  static BrowserContextKeyedService* BuildP2PInvalidationServiceFor(
-      Profile* profile);
-  static BrowserContextKeyedService* BuildTestServiceInstanceFor(
-      Profile* profile);
+  // A helper function to set this factory to return FakeInvalidationServices
+  // instead of the default InvalidationService objects.
+  void SetBuildOnlyFakeInvalidatorsForTest(bool test_mode_enabled);
+
+  // These helper functions to set the factory to build a test-only type of
+  // invalidator and return the instance immeidately.
+  P2PInvalidationService* BuildAndUseP2PInvalidationServiceForTest(
+      content::BrowserContext* context);
 
  private:
   friend struct DefaultSingletonTraits<InvalidationServiceFactory>;
@@ -44,10 +53,12 @@
 
   // BrowserContextKeyedServiceFactory:
   virtual BrowserContextKeyedService* BuildServiceInstanceFor(
-      content::BrowserContext* profile) const OVERRIDE;
-  // TODO(rlarocque): Use this class, not InvalidatorStorage, to register
-  // for user prefs.
-  // virtual void RegisterUserPrefs(PrefRegistrySyncable* registry) OVERRIDE;
+      content::BrowserContext* context) const OVERRIDE;
+  virtual void RegisterUserPrefs(
+      user_prefs::PrefRegistrySyncable* registry) OVERRIDE;
+
+  // If true, this factory will return only FakeInvalidationService instances.
+  bool build_fake_invalidators_;
 
   DISALLOW_COPY_AND_ASSIGN(InvalidationServiceFactory);
 };
diff --git a/chrome/browser/invalidation/invalidation_service_test_template.cc b/chrome/browser/invalidation/invalidation_service_test_template.cc
new file mode 100644
index 0000000..1b591e8
--- /dev/null
+++ b/chrome/browser/invalidation/invalidation_service_test_template.cc
@@ -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.
+
+#include "chrome/browser/invalidation/invalidation_service_test_template.h"
+
+namespace internal {
+
+BoundFakeInvalidationHandler::BoundFakeInvalidationHandler(
+    const invalidation::InvalidationService& invalidator)
+    : invalidator_(invalidator),
+      last_retrieved_state_(syncer::DEFAULT_INVALIDATION_ERROR) {}
+
+BoundFakeInvalidationHandler::~BoundFakeInvalidationHandler() {}
+
+syncer::InvalidatorState
+BoundFakeInvalidationHandler::GetLastRetrievedState() const {
+  return last_retrieved_state_;
+}
+
+void BoundFakeInvalidationHandler::OnInvalidatorStateChange(
+    syncer::InvalidatorState state) {
+  FakeInvalidationHandler::OnInvalidatorStateChange(state);
+  last_retrieved_state_ = invalidator_.GetInvalidatorState();
+}
+
+}  // namespace internal
diff --git a/chrome/browser/invalidation/invalidation_service_test_template.h b/chrome/browser/invalidation/invalidation_service_test_template.h
new file mode 100644
index 0000000..baad132
--- /dev/null
+++ b/chrome/browser/invalidation/invalidation_service_test_template.h
@@ -0,0 +1,384 @@
+// 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 class defines tests that implementations of InvalidationService should
+// pass in order to be conformant.  Here's how you use it to test your
+// implementation.
+//
+// Say your class is called MyInvalidationService.  Then you need to define a
+// class called MyInvalidationServiceTestDelegate in
+// my_invalidation_frontend_unittest.cc like this:
+//
+//   class MyInvalidationServiceTestDelegate {
+//    public:
+//     MyInvalidationServiceTestDelegate() ...
+//
+//     ~MyInvalidationServiceTestDelegate() {
+//       // DestroyInvalidator() may not be explicitly called by tests.
+//       DestroyInvalidator();
+//     }
+//
+//     // Create the InvalidationService implementation with the given params.
+//     void CreateInvalidationService() {
+//       ...
+//     }
+//
+//     // Should return the InvalidationService implementation.  Only called
+//     // after CreateInvalidator and before DestroyInvalidator.
+//     MyInvalidationService* GetInvalidationService() {
+//       ...
+//     }
+//
+//     // Destroy the InvalidationService implementation.
+//     void DestroyInvalidationService() {
+//       ...
+//     }
+//
+//     // The Trigger* functions below should block until the effects of
+//     // the call are visible on the current thread.
+//
+//     // Should cause OnInvalidatorStateChange() to be called on all
+//     // observers of the InvalidationService implementation with the given
+//     // parameters.
+//     void TriggerOnInvalidatorStateChange(InvalidatorState state) {
+//       ...
+//     }
+//
+//     // Should cause OnIncomingInvalidation() to be called on all
+//     // observers of the InvalidationService implementation with the given
+//     // parameters.
+//     void TriggerOnIncomingInvalidation(
+//         const ObjectIdInvalidationMap& invalidation_map) {
+//       ...
+//     }
+//   };
+//
+// The InvalidationServiceTest test harness will have a member variable of
+// this delegate type and will call its functions in the various
+// tests.
+//
+// Then you simply #include this file as well as gtest.h and add the
+// following statement to my_sync_notifier_unittest.cc:
+//
+//   INSTANTIATE_TYPED_TEST_CASE_P(
+//       MyInvalidationService,
+//       InvalidationServiceTest,
+//       MyInvalidatorTestDelegate);
+//
+// Easy!
+
+#ifndef CHROME_BROWSER_INVALIDATION_INVALIDATION_SERVICE_TEST_TEMPLATE_H_
+#define CHROME_BROWSER_INVALIDATION_INVALIDATION_SERVICE_TEST_TEMPLATE_H_
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "chrome/browser/invalidation/invalidation_service.h"
+#include "google/cacheinvalidation/include/types.h"
+#include "google/cacheinvalidation/types.pb.h"
+#include "sync/notifier/fake_invalidation_handler.h"
+#include "sync/notifier/object_id_invalidation_map.h"
+#include "sync/notifier/object_id_invalidation_map_test_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+template <typename InvalidatorTestDelegate>
+class InvalidationServiceTest : public testing::Test {
+ protected:
+  // Note: The IDs defined below must be valid.  Otherwise they won't make it
+  // through the round-trip to ModelTypeInvalidationMap and back that the
+  // AndroidInvalidation test requires.
+  InvalidationServiceTest()
+      : id1(ipc::invalidation::ObjectSource::CHROME_SYNC, "BOOKMARK"),
+        id2(ipc::invalidation::ObjectSource::CHROME_SYNC, "PREFERENCE"),
+        id3(ipc::invalidation::ObjectSource::CHROME_SYNC, "AUTOFILL"),
+        id4(ipc::invalidation::ObjectSource::CHROME_SYNC, "EXPERIMENTS") {
+  }
+
+  invalidation::InvalidationService*
+  CreateAndInitializeInvalidationService() {
+    this->delegate_.CreateInvalidationService();
+    return this->delegate_.GetInvalidationService();
+  }
+
+  InvalidatorTestDelegate delegate_;
+
+  const invalidation::ObjectId id1;
+  const invalidation::ObjectId id2;
+  const invalidation::ObjectId id3;
+  const invalidation::ObjectId id4;
+};
+
+TYPED_TEST_CASE_P(InvalidationServiceTest);
+
+// Initialize the invalidator, register a handler, register some IDs for that
+// handler, and then unregister the handler, dispatching invalidations in
+// between.  The handler should only see invalidations when its registered and
+// its IDs are registered.
+TYPED_TEST_P(InvalidationServiceTest, Basic) {
+  invalidation::InvalidationService* const invalidator =
+      this->CreateAndInitializeInvalidationService();
+
+  syncer::FakeInvalidationHandler handler;
+
+  invalidator->RegisterInvalidationHandler(&handler);
+
+  syncer::ObjectIdInvalidationMap states;
+  states[this->id1].payload = "1";
+  states[this->id2].payload = "2";
+  states[this->id3].payload = "3";
+
+  // Should be ignored since no IDs are registered to |handler|.
+  this->delegate_.TriggerOnIncomingInvalidation(states);
+  EXPECT_EQ(0, handler.GetInvalidationCount());
+
+  syncer::ObjectIdSet ids;
+  ids.insert(this->id1);
+  ids.insert(this->id2);
+  invalidator->UpdateRegisteredInvalidationIds(&handler, ids);
+
+  this->delegate_.TriggerOnInvalidatorStateChange(
+      syncer::INVALIDATIONS_ENABLED);
+  EXPECT_EQ(syncer::INVALIDATIONS_ENABLED, handler.GetInvalidatorState());
+
+  syncer::ObjectIdInvalidationMap expected_states;
+  expected_states[this->id1].payload = "1";
+  expected_states[this->id2].payload = "2";
+
+  this->delegate_.TriggerOnIncomingInvalidation(states);
+  EXPECT_EQ(1, handler.GetInvalidationCount());
+  EXPECT_THAT(expected_states, Eq(handler.GetLastInvalidationMap()));
+
+  ids.erase(this->id1);
+  ids.insert(this->id3);
+  invalidator->UpdateRegisteredInvalidationIds(&handler, ids);
+
+  expected_states.erase(this->id1);
+  expected_states[this->id3].payload = "3";
+
+  // Removed object IDs should not be notified, newly-added ones should.
+  this->delegate_.TriggerOnIncomingInvalidation(states);
+  EXPECT_EQ(2, handler.GetInvalidationCount());
+  EXPECT_THAT(expected_states, Eq(handler.GetLastInvalidationMap()));
+
+  this->delegate_.TriggerOnInvalidatorStateChange(
+      syncer::TRANSIENT_INVALIDATION_ERROR);
+  EXPECT_EQ(syncer::TRANSIENT_INVALIDATION_ERROR,
+            handler.GetInvalidatorState());
+
+  this->delegate_.TriggerOnInvalidatorStateChange(
+      syncer::INVALIDATIONS_ENABLED);
+  EXPECT_EQ(syncer::INVALIDATIONS_ENABLED,
+            handler.GetInvalidatorState());
+
+  invalidator->UnregisterInvalidationHandler(&handler);
+
+  // Should be ignored since |handler| isn't registered anymore.
+  this->delegate_.TriggerOnIncomingInvalidation(states);
+  EXPECT_EQ(2, handler.GetInvalidationCount());
+}
+
+// Register handlers and some IDs for those handlers, register a handler with
+// no IDs, and register a handler with some IDs but unregister it.  Then,
+// dispatch some invalidations and invalidations.  Handlers that are registered
+// should get invalidations, and the ones that have registered IDs should
+// receive invalidations for those IDs.
+TYPED_TEST_P(InvalidationServiceTest, MultipleHandlers) {
+  invalidation::InvalidationService* const invalidator =
+      this->CreateAndInitializeInvalidationService();
+
+  syncer::FakeInvalidationHandler handler1;
+  syncer::FakeInvalidationHandler handler2;
+  syncer::FakeInvalidationHandler handler3;
+  syncer::FakeInvalidationHandler handler4;
+
+  invalidator->RegisterInvalidationHandler(&handler1);
+  invalidator->RegisterInvalidationHandler(&handler2);
+  invalidator->RegisterInvalidationHandler(&handler3);
+  invalidator->RegisterInvalidationHandler(&handler4);
+
+  {
+    syncer::ObjectIdSet ids;
+    ids.insert(this->id1);
+    ids.insert(this->id2);
+    invalidator->UpdateRegisteredInvalidationIds(&handler1, ids);
+  }
+
+  {
+    syncer::ObjectIdSet ids;
+    ids.insert(this->id3);
+    invalidator->UpdateRegisteredInvalidationIds(&handler2, ids);
+  }
+
+  // Don't register any IDs for handler3.
+
+  {
+    syncer::ObjectIdSet ids;
+    ids.insert(this->id4);
+    invalidator->UpdateRegisteredInvalidationIds(&handler4, ids);
+  }
+
+  invalidator->UnregisterInvalidationHandler(&handler4);
+
+  this->delegate_.TriggerOnInvalidatorStateChange(
+      syncer::INVALIDATIONS_ENABLED);
+  EXPECT_EQ(syncer::INVALIDATIONS_ENABLED, handler1.GetInvalidatorState());
+  EXPECT_EQ(syncer::INVALIDATIONS_ENABLED, handler2.GetInvalidatorState());
+  EXPECT_EQ(syncer::INVALIDATIONS_ENABLED, handler3.GetInvalidatorState());
+  EXPECT_EQ(syncer::TRANSIENT_INVALIDATION_ERROR,
+            handler4.GetInvalidatorState());
+
+  {
+    syncer::ObjectIdInvalidationMap states;
+    states[this->id1].payload = "1";
+    states[this->id2].payload = "2";
+    states[this->id3].payload = "3";
+    states[this->id4].payload = "4";
+    this->delegate_.TriggerOnIncomingInvalidation(states);
+
+    syncer::ObjectIdInvalidationMap expected_states;
+    expected_states[this->id1].payload = "1";
+    expected_states[this->id2].payload = "2";
+
+    EXPECT_EQ(1, handler1.GetInvalidationCount());
+    EXPECT_THAT(expected_states, Eq(handler1.GetLastInvalidationMap()));
+
+    expected_states.clear();
+    expected_states[this->id3].payload = "3";
+
+    EXPECT_EQ(1, handler2.GetInvalidationCount());
+    EXPECT_THAT(expected_states, Eq(handler2.GetLastInvalidationMap()));
+
+    EXPECT_EQ(0, handler3.GetInvalidationCount());
+    EXPECT_EQ(0, handler4.GetInvalidationCount());
+  }
+
+  this->delegate_.TriggerOnInvalidatorStateChange(
+      syncer::TRANSIENT_INVALIDATION_ERROR);
+  EXPECT_EQ(syncer::TRANSIENT_INVALIDATION_ERROR,
+            handler1.GetInvalidatorState());
+  EXPECT_EQ(syncer::TRANSIENT_INVALIDATION_ERROR,
+            handler2.GetInvalidatorState());
+  EXPECT_EQ(syncer::TRANSIENT_INVALIDATION_ERROR,
+            handler3.GetInvalidatorState());
+  EXPECT_EQ(syncer::TRANSIENT_INVALIDATION_ERROR,
+            handler4.GetInvalidatorState());
+
+  invalidator->UnregisterInvalidationHandler(&handler3);
+  invalidator->UnregisterInvalidationHandler(&handler2);
+  invalidator->UnregisterInvalidationHandler(&handler1);
+}
+
+// Make sure that passing an empty set to UpdateRegisteredInvalidationIds clears
+// the corresponding entries for the handler.
+TYPED_TEST_P(InvalidationServiceTest, EmptySetUnregisters) {
+  invalidation::InvalidationService* const invalidator =
+      this->CreateAndInitializeInvalidationService();
+
+  syncer::FakeInvalidationHandler handler1;
+
+  // Control observer.
+  syncer::FakeInvalidationHandler handler2;
+
+  invalidator->RegisterInvalidationHandler(&handler1);
+  invalidator->RegisterInvalidationHandler(&handler2);
+
+  {
+    syncer::ObjectIdSet ids;
+    ids.insert(this->id1);
+    ids.insert(this->id2);
+    invalidator->UpdateRegisteredInvalidationIds(&handler1, ids);
+  }
+
+  {
+    syncer::ObjectIdSet ids;
+    ids.insert(this->id3);
+    invalidator->UpdateRegisteredInvalidationIds(&handler2, ids);
+  }
+
+  // Unregister the IDs for the first observer. It should not receive any
+  // further invalidations.
+  invalidator->UpdateRegisteredInvalidationIds(&handler1,
+                                               syncer::ObjectIdSet());
+
+  this->delegate_.TriggerOnInvalidatorStateChange(
+      syncer::INVALIDATIONS_ENABLED);
+  EXPECT_EQ(syncer::INVALIDATIONS_ENABLED, handler1.GetInvalidatorState());
+  EXPECT_EQ(syncer::INVALIDATIONS_ENABLED, handler2.GetInvalidatorState());
+
+  {
+    syncer::ObjectIdInvalidationMap states;
+    states[this->id1].payload = "1";
+    states[this->id2].payload = "2";
+    states[this->id3].payload = "3";
+    this->delegate_.TriggerOnIncomingInvalidation(states);
+    EXPECT_EQ(0, handler1.GetInvalidationCount());
+    EXPECT_EQ(1, handler2.GetInvalidationCount());
+  }
+
+  this->delegate_.TriggerOnInvalidatorStateChange(
+      syncer::TRANSIENT_INVALIDATION_ERROR);
+  EXPECT_EQ(syncer::TRANSIENT_INVALIDATION_ERROR,
+            handler1.GetInvalidatorState());
+  EXPECT_EQ(syncer::TRANSIENT_INVALIDATION_ERROR,
+            handler2.GetInvalidatorState());
+
+  invalidator->UnregisterInvalidationHandler(&handler2);
+  invalidator->UnregisterInvalidationHandler(&handler1);
+}
+
+namespace internal {
+
+// A FakeInvalidationHandler that is "bound" to a specific
+// InvalidationService.  This is for cross-referencing state information with
+// the bound InvalidationService.
+class BoundFakeInvalidationHandler : public syncer::FakeInvalidationHandler {
+ public:
+  explicit BoundFakeInvalidationHandler(
+      const invalidation::InvalidationService& invalidator);
+  virtual ~BoundFakeInvalidationHandler();
+
+  // Returns the last return value of GetInvalidatorState() on the
+  // bound invalidator from the last time the invalidator state
+  // changed.
+  syncer::InvalidatorState GetLastRetrievedState() const;
+
+  // InvalidationHandler implementation.
+  virtual void OnInvalidatorStateChange(
+      syncer::InvalidatorState state) OVERRIDE;
+
+ private:
+  const invalidation::InvalidationService& invalidator_;
+  syncer::InvalidatorState last_retrieved_state_;
+
+  DISALLOW_COPY_AND_ASSIGN(BoundFakeInvalidationHandler);
+};
+
+}  // namespace internal
+
+TYPED_TEST_P(InvalidationServiceTest, GetInvalidatorStateAlwaysCurrent) {
+  invalidation::InvalidationService* const invalidator =
+      this->CreateAndInitializeInvalidationService();
+
+  internal::BoundFakeInvalidationHandler handler(*invalidator);
+  invalidator->RegisterInvalidationHandler(&handler);
+
+  this->delegate_.TriggerOnInvalidatorStateChange(
+      syncer::INVALIDATIONS_ENABLED);
+  EXPECT_EQ(syncer::INVALIDATIONS_ENABLED, handler.GetInvalidatorState());
+  EXPECT_EQ(syncer::INVALIDATIONS_ENABLED, handler.GetLastRetrievedState());
+
+  this->delegate_.TriggerOnInvalidatorStateChange(
+      syncer::TRANSIENT_INVALIDATION_ERROR);
+  EXPECT_EQ(syncer::TRANSIENT_INVALIDATION_ERROR,
+            handler.GetInvalidatorState());
+  EXPECT_EQ(syncer::TRANSIENT_INVALIDATION_ERROR,
+            handler.GetLastRetrievedState());
+
+  invalidator->UnregisterInvalidationHandler(&handler);
+}
+
+REGISTER_TYPED_TEST_CASE_P(InvalidationServiceTest,
+                           Basic, MultipleHandlers, EmptySetUnregisters,
+                           GetInvalidatorStateAlwaysCurrent);
+
+#endif  // CHROME_BROWSER_INVALIDATION_INVALIDATION_SERVICE_TEST_TEMPLATE_H_
diff --git a/chrome/browser/invalidation/p2p_invalidation_service.h b/chrome/browser/invalidation/p2p_invalidation_service.h
index b624688..bbb18b9 100644
--- a/chrome/browser/invalidation/p2p_invalidation_service.h
+++ b/chrome/browser/invalidation/p2p_invalidation_service.h
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 #include "base/threading/non_thread_safe.h"
-#include "chrome/browser/invalidation/invalidation_frontend.h"
+#include "chrome/browser/invalidation/invalidation_service.h"
 #include "components/browser_context_keyed_service/browser_context_keyed_service.h"
 #include "sync/notifier/object_id_invalidation_map.h"
 
@@ -23,8 +23,7 @@
 // only in tests, where we're unable to connect to a real invalidations server.
 class P2PInvalidationService
     : public base::NonThreadSafe,
-      public BrowserContextKeyedService,
-      public InvalidationFrontend {
+      public InvalidationService {
  public:
   explicit P2PInvalidationService(Profile* profile);
   virtual ~P2PInvalidationService();
@@ -32,7 +31,7 @@
   // Overrides BrowserContextKeyedService method.
   virtual void Shutdown() OVERRIDE;
 
-  // InvalidationFrontend implementation.
+  // InvalidationService implementation.
   // It is an error to have registered handlers when Shutdown() is called.
   virtual void RegisterInvalidationHandler(
       syncer::InvalidationHandler* handler) OVERRIDE;
@@ -45,7 +44,7 @@
       const invalidation::ObjectId& id,
       const syncer::AckHandle& ack_handle) OVERRIDE;
   virtual syncer::InvalidatorState GetInvalidatorState() const OVERRIDE;
-  virtual std::string GetInvalidatorClientId() const;
+  virtual std::string GetInvalidatorClientId() const OVERRIDE;
 
   void UpdateCredentials(const std::string& username,
                          const std::string& password);
diff --git a/chrome/browser/invalidation/ticl_invalidation_service.cc b/chrome/browser/invalidation/ticl_invalidation_service.cc
index bfee8f0..11a9759 100644
--- a/chrome/browser/invalidation/ticl_invalidation_service.cc
+++ b/chrome/browser/invalidation/ticl_invalidation_service.cc
@@ -6,9 +6,11 @@
 
 #include "base/command_line.h"
 #include "chrome/browser/invalidation/invalidation_service_util.h"
+#include "chrome/browser/managed_mode/managed_user_service.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/signin/profile_oauth2_token_service.h"
+#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
 #include "chrome/browser/signin/signin_manager.h"
-#include "chrome/browser/signin/token_service.h"
 #include "chrome/common/chrome_notification_types.h"
 #include "content/public/browser/notification_service.h"
 #include "google_apis/gaia/gaia_constants.h"
@@ -16,15 +18,52 @@
 #include "sync/notifier/invalidator_state.h"
 #include "sync/notifier/non_blocking_invalidator.h"
 
+static const char* kOAuth2Scopes[] = {
+  GaiaConstants::kGoogleTalkOAuth2Scope
+};
+
+static const net::BackoffEntry::Policy kRequestAccessTokenBackoffPolicy = {
+  // Number of initial errors (in sequence) to ignore before applying
+  // exponential back-off rules.
+  0,
+
+  // Initial delay for exponential back-off in ms.
+  2000,
+
+  // Factor by which the waiting time will be multiplied.
+  2,
+
+  // Fuzzing percentage. ex: 10% will spread requests randomly
+  // between 90%-100% of the calculated time.
+  0.2, // 20%
+
+  // Maximum amount of time we are willing to delay our request in ms.
+  // TODO(pavely): crbug.com/246686 ProfileSyncService should retry
+  // RequestAccessToken on connection state change after backoff
+  1000 * 3600 * 4, // 4 hours.
+
+  // Time to keep an entry from being discarded even when it
+  // has no significant state, -1 to never discard.
+  -1,
+
+  // Don't use initial delay unless the last request was an error.
+  false,
+};
+
 namespace invalidation {
 
-TiclInvalidationService::TiclInvalidationService(SigninManagerBase* signin,
-                                                 TokenService* token_service,
-                                                 Profile* profile)
-  : profile_(profile),
-    signin_manager_(signin),
-    token_service_(token_service),
-    invalidator_registrar_(new syncer::InvalidatorRegistrar()) { }
+TiclInvalidationService::TiclInvalidationService(
+    SigninManagerBase* signin,
+    TokenService* token_service,
+    OAuth2TokenService* oauth2_token_service,
+    Profile* profile)
+    : profile_(profile),
+      signin_manager_(signin),
+      token_service_(token_service),
+      oauth2_token_service_(oauth2_token_service),
+      invalidator_registrar_(new syncer::InvalidatorRegistrar()),
+      request_access_token_backoff_(&kRequestAccessTokenBackoffPolicy) {
+}
 
 TiclInvalidationService::~TiclInvalidationService() {
   DCHECK(CalledOnValidThread());
@@ -41,20 +80,24 @@
   }
 
   if (IsReadyToStart()) {
-    Start();
+    StartInvalidator();
   }
 
   notification_registrar_.Add(this,
+                              chrome::NOTIFICATION_GOOGLE_SIGNED_OUT,
+                              content::Source<Profile>(profile_));
+  notification_registrar_.Add(this,
                               chrome::NOTIFICATION_TOKEN_AVAILABLE,
                               content::Source<TokenService>(token_service_));
   notification_registrar_.Add(this,
-                              chrome::NOTIFICATION_GOOGLE_SIGNED_OUT,
-                              content::Source<Profile>(profile_));
+                              chrome::NOTIFICATION_TOKENS_CLEARED,
+                              content::Source<TokenService>(token_service_));
 }
 
 void TiclInvalidationService::InitForTest(syncer::Invalidator* invalidator) {
-  // Here we perform the equivalent of Init() and Start(), but with some minor
-  // changes to account for the fact that we're injecting the invalidator.
+  // Here we perform the equivalent of Init() and StartInvalidator(), but with
+  // some minor changes to account for the fact that we're injecting the
+  // invalidator.
   invalidator_.reset(invalidator);
 
   invalidator_->RegisterHandler(this);
@@ -129,16 +172,15 @@
 
   switch (type) {
     case chrome::NOTIFICATION_TOKEN_AVAILABLE: {
-      const TokenService::TokenAvailableDetails& token_details =
-          *(content::Details<const TokenService::TokenAvailableDetails>(
-                  details).ptr());
-      if (token_details.service() == GaiaConstants::kSyncService) {
-        DCHECK(IsReadyToStart());
-        if (!IsStarted()) {
-          Start();
-        } else {
-          UpdateToken();
-        }
+      if (!IsStarted() && IsReadyToStart()) {
+        StartInvalidator();
+      }
+      break;
+    }
+    case chrome::NOTIFICATION_TOKENS_CLEARED: {
+      access_token_.clear();
+      if (IsStarted()) {
+        UpdateInvalidatorCredentials();
       }
       break;
     }
@@ -152,6 +194,68 @@
   }
 }
 
+void TiclInvalidationService::RequestAccessToken() {
+  // Only one active request at a time.
+  if (access_token_request_ != NULL)
+    return;
+  request_access_token_retry_timer_.Stop();
+  OAuth2TokenService::ScopeSet oauth2_scopes;
+  for (size_t i = 0; i < arraysize(kOAuth2Scopes); i++)
+    oauth2_scopes.insert(kOAuth2Scopes[i]);
+  // Invalidate previous token, otherwise token service will return the same
+  // token again.
+  oauth2_token_service_->InvalidateToken(oauth2_scopes, access_token_);
+  access_token_.clear();
+  access_token_request_ =
+      oauth2_token_service_->StartRequest(oauth2_scopes, this);
+}
+
+void TiclInvalidationService::OnGetTokenSuccess(
+    const OAuth2TokenService::Request* request,
+    const std::string& access_token,
+    const base::Time& expiration_time) {
+  DCHECK_EQ(access_token_request_, request);
+  access_token_request_.reset();
+  // Reset backoff time after successful response.
+  request_access_token_backoff_.Reset();
+  access_token_ = access_token;
+  if (!IsStarted() && IsReadyToStart()) {
+    StartInvalidator();
+  } else {
+    UpdateInvalidatorCredentials();
+  }
+}
+
+void TiclInvalidationService::OnGetTokenFailure(
+    const OAuth2TokenService::Request* request,
+    const GoogleServiceAuthError& error) {
+  DCHECK_EQ(access_token_request_, request);
+  DCHECK_NE(error.state(), GoogleServiceAuthError::NONE);
+  access_token_request_.reset();
+  switch (error.state()) {
+    case GoogleServiceAuthError::CONNECTION_FAILED:
+    case GoogleServiceAuthError::SERVICE_UNAVAILABLE: {
+      // Transient error. Retry after some time.
+      request_access_token_backoff_.InformOfRequest(false);
+      request_access_token_retry_timer_.Start(
+            FROM_HERE,
+            request_access_token_backoff_.GetTimeUntilRelease(),
+            base::Bind(&TiclInvalidationService::RequestAccessToken,
+                       base::Unretained(this)));
+      break;
+    }
+    case GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS: {
+      // This is a real auth error.
+      invalidator_registrar_->UpdateInvalidatorState(
+          syncer::INVALIDATION_CREDENTIALS_REJECTED);
+      break;
+    }
+    default: {
+      // We have no way to notify the user of this.  Do nothing.
+    }
+  }
+}
+
 void TiclInvalidationService::OnInvalidatorStateChange(
     syncer::InvalidatorState state) {
   invalidator_registrar_->UpdateInvalidatorState(state);
@@ -172,19 +276,25 @@
 }
 
 bool TiclInvalidationService::IsReadyToStart() {
-  if (signin_manager_->GetAuthenticatedUsername().empty()) {
-    DVLOG(2) << "Not starting TiclInvalidationService: user is not signed in.";
+  if (ManagedUserService::ProfileIsManaged(profile_)) {
+    DVLOG(2) << "Not starting TiclInvalidationService: User is managed.";
     return false;
   }
 
-  if (!token_service_) {
+  if (signin_manager_->GetAuthenticatedUsername().empty()) {
+    DVLOG(2) << "Not starting TiclInvalidationService: User is not signed in.";
+    return false;
+  }
+
+  if (!oauth2_token_service_) {
     DVLOG(2)
         << "Not starting TiclInvalidationService: TokenService unavailable.";
     return false;
   }
 
-  if (!token_service_->HasTokenForService(GaiaConstants::kSyncService)) {
-    DVLOG(2) << "Not starting TiclInvalidationService: Sync token unavailable.";
+  if (!oauth2_token_service_->RefreshTokenIsAvailable()) {
+    DVLOG(2)
+        << "Not starting TiclInvalidationServce: Waiting for refresh token.";
     return false;
   }
 
@@ -195,15 +305,24 @@
   return invalidator_.get() != NULL;
 }
 
-void TiclInvalidationService::Start() {
+void TiclInvalidationService::StartInvalidator() {
   DCHECK(CalledOnValidThread());
   DCHECK(!invalidator_);
   DCHECK(invalidator_storage_);
   DCHECK(!invalidator_storage_->GetInvalidatorClientId().empty());
 
+  if (access_token_.empty()) {
+    DVLOG(1)
+        << "TiclInvalidationService: "
+        << "Deferring start until we have an access token.";
+    RequestAccessToken();
+    return;
+  }
+
   notifier::NotifierOptions options =
       ParseNotifierOptions(*CommandLine::ForCurrentProcess());
   options.request_context_getter = profile_->GetRequestContext();
+  options.auth_mechanism = "X-OAUTH2";
   invalidator_.reset(new syncer::NonBlockingInvalidator(
           options,
           invalidator_storage_->GetInvalidatorClientId(),
@@ -213,7 +332,7 @@
               invalidator_storage_->AsWeakPtr()),
           content::GetUserAgent(GURL())));
 
-  UpdateToken();
+  UpdateInvalidatorCredentials();
 
   invalidator_->RegisterHandler(this);
   invalidator_->UpdateRegisteredIds(
@@ -221,16 +340,14 @@
       invalidator_registrar_->GetAllRegisteredIds());
 }
 
-void TiclInvalidationService::UpdateToken() {
+void TiclInvalidationService::UpdateInvalidatorCredentials() {
   std::string email = signin_manager_->GetAuthenticatedUsername();
-  DCHECK(!email.empty()) << "Expected user to be signed in.";
-  DCHECK(token_service_->HasTokenForService(GaiaConstants::kSyncService));
 
-  std::string sync_token = token_service_->GetTokenForService(
-      GaiaConstants::kSyncService);
+  DCHECK(!email.empty()) << "Expected user to be signed in.";
+  DCHECK(!access_token_.empty());
 
   DVLOG(2) << "UpdateCredentials: " << email;
-  invalidator_->UpdateCredentials(email, sync_token);
+  invalidator_->UpdateCredentials(email, access_token_);
 }
 
 void TiclInvalidationService::StopInvalidator() {
@@ -240,7 +357,11 @@
 }
 
 void TiclInvalidationService::Logout() {
-  StopInvalidator();
+  request_access_token_retry_timer_.Stop();
+
+  if (IsStarted()) {
+    StopInvalidator();
+  }
 
   // This service always expects to have a valid invalidator storage.
   // So we must not only clear the old one, but also start a new one.
diff --git a/chrome/browser/invalidation/ticl_invalidation_service.h b/chrome/browser/invalidation/ticl_invalidation_service.h
index dde6606..2403817 100644
--- a/chrome/browser/invalidation/ticl_invalidation_service.h
+++ b/chrome/browser/invalidation/ticl_invalidation_service.h
@@ -7,18 +7,20 @@
 
 #include "base/memory/scoped_ptr.h"
 #include "base/threading/non_thread_safe.h"
-#include "chrome/browser/invalidation/invalidation_frontend.h"
+#include "base/timer/timer.h"
+#include "chrome/browser/invalidation/invalidation_service.h"
 #include "chrome/browser/invalidation/invalidator_storage.h"
-#include "chrome/browser/signin/signin_global_error.h"
+#include "chrome/browser/signin/oauth2_token_service.h"
+#include "chrome/browser/signin/token_service.h"
 #include "components/browser_context_keyed_service/browser_context_keyed_service.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
+#include "net/base/backoff_entry.h"
 #include "sync/notifier/invalidation_handler.h"
 #include "sync/notifier/invalidator_registrar.h"
 
 class Profile;
 class SigninManagerBase;
-class TokenService;
 
 namespace syncer {
 class Invalidator;
@@ -30,19 +32,20 @@
 // It provides invalidations for desktop platforms (Win, Mac, Linux).
 class TiclInvalidationService
     : public base::NonThreadSafe,
-      public BrowserContextKeyedService,
-      public InvalidationFrontend,
+      public InvalidationService,
       public content::NotificationObserver,
+      public OAuth2TokenService::Consumer,
       public syncer::InvalidationHandler {
  public:
   TiclInvalidationService(SigninManagerBase* signin,
                           TokenService* token_service,
+                          OAuth2TokenService* oauth2_token_service,
                           Profile* profile);
   virtual ~TiclInvalidationService();
 
   void Init();
 
-  // InvalidationFrontend implementation.
+  // InvalidationService implementation.
   // It is an error to have registered handlers when Shutdown() is called.
   virtual void RegisterInvalidationHandler(
       syncer::InvalidationHandler* handler) OVERRIDE;
@@ -55,13 +58,24 @@
       const invalidation::ObjectId& id,
       const syncer::AckHandle& ack_handle) OVERRIDE;
   virtual syncer::InvalidatorState GetInvalidatorState() const OVERRIDE;
-  virtual std::string GetInvalidatorClientId() const;
+  virtual std::string GetInvalidatorClientId() const OVERRIDE;
 
   // content::NotificationObserver implementation.
   virtual void Observe(int type,
                        const content::NotificationSource& source,
                        const content::NotificationDetails& details) OVERRIDE;
 
+  void RequestAccessToken();
+
+  // OAuth2TokenService::Consumer implementation
+  virtual void OnGetTokenSuccess(
+      const OAuth2TokenService::Request* request,
+      const std::string& access_token,
+      const base::Time& expiration_time) OVERRIDE;
+  virtual void OnGetTokenFailure(
+      const OAuth2TokenService::Request* request,
+      const GoogleServiceAuthError& error) OVERRIDE;
+
   // syncer::InvalidationHandler implementation.
   virtual void OnInvalidatorStateChange(
       syncer::InvalidatorState state) OVERRIDE;
@@ -81,14 +95,15 @@
   bool IsReadyToStart();
   bool IsStarted();
 
-  void Start();
-  void UpdateToken();
+  void StartInvalidator();
+  void UpdateInvalidatorCredentials();
   void StopInvalidator();
   void Logout();
 
   Profile *const profile_;
   SigninManagerBase *const signin_manager_;
   TokenService *const token_service_;
+  OAuth2TokenService *const oauth2_token_service_;
 
   scoped_ptr<syncer::InvalidatorRegistrar> invalidator_registrar_;
   scoped_ptr<InvalidatorStorage> invalidator_storage_;
@@ -96,9 +111,19 @@
 
   content::NotificationRegistrar notification_registrar_;
 
+  // TiclInvalidationService needs to remember access token in order to
+  // invalidate it with OAuth2TokenService.
+  std::string access_token_;
+
+  // TiclInvalidationService needs to hold reference to access_token_request_
+  // for the duration of request in order to receive callbacks.
+  scoped_ptr<OAuth2TokenService::Request> access_token_request_;
+  base::OneShotTimer<TiclInvalidationService> request_access_token_retry_timer_;
+  net::BackoffEntry request_access_token_backoff_;
+
   DISALLOW_COPY_AND_ASSIGN(TiclInvalidationService);
 };
 
-}
+}  // namespace invalidation
 
 #endif  // CHROME_BROWSER_INVALIDATION_TICL_INVALIDATION_SERVICE_H_
diff --git a/chrome/browser/invalidation/ticl_invalidation_service_unittest.cc b/chrome/browser/invalidation/ticl_invalidation_service_unittest.cc
index 225dc0a..314e8a7 100644
--- a/chrome/browser/invalidation/ticl_invalidation_service_unittest.cc
+++ b/chrome/browser/invalidation/ticl_invalidation_service_unittest.cc
@@ -4,8 +4,8 @@
 
 #include "chrome/browser/invalidation/ticl_invalidation_service.h"
 
-#include "chrome/browser/invalidation/invalidation_frontend_test_template.h"
 #include "chrome/browser/invalidation/invalidation_service_factory.h"
+#include "chrome/browser/invalidation/invalidation_service_test_template.h"
 #include "chrome/test/base/testing_profile.h"
 #include "sync/notifier/fake_invalidation_handler.h"
 #include "sync/notifier/fake_invalidator.h"
@@ -19,22 +19,22 @@
   TiclInvalidationServiceTestDelegate() { }
 
   ~TiclInvalidationServiceTestDelegate() {
-    DestroyInvalidationFrontend();
+    DestroyInvalidationService();
   }
 
-  void CreateInvalidationFrontend() {
+  void CreateInvalidationService() {
     fake_invalidator_ = new syncer::FakeInvalidator();
     profile_.reset(new TestingProfile());
     invalidation_service_.reset(
-        new TiclInvalidationService(NULL, NULL, profile_.get()));
+        new TiclInvalidationService(NULL, NULL, NULL, profile_.get()));
     invalidation_service_->InitForTest(fake_invalidator_);
   }
 
-  InvalidationFrontend* GetInvalidationFrontend() {
+  InvalidationService* GetInvalidationService() {
     return invalidation_service_.get();
   }
 
-  void DestroyInvalidationFrontend() {
+  void DestroyInvalidationService() {
     invalidation_service_->Shutdown();
   }
 
@@ -53,7 +53,7 @@
 };
 
 INSTANTIATE_TYPED_TEST_CASE_P(
-    TiclInvalidationServiceTest, InvalidationFrontendTest,
+    TiclInvalidationServiceTest, InvalidationServiceTest,
     TiclInvalidationServiceTestDelegate);
 
 }  // namespace invalidation
diff --git a/chrome/browser/io_thread.cc b/chrome/browser/io_thread.cc
index f67c1ae..d68b6e5 100644
--- a/chrome/browser/io_thread.cc
+++ b/chrome/browser/io_thread.cc
@@ -692,6 +692,8 @@
     std::string spdy_mode =
         command_line.GetSwitchValueASCII(switches::kUseSpdy);
     EnableSpdy(spdy_mode);
+  } else if (command_line.HasSwitch(switches::kEnableSpdy4a2)) {
+    net::HttpStreamFactory::EnableNpnSpdy4a2();
   } else if (command_line.HasSwitch(switches::kDisableSpdy31)) {
     net::HttpStreamFactory::EnableNpnSpdy3();
   } else if (command_line.HasSwitch(switches::kEnableNpn)) {
diff --git a/chrome/browser/jankometer.cc b/chrome/browser/jankometer.cc
index af96cfc..5fa82c3 100644
--- a/chrome/browser/jankometer.cc
+++ b/chrome/browser/jankometer.cc
@@ -17,7 +17,7 @@
 #include "base/strings/string_util.h"
 #include "base/threading/thread.h"
 #include "base/threading/watchdog.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/common/chrome_switches.h"
diff --git a/chrome/browser/jumplist_win.cc b/chrome/browser/jumplist_win.cc
index d78a9fd..4447141 100644
--- a/chrome/browser/jumplist_win.cc
+++ b/chrome/browser/jumplist_win.cc
@@ -40,7 +40,6 @@
 #include "chrome/common/url_constants.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/notification_source.h"
-#include "googleurl/src/gurl.h"
 #include "grit/chromium_strings.h"
 #include "grit/generated_resources.h"
 #include "third_party/skia/include/core/SkBitmap.h"
@@ -49,6 +48,7 @@
 #include "ui/gfx/favicon_size.h"
 #include "ui/gfx/icon_util.h"
 #include "ui/gfx/image/image_family.h"
+#include "url/gurl.h"
 
 using content::BrowserThread;
 
@@ -736,8 +736,8 @@
   // icon files.
   base::FilePath icon_dir_old(icon_dir_.value() + L"Old");
   if (file_util::PathExists(icon_dir_old))
-    file_util::Delete(icon_dir_old, true);
-  file_util::Move(icon_dir_, icon_dir_old);
+    base::Delete(icon_dir_old, true);
+  base::Move(icon_dir_, icon_dir_old);
   file_util::CreateDirectory(icon_dir_);
 
   // Create temporary icon files for shortcuts in the "Most Visited" category.
diff --git a/chrome/browser/loadtimes_extension_bindings_browsertest.cc b/chrome/browser/loadtimes_extension_bindings_browsertest.cc
index efca60a..24ab846 100644
--- a/chrome/browser/loadtimes_extension_bindings_browsertest.cc
+++ b/chrome/browser/loadtimes_extension_bindings_browsertest.cc
@@ -8,7 +8,7 @@
 #include "chrome/test/base/ui_test_utils.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/browser_test_utils.h"
-#include "net/test/spawned_test_server/spawned_test_server.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
 
 class LoadtimesExtensionBindingsTest : public InProcessBrowserTest {
  public:
@@ -45,8 +45,8 @@
 
 IN_PROC_BROWSER_TEST_F(LoadtimesExtensionBindingsTest,
                        LoadTimesSameAfterClientInDocNavigation) {
-  ASSERT_TRUE(test_server()->Start());
-  GURL plain_url = test_server()->GetURL("blank");
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+  GURL plain_url = embedded_test_server()->GetURL("/simple.html");
   ui_test_utils::NavigateToURL(browser(), plain_url);
   content::WebContents* contents =
       browser()->tab_strip_model()->GetActiveWebContents();
@@ -61,8 +61,8 @@
 
 IN_PROC_BROWSER_TEST_F(LoadtimesExtensionBindingsTest,
                        LoadTimesSameAfterUserInDocNavigation) {
-  ASSERT_TRUE(test_server()->Start());
-  GURL plain_url = test_server()->GetURL("blank");
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+  GURL plain_url = embedded_test_server()->GetURL("/simple.html");
   GURL hash_url(plain_url.spec() + "#");
   ui_test_utils::NavigateToURL(browser(), plain_url);
   content::WebContents* contents =
diff --git a/chrome/browser/local_discovery/local_domain_resolver.cc b/chrome/browser/local_discovery/local_domain_resolver.cc
new file mode 100644
index 0000000..bb5e563
--- /dev/null
+++ b/chrome/browser/local_discovery/local_domain_resolver.cc
@@ -0,0 +1,82 @@
+// 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/bind.h"
+#include "chrome/browser/local_discovery/local_domain_resolver.h"
+#include "net/dns/dns_protocol.h"
+#include "net/dns/record_parsed.h"
+#include "net/dns/record_rdata.h"
+
+namespace local_discovery {
+
+LocalDomainResolver::LocalDomainResolver(net::MDnsClient* mdns_client,
+                                         const std::string& domain,
+                                         net::AddressFamily address_family,
+                                         const IPAddressCallback& callback)
+    : domain_(domain), address_family_(address_family), callback_(callback),
+      transaction_failures_(0), mdns_client_(mdns_client) {
+}
+
+LocalDomainResolver::~LocalDomainResolver() {
+}
+
+bool LocalDomainResolver::Start() {
+  if (address_family_ == net::ADDRESS_FAMILY_IPV4 ||
+      address_family_ == net::ADDRESS_FAMILY_UNSPECIFIED) {
+    transaction_a_ = CreateTransaction(net::dns_protocol::kTypeA);
+    if (!transaction_a_->Start())
+      return false;
+  }
+
+  if (address_family_ == net::ADDRESS_FAMILY_IPV6 ||
+      address_family_ == net::ADDRESS_FAMILY_UNSPECIFIED) {
+    transaction_aaaa_ = CreateTransaction(net::dns_protocol::kTypeAAAA);
+    if (!transaction_aaaa_->Start())
+      return false;
+  }
+
+  return true;
+}
+
+scoped_ptr<net::MDnsTransaction> LocalDomainResolver::CreateTransaction(
+    uint16 type) {
+  return mdns_client_->CreateTransaction(
+      type, domain_, net::MDnsTransaction::SINGLE_RESULT |
+                     net::MDnsTransaction::QUERY_CACHE |
+                     net::MDnsTransaction::QUERY_NETWORK,
+      base::Bind(&LocalDomainResolver::OnTransactionComplete,
+                 base::Unretained(this)));
+}
+
+void LocalDomainResolver::OnTransactionComplete(
+    net::MDnsTransaction::Result result, const net::RecordParsed* record) {
+  if (result != net::MDnsTransaction::RESULT_RECORD &&
+      address_family_ == net::ADDRESS_FAMILY_UNSPECIFIED) {
+    transaction_failures_++;
+
+    if (transaction_failures_ < 2) {
+      return;
+    }
+  }
+
+  transaction_a_.reset();
+  transaction_aaaa_.reset();
+
+  net::IPAddressNumber address;
+  if (result == net::MDnsTransaction::RESULT_RECORD) {
+    if (record->type() == net::dns_protocol::kTypeA) {
+      const net::ARecordRdata* rdata = record->rdata<net::ARecordRdata>();
+      DCHECK(rdata);
+      address = rdata->address();
+    } else {
+      DCHECK(record->type() == net::dns_protocol::kTypeAAAA);
+      const net::AAAARecordRdata* rdata = record->rdata<net::AAAARecordRdata>();
+      address = rdata->address();
+    }
+  }
+
+  callback_.Run(result == net::MDnsTransaction::RESULT_RECORD, address);
+}
+
+}  // namespace local_discovery
diff --git a/chrome/browser/local_discovery/local_domain_resolver.h b/chrome/browser/local_discovery/local_domain_resolver.h
new file mode 100644
index 0000000..6c0c50d
--- /dev/null
+++ b/chrome/browser/local_discovery/local_domain_resolver.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.
+
+#include <string>
+
+#include "base/callback.h"
+#include "net/base/address_family.h"
+#include "net/base/net_util.h"
+#include "net/dns/mdns_client.h"
+
+#ifndef CHROME_BROWSER_LOCAL_DISCOVERY_LOCAL_DOMAIN_RESOLVER_H_
+#define CHROME_BROWSER_LOCAL_DISCOVERY_LOCAL_DOMAIN_RESOLVER_H_
+
+namespace local_discovery {
+
+class LocalDomainResolver {
+ public:
+  typedef base::Callback<void(bool, const net::IPAddressNumber&)>
+      IPAddressCallback;
+
+  // |mdns_client| must outlive the LocalDomainResolver.
+  LocalDomainResolver(net::MDnsClient* mdns_client,
+                      const std::string& domain,
+                      net::AddressFamily address_family,
+                      const IPAddressCallback& callback);
+  ~LocalDomainResolver();
+
+  bool Start();
+
+  const std::string& domain() { return domain_; }
+
+ private:
+  void OnTransactionComplete(
+      net::MDnsTransaction::Result result,
+      const net::RecordParsed* record);
+
+  scoped_ptr<net::MDnsTransaction> CreateTransaction(uint16 type);
+
+  std::string domain_;
+  net::AddressFamily address_family_;
+  IPAddressCallback callback_;
+
+  scoped_ptr<net::MDnsTransaction> transaction_a_;
+  scoped_ptr<net::MDnsTransaction> transaction_aaaa_;
+
+  int transaction_failures_;
+
+  net::MDnsClient* mdns_client_;
+
+  DISALLOW_COPY_AND_ASSIGN(LocalDomainResolver);
+};
+
+}  // namespace local_discovery
+
+#endif  // CHROME_BROWSER_LOCAL_DISCOVERY_LOCAL_DOMAIN_RESOLVER_H_
diff --git a/chrome/browser/local_discovery/local_domain_resolver_unittest.cc b/chrome/browser/local_discovery/local_domain_resolver_unittest.cc
new file mode 100644
index 0000000..96e6088
--- /dev/null
+++ b/chrome/browser/local_discovery/local_domain_resolver_unittest.cc
@@ -0,0 +1,168 @@
+// 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/local_discovery/local_domain_resolver.h"
+#include "net/dns/mdns_client_impl.h"
+#include "net/dns/mock_mdns_socket_factory.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using ::testing::_;
+
+namespace local_discovery {
+
+namespace {
+
+const char kSamplePacketA[] = {
+  // Header
+  '\x00', '\x00',               // ID is zeroed out
+  '\x81', '\x80',               // Standard query response, RA, no error
+  '\x00', '\x00',               // No questions (for simplicity)
+  '\x00', '\x01',               // 1 RR (answers)
+  '\x00', '\x00',               // 0 authority RRs
+  '\x00', '\x00',               // 0 additional RRs
+
+  '\x07', 'm', 'y', 'h', 'e', 'l', 'l', 'o',
+  '\x05', 'l', 'o', 'c', 'a', 'l',
+  '\x00',
+  '\x00', '\x01',        // TYPE is A.
+  '\x00', '\x01',        // CLASS is IN.
+  '\x00', '\x00',        // TTL (4 bytes) is 16 seconds.
+  '\x00', '\x10',
+  '\x00', '\x04',        // RDLENGTH is 4 bytes.
+  '\x01', '\x02',
+  '\x03', '\x04',
+};
+
+const char kSamplePacketAAAA[] = {
+  // Header
+  '\x00', '\x00',               // ID is zeroed out
+  '\x81', '\x80',               // Standard query response, RA, no error
+  '\x00', '\x00',               // No questions (for simplicity)
+  '\x00', '\x01',               // 1 RR (answers)
+  '\x00', '\x00',               // 0 authority RRs
+  '\x00', '\x00',               // 0 additional RRs
+
+  '\x07', 'm', 'y', 'h', 'e', 'l', 'l', 'o',
+  '\x05', 'l', 'o', 'c', 'a', 'l',
+  '\x00',
+  '\x00', '\x1C',        // TYPE is AAAA.
+  '\x00', '\x01',        // CLASS is IN.
+  '\x00', '\x00',        // TTL (4 bytes) is 16 seconds.
+  '\x00', '\x10',
+  '\x00', '\x10',        // RDLENGTH is 4 bytes.
+  '\x00', '\x0A', '\x00', '\x00',
+  '\x00', '\x00', '\x00', '\x00',
+  '\x00', '\x01', '\x00', '\x02',
+  '\x00', '\x03', '\x00', '\x04',
+};
+
+class LocalDomainResolverTest : public testing::Test {
+ public:
+  LocalDomainResolverTest() : socket_factory_(new net::MockMDnsSocketFactory),
+    mdns_client_(
+        scoped_ptr<net::MDnsConnection::SocketFactory>(
+            socket_factory_)) {
+  }
+
+  ~LocalDomainResolverTest() {
+  }
+
+  void AddressCallback(bool resolved, const net::IPAddressNumber& address) {
+    if (address == net::IPAddressNumber()) {
+      AddressCallbackInternal(resolved, "");
+    } else {
+      AddressCallbackInternal(resolved, net::IPAddressToString(address));
+    }
+  }
+
+  void RunFor(base::TimeDelta time_period) {
+    base::CancelableCallback<void()> callback(base::Bind(
+        &base::MessageLoop::Quit,
+        base::Unretained(base::MessageLoop::current())));
+    base::MessageLoop::current()->PostDelayedTask(
+        FROM_HERE, callback.callback(), time_period);
+
+    base::MessageLoop::current()->Run();
+    callback.Cancel();
+  }
+
+  MOCK_METHOD2(AddressCallbackInternal,
+               void(bool resolved, std::string address));
+
+  net::MockMDnsSocketFactory* socket_factory_;
+  net::MDnsClientImpl mdns_client_;
+  base::MessageLoop message_loop_;
+};
+
+TEST_F(LocalDomainResolverTest, ResolveDomainA) {
+  LocalDomainResolver resolver(
+      &mdns_client_, "myhello.local", net::ADDRESS_FAMILY_IPV4,
+      base::Bind(&LocalDomainResolverTest::AddressCallback,
+                 base::Unretained(this)));
+
+  EXPECT_CALL(*socket_factory_, OnSendTo(_))
+      .Times(2);  // Twice per query
+
+  EXPECT_TRUE(resolver.Start());
+
+  EXPECT_CALL(*this, AddressCallbackInternal(true, "1.2.3.4"));
+
+  socket_factory_->SimulateReceive(
+      kSamplePacketA, sizeof(kSamplePacketA));
+}
+
+TEST_F(LocalDomainResolverTest, ResolveDomainAAAA) {
+  LocalDomainResolver resolver(
+      &mdns_client_, "myhello.local", net::ADDRESS_FAMILY_IPV6,
+      base::Bind(&LocalDomainResolverTest::AddressCallback,
+                 base::Unretained(this)));
+
+  EXPECT_CALL(*socket_factory_, OnSendTo(_))
+      .Times(2);  // Twice per query
+
+  EXPECT_TRUE(resolver.Start());
+
+  EXPECT_CALL(*this, AddressCallbackInternal(true, "a::1:2:3:4"));
+
+  socket_factory_->SimulateReceive(
+      kSamplePacketAAAA, sizeof(kSamplePacketAAAA));
+}
+
+TEST_F(LocalDomainResolverTest, ResolveDomainAny) {
+  LocalDomainResolver resolver(
+      &mdns_client_, "myhello.local", net::ADDRESS_FAMILY_UNSPECIFIED,
+      base::Bind(&LocalDomainResolverTest::AddressCallback,
+                 base::Unretained(this)));
+
+  EXPECT_CALL(*socket_factory_, OnSendTo(_))
+      .Times(4);  // Twice per query
+
+  EXPECT_TRUE(resolver.Start());
+
+  EXPECT_CALL(*this, AddressCallbackInternal(true, "a::1:2:3:4"));
+
+  socket_factory_->SimulateReceive(
+      kSamplePacketAAAA, sizeof(kSamplePacketAAAA));
+}
+
+TEST_F(LocalDomainResolverTest, ResolveDomainNone) {
+  LocalDomainResolver resolver(
+      &mdns_client_, "myhello.local", net::ADDRESS_FAMILY_UNSPECIFIED,
+      base::Bind(&LocalDomainResolverTest::AddressCallback,
+                 base::Unretained(this)));
+
+  EXPECT_CALL(*socket_factory_, OnSendTo(_))
+      .Times(4);  // Twice per query
+
+  EXPECT_TRUE(resolver.Start());
+
+  EXPECT_CALL(*this, AddressCallbackInternal(false, ""));
+
+  RunFor(base::TimeDelta::FromSeconds(4));
+}
+
+}  // namespace
+
+}  // namespace local_discovery
diff --git a/chrome/browser/local_discovery/service_discovery_client.cc b/chrome/browser/local_discovery/service_discovery_client.cc
new file mode 100644
index 0000000..0b63b85
--- /dev/null
+++ b/chrome/browser/local_discovery/service_discovery_client.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/local_discovery/service_discovery_client.h"
+
+namespace local_discovery {
+
+ServiceDescription::ServiceDescription() {
+}
+
+ServiceDescription::~ServiceDescription() {
+}
+
+std::string ServiceDescription::instance_name() const {
+  // TODO(noamsml): Once we have escaping working, get this to
+  // parse escaped domains.
+  size_t first_period = service_name.find_first_of('.');
+  return service_name.substr(0, first_period);
+}
+
+std::string ServiceDescription::service_type() const {
+  // TODO(noamsml): Once we have escaping working, get this to
+  // parse escaped domains.
+  size_t first_period = service_name.find_first_of('.');
+  if (first_period == std::string::npos)
+    return "";
+  return service_name.substr(first_period+1);
+}
+
+}  // namespace local_discovery
diff --git a/chrome/browser/local_discovery/service_discovery_client.h b/chrome/browser/local_discovery/service_discovery_client.h
new file mode 100644
index 0000000..ceeca7a
--- /dev/null
+++ b/chrome/browser/local_discovery/service_discovery_client.h
@@ -0,0 +1,137 @@
+// 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_LOCAL_DISCOVERY_SERVICE_DISCOVERY_CLIENT_H_
+#define CHROME_BROWSER_LOCAL_DISCOVERY_SERVICE_DISCOVERY_CLIENT_H_
+
+#include <string>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/time/time.h"
+#include "net/base/host_port_pair.h"
+#include "net/base/net_util.h"
+
+namespace net {
+class MDnsClient;
+}
+
+namespace local_discovery {
+
+struct ServiceDescription {
+ public:
+  ServiceDescription();
+  ~ServiceDescription();
+
+  // Convenience function to get useful parts of the service name. A service
+  // name follows the format <instance_name>.<service_type>.
+  std::string instance_name() const;
+  std::string service_type() const;
+
+  // The name of the service.
+  std::string service_name;
+  // The address (in host/port format) for the service (from SRV record).
+  net::HostPortPair address;
+  // The metadata (from TXT record) of the service.
+  std::vector<std::string> metadata;
+  // IP address of the service, if available from cache. May be empty.
+  net::IPAddressNumber ip_address;
+  // Last time the service was seen.
+  base::Time last_seen;
+};
+
+// Lets users browse the network for services of interest or listen for changes
+// in the services they are interested in. See
+// |ServiceDiscoveryClient::CreateServiceWatcher|.
+class ServiceWatcher {
+ public:
+  enum UpdateType {
+    UPDATE_ADDED,
+    UPDATE_CHANGED,
+    UPDATE_REMOVED
+  };
+
+  class Delegate {
+   public:
+    virtual ~Delegate() {}
+
+    // A service has been added or removed for a certain service name.
+    virtual void OnServiceUpdated(UpdateType update,
+                                  const std::string& service_name) = 0;
+  };
+
+  // Listening will automatically stop when the destructor is called.
+  virtual ~ServiceWatcher() {}
+
+  // Start the service type watcher.
+  virtual bool Start() = 0;
+
+  // Get all known services names of this watcher's type. Return them in
+  // |services|.
+  virtual void GetAvailableServices(
+      std::vector<std::string>* services) const = 0;
+
+  // Read services from the cache, alerting the delegate to any service that
+  // is not yet known.
+  virtual void ReadCachedServices() = 0;
+
+  // Probe for services of this type.
+  virtual void DiscoverNewServices(bool force_update) = 0;
+
+  virtual std::string GetServiceType() const = 0;
+};
+
+// Represents a service on the network and allows users to access the service's
+// address and metadata. See |ServiceDiscoveryClient::CreateServiceResolver|.
+class ServiceResolver {
+ public:
+  enum RequestStatus {
+    STATUS_SUCCESS = 0,
+    STATUS_REQUEST_TIMEOUT = 1,
+    STATUS_KNOWN_NONEXISTENT = 2
+  };
+
+  // A callback called once the service has been resolved.
+  typedef base::Callback<void(RequestStatus, const ServiceDescription&)>
+      ResolveCompleteCallback;
+
+  // Listening will automatically stop when the destructor is called.
+  virtual ~ServiceResolver() {}
+
+  // Start the service reader.
+  virtual bool StartResolving() = 0;
+
+  // Check whether the resolver is currently resolving. Can be called multiple
+  // times.
+  virtual bool IsResolving() const = 0;
+
+  // Check wheteher the resolver has resolved the service already.
+  virtual bool HasResolved() const = 0;
+
+  virtual std::string GetName() const = 0;
+
+  virtual const ServiceDescription& GetServiceDescription() const = 0;
+};
+
+class ServiceDiscoveryClient {
+ public:
+  virtual ~ServiceDiscoveryClient() {}
+
+  // Create a service watcher object listening for DNS-SD service announcements
+  // on service type |service_type|.
+  virtual scoped_ptr<ServiceWatcher> CreateServiceWatcher(
+      const std::string& service_type,
+      ServiceWatcher::Delegate* delegate) = 0;
+
+  // Create a service resolver object for getting detailed service information
+  // for the service called |service_name|.
+  virtual scoped_ptr<ServiceResolver> CreateServiceResolver(
+      const std::string& service_name,
+      const ServiceResolver::ResolveCompleteCallback& callback) = 0;
+};
+
+}  // namespace local_discovery
+
+#endif  // CHROME_BROWSER_LOCAL_DISCOVERY_SERVICE_DISCOVERY_CLIENT_H_
diff --git a/chrome/browser/local_discovery/service_discovery_client_impl.cc b/chrome/browser/local_discovery/service_discovery_client_impl.cc
new file mode 100644
index 0000000..219f5ed
--- /dev/null
+++ b/chrome/browser/local_discovery/service_discovery_client_impl.cc
@@ -0,0 +1,411 @@
+// 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 <utility>
+
+#include "base/logging.h"
+#include "base/memory/singleton.h"
+#include "base/message_loop/message_loop_proxy.h"
+#include "base/stl_util.h"
+#include "chrome/browser/local_discovery/service_discovery_client_impl.h"
+#include "net/dns/dns_protocol.h"
+#include "net/dns/record_rdata.h"
+
+namespace local_discovery {
+
+ServiceDiscoveryClientImpl::ServiceDiscoveryClientImpl(
+    net::MDnsClient* mdns_client) : mdns_client_(mdns_client) {
+}
+
+ServiceDiscoveryClientImpl::~ServiceDiscoveryClientImpl() {
+}
+
+scoped_ptr<ServiceWatcher> ServiceDiscoveryClientImpl::CreateServiceWatcher(
+    const std::string& service_type,
+    ServiceWatcher::Delegate* delegate) {
+  return scoped_ptr<ServiceWatcher>(new ServiceWatcherImpl(
+      service_type,  delegate, mdns_client_));
+}
+
+scoped_ptr<ServiceResolver> ServiceDiscoveryClientImpl::CreateServiceResolver(
+    const std::string& service_name,
+    const ServiceResolver::ResolveCompleteCallback& callback) {
+  return scoped_ptr<ServiceResolver>(new ServiceResolverImpl(
+      service_name, callback, mdns_client_));
+}
+
+ServiceWatcherImpl::ServiceWatcherImpl(
+    const std::string& service_type,
+    ServiceWatcher::Delegate* delegate,
+    net::MDnsClient* mdns_client)
+    : service_type_(service_type), delegate_(delegate), started_(false),
+      mdns_client_(mdns_client) {
+}
+
+bool ServiceWatcherImpl::Start() {
+  DCHECK(!started_);
+  listener_ = mdns_client_->CreateListener(
+      net::dns_protocol::kTypePTR, service_type_, this);
+  if (!listener_->Start())
+    return false;
+
+  started_ = true;
+  return true;
+}
+
+ServiceWatcherImpl::~ServiceWatcherImpl() {
+}
+
+void ServiceWatcherImpl::GetAvailableServices(
+    std::vector<std::string>* services) const {
+  DCHECK(started_);
+  DCHECK(services);
+  services->reserve(services_.size());
+  for (ServiceListenersMap::const_iterator i = services_.begin();
+       i != services_.end(); i++) {
+    services->push_back(i->first);
+  }
+}
+
+void ServiceWatcherImpl::DiscoverNewServices(bool force_update) {
+  DCHECK(started_);
+  if (force_update)
+    services_.clear();
+  CreateTransaction(true /*network*/, false /*cache*/, force_update,
+                    &transaction_network_);
+}
+
+void ServiceWatcherImpl::ReadCachedServices() {
+  DCHECK(started_);
+  CreateTransaction(false /*network*/, true /*cache*/, false /*force refresh*/,
+                    &transaction_cache_);
+}
+
+bool ServiceWatcherImpl::CreateTransaction(
+    bool network, bool cache, bool force_refresh,
+    scoped_ptr<net::MDnsTransaction>* transaction) {
+  int transaction_flags = 0;
+  if (network)
+    transaction_flags |= net::MDnsTransaction::QUERY_NETWORK;
+
+  if (cache)
+    transaction_flags |= net::MDnsTransaction::QUERY_CACHE;
+
+  // TODO(noamsml): Add flag for force_refresh when supported.
+
+  if (transaction_flags) {
+    *transaction = mdns_client_->CreateTransaction(
+        net::dns_protocol::kTypePTR, service_type_, transaction_flags,
+        base::Bind(&ServiceWatcherImpl::OnTransactionResponse,
+                   base::Unretained(this), transaction));
+    return (*transaction)->Start();
+  }
+
+  return true;
+}
+
+std::string ServiceWatcherImpl::GetServiceType() const {
+  return listener_->GetName();
+}
+
+void ServiceWatcherImpl::OnRecordUpdate(
+    net::MDnsListener::UpdateType update,
+    const net::RecordParsed* record) {
+  DCHECK(started_);
+  if (record->type() == net::dns_protocol::kTypePTR) {
+    DCHECK(record->name() == GetServiceType());
+    const net::PtrRecordRdata* rdata = record->rdata<net::PtrRecordRdata>();
+
+    switch (update) {
+      case net::MDnsListener::RECORD_ADDED:
+        AddService(rdata->ptrdomain());
+        break;
+      case net::MDnsListener::RECORD_CHANGED:
+        NOTREACHED();
+        break;
+      case net::MDnsListener::RECORD_REMOVED:
+        RemoveService(rdata->ptrdomain());
+        break;
+    }
+  } else {
+    DCHECK(record->type() == net::dns_protocol::kTypeSRV ||
+           record->type() == net::dns_protocol::kTypeTXT);
+    DCHECK(services_.find(record->name()) != services_.end());
+
+    DeferUpdate(UPDATE_CHANGED, record->name());
+  }
+}
+
+void ServiceWatcherImpl::OnCachePurged() {
+  // Not yet implemented.
+}
+
+void ServiceWatcherImpl::OnTransactionResponse(
+    scoped_ptr<net::MDnsTransaction>* transaction,
+    net::MDnsTransaction::Result result,
+    const net::RecordParsed* record) {
+  DCHECK(started_);
+  if (result == net::MDnsTransaction::RESULT_RECORD) {
+    const net::PtrRecordRdata* rdata = record->rdata<net::PtrRecordRdata>();
+    DCHECK(rdata);
+    AddService(rdata->ptrdomain());
+  } else if (result == net::MDnsTransaction::RESULT_DONE) {
+    transaction->reset();
+  }
+
+  // Do nothing for NSEC records. It is an error for hosts to broadcast an NSEC
+  // record for PTR records on any name.
+}
+
+ServiceWatcherImpl::ServiceListeners::ServiceListeners(
+    const std::string& service_name,
+    ServiceWatcherImpl* watcher,
+    net::MDnsClient* mdns_client) : update_pending_(false) {
+  srv_listener_ = mdns_client->CreateListener(
+      net::dns_protocol::kTypeSRV, service_name, watcher);
+  txt_listener_ = mdns_client->CreateListener(
+      net::dns_protocol::kTypeTXT, service_name, watcher);
+}
+
+ServiceWatcherImpl::ServiceListeners::~ServiceListeners() {
+}
+
+bool ServiceWatcherImpl::ServiceListeners::Start() {
+  if (!srv_listener_->Start())
+    return false;
+  return txt_listener_->Start();
+}
+
+void ServiceWatcherImpl::AddService(const std::string& service) {
+  DCHECK(started_);
+  std::pair<ServiceListenersMap::iterator, bool> found = services_.insert(
+      make_pair(service, static_cast<ServiceListeners*>(NULL)));
+  if (found.second) {  // Newly inserted.
+    found.first->second = linked_ptr<ServiceListeners>(
+        new ServiceListeners(service, this, mdns_client_));
+    bool success = found.first->second->Start();
+
+    DeferUpdate(UPDATE_ADDED, service);
+
+    DCHECK(success);
+  }
+}
+
+void ServiceWatcherImpl::DeferUpdate(ServiceWatcher::UpdateType update_type,
+                                     const std::string& service_name) {
+  ServiceListenersMap::iterator found = services_.find(service_name);
+
+  if (found != services_.end() && !found->second->update_pending()) {
+    found->second->set_update_pending(true);
+    base::MessageLoop::current()->PostTask(
+        FROM_HERE,
+        base::Bind(&ServiceWatcherImpl::DeliverDeferredUpdate, AsWeakPtr(),
+                   update_type, service_name));
+  }
+}
+
+void ServiceWatcherImpl::DeliverDeferredUpdate(
+    ServiceWatcher::UpdateType update_type, const std::string& service_name) {
+  ServiceListenersMap::iterator found = services_.find(service_name);
+
+  if (found != services_.end()) {
+    found->second->set_update_pending(false);
+    delegate_->OnServiceUpdated(update_type, service_name);
+  }
+}
+
+void ServiceWatcherImpl::RemoveService(const std::string& service) {
+  DCHECK(started_);
+  ServiceListenersMap::iterator found = services_.find(service);
+  if (found != services_.end()) {
+    services_.erase(found);
+    delegate_->OnServiceUpdated(UPDATE_REMOVED, service);
+  }
+}
+
+void ServiceWatcherImpl::OnNsecRecord(const std::string& name,
+                                      unsigned rrtype) {
+  // Do nothing. It is an error for hosts to broadcast an NSEC record for PTR
+  // on any name.
+}
+
+ServiceResolverImpl::ServiceResolverImpl(
+    const std::string& service_name,
+    const ResolveCompleteCallback& callback,
+    net::MDnsClient* mdns_client)
+    : service_name_(service_name), callback_(callback),
+      is_resolving_(false), has_resolved_(false), metadata_resolved_(false),
+      address_resolved_(false), service_staging_(new ServiceDescription),
+      service_final_(new ServiceDescription), mdns_client_(mdns_client) {
+  service_staging_->service_name = service_name_;
+  service_final_->service_name = service_name_;
+}
+
+bool ServiceResolverImpl::StartResolving() {
+  is_resolving_ = true;
+  address_resolved_ = false;
+  metadata_resolved_ = false;
+
+  if (!CreateTxtTransaction())
+    return false;
+  if (!CreateSrvTransaction())
+    return false;
+  return true;
+}
+
+bool ServiceResolverImpl::IsResolving() const {
+  return is_resolving_;
+}
+
+bool ServiceResolverImpl::HasResolved() const {
+  return has_resolved_;
+}
+
+ServiceResolverImpl::~ServiceResolverImpl() {
+}
+
+bool ServiceResolverImpl::CreateTxtTransaction() {
+  txt_transaction_ = mdns_client_->CreateTransaction(
+      net::dns_protocol::kTypeTXT, service_name_,
+      net::MDnsTransaction::SINGLE_RESULT | net::MDnsTransaction::QUERY_CACHE |
+      net::MDnsTransaction::QUERY_NETWORK,
+      base::Bind(&ServiceResolverImpl::TxtRecordTransactionResponse,
+                 AsWeakPtr()));
+  return txt_transaction_->Start();
+}
+
+// TODO(noamsml): quick-resolve for AAAA records.  Since A records tend to be in
+void ServiceResolverImpl::CreateATransaction() {
+  a_transaction_ = mdns_client_->CreateTransaction(
+      net::dns_protocol::kTypeA,
+      service_staging_.get()->address.host(),
+      net::MDnsTransaction::SINGLE_RESULT | net::MDnsTransaction::QUERY_CACHE,
+      base::Bind(&ServiceResolverImpl::ARecordTransactionResponse,
+                 AsWeakPtr()));
+  a_transaction_->Start();
+}
+
+bool ServiceResolverImpl::CreateSrvTransaction() {
+  srv_transaction_ = mdns_client_->CreateTransaction(
+      net::dns_protocol::kTypeSRV, service_name_,
+      net::MDnsTransaction::SINGLE_RESULT | net::MDnsTransaction::QUERY_CACHE |
+      net::MDnsTransaction::QUERY_NETWORK,
+      base::Bind(&ServiceResolverImpl::SrvRecordTransactionResponse,
+                 AsWeakPtr()));
+  return srv_transaction_->Start();
+}
+
+std::string ServiceResolverImpl::GetName() const {
+  return service_name_;
+}
+
+void ServiceResolverImpl::SrvRecordTransactionResponse(
+    net::MDnsTransaction::Result status, const net::RecordParsed* record) {
+  srv_transaction_.reset();
+  if (status == net::MDnsTransaction::RESULT_RECORD) {
+    DCHECK(record);
+    service_staging_.get()->address = RecordToAddress(record);
+    service_staging_.get()->last_seen = record->time_created();
+    CreateATransaction();
+  } else {
+    ServiceNotFound(MDnsStatusToRequestStatus(status));
+  }
+}
+
+void ServiceResolverImpl::TxtRecordTransactionResponse(
+    net::MDnsTransaction::Result status, const net::RecordParsed* record) {
+  txt_transaction_.reset();
+  if (status == net::MDnsTransaction::RESULT_RECORD) {
+    DCHECK(record);
+    service_staging_.get()->metadata = RecordToMetadata(record);
+  } else {
+    service_staging_.get()->metadata = std::vector<std::string>();
+  }
+
+  metadata_resolved_ = true;
+  AlertCallbackIfReady();
+}
+
+void ServiceResolverImpl::ARecordTransactionResponse(
+    net::MDnsTransaction::Result status, const net::RecordParsed* record) {
+  a_transaction_.reset();
+
+  if (status == net::MDnsTransaction::RESULT_RECORD) {
+    DCHECK(record);
+    service_staging_.get()->ip_address = RecordToIPAddress(record);
+  } else {
+    service_staging_.get()->ip_address = net::IPAddressNumber();
+  }
+
+  address_resolved_ = true;
+  AlertCallbackIfReady();
+}
+
+void ServiceResolverImpl::AlertCallbackIfReady() {
+  if (metadata_resolved_ && address_resolved_) {
+    txt_transaction_.reset();
+    srv_transaction_.reset();
+    a_transaction_.reset();
+    has_resolved_ = true;
+    is_resolving_ = false;
+    service_final_.swap(service_staging_);
+    callback_.Run(STATUS_SUCCESS, GetServiceDescription());
+  }
+}
+
+void ServiceResolverImpl::ServiceNotFound(
+    ServiceResolver::RequestStatus status) {
+  txt_transaction_.reset();
+  srv_transaction_.reset();
+  a_transaction_.reset();
+  is_resolving_ = false;
+
+  callback_.Run(status, GetServiceDescription());
+}
+
+const ServiceDescription& ServiceResolverImpl::GetServiceDescription() const {
+  return *service_final_.get();
+}
+
+ServiceResolver::RequestStatus ServiceResolverImpl::MDnsStatusToRequestStatus(
+    net::MDnsTransaction::Result status) const {
+  switch (status) {
+    case net::MDnsTransaction::RESULT_RECORD:
+      return ServiceResolver::STATUS_SUCCESS;
+    case net::MDnsTransaction::RESULT_NO_RESULTS:
+      return ServiceResolver::STATUS_REQUEST_TIMEOUT;
+    case net::MDnsTransaction::RESULT_NSEC:
+      return ServiceResolver::STATUS_KNOWN_NONEXISTENT;
+    case net::MDnsTransaction::RESULT_DONE:  // Pass through.
+    default:
+      NOTREACHED();
+      return ServiceResolver::STATUS_REQUEST_TIMEOUT;
+  }
+}
+
+const std::vector<std::string>& ServiceResolverImpl::RecordToMetadata(
+    const net::RecordParsed* record) const {
+  DCHECK(record->type() == net::dns_protocol::kTypeTXT);
+  const net::TxtRecordRdata* txt_rdata = record->rdata<net::TxtRecordRdata>();
+  DCHECK(txt_rdata);
+  return txt_rdata->texts();
+}
+
+net::HostPortPair ServiceResolverImpl::RecordToAddress(
+    const net::RecordParsed* record) const {
+  DCHECK(record->type() == net::dns_protocol::kTypeSRV);
+  const net::SrvRecordRdata* srv_rdata = record->rdata<net::SrvRecordRdata>();
+  DCHECK(srv_rdata);
+  return net::HostPortPair(srv_rdata->target(), srv_rdata->port());
+}
+
+const net::IPAddressNumber& ServiceResolverImpl::RecordToIPAddress(
+    const net::RecordParsed* record) const {
+  DCHECK(record->type() == net::dns_protocol::kTypeA);
+  const net::ARecordRdata* a_rdata = record->rdata<net::ARecordRdata>();
+  DCHECK(a_rdata);
+  return a_rdata->address();
+}
+
+}  // namespace local_discovery
diff --git a/chrome/browser/local_discovery/service_discovery_client_impl.h b/chrome/browser/local_discovery/service_discovery_client_impl.h
new file mode 100644
index 0000000..13765e0
--- /dev/null
+++ b/chrome/browser/local_discovery/service_discovery_client_impl.h
@@ -0,0 +1,204 @@
+// 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_LOCAL_DISCOVERY_SERVICE_DISCOVERY_CLIENT_IMPL_H_
+#define CHROME_BROWSER_LOCAL_DISCOVERY_SERVICE_DISCOVERY_CLIENT_IMPL_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/cancelable_callback.h"
+#include "base/memory/linked_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "base/message_loop.h"
+#include "chrome/browser/local_discovery/service_discovery_client.h"
+#include "net/dns/mdns_client.h"
+
+namespace local_discovery {
+
+class ServiceDiscoveryClientImpl : public ServiceDiscoveryClient {
+ public:
+  // |mdns_client| must outlive the Service Discovery Client.
+  explicit ServiceDiscoveryClientImpl(net::MDnsClient* mdns_client);
+  virtual ~ServiceDiscoveryClientImpl();
+
+  // ServiceDiscoveryClient implementation:
+  virtual scoped_ptr<ServiceWatcher> CreateServiceWatcher(
+      const std::string& service_type,
+      ServiceWatcher::Delegate* delegate) OVERRIDE;
+
+  virtual scoped_ptr<ServiceResolver> CreateServiceResolver(
+      const std::string& service_name,
+      const ServiceResolver::ResolveCompleteCallback& callback) OVERRIDE;
+ private:
+  net::MDnsClient* mdns_client_;
+
+  DISALLOW_COPY_AND_ASSIGN(ServiceDiscoveryClientImpl);
+};
+
+class ServiceWatcherImpl : public ServiceWatcher,
+                           public net::MDnsListener::Delegate,
+                           public base::SupportsWeakPtr<ServiceWatcherImpl> {
+ public:
+  ServiceWatcherImpl(const std::string& service_type,
+                     ServiceWatcher::Delegate* delegate,
+                     net::MDnsClient* mdns_client);
+  // Listening will automatically stop when the destructor is called.
+  virtual ~ServiceWatcherImpl();
+
+  // ServiceWatcher implementation:
+  virtual bool Start() OVERRIDE;
+
+  virtual void GetAvailableServices(
+      std::vector<std::string>* services) const OVERRIDE;
+
+  virtual void DiscoverNewServices(bool force_update) OVERRIDE;
+
+  virtual std::string GetServiceType() const OVERRIDE;
+
+  virtual void ReadCachedServices() OVERRIDE;
+
+  virtual void OnRecordUpdate(net::MDnsListener::UpdateType update,
+                              const net::RecordParsed* record) OVERRIDE;
+
+  virtual void OnNsecRecord(const std::string& name, unsigned rrtype) OVERRIDE;
+
+  virtual void OnCachePurged() OVERRIDE;
+
+  virtual void OnTransactionResponse(
+      scoped_ptr<net::MDnsTransaction>* transaction,
+      net::MDnsTransaction::Result result,
+      const net::RecordParsed* record);
+
+ private:
+  struct ServiceListeners {
+    ServiceListeners(const std::string& service_name,
+                     ServiceWatcherImpl* watcher,
+                     net::MDnsClient* mdns_client);
+    ~ServiceListeners();
+    bool Start();
+
+    void set_update_pending(bool update_pending) {
+      update_pending_ = update_pending;
+    }
+
+    bool update_pending() { return update_pending_; }
+   private:
+    scoped_ptr<net::MDnsListener> srv_listener_;
+    scoped_ptr<net::MDnsListener> txt_listener_;
+    bool update_pending_;
+  };
+
+  typedef std::map<std::string, linked_ptr<ServiceListeners> >
+      ServiceListenersMap;
+
+  void AddService(const std::string& service);
+  void RemoveService(const std::string& service);
+  bool CreateTransaction(bool active, bool alert_existing_services,
+                         bool force_refresh,
+                         scoped_ptr<net::MDnsTransaction>* transaction);
+
+  void DeferUpdate(ServiceWatcher::UpdateType update_type,
+                   const std::string& service_name);
+  void DeliverDeferredUpdate(ServiceWatcher::UpdateType update_type,
+                             const std::string& service_name);
+
+  std::string service_type_;
+  ServiceListenersMap services_;
+  scoped_ptr<net::MDnsTransaction> transaction_network_;
+  scoped_ptr<net::MDnsTransaction> transaction_cache_;
+  scoped_ptr<net::MDnsListener> listener_;
+
+  ServiceWatcher::Delegate* delegate_;
+  bool started_;
+
+  net::MDnsClient* mdns_client_;
+
+  DISALLOW_COPY_AND_ASSIGN(ServiceWatcherImpl);
+};
+
+class ServiceResolverImpl
+    : public ServiceResolver,
+      public base::SupportsWeakPtr<ServiceResolverImpl> {
+ public:
+  ServiceResolverImpl(const std::string& service_name,
+                      const ServiceResolver::ResolveCompleteCallback& callback,
+                      net::MDnsClient* mdns_client);
+
+  virtual ~ServiceResolverImpl();
+
+  // ServiceResolver implementation:
+  virtual bool StartResolving() OVERRIDE;
+
+  virtual bool IsResolving() const OVERRIDE;
+
+  virtual bool HasResolved() const OVERRIDE;
+
+  virtual std::string GetName() const OVERRIDE;
+
+  virtual const ServiceDescription& GetServiceDescription() const OVERRIDE;
+
+ private:
+  // Respond to transaction finishing for SRV records.
+  void SrvRecordTransactionResponse(net::MDnsTransaction::Result status,
+                                    const net::RecordParsed* record);
+
+  // Respond to transaction finishing for TXT records.
+  void TxtRecordTransactionResponse(net::MDnsTransaction::Result status,
+                                    const net::RecordParsed* record);
+
+  // Respond to transaction finishing for A records.
+  void ARecordTransactionResponse(net::MDnsTransaction::Result status,
+                                  const net::RecordParsed* record);
+
+  void AlertCallbackIfReady();
+
+  void ServiceNotFound(RequestStatus status);
+
+  // Convert a TXT record to a vector of strings (metadata).
+  const std::vector<std::string>& RecordToMetadata(
+      const net::RecordParsed* record) const;
+
+  // Convert an SRV record to a host and port pair.
+  net::HostPortPair RecordToAddress(
+      const net::RecordParsed* record) const;
+
+  // Convert an A record to an IP address.
+  const net::IPAddressNumber& RecordToIPAddress(
+      const net::RecordParsed* record) const;
+
+  // Convert an MDns status to a service discovery status.
+  RequestStatus MDnsStatusToRequestStatus(
+      net::MDnsTransaction::Result status) const;
+
+  bool CreateTxtTransaction();
+  bool CreateSrvTransaction();
+  void CreateATransaction();
+
+  std::string service_name_;
+  ResolveCompleteCallback callback_;
+
+  bool is_resolving_;
+  bool has_resolved_;
+
+  bool metadata_resolved_;
+  bool address_resolved_;
+
+  scoped_ptr<net::MDnsTransaction> txt_transaction_;
+  scoped_ptr<net::MDnsTransaction> srv_transaction_;
+  scoped_ptr<net::MDnsTransaction> a_transaction_;
+
+  scoped_ptr<ServiceDescription> service_staging_;
+  scoped_ptr<ServiceDescription> service_final_;
+
+  net::MDnsClient* mdns_client_;
+
+  DISALLOW_COPY_AND_ASSIGN(ServiceResolverImpl);
+};
+
+}  // namespace local_discovery
+
+#endif  // CHROME_BROWSER_LOCAL_DISCOVERY_SERVICE_DISCOVERY_CLIENT_IMPL_H_
diff --git a/chrome/browser/local_discovery/service_discovery_client_unittest.cc b/chrome/browser/local_discovery/service_discovery_client_unittest.cc
new file mode 100644
index 0000000..9a7d90a
--- /dev/null
+++ b/chrome/browser/local_discovery/service_discovery_client_unittest.cc
@@ -0,0 +1,468 @@
+// 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/weak_ptr.h"
+#include "chrome/browser/local_discovery/service_discovery_client_impl.h"
+#include "net/base/net_errors.h"
+#include "net/dns/dns_protocol.h"
+#include "net/dns/mdns_client_impl.h"
+#include "net/dns/mock_mdns_socket_factory.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using ::testing::_;
+using ::testing::Invoke;
+using ::testing::StrictMock;
+using ::testing::NiceMock;
+using ::testing::Mock;
+using ::testing::SaveArg;
+using ::testing::SetArgPointee;
+using ::testing::Return;
+using ::testing::Exactly;
+
+namespace local_discovery {
+
+namespace {
+
+const char kSamplePacketPTR[] = {
+  // Header
+  '\x00', '\x00',               // ID is zeroed out
+  '\x81', '\x80',               // Standard query response, RA, no error
+  '\x00', '\x00',               // No questions (for simplicity)
+  '\x00', '\x01',               // 1 RR (answers)
+  '\x00', '\x00',               // 0 authority RRs
+  '\x00', '\x00',               // 0 additional RRs
+
+  '\x07', '_', 'p', 'r', 'i', 'v', 'e', 't',
+  '\x04', '_', 't', 'c', 'p',
+  '\x05', 'l', 'o', 'c', 'a', 'l',
+  '\x00',
+  '\x00', '\x0c',        // TYPE is PTR.
+  '\x00', '\x01',        // CLASS is IN.
+  '\x00', '\x00',        // TTL (4 bytes) is 1 second.
+  '\x00', '\x01',
+  '\x00', '\x08',        // RDLENGTH is 8 bytes.
+  '\x05', 'h', 'e', 'l', 'l', 'o',
+  '\xc0', '\x0c'
+};
+
+const char kSamplePacketSRV[] = {
+  // Header
+  '\x00', '\x00',               // ID is zeroed out
+  '\x81', '\x80',               // Standard query response, RA, no error
+  '\x00', '\x00',               // No questions (for simplicity)
+  '\x00', '\x01',               // 1 RR (answers)
+  '\x00', '\x00',               // 0 authority RRs
+  '\x00', '\x00',               // 0 additional RRs
+
+  '\x05', 'h', 'e', 'l', 'l', 'o',
+  '\x07', '_', 'p', 'r', 'i', 'v', 'e', 't',
+  '\x04', '_', 't', 'c', 'p',
+  '\x05', 'l', 'o', 'c', 'a', 'l',
+  '\x00',
+  '\x00', '\x21',        // TYPE is SRV.
+  '\x00', '\x01',        // CLASS is IN.
+  '\x00', '\x00',        // TTL (4 bytes) is 1 second.
+  '\x00', '\x01',
+  '\x00', '\x15',        // RDLENGTH is 21 bytes.
+  '\x00', '\x00',
+  '\x00', '\x00',
+  '\x22', '\xb8',  // port 8888
+  '\x07', 'm', 'y', 'h', 'e', 'l', 'l', 'o',
+  '\x05', 'l', 'o', 'c', 'a', 'l',
+  '\x00',
+};
+
+const char kSamplePacketTXT[] = {
+  // Header
+  '\x00', '\x00',               // ID is zeroed out
+  '\x81', '\x80',               // Standard query response, RA, no error
+  '\x00', '\x00',               // No questions (for simplicity)
+  '\x00', '\x01',               // 1 RR (answers)
+  '\x00', '\x00',               // 0 authority RRs
+  '\x00', '\x00',               // 0 additional RRs
+
+  '\x05', 'h', 'e', 'l', 'l', 'o',
+  '\x07', '_', 'p', 'r', 'i', 'v', 'e', 't',
+  '\x04', '_', 't', 'c', 'p',
+  '\x05', 'l', 'o', 'c', 'a', 'l',
+  '\x00',
+  '\x00', '\x10',        // TYPE is PTR.
+  '\x00', '\x01',        // CLASS is IN.
+  '\x00', '\x00',        // TTL (4 bytes) is 20 hours, 47 minutes, 48 seconds.
+  '\x00', '\x01',
+  '\x00', '\x06',        // RDLENGTH is 21 bytes.
+  '\x05', 'h', 'e', 'l', 'l', 'o'
+};
+
+const char kSamplePacketSRVA[] = {
+  // Header
+  '\x00', '\x00',               // ID is zeroed out
+  '\x81', '\x80',               // Standard query response, RA, no error
+  '\x00', '\x00',               // No questions (for simplicity)
+  '\x00', '\x02',               // 2 RR (answers)
+  '\x00', '\x00',               // 0 authority RRs
+  '\x00', '\x00',               // 0 additional RRs
+
+  '\x05', 'h', 'e', 'l', 'l', 'o',
+  '\x07', '_', 'p', 'r', 'i', 'v', 'e', 't',
+  '\x04', '_', 't', 'c', 'p',
+  '\x05', 'l', 'o', 'c', 'a', 'l',
+  '\x00',
+  '\x00', '\x21',        // TYPE is SRV.
+  '\x00', '\x01',        // CLASS is IN.
+  '\x00', '\x00',        // TTL (4 bytes) is 16 seconds.
+  '\x00', '\x10',
+  '\x00', '\x15',        // RDLENGTH is 21 bytes.
+  '\x00', '\x00',
+  '\x00', '\x00',
+  '\x22', '\xb8',  // port 8888
+  '\x07', 'm', 'y', 'h', 'e', 'l', 'l', 'o',
+  '\x05', 'l', 'o', 'c', 'a', 'l',
+  '\x00',
+
+  '\x07', 'm', 'y', 'h', 'e', 'l', 'l', 'o',
+  '\x05', 'l', 'o', 'c', 'a', 'l',
+  '\x00',
+  '\x00', '\x01',        // TYPE is A.
+  '\x00', '\x01',        // CLASS is IN.
+  '\x00', '\x00',        // TTL (4 bytes) is 16 seconds.
+  '\x00', '\x10',
+  '\x00', '\x04',        // RDLENGTH is 4 bytes.
+  '\x01', '\x02',
+  '\x03', '\x04',
+};
+
+class MockServiceWatcherDelegate : public ServiceWatcher::Delegate {
+ public:
+  MockServiceWatcherDelegate() {}
+  virtual ~MockServiceWatcherDelegate() {}
+
+  MOCK_METHOD2(OnServiceUpdated, void(ServiceWatcher::UpdateType,
+                                      const std::string&));
+};
+
+class ServiceDiscoveryTest : public ::testing::Test {
+ public:
+  ServiceDiscoveryTest()
+      : socket_factory_(new net::MockMDnsSocketFactory),
+        mdns_client_(
+            scoped_ptr<net::MDnsConnection::SocketFactory>(
+                socket_factory_)),
+        service_discovery_client_(&mdns_client_) {
+    mdns_client_.StartListening();
+  }
+
+  virtual ~ServiceDiscoveryTest() {
+  }
+
+ protected:
+  void RunFor(base::TimeDelta time_period) {
+    base::CancelableCallback<void()> callback(base::Bind(
+        &ServiceDiscoveryTest::Stop, base::Unretained(this)));
+    base::MessageLoop::current()->PostDelayedTask(
+        FROM_HERE, callback.callback(), time_period);
+
+    base::MessageLoop::current()->Run();
+    callback.Cancel();
+  }
+
+  void Stop() {
+    base::MessageLoop::current()->Quit();
+  }
+
+  net::MockMDnsSocketFactory* socket_factory_;
+  net::MDnsClientImpl mdns_client_;
+  ServiceDiscoveryClientImpl service_discovery_client_;
+  base::MessageLoop loop_;
+};
+
+TEST_F(ServiceDiscoveryTest, AddRemoveService) {
+  scoped_ptr<ServiceWatcher> watcher;
+  StrictMock<MockServiceWatcherDelegate> delegate;
+
+  watcher = service_discovery_client_.CreateServiceWatcher(
+      "_privet._tcp.local", &delegate);
+
+  watcher->Start();
+
+  EXPECT_CALL(delegate, OnServiceUpdated(ServiceWatcher::UPDATE_ADDED,
+                                         "hello._privet._tcp.local"))
+      .Times(Exactly(1));
+
+  socket_factory_->SimulateReceive(
+      kSamplePacketPTR, sizeof(kSamplePacketPTR));
+
+  EXPECT_CALL(delegate, OnServiceUpdated(ServiceWatcher::UPDATE_REMOVED,
+                                         "hello._privet._tcp.local"))
+      .Times(Exactly(1));
+
+  RunFor(base::TimeDelta::FromSeconds(2));
+};
+
+TEST_F(ServiceDiscoveryTest, DiscoverNewServices) {
+  scoped_ptr<ServiceWatcher> watcher;
+  StrictMock<MockServiceWatcherDelegate> delegate;
+
+  watcher = service_discovery_client_.CreateServiceWatcher(
+      "_privet._tcp.local", &delegate);
+
+  watcher->Start();
+
+  EXPECT_CALL(*socket_factory_, OnSendTo(_))
+      .Times(2);
+
+  watcher->DiscoverNewServices(false);
+};
+
+TEST_F(ServiceDiscoveryTest, GetAvailableServices) {
+  NiceMock<MockServiceWatcherDelegate> delegate;
+
+  std::vector<std::string> data_expected;
+  std::vector<std::string> data;
+
+  data_expected.push_back("hello._privet._tcp.local");
+
+  scoped_ptr<ServiceWatcher> watcher =
+      service_discovery_client_.CreateServiceWatcher(
+          "_privet._tcp.local", &delegate);
+
+  watcher->Start();
+
+  socket_factory_->SimulateReceive(
+      kSamplePacketPTR, sizeof(kSamplePacketPTR));
+
+  watcher->GetAvailableServices(&data);
+
+  EXPECT_EQ(data, data_expected);
+};
+
+TEST_F(ServiceDiscoveryTest, ReadCachedServices) {
+  NiceMock<MockServiceWatcherDelegate> delegate_irrelevant;
+  scoped_ptr<ServiceWatcher> watcher_irrelevant =
+      service_discovery_client_.CreateServiceWatcher(
+          "_privet._tcp.local", &delegate_irrelevant);
+
+  watcher_irrelevant->Start();
+
+  socket_factory_->SimulateReceive(
+      kSamplePacketPTR, sizeof(kSamplePacketPTR));
+
+  StrictMock<MockServiceWatcherDelegate> delegate;
+  scoped_ptr<ServiceWatcher> watcher =
+      service_discovery_client_.CreateServiceWatcher(
+          "_privet._tcp.local", &delegate);
+
+  watcher->Start();
+
+  EXPECT_CALL(delegate, OnServiceUpdated(ServiceWatcher::UPDATE_ADDED,
+                                         "hello._privet._tcp.local"))
+      .Times(Exactly(1));
+
+  watcher->ReadCachedServices();
+
+  base::MessageLoop::current()->RunUntilIdle();
+};
+
+TEST_F(ServiceDiscoveryTest, OnServiceChanged) {
+  StrictMock<MockServiceWatcherDelegate> delegate;
+  scoped_ptr<ServiceWatcher> watcher =
+      service_discovery_client_.CreateServiceWatcher(
+          "_privet._tcp.local", &delegate);
+
+  watcher->Start();
+
+  EXPECT_CALL(delegate, OnServiceUpdated(ServiceWatcher::UPDATE_ADDED,
+                                         "hello._privet._tcp.local"))
+      .Times(Exactly(1));
+
+  socket_factory_->SimulateReceive(
+      kSamplePacketPTR, sizeof(kSamplePacketPTR));
+
+  base::MessageLoop::current()->RunUntilIdle();
+
+  EXPECT_CALL(delegate, OnServiceUpdated(ServiceWatcher::UPDATE_CHANGED,
+                                         "hello._privet._tcp.local"))
+      .Times(Exactly(1));
+
+  socket_factory_->SimulateReceive(
+      kSamplePacketSRV, sizeof(kSamplePacketSRV));
+
+  socket_factory_->SimulateReceive(
+      kSamplePacketTXT, sizeof(kSamplePacketTXT));
+
+  base::MessageLoop::current()->RunUntilIdle();
+};
+
+TEST_F(ServiceDiscoveryTest, SinglePacket) {
+  StrictMock<MockServiceWatcherDelegate> delegate;
+  scoped_ptr<ServiceWatcher> watcher =
+      service_discovery_client_.CreateServiceWatcher(
+          "_privet._tcp.local", &delegate);
+
+  watcher->Start();
+
+  EXPECT_CALL(delegate, OnServiceUpdated(ServiceWatcher::UPDATE_ADDED,
+                                         "hello._privet._tcp.local"))
+      .Times(Exactly(1));
+
+  socket_factory_->SimulateReceive(
+      kSamplePacketPTR, sizeof(kSamplePacketPTR));
+
+  // Reset the "already updated" flag.
+  base::MessageLoop::current()->RunUntilIdle();
+
+  EXPECT_CALL(delegate, OnServiceUpdated(ServiceWatcher::UPDATE_CHANGED,
+                                         "hello._privet._tcp.local"))
+      .Times(Exactly(1));
+
+  socket_factory_->SimulateReceive(
+      kSamplePacketSRV, sizeof(kSamplePacketSRV));
+
+  socket_factory_->SimulateReceive(
+      kSamplePacketTXT, sizeof(kSamplePacketTXT));
+
+  base::MessageLoop::current()->RunUntilIdle();
+};
+
+class ServiceResolverTest : public ServiceDiscoveryTest {
+ public:
+  ServiceResolverTest() {
+    metadata_expected_.push_back("hello");
+    address_expected_ = net::HostPortPair("myhello.local", 8888);
+    ip_address_expected_.push_back(1);
+    ip_address_expected_.push_back(2);
+    ip_address_expected_.push_back(3);
+    ip_address_expected_.push_back(4);
+  }
+
+  ~ServiceResolverTest() {
+  }
+
+  void SetUp()  {
+    resolver_ = service_discovery_client_.CreateServiceResolver(
+        "hello._privet._tcp.local",
+        base::Bind(&ServiceResolverTest::OnFinishedResolving,
+                   base::Unretained(this)));
+  }
+
+  void OnFinishedResolving(ServiceResolver::RequestStatus request_status,
+                           const ServiceDescription& service_description) {
+    OnFinishedResolvingInternal(request_status);
+  }
+
+  MOCK_METHOD1(OnFinishedResolvingInternal, void(
+      ServiceResolver::RequestStatus));
+
+ protected:
+  scoped_ptr<ServiceResolver> resolver_;
+  net::IPAddressNumber ip_address_;
+  net::HostPortPair address_expected_;
+  std::vector<std::string> metadata_expected_;
+  net::IPAddressNumber ip_address_expected_;
+};
+
+TEST_F(ServiceResolverTest, TxtAndSrvButNoA) {
+  EXPECT_CALL(*socket_factory_, OnSendTo(_))
+      .Times(4);
+
+  EXPECT_FALSE(resolver_->IsResolving());
+  EXPECT_FALSE(resolver_->HasResolved());
+  EXPECT_TRUE(resolver_->StartResolving());
+  EXPECT_TRUE(resolver_->IsResolving());
+  EXPECT_FALSE(resolver_->HasResolved());
+
+  socket_factory_->SimulateReceive(
+      kSamplePacketSRV, sizeof(kSamplePacketSRV));
+
+  base::MessageLoop::current()->RunUntilIdle();
+
+  EXPECT_CALL(*this, OnFinishedResolvingInternal(
+      ServiceResolver::STATUS_SUCCESS));
+
+  socket_factory_->SimulateReceive(
+      kSamplePacketTXT, sizeof(kSamplePacketTXT));
+
+  EXPECT_EQ(address_expected_.ToString(),
+            resolver_->GetServiceDescription().address.ToString());
+  EXPECT_EQ(metadata_expected_, resolver_->GetServiceDescription().metadata);
+  EXPECT_EQ(net::IPAddressNumber(),
+            resolver_->GetServiceDescription().ip_address);
+};
+
+TEST_F(ServiceResolverTest, TxtSrvAndA) {
+  EXPECT_CALL(*socket_factory_, OnSendTo(_))
+      .Times(4);
+
+  EXPECT_FALSE(resolver_->IsResolving());
+  EXPECT_FALSE(resolver_->HasResolved());
+  EXPECT_TRUE(resolver_->StartResolving());
+  EXPECT_TRUE(resolver_->IsResolving());
+  EXPECT_FALSE(resolver_->HasResolved());
+
+  EXPECT_CALL(*this, OnFinishedResolvingInternal(
+      ServiceResolver::STATUS_SUCCESS));
+
+  socket_factory_->SimulateReceive(
+      kSamplePacketTXT, sizeof(kSamplePacketTXT));
+
+  socket_factory_->SimulateReceive(
+      kSamplePacketSRVA, sizeof(kSamplePacketSRVA));
+
+  EXPECT_EQ(address_expected_.ToString(),
+            resolver_->GetServiceDescription().address.ToString());
+  EXPECT_EQ(metadata_expected_, resolver_->GetServiceDescription().metadata);
+  EXPECT_EQ(ip_address_expected_,
+            resolver_->GetServiceDescription().ip_address);
+};
+
+TEST_F(ServiceResolverTest, JustSrv) {
+  EXPECT_CALL(*socket_factory_, OnSendTo(_))
+      .Times(4);
+
+  EXPECT_FALSE(resolver_->IsResolving());
+  EXPECT_FALSE(resolver_->HasResolved());
+  EXPECT_TRUE(resolver_->StartResolving());
+  EXPECT_TRUE(resolver_->IsResolving());
+  EXPECT_FALSE(resolver_->HasResolved());
+
+  EXPECT_CALL(*this, OnFinishedResolvingInternal(
+      ServiceResolver::STATUS_SUCCESS));
+
+  socket_factory_->SimulateReceive(
+      kSamplePacketSRVA, sizeof(kSamplePacketSRVA));
+
+  // TODO(noamsml): When NSEC record support is added, change this to use an
+  // NSEC record.
+  RunFor(base::TimeDelta::FromSeconds(4));
+
+  EXPECT_EQ(address_expected_.ToString(),
+            resolver_->GetServiceDescription().address.ToString());
+  EXPECT_EQ(std::vector<std::string>() ,
+            resolver_->GetServiceDescription().metadata);
+  EXPECT_EQ(ip_address_expected_,
+            resolver_->GetServiceDescription().ip_address);
+};
+
+TEST_F(ServiceResolverTest, WithNothing) {
+  EXPECT_CALL(*socket_factory_, OnSendTo(_))
+      .Times(4);
+
+  EXPECT_FALSE(resolver_->IsResolving());
+  EXPECT_FALSE(resolver_->HasResolved());
+  EXPECT_TRUE(resolver_->StartResolving());
+  EXPECT_TRUE(resolver_->IsResolving());
+  EXPECT_FALSE(resolver_->HasResolved());
+
+  EXPECT_CALL(*this, OnFinishedResolvingInternal(
+      ServiceResolver::STATUS_REQUEST_TIMEOUT));
+
+  // TODO(noamsml): When NSEC record support is added, change this to use an
+  // NSEC record.
+  RunFor(base::TimeDelta::FromSeconds(4));
+};
+
+}  // namespace
+
+}  // namespace local_discovery
diff --git a/chrome/browser/logging_chrome_browsertest.cc b/chrome/browser/logging_chrome_browsertest.cc
index d45b3f2..d3211fb 100644
--- a/chrome/browser/logging_chrome_browsertest.cc
+++ b/chrome/browser/logging_chrome_browsertest.cc
@@ -5,17 +5,17 @@
 #include "base/command_line.h"
 #include "base/environment.h"
 #include "chrome/common/chrome_switches.h"
-#include "chrome/common/url_constants.h"
 #include "chrome/common/env_vars.h"
 #include "chrome/common/logging_chrome.h"
+#include "chrome/common/url_constants.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/notification_types.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/web_contents.h"
-#include "googleurl/src/gurl.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
 
 using content::RenderProcessHost;
 
diff --git a/chrome/browser/mac/dock.mm b/chrome/browser/mac/dock.mm
index 51ac395..e55f4c8 100644
--- a/chrome/browser/mac/dock.mm
+++ b/chrome/browser/mac/dock.mm
@@ -47,7 +47,7 @@
 // Foundation data types and returns an autoreleased NSDictionary.
 NSDictionary* NSURLCopyDictionary(NSURL* url) {
   CFURLRef url_cf = base::mac::NSToCFCast(url);
-  base::mac::ScopedCFTypeRef<CFPropertyListRef> property_list(
+  base::ScopedCFTypeRef<CFPropertyListRef> property_list(
       _CFURLCopyPropertyListRepresentation(url_cf));
   CFDictionaryRef dictionary_cf =
       base::mac::CFCast<CFDictionaryRef>(property_list);
@@ -65,7 +65,7 @@
 // on Foundation data types and returns an autoreleased NSURL.
 NSURL* NSURLCreateFromDictionary(NSDictionary* dictionary) {
   CFDictionaryRef dictionary_cf = base::mac::NSToCFCast(dictionary);
-  base::mac::ScopedCFTypeRef<CFURLRef> url_cf(
+  base::ScopedCFTypeRef<CFURLRef> url_cf(
       _CFURLCreateFromPropertyListRepresentation(NULL, dictionary_cf));
   NSURL* url = base::mac::CFToNSCast(url_cf);
 
diff --git a/chrome/browser/mac/install_from_dmg.mm b/chrome/browser/mac/install_from_dmg.mm
index 56912db..ed64829 100644
--- a/chrome/browser/mac/install_from_dmg.mm
+++ b/chrome/browser/mac/install_from_dmg.mm
@@ -121,17 +121,15 @@
   }
 
   if (image_path) {
-    base::mac::ScopedCFTypeRef<CFTypeRef> image_path_cftyperef(
-        IORegistryEntryCreateCFProperty(hdix_drive,
-                                        CFSTR("image-path"),
-                                        NULL,
-                                        0));
+    base::ScopedCFTypeRef<CFTypeRef> image_path_cftyperef(
+        IORegistryEntryCreateCFProperty(
+            hdix_drive, CFSTR("image-path"), NULL, 0));
     if (!image_path_cftyperef) {
       LOG(ERROR) << "IORegistryEntryCreateCFProperty";
       return true;
     }
     if (CFGetTypeID(image_path_cftyperef) != CFDataGetTypeID()) {
-      base::mac::ScopedCFTypeRef<CFStringRef> observed_type_cf(
+      base::ScopedCFTypeRef<CFStringRef> observed_type_cf(
           CFCopyTypeIDDescription(CFGetTypeID(image_path_cftyperef)));
       std::string observed_type;
       if (observed_type_cf) {
@@ -516,7 +514,7 @@
         run_loop_running(false) {
   }
 
-  base::mac::ScopedCFTypeRef<DADissenterRef> dissenter;
+  base::ScopedCFTypeRef<DADissenterRef> dissenter;
   bool callback_called;
   bool run_loop_running;
 
@@ -605,13 +603,13 @@
 }  // namespace
 
 void EjectAndTrashDiskImage(const std::string& dmg_bsd_device_name) {
-  base::mac::ScopedCFTypeRef<DASessionRef> session(DASessionCreate(NULL));
+  base::ScopedCFTypeRef<DASessionRef> session(DASessionCreate(NULL));
   if (!session.get()) {
     LOG(ERROR) << "DASessionCreate";
     return;
   }
 
-  base::mac::ScopedCFTypeRef<DADiskRef> disk(
+  base::ScopedCFTypeRef<DADiskRef> disk(
       DADiskCreateFromBSDName(NULL, session, dmg_bsd_device_name.c_str()));
   if (!disk.get()) {
     LOG(ERROR) << "DADiskCreateFromBSDName";
diff --git a/chrome/browser/mac/keychain_reauthorize.mm b/chrome/browser/mac/keychain_reauthorize.mm
index 3e91511..24d046d 100644
--- a/chrome/browser/mac/keychain_reauthorize.mm
+++ b/chrome/browser/mac/keychain_reauthorize.mm
@@ -118,12 +118,10 @@
   // use CSSM_DL_DB_RECORD_ALL_KEYS, but that doesn't work.
   // CSSM_DL_DB_RECORD_ANY (as used by SecurityTool's keychain-dump) does
   // work.
-  base::mac::ScopedCFTypeRef<SecKeychainSearchRef> search(
-    CrSKeychainSearchCreateFromAttributes(NULL,
-                                          CSSM_DL_DB_RECORD_ANY,
-                                          NULL));
+  base::ScopedCFTypeRef<SecKeychainSearchRef> search(
+      CrSKeychainSearchCreateFromAttributes(NULL, CSSM_DL_DB_RECORD_ANY, NULL));
 
-  base::mac::ScopedCFTypeRef<SecTrustedApplicationRef> this_application(
+  base::ScopedCFTypeRef<SecTrustedApplicationRef> this_application(
       CrSTrustedApplicationCreateFromPath(NULL));
 
   std::vector<std::string> requirement_matches =
@@ -178,9 +176,9 @@
 
 std::string RequirementStringForApplication(
     SecTrustedApplicationRef application) {
-  base::mac::ScopedCFTypeRef<SecRequirementRef> requirement(
+  base::ScopedCFTypeRef<SecRequirementRef> requirement(
       CrSTrustedApplicationCopyRequirement(application));
-  base::mac::ScopedCFTypeRef<CFStringRef> requirement_string_cf(
+  base::ScopedCFTypeRef<CFStringRef> requirement_string_cf(
       CrSRequirementCopyString(requirement, kSecCSDefaultFlags));
   if (!requirement_string_cf) {
     return std::string();
@@ -298,7 +296,7 @@
     SecTrustedApplicationRef this_application) {
   std::vector<CrSKeychainItemAndAccess> items_and_accesses;
 
-  base::mac::ScopedCFTypeRef<SecKeychainItemRef> item;
+  base::ScopedCFTypeRef<SecKeychainItemRef> item;
   while (item.reset(CrSKeychainSearchCopyNext(search)), item) {
     scoped_ptr<CrSKeychainItemAndAccess> item_and_access(
         KCItemToKCItemAndReauthorizedAccess(item,
@@ -321,10 +319,8 @@
     return NULL;
   }
 
-  base::mac::ScopedCFTypeRef<SecAccessRef> access(
-      CrSKeychainItemCopyAccess(item));
-  base::mac::ScopedCFTypeRef<CFArrayRef> acl_list(
-      CrSAccessCopyACLList(access));
+  base::ScopedCFTypeRef<SecAccessRef> access(CrSKeychainItemCopyAccess(item));
+  base::ScopedCFTypeRef<CFArrayRef> acl_list(CrSAccessCopyACLList(access));
   if (!acl_list) {
     return NULL;
   }
@@ -444,7 +440,7 @@
 void WriteKCItemAndReauthorizedAccess(
     const CrSKeychainItemAndAccess& item_and_reauthorized_access) {
   SecKeychainItemRef old_item = item_and_reauthorized_access.item();
-  base::mac::ScopedCFTypeRef<SecKeychainRef> keychain(
+  base::ScopedCFTypeRef<SecKeychainRef> keychain(
       CrSKeychainItemCopyKeychain(old_item));
 
   ScopedCrSKeychainItemAttributesAndData old_attributes_and_data(
@@ -501,7 +497,7 @@
     return;
   }
 
-  base::mac::ScopedCFTypeRef<SecKeychainItemRef> new_item(
+  base::ScopedCFTypeRef<SecKeychainItemRef> new_item(
       CrSKeychainItemCreateFromContent(new_attributes_and_data,
                                        keychain,
                                        item_and_reauthorized_access.access()));
diff --git a/chrome/browser/mac/keystone_glue.h b/chrome/browser/mac/keystone_glue.h
index 8b696c2..d85763c 100644
--- a/chrome/browser/mac/keystone_glue.h
+++ b/chrome/browser/mac/keystone_glue.h
@@ -12,7 +12,7 @@
 #import <Foundation/Foundation.h>
 
 #include "base/mac/scoped_authorizationref.h"
-#import "base/memory/scoped_nsobject.h"
+#import "base/mac/scoped_nsobject.h"
 
 // Possible outcomes of various operations.  A version may accompany some of
 // these, but beware: a version is never required.  For statuses that can be
@@ -89,7 +89,7 @@
   NSTimer* timer_;  // strong
 
   // The most recent kAutoupdateStatusNotification notification posted.
-  scoped_nsobject<NSNotification> recentNotification_;
+  base::scoped_nsobject<NSNotification> recentNotification_;
 
   // The authorization object, when it needs to persist because it's being
   // carried across threads.
diff --git a/chrome/browser/mac/keystone_glue.mm b/chrome/browser/mac/keystone_glue.mm
index 0a97252..f93e86d 100644
--- a/chrome/browser/mac/keystone_glue.mm
+++ b/chrome/browser/mac/keystone_glue.mm
@@ -97,9 +97,9 @@
     [target_ performSelector:sel_ withObject:arg_];
   }
 
-  scoped_nsobject<id> target_;
+  base::scoped_nsobject<id> target_;
   SEL sel_;
-  scoped_nsobject<id> arg_;
+  base::scoped_nsobject<id> arg_;
 };
 
 }  // namespace
diff --git a/chrome/browser/mac/relauncher.cc b/chrome/browser/mac/relauncher.cc
index 1f3db81..aa4794f 100644
--- a/chrome/browser/mac/relauncher.cc
+++ b/chrome/browser/mac/relauncher.cc
@@ -34,15 +34,6 @@
 #include "content/public/common/content_switches.h"
 #include "content/public/common/main_function_params.h"
 
-// RTLD_MAIN_ONLY is supported as of Mac OS X 10.5, but <dlfcn.h> does not
-// define it in the 10.5 SDK. It is present in the 10.6 SDK and is documented
-// as working on 10.5 and later. The source code for the version of dyld that
-// shipped in 10.5, dyld-95.3/src/dyldAPIs.cpp, confirms that this feature is
-// supported. Provide a fallback definition here.
-#if MAC_OS_X_VERSION_MAX_ALLOWED == MAC_OS_X_VERSION_10_5  // 10.5 SDK
-#define RTLD_MAIN_ONLY ((void*)-5)  // Search main executable only.
-#endif
-
 namespace mac_relauncher {
 
 const char* const kRelauncherDMGDeviceArg = "--dmg-device=";
@@ -294,7 +285,7 @@
   // won't contain the argv[0] of the relauncher process, the
   // RelauncherTypeArg() at argv[1], kRelauncherArgSeparator, or the
   // executable path of the process to be launched.
-  base::mac::ScopedCFTypeRef<CFMutableArrayRef> relaunch_args(
+  base::ScopedCFTypeRef<CFMutableArrayRef> relaunch_args(
       CFArrayCreateMutable(NULL, argc - 4, &kCFTypeArrayCallBacks));
   if (!relaunch_args) {
     LOG(ERROR) << "CFArrayCreateMutable";
@@ -335,7 +326,7 @@
         relaunch_executable.assign(arg);
         seen_relaunch_executable = true;
       } else {
-        base::mac::ScopedCFTypeRef<CFStringRef> arg_cf(
+        base::ScopedCFTypeRef<CFStringRef> arg_cf(
             base::SysUTF8ToCFStringRef(arg));
         if (!arg_cf) {
           LOG(ERROR) << "base::SysUTF8ToCFStringRef failed for " << arg;
diff --git a/chrome/browser/mac/security_wrappers.cc b/chrome/browser/mac/security_wrappers.cc
index 5e34b8a..85488d1 100644
--- a/chrome/browser/mac/security_wrappers.cc
+++ b/chrome/browser/mac/security_wrappers.cc
@@ -7,27 +7,6 @@
 #include "base/mac/foundation_util.h"
 #include "base/mac/mac_logging.h"
 
-#if !defined(MAC_OS_X_VERSION_10_5) || \
-    MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5
-
-enum {
-  // New Security.framework code uses errSecSuccess instead of noErr, but the
-  // constant is new in 10.6.
-  errSecSuccess = 0
-};
-
-// This exists on 10.5 for linking, but but because
-// <Security/SecRequirement.h> did not ship in the SDK in that version, no
-// declaration is present. This declaration is correct on 10.5, see
-// 10.5.0 libsecurity_codesigning-32568/lib/SecRequirement.h.
-extern "C" {
-OSStatus SecRequirementCopyString(SecRequirementRef requirement,
-                                  SecCSFlags flags,
-                                  CFStringRef* text);
-}  // extern "C"
-
-#endif
-
 extern "C" {
 OSStatus SecTrustedApplicationCopyRequirement(
     SecTrustedApplicationRef application,
@@ -361,7 +340,14 @@
     case kSecGenericPasswordItemClass:
       item_id = CSSM_DL_DB_RECORD_GENERIC_PASSWORD;
       break;
+    // kSecInternetPasswordItemClass is marked as deprecated in the 10.9 sdk,
+    // but the files in libsecurity_keychain from 10.7 referenced above still
+    // use it. Also see rdar://14281375 /
+    // http://openradar.appspot.com/radar?id=3143412 .
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
     case kSecAppleSharePasswordItemClass:
+#pragma clang diagnostic pop
       item_id = CSSM_DL_DB_RECORD_APPLESHARE_PASSWORD;
       break;
     default:
diff --git a/chrome/browser/mac/security_wrappers.h b/chrome/browser/mac/security_wrappers.h
index 42a7801..173c130 100644
--- a/chrome/browser/mac/security_wrappers.h
+++ b/chrome/browser/mac/security_wrappers.h
@@ -45,8 +45,8 @@
   SecAccessRef access() const { return access_; }
 
  private:
-  base::mac::ScopedCFTypeRef<SecKeychainItemRef> item_;
-  base::mac::ScopedCFTypeRef<SecAccessRef> access_;
+  base::ScopedCFTypeRef<SecKeychainItemRef> item_;
+  base::ScopedCFTypeRef<SecAccessRef> access_;
 };
 
 // Holds the return value from CrSACLCopySimpleContents and an argument to
@@ -56,8 +56,8 @@
   CrSACLSimpleContents();
   ~CrSACLSimpleContents();
 
-  base::mac::ScopedCFTypeRef<CFArrayRef> application_list;
-  base::mac::ScopedCFTypeRef<CFStringRef> description;
+  base::ScopedCFTypeRef<CFArrayRef> application_list;
+  base::ScopedCFTypeRef<CFStringRef> description;
   CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR prompt_selector;
 };
 
diff --git a/chrome/browser/managed_mode/managed_mode.cc b/chrome/browser/managed_mode/managed_mode.cc
index 1f3912a..4375615 100644
--- a/chrome/browser/managed_mode/managed_mode.cc
+++ b/chrome/browser/managed_mode/managed_mode.cc
@@ -51,7 +51,8 @@
 
   CommandLine* command_line = CommandLine::ForCurrentProcess();
 
-  if (ManagedUserService::AreManagedUsersEnabled()) {
+  if (CommandLine::ForCurrentProcess()->HasSwitch(
+      switches::kEnableManagedUsers)) {
     RecordAction(UserMetricsAction("ManagedMode_StartupEnableManagedSwitch"));
   }
 
diff --git a/chrome/browser/managed_mode/managed_mode_interstitial.cc b/chrome/browser/managed_mode/managed_mode_interstitial.cc
index d444fca..e74e665 100644
--- a/chrome/browser/managed_mode/managed_mode_interstitial.cc
+++ b/chrome/browser/managed_mode/managed_mode_interstitial.cc
@@ -52,19 +52,25 @@
   DictionaryValue strings;
   strings.SetString("blockPageTitle",
                     l10n_util::GetStringUTF16(IDS_BLOCK_INTERSTITIAL_TITLE));
-  strings.SetString("blockPageMessage",
-                    l10n_util::GetStringUTF16(IDS_BLOCK_INTERSTITIAL_MESSAGE));
+
+  Profile* profile =
+      Profile::FromBrowserContext(web_contents_->GetBrowserContext());
+  ManagedUserService* managed_user_service =
+      ManagedUserServiceFactory::GetForProfile(profile);
+  string16 custodian = UTF8ToUTF16(managed_user_service->GetCustodianName());
+  strings.SetString(
+      "blockPageMessage",
+      l10n_util::GetStringFUTF16(IDS_BLOCK_INTERSTITIAL_MESSAGE, custodian));
+
   strings.SetString("backButton", l10n_util::GetStringUTF16(IDS_BACK_BUTTON));
   strings.SetString(
       "requestAccessButton",
       l10n_util::GetStringUTF16(IDS_BLOCK_INTERSTITIAL_REQUEST_ACCESS_BUTTON));
 
-  // TODO(sergiu): Set name to real value here.
-  std::string custodian_name("John Doe");
   strings.SetString(
       "requestSentMessage",
       l10n_util::GetStringFUTF16(IDS_BLOCK_INTERSTITIAL_REQUEST_SENT_MESSAGE,
-                                 ASCIIToUTF16(custodian_name)));
+                                 custodian));
 
   webui::SetFontAndTextDirection(&strings);
 
diff --git a/chrome/browser/managed_mode/managed_mode_interstitial.h b/chrome/browser/managed_mode/managed_mode_interstitial.h
index ece0f31..656727c 100644
--- a/chrome/browser/managed_mode/managed_mode_interstitial.h
+++ b/chrome/browser/managed_mode/managed_mode_interstitial.h
@@ -11,7 +11,7 @@
 #include "base/compiler_specific.h"
 #include "base/memory/weak_ptr.h"
 #include "content/public/browser/interstitial_page_delegate.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 namespace content {
 class InterstitialPage;
diff --git a/chrome/browser/managed_mode/managed_mode_navigation_observer.cc b/chrome/browser/managed_mode/managed_mode_navigation_observer.cc
index c7666f8..7681a11 100644
--- a/chrome/browser/managed_mode/managed_mode_navigation_observer.cc
+++ b/chrome/browser/managed_mode/managed_mode_navigation_observer.cc
@@ -125,7 +125,7 @@
 }
 
 string16 ManagedModeWarningInfobarDelegate::GetMessageText() const {
-  return l10n_util::GetStringUTF16(IDS_MANAGED_MODE_WARNING_MESSAGE);
+  return l10n_util::GetStringUTF16(IDS_MANAGED_USER_WARN_INFOBAR_MESSAGE);
 }
 
 int ManagedModeWarningInfobarDelegate::GetButtons() const {
@@ -135,7 +135,7 @@
 string16 ManagedModeWarningInfobarDelegate::GetButtonLabel(
     InfoBarButton button) const {
   DCHECK_EQ(BUTTON_OK, button);
-  return l10n_util::GetStringUTF16(IDS_MANAGED_MODE_GO_BACK_ACTION);
+  return l10n_util::GetStringUTF16(IDS_MANAGED_USER_WARN_INFOBAR_GO_BACK);
 }
 
 bool ManagedModeWarningInfobarDelegate::Accept() {
diff --git a/chrome/browser/managed_mode/managed_mode_unittest.cc b/chrome/browser/managed_mode/managed_mode_unittest.cc
index d1d0241..a3fb02f 100644
--- a/chrome/browser/managed_mode/managed_mode_unittest.cc
+++ b/chrome/browser/managed_mode/managed_mode_unittest.cc
@@ -73,7 +73,7 @@
  public:
   BrowserFixture(FakeManagedMode* managed_mode,
                  TestingProfile* profile) {
-    Browser::CreateParams params(profile, chrome::HOST_DESKTOP_TYPE_NATIVE);
+    Browser::CreateParams params(profile, chrome::GetActiveDesktop());
     params.window = &window_;
     browser_.reset(new Browser(params));
   }
diff --git a/chrome/browser/managed_mode/managed_mode_url_filter.cc b/chrome/browser/managed_mode/managed_mode_url_filter.cc
index 85be975..189773e 100644
--- a/chrome/browser/managed_mode/managed_mode_url_filter.cc
+++ b/chrome/browser/managed_mode/managed_mode_url_filter.cc
@@ -15,7 +15,7 @@
 #include "base/threading/sequenced_worker_pool.h"
 #include "content/public/browser/browser_thread.h"
 #include "extensions/common/matcher/url_matcher.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 using content::BrowserThread;
 using extensions::URLMatcher;
diff --git a/chrome/browser/managed_mode/managed_mode_url_filter_unittest.cc b/chrome/browser/managed_mode/managed_mode_url_filter_unittest.cc
index f5ed8c5..4eaa308 100644
--- a/chrome/browser/managed_mode/managed_mode_url_filter_unittest.cc
+++ b/chrome/browser/managed_mode/managed_mode_url_filter_unittest.cc
@@ -7,8 +7,8 @@
 #include "base/message_loop.h"
 #include "base/run_loop.h"
 #include "chrome/browser/managed_mode/managed_mode_url_filter.h"
-#include "googleurl/src/gurl.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
 
 class ManagedModeURLFilterTest : public ::testing::Test,
                                  public ManagedModeURLFilter::Observer {
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 de1a0fa..5c5a1a6 100644
--- a/chrome/browser/managed_mode/managed_user_refresh_token_fetcher.cc
+++ b/chrome/browser/managed_mode/managed_user_refresh_token_fetcher.cc
@@ -12,6 +12,7 @@
 #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"
 #include "google_apis/gaia/gaia_oauth_client.h"
 #include "google_apis/gaia/gaia_urls.h"
 #include "google_apis/gaia/google_service_auth_error.h"
@@ -25,6 +26,7 @@
 
 using base::Time;
 using gaia::GaiaOAuthClient;
+using GaiaConstants::kChromeSyncManagedOAuth2Scope;
 using net::URLFetcher;
 using net::URLFetcherDelegate;
 using net::URLRequestContextGetter;
@@ -33,9 +35,6 @@
 
 const int kNumRetries = 1;
 
-static const char kChromeSyncManagedScope[] =
-    "https://www.googleapis.com/auth/chromesync_playpen";
-
 static const char kIssueTokenBodyFormat[] =
     "client_id=%s"
     "&scope=%s"
@@ -161,7 +160,7 @@
       kIssueTokenBodyFormat,
       net::EscapeUrlEncodedData(
           GaiaUrls::GetInstance()->oauth2_chrome_client_id(), true).c_str(),
-      net::EscapeUrlEncodedData(kChromeSyncManagedScope, 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());
@@ -222,9 +221,7 @@
   GaiaUrls* urls = GaiaUrls::GetInstance();
   client_info.client_id = urls->oauth2_chrome_client_id();
   client_info.client_secret = urls->oauth2_chrome_client_secret();
-  gaia_oauth_client_.reset(
-      new gaia::GaiaOAuthClient(GaiaUrls::GetInstance()->oauth2_token_url(),
-                                context_));
+  gaia_oauth_client_.reset(new gaia::GaiaOAuthClient(context_));
   gaia_oauth_client_->GetTokensFromAuthCode(client_info, auth_code, kNumRetries,
                                             this);
 }
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 d488c11..424ed86 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
@@ -11,6 +11,7 @@
 #include "chrome/browser/signin/oauth2_token_service.h"
 #include "chrome/test/base/testing_profile.h"
 #include "content/public/test/test_browser_thread.h"
+#include "google_apis/gaia/gaia_oauth_client.h"
 #include "google_apis/gaia/gaia_urls.h"
 #include "google_apis/gaia/google_service_auth_error.h"
 #include "net/base/net_errors.h"
@@ -258,7 +259,8 @@
 
 net::TestURLFetcher*
 ManagedUserRefreshTokenFetcherTest::GetRefreshTokenRequest() {
-  net::TestURLFetcher* url_fetcher = url_fetcher_factory_.GetFetcherByID(0);
+  net::TestURLFetcher* url_fetcher = url_fetcher_factory_.GetFetcherByID(
+      gaia::GaiaOAuthClient::kUrlFetcherId);
   if (!url_fetcher)
     return NULL;
 
diff --git a/chrome/browser/managed_mode/managed_user_registration_service.cc b/chrome/browser/managed_mode/managed_user_registration_service.cc
index 25c5954..ae0da0e 100644
--- a/chrome/browser/managed_mode/managed_user_registration_service.cc
+++ b/chrome/browser/managed_mode/managed_user_registration_service.cc
@@ -74,7 +74,8 @@
     : weak_ptr_factory_(this),
       prefs_(prefs),
       token_fetcher_(token_fetcher.Pass()),
-      pending_managed_user_acknowledged_(false) {
+      pending_managed_user_acknowledged_(false),
+      download_profile_(NULL) {
   pref_change_registrar_.Init(prefs);
   pref_change_registrar_.Add(
       prefs::kGoogleServicesLastUsername,
@@ -143,6 +144,18 @@
                  weak_ptr_factory_.GetWeakPtr(), info.name));
 }
 
+void ManagedUserRegistrationService::DownloadProfile(
+    Profile* profile,
+    const DownloadProfileCallback& callback) {
+  download_callback_ = callback;
+  download_profile_ = profile;
+  // If another profile download is in progress, drop it. It's not worth
+  // queueing them up, and more likely that the one that hasn't ended yet is
+  // failing somehow than that the new one won't succeed.
+  profile_downloader_.reset(new ProfileDownloader(this));
+  profile_downloader_->Start();
+}
+
 void ManagedUserRegistrationService::CancelPendingRegistration() {
   AbortPendingRegistration(
       false,  // Don't run the callback. The error will be ignored.
@@ -399,3 +412,39 @@
   pending_managed_user_id_.clear();
   pending_managed_user_acknowledged_ = false;
 }
+
+bool ManagedUserRegistrationService::NeedsProfilePicture() const {
+  return false;
+}
+
+int ManagedUserRegistrationService::GetDesiredImageSideLength() const {
+  return 0;
+}
+
+std::string ManagedUserRegistrationService::GetCachedPictureURL() const {
+  return std::string();
+}
+
+Profile* ManagedUserRegistrationService::GetBrowserProfile() {
+  DCHECK(download_profile_);
+  return download_profile_;
+}
+
+void ManagedUserRegistrationService::OnProfileDownloadComplete() {
+  download_callback_.Reset();
+  download_profile_ = NULL;
+  profile_downloader_.reset();
+}
+
+void ManagedUserRegistrationService::OnProfileDownloadSuccess(
+    ProfileDownloader* downloader) {
+  download_callback_.Run(downloader->GetProfileFullName());
+  OnProfileDownloadComplete();
+}
+
+void ManagedUserRegistrationService::OnProfileDownloadFailure(
+    ProfileDownloader* downloader,
+    ProfileDownloaderDelegate::FailureReason reason) {
+  // Ignore failures; proceed without the custodian's name.
+  OnProfileDownloadComplete();
+}
diff --git a/chrome/browser/managed_mode/managed_user_registration_service.h b/chrome/browser/managed_mode/managed_user_registration_service.h
index c2938f4..c069ff4 100644
--- a/chrome/browser/managed_mode/managed_user_registration_service.h
+++ b/chrome/browser/managed_mode/managed_user_registration_service.h
@@ -12,7 +12,9 @@
 #include "base/memory/weak_ptr.h"
 #include "base/prefs/pref_change_registrar.h"
 #include "base/strings/string16.h"
-#include "base/timer.h"
+#include "base/timer/timer.h"
+#include "chrome/browser/profiles/profile_downloader.h"
+#include "chrome/browser/profiles/profile_downloader_delegate.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "components/browser_context_keyed_service/browser_context_keyed_service.h"
 #include "sync/api/syncable_service.h"
@@ -40,7 +42,8 @@
 // management server and associating it with its custodian. It is owned by the
 // custodian's profile.
 class ManagedUserRegistrationService : public BrowserContextKeyedService,
-                                       public syncer::SyncableService {
+                                       public syncer::SyncableService,
+                                       public ProfileDownloaderDelegate {
  public:
   // Callback for Register() below. If registration is successful, |token| will
   // contain an OAuth2 refresh token for the newly registered managed user,
@@ -50,11 +53,26 @@
                               const std::string& /* token */)>
       RegistrationCallback;
 
+  // Callback for DownloadProfile() below. If the GAIA profile download is
+  // successful, the profile's full (display) name will be returned.
+  typedef base::Callback<void(const string16& /* full name */)>
+      DownloadProfileCallback;
+
   ManagedUserRegistrationService(
       PrefService* prefs,
       scoped_ptr<ManagedUserRefreshTokenFetcher> token_fetcher);
   virtual ~ManagedUserRegistrationService();
 
+  // ProfileDownloaderDelegate:
+  virtual bool NeedsProfilePicture() const OVERRIDE;
+  virtual int GetDesiredImageSideLength() const OVERRIDE;
+  virtual std::string GetCachedPictureURL() const OVERRIDE;
+  virtual Profile* GetBrowserProfile() OVERRIDE;
+  virtual void OnProfileDownloadSuccess(ProfileDownloader* downloader) OVERRIDE;
+  virtual void OnProfileDownloadFailure(
+      ProfileDownloader* downloader,
+      ProfileDownloaderDelegate::FailureReason reason) OVERRIDE;
+
   static void RegisterUserPrefs(user_prefs::PrefRegistrySyncable* registry);
 
   // Registers a new managed user with the server. |info| contains necessary
@@ -65,6 +83,14 @@
   void Register(const ManagedUserRegistrationInfo& info,
                 const RegistrationCallback& callback);
 
+  // Downloads the GAIA account information for the |profile|. This is a best-
+  // effort attempt with no error reporting nor timeout. If the download is
+  // successful, the profile's full (display) name will be returned via the
+  // callback. If the download fails or never completes, the callback will
+  // not be called.
+  void DownloadProfile(Profile* profile,
+                       const DownloadProfileCallback& callback);
+
   // Cancels any registration currently in progress, without calling the
   // callback or reporting an error. This should be called when the user
   // actively cancels the registration by canceling profile creation.
@@ -114,6 +140,8 @@
   void CompleteRegistration(bool run_callback,
                             const GoogleServiceAuthError& error);
 
+  void OnProfileDownloadComplete();
+
   base::WeakPtrFactory<ManagedUserRegistrationService> weak_ptr_factory_;
   PrefService* prefs_;
   PrefChangeRegistrar pref_change_registrar_;
@@ -130,6 +158,10 @@
   bool pending_managed_user_acknowledged_;
   RegistrationCallback callback_;
 
+  Profile* download_profile_;
+  scoped_ptr<ProfileDownloader> profile_downloader_;
+  DownloadProfileCallback download_callback_;
+
   DISALLOW_COPY_AND_ASSIGN(ManagedUserRegistrationService);
 };
 
diff --git a/chrome/browser/managed_mode/managed_user_service.cc b/chrome/browser/managed_mode/managed_user_service.cc
index 7ad603a..6d2e45f 100644
--- a/chrome/browser/managed_mode/managed_user_service.cc
+++ b/chrome/browser/managed_mode/managed_user_service.cc
@@ -139,10 +139,21 @@
 ManagedUserService::ManagedUserService(Profile* profile)
     : weak_ptr_factory_(this),
       profile_(profile),
-      elevated_for_testing_(false) {}
+      waiting_for_sync_initialization_(false),
+      elevated_for_testing_(false) {
+}
 
 ManagedUserService::~ManagedUserService() {}
 
+void ManagedUserService::Shutdown() {
+  if (!waiting_for_sync_initialization_)
+    return;
+
+  ProfileSyncService* sync_service =
+        ProfileSyncServiceFactory::GetForProfile(profile_);
+  sync_service->RemoveObserver(this);
+}
+
 bool ManagedUserService::ProfileIsManaged() const {
   return ProfileIsManaged(profile_);
 }
@@ -165,7 +176,12 @@
       prefs::kDefaultManagedModeFilteringBehavior, ManagedModeURLFilter::ALLOW,
       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
   registry->RegisterStringPref(
-      prefs::kManagedUserCustodian, std::string(),
+      prefs::kManagedUserCustodianEmail, std::string(),
+      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
+  registry->RegisterStringPref(
+      prefs::kManagedUserCustodianName, std::string(),
+      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
+  registry->RegisterBooleanPref(prefs::kManagedUserCreationAllowed, true,
       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
 }
 
@@ -207,7 +223,13 @@
 }
 
 std::string ManagedUserService::GetCustodianEmailAddress() const {
-  return profile_->GetPrefs()->GetString(prefs::kManagedUserCustodian);
+  return profile_->GetPrefs()->GetString(prefs::kManagedUserCustodianEmail);
+}
+
+std::string ManagedUserService::GetCustodianName() const {
+  std::string name = profile_->GetPrefs()->GetString(
+      prefs::kManagedUserCustodianName);
+  return name.empty() ? GetCustodianEmailAddress() : name;
 }
 
 std::string ManagedUserService::GetDebugPolicyProviderName() const {
@@ -269,6 +291,21 @@
       extension ? extension->id() : std::string(), error);
 }
 
+void ManagedUserService::OnStateChanged() {
+  ProfileSyncService* service =
+      ProfileSyncServiceFactory::GetForProfile(profile_);
+  if (waiting_for_sync_initialization_ && service->sync_initialized()) {
+    SetupSync();
+    service->RemoveObserver(this);
+    waiting_for_sync_initialization_ = false;
+    return;
+  }
+
+  DLOG_IF(ERROR, service->GetAuthError().state() ==
+                     GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS)
+      << "Credentials rejected";
+}
+
 void ManagedUserService::Observe(int type,
                           const content::NotificationSource& source,
                           const content::NotificationDetails& details) {
@@ -296,6 +333,21 @@
   }
 }
 
+void ManagedUserService::SetupSync() {
+  ProfileSyncService* service =
+      ProfileSyncServiceFactory::GetForProfile(profile_);
+  DCHECK(service->sync_initialized());
+
+  bool sync_everything = false;
+  syncer::ModelTypeSet synced_datatypes;
+  synced_datatypes.Put(syncer::MANAGED_USER_SETTINGS);
+  service->OnUserChoseDatatypes(sync_everything, synced_datatypes);
+
+  // Notify ProfileSyncService that we are done with configuration.
+  service->SetSetupInProgress(false);
+  service->SetSyncSetupCompleted();
+}
+
 bool ManagedUserService::ExtensionManagementPolicyImpl(
     const std::string& extension_id,
     string16* error) const {
@@ -306,7 +358,7 @@
     return true;
 
   if (error)
-    *error = l10n_util::GetStringUTF16(IDS_EXTENSIONS_LOCKED_MANAGED_MODE);
+    *error = l10n_util::GetStringUTF16(IDS_EXTENSIONS_LOCKED_MANAGED_USER);
   return false;
 }
 
@@ -413,25 +465,24 @@
   Init();
 }
 
-void ManagedUserService::InitSync(const std::string& sync_token) {
+void ManagedUserService::InitSync(const std::string& refresh_token) {
   ProfileSyncService* service =
       ProfileSyncServiceFactory::GetForProfile(profile_);
-  DCHECK(!service->sync_initialized());
   // Tell the sync service that setup is in progress so we don't start syncing
   // until we've finished configuration.
   service->SetSetupInProgress(true);
 
   TokenService* token_service = TokenServiceFactory::GetForProfile(profile_);
-  token_service->AddAuthTokenManually(GaiaConstants::kSyncService, sync_token);
+  token_service->UpdateCredentialsWithOAuth2(
+      GaiaAuthConsumer::ClientOAuthResult(refresh_token, std::string(), 0));
 
-  bool sync_everything = false;
-  syncer::ModelTypeSet synced_datatypes;
-  synced_datatypes.Put(syncer::MANAGED_USER_SETTINGS);
-  service->OnUserChoseDatatypes(sync_everything, synced_datatypes);
-
-  // Notify ProfileSyncService that we are done with configuration.
-  service->SetSetupInProgress(false);
-  service->SetSyncSetupCompleted();
+  // Continue in SetupSync() once the Sync backend has been initialized.
+  if (service->sync_initialized()) {
+    SetupSync();
+  } else {
+    ProfileSyncServiceFactory::GetForProfile(profile_)->AddObserver(this);
+    waiting_for_sync_initialization_ = true;
+  }
 }
 
 // static
@@ -454,6 +505,11 @@
         command_line->GetSwitchValueASCII(switches::kManagedUserSyncToken));
   }
 
+  // TokenService only loads tokens automatically if we're signed in, so we have
+  // to nudge it ourselves.
+  TokenService* token_service = TokenServiceFactory::GetForProfile(profile_);
+  token_service->LoadTokensFromDB();
+
   extensions::ExtensionSystem* extension_system =
       extensions::ExtensionSystem::Get(profile_);
   extensions::ManagementPolicy* management_policy =
@@ -491,6 +547,8 @@
 void ManagedUserService::RegisterAndInitSync(
     Profile* custodian_profile,
     const ProfileManager::CreateCallback& callback) {
+
+  // Register the managed user with the custodian's account.
   ManagedUserRegistrationService* registration_service =
       ManagedUserRegistrationServiceFactory::GetForProfile(custodian_profile);
   string16 name = UTF8ToUTF16(
@@ -500,6 +558,19 @@
       info,
       base::Bind(&ManagedUserService::OnManagedUserRegistered,
                  weak_ptr_factory_.GetWeakPtr(), callback, custodian_profile));
+
+  // Fetch the custodian's profile information, to store the name.
+  // TODO(pamg): If --gaia-profile-info (keyword: switches::kGaiaProfileInfo)
+  // is ever enabled, take the name from the ProfileInfoCache instead.
+  registration_service->DownloadProfile(custodian_profile,
+    base::Bind(&ManagedUserService::OnCustodianProfileDownloaded,
+               weak_ptr_factory_.GetWeakPtr()));
+}
+
+void ManagedUserService::OnCustodianProfileDownloaded(
+    const string16& full_name) {
+  profile_->GetPrefs()->SetString(prefs::kManagedUserCustodianName,
+                                  UTF16ToUTF8(full_name));
 }
 
 void ManagedUserService::OnManagedUserRegistered(
@@ -517,7 +588,7 @@
   InitSync(token);
   SigninManagerBase* signin =
       SigninManagerFactory::GetForProfile(custodian_profile);
-  profile_->GetPrefs()->SetString(prefs::kManagedUserCustodian,
+  profile_->GetPrefs()->SetString(prefs::kManagedUserCustodianEmail,
                                   signin->GetAuthenticatedUsername());
   callback.Run(profile_, Profile::CREATE_STATUS_INITIALIZED);
 }
diff --git a/chrome/browser/managed_mode/managed_user_service.h b/chrome/browser/managed_mode/managed_user_service.h
index 43677d9..7c6da2a 100644
--- a/chrome/browser/managed_mode/managed_user_service.h
+++ b/chrome/browser/managed_mode/managed_user_service.h
@@ -14,6 +14,7 @@
 #include "chrome/browser/extensions/management_policy.h"
 #include "chrome/browser/managed_mode/managed_mode_url_filter.h"
 #include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/sync/profile_sync_service_observer.h"
 #include "components/browser_context_keyed_service/browser_context_keyed_service.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
@@ -39,6 +40,7 @@
 // manual whitelist/blacklist overrides).
 class ManagedUserService : public BrowserContextKeyedService,
                            public extensions::ManagementPolicy::Provider,
+                           public ProfileSyncServiceObserver,
                            public content::NotificationObserver {
  public:
   typedef std::vector<string16> CategoryList;
@@ -52,6 +54,9 @@
   explicit ManagedUserService(Profile* profile);
   virtual ~ManagedUserService();
 
+  // ProfileKeyedService override:
+  virtual void Shutdown() OVERRIDE;
+
   bool ProfileIsManaged() const;
 
   // Checks whether the given profile is managed without constructing a
@@ -60,8 +65,9 @@
 
   static void RegisterUserPrefs(user_prefs::PrefRegistrySyncable* registry);
 
-  // Returns whether managed users are enabled by Finch or the command line
-  // flag.
+  // Returns true if managed users are enabled by either Finch or the command
+  // line flag.
+  // TODO(pamg, sergiu): Remove this once the feature is fully launched.
   static bool AreManagedUsersEnabled();
 
   // Returns the URL filter for the IO thread, for filtering network requests
@@ -88,6 +94,10 @@
   // Returns the email address of the custodian.
   std::string GetCustodianEmailAddress() const;
 
+  // Returns the name of the custodian, or the email address if the name is
+  // empty.
+  std::string GetCustodianName() const;
+
   // These methods allow querying and modifying the manual filtering behavior.
   // The manual behavior is set by the user and overrides all other settings
   // (whitelists or the default behavior).
@@ -109,9 +119,9 @@
   // Marks the profile as managed and initializes it.
   void InitForTesting();
 
-  // Initializes this profile for syncing, using the provided |token| to
-  // authenticate requests.
-  void InitSync(const std::string& token);
+  // Initializes this profile for syncing, using the provided |refresh_token| to
+  // mint access tokens for Sync.
+  void InitSync(const std::string& refresh_token);
 
   // Convenience method that registers this managed user with
   // |registration_service| and initializes sync with the returned token.
@@ -138,6 +148,9 @@
   virtual bool UserMayModifySettings(const extensions::Extension* extension,
                                      string16* error) const OVERRIDE;
 
+  // ProfileSyncServiceObserver implementation:
+  virtual void OnStateChanged() OVERRIDE;
+
   // content::NotificationObserver implementation:
   virtual void Observe(int type,
                        const content::NotificationSource& source,
@@ -176,11 +189,15 @@
     DISALLOW_COPY_AND_ASSIGN(URLFilterContext);
   };
 
+  void OnCustodianProfileDownloaded(const string16& full_name);
+
   void OnManagedUserRegistered(const ProfileManager::CreateCallback& callback,
                                Profile* custodian_profile,
                                const GoogleServiceAuthError& auth_error,
                                const std::string& token);
 
+  void SetupSync();
+
   // Internal implementation for ExtensionManagementPolicy::Delegate methods.
   // If |error| is not NULL, it will be filled with an error message if the
   // requested extension action (install, modify status, etc.) is not permitted.
@@ -213,6 +230,9 @@
   content::NotificationRegistrar registrar_;
   PrefChangeRegistrar pref_change_registrar_;
 
+  // True iff we're waiting for the Sync service to be initialized.
+  bool waiting_for_sync_initialization_;
+
   // Sets a profile in elevated state for testing if set to true.
   bool elevated_for_testing_;
 
diff --git a/chrome/browser/media/chrome_media_stream_infobar_browsertest.cc b/chrome/browser/media/chrome_media_stream_infobar_browsertest.cc
new file mode 100644
index 0000000..1e85475
--- /dev/null
+++ b/chrome/browser/media/chrome_media_stream_infobar_browsertest.cc
@@ -0,0 +1,287 @@
+// 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/file_util.h"
+#include "base/path_service.h"
+#include "base/process_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/test/test_timeouts.h"
+#include "base/time/time.h"
+#include "chrome/browser/content_settings/host_content_settings_map.h"
+#include "chrome/browser/infobars/infobar.h"
+#include "chrome/browser/infobars/infobar_service.h"
+#include "chrome/browser/media/media_stream_infobar_delegate.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_tabstrip.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/common/chrome_notification_types.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/content_settings_types.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "chrome/test/base/ui_test_utils.h"
+#include "chrome/test/ui/ui_test.h"
+#include "content/public/browser/notification_service.h"
+#include "content/public/test/browser_test_utils.h"
+#include "net/test/spawned_test_server/spawned_test_server.h"
+
+static const char kMainWebrtcTestHtmlPage[] =
+    "files/webrtc/webrtc_jsep01_test.html";
+static const char kFailedWithErrorPermissionDenied[] =
+    "failed-with-error-PERMISSION_DENIED";
+
+static const char kAudioVideoCallConstraints[] = "'{audio: true, video: true}'";
+static const char kAudioOnlyCallConstraints[] = "'{audio: true}'";
+static const char kVideoOnlyCallConstraints[] = "'{video: true}'";
+static const char kOkGotStream[] = "ok-got-stream";
+
+// Media stream infobar test for WebRTC.
+class MediaStreamInfobarTest : public InProcessBrowserTest {
+ public:
+  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
+    // This test expects to run with fake devices but real UI.
+    command_line->AppendSwitch(switches::kUseFakeDeviceForMediaStream);
+    EXPECT_FALSE(command_line->HasSwitch(switches::kUseFakeUIForMediaStream))
+        << "Since this test tests the UI we want the real UI!";
+  }
+ protected:
+  content::WebContents* LoadTestPageInTab() {
+    EXPECT_TRUE(test_server()->Start());
+
+    ui_test_utils::NavigateToURL(
+        browser(), test_server()->GetURL(kMainWebrtcTestHtmlPage));
+    return browser()->tab_strip_model()->GetActiveWebContents();
+  }
+
+  // TODO(phoglund): upstream and reuse in other browser tests.
+  MediaStreamInfoBarDelegate* GetUserMediaAndWaitForInfobar(
+      content::WebContents* tab_contents,
+      const std::string& constraints) {
+    content::WindowedNotificationObserver infobar_added(
+        chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_ADDED,
+        content::NotificationService::AllSources());
+
+    // Request user media: this will launch the media stream info bar.
+    GetUserMedia(constraints, tab_contents);
+
+    // Wait for the bar to pop up, then return it
+    infobar_added.Wait();
+    content::Details<InfoBarAddedDetails> details(infobar_added.details());
+    MediaStreamInfoBarDelegate* media_infobar =
+        details.ptr()->AsMediaStreamInfoBarDelegate();
+    return media_infobar;
+  }
+
+  void CloseInfobarInTab(content::WebContents* tab_contents,
+                         MediaStreamInfoBarDelegate* infobar) {
+    content::WindowedNotificationObserver infobar_removed(
+        chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REMOVED,
+        content::NotificationService::AllSources());
+
+    InfoBarService* infobar_service =
+        InfoBarService::FromWebContents(tab_contents);
+    infobar_service->RemoveInfoBar(infobar);
+
+    infobar_removed.Wait();
+  }
+
+  // Convenience method which executes the provided javascript in the context
+  // of the provided web contents and returns what it evaluated to.
+  std::string ExecuteJavascript(const std::string& javascript,
+                                content::WebContents* tab_contents) {
+    std::string result;
+    EXPECT_TRUE(content::ExecuteScriptAndExtractString(
+        tab_contents, javascript, &result));
+    return result;
+  }
+
+  void TestAcceptOnInfobar(content::WebContents* tab_contents) {
+    TestAcceptOnInfobarWithSpecificConstraints(tab_contents,
+                                               kAudioVideoCallConstraints);
+  }
+
+  void TestAcceptOnInfobarWithSpecificConstraints(
+      content::WebContents* tab_contents, const std::string& constraints) {
+    MediaStreamInfoBarDelegate* media_infobar =
+        GetUserMediaAndWaitForInfobar(tab_contents, constraints);
+
+    media_infobar->Accept();
+
+    CloseInfobarInTab(tab_contents, media_infobar);
+
+    // Wait for WebRTC to call the success callback.
+    EXPECT_TRUE(UglyPollingWaitUntil(
+        "obtainGetUserMediaResult()", kOkGotStream, tab_contents));
+  }
+
+  void TestDenyOnInfobar(content::WebContents* tab_contents) {
+    return TestDenyWithSpecificConstraints(tab_contents,
+                                           kAudioVideoCallConstraints);
+  }
+
+  void TestDenyWithSpecificConstraints(content::WebContents* tab_contents,
+                                       const std::string& constraints) {
+    MediaStreamInfoBarDelegate* media_infobar =
+        GetUserMediaAndWaitForInfobar(tab_contents, constraints);
+
+    media_infobar->Cancel();
+
+    CloseInfobarInTab(tab_contents, media_infobar);
+
+    // Wait for WebRTC to call the fail callback.
+    EXPECT_TRUE(UglyPollingWaitUntil("obtainGetUserMediaResult()",
+                                     kFailedWithErrorPermissionDenied,
+                                     tab_contents));
+  }
+
+  void TestDismissOnInfobar(content::WebContents* tab_contents) {
+    MediaStreamInfoBarDelegate* media_infobar =
+        GetUserMediaAndWaitForInfobar(tab_contents, kAudioVideoCallConstraints);
+
+    media_infobar->InfoBarDismissed();
+
+    CloseInfobarInTab(tab_contents, media_infobar);
+
+    // A dismiss should be treated like a deny.
+    EXPECT_TRUE(UglyPollingWaitUntil("obtainGetUserMediaResult()",
+                                     kFailedWithErrorPermissionDenied,
+                                     tab_contents));
+  }
+
+  // TODO(phoglund): de-dupe
+  // TODO(phoglund): This ugly poll method is only here while we transition
+  // the test javascript to just post events when things happen. Right now they
+  // don't because the webrtc_call.py and other tests use this polling way of
+  // communicating when we are waiting from an asynchronous event in the
+  // javascript. This method is meant to emulate WaitUntil in the PyAuto
+  // framework.
+  bool UglyPollingWaitUntil(const std::string& javascript,
+                            const std::string& evaluates_to,
+                            content::WebContents* tab_contents) {
+    const base::Time start_time = base::Time::Now();
+    const base::TimeDelta timeout = TestTimeouts::action_max_timeout();
+    std::string result;
+
+    while (base::Time::Now() - start_time < timeout) {
+      result = ExecuteJavascript(javascript, tab_contents);
+      LOG(INFO) << result;
+      if (evaluates_to == result)
+        return true;
+    }
+    LOG(ERROR) << "Timed out while waiting for " << javascript
+               << " to evaluate to " << evaluates_to << "; last result was '"
+               << result << "'";
+    return false;
+  }
+
+  void GetUserMedia(const std::string& constraints,
+                    content::WebContents* tab_contents) {
+    // Request user media: this will launch the media stream info bar.
+    EXPECT_EQ("ok-requested",
+              ExecuteJavascript(
+                  base::StringPrintf("getUserMedia(%s);", constraints.c_str()),
+                  tab_contents));
+  }
+};
+
+IN_PROC_BROWSER_TEST_F(MediaStreamInfobarTest, TestAllowingUserMedia) {
+  content::WebContents* tab_contents = LoadTestPageInTab();
+  TestAcceptOnInfobar(tab_contents);
+}
+
+IN_PROC_BROWSER_TEST_F(MediaStreamInfobarTest, TestDenyingUserMedia) {
+  content::WebContents* tab_contents = LoadTestPageInTab();
+  TestDenyOnInfobar(tab_contents);
+}
+
+IN_PROC_BROWSER_TEST_F(MediaStreamInfobarTest, TestDismissingInfobar) {
+  content::WebContents* tab_contents = LoadTestPageInTab();
+  TestDismissOnInfobar(tab_contents);
+}
+
+IN_PROC_BROWSER_TEST_F(MediaStreamInfobarTest,
+                       TestAcceptThenDenyWhichShouldBeSticky) {
+  content::WebContents* tab_contents = LoadTestPageInTab();
+
+  TestAcceptOnInfobar(tab_contents);
+  TestDenyOnInfobar(tab_contents);
+
+  // Should fail with permission denied right away with no infobar popping up.
+  GetUserMedia(kAudioVideoCallConstraints, tab_contents);
+  EXPECT_TRUE(UglyPollingWaitUntil("obtainGetUserMediaResult()",
+                                   kFailedWithErrorPermissionDenied,
+                                   tab_contents));
+  InfoBarService* infobar_service =
+      InfoBarService::FromWebContents(tab_contents);
+  EXPECT_EQ(0u, infobar_service->infobar_count());
+}
+
+IN_PROC_BROWSER_TEST_F(MediaStreamInfobarTest, TestAcceptIsNotSticky) {
+  content::WebContents* tab_contents = LoadTestPageInTab();
+
+  // If accept were sticky the second call would hang because it hangs if an
+  // infobar does not pop up.
+  TestAcceptOnInfobar(tab_contents);
+  TestAcceptOnInfobar(tab_contents);
+}
+
+IN_PROC_BROWSER_TEST_F(MediaStreamInfobarTest, TestDismissIsNotSticky) {
+  content::WebContents* tab_contents = LoadTestPageInTab();
+
+  // If dismiss were sticky the second call would hang because it hangs if an
+  // infobar does not pop up.
+  TestDismissOnInfobar(tab_contents);
+  TestDismissOnInfobar(tab_contents);
+}
+
+IN_PROC_BROWSER_TEST_F(MediaStreamInfobarTest,
+                       TestDenyingThenClearingStickyException) {
+  content::WebContents* tab_contents = LoadTestPageInTab();
+
+  TestDenyOnInfobar(tab_contents);
+
+  HostContentSettingsMap* settings_map =
+      browser()->profile()->GetHostContentSettingsMap();
+
+  settings_map->ClearSettingsForOneType(
+      CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC);
+  settings_map->ClearSettingsForOneType(
+      CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA);
+
+  // If an infobar is not launched now, this will hang.
+  TestDenyOnInfobar(tab_contents);
+}
+
+IN_PROC_BROWSER_TEST_F(MediaStreamInfobarTest,
+                       DenyingMicDoesNotCauseStickyDenyForCameras) {
+  content::WebContents* tab_contents = LoadTestPageInTab();
+
+  // If mic blocking also blocked cameras, the second call here would hang.
+  TestDenyWithSpecificConstraints(tab_contents, kAudioOnlyCallConstraints);
+  TestAcceptOnInfobarWithSpecificConstraints(tab_contents,
+                                             kVideoOnlyCallConstraints);
+}
+
+IN_PROC_BROWSER_TEST_F(MediaStreamInfobarTest,
+                       DenyingCameraDoesNotCauseStickyDenyForMics) {
+  content::WebContents* tab_contents = LoadTestPageInTab();
+
+  // If camera blocking also blocked mics, the second call here would hang.
+  TestDenyWithSpecificConstraints(tab_contents, kVideoOnlyCallConstraints);
+  TestAcceptOnInfobarWithSpecificConstraints(tab_contents,
+                                             kAudioOnlyCallConstraints);
+}
+
+IN_PROC_BROWSER_TEST_F(MediaStreamInfobarTest,
+                       DenyingMicStillSucceedsWithCameraForAudioVideoCalls) {
+  content::WebContents* tab_contents = LoadTestPageInTab();
+
+  // If microphone blocking also blocked a AV call, the second call here
+  // would hang. The requester should only be granted access to the cam though.
+  TestDenyWithSpecificConstraints(tab_contents, kAudioOnlyCallConstraints);
+  TestAcceptOnInfobarWithSpecificConstraints(tab_contents,
+                                             kAudioVideoCallConstraints);
+
+  // TODO(phoglund): verify the requester actually only gets video tracks.
+}
diff --git a/chrome/browser/media/chrome_webrtc_browsertest.cc b/chrome/browser/media/chrome_webrtc_browsertest.cc
index 50ab0bc..fe63cd6 100644
--- a/chrome/browser/media/chrome_webrtc_browsertest.cc
+++ b/chrome/browser/media/chrome_webrtc_browsertest.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.
 
@@ -6,7 +6,7 @@
 #include "base/path_service.h"
 #include "base/process_util.h"
 #include "base/strings/stringprintf.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/infobars/infobar.h"
 #include "chrome/browser/infobars/infobar_service.h"
 #include "chrome/browser/media/media_stream_infobar_delegate.h"
@@ -21,7 +21,7 @@
 #include "chrome/test/ui/ui_test.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/test/browser_test_utils.h"
-#include "net/test/spawned_test_server/spawned_test_server.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
 
 static const base::FilePath::CharType kPeerConnectionServer[] =
 #if defined(OS_WIN)
@@ -31,7 +31,7 @@
 #endif
 
 static const char kMainWebrtcTestHtmlPage[] =
-    "files/webrtc/webrtc_jsep01_test.html";
+    "/webrtc/webrtc_jsep01_test.html";
 
 // Top-level integration test for WebRTC. Requires a real webcam and microphone
 // on the running system. This test is not meant to run in the main browser
@@ -58,6 +58,8 @@
     // device; it will not work with fake devices.
     EXPECT_FALSE(command_line->HasSwitch(
         switches::kUseFakeDeviceForMediaStream));
+    EXPECT_FALSE(command_line->HasSwitch(
+        switches::kUseFakeUIForMediaStream));
   }
 
   // TODO(phoglund): This ugly poll method is only here while we transition
@@ -216,10 +218,10 @@
 
 IN_PROC_BROWSER_TEST_F(WebrtcBrowserTest,
                        MANUAL_RunsAudioVideoWebRTCCallInTwoTabs) {
-  EXPECT_TRUE(test_server()->Start());
+  EXPECT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
 
   ui_test_utils::NavigateToURL(
-      browser(), test_server()->GetURL(kMainWebrtcTestHtmlPage));
+      browser(), embedded_test_server()->GetURL(kMainWebrtcTestHtmlPage));
   content::WebContents* left_tab =
       browser()->tab_strip_model()->GetActiveWebContents();
   GetUserMedia(left_tab);
@@ -228,7 +230,7 @@
   content::WebContents* right_tab =
       browser()->tab_strip_model()->GetActiveWebContents();
   ui_test_utils::NavigateToURL(
-        browser(), test_server()->GetURL(kMainWebrtcTestHtmlPage));
+        browser(), embedded_test_server()->GetURL(kMainWebrtcTestHtmlPage));
   GetUserMedia(right_tab);
 
   ConnectToPeerConnectionServer("peer 1", left_tab);
@@ -255,10 +257,10 @@
 
 IN_PROC_BROWSER_TEST_F(WebrtcBrowserTest,
                        MANUAL_TestMediaStreamTrackEnableDisable) {
-  EXPECT_TRUE(test_server()->Start());
+  EXPECT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
 
   ui_test_utils::NavigateToURL(
-      browser(), test_server()->GetURL(kMainWebrtcTestHtmlPage));
+      browser(), embedded_test_server()->GetURL(kMainWebrtcTestHtmlPage));
   content::WebContents* left_tab =
       browser()->tab_strip_model()->GetActiveWebContents();
   GetUserMedia(left_tab);
@@ -267,7 +269,7 @@
   content::WebContents* right_tab =
       browser()->tab_strip_model()->GetActiveWebContents();
   ui_test_utils::NavigateToURL(
-        browser(), test_server()->GetURL(kMainWebrtcTestHtmlPage));
+        browser(), embedded_test_server()->GetURL(kMainWebrtcTestHtmlPage));
   GetUserMedia(right_tab);
 
   ConnectToPeerConnectionServer("peer 1", left_tab);
diff --git a/chrome/browser/media/chrome_webrtc_video_quality_browsertest.cc b/chrome/browser/media/chrome_webrtc_video_quality_browsertest.cc
new file mode 100644
index 0000000..68f9057
--- /dev/null
+++ b/chrome/browser/media/chrome_webrtc_video_quality_browsertest.cc
@@ -0,0 +1,531 @@
+// 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/environment.h"
+#include "base/file_util.h"
+#include "base/path_service.h"
+#include "base/process_util.h"
+#include "base/strings/string_split.h"
+#include "base/strings/stringprintf.h"
+#include "base/test/test_timeouts.h"
+#include "base/time/time.h"
+#include "chrome/browser/infobars/infobar.h"
+#include "chrome/browser/infobars/infobar_service.h"
+#include "chrome/browser/media/media_stream_infobar_delegate.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_tabstrip.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/common/chrome_notification_types.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "chrome/test/base/ui_test_utils.h"
+#include "chrome/test/perf/perf_test.h"
+#include "chrome/test/ui/ui_test.h"
+#include "content/public/browser/notification_service.h"
+#include "content/public/test/browser_test_utils.h"
+#include "net/test/python_utils.h"
+#include "net/test/spawned_test_server/spawned_test_server.h"
+
+static const base::FilePath::CharType kPeerConnectionServer[] =
+#if defined(OS_WIN)
+    FILE_PATH_LITERAL("peerconnection_server.exe");
+#else
+    FILE_PATH_LITERAL("peerconnection_server");
+#endif
+
+static const base::FilePath::CharType kFrameAnalyzerExecutable[] =
+#if defined(OS_WIN)
+    FILE_PATH_LITERAL("frame_analyzer.exe");
+#else
+    FILE_PATH_LITERAL("frame_analyzer");
+#endif
+
+static const base::FilePath::CharType kArgbToI420ConverterExecutable[] =
+#if defined(OS_WIN)
+    FILE_PATH_LITERAL("rgba_to_i420_converter.exe");
+#else
+    FILE_PATH_LITERAL("rgba_to_i420_converter");
+#endif
+
+static const char kHomeEnvName[] =
+#if defined(OS_WIN)
+    "HOMEPATH";
+#else
+    "HOME";
+#endif
+
+// The working dir should be in the user's home folder.
+static const base::FilePath::CharType kWorkingDirName[] =
+    FILE_PATH_LITERAL("webrtc_video_quality");
+static const base::FilePath::CharType kReferenceYuvFileName[] =
+    FILE_PATH_LITERAL("reference_video.yuv");
+static const base::FilePath::CharType kCapturedYuvFileName[] =
+    FILE_PATH_LITERAL("captured_video.yuv");
+static const base::FilePath::CharType kStatsFileName[] =
+    FILE_PATH_LITERAL("stats.txt");
+static const char kMainWebrtcTestHtmlPage[] =
+    "files/webrtc/webrtc_jsep01_test.html";
+static const char kCapturingWebrtcHtmlPage[] =
+    "files/webrtc/webrtc_video_quality_test.html";
+static const int kVgaWidth = 640;
+static const int kVgaHeight = 480;
+
+// If you change the port number, don't forget to modify video_extraction.js
+// too!
+static const char kPyWebSocketPortNumber[] = "12221";
+
+// Test the video quality of the WebRTC output.
+//
+// Prerequisites: This test case must run on a machine with a virtual webcam
+// that plays video from the reference file located in <the running users home
+// folder>/kWorkingDirName/kReferenceYuvFileName.
+//
+// You must also compile the chromium_builder_webrtc target before you run this
+// test to get all the tools built.
+//
+// The external compare_videos.py script also depends on two external
+// executables which must be located in the PATH when running this test.
+// * zxing (see the CPP version at https://code.google.com/p/zxing)
+// * ffmpeg 0.11.1 or compatible version (see http://www.ffmpeg.org)
+//
+// The test case will launch a custom binary (peerconnection_server) which will
+// allow two WebRTC clients to find each other.
+//
+// The test also runs several other custom binaries - rgba_to_i420 converter and
+// frame_analyzer. Both tools can be found under third_party/webrtc/tools. The
+// test also runs a stand alone Python implementation of a WebSocket server
+// (pywebsocket) and a barcode_decoder script.
+class WebrtcVideoQualityBrowserTest : public InProcessBrowserTest {
+ public:
+  WebrtcVideoQualityBrowserTest()
+      : peerconnection_server_(0),
+        pywebsocket_server_(0),
+        environment_(base::Environment::Create()) {}
+
+  virtual void SetUp() OVERRIDE {
+    RunPeerConnectionServer();
+    InProcessBrowserTest::SetUp();
+
+    // Ensure we have the stuff we need.
+    EXPECT_TRUE(file_util::PathExists(GetWorkingDir()))
+        << "Cannot find the working directory for the reference video and "
+           "the temporary files:" << GetWorkingDir().value();
+    base::FilePath reference_file =
+        GetWorkingDir().Append(kReferenceYuvFileName);
+    EXPECT_TRUE(file_util::PathExists(reference_file))
+        << "Cannot find the reference file to be used for video quality "
+        << "comparison: " << reference_file.value();
+  }
+
+  virtual void TearDown() OVERRIDE {
+    ShutdownPeerConnectionServer();
+    InProcessBrowserTest::TearDown();
+    ShutdownPyWebSocketServer();
+  }
+
+  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
+    // TODO(phoglund): check that user actually has the requisite devices and
+    // print a nice message if not; otherwise the test just times out which can
+    // be confusing.
+    // This test expects real device handling and requires a real webcam / audio
+    // device; it will not work with fake devices.
+    EXPECT_FALSE(
+        command_line->HasSwitch(switches::kUseFakeDeviceForMediaStream))
+        << "You cannot run this test with fake devices.";
+  }
+
+  void StartPyWebSocketServer() {
+    base::FilePath path_pywebsocket_dir =
+        GetSourceDir().Append(FILE_PATH_LITERAL("third_party/pywebsocket/src"));
+    base::FilePath pywebsocket_server = path_pywebsocket_dir.Append(
+        FILE_PATH_LITERAL("mod_pywebsocket/standalone.py"));
+    base::FilePath path_to_data_handler =
+        GetSourceDir().Append(FILE_PATH_LITERAL("chrome/test/functional"));
+
+    EXPECT_TRUE(file_util::PathExists(pywebsocket_server))
+        << "Fatal: missing pywebsocket server.";
+    EXPECT_TRUE(file_util::PathExists(path_to_data_handler))
+        << "Fatal: missing data handler for pywebsocket server.";
+
+    AppendToPythonPath(path_pywebsocket_dir);
+    CommandLine pywebsocket_command = MakePythonCommand(pywebsocket_server);
+
+    // Construct the command line manually, the server doesn't support -arg=val.
+    pywebsocket_command.AppendArg("-p");
+    pywebsocket_command.AppendArg(kPyWebSocketPortNumber);
+    pywebsocket_command.AppendArg("-d");
+    pywebsocket_command.AppendArgPath(path_to_data_handler);
+
+    LOG(INFO) << "Running " << pywebsocket_command.GetCommandLineString();
+    EXPECT_TRUE(base::LaunchProcess(
+        pywebsocket_command, base::LaunchOptions(), &pywebsocket_server_))
+        << "Failed to launch pywebsocket server.";
+  }
+
+  void ShutdownPyWebSocketServer() {
+    EXPECT_TRUE(base::KillProcess(pywebsocket_server_, 0, false))
+        << "Failed to shut down pywebsocket server!";
+  }
+
+  // TODO(phoglund): This ugly poll method is only here while we transition
+  // the test javascript to just post events when things happen. Right now they
+  // don't because the webrtc_call.py and other tests use this polling way of
+  // communicating when we are waiting from an asynchronous event in the
+  // javascript. This method is meant to emulate WaitUntil in the PyAuto
+  // framework.
+  bool UglyPollingWaitUntil(const std::string& javascript,
+                            const std::string& evaluates_to,
+                            content::WebContents* tab_contents) {
+    base::Time start_time = base::Time::Now();
+    base::TimeDelta timeout = TestTimeouts::action_max_timeout();
+    std::string result;
+
+    while (base::Time::Now() - start_time < timeout) {
+      result = ExecuteJavascript(javascript, tab_contents);
+      if (evaluates_to == result)
+        return true;
+    }
+    LOG(ERROR) << "Timed out while waiting for " << javascript
+               << " to evaluate to " << evaluates_to << "; last result was '"
+               << result << "'";
+    return false;
+  }
+
+  // Convenience method which executes the provided javascript in the context
+  // of the provided web contents and returns what it evaluated to.
+  std::string ExecuteJavascript(const std::string& javascript,
+                                content::WebContents* tab_contents) {
+    std::string result;
+    EXPECT_TRUE(content::ExecuteScriptAndExtractString(
+        tab_contents, javascript, &result));
+    return result;
+  }
+
+  void GetUserMedia(content::WebContents* tab_contents) {
+    content::WindowedNotificationObserver infobar_added(
+        chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_ADDED,
+        content::NotificationService::AllSources());
+
+    // Request user media: this will launch the media stream info bar.
+    EXPECT_EQ("ok-requested",
+              ExecuteJavascript("getUserMedia('{video: true, audio: true}');",
+                                tab_contents));
+
+    // Wait for the bar to pop up, then accept.
+    infobar_added.Wait();
+    content::Details<InfoBarAddedDetails> details(infobar_added.details());
+    MediaStreamInfoBarDelegate* media_infobar =
+        details.ptr()->AsMediaStreamInfoBarDelegate();
+    media_infobar->Accept();
+
+    // Wait for WebRTC to call the success callback.
+    EXPECT_TRUE(UglyPollingWaitUntil(
+        "obtainGetUserMediaResult();", "ok-got-stream", tab_contents));
+  }
+
+  // Ensures we didn't get any errors asynchronously (e.g. while no javascript
+  // call from this test was outstanding).
+  // TODO(phoglund): this becomes obsolete when we switch to communicating with
+  // the DOM message queue.
+  void AssertNoAsynchronousErrors(content::WebContents* tab_contents) {
+    EXPECT_EQ("ok-no-errors",
+              ExecuteJavascript("getAnyTestFailures()", tab_contents));
+  }
+
+  // The peer connection server lets our two tabs find each other and talk to
+  // each other (e.g. it is the application-specific "signaling solution").
+  void ConnectToPeerConnectionServer(const std::string peer_name,
+                                     content::WebContents* tab_contents) {
+    std::string javascript = base::StringPrintf(
+        "connect('http://localhost:8888', '%s');", peer_name.c_str());
+    EXPECT_EQ("ok-connected", ExecuteJavascript(javascript, tab_contents));
+  }
+
+  void EstablishCall(content::WebContents* from_tab,
+                     content::WebContents* to_tab) {
+    EXPECT_EQ("ok-peerconnection-created",
+              ExecuteJavascript("preparePeerConnection()", from_tab));
+    EXPECT_EQ("ok-added", ExecuteJavascript("addLocalStream()", from_tab));
+    EXPECT_EQ("ok-negotiating", ExecuteJavascript("negotiateCall()", from_tab));
+
+    // Ensure the call gets up on both sides.
+    EXPECT_TRUE(UglyPollingWaitUntil(
+        "getPeerConnectionReadyState()", "active", from_tab));
+    EXPECT_TRUE(UglyPollingWaitUntil(
+        "getPeerConnectionReadyState()", "active", to_tab));
+  }
+
+  void HangUp(content::WebContents* from_tab) {
+    EXPECT_EQ("ok-call-hung-up", ExecuteJavascript("hangUp()", from_tab));
+  }
+
+  void WaitUntilHangupVerified(content::WebContents* tab_contents) {
+    EXPECT_TRUE(UglyPollingWaitUntil(
+        "getPeerConnectionReadyState()", "no-peer-connection", tab_contents));
+  }
+
+  // Runs the RGBA to I420 converter on the video in |capture_video_filename|,
+  // which should contain frames of size |width| x |height|.
+  //
+  // The rgba_to_i420_converter is part of the webrtc_test_tools target which
+  // should be build prior to running this test. The resulting binary should
+  // live next to Chrome.
+  void RunARGBtoI420Converter(int width,
+                              int height,
+                              const base::FilePath& captured_video_filename) {
+    base::FilePath path_to_converter = base::MakeAbsoluteFilePath(
+        GetBrowserDir().Append(kArgbToI420ConverterExecutable));
+    EXPECT_TRUE(file_util::PathExists(path_to_converter))
+        << "Missing ARGB->I420 converter: should be in "
+        << path_to_converter.value();
+
+    CommandLine converter_command(path_to_converter);
+    converter_command.AppendSwitchPath("--frames_dir", GetWorkingDir());
+    converter_command.AppendSwitchPath("--output_file",
+                                       captured_video_filename);
+    converter_command.AppendSwitchASCII("--width",
+                                        base::StringPrintf("%d", width));
+    converter_command.AppendSwitchASCII("--height",
+                                        base::StringPrintf("%d", height));
+
+    // We produce an output file that will later be used as an input to the
+    // barcode decoder and frame analyzer tools.
+    LOG(INFO) << "Running " << converter_command.GetCommandLineString();
+    std::string result;
+    EXPECT_TRUE(base::GetAppOutput(converter_command, &result));
+    LOG(INFO) << "Output was:\n\n" << result;
+  }
+
+  // Compares the |captured_video_filename| with the |reference_video_filename|.
+  //
+  // The barcode decoder decodes the captured video containing barcodes overlaid
+  // into every frame of the video (produced by rgba_to_i420_converter). It
+  // produces a set of PNG images and a |stats_file| that maps each captured
+  // frame to a frame in the reference video. The frames should be of size
+  // |width| x |height|. The output of compare_videos.py is returned.
+  std::string CompareVideos(int width,
+                            int height,
+                            const base::FilePath& captured_video_filename,
+                            const base::FilePath& reference_video_filename,
+                            const base::FilePath& stats_file) {
+    base::FilePath path_to_analyzer = base::MakeAbsoluteFilePath(
+        GetBrowserDir().Append(kFrameAnalyzerExecutable));
+    base::FilePath path_to_compare_script = GetSourceDir().Append(
+        FILE_PATH_LITERAL("third_party/webrtc/tools/compare_videos.py"));
+
+    EXPECT_TRUE(file_util::PathExists(path_to_analyzer))
+        << "Missing frame analyzer: should be in " << path_to_analyzer.value();
+    EXPECT_TRUE(file_util::PathExists(path_to_compare_script))
+        << "Missing video compare script: should be in "
+        << path_to_compare_script.value();
+
+    CommandLine compare_command = MakePythonCommand(path_to_compare_script);
+    compare_command.AppendSwitchPath("--ref_video", reference_video_filename);
+    compare_command.AppendSwitchPath("--test_video", captured_video_filename);
+    compare_command.AppendSwitchPath("--frame_analyzer", path_to_analyzer);
+    compare_command.AppendSwitchASCII("--yuv_frame_width",
+                                      base::StringPrintf("%d", width));
+    compare_command.AppendSwitchASCII("--yuv_frame_height",
+                                      base::StringPrintf("%d", height));
+    compare_command.AppendSwitchPath("--stats_file", stats_file);
+
+    LOG(INFO) << "Running " << compare_command.GetCommandLineString();
+    std::string result;
+    EXPECT_TRUE(base::GetAppOutput(compare_command, &result));
+    LOG(INFO) << "Output was:\n\n" << result;
+    return result;
+  }
+
+  // Processes the |frame_analyzer_output| for the different frame counts.
+  //
+  // The frame analyzer outputs additional information about the number of
+  // unique frames captured, The max number of repeated frames in a sequence and
+  // the max number of skipped frames. These values are then written to the Perf
+  // Graph. (Note: Some of the repeated or skipped frames will probably be due
+  // to the imperfection of JavaScript timers).
+  void PrintFramesCountPerfResults(std::string frame_analyzer_output) {
+    size_t unique_frames_pos =
+        frame_analyzer_output.rfind("Unique_frames_count");
+    EXPECT_NE(unique_frames_pos, std::string::npos)
+        << "Missing Unique_frames_count in frame analyzer output:\n"
+        << frame_analyzer_output;
+
+    std::string unique_frame_counts =
+        frame_analyzer_output.substr(unique_frames_pos);
+    // TODO(phoglund): Fix ESTATS result to not have this silly newline.
+    std::replace(
+        unique_frame_counts.begin(), unique_frame_counts.end(), '\n', ' ');
+
+    std::vector<std::pair<std::string, std::string> > key_values;
+    base::SplitStringIntoKeyValuePairs(
+        unique_frame_counts, ':', ' ', &key_values);
+    std::vector<std::pair<std::string, std::string> >::const_iterator iter;
+    for (iter = key_values.begin(); iter != key_values.end(); ++iter) {
+      const std::pair<std::string, std::string>& key_value = *iter;
+      perf_test::PrintResult(
+          key_value.first, "", "VGA", key_value.second, "", false);
+    }
+  }
+
+  // Processes the |frame_analyzer_output| to extract the PSNR and SSIM values.
+  //
+  // The frame analyzer produces PSNR and SSIM results for every unique frame
+  // that has been captured. This method forms a list of all the psnr and ssim
+  // values and passes it to PrintResultList() for printing on the Perf Graph.
+  void PrintPsnrAndSsimPerfResults(std::string frame_analyzer_output) {
+    size_t stats_start = frame_analyzer_output.find("BSTATS");
+    EXPECT_NE(stats_start, std::string::npos)
+        << "Missing BSTATS in frame analyzer output:\n"
+        << frame_analyzer_output;
+    size_t stats_end = frame_analyzer_output.find("ESTATS");
+    EXPECT_NE(stats_end, std::string::npos)
+        << "Missing ESTATS in frame analyzer output:\n"
+        << frame_analyzer_output;
+
+    stats_start += std::string("BSTATS").size();
+    std::string psnr_ssim_stats =
+        frame_analyzer_output.substr(stats_start, stats_end - stats_start);
+
+    // PSNR and SSIM values aren't really key-value pairs but it is convenient
+    // to parse them as such.
+    // TODO(phoglund): make the format more convenient so we need less
+    // processing here.
+    std::vector<std::pair<std::string, std::string> > psnr_ssim_entries;
+    base::SplitStringIntoKeyValuePairs(
+        psnr_ssim_stats, ' ', ';', &psnr_ssim_entries);
+
+    std::string psnr_value_list;
+    std::string ssim_value_list;
+    std::vector<std::pair<std::string, std::string> >::const_iterator iter;
+    for (iter = psnr_ssim_entries.begin(); iter != psnr_ssim_entries.end();
+         ++iter) {
+      const std::pair<std::string, std::string>& psnr_and_ssim = *iter;
+      psnr_value_list.append(psnr_and_ssim.first).append(",");
+      ssim_value_list.append(psnr_and_ssim.second).append(",");
+    }
+    // Nuke last comma.
+    psnr_value_list.erase(psnr_value_list.size() - 1);
+    ssim_value_list.erase(ssim_value_list.size() - 1);
+
+    perf_test::PrintResultList("PSNR", "", "VGA", psnr_value_list, "dB", false);
+    perf_test::PrintResultList("SSIM", "", "VGA", ssim_value_list, "", false);
+  }
+
+  base::FilePath GetWorkingDir() {
+    std::string home_dir;
+    environment_->GetVar(kHomeEnvName, &home_dir);
+    base::FilePath::StringType native_home_dir(home_dir.begin(),
+                                               home_dir.end());
+    return base::FilePath(native_home_dir).Append(kWorkingDirName);
+  }
+
+ private:
+  void RunPeerConnectionServer() {
+    // TODO(phoglund): de-dupe later: next line differs from original.
+    base::FilePath peerconnection_server =
+        GetBrowserDir().Append(kPeerConnectionServer);
+
+    EXPECT_TRUE(file_util::PathExists(peerconnection_server))
+        << "Missing peerconnection_server. You must build "
+           "it so it ends up next to the browser test binary.";
+    EXPECT_TRUE(base::LaunchProcess(CommandLine(peerconnection_server),
+                                    base::LaunchOptions(),
+                                    &peerconnection_server_))
+        << "Failed to launch peerconnection_server.";
+  }
+
+  void ShutdownPeerConnectionServer() {
+    EXPECT_TRUE(base::KillProcess(peerconnection_server_, 0, false))
+        << "Failed to shut down peerconnection_server!";
+  }
+
+  base::FilePath GetSourceDir() {
+    base::FilePath source_dir;
+    PathService::Get(base::DIR_SOURCE_ROOT, &source_dir);
+    return source_dir;
+  }
+
+  base::FilePath GetBrowserDir() {
+    base::FilePath browser_dir;
+    EXPECT_TRUE(PathService::Get(base::DIR_MODULE, &browser_dir));
+    return browser_dir;
+  }
+
+  CommandLine MakePythonCommand(base::FilePath python_script) {
+    CommandLine python_command(CommandLine::NO_PROGRAM);
+    EXPECT_TRUE(GetPythonCommand(&python_command));
+    CommandLine complete_command(python_script);
+    complete_command.PrependWrapper(python_command.GetCommandLineString());
+    return complete_command;
+  }
+
+  base::ProcessHandle peerconnection_server_;
+  base::ProcessHandle pywebsocket_server_;
+  scoped_ptr<base::Environment> environment_;
+};
+
+#if defined(OS_WIN)
+// Broken on Win: failing to start pywebsocket_server. http://crbug.com/255499.
+#define MAYBE_MANUAL_TestVGAVideoQuality DISABLED_MANUAL_TestVGAVideoQuality
+#else
+#define MAYBE_MANUAL_TestVGAVideoQuality MANUAL_TestVGAVideoQuality
+#endif
+
+IN_PROC_BROWSER_TEST_F(WebrtcVideoQualityBrowserTest,
+                       MAYBE_MANUAL_TestVGAVideoQuality) {
+  // TODO(phoglund): de-dupe from chrome_webrtc_browsertest.cc.
+  StartPyWebSocketServer();
+
+  EXPECT_TRUE(test_server()->Start());
+
+  ui_test_utils::NavigateToURL(browser(),
+                               test_server()->GetURL(kMainWebrtcTestHtmlPage));
+  content::WebContents* left_tab =
+      browser()->tab_strip_model()->GetActiveWebContents();
+  GetUserMedia(left_tab);
+
+  chrome::AddBlankTabAt(browser(), -1, true);
+  content::WebContents* right_tab =
+      browser()->tab_strip_model()->GetActiveWebContents();
+  // TODO(phoglund): (de-dupe later) different from original flow.
+  ui_test_utils::NavigateToURL(browser(),
+                               test_server()->GetURL(kCapturingWebrtcHtmlPage));
+  GetUserMedia(right_tab);
+
+  ConnectToPeerConnectionServer("peer 1", left_tab);
+  ConnectToPeerConnectionServer("peer 2", right_tab);
+
+  EstablishCall(left_tab, right_tab);
+
+  AssertNoAsynchronousErrors(left_tab);
+  AssertNoAsynchronousErrors(right_tab);
+
+  // TODO(phoglund): (de-dupe later) different from original flow.
+  EXPECT_TRUE(UglyPollingWaitUntil(
+      "doneFrameCapturing()", "done-capturing", right_tab));
+
+  HangUp(left_tab);
+  WaitUntilHangupVerified(left_tab);
+  WaitUntilHangupVerified(right_tab);
+
+  AssertNoAsynchronousErrors(left_tab);
+  AssertNoAsynchronousErrors(right_tab);
+
+  // TODO(phoglund): (de-dupe later) different from original flow.
+  EXPECT_TRUE(UglyPollingWaitUntil(
+      "haveMoreFramesToSend()", "no-more-frames", right_tab));
+
+  RunARGBtoI420Converter(
+      kVgaWidth, kVgaHeight, GetWorkingDir().Append(kCapturedYuvFileName));
+  std::string output =
+      CompareVideos(kVgaWidth,
+                    kVgaHeight,
+                    GetWorkingDir().Append(kCapturedYuvFileName),
+                    GetWorkingDir().Append(kReferenceYuvFileName),
+                    GetWorkingDir().Append(kStatsFileName));
+
+  PrintFramesCountPerfResults(output);
+  PrintPsnrAndSsimPerfResults(output);
+}
diff --git a/chrome/browser/media/media_capture_devices_dispatcher.cc b/chrome/browser/media/media_capture_devices_dispatcher.cc
index 56a7096..788d79d 100644
--- a/chrome/browser/media/media_capture_devices_dispatcher.cc
+++ b/chrome/browser/media/media_capture_devices_dispatcher.cc
@@ -137,9 +137,7 @@
 MediaCaptureDevicesDispatcher::GetAudioCaptureDevices() {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   if (!is_device_enumeration_disabled_ && !devices_enumerated_) {
-    BrowserThread::PostTask(
-        BrowserThread::IO, FROM_HERE,
-        base::Bind(&content::EnsureMonitorCaptureDevices));
+    content::EnsureMonitorCaptureDevices();
     devices_enumerated_ = true;
   }
   return audio_devices_;
@@ -149,9 +147,7 @@
 MediaCaptureDevicesDispatcher::GetVideoCaptureDevices() {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   if (!is_device_enumeration_disabled_ && !devices_enumerated_) {
-    BrowserThread::PostTask(
-        BrowserThread::IO, FROM_HERE,
-        base::Bind(&content::EnsureMonitorCaptureDevices));
+    content::EnsureMonitorCaptureDevices();
     devices_enumerated_ = true;
   }
   return video_devices_;
diff --git a/chrome/browser/media/media_stream_infobar_delegate.cc b/chrome/browser/media/media_stream_infobar_delegate.cc
index 403ca77..36bfa97 100644
--- a/chrome/browser/media/media_stream_infobar_delegate.cc
+++ b/chrome/browser/media/media_stream_infobar_delegate.cc
@@ -11,10 +11,10 @@
 #include "chrome/browser/infobars/infobar_service.h"
 #include "chrome/common/url_constants.h"
 #include "content/public/browser/web_contents.h"
-#include "googleurl/src/gurl.h"
 #include "grit/generated_resources.h"
 #include "grit/theme_resources.h"
 #include "ui/base/l10n/l10n_util.h"
+#include "url/gurl.h"
 
 namespace {
 
diff --git a/chrome/browser/media/media_stream_infobar_delegate.h b/chrome/browser/media/media_stream_infobar_delegate.h
index 2950300..146c7536 100644
--- a/chrome/browser/media/media_stream_infobar_delegate.h
+++ b/chrome/browser/media/media_stream_infobar_delegate.h
@@ -31,7 +31,9 @@
                      const content::MediaResponseCallback& callback);
 
  private:
+  friend class MediaStreamInfobarTest;
   friend class WebrtcBrowserTest;
+  friend class WebrtcVideoQualityBrowserTest;
 
   // MediaStreamInfoBarDelegate takes the ownership of the |controller|.
   MediaStreamInfoBarDelegate(
diff --git a/chrome/browser/media/webrtc_log_upload_list.cc b/chrome/browser/media/webrtc_log_upload_list.cc
new file mode 100644
index 0000000..fdaaad0
--- /dev/null
+++ b/chrome/browser/media/webrtc_log_upload_list.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 "chrome/browser/media/webrtc_log_upload_list.h"
+
+#include "base/files/file_path.h"
+#include "base/path_service.h"
+#include "chrome/common/chrome_paths.h"
+
+// static
+const char* WebRtcLogUploadList::kWebRtcLogListFilename =
+    "webrtc_log_uploads.log";
+
+// static
+WebRtcLogUploadList* WebRtcLogUploadList::Create(Delegate* delegate) {
+  base::FilePath log_dir_path;
+  PathService::Get(chrome::DIR_USER_DATA, &log_dir_path);
+  base::FilePath upload_log_path =
+      log_dir_path.AppendASCII(kWebRtcLogListFilename);
+  return new WebRtcLogUploadList(delegate, upload_log_path);
+}
+
+WebRtcLogUploadList::WebRtcLogUploadList(Delegate* delegate,
+                                         const base::FilePath& upload_log_path)
+    : UploadList(delegate, upload_log_path) {}
+
+WebRtcLogUploadList::~WebRtcLogUploadList() {}
diff --git a/chrome/browser/media/webrtc_log_upload_list.h b/chrome/browser/media/webrtc_log_upload_list.h
new file mode 100644
index 0000000..b829d8e
--- /dev/null
+++ b/chrome/browser/media/webrtc_log_upload_list.h
@@ -0,0 +1,32 @@
+// 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_WEBRTC_LOG_UPLOAD_LIST_H_
+#define CHROME_BROWSER_MEDIA_WEBRTC_LOG_UPLOAD_LIST_H_
+
+#include "chrome/browser/upload_list.h"
+
+// Loads and parses a text file list of uploaded WebRTC logs.
+class WebRtcLogUploadList : public UploadList {
+ public:
+  // Creates the WebRTC log upload list with the given callback delegate.
+  static WebRtcLogUploadList* Create(Delegate* delegate);
+
+  // Used in this class when reading the list file and in WebRtcLogUploader when
+  // writing to the list file.
+  static const char* kWebRtcLogListFilename;
+
+  // Creates a new WebRTC log upload list with the given callback delegate.
+  // |upload_log_path| is the full path to the file to read the list from.
+  explicit WebRtcLogUploadList(Delegate* delegate,
+                               const base::FilePath& upload_log_path);
+
+ protected:
+  virtual ~WebRtcLogUploadList();
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(WebRtcLogUploadList);
+};
+
+#endif  // CHROME_BROWSER_MEDIA_WEBRTC_LOG_UPLOAD_LIST_H_
diff --git a/chrome/browser/media/webrtc_logging_handler_host.cc b/chrome/browser/media/webrtc_logging_handler_host.cc
index a318981..c46ae32 100644
--- a/chrome/browser/media/webrtc_logging_handler_host.cc
+++ b/chrome/browser/media/webrtc_logging_handler_host.cc
@@ -4,6 +4,8 @@
 
 #include "chrome/browser/media/webrtc_logging_handler_host.h"
 
+#include <string>
+
 #include "base/bind.h"
 #include "base/cpu.h"
 #include "base/logging.h"
@@ -22,6 +24,8 @@
 #include "content/public/browser/render_process_host.h"
 #include "gpu/config/gpu_info.h"
 #include "gpu/config/gpu_info_collector.h"
+#include "net/base/address_family.h"
+#include "net/base/net_util.h"
 #include "net/url_request/url_request_context_getter.h"
 
 #if defined(OS_LINUX)
@@ -42,6 +46,47 @@
 const size_t kWebRtcLogSize = 6 * 1024 * 1024;  // 6 MB
 #endif
 
+namespace {
+
+// For privacy reasons when logging IP addresses. The returned "sensitive
+// string" is for release builds a string with the end stripped away. Last
+// octet for IPv4 and last 80 bits (5 groups) for IPv6. String will be
+// "1.2.3.x" and "1.2.3::" respectively. For debug builds, the string is
+// not stripped.
+std::string IPAddressToSensitiveString(const net::IPAddressNumber& address) {
+#if defined(NDEBUG)
+  std::string sensitive_address;
+  switch (net::GetAddressFamily(address)) {
+    case net::ADDRESS_FAMILY_IPV4: {
+      sensitive_address = net::IPAddressToString(address);
+      size_t find_pos = sensitive_address.rfind('.');
+      if (find_pos == std::string::npos)
+        return std::string();
+      sensitive_address.resize(find_pos);
+      sensitive_address += ".x";
+      break;
+    }
+    case net::ADDRESS_FAMILY_IPV6: {
+      // TODO(grunell): Create a string of format "1:2:3:x:x:x:x:x" to clarify
+      // that the end has been stripped out.
+      net::IPAddressNumber sensitive_address_number = address;
+      sensitive_address_number.resize(net::kIPv6AddressSize - 10);
+      sensitive_address_number.resize(net::kIPv6AddressSize, 0);
+      sensitive_address = net::IPAddressToString(sensitive_address_number);
+      break;
+    }
+    case net::ADDRESS_FAMILY_UNSPECIFIED: {
+      break;
+    }
+  }
+  return sensitive_address;
+#else
+  return net::IPAddressToString(address);
+#endif
+}
+
+}  // namespace
+
 WebRtcLoggingHandlerHost::WebRtcLoggingHandlerHost() {}
 
 WebRtcLoggingHandlerHost::~WebRtcLoggingHandlerHost() {}
@@ -88,6 +133,10 @@
 #if defined(OS_CHROMEOS)
   chromeos::CrosSettings::Get()->GetBoolean(chromeos::kStatsReportingPref,
                                             &enabled);
+#elif defined(OS_ANDROID)
+  // Android has its own settings for metrics / crash uploading.
+  enabled = g_browser_process->local_state()->GetBoolean(
+      prefs::kCrashReportingEnabled);
 #else
   enabled = g_browser_process->local_state()->GetBoolean(
       prefs::kMetricsReportingEnabled);
@@ -156,6 +205,7 @@
   pcb.Write(info.c_str(), info.length());
   std::string cpu_brand = cpu.cpu_brand();
   // Workaround for crbug.com/249713.
+  // TODO(grunell): Remove workaround when bug is fixed.
   size_t null_pos = cpu_brand.find('\0');
   if (null_pos != std::string::npos)
     cpu_brand.erase(null_pos);
@@ -180,6 +230,19 @@
          "', driver-version=" + gpu_info.driver_version + '\n';
   pcb.Write(info.c_str(), info.length());
 
+  // Network interfaces
+  net::NetworkInterfaceList network_list;
+  net::GetNetworkList(&network_list);
+  info  = "Discovered " + IntToString(network_list.size()) +
+          " network interfaces:" + '\n';
+  pcb.Write(info.c_str(), info.length());
+  for (net::NetworkInterfaceList::iterator it = network_list.begin();
+       it != network_list.end(); ++it) {
+    info = "Name: " + it->name +
+           ", Address: " + IPAddressToSensitiveString(it->address) + '\n';
+    pcb.Write(info.c_str(), info.length());
+  }
+
   BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, base::Bind(
       &WebRtcLoggingHandlerHost::NotifyLogOpened, this));
 }
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 b1cba04..29a7f11 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
@@ -91,8 +91,7 @@
   if (!callback.is_null()) {
     base::PlatformFile invalid_file = base::kInvalidPlatformFileValue;
     callback.Run(base::PLATFORM_FILE_ERROR_SECURITY,
-                 base::PassPlatformFile(&invalid_file),
-                 false);
+                 base::PassPlatformFile(&invalid_file));
   }
   return true;
 }
@@ -249,6 +248,16 @@
   return true;
 }
 
+bool DeviceMediaAsyncFileUtil::DeleteRecursively(
+    scoped_ptr<FileSystemOperationContext> context,
+    const FileSystemURL& url,
+    const StatusCallback& callback) {
+  DCHECK(IsOnIOThread(context.get()));
+  if (!callback.is_null())
+    callback.Run(base::PLATFORM_FILE_ERROR_INVALID_OPERATION);
+  return true;
+}
+
 bool DeviceMediaAsyncFileUtil::CreateSnapshotFile(
     scoped_ptr<FileSystemOperationContext> context,
     const FileSystemURL& url,
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 d965c50..e109c64 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
@@ -91,6 +91,10 @@
       scoped_ptr<fileapi::FileSystemOperationContext> context,
       const fileapi::FileSystemURL& url,
       const StatusCallback& callback) OVERRIDE;
+  virtual bool DeleteRecursively(
+      scoped_ptr<fileapi::FileSystemOperationContext> context,
+      const fileapi::FileSystemURL& url,
+      const StatusCallback& callback) OVERRIDE;
   virtual bool CreateSnapshotFile(
       scoped_ptr<fileapi::FileSystemOperationContext> context,
       const fileapi::FileSystemURL& url,
diff --git a/chrome/browser/media_galleries/fileapi/itunes_data_provider.cc b/chrome/browser/media_galleries/fileapi/itunes_data_provider.cc
index 9709b66..951e91b 100644
--- a/chrome/browser/media_galleries/fileapi/itunes_data_provider.cc
+++ b/chrome/browser/media_galleries/fileapi/itunes_data_provider.cc
@@ -7,13 +7,16 @@
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/format_macros.h"
+#include "base/location.h"
 #include "base/logging.h"
 #include "base/platform_file.h"
 #include "base/stl_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/threading/thread_restrictions.h"
-#include "chrome/browser/media_galleries/fileapi/itunes_library_parser.h"
 #include "chrome/browser/media_galleries/fileapi/media_file_system_mount_point_provider.h"
+#include "chrome/browser/media_galleries/imported_media_gallery_registry.h"
+#include "chrome/common/itunes_library.h"
+#include "content/public/browser/browser_thread.h"
 
 using chrome::MediaFileSystemMountPointProvider;
 
@@ -21,49 +24,22 @@
 
 namespace {
 
-// A "reasonable" artificial limit.
-// TODO(vandebo): Add a UMA to figure out what common values are.
-const int64 kMaxLibraryFileSize = 150 * 1024 * 1024;
+typedef base::Callback<void(scoped_ptr<base::FilePathWatcher> watcher)>
+    FileWatchStartedCallback;
 
-std::string ReadFile(const base::FilePath& path) {
-  base::ThreadRestrictions::AssertIOAllowed();
-
-  base::PlatformFile file = base::CreatePlatformFile(
-      path, base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ, NULL, NULL);
-  if (file == base::kInvalidPlatformFileValue)
-    return std::string();
-
-  base::PlatformFileInfo file_info;
-  if (!base::GetPlatformFileInfo(file, &file_info) ||
-      file_info.size > kMaxLibraryFileSize) {
-    base::ClosePlatformFile(file);
-    return std::string();
-  }
-
-  std::string result(file_info.size, 0);
-  if (base::ReadPlatformFile(file, 0, string_as_array(&result),
-        file_info.size) != file_info.size) {
-    result.clear();
-  }
-
-  base::ClosePlatformFile(file);
-  return result;
-}
-
-ITunesDataProvider::Album MakeUniqueTrackNames(
-    const ITunesLibraryParser::Album& album) {
+ITunesDataProvider::Album MakeUniqueTrackNames(const parser::Album& album) {
   // TODO(vandebo): It would be nice to ensure that names returned from here
   // are stable, but aside from persisting every name returned, it's not
   // obvious how to do that (without including the track id in every name).
-  typedef std::set<const ITunesLibraryParser::Track*> TrackRefs;
+  typedef std::set<const parser::Track*> TrackRefs;
   typedef std::map<ITunesDataProvider::TrackName, TrackRefs> AlbumInfo;
 
   ITunesDataProvider::Album result;
   AlbumInfo duped_tracks;
 
-  ITunesLibraryParser::Album::const_iterator album_it;
+  parser::Album::const_iterator album_it;
   for (album_it = album.begin(); album_it != album.end(); ++album_it) {
-    const ITunesLibraryParser::Track& track = *album_it;
+    const parser::Track& track = *album_it;
     std::string name = track.location.BaseName().AsUTF8Unsafe();
     duped_tracks[name].insert(&track);
   }
@@ -90,33 +66,68 @@
   return result;
 }
 
+// Bounces |path| and |error| to |callback| from the FILE thread to the media
+// task runner.
+void OnLibraryChanged(const base::FilePathWatcher::Callback& callback,
+                      const base::FilePath& path,
+                      bool error) {
+  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
+  MediaFileSystemMountPointProvider::MediaTaskRunner()->PostTask(
+      FROM_HERE, base::Bind(callback, path, error));
+}
+
+// The watch has to be started on the FILE thread, and the callback called by
+// the FilePathWatcher also needs to run on the FILE thread.
+void StartLibraryWatchOnFileThread(
+    const base::FilePath& library_path,
+    const FileWatchStartedCallback& watch_started_callback,
+    const base::FilePathWatcher::Callback& library_changed_callback) {
+  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
+  scoped_ptr<base::FilePathWatcher> watcher(new base::FilePathWatcher);
+  bool success = watcher->Watch(
+      library_path, false /*recursive*/,
+      base::Bind(&OnLibraryChanged, library_changed_callback));
+  if (!success)
+    LOG(ERROR) << "Adding watch for " << library_path.value() << " failed";
+  MediaFileSystemMountPointProvider::MediaTaskRunner()->PostTask(
+      FROM_HERE,
+      base::Bind(watch_started_callback, base::Passed(&watcher)));
+}
+
 }  // namespace
 
 ITunesDataProvider::ITunesDataProvider(const base::FilePath& library_path)
     : library_path_(library_path),
       needs_refresh_(true),
-      is_valid_(false),
-      weak_factory_(this) {
+      is_valid_(false) {
   DCHECK(MediaFileSystemMountPointProvider::CurrentlyOnMediaTaskRunnerThread());
   DCHECK(!library_path_.empty());
-  bool ret = library_watcher_.Watch(
-      library_path_, false /*recursive*/,
-      base::Bind(&ITunesDataProvider::OnLibraryChanged,
-                 weak_factory_.GetWeakPtr()));
-  if (!ret)
-    LOG(ERROR) << "Adding watch for " << library_path_.value() << " failed";
+
+  content::BrowserThread::PostTask(
+      content::BrowserThread::FILE,
+      FROM_HERE,
+      base::Bind(StartLibraryWatchOnFileThread,
+                 library_path_,
+                 base::Bind(&ITunesDataProvider::OnLibraryWatchStartedCallback),
+                 base::Bind(&ITunesDataProvider::OnLibraryChangedCallback)));
 }
 
 ITunesDataProvider::~ITunesDataProvider() {}
 
-void ITunesDataProvider::RefreshData(
-    const base::Callback<void(bool)>& ready_callback) {
+// TODO(vandebo): add a file watch that resets |needs_refresh_| when the
+// file changes.
+void ITunesDataProvider::RefreshData(const ReadyCallback& ready_callback) {
   DCHECK(MediaFileSystemMountPointProvider::CurrentlyOnMediaTaskRunnerThread());
-  if (needs_refresh_) {
-    is_valid_ = ParseLibrary();
-    needs_refresh_ = false;
+  if (!needs_refresh_) {
+    ready_callback.Run(is_valid_);
+    return;
   }
-  ready_callback.Run(is_valid_);
+
+  needs_refresh_ = false;
+  xml_parser_ = new SafeITunesLibraryParser(
+      library_path_,
+      base::Bind(&ITunesDataProvider::OnLibraryParsedCallback, ready_callback));
+  xml_parser_->Start();
 }
 
 const base::FilePath& ITunesDataProvider::library_path() const {
@@ -137,7 +148,6 @@
   if (library_it == library_.end())
     return false;
   return ContainsKey(library_it->second, album);
-
 }
 
 base::FilePath ITunesDataProvider::GetTrackLocation(
@@ -192,40 +202,55 @@
     const ArtistName& artist, const AlbumName& album) const {
   DCHECK(MediaFileSystemMountPointProvider::CurrentlyOnMediaTaskRunnerThread());
   DCHECK(is_valid_);
-  Album empty_result;
+  Album result;
   Library::const_iterator artist_lookup = library_.find(artist);
-  if (artist_lookup == library_.end())
-    return empty_result;
-
-  Artist::const_iterator album_lookup = artist_lookup->second.find(album);
-  if (album_lookup == artist_lookup->second.end())
-    return empty_result;
-
-  return album_lookup->second;
+  if (artist_lookup != library_.end()) {
+    Artist::const_iterator album_lookup = artist_lookup->second.find(album);
+    if (album_lookup != artist_lookup->second.end())
+      result = album_lookup->second;
+  }
+  return result;
 }
 
-bool ITunesDataProvider::ParseLibrary() {
+// static
+void ITunesDataProvider::OnLibraryWatchStartedCallback(
+    scoped_ptr<base::FilePathWatcher> library_watcher) {
   DCHECK(MediaFileSystemMountPointProvider::CurrentlyOnMediaTaskRunnerThread());
-  std::string xml = ReadFile(library_path_);
+  ITunesDataProvider* provider =
+      chrome::ImportedMediaGalleryRegistry::ITunesDataProvider();
+  if (provider)
+    provider->OnLibraryWatchStarted(library_watcher.Pass());
+}
 
-  library_.clear();
-  ITunesLibraryParser parser;
-  if (!parser.Parse(xml))
-    return false;
+// static
+void ITunesDataProvider::OnLibraryChangedCallback(const base::FilePath& path,
+                                                  bool error) {
+  DCHECK(MediaFileSystemMountPointProvider::CurrentlyOnMediaTaskRunnerThread());
+  ITunesDataProvider* provider =
+      chrome::ImportedMediaGalleryRegistry::ITunesDataProvider();
+  if (provider)
+    provider->OnLibraryChanged(path, error);
+}
 
-  ITunesLibraryParser::Library::const_iterator artist_it;
-  ITunesLibraryParser::Albums::const_iterator album_it;
-  for (artist_it = parser.library().begin();
-       artist_it != parser.library().end();
-       ++artist_it) {
-    for (album_it = artist_it->second.begin();
-         album_it != artist_it->second.end();
-         ++album_it) {
-      library_[artist_it->first][album_it->first] =
-          MakeUniqueTrackNames(album_it->second);
-    }
+// static
+void ITunesDataProvider::OnLibraryParsedCallback(
+    const ReadyCallback& ready_callback,
+    bool result,
+    const parser::Library& library) {
+  DCHECK(MediaFileSystemMountPointProvider::CurrentlyOnMediaTaskRunnerThread());
+  ITunesDataProvider* provider =
+      chrome::ImportedMediaGalleryRegistry::ITunesDataProvider();
+  if (!provider) {
+    ready_callback.Run(false);
+    return;
   }
-  return true;
+  provider->OnLibraryParsed(ready_callback, result, library);
+}
+
+void ITunesDataProvider::OnLibraryWatchStarted(
+    scoped_ptr<base::FilePathWatcher> library_watcher) {
+  DCHECK(MediaFileSystemMountPointProvider::CurrentlyOnMediaTaskRunnerThread());
+  library_watcher_.reset(library_watcher.release());
 }
 
 void ITunesDataProvider::OnLibraryChanged(const base::FilePath& path,
@@ -237,4 +262,25 @@
   needs_refresh_ = true;
 }
 
+void ITunesDataProvider::OnLibraryParsed(const ReadyCallback& ready_callback,
+                                         bool result,
+                                         const parser::Library& library) {
+  DCHECK(MediaFileSystemMountPointProvider::CurrentlyOnMediaTaskRunnerThread());
+  is_valid_ = result;
+  if (is_valid_) {
+    library_.clear();
+    for (parser::Library::const_iterator artist_it = library.begin();
+         artist_it != library.end();
+         ++artist_it) {
+      for (parser::Albums::const_iterator album_it = artist_it->second.begin();
+           album_it != artist_it->second.end();
+           ++album_it) {
+        library_[artist_it->first][album_it->first] =
+            MakeUniqueTrackNames(album_it->second);
+      }
+    }
+  }
+  ready_callback.Run(is_valid_);
+}
+
 }  // namespace itunes
diff --git a/chrome/browser/media_galleries/fileapi/itunes_data_provider.h b/chrome/browser/media_galleries/fileapi/itunes_data_provider.h
index 26d7e14..5d8cb4f 100644
--- a/chrome/browser/media_galleries/fileapi/itunes_data_provider.h
+++ b/chrome/browser/media_galleries/fileapi/itunes_data_provider.h
@@ -13,8 +13,7 @@
 #include "base/callback_forward.h"
 #include "base/files/file_path.h"
 #include "base/files/file_path_watcher.h"
-#include "base/memory/weak_ptr.h"
-#include "chrome/browser/media_galleries/fileapi/itunes_library_parser.h"
+#include "chrome/browser/media_galleries/fileapi/safe_itunes_library_parser.h"
 
 namespace itunes {
 
@@ -28,13 +27,14 @@
   typedef std::string AlbumName;
   typedef std::string TrackName;
   typedef std::map<TrackName, base::FilePath> Album;
+  typedef base::Callback<void(bool)> ReadyCallback;
 
   explicit ITunesDataProvider(const base::FilePath& library_path);
   ~ITunesDataProvider();
 
   // Ask the data provider to refresh the data if necessary. |ready_callback|
   // will be called with the result; false if unable to parse the XML file.
-  void RefreshData(const base::Callback<void(bool)>& ready_callback);
+  void RefreshData(const ReadyCallback& ready_callback);
 
   // Get the platform path for the library XML file.
   const base::FilePath& library_path() const;
@@ -64,10 +64,29 @@
   typedef std::map<AlbumName, Album> Artist;
   typedef std::map<ArtistName, Artist> Library;
 
-  bool ParseLibrary();
+  // These are hacks to work around http://crbug.com/165590. Otherwise a
+  // WeakPtrFactory would be the obvious answer here.
+  // static so they can call their real counterparts.
+  // TODO(vandebo) Remove these when the bug is fixed.
+  static void OnLibraryWatchStartedCallback(
+      scoped_ptr<base::FilePathWatcher> library_watcher);
+  static void OnLibraryChangedCallback(const base::FilePath& path, bool error);
+  static void OnLibraryParsedCallback(const ReadyCallback& ready_callback,
+                                      bool result,
+                                      const parser::Library& library);
 
+  // Called when the FilePathWatcher for |library_path_| has tried to add an
+  // watch.
+  void OnLibraryWatchStarted(scoped_ptr<base::FilePathWatcher> library_watcher);
+
+  // Called when |library_path_| has changed.
   void OnLibraryChanged(const base::FilePath& path, bool error);
 
+  // Called when the utility process finishes parsing the library XML file.
+  void OnLibraryParsed(const ReadyCallback& ready_callback,
+                       bool result,
+                       const parser::Library& library);
+
   // Path to the library XML file.
   const base::FilePath library_path_;
 
@@ -82,9 +101,9 @@
   bool is_valid_;
 
   // A watcher on the library xml file.
-  base::FilePathWatcher library_watcher_;
+  scoped_ptr<base::FilePathWatcher> library_watcher_;
 
-  base::WeakPtrFactory<ITunesDataProvider> weak_factory_;
+  scoped_refptr<SafeITunesLibraryParser> xml_parser_;
 
   DISALLOW_COPY_AND_ASSIGN(ITunesDataProvider);
 };
diff --git a/chrome/browser/media_galleries/fileapi/itunes_file_util.cc b/chrome/browser/media_galleries/fileapi/itunes_file_util.cc
index 12c0e70..d5e247d 100644
--- a/chrome/browser/media_galleries/fileapi/itunes_file_util.cc
+++ b/chrome/browser/media_galleries/fileapi/itunes_file_util.cc
@@ -4,6 +4,11 @@
 
 #include "chrome/browser/media_galleries/fileapi/itunes_file_util.h"
 
+#include <set>
+#include <string>
+#include <vector>
+
+#include "base/bind_helpers.h"
 #include "base/file_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/media_galleries/fileapi/itunes_data_provider.h"
@@ -46,30 +51,33 @@
 }
 
 void ItunesFileUtil::GetFileInfoOnTaskRunnerThread(
-    fileapi::FileSystemOperationContext* context,
+    scoped_ptr<fileapi::FileSystemOperationContext> context,
     const fileapi::FileSystemURL& url,
     const GetFileInfoCallback& callback) {
   GetDataProvider()->RefreshData(
       base::Bind(&ItunesFileUtil::GetFileInfoWithFreshDataProvider,
-                 weak_factory_.GetWeakPtr(), context, url, callback));
+                 weak_factory_.GetWeakPtr(), base::Passed(&context), url,
+                 callback));
 }
 
 void ItunesFileUtil::ReadDirectoryOnTaskRunnerThread(
-    fileapi::FileSystemOperationContext* context,
+    scoped_ptr<fileapi::FileSystemOperationContext> context,
     const fileapi::FileSystemURL& url,
     const ReadDirectoryCallback& callback) {
   GetDataProvider()->RefreshData(
       base::Bind(&ItunesFileUtil::ReadDirectoryWithFreshDataProvider,
-                 weak_factory_.GetWeakPtr(), context, url, callback));
+                 weak_factory_.GetWeakPtr(), base::Passed(&context), url,
+                 callback));
 }
 
 void ItunesFileUtil::CreateSnapshotFileOnTaskRunnerThread(
-    fileapi::FileSystemOperationContext* context,
+    scoped_ptr<fileapi::FileSystemOperationContext> context,
     const fileapi::FileSystemURL& url,
     const CreateSnapshotFileCallback& callback) {
   GetDataProvider()->RefreshData(
       base::Bind(&ItunesFileUtil::CreateSnapshotFileWithFreshDataProvider,
-                 weak_factory_.GetWeakPtr(), context, url, callback));
+                 weak_factory_.GetWeakPtr(), base::Passed(&context), url,
+                 callback));
 }
 
 // Contents of the iTunes media gallery:
@@ -262,7 +270,7 @@
 }
 
 void ItunesFileUtil::GetFileInfoWithFreshDataProvider(
-    fileapi::FileSystemOperationContext* context,
+    scoped_ptr<fileapi::FileSystemOperationContext> context,
     const fileapi::FileSystemURL& url,
     const GetFileInfoCallback& callback,
     bool valid_parse) {
@@ -276,11 +284,12 @@
     }
     return;
   }
-  NativeMediaFileUtil::GetFileInfoOnTaskRunnerThread(context, url, callback);
+  NativeMediaFileUtil::GetFileInfoOnTaskRunnerThread(context.Pass(), url,
+                                                     callback);
 }
 
 void ItunesFileUtil::ReadDirectoryWithFreshDataProvider(
-    fileapi::FileSystemOperationContext* context,
+    scoped_ptr<fileapi::FileSystemOperationContext> context,
     const fileapi::FileSystemURL& url,
     const ReadDirectoryCallback& callback,
     bool valid_parse) {
@@ -294,11 +303,12 @@
     }
     return;
   }
-  NativeMediaFileUtil::ReadDirectoryOnTaskRunnerThread(context, url, callback);
+  NativeMediaFileUtil::ReadDirectoryOnTaskRunnerThread(context.Pass(), url,
+                                                       callback);
 }
 
 void ItunesFileUtil::CreateSnapshotFileWithFreshDataProvider(
-    fileapi::FileSystemOperationContext* context,
+    scoped_ptr<fileapi::FileSystemOperationContext> context,
     const fileapi::FileSystemURL& url,
     const CreateSnapshotFileCallback& callback,
     bool valid_parse) {
@@ -315,7 +325,7 @@
     }
     return;
   }
-  NativeMediaFileUtil::CreateSnapshotFileOnTaskRunnerThread(context, url,
+  NativeMediaFileUtil::CreateSnapshotFileOnTaskRunnerThread(context.Pass(), url,
                                                             callback);
 }
 
diff --git a/chrome/browser/media_galleries/fileapi/itunes_file_util.h b/chrome/browser/media_galleries/fileapi/itunes_file_util.h
index b1208fa..d87bb51 100644
--- a/chrome/browser/media_galleries/fileapi/itunes_file_util.h
+++ b/chrome/browser/media_galleries/fileapi/itunes_file_util.h
@@ -5,6 +5,7 @@
 #ifndef CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_ITUNES_FILE_UTIL_H_
 #define CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_ITUNES_FILE_UTIL_H_
 
+#include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/media_galleries/fileapi/native_media_file_util.h"
 
@@ -24,15 +25,15 @@
  protected:
   // NativeMediaFileUtil overrides.
   virtual void GetFileInfoOnTaskRunnerThread(
-      fileapi::FileSystemOperationContext* context,
+      scoped_ptr<fileapi::FileSystemOperationContext> context,
       const fileapi::FileSystemURL& url,
       const GetFileInfoCallback& callback) OVERRIDE;
   virtual void ReadDirectoryOnTaskRunnerThread(
-      fileapi::FileSystemOperationContext* context,
+      scoped_ptr<fileapi::FileSystemOperationContext> context,
       const fileapi::FileSystemURL& url,
       const ReadDirectoryCallback& callback) OVERRIDE;
   virtual void CreateSnapshotFileOnTaskRunnerThread(
-      fileapi::FileSystemOperationContext* context,
+      scoped_ptr<fileapi::FileSystemOperationContext> context,
       const fileapi::FileSystemURL& url,
       const CreateSnapshotFileCallback& callback) OVERRIDE;
   virtual base::PlatformFileError GetFileInfoSync(
@@ -57,17 +58,17 @@
 
  private:
   void GetFileInfoWithFreshDataProvider(
-      fileapi::FileSystemOperationContext* context,
+      scoped_ptr<fileapi::FileSystemOperationContext> context,
       const fileapi::FileSystemURL& url,
       const GetFileInfoCallback& callback,
       bool valid_parse);
   void ReadDirectoryWithFreshDataProvider(
-      fileapi::FileSystemOperationContext* context,
+      scoped_ptr<fileapi::FileSystemOperationContext> context,
       const fileapi::FileSystemURL& url,
       const ReadDirectoryCallback& callback,
       bool valid_parse);
   virtual void CreateSnapshotFileWithFreshDataProvider(
-      fileapi::FileSystemOperationContext* context,
+      scoped_ptr<fileapi::FileSystemOperationContext> context,
       const fileapi::FileSystemURL& url,
       const CreateSnapshotFileCallback& callback,
       bool valid_parse);
diff --git a/chrome/browser/media_galleries/fileapi/itunes_finder.cc b/chrome/browser/media_galleries/fileapi/itunes_finder.cc
index 3c4eaf4..1a59629 100644
--- a/chrome/browser/media_galleries/fileapi/itunes_finder.cc
+++ b/chrome/browser/media_galleries/fileapi/itunes_finder.cc
@@ -47,8 +47,8 @@
 
 void ITunesFinder::PostResultToUIThread(const std::string& unique_id) {
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
-  // The use of base::Owned() below will cause this class to delete as soon as
-  // FinishOnUIThread() finishes.
+  // The use of base::Owned() below will cause this class to get deleted either
+  // when FinishOnUIThread() finishes or if the PostTask() fails.
   content::BrowserThread::PostTask(
       content::BrowserThread::UI,
       FROM_HERE,
diff --git a/chrome/browser/media_galleries/fileapi/itunes_finder_mac.mm b/chrome/browser/media_galleries/fileapi/itunes_finder_mac.mm
index 79846ac..3780160 100644
--- a/chrome/browser/media_galleries/fileapi/itunes_finder_mac.mm
+++ b/chrome/browser/media_galleries/fileapi/itunes_finder_mac.mm
@@ -7,9 +7,9 @@
 #include "base/file_util.h"
 #include "base/logging.h"
 #import "base/mac/foundation_util.h"
-#import "base/memory/scoped_nsobject.h"
+#import "base/mac/scoped_nsobject.h"
 #include "base/strings/sys_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "content/public/browser/browser_thread.h"
 
 using base::mac::CFCast;
@@ -28,8 +28,8 @@
 
   CFStringRef iapp_id = CFSTR("com.apple.iApps");
   CFStringRef itunes_db_key = CFSTR("iTunesRecentDatabasePaths");
-  scoped_nsobject<NSArray> plist(CFToNSCast(CFCast<CFArrayRef>(
-      CFPreferencesCopyAppValue(itunes_db_key, iapp_id))));
+  base::scoped_nsobject<NSArray> plist(CFToNSCast(
+      CFCast<CFArrayRef>(CFPreferencesCopyAppValue(itunes_db_key, iapp_id))));
   if (!plist) {
     PostResultToUIThread(std::string());
     return;
diff --git a/chrome/browser/media_galleries/fileapi/itunes_finder_win.cc b/chrome/browser/media_galleries/fileapi/itunes_finder_win.cc
index 5626c30..40016a5 100644
--- a/chrome/browser/media_galleries/fileapi/itunes_finder_win.cc
+++ b/chrome/browser/media_galleries/fileapi/itunes_finder_win.cc
@@ -6,109 +6,32 @@
 
 #include <string>
 
-#include "base/base64.h"
 #include "base/base_paths_win.h"
 #include "base/file_util.h"
 #include "base/files/file_path.h"
 #include "base/logging.h"
 #include "base/path_service.h"
-#include "base/strings/string_util.h"
-#include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/media_galleries/fileapi/itunes_xml_utils.h"
+#include "chrome/browser/media_galleries/fileapi/safe_itunes_pref_parser_win.h"
 #include "chrome/common/chrome_paths.h"
-#include "third_party/libxml/chromium/libxml_utils.h"
+#include "content/public/browser/browser_thread.h"
 
 namespace itunes {
 
 namespace {
 
-// Read the iTunes preferences from |pref_file| and then try to extract the
-// library XML location from the XML file. Return it if found. The minimal
-// valid snippet of XML is:
-//
-//   <plist>
-//     <dict>
-//       <key>User Preferences</key>
-//       <dict>
-//         <key>iTunes Library XML Location:1</key>
-//         <data>Base64 encoded w string path</data>
-//       </dict>
-//     </dict>
-//   </plist>
-//
-base::FilePath::StringType FindLibraryLocationInPrefXML(
-    const std::string& pref_file) {
-  XmlReader reader;
-  base::FilePath::StringType result;
+// Try to read the iTunes preferences file from the default location and return
+// its contents if found.
+std::string GetPrefFileData() {
+  std::string xml_pref_data;
 
-  if (!reader.LoadFile(pref_file))
-    return result;
-
-  // Find the plist node and then search within that tag.
-  if (!SeekToNodeAtCurrentDepth(&reader, "plist"))
-    return result;
-  if (!reader.Read())
-    return result;
-
-  if (!SeekToNodeAtCurrentDepth(&reader, "dict"))
-    return result;
-
-  if (!SeekInDict(&reader, "User Preferences"))
-    return result;
-
-  if (!SeekToNodeAtCurrentDepth(&reader, "dict"))
-    return result;
-
-  if (!SeekInDict(&reader, "iTunes Library XML Location:1"))
-    return result;
-
-  if (!SeekToNodeAtCurrentDepth(&reader, "data"))
-    return result;
-
-  std::string pref_value;
-  if (!reader.ReadElementContent(&pref_value))
-    return result;
-  // The data is a base64 encoded wchar_t*. Because Base64Decode uses
-  // std::strings, the result has to be casted to a wchar_t*.
-  std::string data;
-  if (!base::Base64Decode(CollapseWhitespaceASCII(pref_value, true), &data))
-    return result;
-  return base::FilePath::StringType(
-      reinterpret_cast<const wchar_t*>(data.data()), data.size()/2);
-}
-
-// Try to find the iTunes library XML by examining the iTunes preferences
-// file and return it if found.
-base::FilePath TryPreferencesFile() {
   base::FilePath appdata_dir;
-  if (!PathService::Get(base::DIR_APP_DATA, &appdata_dir))
-    return base::FilePath();
-  base::FilePath pref_file = appdata_dir.AppendASCII("Apple Computer")
-                                        .AppendASCII("iTunes")
-                                        .AppendASCII("iTunesPrefs.xml");
-  if (!file_util::PathExists(pref_file))
-    return base::FilePath();
-
-  base::FilePath::StringType library_location =
-      FindLibraryLocationInPrefXML(pref_file.AsUTF8Unsafe());
-  base::FilePath library_file(library_location);
-  if (!file_util::PathExists(library_file))
-    return base::FilePath();
-  return library_file;
-}
-
-// Check the default location for the iTunes library XML file. Return the
-// location if found.
-base::FilePath TryDefaultLocation() {
-  base::FilePath music_dir;
-  if (!PathService::Get(chrome::DIR_USER_MUSIC, &music_dir))
-    return base::FilePath();
-  base::FilePath library_file =
-      music_dir.AppendASCII("iTunes").AppendASCII("iTunes Music Library.xml");
-
-  if (!file_util::PathExists(library_file))
-    return base::FilePath();
-  return library_file;
+  if (PathService::Get(base::DIR_APP_DATA, &appdata_dir)) {
+    base::FilePath pref_file = appdata_dir.AppendASCII("Apple Computer")
+                                          .AppendASCII("iTunes")
+                                          .AppendASCII("iTunesPrefs.xml");
+    file_util::ReadFileToString(pref_file, &xml_pref_data);
+  }
+  return xml_pref_data;
 }
 
 }  // namespace
@@ -120,16 +43,48 @@
 ITunesFinderWin::~ITunesFinderWin() {}
 
 void ITunesFinderWin::FindITunesLibraryOnFileThread() {
-  base::FilePath library_file = TryPreferencesFile();
+  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
 
-  if (library_file.empty())
-    library_file = TryDefaultLocation();
-
-  if (library_file.empty()) {
-    PostResultToUIThread(std::string());
+  std::string xml_pref_data = GetPrefFileData();
+  if (xml_pref_data.empty()) {
+    TryDefaultLocation();
     return;
   }
 
+  scoped_refptr<SafeITunesPrefParserWin> parser =
+      new SafeITunesPrefParserWin(
+          xml_pref_data,
+          base::Bind(&ITunesFinderWin::FinishedParsingPrefXML,
+                     base::Unretained(this)));
+  parser->Start();
+}
+
+void ITunesFinderWin::TryDefaultLocation() {
+  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
+
+  base::FilePath music_dir;
+  if (!PathService::Get(chrome::DIR_USER_MUSIC, &music_dir)) {
+    PostResultToUIThread(std::string());
+    return;
+  }
+  base::FilePath library_file =
+      music_dir.AppendASCII("iTunes").AppendASCII("iTunes Music Library.xml");
+
+  if (!file_util::PathExists(library_file)) {
+    PostResultToUIThread(std::string());
+    return;
+  }
+  PostResultToUIThread(library_file.AsUTF8Unsafe());
+}
+
+void ITunesFinderWin::FinishedParsingPrefXML(
+    const base::FilePath& library_file) {
+  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
+
+  if (library_file.empty() || !file_util::PathExists(library_file)) {
+    TryDefaultLocation();
+    return;
+  }
   PostResultToUIThread(library_file.AsUTF8Unsafe());
 }
 
diff --git a/chrome/browser/media_galleries/fileapi/itunes_finder_win.h b/chrome/browser/media_galleries/fileapi/itunes_finder_win.h
index 5dd957a..53307d0 100644
--- a/chrome/browser/media_galleries/fileapi/itunes_finder_win.h
+++ b/chrome/browser/media_galleries/fileapi/itunes_finder_win.h
@@ -7,8 +7,15 @@
 
 #include "chrome/browser/media_galleries/fileapi/itunes_finder.h"
 
+namespace base {
+class FilePath;
+}
+
 namespace itunes {
 
+// This Windows-specific ITunesFinder uses a utility process to parse the
+// iTunes preferences XML file if it exists. If not or if the parsing fails,
+// ITunesFinderWin will try a default location as well.
 class ITunesFinderWin : public ITunesFinder {
  public:
   explicit ITunesFinderWin(const ITunesFinderCallback& callback);
@@ -17,6 +24,14 @@
  private:
   virtual void FindITunesLibraryOnFileThread() OVERRIDE;
 
+  // Check the default location for the iTunes library XML file.
+  // Runs on the FILE thread.
+  void TryDefaultLocation();
+
+  // Called by SafeITunesPrefParser when it finishes parsing the preferences
+  // XML file. Runs on the FILE thread.
+  void FinishedParsingPrefXML(const base::FilePath& library_file);
+
   DISALLOW_COPY_AND_ASSIGN(ITunesFinderWin);
 };
 
diff --git a/chrome/browser/media_galleries/fileapi/itunes_finder_win_browsertest.cc b/chrome/browser/media_galleries/fileapi/itunes_finder_win_browsertest.cc
new file mode 100644
index 0000000..6182ede
--- /dev/null
+++ b/chrome/browser/media_galleries/fileapi/itunes_finder_win_browsertest.cc
@@ -0,0 +1,195 @@
+// 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/base64.h"
+#include "base/base_paths_win.h"
+#include "base/bind.h"
+#include "base/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop.h"
+#include "base/path_service.h"
+#include "base/run_loop.h"
+#include "base/strings/stringprintf.h"
+#include "base/test/scoped_path_override.h"
+#include "chrome/browser/media_galleries/fileapi/itunes_finder_win.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/test/base/in_process_browser_test.h"
+
+namespace itunes {
+
+namespace {
+
+std::string EncodePath(const base::FilePath& path) {
+  std::string input(reinterpret_cast<const char*>(path.value().data()),
+                                                  path.value().size()*2);
+  std::string result;
+  base::Base64Encode(input, &result);
+  return result;
+}
+
+void TouchFile(const base::FilePath& file) {
+  ASSERT_EQ(1, file_util::WriteFile(file, " ", 1));
+}
+
+class ITunesFinderWinTest : public InProcessBrowserTest {
+ public:
+  ITunesFinderWinTest() : test_finder_callback_called_(false) {}
+
+  virtual void SetUp() OVERRIDE {
+    ASSERT_TRUE(app_data_dir_.CreateUniqueTempDir());
+    ASSERT_TRUE(music_dir_.CreateUniqueTempDir());
+    app_data_dir_override_.reset(
+        new base::ScopedPathOverride(base::DIR_APP_DATA, app_data_dir()));
+    music_dir_override_.reset(
+        new base::ScopedPathOverride(chrome::DIR_USER_MUSIC, music_dir()));
+    InProcessBrowserTest::SetUp();
+  }
+
+  const base::FilePath& app_data_dir() {
+    return app_data_dir_.path();
+  }
+
+  const base::FilePath& music_dir() {
+    return music_dir_.path();
+  }
+
+  void WritePrefFile(const std::string& data) {
+    base::FilePath pref_dir =
+        app_data_dir().AppendASCII("Apple Computer").AppendASCII("iTunes");
+    ASSERT_TRUE(file_util::CreateDirectory(pref_dir));
+    ASSERT_EQ(data.size(),
+              file_util::WriteFile(pref_dir.AppendASCII("iTunesPrefs.xml"),
+                                   data.data(), data.size()));
+  }
+
+  void TouchDefault() {
+    base::FilePath default_dir = music_dir().AppendASCII("iTunes");
+    ASSERT_TRUE(file_util::CreateDirectory(default_dir));
+    TouchFile(default_dir.AppendASCII("iTunes Music Library.xml"));
+  }
+
+  void TestFindITunesLibrary() {
+    test_finder_callback_called_ = false;
+    result_.clear();
+    base::RunLoop loop;
+    ITunesFinder::FindITunesLibrary(
+        base::Bind(&ITunesFinderWinTest::TestFinderCallback,
+                   base::Unretained(this),
+                   loop.QuitClosure()));
+    loop.Run();
+  }
+
+  bool EmptyResult() const {
+    return result_.empty();
+  }
+
+  bool test_finder_callback_called() const {
+    return test_finder_callback_called_;
+  }
+
+ private:
+  void TestFinderCallback(const base::Closure& quit_closure,
+                          const std::string& result) {
+    test_finder_callback_called_ = true;
+    result_ = result;
+    quit_closure.Run();
+  }
+
+  scoped_ptr<base::ScopedPathOverride> app_data_dir_override_;
+  scoped_ptr<base::ScopedPathOverride> music_dir_override_;
+  base::ScopedTempDir app_data_dir_;
+  base::ScopedTempDir music_dir_;
+
+  bool test_finder_callback_called_;
+  std::string result_;
+
+  DISALLOW_COPY_AND_ASSIGN(ITunesFinderWinTest);
+};
+
+IN_PROC_BROWSER_TEST_F(ITunesFinderWinTest, NotFound) {
+  TestFindITunesLibrary();
+  EXPECT_TRUE(test_finder_callback_called());
+  EXPECT_TRUE(EmptyResult());
+}
+
+IN_PROC_BROWSER_TEST_F(ITunesFinderWinTest, DefaultLocation) {
+  TouchDefault();
+  TestFindITunesLibrary();
+  EXPECT_TRUE(test_finder_callback_called());
+  EXPECT_FALSE(EmptyResult());
+}
+
+IN_PROC_BROWSER_TEST_F(ITunesFinderWinTest, CustomLocation) {
+  base::FilePath library_xml = music_dir().AppendASCII("library.xml");
+  TouchFile(library_xml);
+  std::string xml = base::StringPrintf(
+      "<plist>"
+      "  <dict>"
+      "    <key>User Preferences</key>"
+      "    <dict>"
+      "      <key>iTunes Library XML Location:1</key>"
+      "      <data>%s</data>"
+      "    </dict>"
+      "  </dict>"
+      "</plist>", EncodePath(library_xml).c_str());
+  WritePrefFile(xml);
+  TestFindITunesLibrary();
+  EXPECT_TRUE(test_finder_callback_called());
+  EXPECT_FALSE(EmptyResult());
+}
+
+IN_PROC_BROWSER_TEST_F(ITunesFinderWinTest, BadCustomLocation) {
+  // Missing file.
+  base::FilePath library_xml = music_dir().AppendASCII("library.xml");
+  std::string xml = base::StringPrintf(
+      "<plist>"
+      "  <dict>"
+      "    <key>User Preferences</key>"
+      "    <dict>"
+      "      <key>iTunes Library XML Location:1</key>"
+      "      <data>%s</data>"
+      "    </dict>"
+      "  </dict>"
+      "</plist>", EncodePath(library_xml).c_str());
+  WritePrefFile(xml);
+  TestFindITunesLibrary();
+  EXPECT_TRUE(test_finder_callback_called());
+  EXPECT_TRUE(EmptyResult());
+  TouchFile(library_xml);
+
+  // User Preferences dictionary at the wrong level.
+  xml = base::StringPrintf(
+      "<plist>"
+      "    <key>User Preferences</key>"
+      "    <dict>"
+      "      <key>iTunes Library XML Location:1</key>"
+      "      <data>%s</data>"
+      "    </dict>"
+      "</plist>", EncodePath(library_xml).c_str());
+  WritePrefFile(xml);
+  TestFindITunesLibrary();
+  EXPECT_TRUE(test_finder_callback_called());
+  EXPECT_TRUE(EmptyResult());
+
+  // Library location at the wrong scope.
+  xml = base::StringPrintf(
+      "<plist>"
+      "  <dict>"
+      "    <key>User Preferences</key>"
+      "    <dict/>"
+      "    <key>iTunes Library XML Location:1</key>"
+      "    <data>%s</data>"
+      "  </dict>"
+      "</plist>", EncodePath(library_xml).c_str());
+  WritePrefFile(xml);
+  TestFindITunesLibrary();
+  EXPECT_TRUE(test_finder_callback_called());
+  EXPECT_TRUE(EmptyResult());
+}
+
+}  // namespace
+
+}  // namespace itunes
diff --git a/chrome/browser/media_galleries/fileapi/itunes_finder_win_unittest.cc b/chrome/browser/media_galleries/fileapi/itunes_finder_win_unittest.cc
deleted file mode 100644
index 7f9571a..0000000
--- a/chrome/browser/media_galleries/fileapi/itunes_finder_win_unittest.cc
+++ /dev/null
@@ -1,181 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/base64.h"
-#include "base/base_paths_win.h"
-#include "base/bind.h"
-#include "base/file_util.h"
-#include "base/files/scoped_temp_dir.h"
-#include "base/logging.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/message_loop.h"
-#include "base/path_service.h"
-#include "base/run_loop.h"
-#include "base/strings/stringprintf.h"
-#include "base/test/scoped_path_override.h"
-#include "chrome/browser/media_galleries/fileapi/itunes_finder.h"
-#include "chrome/browser/media_galleries/fileapi/itunes_finder_win.h"
-#include "chrome/common/chrome_paths.h"
-#include "content/public/test/test_browser_thread.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace itunes {
-
-namespace {
-
-std::string EncodePath(const base::FilePath& path) {
-  std::string input(reinterpret_cast<const char*>(path.value().data()),
-                                                  path.value().size()*2);
-  std::string result;
-  base::Base64Encode(input, &result);
-  return result;
-}
-
-void TouchFile(const base::FilePath& file) {
-  ASSERT_EQ(1, file_util::WriteFile(file, " ", 1));
-}
-
-class ITunesFinderWinTest : public testing::Test {
- public:
-  ITunesFinderWinTest()
-    : ui_thread_(content::BrowserThread::UI, &loop_),
-      file_thread_(content::BrowserThread::FILE, &loop_) {
-  }
-
-  virtual void SetUp() OVERRIDE {
-    ASSERT_TRUE(app_data_dir_.CreateUniqueTempDir());
-    ASSERT_TRUE(music_dir_.CreateUniqueTempDir());
-    app_data_dir_override_.reset(
-        new base::ScopedPathOverride(base::DIR_APP_DATA, app_data_dir()));
-    music_dir_override_.reset(
-        new base::ScopedPathOverride(chrome::DIR_USER_MUSIC, music_dir()));
-  }
-
-  const base::FilePath& app_data_dir() {
-    return app_data_dir_.path();
-  }
-
-  const base::FilePath& music_dir() {
-    return music_dir_.path();
-  }
-
-  void WritePrefFile(const std::string& data) {
-    base::FilePath pref_dir =
-        app_data_dir().AppendASCII("Apple Computer").AppendASCII("iTunes");
-    ASSERT_TRUE(file_util::CreateDirectory(pref_dir));
-    ASSERT_EQ(data.size(),
-              file_util::WriteFile(pref_dir.AppendASCII("iTunesPrefs.xml"),
-                                   data.data(), data.size()));
-  }
-
-  void TouchDefault() {
-    base::FilePath default_dir = music_dir().AppendASCII("iTunes");
-    ASSERT_TRUE(file_util::CreateDirectory(default_dir));
-    TouchFile(default_dir.AppendASCII("iTunes Music Library.xml"));
-  }
-
-  std::string TestFindITunesLibrary() {
-    std::string result;
-    ITunesFinder::FindITunesLibrary(
-        base::Bind(&ITunesFinderWinTest::FinderCallback,
-                   base::Unretained(this), base::Unretained(&result)));
-    base::RunLoop().RunUntilIdle();
-    return result;
-  }
-
- private:
-  void FinderCallback(std::string* result_holder, const std::string& result) {
-    *result_holder = result;
-  }
-
-  scoped_ptr<base::ScopedPathOverride> app_data_dir_override_;
-  scoped_ptr<base::ScopedPathOverride> music_dir_override_;
-  base::ScopedTempDir app_data_dir_;
-  base::ScopedTempDir music_dir_;
-
-  base::MessageLoop loop_;
-  content::TestBrowserThread ui_thread_;
-  content::TestBrowserThread file_thread_;
-
-  DISALLOW_COPY_AND_ASSIGN(ITunesFinderWinTest);
-};
-
-TEST_F(ITunesFinderWinTest, NotFound) {
-  std::string result = TestFindITunesLibrary();
-  EXPECT_TRUE(result.empty());
-}
-
-TEST_F(ITunesFinderWinTest, DefaultLocation) {
-  TouchDefault();
-  std::string result = TestFindITunesLibrary();
-  EXPECT_FALSE(result.empty());
-}
-
-TEST_F(ITunesFinderWinTest, CustomLocation) {
-  base::FilePath library_xml = music_dir().AppendASCII("library.xml");
-  TouchFile(library_xml);
-  std::string xml = base::StringPrintf(
-      "<plist>"
-      "  <dict>"
-      "    <key>User Preferences</key>"
-      "    <dict>"
-      "      <key>iTunes Library XML Location:1</key>"
-      "      <data>%s</data>"
-      "    </dict>"
-      "  </dict>"
-      "</plist>", EncodePath(library_xml).c_str());
-  WritePrefFile(xml);
-  std::string result = TestFindITunesLibrary();
-  EXPECT_FALSE(result.empty());
-}
-
-TEST_F(ITunesFinderWinTest, BadCustomLocation) {
-  // Missing file.
-  base::FilePath library_xml = music_dir().AppendASCII("library.xml");
-  std::string xml = base::StringPrintf(
-      "<plist>"
-      "  <dict>"
-      "    <key>User Preferences</key>"
-      "    <dict>"
-      "      <key>iTunes Library XML Location:1</key>"
-      "      <data>%s</data>"
-      "    </dict>"
-      "  </dict>"
-      "</plist>", EncodePath(library_xml).c_str());
-  WritePrefFile(xml);
-  std::string result = TestFindITunesLibrary();
-  EXPECT_TRUE(result.empty());
-  TouchFile(library_xml);
-
-  // User Preferences dictionary at the wrong level.
-  xml = base::StringPrintf(
-      "<plist>"
-      "    <key>User Preferences</key>"
-      "    <dict>"
-      "      <key>iTunes Library XML Location:1</key>"
-      "      <data>%s</data>"
-      "    </dict>"
-      "</plist>", EncodePath(library_xml).c_str());
-  WritePrefFile(xml);
-  result = TestFindITunesLibrary();
-  EXPECT_TRUE(result.empty());
-
-  // Library location at the wrong scope.
-  xml = base::StringPrintf(
-      "<plist>"
-      "  <dict>"
-      "    <key>User Preferences</key>"
-      "    <dict/>"
-      "    <key>iTunes Library XML Location:1</key>"
-      "    <data>%s</data>"
-      "  </dict>"
-      "</plist>", EncodePath(library_xml).c_str());
-  WritePrefFile(xml);
-  result = TestFindITunesLibrary();
-  EXPECT_TRUE(result.empty());
-}
-
-}  // namespace
-
-}  // namespace itunes
diff --git a/chrome/browser/media_galleries/fileapi/itunes_library_parser.cc b/chrome/browser/media_galleries/fileapi/itunes_library_parser.cc
deleted file mode 100644
index 95f3d71..0000000
--- a/chrome/browser/media_galleries/fileapi/itunes_library_parser.cc
+++ /dev/null
@@ -1,208 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/media_galleries/fileapi/itunes_library_parser.h"
-
-#include <string>
-
-#include "base/logging.h"
-#include "base/strings/string16.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/media_galleries/fileapi/itunes_xml_utils.h"
-#include "googleurl/src/gurl.h"
-#include "googleurl/src/url_canon.h"
-#include "googleurl/src/url_util.h"
-#include "third_party/libxml/chromium/libxml_utils.h"
-
-namespace itunes {
-
-namespace {
-
-struct TrackInfo {
-  uint64 id;
-  base::FilePath location;
-  std::string artist;
-  std::string album;
-};
-
-// Seek to the start of a tag and read the value into |result| if the node's
-// name is |node_name|.
-bool ReadSimpleValue(XmlReader* reader, const std::string& node_name,
-                     std::string* result) {
-  if (!SkipToNextElement(reader))
-      return false;
-  if (reader->NodeName() != node_name)
-    return false;
-  return reader->ReadElementContent(result);
-}
-
-// Get the value out of a string node.
-bool ReadString(XmlReader* reader, std::string* result) {
-  return ReadSimpleValue(reader, "string", result);
-}
-
-// Get the value out of an integer node.
-bool ReadInteger(XmlReader* reader, uint64* result) {
-  std::string value;
-  if (!ReadSimpleValue(reader, "integer", &value))
-    return false;
-  return base::StringToUint64(value, result);
-}
-
-// Walk through a dictionary filling in |result| with track information. Return
-// true if it was all found, false otherwise.  In either case, the cursor is
-// advanced out of the dictionary.
-bool GetTrackInfoFromDict(XmlReader* reader, TrackInfo* result) {
-  DCHECK(result);
-  if (reader->NodeName() != "dict")
-    return false;
-
-  int dict_content_depth = reader->Depth() + 1;
-  // Advance past the dict node and into the body of the dictionary.
-  if (!reader->Read())
-    return false;
-
-  bool found_id = false;
-  bool found_location = false;
-  bool found_artist = false;
-  bool found_album = false;
-  while (reader->Depth() >= dict_content_depth &&
-         !(found_id && found_location && found_artist && found_album)) {
-    if (!SeekToNodeAtCurrentDepth(reader, "key"))
-      break;
-    std::string found_key;
-    if (!reader->ReadElementContent(&found_key))
-      break;
-    DCHECK_EQ(dict_content_depth, reader->Depth());
-
-    if (found_key == "Track ID") {
-      if (found_id)
-        break;
-      if (!ReadInteger(reader, &result->id))
-        break;
-      found_id = true;
-    } else if (found_key == "Location") {
-      if (found_location)
-        break;
-      std::string value;
-      if (!ReadString(reader, &value))
-        break;
-      GURL url(value);
-      if (!url.SchemeIsFile())
-        break;
-      url_canon::RawCanonOutputW<1024> decoded_location;
-      url_util::DecodeURLEscapeSequences(url.path().c_str() + 1,  // Strip /.
-                                         url.path().length() - 1,
-                                         &decoded_location);
-#if defined(OS_WIN)
-      string16 location(decoded_location.data(), decoded_location.length());
-#else
-      string16 location16(decoded_location.data(), decoded_location.length());
-      std::string location = UTF16ToUTF8(location16);
-#endif
-      result->location = base::FilePath(location);
-      found_location = true;
-    } else if (found_key == "Album Artist") {
-      if (found_artist)
-        break;
-      if (!ReadString(reader, &result->artist))
-        break;
-      found_artist = true;
-    } else if (found_key == "Album") {
-      if (found_album)
-        break;
-      if (!ReadString(reader, &result->album))
-        break;
-      found_album = true;
-    } else {
-      if (!SkipToNextElement(reader))
-        break;
-      if (!reader->Next())
-        break;
-    }
-  }
-
-  // Seek to the end of the dictionary
-  while (reader->Depth() >= dict_content_depth)
-    reader->Next();
-
-  return found_id && found_location && found_artist && found_album;
-}
-
-}  // namespace
-
-ITunesLibraryParser::Track::Track(uint64 id, const base::FilePath& location)
-    : id(id),
-      location(location) {
-}
-
-bool ITunesLibraryParser::Track::operator<(const Track& other) const {
-  return id < other.id;
-}
-
-ITunesLibraryParser::ITunesLibraryParser() {}
-ITunesLibraryParser::~ITunesLibraryParser() {}
-
-bool ITunesLibraryParser::Parse(const std::string& library_xml) {
-  XmlReader reader;
-
-  if (!reader.Load(library_xml))
-    return false;
-
-  // Find the plist node and then search within that tag.
-  if (!SeekToNodeAtCurrentDepth(&reader, "plist"))
-    return false;
-  if (!reader.Read())
-    return false;
-
-  if (!SeekToNodeAtCurrentDepth(&reader, "dict"))
-    return false;
-
-  if (!SeekInDict(&reader, "Tracks"))
-    return false;
-
-  // Once inside the Tracks dict, we expect track dictionaries keyed by id. i.e.
-  //   <key>Tracks</key>
-  //   <dict>
-  //     <key>160</key>
-  //     <dict>
-  //       <key>Track ID</key><integer>160</integer>
-  if (!SeekToNodeAtCurrentDepth(&reader, "dict"))
-    return false;
-  int tracks_dict_depth = reader.Depth() + 1;
-  if (!reader.Read())
-    return false;
-
-  // Once parsing has gotten this far, return whatever is found, even if
-  // some of the data isn't extracted just right.
-  bool no_errors = true;
-  bool track_found = false;
-  while (reader.Depth() >= tracks_dict_depth) {
-    if (!SeekToNodeAtCurrentDepth(&reader, "key"))
-      return track_found;
-    std::string key;  // Should match track id below.
-    if (!reader.ReadElementContent(&key))
-      return track_found;
-    uint64 id;
-    bool id_valid = base::StringToUint64(key, &id);
-    if (!reader.SkipToElement())
-      return track_found;
-
-    TrackInfo track_info;
-    if (GetTrackInfoFromDict(&reader, &track_info) &&
-        id_valid &&
-        id == track_info.id) {
-      Track track(track_info.id, track_info.location);
-      library_[track_info.artist][track_info.album].insert(track);
-      track_found = true;
-    } else {
-      no_errors = false;
-    }
-  }
-
-  return track_found || no_errors;
-}
-
-}  // namespace itunes
diff --git a/chrome/browser/media_galleries/fileapi/itunes_library_parser.h b/chrome/browser/media_galleries/fileapi/itunes_library_parser.h
deleted file mode 100644
index 6f6ad82..0000000
--- a/chrome/browser/media_galleries/fileapi/itunes_library_parser.h
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_ITUNES_LIBRARY_PARSER_H_
-#define CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_ITUNES_LIBRARY_PARSER_H_
-
-#include <map>
-#include <set>
-
-#include "base/files/file_path.h"
-
-namespace itunes {
-
-class ITunesLibraryParser {
- public:
-  struct Track {
-    Track(uint64 id, const base::FilePath& location);
-    bool operator<(const Track& other) const;
-
-    uint64 id;
-    base::FilePath location;
-  };
-
-  typedef std::set<Track> Album;
-  typedef std::map<std::string /*album name*/, Album> Albums;
-  typedef std::map<std::string /*artist name*/, Albums> Library;
-
-  ITunesLibraryParser();
-  ~ITunesLibraryParser();
-
-  // Returns true if at least one track was found. Malformed track entries
-  // are silently ignored.
-  bool Parse(const std::string& xml);
-
-  const Library& library() { return library_; }
-
- private:
-  Library library_;
-
-  DISALLOW_COPY_AND_ASSIGN(ITunesLibraryParser);
-};
-
-}  // namespace itunes
-
-#endif  // CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_ITUNES_LIBRARY_PARSER_H_
diff --git a/chrome/browser/media_galleries/fileapi/itunes_library_parser_unittest.cc b/chrome/browser/media_galleries/fileapi/itunes_library_parser_unittest.cc
deleted file mode 100644
index 7f2117f..0000000
--- a/chrome/browser/media_galleries/fileapi/itunes_library_parser_unittest.cc
+++ /dev/null
@@ -1,197 +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/logging.h"
-#include "chrome/browser/media_galleries/fileapi/itunes_library_parser.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-#define SIMPLE_HEADER()         \
-    "<plist>"                   \
-    "  <dict>"                  \
-    "    <key>Tracks</key>"     \
-    "    <dict>"
-
-#define SIMPLE_TRACK(key, id, path, artist, album)                     \
-    "<key>" #key "</key>"                                              \
-    "<dict>"                                                           \
-    "  <key>Track ID</key><integer>" #id "</integer>"                  \
-    "  <key>Location</key><string>file://localhost/" path "</string>"  \
-    "  <key>Album Artist</key><string>" artist "</string>"             \
-    "  <key>Album</key><string>" album "</string>"                     \
-    "</dict>"
-
-#define SIMPLE_FOOTER()  \
-    "    </dict>"        \
-    "  </dict>"          \
-    "</plist>"
-
-namespace itunes {
-
-namespace {
-
-void CompareTrack(const ITunesLibraryParser::Track& a,
-                  const ITunesLibraryParser::Track& b) {
-  EXPECT_EQ(a.id, b.id);
-  EXPECT_EQ(a.location, b.location);
-}
-
-void CompareAlbum(const ITunesLibraryParser::Album& a,
-                  const ITunesLibraryParser::Album& b) {
-  EXPECT_EQ(a.size(), b.size());
-
-  ITunesLibraryParser::Album::const_iterator a_it;
-  ITunesLibraryParser::Album::const_iterator b_it;
-  for (a_it = a.begin(), b_it = b.begin();
-       a_it != a.end() && b_it != b.end();
-       ++a_it, ++b_it) {
-    CompareTrack(*a_it, *b_it);
-  }
-}
-
-void CompareAlbums(const ITunesLibraryParser::Albums& a,
-                   const ITunesLibraryParser::Albums& b) {
-  EXPECT_EQ(a.size(), b.size());
-
-  ITunesLibraryParser::Albums::const_iterator a_it;
-  ITunesLibraryParser::Albums::const_iterator b_it;
-  for (a_it = a.begin(), b_it = b.begin();
-       a_it != a.end() && b_it != b.end();
-       ++a_it, ++b_it) {
-    EXPECT_EQ(a_it->first, b_it->first);
-    CompareAlbum(a_it->second, b_it->second);
-  }
-}
-
-void CompareLibrary(const ITunesLibraryParser::Library& a,
-                    const ITunesLibraryParser::Library& b) {
-  EXPECT_EQ(a.size(), b.size());
-
-  ITunesLibraryParser::Library::const_iterator a_it;
-  ITunesLibraryParser::Library::const_iterator b_it;
-  for (a_it = a.begin(), b_it = b.begin();
-       a_it != a.end() && b_it != b.end();
-       ++a_it, ++b_it) {
-    EXPECT_EQ(a_it->first, b_it->first);
-    CompareAlbums(a_it->second, b_it->second);
-  }
-}
-
-class ITunesLibraryParserTest : public testing::Test {
- public:
-  ITunesLibraryParserTest() {}
-
-  void TestParser(bool expected_result, const std::string& xml) {
-    ITunesLibraryParser parser;
-
-    EXPECT_EQ(expected_result, parser.Parse(xml));
-    if (!expected_result)
-      return;
-
-    CompareLibrary(expected_library_, parser.library());
-  }
-
-  void AddExpectedTrack(uint32 id, const std::string& location,
-                        const std::string& artist, const std::string& album) {
-    ITunesLibraryParser::Track track(id,
-                                     base::FilePath::FromUTF8Unsafe(location));
-    expected_library_[artist][album].insert(track);
-  }
-
- private:
-  ITunesLibraryParser::Library expected_library_;
-
-  DISALLOW_COPY_AND_ASSIGN(ITunesLibraryParserTest);
-};
-
-TEST_F(ITunesLibraryParserTest, EmptyLibrary) {
-  TestParser(false, "");
-}
-
-TEST_F(ITunesLibraryParserTest, MinimalXML) {
-  AddExpectedTrack(1, "C:/dir/Song With Space.mp3", "Artist A", "Album A");
-  TestParser(
-      true,
-      SIMPLE_HEADER()
-      SIMPLE_TRACK(1, 1, "C:/dir/Song%20With%20Space.mp3", "Artist A",
-                   "Album A")
-      SIMPLE_FOOTER());
-}
-
-TEST_F(ITunesLibraryParserTest, MultipleSongs) {
-  AddExpectedTrack(1, "C:/dir/SongA1.mp3", "Artist A", "Album A");
-  AddExpectedTrack(2, "C:/dir/SongA2.mp3", "Artist A", "Album A");
-  AddExpectedTrack(3, "C:/dir/SongA3.mp3", "Artist A", "Album A");
-  AddExpectedTrack(4, "C:/dir/SongB1.mp3", "Artist A", "Album B");
-  AddExpectedTrack(5, "C:/dir/SongB2.mp3", "Artist A", "Album B");
-  AddExpectedTrack(6, "C:/dir2/SongB1.mp3", "Artist B", "Album B");
-  AddExpectedTrack(7, "C:/dir2/SongB2.mp3", "Artist B", "Album B");
-  TestParser(
-      true,
-      SIMPLE_HEADER()
-      SIMPLE_TRACK(1, 1, "C:/dir/SongA1.mp3", "Artist A", "Album A")
-      SIMPLE_TRACK(2, 2, "C:/dir/SongA2.mp3", "Artist A", "Album A")
-      SIMPLE_TRACK(3, 3, "C:/dir/SongA3.mp3", "Artist A", "Album A")
-      SIMPLE_TRACK(4, 4, "C:/dir/SongB1.mp3", "Artist A", "Album B")
-      SIMPLE_TRACK(5, 5, "C:/dir/SongB2.mp3", "Artist A", "Album B")
-      SIMPLE_TRACK(6, 6, "C:/dir2/SongB1.mp3", "Artist B", "Album B")
-      SIMPLE_TRACK(7, 7, "C:/dir2/SongB2.mp3", "Artist B", "Album B")
-      SIMPLE_FOOTER());
-}
-
-TEST_F(ITunesLibraryParserTest, MismatchedId) {
-  TestParser(
-      false,
-      SIMPLE_HEADER()
-      SIMPLE_TRACK(1, 2, "C:/dir/SongA1.mp3", "Artist A", "Album A")
-      SIMPLE_FOOTER());
-
-  AddExpectedTrack(1, "C:/dir/SongA1.mp3", "Artist A", "Album A");
-  TestParser(
-      true,
-      SIMPLE_HEADER()
-      SIMPLE_TRACK(1, 1, "C:/dir/SongA1.mp3", "Artist A", "Album A")
-      SIMPLE_TRACK(2, 3, "C:/dir/SongA2.mp3", "Artist A", "Album A")
-      SIMPLE_FOOTER());
-}
-
-TEST_F(ITunesLibraryParserTest, OtherDictionaryEntries) {
-  AddExpectedTrack(1, "C:/dir/SongA1.mp3", "Artist A", "Album A");
-  TestParser(
-      true,
-      "<plist>"
-      "  <dict>"
-      "    <key>Other section</key>"
-      "    <dict>"
-      // In Other section, not Tracks.
-      SIMPLE_TRACK(10, 10, "C:/dir/SongB2.mp3", "Artist B", "Album B")
-      "    </dict>"
-      "    <key>Tracks</key>"
-      "    <dict>"
-      "      <key>1</key>"
-      "      <dict>"
-      // In the body of a track dictionary before the interesting entries.
-      SIMPLE_TRACK(20, 20, "C:/dir/SongB2.mp3", "Artist B", "Album B")
-      // Entries in a different order.
-      "        <key>Album Artist</key><string>Artist A</string>"
-      "        <key>Location</key>"
-      "          <string>file://localhost/C:/dir/SongA1.mp3</string>"
-      "        <key>Album</key><string>Album A</string>"
-      "        <key>Track ID</key><integer>1</integer>"
-      // In the body of a track dictionary after the interesting entries.
-      SIMPLE_TRACK(30, 30, "C:/dir/SongB3.mp3", "Artist B", "Album B")
-      "      </dict>"
-      "      <key>40</key>"
-      "      <dict>"
-      // Missing album name.
-      "        <key>Album Artist</key><string>Artist B</string>"
-      "        <key>Location</key>"
-      "          <string>file://localhost/C:/dir/SongB4.mp3</string>"
-      "        <key>Track ID</key><integer>1</integer>"
-      "      </dict>"
-      SIMPLE_FOOTER());
-}
-
-}  // namespace
-
-}  // namespace itunes
diff --git a/chrome/browser/media_galleries/fileapi/itunes_xml_utils.cc b/chrome/browser/media_galleries/fileapi/itunes_xml_utils.cc
deleted file mode 100644
index d59346b..0000000
--- a/chrome/browser/media_galleries/fileapi/itunes_xml_utils.cc
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/media_galleries/fileapi/itunes_xml_utils.h"
-#include <string>
-
-#include "base/logging.h"
-#include "third_party/libxml/chromium/libxml_utils.h"
-
-namespace itunes {
-
-bool SkipToNextElement(XmlReader* reader) {
-  if (!reader->SkipToElement()) {
-    // SkipToElement returns false if the current node is an end element,
-    // try to advance to the next element and then try again.
-    if (!reader->Read() || !reader->SkipToElement())
-      return false;
-  }
-  return true;
-}
-
-bool SeekToNodeAtCurrentDepth(XmlReader* reader, const std::string& name) {
-  int depth = reader->Depth();
-  do {
-    if (!SkipToNextElement(reader))
-      return false;
-    DCHECK_EQ(depth, reader->Depth());
-    if (reader->NodeName() == name)
-      return true;
-  } while (reader->Next());
-
-  return false;
-}
-
-bool SeekInDict(XmlReader* reader, const std::string& key) {
-  DCHECK_EQ("dict", reader->NodeName());
-
-  int dict_content_depth = reader->Depth() + 1;
-  // Advance past the dict node and into the body of the dictionary.
-  if (!reader->Read())
-    return false;
-
-  while (reader->Depth() >= dict_content_depth) {
-    if (!SeekToNodeAtCurrentDepth(reader, "key"))
-      return false;
-    std::string found_key;
-    if (!reader->ReadElementContent(&found_key))
-      return false;
-    DCHECK_EQ(dict_content_depth, reader->Depth());
-    if (found_key == key)
-      return true;
-  }
-  return false;
-}
-
-}  // namespace itunes
diff --git a/chrome/browser/media_galleries/fileapi/itunes_xml_utils.h b/chrome/browser/media_galleries/fileapi/itunes_xml_utils.h
deleted file mode 100644
index aad4865..0000000
--- a/chrome/browser/media_galleries/fileapi/itunes_xml_utils.h
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_ITUNES_XML_UTILS_H_
-#define CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_ITUNES_XML_UTILS_H_
-
-#include <string>
-
-class XmlReader;
-
-namespace itunes {
-
-// Like XmlReader::SkipToElement, but will advance to the next open tag if the
-// cursor is on a close tag.
-bool SkipToNextElement(XmlReader* reader);
-
-// Traverse |reader| looking for a node named |name| at the current depth
-// of |reader|.
-bool SeekToNodeAtCurrentDepth(XmlReader* reader, const std::string& name);
-
-// Search within a "dict" node for |key|. The cursor must be on the starting
-// "dict" node when entering this function.
-bool SeekInDict(XmlReader* reader, const std::string& key);
-
-}  // namespace itunes
-
-#endif  // CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_ITUNES_XML_UTILS_H_
diff --git a/chrome/browser/media_galleries/fileapi/media_file_system_mount_point_provider.cc b/chrome/browser/media_galleries/fileapi/media_file_system_mount_point_provider.cc
index 52d5c0e..7d65431 100644
--- a/chrome/browser/media_galleries/fileapi/media_file_system_mount_point_provider.cc
+++ b/chrome/browser/media_galleries/fileapi/media_file_system_mount_point_provider.cc
@@ -14,11 +14,9 @@
 #include "base/sequenced_task_runner.h"
 #include "base/threading/sequenced_worker_pool.h"
 #include "chrome/browser/media_galleries/fileapi/device_media_async_file_util.h"
-#include "chrome/browser/media_galleries/fileapi/itunes_file_util.h"
 #include "chrome/browser/media_galleries/fileapi/media_file_validator_factory.h"
 #include "chrome/browser/media_galleries/fileapi/media_path_filter.h"
 #include "chrome/browser/media_galleries/fileapi/native_media_file_util.h"
-#include "chrome/browser/media_galleries/fileapi/picasa/picasa_file_util.h"
 #include "content/public/browser/browser_thread.h"
 #include "webkit/browser/blob/local_file_stream_reader.h"
 #include "webkit/browser/fileapi/async_file_util_adapter.h"
@@ -35,6 +33,11 @@
 #include "webkit/common/fileapi/file_system_types.h"
 #include "webkit/common/fileapi/file_system_util.h"
 
+#if defined(OS_WIN) || defined(OS_MACOSX)
+#include "chrome/browser/media_galleries/fileapi/itunes_file_util.h"
+#include "chrome/browser/media_galleries/fileapi/picasa/picasa_file_util.h"
+#endif  // defined(OS_WIN) || defined(OS_MACOSX)
+
 using fileapi::FileSystemContext;
 using fileapi::FileSystemURL;
 
@@ -56,9 +59,13 @@
       media_copy_or_move_file_validator_factory_(new MediaFileValidatorFactory),
       native_media_file_util_(new NativeMediaFileUtil()),
       device_media_async_file_util_(
-          DeviceMediaAsyncFileUtil::Create(profile_path_)),
+          DeviceMediaAsyncFileUtil::Create(profile_path_))
+#if defined(OS_WIN) || defined(OS_MACOSX)
+      ,
       picasa_file_util_(new picasa::PicasaFileUtil()),
-      itunes_file_util_(new itunes::ItunesFileUtil()) {
+      itunes_file_util_(new itunes::ItunesFileUtil())
+#endif  // defined(OS_WIN) || defined(OS_MACOSX)
+{
 }
 
 MediaFileSystemMountPointProvider::~MediaFileSystemMountPointProvider() {
@@ -72,13 +79,24 @@
   return pool->IsRunningSequenceOnCurrentThread(media_sequence_token);
 }
 
+// static
+scoped_refptr<base::SequencedTaskRunner>
+MediaFileSystemMountPointProvider::MediaTaskRunner() {
+  base::SequencedWorkerPool* pool = content::BrowserThread::GetBlockingPool();
+  base::SequencedWorkerPool::SequenceToken media_sequence_token =
+      pool->GetNamedSequenceToken(kMediaTaskRunnerName);
+  return pool->GetSequencedTaskRunner(media_sequence_token);
+}
+
 bool MediaFileSystemMountPointProvider::CanHandleType(
     fileapi::FileSystemType type) const {
   switch (type) {
     case fileapi::kFileSystemTypeNativeMedia:
     case fileapi::kFileSystemTypeDeviceMedia:
+#if defined(OS_WIN) || defined(OS_MACOSX)
     case fileapi::kFileSystemTypePicasa:
     case fileapi::kFileSystemTypeItunes:
+#endif  // defined(OS_WIN) || defined(OS_MACOSX)
       return true;
     default:
       return false;
@@ -107,12 +125,14 @@
   switch (type) {
     case fileapi::kFileSystemTypeNativeMedia:
       return native_media_file_util_.get();
-    case fileapi::kFileSystemTypePicasa:
-      return picasa_file_util_.get();
     case fileapi::kFileSystemTypeDeviceMedia:
       return device_media_async_file_util_.get();
+#if defined(OS_WIN) || defined(OS_MACOSX)
     case fileapi::kFileSystemTypeItunes:
       return itunes_file_util_.get();
+    case fileapi::kFileSystemTypePicasa:
+      return picasa_file_util_.get();
+#endif  // defined(OS_WIN) || defined(OS_MACOSX)
     default:
       NOTREACHED();
   }
@@ -139,14 +159,6 @@
   return NULL;
 }
 
-fileapi::FilePermissionPolicy
-MediaFileSystemMountPointProvider::GetPermissionPolicy(
-    const FileSystemURL& url, int permissions) const {
-  // Access to media file systems should be checked using per-filesystem
-  // access permission.
-  return fileapi::FILE_PERMISSION_USE_FILESYSTEM_PERMISSION;
-}
-
 fileapi::FileSystemOperation*
 MediaFileSystemMountPointProvider::CreateFileSystemOperation(
     const FileSystemURL& url,
@@ -185,7 +197,9 @@
     int64 offset,
     FileSystemContext* context) const {
   return scoped_ptr<fileapi::FileStreamWriter>(
-      new fileapi::LocalFileStreamWriter(url.path(), offset));
+      new fileapi::LocalFileStreamWriter(
+          context->task_runners()->file_task_runner(),
+          url.path(), offset));
 }
 
 fileapi::FileSystemQuotaUtil*
diff --git a/chrome/browser/media_galleries/fileapi/media_file_system_mount_point_provider.h b/chrome/browser/media_galleries/fileapi/media_file_system_mount_point_provider.h
index b1b07a7..dbe18cf 100644
--- a/chrome/browser/media_galleries/fileapi/media_file_system_mount_point_provider.h
+++ b/chrome/browser/media_galleries/fileapi/media_file_system_mount_point_provider.h
@@ -36,6 +36,7 @@
   virtual ~MediaFileSystemMountPointProvider();
 
   static bool CurrentlyOnMediaTaskRunnerThread();
+  static scoped_refptr<base::SequencedTaskRunner> MediaTaskRunner();
 
   // FileSystemMountPointProvider implementation.
   virtual bool CanHandleType(fileapi::FileSystemType type) const OVERRIDE;
@@ -52,8 +53,6 @@
   GetCopyOrMoveFileValidatorFactory(
       fileapi::FileSystemType type,
       base::PlatformFileError* error_code) OVERRIDE;
-  virtual fileapi::FilePermissionPolicy GetPermissionPolicy(
-      const fileapi::FileSystemURL& url, int permissions) const OVERRIDE;
   virtual fileapi::FileSystemOperation* CreateFileSystemOperation(
       const fileapi::FileSystemURL& url,
       fileapi::FileSystemContext* context,
@@ -86,8 +85,10 @@
 
   scoped_ptr<fileapi::AsyncFileUtil> native_media_file_util_;
   scoped_ptr<DeviceMediaAsyncFileUtil> device_media_async_file_util_;
+#if defined(OS_WIN) || defined(OS_MACOSX)
   scoped_ptr<fileapi::AsyncFileUtil> picasa_file_util_;
   scoped_ptr<fileapi::AsyncFileUtil> itunes_file_util_;
+#endif  // defined(OS_WIN) || defined(OS_MACOSX)
 
   DISALLOW_COPY_AND_ASSIGN(MediaFileSystemMountPointProvider);
 };
diff --git a/chrome/browser/media_galleries/fileapi/media_file_validator_unittest.cc b/chrome/browser/media_galleries/fileapi/media_file_validator_unittest.cc
index e23e5b7..79d030f 100644
--- a/chrome/browser/media_galleries/fileapi/media_file_validator_unittest.cc
+++ b/chrome/browser/media_galleries/fileapi/media_file_validator_unittest.cc
@@ -7,8 +7,8 @@
 #include "base/file_util.h"
 #include "base/files/file_path.h"
 #include "base/files/scoped_temp_dir.h"
-#include "base/message_loop.h"
-#include "base/message_loop_proxy.h"
+#include "base/message_loop/message_loop.h"
+#include "base/message_loop/message_loop_proxy.h"
 #include "chrome/browser/media_galleries/fileapi/media_file_system_mount_point_provider.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "content/public/test/browser_test.h"
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 6cbccee..29e33dc 100644
--- a/chrome/browser/media_galleries/fileapi/native_media_file_util.cc
+++ b/chrome/browser/media_galleries/fileapi/native_media_file_util.cc
@@ -4,7 +4,10 @@
 
 #include "chrome/browser/media_galleries/fileapi/native_media_file_util.h"
 
+#include <string>
+
 #include "base/bind.h"
+#include "base/bind_helpers.h"
 #include "base/file_util.h"
 #include "base/files/file_enumerator.h"
 #include "base/strings/string_util.h"
@@ -12,8 +15,8 @@
 #include "chrome/browser/media_galleries/fileapi/media_file_system_mount_point_provider.h"
 #include "chrome/browser/media_galleries/fileapi/media_path_filter.h"
 #include "content/public/browser/browser_thread.h"
-#include "googleurl/src/gurl.h"
 #include "net/base/mime_sniffer.h"
+#include "url/gurl.h"
 #include "webkit/browser/fileapi/file_system_context.h"
 #include "webkit/browser/fileapi/file_system_operation_context.h"
 #include "webkit/browser/fileapi/file_system_task_runners.h"
@@ -142,8 +145,7 @@
   base::PlatformFile invalid_file(base::kInvalidPlatformFileValue);
   if (!callback.is_null()) {
     callback.Run(base::PLATFORM_FILE_ERROR_SECURITY,
-                 base::PassPlatformFile(&invalid_file),
-                 false);
+                 base::PassPlatformFile(&invalid_file));
   }
   return true;
 }
@@ -165,11 +167,11 @@
     bool recursive,
     const StatusCallback& callback) {
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
-  fileapi::FileSystemOperationContext* context_ptr = context.release();
+  fileapi::FileSystemOperationContext* context_ptr = context.get();
   return context_ptr->task_runner()->PostTask(
       FROM_HERE,
       base::Bind(&NativeMediaFileUtil::CreateDirectoryOnTaskRunnerThread,
-                 weak_factory_.GetWeakPtr(), base::Owned(context_ptr),
+                 weak_factory_.GetWeakPtr(), base::Passed(&context),
                  url, exclusive, recursive, callback));
 }
 
@@ -178,11 +180,11 @@
     const fileapi::FileSystemURL& url,
     const GetFileInfoCallback& callback) {
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
-  fileapi::FileSystemOperationContext* context_ptr = context.release();
+  fileapi::FileSystemOperationContext* context_ptr = context.get();
   return context_ptr->task_runner()->PostTask(
       FROM_HERE,
       base::Bind(&NativeMediaFileUtil::GetFileInfoOnTaskRunnerThread,
-                 weak_factory_.GetWeakPtr(), base::Owned(context_ptr),
+                 weak_factory_.GetWeakPtr(), base::Passed(&context),
                  url, callback));
 }
 
@@ -191,11 +193,11 @@
     const fileapi::FileSystemURL& url,
     const ReadDirectoryCallback& callback) {
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
-  fileapi::FileSystemOperationContext* context_ptr = context.release();
+  fileapi::FileSystemOperationContext* context_ptr = context.get();
   return context_ptr->task_runner()->PostTask(
       FROM_HERE,
       base::Bind(&NativeMediaFileUtil::ReadDirectoryOnTaskRunnerThread,
-                 weak_factory_.GetWeakPtr(), base::Owned(context_ptr),
+                 weak_factory_.GetWeakPtr(), base::Passed(&context),
                  url, callback));
 }
 
@@ -228,11 +230,11 @@
     const fileapi::FileSystemURL& dest_url,
     const StatusCallback& callback) {
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
-  fileapi::FileSystemOperationContext* context_ptr = context.release();
+  fileapi::FileSystemOperationContext* context_ptr = context.get();
   return context_ptr->task_runner()->PostTask(
       FROM_HERE,
       base::Bind(&NativeMediaFileUtil::CopyOrMoveFileLocalOnTaskRunnerThread,
-                 weak_factory_.GetWeakPtr(), base::Owned(context_ptr),
+                 weak_factory_.GetWeakPtr(), base::Passed(&context),
                  src_url, dest_url, true /* copy */, callback));
 }
 
@@ -242,11 +244,11 @@
     const fileapi::FileSystemURL& dest_url,
     const StatusCallback& callback) {
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
-  fileapi::FileSystemOperationContext* context_ptr = context.release();
+  fileapi::FileSystemOperationContext* context_ptr = context.get();
   return context_ptr->task_runner()->PostTask(
       FROM_HERE,
       base::Bind(&NativeMediaFileUtil::CopyOrMoveFileLocalOnTaskRunnerThread,
-                 weak_factory_.GetWeakPtr(), base::Owned(context_ptr),
+                 weak_factory_.GetWeakPtr(), base::Passed(&context),
                  src_url, dest_url, false /* copy */, callback));
 }
 
@@ -256,11 +258,11 @@
     const fileapi::FileSystemURL& dest_url,
     const StatusCallback& callback) {
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
-  fileapi::FileSystemOperationContext* context_ptr = context.release();
+  fileapi::FileSystemOperationContext* context_ptr = context.get();
   return context_ptr->task_runner()->PostTask(
       FROM_HERE,
       base::Bind(&NativeMediaFileUtil::CopyInForeignFileOnTaskRunnerThread,
-                 weak_factory_.GetWeakPtr(), base::Owned(context_ptr),
+                 weak_factory_.GetWeakPtr(), base::Passed(&context),
                  src_file_path, dest_url, callback));
 }
 
@@ -280,36 +282,46 @@
     const fileapi::FileSystemURL& url,
     const StatusCallback& callback) {
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
-  fileapi::FileSystemOperationContext* context_ptr = context.release();
+  fileapi::FileSystemOperationContext* context_ptr = context.get();
   return context_ptr->task_runner()->PostTask(
       FROM_HERE,
       base::Bind(&NativeMediaFileUtil::DeleteDirectoryOnTaskRunnerThread,
-                 weak_factory_.GetWeakPtr(), base::Owned(context_ptr),
+                 weak_factory_.GetWeakPtr(), base::Passed(&context),
                  url, callback));
 }
 
+bool NativeMediaFileUtil::DeleteRecursively(
+    scoped_ptr<fileapi::FileSystemOperationContext> context,
+    const fileapi::FileSystemURL& url,
+    const StatusCallback& callback) {
+  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
+  if (!callback.is_null())
+    callback.Run(base::PLATFORM_FILE_ERROR_INVALID_OPERATION);
+  return true;
+}
+
 bool NativeMediaFileUtil::CreateSnapshotFile(
     scoped_ptr<fileapi::FileSystemOperationContext> context,
     const fileapi::FileSystemURL& url,
     const CreateSnapshotFileCallback& callback) {
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
-  fileapi::FileSystemOperationContext* context_ptr = context.release();
+  fileapi::FileSystemOperationContext* context_ptr = context.get();
   return context_ptr->task_runner()->PostTask(
       FROM_HERE,
       base::Bind(&NativeMediaFileUtil::CreateSnapshotFileOnTaskRunnerThread,
-                 weak_factory_.GetWeakPtr(), base::Owned(context_ptr),
+                 weak_factory_.GetWeakPtr(), base::Passed(&context),
                  url, callback));
 }
 
 void NativeMediaFileUtil::CreateDirectoryOnTaskRunnerThread(
-    fileapi::FileSystemOperationContext* context,
+    scoped_ptr<fileapi::FileSystemOperationContext> context,
     const fileapi::FileSystemURL& url,
     bool exclusive,
     bool recursive,
     const StatusCallback& callback) {
-  DCHECK(IsOnTaskRunnerThread(context));
+  DCHECK(IsOnTaskRunnerThread(context.get()));
   base::PlatformFileError error =
-      CreateDirectorySync(context, url, exclusive, recursive);
+      CreateDirectorySync(context.get(), url, exclusive, recursive);
   if (callback.is_null())
     return;
   content::BrowserThread::PostTask(
@@ -319,15 +331,15 @@
 }
 
 void NativeMediaFileUtil::GetFileInfoOnTaskRunnerThread(
-    fileapi::FileSystemOperationContext* context,
+    scoped_ptr<fileapi::FileSystemOperationContext> context,
     const fileapi::FileSystemURL& url,
     const GetFileInfoCallback& callback) {
-  DCHECK(IsOnTaskRunnerThread(context));
+  DCHECK(IsOnTaskRunnerThread(context.get()));
   base::PlatformFileInfo file_info;
   // TODO(thestig): remove this.
   base::FilePath platform_path;
   base::PlatformFileError error =
-      GetFileInfoSync(context, url, &file_info, &platform_path);
+      GetFileInfoSync(context.get(), url, &file_info, &platform_path);
   if (callback.is_null())
     return;
   content::BrowserThread::PostTask(
@@ -337,13 +349,13 @@
 }
 
 void NativeMediaFileUtil::ReadDirectoryOnTaskRunnerThread(
-    fileapi::FileSystemOperationContext* context,
+    scoped_ptr<fileapi::FileSystemOperationContext> context,
     const fileapi::FileSystemURL& url,
     const ReadDirectoryCallback& callback) {
-  DCHECK(IsOnTaskRunnerThread(context));
+  DCHECK(IsOnTaskRunnerThread(context.get()));
   EntryList entry_list;
   base::PlatformFileError error =
-      ReadDirectorySync(context, url, &entry_list);
+      ReadDirectorySync(context.get(), url, &entry_list);
   if (callback.is_null())
     return;
   content::BrowserThread::PostTask(
@@ -353,14 +365,14 @@
 }
 
 void NativeMediaFileUtil::CopyOrMoveFileLocalOnTaskRunnerThread(
-    fileapi::FileSystemOperationContext* context,
+    scoped_ptr<fileapi::FileSystemOperationContext> context,
     const fileapi::FileSystemURL& src_url,
     const fileapi::FileSystemURL& dest_url,
     bool copy,
     const StatusCallback& callback) {
-  DCHECK(IsOnTaskRunnerThread(context));
+  DCHECK(IsOnTaskRunnerThread(context.get()));
   base::PlatformFileError error =
-      CopyOrMoveFileSync(context, src_url, dest_url, copy);
+      CopyOrMoveFileSync(context.get(), src_url, dest_url, copy);
   if (callback.is_null())
     return;
   content::BrowserThread::PostTask(
@@ -370,13 +382,13 @@
 }
 
 void NativeMediaFileUtil::CopyInForeignFileOnTaskRunnerThread(
-    fileapi::FileSystemOperationContext* context,
+    scoped_ptr<fileapi::FileSystemOperationContext> context,
     const base::FilePath& src_file_path,
     const fileapi::FileSystemURL& dest_url,
     const StatusCallback& callback) {
-  DCHECK(IsOnTaskRunnerThread(context));
+  DCHECK(IsOnTaskRunnerThread(context.get()));
   base::PlatformFileError error =
-      CopyInForeignFileSync(context, src_file_path, dest_url);
+      CopyInForeignFileSync(context.get(), src_file_path, dest_url);
   if (callback.is_null())
     return;
   content::BrowserThread::PostTask(
@@ -386,11 +398,11 @@
 }
 
 void NativeMediaFileUtil::DeleteDirectoryOnTaskRunnerThread(
-    fileapi::FileSystemOperationContext* context,
+    scoped_ptr<fileapi::FileSystemOperationContext> context,
     const fileapi::FileSystemURL& url,
     const StatusCallback& callback) {
-  DCHECK(IsOnTaskRunnerThread(context));
-  base::PlatformFileError error = DeleteDirectorySync(context, url);
+  DCHECK(IsOnTaskRunnerThread(context.get()));
+  base::PlatformFileError error = DeleteDirectorySync(context.get(), url);
   if (callback.is_null())
     return;
   content::BrowserThread::PostTask(
@@ -400,15 +412,15 @@
 }
 
 void NativeMediaFileUtil::CreateSnapshotFileOnTaskRunnerThread(
-    fileapi::FileSystemOperationContext* context,
+    scoped_ptr<fileapi::FileSystemOperationContext> context,
     const fileapi::FileSystemURL& url,
     const CreateSnapshotFileCallback& callback) {
-  DCHECK(IsOnTaskRunnerThread(context));
+  DCHECK(IsOnTaskRunnerThread(context.get()));
   base::PlatformFileInfo file_info;
   base::FilePath platform_path;
   scoped_refptr<webkit_blob::ShareableFileReference> file_ref;
   base::PlatformFileError error =
-      CreateSnapshotFileSync(context, url, &file_info, &platform_path,
+      CreateSnapshotFileSync(context.get(), url, &file_info, &platform_path,
                              &file_ref);
   if (callback.is_null())
     return;
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 76c1e58..731bdb9 100644
--- a/chrome/browser/media_galleries/fileapi/native_media_file_util.h
+++ b/chrome/browser/media_galleries/fileapi/native_media_file_util.h
@@ -82,6 +82,10 @@
       scoped_ptr<fileapi::FileSystemOperationContext> context,
       const fileapi::FileSystemURL& url,
       const StatusCallback& callback) OVERRIDE;
+  virtual bool DeleteRecursively(
+      scoped_ptr<fileapi::FileSystemOperationContext> context,
+      const fileapi::FileSystemURL& url,
+      const StatusCallback& callback) OVERRIDE;
   virtual bool CreateSnapshotFile(
       scoped_ptr<fileapi::FileSystemOperationContext> context,
       const fileapi::FileSystemURL& url,
@@ -89,36 +93,36 @@
 
  protected:
   virtual void CreateDirectoryOnTaskRunnerThread(
-      fileapi::FileSystemOperationContext* context,
+      scoped_ptr<fileapi::FileSystemOperationContext> context,
       const fileapi::FileSystemURL& url,
       bool exclusive,
       bool recursive,
       const StatusCallback& callback);
   virtual void GetFileInfoOnTaskRunnerThread(
-      fileapi::FileSystemOperationContext* context,
+      scoped_ptr<fileapi::FileSystemOperationContext> context,
       const fileapi::FileSystemURL& url,
       const GetFileInfoCallback& callback);
   virtual void ReadDirectoryOnTaskRunnerThread(
-      fileapi::FileSystemOperationContext* context,
+      scoped_ptr<fileapi::FileSystemOperationContext> context,
       const fileapi::FileSystemURL& url,
       const ReadDirectoryCallback& callback);
   virtual void CopyOrMoveFileLocalOnTaskRunnerThread(
-      fileapi::FileSystemOperationContext* context,
+      scoped_ptr<fileapi::FileSystemOperationContext> context,
       const fileapi::FileSystemURL& src_url,
       const fileapi::FileSystemURL& dest_url,
       bool copy,
       const StatusCallback& callback);
   virtual void CopyInForeignFileOnTaskRunnerThread(
-      fileapi::FileSystemOperationContext* context,
+      scoped_ptr<fileapi::FileSystemOperationContext> context,
       const base::FilePath& src_file_path,
       const fileapi::FileSystemURL& dest_url,
       const StatusCallback& callback);
   virtual void DeleteDirectoryOnTaskRunnerThread(
-      fileapi::FileSystemOperationContext* context,
+      scoped_ptr<fileapi::FileSystemOperationContext> context,
       const fileapi::FileSystemURL& url,
       const StatusCallback& callback);
   virtual void CreateSnapshotFileOnTaskRunnerThread(
-      fileapi::FileSystemOperationContext* context,
+      scoped_ptr<fileapi::FileSystemOperationContext> context,
       const fileapi::FileSystemURL& url,
       const CreateSnapshotFileCallback& callback);
 
diff --git a/chrome/browser/media_galleries/fileapi/native_media_file_util_unittest.cc b/chrome/browser/media_galleries/fileapi/native_media_file_util_unittest.cc
index 6fdd7cb..71f752f 100644
--- a/chrome/browser/media_galleries/fileapi/native_media_file_util_unittest.cc
+++ b/chrome/browser/media_galleries/fileapi/native_media_file_util_unittest.cc
@@ -9,10 +9,10 @@
 #include "base/file_util.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/format_macros.h"
-#include "base/message_loop.h"
-#include "base/message_loop_proxy.h"
+#include "base/message_loop/message_loop.h"
+#include "base/message_loop/message_loop_proxy.h"
 #include "base/strings/stringprintf.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/media_galleries/fileapi/media_file_system_mount_point_provider.h"
 #include "chrome/browser/media_galleries/fileapi/native_media_file_util.h"
 #include "content/public/test/test_browser_thread.h"
@@ -288,7 +288,7 @@
     for (size_t i = 0; i < arraysize(kFilteringTestCases); ++i) {
       // Always start with an empty destination directory.
       // Copying to a non-empty destination directory is an invalid operation.
-      ASSERT_TRUE(file_util::Delete(dest_path, true));
+      ASSERT_TRUE(base::Delete(dest_path, true));
       ASSERT_TRUE(file_util::CreateDirectory(dest_path));
 
       FileSystemURL root_url = CreateURL(FPL(""));
@@ -318,7 +318,7 @@
     if (loop_count == 1) {
       // Reset the test directory between the two loops to remove old
       // directories and create new ones that should pre-exist.
-      ASSERT_TRUE(file_util::Delete(root_path(), true));
+      ASSERT_TRUE(base::Delete(root_path(), true));
       ASSERT_TRUE(file_util::CreateDirectory(root_path()));
       PopulateDirectoryWithTestCases(root_path(),
                                      kFilteringTestCases,
@@ -387,7 +387,7 @@
     for (size_t i = 0; i < arraysize(kFilteringTestCases); ++i) {
       // Always start with an empty destination directory.
       // Moving to a non-empty destination directory is an invalid operation.
-      ASSERT_TRUE(file_util::Delete(dest_path, true));
+      ASSERT_TRUE(base::Delete(dest_path, true));
       ASSERT_TRUE(file_util::CreateDirectory(dest_path));
 
       FileSystemURL root_url = CreateURL(FPL(""));
@@ -417,7 +417,7 @@
     if (loop_count == 1) {
       // Reset the test directory between the two loops to remove old
       // directories and create new ones that should pre-exist.
-      ASSERT_TRUE(file_util::Delete(root_path(), true));
+      ASSERT_TRUE(base::Delete(root_path(), true));
       ASSERT_TRUE(file_util::CreateDirectory(root_path()));
       PopulateDirectoryWithTestCases(root_path(),
                                      kFilteringTestCases,
diff --git a/chrome/browser/media_galleries/fileapi/picasa/picasa_album_table_reader.cc b/chrome/browser/media_galleries/fileapi/picasa/picasa_album_table_reader.cc
deleted file mode 100644
index e32e390..0000000
--- a/chrome/browser/media_galleries/fileapi/picasa/picasa_album_table_reader.cc
+++ /dev/null
@@ -1,127 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/media_galleries/fileapi/picasa/picasa_album_table_reader.h"
-
-#include <vector>
-
-#include "base/path_service.h"
-#include "base/strings/string_util.h"
-#include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/media_galleries/fileapi/picasa/pmp_column_reader.h"
-#include "chrome/browser/media_galleries/fileapi/picasa/pmp_constants.h"
-#include "chrome/browser/media_galleries/fileapi/picasa/pmp_table_reader.h"
-
-namespace picasa {
-
-namespace {
-
-// |variant_time| is specified as the number of days from Dec 30, 1899.
-base::Time TimeFromMicrosoftVariantTime(double variant_time) {
-  base::TimeDelta variant_delta = base::TimeDelta::FromMicroseconds(
-      static_cast<int64>(variant_time * base::Time::kMicrosecondsPerDay));
-
-  return base::Time::FromLocalExploded(kPicasaVariantTimeEpoch) + variant_delta;
-}
-
-}  // namespace
-
-AlbumInfo::AlbumInfo() {}
-
-AlbumInfo::AlbumInfo(const std::string& name, const base::Time& timestamp,
-                     const std::string& uid, const base::FilePath& path)
-    : name(name),
-      timestamp(timestamp),
-      uid(uid),
-      path(path) {
-}
-
-AlbumInfo::~AlbumInfo() {}
-
-PicasaAlbumTableReader::PicasaAlbumTableReader(
-    const base::FilePath& directory_path)
-    : directory_path_(directory_path),
-      initialized_(false) {}
-
-PicasaAlbumTableReader::~PicasaAlbumTableReader() {}
-
-const std::vector<AlbumInfo>& PicasaAlbumTableReader::folders() const {
-  DCHECK(initialized_);
-  return folders_;
-}
-
-const std::vector<AlbumInfo>& PicasaAlbumTableReader::albums() const {
-  DCHECK(initialized_);
-  return albums_;
-}
-
-bool PicasaAlbumTableReader::Init() {
-  if (initialized_)
-    return true;
-
-  PmpTableReader pmp_reader(kPicasaAlbumTableName, directory_path_);
-
-  const PmpColumnReader* category_column =
-      pmp_reader.AddColumn("category", PMP_TYPE_UINT32);
-  const PmpColumnReader* date_column =
-      pmp_reader.AddColumn("date", PMP_TYPE_DOUBLE64);
-  const PmpColumnReader* filename_column =
-      pmp_reader.AddColumn("filename", PMP_TYPE_STRING);
-  const PmpColumnReader* name_column =
-      pmp_reader.AddColumn("name", PMP_TYPE_STRING);
-  const PmpColumnReader* token_column =
-      pmp_reader.AddColumn("token", PMP_TYPE_STRING);
-  const PmpColumnReader* uid_column =
-      pmp_reader.AddColumn("uid", PMP_TYPE_STRING);
-
-  if (pmp_reader.Columns().size() != 6)
-    return false;
-
-  for (uint32 i = 0; i < pmp_reader.RowCount(); i++) {
-    uint32 category = kAlbumCategoryInvalid;
-    double date = 0;
-    std::string name;
-    std::string uid;
-    if (!category_column->ReadUInt32(i, &category) ||
-        !date_column->ReadDouble64(i, &date) ||
-        !name_column->ReadString(i, &name) || name.empty() ||
-        !uid_column->ReadString(i, &uid) || uid.empty()) {
-      continue;
-    }
-
-    base::Time timestamp = TimeFromMicrosoftVariantTime(date);
-
-    switch (category) {
-      case kAlbumCategoryAlbum: {
-        std::string token;
-        if (!token_column->ReadString(i, &token) || token.empty() ||
-            !StartsWithASCII(token, kAlbumTokenPrefix, false)) {
-          continue;
-        }
-
-        albums_.push_back(AlbumInfo(name, timestamp, uid, base::FilePath()));
-        break;
-      }
-      case kAlbumCategoryFolder: {
-        std::string filename;
-        if (!filename_column->ReadString(i, &filename) || filename.empty())
-          continue;
-
-        base::FilePath path =
-            base::FilePath(base::FilePath::FromUTF8Unsafe(filename));
-
-        folders_.push_back(AlbumInfo(name, timestamp, uid, path));
-        break;
-      }
-      default: {
-        break;
-      }
-    }
-  }
-
-  initialized_ = true;
-  return true;
-}
-
-}  // namespace picasa
diff --git a/chrome/browser/media_galleries/fileapi/picasa/picasa_album_table_reader.h b/chrome/browser/media_galleries/fileapi/picasa/picasa_album_table_reader.h
deleted file mode 100644
index b4ef981..0000000
--- a/chrome/browser/media_galleries/fileapi/picasa/picasa_album_table_reader.h
+++ /dev/null
@@ -1,64 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_PICASA_PICASA_ALBUM_TABLE_READER_H_
-#define CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_PICASA_PICASA_ALBUM_TABLE_READER_H_
-
-#include "base/basictypes.h"
-#include "base/files/file_path.h"
-#include "base/time.h"
-
-namespace picasa {
-
-const base::Time::Exploded kPicasaVariantTimeEpoch = {
-  1899, 12, 7, 30,  // Dec 30, 1899 (Saturday)
-  0, 0, 0, 0        // 00:00:00.000
-};
-
-const char kPicasaAlbumTableName[] = "albumdata";
-
-const uint32 kAlbumCategoryAlbum     = 0;
-const uint32 kAlbumCategoryFolder    = 2;
-const uint32 kAlbumCategoryInvalid   = 0xffff;  // Sentinel value.
-
-const char kAlbumTokenPrefix[] = "]album:";
-
-struct AlbumInfo {
-  AlbumInfo();
-  AlbumInfo(const std::string& name, const base::Time& timestamp,
-            const std::string& uid, const base::FilePath& path);
-
-  ~AlbumInfo();
-
-  std::string name;
-  base::Time timestamp;
-  std::string uid;
-  base::FilePath path;
-};
-
-class PicasaAlbumTableReader {
- public:
-  // |directory_path| is Picasa's db3 directory where the PMP table is stored.
-  explicit PicasaAlbumTableReader(const base::FilePath& directory_path);
-  virtual ~PicasaAlbumTableReader();
-
-  bool Init();
-
-  const std::vector<AlbumInfo>& albums() const;
-  const std::vector<AlbumInfo>& folders() const;
-
- private:
-  const base::FilePath directory_path_;
-
-  bool initialized_;
-
-  std::vector<AlbumInfo> albums_;
-  std::vector<AlbumInfo> folders_;
-
-  DISALLOW_COPY_AND_ASSIGN(PicasaAlbumTableReader);
-};
-
-}  // namespace picasa
-
-#endif  // CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_PICASA_PICASA_ALBUM_TABLE_READER_H_
diff --git a/chrome/browser/media_galleries/fileapi/picasa/picasa_album_table_reader_unittest.cc b/chrome/browser/media_galleries/fileapi/picasa/picasa_album_table_reader_unittest.cc
deleted file mode 100644
index b36691d..0000000
--- a/chrome/browser/media_galleries/fileapi/picasa/picasa_album_table_reader_unittest.cc
+++ /dev/null
@@ -1,89 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/media_galleries/fileapi/picasa/picasa_album_table_reader.h"
-#include "chrome/browser/media_galleries/fileapi/picasa/pmp_constants.h"
-#include "chrome/browser/media_galleries/fileapi/picasa/pmp_test_helper.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace {
-
-using picasa::PmpTestHelper;
-using picasa::PMP_TYPE_UINT32;
-
-TEST(PicasaAlbumTableReaderTest, FoldersAndAlbums) {
-  PmpTestHelper test_helper(picasa::kPicasaAlbumTableName);
-  ASSERT_TRUE(test_helper.Init());
-
-  int test_time_delta = 100;
-
-  std::vector<uint32> category_vector;
-  category_vector.push_back(picasa::kAlbumCategoryFolder);
-  category_vector.push_back(picasa::kAlbumCategoryInvalid);
-  category_vector.push_back(picasa::kAlbumCategoryAlbum);
-
-  std::vector<double> date_vector;
-  date_vector.push_back(0.0);
-  date_vector.push_back(0.0);
-  date_vector.push_back(0.0 + test_time_delta);
-
-  std::string test_folder_name = "Pix4dalulz";
-  std::string test_album_name = "Cats";
-
-  base::FilePath test_folder_path =
-      base::FilePath(base::FilePath::FromUTF8Unsafe("C:\\Pix4dalulz"));
-
-  // Only folders require filenames. Tests handling of different length columns.
-  std::vector<std::string> filename_vector;
-  filename_vector.push_back(test_folder_path.AsUTF8Unsafe());
-
-  std::vector<std::string> name_vector;
-  name_vector.push_back(test_folder_name);
-  name_vector.push_back("");
-  name_vector.push_back(test_album_name);
-
-  std::vector<std::string> token_vector;
-  token_vector.push_back("");
-  token_vector.push_back("");
-  token_vector.push_back(std::string(picasa::kAlbumTokenPrefix) + "uid3");
-
-  std::vector<std::string> uid_vector;
-  uid_vector.push_back("uid1");
-  uid_vector.push_back("uid2");
-  uid_vector.push_back("uid3");
-
-  ASSERT_TRUE(test_helper.WriteColumnFileFromVector(
-      "category", picasa::PMP_TYPE_UINT32, category_vector));
-  ASSERT_TRUE(test_helper.WriteColumnFileFromVector(
-      "date", picasa::PMP_TYPE_DOUBLE64, date_vector));
-  ASSERT_TRUE(test_helper.WriteColumnFileFromVector(
-      "filename", picasa::PMP_TYPE_STRING, filename_vector));
-  ASSERT_TRUE(test_helper.WriteColumnFileFromVector(
-      "name", picasa::PMP_TYPE_STRING, name_vector));
-  ASSERT_TRUE(test_helper.WriteColumnFileFromVector(
-      "token", picasa::PMP_TYPE_STRING, token_vector));
-  ASSERT_TRUE(test_helper.WriteColumnFileFromVector(
-      "uid", picasa::PMP_TYPE_STRING, uid_vector));
-
-  picasa::PicasaAlbumTableReader reader(test_helper.GetTempDirPath());
-
-  ASSERT_TRUE(reader.Init());
-
-  const std::vector<picasa::AlbumInfo>& albums = reader.albums();
-  const std::vector<picasa::AlbumInfo>& folders = reader.folders();
-
-  ASSERT_EQ(1u, albums.size());
-  ASSERT_EQ(1u, folders.size());
-
-  EXPECT_EQ(test_album_name, albums[0].name);
-  EXPECT_EQ(test_folder_name, folders[0].name);
-
-  EXPECT_EQ(test_folder_path, folders[0].path);
-
-  base::TimeDelta time_delta = albums[0].timestamp - folders[0].timestamp;
-
-  EXPECT_EQ(test_time_delta, time_delta.InDays());
-}
-
-}  // namespace
diff --git a/chrome/browser/media_galleries/fileapi/picasa/picasa_data_provider.cc b/chrome/browser/media_galleries/fileapi/picasa/picasa_data_provider.cc
index cdeec76..3cd4f8e 100644
--- a/chrome/browser/media_galleries/fileapi/picasa/picasa_data_provider.cc
+++ b/chrome/browser/media_galleries/fileapi/picasa/picasa_data_provider.cc
@@ -9,7 +9,7 @@
 #include "base/basictypes.h"
 #include "base/callback.h"
 #include "base/strings/stringprintf.h"
-#include "chrome/browser/media_galleries/fileapi/picasa/picasa_album_table_reader.h"
+#include "chrome/common/media_galleries/picasa_types.h"
 #include "webkit/browser/fileapi/file_system_operation_context.h"
 #include "webkit/browser/fileapi/file_system_url.h"
 
@@ -89,13 +89,20 @@
 }
 
 bool PicasaDataProvider::ReadData() {
-  PicasaAlbumTableReader album_table_reader(database_path_);
-
-  if (!album_table_reader.Init())
-    return false;
-
-  InitializeWith(album_table_reader.albums(),
-                 album_table_reader.folders());
+  // TODO(tommycli): Disabled until utility process host client implemented.
+  // PicasaAlbumTableFiles album_table_files(database_path_);
+  // PicasaAlbumTableReader album_table_reader((album_table_files));
+  //
+  // bool read_success = album_table_reader.Init();
+  //
+  // ClosePicasaAlbumTableFiles(&album_table_files);
+  //
+  // if (read_success) {
+  //   InitializeWith(album_table_reader.albums(),
+  //                  album_table_reader.folders());
+  // }
+  //
+  //  return read_success;
 
   return true;
 }
diff --git a/chrome/browser/media_galleries/fileapi/picasa/picasa_data_provider.h b/chrome/browser/media_galleries/fileapi/picasa/picasa_data_provider.h
index 20feb91..40a9bd1 100644
--- a/chrome/browser/media_galleries/fileapi/picasa/picasa_data_provider.h
+++ b/chrome/browser/media_galleries/fileapi/picasa/picasa_data_provider.h
@@ -12,7 +12,7 @@
 #include "base/callback_forward.h"
 #include "base/files/file_path.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/time.h"
+#include "base/time/time.h"
 
 namespace picasa {
 
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 b779535..15ce254 100644
--- a/chrome/browser/media_galleries/fileapi/picasa/picasa_file_util.cc
+++ b/chrome/browser/media_galleries/fileapi/picasa/picasa_file_util.cc
@@ -4,15 +4,19 @@
 
 #include "chrome/browser/media_galleries/fileapi/picasa/picasa_file_util.h"
 
+#include <string>
+#include <vector>
+
 #include "base/basictypes.h"
+#include "base/bind_helpers.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/sys_string_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/media_galleries/fileapi/media_file_system_mount_point_provider.h"
-#include "chrome/browser/media_galleries/fileapi/picasa/picasa_album_table_reader.h"
 #include "chrome/browser/media_galleries/fileapi/picasa/picasa_data_provider.h"
 #include "chrome/browser/media_galleries/imported_media_gallery_registry.h"
+#include "chrome/common/media_galleries/picasa_types.h"
 #include "webkit/browser/fileapi/file_system_operation_context.h"
 #include "webkit/browser/fileapi/file_system_url.h"
 #include "webkit/common/fileapi/file_system_util.h"
@@ -56,21 +60,23 @@
 PicasaFileUtil::~PicasaFileUtil() {}
 
 void PicasaFileUtil::GetFileInfoOnTaskRunnerThread(
-    fileapi::FileSystemOperationContext* context,
+    scoped_ptr<fileapi::FileSystemOperationContext> context,
     const fileapi::FileSystemURL& url,
     const GetFileInfoCallback& callback) {
   GetDataProvider()->RefreshData(
       base::Bind(&PicasaFileUtil::GetFileInfoWithFreshDataProvider,
-                 weak_factory_.GetWeakPtr(), context, url, callback));
+                 weak_factory_.GetWeakPtr(), base::Passed(&context), url,
+                 callback));
 }
 
 void PicasaFileUtil::ReadDirectoryOnTaskRunnerThread(
-    fileapi::FileSystemOperationContext* context,
+    scoped_ptr<fileapi::FileSystemOperationContext> context,
     const fileapi::FileSystemURL& url,
     const ReadDirectoryCallback& callback) {
   GetDataProvider()->RefreshData(
       base::Bind(&PicasaFileUtil::ReadDirectoryWithFreshDataProvider,
-                 weak_factory_.GetWeakPtr(), context, url, callback));
+                 weak_factory_.GetWeakPtr(), base::Passed(&context), url,
+                 callback));
 }
 
 base::PlatformFileError PicasaFileUtil::GetFileInfoSync(
@@ -273,17 +279,19 @@
 }
 
 void PicasaFileUtil::GetFileInfoWithFreshDataProvider(
-    fileapi::FileSystemOperationContext* context,
+    scoped_ptr<fileapi::FileSystemOperationContext> context,
     const fileapi::FileSystemURL& url,
     const GetFileInfoCallback& callback) {
-  NativeMediaFileUtil::GetFileInfoOnTaskRunnerThread(context, url, callback);
+  NativeMediaFileUtil::GetFileInfoOnTaskRunnerThread(context.Pass(), url,
+                                                     callback);
 }
 
 void PicasaFileUtil::ReadDirectoryWithFreshDataProvider(
-    fileapi::FileSystemOperationContext* context,
+    scoped_ptr<fileapi::FileSystemOperationContext> context,
     const fileapi::FileSystemURL& url,
     const ReadDirectoryCallback& callback) {
-  NativeMediaFileUtil::ReadDirectoryOnTaskRunnerThread(context, url, callback);
+  NativeMediaFileUtil::ReadDirectoryOnTaskRunnerThread(context.Pass(), url,
+                                                       callback);
 }
 
 PicasaDataProvider* PicasaFileUtil::GetDataProvider() {
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 1b14f16..f17cb66 100644
--- a/chrome/browser/media_galleries/fileapi/picasa/picasa_file_util.h
+++ b/chrome/browser/media_galleries/fileapi/picasa/picasa_file_util.h
@@ -5,6 +5,7 @@
 #ifndef CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_PICASA_PICASA_FILE_UTIL_H_
 #define CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_PICASA_PICASA_FILE_UTIL_H_
 
+#include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/media_galleries/fileapi/native_media_file_util.h"
 
@@ -23,11 +24,11 @@
  protected:
   // NativeMediaFileUtil overrides.
   virtual void GetFileInfoOnTaskRunnerThread(
-      fileapi::FileSystemOperationContext* context,
+      scoped_ptr<fileapi::FileSystemOperationContext> context,
       const fileapi::FileSystemURL& url,
       const GetFileInfoCallback& callback) OVERRIDE;
   virtual void ReadDirectoryOnTaskRunnerThread(
-      fileapi::FileSystemOperationContext* context,
+      scoped_ptr<fileapi::FileSystemOperationContext> context,
       const fileapi::FileSystemURL& url,
       const ReadDirectoryCallback& callback) OVERRIDE;
   virtual base::PlatformFileError GetFileInfoSync(
@@ -46,11 +47,11 @@
 
  private:
   void GetFileInfoWithFreshDataProvider(
-      fileapi::FileSystemOperationContext* context,
+      scoped_ptr<fileapi::FileSystemOperationContext> context,
       const fileapi::FileSystemURL& url,
       const GetFileInfoCallback& callback);
   void ReadDirectoryWithFreshDataProvider(
-      fileapi::FileSystemOperationContext* context,
+      scoped_ptr<fileapi::FileSystemOperationContext> context,
       const fileapi::FileSystemURL& url,
       const ReadDirectoryCallback& callback);
 
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 fd7a29b..10ebb3a 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
@@ -4,22 +4,22 @@
 
 #include <set>
 #include <string>
+#include <vector>
 
 #include "base/file_util.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/memory/scoped_vector.h"
-#include "base/message_loop.h"
-#include "base/message_loop_proxy.h"
+#include "base/message_loop/message_loop.h"
+#include "base/message_loop/message_loop_proxy.h"
 #include "base/run_loop.h"
 #include "base/strings/stringprintf.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/media_galleries/fileapi/media_file_system_mount_point_provider.h"
 #include "chrome/browser/media_galleries/fileapi/media_path_filter.h"
-#include "chrome/browser/media_galleries/fileapi/picasa/picasa_album_table_reader.h"
 #include "chrome/browser/media_galleries/fileapi/picasa/picasa_data_provider.h"
 #include "chrome/browser/media_galleries/fileapi/picasa/picasa_file_util.h"
-#include "chrome/browser/media_galleries/fileapi/picasa/pmp_constants.h"
-#include "chrome/browser/media_galleries/fileapi/picasa/pmp_test_helper.h"
+#include "chrome/common/media_galleries/picasa_types.h"
+#include "chrome/common/media_galleries/pmp_constants.h"
 #include "content/public/test/test_browser_thread.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "webkit/browser/fileapi/async_file_util_adapter.h"
@@ -87,7 +87,7 @@
   double GetVariantTimestamp() const {
     DCHECK(!folder_dir_.path().empty());
     base::Time variant_epoch = base::Time::FromLocalExploded(
-        picasa::kPicasaVariantTimeEpoch);
+        picasa::kPmpVariantTimeEpoch);
 
     int64 microseconds_since_epoch =
         (folder_info_.timestamp - variant_epoch).InMicroseconds();
@@ -121,17 +121,26 @@
 
 class TestPicasaDataProvider : public PicasaDataProvider {
  public:
-  TestPicasaDataProvider(const std::vector<AlbumInfo>& albums,
-                         const std::vector<AlbumInfo>& folders)
-      : PicasaDataProvider(base::FilePath(FILE_PATH_LITERAL("Fake"))) {
+  TestPicasaDataProvider()
+      : PicasaDataProvider(base::FilePath(FILE_PATH_LITERAL("Fake"))),
+        initialized_(false) {
+  }
+
+  virtual ~TestPicasaDataProvider() {}
+
+  void Init(const std::vector<AlbumInfo>& albums,
+            const std::vector<AlbumInfo>& folders) {
     InitializeWith(albums, folders);
+    initialized_ = true;
   }
 
  private:
   virtual bool ReadData() OVERRIDE {
+    DCHECK(initialized_);
     return true;
   }
-  virtual ~TestPicasaDataProvider() {}
+
+  bool initialized_;
 };
 
 class TestPicasaFileUtil : public PicasaFileUtil {
@@ -142,10 +151,10 @@
   virtual ~TestPicasaFileUtil() {}
  private:
   virtual PicasaDataProvider* GetDataProvider() OVERRIDE {
-    return data_provider_.get();
+    return data_provider_;
   }
 
-  scoped_ptr<PicasaDataProvider> data_provider_;
+  PicasaDataProvider* data_provider_;
 };
 
 class TestMediaFileSystemMountPointProvider
@@ -218,19 +227,17 @@
   virtual ~PicasaFileUtilTest() {}
 
   virtual void SetUp() OVERRIDE {
-    test_helper_.reset(new PmpTestHelper(kPicasaAlbumTableName));
-    ASSERT_TRUE(test_helper_->Init());
-
     ASSERT_TRUE(profile_dir_.CreateUniqueTempDir());
 
     scoped_refptr<quota::SpecialStoragePolicy> storage_policy =
         new quota::MockSpecialStoragePolicy();
 
+    picasa_data_provider_.reset(new TestPicasaDataProvider());
+
     ScopedVector<fileapi::FileSystemMountPointProvider> additional_providers;
     additional_providers.push_back(new TestMediaFileSystemMountPointProvider(
         profile_dir_.path(),
-        new TestPicasaFileUtil(
-            new PicasaDataProvider(test_helper_->GetTempDirPath()))));
+        new TestPicasaFileUtil(picasa_data_provider_.get())));
 
     file_system_context_ = new fileapi::FileSystemContext(
         fileapi::FileSystemTaskRunners::CreateMockTaskRunners(),
@@ -245,38 +252,14 @@
  protected:
   // |test_folders| must be in alphabetical order for easy verification
   void SetupFolders(ScopedVector<TestFolder>* test_folders) {
-    // Build up pmp files.
-    std::vector<uint32> category_column;
-    std::vector<double> date_column;
-    std::vector<std::string> filename_column;
-    std::vector<std::string> name_column;
-    std::vector<std::string> uid_column;
-    std::vector<std::string> token_column;
-
+    std::vector<AlbumInfo> folders;
     for (ScopedVector<TestFolder>::iterator it = test_folders->begin();
         it != test_folders->end(); ++it) {
       TestFolder* test_folder = *it;
       ASSERT_TRUE(test_folder->Init());
-      category_column.push_back(picasa::kAlbumCategoryFolder);
-      date_column.push_back(test_folder->GetVariantTimestamp());
-      filename_column.push_back(test_folder->folder_info().path.AsUTF8Unsafe());
-      name_column.push_back(test_folder->folder_info().name);
-      uid_column.push_back(test_folder->folder_info().uid);
-      token_column.push_back("]album:" + test_folder->folder_info().uid);
+      folders.push_back(test_folder->folder_info());
     }
-
-    ASSERT_TRUE(test_helper_->WriteColumnFileFromVector(
-        "category", picasa::PMP_TYPE_UINT32, category_column));
-    ASSERT_TRUE(test_helper_->WriteColumnFileFromVector(
-        "date", picasa::PMP_TYPE_DOUBLE64, date_column));
-    ASSERT_TRUE(test_helper_->WriteColumnFileFromVector(
-        "filename", picasa::PMP_TYPE_STRING, filename_column));
-    ASSERT_TRUE(test_helper_->WriteColumnFileFromVector(
-        "name", picasa::PMP_TYPE_STRING, name_column));
-    ASSERT_TRUE(test_helper_->WriteColumnFileFromVector(
-        "uid", picasa::PMP_TYPE_STRING, uid_column));
-    ASSERT_TRUE(test_helper_->WriteColumnFileFromVector(
-        "token", picasa::PMP_TYPE_STRING, token_column));
+    picasa_data_provider_->Init(std::vector<AlbumInfo>(), folders);
   }
 
   void VerifyFolderDirectoryList(const ScopedVector<TestFolder>& test_folders) {
@@ -363,7 +346,7 @@
   base::ScopedTempDir profile_dir_;
 
   scoped_refptr<fileapi::FileSystemContext> file_system_context_;
-  scoped_ptr<PmpTestHelper> test_helper_;
+  scoped_ptr<TestPicasaDataProvider> picasa_data_provider_;
 
   DISALLOW_COPY_AND_ASSIGN(PicasaFileUtilTest);
 };
@@ -419,8 +402,10 @@
       chrome::MediaFileSystemMountPointProvider::kMediaPathFilterKey,
       media_path_filter.get());
 
-  TestPicasaFileUtil test_file_util(
-      new TestPicasaDataProvider(std::vector<AlbumInfo>(), folders));
+  scoped_ptr<TestPicasaDataProvider> test_picasa_data_provider(
+      new TestPicasaDataProvider());
+  test_picasa_data_provider->Init(std::vector<AlbumInfo>(), folders);
+  TestPicasaFileUtil test_file_util(test_picasa_data_provider.get());
 
   fileapi::AsyncFileUtil::EntryList file_list;
   ASSERT_EQ(base::PLATFORM_FILE_OK,
@@ -438,6 +423,9 @@
 }
 
 TEST_F(PicasaFileUtilTest, RootFolders) {
+  ScopedVector<TestFolder> empty_folders_list;
+  SetupFolders(&empty_folders_list);
+
   FileSystemOperation::FileEntryList contents;
   FileSystemURL url = CreateURL("");
   bool completed = false;
diff --git a/chrome/browser/media_galleries/fileapi/picasa/pmp_column_reader.cc b/chrome/browser/media_galleries/fileapi/picasa/pmp_column_reader.cc
deleted file mode 100644
index cf799d4..0000000
--- a/chrome/browser/media_galleries/fileapi/picasa/pmp_column_reader.cc
+++ /dev/null
@@ -1,197 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/media_galleries/fileapi/picasa/pmp_column_reader.h"
-
-#include <cstring>
-
-#include "base/file_util.h"
-#include "base/files/file_path.h"
-#include "base/logging.h"
-#include "base/threading/thread_restrictions.h"
-
-namespace picasa {
-
-namespace {
-
-const int64 kPmpMaxFilesize = 50*1024*1024;  // Arbitrary maximum of 50 MB.
-
-}  // namespace
-
-PmpColumnReader::PmpColumnReader()
-    : length_(0),
-      field_type_(PMP_TYPE_INVALID),
-      rows_(0) {}
-
-PmpColumnReader::~PmpColumnReader() {}
-
-bool PmpColumnReader::Init(const base::FilePath& filepath,
-                           const PmpFieldType expected_type,
-                           uint32* rows_read) {
-  DCHECK(!data_.get());
-  base::ThreadRestrictions::AssertIOAllowed();
-
-  if (!file_util::GetFileSize(filepath, &length_))
-    return false;
-
-  if (length_ < kPmpHeaderSize || length_ > kPmpMaxFilesize)
-    return false;
-
-  data_.reset(new uint8[length_]);
-
-  char* data_begin = reinterpret_cast<char*>(data_.get());
-
-  DCHECK(length_ < kint32max);  // ReadFile expects an int.
-
-  bool success = file_util::ReadFile(filepath, data_begin, length_) &&
-                 ParseData(expected_type, rows_read);
-
-  if (!success)
-    rows_ = 0;  // If any of the reading or parsing fails, prevent Read* calls.
-
-  return success;
-}
-
-bool PmpColumnReader::ReadString(const uint32 row, std::string* result) const {
-  DCHECK(data_.get() != NULL);
-
-  if (field_type_ != PMP_TYPE_STRING || row >= rows_)
-    return false;
-
-  DCHECK_LT(row, strings_.size());
-  *result = strings_[row];
-  return true;
-}
-
-bool PmpColumnReader::ReadUInt32(const uint32 row, uint32* result) const {
-  DCHECK(data_.get() != NULL);
-
-  if (field_type_ != PMP_TYPE_UINT32 || row >= rows_)
-    return false;
-
-  *result = reinterpret_cast<uint32*>(data_.get() + kPmpHeaderSize)[row];
-  return true;
-}
-
-bool PmpColumnReader::ReadDouble64(const uint32 row, double* result) const {
-  DCHECK(data_.get() != NULL);
-
-  if (field_type_ != PMP_TYPE_DOUBLE64 || row >= rows_)
-    return false;
-
-  *result = reinterpret_cast<double*>(data_.get() + kPmpHeaderSize)[row];
-  return true;
-}
-
-bool PmpColumnReader::ReadUInt8(const uint32 row, uint8* result) const {
-  DCHECK(data_.get() != NULL);
-
-  if (field_type_ != PMP_TYPE_UINT8 || row >= rows_)
-    return false;
-
-  *result = reinterpret_cast<uint8*>(data_.get() + kPmpHeaderSize)[row];
-  return true;
-}
-
-bool PmpColumnReader::ReadUInt64(const uint32 row, uint64* result) const {
-  DCHECK(data_.get() != NULL);
-
-  if (field_type_ != PMP_TYPE_UINT64 || row >= rows_)
-    return false;
-
-  *result = reinterpret_cast<uint64*>(data_.get() + kPmpHeaderSize)[row];
-  return true;
-}
-
-bool PmpColumnReader::ParseData(const PmpFieldType expected_type,
-                                uint32* rows_read) {
-  DCHECK(data_.get() != NULL);
-  DCHECK_GE(length_, kPmpHeaderSize);
-
-  // Check all magic bytes.
-  if (memcmp(&kPmpMagic1, &data_[kPmpMagic1Offset], sizeof(kPmpMagic1)) != 0 ||
-      memcmp(&kPmpMagic2, &data_[kPmpMagic2Offset], sizeof(kPmpMagic2)) != 0 ||
-      memcmp(&kPmpMagic3, &data_[kPmpMagic3Offset], sizeof(kPmpMagic3)) != 0 ||
-      memcmp(&kPmpMagic4, &data_[kPmpMagic4Offset], sizeof(kPmpMagic4)) != 0) {
-    return false;
-  }
-
-  uint16 field_type_data =
-      *(reinterpret_cast<uint16*>(&data_[kPmpFieldType1Offset]));
-
-  // Verify if field type matches second declaration
-  if (field_type_data !=
-      *(reinterpret_cast<uint16*>(&data_[kPmpFieldType2Offset]))) {
-    return false;
-  }
-
-  field_type_ = static_cast<PmpFieldType>(field_type_data);
-
-  if (field_type_ != expected_type)
-    return false;
-
-  rows_ = *(reinterpret_cast<uint32*>(&data_[kPmpRowCountOffset]));
-
-  // Sanity check against malicious row field.
-  if (rows_ > (kPmpMaxFilesize - kPmpHeaderSize))
-    return false;
-
-  DCHECK_GE(length_, kPmpHeaderSize);
-  int64 body_length = length_ - kPmpHeaderSize;
-  int64 expected_body_length = 0;
-  switch (field_type_) {
-    case PMP_TYPE_STRING:
-      expected_body_length = IndexStrings();
-      break;
-    case PMP_TYPE_UINT32:
-      expected_body_length = static_cast<int64>(rows_) * sizeof(uint32);
-      break;
-    case PMP_TYPE_DOUBLE64:
-      expected_body_length = static_cast<int64>(rows_) * sizeof(double);
-      break;
-    case PMP_TYPE_UINT8:
-      expected_body_length = static_cast<int64>(rows_) * sizeof(uint8);
-      break;
-    case PMP_TYPE_UINT64:
-      expected_body_length = static_cast<int64>(rows_) * sizeof(uint64);
-      break;
-    default:
-      return false;
-      break;
-  }
-
-  if (body_length == expected_body_length && rows_read)
-    *rows_read = rows_;
-  return body_length == expected_body_length;
-}
-
-int64 PmpColumnReader::IndexStrings() {
-  DCHECK(data_.get() != NULL);
-  DCHECK_GE(length_, kPmpHeaderSize);
-
-  strings_.reserve(rows_);
-
-  int64 bytes_parsed = kPmpHeaderSize;
-  const uint8* data_cursor = data_.get() + kPmpHeaderSize;
-
-  while (strings_.size() < rows_) {
-    const uint8* string_end = static_cast<const uint8*>(
-        memchr(data_cursor, '\0', length_ - bytes_parsed));
-
-    // Fail if cannot find null termination. String runs on past file end.
-    if (string_end == NULL)
-      return -1;
-
-    // Length of string. (+1 to include the termination character).
-    ptrdiff_t length_in_bytes = string_end - data_cursor + 1;
-
-    strings_.push_back(reinterpret_cast<const char*>(data_cursor));
-    data_cursor += length_in_bytes;
-    bytes_parsed += length_in_bytes;
-  }
-
-  return bytes_parsed - kPmpHeaderSize;
-}
-
-}  // namespace picasa
diff --git a/chrome/browser/media_galleries/fileapi/picasa/pmp_column_reader.h b/chrome/browser/media_galleries/fileapi/picasa/pmp_column_reader.h
deleted file mode 100644
index 19ec1d5..0000000
--- a/chrome/browser/media_galleries/fileapi/picasa/pmp_column_reader.h
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_PICASA_PMP_COLUMN_READER_H_
-#define CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_PICASA_PMP_COLUMN_READER_H_
-
-#include <string>
-#include <vector>
-
-#include "base/basictypes.h"
-#include "base/memory/scoped_ptr.h"
-#include "chrome/browser/media_galleries/fileapi/picasa/pmp_constants.h"
-
-namespace base {
-class FilePath;
-}
-
-namespace picasa {
-
-// Reads a single PMP column from a file.
-class PmpColumnReader {
- public:
-  PmpColumnReader();
-  virtual ~PmpColumnReader();
-
-  // Returns true if read successfully.
-  // |rows_read| is undefined if returns false.
-  bool Init(const base::FilePath& filepath, const PmpFieldType expected_type,
-            uint32* rows_read);
-
-  // These functions read the value of that |row| into |result|.
-  // Functions return false if the column is of the wrong type or the row
-  // is out of range.
-  bool ReadString(const uint32 row, std::string* result) const;
-  bool ReadUInt32(const uint32 row, uint32* result) const;
-  bool ReadDouble64(const uint32 row, double* result) const;
-  bool ReadUInt8(const uint32 row, uint8* result) const;
-  bool ReadUInt64(const uint32 row, uint64* result) const;
-
- private:
-  bool ParseData(const PmpFieldType expected_type, uint32* rows_read);
-  // Returns the number of bytes parsed in the body, or, -1 on failure.
-  int64 IndexStrings();
-
-  // Source data
-  scoped_ptr<uint8[]> data_;
-  int64 length_;
-
-  // Header data
-  PmpFieldType field_type_;
-  uint32 rows_;
-
-  // Index of string start locations if fields are strings. Empty otherwise.
-  std::vector<const char*> strings_;
-
-  DISALLOW_COPY_AND_ASSIGN(PmpColumnReader);
-};
-
-}  // namespace picasa
-
-#endif  // CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_PICASA_PMP_COLUMN_READER_H_
diff --git a/chrome/browser/media_galleries/fileapi/picasa/pmp_column_reader_unittest.cc b/chrome/browser/media_galleries/fileapi/picasa/pmp_column_reader_unittest.cc
deleted file mode 100644
index 1873d16..0000000
--- a/chrome/browser/media_galleries/fileapi/picasa/pmp_column_reader_unittest.cc
+++ /dev/null
@@ -1,202 +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 <algorithm>
-#include <vector>
-
-#include "chrome/browser/media_galleries/fileapi/picasa/pmp_column_reader.h"
-#include "chrome/browser/media_galleries/fileapi/picasa/pmp_constants.h"
-#include "chrome/browser/media_galleries/fileapi/picasa/pmp_test_helper.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace {
-
-using picasa::PmpColumnReader;
-using picasa::PmpTestHelper;
-
-// Overridden version of Read method to make test code templatable.
-bool DoRead(const PmpColumnReader* reader, uint32 row, std::string* target) {
-  return reader->ReadString(row, target);
-}
-
-bool DoRead(const PmpColumnReader* reader, uint32 row, uint32* target) {
-  return reader->ReadUInt32(row, target);
-}
-
-bool DoRead(const PmpColumnReader* reader, uint32 row, double* target) {
-  return reader->ReadDouble64(row, target);
-}
-
-bool DoRead(const PmpColumnReader* reader, uint32 row, uint8* target) {
-  return reader->ReadUInt8(row, target);
-}
-
-bool DoRead(const PmpColumnReader* reader, uint32 row, uint64* target) {
-  return reader->ReadUInt64(row, target);
-}
-
-// TestValid
-template<class T>
-void TestValid(const picasa::PmpFieldType field_type,
-               const std::vector<T>& elems) {
-  PmpTestHelper test_helper("test");
-  ASSERT_TRUE(test_helper.Init());
-
-  PmpColumnReader reader;
-
-  uint32 rows_read = 0xFF;
-
-  std::vector<uint8> data =
-      PmpTestHelper::MakeHeaderAndBody(field_type, elems.size(), elems);
-  ASSERT_TRUE(test_helper.InitColumnReaderFromBytes(
-      &reader, data, field_type, &rows_read));
-  EXPECT_EQ(elems.size(), rows_read);
-
-  for (uint32 i = 0; i < elems.size() && i < rows_read; i++) {
-    T target;
-    EXPECT_TRUE(DoRead(&reader, i, &target));
-    EXPECT_EQ(elems[i], target);
-  }
-}
-
-template<class T>
-void TestMalformed(const picasa::PmpFieldType field_type,
-                   const std::vector<T>& elems) {
-  PmpTestHelper test_helper("test");
-  ASSERT_TRUE(test_helper.Init());
-
-  PmpColumnReader reader_too_few_declared_rows;
-  std::vector<uint8> data_too_few_declared_rows =
-      PmpTestHelper::MakeHeaderAndBody(field_type, elems.size()-1, elems);
-  EXPECT_FALSE(test_helper.InitColumnReaderFromBytes(
-      &reader_too_few_declared_rows,
-      data_too_few_declared_rows,
-      field_type,
-      NULL));
-
-  PmpColumnReader reader_too_many_declared_rows;
-  std::vector<uint8> data_too_many_declared_rows =
-      PmpTestHelper::MakeHeaderAndBody(field_type, elems.size()+1, elems);
-  EXPECT_FALSE(test_helper.InitColumnReaderFromBytes(
-      &reader_too_many_declared_rows,
-      data_too_many_declared_rows,
-      field_type,
-      NULL));
-
-  PmpColumnReader reader_truncated;
-  std::vector<uint8> data_truncated =
-      PmpTestHelper::MakeHeaderAndBody(field_type, elems.size(), elems);
-  data_truncated.resize(data_truncated.size()-10);
-  EXPECT_FALSE(test_helper.InitColumnReaderFromBytes(
-      &reader_truncated, data_truncated, field_type, NULL));
-
-  PmpColumnReader reader_padded;
-  std::vector<uint8> data_padded =
-      PmpTestHelper::MakeHeaderAndBody(field_type, elems.size(), elems);
-  data_padded.resize(data_padded.size()+10);
-  EXPECT_FALSE(test_helper.InitColumnReaderFromBytes(
-      &reader_padded, data_padded, field_type, NULL));
-}
-
-template<class T>
-void TestPrimitive(const picasa::PmpFieldType field_type) {
-  // Make an ascending vector of the primitive.
-  uint32 n = 100;
-  std::vector<T> data(n, 0);
-  for (uint32 i = 0; i < n; i++) {
-    data[i] = i*3;
-  }
-
-  TestValid<T>(field_type, data);
-  TestMalformed<T>(field_type, data);
-}
-
-
-TEST(PmpColumnReaderTest, HeaderParsingAndValidation) {
-  PmpTestHelper test_helper("test");
-  ASSERT_TRUE(test_helper.Init());
-
-  PmpColumnReader reader_good_header;
-  uint32 rows_read = 0xFF;
-  std::vector<uint8> good_header =
-      PmpTestHelper::MakeHeader(picasa::PMP_TYPE_STRING, 0);
-  EXPECT_TRUE(test_helper.InitColumnReaderFromBytes(
-      &reader_good_header,
-      good_header,
-      picasa::PMP_TYPE_STRING,
-      &rows_read));
-  EXPECT_EQ(0U, rows_read) << "Read non-zero rows from header-only data.";
-
-  PmpColumnReader reader_bad_magic_bytes;
-  std::vector<uint8> bad_magic_bytes =
-      PmpTestHelper::MakeHeader(picasa::PMP_TYPE_STRING, 0);
-  bad_magic_bytes[0] = 0xff;
-  EXPECT_FALSE(test_helper.InitColumnReaderFromBytes(
-      &reader_bad_magic_bytes,
-      bad_magic_bytes,
-      picasa::PMP_TYPE_STRING,
-      NULL));
-
-  PmpColumnReader reader_inconsistent_types;
-  std::vector<uint8> inconsistent_type =
-      PmpTestHelper::MakeHeader(picasa::PMP_TYPE_STRING, 0);
-  inconsistent_type[picasa::kPmpFieldType1Offset] = 0xff;
-  EXPECT_FALSE(test_helper.InitColumnReaderFromBytes(
-      &reader_inconsistent_types,
-      inconsistent_type,
-      picasa::PMP_TYPE_STRING,
-      NULL));
-
-  PmpColumnReader reader_invalid_type;
-  std::vector<uint8> invalid_type =
-      PmpTestHelper::MakeHeader(picasa::PMP_TYPE_STRING, 0);
-  invalid_type[picasa::kPmpFieldType1Offset] = 0xff;
-  invalid_type[picasa::kPmpFieldType2Offset] = 0xff;
-  EXPECT_FALSE(test_helper.InitColumnReaderFromBytes(
-      &reader_invalid_type,
-      invalid_type,
-      picasa::PMP_TYPE_STRING,
-      NULL));
-
-  PmpColumnReader reader_incomplete_header;
-  std::vector<uint8> incomplete_header =
-      PmpTestHelper::MakeHeader(picasa::PMP_TYPE_STRING, 0);
-  incomplete_header.resize(10);
-  EXPECT_FALSE(test_helper.InitColumnReaderFromBytes(
-      &reader_incomplete_header,
-      incomplete_header,
-      picasa::PMP_TYPE_STRING,
-      NULL));
-}
-
-TEST(PmpColumnReaderTest, StringParsing) {
-  std::vector<std::string> empty_strings(100, "");
-
-  // Test empty strings read okay.
-  TestValid(picasa::PMP_TYPE_STRING, empty_strings);
-
-  std::vector<std::string> mixed_strings;
-  mixed_strings.push_back("");
-  mixed_strings.push_back("Hello");
-  mixed_strings.push_back("World");
-  mixed_strings.push_back("");
-  mixed_strings.push_back("123123");
-  mixed_strings.push_back("Q");
-  mixed_strings.push_back("");
-
-  // Test that a mixed set of strings read correctly.
-  TestValid(picasa::PMP_TYPE_STRING, mixed_strings);
-
-  // Test with the data messed up in a variety of ways.
-  TestMalformed(picasa::PMP_TYPE_STRING, mixed_strings);
-}
-
-TEST(PmpColumnReaderTest, PrimitiveParsing) {
-  TestPrimitive<uint32>(picasa::PMP_TYPE_UINT32);
-  TestPrimitive<double>(picasa::PMP_TYPE_DOUBLE64);
-  TestPrimitive<uint8>(picasa::PMP_TYPE_UINT8);
-  TestPrimitive<uint64>(picasa::PMP_TYPE_UINT64);
-}
-
-}  // namespace
diff --git a/chrome/browser/media_galleries/fileapi/picasa/pmp_constants.h b/chrome/browser/media_galleries/fileapi/picasa/pmp_constants.h
deleted file mode 100644
index 49ea36c..0000000
--- a/chrome/browser/media_galleries/fileapi/picasa/pmp_constants.h
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_PICASA_PMP_CONSTANTS_H_
-#define CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_PICASA_PMP_CONSTANTS_H_
-
-#include <string>
-
-#include "base/basictypes.h"
-
-namespace picasa {
-
-// PMP file format.
-// Info derived from: http://sbktech.blogspot.com/2011/12/picasa-pmp-format.html
-
-const char* const kPmpExtension = "pmp";
-
-const int64 kPmpHeaderSize = 20;
-
-const int kPmpMagic1Offset = 0;
-const int kPmpMagic2Offset = 6;
-const int kPmpMagic3Offset = 8;
-const int kPmpMagic4Offset = 14;
-
-const uint32 kPmpMagic1 = 0x3fcccccd;
-const uint16 kPmpMagic2 = 0x1332;
-const uint32 kPmpMagic3 = 0x00000002;
-const uint16 kPmpMagic4 = 0x1332;
-
-const int kPmpFieldType1Offset = 4;
-const int kPmpFieldType2Offset = 12;
-const int kPmpRowCountOffset   = 16;
-
-enum PmpFieldType {
-  PMP_TYPE_STRING   = 0x00,
-  PMP_TYPE_UINT32   = 0x01,
-  PMP_TYPE_DOUBLE64 = 0x02,
-  PMP_TYPE_UINT8    = 0x03,
-  PMP_TYPE_UINT64   = 0x04,
-  PMP_TYPE_INVALID  = 0xff
-};
-
-}  // namespace picasa
-
-#endif  // CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_PICASA_PMP_CONSTANTS_H_
diff --git a/chrome/browser/media_galleries/fileapi/picasa/pmp_table_reader.cc b/chrome/browser/media_galleries/fileapi/picasa/pmp_table_reader.cc
deleted file mode 100644
index cf0b4fd..0000000
--- a/chrome/browser/media_galleries/fileapi/picasa/pmp_table_reader.cc
+++ /dev/null
@@ -1,78 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/media_galleries/fileapi/picasa/pmp_table_reader.h"
-
-#include <algorithm>
-
-#include "base/file_util.h"
-#include "base/logging.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/threading/thread_restrictions.h"
-#include "chrome/browser/media_galleries/fileapi/picasa/pmp_column_reader.h"
-
-namespace picasa {
-
-namespace {
-
-COMPILE_ASSERT(sizeof(double) == 8, double_must_be_8_bytes_long);
-
-}  // namespace
-
-PmpTableReader::PmpTableReader(const std::string& table_name,
-                               const base::FilePath& directory_path)
-    : initialized_(false),
-      table_name_(table_name),
-      directory_path_(directory_path),
-      max_row_count_(0) {
-  base::ThreadRestrictions::AssertIOAllowed();
-
-  if (!file_util::DirectoryExists(directory_path_))
-    return;
-
-  std::string indicator_file_name = table_name_ + "_0";
-
-  base::FilePath indicator_file = directory_path_.Append(
-      base::FilePath::FromUTF8Unsafe(indicator_file_name));
-
-  // Look for the indicator_file file, indicating table existence.
-  initialized_ = file_util::PathExists(indicator_file) &&
-                 !file_util::DirectoryExists(indicator_file);
-}
-
-PmpTableReader::~PmpTableReader() {}
-
-const PmpColumnReader* PmpTableReader::AddColumn(
-    const std::string& column_name, const PmpFieldType expected_type) {
-  if (!initialized_)
-    return NULL;
-
-  std::string filename = table_name_ + "_" + column_name + "." + kPmpExtension;
-
-  base::FilePath column_file_path = directory_path_.Append(
-        base::FilePath::FromUTF8Unsafe(filename));
-  scoped_ptr<PmpColumnReader> column_reader(new PmpColumnReader());
-
-  uint32 row_count;
-  if (!column_reader->Init(column_file_path, expected_type, &row_count))
-    return NULL;
-
-  column_readers_.push_back(column_reader.release());
-  column_map_[column_name] = column_readers_.back();
-
-  max_row_count_ = std::max(max_row_count_, row_count);
-
-  return column_readers_.back();
-}
-
-uint32 PmpTableReader::RowCount() const {
-  return max_row_count_;
-}
-
-std::map<std::string, const PmpColumnReader*> PmpTableReader::Columns() const {
-  return column_map_;
-}
-
-}  // namespace picasa
diff --git a/chrome/browser/media_galleries/fileapi/picasa/pmp_table_reader.h b/chrome/browser/media_galleries/fileapi/picasa/pmp_table_reader.h
deleted file mode 100644
index 8374a95..0000000
--- a/chrome/browser/media_galleries/fileapi/picasa/pmp_table_reader.h
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_PICASA_PMP_TABLE_READER_H_
-#define CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_PICASA_PMP_TABLE_READER_H_
-
-#include <map>
-#include <string>
-
-#include "base/basictypes.h"
-#include "base/files/file_path.h"
-#include "base/memory/scoped_vector.h"
-#include "chrome/browser/media_galleries/fileapi/picasa/pmp_constants.h"
-
-namespace base {
-class FilePath;
-}
-
-namespace picasa {
-
-class PmpColumnReader;
-
-class PmpTableReader {
- public:
-  PmpTableReader(const std::string& table_name,
-                 const base::FilePath& directory_path);
-
-  virtual ~PmpTableReader();
-
-  // Returns NULL on failure.
-  const PmpColumnReader* AddColumn(const std::string& column_name,
-                                   const PmpFieldType expected_type);
-
-  // Returns a const "view" of the successfully added columns.
-  std::map<std::string, const PmpColumnReader*> Columns() const;
-
-  // This value may change after calls to AddColumn().
-  uint32 RowCount() const;
-
- private:
-  bool initialized_;
-
-  std::string table_name_;
-  base::FilePath directory_path_;
-
-  ScopedVector<PmpColumnReader> column_readers_;
-  std::map<std::string, const PmpColumnReader*> column_map_;
-
-  uint32 max_row_count_;
-
-  DISALLOW_COPY_AND_ASSIGN(PmpTableReader);
-};
-
-}  // namespace picasa
-
-#endif  // CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_PICASA_PMP_TABLE_READER_H_
diff --git a/chrome/browser/media_galleries/fileapi/picasa/pmp_table_reader_unittest.cc b/chrome/browser/media_galleries/fileapi/picasa/pmp_table_reader_unittest.cc
deleted file mode 100644
index 91df98b..0000000
--- a/chrome/browser/media_galleries/fileapi/picasa/pmp_table_reader_unittest.cc
+++ /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.
-
-#include <algorithm>
-#include <vector>
-
-#include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/media_galleries/fileapi/picasa/pmp_column_reader.h"
-#include "chrome/browser/media_galleries/fileapi/picasa/pmp_constants.h"
-#include "chrome/browser/media_galleries/fileapi/picasa/pmp_table_reader.h"
-#include "chrome/browser/media_galleries/fileapi/picasa/pmp_test_helper.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace {
-
-using picasa::PmpTestHelper;
-
-TEST(PmpTableReaderTest, RowCountAndFieldType) {
-  std::string table_name("tabletest");
-  PmpTestHelper test_helper(table_name);
-  ASSERT_TRUE(test_helper.Init());
-
-  std::vector<std::string> column_names;
-  column_names.push_back("strings");
-  column_names.push_back("uint32s");
-  column_names.push_back("doubles");
-
-  const std::vector<std::string> strings_vector(10, "Hello");
-  const std::vector<uint32> uint32s_vector(30, 42);
-  const std::vector<double> doubles_vector(20, 0.5);
-
-  picasa::PmpFieldType column_field_types[] = {
-    picasa::PMP_TYPE_STRING,
-    picasa::PMP_TYPE_UINT32,
-    picasa::PMP_TYPE_DOUBLE64
-  };
-
-  const uint32 max_rows = uint32s_vector.size();
-
-  // Write three column files, one each for strings, uint32s, and doubles.
-
-  ASSERT_TRUE(test_helper.WriteColumnFileFromVector(
-      column_names[0], column_field_types[0], strings_vector));
-  ASSERT_TRUE(test_helper.WriteColumnFileFromVector(
-      column_names[1], column_field_types[1], uint32s_vector));
-  ASSERT_TRUE(test_helper.WriteColumnFileFromVector(
-      column_names[2], column_field_types[2], doubles_vector));
-
-  picasa::PmpTableReader table_reader(table_name,
-                                            test_helper.GetTempDirPath());
-
-  for (unsigned int i = 0; i < column_names.size(); i++) {
-    ASSERT_TRUE(
-        table_reader.AddColumn(column_names[i], column_field_types[i]) != NULL);
-  }
-
-  EXPECT_EQ(max_rows, table_reader.RowCount());
-}
-
-}  // namespace
diff --git a/chrome/browser/media_galleries/fileapi/picasa/pmp_test_helper.cc b/chrome/browser/media_galleries/fileapi/picasa/pmp_test_helper.cc
deleted file mode 100644
index b2c28c7..0000000
--- a/chrome/browser/media_galleries/fileapi/picasa/pmp_test_helper.cc
+++ /dev/null
@@ -1,182 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/media_galleries/fileapi/picasa/pmp_test_helper.h"
-
-#include <algorithm>
-#include <iterator>
-
-#include "base/file_util.h"
-#include "base/logging.h"
-#include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/media_galleries/fileapi/picasa/pmp_column_reader.h"
-
-namespace picasa {
-
-namespace {
-
-bool WriteToFile(const base::FilePath& path, std::vector<uint8> data) {
-  // Cast for usage in WriteFile function
-  const char* data_char = reinterpret_cast<const char*>(&data[0]);
-  size_t bytes_written = file_util::WriteFile(path, data_char, data.size());
-  return (bytes_written == data.size());
-}
-
-// Flatten a vector of elements into an array of bytes.
-template<class T>
-std::vector<uint8> Flatten(const std::vector<T>& elems) {
-  if (elems.empty())
-    return std::vector<uint8>();
-
-  const uint8* elems0 = reinterpret_cast<const uint8*>(&elems[0]);
-  std::vector<uint8> data_body(elems0, elems0 + sizeof(T) * elems.size());
-
-  return data_body;
-}
-
-// Custom specialization for std::string.
-template<>
-std::vector<uint8> Flatten(const std::vector<std::string>& strings) {
-  std::vector<uint8> totalchars;
-
-  for (std::vector<std::string>::const_iterator it = strings.begin();
-      it != strings.end(); ++it) {
-    std::copy(it->begin(), it->end(), std::back_inserter(totalchars));
-    totalchars.push_back('\0');  // Add the null termination too.
-  }
-
-  return totalchars;
-}
-
-// Returns a new vector with the concatenated contents of |a| and |b|.
-std::vector<uint8> CombinedVectors(const std::vector<uint8>& a,
-                                   const std::vector<uint8>& b) {
-  std::vector<uint8> total;
-
-  std::copy(a.begin(), a.end(), std::back_inserter(total));
-  std::copy(b.begin(), b.end(), std::back_inserter(total));
-
-  return total;
-}
-
-}  // namespace
-
-PmpTestHelper::PmpTestHelper(const std::string& table_name)
-    : table_name_(table_name) {
-}
-
-bool PmpTestHelper::Init() {
-  if (!temp_dir_.CreateUniqueTempDir() || !temp_dir_.IsValid())
-    return false;
-
-  base::FilePath indicator_path = temp_dir_.path().Append(
-      base::FilePath::FromUTF8Unsafe(table_name_ + "_0"));
-
-  return file_util::WriteFile(indicator_path, NULL, 0) == 0;
-}
-
-base::FilePath PmpTestHelper::GetTempDirPath() {
-  DCHECK(temp_dir_.IsValid());
-  return temp_dir_.path();
-}
-
-template<class T>
-bool PmpTestHelper::WriteColumnFileFromVector(
-    const std::string& column_name, const PmpFieldType field_type,
-    const std::vector<T>& elements_vector) {
-  DCHECK(temp_dir_.IsValid());
-
-  std::string file_name = table_name_ + "_" + column_name + "." + kPmpExtension;
-
-  base::FilePath path = temp_dir_.path().Append(
-      base::FilePath::FromUTF8Unsafe(file_name));
-
-  std::vector<uint8> data = PmpTestHelper::MakeHeaderAndBody(
-      field_type, elements_vector.size(), elements_vector);
-
-  return WriteToFile(path, data);
-}
-
-// Explicit Instantiation for all the valid types.
-template bool PmpTestHelper::WriteColumnFileFromVector<std::string>(
-    const std::string&, const PmpFieldType, const std::vector<std::string>&);
-template bool PmpTestHelper::WriteColumnFileFromVector<uint32>(
-    const std::string&, const PmpFieldType, const std::vector<uint32>&);
-template bool PmpTestHelper::WriteColumnFileFromVector<double>(
-    const std::string&, const PmpFieldType, const std::vector<double>&);
-template bool PmpTestHelper::WriteColumnFileFromVector<uint8>(
-    const std::string&, const PmpFieldType, const std::vector<uint8>&);
-template bool PmpTestHelper::WriteColumnFileFromVector<uint64>(
-    const std::string&, const PmpFieldType, const std::vector<uint64>&);
-
-bool PmpTestHelper::InitColumnReaderFromBytes(PmpColumnReader* const reader,
-                                              const std::vector<uint8>& data,
-                                              const PmpFieldType expected_type,
-                                              uint32* rows_read) {
-  DCHECK(temp_dir_.IsValid());
-
-  base::FilePath temp_path;
-
-  if (!file_util::CreateTemporaryFileInDir(temp_dir_.path(), &temp_path)
-      || !WriteToFile(temp_path, data)) {
-    return false;
-  }
-
-  bool success = reader->Init(temp_path, expected_type, rows_read);
-
-  file_util::Delete(temp_path, true);
-
-  return success;
-
-}
-
-// Return a vector so we don't have to worry about memory management.
-std::vector<uint8> PmpTestHelper::MakeHeader(const PmpFieldType field_type,
-                                             const uint32 row_count) {
-  std::vector<uint8> header(picasa::kPmpHeaderSize);
-
-  // Copy in magic bytes.
-  memcpy(&header[picasa::kPmpMagic1Offset], &picasa::kPmpMagic1,
-         sizeof(picasa::kPmpMagic1));
-  memcpy(&header[picasa::kPmpMagic2Offset], &picasa::kPmpMagic2,
-         sizeof(picasa::kPmpMagic2));
-  memcpy(&header[picasa::kPmpMagic3Offset], &picasa::kPmpMagic3,
-         sizeof(picasa::kPmpMagic3));
-  memcpy(&header[picasa::kPmpMagic4Offset], &picasa::kPmpMagic4,
-         sizeof(picasa::kPmpMagic4));
-
-  // Copy in field type.
-  uint16 field_type_short = static_cast<uint16>(field_type);
-  memcpy(&header[picasa::kPmpFieldType1Offset], &field_type_short,
-         sizeof(uint16));
-  memcpy(&header[picasa::kPmpFieldType2Offset], &field_type_short,
-         sizeof(uint16));
-
-  // Copy in row count.
-  memcpy(&header[picasa::kPmpRowCountOffset], &row_count, sizeof(uint32));
-
-  return header;
-}
-
-template<class T>
-std::vector<uint8> PmpTestHelper::MakeHeaderAndBody(
-    const PmpFieldType field_type, const uint32 row_count,
-    const std::vector<T>& elems) {
-  return CombinedVectors(PmpTestHelper::MakeHeader(field_type, row_count),
-                         Flatten(elems));
-}
-
-// Explicit Instantiation for all the valid types.
-template std::vector<uint8> PmpTestHelper::MakeHeaderAndBody<std::string>(
-    const PmpFieldType, const uint32, const std::vector<std::string>&);
-template std::vector<uint8> PmpTestHelper::MakeHeaderAndBody<uint32>(
-    const PmpFieldType, const uint32, const std::vector<uint32>&);
-template std::vector<uint8> PmpTestHelper::MakeHeaderAndBody<double>(
-    const PmpFieldType, const uint32, const std::vector<double>&);
-template std::vector<uint8> PmpTestHelper::MakeHeaderAndBody<uint8>(
-    const PmpFieldType, const uint32, const std::vector<uint8>&);
-template std::vector<uint8> PmpTestHelper::MakeHeaderAndBody<uint64>(
-    const PmpFieldType, const uint32, const std::vector<uint64>&);
-
-}  // namespace picasa
diff --git a/chrome/browser/media_galleries/fileapi/picasa/pmp_test_helper.h b/chrome/browser/media_galleries/fileapi/picasa/pmp_test_helper.h
deleted file mode 100644
index a20ac33..0000000
--- a/chrome/browser/media_galleries/fileapi/picasa/pmp_test_helper.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 CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_PICASA_PMP_TEST_HELPER_H_
-#define CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_PICASA_PMP_TEST_HELPER_H_
-
-#include <vector>
-
-#include "base/basictypes.h"
-#include "base/files/scoped_temp_dir.h"
-#include "chrome/browser/media_galleries/fileapi/picasa/pmp_constants.h"
-
-namespace base {
-class FilePath;
-}  // namespace base
-
-namespace picasa {
-
-class PmpColumnReader;
-
-// A helper class used for unit tests only
-class PmpTestHelper {
- public:
-  explicit PmpTestHelper(const std::string& table_name);
-
-  bool Init();
-
-  base::FilePath GetTempDirPath();
-
-  template<class T>
-  bool WriteColumnFileFromVector(const std::string& column_name,
-                                 const PmpFieldType field_type,
-                                 const std::vector<T>& elements_vector);
-
-  bool InitColumnReaderFromBytes(PmpColumnReader* const reader,
-                                 const std::vector<uint8>& data,
-                                 const PmpFieldType expected_type,
-                                 uint32* rows_read);
-
-  static std::vector<uint8> MakeHeader(const PmpFieldType field_type,
-                                       const uint32 row_count);
-
-  template<class T>
-  static std::vector<uint8> MakeHeaderAndBody(const PmpFieldType field_type,
-                                              const uint32 row_count,
-                                              const std::vector<T>& elems);
-
- private:
-  std::string table_name_;
-  base::ScopedTempDir temp_dir_;
-};
-
-}  // namespace picasa
-
-#endif  // CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_PICASA_PMP_TEST_HELPER_H_
diff --git a/chrome/browser/media_galleries/fileapi/safe_itunes_library_parser.cc b/chrome/browser/media_galleries/fileapi/safe_itunes_library_parser.cc
new file mode 100644
index 0000000..1935336
--- /dev/null
+++ b/chrome/browser/media_galleries/fileapi/safe_itunes_library_parser.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 "chrome/browser/media_galleries/fileapi/safe_itunes_library_parser.h"
+
+#include "chrome/browser/media_galleries/fileapi/media_file_system_mount_point_provider.h"
+#include "chrome/common/chrome_utility_messages.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/child_process_data.h"
+#include "ipc/ipc_platform_file.h"
+
+using chrome::MediaFileSystemMountPointProvider;
+using content::BrowserThread;
+using content::UtilityProcessHost;
+
+namespace itunes {
+
+SafeITunesLibraryParser::SafeITunesLibraryParser(
+    const base::FilePath& itunes_library_file,
+    const ParserCallback& callback)
+    : itunes_library_file_(itunes_library_file),
+      callback_(callback),
+      parser_state_(INITIAL_STATE) {}
+
+void SafeITunesLibraryParser::Start() {
+  DCHECK(MediaFileSystemMountPointProvider::CurrentlyOnMediaTaskRunnerThread());
+
+  // |itunes_library_platform_file_| will be closed on the IO thread once it
+  // has been handed off to the child process.
+  itunes_library_platform_file_ = base::CreatePlatformFile(
+      itunes_library_file_,
+      base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ,
+      NULL,   // created
+      NULL);  // error_code
+  if (itunes_library_platform_file_ == base::kInvalidPlatformFileValue) {
+    VLOG(1) << "Could not open iTunes library XML file: "
+            << itunes_library_file_.value();
+    callback_.Run(false /* failed */, parser::Library());
+    BrowserThread::PostTask(
+        BrowserThread::IO, FROM_HERE,
+        base::Bind(&SafeITunesLibraryParser::OnOpenLibraryFileFailed, this));
+    return;
+  }
+
+  BrowserThread::PostTask(
+      BrowserThread::IO, FROM_HERE,
+      base::Bind(&SafeITunesLibraryParser::StartProcessOnIOThread, this));
+}
+
+SafeITunesLibraryParser::~SafeITunesLibraryParser() {}
+
+void SafeITunesLibraryParser::StartProcessOnIOThread() {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+  DCHECK_EQ(INITIAL_STATE, parser_state_);
+
+  scoped_refptr<base::MessageLoopProxy> message_loop_proxy =
+      BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO);
+  utility_process_host_ =
+      UtilityProcessHost::Create(this, message_loop_proxy.get())->AsWeakPtr();
+  // Wait for the startup notification before sending the main IPC to the
+  // utility process, so that we can dup the file handle.
+  utility_process_host_->Send(new ChromeUtilityMsg_StartupPing);
+  parser_state_ = PINGED_UTILITY_PROCESS_STATE;
+}
+
+void SafeITunesLibraryParser::OnUtilityProcessStarted() {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+  if (parser_state_ != PINGED_UTILITY_PROCESS_STATE)
+    return;
+
+  if (utility_process_host_->GetData().handle == base::kNullProcessHandle)
+    DLOG(ERROR) << "Child process handle is null";
+  utility_process_host_->Send(
+      new ChromeUtilityMsg_ParseITunesLibraryXmlFile(
+          IPC::GetFileHandleForProcess(
+              itunes_library_platform_file_,
+              utility_process_host_->GetData().handle,
+              true /* close_source_handle */)));
+  parser_state_ = STARTED_PARSING_STATE;
+}
+
+void SafeITunesLibraryParser::OnGotITunesLibrary(
+    bool result, const parser::Library& library) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+
+  if (parser_state_ != STARTED_PARSING_STATE)
+    return;
+
+  MediaFileSystemMountPointProvider::MediaTaskRunner()->PostTask(
+      FROM_HERE,
+      base::Bind(callback_, result, library));
+  parser_state_ = FINISHED_PARSING_STATE;
+}
+
+void SafeITunesLibraryParser::OnOpenLibraryFileFailed() {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+  parser_state_ = FINISHED_PARSING_STATE;
+}
+
+void SafeITunesLibraryParser::OnProcessCrashed(int exit_code) {
+  OnGotITunesLibrary(false /* failed */, parser::Library());
+}
+
+bool SafeITunesLibraryParser::OnMessageReceived(
+    const IPC::Message& message) {
+  bool handled = true;
+  IPC_BEGIN_MESSAGE_MAP(SafeITunesLibraryParser, message)
+    IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_ProcessStarted,
+                        OnUtilityProcessStarted)
+    IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_GotITunesLibrary,
+                        OnGotITunesLibrary)
+    IPC_MESSAGE_UNHANDLED(handled = false)
+  IPC_END_MESSAGE_MAP()
+  return handled;
+}
+
+}  // namespace itunes
diff --git a/chrome/browser/media_galleries/fileapi/safe_itunes_library_parser.h b/chrome/browser/media_galleries/fileapi/safe_itunes_library_parser.h
new file mode 100644
index 0000000..26e2e59
--- /dev/null
+++ b/chrome/browser/media_galleries/fileapi/safe_itunes_library_parser.h
@@ -0,0 +1,98 @@
+// 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_SAFE_ITUNES_LIBRARY_PARSER_H_
+#define CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_SAFE_ITUNES_LIBRARY_PARSER_H_
+
+#include <string>
+
+#include "base/callback.h"
+#include "base/compiler_specific.h"
+#include "base/files/file_path.h"
+#include "base/memory/weak_ptr.h"
+#include "base/platform_file.h"
+#include "chrome/common/itunes_library.h"
+#include "content/public/browser/utility_process_host.h"
+#include "content/public/browser/utility_process_host_client.h"
+
+namespace IPC {
+class Message;
+}
+
+namespace itunes {
+
+// SafeITunesLibraryParser parses the given iTunes library XML file safely via
+// a utility process. The SafeITunesLibraryParser object is ref-counted and
+// kept alive after Start() is called until the ParserCallback is called.
+// The ParserCallback is guaranteed to be called eventually either when the
+// utility process replies or when it dies.
+// Since iTunes library XML files can be big, SafeITunesLibraryParser passes
+// the file handle to the utility process.
+// SafeITunesLibraryParser lives on the Media Task Runner unless otherwise
+// noted.
+class SafeITunesLibraryParser : public content::UtilityProcessHostClient {
+ public:
+  typedef base::Callback<void(bool, const parser::Library&)> ParserCallback;
+
+  SafeITunesLibraryParser(const base::FilePath& itunes_library_file,
+                          const ParserCallback& callback);
+
+  // Posts a task to start the XML parsing in the utility process.
+  void Start();
+
+ private:
+  enum ParserState {
+    INITIAL_STATE,
+    PINGED_UTILITY_PROCESS_STATE,
+    STARTED_PARSING_STATE,
+    FINISHED_PARSING_STATE,
+  };
+
+  // content::UtilityProcessHostClient is ref-counted.
+  virtual ~SafeITunesLibraryParser();
+
+  // Launches the utility process.  Must run on the IO thread.
+  void StartProcessOnIOThread();
+
+  // Notification that the utility process is running, and we can now get its
+  // process handle.
+  // Runs on the IO thread.
+  void OnUtilityProcessStarted();
+
+  // Notification from the utility process when it finishes parsing the XML.
+  // Runs on the IO thread.
+  void OnGotITunesLibrary(bool result, const parser::Library& library);
+
+  // Sets |parser_state_| in case the library XML file cannot be opened.
+  // Runs on the IO thread.
+  void OnOpenLibraryFileFailed();
+
+  // UtilityProcessHostClient implementation.
+  // Runs on the IO thread.
+  virtual void OnProcessCrashed(int exit_code) OVERRIDE;
+  virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
+
+  const base::FilePath itunes_library_file_;
+
+  // Once we have opened the file, we store the handle so that we can use it
+  // once the utility process has launched.
+  base::PlatformFile itunes_library_platform_file_;
+
+  // Only accessed on the IO thread.
+  base::WeakPtr<content::UtilityProcessHost> utility_process_host_;
+
+  // Only accessed on the Media Task Runner.
+  const ParserCallback callback_;
+
+  // Verifies the messages from the utility process came at the right time.
+  // Initialized on the Media Task Runner, but only accessed on the IO thread.
+  ParserState parser_state_;
+
+
+  DISALLOW_COPY_AND_ASSIGN(SafeITunesLibraryParser);
+};
+
+}  // namespace itunes
+
+#endif  // CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_SAFE_ITUNES_LIBRARY_PARSER_H_
diff --git a/chrome/browser/media_galleries/fileapi/safe_itunes_pref_parser_win.cc b/chrome/browser/media_galleries/fileapi/safe_itunes_pref_parser_win.cc
new file mode 100644
index 0000000..a22a0eb
--- /dev/null
+++ b/chrome/browser/media_galleries/fileapi/safe_itunes_pref_parser_win.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 "chrome/browser/media_galleries/fileapi/safe_itunes_pref_parser_win.h"
+
+#include "chrome/common/chrome_utility_messages.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/utility_process_host.h"
+
+using content::BrowserThread;
+using content::UtilityProcessHost;
+
+namespace itunes {
+
+SafeITunesPrefParserWin::SafeITunesPrefParserWin(
+    const std::string& unsafe_xml,
+    const ParserCallback& callback)
+    : unsafe_xml_(unsafe_xml),
+      callback_(callback),
+      parser_state_(INITIAL_STATE) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+  DCHECK(!callback_.is_null());
+}
+
+void SafeITunesPrefParserWin::Start() {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+  BrowserThread::PostTask(
+      BrowserThread::IO,
+      FROM_HERE,
+      base::Bind(&SafeITunesPrefParserWin::StartWorkOnIOThread, this));
+}
+
+SafeITunesPrefParserWin::~SafeITunesPrefParserWin() {
+}
+
+void SafeITunesPrefParserWin::StartWorkOnIOThread() {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+  DCHECK_EQ(INITIAL_STATE, parser_state_);
+
+  UtilityProcessHost* host =
+      UtilityProcessHost::Create(this, base::MessageLoopProxy::current());
+  host->EnableZygote();
+  host->Send(new ChromeUtilityMsg_ParseITunesPrefXml(unsafe_xml_));
+  parser_state_ = STARTED_PARSING_STATE;
+}
+
+void SafeITunesPrefParserWin::OnGotITunesDirectory(
+    const base::FilePath& library_file) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+
+  if (parser_state_ != STARTED_PARSING_STATE)
+    return;
+  BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
+                          base::Bind(callback_, library_file));
+  parser_state_ = FINISHED_PARSING_STATE;
+}
+
+void SafeITunesPrefParserWin::OnProcessCrashed(int exit_code) {
+  OnGotITunesDirectory(base::FilePath());
+}
+
+bool SafeITunesPrefParserWin::OnMessageReceived(
+    const IPC::Message& message) {
+  bool handled = true;
+  IPC_BEGIN_MESSAGE_MAP(SafeITunesPrefParserWin, message)
+    IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_GotITunesDirectory,
+                        OnGotITunesDirectory)
+    IPC_MESSAGE_UNHANDLED(handled = false)
+  IPC_END_MESSAGE_MAP()
+  return handled;
+}
+
+}  // namespace itunes
diff --git a/chrome/browser/media_galleries/fileapi/safe_itunes_pref_parser_win.h b/chrome/browser/media_galleries/fileapi/safe_itunes_pref_parser_win.h
new file mode 100644
index 0000000..632be61
--- /dev/null
+++ b/chrome/browser/media_galleries/fileapi/safe_itunes_pref_parser_win.h
@@ -0,0 +1,70 @@
+// 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_SAFE_ITUNES_PREF_PARSER_WIN_H_
+#define CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_SAFE_ITUNES_PREF_PARSER_WIN_H_
+
+#include <string>
+
+#include "base/callback.h"
+#include "base/compiler_specific.h"
+#include "content/public/browser/utility_process_host_client.h"
+
+namespace base {
+class FilePath;
+}
+
+namespace IPC {
+class Message;
+}
+
+namespace itunes {
+
+// SafeITunesPrefParserWin parses the given iTunes preferences XML data safely
+// via a utility process. The SafeITunesPrefParserWin object is ref-counted and
+// kept alive after Start() is called until the ParserCallback is called.
+// The ParserCallback is guaranteed to be called eventually either when the
+// utility process replies or when it dies.
+class SafeITunesPrefParserWin : public content::UtilityProcessHostClient {
+ public:
+  typedef base::Callback<void(const base::FilePath&)> ParserCallback;
+
+  SafeITunesPrefParserWin(const std::string& unsafe_xml,
+                          const ParserCallback& callback);
+
+  void Start();
+
+ private:
+  enum ParserState {
+    INITIAL_STATE,
+    STARTED_PARSING_STATE,
+    FINISHED_PARSING_STATE,
+  };
+
+  // Private because content::UtilityProcessHostClient is ref-counted.
+  virtual ~SafeITunesPrefParserWin();
+
+  void StartWorkOnIOThread();
+
+  // Handles the results from OnProcessCrashed() and OnMessageReceived() on
+  // the IO thread.
+  void OnGotITunesDirectory(const base::FilePath& library_file);
+
+  // UtilityProcessHostClient implementation.
+  virtual void OnProcessCrashed(int exit_code) OVERRIDE;
+  virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
+
+  const std::string unsafe_xml_;
+  const ParserCallback callback_;
+
+  // Verifies the messages from the utility process came at the right time.
+  // Initialized on the FILE thread, but only accessed on the IO thread.
+  ParserState parser_state_;
+
+  DISALLOW_COPY_AND_ASSIGN(SafeITunesPrefParserWin);
+};
+
+}  // namespace itunes
+
+#endif  // CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_SAFE_ITUNES_PREF_PARSER_WIN_H_
diff --git a/chrome/browser/media_galleries/imported_media_gallery_registry.cc b/chrome/browser/media_galleries/imported_media_gallery_registry.cc
index a42b959..b9f6c13 100644
--- a/chrome/browser/media_galleries/imported_media_gallery_registry.cc
+++ b/chrome/browser/media_galleries/imported_media_gallery_registry.cc
@@ -6,7 +6,6 @@
 
 #include "base/bind.h"
 #include "base/logging.h"
-#include "base/threading/sequenced_worker_pool.h"
 #include "chrome/browser/media_galleries/fileapi/itunes_data_provider.h"
 #include "chrome/browser/media_galleries/fileapi/media_file_system_mount_point_provider.h"
 #include "chrome/browser/media_galleries/fileapi/picasa/picasa_data_provider.h"
@@ -15,22 +14,12 @@
 #include "webkit/browser/fileapi/isolated_context.h"
 
 using base::Bind;
+using fileapi::IsolatedContext;
 
 namespace chrome {
 
 namespace {
 
-scoped_refptr<base::SequencedTaskRunner> MediaTaskRunner() {
-  DCHECK(
-      !MediaFileSystemMountPointProvider::CurrentlyOnMediaTaskRunnerThread());
-  base::SequencedWorkerPool* pool = content::BrowserThread::GetBlockingPool();
-  base::SequencedWorkerPool::SequenceToken media_sequence_token =
-      pool->GetNamedSequenceToken(
-          MediaFileSystemMountPointProvider::kMediaTaskRunnerName);
-
-  return pool->GetSequencedTaskRunner(media_sequence_token);
-}
-
 static base::LazyInstance<ImportedMediaGalleryRegistry>::Leaky
 g_imported_media_gallery_registry = LAZY_INSTANCE_INITIALIZER;
 
@@ -46,19 +35,21 @@
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
   DCHECK(!database_path.empty());
 
-  std::string fsid =
-      fileapi::IsolatedContext::GetInstance()->RegisterFileSystemForVirtualPath(
+  std::string fsid;
+
+#if defined(OS_WIN) || defined(OS_MACOSX)
+  fsid = IsolatedContext::GetInstance()->RegisterFileSystemForVirtualPath(
            fileapi::kFileSystemTypePicasa,
            extension_misc::kMediaFileSystemPathPart,
            base::FilePath());
 
   if (fsid.empty())
-    return "";
+    return fsid;
 
   picasa_fsids_.insert(fsid);
 
   if (picasa_fsids_.size() == 1) {
-    MediaTaskRunner()->PostTask(
+    MediaFileSystemMountPointProvider::MediaTaskRunner()->PostTask(
         FROM_HERE,
         Bind(&ImportedMediaGalleryRegistry::RegisterPicasaFileSystem,
              base::Unretained(this), database_path));
@@ -68,6 +59,7 @@
     DCHECK_EQ(picasa_database_path_.value(), database_path.value());
 #endif
   }
+#endif  // defined(OS_WIN) || defined(OS_MACOSX)
 
   return fsid;
 }
@@ -77,19 +69,21 @@
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
   DCHECK(!library_xml_path.empty());
 
-  std::string fsid =
-      fileapi::IsolatedContext::GetInstance()->RegisterFileSystemForVirtualPath(
+  std::string fsid;
+
+#if defined(OS_WIN) || defined(OS_MACOSX)
+  fsid = IsolatedContext::GetInstance()->RegisterFileSystemForVirtualPath(
            fileapi::kFileSystemTypeItunes,
            extension_misc::kMediaFileSystemPathPart,
            base::FilePath());
 
   if (fsid.empty())
-    return std::string();
+    return fsid;
 
   itunes_fsids_.insert(fsid);
 
   if (itunes_fsids_.size() == 1) {
-    MediaTaskRunner()->PostTask(
+    MediaFileSystemMountPointProvider::MediaTaskRunner()->PostTask(
         FROM_HERE,
         Bind(&ImportedMediaGalleryRegistry::RegisterITunesFileSystem,
              base::Unretained(this), library_xml_path));
@@ -99,6 +93,7 @@
     DCHECK_EQ(itunes_xml_library_path_.value(), library_xml_path.value());
 #endif
   }
+#endif  // defined(OS_WIN) || defined(OS_MACOSX)
 
   return fsid;
 }
@@ -107,29 +102,32 @@
     const std::string& fsid) {
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
 
+#if defined(OS_WIN) || defined(OS_MACOSX)
   if (picasa_fsids_.erase(fsid)) {
     if (picasa_fsids_.empty()) {
-      MediaTaskRunner()->PostTask(
+      MediaFileSystemMountPointProvider::MediaTaskRunner()->PostTask(
           FROM_HERE,
           Bind(&ImportedMediaGalleryRegistry::RevokePicasaFileSystem,
                base::Unretained(this)));
     }
-    return fileapi::IsolatedContext::GetInstance()->RevokeFileSystem(fsid);
+    return IsolatedContext::GetInstance()->RevokeFileSystem(fsid);
   }
 
   if (itunes_fsids_.erase(fsid)) {
     if (itunes_fsids_.empty()) {
-      MediaTaskRunner()->PostTask(
+      MediaFileSystemMountPointProvider::MediaTaskRunner()->PostTask(
           FROM_HERE,
           Bind(&ImportedMediaGalleryRegistry::RevokeITunesFileSystem,
                base::Unretained(this)));
     }
-    return fileapi::IsolatedContext::GetInstance()->RevokeFileSystem(fsid);
+    return IsolatedContext::GetInstance()->RevokeFileSystem(fsid);
   }
+#endif  // defined(OS_WIN) || defined(OS_MACOSX)
 
   return false;
 }
 
+#if defined(OS_WIN) || defined(OS_MACOSX)
 // static
 picasa::PicasaDataProvider*
 ImportedMediaGalleryRegistry::PicasaDataProvider() {
@@ -145,14 +143,18 @@
   DCHECK(GetInstance()->itunes_data_provider_);
   return GetInstance()->itunes_data_provider_.get();
 }
+#endif  // defined(OS_WIN) || defined(OS_MACOSX)
 
 ImportedMediaGalleryRegistry::ImportedMediaGalleryRegistry() {}
 
 ImportedMediaGalleryRegistry::~ImportedMediaGalleryRegistry() {
+#if defined(OS_WIN) || defined(OS_MACOSX)
   DCHECK_EQ(0U, picasa_fsids_.size());
   DCHECK_EQ(0U, itunes_fsids_.size());
+#endif  // defined(OS_WIN) || defined(OS_MACOSX)
 }
 
+#if defined(OS_WIN) || defined(OS_MACOSX)
 void ImportedMediaGalleryRegistry::RegisterPicasaFileSystem(
     const base::FilePath& database_path) {
   DCHECK(MediaFileSystemMountPointProvider::CurrentlyOnMediaTaskRunnerThread());
@@ -178,5 +180,6 @@
   DCHECK(itunes_data_provider_);
   itunes_data_provider_.reset();
 }
+#endif  // defined(OS_WIN) || defined(OS_MACOSX)
 
 }  // namespace chrome
diff --git a/chrome/browser/media_galleries/imported_media_gallery_registry.h b/chrome/browser/media_galleries/imported_media_gallery_registry.h
index d8f0e69..f90e7c1 100644
--- a/chrome/browser/media_galleries/imported_media_gallery_registry.h
+++ b/chrome/browser/media_galleries/imported_media_gallery_registry.h
@@ -42,8 +42,10 @@
   bool RevokeImportedFilesystemOnUIThread(const std::string& fsid);
 
   // Should be called on the MediaTaskRunner thread only.
+#if defined(OS_WIN) || defined(OS_MACOSX)
   static picasa::PicasaDataProvider* PicasaDataProvider();
   static itunes::ITunesDataProvider* ITunesDataProvider();
+#endif  // defined(OS_WIN) || defined(OS_MACOSX)
 
  private:
   friend struct base::DefaultLazyInstanceTraits<ImportedMediaGalleryRegistry>;
@@ -51,6 +53,7 @@
   ImportedMediaGalleryRegistry();
   virtual ~ImportedMediaGalleryRegistry();
 
+#if defined(OS_WIN) || defined(OS_MACOSX)
   void RegisterPicasaFileSystem(const base::FilePath& database_path);
   void RevokePicasaFileSystem();
 
@@ -69,6 +72,7 @@
   base::FilePath picasa_database_path_;
   base::FilePath itunes_xml_library_path_;
 #endif
+#endif  // defined(OS_WIN) || defined(OS_MACOSX)
 
   DISALLOW_COPY_AND_ASSIGN(ImportedMediaGalleryRegistry);
 };
diff --git a/chrome/browser/media_galleries/linux/mtp_device_object_enumerator.h b/chrome/browser/media_galleries/linux/mtp_device_object_enumerator.h
index c5d1215..31a2ce4 100644
--- a/chrome/browser/media_galleries/linux/mtp_device_object_enumerator.h
+++ b/chrome/browser/media_galleries/linux/mtp_device_object_enumerator.h
@@ -8,7 +8,7 @@
 #include <vector>
 
 #include "base/files/file_path.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "device/media_transfer_protocol/mtp_file_entry.pb.h"
 #include "webkit/browser/fileapi/file_system_file_util.h"
 
diff --git a/chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac.mm b/chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac.mm
index 7c4447f..87119f1 100644
--- a/chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac.mm
+++ b/chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac.mm
@@ -6,7 +6,7 @@
 
 #include <algorithm>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "base/threading/sequenced_worker_pool.h"
 #include "chrome/browser/media_galleries/mtp_device_delegate_impl.h"
 #include "chrome/browser/storage_monitor/image_capture_device.h"
@@ -61,7 +61,7 @@
   virtual void ResetDelegate();
 
  private:
-  scoped_nsobject<ImageCaptureDevice> camera_device_;
+  base::scoped_nsobject<ImageCaptureDevice> camera_device_;
 
   // Weak pointer
   MTPDeviceDelegateImplMac* delegate_;
diff --git a/chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac_unittest.mm b/chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac_unittest.mm
index c88493b..7e71717 100644
--- a/chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac_unittest.mm
+++ b/chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac_unittest.mm
@@ -9,7 +9,7 @@
 #include "base/files/scoped_temp_dir.h"
 #include "base/mac/cocoa_protocols.h"
 #include "base/mac/foundation_util.h"
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "base/message_loop.h"
 #include "base/run_loop.h"
 #include "base/strings/sys_string_conversions.h"
@@ -47,7 +47,7 @@
 
 @interface MockMTPICCameraDevice : ICCameraDevice {
  @private
-  scoped_nsobject<NSMutableArray> allMediaFiles_;
+  base::scoped_nsobject<NSMutableArray> allMediaFiles_;
 }
 
 - (void)addMediaFile:(ICCameraFile*)file;
@@ -121,8 +121,8 @@
 
 @interface MockMTPICCameraFile : ICCameraFile {
  @private
-  scoped_nsobject<NSString> name_;
-  scoped_nsobject<NSDate> date_;
+  base::scoped_nsobject<NSString> name_;
+  base::scoped_nsobject<NSDate> date_;
 }
 
 - (id)init:(NSString*)name;
@@ -546,7 +546,7 @@
   info.last_accessed = t1;
   info.creation_time = t1;
   std::string kTestFileName("filename");
-  scoped_nsobject<MockMTPICCameraFile> picture1(
+  base::scoped_nsobject<MockMTPICCameraFile> picture1(
       [[MockMTPICCameraFile alloc]
           init:base::SysUTF8ToNSString(kTestFileName)]);
   [camera_ addMediaFile:picture1];
diff --git a/chrome/browser/media_galleries/media_file_system_registry.cc b/chrome/browser/media_galleries/media_file_system_registry.cc
index 345e8ea..b1a2f9d 100644
--- a/chrome/browser/media_galleries/media_file_system_registry.cc
+++ b/chrome/browser/media_galleries/media_file_system_registry.cc
@@ -341,8 +341,7 @@
         continue;
 
       MediaFileSystemInfo new_entry(
-          MediaGalleriesDialogController::GetGalleryDisplayNameNoAttachment(
-              gallery_info),
+          gallery_info.GetGalleryDisplayName(),
           path,
           fsid,
           pref_id,
diff --git a/chrome/browser/media_galleries/media_file_system_registry_unittest.cc b/chrome/browser/media_galleries/media_file_system_registry_unittest.cc
index c7b4adc..59a411b 100644
--- a/chrome/browser/media_galleries/media_file_system_registry_unittest.cc
+++ b/chrome/browser/media_galleries/media_file_system_registry_unittest.cc
@@ -54,12 +54,6 @@
 #include "chrome/browser/chromeos/settings/device_settings_service.h"
 #endif
 
-#if defined(OS_WIN)
-#include "chrome/browser/storage_monitor/test_portable_device_watcher_win.h"
-#include "chrome/browser/storage_monitor/test_storage_monitor_win.h"
-#include "chrome/browser/storage_monitor/test_volume_mount_watcher_win.h"
-#endif
-
 using content::BrowserThread;
 
 namespace chrome {
@@ -384,12 +378,7 @@
   scoped_ptr<chromeos::ScopedTestUserManager> test_user_manager_;
 #endif
 
-// TODO(gbillock): Eliminate windows-specific code from this test.
-#if defined(OS_WIN)
-  scoped_ptr<test::TestStorageMonitorWin> monitor_;
-#else
   scoped_ptr<chrome::test::TestStorageMonitor> monitor_;
-#endif
 
   MockProfileSharedRenderProcessHostFactory rph_factory_;
 
@@ -758,20 +747,10 @@
 
 void MediaFileSystemRegistryTest::SetUp() {
   ChromeRenderViewHostTestHarness::SetUp();
-#if defined(OS_WIN)
-  test::TestPortableDeviceWatcherWin* portable_device_watcher =
-      new test::TestPortableDeviceWatcherWin;
-  test::TestVolumeMountWatcherWin* mount_watcher =
-      new test::TestVolumeMountWatcherWin;
-  portable_device_watcher->set_use_dummy_mtp_storage_info(true);
-  monitor_.reset(new test::TestStorageMonitorWin(
-      mount_watcher, portable_device_watcher));
-#else
   monitor_.reset(new test::TestStorageMonitor());
   monitor_->MarkInitialized();
-#endif
   base::RunLoop runloop;
-  monitor_->Initialize(runloop.QuitClosure());
+  monitor_->EnsureInitialized(runloop.QuitClosure());
   runloop.Run();
 
   DeleteContents();
@@ -801,9 +780,6 @@
   test_user_manager_.reset();
 #endif
 
-#if defined(OS_WIN)
-  monitor_.reset();
-#endif
   ChromeRenderViewHostTestHarness::TearDown();
 }
 
@@ -925,21 +901,13 @@
   }
 }
 
-// TODO(gbillock): Put the platform-specific parts of this test in tests
-// for those classes, not here. This test, internally, ends up creating an
-// MTP delegate. (Probably ./win/mtp_device_delegate_impl_win_unittest)
-#if !defined(OS_MACOSX)
+// TODO(gbillock): Move the remaining test into the linux directory.
+#if !defined(OS_MACOSX) && !defined(OS_WIN)
 TEST_F(MediaFileSystemRegistryTest, GalleryMTP) {
   FSInfoMap galleries_info;
   InitForGalleriesInfoTest(&galleries_info);
 
-#if defined(OS_WIN)
-  base::FilePath location(
-      PortableDeviceWatcherWin::GetStoragePathFromStorageId(
-          test::TestPortableDeviceWatcherWin::kStorageUniqueIdA));
-#else
   base::FilePath location(FILE_PATH_LITERAL("/mtp_bogus"));
-#endif
   AttachDevice(StorageInfo::MTP_OR_PTP, "mtp_fake_id", location);
   CheckNewGalleryInfo(GetProfileState(0U), galleries_info, location,
                       true /*removable*/, true /* media device */);
diff --git a/chrome/browser/media_galleries/media_galleries_dialog_controller.cc b/chrome/browser/media_galleries/media_galleries_dialog_controller.cc
index 57e98d2..973bcdf 100644
--- a/chrome/browser/media_galleries/media_galleries_dialog_controller.cc
+++ b/chrome/browser/media_galleries/media_galleries_dialog_controller.cc
@@ -4,7 +4,6 @@
 
 #include "chrome/browser/media_galleries/media_galleries_dialog_controller.h"
 
-#include "base/i18n/time_formatting.h"
 #include "base/path_service.h"
 #include "base/stl_util.h"
 #include "base/strings/utf_string_conversions.h"
@@ -28,19 +27,6 @@
 
 namespace {
 
-bool IsAttachedDevice(const std::string& device_id) {
-  if (!StorageInfo::IsRemovableDevice(device_id))
-    return false;
-
-  std::vector<StorageInfo> storages =
-      StorageMonitor::GetInstance()->GetAllAvailableStorages();
-  for (size_t i = 0; i < storages.size(); ++i) {
-    if (storages[i].device_id() == device_id)
-      return true;
-  }
-  return false;
-}
-
 // Comparator for sorting GalleryPermissionsVector -- sorts
 // allowed galleries low, and then sorts by absolute path.
 bool GalleriesVectorComparator(
@@ -54,41 +40,6 @@
   return a.pref_info.AbsolutePath() < b.pref_info.AbsolutePath();
 }
 
-string16 GetDisplayNameForDevice(uint64 storage_size_in_bytes,
-                                 const string16& name) {
-  DCHECK(!name.empty());
-  return (storage_size_in_bytes == 0) ?
-      name : ui::FormatBytes(storage_size_in_bytes) + ASCIIToUTF16(" ") + name;
-}
-
-
-// For a device with |device_name| and a relative path |sub_folder|, construct
-// a display name. If |sub_folder| is empty, then just return |device_name|.
-string16 GetDisplayNameForSubFolder(const string16& device_name,
-                                    const base::FilePath& sub_folder) {
-  if (sub_folder.empty())
-    return device_name;
-  return (sub_folder.BaseName().LossyDisplayName() +
-          ASCIIToUTF16(" - ") +
-          device_name);
-}
-
-string16 GetFullProductName(const string16& vendor_name,
-                            const string16& model_name) {
-  if (vendor_name.empty() && model_name.empty())
-    return string16();
-
-  string16 product_name;
-  if (vendor_name.empty())
-    product_name = model_name;
-  else if (model_name.empty())
-    product_name = vendor_name;
-  else if (!vendor_name.empty() && !model_name.empty())
-    product_name = vendor_name + UTF8ToUTF16(", ") + model_name;
-
-  return product_name;
-}
-
 }  // namespace
 
 MediaGalleriesDialogController::MediaGalleriesDialogController(
@@ -101,7 +52,7 @@
   // Passing unretained pointer is safe, since the dialog controller
   // is self-deleting, and so won't be deleted until it can be shown
   // and then closed.
-  StorageMonitor::GetInstance()->Initialize(base::Bind(
+  StorageMonitor::GetInstance()->EnsureInitialized(base::Bind(
       &MediaGalleriesDialogController::OnStorageMonitorInitialized,
       base::Unretained(this)));
 }
@@ -133,96 +84,15 @@
     select_folder_dialog_->ListenerDestroyed();
 }
 
-// static
-string16 MediaGalleriesDialogController::GetGalleryDisplayName(
-    const MediaGalleryPrefInfo& gallery) {
-  string16 name = gallery.display_name;
-  if (IsAttachedDevice(gallery.device_id)) {
-    name += ASCIIToUTF16(" ");
-    name +=
-        l10n_util::GetStringUTF16(IDS_MEDIA_GALLERIES_DIALOG_DEVICE_ATTACHED);
-  }
-  return name;
-}
-
-// TODO(gbillock): Move this function and attendant helpers somewhere else,
-// probably to StorageInfo.
-// static
-string16 MediaGalleriesDialogController::GetGalleryDisplayNameNoAttachment(
-    const MediaGalleryPrefInfo& gallery) {
-  if (!StorageInfo::IsRemovableDevice(gallery.device_id)) {
-    // For fixed storage, the name is the directory name, or, in the case
-    // of a root directory, the root directory name.
-    // TODO(gbillock): Using only the BaseName can lead to ambiguity. The
-    // tooltip resolves it. Is that enough?
-    base::FilePath path = gallery.AbsolutePath();
-    if (!gallery.display_name.empty())
-      return gallery.display_name;
-    if (path == path.DirName())
-      return path.LossyDisplayName();
-    return path.BaseName().LossyDisplayName();
-  }
-
-  string16 name = gallery.display_name;
-  if (name.empty())
-    name = gallery.volume_label;
-  if (name.empty())
-    name = GetFullProductName(gallery.vendor_name, gallery.model_name);
-  if (name.empty())
-    name = l10n_util::GetStringUTF16(IDS_MEDIA_GALLERIES_UNLABELED_DEVICE);
-
-  name = GetDisplayNameForDevice(gallery.total_size_in_bytes, name);
-
-  if (!gallery.path.empty())
-    name = GetDisplayNameForSubFolder(name, gallery.path);
-
-  return name;
-}
-
-// static
-string16 MediaGalleriesDialogController::GetGalleryTooltip(
-    const MediaGalleryPrefInfo& gallery) {
-  return gallery.AbsolutePath().LossyDisplayName();
-}
-
-// static
-bool MediaGalleriesDialogController::GetGalleryAttached(
-    const MediaGalleryPrefInfo& gallery) {
-  return !StorageInfo::IsRemovableDevice(gallery.device_id) ||
-         IsAttachedDevice(gallery.device_id);
-}
-
-// static
-string16 MediaGalleriesDialogController::GetGalleryAdditionalDetails(
-    const MediaGalleryPrefInfo& gallery) {
-  string16 attached;
-  if (StorageInfo::IsRemovableDevice(gallery.device_id)) {
-    if (IsAttachedDevice(gallery.device_id)) {
-      attached = l10n_util::GetStringUTF16(
-          IDS_MEDIA_GALLERIES_DIALOG_DEVICE_ATTACHED);
-    } else if (!gallery.last_attach_time.is_null()) {
-      attached = l10n_util::GetStringFUTF16(
-          IDS_MEDIA_GALLERIES_LAST_ATTACHED,
-          base::TimeFormatShortDateNumeric(gallery.last_attach_time));
-    } else {
-      attached = l10n_util::GetStringUTF16(
-          IDS_MEDIA_GALLERIES_DIALOG_DEVICE_NOT_ATTACHED);
-    }
-  }
-
-  // TODO(gbillock): This is a placeholder. Need to actually get the
-  // right text here.
-  return attached;
-}
-
 string16 MediaGalleriesDialogController::GetHeader() const {
   return l10n_util::GetStringUTF16(IDS_MEDIA_GALLERIES_DIALOG_HEADER);
 }
 
 string16 MediaGalleriesDialogController::GetSubtext() const {
   std::string extension_name(extension_ ? extension_->name() : std::string());
-  return l10n_util::GetStringFUTF16(IDS_MEDIA_GALLERIES_DIALOG_SUBTEXT,
-                                    UTF8ToUTF16(extension_name));
+  return l10n_util::GetStringFUTF16(
+      IDS_MEDIA_GALLERIES_DIALOG_SUBTEXT_READ_ONLY,
+      UTF8ToUTF16(extension_name));
 }
 
 string16 MediaGalleriesDialogController::GetUnattachedLocationsHeader() const {
@@ -252,15 +122,15 @@
     const {
   for (KnownGalleryPermissions::const_iterator iter = known_galleries_.begin();
        iter != known_galleries_.end(); ++iter) {
-    if ((attached && GetGalleryAttached(iter->second.pref_info)) ||
-        (!attached && !GetGalleryAttached(iter->second.pref_info))) {
+    if ((attached && iter->second.pref_info.IsGalleryAvailable()) ||
+        (!attached && !iter->second.pref_info.IsGalleryAvailable())) {
       permissions->push_back(iter->second);
     }
   }
   for (GalleryPermissionsVector::const_iterator iter = new_galleries_.begin();
        iter != new_galleries_.end(); ++iter) {
-    if ((attached && GetGalleryAttached(iter->pref_info)) ||
-        (!attached && !GetGalleryAttached(iter->pref_info))) {
+    if ((attached && iter->pref_info.IsGalleryAvailable()) ||
+        (!attached && !iter->pref_info.IsGalleryAvailable())) {
       permissions->push_back(*iter);
     }
   }
diff --git a/chrome/browser/media_galleries/media_galleries_dialog_controller.h b/chrome/browser/media_galleries/media_galleries_dialog_controller.h
index b6bc2a2..c6d4d3b 100644
--- a/chrome/browser/media_galleries/media_galleries_dialog_controller.h
+++ b/chrome/browser/media_galleries/media_galleries_dialog_controller.h
@@ -72,17 +72,6 @@
                                  const extensions::Extension& extension,
                                  const base::Closure& on_finish);
 
-  // Called by the view to provide details for a particular gallery
-  // permission entry.
-  static string16 GetGalleryDisplayName(
-      const MediaGalleryPrefInfo& gallery);
-  static string16 GetGalleryDisplayNameNoAttachment(
-      const MediaGalleryPrefInfo& gallery);
-  static string16 GetGalleryTooltip(const MediaGalleryPrefInfo& gallery);
-  static bool GetGalleryAttached(const MediaGalleryPrefInfo& gallery);
-  static string16 GetGalleryAdditionalDetails(
-      const MediaGalleryPrefInfo& gallery);
-
   // The title of the dialog view.
   string16 GetHeader() const;
 
diff --git a/chrome/browser/media_galleries/media_galleries_dialog_controller_unittest.cc b/chrome/browser/media_galleries/media_galleries_dialog_controller_unittest.cc
index 33a354e..890750e 100644
--- a/chrome/browser/media_galleries/media_galleries_dialog_controller_unittest.cc
+++ b/chrome/browser/media_galleries/media_galleries_dialog_controller_unittest.cc
@@ -3,8 +3,8 @@
 // found in the LICENSE file.
 
 #include "base/files/file_path.h"
-#include "base/string_util.h"
 #include "base/strings/string16.h"
+#include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/media_galleries/media_galleries_dialog_controller.h"
 #include "chrome/browser/media_galleries/media_galleries_preferences.h"
@@ -12,10 +12,7 @@
 #include "testing/gtest/include/gtest/gtest.h"
 
 std::string GalleryName(const chrome::MediaGalleryPrefInfo& gallery) {
-  using chrome::MediaGalleriesDialogController;
-  string16 name =
-      MediaGalleriesDialogController::GetGalleryDisplayNameNoAttachment(
-          gallery);
+  string16 name = gallery.GetGalleryDisplayName();
   return UTF16ToASCII(name);
 }
 
diff --git a/chrome/browser/media_galleries/media_galleries_preferences.cc b/chrome/browser/media_galleries/media_galleries_preferences.cc
index 3843d58..451b617 100644
--- a/chrome/browser/media_galleries/media_galleries_preferences.cc
+++ b/chrome/browser/media_galleries/media_galleries_preferences.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/media_galleries/media_galleries_preferences.h"
 
+#include "base/i18n/time_formatting.h"
 #include "base/path_service.h"
 #include "base/prefs/pref_service.h"
 #include "base/stl_util.h"
@@ -30,6 +31,9 @@
 #include "chrome/common/extensions/permissions/permissions_data.h"
 #include "chrome/common/pref_names.h"
 #include "components/user_prefs/pref_registry_syncable.h"
+#include "grit/generated_resources.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/text/bytes_formatting.h"
 
 using base::DictionaryValue;
 using base::ListValue;
@@ -217,6 +221,40 @@
   return false;
 }
 
+string16 GetDisplayNameForDevice(uint64 storage_size_in_bytes,
+                                 const string16& name) {
+  DCHECK(!name.empty());
+  return (storage_size_in_bytes == 0) ?
+      name : ui::FormatBytes(storage_size_in_bytes) + ASCIIToUTF16(" ") + name;
+}
+
+// For a device with |device_name| and a relative path |sub_folder|, construct
+// a display name. If |sub_folder| is empty, then just return |device_name|.
+string16 GetDisplayNameForSubFolder(const string16& device_name,
+                                    const base::FilePath& sub_folder) {
+  if (sub_folder.empty())
+    return device_name;
+  return (sub_folder.BaseName().LossyDisplayName() +
+          ASCIIToUTF16(" - ") +
+          device_name);
+}
+
+string16 GetFullProductName(const string16& vendor_name,
+                            const string16& model_name) {
+  if (vendor_name.empty() && model_name.empty())
+    return string16();
+
+  string16 product_name;
+  if (vendor_name.empty())
+    product_name = model_name;
+  else if (model_name.empty())
+    product_name = vendor_name;
+  else if (!vendor_name.empty() && !model_name.empty())
+    product_name = vendor_name + UTF8ToUTF16(", ") + model_name;
+
+  return product_name;
+}
+
 }  // namespace
 
 MediaGalleryPrefInfo::MediaGalleryPrefInfo()
@@ -235,6 +273,64 @@
   return base_path.empty() ? base_path : base_path.Append(path);
 }
 
+string16 MediaGalleryPrefInfo::GetGalleryDisplayName() const {
+  if (!StorageInfo::IsRemovableDevice(device_id)) {
+    // For fixed storage, the name is the directory name, or, in the case
+    // of a root directory, the root directory name.
+    // TODO(gbillock): Using only the BaseName can lead to ambiguity. The
+    // tooltip resolves it. Is that enough?
+    base::FilePath path = AbsolutePath();
+    if (!display_name.empty())
+      return display_name;
+    if (path == path.DirName())
+      return path.LossyDisplayName();
+    return path.BaseName().LossyDisplayName();
+  }
+
+  string16 name = display_name;
+  if (name.empty())
+    name = volume_label;
+  if (name.empty())
+    name = GetFullProductName(vendor_name, model_name);
+  if (name.empty())
+    name = l10n_util::GetStringUTF16(IDS_MEDIA_GALLERIES_UNLABELED_DEVICE);
+
+  name = GetDisplayNameForDevice(total_size_in_bytes, name);
+
+  if (!path.empty())
+    name = GetDisplayNameForSubFolder(name, path);
+
+  return name;
+}
+
+string16 MediaGalleryPrefInfo::GetGalleryTooltip() const {
+  return AbsolutePath().LossyDisplayName();
+}
+
+string16 MediaGalleryPrefInfo::GetGalleryAdditionalDetails() const {
+  string16 attached;
+  if (StorageInfo::IsRemovableDevice(device_id)) {
+    if (MediaStorageUtil::IsRemovableStorageAttached(device_id)) {
+      attached = l10n_util::GetStringUTF16(
+          IDS_MEDIA_GALLERIES_DIALOG_DEVICE_ATTACHED);
+    } else if (!last_attach_time.is_null()) {
+      attached = l10n_util::GetStringFUTF16(
+          IDS_MEDIA_GALLERIES_LAST_ATTACHED,
+          base::TimeFormatShortDateNumeric(last_attach_time));
+    } else {
+      attached = l10n_util::GetStringUTF16(
+          IDS_MEDIA_GALLERIES_DIALOG_DEVICE_NOT_ATTACHED);
+    }
+  }
+
+  return attached;
+}
+
+bool MediaGalleryPrefInfo::IsGalleryAvailable() const {
+  return !StorageInfo::IsRemovableDevice(device_id) ||
+         MediaStorageUtil::IsRemovableStorageAttached(device_id);
+}
+
 MediaGalleriesPreferences::GalleryChangeObserver::~GalleryChangeObserver() {}
 
 MediaGalleriesPreferences::MediaGalleriesPreferences(Profile* profile)
diff --git a/chrome/browser/media_galleries/media_galleries_preferences.h b/chrome/browser/media_galleries/media_galleries_preferences.h
index 3d3cb4d..f15dc9b 100644
--- a/chrome/browser/media_galleries/media_galleries_preferences.h
+++ b/chrome/browser/media_galleries/media_galleries_preferences.h
@@ -14,7 +14,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
 #include "base/strings/string16.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/storage_monitor/removable_storage_observer.h"
 #include "components/browser_context_keyed_service/browser_context_keyed_service.h"
 
@@ -103,6 +103,15 @@
   // 1 if the display_name is only set externally when it is overriding
   // the name constructed from volume metadata.
   int prefs_version;
+
+  // Called by views to provide details for the gallery permission entries.
+  string16 GetGalleryDisplayName() const;
+  string16 GetGalleryTooltip() const;
+  string16 GetGalleryAdditionalDetails() const;
+
+  // Returns true if the gallery is currently a removable device gallery which
+  // is now attached, or a fixed storage gallery.
+  bool IsGalleryAvailable() const;
 };
 
 typedef std::map<MediaGalleryPrefId, MediaGalleryPrefInfo>
diff --git a/chrome/browser/media_galleries/media_galleries_preferences_unittest.cc b/chrome/browser/media_galleries/media_galleries_preferences_unittest.cc
index 9239aab..e4c208c 100644
--- a/chrome/browser/media_galleries/media_galleries_preferences_unittest.cc
+++ b/chrome/browser/media_galleries/media_galleries_preferences_unittest.cc
@@ -23,8 +23,10 @@
 #include "chrome/common/extensions/extension.h"
 #include "chrome/test/base/testing_profile.h"
 #include "content/public/test/test_browser_thread.h"
+#include "grit/generated_resources.h"
 #include "sync/api/string_ordinal.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/l10n/l10n_util.h"
 
 #if defined(OS_CHROMEOS)
 #include "chrome/browser/chromeos/login/user_manager.h"
@@ -809,4 +811,46 @@
   EXPECT_FALSE(UpdateDeviceIDForSingletonType(new_device_id));
 }
 
+TEST(MediaGalleryPrefInfoTest, NameGeneration) {
+  test::TestStorageMonitor monitor;
+
+  MediaGalleryPrefInfo info;
+  info.pref_id = 1;
+  info.display_name = ASCIIToUTF16("override");
+  info.device_id = StorageInfo::MakeDeviceId(
+      StorageInfo::REMOVABLE_MASS_STORAGE_WITH_DCIM, "unique");
+
+  EXPECT_EQ(ASCIIToUTF16("override"), info.GetGalleryDisplayName());
+
+  info.display_name = ASCIIToUTF16("o2");
+  EXPECT_EQ(ASCIIToUTF16("o2"), info.GetGalleryDisplayName());
+
+  EXPECT_EQ(l10n_util::GetStringUTF16(
+                IDS_MEDIA_GALLERIES_DIALOG_DEVICE_NOT_ATTACHED),
+            info.GetGalleryAdditionalDetails());
+
+  info.last_attach_time = base::Time::Now();
+  EXPECT_NE(l10n_util::GetStringUTF16(
+                IDS_MEDIA_GALLERIES_DIALOG_DEVICE_NOT_ATTACHED),
+            info.GetGalleryAdditionalDetails());
+  EXPECT_NE(l10n_util::GetStringUTF16(
+                IDS_MEDIA_GALLERIES_DIALOG_DEVICE_ATTACHED),
+            info.GetGalleryAdditionalDetails());
+
+  info.volume_label = ASCIIToUTF16("vol");
+  info.vendor_name = ASCIIToUTF16("vendor");
+  info.model_name = ASCIIToUTF16("model");
+  EXPECT_EQ(ASCIIToUTF16("o2"), info.GetGalleryDisplayName());
+
+  info.display_name = string16();
+  EXPECT_EQ(ASCIIToUTF16("vol"), info.GetGalleryDisplayName());
+  info.volume_label = string16();
+  EXPECT_EQ(ASCIIToUTF16("vendor, model"), info.GetGalleryDisplayName());
+
+  info.device_id = StorageInfo::MakeDeviceId(
+      StorageInfo::FIXED_MASS_STORAGE, "unique");
+  EXPECT_EQ(base::FilePath(FILE_PATH_LITERAL("unique")).AsUTF8Unsafe(),
+            UTF16ToUTF8(info.GetGalleryTooltip()));
+}
+
 }  // namespace chrome
diff --git a/chrome/browser/media_galleries/media_galleries_test_util.cc b/chrome/browser/media_galleries/media_galleries_test_util.cc
index a3e42fb..c73a5be 100644
--- a/chrome/browser/media_galleries/media_galleries_test_util.cc
+++ b/chrome/browser/media_galleries/media_galleries_test_util.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/media_galleries/media_galleries_test_util.h"
 
+#include "base/base_paths.h"
 #include "base/file_util.h"
 #include "base/files/file_path.h"
 #include "base/path_service.h"
@@ -71,35 +72,30 @@
   Init();
 }
 
+EnsureMediaDirectoriesExists::~EnsureMediaDirectoriesExists() {
+}
+
 void EnsureMediaDirectoriesExists::Init() {
 #if defined(OS_CHROMEOS) || defined(OS_ANDROID)
   return;
 #else
+
   ASSERT_TRUE(fake_dir_.CreateUniqueTempDir());
 
-  const int kDirectoryKeys[] = {
-    chrome::DIR_USER_MUSIC,
-    chrome::DIR_USER_PICTURES,
-    chrome::DIR_USER_VIDEOS,
-  };
+#if defined(OS_WIN) || defined(OS_MACOSX)
+  // This is to make sure the tests don't think iTunes is installed (unless
+  // we control it specifically).
+  appdir_override_.reset(new base::ScopedPathOverride(
+      base::DIR_APP_DATA, fake_dir_.path().AppendASCII("itunes")));
+#endif
 
-  const char* kDirectoryNames[] = {
-    "music",
-    "pictures",
-    "videos",
-  };
-
-  for (size_t i = 0; i < arraysize(kDirectoryKeys); ++i) {
-    PathService::OverrideAndCreateIfNeeded(
-        kDirectoryKeys[i], fake_dir_.path().AppendASCII(kDirectoryNames[i]),
-        true /*create*/);
-    base::FilePath path;
-    if (PathService::Get(kDirectoryKeys[i], &path) &&
-        file_util::DirectoryExists(path)) {
-      ++num_galleries_;
-    }
-  }
-  ASSERT_GT(num_galleries_, 0);
+  music_override_.reset(new base::ScopedPathOverride(
+    chrome::DIR_USER_MUSIC, fake_dir_.path().AppendASCII("music")));
+  pictures_override_.reset(new base::ScopedPathOverride(
+    chrome::DIR_USER_PICTURES, fake_dir_.path().AppendASCII("pictures")));
+  video_override_.reset(new base::ScopedPathOverride(
+    chrome::DIR_USER_VIDEOS, fake_dir_.path().AppendASCII("videos")));
+  num_galleries_ = 3;
 #endif
 }
 
diff --git a/chrome/browser/media_galleries/media_galleries_test_util.h b/chrome/browser/media_galleries/media_galleries_test_util.h
index 3a78643..d18f722 100644
--- a/chrome/browser/media_galleries/media_galleries_test_util.h
+++ b/chrome/browser/media_galleries/media_galleries_test_util.h
@@ -8,6 +8,8 @@
 #include "base/basictypes.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/test/scoped_path_override.h"
 
 namespace extensions {
 class Extension;
@@ -25,6 +27,7 @@
 class EnsureMediaDirectoriesExists {
  public:
   EnsureMediaDirectoriesExists();
+  ~EnsureMediaDirectoriesExists();
 
   int num_galleries() const { return num_galleries_; }
 
@@ -35,6 +38,11 @@
 
   int num_galleries_;
 
+  scoped_ptr<base::ScopedPathOverride> appdir_override_;
+  scoped_ptr<base::ScopedPathOverride> music_override_;
+  scoped_ptr<base::ScopedPathOverride> pictures_override_;
+  scoped_ptr<base::ScopedPathOverride> video_override_;
+
   DISALLOW_COPY_AND_ASSIGN(EnsureMediaDirectoriesExists);
 };
 
diff --git a/chrome/browser/media_galleries/win/mtp_device_delegate_impl_win_unittest.cc b/chrome/browser/media_galleries/win/mtp_device_delegate_impl_win_unittest.cc
new file mode 100644
index 0000000..8f7d042
--- /dev/null
+++ b/chrome/browser/media_galleries/win/mtp_device_delegate_impl_win_unittest.cc
@@ -0,0 +1,167 @@
+// 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 <vector>
+
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/message_loop.h"
+#include "base/run_loop.h"
+#include "base/stl_util.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/extensions/extension_system.h"
+#include "chrome/browser/extensions/test_extension_system.h"
+#include "chrome/browser/media_galleries/media_file_system_registry.h"
+#include "chrome/browser/media_galleries/media_galleries_test_util.h"
+#include "chrome/browser/storage_monitor/storage_info.h"
+#include "chrome/browser/storage_monitor/storage_monitor.h"
+#include "chrome/browser/storage_monitor/test_portable_device_watcher_win.h"
+#include "chrome/browser/storage_monitor/test_storage_monitor_win.h"
+#include "chrome/browser/storage_monitor/test_volume_mount_watcher_win.h"
+#include "chrome/test/base/chrome_render_view_host_test_harness.h"
+#include "chrome/test/base/testing_profile.h"
+#include "content/public/browser/render_view_host.h"
+#include "content/public/browser/web_contents.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace chrome {
+
+namespace {
+
+typedef std::map<MediaGalleryPrefId, MediaFileSystemInfo> FSInfoMap;
+
+void GetGalleryInfoCallback(
+    FSInfoMap* results,
+    const std::vector<MediaFileSystemInfo>& file_systems) {
+  for (size_t i = 0; i < file_systems.size(); ++i) {
+    ASSERT_FALSE(ContainsKey(*results, file_systems[i].pref_id));
+    (*results)[file_systems[i].pref_id] = file_systems[i];
+  }
+}
+
+}  // namespace
+
+class MTPDeviceDelegateImplWinTest : public ChromeRenderViewHostTestHarness {
+ protected:
+  void SetUp() OVERRIDE;
+  void TearDown() OVERRIDE;
+
+  void ProcessAttach(const std::string& id,
+                     const string16& name,
+                     const base::FilePath::StringType& location);
+  std::string AttachDevice(StorageInfo::Type type,
+                           const std::string& unique_id,
+                           const base::FilePath& location);
+  void CheckGalleryInfo(const MediaFileSystemInfo& info,
+                        const string16& name,
+                        const base::FilePath& path,
+                        bool removable,
+                        bool media_device);
+
+  // Note: need to make this weak ptr once ownership moves to g_browser_process
+  scoped_ptr<test::TestStorageMonitorWin> monitor_;
+  scoped_refptr<extensions::Extension> extension_;
+
+  EnsureMediaDirectoriesExists media_directories_;
+};
+
+void MTPDeviceDelegateImplWinTest::SetUp() {
+  ChromeRenderViewHostTestHarness::SetUp();
+  test::TestPortableDeviceWatcherWin* portable_device_watcher =
+      new test::TestPortableDeviceWatcherWin;
+  test::TestVolumeMountWatcherWin* mount_watcher =
+      new test::TestVolumeMountWatcherWin;
+  portable_device_watcher->set_use_dummy_mtp_storage_info(true);
+  monitor_.reset(new test::TestStorageMonitorWin(
+      mount_watcher, portable_device_watcher));
+  base::RunLoop runloop;
+  monitor_->EnsureInitialized(runloop.QuitClosure());
+  runloop.Run();
+
+  extensions::TestExtensionSystem* extension_system(
+      static_cast<extensions::TestExtensionSystem*>(
+          extensions::ExtensionSystem::Get(profile())));
+  extension_system->CreateExtensionService(
+      CommandLine::ForCurrentProcess(), base::FilePath(), false);
+
+  std::vector<std::string> all_permissions;
+  all_permissions.push_back("allAutoDetected");
+  all_permissions.push_back("read");
+  extension_ = AddMediaGalleriesApp("all", all_permissions, profile());
+}
+
+void MTPDeviceDelegateImplWinTest::TearDown() {
+  monitor_.reset();
+
+  ChromeRenderViewHostTestHarness::TearDown();
+}
+
+void MTPDeviceDelegateImplWinTest::ProcessAttach(
+    const std::string& id,
+    const string16& label,
+    const base::FilePath::StringType& location) {
+  StorageInfo info(id, string16(), location, label, string16(), string16(), 0);
+  monitor_->receiver()->ProcessAttach(info);
+}
+
+std::string MTPDeviceDelegateImplWinTest::AttachDevice(
+    StorageInfo::Type type,
+    const std::string& unique_id,
+    const base::FilePath& location) {
+  std::string device_id = StorageInfo::MakeDeviceId(type, unique_id);
+  DCHECK(StorageInfo::IsRemovableDevice(device_id));
+  string16 label = location.LossyDisplayName();
+  ProcessAttach(device_id, label, location.value());
+  base::RunLoop().RunUntilIdle();
+  return device_id;
+}
+
+void MTPDeviceDelegateImplWinTest::CheckGalleryInfo(
+    const MediaFileSystemInfo& info,
+    const string16& name,
+    const base::FilePath& path,
+    bool removable,
+    bool media_device) {
+  EXPECT_EQ(name, info.name);
+  EXPECT_EQ(path, info.path);
+  EXPECT_EQ(removable, info.removable);
+  EXPECT_EQ(media_device, info.media_device);
+  EXPECT_NE(0UL, info.pref_id);
+
+  if (removable)
+    EXPECT_NE(0UL, info.transient_device_id.size());
+  else
+    EXPECT_EQ(0UL, info.transient_device_id.size());
+}
+
+TEST_F(MTPDeviceDelegateImplWinTest, GalleryNameMTP) {
+  base::FilePath location(
+      PortableDeviceWatcherWin::GetStoragePathFromStorageId(
+          test::TestPortableDeviceWatcherWin::kStorageUniqueIdA));
+  AttachDevice(StorageInfo::MTP_OR_PTP, "mtp_fake_id", location);
+
+  content::RenderViewHost* rvh = web_contents()->GetRenderViewHost();
+  FSInfoMap results;
+  MediaFileSystemRegistry* registry =
+      g_browser_process->media_file_system_registry();
+  registry->GetMediaFileSystemsForExtension(
+      rvh, extension_.get(),
+      base::Bind(&GetGalleryInfoCallback, base::Unretained(&results)));
+  base::RunLoop().RunUntilIdle();
+
+  ASSERT_EQ(media_directories_.num_galleries() + 1, results.size());
+  bool checked = false;
+  for (FSInfoMap::iterator i = results.begin(); i != results.end(); ++i) {
+    MediaFileSystemInfo info = i->second;
+    if (info.path == location) {
+      CheckGalleryInfo(info, location.LossyDisplayName(), location, true, true);
+      checked = true;
+      break;
+    }
+  }
+  EXPECT_TRUE(checked);
+}
+
+}  // namespace chrome
diff --git a/chrome/browser/media_galleries/win/mtp_device_object_entry.h b/chrome/browser/media_galleries/win/mtp_device_object_entry.h
index 4f80946..e9a5e64 100644
--- a/chrome/browser/media_galleries/win/mtp_device_object_entry.h
+++ b/chrome/browser/media_galleries/win/mtp_device_object_entry.h
@@ -9,7 +9,7 @@
 
 #include "base/basictypes.h"
 #include "base/strings/string16.h"
-#include "base/time.h"
+#include "base/time/time.h"
 
 namespace chrome {
 
diff --git a/chrome/browser/media_galleries/win/mtp_device_object_enumerator.h b/chrome/browser/media_galleries/win/mtp_device_object_enumerator.h
index 840a911..3287715 100644
--- a/chrome/browser/media_galleries/win/mtp_device_object_enumerator.h
+++ b/chrome/browser/media_galleries/win/mtp_device_object_enumerator.h
@@ -10,7 +10,7 @@
 
 #include "base/files/file_path.h"
 #include "base/threading/thread_checker.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/media_galleries/win/mtp_device_object_entry.h"
 #include "webkit/browser/fileapi/file_system_file_util.h"
 
diff --git a/chrome/browser/media_galleries/win/mtp_device_object_enumerator_unittest.cc b/chrome/browser/media_galleries/win/mtp_device_object_enumerator_unittest.cc
index 8f1f85b..24f5a55 100644
--- a/chrome/browser/media_galleries/win/mtp_device_object_enumerator_unittest.cc
+++ b/chrome/browser/media_galleries/win/mtp_device_object_enumerator_unittest.cc
@@ -10,7 +10,7 @@
 
 #include "base/basictypes.h"
 #include "base/strings/string16.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/media_galleries/win/mtp_device_object_entry.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/chrome/browser/media_galleries/win/mtp_device_operations_util.cc b/chrome/browser/media_galleries/win/mtp_device_operations_util.cc
index afe4af5..cb59d1a 100644
--- a/chrome/browser/media_galleries/win/mtp_device_operations_util.cc
+++ b/chrome/browser/media_galleries/win/mtp_device_operations_util.cc
@@ -15,7 +15,7 @@
 #include "base/safe_numerics.h"
 #include "base/strings/string_util.h"
 #include "base/threading/thread_restrictions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "base/win/scoped_co_mem.h"
 #include "base/win/scoped_propvariant.h"
 #include "chrome/browser/storage_monitor/removable_device_constants.h"
diff --git a/chrome/browser/memory_details.cc b/chrome/browser/memory_details.cc
index 716974a..8274960 100644
--- a/chrome/browser/memory_details.cc
+++ b/chrome/browser/memory_details.cc
@@ -214,11 +214,10 @@
     ProcessMemoryInformation& process =
         chrome_browser->processes[index];
 
-    for (content::RenderProcessHost::iterator renderer_iter(
-            content::RenderProcessHost::AllHostsIterator());
-         !renderer_iter.IsAtEnd(); renderer_iter.Advance()) {
+    RenderWidgetHost::List widgets = RenderWidgetHost::GetRenderWidgetHosts();
+    for (size_t i = 0; i < widgets.size(); ++i) {
       content::RenderProcessHost* render_process_host =
-          renderer_iter.GetCurrentValue();
+          widgets[i]->GetProcess();
       DCHECK(render_process_host);
       // Ignore processes that don't have a connection, such as crashed tabs.
       if (!render_process_host->HasConnection() ||
@@ -238,110 +237,104 @@
       // The RenderProcessHost may host multiple WebContentses.  Any
       // of them which contain diagnostics information make the whole
       // process be considered a diagnostics process.
-      content::RenderProcessHost::RenderWidgetHostsIterator iter(
-          render_process_host->GetRenderWidgetHostsIterator());
-      for (; !iter.IsAtEnd(); iter.Advance()) {
-        const RenderWidgetHost* widget = iter.GetCurrentValue();
-        DCHECK(widget);
-        if (!widget || !widget->IsRenderView())
-          continue;
+      if (!widgets[i]->IsRenderView())
+        continue;
 
-        RenderViewHost* host =
-            RenderViewHost::From(const_cast<RenderWidgetHost*>(widget));
-        WebContents* contents = WebContents::FromRenderViewHost(host);
-        GURL url;
-        if (contents) {
-          url = contents->GetURL();
-          SiteData* site_data =
-              &chrome_browser->site_data[contents->GetBrowserContext()];
-          SiteDetails::CollectSiteInfo(contents, site_data);
-        }
-        extensions::ViewType type = extensions::GetViewType(contents);
-        if (host->GetEnabledBindings() & content::BINDINGS_POLICY_WEB_UI) {
-          process.renderer_type = ProcessMemoryInformation::RENDERER_CHROME;
-        } else if (extension_process_map &&
-            extension_process_map->Contains(host->GetProcess()->GetID())) {
-          // For our purposes, don't count processes containing only hosted apps
-          // as extension processes. See also: crbug.com/102533.
-          std::set<std::string> extension_ids =
-              extension_process_map->GetExtensionsInProcess(
-                  host->GetProcess()->GetID());
-          for (std::set<std::string>::iterator iter = extension_ids.begin();
-               iter != extension_ids.end(); ++iter) {
-            const Extension* extension =
-                extension_service->GetExtensionById(*iter, false);
-            if (extension && !extension->is_hosted_app()) {
-              process.renderer_type =
-                  ProcessMemoryInformation::RENDERER_EXTENSION;
-              break;
-            }
-          }
-        }
-        if (extension_process_map &&
-            extension_process_map->Contains(host->GetProcess()->GetID())) {
+      RenderViewHost* host = RenderViewHost::From(widgets[i]);
+      WebContents* contents = WebContents::FromRenderViewHost(host);
+      GURL url;
+      if (contents) {
+        url = contents->GetURL();
+        SiteData* site_data =
+            &chrome_browser->site_data[contents->GetBrowserContext()];
+        SiteDetails::CollectSiteInfo(contents, site_data);
+      }
+      extensions::ViewType type = extensions::GetViewType(contents);
+      if (host->GetEnabledBindings() & content::BINDINGS_POLICY_WEB_UI) {
+        process.renderer_type = ProcessMemoryInformation::RENDERER_CHROME;
+      } else if (extension_process_map &&
+                 extension_process_map->Contains(host->GetProcess()->GetID())) {
+        // For our purposes, don't count processes containing only hosted apps
+        // as extension processes. See also: crbug.com/102533.
+        std::set<std::string> extension_ids =
+            extension_process_map->GetExtensionsInProcess(
+            host->GetProcess()->GetID());
+        for (std::set<std::string>::iterator iter = extension_ids.begin();
+             iter != extension_ids.end(); ++iter) {
           const Extension* extension =
-              extension_service->extensions()->GetByID(url.host());
-          if (extension) {
-            string16 title = UTF8ToUTF16(extension->name());
-            process.titles.push_back(title);
+              extension_service->GetExtensionById(*iter, false);
+          if (extension && !extension->is_hosted_app()) {
             process.renderer_type =
                 ProcessMemoryInformation::RENDERER_EXTENSION;
-            continue;
+            break;
           }
         }
-
-        if (!contents) {
+      }
+      if (extension_process_map &&
+          extension_process_map->Contains(host->GetProcess()->GetID())) {
+        const Extension* extension =
+            extension_service->extensions()->GetByID(url.host());
+        if (extension) {
+          string16 title = UTF8ToUTF16(extension->name());
+          process.titles.push_back(title);
           process.renderer_type =
-                ProcessMemoryInformation::RENDERER_INTERSTITIAL;
+              ProcessMemoryInformation::RENDERER_EXTENSION;
           continue;
         }
+      }
 
-        if (type == extensions::VIEW_TYPE_BACKGROUND_CONTENTS) {
-          process.titles.push_back(UTF8ToUTF16(url.spec()));
-          process.renderer_type =
-                    ProcessMemoryInformation::RENDERER_BACKGROUND_APP;
-          continue;
-        }
+      if (!contents) {
+        process.renderer_type =
+            ProcessMemoryInformation::RENDERER_INTERSTITIAL;
+        continue;
+      }
 
-        if (type == extensions::VIEW_TYPE_NOTIFICATION) {
-          process.titles.push_back(UTF8ToUTF16(url.spec()));
-          process.renderer_type =
-                    ProcessMemoryInformation::RENDERER_NOTIFICATION;
-          continue;
-        }
+      if (type == extensions::VIEW_TYPE_BACKGROUND_CONTENTS) {
+        process.titles.push_back(UTF8ToUTF16(url.spec()));
+        process.renderer_type =
+            ProcessMemoryInformation::RENDERER_BACKGROUND_APP;
+        continue;
+      }
 
-        // Since we have a WebContents and and the renderer type hasn't been
-        // set yet, it must be a normal tabbed renderer.
-        if (process.renderer_type == ProcessMemoryInformation::RENDERER_UNKNOWN)
-          process.renderer_type = ProcessMemoryInformation::RENDERER_NORMAL;
+      if (type == extensions::VIEW_TYPE_NOTIFICATION) {
+        process.titles.push_back(UTF8ToUTF16(url.spec()));
+        process.renderer_type =
+            ProcessMemoryInformation::RENDERER_NOTIFICATION;
+        continue;
+      }
 
-        string16 title = contents->GetTitle();
-        if (!title.length())
-          title = l10n_util::GetStringUTF16(IDS_DEFAULT_TAB_TITLE);
-        process.titles.push_back(title);
+      // Since we have a WebContents and and the renderer type hasn't been
+      // set yet, it must be a normal tabbed renderer.
+      if (process.renderer_type == ProcessMemoryInformation::RENDERER_UNKNOWN)
+        process.renderer_type = ProcessMemoryInformation::RENDERER_NORMAL;
 
-        // We need to check the pending entry as well as the virtual_url to
-        // see if it's a chrome://memory URL (we don't want to count these in
-        // the total memory usage of the browser).
-        //
-        // When we reach here, chrome://memory will be the pending entry since
-        // we haven't responded with any data such that it would be committed.
-        // If you have another chrome://memory tab open (which would be
-        // committed), we don't want to count it either, so we also check the
-        // last committed entry.
-        //
-        // Either the pending or last committed entries can be NULL.
-        const NavigationEntry* pending_entry =
-            contents->GetController().GetPendingEntry();
-        const NavigationEntry* last_committed_entry =
-            contents->GetController().GetLastCommittedEntry();
-        if ((last_committed_entry &&
-             LowerCaseEqualsASCII(last_committed_entry->GetVirtualURL().spec(),
-                                  chrome::kChromeUIMemoryURL)) ||
-            (pending_entry &&
-             LowerCaseEqualsASCII(pending_entry->GetVirtualURL().spec(),
-                                  chrome::kChromeUIMemoryURL)))
-          process.is_diagnostics = true;
+      string16 title = contents->GetTitle();
+      if (!title.length())
+        title = l10n_util::GetStringUTF16(IDS_DEFAULT_TAB_TITLE);
+      process.titles.push_back(title);
+
+      // We need to check the pending entry as well as the virtual_url to
+      // see if it's a chrome://memory URL (we don't want to count these in
+      // the total memory usage of the browser).
+      //
+      // When we reach here, chrome://memory will be the pending entry since
+      // we haven't responded with any data such that it would be committed.
+      // If you have another chrome://memory tab open (which would be
+      // committed), we don't want to count it either, so we also check the
+      // last committed entry.
+      //
+      // Either the pending or last committed entries can be NULL.
+      const NavigationEntry* pending_entry =
+          contents->GetController().GetPendingEntry();
+      const NavigationEntry* last_committed_entry =
+          contents->GetController().GetLastCommittedEntry();
+      if ((last_committed_entry &&
+           LowerCaseEqualsASCII(last_committed_entry->GetVirtualURL().spec(),
+                                chrome::kChromeUIMemoryURL)) ||
+          (pending_entry &&
+           LowerCaseEqualsASCII(pending_entry->GetVirtualURL().spec(),
+                                chrome::kChromeUIMemoryURL))) {
+        process.is_diagnostics = true;
       }
     }
 
diff --git a/chrome/browser/metrics/chrome_browser_main_extra_parts_metrics.cc b/chrome/browser/metrics/chrome_browser_main_extra_parts_metrics.cc
index 90f3855..7e50792 100644
--- a/chrome/browser/metrics/chrome_browser_main_extra_parts_metrics.cc
+++ b/chrome/browser/metrics/chrome_browser_main_extra_parts_metrics.cc
@@ -11,7 +11,7 @@
 #include "base/cpu.h"
 #include "base/metrics/histogram.h"
 #include "base/threading/sequenced_worker_pool.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/about_flags.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chrome_browser_main.h"
diff --git a/chrome/browser/metrics/metrics_log.cc b/chrome/browser/metrics/metrics_log.cc
index 75c68f1..bc8a7e7 100644
--- a/chrome/browser/metrics/metrics_log.cc
+++ b/chrome/browser/metrics/metrics_log.cc
@@ -21,7 +21,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/sys_info.h"
 #include "base/third_party/nspr/prtime.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "base/tracked_objects.h"
 #include "chrome/browser/autocomplete/autocomplete_input.h"
 #include "chrome/browser/autocomplete/autocomplete_match.h"
@@ -46,9 +46,9 @@
 #include "device/bluetooth/bluetooth_adapter.h"
 #include "device/bluetooth/bluetooth_adapter_factory.h"
 #include "device/bluetooth/bluetooth_device.h"
-#include "googleurl/src/gurl.h"
 #include "gpu/config/gpu_info.h"
 #include "ui/gfx/screen.h"
+#include "url/gurl.h"
 #include "webkit/plugins/webplugininfo.h"
 
 #if defined(OS_ANDROID)
@@ -165,8 +165,6 @@
       return ProfilerEventProto::TrackedObject::PPAPI_PLUGIN;
     case content::PROCESS_TYPE_PPAPI_BROKER:
       return ProfilerEventProto::TrackedObject::PPAPI_BROKER;
-    case PROCESS_TYPE_PROFILE_IMPORT:
-      return ProfilerEventProto::TrackedObject::PROFILE_IMPORT;
     case PROCESS_TYPE_NACL_LOADER:
       return ProfilerEventProto::TrackedObject::NACL_LOADER;
     case PROCESS_TYPE_NACL_BROKER:
@@ -420,8 +418,6 @@
   OPEN_ELEMENT_FOR_SCOPE("profile");
   WriteCommonEventAttributes();
 
-  WriteInstallElement();
-
   {
     OPEN_ELEMENT_FOR_SCOPE("stability");  // Minimal set of stability elements.
     WriteRequiredStabilityAttributes(pref);
@@ -688,56 +684,21 @@
 }
 
 void MetricsLog::WritePluginList(
-    const std::vector<webkit::WebPluginInfo>& plugin_list,
-    bool write_as_xml) {
+    const std::vector<webkit::WebPluginInfo>& plugin_list) {
   DCHECK(!locked());
 
-  OPEN_ELEMENT_FOR_SCOPE("plugins");
-
 #if defined(ENABLE_PLUGINS)
   PluginPrefs* plugin_prefs = GetPluginPrefs();
   SystemProfileProto* system_profile = uma_proto()->mutable_system_profile();
   for (std::vector<webkit::WebPluginInfo>::const_iterator iter =
            plugin_list.begin();
        iter != plugin_list.end(); ++iter) {
-    if (write_as_xml) {
-      std::string base64_name_hash;
-      uint64 numeric_hash_ignored;
-      CreateHashes(UTF16ToUTF8(iter->name), &base64_name_hash,
-                   &numeric_hash_ignored);
-
-      std::string filename_bytes = iter->path.BaseName().AsUTF8Unsafe();
-      std::string base64_filename_hash;
-      CreateHashes(filename_bytes, &base64_filename_hash,
-                   &numeric_hash_ignored);
-
-      // Write the XML version.
-      OPEN_ELEMENT_FOR_SCOPE("plugin");
-
-      // Plugin name and filename are hashed for the privacy of those
-      // testing unreleased new extensions.
-      WriteAttribute("name", base64_name_hash);
-      WriteAttribute("filename", base64_filename_hash);
-      WriteAttribute("version", UTF16ToUTF8(iter->version));
-      if (plugin_prefs)
-        WriteIntAttribute("disabled", !plugin_prefs->IsPluginEnabled(*iter));
-    } else {
-      // Write the protobuf version.
-      SystemProfileProto::Plugin* plugin = system_profile->add_plugin();
-      SetPluginInfo(*iter, plugin_prefs, plugin);
-    }
+    SystemProfileProto::Plugin* plugin = system_profile->add_plugin();
+    SetPluginInfo(*iter, plugin_prefs, plugin);
   }
 #endif  // defined(ENABLE_PLUGINS)
 }
 
-void MetricsLog::WriteInstallElement() {
-  // Write the XML version.
-  // We'll write the protobuf version in RecordEnvironmentProto().
-  OPEN_ELEMENT_FOR_SCOPE("install");
-  WriteAttribute("installdate", GetMetricsEnabledDate(GetPrefService()));
-  WriteIntAttribute("buildid", 0);  // We're using appversion instead.
-}
-
 void MetricsLog::RecordEnvironment(
          const std::vector<webkit::WebPluginInfo>& plugin_list,
          const GoogleUpdateMetrics& google_update_metrics,
@@ -749,13 +710,6 @@
   OPEN_ELEMENT_FOR_SCOPE("profile");
   WriteCommonEventAttributes();
 
-  WriteInstallElement();
-
-  // Write the XML version.
-  // We'll write the protobuf version in RecordEnvironmentProto().
-  bool write_as_xml = true;
-  WritePluginList(plugin_list, write_as_xml);
-
   WriteStabilityElement(plugin_list, pref);
 
   {
@@ -912,8 +866,7 @@
 
   WriteGoogleUpdateProto(google_update_metrics);
 
-  bool write_as_xml = false;
-  WritePluginList(plugin_list, write_as_xml);
+  WritePluginList(plugin_list);
 
   std::vector<ActiveGroupId> field_trial_ids;
   GetFieldTrialIds(&field_trial_ids);
@@ -1020,55 +973,10 @@
 void MetricsLog::RecordOmniboxOpenedURL(const OmniboxLog& log) {
   DCHECK(!locked());
 
-  // Write the XML version.
-  OPEN_ELEMENT_FOR_SCOPE("uielement");
-  WriteAttribute("action", "autocomplete");
-  WriteAttribute("targetidhash", std::string());
-  // TODO(kochi): Properly track windows.
-  WriteIntAttribute("window", 0);
-  if (log.tab_id != -1) {
-    // If we know what tab the autocomplete URL was opened in, log it.
-    WriteIntAttribute("tab", static_cast<int>(log.tab_id));
-  }
-  WriteCommonEventAttributes();
-
   std::vector<string16> terms;
   const int num_terms =
       static_cast<int>(Tokenize(log.text, kWhitespaceUTF16, &terms));
-  {
-    OPEN_ELEMENT_FOR_SCOPE("autocomplete");
 
-    WriteIntAttribute("typedlength", static_cast<int>(log.text.length()));
-    WriteIntAttribute("numterms", num_terms);
-    WriteIntAttribute("selectedindex", static_cast<int>(log.selected_index));
-    WriteIntAttribute("completedlength",
-                      log.completed_length != string16::npos ?
-                      static_cast<int>(log.completed_length) : 0);
-    if (log.elapsed_time_since_user_first_modified_omnibox !=
-        base::TimeDelta::FromMilliseconds(-1)) {
-      // Only upload the typing duration if it is set/valid.
-      WriteInt64Attribute("typingduration",
-          log.elapsed_time_since_user_first_modified_omnibox.InMilliseconds());
-    }
-    const std::string input_type(
-        AutocompleteInput::TypeToString(log.input_type));
-    if (!input_type.empty())
-      WriteAttribute("inputtype", input_type);
-
-    for (AutocompleteResult::const_iterator i(log.result.begin());
-         i != log.result.end(); ++i) {
-      OPEN_ELEMENT_FOR_SCOPE("autocompleteitem");
-      if (i->provider)
-        WriteAttribute("provider", i->provider->GetName());
-      const std::string result_type(AutocompleteMatchType::ToString(i->type));
-      if (!result_type.empty())
-        WriteAttribute("resulttype", result_type);
-      WriteIntAttribute("relevance", i->relevance);
-      WriteIntAttribute("isstarred", i->starred ? 1 : 0);
-    }
-  }
-
-  // Write the protobuf version.
   OmniboxEventProto* omnibox_event = uma_proto()->add_omnibox_event();
   omnibox_event->set_time(MetricsLogBase::GetCurrentTime());
   if (log.tab_id != -1) {
diff --git a/chrome/browser/metrics/metrics_log.h b/chrome/browser/metrics/metrics_log.h
index 303720c..86c84cc 100644
--- a/chrome/browser/metrics/metrics_log.h
+++ b/chrome/browser/metrics/metrics_log.h
@@ -170,14 +170,8 @@
   // chromium processes (ones that don't crash, and keep on running).
   void WriteRealtimeStabilityAttributes(PrefService* pref);
 
-  // Writes the list of installed plugins.  If |write_as_xml| is true, writes
-  // the XML version.  Otherwise, writes the protobuf version.
-  void WritePluginList(
-      const std::vector<webkit::WebPluginInfo>& plugin_list,
-      bool write_as_xml);
-
-  // Within the profile group, write basic install info including appversion.
-  void WriteInstallElement();
+  // Writes the list of installed plugins.
+  void WritePluginList(const std::vector<webkit::WebPluginInfo>& plugin_list);
 
   // Writes all profile metrics. This invokes WriteProfileMetrics for each key
   // in all_profiles_metrics that starts with kProfilePrefix.
diff --git a/chrome/browser/metrics/metrics_log_unittest.cc b/chrome/browser/metrics/metrics_log_unittest.cc
index b78c0d7..a319880 100644
--- a/chrome/browser/metrics/metrics_log_unittest.cc
+++ b/chrome/browser/metrics/metrics_log_unittest.cc
@@ -12,7 +12,7 @@
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/threading/sequenced_worker_pool.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "base/tracked_objects.h"
 #include "chrome/browser/google/google_util.h"
 #include "chrome/browser/metrics/metrics_log.h"
@@ -25,9 +25,9 @@
 #include "chrome/installer/util/google_update_settings.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/test/test_utils.h"
-#include "googleurl/src/gurl.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/gfx/size.h"
+#include "url/gurl.h"
 #include "webkit/plugins/webplugininfo.h"
 
 #if defined(OS_CHROMEOS)
diff --git a/chrome/browser/metrics/metrics_reporting_scheduler.h b/chrome/browser/metrics/metrics_reporting_scheduler.h
index 320c41b..695f6ec 100644
--- a/chrome/browser/metrics/metrics_reporting_scheduler.h
+++ b/chrome/browser/metrics/metrics_reporting_scheduler.h
@@ -8,8 +8,8 @@
 #include "base/basictypes.h"
 #include "base/callback.h"
 #include "base/memory/weak_ptr.h"
-#include "base/time.h"
-#include "base/timer.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
 
 // Scheduler task to drive a MetricsService object's uploading.
 class MetricsReportingScheduler {
diff --git a/chrome/browser/metrics/metrics_service.cc b/chrome/browser/metrics/metrics_service.cc
index 024ec22..1a7c769 100644
--- a/chrome/browser/metrics/metrics_service.cc
+++ b/chrome/browser/metrics/metrics_service.cc
@@ -36,7 +36,7 @@
 // the MS was first constructed.  Note that even though the initial log is
 // commonly sent a full minute after startup, the initial log does not include
 // much in the way of user stats.   The most common interlog period (delay)
-// is 20 minutes. That time period starts when the first user action causes a
+// is 30 minutes. That time period starts when the first user action causes a
 // logging event.  This means that if there is no user action, there may be long
 // periods without any (ongoing) log transmissions.  Ongoing logs typically
 // contain very detailed records of user activities (ex: opened tab, closed
@@ -188,6 +188,7 @@
 #include "chrome/browser/search_engines/template_url_service.h"
 #include "chrome/browser/ui/browser_list.h"
 #include "chrome/browser/ui/browser_otr_state.h"
+#include "chrome/browser/ui/search/search_tab_helper.h"
 #include "chrome/common/child_process_logging.h"
 #include "chrome/common/chrome_notification_types.h"
 #include "chrome/common/chrome_process_type.h"
@@ -291,9 +292,9 @@
 }
 
 // The argument used to generate a non-identifying entropy source. We want no
-// more than 13 bits of entropy, so use this max to return a number between 1
-// and 2^13 = 8192 as the entropy source.
-const uint32 kMaxLowEntropySize = (1 << 13);
+// more than 13 bits of entropy, so use this max to return a number in the range
+// [0, 7999] as the entropy source (12.97 bits of entropy).
+const int kMaxLowEntropySize = 8000;
 
 // Default prefs value for prefs::kMetricsLowEntropySource to indicate that the
 // value has not yet been set.
@@ -705,9 +706,13 @@
       LogLoadComplete(type, source, details);
       break;
 
-    case content::NOTIFICATION_LOAD_START:
-      LogLoadStarted();
+    case content::NOTIFICATION_LOAD_START: {
+      content::NavigationController* controller =
+          content::Source<content::NavigationController>(source).ptr();
+      content::WebContents* web_contents = controller->GetWebContents();
+      LogLoadStarted(web_contents);
       break;
+    }
 
     case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: {
         content::RenderProcessHost::RendererClosedDetails* process_details =
@@ -1043,13 +1048,17 @@
   // Only try to load the value from prefs if the user did not request a reset.
   // Otherwise, skip to generating a new value.
   if (!command_line->HasSwitch(switches::kResetVariationState)) {
-    const int value = local_state->GetInteger(prefs::kMetricsLowEntropySource);
-    if (value != kLowEntropySourceNotSet) {
-      // Ensure the prefs value is in the range [0, kMaxLowEntropySize). Old
-      // versions of the code would generate values in the range of [1, 8192],
-      // so the below line ensures 8192 gets mapped to 0 and also guards against
-      // the case of corrupted values.
-      low_entropy_source_ = value % kMaxLowEntropySize;
+    int value = local_state->GetInteger(prefs::kMetricsLowEntropySource);
+    // Old versions of the code would generate values in the range of [1, 8192],
+    // before the range was switched to [0, 8191] and then to [0, 7999]. Map
+    // 8192 to 0, so that the 0th bucket remains uniform, while re-generating
+    // the low entropy source for old values in the [8000, 8191] range.
+    if (value == 8192)
+      value = 0;
+    // If the value is outside the [0, kMaxLowEntropySize) range, re-generate
+    // it below.
+    if (value >= 0 && value < kMaxLowEntropySize) {
+      low_entropy_source_ = value;
       UMA_HISTOGRAM_BOOLEAN("UMA.GeneratedLowEntropySource", false);
       return low_entropy_source_;
     }
@@ -1569,13 +1578,23 @@
   pref->SetInt64(path, value + 1);
 }
 
-void MetricsService::LogLoadStarted() {
+void MetricsService::LogLoadStarted(content::WebContents* web_contents) {
   content::RecordAction(content::UserMetricsAction("PageLoad"));
   HISTOGRAM_ENUMERATION("Chrome.UmaPageloadCounter", 1, 2);
   IncrementPrefValue(prefs::kStabilityPageLoadCount);
   IncrementLongPrefsValue(prefs::kUninstallMetricsPageLoadCount);
   // We need to save the prefs, as page load count is a critical stat, and it
   // might be lost due to a crash :-(.
+
+  // Track whether the page loaded is a search results page.
+  if (web_contents) {
+    SearchTabHelper* search_tab_helper =
+        SearchTabHelper::FromWebContents(web_contents);
+    if (search_tab_helper) {
+      if (search_tab_helper->model()->mode().is_search_results())
+        content::RecordAction(content::UserMetricsAction("PageLoadSRP"));
+    }
+  }
 }
 
 void MetricsService::LogRendererCrash(content::RenderProcessHost* host,
diff --git a/chrome/browser/metrics/metrics_service.h b/chrome/browser/metrics/metrics_service.h
index 365e857..52c9152 100644
--- a/chrome/browser/metrics/metrics_service.h
+++ b/chrome/browser/metrics/metrics_service.h
@@ -45,6 +45,7 @@
 
 namespace content {
 class RenderProcessHost;
+class WebContents;
 }
 
 namespace extensions {
@@ -385,8 +386,9 @@
   // buffered plugin stability statistics.
   void RecordCurrentState(PrefService* pref);
 
-  // Logs the initiation of a page load
-  void LogLoadStarted();
+  // Logs the initiation of a page load and uses |web_contents| to do
+  // additional logging of the type of page loaded.
+  void LogLoadStarted(content::WebContents* web_contents);
 
   // Records a page load notification.
   void LogLoadComplete(int type,
diff --git a/chrome/browser/metrics/metrics_service_browsertest.cc b/chrome/browser/metrics/metrics_service_browsertest.cc
index 7545615..228dbd3 100644
--- a/chrome/browser/metrics/metrics_service_browsertest.cc
+++ b/chrome/browser/metrics/metrics_service_browsertest.cc
@@ -21,9 +21,9 @@
 #include "chrome/test/base/ui_test_utils.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/notification_types.h"
-#include "googleurl/src/gurl.h"
 #include "net/base/net_util.h"
 #include "ui/base/window_open_disposition.h"
+#include "url/gurl.h"
 
 class MetricsServiceBrowserTest : public InProcessBrowserTest {
  public:
diff --git a/chrome/browser/metrics/perf_provider_chromeos.h b/chrome/browser/metrics/perf_provider_chromeos.h
index e3130be..6ba943e 100644
--- a/chrome/browser/metrics/perf_provider_chromeos.h
+++ b/chrome/browser/metrics/perf_provider_chromeos.h
@@ -9,8 +9,8 @@
 
 #include "base/basictypes.h"
 #include "base/threading/non_thread_safe.h"
-#include "base/time.h"
-#include "base/timer.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
 #include "chrome/common/metrics/proto/perf_data.pb.h"
 
 namespace metrics {
diff --git a/chrome/browser/metrics/thread_watcher.h b/chrome/browser/metrics/thread_watcher.h
index 0e7fd6c..487d6de 100644
--- a/chrome/browser/metrics/thread_watcher.h
+++ b/chrome/browser/metrics/thread_watcher.h
@@ -57,7 +57,7 @@
 #include "base/threading/platform_thread.h"
 #include "base/threading/thread.h"
 #include "base/threading/watchdog.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
diff --git a/chrome/browser/metrics/thread_watcher_unittest.cc b/chrome/browser/metrics/thread_watcher_unittest.cc
index fdd03ec..6670722 100644
--- a/chrome/browser/metrics/thread_watcher_unittest.cc
+++ b/chrome/browser/metrics/thread_watcher_unittest.cc
@@ -16,7 +16,7 @@
 #include "base/synchronization/condition_variable.h"
 #include "base/synchronization/lock.h"
 #include "base/threading/platform_thread.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "build/build_config.h"
 #include "chrome/browser/metrics/thread_watcher.h"
 #include "chrome/common/chrome_switches.h"
diff --git a/chrome/browser/metrics/variations/variations_http_header_provider.cc b/chrome/browser/metrics/variations/variations_http_header_provider.cc
index 6a0e565..ebdf773 100644
--- a/chrome/browser/metrics/variations/variations_http_header_provider.cc
+++ b/chrome/browser/metrics/variations/variations_http_header_provider.cc
@@ -38,8 +38,7 @@
   //    for this install of Chrome.
   // 4. For the X-Chrome-Variations, only include non-empty variation IDs.
   if (incognito ||
-      !google_util::IsGoogleDomainUrl(url.spec(),
-                                      google_util::ALLOW_SUBDOMAIN,
+      !google_util::IsGoogleDomainUrl(url, google_util::ALLOW_SUBDOMAIN,
                                       google_util::ALLOW_NON_STANDARD_PORTS)) {
     return;
   }
diff --git a/chrome/browser/metrics/variations/variations_registry_syncer_win.h b/chrome/browser/metrics/variations/variations_registry_syncer_win.h
index 297a3ca..18ad9d5 100644
--- a/chrome/browser/metrics/variations/variations_registry_syncer_win.h
+++ b/chrome/browser/metrics/variations/variations_registry_syncer_win.h
@@ -5,7 +5,7 @@
 #ifndef CHROME_BROWSER_METRICS_VARIATIONS_VARIATIONS_REGISTRY_SYNCER_WIN_H_
 #define CHROME_BROWSER_METRICS_VARIATIONS_VARIATIONS_REGISTRY_SYNCER_WIN_H_
 
-#include "base/timer.h"
+#include "base/timer/timer.h"
 
 namespace chrome_variations {
 
diff --git a/chrome/browser/metrics/variations/variations_request_scheduler.h b/chrome/browser/metrics/variations/variations_request_scheduler.h
index e6113ed..beb3bbf 100644
--- a/chrome/browser/metrics/variations/variations_request_scheduler.h
+++ b/chrome/browser/metrics/variations/variations_request_scheduler.h
@@ -6,8 +6,9 @@
 #define CHROME_BROWSER_METRICS_VARIATIONS_VARIATIONS_REQUEST_SCHEDULER_H_
 
 #include "base/bind.h"
-#include "base/time.h"
-#include "base/timer.h"
+#include "base/gtest_prod_util.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
 
 class PrefService;
 
@@ -40,6 +41,9 @@
   base::Closure task() const;
 
  private:
+  FRIEND_TEST_ALL_PREFIXES(VariationsRequestSchedulerTest,
+                           ScheduleFetchShortly);
+
   // The task scheduled by this class.
   base::Closure task_;
 
diff --git a/chrome/browser/metrics/variations/variations_request_scheduler_unittest.cc b/chrome/browser/metrics/variations/variations_request_scheduler_unittest.cc
new file mode 100644
index 0000000..f69a0b8
--- /dev/null
+++ b/chrome/browser/metrics/variations/variations_request_scheduler_unittest.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/metrics/variations/variations_request_scheduler.h"
+
+#include "base/bind.h"
+#include "base/message_loop.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace chrome_variations {
+
+namespace {
+
+void DoNothing() {
+}
+
+}  // namespace
+
+TEST(VariationsRequestSchedulerTest, ScheduleFetchShortly) {
+  base::MessageLoopForUI message_loop_;
+
+  const base::Closure task = base::Bind(&DoNothing);
+  VariationsRequestScheduler scheduler(task);
+  EXPECT_FALSE(scheduler.one_shot_timer_.IsRunning());
+
+  scheduler.ScheduleFetchShortly();
+  EXPECT_TRUE(scheduler.one_shot_timer_.IsRunning());
+}
+
+}  // namespace chrome_variations
diff --git a/chrome/browser/metrics/variations/variations_service.cc b/chrome/browser/metrics/variations/variations_service.cc
index 2b1bb3b..614290c 100644
--- a/chrome/browser/metrics/variations/variations_service.cc
+++ b/chrome/browser/metrics/variations/variations_service.cc
@@ -24,7 +24,6 @@
 #include "chrome/common/pref_names.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/common/url_fetcher.h"
-#include "googleurl/src/gurl.h"
 #include "net/base/load_flags.h"
 #include "net/base/net_errors.h"
 #include "net/base/network_change_notifier.h"
@@ -34,6 +33,7 @@
 #include "net/http/http_util.h"
 #include "net/url_request/url_fetcher.h"
 #include "net/url_request/url_request_status.h"
+#include "url/gurl.h"
 
 #if defined(OS_CHROMEOS)
 #include "chrome/browser/chromeos/settings/cros_settings.h"
diff --git a/chrome/browser/metrics/variations/variations_service.h b/chrome/browser/metrics/variations/variations_service.h
index 35c2723..9275786 100644
--- a/chrome/browser/metrics/variations/variations_service.h
+++ b/chrome/browser/metrics/variations/variations_service.h
@@ -11,14 +11,14 @@
 #include "base/gtest_prod_util.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/metrics/field_trial.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/metrics/proto/study.pb.h"
 #include "chrome/browser/metrics/proto/trials_seed.pb.h"
 #include "chrome/browser/metrics/variations/variations_request_scheduler.h"
 #include "chrome/browser/web_resource/resource_request_allowed_notifier.h"
 #include "chrome/common/chrome_version_info.h"
-#include "googleurl/src/gurl.h"
 #include "net/url_request/url_fetcher_delegate.h"
+#include "url/gurl.h"
 
 #if defined(OS_WIN)
 #include "chrome/browser/metrics/variations/variations_registry_syncer_win.h"
diff --git a/chrome/browser/metro_viewer/chrome_metro_viewer_process_host_aurawin.cc b/chrome/browser/metro_viewer/chrome_metro_viewer_process_host_aurawin.cc
index 268510e..3518726 100644
--- a/chrome/browser/metro_viewer/chrome_metro_viewer_process_host_aurawin.cc
+++ b/chrome/browser/metro_viewer/chrome_metro_viewer_process_host_aurawin.cc
@@ -9,9 +9,7 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/browser_process_platform_part_aurawin.h"
 #include "chrome/browser/profiles/profile_manager.h"
-#include "chrome/browser/search_engines/template_url.h"
-#include "chrome/browser/search_engines/template_url_service.h"
-#include "chrome/browser/search_engines/template_url_service_factory.h"
+#include "chrome/browser/search_engines/util.h"
 #include "chrome/browser/ui/ash/ash_init.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_finder.h"
@@ -24,9 +22,9 @@
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/page_navigator.h"
 #include "content/public/browser/web_contents.h"
-#include "googleurl/src/gurl.h"
 #include "ui/aura/remote_root_window_host_win.h"
 #include "ui/surface/accelerated_surface_win.h"
+#include "url/gurl.h"
 
 namespace {
 
@@ -57,12 +55,10 @@
 
 }  // namespace
 
-ChromeMetroViewerProcessHost::ChromeMetroViewerProcessHost(
-    const std::string& ipc_channel_name)
-        : MetroViewerProcessHost(
-              ipc_channel_name,
-              content::BrowserThread::GetMessageLoopProxyForThread(
-                  content::BrowserThread::IO)) {
+ChromeMetroViewerProcessHost::ChromeMetroViewerProcessHost()
+    : MetroViewerProcessHost(
+          content::BrowserThread::GetMessageLoopProxyForThread(
+              content::BrowserThread::IO)) {
   g_browser_process->AddRefModule();
 }
 
@@ -107,15 +103,8 @@
 
 void ChromeMetroViewerProcessHost::OnHandleSearchRequest(
     const string16& search_string) {
-  const TemplateURL* default_provider =
-      TemplateURLServiceFactory::GetForProfile(
-          ProfileManager::GetDefaultProfileOrOffTheRecord())->
-              GetDefaultSearchProvider();
-  if (default_provider) {
-    const TemplateURLRef& search_url = default_provider->url_ref();
-    DCHECK(search_url.SupportsReplacement());
-    GURL request_url = GURL(search_url.ReplaceSearchTerms(
-        TemplateURLRef::SearchTermsArgs(search_string)));
-    OpenURL(request_url);
-  }
+  GURL url(GetDefaultSearchURLForSearchTerms(
+      ProfileManager::GetDefaultProfileOrOffTheRecord(), search_string));
+  if (url.is_valid())
+    OpenURL(url);
 }
diff --git a/chrome/browser/metro_viewer/chrome_metro_viewer_process_host_aurawin.h b/chrome/browser/metro_viewer/chrome_metro_viewer_process_host_aurawin.h
index 826deb2..96ff005 100644
--- a/chrome/browser/metro_viewer/chrome_metro_viewer_process_host_aurawin.h
+++ b/chrome/browser/metro_viewer/chrome_metro_viewer_process_host_aurawin.h
@@ -5,13 +5,11 @@
 #ifndef CHROME_BROWSER_METRO_VIEWER_CHROME_METRO_VIEWER_PROCESS_HOST_AURAWIN_H_
 #define CHROME_BROWSER_METRO_VIEWER_CHROME_METRO_VIEWER_PROCESS_HOST_AURAWIN_H_
 
-#include <string>
-
 #include "win8/viewer/metro_viewer_process_host.h"
 
 class ChromeMetroViewerProcessHost : public win8::MetroViewerProcessHost {
  public:
-  explicit ChromeMetroViewerProcessHost(const std::string& ipc_channel_name);
+  ChromeMetroViewerProcessHost();
 
  private:
   // win8::MetroViewerProcessHost implementation
diff --git a/chrome/browser/nacl_host/nacl_broker_host_win.cc b/chrome/browser/nacl_host/nacl_broker_host_win.cc
index 2115adb..74e4161 100644
--- a/chrome/browser/nacl_host/nacl_broker_host_win.cc
+++ b/chrome/browser/nacl_host/nacl_broker_host_win.cc
@@ -8,13 +8,13 @@
 #include "base/path_service.h"
 #include "ipc/ipc_switches.h"
 #include "chrome/browser/nacl_host/nacl_broker_service_win.h"
-#include "chrome/browser/nacl_host/nacl_process_host.h"
-#include "chrome/common/chrome_constants.h"
+#include "chrome/browser/nacl_host/nacl_browser.h"
 #include "chrome/common/chrome_process_type.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/logging_chrome.h"
 #include "chrome/common/nacl_cmd_line.h"
 #include "chrome/common/nacl_messages.h"
+#include "components/nacl/common/nacl_switches.h"
 #include "content/public/browser/browser_child_process_host.h"
 #include "content/public/browser/child_process_data.h"
 #include "content/public/common/child_process_host.h"
@@ -52,11 +52,10 @@
     return false;
 
   // Create the path to the nacl broker/loader executable.
-  base::FilePath module_path;
-  if (!PathService::Get(base::FILE_MODULE, &module_path))
+  base::FilePath nacl_path;
+  if (!NaClBrowser::GetInstance()->GetNaCl64ExePath(&nacl_path))
     return false;
 
-  base::FilePath nacl_path = module_path.DirName().Append(chrome::kNaClAppName);
   CommandLine* cmd_line = new CommandLine(nacl_path);
   nacl::CopyNaClCommandLineArguments(cmd_line);
 
diff --git a/chrome/browser/nacl_host/nacl_browser.cc b/chrome/browser/nacl_host/nacl_browser.cc
index e6811d3..9cf4bcd 100644
--- a/chrome/browser/nacl_host/nacl_browser.cc
+++ b/chrome/browser/nacl_host/nacl_browser.cc
@@ -19,7 +19,7 @@
 #include "chrome/common/chrome_switches.h"
 #include "content/public/browser/browser_thread.h"
 #include "extensions/common/url_pattern.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 namespace {
 
@@ -101,7 +101,7 @@
 
 void RemoveCache(const base::FilePath& filename,
                  const base::Closure& callback) {
-  file_util::Delete(filename, false);
+  base::Delete(filename, false);
   content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE,
                                    callback);
 }
@@ -197,6 +197,18 @@
   }
 }
 
+#if defined(OS_WIN)
+bool NaClBrowser::GetNaCl64ExePath(base::FilePath* exe_path) {
+  base::FilePath module_path;
+  if (!PathService::Get(base::FILE_MODULE, &module_path)) {
+    LOG(ERROR) << "NaCl process launch failed: could not resolve module";
+    return false;
+  }
+  *exe_path = module_path.DirName().Append(L"nacl64");
+  return true;
+}
+#endif
+
 NaClBrowser* NaClBrowser::GetInstance() {
   return Singleton<NaClBrowser>::get();
 }
diff --git a/chrome/browser/nacl_host/nacl_browser.h b/chrome/browser/nacl_host/nacl_browser.h
index e2f041e..77bae0f 100644
--- a/chrome/browser/nacl_host/nacl_browser.h
+++ b/chrome/browser/nacl_host/nacl_browser.h
@@ -109,6 +109,11 @@
   bool QueryKnownToValidate(const std::string& signature, bool off_the_record);
   void SetKnownToValidate(const std::string& signature, bool off_the_record);
   void ClearValidationCache(const base::Closure& callback);
+#if defined(OS_WIN)
+  // Get path to NaCl loader on the filesystem if possible.
+  // |exe_path| does not change if the method fails.
+  bool GetNaCl64ExePath(base::FilePath* exe_path);
+#endif
 
  private:
   friend struct DefaultSingletonTraits<NaClBrowser>;
diff --git a/chrome/browser/nacl_host/nacl_file_host.cc b/chrome/browser/nacl_host/nacl_file_host.cc
index 788876e..1acca3a 100644
--- a/chrome/browser/nacl_host/nacl_file_host.cc
+++ b/chrome/browser/nacl_host/nacl_file_host.cc
@@ -11,6 +11,8 @@
 #include "base/platform_file.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/sequenced_worker_pool.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/component_updater/pnacl/pnacl_component_installer.h"
 #include "chrome/browser/extensions/extension_info_map.h"
 #include "chrome/browser/nacl_host/nacl_browser.h"
 #include "chrome/browser/nacl_host/nacl_host_message_filter.h"
@@ -58,10 +60,64 @@
 void DoOpenPnaclFile(
     scoped_refptr<NaClHostMessageFilter> nacl_host_message_filter,
     const std::string& filename,
+    IPC::Message* reply_msg);
+
+void PnaclCheckDone(
+    scoped_refptr<NaClHostMessageFilter> nacl_host_message_filter,
+    const std::string& filename,
+    IPC::Message* reply_msg,
+    bool success) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  if (!success) {
+    NotifyRendererOfError(nacl_host_message_filter.get(), reply_msg);
+  } else {
+    if (!BrowserThread::PostBlockingPoolTask(
+            FROM_HERE,
+            base::Bind(&DoOpenPnaclFile,
+                       nacl_host_message_filter,
+                       filename,
+                       reply_msg))) {
+      NotifyRendererOfError(nacl_host_message_filter.get(), reply_msg);
+    }
+  }
+}
+
+void TryInstallPnacl(
+    scoped_refptr<NaClHostMessageFilter> nacl_host_message_filter,
+    const std::string& filename,
+    IPC::Message* reply_msg) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  ComponentUpdateService* cus = g_browser_process->component_updater();
+  PnaclComponentInstaller* pci =
+      g_browser_process->pnacl_component_installer();
+  RequestFirstInstall(cus,
+                      pci,
+                      base::Bind(&PnaclCheckDone,
+                                 nacl_host_message_filter,
+                                 filename,
+                                 reply_msg));
+}
+
+void DoOpenPnaclFile(
+    scoped_refptr<NaClHostMessageFilter> nacl_host_message_filter,
+    const std::string& filename,
     IPC::Message* reply_msg) {
   DCHECK(BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
   base::FilePath full_filepath;
 
+  // PNaCl must be installed.
+  base::FilePath pnacl_dir;
+  if (!PathService::Get(chrome::DIR_PNACL_COMPONENT, &pnacl_dir) ||
+      !file_util::PathExists(pnacl_dir)) {
+    BrowserThread::PostTask(
+        BrowserThread::UI, FROM_HERE,
+        base::Bind(&TryInstallPnacl,
+                   nacl_host_message_filter,
+                   filename,
+                   reply_msg));
+    return;
+  }
+
   // Do some validation.
   if (!nacl_file_host::PnaclCanOpenFile(filename, &full_filepath)) {
     NotifyRendererOfError(nacl_host_message_filter.get(), reply_msg);
diff --git a/chrome/browser/nacl_host/nacl_host_message_filter.cc b/chrome/browser/nacl_host/nacl_host_message_filter.cc
index 20ad21f..1cb2167 100644
--- a/chrome/browser/nacl_host/nacl_host_message_filter.cc
+++ b/chrome/browser/nacl_host/nacl_host_message_filter.cc
@@ -13,23 +13,38 @@
 #include "chrome/browser/nacl_host/nacl_file_host.h"
 #include "chrome/browser/nacl_host/nacl_infobar.h"
 #include "chrome/browser/nacl_host/nacl_process_host.h"
-#include "chrome/browser/profiles/profile.h"
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/nacl_host_messages.h"
-#include "googleurl/src/gurl.h"
+#include "extensions/common/constants.h"
 #include "net/url_request/url_request_context.h"
 #include "net/url_request/url_request_context_getter.h"
+#include "url/gurl.h"
+
+static base::FilePath GetManifestPath(
+    ExtensionInfoMap* extension_info_map, const std::string& manifest) {
+  GURL manifest_url(manifest);
+  const extensions::Extension* extension = extension_info_map->extensions()
+      .GetExtensionOrAppByURL(ExtensionURLInfo(manifest_url));
+  if (extension != NULL &&
+      manifest_url.SchemeIs(extensions::kExtensionScheme)) {
+    std::string path = manifest_url.path();
+    TrimString(path, "/", &path);  // Remove first slash
+    return extension->path().AppendASCII(path);
+  }
+  return base::FilePath();
+}
 
 NaClHostMessageFilter::NaClHostMessageFilter(
     int render_process_id,
-    Profile* profile,
+    bool is_off_the_record,
+    const base::FilePath& profile_directory,
+    ExtensionInfoMap* extension_info_map,
     net::URLRequestContextGetter* request_context)
     : render_process_id_(render_process_id),
-      profile_(profile),
-      off_the_record_(profile_->IsOffTheRecord()),
+      off_the_record_(is_off_the_record),
+      profile_directory_(profile_directory),
       request_context_(request_context),
-      extension_info_map_(
-          extensions::ExtensionSystem::Get(profile)->info_map()),
+      extension_info_map_(extension_info_map),
       weak_ptr_factory_(this) {
 }
 
@@ -72,8 +87,11 @@
       launch_params.enable_dyncode_syscalls,
       launch_params.enable_exception_handling,
       off_the_record_,
-      profile_->GetPath());
-  host->Launch(this, reply_msg, extension_info_map_);
+      profile_directory_);
+  base::FilePath manifest_url = GetManifestPath(
+        extension_info_map_,
+        launch_params.manifest_url);
+  host->Launch(this, reply_msg, manifest_url);
 }
 
 void NaClHostMessageFilter::OnGetReadonlyPnaclFd(
diff --git a/chrome/browser/nacl_host/nacl_host_message_filter.h b/chrome/browser/nacl_host/nacl_host_message_filter.h
index 61ffc74..4d9cdb0 100644
--- a/chrome/browser/nacl_host/nacl_host_message_filter.h
+++ b/chrome/browser/nacl_host/nacl_host_message_filter.h
@@ -5,12 +5,12 @@
 #ifndef CHROME_BROWSER_NACL_HOST_NACL_HOST_MESSAGE_FILTER_H_
 #define CHROME_BROWSER_NACL_HOST_NACL_HOST_MESSAGE_FILTER_H_
 
+#include "base/files/file_path.h"
 #include "base/memory/weak_ptr.h"
 #include "content/public/browser/browser_message_filter.h"
 
 class ExtensionInfoMap;
 class GURL;
-class Profile;
 
 namespace nacl {
 struct NaClLaunchParams;
@@ -26,7 +26,9 @@
 class NaClHostMessageFilter : public content::BrowserMessageFilter {
  public:
   NaClHostMessageFilter(int render_process_id,
-                        Profile* profile,
+                        bool is_off_the_record,
+                        const base::FilePath& profile_directory,
+                        ExtensionInfoMap* extension_info_map,
                         net::URLRequestContextGetter* request_context);
 
   // content::BrowserMessageFilter methods:
@@ -56,11 +58,10 @@
 #endif
   int render_process_id_;
 
-  // The Profile associated with our renderer process.  This should only be
-  // accessed on the UI thread!
-  Profile* profile_;
-  // Copied from the profile so that it can be read on the IO thread.
+  // off_the_record_ is copied from the profile partly so that it can be
+  // read on the IO thread.
   bool off_the_record_;
+  base::FilePath profile_directory_;
   scoped_refptr<net::URLRequestContextGetter> request_context_;
   scoped_refptr<ExtensionInfoMap> extension_info_map_;
 
diff --git a/chrome/browser/nacl_host/nacl_infobar.cc b/chrome/browser/nacl_host/nacl_infobar.cc
index 7583c22..e9c33d4 100644
--- a/chrome/browser/nacl_host/nacl_infobar.cc
+++ b/chrome/browser/nacl_host/nacl_infobar.cc
@@ -11,10 +11,10 @@
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/web_contents.h"
-#include "googleurl/src/gurl.h"
 #include "grit/generated_resources.h"
 #include "ppapi/c/private/ppb_nacl_private.h"
 #include "ui/base/l10n/l10n_util.h"
+#include "url/gurl.h"
 
 using content::BrowserThread;
 using content::RenderViewHost;
diff --git a/chrome/browser/nacl_host/nacl_process_host.cc b/chrome/browser/nacl_host/nacl_process_host.cc
index 6f7f50c..f713448 100644
--- a/chrome/browser/nacl_host/nacl_process_host.cc
+++ b/chrome/browser/nacl_host/nacl_process_host.cc
@@ -23,11 +23,9 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/win/windows_version.h"
 #include "build/build_config.h"
-#include "chrome/browser/extensions/extension_info_map.h"
 #include "chrome/browser/nacl_host/nacl_browser.h"
 #include "chrome/browser/nacl_host/nacl_host_message_filter.h"
 #include "chrome/browser/renderer_host/pepper/chrome_browser_pepper_host_factory.h"
-#include "chrome/common/chrome_constants.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/chrome_process_type.h"
 #include "chrome/common/chrome_switches.h"
@@ -37,12 +35,12 @@
 #include "chrome/common/nacl_host_messages.h"
 #include "chrome/common/nacl_messages.h"
 #include "chrome/common/render_messages.h"
+#include "components/nacl/common/nacl_switches.h"
 #include "content/public/browser/browser_child_process_host.h"
 #include "content/public/browser/browser_ppapi_host.h"
 #include "content/public/browser/child_process_data.h"
 #include "content/public/common/child_process_host.h"
 #include "content/public/common/process_type.h"
-#include "extensions/common/constants.h"
 #include "ipc/ipc_channel.h"
 #include "ipc/ipc_switches.h"
 #include "native_client/src/shared/imc/nacl_imc_c.h"
@@ -282,10 +280,10 @@
 void NaClProcessHost::Launch(
     NaClHostMessageFilter* nacl_host_message_filter,
     IPC::Message* reply_msg,
-    scoped_refptr<ExtensionInfoMap> extension_info_map) {
+    const base::FilePath& manifest_path) {
   nacl_host_message_filter_ = nacl_host_message_filter;
   reply_msg_ = reply_msg;
-  extension_info_map_ = extension_info_map;
+  manifest_path_ = manifest_path;
 
   // Start getting the IRT open asynchronously while we launch the NaCl process.
   // We'll make sure this actually finished in StartWithLaunchedProcess, below.
@@ -374,10 +372,9 @@
   std::replace(irt_path.begin(), irt_path.end(), '\\', '/');
   cmd_line.AppendArgNative(FILE_PATH_LITERAL("nacl-irt \"") + irt_path +
                            FILE_PATH_LITERAL("\""));
-  base::FilePath manifest_path = GetManifestPath();
-  if (!manifest_path.empty()) {
+  if (!manifest_path_.empty()) {
     cmd_line.AppendArg("--eval-command");
-    base::FilePath::StringType manifest_path_value(manifest_path.value());
+    base::FilePath::StringType manifest_path_value(manifest_path_.value());
     std::replace(manifest_path_value.begin(), manifest_path_value.end(),
                  '\\', '/');
     cmd_line.AppendArgNative(FILE_PATH_LITERAL("nacl-manifest \"") +
@@ -394,18 +391,6 @@
   return base::LaunchProcess(cmd_line, base::LaunchOptions(), NULL);
 }
 
-base::FilePath NaClProcessHost::GetManifestPath() {
-  const extensions::Extension* extension = extension_info_map_->extensions()
-      .GetExtensionOrAppByURL(ExtensionURLInfo(manifest_url_));
-  if (extension != NULL &&
-      manifest_url_.SchemeIs(extensions::kExtensionScheme)) {
-    std::string path = manifest_url_.path();
-    TrimString(path, "/", &path);  // Remove first slash
-    return extension->path().AppendASCII(path);
-  }
-  return base::FilePath();
-}
-
 bool NaClProcessHost::LaunchSelLdr() {
   std::string channel_id = process_->GetHost()->CreateChannel();
   if (channel_id.empty()) {
@@ -443,12 +428,9 @@
 #if defined(OS_WIN)
   // On Windows 64-bit NaCl loader is called nacl64.exe instead of chrome.exe
   if (RunningOnWOW64()) {
-    base::FilePath module_path;
-    if (!PathService::Get(base::FILE_MODULE, &module_path)) {
-      LOG(ERROR) << "NaCl process launch failed: could not resolve module";
+    if (!NaClBrowser::GetInstance()->GetNaCl64ExePath(&exe_path)) {
       return false;
     }
-    exe_path = module_path.DirName().Append(chrome::kNaClAppName);
   }
 #endif
 
diff --git a/chrome/browser/nacl_host/nacl_process_host.h b/chrome/browser/nacl_host/nacl_process_host.h
index 4f15e8a..4496f92 100644
--- a/chrome/browser/nacl_host/nacl_process_host.h
+++ b/chrome/browser/nacl_host/nacl_process_host.h
@@ -16,14 +16,13 @@
 #include "chrome/common/nacl_types.h"
 #include "content/public/browser/browser_child_process_host_delegate.h"
 #include "content/public/browser/browser_child_process_host_iterator.h"
-#include "googleurl/src/gurl.h"
 #include "ipc/ipc_channel_handle.h"
 #include "net/socket/tcp_listen_socket.h"
 #include "ppapi/shared_impl/ppapi_permissions.h"
+#include "url/gurl.h"
 
 class NaClHostMessageFilter;
 class CommandLine;
-class ExtensionInfoMap;
 
 namespace content {
 class BrowserChildProcessHost;
@@ -65,7 +64,7 @@
   // message reply_msg.
   void Launch(NaClHostMessageFilter* nacl_host_message_filter,
               IPC::Message* reply_msg,
-              scoped_refptr<ExtensionInfoMap> extension_info_map);
+              const base::FilePath& manifest_path);
 
   virtual void OnChannelConnected(int32 peer_pid) OVERRIDE;
 
@@ -107,8 +106,6 @@
   // is enabled.
   SocketDescriptor GetDebugStubSocketHandle();
 #endif
-  // Get path to manifest on local disk if possible.
-  base::FilePath GetManifestPath();
   bool LaunchSelLdr();
 
   // BrowserChildProcessHostDelegate implementation:
@@ -181,9 +178,9 @@
   scoped_ptr<IPC::Message> attach_debug_exception_handler_reply_msg_;
 #endif
 
-  // Set of extensions for (NaCl) manifest auto-detection. The file path to
-  // manifest is passed to nacl-gdb when it is used to debug the NaCl loader.
-  scoped_refptr<ExtensionInfoMap> extension_info_map_;
+  // The file path to the manifest is passed to nacl-gdb when it is used to
+  // debug the NaCl loader.
+  base::FilePath manifest_path_;
 
   // Socket pairs for the NaCl process and renderer.
   scoped_ptr<NaClInternal> internal_;
diff --git a/chrome/browser/nacl_host/test/nacl_gdb_browsertest.cc b/chrome/browser/nacl_host/test/nacl_gdb_browsertest.cc
index 141008e..6e1c074 100644
--- a/chrome/browser/nacl_host/test/nacl_gdb_browsertest.cc
+++ b/chrome/browser/nacl_host/test/nacl_gdb_browsertest.cc
@@ -9,6 +9,7 @@
 #include "base/win/windows_version.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/test/ppapi/ppapi_test.h"
+#include "components/nacl/common/nacl_switches.h"
 
 static const base::FilePath::CharType kMockNaClGdb[] =
 #if defined(OS_WIN)
@@ -56,12 +57,12 @@
 
     EXPECT_TRUE(file_util::ReadFileToString(mock_nacl_gdb_file, &content));
     EXPECT_STREQ("PASS", content.c_str());
-    EXPECT_TRUE(file_util::Delete(mock_nacl_gdb_file, false));
+    EXPECT_TRUE(base::Delete(mock_nacl_gdb_file, false));
 
     content.clear();
     EXPECT_TRUE(file_util::ReadFileToString(script_, &content));
     EXPECT_STREQ("PASS", content.c_str());
-    EXPECT_TRUE(file_util::Delete(script_, false));
+    EXPECT_TRUE(base::Delete(script_, false));
   }
 
  private:
diff --git a/chrome/browser/net/chrome_fraudulent_certificate_reporter.cc b/chrome/browser/net/chrome_fraudulent_certificate_reporter.cc
index c5aed31..89e8b48 100644
--- a/chrome/browser/net/chrome_fraudulent_certificate_reporter.cc
+++ b/chrome/browser/net/chrome_fraudulent_certificate_reporter.cc
@@ -9,7 +9,7 @@
 #include "base/base64.h"
 #include "base/logging.h"
 #include "base/stl_util.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/net/cert_logger.pb.h"
 #include "net/base/load_flags.h"
 #include "net/base/upload_bytes_element_reader.h"
diff --git a/chrome/browser/net/chrome_net_log.cc b/chrome/browser/net/chrome_net_log.cc
index 093b0b5..b9a417a 100644
--- a/chrome/browser/net/chrome_net_log.cc
+++ b/chrome/browser/net/chrome_net_log.cc
@@ -11,9 +11,11 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/values.h"
-#include "chrome/browser/net/net_log_logger.h"
 #include "chrome/browser/net/net_log_temp_file.h"
+#include "chrome/browser/ui/webui/net_internals/net_internals_ui.h"
 #include "chrome/common/chrome_switches.h"
+#include "content/public/common/content_switches.h"
+#include "net/base/net_log_logger.h"
 
 ChromeNetLog::ChromeNetLog()
     : net_log_temp_file_(new NetLogTempFile(this)) {
@@ -52,7 +54,8 @@
       LOG(ERROR) << "Could not open file " << log_path.value()
                  << " for net logging";
     } else {
-      net_log_logger_.reset(new NetLogLogger(file));
+      scoped_ptr<base::Value> constants(NetInternalsUI::GetConstants());
+      net_log_logger_.reset(new net::NetLogLogger(file, *constants));
       net_log_logger_->StartObserving(this);
     }
   }
diff --git a/chrome/browser/net/chrome_net_log.h b/chrome/browser/net/chrome_net_log.h
index 10e45fb..4114868 100644
--- a/chrome/browser/net/chrome_net_log.h
+++ b/chrome/browser/net/chrome_net_log.h
@@ -11,15 +11,14 @@
 #include "base/synchronization/lock.h"
 #include "net/base/net_log.h"
 
+namespace net {
 class NetLogLogger;
+}
+
 class NetLogTempFile;
 
-// ChromeNetLog is an implementation of NetLog that dispatches network log
-// messages to a list of observers.
-//
-// All methods are thread safe, with the exception that no NetLog or
-// NetLog::ThreadSafeObserver functions may be called by an observer's
-// OnAddEntry() method.  Doing so will result in a deadlock.
+// ChromeNetLog is an implementation of NetLog that adds file loggers
+// as its observers.
 class ChromeNetLog : public net::NetLog {
  public:
   ChromeNetLog();
@@ -30,7 +29,7 @@
   }
 
  private:
-  scoped_ptr<NetLogLogger> net_log_logger_;
+  scoped_ptr<net::NetLogLogger> net_log_logger_;
   scoped_ptr<NetLogTempFile> net_log_temp_file_;
 
   DISALLOW_COPY_AND_ASSIGN(ChromeNetLog);
diff --git a/chrome/browser/net/chrome_network_delegate.cc b/chrome/browser/net/chrome_network_delegate.cc
index b43b53b..6697181 100644
--- a/chrome/browser/net/chrome_network_delegate.cc
+++ b/chrome/browser/net/chrome_network_delegate.cc
@@ -136,8 +136,8 @@
 // Sets the query part of |new_url| with the new value of the parameters.
 void ForceGoogleSafeSearch(net::URLRequest* request,
                            GURL* new_url) {
-  if (!google_util::IsGoogleSearchUrl(request->url().spec()) &&
-      !google_util::IsGoogleHomePageUrl(request->url().spec()))
+  if (!google_util::IsGoogleSearchUrl(request->url()) &&
+      !google_util::IsGoogleHomePageUrl(request->url()))
     return;
 
   std::string query = request->url().query();
@@ -327,7 +327,8 @@
 }
 
 void RecordContentLengthHistograms(
-    int64 received_content_length, int64 original_content_length,
+    int64 received_content_length,
+    int64 original_content_length,
     const base::TimeDelta& freshness_lifetime) {
 #if defined(OS_ANDROID)
   // Add the current resource to these histograms only when a valid
@@ -349,10 +350,11 @@
                        original_content_length);
   UMA_HISTOGRAM_COUNTS("Net.HttpContentLengthDifference",
                        original_content_length - received_content_length);
-  UMA_HISTOGRAM_CUSTOM_TIMES("Net.HttpContentFreshnessLifetime",
-                             freshness_lifetime,
-                             base::TimeDelta::FromHours(1),
-                             base::TimeDelta::FromDays(30), 100);
+  UMA_HISTOGRAM_CUSTOM_COUNTS("Net.HttpContentFreshnessLifetime",
+                              freshness_lifetime.InSeconds(),
+                              base::TimeDelta::FromHours(1).InSeconds(),
+                              base::TimeDelta::FromDays(30).InSeconds(),
+                              100);
   if (freshness_lifetime.InSeconds() <= 0)
     return;
   UMA_HISTOGRAM_COUNTS("Net.HttpContentLengthCacheable",
diff --git a/chrome/browser/net/chrome_url_request_context.cc b/chrome/browser/net/chrome_url_request_context.cc
index c39ebec..a52fb1a 100644
--- a/chrome/browser/net/chrome_url_request_context.cc
+++ b/chrome/browser/net/chrome_url_request_context.cc
@@ -298,7 +298,8 @@
 ChromeURLRequestContext::ChromeURLRequestContext(
     ContextType type,
     chrome_browser_net::LoadTimeStats* load_time_stats)
-    : load_time_stats_(load_time_stats) {
+    : weak_factory_(this),
+      load_time_stats_(load_time_stats) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
   if (load_time_stats_)
     load_time_stats_->RegisterURLRequestContext(this, type);
diff --git a/chrome/browser/net/chrome_url_request_context.h b/chrome/browser/net/chrome_url_request_context.h
index 86f09fc..db09992 100644
--- a/chrome/browser/net/chrome_url_request_context.h
+++ b/chrome/browser/net/chrome_url_request_context.h
@@ -41,13 +41,15 @@
   virtual ~ChromeURLRequestContext();
 
   base::WeakPtr<ChromeURLRequestContext> GetWeakPtr() {
-    return base::AsWeakPtr(this);
+    return weak_factory_.GetWeakPtr();
   }
 
   // Copies the state from |other| into this context.
   void CopyFrom(ChromeURLRequestContext* other);
 
  private:
+  base::WeakPtrFactory<ChromeURLRequestContext> weak_factory_;
+
   // ---------------------------------------------------------------------------
   // Important: When adding any new members below, consider whether they need to
   // be added to CopyFrom.
diff --git a/chrome/browser/net/connection_tester.h b/chrome/browser/net/connection_tester.h
index d25c266..df1bf34 100644
--- a/chrome/browser/net/connection_tester.h
+++ b/chrome/browser/net/connection_tester.h
@@ -9,8 +9,8 @@
 
 #include "base/basictypes.h"
 #include "base/memory/scoped_ptr.h"
-#include "googleurl/src/gurl.h"
 #include "net/base/completion_callback.h"
+#include "url/gurl.h"
 
 namespace net {
 class NetLog;
diff --git a/chrome/browser/net/crl_set_fetcher.cc b/chrome/browser/net/crl_set_fetcher.cc
index eba5d7c..95fbfd3 100644
--- a/chrome/browser/net/crl_set_fetcher.cc
+++ b/chrome/browser/net/crl_set_fetcher.cc
@@ -9,7 +9,7 @@
 #include "base/path_service.h"
 #include "base/rand_util.h"
 #include "base/strings/string_number_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/component_updater/component_updater_service.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/chrome_constants.h"
@@ -205,4 +205,9 @@
   return true;
 }
 
+bool CRLSetFetcher::GetInstalledFile(
+    const std::string& file, base::FilePath* installed_file) {
+  return false;
+}
+
 CRLSetFetcher::~CRLSetFetcher() {}
diff --git a/chrome/browser/net/crl_set_fetcher.h b/chrome/browser/net/crl_set_fetcher.h
index 476e1b9..5f7bdf3 100644
--- a/chrome/browser/net/crl_set_fetcher.h
+++ b/chrome/browser/net/crl_set_fetcher.h
@@ -33,6 +33,8 @@
   virtual void OnUpdateError(int error) OVERRIDE;
   virtual bool Install(const base::DictionaryValue& manifest,
                        const base::FilePath& unpack_path) OVERRIDE;
+  virtual bool GetInstalledFile(const std::string& file,
+                                base::FilePath* installed_file) OVERRIDE;
 
  private:
   friend class base::RefCountedThreadSafe<CRLSetFetcher>;
diff --git a/chrome/browser/net/dns_probe_job.cc b/chrome/browser/net/dns_probe_job.cc
index 204484e..f51f450 100644
--- a/chrome/browser/net/dns_probe_job.cc
+++ b/chrome/browser/net/dns_probe_job.cc
@@ -8,7 +8,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/message_loop.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "net/base/address_list.h"
 #include "net/base/net_errors.h"
 #include "net/base/net_log.h"
diff --git a/chrome/browser/net/dns_probe_service.h b/chrome/browser/net/dns_probe_service.h
index c40967a..a906d75 100644
--- a/chrome/browser/net/dns_probe_service.h
+++ b/chrome/browser/net/dns_probe_service.h
@@ -9,7 +9,7 @@
 
 #include "base/basictypes.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/net/dns_probe_job.h"
 #include "chrome/common/net/net_error_info.h"
 #include "net/base/network_change_notifier.h"
diff --git a/chrome/browser/net/evicted_domain_cookie_counter.h b/chrome/browser/net/evicted_domain_cookie_counter.h
index cd952c8..5cf8797 100644
--- a/chrome/browser/net/evicted_domain_cookie_counter.h
+++ b/chrome/browser/net/evicted_domain_cookie_counter.h
@@ -12,7 +12,7 @@
 #include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "net/cookies/cookie_monster.h"
 
 namespace net {
diff --git a/chrome/browser/net/evicted_domain_cookie_counter_unittest.cc b/chrome/browser/net/evicted_domain_cookie_counter_unittest.cc
index b5831b0..ca2597d 100644
--- a/chrome/browser/net/evicted_domain_cookie_counter_unittest.cc
+++ b/chrome/browser/net/evicted_domain_cookie_counter_unittest.cc
@@ -9,12 +9,12 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/scoped_vector.h"
 #include "base/strings/string_number_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/net/evicted_domain_cookie_counter.h"
-#include "googleurl/src/gurl.h"
 #include "net/cookies/canonical_cookie.h"
 #include "net/cookies/cookie_monster.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
 
 namespace chrome_browser_net {
 
diff --git a/chrome/browser/net/ftp_browsertest.cc b/chrome/browser/net/ftp_browsertest.cc
index 283593e..50b3a6c 100644
--- a/chrome/browser/net/ftp_browsertest.cc
+++ b/chrome/browser/net/ftp_browsertest.cc
@@ -4,9 +4,9 @@
 
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
-#include "googleurl/src/gurl.h"
 #include "net/test/spawned_test_server/spawned_test_server.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
 
 class FtpBrowserTest : public InProcessBrowserTest {
  public:
diff --git a/chrome/browser/net/gaia/gaia_oauth_fetcher.h b/chrome/browser/net/gaia/gaia_oauth_fetcher.h
index 46389ca..9228cd6 100644
--- a/chrome/browser/net/gaia/gaia_oauth_fetcher.h
+++ b/chrome/browser/net/gaia/gaia_oauth_fetcher.h
@@ -10,8 +10,8 @@
 
 #include "base/memory/scoped_ptr.h"
 #include "google_apis/gaia/google_service_auth_error.h"
-#include "googleurl/src/gurl.h"
 #include "net/url_request/url_fetcher_delegate.h"
+#include "url/gurl.h"
 
 class GaiaOAuthConsumer;
 
diff --git a/chrome/browser/net/gaia/gaia_oauth_fetcher_unittest.cc b/chrome/browser/net/gaia/gaia_oauth_fetcher_unittest.cc
index 75e9d29..284d34b 100644
--- a/chrome/browser/net/gaia/gaia_oauth_fetcher_unittest.cc
+++ b/chrome/browser/net/gaia/gaia_oauth_fetcher_unittest.cc
@@ -15,13 +15,13 @@
 #include "google_apis/gaia/gaia_constants.h"
 #include "google_apis/gaia/gaia_urls.h"
 #include "google_apis/gaia/google_service_auth_error.h"
-#include "googleurl/src/gurl.h"
 #include "net/base/net_errors.h"
 #include "net/http/http_status_code.h"
 #include "net/url_request/test_url_fetcher_factory.h"
 #include "net/url_request/url_request_status.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
 
 using ::testing::_;
 
diff --git a/chrome/browser/net/http_server_properties_manager.h b/chrome/browser/net/http_server_properties_manager.h
index ad87388..a63859a 100644
--- a/chrome/browser/net/http_server_properties_manager.h
+++ b/chrome/browser/net/http_server_properties_manager.h
@@ -12,7 +12,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/prefs/pref_change_registrar.h"
-#include "base/timer.h"
+#include "base/timer/timer.h"
 #include "base/values.h"
 #include "net/base/host_port_pair.h"
 #include "net/http/http_pipelined_host_capability.h"
diff --git a/chrome/browser/net/http_server_properties_manager_unittest.cc b/chrome/browser/net/http_server_properties_manager_unittest.cc
index 5ce5584..5be9d96 100644
--- a/chrome/browser/net/http_server_properties_manager_unittest.cc
+++ b/chrome/browser/net/http_server_properties_manager_unittest.cc
@@ -11,9 +11,9 @@
 #include "base/values.h"
 #include "chrome/common/pref_names.h"
 #include "content/public/test/test_browser_thread.h"
-#include "googleurl/src/gurl.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
 
 namespace chrome_browser_net {
 
diff --git a/chrome/browser/net/load_time_stats.cc b/chrome/browser/net/load_time_stats.cc
index 8446b78..0801775 100644
--- a/chrome/browser/net/load_time_stats.cc
+++ b/chrome/browser/net/load_time_stats.cc
@@ -8,7 +8,7 @@
 #include "base/metrics/histogram.h"
 #include "base/stl_util.h"
 #include "base/strings/string_number_conversions.h"
-#include "base/timer.h"
+#include "base/timer/timer.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/io_thread.h"
 #include "chrome/browser/profiles/profile.h"
diff --git a/chrome/browser/net/load_time_stats.h b/chrome/browser/net/load_time_stats.h
index 958e922..c7ea58d 100644
--- a/chrome/browser/net/load_time_stats.h
+++ b/chrome/browser/net/load_time_stats.h
@@ -13,7 +13,7 @@
 #include "base/containers/hash_tables.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/message_loop.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/net/chrome_url_request_context.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/browser/web_contents_user_data.h"
diff --git a/chrome/browser/net/load_timing_browsertest.cc b/chrome/browser/net/load_timing_browsertest.cc
index b42bbf8..ac6e2a6 100644
--- a/chrome/browser/net/load_timing_browsertest.cc
+++ b/chrome/browser/net/load_timing_browsertest.cc
@@ -20,12 +20,12 @@
 #include "chrome/test/base/ui_test_utils.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/test/browser_test_utils.h"
-#include "googleurl/src/gurl.h"
 #include "net/base/load_timing_info.h"
 #include "net/test/spawned_test_server/spawned_test_server.h"
 #include "net/url_request/url_request_file_job.h"
 #include "net/url_request/url_request_filter.h"
 #include "net/url_request/url_request_job_factory.h"
+#include "url/gurl.h"
 
 // This file tests that net::LoadTimingInfo is correctly hooked up to the
 // NavigationTiming API.  It depends on behavior in a large number of files
diff --git a/chrome/browser/net/net_log_logger.cc b/chrome/browser/net/net_log_logger.cc
deleted file mode 100644
index 35da9ef..0000000
--- a/chrome/browser/net/net_log_logger.cc
+++ /dev/null
@@ -1,52 +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/net/net_log_logger.h"
-
-#include <stdio.h>
-
-#include "base/json/json_writer.h"
-#include "base/logging.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/values.h"
-#include "chrome/browser/ui/webui/net_internals/net_internals_ui.h"
-
-NetLogLogger::NetLogLogger(FILE* file) : file_(file), added_events_(false) {
-  DCHECK(file);
-
-  // Write constants to the output file.  This allows loading files that have
-  // different source and event types, as they may be added and removed
-  // between Chrome versions.
-  scoped_ptr<Value> value(NetInternalsUI::GetConstants());
-  std::string json;
-  base::JSONWriter::Write(value.get(), &json);
-  fprintf(file_.get(), "{\"constants\": %s,\n", json.c_str());
-  fprintf(file_.get(), "\"events\": [\n");
-}
-
-NetLogLogger::~NetLogLogger() {
-  if (file_.get())
-    fprintf(file_.get(), "]}");
-}
-
-void NetLogLogger::StartObserving(net::NetLog* net_log) {
-  net_log->AddThreadSafeObserver(this, net::NetLog::LOG_ALL_BUT_BYTES);
-}
-
-void NetLogLogger::StopObserving() {
-  net_log()->RemoveThreadSafeObserver(this);
-}
-
-void NetLogLogger::OnAddEntry(const net::NetLog::Entry& entry) {
-  // Add a comma and newline for every event but the first.  Newlines are needed
-  // so can load partial log files by just ignoring the last line.  For this to
-  // work, lines cannot be pretty printed.
-  scoped_ptr<Value> value(entry.ToValue());
-  std::string json;
-  base::JSONWriter::Write(value.get(), &json);
-  fprintf(file_.get(), "%s%s",
-          (added_events_ ? ",\n" : ""),
-          json.c_str());
-  added_events_ = true;
-}
diff --git a/chrome/browser/net/net_log_logger.h b/chrome/browser/net/net_log_logger.h
deleted file mode 100644
index bc9b19b..0000000
--- a/chrome/browser/net/net_log_logger.h
+++ /dev/null
@@ -1,52 +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_NET_NET_LOG_LOGGER_H_
-#define CHROME_BROWSER_NET_NET_LOG_LOGGER_H_
-
-#include <stdio.h>
-
-#include "base/memory/scoped_handle.h"
-#include "net/base/net_log.h"
-
-namespace base {
-class FilePath;
-}
-
-// NetLogLogger watches the NetLog event stream, and sends all entries to
-// a file specified on creation.  This is to debug errors in cases where
-// about:net-internals doesn't work well (Mobile, startup / shutdown errors,
-// errors that prevent getting to the about:net-internals).
-//
-// The text file will contain a single JSON object.
-//
-// Relies on ChromeNetLog only calling an Observer once at a time for
-// thread-safety.
-class NetLogLogger : public net::NetLog::ThreadSafeObserver {
- public:
-  // Takes ownership of |file| and will write network events to it once logging
-  // starts.  |file| must be non-NULL handle and be open for writing.
-  explicit NetLogLogger(FILE* file);
-  virtual ~NetLogLogger();
-
-  // Starts observing specified NetLog.  Must not already be watching a NetLog.
-  // Separate from constructor to enforce thread safety.
-  void StartObserving(net::NetLog* net_log);
-
-  // Stops observing net_log().  Must already be watching.
-  void StopObserving();
-
-  // net::NetLog::ThreadSafeObserver implementation:
-  virtual void OnAddEntry(const net::NetLog::Entry& entry) OVERRIDE;
-
- private:
-  ScopedStdioHandle file_;
-
-  // True if OnAddEntry() has been called at least once.
-  bool added_events_;
-
-  DISALLOW_COPY_AND_ASSIGN(NetLogLogger);
-};
-
-#endif  // CHROME_BROWSER_NET_NET_LOG_LOGGER_H_
diff --git a/chrome/browser/net/net_log_logger_unittest.cc b/chrome/browser/net/net_log_logger_unittest.cc
deleted file mode 100644
index 52bbc624..0000000
--- a/chrome/browser/net/net_log_logger_unittest.cc
+++ /dev/null
@@ -1,112 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/net/net_log_logger.h"
-
-#include "base/file_util.h"
-#include "base/files/file_path.h"
-#include "base/files/scoped_temp_dir.h"
-#include "base/json/json_reader.h"
-#include "base/values.h"
-#include "net/base/net_log.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-class NetLogLoggerTest : public testing::Test {
- public:
-  virtual void SetUp() {
-    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
-    log_path_ = temp_dir_.path().AppendASCII("NetLogFile");
-  }
-
- protected:
-  base::ScopedTempDir temp_dir_;
-  base::FilePath log_path_;
-};
-
-TEST_F(NetLogLoggerTest, GeneratesValidJSONForNoEvents) {
-  {
-    // Create and destroy a logger.
-    FILE* file = file_util::OpenFile(log_path_, "w");
-    ASSERT_TRUE(file);
-    NetLogLogger logger(file);
-  }
-
-  std::string input;
-  ASSERT_TRUE(file_util::ReadFileToString(log_path_, &input));
-
-  base::JSONReader reader;
-  scoped_ptr<base::Value> root(reader.ReadToValue(input));
-  ASSERT_TRUE(root) << reader.GetErrorMessage();
-
-  base::DictionaryValue* dict;
-  ASSERT_TRUE(root->GetAsDictionary(&dict));
-  base::ListValue* events;
-  ASSERT_TRUE(dict->GetList("events", &events));
-  ASSERT_EQ(0u, events->GetSize());
-}
-
-TEST_F(NetLogLoggerTest, GeneratesValidJSONWithOneEvent) {
-  {
-    FILE* file = file_util::OpenFile(log_path_, "w");
-    ASSERT_TRUE(file);
-    NetLogLogger logger(file);
-
-    const int kDummyId = 1;
-    net::NetLog::Source source(net::NetLog::SOURCE_SPDY_SESSION, kDummyId);
-    net::NetLog::Entry entry(net::NetLog::TYPE_PROXY_SERVICE,
-                             source,
-                             net::NetLog::PHASE_BEGIN,
-                             base::TimeTicks::Now(),
-                             NULL,
-                             net::NetLog::LOG_BASIC);
-    logger.OnAddEntry(entry);
-  }
-
-  std::string input;
-  ASSERT_TRUE(file_util::ReadFileToString(log_path_, &input));
-
-  base::JSONReader reader;
-  scoped_ptr<base::Value> root(reader.ReadToValue(input));
-  ASSERT_TRUE(root) << reader.GetErrorMessage();
-
-  base::DictionaryValue* dict;
-  ASSERT_TRUE(root->GetAsDictionary(&dict));
-  base::ListValue* events;
-  ASSERT_TRUE(dict->GetList("events", &events));
-  ASSERT_EQ(1u, events->GetSize());
-}
-
-TEST_F(NetLogLoggerTest, GeneratesValidJSONWithMultipleEvents) {
-  {
-    FILE* file = file_util::OpenFile(log_path_, "w");
-    ASSERT_TRUE(file);
-    NetLogLogger logger(file);
-
-    const int kDummyId = 1;
-    net::NetLog::Source source(net::NetLog::SOURCE_SPDY_SESSION, kDummyId);
-    net::NetLog::Entry entry(net::NetLog::TYPE_PROXY_SERVICE,
-                             source,
-                             net::NetLog::PHASE_BEGIN,
-                             base::TimeTicks::Now(),
-                             NULL,
-                             net::NetLog::LOG_BASIC);
-
-    // Add the entry multiple times.
-    logger.OnAddEntry(entry);
-    logger.OnAddEntry(entry);
-  }
-
-  std::string input;
-  ASSERT_TRUE(file_util::ReadFileToString(log_path_, &input));
-
-  base::JSONReader reader;
-  scoped_ptr<base::Value> root(reader.ReadToValue(input));
-  ASSERT_TRUE(root) << reader.GetErrorMessage();
-
-  base::DictionaryValue* dict;
-  ASSERT_TRUE(root->GetAsDictionary(&dict));
-  base::ListValue* events;
-  ASSERT_TRUE(dict->GetList("events", &events));
-  ASSERT_EQ(2u, events->GetSize());
-}
diff --git a/chrome/browser/net/net_log_temp_file.cc b/chrome/browser/net/net_log_temp_file.cc
index e7e2869..c764d1f 100644
--- a/chrome/browser/net/net_log_temp_file.cc
+++ b/chrome/browser/net/net_log_temp_file.cc
@@ -7,8 +7,9 @@
 #include "base/file_util.h"
 #include "base/values.h"
 #include "chrome/browser/net/chrome_net_log.h"
-#include "chrome/browser/net/net_log_logger.h"
+#include "chrome/browser/ui/webui/net_internals/net_internals_ui.h"
 #include "content/public/browser/browser_thread.h"
+#include "net/base/net_log_logger.h"
 
 using content::BrowserThread;
 
@@ -99,7 +100,8 @@
   if (file == NULL)
     return;
 
-  net_log_logger_.reset(new NetLogLogger(file));
+  scoped_ptr<base::Value> constants(NetInternalsUI::GetConstants());
+  net_log_logger_.reset(new net::NetLogLogger(file, *constants));
   net_log_logger_->StartObserving(chrome_net_log_);
   state_ = STATE_ALLOW_STOP;
 }
diff --git a/chrome/browser/net/net_log_temp_file.h b/chrome/browser/net/net_log_temp_file.h
index 83d3d85..4688526 100644
--- a/chrome/browser/net/net_log_temp_file.h
+++ b/chrome/browser/net/net_log_temp_file.h
@@ -16,8 +16,11 @@
 class DictionaryValue;
 }
 
-class ChromeNetLog;
+namespace net {
 class NetLogLogger;
+}
+
+class ChromeNetLog;
 
 // NetLogTempFile logs all the NetLog entries into a temporary file
 // "chrome-net-export-log.json" created in file_util::GetTempDir() directory.
@@ -123,7 +126,7 @@
 
   // |net_log_logger_| watches the NetLog event stream, and sends all entries to
   // the file created in StartNetLog().
-  scoped_ptr<NetLogLogger> net_log_logger_;
+  scoped_ptr<net::NetLogLogger> net_log_logger_;
 
   // The |chrome_net_log_| is owned by the browser process, cached here to avoid
   // using global (g_browser_process).
diff --git a/chrome/browser/net/net_log_temp_file_unittest.cc b/chrome/browser/net/net_log_temp_file_unittest.cc
index 553c820..e77ecc5 100644
--- a/chrome/browser/net/net_log_temp_file_unittest.cc
+++ b/chrome/browser/net/net_log_temp_file_unittest.cc
@@ -79,7 +79,7 @@
 
   virtual void TearDown() OVERRIDE {
     // Delete the temporary file we have created.
-    ASSERT_TRUE(file_util::Delete(net_export_log_, false));
+    ASSERT_TRUE(base::Delete(net_export_log_, false));
   }
 
   std::string GetStateString() const {
diff --git a/chrome/browser/net/network_stats.cc b/chrome/browser/net/network_stats.cc
index a2ac5e4..5ea2ed2 100644
--- a/chrome/browser/net/network_stats.cc
+++ b/chrome/browser/net/network_stats.cc
@@ -12,11 +12,10 @@
 #include "base/rand_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/threading/platform_thread.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "base/tuple.h"
 #include "chrome/common/chrome_version_info.h"
 #include "content/public/browser/browser_thread.h"
-#include "googleurl/src/gurl.h"
 #include "net/base/net_errors.h"
 #include "net/base/net_util.h"
 #include "net/base/network_change_notifier.h"
@@ -25,6 +24,7 @@
 #include "net/proxy/proxy_service.h"
 #include "net/udp/udp_client_socket.h"
 #include "net/udp/udp_server_socket.h"
+#include "url/gurl.h"
 
 using content::BrowserThread;
 
diff --git a/chrome/browser/net/network_stats.h b/chrome/browser/net/network_stats.h
index d18aaf1..2d56c72 100644
--- a/chrome/browser/net/network_stats.h
+++ b/chrome/browser/net/network_stats.h
@@ -12,7 +12,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/strings/string_util.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/io_thread.h"
 #include "net/base/address_list.h"
 #include "net/base/completion_callback.h"
diff --git a/chrome/browser/net/network_time_tracker.h b/chrome/browser/net/network_time_tracker.h
index 53e9bcc..5eaf97a 100644
--- a/chrome/browser/net/network_time_tracker.h
+++ b/chrome/browser/net/network_time_tracker.h
@@ -8,7 +8,7 @@
 #include "base/callback.h"
 #include "base/memory/weak_ptr.h"
 #include "base/threading/thread_checker.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "net/base/network_time_notifier.h"
 
 class IOThread;
diff --git a/chrome/browser/net/predictor.cc b/chrome/browser/net/predictor.cc
index b7061c7..67273cb 100644
--- a/chrome/browser/net/predictor.cc
+++ b/chrome/browser/net/predictor.cc
@@ -20,7 +20,7 @@
 #include "base/strings/stringprintf.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/threading/thread_restrictions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "base/values.h"
 #include "chrome/browser/io_thread.h"
 #include "chrome/browser/net/preconnect.h"
diff --git a/chrome/browser/net/predictor_unittest.cc b/chrome/browser/net/predictor_unittest.cc
index a2940a8..bc45792 100644
--- a/chrome/browser/net/predictor_unittest.cc
+++ b/chrome/browser/net/predictor_unittest.cc
@@ -11,7 +11,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/message_loop.h"
 #include "base/strings/string_number_conversions.h"
-#include "base/timer.h"
+#include "base/timer/timer.h"
 #include "base/values.h"
 #include "chrome/browser/net/predictor.h"
 #include "chrome/browser/net/url_info.h"
diff --git a/chrome/browser/net/referrer.h b/chrome/browser/net/referrer.h
index b38d96d..fb5d6d2 100644
--- a/chrome/browser/net/referrer.h
+++ b/chrome/browser/net/referrer.h
@@ -18,9 +18,9 @@
 #include <map>
 
 #include "base/basictypes.h"
-#include "base/time.h"
-#include "googleurl/src/gurl.h"
+#include "base/time/time.h"
 #include "net/base/host_port_pair.h"
+#include "url/gurl.h"
 
 namespace base {
 class Value;
diff --git a/chrome/browser/net/resource_prefetch_predictor_observer.cc b/chrome/browser/net/resource_prefetch_predictor_observer.cc
index c193f18..1ce3f8d 100644
--- a/chrome/browser/net/resource_prefetch_predictor_observer.cc
+++ b/chrome/browser/net/resource_prefetch_predictor_observer.cc
@@ -9,8 +9,8 @@
 #include "base/metrics/histogram.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/resource_request_info.h"
-#include "googleurl/src/gurl.h"
 #include "net/url_request/url_request.h"
+#include "url/gurl.h"
 
 using content::BrowserThread;
 using predictors::ResourcePrefetchPredictor;
diff --git a/chrome/browser/net/sqlite_server_bound_cert_store.cc b/chrome/browser/net/sqlite_server_bound_cert_store.cc
index cf2bca5..fe28561 100644
--- a/chrome/browser/net/sqlite_server_bound_cert_store.cc
+++ b/chrome/browser/net/sqlite_server_bound_cert_store.cc
@@ -19,7 +19,6 @@
 #include "base/threading/thread_restrictions.h"
 #include "chrome/browser/diagnostics/sqlite_diagnostics.h"
 #include "content/public/browser/browser_thread.h"
-#include "googleurl/src/gurl.h"
 #include "net/cert/x509_certificate.h"
 #include "net/cookies/cookie_util.h"
 #include "net/ssl/ssl_client_cert_type.h"
@@ -28,6 +27,7 @@
 #include "sql/statement.h"
 #include "sql/transaction.h"
 #include "third_party/sqlite/sqlite3.h"
+#include "url/gurl.h"
 #include "webkit/browser/quota/special_storage_policy.h"
 
 using content::BrowserThread;
diff --git a/chrome/browser/net/timed_cache.cc b/chrome/browser/net/timed_cache.cc
index e88fd27..2d0dd94 100644
--- a/chrome/browser/net/timed_cache.cc
+++ b/chrome/browser/net/timed_cache.cc
@@ -4,7 +4,7 @@
 
 #include "chrome/browser/net/timed_cache.h"
 
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 namespace chrome_browser_net {
 
diff --git a/chrome/browser/net/timed_cache.h b/chrome/browser/net/timed_cache.h
index f8b3c3b..dfcdc98 100644
--- a/chrome/browser/net/timed_cache.h
+++ b/chrome/browser/net/timed_cache.h
@@ -7,7 +7,7 @@
 
 #include "base/basictypes.h"
 #include "base/containers/mru_cache.h"
-#include "base/time.h"
+#include "base/time/time.h"
 
 class GURL;
 
diff --git a/chrome/browser/net/url_fixer_upper.cc b/chrome/browser/net/url_fixer_upper.cc
index fc68d2a..6c82ba4 100644
--- a/chrome/browser/net/url_fixer_upper.cc
+++ b/chrome/browser/net/url_fixer_upper.cc
@@ -14,12 +14,12 @@
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/common/url_constants.h"
-#include "googleurl/src/url_file.h"
-#include "googleurl/src/url_parse.h"
-#include "googleurl/src/url_util.h"
 #include "net/base/escape.h"
 #include "net/base/net_util.h"
 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
+#include "url/url_file.h"
+#include "url/url_parse.h"
+#include "url/url_util.h"
 
 const char* URLFixerUpper::home_directory_override = NULL;
 
diff --git a/chrome/browser/net/url_fixer_upper.h b/chrome/browser/net/url_fixer_upper.h
index eaf89c8..57ed512 100644
--- a/chrome/browser/net/url_fixer_upper.h
+++ b/chrome/browser/net/url_fixer_upper.h
@@ -8,7 +8,7 @@
 #include <string>
 
 #include "base/strings/string16.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 namespace base {
 class FilePath;
diff --git a/chrome/browser/net/url_fixer_upper_unittest.cc b/chrome/browser/net/url_fixer_upper_unittest.cc
index 706418a..5dc335c 100644
--- a/chrome/browser/net/url_fixer_upper_unittest.cc
+++ b/chrome/browser/net/url_fixer_upper_unittest.cc
@@ -11,10 +11,10 @@
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/net/url_fixer_upper.h"
 #include "chrome/common/chrome_paths.h"
-#include "googleurl/src/gurl.h"
-#include "googleurl/src/url_parse.h"
 #include "net/base/net_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+#include "url/url_parse.h"
 
 namespace {
   class URLFixerUpperTest : public testing::Test {
@@ -459,7 +459,7 @@
         file_cases[i].desired_tld).possibly_invalid_spec());
   }
 
-  EXPECT_TRUE(file_util::Delete(original, false));
+  EXPECT_TRUE(base::Delete(original, false));
 }
 
 TEST(URLFixerUpperTest, FixupRelativeFile) {
@@ -483,7 +483,7 @@
   // are no backslashes
   EXPECT_TRUE(IsMatchingFileURL(URLFixerUpper::FixupRelativeFile(dir,
       file_part).possibly_invalid_spec(), full_path));
-  EXPECT_TRUE(file_util::Delete(full_path, false));
+  EXPECT_TRUE(base::Delete(full_path, false));
 
   // create a filename we know doesn't exist and make sure it doesn't get
   // fixed up to a file URL
@@ -527,8 +527,8 @@
       base::FilePath(relative_file_str)).possibly_invalid_spec(), full_path));
 
   // done with the subdir
-  EXPECT_TRUE(file_util::Delete(full_path, false));
-  EXPECT_TRUE(file_util::Delete(new_dir, true));
+  EXPECT_TRUE(base::Delete(full_path, false));
+  EXPECT_TRUE(base::Delete(new_dir, true));
 
   // Test that an obvious HTTP URL isn't accidentally treated as an absolute
   // file path (on account of system-specific craziness).
diff --git a/chrome/browser/net/url_info.h b/chrome/browser/net/url_info.h
index 54c8159..e8e3408 100644
--- a/chrome/browser/net/url_info.h
+++ b/chrome/browser/net/url_info.h
@@ -19,9 +19,9 @@
 #include <string>
 #include <vector>
 
-#include "base/time.h"
-#include "googleurl/src/gurl.h"
+#include "base/time/time.h"
 #include "net/base/host_port_pair.h"
+#include "url/gurl.h"
 
 namespace chrome_browser_net {
 
diff --git a/chrome/browser/net/url_info_unittest.cc b/chrome/browser/net/url_info_unittest.cc
index 1ae6a89..730bb96 100644
--- a/chrome/browser/net/url_info_unittest.cc
+++ b/chrome/browser/net/url_info_unittest.cc
@@ -8,7 +8,7 @@
 #include <string>
 
 #include "base/threading/platform_thread.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/net/url_info.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/chrome/browser/notifications/balloon_collection_base.cc b/chrome/browser/notifications/balloon_collection_base.cc
index c97c14d..c748739 100644
--- a/chrome/browser/notifications/balloon_collection_base.cc
+++ b/chrome/browser/notifications/balloon_collection_base.cc
@@ -7,7 +7,7 @@
 #include "base/stl_util.h"
 #include "chrome/browser/notifications/balloon.h"
 #include "chrome/browser/notifications/notification.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 BalloonCollectionBase::BalloonCollectionBase() {
 }
diff --git a/chrome/browser/notifications/desktop_notification_service.cc b/chrome/browser/notifications/desktop_notification_service.cc
index 7459310..1fc2985 100644
--- a/chrome/browser/notifications/desktop_notification_service.cc
+++ b/chrome/browser/notifications/desktop_notification_service.cc
@@ -20,6 +20,8 @@
 #include "chrome/browser/notifications/notification.h"
 #include "chrome/browser/notifications/notification_object_proxy.h"
 #include "chrome/browser/notifications/notification_ui_manager.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/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
@@ -50,46 +52,13 @@
 using content::BrowserThread;
 using content::RenderViewHost;
 using content::WebContents;
+using message_center::NotifierId;
 using WebKit::WebNotificationPresenter;
 using WebKit::WebTextDirection;
 using WebKit::WebSecurityOrigin;
 
 const ContentSetting kDefaultSetting = CONTENT_SETTING_ASK;
 
-namespace {
-
-void ToggleListPrefItem(PrefService* prefs, const char* key,
-                        const std::string& item, bool flag) {
-  ListPrefUpdate update(prefs, key);
-  base::ListValue* const list = update.Get();
-  if (flag) {
-    // AppendIfNotPresent will delete |adding_value| when the same value
-    // already exists.
-    base::StringValue* const adding_value = new base::StringValue(item);
-    list->AppendIfNotPresent(adding_value);
-  } else {
-    base::StringValue removed_value(item);
-    list->Remove(removed_value, NULL);
-  }
-}
-
-void CopySetFromPrefToMemory(PrefService* prefs, const char* key,
-                             std::set<std::string>* dst) {
-  dst->clear();
-  const base::ListValue* pref_list = prefs->GetList(key);
-  for (size_t i = 0; i < pref_list->GetSize(); ++i) {
-    std::string element;
-    if (!pref_list->GetString(i, &element) && element.empty()) {
-      LOG(WARNING) << i << "-th element is not a string for "
-                   << key;
-      continue;
-    }
-    dst->insert(element);
-  }
-}
-
-}  // namespace
-
 // NotificationPermissionInfoBarDelegate --------------------------------------
 
 // The delegate for the infobar shown when an origin requests notification
@@ -234,6 +203,8 @@
                              user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
   registry->RegisterListPref(prefs::kMessageCenterDisabledSystemComponentIds,
                              user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
+  registry->RegisterListPref(prefs::kMessageCenterEnabledSyncNotifierIds,
+                             user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
 }
 
 // static
@@ -351,22 +322,53 @@
     NotificationUIManager* ui_manager)
     : profile_(profile),
       ui_manager_(ui_manager) {
-  OnDisabledExtensionIdsChanged();
-  OnDisabledSystemComponentIdsChanged();
+  OnStringListPrefChanged(
+      prefs::kMessageCenterDisabledExtensionIds, &disabled_extension_ids_);
+  OnStringListPrefChanged(
+      prefs::kMessageCenterDisabledSystemComponentIds,
+      &disabled_system_component_ids_);
+  OnStringListPrefChanged(
+      prefs::kMessageCenterEnabledSyncNotifierIds, &enabled_sync_notifier_ids_);
   disabled_extension_id_pref_.Init(
       prefs::kMessageCenterDisabledExtensionIds,
       profile_->GetPrefs(),
       base::Bind(
-          &DesktopNotificationService::OnDisabledExtensionIdsChanged,
-          base::Unretained(this)));
+          &DesktopNotificationService::OnStringListPrefChanged,
+          base::Unretained(this),
+          base::Unretained(prefs::kMessageCenterDisabledExtensionIds),
+          base::Unretained(&disabled_extension_ids_)));
   disabled_system_component_id_pref_.Init(
       prefs::kMessageCenterDisabledSystemComponentIds,
       profile_->GetPrefs(),
       base::Bind(
-          &DesktopNotificationService::OnDisabledSystemComponentIdsChanged,
-          base::Unretained(this)));
+          &DesktopNotificationService::OnStringListPrefChanged,
+          base::Unretained(this),
+          base::Unretained(prefs::kMessageCenterDisabledSystemComponentIds),
+          base::Unretained(&disabled_system_component_ids_)));
+  enabled_sync_notifier_id_pref_.Init(
+      prefs::kMessageCenterEnabledSyncNotifierIds,
+      profile_->GetPrefs(),
+      base::Bind(
+          &DesktopNotificationService::OnStringListPrefChanged,
+          base::Unretained(this),
+          base::Unretained(prefs::kMessageCenterEnabledSyncNotifierIds),
+          base::Unretained(&enabled_sync_notifier_ids_)));
   registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNINSTALLED,
                  content::Source<Profile>(profile_));
+  // TODO(mukai, petewil): invoking notifier_service here directly may cause
+  // crashes on several tests, since notifier_service relies on
+  // NotificationUIManager in g_browser_process. To suppress the crashes,
+  // here checks if it really needs to ping notifier_service here.
+  if (!enabled_sync_notifier_ids_.empty()) {
+    notifier::ChromeNotifierService* notifier_service =
+        notifier::ChromeNotifierServiceFactory::GetInstance()->GetForProfile(
+            profile, Profile::EXPLICIT_ACCESS);
+    for (std::set<std::string>::const_iterator it =
+             enabled_sync_notifier_ids_.begin();
+         it != enabled_sync_notifier_ids_.end(); ++it) {
+      notifier_service->OnSyncedNotificationServiceEnabled(*it, true);
+    }
+  }
 }
 
 DesktopNotificationService::~DesktopNotificationService() {
@@ -534,7 +536,8 @@
           &extensions);
       for (ExtensionSet::const_iterator iter = extensions.begin();
            iter != extensions.end(); ++iter) {
-        if (IsExtensionEnabled((*iter)->id()))
+        NotifierId notifier_id(NotifierId::APPLICATION, (*iter)->id());
+        if (IsNotifierEnabled(notifier_id))
           return UTF8ToUTF16((*iter)->name());
       }
     }
@@ -557,49 +560,88 @@
   return ui_manager_;
 }
 
-bool DesktopNotificationService::IsExtensionEnabled(const std::string& id) {
-  return disabled_extension_ids_.find(id) == disabled_extension_ids_.end();
+bool DesktopNotificationService::IsNotifierEnabled(
+    const NotifierId& notifier_id) {
+  switch (notifier_id.type) {
+    case NotifierId::APPLICATION:
+      return disabled_extension_ids_.find(notifier_id.id) ==
+          disabled_extension_ids_.end();
+    case NotifierId::WEB_PAGE:
+      return GetContentSetting(notifier_id.url) == CONTENT_SETTING_ALLOW;
+    case NotifierId::SYSTEM_COMPONENT:
+      return disabled_system_component_ids_.find(
+          message_center::ToString(notifier_id.system_component_type)) ==
+          disabled_system_component_ids_.end();
+    case NotifierId::SYNCED_NOTIFICATION_SERVICE:
+      return enabled_sync_notifier_ids_.find(notifier_id.id) !=
+          enabled_sync_notifier_ids_.end();
+  }
+
+  NOTREACHED();
+  return false;
 }
 
-void DesktopNotificationService::SetExtensionEnabled(
-    const std::string& id, bool enabled) {
-  // Do not touch |disabled_extension_ids_|. It will be updated at
-  // OnDisabledExtensionIdsChanged() which will be called when the pref changes.
-  ToggleListPrefItem(
-      profile_->GetPrefs(),
-      prefs::kMessageCenterDisabledExtensionIds,
-      id,
-      !enabled);
+void DesktopNotificationService::SetNotifierEnabled(
+    const NotifierId& notifier_id,
+    bool enabled) {
+  DCHECK_NE(NotifierId::WEB_PAGE, notifier_id.type);
+
+  bool add_new_item = false;
+  const char* pref_name = NULL;
+  scoped_ptr<base::StringValue> id;
+  switch (notifier_id.type) {
+    case NotifierId::APPLICATION:
+      pref_name = prefs::kMessageCenterDisabledExtensionIds;
+      add_new_item = !enabled;
+      id.reset(new base::StringValue(notifier_id.id));
+      break;
+    case NotifierId::SYSTEM_COMPONENT:
+      pref_name = prefs::kMessageCenterDisabledSystemComponentIds;
+      add_new_item = !enabled;
+      id.reset(new base::StringValue(
+          message_center::ToString(notifier_id.system_component_type)));
+      break;
+    case NotifierId::SYNCED_NOTIFICATION_SERVICE:
+      pref_name = prefs::kMessageCenterEnabledSyncNotifierIds;
+      // Adding a new item if |enabled| == true, since synced notification
+      // services are opt-in.
+      add_new_item = enabled;
+      id.reset(new base::StringValue(notifier_id.id));
+      break;
+    default:
+      NOTREACHED();
+  }
+  DCHECK(pref_name != NULL);
+
+  {
+    ListPrefUpdate update(profile_->GetPrefs(), pref_name);
+    base::ListValue* const list = update.Get();
+    if (add_new_item) {
+      // AppendIfNotPresent will delete |adding_value| when the same value
+      // already exists.
+      list->AppendIfNotPresent(id.release());
+    } else {
+      list->Remove(*id, NULL);
+    }
+  }
 }
 
-void DesktopNotificationService::OnDisabledExtensionIdsChanged() {
-  CopySetFromPrefToMemory(profile_->GetPrefs(),
-                          prefs::kMessageCenterDisabledExtensionIds,
-                          &disabled_extension_ids_);
+bool DesktopNotificationService::IsExtensionEnabled(
+    const std::string& extension_id) {
+  return IsNotifierEnabled(NotifierId(NotifierId::APPLICATION, extension_id));
 }
 
-bool DesktopNotificationService::IsSystemComponentEnabled(
-    message_center::Notifier::SystemComponentNotifierType type) {
-  return disabled_system_component_ids_.find(message_center::ToString(type)) ==
-         disabled_system_component_ids_.end();
-}
-
-void DesktopNotificationService::SetSystemComponentEnabled(
-    message_center::Notifier::SystemComponentNotifierType type, bool enabled) {
-  // Do not touch |disabled_extension_ids_|. It will be updated at
-  // OnDisabledExtensionIdsChanged() which will be called when the pref changes.
-  ToggleListPrefItem(
-      profile_->GetPrefs(),
-      prefs::kMessageCenterDisabledSystemComponentIds,
-      message_center::ToString(type),
-      !enabled);
-}
-
-void DesktopNotificationService::OnDisabledSystemComponentIdsChanged() {
-  disabled_system_component_ids_.clear();
-  CopySetFromPrefToMemory(profile_->GetPrefs(),
-                          prefs::kMessageCenterDisabledSystemComponentIds,
-                          &disabled_system_component_ids_);
+void DesktopNotificationService::OnStringListPrefChanged(
+    const char* pref_name, std::set<std::string>* ids_field) {
+  ids_field->clear();
+  const base::ListValue* pref_list = profile_->GetPrefs()->GetList(pref_name);
+  for (size_t i = 0; i < pref_list->GetSize(); ++i) {
+    std::string element;
+    if (pref_list->GetString(i, &element) && !element.empty())
+      ids_field->insert(element);
+    else
+      LOG(WARNING) << i << "-th element is not a string for " << pref_name;
+  }
 }
 
 WebKit::WebNotificationPresenter::Permission
@@ -631,8 +673,9 @@
 
   extensions::Extension* extension =
       content::Details<extensions::Extension>(details).ptr();
-  if (IsExtensionEnabled(extension->id()))
+  NotifierId notifier_id(NotifierId::APPLICATION, extension->id());
+  if (IsNotifierEnabled(notifier_id))
     return;
 
-  SetExtensionEnabled(extension->id(), true);
+  SetNotifierEnabled(notifier_id, true);
 }
diff --git a/chrome/browser/notifications/desktop_notification_service.h b/chrome/browser/notifications/desktop_notification_service.h
index bad1d6f..3783950 100644
--- a/chrome/browser/notifications/desktop_notification_service.h
+++ b/chrome/browser/notifications/desktop_notification_service.h
@@ -18,10 +18,10 @@
 #include "components/browser_context_keyed_service/browser_context_keyed_service.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
-#include "googleurl/src/gurl.h"
 #include "third_party/WebKit/public/web/WebNotificationPresenter.h"
 #include "third_party/WebKit/public/web/WebTextDirection.h"
 #include "ui/message_center/notifier_settings.h"
+#include "url/gurl.h"
 
 class ContentSettingsPattern;
 class Notification;
@@ -152,21 +152,17 @@
   WebKit::WebNotificationPresenter::Permission
       HasPermission(const GURL& origin);
 
-  // Returns true if the extension of the specified |id| is allowed to send
+  // Returns true if the notifier with |notifier_id| is allowed to send
   // notifications.
-  bool IsExtensionEnabled(const std::string& id);
+  bool IsNotifierEnabled(const message_center::NotifierId& notifier_id);
 
-  // Updates the availability of the extension to send notifications.
-  void SetExtensionEnabled(const std::string& id, bool enabled);
+  // Updates the availability of the notifier.
+  void SetNotifierEnabled(const message_center::NotifierId& notifier_id,
+                          bool enabled);
 
-  // Returns true if the system component of the specified |id| is allowed to
-  // send notifications.
-  bool IsSystemComponentEnabled(
-      message_center::Notifier::SystemComponentNotifierType type);
-
-  // Updates the availability of the system component to send notifications.
-  void SetSystemComponentEnabled(
-      message_center::Notifier::SystemComponentNotifierType type, bool enabled);
+  // IsExtensionEnabled is obsoleted, do not use this.
+  // TODO(mukai): remove this.
+  bool IsExtensionEnabled(const std::string& extension_id);
 
  private:
   // Takes a notification object and shows it in the UI.
@@ -182,12 +178,19 @@
 
   NotificationUIManager* GetUIManager();
 
+  // Called when the string list pref has been changed.
+  void OnStringListPrefChanged(
+      const char* pref_name, std::set<std::string>* ids_field);
+
   // Called when the disabled_extension_id pref has been changed.
   void OnDisabledExtensionIdsChanged();
 
   // Called when the disabled_system_component_id pref has been changed.
   void OnDisabledSystemComponentIdsChanged();
 
+  // Called when the enabled_sync_notifier_id pref has been changed.
+  void OnEnabledSyncNotifierIdsChanged();
+
   // content::NotificationObserver override.
   virtual void Observe(int type,
                        const content::NotificationSource& source,
@@ -203,15 +206,21 @@
   // Prefs listener for disabled_extension_id.
   StringListPrefMember disabled_extension_id_pref_;
 
-  // Prefs listener for disabled_extension_id.
+  // Prefs listener for disabled_system_component_id.
   StringListPrefMember disabled_system_component_id_pref_;
 
+  // Prefs listener for enabled_sync_notifier_id.
+  StringListPrefMember enabled_sync_notifier_id_pref_;
+
   // On-memory data for the availability of extensions.
   std::set<std::string> disabled_extension_ids_;
 
   // On-memory data for the availability of system_component.
   std::set<std::string> disabled_system_component_ids_;
 
+  // On-memory data for the availability of sync notifiers.
+  std::set<std::string> enabled_sync_notifier_ids_;
+
   // Registrar for the other kind of notifications (event signaling).
   content::NotificationRegistrar registrar_;
 
diff --git a/chrome/browser/notifications/desktop_notifications_unittest.cc b/chrome/browser/notifications/desktop_notifications_unittest.cc
index a539e7b..7b969f3 100644
--- a/chrome/browser/notifications/desktop_notifications_unittest.cc
+++ b/chrome/browser/notifications/desktop_notifications_unittest.cc
@@ -21,7 +21,6 @@
 #if defined(USE_ASH)
 #include "ash/shell.h"
 #include "ash/test/test_shell_delegate.h"
-#include "chrome/browser/ui/aura/active_desktop_monitor.h"
 #include "third_party/WebKit/public/web/WebKit.h"
 #include "ui/aura/env.h"
 #include "ui/aura/root_window.h"
@@ -113,7 +112,6 @@
   // MockBalloonCollection retrieves information about the screen on creation.
   // So it is necessary to make sure the desktop gets created first.
   ash::Shell::CreateInstance(new ash::test::TestShellDelegate);
-  active_desktop_monitor_.reset(new ActiveDesktopMonitor);
 #endif
 
   chrome::RegisterLocalState(local_state_.registry());
@@ -130,7 +128,6 @@
   ui_manager_.reset(NULL);
   profile_.reset(NULL);
 #if defined(USE_ASH)
-  active_desktop_monitor_.reset();
   ash::Shell::DeleteInstance();
   // The message center is notmally shutdown on |g_browser_process| which
   // is not created for these tests.
diff --git a/chrome/browser/notifications/desktop_notifications_unittest.h b/chrome/browser/notifications/desktop_notifications_unittest.h
index 1aa5947..ad8d0d8 100644
--- a/chrome/browser/notifications/desktop_notifications_unittest.h
+++ b/chrome/browser/notifications/desktop_notifications_unittest.h
@@ -117,8 +117,6 @@
 #if defined(USE_ASH)
   content::RenderViewTest::RendererWebKitPlatformSupportImplNoSandbox
       webkit_platform_support_;
-
-  scoped_ptr<ActiveDesktopMonitor> active_desktop_monitor_;
 #endif
 
   // Contains the cumulative output of the unit test.
diff --git a/chrome/browser/notifications/message_center_notification_manager.cc b/chrome/browser/notifications/message_center_notification_manager.cc
index be8bd2e..d0cbb7e 100644
--- a/chrome/browser/notifications/message_center_notification_manager.cc
+++ b/chrome/browser/notifications/message_center_notification_manager.cc
@@ -25,12 +25,29 @@
 #include "ui/message_center/message_center_tray.h"
 #include "ui/message_center/notifier_settings.h"
 
+namespace {
+// The first-run balloon will be shown |kFirstRunIdleDelaySeconds| after all
+// popups go away and the user has notifications in the message center.
+const int kFirstRunIdleDelaySeconds = 1;
+}  // namespace
+
 MessageCenterNotificationManager::MessageCenterNotificationManager(
-    message_center::MessageCenter* message_center)
+    message_center::MessageCenter* message_center,
+    PrefService* local_state)
     : message_center_(message_center),
+#if defined(OS_WIN)
+      first_run_idle_timeout_(
+          base::TimeDelta::FromSeconds(kFirstRunIdleDelaySeconds)),
+      weak_factory_(this),
+#endif
       settings_controller_(new MessageCenterSettingsController) {
+#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());
 
 #if defined(OS_WIN) || defined(OS_MACOSX) \
   || (defined(USE_AURA) && !defined(USE_ASH))
@@ -44,7 +61,6 @@
   message_center_->RemoveObserver(this);
 }
 
-
 ////////////////////////////////////////////////////////////////////////////////
 // NotificationUIManager
 
@@ -83,7 +99,7 @@
   for (NotificationMap::iterator iter = profile_notifications_.begin();
        iter != profile_notifications_.end(); iter++) {
     if ((*iter).second->notification().origin_url() == source &&
-        profile->IsSameProfile((*iter).second->profile())) {
+        profile == (*iter).second->profile()) {
       notification_ids.insert(iter->first);
     }
   }
@@ -114,7 +130,7 @@
   for (NotificationMap::iterator loopiter = profile_notifications_.begin();
        loopiter != profile_notifications_.end(); ) {
     NotificationMap::iterator curiter = loopiter++;
-    if (profile->IsSameProfile((*curiter).second->profile())) {
+    if (profile == (*curiter).second->profile()) {
       message_center_->RemoveNotification(curiter->first, /* by_user */ false);
       removed = true;
     }
@@ -164,7 +180,7 @@
     ProfileNotification* old_notification = (*iter).second;
     if (old_notification->notification().replace_id() == replace_id &&
         old_notification->notification().origin_url() == origin_url &&
-        old_notification->profile()->IsSameProfile(profile)) {
+        old_notification->profile() == profile) {
       std::string old_id =
           old_notification->notification().notification_id();
       DCHECK(message_center_->HasNotification(old_id));
@@ -208,7 +224,9 @@
   DesktopNotificationService* service =
       DesktopNotificationServiceFactory::GetForProfile(
           profile_notification->profile());
-  service->SetExtensionEnabled(extension_id, false);
+  message_center::NotifierId notifier_id(
+      message_center::NotifierId::APPLICATION, extension_id);
+  service->SetNotifierEnabled(notifier_id, false);
 }
 
 void MessageCenterNotificationManager::DisableNotificationsFromSource(
@@ -227,9 +245,9 @@
       chrome::kChromeUIScheme) {
     const std::string name =
         profile_notification->notification().origin_url().host();
-    const message_center::Notifier::SystemComponentNotifierType type =
-        message_center::ParseSystemComponentName(name);
-    service->SetSystemComponentEnabled(type, false);
+    message_center::NotifierId notifier_id(
+        message_center::ParseSystemComponentName(name));
+    service->SetNotifierEnabled(notifier_id, false);
   } else {
     service->DenyPermission(profile_notification->notification().origin_url());
   }
@@ -257,11 +275,6 @@
     chrome::ShowExtensions(browser, std::string());
 }
 
-message_center::NotifierSettingsDelegate*
-MessageCenterNotificationManager::ShowSettingsDialog(gfx::NativeView context) {
-  return settings_controller_->ShowSettingsDialog(context);
-}
-
 ////////////////////////////////////////////////////////////////////////////////
 // MessageCenter::Observer
 void MessageCenterNotificationManager::OnNotificationRemoved(
@@ -274,12 +287,31 @@
       profile_notifications_.find(notification_id);
   if (iter != profile_notifications_.end())
     RemoveProfileNotification(iter->second, by_user);
+
+#if defined(OS_WIN)
+  CheckFirstRunTimer();
+#endif
 }
 
 void MessageCenterNotificationManager::OnNotificationCenterClosed() {
   // When the center is open it halts all notifications, so we need to listen
   // for events indicating it's been closed.
   CheckAndShowNotifications();
+#if defined(OS_WIN)
+  CheckFirstRunTimer();
+#endif
+}
+
+void MessageCenterNotificationManager::OnNotificationUpdated(
+    const std::string& notification_id) {
+#if defined(OS_WIN)
+  CheckFirstRunTimer();
+#endif
+}
+
+void MessageCenterNotificationManager::SetMessageCenterTrayDelegateForTest(
+    message_center::MessageCenterTrayDelegate* delegate) {
+  tray_.reset(delegate);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -377,8 +409,9 @@
 
   contents->DownloadImage(
       url,
-      false,
-      size,
+      false,  // Not a favicon
+      size,  // Preferred size
+      0,  // No maximum size
       base::Bind(
           &MessageCenterNotificationManager::ImageDownloads::DownloadComplete,
           AsWeakPtr(),
@@ -451,8 +484,10 @@
       DesktopNotificationServiceFactory::GetForProfile(profile());
   for (ExtensionSet::const_iterator iter = extensions.begin();
        iter != extensions.end(); ++iter) {
-    if (desktop_service->IsExtensionEnabled((*iter)->id()))
+    if (desktop_service->IsNotifierEnabled(message_center::NotifierId(
+            message_center::NotifierId::APPLICATION, (*iter)->id()))) {
       return (*iter)->id();
+    }
   }
   return std::string();
 }
diff --git a/chrome/browser/notifications/message_center_notification_manager.h b/chrome/browser/notifications/message_center_notification_manager.h
index ae5fc9a..8ae5ee5 100644
--- a/chrome/browser/notifications/message_center_notification_manager.h
+++ b/chrome/browser/notifications/message_center_notification_manager.h
@@ -9,6 +9,10 @@
 #include <string>
 
 #include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "base/prefs/pref_member.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
 #include "chrome/browser/notifications/notification.h"
 #include "chrome/browser/notifications/notification_ui_manager.h"
 #include "chrome/browser/notifications/notification_ui_manager_impl.h"
@@ -18,6 +22,7 @@
 
 class MessageCenterSettingsController;
 class Notification;
+class PrefService;
 class Profile;
 
 // This class extends NotificationUIManagerImpl and delegates actual display
@@ -28,7 +33,8 @@
       public message_center::MessageCenterObserver {
  public:
   explicit MessageCenterNotificationManager(
-      message_center::MessageCenter* message_center);
+      message_center::MessageCenter* message_center,
+      PrefService* local_state);
   virtual ~MessageCenterNotificationManager();
 
   // NotificationUIManager
@@ -52,13 +58,27 @@
   virtual void DisableNotificationsFromSource(
       const std::string& notification_id) OVERRIDE;
   virtual void ShowSettings(const std::string& notification_id) OVERRIDE;
-  virtual message_center::NotifierSettingsDelegate* ShowSettingsDialog(
-      gfx::NativeView context) OVERRIDE;
 
   // MessageCenterObserver
   virtual void OnNotificationRemoved(const std::string& notification_id,
                                      bool by_user) OVERRIDE;
   virtual void OnNotificationCenterClosed() OVERRIDE;
+  virtual void OnNotificationUpdated(const std::string& notification_id)
+      OVERRIDE;
+
+#if defined(OS_WIN)
+  // Called when the pref changes for the first run balloon. The first run
+  // balloon is only displayed on Windows, since the visibility of the tray
+  // icon is limited.
+  void DisplayFirstRunBalloon();
+
+  void SetFirstRunTimeoutForTest(base::TimeDelta timeout);
+  bool FirstRunTimerIsActive() const;
+#endif
+
+  // Takes ownership of |delegate|.
+  void SetMessageCenterTrayDelegateForTest(
+      message_center::MessageCenterTrayDelegate* delegate);
 
  private:
   class ImageDownloadsObserver {
@@ -159,8 +179,6 @@
   typedef std::map<std::string, ProfileNotification*> NotificationMap;
   NotificationMap profile_notifications_;
 
-  scoped_ptr<MessageCenterSettingsController> settings_controller_;
-
   // Helpers that add/remove the notification from local map and MessageCenter.
   // They take ownership of profile_notification object.
   void AddProfileNotification(ProfileNotification* profile_notification);
@@ -171,6 +189,30 @@
   // notification is found.
   ProfileNotification* FindProfileNotification(const std::string& id) const;
 
+#if defined(OS_WIN)
+  // This function is run on update to ensure that the notification balloon is
+  // shown only when there are no popups present.
+  void CheckFirstRunTimer();
+
+  // |first_run_pref_| is used to keep track of whether we've ever shown the
+  // first run balloon before, even across restarts.
+  BooleanPrefMember first_run_pref_;
+
+  // The timer after which we will show the first run balloon.  This timer is
+  // restarted every time the message center is closed and every time the last
+  // popup disappears from the screen.
+  base::OneShotTimer<MessageCenterNotificationManager> first_run_balloon_timer_;
+
+  // The first-run balloon will be shown |first_run_idle_timeout_| after all
+  // popups go away and the user has notifications in the message center.
+  base::TimeDelta first_run_idle_timeout_;
+
+  // Provides weak pointers for the purpose of the first run timer.
+  base::WeakPtrFactory<MessageCenterNotificationManager> weak_factory_;
+#endif
+
+  scoped_ptr<MessageCenterSettingsController> settings_controller_;
+
   DISALLOW_COPY_AND_ASSIGN(MessageCenterNotificationManager);
 };
 
diff --git a/chrome/browser/notifications/message_center_notification_manager_win.cc b/chrome/browser/notifications/message_center_notification_manager_win.cc
new file mode 100644
index 0000000..43525d2
--- /dev/null
+++ b/chrome/browser/notifications/message_center_notification_manager_win.cc
@@ -0,0 +1,53 @@
+// 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/notifications/message_center_notification_manager.h"
+
+#include "chrome/common/pref_names.h"
+#include "ui/message_center/message_center_tray.h"
+
+void MessageCenterNotificationManager::DisplayFirstRunBalloon() {
+  // Store for posterity the fact that we've shown the first-run balloon.
+  DCHECK(tray_.get());
+  first_run_pref_.SetValue(true);
+  tray_->DisplayFirstRunBalloon();
+}
+
+void MessageCenterNotificationManager::SetFirstRunTimeoutForTest(
+    base::TimeDelta timeout) {
+  first_run_idle_timeout_ = timeout;
+}
+
+bool MessageCenterNotificationManager::FirstRunTimerIsActive() const {
+  return first_run_balloon_timer_.IsRunning();
+}
+
+void MessageCenterNotificationManager::CheckFirstRunTimer() {
+  // If there is no tray_, we can't display a balloon here anyway.
+  // Also, we only want to display the first run balloon once, so the pref will
+  // store the flag on disk based on whether we ever showed the balloon.
+  DCHECK(tray_.get());
+  if (first_run_pref_.GetValue())
+    return;
+
+  // If there are popups, the message center is visible, or there are no more
+  // notifications, don't continue the timer since it will be annoying or
+  // useless.
+  if (message_center_->HasPopupNotifications() ||
+      message_center_->IsMessageCenterVisible() ||
+      0 == message_center_->NotificationCount()) {
+    first_run_balloon_timer_.Stop();
+    return;
+  }
+
+  // No need to restart the timer if it's already going.
+  if (first_run_balloon_timer_.IsRunning())
+    return;
+
+  first_run_balloon_timer_.Start(
+      FROM_HERE,
+      first_run_idle_timeout_,
+      base::Bind(&MessageCenterNotificationManager::DisplayFirstRunBalloon,
+                 weak_factory_.GetWeakPtr()));
+}
diff --git a/chrome/browser/notifications/message_center_notifications_unittest_win.cc b/chrome/browser/notifications/message_center_notifications_unittest_win.cc
new file mode 100644
index 0000000..8846ecc
--- /dev/null
+++ b/chrome/browser/notifications/message_center_notifications_unittest_win.cc
@@ -0,0 +1,159 @@
+// 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/scoped_ptr.h"
+#include "base/prefs/testing_pref_service.h"
+#include "base/run_loop.h"
+#include "base/test/test_timeouts.h"
+#include "base/values.h"
+#include "chrome/browser/notifications/message_center_notification_manager.h"
+#include "chrome/browser/notifications/notification.h"
+#include "chrome/browser/notifications/notification_prefs_manager.h"
+#include "chrome/browser/notifications/notification_test_util.h"
+#include "chrome/common/pref_names.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 "content/public/test/test_browser_thread_bundle.h"
+#include "testing/gtest/include/gtest/gtest.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"
+
+namespace message_center {
+class FakeMessageCenterTrayDelegate : public MessageCenterTrayDelegate {
+ public:
+  FakeMessageCenterTrayDelegate(MessageCenter* message_center,
+                                base::Closure quit_closure)
+      : tray_(this, message_center),
+        quit_closure_(quit_closure),
+        displayed_first_run_balloon_(false) {}
+
+  virtual void DisplayFirstRunBalloon() OVERRIDE {
+    displayed_first_run_balloon_ = true;
+    base::MessageLoop::current()->PostTask(FROM_HERE, quit_closure_);
+  }
+
+  virtual void OnMessageCenterTrayChanged() OVERRIDE {}
+  virtual bool ShowPopups() OVERRIDE { return true; }
+  virtual void HidePopups() OVERRIDE {}
+  virtual void UpdatePopups() OVERRIDE {}
+  virtual bool ShowMessageCenter() OVERRIDE { return true; }
+  virtual bool ShowNotifierSettings() OVERRIDE { return true; }
+  virtual void HideMessageCenter() OVERRIDE {}
+
+  bool displayed_first_run_balloon() const {
+    return displayed_first_run_balloon_;
+  }
+ private:
+  MessageCenterTray tray_;
+  base::Closure quit_closure_;
+  bool displayed_first_run_balloon_;
+};
+
+class MessageCenterNotificationManagerTest : public testing::Test {
+ protected:
+  MessageCenterNotificationManagerTest() {
+    NotificationPrefsManager::RegisterPrefs(local_state_.registry());
+  }
+
+  virtual void SetUp() {
+    // Clear the preference and initialize.
+    local_state_.ClearPref(prefs::kMessageCenterShowedFirstRunBalloon);
+    first_run_pref_.Init(prefs::kMessageCenterShowedFirstRunBalloon,
+                         &local_state_);
+
+    // Get ourselves a run loop.
+    run_loop_.reset(new base::RunLoop());
+
+    // Initialize message center infrastructure with mock tray delegate.
+    MessageCenter::Initialize();
+    message_center_ = MessageCenter::Get();
+    notification_manager_.reset(
+        new MessageCenterNotificationManager(message_center_, &local_state_));
+    delegate_ = new FakeMessageCenterTrayDelegate(message_center_,
+                                                  run_loop_->QuitClosure());
+    notification_manager_->SetMessageCenterTrayDelegateForTest(delegate_);
+    notification_manager_->SetFirstRunTimeoutForTest(
+        TestTimeouts::tiny_timeout());
+  }
+
+  virtual void TearDown() {
+    run_loop_.reset();
+    notification_manager_.reset();
+    MessageCenter::Shutdown();
+  }
+
+  MessageCenterNotificationManager* notification_manager() {
+    return notification_manager_.get();
+  }
+
+  FakeMessageCenterTrayDelegate* delegate() { return delegate_; }
+
+  MessageCenter* message_center() { return message_center_; }
+
+  const ::Notification GetANotification(const std::string& id) {
+    return ::Notification(GURL(),
+                          GURL(),
+                          string16(),
+                          string16(),
+                          new MockNotificationDelegate(id));
+  }
+
+  base::RunLoop* run_loop() { return run_loop_.get(); }
+  const TestingPrefServiceSimple& local_state() { return local_state_; }
+  bool DidFirstRunPref() { return first_run_pref_.GetValue(); }
+
+ private:
+  scoped_ptr<base::RunLoop> run_loop_;
+  TestingPrefServiceSimple local_state_;
+  MessageCenter* message_center_;
+  scoped_ptr<MessageCenterNotificationManager> notification_manager_;
+  FakeMessageCenterTrayDelegate* delegate_;
+  content::TestBrowserThreadBundle thread_bundle_;
+  BooleanPrefMember first_run_pref_;
+};
+
+TEST_F(MessageCenterNotificationManagerTest, SetupNotificationManager) {
+  TestingProfile profile;
+  notification_manager()->Add(GetANotification("test"), &profile);
+  EXPECT_FALSE(DidFirstRunPref());
+}
+
+// The following tests test the first run balloon, which is only implemented for
+// Windows.
+TEST_F(MessageCenterNotificationManagerTest, FirstRunShown) {
+  TestingProfile profile;
+  notification_manager()->Add(GetANotification("test"), &profile);
+  message_center()->DisplayedNotification("test");
+  message_center()->MarkSinglePopupAsShown("test", false);
+
+  run_loop()->Run();
+  base::RunLoop run_loop_2;
+  run_loop_2.RunUntilIdle();
+  EXPECT_TRUE(delegate()->displayed_first_run_balloon());
+  EXPECT_TRUE(DidFirstRunPref());
+}
+
+TEST_F(MessageCenterNotificationManagerTest,
+       FirstRunNotShownWithPopupsVisible) {
+  TestingProfile profile;
+  notification_manager()->Add(GetANotification("test"), &profile);
+  message_center()->DisplayedNotification("test");
+  run_loop()->RunUntilIdle();
+  EXPECT_FALSE(delegate()->displayed_first_run_balloon());
+  EXPECT_FALSE(notification_manager()->FirstRunTimerIsActive());
+  EXPECT_FALSE(DidFirstRunPref());
+}
+
+TEST_F(MessageCenterNotificationManagerTest,
+       FirstRunNotShownWithMessageCenter) {
+  TestingProfile profile;
+  notification_manager()->Add(GetANotification("test"), &profile);
+  message_center()->SetMessageCenterVisible(true);
+  run_loop()->RunUntilIdle();
+  EXPECT_FALSE(notification_manager()->FirstRunTimerIsActive());
+  EXPECT_FALSE(DidFirstRunPref());
+}
+}  // namespace message_center
diff --git a/chrome/browser/notifications/message_center_settings_controller.cc b/chrome/browser/notifications/message_center_settings_controller.cc
index 924c669..9acefdf 100644
--- a/chrome/browser/notifications/message_center_settings_controller.cc
+++ b/chrome/browser/notifications/message_center_settings_controller.cc
@@ -6,6 +6,7 @@
 
 #include <algorithm>
 
+#include "base/command_line.h"
 #include "base/i18n/string_compare.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/extensions/app_icon_loader_impl.h"
@@ -16,6 +17,8 @@
 #include "chrome/browser/history/history_types.h"
 #include "chrome/browser/notifications/desktop_notification_service.h"
 #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_manager.h"
 #include "chrome/common/cancelable_task_tracker.h"
@@ -27,7 +30,13 @@
 #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 {
 
@@ -50,24 +59,29 @@
 
 }  // namespace
 
-MessageCenterSettingsController::MessageCenterSettingsController()
-    : delegate_(NULL) {
+MessageCenterSettingsController::MessageCenterSettingsController() {
 }
 
 MessageCenterSettingsController::~MessageCenterSettingsController() {
 }
 
-message_center::NotifierSettingsDelegate*
-MessageCenterSettingsController::ShowSettingsDialog(gfx::NativeView context) {
-  delegate_ = message_center::ShowSettings(this, context);
-  return delegate_;
+void MessageCenterSettingsController::AddObserver(
+    message_center::NotifierSettingsObserver* observer) {
+  observers_.AddObserver(observer);
+}
+
+void MessageCenterSettingsController::RemoveObserver(
+    message_center::NotifierSettingsObserver* observer) {
+  observers_.RemoveObserver(observer);
 }
 
 void MessageCenterSettingsController::GetNotifierList(
     std::vector<Notifier*>* notifiers) {
   DCHECK(notifiers);
   // TODO(mukai): Fix this for multi-profile.
-  Profile* profile = ProfileManager::GetDefaultProfile();
+  // Temporarily use the last used profile to prevent chrome from crashing when
+  // the default profile is not loaded.
+  Profile* profile = ProfileManager::GetLastUsedProfileAllowedByPolicy();
   DesktopNotificationService* notification_service =
       DesktopNotificationServiceFactory::GetForProfile(profile);
 
@@ -94,16 +108,27 @@
       continue;
     }
 
-    notifiers->push_back(new message_center::Notifier(
-        extension->id(),
+    NotifierId notifier_id(NotifierId::APPLICATION, extension->id());
+    notifiers->push_back(new Notifier(
+        notifier_id,
         UTF8ToUTF16(extension->name()),
-        notification_service->IsExtensionEnabled(extension->id())));
+        notification_service->IsNotifierEnabled(notifier_id)));
     app_icon_loader_->FetchImage(extension->id());
   }
-  if (comparator)
-    std::sort(notifiers->begin(), notifiers->end(), *comparator);
-  else
-    std::sort(notifiers->begin(), notifiers->end(), SimpleCompareNotifiers);
+
+  if (notifier::ChromeNotifierServiceFactory::UseSyncedNotifications(
+          CommandLine::ForCurrentProcess())) {
+    notifier::ChromeNotifierService* sync_notifier_service =
+        notifier::ChromeNotifierServiceFactory::GetInstance()->GetForProfile(
+            profile, Profile::EXPLICIT_ACCESS);
+    sync_notifier_service->GetSyncedNotificationServices(notifiers);
+
+    if (comparator)
+      std::sort(notifiers->begin(), notifiers->end(), *comparator);
+    else
+      std::sort(notifiers->begin(), notifiers->end(), SimpleCompareNotifiers);
+  }
+
   int app_count = notifiers->size();
 
   ContentSettingsForOneType settings;
@@ -123,10 +148,11 @@
     std::string url_pattern = iter->primary_pattern.ToString();
     string16 name = UTF8ToUTF16(url_pattern);
     GURL url(url_pattern);
-    notifiers->push_back(new message_center::Notifier(
-        url,
+    NotifierId notifier_id(url);
+    notifiers->push_back(new Notifier(
+        notifier_id,
         name,
-        notification_service->GetContentSetting(url) == CONTENT_SETTING_ALLOW));
+        notification_service->IsNotifierEnabled(notifier_id)));
     patterns_[name] = iter->primary_pattern;
     FaviconService::FaviconForURLParams favicon_params(
         profile, url, chrome::FAVICON | chrome::TOUCH_ICON,
@@ -145,12 +171,11 @@
 #if defined(OS_CHROMEOS)
   const string16 screenshot_name =
       l10n_util::GetStringUTF16(IDS_MESSAGE_CENTER_NOTIFIER_SCREENSHOT_NAME);
-  message_center::Notifier* const screenshot_notifier =
-      new message_center::Notifier(
-          message_center::Notifier::SCREENSHOT,
-          screenshot_name,
-          notification_service->IsSystemComponentEnabled(
-              message_center::Notifier::SCREENSHOT));
+  NotifierId screenshot_notifier_id(NotifierId::SCREENSHOT);
+  Notifier* const screenshot_notifier = new Notifier(
+      screenshot_notifier_id,
+      screenshot_name,
+      notification_service->IsNotifierEnabled(screenshot_notifier_id));
   screenshot_notifier->icon =
       ui::ResourceBundle::GetSharedInstance().GetImageNamed(
           IDR_SCREENSHOT_NOTIFICATION_ICON);
@@ -173,46 +198,49 @@
   DesktopNotificationService* notification_service =
       DesktopNotificationServiceFactory::GetForProfile(profile);
 
-  switch (notifier.type) {
-    case Notifier::APPLICATION:
-      notification_service->SetExtensionEnabled(notifier.id, enabled);
-      break;
-    case Notifier::WEB_PAGE: {
-      ContentSetting default_setting =
-          notification_service->GetDefaultContentSetting(NULL);
-      DCHECK(default_setting == CONTENT_SETTING_ALLOW ||
-             default_setting == CONTENT_SETTING_BLOCK ||
-             default_setting == CONTENT_SETTING_ASK);
-      if ((enabled && default_setting != CONTENT_SETTING_ALLOW) ||
-          (!enabled && default_setting == CONTENT_SETTING_ALLOW)) {
-        if (notifier.url.is_valid()) {
-          if (enabled)
-            notification_service->GrantPermission(notifier.url);
-          else
-            notification_service->DenyPermission(notifier.url);
-        } else {
-          LOG(ERROR) << "Invalid url pattern: " << notifier.url.spec();
-        }
+  if (notifier.notifier_id.type == NotifierId::WEB_PAGE) {
+    // WEB_PAGE notifier cannot handle in DesktopNotificationService
+    // since it has the exact URL pattern.
+    // TODO(mukai): fix this.
+    ContentSetting default_setting =
+        notification_service->GetDefaultContentSetting(NULL);
+    DCHECK(default_setting == CONTENT_SETTING_ALLOW ||
+           default_setting == CONTENT_SETTING_BLOCK ||
+           default_setting == CONTENT_SETTING_ASK);
+    if ((enabled && default_setting != CONTENT_SETTING_ALLOW) ||
+        (!enabled && default_setting == CONTENT_SETTING_ALLOW)) {
+      if (notifier.notifier_id.url.is_valid()) {
+        if (enabled)
+          notification_service->GrantPermission(notifier.notifier_id.url);
+        else
+          notification_service->DenyPermission(notifier.notifier_id.url);
       } else {
-        std::map<string16, ContentSettingsPattern>::const_iterator iter =
-            patterns_.find(notifier.name);
-        if (iter != patterns_.end()) {
-          notification_service->ClearSetting(iter->second);
-        } else {
-          LOG(ERROR) << "Invalid url pattern: " << notifier.url.spec();
-        }
+        LOG(ERROR) << "Invalid url pattern: "
+                   << notifier.notifier_id.url.spec();
       }
-      break;
+    } else {
+      std::map<string16, ContentSettingsPattern>::const_iterator iter =
+          patterns_.find(notifier.name);
+      if (iter != patterns_.end()) {
+        notification_service->ClearSetting(iter->second);
+      } else {
+        LOG(ERROR) << "Invalid url pattern: "
+                   << notifier.notifier_id.url.spec();
+      }
     }
-    case message_center::Notifier::SYSTEM_COMPONENT:
-      notification_service->SetSystemComponentEnabled(
-          notifier.system_component_type, enabled);
-      break;
+  } else {
+    notification_service->SetNotifierEnabled(notifier.notifier_id, enabled);
+    if (notifier.notifier_id.type == NotifierId::SYNCED_NOTIFICATION_SERVICE) {
+      notifier::ChromeNotifierService* notifier_service =
+          notifier::ChromeNotifierServiceFactory::GetInstance()->GetForProfile(
+              profile, Profile::EXPLICIT_ACCESS);
+      notifier_service->OnSyncedNotificationServiceEnabled(
+          notifier.notifier_id.id, enabled);
+    }
   }
 }
 
 void MessageCenterSettingsController::OnNotifierSettingsClosing() {
-  delegate_ = NULL;
   DCHECK(favicon_tracker_.get());
   favicon_tracker_->TryCancelAll();
   patterns_.clear();
@@ -221,15 +249,16 @@
 void MessageCenterSettingsController::OnFaviconLoaded(
     const GURL& url,
     const chrome::FaviconImageResult& favicon_result) {
-  if (!delegate_)
-    return;
-  delegate_->UpdateFavicon(url, favicon_result.image);
+  FOR_EACH_OBSERVER(message_center::NotifierSettingsObserver,
+                    observers_,
+                    UpdateIconImage(NotifierId(url), favicon_result.image));
 }
 
 
 void MessageCenterSettingsController::SetAppImage(const std::string& id,
                                                   const gfx::ImageSkia& image) {
-  if (!delegate_)
-    return;
-  delegate_->UpdateIconImage(id, gfx::Image(image) );
+  FOR_EACH_OBSERVER(message_center::NotifierSettingsObserver,
+                    observers_,
+                    UpdateIconImage(NotifierId(NotifierId::APPLICATION, id),
+                                    gfx::Image(image)));
 }
diff --git a/chrome/browser/notifications/message_center_settings_controller.h b/chrome/browser/notifications/message_center_settings_controller.h
index 45f6331..71487c5 100644
--- a/chrome/browser/notifications/message_center_settings_controller.h
+++ b/chrome/browser/notifications/message_center_settings_controller.h
@@ -10,6 +10,7 @@
 
 #include "base/basictypes.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/observer_list.h"
 #include "chrome/browser/extensions/app_icon_loader.h"
 #include "chrome/common/content_settings.h"
 #include "ui/message_center/notifier_settings.h"
@@ -29,13 +30,11 @@
   MessageCenterSettingsController();
   virtual ~MessageCenterSettingsController();
 
-  // Shows a new settings dialog window with specified |context|. If there's
-  // already an existing dialog, it raises the dialog instead of creating a new
-  // one.
-  message_center::NotifierSettingsDelegate* ShowSettingsDialog(
-      gfx::NativeView context);
-
-  // Overridden from message_center::NotifierSettingsViewDelegate.
+  // Overridden from message_center::NotifierSettingsProvider.
+  virtual void AddObserver(
+      message_center::NotifierSettingsObserver* observer) OVERRIDE;
+  virtual void RemoveObserver(
+      message_center::NotifierSettingsObserver* observer) OVERRIDE;
   virtual void GetNotifierList(
       std::vector<message_center::Notifier*>* notifiers)
       OVERRIDE;
@@ -52,9 +51,8 @@
   void OnFaviconLoaded(const GURL& url,
                        const chrome::FaviconImageResult& favicon_result);
 
-  // The view displaying notifier settings. NULL if the settings are not
-  // visible.
-  message_center::NotifierSettingsDelegate* delegate_;
+  // The views displaying notifier settings.
+  ObserverList<message_center::NotifierSettingsObserver> observers_;
 
   // The task tracker for loading favicons.
   scoped_ptr<CancelableTaskTracker> favicon_tracker_;
diff --git a/chrome/browser/notifications/notification.h b/chrome/browser/notifications/notification.h
index 05c3fff..3e4685c 100644
--- a/chrome/browser/notifications/notification.h
+++ b/chrome/browser/notifications/notification.h
@@ -12,11 +12,11 @@
 #include "base/strings/string16.h"
 #include "base/values.h"
 #include "chrome/browser/notifications/notification_delegate.h"
-#include "googleurl/src/gurl.h"
 #include "third_party/WebKit/public/web/WebTextDirection.h"
 #include "ui/gfx/image/image.h"
 #include "ui/message_center/notification.h"
 #include "ui/message_center/notification_types.h"
+#include "url/gurl.h"
 
 // Representation of a notification to be shown to the user.
 // On non-Ash platforms these are rendered as HTML, sometimes described by a
diff --git a/chrome/browser/notifications/notification_audio_controller.h b/chrome/browser/notifications/notification_audio_controller.h
index ce6cbdb..c8a27a7 100644
--- a/chrome/browser/notifications/notification_audio_controller.h
+++ b/chrome/browser/notifications/notification_audio_controller.h
@@ -10,7 +10,7 @@
 #include "base/callback.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_vector.h"
-#include "base/string_piece.h"
+#include "base/strings/string_piece.h"
 #include "media/audio/audio_parameters.h"
 
 namespace base {
diff --git a/chrome/browser/notifications/notification_browsertest.cc b/chrome/browser/notifications/notification_browsertest.cc
index 06fe062..fe5982a 100644
--- a/chrome/browser/notifications/notification_browsertest.cc
+++ b/chrome/browser/notifications/notification_browsertest.cc
@@ -40,15 +40,15 @@
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/test_utils.h"
-#include "googleurl/src/gurl.h"
 #include "net/base/net_util.h"
-#include "net/test/spawned_test_server/spawned_test_server.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/window_open_disposition.h"
 #include "ui/message_center/message_center.h"
 #include "ui/message_center/message_center_observer.h"
 #include "ui/message_center/message_center_switches.h"
 #include "ui/message_center/message_center_util.h"
+#include "url/gurl.h"
 
 // TODO(kbr): remove: http://crbug.com/222296
 #if defined(OS_MACOSX)
@@ -57,7 +57,7 @@
 
 namespace {
 
-const char kExpectedIconUrl[] = "files/notifications/no_such_file.png";
+const char kExpectedIconUrl[] = "/notifications/no_such_file.png";
 
 enum InfobarAction {
   DISMISS = 0,
@@ -206,9 +206,6 @@
   NotificationsTest() {}
 
  protected:
-  // Overriden from InProcessBrowserTest:
-  virtual void SetUpInProcessBrowserTestFixture() OVERRIDE;
-
   int GetNotificationCount();
 
   NotificationChangeObserver* CreateObserver();
@@ -244,23 +241,16 @@
   bool CheckOriginInSetting(const ContentSettingsForOneType& settings,
                             const GURL& origin);
 
-  GURL empty_page_url_;
-  GURL test_page_url_;
+  GURL GetTestPageURL() const {
+    return embedded_test_server()->GetURL(
+      "/notifications/notification_tester.html");
+  }
 
  private:
   void DropOriginPreference(const GURL& origin);
   DesktopNotificationService* GetDesktopNotificationService();
 };
 
-void NotificationsTest::SetUpInProcessBrowserTestFixture() {
-  InProcessBrowserTest::SetUpInProcessBrowserTestFixture();
-
-  ASSERT_TRUE(test_server()->Start());
-  empty_page_url_ = test_server()->GetURL("files/empty.html");
-  test_page_url_ = test_server()->GetURL(
-      "files/notifications/notification_tester.html");
-}
-
 int NotificationsTest::GetNotificationCount() {
   if (message_center::IsRichNotificationEnabled()) {
     return message_center::MessageCenter::Get()->NotificationCount();
@@ -483,10 +473,12 @@
 
 // If this flakes, use http://crbug.com/62311 and http://crbug.com/74428.
 IN_PROC_BROWSER_TEST_F(NotificationsTest, TestUserGestureInfobar) {
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+
   ui_test_utils::NavigateToURL(
       browser(),
-      test_server()->GetURL(
-          "files/notifications/notifications_request_function.html"));
+      embedded_test_server()->GetURL(
+          "/notifications/notifications_request_function.html"));
 
   // Request permission by calling request() while eval'ing an inline script;
   // That's considered a user gesture to webkit, and should produce an infobar.
@@ -503,12 +495,14 @@
 
 // If this flakes, use http://crbug.com/62311.
 IN_PROC_BROWSER_TEST_F(NotificationsTest, TestNoUserGestureInfobar) {
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+
   // Load a page which just does a request; no user gesture should result
   // in no infobar.
   ui_test_utils::NavigateToURL(
       browser(),
-      test_server()->GetURL(
-          "files/notifications/notifications_request_inline.html"));
+      embedded_test_server()->GetURL(
+          "/notifications/notifications_request_inline.html"));
 
   EXPECT_EQ(0U, InfoBarService::FromWebContents(
       browser()->tab_strip_model()->GetWebContentsAt(0))->infobar_count());
@@ -521,14 +515,16 @@
     return;
 #endif
 
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+
   // Creates a simple notification.
   AllowAllOrigins();
-  ui_test_utils::NavigateToURL(browser(), test_page_url_);
+  ui_test_utils::NavigateToURL(browser(), GetTestPageURL());
 
   std::string result = CreateSimpleNotification(browser(), true);
   EXPECT_NE("-1", result);
 
-  GURL EXPECTED_ICON_URL = test_server()->GetURL(kExpectedIconUrl);
+  GURL EXPECTED_ICON_URL = embedded_test_server()->GetURL(kExpectedIconUrl);
   ASSERT_EQ(1, GetNotificationCount());
   if (message_center::IsRichNotificationEnabled()) {
     message_center::NotificationList::Notifications notifications =
@@ -553,9 +549,11 @@
     return;
 #endif
 
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+
   // Creates a notification and closes it.
   AllowAllOrigins();
-  ui_test_utils::NavigateToURL(browser(), test_page_url_);
+  ui_test_utils::NavigateToURL(browser(), GetTestPageURL());
 
   std::string result = CreateSimpleNotification(browser(), true);
   EXPECT_NE("-1", result);
@@ -582,9 +580,11 @@
     return;
 #endif
 
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+
   // Creates a notification and cancels it in the origin page.
   AllowAllOrigins();
-  ui_test_utils::NavigateToURL(browser(), test_page_url_);
+  ui_test_utils::NavigateToURL(browser(), GetTestPageURL());
 
   std::string note_id = CreateSimpleNotification(browser(), true);
   EXPECT_NE(note_id, "-1");
@@ -595,8 +595,10 @@
 }
 
 IN_PROC_BROWSER_TEST_F(NotificationsTest, TestPermissionInfobarAppears) {
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+
   // Requests notification privileges and verifies the infobar appears.
-  ui_test_utils::NavigateToURL(browser(), test_page_url_);
+  ui_test_utils::NavigateToURL(browser(), GetTestPageURL());
   ASSERT_TRUE(RequestPermissionAndWait(browser()));
 
   ASSERT_EQ(0, GetNotificationCount());
@@ -610,8 +612,10 @@
     return;
 #endif
 
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+
   // Tries to create a notification and clicks allow on the infobar.
-  ui_test_utils::NavigateToURL(browser(), test_page_url_);
+  ui_test_utils::NavigateToURL(browser(), GetTestPageURL());
   // This notification should not be shown because we do not have permission.
   CreateSimpleNotification(browser(), false);
   ASSERT_EQ(0, GetNotificationCount());
@@ -624,21 +628,25 @@
 }
 
 IN_PROC_BROWSER_TEST_F(NotificationsTest, TestDenyOnPermissionInfobar) {
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+
   // Test that no notification is created
   // when Deny is chosen from permission infobar.
-  ui_test_utils::NavigateToURL(browser(), test_page_url_);
+  ui_test_utils::NavigateToURL(browser(), GetTestPageURL());
   ASSERT_TRUE(RequestPermissionAndWait(browser()));
   PerformActionOnInfobar(browser(), DENY, 0, 0);
   CreateSimpleNotification(browser(), false);
   ASSERT_EQ(0, GetNotificationCount());
   ContentSettingsForOneType settings;
   GetPrefsByContentSetting(CONTENT_SETTING_BLOCK, &settings);
-  EXPECT_TRUE(CheckOriginInSetting(settings, test_page_url_));
+  EXPECT_TRUE(CheckOriginInSetting(settings, GetTestPageURL()));
 }
 
 IN_PROC_BROWSER_TEST_F(NotificationsTest, TestClosePermissionInfobar) {
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+
   // Test that no notification is created when permission infobar is dismissed.
-  ui_test_utils::NavigateToURL(browser(), test_page_url_);
+  ui_test_utils::NavigateToURL(browser(), GetTestPageURL());
   ASSERT_TRUE(RequestPermissionAndWait(browser()));
   PerformActionOnInfobar(browser(), DISMISS, 0, 0);
   CreateSimpleNotification(browser(), false);
@@ -654,9 +662,12 @@
   if (base::mac::IsOSMountainLionOrLater())
     return;
 #endif
+
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+
   // Verify that all domains can be allowed to show notifications.
   SetDefaultPermissionSetting(CONTENT_SETTING_ALLOW);
-  ui_test_utils::NavigateToURL(browser(), test_page_url_);
+  ui_test_utils::NavigateToURL(browser(), GetTestPageURL());
 
   std::string result = CreateSimpleNotification(browser(), true);
   EXPECT_NE("-1", result);
@@ -667,9 +678,11 @@
 }
 
 IN_PROC_BROWSER_TEST_F(NotificationsTest, TestDenyNotificationsFromAllSites) {
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+
   // Verify that no domain can show notifications.
   SetDefaultPermissionSetting(CONTENT_SETTING_BLOCK);
-  ui_test_utils::NavigateToURL(browser(), test_page_url_);
+  ui_test_utils::NavigateToURL(browser(), GetTestPageURL());
 
   std::string result = CreateSimpleNotification(browser(), false);
   EXPECT_EQ("-1", result);
@@ -678,12 +691,14 @@
 }
 
 IN_PROC_BROWSER_TEST_F(NotificationsTest, TestDenyDomainAndAllowAll) {
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+
   // Verify that denying a domain and allowing all shouldn't show
   // notifications from the denied domain.
-  DenyOrigin(test_page_url_.GetOrigin());
+  DenyOrigin(GetTestPageURL().GetOrigin());
   SetDefaultPermissionSetting(CONTENT_SETTING_ALLOW);
 
-  ui_test_utils::NavigateToURL(browser(), test_page_url_);
+  ui_test_utils::NavigateToURL(browser(), GetTestPageURL());
 
   std::string result = CreateSimpleNotification(browser(), false);
   EXPECT_EQ("-1", result);
@@ -697,12 +712,15 @@
   if (base::mac::IsOSMountainLionOrLater())
     return;
 #endif
+
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+
   // Verify that allowing a domain and denying all others should show
   // notifications from the allowed domain.
-  AllowOrigin(test_page_url_.GetOrigin());
+  AllowOrigin(GetTestPageURL().GetOrigin());
   SetDefaultPermissionSetting(CONTENT_SETTING_BLOCK);
 
-  ui_test_utils::NavigateToURL(browser(), test_page_url_);
+  ui_test_utils::NavigateToURL(browser(), GetTestPageURL());
 
   std::string result = CreateSimpleNotification(browser(), true);
   EXPECT_NE("-1", result);
@@ -716,17 +734,20 @@
   if (base::mac::IsOSMountainLionOrLater())
     return;
 #endif
-  // Verify that denying and again allowing should show notifications.
-  DenyOrigin(test_page_url_.GetOrigin());
 
-  ui_test_utils::NavigateToURL(browser(), test_page_url_);
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+
+  // Verify that denying and again allowing should show notifications.
+  DenyOrigin(GetTestPageURL().GetOrigin());
+
+  ui_test_utils::NavigateToURL(browser(), GetTestPageURL());
 
   std::string result = CreateSimpleNotification(browser(), false);
   EXPECT_EQ("-1", result);
 
   ASSERT_EQ(0, GetNotificationCount());
 
-  AllowOrigin(test_page_url_.GetOrigin());
+  AllowOrigin(GetTestPageURL().GetOrigin());
   result = CreateSimpleNotification(browser(), true);
   EXPECT_NE("-1", result);
 
@@ -741,16 +762,19 @@
   if (base::mac::IsOSMountainLionOrLater())
     return;
 #endif
+
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+
   // Verify able to create, deny, and close the notification.
   AllowAllOrigins();
-  ui_test_utils::NavigateToURL(browser(), test_page_url_);
+  ui_test_utils::NavigateToURL(browser(), GetTestPageURL());
   CreateSimpleNotification(browser(), true);
   ASSERT_EQ(1, GetNotificationCount());
 
-  DenyOrigin(test_page_url_.GetOrigin());
+  DenyOrigin(GetTestPageURL().GetOrigin());
   ContentSettingsForOneType settings;
   GetPrefsByContentSetting(CONTENT_SETTING_BLOCK, &settings);
-  ASSERT_TRUE(CheckOriginInSetting(settings, test_page_url_.GetOrigin()));
+  ASSERT_TRUE(CheckOriginInSetting(settings, GetTestPageURL().GetOrigin()));
 
   EXPECT_EQ(1, GetNotificationCount());
   if (message_center::IsRichNotificationEnabled()) {
@@ -770,15 +794,17 @@
 IN_PROC_BROWSER_TEST_F(
     NotificationsTest,
     DISABLED_TestOriginPrefsNotSavedInIncognito) {
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+
   // Verify that allow/deny origin preferences are not saved in incognito.
   Browser* incognito = CreateIncognitoBrowser();
-  ui_test_utils::NavigateToURL(incognito, test_page_url_);
+  ui_test_utils::NavigateToURL(incognito, GetTestPageURL());
   ASSERT_TRUE(RequestPermissionAndWait(incognito));
   PerformActionOnInfobar(incognito, DENY, 0, 0);
   CloseBrowserWindow(incognito);
 
   incognito = CreateIncognitoBrowser();
-  ui_test_utils::NavigateToURL(incognito, test_page_url_);
+  ui_test_utils::NavigateToURL(incognito, GetTestPageURL());
   ASSERT_TRUE(RequestPermissionAndWait(incognito));
   PerformActionOnInfobar(incognito, ALLOW, 0, 0);
   CreateSimpleNotification(incognito, true);
@@ -786,7 +812,7 @@
   CloseBrowserWindow(incognito);
 
   incognito = CreateIncognitoBrowser();
-  ui_test_utils::NavigateToURL(incognito, test_page_url_);
+  ui_test_utils::NavigateToURL(incognito, GetTestPageURL());
   ASSERT_TRUE(RequestPermissionAndWait(incognito));
 
   ContentSettingsForOneType settings;
@@ -797,8 +823,10 @@
 }
 
 IN_PROC_BROWSER_TEST_F(NotificationsTest, TestExitBrowserWithInfobar) {
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+
   // Exit the browser window, when the infobar appears.
-  ui_test_utils::NavigateToURL(browser(), test_page_url_);
+  ui_test_utils::NavigateToURL(browser(), GetTestPageURL());
   ASSERT_TRUE(RequestPermissionAndWait(browser()));
 }
 
@@ -812,14 +840,16 @@
 #endif
 IN_PROC_BROWSER_TEST_F(NotificationsTest,
                        MAYBE_TestCrashTabWithPermissionInfobar) {
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+
   // Test crashing the tab with permission infobar doesn't crash Chrome.
   ui_test_utils::NavigateToURLWithDisposition(
       browser(),
-      empty_page_url_,
+      embedded_test_server()->GetURL("/empty.html"),
       NEW_BACKGROUND_TAB,
       ui_test_utils::BROWSER_TEST_WAIT_FOR_TAB);
   browser()->tab_strip_model()->ActivateTabAt(0, true);
-  ui_test_utils::NavigateToURL(browser(), test_page_url_);
+  ui_test_utils::NavigateToURL(browser(), GetTestPageURL());
   ASSERT_TRUE(RequestPermissionAndWait(browser()));
   CrashTab(browser(), 0);
 }
@@ -834,9 +864,12 @@
   if (base::mac::IsOSMountainLionOrLater())
     return;
 #endif
+
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+
   // Test killing a notification doesn't crash Chrome.
   AllowAllOrigins();
-  ui_test_utils::NavigateToURL(browser(), test_page_url_);
+  ui_test_utils::NavigateToURL(browser(), GetTestPageURL());
   CreateSimpleNotification(browser(), true);
   ASSERT_EQ(1, GetNotificationCount());
 
@@ -852,9 +885,12 @@
   if (base::mac::IsOSMountainLionOrLater())
     return;
 #endif
+
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+
   // Test notifications in incognito window.
   Browser* browser = CreateIncognitoBrowser();
-  ui_test_utils::NavigateToURL(browser, test_page_url_);
+  ui_test_utils::NavigateToURL(browser, GetTestPageURL());
   browser->tab_strip_model()->ActivateTabAt(0, true);
   ASSERT_TRUE(RequestPermissionAndWait(browser));
   PerformActionOnInfobar(browser, ALLOW, 0, 0);
@@ -863,6 +899,8 @@
 }
 
 IN_PROC_BROWSER_TEST_F(NotificationsTest, TestCloseTabWithPermissionInfobar) {
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+
   // Test that user can close tab when infobar present.
   ui_test_utils::NavigateToURLWithDisposition(
       browser(),
@@ -870,7 +908,7 @@
       NEW_BACKGROUND_TAB,
       ui_test_utils::BROWSER_TEST_WAIT_FOR_TAB);
   browser()->tab_strip_model()->ActivateTabAt(0, true);
-  ui_test_utils::NavigateToURL(browser(), test_page_url_);
+  ui_test_utils::NavigateToURL(browser(), GetTestPageURL());
   ASSERT_TRUE(RequestPermissionAndWait(browser()));
   content::WindowedNotificationObserver observer(
       content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
@@ -888,6 +926,9 @@
   if (base::mac::IsOSMountainLionOrLater())
     return;
 #endif
+
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+
   // Test navigating away when an infobar is present,
   // then trying to create a notification from the same page.
   ui_test_utils::NavigateToURLWithDisposition(
@@ -896,9 +937,9 @@
       NEW_BACKGROUND_TAB,
       ui_test_utils::BROWSER_TEST_WAIT_FOR_TAB);
   browser()->tab_strip_model()->ActivateTabAt(0, true);
-  ui_test_utils::NavigateToURL(browser(), test_page_url_);
+  ui_test_utils::NavigateToURL(browser(), GetTestPageURL());
   ASSERT_TRUE(RequestPermissionAndWait(browser()));
-  ui_test_utils::NavigateToURL(browser(), test_page_url_);
+  ui_test_utils::NavigateToURL(browser(), GetTestPageURL());
   ASSERT_TRUE(RequestPermissionAndWait(browser()));
   PerformActionOnInfobar(browser(), ALLOW, 0, 0);
   CreateSimpleNotification(browser(), true);
@@ -921,6 +962,9 @@
   if (base::mac::IsOSMountainLionOrLater())
     return;
 #endif
+
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+
   // Test crashing renderer does not close or crash notification.
   AllowAllOrigins();
   ui_test_utils::NavigateToURLWithDisposition(
@@ -929,7 +973,7 @@
       NEW_BACKGROUND_TAB,
       ui_test_utils::BROWSER_TEST_WAIT_FOR_TAB);
   browser()->tab_strip_model()->ActivateTabAt(0, true);
-  ui_test_utils::NavigateToURL(browser(), test_page_url_);
+  ui_test_utils::NavigateToURL(browser(), GetTestPageURL());
   CreateSimpleNotification(browser(), true);
   ASSERT_EQ(1, GetNotificationCount());
   CrashTab(browser(), 0);
@@ -942,10 +986,13 @@
   if (base::mac::IsOSMountainLionOrLater())
     return;
 #endif
+
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+
   // Test that we can replace a notification using the replaceId.
   AllowAllOrigins();
 
-  ui_test_utils::NavigateToURL(browser(), test_page_url_);
+  ui_test_utils::NavigateToURL(browser(), GetTestPageURL());
 
   std::string result = CreateNotification(
       browser(), true, "abc.png", "Title1", "Body1", "chat");
@@ -968,7 +1015,7 @@
     ASSERT_EQ(1U, balloons.size());
     Balloon* balloon = balloons[0];
     const Notification& notification = balloon->notification();
-    GURL EXPECTED_ICON_URL = test_server()->GetURL(kExpectedIconUrl);
+    GURL EXPECTED_ICON_URL = embedded_test_server()->GetURL(kExpectedIconUrl);
     EXPECT_EQ(EXPECTED_ICON_URL, notification.icon_url());
     EXPECT_EQ(ASCIIToUTF16("Title2"), notification.title());
     EXPECT_EQ(ASCIIToUTF16("Body2"), notification.message());
diff --git a/chrome/browser/notifications/notification_prefs_manager.cc b/chrome/browser/notifications/notification_prefs_manager.cc
index ad4b73b..a77eb63 100644
--- a/chrome/browser/notifications/notification_prefs_manager.cc
+++ b/chrome/browser/notifications/notification_prefs_manager.cc
@@ -25,4 +25,6 @@
 void NotificationPrefsManager::RegisterPrefs(PrefRegistrySimple* registry) {
   registry->RegisterIntegerPref(prefs::kDesktopNotificationPosition,
                                 BalloonCollection::DEFAULT_POSITION);
+  registry->RegisterBooleanPref(prefs::kMessageCenterShowedFirstRunBalloon,
+                                false);
 }
diff --git a/chrome/browser/notifications/notification_ui_manager.cc b/chrome/browser/notifications/notification_ui_manager.cc
index 2c73a9e..8bbafe7 100644
--- a/chrome/browser/notifications/notification_ui_manager.cc
+++ b/chrome/browser/notifications/notification_ui_manager.cc
@@ -26,7 +26,7 @@
 NotificationUIManager* NotificationUIManager::Create(PrefService* local_state) {
   if (DelegatesToMessageCenter())
     return new MessageCenterNotificationManager(
-        g_browser_process->message_center());
+        g_browser_process->message_center(), local_state);
 
   BalloonNotificationUIManager* balloon_manager =
       new BalloonNotificationUIManager(local_state);
diff --git a/chrome/browser/notifications/notification_ui_manager_impl.h b/chrome/browser/notifications/notification_ui_manager_impl.h
index 273beea..f8544ea 100644
--- a/chrome/browser/notifications/notification_ui_manager_impl.h
+++ b/chrome/browser/notifications/notification_ui_manager_impl.h
@@ -12,7 +12,7 @@
 #include "base/id_map.h"
 #include "base/memory/linked_ptr.h"
 #include "base/prefs/pref_member.h"
-#include "base/timer.h"
+#include "base/timer/timer.h"
 #include "chrome/browser/notifications/notification_ui_manager.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
diff --git a/chrome/browser/notifications/notification_ui_manager_mac.h b/chrome/browser/notifications/notification_ui_manager_mac.h
index 709e2d2..20cc582 100644
--- a/chrome/browser/notifications/notification_ui_manager_mac.h
+++ b/chrome/browser/notifications/notification_ui_manager_mac.h
@@ -11,7 +11,7 @@
 #include <set>
 
 #include "base/basictypes.h"
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/strings/string16.h"
 #include "chrome/browser/notifications/balloon_notification_ui_manager.h"
@@ -74,7 +74,7 @@
       const string16& replacement_id) const;
 
   // Cocoa class that receives callbacks from the NSUserNotificationCenter.
-  scoped_nsobject<NotificationCenterDelegate> delegate_;
+  base::scoped_nsobject<NotificationCenterDelegate> delegate_;
 
   // Maps notification_ids to ControllerNotifications. The map owns the value,
   // so it must be deleted when remvoed from the map. This is typically handled
diff --git a/chrome/browser/notifications/notification_ui_manager_mac.mm b/chrome/browser/notifications/notification_ui_manager_mac.mm
index 96cea87..5222aa1 100644
--- a/chrome/browser/notifications/notification_ui_manager_mac.mm
+++ b/chrome/browser/notifications/notification_ui_manager_mac.mm
@@ -102,7 +102,7 @@
   // notification_ui_manager.cc.
   if (DelegatesToMessageCenter()) {
     return new MessageCenterNotificationManager(
-        g_browser_process->message_center());
+        g_browser_process->message_center(), local_state);
   }
 
   BalloonNotificationUIManager* balloon_manager = NULL;
diff --git a/chrome/browser/notifications/sync_notifier/chrome_notifier_service.cc b/chrome/browser/notifications/sync_notifier/chrome_notifier_service.cc
index ff4c5b4..8cb839f 100644
--- a/chrome/browser/notifications/sync_notifier/chrome_notifier_service.cc
+++ b/chrome/browser/notifications/sync_notifier/chrome_notifier_service.cc
@@ -8,18 +8,28 @@
 
 #include "chrome/browser/notifications/sync_notifier/chrome_notifier_service.h"
 
+#include "chrome/browser/notifications/desktop_notification_service.h"
+#include "chrome/browser/notifications/desktop_notification_service_factory.h"
 #include "chrome/browser/notifications/notification.h"
 #include "chrome/browser/notifications/notification_ui_manager.h"
 #include "chrome/browser/profiles/profile.h"
-#include "googleurl/src/gurl.h"
+#include "grit/ui_strings.h"
 #include "sync/api/sync_change.h"
 #include "sync/api/sync_change_processor.h"
 #include "sync/api/sync_error_factory.h"
 #include "sync/protocol/sync.pb.h"
 #include "sync/protocol/synced_notification_specifics.pb.h"
 #include "third_party/WebKit/public/web/WebTextDirection.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/message_center/notifier_settings.h"
+#include "url/gurl.h"
 
 namespace notifier {
+namespace {
+
+const char kSampleSyncedNotificationServiceId[] = "sample-synced-service";
+
+}
 
 bool ChromeNotifierService::avoid_bitmap_fetching_for_test_ = false;
 
@@ -251,6 +261,27 @@
   return NULL;
 }
 
+void ChromeNotifierService::GetSyncedNotificationServices(
+    std::vector<message_center::Notifier*>* notifiers) {
+  // TODO(mukai|petewil): should check the profile's eligibility before adding
+  // the sample app.
+
+  // Currently we just use kSampleSyncedNotificationServiceId as a place holder.
+  // TODO(petewil): Really obtain the list of apps from the server and create
+  // the list of ids here.
+  DesktopNotificationService* desktop_notification_service =
+      DesktopNotificationServiceFactory::GetForProfile(profile_);
+  message_center::NotifierId notifier_id(
+      message_center::NotifierId::SYNCED_NOTIFICATION_SERVICE,
+      kSampleSyncedNotificationServiceId);
+  notifiers->push_back(new message_center::Notifier(
+      notifier_id,
+      l10n_util::GetStringUTF16(
+          IDS_MESSAGE_CENTER_SAMPLE_SYNCED_NOTIFICATION_SERVICE_NAME),
+      desktop_notification_service->IsNotifierEnabled(notifier_id)));
+  // TODO(mukai): should add icon for the sample app.
+}
+
 void ChromeNotifierService::MarkNotificationAsDismissed(
     const std::string& key) {
   SyncedNotification* notification = FindNotificationByKey(key);
@@ -291,4 +322,9 @@
   notification_copy->StartBitmapFetch();
 }
 
+void ChromeNotifierService::OnSyncedNotificationServiceEnabled(
+    const std::string& notifier_id, bool enabled) {
+  // TODO(petewil): start/stop syncing
+}
+
 }  // namespace notifier
diff --git a/chrome/browser/notifications/sync_notifier/chrome_notifier_service.h b/chrome/browser/notifications/sync_notifier/chrome_notifier_service.h
index 270157f..ba3666d 100644
--- a/chrome/browser/notifications/sync_notifier/chrome_notifier_service.h
+++ b/chrome/browser/notifications/sync_notifier/chrome_notifier_service.h
@@ -17,6 +17,10 @@
 class NotificationUIManager;
 class Profile;
 
+namespace message_center {
+struct Notifier;
+}
+
 namespace notifier {
 
 // The ChromeNotifierService holds notifications which represent the state of
@@ -56,9 +60,19 @@
   // The caller must not free it.
   notifier::SyncedNotification* FindNotificationByKey(const std::string& key);
 
+  // Get the list of synced notification services and fill their meta data to
+  // |notifiers|.
+  void GetSyncedNotificationServices(
+      std::vector<message_center::Notifier*>* notifiers);
+
   // Called when we dismiss a notification.
   void MarkNotificationAsDismissed(const std::string& id);
 
+  // Called when a notier is enabled or disabled.
+  void OnSyncedNotificationServiceEnabled(
+      const std::string& notifier_id,
+      bool enabled);
+
   // functions for test
   void AddForTest(scoped_ptr<notifier::SyncedNotification> notification) {
     Add(notification.Pass());
diff --git a/chrome/browser/notifications/sync_notifier/chrome_notifier_service_factory.cc b/chrome/browser/notifications/sync_notifier/chrome_notifier_service_factory.cc
index a029c4d..16216a7 100644
--- a/chrome/browser/notifications/sync_notifier/chrome_notifier_service_factory.cc
+++ b/chrome/browser/notifications/sync_notifier/chrome_notifier_service_factory.cc
@@ -4,8 +4,10 @@
 
 #include "chrome/browser/notifications/sync_notifier/chrome_notifier_service_factory.h"
 
+#include "base/command_line.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/notifications/sync_notifier/chrome_notifier_service.h"
+#include "chrome/common/chrome_switches.h"
 #include "components/browser_context_keyed_service/browser_context_dependency_manager.h"
 
 namespace notifier {
@@ -22,6 +24,16 @@
   return Singleton<ChromeNotifierServiceFactory>::get();
 }
 
+// static
+bool ChromeNotifierServiceFactory::UseSyncedNotifications(
+    CommandLine* command_line) {
+  if (command_line->HasSwitch(switches::kDisableSyncSyncedNotifications))
+    return false;
+  if (command_line->HasSwitch(switches::kEnableSyncSyncedNotifications))
+    return true;
+  return false;
+}
+
 ChromeNotifierServiceFactory::ChromeNotifierServiceFactory()
     : BrowserContextKeyedServiceFactory(
         "ChromeNotifierService",
diff --git a/chrome/browser/notifications/sync_notifier/chrome_notifier_service_factory.h b/chrome/browser/notifications/sync_notifier/chrome_notifier_service_factory.h
index 2261f9c..4861dad 100644
--- a/chrome/browser/notifications/sync_notifier/chrome_notifier_service_factory.h
+++ b/chrome/browser/notifications/sync_notifier/chrome_notifier_service_factory.h
@@ -9,6 +9,8 @@
 #include "chrome/browser/profiles/profile.h"
 #include "components/browser_context_keyed_service/browser_context_keyed_service_factory.h"
 
+class CommandLine;
+
 namespace notifier {
 
 class ChromeNotifierService;
@@ -20,6 +22,12 @@
 
   static ChromeNotifierServiceFactory* GetInstance();
 
+  // Based on command line switches, make the call to use SyncedNotifications or
+  // not.
+  // TODO(petewil): Remove this when the SyncedNotifications feature is ready
+  // to be turned on by default, and just use a disable switch instead then.
+  static bool UseSyncedNotifications(CommandLine* command_line);
+
  private:
   friend struct DefaultSingletonTraits<ChromeNotifierServiceFactory>;
 
diff --git a/chrome/browser/notifications/sync_notifier/notification_bitmap_fetcher.h b/chrome/browser/notifications/sync_notifier/notification_bitmap_fetcher.h
index e8c17cb..7a268e6 100644
--- a/chrome/browser/notifications/sync_notifier/notification_bitmap_fetcher.h
+++ b/chrome/browser/notifications/sync_notifier/notification_bitmap_fetcher.h
@@ -7,9 +7,9 @@
 
 #include "base/memory/scoped_ptr.h"
 #include "chrome/browser/image_decoder.h"
-#include "googleurl/src/gurl.h"
 #include "net/url_request/url_fetcher_delegate.h"
 #include "third_party/skia/include/core/SkBitmap.h"
+#include "url/gurl.h"
 
 namespace net {
 class URLFetcher;
diff --git a/chrome/browser/notifications/sync_notifier/synced_notification.cc b/chrome/browser/notifications/sync_notifier/synced_notification.cc
index e918c8b..69c19d6 100644
--- a/chrome/browser/notifications/sync_notifier/synced_notification.cc
+++ b/chrome/browser/notifications/sync_notifier/synced_notification.cc
@@ -6,7 +6,7 @@
 
 #include "base/basictypes.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/notifications/notification.h"
diff --git a/chrome/browser/notifications/sync_notifier/synced_notification.h b/chrome/browser/notifications/sync_notifier/synced_notification.h
index 70c15c2..52f37ee 100644
--- a/chrome/browser/notifications/sync_notifier/synced_notification.h
+++ b/chrome/browser/notifications/sync_notifier/synced_notification.h
@@ -15,10 +15,10 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/scoped_vector.h"
 #include "chrome/browser/notifications/sync_notifier/notification_bitmap_fetcher.h"
-#include "googleurl/src/gurl.h"
 #include "sync/api/sync_data.h"
 #include "sync/protocol/sync.pb.h"
 #include "ui/gfx/image/image.h"
+#include "url/gurl.h"
 
 namespace sync_pb {
 class SyncedNotificationSpecifics;
diff --git a/chrome/browser/omnibox/omnibox_field_trial.cc b/chrome/browser/omnibox/omnibox_field_trial.cc
index 4ec2c5c..da16943 100644
--- a/chrome/browser/omnibox/omnibox_field_trial.cc
+++ b/chrome/browser/omnibox/omnibox_field_trial.cc
@@ -22,6 +22,7 @@
 const char kHUPCreateShorterMatchFieldTrialName[] =
     "OmniboxHUPCreateShorterMatch";
 const char kStopTimerFieldTrialName[] = "OmniboxStopTimer";
+const char kShortcutsScoringFieldTrialName[] = "OmniboxShortcutsScoring";
 
 // The autocomplete dynamic field trial name prefix.  Each field trial is
 // configured dynamically and is retrieved automatically by Chrome during
@@ -240,3 +241,20 @@
   }
   return false;
 }
+
+// If the active group name starts with "MaxRelevance_", extract the
+// int that immediately following that, returning true on success.
+bool OmniboxFieldTrial::ShortcutsScoringMaxRelevance(int* max_relevance) {
+  std::string group_name =
+      base::FieldTrialList::FindFullName(kShortcutsScoringFieldTrialName);
+  const char kMaxRelevanceGroupPrefix[] = "MaxRelevance_";
+  if (!StartsWithASCII(group_name, kMaxRelevanceGroupPrefix, true))
+    return false;
+  if (!base::StringToInt(base::StringPiece(
+          group_name.substr(strlen(kMaxRelevanceGroupPrefix))),
+                         max_relevance)) {
+    LOG(WARNING) << "Malformed MaxRelevance string: " << group_name;
+    return false;
+  }
+  return true;
+}
diff --git a/chrome/browser/omnibox/omnibox_field_trial.h b/chrome/browser/omnibox/omnibox_field_trial.h
index e6f0345..ab5babc 100644
--- a/chrome/browser/omnibox/omnibox_field_trial.h
+++ b/chrome/browser/omnibox/omnibox_field_trial.h
@@ -97,6 +97,22 @@
   // user clicks on the omnibox but has not typed anything yet.
   static bool InZeroSuggestFieldTrial();
 
+  // ---------------------------------------------------------
+  // For the ShortcutsScoring field trial.
+
+  // If the field trial is active and the user is in an experiment
+  // group, extract from the experiment group name the maximum
+  // relevance score ShortcutsProvider:: CalculateScore() can return.
+  // Returns true on a successful extraction.  If the extraction failed,
+  // if the field trial is not active, etc., returns false.
+  // CalculateScore()'s return value is a product of this maximum
+  // relevance score and some attenuating factors that are all between
+  // 0 and 1.  (Note that Shortcuts results may have their scores
+  // reduced later if the assigned score is higher than allowed for
+  // non-inlineable results.  Shortcuts results are not allowed to be
+  // inlined.)
+  static bool ShortcutsScoringMaxRelevance(int* max_relevance);
+
  private:
   DISALLOW_IMPLICIT_CONSTRUCTORS(OmniboxFieldTrial);
 };
diff --git a/chrome/browser/omnibox/omnibox_log.h b/chrome/browser/omnibox/omnibox_log.h
index 461ff85..a31c9c7 100644
--- a/chrome/browser/omnibox/omnibox_log.h
+++ b/chrome/browser/omnibox/omnibox_log.h
@@ -8,7 +8,7 @@
 #include <stddef.h>
 
 #include "base/strings/string16.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/autocomplete/autocomplete_input.h"
 #include "chrome/browser/autocomplete/autocomplete_provider.h"
 #include "chrome/browser/sessions/session_id.h"
diff --git a/chrome/browser/page_cycler/page_cycler.cc b/chrome/browser/page_cycler/page_cycler.cc
index 4912fe7..0d10e08 100644
--- a/chrome/browser/page_cycler/page_cycler.cc
+++ b/chrome/browser/page_cycler/page_cycler.cc
@@ -222,7 +222,7 @@
                            error_.size());
     } else if (file_util::PathExists(errors_file_)) {
       // If there is an old error file, delete it to avoid confusion.
-      file_util::Delete(errors_file_, false);
+      base::Delete(errors_file_, false);
     }
   }
   if (aborted_) {
diff --git a/chrome/browser/page_cycler/page_cycler_browsertest.cc b/chrome/browser/page_cycler/page_cycler_browsertest.cc
index c31f1e9..c4d8650 100644
--- a/chrome/browser/page_cycler/page_cycler_browsertest.cc
+++ b/chrome/browser/page_cycler/page_cycler_browsertest.cc
@@ -25,7 +25,7 @@
 #include "content/public/browser/notification_service.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/common/url_constants.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 // TODO(kbr): remove: http://crbug.com/222296
 #if defined(OS_MACOSX)
diff --git a/chrome/browser/password_manager/OWNERS b/chrome/browser/password_manager/OWNERS
index c1f1541..0249ef7 100644
--- a/chrome/browser/password_manager/OWNERS
+++ b/chrome/browser/password_manager/OWNERS
@@ -1,4 +1,5 @@
 albertb@chromium.org
+gcasto@chromium.org
 isherman@chromium.org
 mdm@chromium.org
 stuartmorgan@chromium.org
diff --git a/chrome/browser/password_manager/login_database.cc b/chrome/browser/password_manager/login_database.cc
index 4327728..be50c61 100644
--- a/chrome/browser/password_manager/login_database.cc
+++ b/chrome/browser/password_manager/login_database.cc
@@ -7,14 +7,16 @@
 #include <algorithm>
 #include <limits>
 
-#include "base/file_util.h"
+#include "base/command_line.h"
 #include "base/files/file_path.h"
 #include "base/logging.h"
 #include "base/metrics/histogram.h"
 #include "base/pickle.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
+#include "base/strings/string_util.h"
+#include "base/time/time.h"
+#include "chrome/common/chrome_switches.h"
+#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
+#include "sql/connection.h"
 #include "sql/statement.h"
 #include "sql/transaction.h"
 
@@ -45,9 +47,45 @@
   COLUMN_TIMES_USED
 };
 
+std::string GetRegistryControlledDomain(const GURL& signon_realm) {
+  return net::registry_controlled_domains::GetDomainAndRegistry(
+      signon_realm,
+      net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES);
+}
+
+std::string GetRegistryControlledDomain(const std::string& signon_realm_str) {
+  GURL signon_realm(signon_realm_str);
+  return net::registry_controlled_domains::GetDomainAndRegistry(
+      signon_realm,
+      net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES);
+}
+
+bool RegistryControlledDomainMatches(const scoped_ptr<PasswordForm>& found,
+                                     const PasswordForm current) {
+  const std::string found_registry_controlled_domain =
+      GetRegistryControlledDomain(found->signon_realm);
+  const std::string form_registry_controlled_domain =
+      GetRegistryControlledDomain(current.signon_realm);
+  return found_registry_controlled_domain == form_registry_controlled_domain;
+}
+
+bool SchemeMatches(const scoped_ptr<PasswordForm>& found,
+                   const PasswordForm current) {
+  const std::string found_scheme = GURL(found->signon_realm).scheme();
+  const std::string form_scheme = GURL(current.signon_realm).scheme();
+  return found_scheme == form_scheme;
+}
+
+bool PortMatches(const scoped_ptr<PasswordForm>& found,
+                   const PasswordForm current) {
+  const std::string found_port = GURL(found->signon_realm).port();
+  const std::string form_port = GURL(current.signon_realm).port();
+  return found_port == form_port;
+}
+
 }  // namespace
 
-LoginDatabase::LoginDatabase() {
+LoginDatabase::LoginDatabase() : public_suffix_domain_matching_(false) {
 }
 
 LoginDatabase::~LoginDatabase() {
@@ -100,6 +138,10 @@
     db_.Close();
     return false;
   }
+
+  public_suffix_domain_matching_ = CommandLine::ForCurrentProcess()->HasSwitch(
+      switches::kEnablePasswordAutofillPublicSuffixDomainMatching);
+
   return true;
 }
 
@@ -357,19 +399,73 @@
                               std::vector<PasswordForm*>* forms) const {
   DCHECK(forms);
   // You *must* change LoginTableColumns if this query changes.
-  sql::Statement s(db_.GetCachedStatement(SQL_FROM_HERE,
-      "SELECT origin_url, action_url, "
+  const std::string sql_query = "SELECT origin_url, action_url, "
       "username_element, username_value, "
       "password_element, password_value, submit_element, "
       "signon_realm, ssl_valid, preferred, date_created, blacklisted_by_user, "
       "scheme, password_type, possible_usernames, times_used "
-      "FROM logins WHERE signon_realm == ? "));
-  s.BindString(0, form.signon_realm);
+      "FROM logins WHERE signon_realm == ? ";
+  sql::Statement s;
+  if (public_suffix_domain_matching_) {
+    // We are extending the original SQL query with one that includes more
+    // possible matches based on public suffix domain matching. Using a regexp
+    // here is just an optimization to not have to parse all the stored entries
+    // in the |logins| table. The result (scheme, domain and port) is verified
+    // further down using GURL. See the functions SchemeMatches,
+    // RegistryControlledDomainMatches and PortMatches.
+    const std::string extended_sql_query =
+        sql_query + "OR signon_realm REGEXP ? ";
+    // TODO(nyquist) Re-enable usage of GetCachedStatement when
+    // http://crbug.com/248608 is fixed.
+    s.Assign(db_.GetUniqueStatement(extended_sql_query.c_str()));
+    const GURL signon_realm(form.signon_realm);
+    std::string domain = GetRegistryControlledDomain(signon_realm);
+    // We need to escape . in the domain. Since the domain has already been
+    // sanitized using GURL, we do not need to escape any other characters.
+    ReplaceChars(domain, ".", "\\.", &domain);
+    std::string scheme = signon_realm.scheme();
+    // We need to escape . in the scheme. Since the scheme has already been
+    // sanitized using GURL, we do not need to escape any other characters.
+    // The scheme soap.beep is an example with '.'.
+    ReplaceChars(scheme, ".", "\\.", &scheme);
+    const std::string port = signon_realm.port();
+    // For a signon realm such as http://foo.bar/, this regexp will match
+    // domains on the form http://foo.bar/, http://www.foo.bar/,
+    // http://www.mobile.foo.bar/. It will not match http://notfoo.bar/.
+    // The scheme and port has to be the same as the observed form.
+    std::string regexp = "^(" + scheme + ":\\/\\/)([\\w-]+\\.)*" +
+                         domain + "(:" + port + ")?\\/$";
+    s.BindString(0, form.signon_realm);
+    s.BindString(1, regexp);
+  } else {
+    s.Assign(db_.GetCachedStatement(SQL_FROM_HERE, sql_query.c_str()));
+    s.BindString(0, form.signon_realm);
+  }
 
   while (s.Step()) {
     scoped_ptr<PasswordForm> new_form(new PasswordForm());
     if (!InitPasswordFormFromStatement(new_form.get(), s))
       return false;
+    if (public_suffix_domain_matching_) {
+      if (!SchemeMatches(new_form, form) ||
+          !RegistryControlledDomainMatches(new_form, form) ||
+          !PortMatches(new_form, form)) {
+        // The database returned results that should not match. Skipping result.
+        continue;
+      }
+      if (form.signon_realm != new_form->signon_realm) {
+        // This is not a perfect match, so we need to create a new valid result.
+        // We do this by copying over origin, signon realm and action from the
+        // observed form and setting the original signon realm to what we found
+        // in the database. We use the fact that |original_signon_realm| is
+        // non-empty to communicate that this match was found using public
+        // suffix matching.
+        new_form->original_signon_realm = new_form->signon_realm;
+        new_form->origin = form.origin;
+        new_form->signon_realm = form.signon_realm;
+        new_form->action = form.action;
+      }
+    }
     forms->push_back(new_form.release());
   }
   return s.Succeeded();
@@ -438,7 +534,7 @@
   DCHECK(db_.is_open());
   meta_table_.Reset();
   db_.Close();
-  file_util::Delete(db_path_, false);
+  sql::Connection::Delete(db_path_);
   return Init(db_path_);
 }
 
diff --git a/chrome/browser/password_manager/login_database.h b/chrome/browser/password_manager/login_database.h
index 0cfa07e..f1d0e8d 100644
--- a/chrome/browser/password_manager/login_database.h
+++ b/chrome/browser/password_manager/login_database.h
@@ -115,6 +115,9 @@
   mutable sql::Connection db_;
   sql::MetaTable meta_table_;
 
+  // Set to true if the public suffix based domain matching is enabled.
+  bool public_suffix_domain_matching_;
+
   DISALLOW_COPY_AND_ASSIGN(LoginDatabase);
 };
 
diff --git a/chrome/browser/password_manager/login_database_unittest.cc b/chrome/browser/password_manager/login_database_unittest.cc
index 7c1b52d..3338058 100644
--- a/chrome/browser/password_manager/login_database_unittest.cc
+++ b/chrome/browser/password_manager/login_database_unittest.cc
@@ -9,7 +9,7 @@
 #include "base/path_service.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/password_manager/login_database.h"
 #include "chrome/common/chrome_paths.h"
 #include "content/public/common/password_form.h"
@@ -36,6 +36,10 @@
     return db_.DeserializeVector(pickle);
   }
 
+  void SetPublicSuffixMatching(bool enabled) {
+    db_.public_suffix_domain_matching_ = enabled;
+  }
+
   LoginDatabase db_;
   base::FilePath file_;
   base::ScopedTempDir temp_dir_;
@@ -177,6 +181,275 @@
   EXPECT_EQ(0U, result.size());
 }
 
+TEST_F(LoginDatabaseTest, TestPublicSuffixDomainMatching) {
+  SetPublicSuffixMatching(true);
+  std::vector<PasswordForm*> result;
+
+  // Verify the database is empty.
+  EXPECT_TRUE(db_.GetAutofillableLogins(&result));
+  EXPECT_EQ(0U, result.size());
+
+  // Example password form.
+  PasswordForm form;
+  form.origin = GURL("https://foo.com/");
+  form.action = GURL("https://foo.com/login");
+  form.username_element = ASCIIToUTF16("username");
+  form.username_value = ASCIIToUTF16("test@gmail.com");
+  form.password_element = ASCIIToUTF16("password");
+  form.password_value = ASCIIToUTF16("test");
+  form.submit_element = ASCIIToUTF16("");
+  form.signon_realm = "https://foo.com/";
+  form.ssl_valid = true;
+  form.preferred = false;
+  form.scheme = PasswordForm::SCHEME_HTML;
+
+  // Add it and make sure it is there.
+  EXPECT_TRUE(db_.AddLogin(form));
+  EXPECT_TRUE(db_.GetAutofillableLogins(&result));
+  EXPECT_EQ(1U, result.size());
+  delete result[0];
+  result.clear();
+
+  // Match against an exact copy.
+  EXPECT_TRUE(db_.GetLogins(form, &result));
+  EXPECT_EQ(1U, result.size());
+  delete result[0];
+  result.clear();
+
+  // We go to the mobile site.
+  PasswordForm form2(form);
+  form2.origin = GURL("https://mobile.foo.com/");
+  form2.action = GURL("https://mobile.foo.com/login");
+  form2.signon_realm = "https://mobile.foo.com/";
+
+  // Match against the mobile site.
+  EXPECT_TRUE(db_.GetLogins(form2, &result));
+  EXPECT_EQ(1U, result.size());
+  EXPECT_EQ("https://mobile.foo.com/", result[0]->signon_realm);
+  EXPECT_EQ("https://foo.com/", result[0]->original_signon_realm);
+  delete result[0];
+  result.clear();
+}
+
+// This test fails if the implementation of GetLogins uses GetCachedStatement
+// instead of GetUniqueStatement, since REGEXP is in use. See
+// http://crbug.com/248608.
+TEST_F(LoginDatabaseTest, TestPublicSuffixDomainMatchingDifferentSites) {
+  SetPublicSuffixMatching(true);
+  std::vector<PasswordForm*> result;
+
+  // Verify the database is empty.
+  EXPECT_TRUE(db_.GetAutofillableLogins(&result));
+  EXPECT_EQ(0U, result.size());
+
+  // Example password form.
+  PasswordForm form;
+  form.origin = GURL("https://foo.com/");
+  form.action = GURL("https://foo.com/login");
+  form.username_element = ASCIIToUTF16("username");
+  form.username_value = ASCIIToUTF16("test@gmail.com");
+  form.password_element = ASCIIToUTF16("password");
+  form.password_value = ASCIIToUTF16("test");
+  form.submit_element = ASCIIToUTF16("");
+  form.signon_realm = "https://foo.com/";
+  form.ssl_valid = true;
+  form.preferred = false;
+  form.scheme = PasswordForm::SCHEME_HTML;
+
+  // Add it and make sure it is there.
+  EXPECT_TRUE(db_.AddLogin(form));
+  EXPECT_TRUE(db_.GetAutofillableLogins(&result));
+  EXPECT_EQ(1U, result.size());
+  delete result[0];
+  result.clear();
+
+  // Match against an exact copy.
+  EXPECT_TRUE(db_.GetLogins(form, &result));
+  EXPECT_EQ(1U, result.size());
+  delete result[0];
+  result.clear();
+
+  // We go to the mobile site.
+  PasswordForm form2(form);
+  form2.origin = GURL("https://mobile.foo.com/");
+  form2.action = GURL("https://mobile.foo.com/login");
+  form2.signon_realm = "https://mobile.foo.com/";
+
+  // Match against the mobile site.
+  EXPECT_TRUE(db_.GetLogins(form2, &result));
+  EXPECT_EQ(1U, result.size());
+  EXPECT_EQ("https://mobile.foo.com/", result[0]->signon_realm);
+  EXPECT_EQ("https://foo.com/", result[0]->original_signon_realm);
+  delete result[0];
+  result.clear();
+
+  // Add baz.com desktop site.
+  form.origin = GURL("https://baz.com/login/");
+  form.action = GURL("https://baz.com/login/");
+  form.username_element = ASCIIToUTF16("email");
+  form.username_value = ASCIIToUTF16("test@gmail.com");
+  form.password_element = ASCIIToUTF16("password");
+  form.password_value = ASCIIToUTF16("test");
+  form.submit_element = ASCIIToUTF16("");
+  form.signon_realm = "https://baz.com/";
+  form.ssl_valid = true;
+  form.preferred = false;
+  form.scheme = PasswordForm::SCHEME_HTML;
+
+  // Add it and make sure it is there.
+  EXPECT_TRUE(db_.AddLogin(form));
+  EXPECT_TRUE(db_.GetAutofillableLogins(&result));
+  EXPECT_EQ(2U, result.size());
+  delete result[0];
+  delete result[1];
+  result.clear();
+
+  // We go to the mobile site of baz.com.
+  PasswordForm form3(form);
+  form3.origin = GURL("https://m.baz.com/login/");
+  form3.action = GURL("https://m.baz.com/login/");
+  form3.signon_realm = "https://m.baz.com/";
+
+  // Match against the mobile site of baz.com.
+  EXPECT_TRUE(db_.GetLogins(form3, &result));
+  EXPECT_EQ(1U, result.size());
+  EXPECT_EQ("https://m.baz.com/", result[0]->signon_realm);
+  EXPECT_EQ("https://baz.com/", result[0]->original_signon_realm);
+  delete result[0];
+  result.clear();
+}
+
+PasswordForm GetFormWithNewSignonRealm(PasswordForm form,
+                                       std::string signon_realm) {
+  PasswordForm form2(form);
+  form2.origin = GURL(signon_realm);
+  form2.action = GURL(signon_realm);
+  form2.signon_realm = signon_realm;
+  return form2;
+}
+
+TEST_F(LoginDatabaseTest, TestPublicSuffixDomainMatchingRegexp) {
+  SetPublicSuffixMatching(true);
+  std::vector<PasswordForm*> result;
+
+  // Verify the database is empty.
+  EXPECT_TRUE(db_.GetAutofillableLogins(&result));
+  EXPECT_EQ(0U, result.size());
+
+  // Example password form.
+  PasswordForm form;
+  form.origin = GURL("http://foo.com/");
+  form.action = GURL("http://foo.com/login");
+  form.username_element = ASCIIToUTF16("username");
+  form.username_value = ASCIIToUTF16("test@gmail.com");
+  form.password_element = ASCIIToUTF16("password");
+  form.password_value = ASCIIToUTF16("test");
+  form.submit_element = ASCIIToUTF16("");
+  form.signon_realm = "http://foo.com/";
+  form.ssl_valid = false;
+  form.preferred = false;
+  form.scheme = PasswordForm::SCHEME_HTML;
+
+  // Add it and make sure it is there.
+  EXPECT_TRUE(db_.AddLogin(form));
+  EXPECT_TRUE(db_.GetAutofillableLogins(&result));
+  EXPECT_EQ(1U, result.size());
+  delete result[0];
+  result.clear();
+
+  // Example password form that has - in the domain name.
+  PasswordForm form_dash =
+      GetFormWithNewSignonRealm(form, "http://www.foo-bar.com/");
+
+  // Add it and make sure it is there.
+  EXPECT_TRUE(db_.AddLogin(form_dash));
+  EXPECT_TRUE(db_.GetAutofillableLogins(&result));
+  EXPECT_EQ(2U, result.size());
+  delete result[0];
+  delete result[1];
+  result.clear();
+
+  // Match against an exact copy.
+  EXPECT_TRUE(db_.GetLogins(form, &result));
+  EXPECT_EQ(1U, result.size());
+  delete result[0];
+  result.clear();
+
+  // www.foo.com should match.
+  PasswordForm form2 = GetFormWithNewSignonRealm(form, "http://www.foo.com/");
+  EXPECT_TRUE(db_.GetLogins(form2, &result));
+  EXPECT_EQ(1U, result.size());
+  delete result[0];
+  result.clear();
+
+  // a.b.foo.com should match.
+  form2 = GetFormWithNewSignonRealm(form, "http://a.b.foo.com/");
+  EXPECT_TRUE(db_.GetLogins(form2, &result));
+  EXPECT_EQ(1U, result.size());
+  delete result[0];
+  result.clear();
+
+  // a-b.foo.com should match.
+  form2 = GetFormWithNewSignonRealm(form, "http://a-b.foo.com/");
+  EXPECT_TRUE(db_.GetLogins(form2, &result));
+  EXPECT_EQ(1U, result.size());
+  delete result[0];
+  result.clear();
+
+  // foo-bar.com should match.
+  form2 = GetFormWithNewSignonRealm(form, "http://foo-bar.com/");
+  EXPECT_TRUE(db_.GetLogins(form2, &result));
+  EXPECT_EQ(1U, result.size());
+  delete result[0];
+  result.clear();
+
+  // www.foo-bar.com should match.
+  form2 = GetFormWithNewSignonRealm(form, "http://www.foo-bar.com/");
+  EXPECT_TRUE(db_.GetLogins(form2, &result));
+  EXPECT_EQ(1U, result.size());
+  delete result[0];
+  result.clear();
+
+  // a.b.foo-bar.com should match.
+  form2 = GetFormWithNewSignonRealm(form, "http://a.b.foo-bar.com/");
+  EXPECT_TRUE(db_.GetLogins(form2, &result));
+  EXPECT_EQ(1U, result.size());
+  delete result[0];
+  result.clear();
+
+  // a-b.foo-bar.com should match.
+  form2 = GetFormWithNewSignonRealm(form, "http://a-b.foo-bar.com/");
+  EXPECT_TRUE(db_.GetLogins(form2, &result));
+  EXPECT_EQ(1U, result.size());
+  delete result[0];
+  result.clear();
+
+  // foo.com with port 1337 should not match.
+  form2 = GetFormWithNewSignonRealm(form, "http://foo.com:1337/");
+  EXPECT_TRUE(db_.GetLogins(form2, &result));
+  EXPECT_EQ(0U, result.size());
+
+  // http://foo.com should not match since the scheme is wrong.
+  form2 = GetFormWithNewSignonRealm(form, "https://foo.com/");
+  EXPECT_TRUE(db_.GetLogins(form2, &result));
+  EXPECT_EQ(0U, result.size());
+
+  // notfoo.com should not match.
+  form2 = GetFormWithNewSignonRealm(form, "http://notfoo.com/");
+  EXPECT_TRUE(db_.GetLogins(form2, &result));
+  EXPECT_EQ(0U, result.size());
+
+  // baz.com should not match.
+  form2 = GetFormWithNewSignonRealm(form, "http://baz.com/");
+  EXPECT_TRUE(db_.GetLogins(form2, &result));
+  EXPECT_EQ(0U, result.size());
+
+  // foo-baz.com should not match.
+  form2 = GetFormWithNewSignonRealm(form, "http://foo-baz.com/");
+  EXPECT_TRUE(db_.GetLogins(form2, &result));
+  EXPECT_EQ(0U, result.size());
+}
+
 static bool AddTimestampedLogin(LoginDatabase* db, std::string url,
                                 const std::string& unique_string,
                                 const base::Time& time) {
diff --git a/chrome/browser/password_manager/native_backend_gnome_x.cc b/chrome/browser/password_manager/native_backend_gnome_x.cc
index 735e381..68c54d4 100644
--- a/chrome/browser/password_manager/native_backend_gnome_x.cc
+++ b/chrome/browser/password_manager/native_backend_gnome_x.cc
@@ -18,7 +18,7 @@
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/synchronization/waitable_event.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "content/public/browser/browser_thread.h"
 
 using content::BrowserThread;
diff --git a/chrome/browser/password_manager/native_backend_gnome_x.h b/chrome/browser/password_manager/native_backend_gnome_x.h
index f421831..567d733 100644
--- a/chrome/browser/password_manager/native_backend_gnome_x.h
+++ b/chrome/browser/password_manager/native_backend_gnome_x.h
@@ -10,7 +10,7 @@
 #include <string>
 
 #include "base/basictypes.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/password_manager/password_store_factory.h"
 #include "chrome/browser/password_manager/password_store_x.h"
 #include "chrome/browser/profiles/profile.h"
diff --git a/chrome/browser/password_manager/native_backend_gnome_x_unittest.cc b/chrome/browser/password_manager/native_backend_gnome_x_unittest.cc
index a35b7e4..fac8b9f 100644
--- a/chrome/browser/password_manager/native_backend_gnome_x_unittest.cc
+++ b/chrome/browser/password_manager/native_backend_gnome_x_unittest.cc
@@ -10,7 +10,7 @@
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/password_manager/native_backend_gnome_x.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/testing_profile.h"
diff --git a/chrome/browser/password_manager/native_backend_kwallet_x.h b/chrome/browser/password_manager/native_backend_kwallet_x.h
index e19bc3d..8029e61 100644
--- a/chrome/browser/password_manager/native_backend_kwallet_x.h
+++ b/chrome/browser/password_manager/native_backend_kwallet_x.h
@@ -9,7 +9,7 @@
 
 #include "base/basictypes.h"
 #include "base/memory/ref_counted.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/password_manager/password_store_factory.h"
 #include "chrome/browser/password_manager/password_store_x.h"
 #include "chrome/browser/profiles/profile.h"
diff --git a/chrome/browser/password_manager/password_form_manager.cc b/chrome/browser/password_manager/password_form_manager.cc
index 1bf3d7d..59c5a6a 100644
--- a/chrome/browser/password_manager/password_form_manager.cc
+++ b/chrome/browser/password_manager/password_form_manager.cc
@@ -13,7 +13,7 @@
 #include "chrome/browser/password_manager/password_store.h"
 #include "chrome/browser/password_manager/password_store_factory.h"
 #include "chrome/browser/profiles/profile.h"
-#include "components/autofill/browser/validation.h"
+#include "components/autofill/core/browser/validation.h"
 #include "components/autofill/core/common/autofill_messages.h"
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/web_contents.h"
@@ -153,6 +153,10 @@
   return is_new_login_;
 }
 
+bool PasswordFormManager::IsPendingCredentialsPublicSuffixMatch() {
+  return pending_credentials_.IsPublicSuffixMatch();
+}
+
 void PasswordFormManager::SetHasGeneratedPassword() {
   has_generated_password_ = true;
 }
@@ -189,7 +193,10 @@
   if (it != best_matches_.end()) {
     // The user signed in with a login we autofilled.
     pending_credentials_ = *it->second;
-    is_new_login_ = false;
+
+    // Public suffix matches should always be new logins, since we want to store
+    // them so they can automatically be filled in later.
+    is_new_login_ = IsPendingCredentialsPublicSuffixMatch();
 
     // Check to see if we're using a known username but a new password.
     if (pending_credentials_.password_value != credentials.password_value)
@@ -337,12 +344,14 @@
   SendNotBlacklistedToRenderer();
 
   // Proceed to autofill.
-  // Note that we provide the choices but don't actually prefill a value if
-  // either: (1) we are in Incognito mode, or (2) the ACTION paths don't match.
+  // Note that we provide the choices but don't actually prefill a value if:
+  // (1) we are in Incognito mode, (2) the ACTION paths don't match,
+  // or (3) if it matched using public suffix domain matching.
   bool wait_for_username =
       profile_->IsOffTheRecord() ||
       observed_form_.action.GetWithEmptyPath() !=
-          preferred_match_->action.GetWithEmptyPath();
+          preferred_match_->action.GetWithEmptyPath() ||
+          preferred_match_->IsPublicSuffixMatch();
   if (wait_for_username)
     manager_action_ = kManagerActionNone;
   else
@@ -528,19 +537,21 @@
   // The most important element that should match is the origin, followed by
   // the action, the password name, the submit button name, and finally the
   // username input field name.
-  // Exact origin match gives an addition of 32 (1 << 5) + # of matching url
+  // Exact origin match gives an addition of 64 (1 << 6) + # of matching url
   // dirs.
-  // Partial match gives an addition of 16 (1 << 4) + # matching url dirs
+  // Partial match gives an addition of 32 (1 << 5) + # matching url dirs
   // That way, a partial match cannot trump an exact match even if
   // the partial one matches all other attributes (action, elements) (and
   // regardless of the matching depth in the URL path).
+  // If public suffix origin match was not used, it gives an addition of
+  // 16 (1 << 4).
   int score = 0;
   if (candidate.origin == observed_form_.origin) {
     // This check is here for the most common case which
     // is we have a single match in the db for the given host,
     // so we don't generally need to walk the entire URL path (the else
     // clause).
-    score += (1 << 5) + static_cast<int>(form_path_tokens_.size());
+    score += (1 << 6) + static_cast<int>(form_path_tokens_.size());
   } else {
     // Walk the origin URL paths one directory at a time to see how
     // deep the two match.
@@ -555,9 +566,11 @@
       score++;
     }
     // do we have a partial match?
-    score += (depth > 0) ? 1 << 4 : 0;
+    score += (depth > 0) ? 1 << 5 : 0;
   }
   if (observed_form_.scheme == PasswordForm::SCHEME_HTML) {
+    if (!candidate.IsPublicSuffixMatch())
+      score += 1 << 4;
     if (candidate.action == observed_form_.action)
       score += 1 << 3;
     if (candidate.password_element == observed_form_.password_element)
diff --git a/chrome/browser/password_manager/password_form_manager.h b/chrome/browser/password_manager/password_form_manager.h
index cd5cf3e..8777299 100644
--- a/chrome/browser/password_manager/password_form_manager.h
+++ b/chrome/browser/password_manager/password_form_manager.h
@@ -79,6 +79,11 @@
   // managed by this.
   bool IsNewLogin();
 
+  // Returns true if the current pending credentials were found using
+  // origin matching of the public suffix, instead of the signon realm of the
+  // form.
+  bool IsPendingCredentialsPublicSuffixMatch();
+
   // Checks if the form is a valid password form. Forms which lack either
   // login or password field are not considered valid.
   bool HasValidPasswordForm();
diff --git a/chrome/browser/password_manager/password_generation_manager.cc b/chrome/browser/password_manager/password_generation_manager.cc
index 4742d21..4c8051b 100644
--- a/chrome/browser/password_manager/password_generation_manager.cc
+++ b/chrome/browser/password_manager/password_generation_manager.cc
@@ -13,7 +13,7 @@
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/common/pref_names.h"
-#include "components/autofill/browser/password_generator.h"
+#include "components/autofill/core/browser/password_generator.h"
 #include "components/autofill/core/common/autofill_messages.h"
 #include "components/user_prefs/pref_registry_syncable.h"
 #include "content/public/browser/browser_thread.h"
diff --git a/chrome/browser/password_manager/password_manager.cc b/chrome/browser/password_manager/password_manager.cc
index a262a18..2affc0b 100644
--- a/chrome/browser/password_manager/password_manager.cc
+++ b/chrome/browser/password_manager/password_manager.cc
@@ -268,6 +268,12 @@
   }
 }
 
+bool PasswordManager::ShouldShowSavePasswordInfoBar() const {
+  return provisional_save_manager_->IsNewLogin() &&
+      !provisional_save_manager_->HasGeneratedPassword() &&
+      !provisional_save_manager_->IsPendingCredentialsPublicSuffixMatch();
+}
+
 void PasswordManager::OnPasswordFormsRendered(
     const std::vector<PasswordForm>& visible_forms) {
   if (!provisional_save_manager_.get())
@@ -302,8 +308,7 @@
   provisional_save_manager_->SubmitPassed();
   if (provisional_save_manager_->HasGeneratedPassword())
     UMA_HISTOGRAM_COUNTS("PasswordGeneration.Submitted", 1);
-  if (provisional_save_manager_->IsNewLogin() &&
-      !provisional_save_manager_->HasGeneratedPassword()) {
+  if (ShouldShowSavePasswordInfoBar()) {
     delegate_->AddSavePasswordInfoBarIfPermitted(
         provisional_save_manager_.release());
   } else {
diff --git a/chrome/browser/password_manager/password_manager.h b/chrome/browser/password_manager/password_manager.h
index eda8654..f2a84e4 100644
--- a/chrome/browser/password_manager/password_manager.h
+++ b/chrome/browser/password_manager/password_manager.h
@@ -102,6 +102,10 @@
   // the username for the form is ambigious.
   bool OtherPossibleUsernamesEnabled() const;
 
+  // Returns true if we should show an infobar instead of automatically saving
+  // the password, based on inspecting the state of |provisional_save_manager_|.
+  bool ShouldShowSavePasswordInfoBar() const;
+
   // Note about how a PasswordFormManager can transition from
   // pending_login_managers_ to provisional_save_manager_ and the infobar.
   //
diff --git a/chrome/browser/password_manager/password_manager_delegate_impl.cc b/chrome/browser/password_manager/password_manager_delegate_impl.cc
index 822f983..1df2755 100644
--- a/chrome/browser/password_manager/password_manager_delegate_impl.cc
+++ b/chrome/browser/password_manager/password_manager_delegate_impl.cc
@@ -13,8 +13,8 @@
 #include "chrome/browser/password_manager/password_manager.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/sync/one_click_signin_helper.h"
-#include "components/autofill/browser/autofill_manager.h"
 #include "components/autofill/content/browser/autofill_driver_impl.h"
+#include "components/autofill/core/browser/autofill_manager.h"
 #include "components/autofill/core/common/autofill_messages.h"
 #include "content/public/browser/navigation_entry.h"
 #include "content/public/browser/render_view_host.h"
@@ -167,16 +167,10 @@
 
 void PasswordManagerDelegateImpl::FillPasswordForm(
     const autofill::PasswordFormFillData& form_data) {
-  autofill::AutofillDriverImpl* autofill_driver =
-      autofill::AutofillDriverImpl::FromWebContents(web_contents_);
-  // Browser process will own popup UI, so renderer should not show the popup.
-  bool disable_popup = autofill_driver->autofill_manager()->IsNativeUiEnabled();
-
   web_contents_->GetRenderViewHost()->Send(
       new AutofillMsg_FillPasswordForm(
           web_contents_->GetRenderViewHost()->GetRoutingID(),
-          form_data,
-          disable_popup));
+          form_data));
 }
 
 void PasswordManagerDelegateImpl::AddSavePasswordInfoBarIfPermitted(
diff --git a/chrome/browser/password_manager/password_store.h b/chrome/browser/password_manager/password_store.h
index 04fdffc..4d6079f 100644
--- a/chrome/browser/password_manager/password_store.h
+++ b/chrome/browser/password_manager/password_store.h
@@ -11,7 +11,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/observer_list.h"
 #include "base/threading/thread.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/common/cancelable_request.h"
 #include "chrome/common/cancelable_task_tracker.h"
 #include "components/browser_context_keyed_service/refcounted_browser_context_keyed_service.h"
diff --git a/chrome/browser/password_manager/password_store_default_unittest.cc b/chrome/browser/password_manager/password_store_default_unittest.cc
index 99c6ad4..a949061 100644
--- a/chrome/browser/password_manager/password_store_default_unittest.cc
+++ b/chrome/browser/password_manager/password_store_default_unittest.cc
@@ -10,7 +10,7 @@
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/synchronization/waitable_event.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/password_manager/password_form_data.h"
 #include "chrome/browser/password_manager/password_store_change.h"
 #include "chrome/browser/password_manager/password_store_consumer.h"
diff --git a/chrome/browser/password_manager/password_store_unittest.cc b/chrome/browser/password_manager/password_store_unittest.cc
index a4b695a..458d222 100644
--- a/chrome/browser/password_manager/password_store_unittest.cc
+++ b/chrome/browser/password_manager/password_store_unittest.cc
@@ -7,7 +7,7 @@
 #include "base/stl_util.h"
 #include "base/strings/string_util.h"
 #include "base/synchronization/waitable_event.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/password_manager/password_form_data.h"
 #include "chrome/browser/password_manager/password_store_consumer.h"
 #include "chrome/browser/password_manager/password_store_default.h"
diff --git a/chrome/browser/password_manager/password_store_win_unittest.cc b/chrome/browser/password_manager/password_store_win_unittest.cc
index 488cb09..dfbe3c5 100644
--- a/chrome/browser/password_manager/password_store_win_unittest.cc
+++ b/chrome/browser/password_manager/password_store_win_unittest.cc
@@ -15,7 +15,7 @@
 #include "base/prefs/pref_service.h"
 #include "base/stl_util.h"
 #include "base/synchronization/waitable_event.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/password_manager/password_form_data.h"
 #include "chrome/browser/password_manager/password_store_consumer.h"
 #include "chrome/browser/password_manager/password_store_win.h"
diff --git a/chrome/browser/password_manager/password_store_x.h b/chrome/browser/password_manager/password_store_x.h
index 80c8527..05e0351 100644
--- a/chrome/browser/password_manager/password_store_x.h
+++ b/chrome/browser/password_manager/password_store_x.h
@@ -8,7 +8,7 @@
 #include <vector>
 
 #include "base/memory/scoped_ptr.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/password_manager/password_store_default.h"
 
 class LoginDatabase;
diff --git a/chrome/browser/password_manager/password_store_x_unittest.cc b/chrome/browser/password_manager/password_store_x_unittest.cc
index 22b7467..8b5cb44 100644
--- a/chrome/browser/password_manager/password_store_x_unittest.cc
+++ b/chrome/browser/password_manager/password_store_x_unittest.cc
@@ -14,7 +14,7 @@
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/synchronization/waitable_event.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/password_manager/password_form_data.h"
 #include "chrome/browser/password_manager/password_store_change.h"
 #include "chrome/browser/password_manager/password_store_consumer.h"
diff --git a/chrome/browser/pepper_broker_infobar_delegate.h b/chrome/browser/pepper_broker_infobar_delegate.h
index 9b5bdb3..fa5a936 100644
--- a/chrome/browser/pepper_broker_infobar_delegate.h
+++ b/chrome/browser/pepper_broker_infobar_delegate.h
@@ -8,7 +8,7 @@
 #include "base/callback.h"
 #include "base/files/file_path.h"
 #include "chrome/browser/infobars/confirm_infobar_delegate.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 class HostContentSettingsMap;
 class InfoBarService;
diff --git a/chrome/browser/pepper_flash_settings_manager.cc b/chrome/browser/pepper_flash_settings_manager.cc
index fbf0c84..c6454bd 100644
--- a/chrome/browser/pepper_flash_settings_manager.cc
+++ b/chrome/browser/pepper_flash_settings_manager.cc
@@ -24,10 +24,10 @@
 #include "content/public/browser/pepper_flash_settings_helper.h"
 #include "content/public/browser/plugin_service.h"
 #include "content/public/common/content_constants.h"
-#include "googleurl/src/gurl.h"
 #include "ipc/ipc_channel.h"
 #include "ipc/ipc_listener.h"
 #include "ppapi/proxy/ppapi_messages.h"
+#include "url/gurl.h"
 #include "webkit/plugins/plugin_constants.h"
 #include "webkit/plugins/webplugininfo.h"
 
@@ -461,7 +461,7 @@
   // Wipe that file.
   const base::FilePath& device_id_path =
       chrome::DeviceIDFetcher::GetLegacyDeviceIDPath(profile_path);
-  bool success = file_util::Delete(device_id_path, false);
+  bool success = base::Delete(device_id_path, false);
 
   BrowserThread::PostTask(
       BrowserThread::IO, FROM_HERE,
diff --git a/chrome/browser/performance_monitor/constants.h b/chrome/browser/performance_monitor/constants.h
index 5face47..168baf2 100644
--- a/chrome/browser/performance_monitor/constants.h
+++ b/chrome/browser/performance_monitor/constants.h
@@ -6,7 +6,7 @@
 #define CHROME_BROWSER_PERFORMANCE_MONITOR_CONSTANTS_H_
 
 #include "base/basictypes.h"
-#include "base/time.h"
+#include "base/time/time.h"
 
 namespace performance_monitor {
 
@@ -34,7 +34,7 @@
 const int64 kBytesPerGigabyte = kBytesPerMegabyte * (1 << 10);
 const int64 kBytesPerTerabyte = kBytesPerGigabyte * (1 << 10);
 
-// Time measurements - Most of these are imported from base/time.h
+// Time measurements - Most of these are imported from base/time/time.h
 // These units are used for display (and it's related calculations), not for
 // any mathematical analysis. Thus we can estimate for values without an exact
 // conversion.
diff --git a/chrome/browser/performance_monitor/database.cc b/chrome/browser/performance_monitor/database.cc
index a109f3b..36bc93c 100644
--- a/chrome/browser/performance_monitor/database.cc
+++ b/chrome/browser/performance_monitor/database.cc
@@ -13,7 +13,7 @@
 #include "base/stl_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/performance_monitor/key_builder.h"
 #include "chrome/common/chrome_paths.h"
 #include "content/public/browser/browser_thread.h"
diff --git a/chrome/browser/performance_monitor/database.h b/chrome/browser/performance_monitor/database.h
index 0ac1fb8..87082cd 100644
--- a/chrome/browser/performance_monitor/database.h
+++ b/chrome/browser/performance_monitor/database.h
@@ -13,7 +13,7 @@
 #include "base/gtest_prod_util.h"
 #include "base/memory/linked_ptr.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/performance_monitor/constants.h"
 #include "chrome/browser/performance_monitor/event.h"
 #include "chrome/browser/performance_monitor/metric.h"
diff --git a/chrome/browser/performance_monitor/database_unittest.cc b/chrome/browser/performance_monitor/database_unittest.cc
index f92505a..bde1fe3 100644
--- a/chrome/browser/performance_monitor/database_unittest.cc
+++ b/chrome/browser/performance_monitor/database_unittest.cc
@@ -9,7 +9,7 @@
 #include "base/files/file_path.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/performance_monitor/database.h"
 #include "chrome/browser/performance_monitor/key_builder.h"
 #include "chrome/browser/performance_monitor/metric.h"
diff --git a/chrome/browser/performance_monitor/event.h b/chrome/browser/performance_monitor/event.h
index 1dbbe3b..b7666b4 100644
--- a/chrome/browser/performance_monitor/event.h
+++ b/chrome/browser/performance_monitor/event.h
@@ -5,9 +5,9 @@
 #ifndef CHROME_BROWSER_PERFORMANCE_MONITOR_EVENT_H_
 #define CHROME_BROWSER_PERFORMANCE_MONITOR_EVENT_H_
 
-#include "base/values.h"
-#include "base/time.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/time/time.h"
+#include "base/values.h"
 
 namespace performance_monitor {
 
diff --git a/chrome/browser/performance_monitor/events.json b/chrome/browser/performance_monitor/events.json
index ab5ffc6..3b04c35 100644
--- a/chrome/browser/performance_monitor/events.json
+++ b/chrome/browser/performance_monitor/events.json
@@ -5,6 +5,7 @@
 [
   {
     "namespace": "events",
+    "description": "Performance monitor events",
     "types": [
       {
         "id": "ExtensionEvent",
diff --git a/chrome/browser/performance_monitor/metric.cc b/chrome/browser/performance_monitor/metric.cc
index de50cb3..2699c41 100644
--- a/chrome/browser/performance_monitor/metric.cc
+++ b/chrome/browser/performance_monitor/metric.cc
@@ -7,7 +7,7 @@
 #include "base/basictypes.h"
 #include "base/logging.h"
 #include "base/strings/string_number_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/performance_monitor/constants.h"
 
 namespace performance_monitor {
diff --git a/chrome/browser/performance_monitor/metric.h b/chrome/browser/performance_monitor/metric.h
index a7772ec..ab9da9f 100644
--- a/chrome/browser/performance_monitor/metric.h
+++ b/chrome/browser/performance_monitor/metric.h
@@ -6,7 +6,7 @@
 #define CHROME_BROWSER_PERFORMANCE_MONITOR_METRIC_H_
 
 #include <string>
-#include "base/time.h"
+#include "base/time/time.h"
 
 namespace performance_monitor {
 
diff --git a/chrome/browser/performance_monitor/performance_monitor.cc b/chrome/browser/performance_monitor/performance_monitor.cc
index 643c4c1..6d7ed4f 100644
--- a/chrome/browser/performance_monitor/performance_monitor.cc
+++ b/chrome/browser/performance_monitor/performance_monitor.cc
@@ -14,7 +14,7 @@
 #include "base/stl_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/threading/worker_pool.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/browser_shutdown.h"
 #include "chrome/browser/extensions/crx_installer.h"
@@ -618,23 +618,19 @@
       details.status == base::TERMINATION_STATUS_PROCESS_WAS_KILLED ?
       EVENT_RENDERER_KILLED : EVENT_RENDERER_CRASH;
 
-  content::RenderProcessHost::RenderWidgetHostsIterator iter =
-      host->GetRenderWidgetHostsIterator();
-
   // A RenderProcessHost may contain multiple render views - for each valid
   // render view, extract the url, and append it to the string, comma-separating
   // the entries.
   std::string url_list;
-  for (; !iter.IsAtEnd(); iter.Advance()) {
-    const content::RenderWidgetHost* widget = iter.GetCurrentValue();
-    DCHECK(widget);
-    if (!widget || !widget->IsRenderView())
+  content::RenderWidgetHost::List widgets =
+      content::RenderWidgetHost::GetRenderWidgetHosts();
+  for (size_t i = 0; i < widgets.size(); ++i) {
+    if (widgets[i]->GetProcess()->GetID() != host->GetID())
+      continue;
+    if (!widgets[i]->IsRenderView())
       continue;
 
-    content::RenderViewHost* view =
-        content::RenderViewHost::From(
-            const_cast<content::RenderWidgetHost*>(widget));
-
+    content::RenderViewHost* view = content::RenderViewHost::From(widgets[i]);
     std::string url;
     if (!MaybeGetURLFromRenderView(view, &url))
       continue;
diff --git a/chrome/browser/performance_monitor/performance_monitor.h b/chrome/browser/performance_monitor/performance_monitor.h
index 652b4ea..d8cd74e 100644
--- a/chrome/browser/performance_monitor/performance_monitor.h
+++ b/chrome/browser/performance_monitor/performance_monitor.h
@@ -15,7 +15,7 @@
 #include "base/memory/singleton.h"
 #include "base/process.h"
 #include "base/process_util.h"
-#include "base/timer.h"
+#include "base/timer/timer.h"
 #include "chrome/browser/performance_monitor/database.h"
 #include "chrome/browser/performance_monitor/event.h"
 #include "content/public/browser/notification_details.h"
diff --git a/chrome/browser/performance_monitor/performance_monitor_browsertest.cc b/chrome/browser/performance_monitor/performance_monitor_browsertest.cc
index 535bb34..3d2c95c 100644
--- a/chrome/browser/performance_monitor/performance_monitor_browsertest.cc
+++ b/chrome/browser/performance_monitor/performance_monitor_browsertest.cc
@@ -374,7 +374,7 @@
     content::TestNavigationObserver restore_observer(NULL, expected_tab_count);
     restore_observer.StartWatchingNewWebContents();
     ui_test_utils::BrowserAddedObserver window_observer;
-    chrome::NewEmptyWindow(profile, chrome::HOST_DESKTOP_TYPE_NATIVE);
+    chrome::NewEmptyWindow(profile, chrome::GetActiveDesktop());
     Browser* new_browser = window_observer.WaitForSingleNewBrowser();
     restore_observer.Wait();
     g_browser_process->ReleaseModule();
diff --git a/chrome/browser/performance_monitor/performance_monitor_util.cc b/chrome/browser/performance_monitor/performance_monitor_util.cc
index 2682240..7f94a01 100644
--- a/chrome/browser/performance_monitor/performance_monitor_util.cc
+++ b/chrome/browser/performance_monitor/performance_monitor_util.cc
@@ -8,7 +8,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/threading/sequenced_worker_pool.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/performance_monitor/events.h"
 #include "content/public/browser/browser_thread.h"
 
diff --git a/chrome/browser/performance_monitor/performance_monitor_util.h b/chrome/browser/performance_monitor/performance_monitor_util.h
index b1052db..7ad35bc 100644
--- a/chrome/browser/performance_monitor/performance_monitor_util.h
+++ b/chrome/browser/performance_monitor/performance_monitor_util.h
@@ -6,7 +6,7 @@
 #define CHROME_BROWSER_PERFORMANCE_MONITOR_PERFORMANCE_MONITOR_UTIL_H_
 
 #include "base/callback.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "base/tracked_objects.h"
 #include "chrome/browser/performance_monitor/database.h"
 #include "chrome/browser/performance_monitor/event.h"
diff --git a/chrome/browser/performance_monitor/startup_timer.h b/chrome/browser/performance_monitor/startup_timer.h
index 2bab4db..fc32a32 100644
--- a/chrome/browser/performance_monitor/startup_timer.h
+++ b/chrome/browser/performance_monitor/startup_timer.h
@@ -5,7 +5,7 @@
 #ifndef CHROME_BROWSER_PERFORMANCE_MONITOR_STARTUP_TIMER_H_
 #define CHROME_BROWSER_PERFORMANCE_MONITOR_STARTUP_TIMER_H_
 
-#include "base/time.h"
+#include "base/time/time.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
 
diff --git a/chrome/browser/platform_util_chromeos.cc b/chrome/browser/platform_util_chromeos.cc
index 1d68cab..ae27115 100644
--- a/chrome/browser/platform_util_chromeos.cc
+++ b/chrome/browser/platform_util_chromeos.cc
@@ -12,7 +12,7 @@
 #include "chrome/browser/ui/host_desktop.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "content/public/browser/browser_thread.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 using content::BrowserThread;
 
@@ -29,6 +29,7 @@
   chrome::NavigateParams params(
       browser, GURL(url), content::PAGE_TRANSITION_LINK);
   params.disposition = NEW_FOREGROUND_TAB;
+  params.window_action = chrome::NavigateParams::SHOW_WINDOW;
   chrome::Navigate(&params);
 }
 
@@ -61,6 +62,9 @@
     string_url.append(url.spec());
     BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
                             base::Bind(OpenURL, string_url));
+  } else if (url.is_valid()) {
+    BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+                            base::Bind(OpenURL, url.spec()));
   }
 }
 
diff --git a/chrome/browser/platform_util_linux.cc b/chrome/browser/platform_util_linux.cc
index 5bae77f..9ac22d7 100644
--- a/chrome/browser/platform_util_linux.cc
+++ b/chrome/browser/platform_util_linux.cc
@@ -9,7 +9,7 @@
 #include "base/process_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "content/public/browser/browser_thread.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 using content::BrowserThread;
 
diff --git a/chrome/browser/platform_util_mac.mm b/chrome/browser/platform_util_mac.mm
index 5a97ecf..fad64e6 100644
--- a/chrome/browser/platform_util_mac.mm
+++ b/chrome/browser/platform_util_mac.mm
@@ -13,10 +13,10 @@
 #include "base/mac/mac_logging.h"
 #include "base/mac/scoped_aedesc.h"
 #include "base/strings/sys_string_conversions.h"
-#include "googleurl/src/gurl.h"
 #include "grit/generated_resources.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/l10n/l10n_util_mac.h"
+#include "url/gurl.h"
 
 namespace platform_util {
 
diff --git a/chrome/browser/platform_util_win.cc b/chrome/browser/platform_util_win.cc
index 90c02c0..2a6a8d7 100644
--- a/chrome/browser/platform_util_win.cc
+++ b/chrome/browser/platform_util_win.cc
@@ -20,9 +20,9 @@
 #include "base/win/scoped_comptr.h"
 #include "base/win/windows_version.h"
 #include "content/public/browser/browser_thread.h"
-#include "googleurl/src/gurl.h"
 #include "ui/base/win/shell.h"
 #include "ui/gfx/native_widget_types.h"
+#include "url/gurl.h"
 
 using content::BrowserThread;
 
diff --git a/chrome/browser/plugins/chrome_plugin_service_filter.cc b/chrome/browser/plugins/chrome_plugin_service_filter.cc
index ac639b7..853018e 100644
--- a/chrome/browser/plugins/chrome_plugin_service_filter.cc
+++ b/chrome/browser/plugins/chrome_plugin_service_filter.cc
@@ -59,8 +59,7 @@
     const GURL& origin) {
   base::AutoLock auto_lock(lock_);
   restricted_plugins_[plugin_path] =
-      std::make_pair(PluginPrefs::GetForProfile(profile),
-                     origin);
+      std::make_pair(PluginPrefs::GetForProfile(profile).get(), origin);
 }
 
 void ChromePluginServiceFilter::UnrestrictPlugin(
diff --git a/chrome/browser/plugins/chrome_plugin_service_filter.h b/chrome/browser/plugins/chrome_plugin_service_filter.h
index 2ef01d4..5b61c3a 100644
--- a/chrome/browser/plugins/chrome_plugin_service_filter.h
+++ b/chrome/browser/plugins/chrome_plugin_service_filter.h
@@ -17,7 +17,7 @@
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
 #include "content/public/browser/plugin_service_filter.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 #include "webkit/plugins/webplugininfo.h"
 
 class PluginPrefs;
diff --git a/chrome/browser/plugins/plugin_finder.cc b/chrome/browser/plugins/plugin_finder.cc
index f32efcb..9dbfa30 100644
--- a/chrome/browser/plugins/plugin_finder.cc
+++ b/chrome/browser/plugins/plugin_finder.cc
@@ -18,9 +18,9 @@
 #include "chrome/common/pref_names.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/plugin_service.h"
-#include "googleurl/src/gurl.h"
 #include "grit/browser_resources.h"
 #include "ui/base/resource/resource_bundle.h"
+#include "url/gurl.h"
 
 #if defined(ENABLE_PLUGIN_INSTALLATION)
 #include "chrome/browser/plugins/plugin_installer.h"
diff --git a/chrome/browser/plugins/plugin_info_message_filter.cc b/chrome/browser/plugins/plugin_info_message_filter.cc
index d04c90a..cb19888 100644
--- a/chrome/browser/plugins/plugin_info_message_filter.cc
+++ b/chrome/browser/plugins/plugin_info_message_filter.cc
@@ -22,7 +22,7 @@
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/plugin_service.h"
 #include "content/public/browser/plugin_service_filter.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 #include "webkit/plugins/npapi/plugin_list.h"
 
 #include "widevine_cdm_version.h"  // In SHARED_INTERMEDIATE_DIR.
@@ -47,13 +47,13 @@
   if (plugin.name == ASCIIToUTF16(chrome::ChromeContentClient::kNaClPluginName))
     return true;
 
-#if defined(WIDEVINE_CDM_AVAILABLE)
+#if defined(WIDEVINE_CDM_AVAILABLE) && defined(ENABLE_PEPPER_CDMS)
   // Treat CDM invocations like JavaScript.
   if (plugin.name == ASCIIToUTF16(kWidevineCdmDisplayName)) {
     DCHECK(plugin.type == WebPluginInfo::PLUGIN_TYPE_PEPPER_OUT_OF_PROCESS);
     return true;
   }
-#endif  // WIDEVINE_CDM_AVAILABLE
+#endif  // defined(WIDEVINE_CDM_AVAILABLE) && defined(ENABLE_PEPPER_CDMS)
 
   return false;
 }
diff --git a/chrome/browser/plugins/plugin_infobar_delegates.h b/chrome/browser/plugins/plugin_infobar_delegates.h
index fcb261f..5e4cb31 100644
--- a/chrome/browser/plugins/plugin_infobar_delegates.h
+++ b/chrome/browser/plugins/plugin_infobar_delegates.h
@@ -7,7 +7,7 @@
 
 #include "base/callback.h"
 #include "chrome/browser/infobars/confirm_infobar_delegate.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 #if defined(ENABLE_PLUGIN_INSTALLATION)
 #include "chrome/browser/plugins/plugin_installer_observer.h"
diff --git a/chrome/browser/plugins/plugin_installer.cc b/chrome/browser/plugins/plugin_installer.cc
index 6cc1b39..bd68407 100644
--- a/chrome/browser/plugins/plugin_installer.cc
+++ b/chrome/browser/plugins/plugin_installer.cc
@@ -23,6 +23,7 @@
 #include "content/public/browser/resource_context.h"
 #include "content/public/browser/resource_dispatcher_host.h"
 #include "content/public/browser/web_contents.h"
+#include "content/public/common/referrer.h"
 #include "net/url_request/url_request.h"
 #include "net/url_request/url_request_context.h"
 
@@ -46,6 +47,7 @@
       resource_context->GetRequestContext()->CreateRequest(url, NULL));
   net::Error error = rdh->BeginDownload(
       request.Pass(),
+      content::Referrer(),
       false,  // is_content_initiated
       resource_context,
       render_process_host_id,
diff --git a/chrome/browser/plugins/plugin_installer.h b/chrome/browser/plugins/plugin_installer.h
index 196007e..36a4261 100644
--- a/chrome/browser/plugins/plugin_installer.h
+++ b/chrome/browser/plugins/plugin_installer.h
@@ -10,8 +10,8 @@
 #include "base/version.h"
 #include "chrome/browser/plugins/plugin_metadata.h"
 #include "content/public/browser/download_item.h"
-#include "googleurl/src/gurl.h"
 #include "net/base/net_errors.h"
+#include "url/gurl.h"
 
 class PluginInstallerObserver;
 class WeakPluginInstallerObserver;
diff --git a/chrome/browser/plugins/plugin_metadata.h b/chrome/browser/plugins/plugin_metadata.h
index b457e6a..69019a7 100644
--- a/chrome/browser/plugins/plugin_metadata.h
+++ b/chrome/browser/plugins/plugin_metadata.h
@@ -10,7 +10,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/strings/string16.h"
 #include "base/version.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 namespace webkit {
 struct WebPluginInfo;
diff --git a/chrome/browser/plugins/plugins_resource_service.cc b/chrome/browser/plugins/plugins_resource_service.cc
index 348ad13..e8ce1ab 100644
--- a/chrome/browser/plugins/plugins_resource_service.cc
+++ b/chrome/browser/plugins/plugins_resource_service.cc
@@ -10,7 +10,7 @@
 #include "chrome/browser/plugins/plugin_finder.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 namespace {
 
diff --git a/chrome/browser/policy/async_policy_loader.h b/chrome/browser/policy/async_policy_loader.h
index bd787bf..ce7b05b 100644
--- a/chrome/browser/policy/async_policy_loader.h
+++ b/chrome/browser/policy/async_policy_loader.h
@@ -11,7 +11,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/policy/policy_service.h"
 
 namespace policy {
diff --git a/chrome/browser/policy/browser_policy_connector.cc b/chrome/browser/policy/browser_policy_connector.cc
index 2e16c0e..18ad7af 100644
--- a/chrome/browser/policy/browser_policy_connector.cc
+++ b/chrome/browser/policy/browser_policy_connector.cc
@@ -207,6 +207,22 @@
           base::MessageLoop::current()->message_loop_proxy()));
   policy_statistics_collector_->Initialize();
 
+#if defined(OS_CHROMEOS)
+  if (command_line->HasSwitch(
+          chromeos::switches::kUseNewNetworkConfigurationHandlers)) {
+    network_configuration_updater_.reset(
+        new NetworkConfigurationUpdaterImpl(
+            GetPolicyService(),
+            make_scoped_ptr(new chromeos::CertificateHandler)));
+  } else {
+    network_configuration_updater_.reset(
+        new NetworkConfigurationUpdaterImplCros(
+            GetPolicyService(),
+            chromeos::CrosLibrary::Get()->GetNetworkLibrary(),
+            make_scoped_ptr(new chromeos::CertificateHandler)));
+  }
+#endif
+
   is_initialized_ = true;
 }
 
@@ -332,30 +348,9 @@
   return app_pack_updater_.get();
 }
 
-NetworkConfigurationUpdater*
-    BrowserPolicyConnector::GetNetworkConfigurationUpdater() {
-  if (!network_configuration_updater_) {
-    CommandLine* command_line = CommandLine::ForCurrentProcess();
-    if (command_line->HasSwitch(
-            chromeos::switches::kUseNewNetworkConfigurationHandlers)) {
-      network_configuration_updater_.reset(
-          new NetworkConfigurationUpdaterImpl(
-              GetPolicyService(),
-              make_scoped_ptr(new chromeos::CertificateHandler)));
-    } else {
-      network_configuration_updater_.reset(
-          new NetworkConfigurationUpdaterImplCros(
-              GetPolicyService(),
-              chromeos::CrosLibrary::Get()->GetNetworkLibrary(),
-              make_scoped_ptr(new chromeos::CertificateHandler)));
-    }
-  }
-  return network_configuration_updater_.get();
-}
-
 net::CertTrustAnchorProvider*
-    BrowserPolicyConnector::GetCertTrustAnchorProvider() {
-  return GetNetworkConfigurationUpdater()->GetCertTrustAnchorProvider();
+BrowserPolicyConnector::GetCertTrustAnchorProvider() {
+  return network_configuration_updater()->GetCertTrustAnchorProvider();
 }
 
 void BrowserPolicyConnector::SetUserPolicyDelegate(
diff --git a/chrome/browser/policy/browser_policy_connector.h b/chrome/browser/policy/browser_policy_connector.h
index 0f6a2c1..1c067b4 100644
--- a/chrome/browser/policy/browser_policy_connector.h
+++ b/chrome/browser/policy/browser_policy_connector.h
@@ -111,7 +111,9 @@
 #if defined(OS_CHROMEOS)
   AppPackUpdater* GetAppPackUpdater();
 
-  NetworkConfigurationUpdater* GetNetworkConfigurationUpdater();
+  NetworkConfigurationUpdater* network_configuration_updater() {
+    return network_configuration_updater_.get();
+  }
 
   net::CertTrustAnchorProvider* GetCertTrustAnchorProvider();
 
diff --git a/chrome/browser/policy/cloud/cloud_policy_browsertest.cc b/chrome/browser/policy/cloud/cloud_policy_browsertest.cc
index 9f6e7f4..0327d98 100644
--- a/chrome/browser/policy/cloud/cloud_policy_browsertest.cc
+++ b/chrome/browser/policy/cloud/cloud_policy_browsertest.cc
@@ -31,12 +31,12 @@
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/notification_source.h"
 #include "content/public/test/test_utils.h"
-#include "googleurl/src/gurl.h"
 #include "policy/policy_constants.h"
 #include "policy/proto/chrome_settings.pb.h"
 #include "policy/proto/cloud_policy.pb.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
 
 #if defined(OS_CHROMEOS)
 #include "chrome/browser/chromeos/login/user_manager.h"
diff --git a/chrome/browser/policy/cloud/cloud_policy_client.h b/chrome/browser/policy/cloud/cloud_policy_client.h
index 010fe69..f30fcc1 100644
--- a/chrome/browser/policy/cloud/cloud_policy_client.h
+++ b/chrome/browser/policy/cloud/cloud_policy_client.h
@@ -13,7 +13,7 @@
 #include "base/callback.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/observer_list.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/policy/cloud/cloud_policy_constants.h"
 #include "chrome/browser/policy/proto/cloud/device_management_backend.pb.h"
 
diff --git a/chrome/browser/policy/cloud/cloud_policy_client_registration_helper.cc b/chrome/browser/policy/cloud/cloud_policy_client_registration_helper.cc
new file mode 100644
index 0000000..7f0b36e
--- /dev/null
+++ b/chrome/browser/policy/cloud/cloud_policy_client_registration_helper.cc
@@ -0,0 +1,167 @@
+// 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/policy/cloud/cloud_policy_client_registration_helper.h"
+
+#include <vector>
+
+#include "base/logging.h"
+#include "base/time/time.h"
+#include "base/values.h"
+#include "google_apis/gaia/gaia_constants.h"
+#include "google_apis/gaia/gaia_urls.h"
+#include "google_apis/gaia/google_service_auth_error.h"
+#include "google_apis/gaia/oauth2_access_token_fetcher.h"
+
+namespace policy {
+
+namespace {
+
+// OAuth2 scope for the userinfo service.
+const char kServiceScopeGetUserInfo[] =
+    "https://www.googleapis.com/auth/userinfo.email";
+
+// The key under which the hosted-domain value is stored in the UserInfo
+// response.
+const char kGetHostedDomainKey[] = "hd";
+
+}  // namespace
+
+CloudPolicyClientRegistrationHelper::CloudPolicyClientRegistrationHelper(
+    net::URLRequestContextGetter* context,
+    CloudPolicyClient* client,
+    bool should_force_load_policy,
+    enterprise_management::DeviceRegisterRequest::Type registration_type)
+    : context_(context),
+      client_(client),
+      should_force_load_policy_(should_force_load_policy),
+      registration_type_(registration_type) {
+  DCHECK(context_);
+  DCHECK(client_);
+}
+
+CloudPolicyClientRegistrationHelper::~CloudPolicyClientRegistrationHelper() {
+  // Clean up any pending observers in case the browser is shutdown while
+  // trying to register for policy.
+  if (client_)
+    client_->RemoveObserver(this);
+}
+
+void CloudPolicyClientRegistrationHelper::StartRegistrationWithLoginToken(
+    const std::string& login_refresh_token,
+    const base::Closure& callback) {
+  DVLOG(1) << "Starting registration process with login token";
+  DCHECK(!client_->is_registered());
+  callback_ = callback;
+  client_->AddObserver(this);
+
+  // Start fetching an OAuth2 access token for the device management and
+  // userinfo services.
+  oauth2_access_token_fetcher_.reset(
+      new OAuth2AccessTokenFetcher(this, context_));
+  std::vector<std::string> scopes;
+  scopes.push_back(GaiaConstants::kDeviceManagementServiceOAuth);
+  scopes.push_back(kServiceScopeGetUserInfo);
+  GaiaUrls* gaia_urls = GaiaUrls::GetInstance();
+  oauth2_access_token_fetcher_->Start(
+      gaia_urls->oauth2_chrome_client_id(),
+      gaia_urls->oauth2_chrome_client_secret(),
+      login_refresh_token,
+      scopes);
+}
+
+void CloudPolicyClientRegistrationHelper::StartRegistrationWithServicesToken(
+    const std::string& services_token,
+    const base::Closure& callback) {
+  DVLOG(1) << "Starting registration process with services token";
+  DCHECK(!client_->is_registered());
+  callback_ = callback;
+  client_->AddObserver(this);
+  OnGetTokenSuccess(services_token, base::Time());
+}
+
+void CloudPolicyClientRegistrationHelper::OnGetTokenFailure(
+    const GoogleServiceAuthError& error) {
+  DLOG(WARNING) << "Could not fetch access token for "
+                << GaiaConstants::kDeviceManagementServiceOAuth;
+  oauth2_access_token_fetcher_.reset();
+
+  // Invoke the callback to let them know the fetch failed.
+  RequestCompleted();
+}
+
+void CloudPolicyClientRegistrationHelper::OnGetTokenSuccess(
+    const std::string& access_token,
+    const base::Time& expiration_time) {
+  // Cache the access token to be used after the GetUserInfo call.
+  oauth_access_token_ = access_token;
+  DVLOG(1) << "Fetched new scoped OAuth token:" << oauth_access_token_;
+  oauth2_access_token_fetcher_.reset();
+  // Now we've gotten our access token - contact GAIA to see if this is a
+  // hosted domain.
+  user_info_fetcher_.reset(new UserInfoFetcher(this, context_));
+  user_info_fetcher_->Start(oauth_access_token_);
+}
+
+void CloudPolicyClientRegistrationHelper::OnGetUserInfoFailure(
+    const GoogleServiceAuthError& error) {
+  DVLOG(1) << "Failed to fetch user info from GAIA: " << error.state();
+  user_info_fetcher_.reset();
+  RequestCompleted();
+}
+
+void CloudPolicyClientRegistrationHelper::OnGetUserInfoSuccess(
+    const base::DictionaryValue* data) {
+  user_info_fetcher_.reset();
+  if (!data->HasKey(kGetHostedDomainKey) && !should_force_load_policy_) {
+    DVLOG(1) << "User not from a hosted domain - skipping registration";
+    RequestCompleted();
+    return;
+  }
+  DVLOG(1) << "Registering CloudPolicyClient for user from hosted domain";
+  // The user is from a hosted domain, so it's OK to register the
+  // CloudPolicyClient and make requests to DMServer.
+  if (client_->is_registered()) {
+    // Client should not be registered yet.
+    NOTREACHED();
+    RequestCompleted();
+    return;
+  }
+
+  // Kick off registration of the CloudPolicyClient with our newly minted
+  // oauth_access_token_.
+  client_->Register(registration_type_, oauth_access_token_,
+                    std::string(), false, std::string());
+}
+
+void CloudPolicyClientRegistrationHelper::OnPolicyFetched(
+    CloudPolicyClient* client) {
+  // Ignored.
+}
+
+void CloudPolicyClientRegistrationHelper::OnRegistrationStateChanged(
+    CloudPolicyClient* client) {
+  DVLOG(1) << "Client registration succeeded";
+  DCHECK_EQ(client, client_);
+  DCHECK(client->is_registered());
+  RequestCompleted();
+}
+
+void CloudPolicyClientRegistrationHelper::OnClientError(
+    CloudPolicyClient* client) {
+  DVLOG(1) << "Client registration failed";
+  DCHECK_EQ(client, client_);
+  RequestCompleted();
+}
+
+void CloudPolicyClientRegistrationHelper::RequestCompleted() {
+  if (client_) {
+    client_->RemoveObserver(this);
+    // |client_| may be freed by the callback so clear it now.
+    client_ = NULL;
+    callback_.Run();
+  }
+}
+
+}  // namespace policy
diff --git a/chrome/browser/policy/cloud/cloud_policy_client_registration_helper.h b/chrome/browser/policy/cloud/cloud_policy_client_registration_helper.h
new file mode 100644
index 0000000..4dc3568
--- /dev/null
+++ b/chrome/browser/policy/cloud/cloud_policy_client_registration_helper.h
@@ -0,0 +1,98 @@
+// 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_POLICY_CLOUD_CLOUD_POLICY_CLIENT_REGISTRATION_HELPER_H_
+#define CHROME_BROWSER_POLICY_CLOUD_CLOUD_POLICY_CLIENT_REGISTRATION_HELPER_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/callback.h"
+#include "base/compiler_specific.h"
+#include "chrome/browser/policy/cloud/cloud_policy_client.h"
+#include "chrome/browser/policy/cloud/user_info_fetcher.h"
+#include "chrome/browser/policy/proto/cloud/device_management_backend.pb.h"
+#include "google_apis/gaia/oauth2_access_token_consumer.h"
+
+class OAuth2AccessTokenFetcher;
+
+namespace net {
+class URLRequestContextGetter;
+}
+
+namespace policy {
+
+// Helper class that registers a CloudPolicyClient. It fetches an OAuth2 token
+// for the DM service if needed, and checks with Gaia if the account has policy
+// management enabled.
+class CloudPolicyClientRegistrationHelper : public OAuth2AccessTokenConsumer,
+                                            public UserInfoFetcher::Delegate,
+                                            public CloudPolicyClient::Observer {
+ public:
+  // |context| and |client| are not owned and must outlive this object.
+  // If |should_force_load_policy| then the cloud policy registration is
+  // performed even if Gaia indicates that this account doesn't have management
+  // enabled.
+  CloudPolicyClientRegistrationHelper(
+      net::URLRequestContextGetter* context,
+      CloudPolicyClient* client,
+      bool should_force_load_policy,
+      enterprise_management::DeviceRegisterRequest::Type registration_type);
+  virtual ~CloudPolicyClientRegistrationHelper();
+
+  // Starts the client registration process. The |login_refresh_token| is used
+  // to mint a new token for the userinfo and DM services.
+  // |callback| is invoked when the registration is complete.
+  void StartRegistrationWithLoginToken(const std::string& login_refresh_token,
+                                       const base::Closure& callback);
+
+  // Starts the client registration process. The |services_token| is an OAuth2
+  // token scoped for the userinfo and DM services.
+  // |callback| is invoked when the registration is complete.
+  void StartRegistrationWithServicesToken(const std::string& services_token,
+                                          const base::Closure& callback);
+
+ private:
+  // OAuth2AccessTokenConsumer implementation:
+  virtual void OnGetTokenSuccess(const std::string& access_token,
+                                 const base::Time& expiration_time) OVERRIDE;
+  virtual void OnGetTokenFailure(const GoogleServiceAuthError& error) OVERRIDE;
+
+  // UserInfoFetcher::Delegate implementation:
+  virtual void OnGetUserInfoSuccess(
+      const base::DictionaryValue* response) OVERRIDE;
+  virtual void OnGetUserInfoFailure(
+      const GoogleServiceAuthError& error) OVERRIDE;
+
+  // CloudPolicyClient::Observer implementation:
+  virtual void OnPolicyFetched(CloudPolicyClient* client) OVERRIDE;
+  virtual void OnRegistrationStateChanged(CloudPolicyClient* client) OVERRIDE;
+  virtual void OnClientError(CloudPolicyClient* client) OVERRIDE;
+
+  // Invoked when the registration request has been completed.
+  void RequestCompleted();
+
+  // Fetcher used while obtaining an OAuth token for client registration.
+  scoped_ptr<OAuth2AccessTokenFetcher> oauth2_access_token_fetcher_;
+
+  // Helper class for fetching information from GAIA about the currently
+  // signed-in user.
+  scoped_ptr<UserInfoFetcher> user_info_fetcher_;
+
+  // Access token used to register the CloudPolicyClient and also access
+  // GAIA to get information about the signed in user.
+  std::string oauth_access_token_;
+
+  net::URLRequestContextGetter* context_;
+  CloudPolicyClient* client_;
+  bool should_force_load_policy_;
+  enterprise_management::DeviceRegisterRequest::Type registration_type_;
+  base::Closure callback_;
+
+  DISALLOW_COPY_AND_ASSIGN(CloudPolicyClientRegistrationHelper);
+};
+
+}  // namespace policy
+
+#endif  // CHROME_BROWSER_POLICY_CLOUD_CLOUD_POLICY_CLIENT_REGISTRATION_HELPER_H_
diff --git a/chrome/browser/policy/cloud/cloud_policy_constants.cc b/chrome/browser/policy/cloud/cloud_policy_constants.cc
index 865c3c6..905ddab 100644
--- a/chrome/browser/policy/cloud/cloud_policy_constants.cc
+++ b/chrome/browser/policy/cloud/cloud_policy_constants.cc
@@ -32,6 +32,8 @@
 const char kValueUserAffiliationNone[] = "none";
 
 const char kChromeDevicePolicyType[] = "google/chromeos/device";
+// TODO(joaodasilva): add a new constant for Android here.
+// http://crbug.com/248527
 #if defined(OS_CHROMEOS)
 const char kChromeUserPolicyType[] = "google/chromeos/user";
 #else
diff --git a/chrome/browser/policy/cloud/cloud_policy_refresh_scheduler.h b/chrome/browser/policy/cloud/cloud_policy_refresh_scheduler.h
index 3c8da4d..c58580a 100644
--- a/chrome/browser/policy/cloud/cloud_policy_refresh_scheduler.h
+++ b/chrome/browser/policy/cloud/cloud_policy_refresh_scheduler.h
@@ -8,7 +8,7 @@
 #include "base/basictypes.h"
 #include "base/cancelable_callback.h"
 #include "base/memory/ref_counted.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/policy/cloud/cloud_policy_client.h"
 #include "chrome/browser/policy/cloud/cloud_policy_store.h"
 #include "chrome/browser/policy/cloud/rate_limiter.h"
diff --git a/chrome/browser/policy/cloud/cloud_policy_validator.h b/chrome/browser/policy/cloud/cloud_policy_validator.h
index 1a41840..d53a0c6 100644
--- a/chrome/browser/policy/cloud/cloud_policy_validator.h
+++ b/chrome/browser/policy/cloud/cloud_policy_validator.h
@@ -13,7 +13,7 @@
 #include "base/callback.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/policy/proto/cloud/chrome_extension_policy.pb.h"
 #include "policy/proto/cloud_policy.pb.h"
 
diff --git a/chrome/browser/policy/cloud/component_cloud_policy_service_unittest.cc b/chrome/browser/policy/cloud/component_cloud_policy_service_unittest.cc
index d4e54d6..1a229c5 100644
--- a/chrome/browser/policy/cloud/component_cloud_policy_service_unittest.cc
+++ b/chrome/browser/policy/cloud/component_cloud_policy_service_unittest.cc
@@ -106,7 +106,6 @@
   virtual void SetUp() OVERRIDE {
     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
     cache_ = new ResourceCache(temp_dir_.path());
-    ASSERT_TRUE(cache_->IsOpen());
     service_.reset(new ComponentCloudPolicyService(
         &delegate_, &store_, make_scoped_ptr(cache_)));
 
diff --git a/chrome/browser/policy/cloud/component_cloud_policy_store.cc b/chrome/browser/policy/cloud/component_cloud_policy_store.cc
index 57b7b2d..afd627a 100644
--- a/chrome/browser/policy/cloud/component_cloud_policy_store.cc
+++ b/chrome/browser/policy/cloud/component_cloud_policy_store.cc
@@ -15,7 +15,7 @@
 #include "chrome/browser/policy/policy_map.h"
 #include "chrome/browser/policy/proto/cloud/chrome_extension_policy.pb.h"
 #include "chrome/browser/policy/proto/cloud/device_management_backend.pb.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 namespace em = enterprise_management;
 
diff --git a/chrome/browser/policy/cloud/component_cloud_policy_updater_unittest.cc b/chrome/browser/policy/cloud/component_cloud_policy_updater_unittest.cc
index 6cdecb9..11a73b5 100644
--- a/chrome/browser/policy/cloud/component_cloud_policy_updater_unittest.cc
+++ b/chrome/browser/policy/cloud/component_cloud_policy_updater_unittest.cc
@@ -21,12 +21,12 @@
 #include "chrome/browser/policy/policy_types.h"
 #include "chrome/browser/policy/proto/cloud/chrome_extension_policy.pb.h"
 #include "chrome/browser/policy/proto/cloud/device_management_backend.pb.h"
-#include "googleurl/src/gurl.h"
 #include "net/url_request/test_url_fetcher_factory.h"
 #include "net/url_request/url_fetcher_delegate.h"
 #include "net/url_request/url_request_context_getter.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
 
 namespace em = enterprise_management;
 
diff --git a/chrome/browser/policy/cloud/device_management_service.cc b/chrome/browser/policy/cloud/device_management_service.cc
index 2a781b6..2892488 100644
--- a/chrome/browser/policy/cloud/device_management_service.cc
+++ b/chrome/browser/policy/cloud/device_management_service.cc
@@ -18,7 +18,6 @@
 #include "chrome/common/chrome_version_info.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/common/content_client.h"
-#include "googleurl/src/gurl.h"
 #include "net/base/escape.h"
 #include "net/base/load_flags.h"
 #include "net/base/net_errors.h"
@@ -32,6 +31,7 @@
 #include "net/url_request/url_request_context.h"
 #include "net/url_request/url_request_context_getter.h"
 #include "net/url_request/url_request_status.h"
+#include "url/gurl.h"
 
 #if defined(OS_CHROMEOS)
 #include "chrome/browser/chromeos/system/statistics_provider.h"
diff --git a/chrome/browser/policy/cloud/external_policy_data_updater.cc b/chrome/browser/policy/cloud/external_policy_data_updater.cc
index c5675a8..fcac402 100644
--- a/chrome/browser/policy/cloud/external_policy_data_updater.cc
+++ b/chrome/browser/policy/cloud/external_policy_data_updater.cc
@@ -13,7 +13,6 @@
 #include "base/sequenced_task_runner.h"
 #include "base/sha1.h"
 #include "base/stl_util.h"
-#include "googleurl/src/gurl.h"
 #include "net/base/backoff_entry.h"
 #include "net/base/load_flags.h"
 #include "net/base/net_errors.h"
@@ -21,6 +20,7 @@
 #include "net/url_request/url_fetcher_delegate.h"
 #include "net/url_request/url_request_context_getter.h"
 #include "net/url_request/url_request_status.h"
+#include "url/gurl.h"
 
 namespace policy {
 
diff --git a/chrome/browser/policy/cloud/external_policy_data_updater_unittest.cc b/chrome/browser/policy/cloud/external_policy_data_updater_unittest.cc
index a07a088..57325f8 100644
--- a/chrome/browser/policy/cloud/external_policy_data_updater_unittest.cc
+++ b/chrome/browser/policy/cloud/external_policy_data_updater_unittest.cc
@@ -12,8 +12,7 @@
 #include "base/sha1.h"
 #include "base/test/test_pending_task.h"
 #include "base/test/test_simple_task_runner.h"
-#include "base/time.h"
-#include "googleurl/src/gurl.h"
+#include "base/time/time.h"
 #include "net/base/net_errors.h"
 #include "net/url_request/test_url_fetcher_factory.h"
 #include "net/url_request/url_fetcher_delegate.h"
@@ -21,6 +20,7 @@
 #include "net/url_request/url_request_status.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
 
 using testing::Mock;
 using testing::Return;
diff --git a/chrome/browser/policy/cloud/policy_builder.cc b/chrome/browser/policy/cloud/policy_builder.cc
index 67d94d1..94ff451 100644
--- a/chrome/browser/policy/cloud/policy_builder.cc
+++ b/chrome/browser/policy/cloud/policy_builder.cc
@@ -95,6 +95,7 @@
 const int64 PolicyBuilder::kFakeTimestamp = 365LL * 24 * 60 * 60 * 1000;
 const char PolicyBuilder::kFakeToken[] = "token";
 const char PolicyBuilder::kFakeUsername[] = "username@example.com";
+const char PolicyBuilder::kFakeServiceAccountIdentity[] = "robot4test@g.com";
 
 PolicyBuilder::PolicyBuilder()
     : policy_data_(new em::PolicyData()),
@@ -107,6 +108,7 @@
   policy_data_->set_username(kFakeUsername);
   policy_data_->set_device_id(kFakeDeviceId);
   policy_data_->set_state(em::PolicyData::ACTIVE);
+  policy_data_->set_service_account_identity(kFakeServiceAccountIdentity);
 }
 
 PolicyBuilder::~PolicyBuilder() {}
diff --git a/chrome/browser/policy/cloud/policy_builder.h b/chrome/browser/policy/cloud/policy_builder.h
index 628483a..2daac43 100644
--- a/chrome/browser/policy/cloud/policy_builder.h
+++ b/chrome/browser/policy/cloud/policy_builder.h
@@ -35,6 +35,7 @@
   static const int64 kFakeTimestamp;
   static const char kFakeToken[];
   static const char kFakeUsername[];
+  static const char kFakeServiceAccountIdentity[];
 
   // Creates a policy builder. The builder will have all PolicyData fields
   // initialized to dummy values and use the test signing keys.
diff --git a/chrome/browser/policy/cloud/rate_limiter.h b/chrome/browser/policy/cloud/rate_limiter.h
index f532a29..00af48d 100644
--- a/chrome/browser/policy/cloud/rate_limiter.h
+++ b/chrome/browser/policy/cloud/rate_limiter.h
@@ -13,7 +13,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/threading/non_thread_safe.h"
-#include "base/time.h"
+#include "base/time/time.h"
 
 namespace base {
 class SequencedTaskRunner;
diff --git a/chrome/browser/policy/cloud/resource_cache.cc b/chrome/browser/policy/cloud/resource_cache.cc
index 74323ce..2214a2e 100644
--- a/chrome/browser/policy/cloud/resource_cache.cc
+++ b/chrome/browser/policy/cloud/resource_cache.cc
@@ -4,46 +4,43 @@
 
 #include "chrome/browser/policy/cloud/resource_cache.h"
 
-#include <string.h>
-
+#include "base/base64.h"
 #include "base/file_util.h"
-#include "base/files/file_path.h"
+#include "base/files/file_enumerator.h"
 #include "base/logging.h"
-#include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
-#include "base/threading/thread_restrictions.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 "third_party/leveldatabase/src/include/leveldb/slice.h"
-#include "third_party/leveldatabase/src/include/leveldb/status.h"
-#include "third_party/leveldatabase/src/include/leveldb/write_batch.h"
 
 namespace policy {
 
-ResourceCache::ResourceCache(const base::FilePath& cache_path) {
-  // Allow the cache to be created in a different thread than the thread that's
+namespace {
+
+// Verifies that |value| is not empty and encodes it into base64url format,
+// which is safe to use as a file name on all platforms.
+bool Base64Encode(const std::string& value, std::string* encoded) {
+  DCHECK(!value.empty());
+  if (value.empty() || !base::Base64Encode(value, encoded))
+    return false;
+  ReplaceChars(*encoded, "+", "-", encoded);
+  ReplaceChars(*encoded, "/", "_", encoded);
+  return true;
+}
+
+// Decodes |encoded| from base64url format and verifies that the result is not
+// emtpy.
+bool Base64Decode(const std::string& encoded, std::string* value) {
+  std::string buffer;
+  ReplaceChars(encoded, "-", "+", &buffer);
+  ReplaceChars(buffer, "_", "/", &buffer);
+  return base::Base64Decode(buffer, value) && !value->empty();
+}
+
+}  // namespace
+
+ResourceCache::ResourceCache(const base::FilePath& cache_dir)
+    : cache_dir_(cache_dir) {
+  // Allow the cache to be created in a different thread than the thread that is
   // going to use it.
   DetachFromThread();
-
-  file_util::CreateDirectory(cache_path.DirName());
-  leveldb::Options options;
-  options.create_if_missing = true;
-  leveldb::DB* db = NULL;
-  leveldb::Status status =
-      leveldb::DB::Open(options, cache_path.AsUTF8Unsafe(), &db);
-  if (!status.ok()) {
-    LOG(WARNING) << "Failed to open leveldb at " << cache_path.AsUTF8Unsafe()
-                 << ": " << status.ToString();
-    // Maybe the database is busted; drop everything and try to create it again.
-    file_util::Delete(cache_path, true);
-    status = leveldb::DB::Open(options, cache_path.AsUTF8Unsafe(), &db);
-
-    if (!status.ok())
-      LOG(WARNING) << "Failed to open a new leveldb after wiping: "
-                   << status.ToString();
-  }
-  db_.reset(db);
 }
 
 ResourceCache::~ResourceCache() {
@@ -54,135 +51,125 @@
                           const std::string& subkey,
                           const std::string& data) {
   DCHECK(CalledOnValidThread());
-  base::ThreadRestrictions::AssertIOAllowed();
-
-  if (!IsOpen())
-    return false;
-
-  std::string path(CreatePath(key, subkey));
-  return db_->Put(leveldb::WriteOptions(), path, data).ok();
+  base::FilePath subkey_path;
+  // Delete the file before writing to it. This ensures that the write does not
+  // follow a symlink planted at |subkey_path|, clobbering a file outside the
+  // cache directory. The mechanism is meant to foil file-system-level attacks
+  // where a symlink is planted in the cache directory before Chrome has
+  // started. An attacker controlling a process running concurrently with Chrome
+  // would be able to race against the protection by re-creating the symlink
+  // between these two calls. There is nothing in file_util that could be used
+  // to protect against such races, especially as the cache is cross-platform
+  // and therefore cannot use any POSIX-only tricks.
+  return VerifyKeyPathAndGetSubkeyPath(key, true, subkey, &subkey_path) &&
+         base::Delete(subkey_path, false) &&
+         file_util::WriteFile(subkey_path, data.data(), data.size());
 }
 
 bool ResourceCache::Load(const std::string& key,
                          const std::string& subkey,
                          std::string* data) {
   DCHECK(CalledOnValidThread());
-  base::ThreadRestrictions::AssertIOAllowed();
-  if (!IsOpen())
+  base::FilePath subkey_path;
+  // Only read from |subkey_path| if it is not a symlink.
+  if (!VerifyKeyPathAndGetSubkeyPath(key, false, subkey, &subkey_path) ||
+      file_util::IsLink(subkey_path)) {
     return false;
-
-  leveldb::ReadOptions options;
-  options.fill_cache = false;
-  std::string path(CreatePath(key, subkey));
-  return db_->Get(options, path, data).ok();
+  }
+  data->clear();
+  return file_util::ReadFileToString(subkey_path, data);
 }
 
 void ResourceCache::LoadAllSubkeys(
     const std::string& key,
     std::map<std::string, std::string>* contents) {
   DCHECK(CalledOnValidThread());
-  base::ThreadRestrictions::AssertIOAllowed();
-  if (!IsOpen())
+  contents->clear();
+  base::FilePath key_path;
+  if (!VerifyKeyPath(key, false, &key_path))
     return;
 
-  contents->clear();
-
-  const std::string prefix(CreatePathPrefix(key));
-  leveldb::ReadOptions options;
-  options.fill_cache = false;
-  scoped_ptr<leveldb::Iterator> it(db_->NewIterator(options));
-  for (it->Seek(prefix); it->Valid(); it->Next()) {
-    if (!it->key().starts_with(prefix))
-      break;
-    const std::string subkey(GetSubkey(it->key().ToString()));
-    leveldb::Slice slice = it->value();
-    (*contents)[subkey].assign(slice.data(), slice.size());
+  base::FileEnumerator enumerator(key_path, false, base::FileEnumerator::FILES);
+  for (base::FilePath path = enumerator.Next(); !path.empty();
+       path = enumerator.Next()) {
+    const std::string encoded_subkey = path.BaseName().MaybeAsASCII();
+    std::string subkey;
+    std::string data;
+    // Only read from |subkey_path| if it is not a symlink and its name is
+    // a base64-encoded string.
+    if (!file_util::IsLink(path) &&
+        Base64Decode(encoded_subkey, &subkey) &&
+        file_util::ReadFileToString(path, &data)) {
+      (*contents)[subkey].swap(data);
+    }
   }
 }
 
 void ResourceCache::Delete(const std::string& key, const std::string& subkey) {
   DCHECK(CalledOnValidThread());
-  base::ThreadRestrictions::AssertIOAllowed();
-  if (!IsOpen())
-    return;
-
-  const std::string path(CreatePath(key, subkey));
-  leveldb::Status status = db_->Delete(leveldb::WriteOptions(), path);
-  if (!status.ok()) {
-    LOG(WARNING) << "Failed to Delete \"" << path << "\" from leveldb: "
-                 << status.ToString();
-  }
+  base::FilePath subkey_path;
+  if (VerifyKeyPathAndGetSubkeyPath(key, false, subkey, &subkey_path))
+    base::Delete(subkey_path, false);
+  // Delete() does nothing if the directory given to it is not empty. Hence, the
+  // call below deletes the directory representing |key| if its last subkey was
+  // just removed and does nothing otherwise.
+  base::Delete(subkey_path.DirName(), false);
 }
 
 void ResourceCache::PurgeOtherSubkeys(
     const std::string& key,
     const std::set<std::string>& subkeys_to_keep) {
   DCHECK(CalledOnValidThread());
-  base::ThreadRestrictions::AssertIOAllowed();
-  if (!IsOpen())
+  base::FilePath key_path;
+  if (!VerifyKeyPath(key, false, &key_path))
     return;
 
-  leveldb::WriteBatch batch;
-  const std::string prefix(CreatePathPrefix(key));
-  leveldb::ReadOptions options;
-  options.fill_cache = false;
-  scoped_ptr<leveldb::Iterator> it(db_->NewIterator(options));
-  for (it->Seek(prefix); it->Valid(); it->Next()) {
-    if (!it->key().starts_with(prefix))
-      break;
-    const std::string subkey(GetSubkey(it->key().ToString()));
-    if (subkeys_to_keep.find(subkey) == subkeys_to_keep.end())
-      batch.Delete(it->key());
+  std::set<std::string> encoded_subkeys_to_keep;
+  for (std::set<std::string>::const_iterator it = subkeys_to_keep.begin();
+       it != subkeys_to_keep.end(); ++it) {
+    std::string encoded;
+    if (!Base64Encode(*it, &encoded))
+      return;
+    encoded_subkeys_to_keep.insert(encoded);
   }
 
-  leveldb::Status status = db_->Write(leveldb::WriteOptions(), &batch);
-  if (!status.ok()) {
-    LOG(WARNING) << "Purge of leveldb subkeys of " << key << " failed: "
-                 << status.ToString();
+  base::FileEnumerator enumerator(key_path, false, base::FileEnumerator::FILES);
+  for (base::FilePath path = enumerator.Next(); !path.empty();
+       path = enumerator.Next()) {
+    const std::string name(path.BaseName().MaybeAsASCII());
+    if (encoded_subkeys_to_keep.find(name) == encoded_subkeys_to_keep.end())
+      base::Delete(path, false);
   }
+  // Delete() does nothing if the directory given to it is not empty. Hence, the
+  // call below deletes the directory representing |key| if all of its subkeys
+  // were just removed and does nothing otherwise.
+  base::Delete(key_path, false);
 }
 
-std::string ResourceCache::GetStringWithPrefix(const std::string& s) {
-  char buffer[sizeof(size_t)];
-  size_t size = s.size();
-  memcpy(buffer, &size, sizeof(size_t));
-  return std::string(buffer, sizeof(size_t)) + s;
+bool ResourceCache::VerifyKeyPath(const std::string& key,
+                                  bool allow_create,
+                                  base::FilePath* path) {
+  std::string encoded;
+  if (!Base64Encode(key, &encoded))
+    return false;
+  *path = cache_dir_.AppendASCII(encoded);
+  return allow_create ? file_util::CreateDirectory(*path) :
+                        file_util::DirectoryExists(*path);
 }
 
-std::string ResourceCache::CreatePathPrefix(const std::string& key) {
-  return GetStringWithPrefix(key);
-}
-
-std::string ResourceCache::CreatePath(const std::string& key,
-                                      const std::string& subkey) {
-  return GetStringWithPrefix(key) + GetStringWithPrefix(subkey);
-}
-
-std::string ResourceCache::GetSubkey(const std::string& path) {
-  // |path| was produced by CreatePath(). Skip the first key, then skip the
-  // size of the subkey.
-  if (path.size() < sizeof(size_t)) {
-    NOTREACHED();
-    return EmptyString();
+bool ResourceCache::VerifyKeyPathAndGetSubkeyPath(const std::string& key,
+                                                  bool allow_create_key,
+                                                  const std::string& subkey,
+                                                  base::FilePath* path) {
+  base::FilePath key_path;
+  std::string encoded;
+  if (!VerifyKeyPath(key, allow_create_key, &key_path) ||
+      !Base64Encode(subkey, &encoded)) {
+    return false;
   }
-
-  // Skip the first string. |offset| is the start of the second string,
-  // immediately preceded by its size.
-  const size_t* size = reinterpret_cast<const size_t*>(path.data());
-  size_t offset = sizeof(size_t) + *size + sizeof(size_t);
-  if (path.size() < offset) {
-    NOTREACHED();
-    return EmptyString();
-  }
-
-  // Skip the size of the second string.
-  size = reinterpret_cast<const size_t*>(path.data() + offset - sizeof(size_t));
-  if (*size != path.size() - offset) {
-    NOTREACHED();
-    return EmptyString();
-  }
-
-  return path.substr(offset, *size);
+  *path = key_path.AppendASCII(encoded);
+  return true;
 }
 
+
 }  // namespace policy
diff --git a/chrome/browser/policy/cloud/resource_cache.h b/chrome/browser/policy/cloud/resource_cache.h
index 40d3a38..8465e8c 100644
--- a/chrome/browser/policy/cloud/resource_cache.h
+++ b/chrome/browser/policy/cloud/resource_cache.h
@@ -10,17 +10,9 @@
 #include <string>
 
 #include "base/basictypes.h"
-#include "base/memory/scoped_ptr.h"
+#include "base/files/file_path.h"
 #include "base/threading/non_thread_safe.h"
 
-namespace base {
-class FilePath;
-}
-
-namespace leveldb {
-class DB;
-}
-
 namespace policy {
 
 // Manages storage of data at a given path. The data is keyed by a key and
@@ -32,11 +24,7 @@
 class ResourceCache : public base::NonThreadSafe {
  public:
   explicit ResourceCache(const base::FilePath& cache_path);
-  ~ResourceCache();
-
-  // Returns true if the underlying database was opened, and false otherwise.
-  // When this returns false then all the other operations will fail.
-  bool IsOpen() const { return db_; }
+  virtual ~ResourceCache();
 
   // Stores |data| under (key, subkey). Returns true if the store suceeded, and
   // false otherwise.
@@ -63,12 +51,23 @@
                          const std::set<std::string>& subkeys_to_keep);
 
  private:
-  std::string GetStringWithPrefix(const std::string& s);
-  std::string CreatePathPrefix(const std::string& key);
-  std::string CreatePath(const std::string& key, const std::string& subkey);
-  std::string GetSubkey(const std::string& path);
+  // Points |path| at the cache directory for |key| and returns whether the
+  // directory exists. If |allow_create| is |true|, the directory is created if
+  // it did not exist yet.
+  bool VerifyKeyPath(const std::string& key,
+                     bool allow_create,
+                     base::FilePath* path);
 
-  scoped_ptr<leveldb::DB> db_;
+  // Points |path| at the file in which data for (key, subkey) should be stored
+  // and returns whether the parent directory of this file exists. If
+  // |allow_create_key| is |true|, the directory is created if it did not exist
+  // yet. This method does not check whether the file at |path| exists or not.
+  bool VerifyKeyPathAndGetSubkeyPath(const std::string& key,
+                                     bool allow_create_key,
+                                     const std::string& subkey,
+                                     base::FilePath* subkey_path);
+
+  base::FilePath cache_dir_;
 
   DISALLOW_COPY_AND_ASSIGN(ResourceCache);
 };
diff --git a/chrome/browser/policy/cloud/resource_cache_unittest.cc b/chrome/browser/policy/cloud/resource_cache_unittest.cc
index d006c5c..fc772e6 100644
--- a/chrome/browser/policy/cloud/resource_cache_unittest.cc
+++ b/chrome/browser/policy/cloud/resource_cache_unittest.cc
@@ -28,7 +28,7 @@
 TEST(ResourceCacheTest, StoreAndLoad) {
   base::ScopedTempDir temp_dir;
   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
-  ResourceCache cache(temp_dir.path().AppendASCII("db"));
+  ResourceCache cache(temp_dir.path());
 
   // No data initially.
   std::string data;
diff --git a/chrome/browser/policy/cloud/test_request_interceptor.cc b/chrome/browser/policy/cloud/test_request_interceptor.cc
index b36b63d..9e254a4 100644
--- a/chrome/browser/policy/cloud/test_request_interceptor.cc
+++ b/chrome/browser/policy/cloud/test_request_interceptor.cc
@@ -13,7 +13,6 @@
 #include "content/public/browser/browser_thread.h"
 #include "content/public/test/test_utils.h"
 #include "content/test/net/url_request_mock_http_job.h"
-#include "googleurl/src/gurl.h"
 #include "net/base/net_errors.h"
 #include "net/base/upload_bytes_element_reader.h"
 #include "net/base/upload_data_stream.h"
@@ -22,6 +21,7 @@
 #include "net/url_request/url_request_filter.h"
 #include "net/url_request/url_request_job_factory.h"
 #include "net/url_request/url_request_test_job.h"
+#include "url/gurl.h"
 
 namespace em = enterprise_management;
 
diff --git a/chrome/browser/policy/cloud/user_cloud_policy_manager.cc b/chrome/browser/policy/cloud/user_cloud_policy_manager.cc
index 9775b28..edaf8be 100644
--- a/chrome/browser/policy/cloud/user_cloud_policy_manager.cc
+++ b/chrome/browser/policy/cloud/user_cloud_policy_manager.cc
@@ -58,13 +58,4 @@
   return client() && client()->is_registered();
 }
 
-void UserCloudPolicyManager::RegisterClient(const std::string& access_token) {
-  DCHECK(client()) << "Callers must invoke Initialize() first";
-  if (!client()->is_registered()) {
-    DVLOG(1) << "Registering client with access token: " << access_token;
-    client()->Register(em::DeviceRegisterRequest::BROWSER,
-                       access_token, std::string(), false, std::string());
-  }
-}
-
 }  // namespace policy
diff --git a/chrome/browser/policy/cloud/user_cloud_policy_manager.h b/chrome/browser/policy/cloud/user_cloud_policy_manager.h
index ddfdae3..b66be9a 100644
--- a/chrome/browser/policy/cloud/user_cloud_policy_manager.h
+++ b/chrome/browser/policy/cloud/user_cloud_policy_manager.h
@@ -46,10 +46,6 @@
   // Virtual for mocking.
   virtual bool IsClientRegistered() const;
 
-  // Register the CloudPolicyClient using the passed OAuth token. This contacts
-  // the DMServer to mint a new DMToken.
-  void RegisterClient(const std::string& access_token);
-
   // Creates a CloudPolicyClient for this client. Used in situations where
   // callers want to create a DMToken without actually initializing the
   // profile's policy infrastructure.
diff --git a/chrome/browser/policy/cloud/user_cloud_policy_store.cc b/chrome/browser/policy/cloud/user_cloud_policy_store.cc
index cef3adb..1381d98 100644
--- a/chrome/browser/policy/cloud/user_cloud_policy_store.cc
+++ b/chrome/browser/policy/cloud/user_cloud_policy_store.cc
@@ -122,7 +122,7 @@
 void UserCloudPolicyStore::Clear() {
   content::BrowserThread::PostTask(
       content::BrowserThread::FILE, FROM_HERE,
-      base::Bind(base::IgnoreResult(&file_util::Delete),
+      base::Bind(base::IgnoreResult(&base::Delete),
                  backing_file_path_,
                  false));
   policy_.reset();
diff --git a/chrome/browser/policy/cloud/user_info_fetcher.cc b/chrome/browser/policy/cloud/user_info_fetcher.cc
index 4aaed1e..996e442 100644
--- a/chrome/browser/policy/cloud/user_info_fetcher.cc
+++ b/chrome/browser/policy/cloud/user_info_fetcher.cc
@@ -10,11 +10,11 @@
 #include "base/values.h"
 #include "google_apis/gaia/gaia_urls.h"
 #include "google_apis/gaia/google_service_auth_error.h"
-#include "googleurl/src/gurl.h"
 #include "net/base/load_flags.h"
 #include "net/http/http_status_code.h"
 #include "net/url_request/url_fetcher.h"
 #include "net/url_request/url_request_status.h"
+#include "url/gurl.h"
 
 namespace {
 
diff --git a/chrome/browser/policy/cloud/user_policy_signin_service.cc b/chrome/browser/policy/cloud/user_policy_signin_service.cc
index 46b60ca..542e458 100644
--- a/chrome/browser/policy/cloud/user_policy_signin_service.cc
+++ b/chrome/browser/policy/cloud/user_policy_signin_service.cc
@@ -4,18 +4,13 @@
 
 #include "chrome/browser/policy/cloud/user_policy_signin_service.h"
 
-#include <vector>
-
-#include "base/command_line.h"
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/callback.h"
 #include "base/prefs/pref_service.h"
-#include "base/values.h"
 #include "chrome/browser/browser_process.h"
-#include "chrome/browser/policy/browser_policy_connector.h"
-#include "chrome/browser/policy/cloud/cloud_policy_client.h"
-#include "chrome/browser/policy/cloud/cloud_policy_service.h"
+#include "chrome/browser/policy/cloud/cloud_policy_client_registration_helper.h"
 #include "chrome/browser/policy/cloud/user_cloud_policy_manager.h"
-#include "chrome/browser/policy/cloud/user_cloud_policy_manager_factory.h"
-#include "chrome/browser/policy/cloud/user_info_fetcher.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/signin/signin_manager.h"
@@ -23,285 +18,77 @@
 #include "chrome/browser/signin/token_service.h"
 #include "chrome/browser/signin/token_service_factory.h"
 #include "chrome/common/chrome_notification_types.h"
-#include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
 #include "content/public/browser/notification_details.h"
-#include "content/public/browser/notification_source.h"
 #include "google_apis/gaia/gaia_constants.h"
-#include "google_apis/gaia/gaia_urls.h"
-#include "google_apis/gaia/oauth2_access_token_consumer.h"
-#include "google_apis/gaia/oauth2_access_token_fetcher.h"
 
-namespace em = enterprise_management;
-
-namespace {
-
-const char kServiceScopeGetUserInfo[] =
-    "https://www.googleapis.com/auth/userinfo.email";
-
-// The key under which the hosted-domain value is stored in the UserInfo
-// response.
-const char kGetHostedDomainKey[] = "hd";
-
-bool ShouldForceLoadPolicy() {
-  return CommandLine::ForCurrentProcess()->HasSwitch(
-      switches::kForceLoadCloudPolicy);
-}
-
-}  // namespace
+#if defined(ENABLE_MANAGED_USERS)
+#include "chrome/browser/managed_mode/managed_user_service.h"
+#endif
 
 namespace policy {
 
-// Helper class that registers a CloudPolicyClient and returns the associated
-// DMToken to the caller.
-class CloudPolicyClientRegistrationHelper
-    : public policy::CloudPolicyClient::Observer,
-      public OAuth2AccessTokenConsumer,
-      public policy::UserInfoFetcher::Delegate {
- public:
-  explicit CloudPolicyClientRegistrationHelper(
-      net::URLRequestContextGetter* context);
-
-  virtual ~CloudPolicyClientRegistrationHelper();
-
-  // Starts the client registration process. Callback is invoked when the
-  // registration is complete.
-  void StartRegistration(policy::CloudPolicyClient* client,
-                         const std::string& oauth2_login_token,
-                         base::Closure callback);
-
-  // OAuth2AccessTokenConsumer implementation.
-  virtual void OnGetTokenSuccess(const std::string& access_token,
-                                 const base::Time& expiration_time) OVERRIDE;
-  virtual void OnGetTokenFailure(const GoogleServiceAuthError& error) OVERRIDE;
-
-  // UserInfoFetcher::Delegate implementation:
-  virtual void OnGetUserInfoSuccess(const DictionaryValue* response) OVERRIDE;
-  virtual void OnGetUserInfoFailure(
-      const GoogleServiceAuthError& error) OVERRIDE;
-
-  // CloudPolicyClient::Observer implementation.
-  virtual void OnPolicyFetched(policy::CloudPolicyClient* client) OVERRIDE {}
-  virtual void OnRegistrationStateChanged(
-      policy::CloudPolicyClient* client) OVERRIDE;
-  virtual void OnClientError(policy::CloudPolicyClient* client) OVERRIDE;
-
- private:
-  // Invoked when the registration request has been completed.
-  void RequestCompleted();
-
-  // Fetcher used while obtaining an OAuth token for client registration.
-  scoped_ptr<OAuth2AccessTokenFetcher> oauth2_access_token_fetcher_;
-
-  // Helper class for fetching information from GAIA about the currently
-  // signed-in user.
-  scoped_ptr<policy::UserInfoFetcher> user_info_fetcher_;
-
-  // Access token used to register the CloudPolicyClient and also access
-  // GAIA to get information about the signed in user.
-  std::string oauth_access_token_;
-
-  net::URLRequestContextGetter* context_;
-  policy::CloudPolicyClient* client_;
-  base::Closure callback_;
-};
-
-CloudPolicyClientRegistrationHelper::CloudPolicyClientRegistrationHelper(
-    net::URLRequestContextGetter* context) : context_(context) {
-  DCHECK(context_);
-}
-
-CloudPolicyClientRegistrationHelper::~CloudPolicyClientRegistrationHelper() {
-  // Clean up any pending observers in case the browser is shutdown while
-  // trying to register for policy.
-  if (client_)
-    client_->RemoveObserver(this);
-}
-
-void CloudPolicyClientRegistrationHelper::RequestCompleted() {
-  if (client_) {
-    client_->RemoveObserver(this);
-    // |client_| may be freed by the callback so clear it now.
-    client_ = NULL;
-    callback_.Run();
-  }
-}
-
-void CloudPolicyClientRegistrationHelper::StartRegistration(
-    policy::CloudPolicyClient* client,
-    const std::string& login_token,
-    base::Closure callback) {
-  DVLOG(1) << "Starting registration process";
-  DCHECK(client);
-  DCHECK(!client->is_registered());
-  client_ = client;
-  callback_ = callback;
-  client_->AddObserver(this);
-
-  // Start fetching an OAuth2 access token for the device management and
-  // userinfo services.
-  oauth2_access_token_fetcher_.reset(
-      new OAuth2AccessTokenFetcher(this, context_));
-  std::vector<std::string> scopes;
-  scopes.push_back(GaiaConstants::kDeviceManagementServiceOAuth);
-  scopes.push_back(kServiceScopeGetUserInfo);
-  GaiaUrls* gaia_urls = GaiaUrls::GetInstance();
-  oauth2_access_token_fetcher_->Start(
-      gaia_urls->oauth2_chrome_client_id(),
-      gaia_urls->oauth2_chrome_client_secret(),
-      login_token,
-      scopes);
-}
-
-void CloudPolicyClientRegistrationHelper::OnGetTokenFailure(
-    const GoogleServiceAuthError& error) {
-  DLOG(WARNING) << "Could not fetch access token for "
-                << GaiaConstants::kDeviceManagementServiceOAuth;
-  oauth2_access_token_fetcher_.reset();
-
-  // Invoke the callback to let them know the fetch failed.
-  RequestCompleted();
-}
-
-void CloudPolicyClientRegistrationHelper::OnGetTokenSuccess(
-    const std::string& access_token,
-    const base::Time& expiration_time) {
-  // Cache the access token to be used after the GetUserInfo call.
-  oauth_access_token_ = access_token;
-  DVLOG(1) << "Fetched new scoped OAuth token:" << oauth_access_token_;
-  oauth2_access_token_fetcher_.reset();
-  // Now we've gotten our access token - contact GAIA to see if this is a
-  // hosted domain.
-  user_info_fetcher_.reset(new policy::UserInfoFetcher(this, context_));
-  user_info_fetcher_->Start(oauth_access_token_);
-}
-
-void CloudPolicyClientRegistrationHelper::OnGetUserInfoFailure(
-    const GoogleServiceAuthError& error) {
-  DVLOG(1) << "Failed to fetch user info from GAIA: " << error.state();
-  user_info_fetcher_.reset();
-  RequestCompleted();
-}
-
-void CloudPolicyClientRegistrationHelper::OnGetUserInfoSuccess(
-    const DictionaryValue* data) {
-  user_info_fetcher_.reset();
-  if (!data->HasKey(kGetHostedDomainKey) && !ShouldForceLoadPolicy()) {
-    DVLOG(1) << "User not from a hosted domain - skipping registration";
-    RequestCompleted();
-    return;
-  }
-  DVLOG(1) << "Registering CloudPolicyClient for user from hosted domain";
-  // The user is from a hosted domain, so it's OK to register the
-  // CloudPolicyClient and make requests to DMServer.
-  if (client_->is_registered()) {
-    // Client should not be registered yet.
-    NOTREACHED();
-    RequestCompleted();
-    return;
-  }
-
-  // Kick off registration of the CloudPolicyClient with our newly minted
-  // oauth_access_token_.
-  client_->Register(em::DeviceRegisterRequest::BROWSER, oauth_access_token_,
-                    std::string(), false, std::string());
-}
-
-void CloudPolicyClientRegistrationHelper::OnRegistrationStateChanged(
-    policy::CloudPolicyClient* client) {
-  DVLOG(1) << "Client registration succeeded";
-  DCHECK_EQ(client, client_);
-  DCHECK(client->is_registered());
-  RequestCompleted();
-}
-
-void CloudPolicyClientRegistrationHelper::OnClientError(
-    policy::CloudPolicyClient* client) {
-  DVLOG(1) << "Client registration failed";
-  DCHECK_EQ(client, client_);
-  RequestCompleted();
-}
-
 UserPolicySigninService::UserPolicySigninService(
-    Profile* profile)
-    : profile_(profile),
-      weak_factory_(this) {
-  if (profile_->GetPrefs()->GetBoolean(prefs::kDisableCloudPolicyOnSignin))
+    Profile* profile) : UserPolicySigninServiceBase(profile) {
+  if (profile->GetPrefs()->GetBoolean(prefs::kDisableCloudPolicyOnSignin))
     return;
 
-  // Initialize/shutdown the UserCloudPolicyManager when the user signs out.
-  registrar_.Add(this,
-                 chrome::NOTIFICATION_GOOGLE_SIGNED_OUT,
-                 content::Source<Profile>(profile));
-
   // Listen for an OAuth token to become available so we can register a client
   // if for some reason the client is not already registered (for example, if
   // the policy load failed during initial signin).
-  registrar_.Add(this,
-                 chrome::NOTIFICATION_TOKEN_AVAILABLE,
-                 content::Source<TokenService>(
-                     TokenServiceFactory::GetForProfile(profile)));
+  registrar()->Add(this,
+                   chrome::NOTIFICATION_TOKEN_AVAILABLE,
+                   content::Source<TokenService>(
+                       TokenServiceFactory::GetForProfile(profile)));
 
   // TokenService should not yet have loaded its tokens since this happens in
   // the background after PKS initialization - so this service should always be
   // created before the oauth token is available.
-  DCHECK(!TokenServiceFactory::GetForProfile(profile_)->HasOAuthLoginToken());
-
-  // Register a listener to be called back once the current profile has finished
-  // initializing, so we can startup the UserCloudPolicyManager.
-  registrar_.Add(this,
-                 chrome::NOTIFICATION_PROFILE_ADDED,
-                 content::Source<Profile>(profile));
+  DCHECK(!TokenServiceFactory::GetForProfile(profile)->HasOAuthLoginToken());
 
   // Register a listener for the import finished notification in a first run
   // scenario, which indicates the profile is ready to be further initialized.
-  registrar_.Add(this,
-                 chrome::NOTIFICATION_IMPORT_FINISHED,
-                 content::Source<Profile>(profile));
+  registrar()->Add(this,
+                   chrome::NOTIFICATION_IMPORT_FINISHED,
+                   content::Source<Profile>(profile));
 }
 
 UserPolicySigninService::~UserPolicySigninService() {}
 
+void UserPolicySigninService::Shutdown() {
+  // Stop any pending registration helper activity. We do this here instead of
+  // in the destructor because we want to shutdown the registration helper
+  // before UserCloudPolicyManager shuts down the CloudPolicyClient.
+  registration_helper_.reset();
+  UserPolicySigninServiceBase::Shutdown();
+}
+
 void UserPolicySigninService::RegisterPolicyClient(
     const std::string& username,
     const std::string& oauth2_refresh_token,
     const PolicyRegistrationCallback& callback) {
-  DCHECK(!username.empty());
   DCHECK(!oauth2_refresh_token.empty());
-  // We should not be called with a client already initialized.
-  DCHECK(!GetManager() || !GetManager()->core()->client());
 
-  // If the user should not get policy, just bail out.
-  if (!GetManager() || !ShouldLoadPolicyForUser(username)) {
-    DVLOG(1) << "Signed in user is not in the whitelist";
-    callback.Run(scoped_ptr<CloudPolicyClient>().Pass());
+  // Create a new CloudPolicyClient for fetching the DMToken.
+  scoped_ptr<CloudPolicyClient> policy_client = PrepareToRegister(username);
+  if (!policy_client) {
+    callback.Run(policy_client.Pass());
     return;
   }
 
-  // If the DeviceManagementService is not yet initialized, start it up now.
-  g_browser_process->browser_policy_connector()->
-      ScheduleServiceInitialization(0);
-
-  // Create a new CloudPolicyClient for fetching the DMToken.
-  scoped_ptr<CloudPolicyClient> policy_client(
-      UserCloudPolicyManager::CreateCloudPolicyClient(
-          g_browser_process->browser_policy_connector()->
-          device_management_service()));
-
-  registration_helper_.reset(
-      new CloudPolicyClientRegistrationHelper(profile_->GetRequestContext()));
-
   // Fire off the registration process. Callback keeps the CloudPolicyClient
   // alive for the length of the registration process.
-  // Grab a pointer to the client before base::Bind() clears the reference in
-  // |policy_client|.
-  CloudPolicyClient* client = policy_client.get();
-  base::Closure registration_callback =
+  registration_helper_.reset(new CloudPolicyClientRegistrationHelper(
+      profile()->GetRequestContext(),
+      policy_client.get(),
+      ShouldForceLoadPolicy(),
+      enterprise_management::DeviceRegisterRequest::BROWSER));
+  registration_helper_->StartRegistrationWithLoginToken(
+      oauth2_refresh_token,
       base::Bind(&UserPolicySigninService::CallPolicyRegistrationCallback,
-                 base::Unretained(this), base::Passed(&policy_client),
-                 callback);
-  registration_helper_->StartRegistration(
-      client, oauth2_refresh_token, registration_callback);
+                 base::Unretained(this),
+                 base::Passed(&policy_client),
+                 callback));
 }
 
 void UserPolicySigninService::CallPolicyRegistrationCallback(
@@ -315,42 +102,6 @@
   callback.Run(client.Pass());
 }
 
-void UserPolicySigninService::FetchPolicyForSignedInUser(
-    scoped_ptr<CloudPolicyClient> client,
-    const PolicyFetchCallback& callback) {
-  DCHECK(client);
-  DCHECK(client->is_registered());
-  // The user has just signed in, so the UserCloudPolicyManager should not yet
-  // be initialized. This routine will initialize the UserCloudPolicyManager
-  // with the passed client and will proactively ask the client to fetch
-  // policy without waiting for the CloudPolicyService to finish initialization.
-  UserCloudPolicyManager* manager = GetManager();
-  DCHECK(manager);
-  DCHECK(!manager->core()->client());
-  InitializeUserCloudPolicyManager(client.Pass());
-  DCHECK(manager->IsClientRegistered());
-
-  // Now initiate a policy fetch.
-  manager->core()->service()->RefreshPolicy(callback);
-}
-
-void UserPolicySigninService::StopObserving() {
-  UserCloudPolicyManager* manager = GetManager();
-  if (manager && manager->core()->service())
-    manager->core()->service()->RemoveObserver(this);
-  if (manager && manager->core()->client())
-    manager->core()->client()->RemoveObserver(this);
-}
-
-void UserPolicySigninService::StartObserving() {
-  UserCloudPolicyManager* manager = GetManager();
-  // Manager should be fully initialized by now.
-  DCHECK(manager);
-  DCHECK(manager->core()->service());
-  manager->core()->service()->AddObserver(this);
-  manager->core()->client()->AddObserver(this);
-}
-
 void UserPolicySigninService::Observe(
     int type,
     const content::NotificationSource& source,
@@ -364,128 +115,59 @@
     return;
   }
 
+#if defined(ENABLE_MANAGED_USERS)
+  if (ManagedUserService::ProfileIsManaged(profile())) {
+    registrar()->RemoveAll();
+    return;
+  }
+#endif
+
   // If using a TestingProfile with no SigninManager or UserCloudPolicyManager,
   // skip initialization.
-  if (!GetManager() || !SigninManagerFactory::GetForProfile(profile_)) {
+  if (!GetManager() || !SigninManagerFactory::GetForProfile(profile())) {
     DVLOG(1) << "Skipping initialization for tests due to missing components.";
     return;
   }
 
   switch (type) {
-    case chrome::NOTIFICATION_GOOGLE_SIGNED_OUT:
-      ShutdownUserCloudPolicyManager();
-      break;
     case chrome::NOTIFICATION_IMPORT_FINISHED:
-    case chrome::NOTIFICATION_PROFILE_ADDED: {
-      // A new profile has been loaded - if it's signed in, then initialize the
-      // UCPM, otherwise shut down the UCPM (which deletes any cached policy
-      // data). This must be done here instead of at constructor time because
-      // the Profile is not fully initialized when this object is constructed
-      // (DoFinalInit() has not yet been called, so ProfileIOData and
-      // SSLConfigServiceManager have not been created yet).
-      // TODO(atwilson): Switch to using a timer instead, to avoid contention
-      // with other services at startup (http://crbug.com/165468).
-      SigninManager* signin_manager =
-          SigninManagerFactory::GetForProfile(profile_);
-      std::string username = signin_manager->GetAuthenticatedUsername();
-      if (username.empty())
-        ShutdownUserCloudPolicyManager();
-      else
-        InitializeForSignedInUser();
+      InitializeOnProfileReady();
       break;
-    }
     case chrome::NOTIFICATION_TOKEN_AVAILABLE: {
       const TokenService::TokenAvailableDetails& token_details =
           *(content::Details<const TokenService::TokenAvailableDetails>(
               details).ptr());
       if (token_details.service() ==
-          GaiaConstants::kGaiaOAuth2LoginRefreshToken) {
+              GaiaConstants::kGaiaOAuth2LoginRefreshToken) {
         SigninManager* signin_manager =
-            SigninManagerFactory::GetForProfile(profile_);
+            SigninManagerFactory::GetForProfile(profile());
         std::string username = signin_manager->GetAuthenticatedUsername();
         // Should not have GAIA tokens if the user isn't signed in.
         DCHECK(!username.empty());
         // TokenService now has a refresh token (implying that the user is
         // signed in) so initialize the UserCloudPolicyManager.
-        InitializeForSignedInUser();
+        InitializeForSignedInUser(username);
       }
       break;
     }
     default:
-      NOTREACHED();
+      UserPolicySigninServiceBase::Observe(type, source, details);
   }
 }
 
-bool UserPolicySigninService::ShouldLoadPolicyForUser(
-    const std::string& username) {
-  if (profile_->GetPrefs()->GetBoolean(prefs::kDisableCloudPolicyOnSignin))
-    return false; // Cloud policy is disabled.
-
-  if (username.empty())
-    return false; // Not signed in.
-
-  if (ShouldForceLoadPolicy())
-    return true;
-
-  return !BrowserPolicyConnector::IsNonEnterpriseUser(username);
-}
-
 void UserPolicySigninService::InitializeUserCloudPolicyManager(
     scoped_ptr<CloudPolicyClient> client) {
-  UserCloudPolicyManager* manager = GetManager();
-  DCHECK(!manager->core()->client());
-  // If there is no cached DMToken then we can detect this below (or when
-  // the OnInitializationCompleted() callback is invoked).
-  manager->Connect(g_browser_process->local_state(), client.Pass());
-  DCHECK(manager->core()->service());
-  StartObserving();
+  UserPolicySigninServiceBase::InitializeUserCloudPolicyManager(client.Pass());
   ProhibitSignoutIfNeeded();
 }
 
-void UserPolicySigninService::InitializeForSignedInUser() {
-  SigninManager* signin_manager =
-      SigninManagerFactory::GetForProfile(profile_);
-  std::string username = signin_manager->GetAuthenticatedUsername();
-
-  if (!ShouldLoadPolicyForUser(username)) {
-    DVLOG(1) << "Policy load not enabled for user: " << username;
-    return;
-  }
-  DCHECK(!username.empty());
-
-  UserCloudPolicyManager* manager = GetManager();
-  // Initialize the UCPM if it is not already initialized.
-  if (!manager->core()->service()) {
-    // If there is no cached DMToken then we can detect this when the
-    // OnInitializationCompleted() callback is invoked and this will
-    // initiate a policy fetch.
-    BrowserPolicyConnector* connector =
-        g_browser_process->browser_policy_connector();
-    InitializeUserCloudPolicyManager(
-        UserCloudPolicyManager::CreateCloudPolicyClient(
-            connector->device_management_service()).Pass());
-  }
-
-  // If the CloudPolicyService is initialized, kick off registration. If the
-  // TokenService doesn't have an OAuth token yet (e.g. this is during initial
-  // signin, or when dynamically loading a signed-in policy) this does nothing
-  // until the OAuth token is loaded.
-  if (manager->core()->service()->IsInitializationComplete())
-    OnInitializationCompleted(manager->core()->service());
-}
-
 void UserPolicySigninService::ShutdownUserCloudPolicyManager() {
-  // Stop any in-progress token fetch.
-  registration_helper_.reset();
-
-  StopObserving();
-
   UserCloudPolicyManager* manager = GetManager();
-  if (manager) {  // Can be null in unit tests.
-    manager->DisconnectAndRemovePolicy();
+  if (manager) {
     // Allow the user to signout again.
-    SigninManagerFactory::GetForProfile(profile_)->ProhibitSignout(false);
+    SigninManagerFactory::GetForProfile(profile())->ProhibitSignout(false);
   }
+  UserPolicySigninServiceBase::ShutdownUserCloudPolicyManager();
 }
 
 void UserPolicySigninService::OnInitializationCompleted(
@@ -499,7 +181,7 @@
   DVLOG_IF(1, manager->IsClientRegistered())
       << "Client already registered - not fetching DMToken";
   if (!manager->IsClientRegistered()) {
-    std::string token = TokenServiceFactory::GetForProfile(profile_)->
+    std::string token = TokenServiceFactory::GetForProfile(profile())->
         GetOAuth2LoginRefreshToken();
     if (token.empty()) {
       // No token yet - this class listens for NOTIFICATION_TOKEN_AVAILABLE
@@ -513,38 +195,8 @@
   ProhibitSignoutIfNeeded();
 }
 
-void UserPolicySigninService::OnPolicyFetched(CloudPolicyClient* client) {
-}
-
-void UserPolicySigninService::OnRegistrationStateChanged(
-    CloudPolicyClient* client) {
-}
-
-void UserPolicySigninService::OnClientError(CloudPolicyClient* client) {
-  if (client->is_registered()) {
-    // If the client is already registered, it means this error must have
-    // come from a policy fetch.
-    if (client->status() ==
-        policy::DM_STATUS_SERVICE_MANAGEMENT_NOT_SUPPORTED) {
-      // OK, policy fetch failed with MANAGEMENT_NOT_SUPPORTED - this is our
-      // trigger to revert to "unmanaged" mode (we will check for management
-      // being re-enabled on the next restart and/or login).
-      DVLOG(1) << "DMServer returned NOT_SUPPORTED error - removing policy";
-
-      // Can't shutdown now because we're in the middle of a callback from
-      // the CloudPolicyClient, so queue up a task to do the shutdown.
-      base::MessageLoop::current()->PostTask(
-          FROM_HERE,
-          base::Bind(&UserPolicySigninService::ShutdownUserCloudPolicyManager,
-                     weak_factory_.GetWeakPtr()));
-    } else {
-      DVLOG(1) << "Error fetching policy: " << client->status();
-    }
-  }
-}
-
 void UserPolicySigninService::RegisterCloudPolicyService(
-    std::string login_token) {
+    const std::string& login_token) {
   DCHECK(!GetManager()->IsClientRegistered());
   DVLOG(1) << "Fetching new DM Token";
   // Do nothing if already starting the registration process.
@@ -553,10 +205,12 @@
 
   // Start the process of registering the CloudPolicyClient. Once it completes,
   // policy fetch will automatically happen.
-  registration_helper_.reset(
-      new CloudPolicyClientRegistrationHelper(profile_->GetRequestContext()));
-  registration_helper_->StartRegistration(
+  registration_helper_.reset(new CloudPolicyClientRegistrationHelper(
+      profile()->GetRequestContext(),
       GetManager()->core()->client(),
+      ShouldForceLoadPolicy(),
+      enterprise_management::DeviceRegisterRequest::BROWSER));
+  registration_helper_->StartRegistrationWithLoginToken(
       login_token,
       base::Bind(&UserPolicySigninService::OnRegistrationComplete,
                  base::Unretained(this)));
@@ -571,21 +225,9 @@
   if (GetManager()->IsClientRegistered()) {
     DVLOG(1) << "User is registered for policy - prohibiting signout";
     SigninManager* signin_manager =
-        SigninManagerFactory::GetForProfile(profile_);
+        SigninManagerFactory::GetForProfile(profile());
     signin_manager->ProhibitSignout(true);
   }
 }
 
-void UserPolicySigninService::Shutdown() {
-  // Stop any pending registration helper activity. We do this here instead of
-  // in the destructor because we want to shutdown the registration helper
-  // before UserCloudPolicyManager shuts down the CloudPolicyClient.
-  registration_helper_.reset();
-  StopObserving();
-}
-
-UserCloudPolicyManager* UserPolicySigninService::GetManager() {
-  return UserCloudPolicyManagerFactory::GetForProfile(profile_);
-}
-
 }  // namespace policy
diff --git a/chrome/browser/policy/cloud/user_policy_signin_service.h b/chrome/browser/policy/cloud/user_policy_signin_service.h
index fda278f..221c226 100644
--- a/chrome/browser/policy/cloud/user_policy_signin_service.h
+++ b/chrome/browser/policy/cloud/user_policy_signin_service.h
@@ -5,55 +5,23 @@
 #ifndef CHROME_BROWSER_POLICY_CLOUD_USER_POLICY_SIGNIN_SERVICE_H_
 #define CHROME_BROWSER_POLICY_CLOUD_USER_POLICY_SIGNIN_SERVICE_H_
 
+#include <string>
+
 #include "base/basictypes.h"
-#include "base/callback.h"
+#include "base/compiler_specific.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/memory/weak_ptr.h"
-#include "chrome/browser/policy/cloud/cloud_policy_service.h"
-#include "chrome/browser/policy/cloud/user_info_fetcher.h"
-#include "components/browser_context_keyed_service/browser_context_keyed_service.h"
-#include "content/public/browser/notification_observer.h"
-#include "content/public/browser/notification_registrar.h"
+#include "chrome/browser/policy/cloud/user_policy_signin_service_base.h"
 
 class Profile;
 
-namespace base {
-class Time;
-}
-
 namespace policy {
 
 class CloudPolicyClientRegistrationHelper;
-class CloudPolicyClient;
-class UserCloudPolicyManager;
 
-// The UserPolicySigninService is responsible for interacting with the policy
-// infrastructure (mainly UserCloudPolicyManager) to load policy for the signed
-// in user.
-//
-// At signin time, this class initializes the UCPM and loads policy before any
-// other signed in services are initialized. After each restart, this class
-// ensures that the CloudPolicyClient is registered (in case the policy server
-// was offline during the initial policy fetch) and if not it initiates a fresh
-// registration process.
-//
-// Finally, if the user signs out, this class is responsible for shutting down
-// the policy infrastructure to ensure that any cached policy is cleared.
-class UserPolicySigninService
-    : public BrowserContextKeyedService,
-      public CloudPolicyClient::Observer,
-      public CloudPolicyService::Observer,
-      public content::NotificationObserver {
+// A specialization of the UserPolicySigninServiceBase for the desktop
+// platforms (Windows, Mac and Linux).
+class UserPolicySigninService : public UserPolicySigninServiceBase {
  public:
-  // The callback invoked once policy registration is complete. Passed
-  // CloudPolicyClient parameter is null if DMToken fetch failed.
-  typedef base::Callback<void(scoped_ptr<CloudPolicyClient>)>
-      PolicyRegistrationCallback;
-
-  // The callback invoked once policy fetch is complete. Passed boolean
-  // parameter is set to true if the policy fetch succeeded.
-  typedef base::Callback<void(bool)> PolicyFetchCallback;
-
   // Creates a UserPolicySigninService associated with the passed |profile|.
   explicit UserPolicySigninService(Profile* profile);
   virtual ~UserPolicySigninService();
@@ -66,47 +34,28 @@
                             const std::string& oauth2_login_token,
                             const PolicyRegistrationCallback& callback);
 
-  // Initiates a policy fetch as part of user signin, using a CloudPolicyClient
-  // previously initialized via RegisterPolicyClient. |callback| is invoked
-  // once the policy fetch is complete, passing true if the policy fetch
-  // succeeded.
-  void FetchPolicyForSignedInUser(scoped_ptr<CloudPolicyClient> client,
-                                  const PolicyFetchCallback& callback);
-
-  // content::NotificationObserver implementation.
+  // content::NotificationObserver implementation:
   virtual void Observe(int type,
                        const content::NotificationSource& source,
                        const content::NotificationDetails& details) OVERRIDE;
 
-  // CloudPolicyService::Observer implementation.
+  // CloudPolicyService::Observer implementation:
   virtual void OnInitializationCompleted(CloudPolicyService* service) OVERRIDE;
 
-  // CloudPolicyClient::Observer implementation.
-  virtual void OnPolicyFetched(CloudPolicyClient* client) OVERRIDE;
-  virtual void OnRegistrationStateChanged(CloudPolicyClient* client) OVERRIDE;
-  virtual void OnClientError(CloudPolicyClient* client) OVERRIDE;
-
   // BrowserContextKeyedService implementation:
   virtual void Shutdown() OVERRIDE;
 
+  // UserPolicySigninServiceBase implementation:
+  virtual void InitializeUserCloudPolicyManager(
+      scoped_ptr<CloudPolicyClient> client) OVERRIDE;
+  virtual void ShutdownUserCloudPolicyManager() OVERRIDE;
+
  private:
-  // Returns false if cloud policy is disabled or if the passed |email_address|
-  // is definitely not from a hosted domain (according to the blacklist in
-  // BrowserPolicyConnector::IsNonEnterpriseUser()).
-  bool ShouldLoadPolicyForUser(const std::string& email_address);
-
-  // Initializes the UserCloudPolicyManager using the passed CloudPolicyClient.
-  void InitializeUserCloudPolicyManager(scoped_ptr<CloudPolicyClient> client);
-
-  // Initializes the UserCloudPolicyManager with policy for the currently
-  // signed-in user.
-  void InitializeForSignedInUser();
-
   // Fetches an OAuth token to allow the cloud policy service to register with
   // the cloud policy server. |oauth_login_token| should contain an OAuth login
   // refresh token that can be downscoped to get an access token for the
   // device_management service.
-  void RegisterCloudPolicyService(std::string oauth_login_token);
+  void RegisterCloudPolicyService(const std::string& oauth_login_token);
 
   // Callback invoked when policy registration has finished.
   void OnRegistrationComplete();
@@ -115,31 +64,12 @@
   // cloud policy.
   void ProhibitSignoutIfNeeded();
 
-  // Helper routines to (un)register for CloudPolicyService and
-  // CloudPolicyClient notifications.
-  void StartObserving();
-  void StopObserving();
-
-  // Shuts down the UserCloudPolicyManager (for example, after the user signs
-  // out) and deletes any cached policy.
-  void ShutdownUserCloudPolicyManager();
-
   // Invoked when a policy registration request is complete.
   void CallPolicyRegistrationCallback(scoped_ptr<CloudPolicyClient> client,
                                       PolicyRegistrationCallback callback);
 
-  // Convenience helper to get the UserCloudPolicyManager for |profile_|.
-  UserCloudPolicyManager* GetManager();
-
-  // Weak pointer to the profile this service is associated with.
-  Profile* profile_;
-
-  content::NotificationRegistrar registrar_;
-
   scoped_ptr<CloudPolicyClientRegistrationHelper> registration_helper_;
 
-  base::WeakPtrFactory<UserPolicySigninService> weak_factory_;
-
   DISALLOW_COPY_AND_ASSIGN(UserPolicySigninService);
 };
 
diff --git a/chrome/browser/policy/cloud/user_policy_signin_service_android.cc b/chrome/browser/policy/cloud/user_policy_signin_service_android.cc
new file mode 100644
index 0000000..80bed74
--- /dev/null
+++ b/chrome/browser/policy/cloud/user_policy_signin_service_android.cc
@@ -0,0 +1,88 @@
+// 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/policy/cloud/user_policy_signin_service_android.h"
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/callback.h"
+#include "base/logging.h"
+#include "chrome/browser/policy/cloud/cloud_policy_client_registration_helper.h"
+#include "chrome/browser/policy/cloud/user_cloud_policy_manager.h"
+#include "chrome/browser/policy/proto/cloud/device_management_backend.pb.h"
+#include "chrome/browser/profiles/profile.h"
+
+namespace policy {
+
+UserPolicySigninService::UserPolicySigninService(Profile* profile)
+    : UserPolicySigninServiceBase(profile) {}
+
+UserPolicySigninService::~UserPolicySigninService() {}
+
+void UserPolicySigninService::RegisterPolicyClient(
+    const std::string& username,
+    const std::string& services_token,
+    const PolicyRegistrationCallback& callback) {
+  DCHECK(!services_token.empty());
+
+  // Create a new CloudPolicyClient for fetching the DMToken.
+  scoped_ptr<CloudPolicyClient> policy_client = PrepareToRegister(username);
+  if (!policy_client) {
+    callback.Run(policy_client.Pass());
+    return;
+  }
+
+  // Fire off the registration process. Callback keeps the CloudPolicyClient
+  // alive for the length of the registration process.
+  // TODO(joaodasilva): use DeviceRegisterRequest::ANDROID_BROWSER here once
+  // the server is ready. http://crbug.com/248527
+  const bool force_load_policy = false;
+  registration_helper_.reset(new CloudPolicyClientRegistrationHelper(
+      profile()->GetRequestContext(),
+      policy_client.get(),
+      force_load_policy,
+      enterprise_management::DeviceRegisterRequest::BROWSER));
+  registration_helper_->StartRegistrationWithServicesToken(
+      services_token,
+      base::Bind(&UserPolicySigninService::CallPolicyRegistrationCallback,
+                 base::Unretained(this),
+                 base::Passed(&policy_client),
+                 callback));
+}
+
+void UserPolicySigninService::CallPolicyRegistrationCallback(
+    scoped_ptr<CloudPolicyClient> client,
+    PolicyRegistrationCallback callback) {
+  registration_helper_.reset();
+  if (!client->is_registered()) {
+    // Registration failed, so free the client and pass NULL to the callback.
+    client.reset();
+  }
+  callback.Run(client.Pass());
+}
+
+void UserPolicySigninService::Shutdown() {
+  registration_helper_.reset();
+  UserPolicySigninServiceBase::Shutdown();
+}
+
+void UserPolicySigninService::OnInitializationCompleted(
+    CloudPolicyService* service) {
+  UserCloudPolicyManager* manager = GetManager();
+  DCHECK_EQ(service, manager->core()->service());
+  DCHECK(service->IsInitializationComplete());
+  // The service is now initialized - if the client is not yet registered, then
+  // it means that there is no cached policy and so we need to initiate a new
+  // client registration.
+  if (manager->IsClientRegistered()) {
+    DVLOG(1) << "Client already registered - not fetching DMToken";
+  } else {
+    // TODO(joaodasilva): figure out what to do in this case: a signed-in user
+    // just started Chrome but hasn't registered for policy yet.
+    // If a registration attempt is started from here then make sure this
+    // doesn't happen on every startup.
+  }
+}
+
+}  // namespace policy
diff --git a/chrome/browser/policy/cloud/user_policy_signin_service_android.h b/chrome/browser/policy/cloud/user_policy_signin_service_android.h
new file mode 100644
index 0000000..0cabf6a
--- /dev/null
+++ b/chrome/browser/policy/cloud/user_policy_signin_service_android.h
@@ -0,0 +1,53 @@
+// 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_POLICY_CLOUD_USER_POLICY_SIGNIN_SERVICE_ANDROID_H_
+#define CHROME_BROWSER_POLICY_CLOUD_USER_POLICY_SIGNIN_SERVICE_ANDROID_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
+#include "chrome/browser/policy/cloud/user_policy_signin_service_base.h"
+
+class Profile;
+
+namespace policy {
+
+class CloudPolicyClientRegistrationHelper;
+
+// A specialization of the UserPolicySigninServiceBase for Android.
+class UserPolicySigninService : public UserPolicySigninServiceBase {
+ public:
+  // Creates a UserPolicySigninService associated with the passed |profile|.
+  explicit UserPolicySigninService(Profile* profile);
+  virtual ~UserPolicySigninService();
+
+  // Registers a CloudPolicyClient for fetching policy for |username|.
+  // |services_token| is an OAuth2 token for the userinfo and DM services.
+  // |callback| is invoked once the CloudPolicyClient is ready to fetch policy,
+  // or once it is determined that |username| is not a managed account.
+  void RegisterPolicyClient(const std::string& username,
+                            const std::string& services_token,
+                            const PolicyRegistrationCallback& callback);
+
+ private:
+  void CallPolicyRegistrationCallback(scoped_ptr<CloudPolicyClient> client,
+                                      PolicyRegistrationCallback callback);
+
+  // BrowserContextKeyedService implementation:
+  virtual void Shutdown() OVERRIDE;
+
+  // CloudPolicyService::Observer implementation:
+  virtual void OnInitializationCompleted(CloudPolicyService* service) OVERRIDE;
+
+  scoped_ptr<CloudPolicyClientRegistrationHelper> registration_helper_;
+
+  DISALLOW_COPY_AND_ASSIGN(UserPolicySigninService);
+};
+
+}  // namespace policy
+
+#endif  // CHROME_BROWSER_POLICY_CLOUD_USER_POLICY_SIGNIN_SERVICE_ANDROID_H_
diff --git a/chrome/browser/policy/cloud/user_policy_signin_service_base.cc b/chrome/browser/policy/cloud/user_policy_signin_service_base.cc
new file mode 100644
index 0000000..de3f7b2
--- /dev/null
+++ b/chrome/browser/policy/cloud/user_policy_signin_service_base.cc
@@ -0,0 +1,242 @@
+// 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/policy/cloud/user_policy_signin_service_base.h"
+
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/message_loop.h"
+#include "base/prefs/pref_service.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/policy/browser_policy_connector.h"
+#include "chrome/browser/policy/cloud/user_cloud_policy_manager.h"
+#include "chrome/browser/policy/cloud/user_cloud_policy_manager_factory.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/signin/signin_manager.h"
+#include "chrome/browser/signin/signin_manager_factory.h"
+#include "chrome/common/chrome_notification_types.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/pref_names.h"
+
+namespace policy {
+
+UserPolicySigninServiceBase::UserPolicySigninServiceBase(
+    Profile* profile)
+    : profile_(profile),
+      weak_factory_(this) {
+  if (profile_->GetPrefs()->GetBoolean(prefs::kDisableCloudPolicyOnSignin))
+    return;
+
+  // Initialize/shutdown the UserCloudPolicyManager when the user signs out.
+  registrar_.Add(this,
+                 chrome::NOTIFICATION_GOOGLE_SIGNED_OUT,
+                 content::Source<Profile>(profile));
+
+  // Register a listener to be called back once the current profile has finished
+  // initializing, so we can startup the UserCloudPolicyManager.
+  registrar_.Add(this,
+                 chrome::NOTIFICATION_PROFILE_ADDED,
+                 content::Source<Profile>(profile));
+}
+
+UserPolicySigninServiceBase::~UserPolicySigninServiceBase() {}
+
+void UserPolicySigninServiceBase::FetchPolicyForSignedInUser(
+    scoped_ptr<CloudPolicyClient> client,
+    const PolicyFetchCallback& callback) {
+  DCHECK(client);
+  DCHECK(client->is_registered());
+  // The user has just signed in, so the UserCloudPolicyManager should not yet
+  // be initialized. This routine will initialize the UserCloudPolicyManager
+  // with the passed client and will proactively ask the client to fetch
+  // policy without waiting for the CloudPolicyService to finish initialization.
+  UserCloudPolicyManager* manager = GetManager();
+  DCHECK(manager);
+  DCHECK(!manager->core()->client());
+  InitializeUserCloudPolicyManager(client.Pass());
+  DCHECK(manager->IsClientRegistered());
+
+  // Now initiate a policy fetch.
+  manager->core()->service()->RefreshPolicy(callback);
+}
+
+void UserPolicySigninServiceBase::Observe(
+    int type,
+    const content::NotificationSource& source,
+    const content::NotificationDetails& details) {
+  // If using a TestingProfile with no SigninManager or UserCloudPolicyManager,
+  // skip initialization.
+  if (!GetManager() || !SigninManagerFactory::GetForProfile(profile_)) {
+    DVLOG(1) << "Skipping initialization for tests due to missing components.";
+    return;
+  }
+
+  switch (type) {
+    case chrome::NOTIFICATION_GOOGLE_SIGNED_OUT:
+      ShutdownUserCloudPolicyManager();
+      break;
+    case chrome::NOTIFICATION_PROFILE_ADDED:
+      // A new profile has been loaded - if it's signed in, then initialize the
+      // UCPM, otherwise shut down the UCPM (which deletes any cached policy
+      // data). This must be done here instead of at constructor time because
+      // the Profile is not fully initialized when this object is constructed
+      // (DoFinalInit() has not yet been called, so ProfileIOData and
+      // SSLConfigServiceManager have not been created yet).
+      // TODO(atwilson): Switch to using a timer instead, to avoid contention
+      // with other services at startup (http://crbug.com/165468).
+      InitializeOnProfileReady();
+      break;
+    default:
+      NOTREACHED();
+  }
+}
+
+void UserPolicySigninServiceBase::OnInitializationCompleted(
+    CloudPolicyService* service) {
+  // This is meant to be overridden by subclasses. Starting and stopping to
+  // observe the CloudPolicyService from this base class avoids the need for
+  // more virtuals.
+}
+
+void UserPolicySigninServiceBase::OnPolicyFetched(CloudPolicyClient* client) {}
+
+void UserPolicySigninServiceBase::OnRegistrationStateChanged(
+    CloudPolicyClient* client) {}
+
+void UserPolicySigninServiceBase::OnClientError(CloudPolicyClient* client) {
+  if (client->is_registered()) {
+    // If the client is already registered, it means this error must have
+    // come from a policy fetch.
+    if (client->status() == DM_STATUS_SERVICE_MANAGEMENT_NOT_SUPPORTED) {
+      // OK, policy fetch failed with MANAGEMENT_NOT_SUPPORTED - this is our
+      // trigger to revert to "unmanaged" mode (we will check for management
+      // being re-enabled on the next restart and/or login).
+      DVLOG(1) << "DMServer returned NOT_SUPPORTED error - removing policy";
+
+      // Can't shutdown now because we're in the middle of a callback from
+      // the CloudPolicyClient, so queue up a task to do the shutdown.
+      base::MessageLoop::current()->PostTask(
+          FROM_HERE,
+          base::Bind(
+              &UserPolicySigninServiceBase::ShutdownUserCloudPolicyManager,
+              weak_factory_.GetWeakPtr()));
+    } else {
+      DVLOG(1) << "Error fetching policy: " << client->status();
+    }
+  }
+}
+
+void UserPolicySigninServiceBase::Shutdown() {
+  UserCloudPolicyManager* manager = GetManager();
+  if (manager && manager->core()->client())
+    manager->core()->client()->RemoveObserver(this);
+  if (manager && manager->core()->service())
+    manager->core()->service()->RemoveObserver(this);
+}
+
+// static
+bool UserPolicySigninServiceBase::ShouldForceLoadPolicy() {
+  return CommandLine::ForCurrentProcess()->HasSwitch(
+      switches::kForceLoadCloudPolicy);
+}
+
+scoped_ptr<CloudPolicyClient> UserPolicySigninServiceBase::PrepareToRegister(
+    const std::string& username) {
+  DCHECK(!username.empty());
+  // We should not be called with a client already initialized.
+  DCHECK(!GetManager() || !GetManager()->core()->client());
+
+  // If the user should not get policy, just bail out.
+  if (!GetManager() || !ShouldLoadPolicyForUser(username)) {
+    DVLOG(1) << "Signed in user is not in the whitelist";
+    return scoped_ptr<CloudPolicyClient>();
+  }
+
+  // If the DeviceManagementService is not yet initialized, start it up now.
+  BrowserPolicyConnector* connector =
+      g_browser_process->browser_policy_connector();
+  connector->ScheduleServiceInitialization(0);
+
+  // Create a new CloudPolicyClient for fetching the DMToken.
+  return UserCloudPolicyManager::CreateCloudPolicyClient(
+      connector->device_management_service());
+}
+
+bool UserPolicySigninServiceBase::ShouldLoadPolicyForUser(
+    const std::string& username) {
+  if (profile_->GetPrefs()->GetBoolean(prefs::kDisableCloudPolicyOnSignin))
+    return false;  // Cloud policy is disabled.
+
+  if (username.empty())
+    return false;  // Not signed in.
+
+  if (ShouldForceLoadPolicy())
+    return true;
+
+  return !BrowserPolicyConnector::IsNonEnterpriseUser(username);
+}
+
+void UserPolicySigninServiceBase::InitializeOnProfileReady() {
+  SigninManager* signin_manager =
+      SigninManagerFactory::GetForProfile(profile_);
+  std::string username = signin_manager->GetAuthenticatedUsername();
+  if (username.empty())
+    ShutdownUserCloudPolicyManager();
+  else
+    InitializeForSignedInUser(username);
+}
+
+void UserPolicySigninServiceBase::InitializeForSignedInUser(
+    const std::string& username) {
+  DCHECK(!username.empty());
+  if (!ShouldLoadPolicyForUser(username)) {
+    DVLOG(1) << "Policy load not enabled for user: " << username;
+    return;
+  }
+
+  UserCloudPolicyManager* manager = GetManager();
+  // Initialize the UCPM if it is not already initialized.
+  if (!manager->core()->service()) {
+    // If there is no cached DMToken then we can detect this when the
+    // OnInitializationCompleted() callback is invoked and this will
+    // initiate a policy fetch.
+    BrowserPolicyConnector* connector =
+        g_browser_process->browser_policy_connector();
+    InitializeUserCloudPolicyManager(
+        UserCloudPolicyManager::CreateCloudPolicyClient(
+            connector->device_management_service()).Pass());
+  }
+
+  // If the CloudPolicyService is initialized, kick off registration.
+  // Otherwise OnInitializationCompleted is invoked as soon as the service
+  // finishes its initialization.
+  if (manager->core()->service()->IsInitializationComplete())
+    OnInitializationCompleted(manager->core()->service());
+}
+
+void UserPolicySigninServiceBase::InitializeUserCloudPolicyManager(
+    scoped_ptr<CloudPolicyClient> client) {
+  UserCloudPolicyManager* manager = GetManager();
+  DCHECK(!manager->core()->client());
+  manager->Connect(g_browser_process->local_state(), client.Pass());
+  DCHECK(manager->core()->service());
+
+  // Observe the client to detect errors fetching policy.
+  manager->core()->client()->AddObserver(this);
+  // Observe the service to determine when it's initialized.
+  manager->core()->service()->AddObserver(this);
+}
+
+void UserPolicySigninServiceBase::ShutdownUserCloudPolicyManager() {
+  Shutdown();
+  UserCloudPolicyManager* manager = GetManager();
+  if (manager)
+    manager->DisconnectAndRemovePolicy();
+}
+
+UserCloudPolicyManager* UserPolicySigninServiceBase::GetManager() {
+  return UserCloudPolicyManagerFactory::GetForProfile(profile_);
+}
+
+}  // namespace policy
diff --git a/chrome/browser/policy/cloud/user_policy_signin_service_base.h b/chrome/browser/policy/cloud/user_policy_signin_service_base.h
new file mode 100644
index 0000000..2f68e62
--- /dev/null
+++ b/chrome/browser/policy/cloud/user_policy_signin_service_base.h
@@ -0,0 +1,137 @@
+// 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_POLICY_CLOUD_USER_POLICY_SIGNIN_SERVICE_BASE_H_
+#define CHROME_BROWSER_POLICY_CLOUD_USER_POLICY_SIGNIN_SERVICE_BASE_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/callback.h"
+#include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "chrome/browser/policy/cloud/cloud_policy_client.h"
+#include "chrome/browser/policy/cloud/cloud_policy_service.h"
+#include "components/browser_context_keyed_service/browser_context_keyed_service.h"
+#include "content/public/browser/notification_observer.h"
+#include "content/public/browser/notification_registrar.h"
+
+class Profile;
+
+namespace policy {
+
+class UserCloudPolicyManager;
+
+// The UserPolicySigninService is responsible for interacting with the policy
+// infrastructure (mainly UserCloudPolicyManager) to load policy for the signed
+// in user. This is the base class that contains shared behavior.
+//
+// At signin time, this class initializes the UCPM and loads policy before any
+// other signed in services are initialized. After each restart, this class
+// ensures that the CloudPolicyClient is registered (in case the policy server
+// was offline during the initial policy fetch) and if not it initiates a fresh
+// registration process.
+//
+// Finally, if the user signs out, this class is responsible for shutting down
+// the policy infrastructure to ensure that any cached policy is cleared.
+class UserPolicySigninServiceBase : public BrowserContextKeyedService,
+                                    public CloudPolicyClient::Observer,
+                                    public CloudPolicyService::Observer,
+                                    public content::NotificationObserver {
+ public:
+  // The callback invoked once policy registration is complete. Passed
+  // CloudPolicyClient parameter is null if DMToken fetch failed.
+  typedef base::Callback<void(scoped_ptr<CloudPolicyClient>)>
+      PolicyRegistrationCallback;
+
+  // The callback invoked once policy fetch is complete. Passed boolean
+  // parameter is set to true if the policy fetch succeeded.
+  typedef base::Callback<void(bool)> PolicyFetchCallback;
+
+  // Creates a UserPolicySigninServiceBase associated with the passed |profile|.
+  explicit UserPolicySigninServiceBase(Profile* profile);
+  virtual ~UserPolicySigninServiceBase();
+
+  // Initiates a policy fetch as part of user signin, using a CloudPolicyClient
+  // previously initialized via RegisterPolicyClient. |callback| is invoked
+  // once the policy fetch is complete, passing true if the policy fetch
+  // succeeded.
+  void FetchPolicyForSignedInUser(scoped_ptr<CloudPolicyClient> client,
+                                  const PolicyFetchCallback& callback);
+
+  // content::NotificationObserver implementation:
+  virtual void Observe(int type,
+                       const content::NotificationSource& source,
+                       const content::NotificationDetails& details) OVERRIDE;
+
+  // CloudPolicyService::Observer implementation:
+  virtual void OnInitializationCompleted(CloudPolicyService* service) OVERRIDE;
+
+  // CloudPolicyClient::Observer implementation:
+  virtual void OnPolicyFetched(CloudPolicyClient* client) OVERRIDE;
+  virtual void OnRegistrationStateChanged(CloudPolicyClient* client) OVERRIDE;
+  virtual void OnClientError(CloudPolicyClient* client) OVERRIDE;
+
+  // BrowserContextKeyedService implementation:
+  virtual void Shutdown() OVERRIDE;
+
+ protected:
+  // Returns true if policy should be loaded even when Gaia reports that the
+  // account doesn't have management enabled.
+  static bool ShouldForceLoadPolicy();
+
+  // Returns a CloudPolicyClient to perform a registration with the DM server,
+  // or NULL if |username| shouldn't register for policy management.
+  scoped_ptr<CloudPolicyClient> PrepareToRegister(const std::string& username);
+
+  // Returns false if cloud policy is disabled or if the passed |email_address|
+  // is definitely not from a hosted domain (according to the blacklist in
+  // BrowserPolicyConnector::IsNonEnterpriseUser()).
+  bool ShouldLoadPolicyForUser(const std::string& email_address);
+
+  // Invoked to initialize the UserPolicySigninService once its owning Profile
+  // becomes ready. If the Profile has a signed-in account associated with it
+  // at startup then this initializes the cloud policy manager by calling
+  // InitializeForSignedInUser(); otherwise it clears any stored policies.
+  void InitializeOnProfileReady();
+
+  // Invoked to initialize the cloud policy service for |username|, which is the
+  // account associated with the Profile that owns this service. This is invoked
+  // from InitializeOnProfileReady() if the Profile already has a signed-in
+  // account at startup, or (on the desktop platforms) as soon as the user
+  // signs-in and an OAuth2 login refresh token becomes available.
+  void InitializeForSignedInUser(const std::string& username);
+
+  // Initializes the cloud policy manager with the passed |client|. This is
+  // called from InitializeForSignedInUser() when the Profile already has a
+  // signed in account at startup, and from FetchPolicyForSignedInUser() during
+  // the initial policy fetch after signing in.
+  virtual void InitializeUserCloudPolicyManager(
+      scoped_ptr<CloudPolicyClient> client);
+
+  // Shuts down the UserCloudPolicyManager (for example, after the user signs
+  // out) and deletes any cached policy.
+  virtual void ShutdownUserCloudPolicyManager();
+
+  // Convenience helper to get the UserCloudPolicyManager for |profile_|.
+  UserCloudPolicyManager* GetManager();
+
+  Profile* profile() { return profile_; }
+  content::NotificationRegistrar* registrar() { return &registrar_; }
+
+ private:
+  // Weak pointer to the profile this service is associated with.
+  Profile* profile_;
+
+  content::NotificationRegistrar registrar_;
+
+  base::WeakPtrFactory<UserPolicySigninServiceBase> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(UserPolicySigninServiceBase);
+};
+
+}  // namespace policy
+
+#endif  // CHROME_BROWSER_POLICY_CLOUD_USER_POLICY_SIGNIN_SERVICE_BASE_H_
diff --git a/chrome/browser/policy/cloud/user_policy_signin_service_factory.cc b/chrome/browser/policy/cloud/user_policy_signin_service_factory.cc
index 3125feb..8461391 100644
--- a/chrome/browser/policy/cloud/user_policy_signin_service_factory.cc
+++ b/chrome/browser/policy/cloud/user_policy_signin_service_factory.cc
@@ -6,21 +6,28 @@
 
 #include "base/prefs/pref_service.h"
 #include "chrome/browser/policy/cloud/user_cloud_policy_manager_factory.h"
-#include "chrome/browser/policy/cloud/user_policy_signin_service.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/signin/signin_manager_factory.h"
-#include "chrome/browser/signin/token_service_factory.h"
 #include "chrome/common/pref_names.h"
 #include "components/browser_context_keyed_service/browser_context_dependency_manager.h"
 #include "components/user_prefs/pref_registry_syncable.h"
 
+#if defined(OS_ANDROID)
+#include "chrome/browser/policy/cloud/user_policy_signin_service_android.h"
+#else
+#include "chrome/browser/policy/cloud/user_policy_signin_service.h"
+#include "chrome/browser/signin/token_service_factory.h"
+#endif
+
 namespace policy {
 
 UserPolicySigninServiceFactory::UserPolicySigninServiceFactory()
     : BrowserContextKeyedServiceFactory(
         "UserPolicySigninService",
         BrowserContextDependencyManager::GetInstance()) {
+#if !defined(OS_ANDROID)
   DependsOn(TokenServiceFactory::GetInstance());
+#endif
   DependsOn(SigninManagerFactory::GetInstance());
   DependsOn(UserCloudPolicyManagerFactory::GetInstance());
 }
diff --git a/chrome/browser/policy/cloud/user_policy_signin_service_unittest.cc b/chrome/browser/policy/cloud/user_policy_signin_service_unittest.cc
index 1dc0afd..7954e17 100644
--- a/chrome/browser/policy/cloud/user_policy_signin_service_unittest.cc
+++ b/chrome/browser/policy/cloud/user_policy_signin_service_unittest.cc
@@ -2,27 +2,23 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "base/command_line.h"
 #include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
 #include "base/message_loop.h"
 #include "base/prefs/pref_service.h"
 #include "base/run_loop.h"
+#include "chrome/browser/browser_process.h"
 #include "chrome/browser/policy/browser_policy_connector.h"
 #include "chrome/browser/policy/cloud/cloud_policy_constants.h"
 #include "chrome/browser/policy/cloud/mock_device_management_service.h"
 #include "chrome/browser/policy/cloud/mock_user_cloud_policy_store.h"
 #include "chrome/browser/policy/cloud/user_cloud_policy_manager.h"
-#include "chrome/browser/policy/cloud/user_policy_signin_service.h"
 #include "chrome/browser/policy/cloud/user_policy_signin_service_factory.h"
 #include "chrome/browser/prefs/browser_prefs.h"
 #include "chrome/browser/signin/fake_signin_manager.h"
 #include "chrome/browser/signin/signin_manager.h"
 #include "chrome/browser/signin/signin_manager_factory.h"
-#include "chrome/browser/signin/token_service.h"
-#include "chrome/browser/signin/token_service_factory.h"
 #include "chrome/common/chrome_notification_types.h"
-#include "chrome/common/chrome_switches.h"
-#include "chrome/common/pref_names.h"
 #include "chrome/test/base/testing_browser_process.h"
 #include "chrome/test/base/testing_pref_service_syncable.h"
 #include "chrome/test/base/testing_profile.h"
@@ -38,6 +34,14 @@
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+#if defined(OS_ANDROID)
+#include "chrome/browser/policy/cloud/user_policy_signin_service_android.h"
+#else
+#include "chrome/browser/policy/cloud/user_policy_signin_service.h"
+#include "chrome/browser/signin/token_service.h"
+#include "chrome/browser/signin/token_service_factory.h"
+#endif
+
 namespace em = enterprise_management;
 
 using testing::AnyNumber;
@@ -48,19 +52,18 @@
 
 namespace {
 
-static const char kValidTokenResponse[] =
+const char kValidTokenResponse[] =
     "{"
     "  \"access_token\": \"at1\","
     "  \"expires_in\": 3600,"
     "  \"token_type\": \"Bearer\""
     "}";
 
-static const char kHostedDomainResponse[] =
+const char kHostedDomainResponse[] =
     "{"
     "  \"hd\": \"test.com\""
     "}";
 
-namespace {
 class SigninManagerFake : public FakeSigninManager {
  public:
   explicit SigninManagerFake(Profile* profile)
@@ -78,7 +81,6 @@
     return new SigninManagerFake(static_cast<Profile*>(profile));
   }
 };
-}  // namespace
 
 class UserPolicySigninServiceTest : public testing::Test {
  public:
@@ -90,6 +92,7 @@
         register_completed_(false) {}
 
   MOCK_METHOD1(OnPolicyRefresh, void(bool));
+
   void OnRegisterCompleted(scoped_ptr<CloudPolicyClient> client) {
     register_completed_ = true;
     created_client_.swap(client);
@@ -112,8 +115,7 @@
 
     local_state_.reset(new TestingPrefServiceSimple);
     chrome::RegisterLocalState(local_state_->registry());
-    TestingBrowserProcess::GetGlobal()->SetLocalState(
-        local_state_.get());
+    TestingBrowserProcess::GetGlobal()->SetLocalState(local_state_.get());
 
     scoped_refptr<net::URLRequestContextGetter> system_request_context;
     g_browser_process->browser_policy_connector()->Init(
@@ -181,8 +183,10 @@
     EXPECT_CALL(*this, OnPolicyRefresh(true)).Times(0);
     RegisterPolicyClientWithCallback(signin_service);
 
+#if !defined(OS_ANDROID)
     // Mimic successful oauth token fetch.
     MakeOAuthTokenFetchSucceed();
+#endif
 
     // When the user is from a hosted domain, this should kick off client
     // registration.
@@ -303,6 +307,11 @@
   ASSERT_FALSE(manager_->core()->service());
 }
 
+  // TODO(joaodasilva): these tests rely on issuing the OAuth2 login refresh
+  // token after signin. Revisit this after figuring how to handle that on
+  // Android.
+#if !defined(OS_ANDROID)
+
 TEST_F(UserPolicySigninServiceTest, InitWhileSignedIn) {
   // Set the user as signed in.
   SigninManagerFactory::GetForProfile(profile_.get())->SetAuthenticatedUsername(
@@ -465,6 +474,8 @@
   ASSERT_FALSE(IsRequestActive());
 }
 
+#endif  // !defined(OS_ANDROID)
+
 TEST_F(UserPolicySigninServiceTest, SignOutAfterInit) {
   EXPECT_CALL(*mock_store_, Clear());
   // Set the user as signed in.
@@ -516,12 +527,15 @@
   ASSERT_FALSE(manager_->core()->service());
   ASSERT_TRUE(IsRequestActive());
 
+#if !defined(OS_ANDROID)
   // Cause the access token request to succeed.
   MakeOAuthTokenFetchSucceed();
 
   // Should be a follow-up fetch to check the hosted-domain status.
   ASSERT_TRUE(IsRequestActive());
   Mock::VerifyAndClearExpectations(this);
+#endif
+
   EXPECT_FALSE(register_completed_);
 
   // Report that the user is not on a hosted domain - callback should be
@@ -543,8 +557,11 @@
   // UserCloudPolicyManager should not be initialized.
   ASSERT_FALSE(manager_->core()->service());
 
+#if !defined(OS_ANDROID)
   // Mimic successful oauth token fetch.
   MakeOAuthTokenFetchSucceed();
+#endif
+
   EXPECT_FALSE(register_completed_);
 
   // When the user is from a hosted domain, this should kick off client
@@ -578,8 +595,10 @@
       UserPolicySigninServiceFactory::GetForProfile(profile_.get());
   RegisterPolicyClientWithCallback(signin_service);
 
+#if !defined(OS_ANDROID)
   // Mimic successful oauth token fetch.
   MakeOAuthTokenFetchSucceed();
+#endif
 
   // When the user is from a hosted domain, this should kick off client
   // registration.
@@ -643,21 +662,22 @@
 }
 
 TEST_F(UserPolicySigninServiceTest, FetchPolicySuccess) {
-  TestSuccessfulSignin();
+  ASSERT_NO_FATAL_FAILURE(TestSuccessfulSignin());
 }
 
 TEST_F(UserPolicySigninServiceTest, SignOutThenSignInAgain) {
-  TestSuccessfulSignin();
+  ASSERT_NO_FATAL_FAILURE(TestSuccessfulSignin());
 
+  EXPECT_CALL(*mock_store_, Clear());
   signin_manager_->ForceSignOut();
   ASSERT_FALSE(manager_->core()->service());
 
   // Now sign in again.
-  TestSuccessfulSignin();
+  ASSERT_NO_FATAL_FAILURE(TestSuccessfulSignin());
 }
 
 TEST_F(UserPolicySigninServiceTest, PolicyFetchFailureTemporary) {
-  TestSuccessfulSignin();
+  ASSERT_NO_FATAL_FAILURE(TestSuccessfulSignin());
 
   ASSERT_TRUE(manager_->IsClientRegistered());
 
@@ -680,10 +700,12 @@
 }
 
 TEST_F(UserPolicySigninServiceTest, PolicyFetchFailureDisableManagement) {
-  TestSuccessfulSignin();
+  ASSERT_NO_FATAL_FAILURE(TestSuccessfulSignin());
 
   EXPECT_TRUE(manager_->IsClientRegistered());
+#if !defined(OS_ANDROID)
   EXPECT_TRUE(signin_manager_->IsSignoutProhibited());
+#endif
 
   // Kick off another policy fetch.
   MockDeviceManagementJob* fetch_request = NULL;
@@ -703,7 +725,9 @@
                               em::DeviceManagementResponse());
   base::RunLoop().RunUntilIdle();
   EXPECT_FALSE(manager_->IsClientRegistered());
+#if !defined(OS_ANDROID)
   EXPECT_FALSE(signin_manager_->IsSignoutProhibited());
+#endif
 }
 
 }  // namespace
diff --git a/chrome/browser/policy/configuration_policy_handler.cc b/chrome/browser/policy/configuration_policy_handler.cc
index be6524f..d3e2c89 100644
--- a/chrome/browser/policy/configuration_policy_handler.cc
+++ b/chrome/browser/policy/configuration_policy_handler.cc
@@ -29,9 +29,9 @@
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/pref_names.h"
 #include "content/public/browser/notification_service.h"
-#include "googleurl/src/gurl.h"
 #include "grit/generated_resources.h"
 #include "policy/policy_constants.h"
+#include "url/gurl.h"
 
 #if !defined(OS_ANDROID)
 #include "chrome/browser/policy/policy_path_parser.h"
@@ -292,6 +292,8 @@
 void StringToIntEnumListPolicyHandler::ApplyPolicySettings(
     const PolicyMap& policies,
     PrefValueMap* prefs) {
+  if (!pref_path_)
+    return;
   const base::Value* value = policies.GetValue(policy_name());
   scoped_ptr<base::ListValue> list(new base::ListValue());
   if (value && Convert(value, list.get(), NULL))
@@ -360,6 +362,8 @@
 
 void IntRangePolicyHandler::ApplyPolicySettings(const PolicyMap& policies,
                                                 PrefValueMap* prefs) {
+  if (!pref_path_)
+    return;
   const base::Value* value = policies.GetValue(policy_name());
   int value_in_range;
   if (value && EnsureInRange(value, &value_in_range, NULL)) {
@@ -386,6 +390,8 @@
 void IntPercentageToDoublePolicyHandler::ApplyPolicySettings(
     const PolicyMap& policies,
     PrefValueMap* prefs) {
+  if (!pref_path_)
+    return;
   const base::Value* value = policies.GetValue(policy_name());
   int percentage;
   if (value && EnsureInRange(value, &percentage, NULL)) {
@@ -616,6 +622,8 @@
 void ExtensionURLPatternListPolicyHandler::ApplyPolicySettings(
     const PolicyMap& policies,
     PrefValueMap* prefs) {
+  if (!pref_path_)
+    return;
   const Value* value = policies.GetValue(policy_name());
   if (value)
     prefs->SetValue(pref_path_, value->DeepCopy());
@@ -636,6 +644,8 @@
 
 void SimplePolicyHandler::ApplyPolicySettings(const PolicyMap& policies,
                                               PrefValueMap* prefs) {
+  if (!pref_path_)
+    return;
   const Value* value = policies.GetValue(policy_name());
   if (value)
     prefs->SetValue(pref_path_, value->DeepCopy());
diff --git a/chrome/browser/policy/configuration_policy_handler_list.cc b/chrome/browser/policy/configuration_policy_handler_list.cc
index 2baabf1..c0b3fc5 100644
--- a/chrome/browser/policy/configuration_policy_handler_list.cc
+++ b/chrome/browser/policy/configuration_policy_handler_list.cc
@@ -18,6 +18,7 @@
 #include "policy/policy_constants.h"
 
 #if defined(OS_CHROMEOS)
+#include "ash/magnifier/magnifier_constants.h"
 #include "chrome/browser/chromeos/policy/configuration_policy_handler_chromeos.h"
 #endif  // defined(OS_CHROMEOS)
 
@@ -330,6 +331,9 @@
   { key::kContentPackManualBehaviorURLs,
     prefs::kManagedModeManualURLs,
     Value::TYPE_DICTIONARY },
+  { key::kSupervisedUserCreationEnabled,
+    prefs::kManagedUserCreationAllowed,
+    Value::TYPE_BOOLEAN },
 
 #if defined(OS_CHROMEOS)
   { key::kChromeOsLockOnIdleSuspend,
@@ -383,6 +387,15 @@
   { key::kHighContrastEnabled,
     prefs::kHighContrastEnabled,
     Value::TYPE_BOOLEAN },
+  { key::kDeviceLoginScreenDefaultLargeCursorEnabled,
+    NULL,
+    Value::TYPE_BOOLEAN },
+  { key::kDeviceLoginScreenDefaultSpokenFeedbackEnabled,
+    NULL,
+    Value::TYPE_BOOLEAN },
+  { key::kDeviceLoginScreenDefaultHighContrastEnabled,
+    NULL,
+    Value::TYPE_BOOLEAN },
   { key::kRebootAfterUpdate,
     prefs::kRebootAfterUpdate,
     Value::TYPE_BOOLEAN },
@@ -517,8 +530,13 @@
           0, INT_MAX, true));
   handlers_.push_back(
       new IntRangePolicyHandler(
-          key::kIdleAction,
-          prefs::kPowerIdleAction,
+          key::kIdleActionAC,
+          prefs::kPowerAcIdleAction,
+          0, 3, false));
+  handlers_.push_back(
+      new IntRangePolicyHandler(
+          key::kIdleActionBattery,
+          prefs::kPowerBatteryIdleAction,
           0, 3, false));
   handlers_.push_back(
       new IntRangePolicyHandler(
@@ -527,8 +545,8 @@
           0, 3, false));
   handlers_.push_back(
       new IntPercentageToDoublePolicyHandler(
-          key::kPresentationIdleDelayScale,
-          prefs::kPowerPresentationIdleDelayFactor,
+          key::kPresentationScreenDimDelayScale,
+          prefs::kPowerPresentationScreenDimDelayFactor,
           100, INT_MAX, true));
   handlers_.push_back(
       new IntPercentageToDoublePolicyHandler(
@@ -538,6 +556,10 @@
   handlers_.push_back(new IntRangePolicyHandler(key::kUptimeLimit,
                                                 prefs::kUptimeLimit,
                                                 3600, INT_MAX, true));
+  handlers_.push_back(new IntRangePolicyHandler(
+      key::kDeviceLoginScreenDefaultScreenMagnifierType,
+      NULL,
+      0, ash::MAGNIFIER_FULL, false));
 #endif  // defined(OS_CHROMEOS)
 }
 
diff --git a/chrome/browser/policy/managed_mode_policy_provider.cc b/chrome/browser/policy/managed_mode_policy_provider.cc
index ecd51c9..ec6fba6 100644
--- a/chrome/browser/policy/managed_mode_policy_provider.cc
+++ b/chrome/browser/policy/managed_mode_policy_provider.cc
@@ -7,7 +7,7 @@
 #include "base/json/json_reader.h"
 #include "base/json/json_writer.h"
 #include "base/prefs/json_pref_store.h"
-#include "base/string_util.h"
+#include "base/strings/string_util.h"
 #include "base/threading/sequenced_worker_pool.h"
 #include "chrome/browser/managed_mode/managed_mode_url_filter.h"
 #include "chrome/browser/policy/policy_bundle.h"
diff --git a/chrome/browser/policy/managed_mode_policy_provider_unittest.cc b/chrome/browser/policy/managed_mode_policy_provider_unittest.cc
index 685f3ff..5b0d661 100644
--- a/chrome/browser/policy/managed_mode_policy_provider_unittest.cc
+++ b/chrome/browser/policy/managed_mode_policy_provider_unittest.cc
@@ -67,7 +67,10 @@
 syncer::SyncError MockSyncErrorFactory::CreateAndUploadError(
     const tracked_objects::Location& location,
     const std::string& message) {
-  return syncer::SyncError(location, message, type_);
+  return syncer::SyncError(location,
+                           syncer::SyncError::DATATYPE_ERROR,
+                           message,
+                           type_);
 }
 
 class TestHarness : public PolicyProviderTestHarness {
diff --git a/chrome/browser/policy/policy_browsertest.cc b/chrome/browser/policy/policy_browsertest.cc
index 6e87fb7..f10972e 100644
--- a/chrome/browser/policy/policy_browsertest.cc
+++ b/chrome/browser/policy/policy_browsertest.cc
@@ -22,7 +22,7 @@
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/test_file_util.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "base/values.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/autocomplete/autocomplete_controller.h"
@@ -101,7 +101,6 @@
 #include "content/public/test/test_utils.h"
 #include "content/test/net/url_request_failed_job.h"
 #include "content/test/net/url_request_mock_http_job.h"
-#include "googleurl/src/gurl.h"
 #include "grit/generated_resources.h"
 #include "net/base/net_errors.h"
 #include "net/base/net_util.h"
@@ -115,6 +114,7 @@
 #include "third_party/WebKit/public/web/WebInputEvent.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/resource/resource_bundle.h"
+#include "url/gurl.h"
 #include "webkit/plugins/npapi/plugin_utils.h"
 #include "webkit/plugins/plugin_constants.h"
 #include "webkit/plugins/webplugininfo.h"
@@ -1499,20 +1499,19 @@
 IN_PROC_BROWSER_TEST_F(PolicyTest, IncognitoEnabled) {
   // Verifies that incognito windows can't be opened when disabled by policy.
 
-  // Only test this on the native desktop.
-  const BrowserList* native_browser_list =
-      BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_NATIVE);
+  const BrowserList* active_browser_list =
+      BrowserList::GetInstance(chrome::GetActiveDesktop());
 
   // Disable incognito via policy and verify that incognito windows can't be
   // opened.
-  EXPECT_EQ(1u, native_browser_list->size());
+  EXPECT_EQ(1u, active_browser_list->size());
   EXPECT_FALSE(BrowserList::IsOffTheRecordSessionActive());
   PolicyMap policies;
   policies.Set(key::kIncognitoEnabled, POLICY_LEVEL_MANDATORY,
                POLICY_SCOPE_USER, base::Value::CreateBooleanValue(false));
   UpdateProviderPolicy(policies);
   EXPECT_FALSE(chrome::ExecuteCommand(browser(), IDC_NEW_INCOGNITO_WINDOW));
-  EXPECT_EQ(1u, native_browser_list->size());
+  EXPECT_EQ(1u, active_browser_list->size());
   EXPECT_FALSE(BrowserList::IsOffTheRecordSessionActive());
 
   // Enable via policy and verify that incognito windows can be opened.
@@ -1520,7 +1519,7 @@
                POLICY_SCOPE_USER, base::Value::CreateBooleanValue(true));
   UpdateProviderPolicy(policies);
   EXPECT_TRUE(chrome::ExecuteCommand(browser(), IDC_NEW_INCOGNITO_WINDOW));
-  EXPECT_EQ(2u, native_browser_list->size());
+  EXPECT_EQ(2u, active_browser_list->size());
   EXPECT_TRUE(BrowserList::IsOffTheRecordSessionActive());
 }
 
diff --git a/chrome/browser/policy/policy_loader_mac.cc b/chrome/browser/policy/policy_loader_mac.cc
index 761a7a6..0cbb519 100644
--- a/chrome/browser/policy/policy_loader_mac.cc
+++ b/chrome/browser/policy/policy_loader_mac.cc
@@ -23,7 +23,7 @@
 #include "policy/policy_constants.h"
 
 using base::mac::CFCast;
-using base::mac::ScopedCFTypeRef;
+using base::ScopedCFTypeRef;
 
 namespace policy {
 
@@ -108,9 +108,9 @@
   bool policy_present = false;
   const PolicyDefinitionList::Entry* current;
   for (current = policy_list_->begin; current != policy_list_->end; ++current) {
-    base::mac::ScopedCFTypeRef<CFStringRef> name(
+    base::ScopedCFTypeRef<CFStringRef> name(
         base::SysUTF8ToCFStringRef(current->name));
-    base::mac::ScopedCFTypeRef<CFPropertyListRef> value(
+    base::ScopedCFTypeRef<CFPropertyListRef> value(
         preferences_->CopyAppValue(name, kCFPreferencesCurrentApplication));
     if (!value.get())
       continue;
@@ -234,7 +234,7 @@
   if (!schema)
     return;
 
-  base::mac::ScopedCFTypeRef<CFStringRef> bundle_id(
+  base::ScopedCFTypeRef<CFStringRef> bundle_id(
       base::SysUTF8ToCFStringRef(bundle_id_string));
   preferences_->AppSynchronize(bundle_id);
 
@@ -246,9 +246,9 @@
 
   for (PolicySchemaMap::const_iterator it = map->begin();
        it != map->end(); ++it) {
-    base::mac::ScopedCFTypeRef<CFStringRef> pref_name(
+    base::ScopedCFTypeRef<CFStringRef> pref_name(
         base::SysUTF8ToCFStringRef(it->first));
-    base::mac::ScopedCFTypeRef<CFPropertyListRef> value(
+    base::ScopedCFTypeRef<CFPropertyListRef> value(
         preferences_->CopyAppValue(pref_name, bundle_id));
     if (!value.get())
       continue;
diff --git a/chrome/browser/policy/policy_loader_mac_unittest.cc b/chrome/browser/policy/policy_loader_mac_unittest.cc
index a5b1f6a..12c21bd 100644
--- a/chrome/browser/policy/policy_loader_mac_unittest.cc
+++ b/chrome/browser/policy/policy_loader_mac_unittest.cc
@@ -17,7 +17,7 @@
 #include "policy/policy_constants.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-using base::mac::ScopedCFTypeRef;
+using base::ScopedCFTypeRef;
 
 namespace policy {
 
diff --git a/chrome/browser/policy/policy_map.h b/chrome/browser/policy/policy_map.h
index 60524bb..3d12fc3 100644
--- a/chrome/browser/policy/policy_map.h
+++ b/chrome/browser/policy/policy_map.h
@@ -23,7 +23,7 @@
   struct Entry {
     PolicyLevel level;
     PolicyScope scope;
-    Value* value;
+    base::Value* value;
 
     Entry()
         : level(POLICY_LEVEL_RECOMMENDED),
@@ -50,14 +50,14 @@
   // Returns a weak reference to the value currently stored for key |policy|,
   // or NULL if not found. Ownership is retained by the PolicyMap.
   // This is equivalent to Get(policy)->value, when it doesn't return NULL.
-  const Value* GetValue(const std::string& policy) const;
+  const base::Value* GetValue(const std::string& policy) const;
 
   // Takes ownership of |value|. Overwrites any existing value stored in the
   // map for the key |policy|.
   void Set(const std::string& policy,
            PolicyLevel level,
            PolicyScope scope,
-           Value* value);
+           base::Value* value);
 
   // Erase the given |policy|, if it exists in this map.
   void Erase(const std::string& policy);
@@ -80,7 +80,7 @@
   // Loads the values in |policies| into this PolicyMap. All policies loaded
   // will have |level| and |scope| in their entries. Existing entries are
   // replaced.
-  void LoadFrom(const DictionaryValue* policies,
+  void LoadFrom(const base::DictionaryValue* policies,
                 PolicyLevel level,
                 PolicyScope scope);
 
diff --git a/chrome/browser/policy/policy_prefs_browsertest.cc b/chrome/browser/policy/policy_prefs_browsertest.cc
index 01ceece..689b40a 100644
--- a/chrome/browser/policy/policy_prefs_browsertest.cc
+++ b/chrome/browser/policy/policy_prefs_browsertest.cc
@@ -32,10 +32,10 @@
 #include "chrome/test/base/ui_test_utils.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/browser_test_utils.h"
-#include "googleurl/src/gurl.h"
 #include "policy/policy_constants.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
 
 using testing::AnyNumber;
 using testing::Return;
diff --git a/chrome/browser/policy/policy_service_impl_unittest.cc b/chrome/browser/policy/policy_service_impl_unittest.cc
index 68026ca..f5efb78 100644
--- a/chrome/browser/policy/policy_service_impl_unittest.cc
+++ b/chrome/browser/policy/policy_service_impl_unittest.cc
@@ -630,10 +630,10 @@
 }
 
 TEST_F(PolicyServiceTest, RegisterPolicyDomain) {
-  EXPECT_FALSE(
-      policy_service_->GetPolicyDomainDescriptor(POLICY_DOMAIN_CHROME));
-  EXPECT_FALSE(
-      policy_service_->GetPolicyDomainDescriptor(POLICY_DOMAIN_EXTENSIONS));
+  EXPECT_FALSE(policy_service_->GetPolicyDomainDescriptor(POLICY_DOMAIN_CHROME)
+                   .get());
+  EXPECT_FALSE(policy_service_->GetPolicyDomainDescriptor(
+      POLICY_DOMAIN_EXTENSIONS).get());
 
   EXPECT_CALL(provider1_, RegisterPolicyDomain(_)).Times(AnyNumber());
   EXPECT_CALL(provider2_, RegisterPolicyDomain(_)).Times(AnyNumber());
@@ -644,9 +644,10 @@
   policy_service_->RegisterPolicyDomain(chrome_descriptor);
   Mock::VerifyAndClearExpectations(&provider0_);
 
-  EXPECT_TRUE(policy_service_->GetPolicyDomainDescriptor(POLICY_DOMAIN_CHROME));
-  EXPECT_FALSE(
-      policy_service_->GetPolicyDomainDescriptor(POLICY_DOMAIN_EXTENSIONS));
+  EXPECT_TRUE(policy_service_->GetPolicyDomainDescriptor(POLICY_DOMAIN_CHROME)
+                  .get());
+  EXPECT_FALSE(policy_service_->GetPolicyDomainDescriptor(
+      POLICY_DOMAIN_EXTENSIONS).get());
 
   // Register another namespace.
   std::string error;
@@ -672,9 +673,10 @@
   policy_service_->RegisterPolicyDomain(extensions_descriptor);
   Mock::VerifyAndClearExpectations(&provider0_);
 
-  EXPECT_TRUE(policy_service_->GetPolicyDomainDescriptor(POLICY_DOMAIN_CHROME));
-  EXPECT_TRUE(
-      policy_service_->GetPolicyDomainDescriptor(POLICY_DOMAIN_EXTENSIONS));
+  EXPECT_TRUE(policy_service_->GetPolicyDomainDescriptor(POLICY_DOMAIN_CHROME)
+                  .get());
+  EXPECT_TRUE(policy_service_->GetPolicyDomainDescriptor(
+      POLICY_DOMAIN_EXTENSIONS).get());
 
   // Remove those components.
   scoped_refptr<PolicyDomainDescriptor> empty_extensions_descriptor =
diff --git a/chrome/browser/policy/policy_statistics_collector.h b/chrome/browser/policy/policy_statistics_collector.h
index 08a7c92..352a591 100644
--- a/chrome/browser/policy/policy_statistics_collector.h
+++ b/chrome/browser/policy/policy_statistics_collector.h
@@ -8,7 +8,7 @@
 #include "base/basictypes.h"
 #include "base/cancelable_callback.h"
 #include "base/memory/ref_counted.h"
-#include "base/time.h"
+#include "base/time/time.h"
 
 class PrefService;
 class PrefRegistrySimple;
diff --git a/chrome/browser/policy/policy_statistics_collector_unittest.cc b/chrome/browser/policy/policy_statistics_collector_unittest.cc
index 20e1319..06a68ca 100644
--- a/chrome/browser/policy/policy_statistics_collector_unittest.cc
+++ b/chrome/browser/policy/policy_statistics_collector_unittest.cc
@@ -10,7 +10,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/prefs/testing_pref_service.h"
 #include "base/test/test_simple_task_runner.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "base/values.h"
 #include "chrome/browser/policy/mock_policy_service.h"
 #include "chrome/browser/policy/policy_map.h"
diff --git a/chrome/browser/policy/preferences_mock_mac.h b/chrome/browser/policy/preferences_mock_mac.h
index 02a4d92..0f6fef1 100644
--- a/chrome/browser/policy/preferences_mock_mac.h
+++ b/chrome/browser/policy/preferences_mock_mac.h
@@ -26,8 +26,8 @@
   void AddTestItem(CFStringRef key, CFPropertyListRef value, bool is_forced);
 
  private:
-  base::mac::ScopedCFTypeRef<CFMutableDictionaryRef> values_;
-  base::mac::ScopedCFTypeRef<CFMutableSetRef> forced_;
+  base::ScopedCFTypeRef<CFMutableDictionaryRef> values_;
+  base::ScopedCFTypeRef<CFMutableSetRef> forced_;
 };
 
 #endif  // CHROME_BROWSER_POLICY_PREFERENCES_MOCK_MAC_H_
diff --git a/chrome/browser/policy/profile_policy_connector.cc b/chrome/browser/policy/profile_policy_connector.cc
index f9f339a..65b95e5 100644
--- a/chrome/browser/policy/profile_policy_connector.cc
+++ b/chrome/browser/policy/profile_policy_connector.cc
@@ -22,10 +22,12 @@
 #include "chrome/browser/chromeos/login/user.h"
 #include "chrome/browser/chromeos/login/user_manager.h"
 #include "chrome/browser/chromeos/policy/device_local_account_policy_provider.h"
+#include "chrome/browser/chromeos/policy/login_profile_policy_provider.h"
 #include "chrome/browser/chromeos/policy/network_configuration_updater.h"
 #include "chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos.h"
 #include "chrome/browser/chromeos/policy/user_cloud_policy_manager_factory_chromeos.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
+#include "chrome/browser/policy/policy_service.h"
 #include "chrome/common/pref_names.h"
 #include "chromeos/dbus/cryptohome_client.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
@@ -60,26 +62,33 @@
   if (cloud_policy_manager)
     providers.push_back(cloud_policy_manager);
 
-  bool is_managed = false;
+  bool allow_trusted_certs_from_policy = false;
   std::string username;
-  if (!chromeos::ProfileHelper::IsSigninProfile(profile_)) {
+  if (chromeos::ProfileHelper::IsSigninProfile(profile_)) {
+    special_user_policy_provider_.reset(new LoginProfilePolicyProvider(
+        connector->GetPolicyService()));
+    special_user_policy_provider_->Init();
+  } else {
     // |user| should never be NULL except for the signin profile.
     // TODO(joaodasilva): get the |user| that corresponds to the |profile_|
     // from the ProfileHelper, once that's ready.
     chromeos::UserManager* user_manager = chromeos::UserManager::Get();
     chromeos::User* user = user_manager->GetActiveUser();
     CHECK(user);
-    // Check if |user| is managed, and if it's a public account.
     username = user->email();
-    is_managed =
-        connector->GetUserAffiliation(username) == USER_AFFILIATION_MANAGED;
     is_primary_user_ =
         chromeos::UserManager::Get()->GetLoggedInUsers().size() == 1;
     if (user->GetType() == chromeos::User::USER_TYPE_PUBLIC_ACCOUNT)
       InitializeDeviceLocalAccountPolicyProvider(username);
-    if (device_local_account_policy_provider_)
-      providers.push_back(device_local_account_policy_provider_.get());
+    // Allow trusted certs from policy only for managed regular accounts.
+    const bool is_managed =
+        connector->GetUserAffiliation(username) == USER_AFFILIATION_MANAGED;
+    if (is_managed && user->GetType() == chromeos::User::USER_TYPE_REGULAR)
+      allow_trusted_certs_from_policy = true;
   }
+  if (special_user_policy_provider_)
+    providers.push_back(special_user_policy_provider_.get());
+
 #else
   UserCloudPolicyManager* cloud_policy_manager =
       UserCloudPolicyManagerFactory::GetForProfile(profile_);
@@ -98,12 +107,10 @@
 
 #if defined(OS_CHROMEOS)
   if (is_primary_user_) {
-    if (cloud_policy_manager) {
+    if (cloud_policy_manager)
       connector->SetUserPolicyDelegate(cloud_policy_manager);
-    } else if (device_local_account_policy_provider_) {
-      connector->SetUserPolicyDelegate(
-          device_local_account_policy_provider_.get());
-    }
+    else if (special_user_policy_provider_)
+      connector->SetUserPolicyDelegate(special_user_policy_provider_.get());
 
     chromeos::CryptohomeClient* cryptohome_client =
         chromeos::DBusThreadManager::Get()->GetCryptohomeClient();
@@ -112,7 +119,7 @@
         base::Bind(
             &ProfilePolicyConnector::InitializeNetworkConfigurationUpdater,
             weak_ptr_factory_.GetWeakPtr(),
-            is_managed));
+            allow_trusted_certs_from_policy));
   }
 #endif
 }
@@ -127,12 +134,10 @@
     BrowserPolicyConnector* connector =
         g_browser_process->browser_policy_connector();
     connector->SetUserPolicyDelegate(NULL);
-    NetworkConfigurationUpdater* network_updater =
-        connector->GetNetworkConfigurationUpdater();
-    network_updater->UnsetUserPolicyService();
+    connector->network_configuration_updater()->UnsetUserPolicyService();
   }
-  if (device_local_account_policy_provider_)
-    device_local_account_policy_provider_->Shutdown();
+  if (special_user_policy_provider_)
+    special_user_policy_provider_->Shutdown();
 #endif
 
 #if defined(ENABLE_MANAGED_USERS)
@@ -158,25 +163,21 @@
       connector->GetDeviceLocalAccountPolicyService();
   if (!device_local_account_policy_service)
     return;
-  device_local_account_policy_provider_.reset(
-      new DeviceLocalAccountPolicyProvider(
-          username, device_local_account_policy_service));
-  device_local_account_policy_provider_->Init();
+  special_user_policy_provider_.reset(new DeviceLocalAccountPolicyProvider(
+      username, device_local_account_policy_service));
+  special_user_policy_provider_->Init();
 }
 
 void ProfilePolicyConnector::InitializeNetworkConfigurationUpdater(
-    bool is_managed,
+    bool allow_trusted_certs_from_policy,
     chromeos::DBusMethodCallStatus status,
     const std::string& hashed_username) {
   // TODO(joaodasilva): create the NetworkConfigurationUpdater for user ONC
   // here, after splitting that class into an instance for device policy and
   // another per profile for user policy.
-  BrowserPolicyConnector* connector =
-      g_browser_process->browser_policy_connector();
-  NetworkConfigurationUpdater* network_updater =
-      connector->GetNetworkConfigurationUpdater();
-  network_updater->SetUserPolicyService(
-      is_managed, hashed_username, policy_service());
+  g_browser_process->browser_policy_connector()->
+      network_configuration_updater()->SetUserPolicyService(
+          allow_trusted_certs_from_policy, hashed_username, policy_service());
 }
 #endif
 
diff --git a/chrome/browser/policy/profile_policy_connector.h b/chrome/browser/policy/profile_policy_connector.h
index 0669c7d..a7d726d 100644
--- a/chrome/browser/policy/profile_policy_connector.h
+++ b/chrome/browser/policy/profile_policy_connector.h
@@ -24,7 +24,7 @@
 
 namespace policy {
 
-class DeviceLocalAccountPolicyProvider;
+class ConfigurationPolicyProvider;
 class ManagedModePolicyProvider;
 class PolicyService;
 
@@ -82,8 +82,7 @@
   // local state.
   bool is_primary_user_;
 
-  scoped_ptr<DeviceLocalAccountPolicyProvider>
-      device_local_account_policy_provider_;
+  scoped_ptr<ConfigurationPolicyProvider> special_user_policy_provider_;
 #endif
 
 #if defined(ENABLE_MANAGED_USERS) && defined(ENABLE_CONFIGURATION_POLICY)
diff --git a/chrome/browser/policy/proto/chromeos/chrome_device_policy.proto b/chrome/browser/policy/proto/chromeos/chrome_device_policy.proto
index 5d83a8a..65fe798 100644
--- a/chrome/browser/policy/proto/chromeos/chrome_device_policy.proto
+++ b/chrome/browser/policy/proto/chromeos/chrome_device_policy.proto
@@ -347,6 +347,72 @@
   optional bool attestation_enabled = 1;
 }
 
+message AccessibilitySettingsProto {
+  // Sets the default state of the large cursor accessibility feature on the
+  // login screen. If this policy is set to true, the large cursor will be
+  // enabled when the login screen is shown. If this policy is set to false, the
+  // large cursor will be disabled when the login screen is shown. Users can
+  // temporarily override this setting by enabling or disabling the large
+  // cursor. However, the user's choice is not persistent and the default is
+  // restored whenever the login screen is shown anew or the user remains idle
+  // on the login screen for a minute. If this policy is left unset, the large
+  // cursor is disabled when the login screen is first shown. Users can enable
+  // or disable the large cursor anytime and its status on the login screen is
+  // persisted between users.
+  optional bool login_screen_default_large_cursor_enabled = 1;
+
+  // Sets the default state of the spoken feedback accessibility feature on the
+  // login screen. If this policy is set to true, spoken feedback will be
+  // enabled when the login screen is shown. If this policy is set to false,
+  // spoken feedback will be disabled when the login screen is shown. Users can
+  // temporarily override this setting by enabling or disabling spoken feedback.
+  // However, the user's choice is not persistent and the default is restored
+  // whenever the login screen is shown anew or the user remains idle on the
+  // login screen for a minute. If this policy is left unset, spoken feedback is
+  // disabled when the login screen is first shown. Users can enable or disable
+  // spoken feedback anytime and its status on the login screen is persisted
+  // between users.
+  optional bool login_screen_default_spoken_feedback_enabled = 2;
+
+  // Sets the default state of the high contrast mode accessibility feature on
+  // the login screen. If this policy is set to true, high contrast mode will be
+  // enabled when the login screen is shown. If this policy is set to false,
+  // high contrast mode will be disabled when the login screen is shown. Users
+  // can temporarily override this setting by enabling or disabling high
+  // contrast mode. However, the user's choice is not persistent and the default
+  // is restored whenever the login screen is shown anew or the user remains
+  // idle on the login screen for a minute. If this policy is left unset, high
+  // contrast mode is disabled when the login screen is first shown. Users can
+  // enable or disable high contrast mode anytime and its status on the login
+  // screen is persisted between users.
+  optional bool login_screen_default_high_contrast_enabled = 3;
+
+  // Enumerates the screen magnifier types.
+  enum ScreenMagnifierType {
+    // Screen magnifier disabled.
+    SCREEN_MAGNIFIER_TYPE_NONE = 0;
+    // Full-screen magnifier enabled.
+    SCREEN_MAGNIFIER_TYPE_FULL = 1;
+  };
+
+  // Sets the default type of screen magnifier that is enabled on the login
+  // screen. If this policy is set, it controls the type of screen magnifier
+  // that is enabled when the login screen is shown. Users can temporarily
+  // override this setting by enabling or disabling the screen magnifier.
+  // However, the user's choice is not persistent and the default is restored
+  // whenever the login screen is shown anew or the user remains idle on the
+  // login screen for a minute. If this policy is left unset, the screen
+  // magnifier is disabled when the login screen is first shown. Users can
+  // enable or disable the screen magnifier anytime and its status on the login
+  // screen is persisted between users.
+  optional ScreenMagnifierType login_screen_default_screen_magnifier_type = 4;
+}
+
+message SupervisedUsersSettingsProto {
+  // Defines whether supervised users can be created on the device.
+  optional bool supervised_users_enabled = 1;
+}
+
 message ChromeDeviceSettingsProto {
   optional DevicePolicyRefreshRateProto device_policy_refresh_rate = 1;
   optional UserWhitelistProto user_whitelist = 2;
@@ -374,4 +440,6 @@
   optional UptimeLimitProto uptime_limit = 24;
   optional VariationsParameterProto variations_parameter = 25;
   optional AttestationSettingsProto attestation_settings = 26;
+  optional AccessibilitySettingsProto accessibility_settings = 27;
+  optional SupervisedUsersSettingsProto supervised_users_settings = 28;
 }
diff --git a/chrome/browser/policy/proto/cloud/device_management_backend.proto b/chrome/browser/policy/proto/cloud/device_management_backend.proto
index ab31bfe..2d1e856 100644
--- a/chrome/browser/policy/proto/cloud/device_management_backend.proto
+++ b/chrome/browser/policy/proto/cloud/device_management_backend.proto
@@ -238,6 +238,10 @@
   // Indicates which public account or extension/plug-in this policy data is
   // for. See PolicyFetchRequest.settings_entity_id for more details.
   optional string settings_entity_id = 11;
+
+  // Indicates the identity the device service account is associated with.
+  // This is only sent as part of device policy fetch.
+  optional string service_account_identity = 12;
 }
 
 message PolicyFetchResponse {
diff --git a/chrome/browser/policy/test/local_policy_test_server.h b/chrome/browser/policy/test/local_policy_test_server.h
index aaf6da0..7dbd2ef 100644
--- a/chrome/browser/policy/test/local_policy_test_server.h
+++ b/chrome/browser/policy/test/local_policy_test_server.h
@@ -12,8 +12,8 @@
 #include "base/files/file_path.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/values.h"
-#include "googleurl/src/gurl.h"
 #include "net/test/spawned_test_server/local_test_server.h"
+#include "url/gurl.h"
 
 namespace crypto {
 class RSAPrivateKey;
diff --git a/chrome/browser/policy/url_blacklist_manager.cc b/chrome/browser/policy/url_blacklist_manager.cc
index dd070b7..66a496e 100644
--- a/chrome/browser/policy/url_blacklist_manager.cc
+++ b/chrome/browser/policy/url_blacklist_manager.cc
@@ -20,10 +20,10 @@
 #include "content/public/browser/notification_source.h"
 #include "content/public/common/url_constants.h"
 #include "google_apis/gaia/gaia_urls.h"
-#include "googleurl/src/gurl.h"
 #include "net/base/load_flags.h"
 #include "net/base/net_util.h"
 #include "net/url_request/url_request.h"
+#include "url/gurl.h"
 
 #if !defined(OS_CHROMEOS)
 #include "chrome/browser/signin/signin_manager.h"
diff --git a/chrome/browser/policy/url_blacklist_manager_unittest.cc b/chrome/browser/policy/url_blacklist_manager_unittest.cc
index a5afd49..977c659 100644
--- a/chrome/browser/policy/url_blacklist_manager_unittest.cc
+++ b/chrome/browser/policy/url_blacklist_manager_unittest.cc
@@ -13,10 +13,10 @@
 #include "chrome/common/pref_names.h"
 #include "content/public/test/test_browser_thread.h"
 #include "google_apis/gaia/gaia_urls.h"
-#include "googleurl/src/gurl.h"
 #include "net/url_request/url_request.h"
 #include "net/url_request/url_request_test_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
 
 namespace policy {
 
diff --git a/chrome/browser/predictors/autocomplete_action_predictor.h b/chrome/browser/predictors/autocomplete_action_predictor.h
index 56adfa8..b1c4f97 100644
--- a/chrome/browser/predictors/autocomplete_action_predictor.h
+++ b/chrome/browser/predictors/autocomplete_action_predictor.h
@@ -18,7 +18,7 @@
 #include "content/public/browser/navigation_controller.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 struct AutocompleteMatch;
 class AutocompleteResult;
diff --git a/chrome/browser/predictors/autocomplete_action_predictor_table.h b/chrome/browser/predictors/autocomplete_action_predictor_table.h
index d6204c6..edde92b 100644
--- a/chrome/browser/predictors/autocomplete_action_predictor_table.h
+++ b/chrome/browser/predictors/autocomplete_action_predictor_table.h
@@ -10,7 +10,7 @@
 
 #include "base/strings/string16.h"
 #include "chrome/browser/predictors/predictor_table_base.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 namespace predictors {
 
diff --git a/chrome/browser/predictors/autocomplete_action_predictor_table_unittest.cc b/chrome/browser/predictors/autocomplete_action_predictor_table_unittest.cc
index f1f2b9e..d29086c 100644
--- a/chrome/browser/predictors/autocomplete_action_predictor_table_unittest.cc
+++ b/chrome/browser/predictors/autocomplete_action_predictor_table_unittest.cc
@@ -6,7 +6,7 @@
 
 #include "base/message_loop.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/predictors/autocomplete_action_predictor_table.h"
 #include "chrome/browser/predictors/predictor_database.h"
 #include "chrome/browser/predictors/predictor_database_factory.h"
diff --git a/chrome/browser/predictors/autocomplete_action_predictor_unittest.cc b/chrome/browser/predictors/autocomplete_action_predictor_unittest.cc
index 009234b..c6ffa7b 100644
--- a/chrome/browser/predictors/autocomplete_action_predictor_unittest.cc
+++ b/chrome/browser/predictors/autocomplete_action_predictor_unittest.cc
@@ -11,7 +11,7 @@
 #include "base/message_loop.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/autocomplete/autocomplete_match.h"
 #include "chrome/browser/history/history_service.h"
 #include "chrome/browser/history/history_service_factory.h"
diff --git a/chrome/browser/predictors/logged_in_predictor_table.h b/chrome/browser/predictors/logged_in_predictor_table.h
index 9cdbd15..30d1495 100644
--- a/chrome/browser/predictors/logged_in_predictor_table.h
+++ b/chrome/browser/predictors/logged_in_predictor_table.h
@@ -8,9 +8,9 @@
 #include <string>
 
 #include "base/containers/hash_tables.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/predictors/predictor_table_base.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 namespace sql {
 class Statement;
diff --git a/chrome/browser/predictors/predictor_database.cc b/chrome/browser/predictors/predictor_database.cc
index 36b713b..a9db8a3 100644
--- a/chrome/browser/predictors/predictor_database.cc
+++ b/chrome/browser/predictors/predictor_database.cc
@@ -72,6 +72,7 @@
       autocomplete_table_(new AutocompleteActionPredictorTable()),
       logged_in_table_(new LoggedInPredictorTable()),
       resource_prefetch_tables_(new ResourcePrefetchPredictorTables()) {
+  db_->set_histogram_tag("Predictor");
   ResourcePrefetchPredictorConfig config;
   is_resource_prefetch_predictor_enabled_ =
       IsSpeculativeResourcePrefetchingEnabled(profile, &config);
diff --git a/chrome/browser/predictors/resource_prefetch_common.h b/chrome/browser/predictors/resource_prefetch_common.h
index ab90972..47243dc 100644
--- a/chrome/browser/predictors/resource_prefetch_common.h
+++ b/chrome/browser/predictors/resource_prefetch_common.h
@@ -5,8 +5,8 @@
 #ifndef CHROME_BROWSER_PREDICTORS_RESOURCE_PREFETCH_COMMON_H_
 #define CHROME_BROWSER_PREDICTORS_RESOURCE_PREFETCH_COMMON_H_
 
-#include "base/time.h"
-#include "googleurl/src/gurl.h"
+#include "base/time/time.h"
+#include "url/gurl.h"
 
 class Profile;
 
diff --git a/chrome/browser/predictors/resource_prefetch_predictor.cc b/chrome/browser/predictors/resource_prefetch_predictor.cc
index 4bce05e..7453009 100644
--- a/chrome/browser/predictors/resource_prefetch_predictor.cc
+++ b/chrome/browser/predictors/resource_prefetch_predictor.cc
@@ -13,7 +13,7 @@
 #include "base/stl_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/history/history_database.h"
 #include "chrome/browser/history/history_db_task.h"
 #include "chrome/browser/history/history_notifications.h"
diff --git a/chrome/browser/predictors/resource_prefetch_predictor.h b/chrome/browser/predictors/resource_prefetch_predictor.h
index fcf54b7..3776241 100644
--- a/chrome/browser/predictors/resource_prefetch_predictor.h
+++ b/chrome/browser/predictors/resource_prefetch_predictor.h
@@ -13,7 +13,7 @@
 #include "base/memory/linked_ptr.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/common/cancelable_request.h"
 #include "chrome/browser/history/history_types.h"
 #include "chrome/browser/predictors/resource_prefetch_common.h"
@@ -22,7 +22,7 @@
 #include "components/browser_context_keyed_service/browser_context_keyed_service.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 #include "webkit/glue/resource_type.h"
 
 class PredictorsHandler;
diff --git a/chrome/browser/predictors/resource_prefetch_predictor_tables.h b/chrome/browser/predictors/resource_prefetch_predictor_tables.h
index 9e7e18a..f8a965e 100644
--- a/chrome/browser/predictors/resource_prefetch_predictor_tables.h
+++ b/chrome/browser/predictors/resource_prefetch_predictor_tables.h
@@ -10,10 +10,10 @@
 #include <string>
 #include <vector>
 
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/predictors/predictor_table_base.h"
 #include "chrome/browser/predictors/resource_prefetch_common.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 #include "webkit/glue/resource_type.h"
 
 namespace sql {
diff --git a/chrome/browser/predictors/resource_prefetch_predictor_unittest.cc b/chrome/browser/predictors/resource_prefetch_predictor_unittest.cc
index d438964..0221767 100644
--- a/chrome/browser/predictors/resource_prefetch_predictor_unittest.cc
+++ b/chrome/browser/predictors/resource_prefetch_predictor_unittest.cc
@@ -7,7 +7,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/message_loop.h"
 #include "base/run_loop.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/history/history_service.h"
 #include "chrome/browser/history/history_service_factory.h"
 #include "chrome/browser/history/history_types.h"
diff --git a/chrome/browser/predictors/resource_prefetcher.h b/chrome/browser/predictors/resource_prefetcher.h
index 81e9481..bd77808 100644
--- a/chrome/browser/predictors/resource_prefetcher.h
+++ b/chrome/browser/predictors/resource_prefetcher.h
@@ -5,8 +5,8 @@
 #ifndef CHROME_BROWSER_PREDICTORS_RESOURCE_PREFETCHER_H_
 #define CHROME_BROWSER_PREDICTORS_RESOURCE_PREFETCHER_H_
 
-#include <map>
 #include <list>
+#include <map>
 #include <vector>
 
 #include "base/gtest_prod_util.h"
@@ -14,8 +14,8 @@
 #include "base/memory/scoped_vector.h"
 #include "base/threading/non_thread_safe.h"
 #include "chrome/browser/predictors/resource_prefetch_common.h"
-#include "googleurl/src/gurl.h"
 #include "net/url_request/url_request.h"
+#include "url/gurl.h"
 
 namespace net {
 class URLRequestContext;
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index 82199f4..d70c205 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -33,7 +33,6 @@
 #include "chrome/browser/gpu/gl_string_manager.h"
 #include "chrome/browser/gpu/gpu_mode_manager.h"
 #include "chrome/browser/intranet_redirect_detector.h"
-#include "chrome/browser/invalidation/invalidator_storage.h"
 #include "chrome/browser/io_thread.h"
 #include "chrome/browser/media/media_capture_devices_dispatcher.h"
 #include "chrome/browser/media/media_stream_devices_controller.h"
@@ -77,6 +76,7 @@
 #include "chrome/browser/ui/search_engines/keyword_editor_controller.h"
 #include "chrome/browser/ui/startup/autolaunch_prompt.h"
 #include "chrome/browser/ui/startup/default_browser_prompt.h"
+#include "chrome/browser/ui/sync/sync_promo_ui.h"
 #include "chrome/browser/ui/tabs/pinned_tab_codec.h"
 #include "chrome/browser/ui/webui/extensions/extension_settings_handler.h"
 #include "chrome/browser/ui/webui/flags_ui.h"
@@ -84,13 +84,12 @@
 #include "chrome/browser/ui/webui/ntp/new_tab_ui.h"
 #include "chrome/browser/ui/webui/plugins_ui.h"
 #include "chrome/browser/ui/webui/print_preview/sticky_settings.h"
-#include "chrome/browser/ui/webui/sync_promo/sync_promo_ui.h"
 #include "chrome/browser/ui/window_snapshot/window_snapshot.h"
 #include "chrome/browser/upgrade_detector.h"
 #include "chrome/browser/web_resource/promo_resource_service.h"
 #include "chrome/common/metrics/entropy_provider.h"
 #include "chrome/common/pref_names.h"
-#include "components/autofill/browser/autofill_manager.h"
+#include "components/autofill/core/browser/autofill_manager.h"
 #include "components/user_prefs/pref_registry_syncable.h"
 #include "content/public/browser/render_process_host.h"
 
@@ -284,6 +283,7 @@
   TRACE_EVENT0("browser", "chrome::RegisterUserPrefs");
   // User prefs. Please keep this list alphabetized.
   AlternateErrorPageTabObserver::RegisterUserPrefs(registry);
+  apps::RegisterUserPrefs(registry);
   autofill::AutofillDialogControllerImpl::RegisterUserPrefs(registry);
   autofill::AutofillManager::RegisterUserPrefs(registry);
   BookmarkPromptPrefs::RegisterUserPrefs(registry);
@@ -302,7 +302,6 @@
   HostContentSettingsMap::RegisterUserPrefs(registry);
   IncognitoModePrefs::RegisterUserPrefs(registry);
   InstantUI::RegisterUserPrefs(registry);
-  invalidation::InvalidatorStorage::RegisterUserPrefs(registry);
   MediaCaptureDevicesDispatcher::RegisterUserPrefs(registry);
   MediaStreamDevicesController::RegisterUserPrefs(registry);
   NetPrefObserver::RegisterUserPrefs(registry);
diff --git a/chrome/browser/prefs/command_line_pref_store.cc b/chrome/browser/prefs/command_line_pref_store.cc
index 9638dea..8e20f13 100644
--- a/chrome/browser/prefs/command_line_pref_store.cc
+++ b/chrome/browser/prefs/command_line_pref_store.cc
@@ -76,6 +76,7 @@
           prefs::kDisableCloudPolicyOnSignin, true },
       { switches::kDisableAsyncDns, prefs::kBuiltInDnsClientEnabled, false },
       { switches::kEnableAsyncDns, prefs::kBuiltInDnsClientEnabled, true },
+      { switches::kEnableSyncFavicons, prefs::kSyncFaviconsEnabled, false },
 };
 
 const CommandLinePrefStore::IntegerSwitchToPreferenceMapEntry
diff --git a/chrome/browser/prefs/pref_model_associator.cc b/chrome/browser/prefs/pref_model_associator.cc
index c49f10c..07792cb 100644
--- a/chrome/browser/prefs/pref_model_associator.cc
+++ b/chrome/browser/prefs/pref_model_associator.cc
@@ -348,8 +348,9 @@
     const syncer::SyncChangeList& change_list) {
   if (!models_associated_) {
     syncer::SyncError error(FROM_HERE,
-                    "Models not yet associated.",
-                    PREFERENCES);
+                            syncer::SyncError::DATATYPE_ERROR,
+                            "Models not yet associated.",
+                            PREFERENCES);
     return error;
   }
   base::AutoReset<bool> processing_changes(&processing_syncer_changes_, true);
diff --git a/chrome/browser/prefs/scoped_user_pref_update.h b/chrome/browser/prefs/scoped_user_pref_update.h
index 24942f1..e83595b 100644
--- a/chrome/browser/prefs/scoped_user_pref_update.h
+++ b/chrome/browser/prefs/scoped_user_pref_update.h
@@ -98,8 +98,10 @@
   DISALLOW_COPY_AND_ASSIGN(ScopedUserPrefUpdate);
 };
 
-typedef ScopedUserPrefUpdate<base::DictionaryValue, Value::TYPE_DICTIONARY>
+typedef ScopedUserPrefUpdate<base::DictionaryValue,
+                             base::Value::TYPE_DICTIONARY>
     DictionaryPrefUpdate;
-typedef ScopedUserPrefUpdate<base::ListValue, Value::TYPE_LIST> ListPrefUpdate;
+typedef ScopedUserPrefUpdate<base::ListValue, base::Value::TYPE_LIST>
+    ListPrefUpdate;
 
 #endif  // CHROME_BROWSER_PREFS_SCOPED_USER_PREF_UPDATE_H_
diff --git a/chrome/browser/prefs/session_startup_pref.h b/chrome/browser/prefs/session_startup_pref.h
index a31380f..379451e 100644
--- a/chrome/browser/prefs/session_startup_pref.h
+++ b/chrome/browser/prefs/session_startup_pref.h
@@ -7,7 +7,7 @@
 
 #include <vector>
 
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 class PrefService;
 class Profile;
diff --git a/chrome/browser/prerender/prerender_browsertest.cc b/chrome/browser/prerender/prerender_browsertest.cc
index a91f33f..47117f1 100644
--- a/chrome/browser/prerender/prerender_browsertest.cc
+++ b/chrome/browser/prerender/prerender_browsertest.cc
@@ -54,7 +54,6 @@
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/test_navigation_observer.h"
 #include "content/public/test/test_utils.h"
-#include "googleurl/src/gurl.h"
 #include "grit/generated_resources.h"
 #include "net/dns/mock_host_resolver.h"
 #include "net/url_request/url_request_context.h"
@@ -62,6 +61,7 @@
 #include "net/url_request/url_request_filter.h"
 #include "net/url_request/url_request_job.h"
 #include "ui/base/l10n/l10n_util.h"
+#include "url/gurl.h"
 
 using content::BrowserThread;
 using content::DevToolsAgentHost;
@@ -1884,7 +1884,7 @@
 // See crbug.com/131836.
 IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest, DISABLED_PrerenderTaskManager) {
   // Show the task manager. This populates the model.
-  chrome::OpenTaskManager(current_browser(), false);
+  chrome::OpenTaskManager(current_browser());
   // Wait for the model of task manager to start.
   TaskManagerBrowserTestUtil::WaitForWebResourceChange(1);
 
@@ -2737,11 +2737,6 @@
 class PrerenderBrowserTestWithExtensions : public PrerenderBrowserTest,
                                            public ExtensionApiTest {
  public:
-  PrerenderBrowserTestWithExtensions() {
-    autostart_test_server_ = false;
-  }
-  virtual ~PrerenderBrowserTestWithExtensions() {}
-
   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
     PrerenderBrowserTest::SetUpCommandLine(command_line);
     ExtensionApiTest::SetUpCommandLine(command_line);
@@ -2765,7 +2760,7 @@
 // http://crbug.com/177163
 IN_PROC_BROWSER_TEST_F(PrerenderBrowserTestWithExtensions,
                        DISABLED_WebNavigation) {
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
   extensions::FrameNavigationState::set_allow_extension_scheme(true);
 
   CommandLine::ForCurrentProcess()->AppendSwitch(
@@ -2796,7 +2791,7 @@
 #define MAYBE_TabsApi TabsApi
 #endif  // defined(OS_WIN)
 IN_PROC_BROWSER_TEST_F(PrerenderBrowserTestWithExtensions, MAYBE_TabsApi) {
-  ASSERT_TRUE(StartTestServer());
+  ASSERT_TRUE(StartEmbeddedTestServer());
   extensions::FrameNavigationState::set_allow_extension_scheme(true);
 
   // Wait for the extension to set itself up and return control to us.
diff --git a/chrome/browser/prerender/prerender_config.h b/chrome/browser/prerender/prerender_config.h
index f31d62d..11729a1 100644
--- a/chrome/browser/prerender/prerender_config.h
+++ b/chrome/browser/prerender/prerender_config.h
@@ -7,7 +7,7 @@
 
 #include <string>
 
-#include "base/time.h"
+#include "base/time/time.h"
 #include "ui/gfx/rect.h"
 
 namespace prerender {
diff --git a/chrome/browser/prerender/prerender_contents.h b/chrome/browser/prerender/prerender_contents.h
index 4b3422c..fca0c8f 100644
--- a/chrome/browser/prerender/prerender_contents.h
+++ b/chrome/browser/prerender/prerender_contents.h
@@ -13,7 +13,7 @@
 #include "base/memory/scoped_vector.h"
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "base/values.h"
 #include "chrome/browser/prerender/prerender_final_status.h"
 #include "chrome/browser/prerender/prerender_origin.h"
diff --git a/chrome/browser/prerender/prerender_histograms.h b/chrome/browser/prerender/prerender_histograms.h
index ade1340..5c9a2d8 100644
--- a/chrome/browser/prerender/prerender_histograms.h
+++ b/chrome/browser/prerender/prerender_histograms.h
@@ -7,12 +7,12 @@
 
 #include <string>
 
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/prerender/prerender_contents.h"
 #include "chrome/browser/prerender/prerender_final_status.h"
 #include "chrome/browser/prerender/prerender_local_predictor.h"
 #include "chrome/browser/prerender/prerender_origin.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 namespace prerender {
 
diff --git a/chrome/browser/prerender/prerender_history.h b/chrome/browser/prerender/prerender_history.h
index 31dcbd4..dff22e2 100644
--- a/chrome/browser/prerender/prerender_history.h
+++ b/chrome/browser/prerender/prerender_history.h
@@ -8,10 +8,10 @@
 #include <list>
 
 #include "base/threading/non_thread_safe.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/prerender/prerender_final_status.h"
 #include "chrome/browser/prerender/prerender_origin.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 namespace base {
 class Value;
diff --git a/chrome/browser/prerender/prerender_link_manager.cc b/chrome/browser/prerender/prerender_link_manager.cc
index 14cdc6e..04dcf82 100644
--- a/chrome/browser/prerender/prerender_link_manager.cc
+++ b/chrome/browser/prerender/prerender_link_manager.cc
@@ -19,8 +19,8 @@
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/session_storage_namespace.h"
 #include "content/public/common/referrer.h"
-#include "googleurl/src/gurl.h"
 #include "ui/gfx/size.h"
+#include "url/gurl.h"
 
 using base::TimeDelta;
 using base::TimeTicks;
diff --git a/chrome/browser/prerender/prerender_link_manager.h b/chrome/browser/prerender/prerender_link_manager.h
index b9987d8..59d00c1 100644
--- a/chrome/browser/prerender/prerender_link_manager.h
+++ b/chrome/browser/prerender/prerender_link_manager.h
@@ -9,10 +9,10 @@
 
 #include "base/basictypes.h"
 #include "base/gtest_prod_util.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/prerender/prerender_handle.h"
 #include "components/browser_context_keyed_service/browser_context_keyed_service.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 class Profile;
 
diff --git a/chrome/browser/prerender/prerender_local_predictor.cc b/chrome/browser/prerender/prerender_local_predictor.cc
index 34f1500..93525f6 100644
--- a/chrome/browser/prerender/prerender_local_predictor.cc
+++ b/chrome/browser/prerender/prerender_local_predictor.cc
@@ -14,7 +14,7 @@
 
 #include "base/metrics/field_trial.h"
 #include "base/metrics/histogram.h"
-#include "base/timer.h"
+#include "base/timer/timer.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/history/history_database.h"
 #include "chrome/browser/history/history_db_task.h"
@@ -35,9 +35,9 @@
 #include "content/public/browser/web_contents_view.h"
 #include "content/public/common/page_transition_types.h"
 #include "crypto/secure_hash.h"
-#include "googleurl/src/url_canon.h"
 #include "grit/browser_resources.h"
 #include "ui/base/resource/resource_bundle.h"
+#include "url/url_canon.h"
 
 using content::BrowserThread;
 using content::PageTransition;
diff --git a/chrome/browser/prerender/prerender_local_predictor.h b/chrome/browser/prerender/prerender_local_predictor.h
index 590eeb8..ebd8e03 100644
--- a/chrome/browser/prerender/prerender_local_predictor.h
+++ b/chrome/browser/prerender/prerender_local_predictor.h
@@ -10,10 +10,10 @@
 #include "base/containers/hash_tables.h"
 #include "base/memory/scoped_vector.h"
 #include "base/memory/weak_ptr.h"
-#include "base/timer.h"
+#include "base/timer/timer.h"
 #include "chrome/browser/common/cancelable_request.h"
 #include "chrome/browser/history/visit_database.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 class HistoryService;
 
diff --git a/chrome/browser/prerender/prerender_manager.cc b/chrome/browser/prerender/prerender_manager.cc
index 40fc8e2..b54d8d0 100644
--- a/chrome/browser/prerender/prerender_manager.cc
+++ b/chrome/browser/prerender/prerender_manager.cc
@@ -17,7 +17,7 @@
 #include "base/prefs/pref_service.h"
 #include "base/stl_util.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/common/cancelable_request.h"
@@ -887,7 +887,9 @@
 
 // static
 bool PrerenderManager::DoesURLHaveValidScheme(const GURL& url) {
-  return IsWebURL(url) || url.SchemeIs(extensions::kExtensionScheme);
+  return (IsWebURL(url) ||
+          url.SchemeIs(extensions::kExtensionScheme) ||
+          url.SchemeIs("data"));
 }
 
 DictionaryValue* PrerenderManager::GetAsValue() const {
diff --git a/chrome/browser/prerender/prerender_manager.h b/chrome/browser/prerender/prerender_manager.h
index 9cbba47..67ff3f3 100644
--- a/chrome/browser/prerender/prerender_manager.h
+++ b/chrome/browser/prerender/prerender_manager.h
@@ -17,8 +17,8 @@
 #include "base/memory/scoped_vector.h"
 #include "base/memory/weak_ptr.h"
 #include "base/threading/non_thread_safe.h"
-#include "base/time.h"
-#include "base/timer.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
 #include "chrome/browser/predictors/logged_in_predictor_table.h"
 #include "chrome/browser/prerender/prerender_config.h"
 #include "chrome/browser/prerender/prerender_contents.h"
@@ -27,8 +27,8 @@
 #include "components/browser_context_keyed_service/browser_context_keyed_service.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
-#include "googleurl/src/gurl.h"
 #include "net/cookies/cookie_monster.h"
+#include "url/gurl.h"
 
 class Profile;
 struct ChromeCookieDetails;
diff --git a/chrome/browser/prerender/prerender_manager_factory.cc b/chrome/browser/prerender/prerender_manager_factory.cc
index 08b17ad..4a3d5d8 100644
--- a/chrome/browser/prerender/prerender_manager_factory.cc
+++ b/chrome/browser/prerender/prerender_manager_factory.cc
@@ -4,6 +4,10 @@
 
 #include "chrome/browser/prerender/prerender_manager_factory.h"
 
+#if defined(OS_ANDROID)
+#include "base/android/sys_utils.h"
+#endif
+
 #include "base/debug/trace_event.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/extensions/extension_system_factory.h"
@@ -52,6 +56,11 @@
 BrowserContextKeyedService* PrerenderManagerFactory::BuildServiceInstanceFor(
     content::BrowserContext* profile) const {
   CHECK(g_browser_process->prerender_tracker());
+#if defined(OS_ANDROID)
+  if (base::android::SysUtils::IsLowEndDevice())
+    return NULL;
+#endif
+
   PrerenderManager* prerender_manager = new PrerenderManager(
       static_cast<Profile*>(profile), g_browser_process->prerender_tracker());
 #if defined(OS_CHROMEOS)
diff --git a/chrome/browser/prerender/prerender_message_filter.h b/chrome/browser/prerender/prerender_message_filter.h
index d8ed3bb..0d5eb06 100644
--- a/chrome/browser/prerender/prerender_message_filter.h
+++ b/chrome/browser/prerender/prerender_message_filter.h
@@ -7,7 +7,7 @@
 
 #include "base/compiler_specific.h"
 #include "content/public/browser/browser_message_filter.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 class Profile;
 
diff --git a/chrome/browser/prerender/prerender_tab_helper.cc b/chrome/browser/prerender/prerender_tab_helper.cc
index 50075f0..5203148 100644
--- a/chrome/browser/prerender/prerender_tab_helper.cc
+++ b/chrome/browser/prerender/prerender_tab_helper.cc
@@ -6,7 +6,7 @@
 
 #include "base/metrics/histogram.h"
 #include "base/strings/string_number_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/predictors/logged_in_predictor_table.h"
 #include "chrome/browser/prerender/prerender_histograms.h"
 #include "chrome/browser/prerender/prerender_local_predictor.h"
diff --git a/chrome/browser/prerender/prerender_tab_helper.h b/chrome/browser/prerender/prerender_tab_helper.h
index f20368f..1e889ce 100644
--- a/chrome/browser/prerender/prerender_tab_helper.h
+++ b/chrome/browser/prerender/prerender_tab_helper.h
@@ -7,10 +7,10 @@
 
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/browser/web_contents_user_data.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 namespace predictors {
 class LoggedInPredictorTable;
diff --git a/chrome/browser/prerender/prerender_tracker.h b/chrome/browser/prerender/prerender_tracker.h
index 15bfd2a..81557f3 100644
--- a/chrome/browser/prerender/prerender_tracker.h
+++ b/chrome/browser/prerender/prerender_tracker.h
@@ -15,7 +15,7 @@
 #include "base/threading/non_thread_safe.h"
 #include "chrome/browser/prerender/prerender_contents.h"
 #include "chrome/browser/prerender/prerender_final_status.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 namespace prerender {
 
diff --git a/chrome/browser/prerender/prerender_unittest.cc b/chrome/browser/prerender/prerender_unittest.cc
index aeed782..5b60f9d 100644
--- a/chrome/browser/prerender/prerender_unittest.cc
+++ b/chrome/browser/prerender/prerender_unittest.cc
@@ -7,7 +7,7 @@
 #include "base/memory/scoped_vector.h"
 #include "base/message_loop.h"
 #include "base/strings/stringprintf.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/prerender/prerender_contents.h"
 #include "chrome/browser/prerender/prerender_handle.h"
 #include "chrome/browser/prerender/prerender_link_manager.h"
@@ -18,9 +18,9 @@
 #include "chrome/test/base/testing_profile.h"
 #include "content/public/browser/render_view_host.h"
 #include "content/public/test/test_browser_thread.h"
-#include "googleurl/src/gurl.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/gfx/size.h"
+#include "url/gurl.h"
 
 using base::Time;
 using base::TimeDelta;
diff --git a/chrome/browser/prerender/prerender_util.cc b/chrome/browser/prerender/prerender_util.cc
index 6a4dc49..ca25418 100644
--- a/chrome/browser/prerender/prerender_util.cc
+++ b/chrome/browser/prerender/prerender_util.cc
@@ -5,14 +5,14 @@
 #include "chrome/browser/prerender/prerender_util.h"
 
 #include "base/logging.h"
-#include "base/metrics/histogram.h"
+#include "base/metrics/sparse_histogram.h"
 #include "base/strings/string_util.h"
 #include "content/public/browser/resource_request_info.h"
-#include "googleurl/src/url_canon.h"
-#include "googleurl/src/url_parse.h"
-#include "googleurl/src/url_util.h"
 #include "net/http/http_response_headers.h"
 #include "net/url_request/url_request.h"
+#include "url/url_canon.h"
+#include "url/url_parse.h"
+#include "url/url_util.h"
 
 namespace prerender {
 
@@ -101,10 +101,10 @@
   // Gather histogram information about the X-Mod-Pagespeed header.
   if (info->GetResourceType() == ResourceType::MAIN_FRAME &&
       IsWebURL(request->url())) {
-    UMA_HISTOGRAM_ENUMERATION(kModPagespeedHistogram, 0, 101);
+    UMA_HISTOGRAM_SPARSE_SLOWLY(kModPagespeedHistogram, 0);
     if (request->response_headers() &&
         request->response_headers()->HasHeader(kModPagespeedHeader)) {
-      UMA_HISTOGRAM_ENUMERATION(kModPagespeedHistogram, 1, 101);
+      UMA_HISTOGRAM_SPARSE_SLOWLY(kModPagespeedHistogram, 1);
 
       // Attempt to parse the version number, and encode it in buckets
       // 2 through 99. 0 and 1 are used to store all pageviews and
@@ -126,7 +126,7 @@
             output++;
           if (output < 2 || output >= 99)
             output = 99;
-          UMA_HISTOGRAM_ENUMERATION(kModPagespeedHistogram, output, 101);
+          UMA_HISTOGRAM_SPARSE_SLOWLY(kModPagespeedHistogram, output);
         }
       }
     }
diff --git a/chrome/browser/prerender/prerender_util.h b/chrome/browser/prerender/prerender_util.h
index 417c951..1c0626e 100644
--- a/chrome/browser/prerender/prerender_util.h
+++ b/chrome/browser/prerender/prerender_util.h
@@ -6,7 +6,7 @@
 #define CHROME_BROWSER_PRERENDER_PRERENDER_UTIL_H_
 
 #include "base/basictypes.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 namespace net {
 class URLRequest;
diff --git a/chrome/browser/printing/OWNERS b/chrome/browser/printing/OWNERS
index f8be0e6..e0b3fde 100644
--- a/chrome/browser/printing/OWNERS
+++ b/chrome/browser/printing/OWNERS
@@ -1,5 +1,4 @@
 abodenha@chromium.org
-dpapad@chromium.org
 gene@chromium.org
 kmadhusu@chromium.org
 scottbyer@chromium.org
diff --git a/chrome/browser/printing/cloud_print/cloud_print_proxy_service.cc b/chrome/browser/printing/cloud_print/cloud_print_proxy_service.cc
index 816f7b5..6e5976e 100644
--- a/chrome/browser/printing/cloud_print/cloud_print_proxy_service.cc
+++ b/chrome/browser/printing/cloud_print/cloud_print_proxy_service.cc
@@ -20,7 +20,6 @@
 #include "chrome/browser/notifications/desktop_notification_service.h"
 #include "chrome/browser/notifications/notification.h"
 #include "chrome/browser/notifications/notification_ui_manager.h"
-#include "chrome/browser/printing/cloud_print/cloud_print_setup_flow.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/service/service_process_control.h"
 #include "chrome/common/chrome_notification_types.h"
@@ -78,15 +77,6 @@
   return false;
 }
 
-void CloudPrintProxyService::EnableForUser(const std::string& lsid,
-                                           const std::string& email) {
-  if (profile_->GetPrefs()->GetBoolean(prefs::kCloudPrintProxyEnabled)) {
-    InvokeServiceTask(
-        base::Bind(&CloudPrintProxyService::EnableCloudPrintProxy,
-                   weak_factory_.GetWeakPtr(), lsid, email));
-  }
-}
-
 void CloudPrintProxyService::EnableForUserWithRobot(
     const std::string& robot_auth_code,
     const std::string& robot_email,
@@ -128,11 +118,6 @@
   return true;
 }
 
-void CloudPrintProxyService::OnCloudPrintSetupClosed() {
-  base::MessageLoop::current()->PostTask(FROM_HERE,
-                                         base::Bind(&chrome::EndKeepAlive));
-}
-
 void CloudPrintProxyService::GetPrintersAvalibleForRegistration(
       std::vector<std::string>* printers) {
   base::FilePath list_path(
@@ -172,15 +157,6 @@
   process_control->GetCloudPrintProxyInfo(callback);
 }
 
-void CloudPrintProxyService::EnableCloudPrintProxy(const std::string& lsid,
-                                                   const std::string& email) {
-  ServiceProcessControl* process_control = GetServiceProcessControl();
-  DCHECK(process_control->IsConnected());
-  process_control->Send(new ServiceMsg_EnableCloudPrintProxy(lsid));
-  // Assume the IPC worked.
-  profile_->GetPrefs()->SetString(prefs::kCloudPrintEmail, email);
-}
-
 void CloudPrintProxyService::EnableCloudPrintProxyWithRobot(
     const std::string& robot_auth_code,
     const std::string& robot_email,
diff --git a/chrome/browser/printing/cloud_print/cloud_print_proxy_service.h b/chrome/browser/printing/cloud_print/cloud_print_proxy_service.h
index 7d8a54a..3426b16 100644
--- a/chrome/browser/printing/cloud_print/cloud_print_proxy_service.h
+++ b/chrome/browser/printing/cloud_print/cloud_print_proxy_service.h
@@ -13,21 +13,22 @@
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
 #include "base/prefs/pref_change_registrar.h"
-#include "chrome/browser/printing/cloud_print/cloud_print_setup_handler.h"
 #include "components/browser_context_keyed_service/browser_context_keyed_service.h"
 
 class Profile;
 class ServiceProcessControl;
 
+namespace base {
+class DictionaryValue;
+}  // namespace base
+
 namespace cloud_print {
 struct CloudPrintProxyInfo;
 }  // namespace cloud_print
 
 // Layer between the browser user interface and the cloud print proxy code
 // running in the service process.
-class CloudPrintProxyService
-    : public CloudPrintSetupHandlerDelegate,
-      public BrowserContextKeyedService {
+class CloudPrintProxyService : public BrowserContextKeyedService {
  public:
   explicit CloudPrintProxyService(Profile* profile);
   virtual ~CloudPrintProxyService();
@@ -37,7 +38,6 @@
   void Initialize();
 
   // Enables/disables cloud printing for the user
-  virtual void EnableForUser(const std::string& lsid, const std::string& email);
   virtual void EnableForUserWithRobot(
       const std::string& robot_auth_code,
       const std::string& robot_email,
@@ -56,9 +56,6 @@
 
   std::string proxy_id() const { return proxy_id_; }
 
-  // CloudPrintSetupHandler::Delegate implementation.
-  virtual void OnCloudPrintSetupClosed() OVERRIDE;
-
   // Returns list of printer names available for registration.
   static void GetPrintersAvalibleForRegistration(
       std::vector<std::string>* printers);
@@ -70,7 +67,6 @@
 
   // Methods that send an IPC to the service.
   void RefreshCloudPrintProxyStatus();
-  void EnableCloudPrintProxy(const std::string& lsid, const std::string& email);
   void EnableCloudPrintProxyWithRobot(
       const std::string& robot_auth_code,
       const std::string& robot_email,
diff --git a/chrome/browser/printing/cloud_print/cloud_print_proxy_service_unittest.cc b/chrome/browser/printing/cloud_print/cloud_print_proxy_service_unittest.cc
index ce27b95..964b0c7 100644
--- a/chrome/browser/printing/cloud_print/cloud_print_proxy_service_unittest.cc
+++ b/chrome/browser/printing/cloud_print/cloud_print_proxy_service_unittest.cc
@@ -136,10 +136,10 @@
 }
 
 void MockServiceProcessControl::SetWillBeEnabledExpectations() {
+  int32 message_id = ServiceMsg_EnableCloudPrintProxyWithRobot::ID;
   EXPECT_CALL(
       *this,
-      Send(Property(&IPC::Message::type,
-                    static_cast<int32>(ServiceMsg_EnableCloudPrintProxy::ID))))
+      Send(Property(&IPC::Message::type, message_id)))
       .Times(1).WillOnce(DoAll(DeleteArg<0>(), Return(true)));
 }
 
@@ -177,6 +177,12 @@
     return &process_control_;
   }
 
+  void EnableForUser() {
+    EnableForUserWithRobot("123", "123@gmail.com",
+                           MockServiceProcessControl::EnabledUserId(),
+                           base::DictionaryValue());
+  }
+
  private:
   MockServiceProcessControl process_control_;
 };
@@ -383,8 +389,7 @@
   EXPECT_EQ(std::string(), prefs->GetString(prefs::kCloudPrintEmail));
 
   service.GetMockServiceProcessControl()->SetWillBeEnabledExpectations();
-  service.EnableForUser(std::string(),
-                        MockServiceProcessControl::EnabledUserId());
+  service.EnableForUser();
 
   EXPECT_EQ(MockServiceProcessControl::EnabledUserId(),
             prefs->GetString(prefs::kCloudPrintEmail));
@@ -407,16 +412,14 @@
   service.Initialize();
 
   EXPECT_EQ(std::string(), prefs->GetString(prefs::kCloudPrintEmail));
-  service.EnableForUser(std::string(),
-                        MockServiceProcessControl::EnabledUserId());
+  service.EnableForUser();
   EXPECT_EQ(std::string(), prefs->GetString(prefs::kCloudPrintEmail));
 
   prefs->RemoveManagedPref(prefs::kCloudPrintProxyEnabled);
   EXPECT_EQ(std::string(), prefs->GetString(prefs::kCloudPrintEmail));
 
   service.GetMockServiceProcessControl()->SetWillBeEnabledExpectations();
-  service.EnableForUser(std::string(),
-                        MockServiceProcessControl::EnabledUserId());
+  service.EnableForUser();
 
   EXPECT_EQ(MockServiceProcessControl::EnabledUserId(),
             prefs->GetString(prefs::kCloudPrintEmail));
diff --git a/chrome/browser/printing/cloud_print/cloud_print_setup_flow.cc b/chrome/browser/printing/cloud_print/cloud_print_setup_flow.cc
deleted file mode 100644
index 780d4cb..0000000
--- a/chrome/browser/printing/cloud_print/cloud_print_setup_flow.cc
+++ /dev/null
@@ -1,343 +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/printing/cloud_print/cloud_print_setup_flow.h"
-
-#include "base/json/json_writer.h"
-#include "base/memory/singleton.h"
-#include "base/prefs/pref_service.h"
-#include "base/strings/string_util.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/values.h"
-#include "chrome/browser/printing/cloud_print/cloud_print_proxy_service.h"
-#include "chrome/browser/printing/cloud_print/cloud_print_proxy_service_factory.h"
-#include "chrome/browser/printing/cloud_print/cloud_print_setup_message_handler.h"
-#include "chrome/browser/printing/cloud_print/cloud_print_setup_source.h"
-#include "chrome/browser/printing/cloud_print/cloud_print_url.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/service/service_process_control.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/browser_dialogs.h"
-#include "chrome/browser/ui/browser_finder.h"
-#include "chrome/browser/ui/browser_window.h"
-#include "chrome/browser/ui/host_desktop.h"
-#include "chrome/common/pref_names.h"
-#include "chrome/common/service_messages.h"
-#include "content/public/browser/render_view_host.h"
-#include "content/public/browser/url_data_source.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/browser/web_ui.h"
-#include "google_apis/gaia/gaia_auth_fetcher.h"
-#include "google_apis/gaia/gaia_constants.h"
-#include "google_apis/gaia/google_service_auth_error.h"
-#include "grit/chromium_strings.h"
-#include "grit/locale_settings.h"
-#include "ui/base/l10n/l10n_font_util.h"
-#include "ui/gfx/font.h"
-
-using content::OpenURLParams;
-using content::Referrer;
-using content::WebContents;
-using content::WebUIMessageHandler;
-
-namespace {
-
-string16 SetupIframeXPath() {
-  return ASCIIToUTF16("//iframe[@id='cloudprintsetup']");
-}
-
-string16 DoneIframeXPath() {
-  return ASCIIToUTF16("//iframe[@id='setupdone']");
-}
-
-}  // end namespace
-
-////////////////////////////////////////////////////////////////////////////////
-// CloudPrintSetupFlow implementation.
-
-// static
-CloudPrintSetupFlow* CloudPrintSetupFlow::OpenDialog(
-    Profile* profile,
-    const base::WeakPtr<Delegate>& delegate,
-    gfx::NativeWindow parent_window) {
-  DCHECK(profile);
-  Browser* browser = chrome::FindLastActiveWithProfile(profile,
-      chrome::GetActiveDesktop());
-  // Set the arguments for showing the gaia login page.
-  DictionaryValue args;
-  args.SetString("user", std::string());
-  args.SetInteger("error", 0);
-  args.SetBoolean("editable_user", true);
-
-  bool setup_done = false;
-  if (profile->GetPrefs()->HasPrefPath(prefs::kCloudPrintEmail) &&
-      !profile->GetPrefs()->GetString(prefs::kCloudPrintEmail).empty())
-    setup_done = true;
-  args.SetString("pageToShow", setup_done ? "setupdone" : "cloudprintsetup");
-
-  std::string json_args;
-  base::JSONWriter::Write(&args, &json_args);
-
-  CloudPrintSetupFlow* flow = new CloudPrintSetupFlow(json_args, profile,
-                                                      delegate, setup_done);
-  // We may not always have a browser. This can happen when we are being
-  // invoked in the context of a "token expired" notfication. If we don't have
-  // a brower, use the underlying dialog system to show the dialog without
-  // using a browser.
-  if (!parent_window && browser && browser->window())
-    parent_window = browser->window()->GetNativeWindow();
-  chrome::ShowWebDialog(parent_window, profile, flow);
-  return flow;
-}
-
-CloudPrintSetupFlow::CloudPrintSetupFlow(
-    const std::string& args,
-    Profile* profile,
-    const base::WeakPtr<Delegate>& delegate,
-    bool setup_done)
-    : web_ui_(NULL),
-      dialog_start_args_(args),
-      last_auth_error_(GoogleServiceAuthError::AuthErrorNone()),
-      setup_done_(setup_done),
-      process_control_(NULL),
-      delegate_(delegate) {
-  // TODO(hclam): The data source should be added once.
-  profile_ = profile;
-  content::URLDataSource::Add(profile, new CloudPrintSetupSource());
-}
-
-CloudPrintSetupFlow::~CloudPrintSetupFlow() {
-}
-
-void CloudPrintSetupFlow::Focus() {
-  // TODO(pranavk): implement this method.
-  NOTIMPLEMENTED();
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// ui::WebDialogDelegate implementation.
-GURL CloudPrintSetupFlow::GetDialogContentURL() const {
-  return GURL("chrome://cloudprintsetup/setupflow");
-}
-
-void CloudPrintSetupFlow::GetWebUIMessageHandlers(
-    std::vector<WebUIMessageHandler*>* handlers) const {
-  // Create the message handler only after we are asked, the caller is
-  // responsible for deleting the objects.
-  handlers->push_back(
-      new CloudPrintSetupMessageHandler(
-          const_cast<CloudPrintSetupFlow*>(this)));
-}
-
-void CloudPrintSetupFlow::GetDialogSize(gfx::Size* size) const {
-  PrefService* prefs = profile_->GetPrefs();
-  gfx::Font approximate_web_font(
-      prefs->GetString(prefs::kWebKitSansSerifFontFamily),
-      prefs->GetInteger(prefs::kWebKitDefaultFontSize));
-
-  if (setup_done_) {
-    *size = ui::GetLocalizedContentsSizeForFont(
-        IDS_CLOUD_PRINT_SETUP_WIZARD_DONE_WIDTH_CHARS,
-        IDS_CLOUD_PRINT_SETUP_WIZARD_DONE_HEIGHT_LINES,
-        approximate_web_font);
-  } else {
-    *size = ui::GetLocalizedContentsSizeForFont(
-        IDS_CLOUD_PRINT_SETUP_WIZARD_WIDTH_CHARS,
-        IDS_CLOUD_PRINT_SETUP_WIZARD_HEIGHT_LINES,
-        approximate_web_font);
-  }
-
-#if !defined(OS_WIN)
-  // NOTE(scottbyer):The following comment comes from
-  // SyncSetupFlow::GetDialogSize, where this hack was copied from. By starting
-  // off development of the UI on Windows, the hack is seemingly backwards.
-
-  // NOTE(akalin): This is a hack to work around a problem with font height on
-  // windows.  Basically font metrics are incorrectly returned in logical units
-  // instead of pixels on Windows.  Logical units are very commonly 96 DPI
-  // so our localized char/line counts are too small by a factor of 96/72.
-  // So we compensate for this on non-windows platform.
-
-  // TODO(scottbyer): Fix the root cause, kill the hacks.
-  float scale_hack = 96.f/72.f;
-  size->set_width(size->width() * scale_hack);
-  size->set_height(size->height() * scale_hack);
-#endif
-}
-
-// A callback to notify the delegate that the dialog closed.
-void CloudPrintSetupFlow::OnDialogClosed(const std::string& json_retval) {
-  // If we are fetching the token then cancel the request.
-  if (authenticator_.get())
-    authenticator_->CancelRequest();
-
-  if (delegate_.get())
-    delegate_->OnDialogClosed();
-  delete this;
-}
-
-std::string CloudPrintSetupFlow::GetDialogArgs() const {
-  return dialog_start_args_;
-}
-
-void CloudPrintSetupFlow::OnCloseContents(WebContents* source,
-                                          bool* out_close_dialog) {
-}
-
-string16 CloudPrintSetupFlow::GetDialogTitle() const {
-  return l10n_util::GetStringFUTF16(IDS_CLOUD_PRINT_SETUP_DIALOG_TITLE,
-      l10n_util::GetStringUTF16(IDS_GOOGLE_CLOUD_PRINT));
-}
-
-ui::ModalType CloudPrintSetupFlow::GetDialogModalType() const {
-  // We are always modeless.
-  return ui::MODAL_TYPE_NONE;
-}
-
-bool CloudPrintSetupFlow::ShouldShowDialogTitle() const {
-  return true;
-}
-
-bool CloudPrintSetupFlow::HandleContextMenu(
-    const content::ContextMenuParams& params) {
-  return true;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// GaiaAuthConsumer implementation.
-void CloudPrintSetupFlow::OnClientLoginSuccess(
-    const GaiaAuthConsumer::ClientLoginResult& credentials) {
-  // Save the token for the cloud print proxy.
-  lsid_ = credentials.lsid;
-
-  // Show that Gaia login has succeeded.
-  ShowGaiaSuccessAndSettingUp();
-  authenticator_.reset();
-
-  CloudPrintProxyServiceFactory::GetForProfile(profile_)->EnableForUser(
-      credentials.lsid, login_);
-  // TODO(sanjeevr): Should we wait and verify that the enable succeeded?
-  ShowSetupDone();
-}
-
-void CloudPrintSetupFlow::OnClientLoginFailure(
-    const GoogleServiceAuthError& error) {
-  last_auth_error_ = error;
-  ShowGaiaFailed(error);
-  authenticator_.reset();
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// Methods called by CloudPrintSetupMessageHandler
-void CloudPrintSetupFlow::Attach(content::WebUI* web_ui) {
-  web_ui_ = web_ui;
-}
-
-void CloudPrintSetupFlow::OnUserSubmittedAuth(const std::string& user,
-                                              const std::string& password,
-                                              const std::string& captcha,
-                                              const std::string& access_code) {
-  // Save the login name only.
-  login_ = user;
-
-  // Start the authenticator.
-  authenticator_.reset(
-      new GaiaAuthFetcher(this, GaiaConstants::kChromeSource,
-                          profile_->GetRequestContext()));
-
-  if (!access_code.empty()) {
-    authenticator_->StartClientLogin(user, access_code,
-                                     GaiaConstants::kCloudPrintService,
-                                     std::string(), std::string(),
-                                     GaiaAuthFetcher::HostedAccountsAllowed);
-  } else {
-    authenticator_->StartClientLogin(user, password,
-                                     GaiaConstants::kCloudPrintService,
-                                     last_auth_error_.captcha().token, captcha,
-                                     GaiaAuthFetcher::HostedAccountsAllowed);
-  }
-}
-
-void CloudPrintSetupFlow::OnUserClickedLearnMore() {
-  OpenURLParams params(CloudPrintURL::GetCloudPrintLearnMoreURL(),
-                       Referrer(), NEW_FOREGROUND_TAB,
-                       content::PAGE_TRANSITION_LINK, false);
-  web_ui_->GetWebContents()->OpenURL(params);
-}
-
-void CloudPrintSetupFlow::OnUserClickedPrintTestPage() {
-  OpenURLParams params(CloudPrintURL::GetCloudPrintTestPageURL(),
-                       Referrer(), NEW_FOREGROUND_TAB,
-                       content::PAGE_TRANSITION_LINK, false);
-  web_ui_->GetWebContents()->OpenURL(params);
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// Helper methods for showing contents of the Web UI
-void CloudPrintSetupFlow::ShowGaiaLogin(const DictionaryValue& args) {
-  if (web_ui_)
-    web_ui_->CallJavascriptFunction("cloudprint.showSetupLogin");
-
-  std::string json;
-  base::JSONWriter::Write(&args, &json);
-  string16 javascript = UTF8ToUTF16("cloudprint.showGaiaLogin(" + json + ");");
-
-  ExecuteJavascriptInIFrame(SetupIframeXPath(), javascript);
-}
-
-void CloudPrintSetupFlow::ShowGaiaSuccessAndSettingUp() {
-  ExecuteJavascriptInIFrame(
-      SetupIframeXPath(),
-      ASCIIToUTF16("cloudprint.showGaiaSuccessAndSettingUp();"));
-}
-
-void CloudPrintSetupFlow::ShowGaiaFailed(const GoogleServiceAuthError& error) {
-  DictionaryValue args;
-  args.SetString("pageToShow", "cloudprintsetup");
-  args.SetString("user", login_);
-  args.SetInteger("error", error.state());
-  args.SetBoolean("editable_user", true);
-  args.SetString("captchaUrl", error.captcha().image_url.spec());
-  ShowGaiaLogin(args);
-}
-
-void CloudPrintSetupFlow::ShowSetupDone() {
-  setup_done_ = true;
-  string16 product_name = l10n_util::GetStringUTF16(IDS_PRODUCT_NAME);
-  string16 message = l10n_util::GetStringFUTF16(IDS_CLOUD_PRINT_SETUP_DONE,
-                                                product_name,
-                                                UTF8ToUTF16(login_));
-  string16 javascript(ASCIIToUTF16("cloudprint.setMessage('") + message +
-                      ASCIIToUTF16("');"));
-  ExecuteJavascriptInIFrame(DoneIframeXPath(), javascript);
-
-  if (web_ui_) {
-    PrefService* prefs = profile_->GetPrefs();
-    gfx::Font approximate_web_font(
-        prefs->GetString(prefs::kWebKitSansSerifFontFamily),
-        prefs->GetInteger(prefs::kWebKitDefaultFontSize));
-    gfx::Size done_size = ui::GetLocalizedContentsSizeForFont(
-        IDS_CLOUD_PRINT_SETUP_WIZARD_DONE_WIDTH_CHARS,
-        IDS_CLOUD_PRINT_SETUP_WIZARD_DONE_HEIGHT_LINES,
-        approximate_web_font);
-
-    base::FundamentalValue new_width(done_size.width());
-    base::FundamentalValue new_height(done_size.height());
-    web_ui_->CallJavascriptFunction("cloudprint.showSetupDone",
-                                    new_width, new_height);
-  }
-
-  ExecuteJavascriptInIFrame(DoneIframeXPath(),
-                            ASCIIToUTF16("cloudprint.onPageShown();"));
-}
-
-void CloudPrintSetupFlow::ExecuteJavascriptInIFrame(
-    const string16& iframe_xpath,
-    const string16& js) {
-  if (web_ui_) {
-    content::RenderViewHost* rvh =
-        web_ui_->GetWebContents()->GetRenderViewHost();
-    rvh->ExecuteJavascriptInWebFrame(iframe_xpath, js);
-  }
-}
diff --git a/chrome/browser/printing/cloud_print/cloud_print_setup_flow.h b/chrome/browser/printing/cloud_print/cloud_print_setup_flow.h
deleted file mode 100644
index abaaf9f..0000000
--- a/chrome/browser/printing/cloud_print/cloud_print_setup_flow.h
+++ /dev/null
@@ -1,156 +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_PRINTING_CLOUD_PRINT_CLOUD_PRINT_SETUP_FLOW_H_
-#define CHROME_BROWSER_PRINTING_CLOUD_PRINT_CLOUD_PRINT_SETUP_FLOW_H_
-
-#include <string>
-#include <vector>
-
-#include "base/memory/weak_ptr.h"
-#include "google_apis/gaia/gaia_auth_consumer.h"
-#include "google_apis/gaia/gaia_auth_fetcher.h"
-#include "google_apis/gaia/google_service_auth_error.h"
-#include "grit/generated_resources.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "ui/gfx/native_widget_types.h"
-#include "ui/web_dialogs/web_dialog_delegate.h"
-
-class CloudPrintServiceProcessHelper;
-class CloudPrintSetupMessageHandler;
-class GaiaAuthFetcher;
-class GoogleServiceAuthError;
-class Profile;
-class ServiceProcessControl;
-
-namespace base {
-class DictionaryValue;
-}
-
-namespace content {
-class WebUI;
-}
-
-// This class is responsible for showing a cloud print setup dialog
-// and perform operations to fill the content of the dialog and handle
-// user actions in the dialog.
-//
-// It is responsible for:
-// 1. Showing the setup dialog.
-// 2. Providing the URL for the content of the dialog.
-// 3. Providing a data source to provide the content HTML files.
-// 4. Providing a message handler to handle user actions in the Web UI.
-// 5. Responding to actions received in the message handler.
-//
-// The architecture for WebUI is designed such that only the message handler
-// can access the WebUI. This splits the flow control across the message
-// handler and this class. In order to centralize all the flow control and
-// content in the WebUI, the WebUI object is given to this object by the
-// message handler through the Attach(WebUI*) method.
-class CloudPrintSetupFlow : public ui::WebDialogDelegate,
-                            public GaiaAuthConsumer {
- public:
-  class Delegate {
-   public:
-    virtual ~Delegate() {}
-    // Called when the setup dialog is closed.
-    virtual void OnDialogClosed() = 0;
-  };
-  virtual ~CloudPrintSetupFlow();
-
-  // Runs a flow from |start| to |end|, and does the work of actually showing
-  // the HTML dialog.  |container| is kept up-to-date with the lifetime of the
-  // flow (e.g it is emptied on dialog close).
-  static CloudPrintSetupFlow* OpenDialog(
-      Profile* service,
-      const base::WeakPtr<Delegate>& delegate,
-      gfx::NativeWindow parent_window);
-
-  // Focuses the dialog.  This is useful in cases where the dialog has been
-  // obscured by a browser window.
-  void Focus();
-
-  // ui::WebDialogDelegate implementation.
-  virtual GURL GetDialogContentURL() const OVERRIDE;
-  virtual void GetWebUIMessageHandlers(
-      std::vector<content::WebUIMessageHandler*>* handlers) const OVERRIDE;
-  virtual void GetDialogSize(gfx::Size* size) const OVERRIDE;
-  virtual std::string GetDialogArgs() const OVERRIDE;
-  virtual void OnDialogClosed(const std::string& json_retval) OVERRIDE;
-  virtual void OnCloseContents(content::WebContents* source,
-                               bool* out_close_dialog) OVERRIDE;
-  virtual string16 GetDialogTitle() const OVERRIDE;
-  virtual ui::ModalType GetDialogModalType() const OVERRIDE;
-  virtual bool ShouldShowDialogTitle() const OVERRIDE;
-  virtual bool HandleContextMenu(
-      const content::ContextMenuParams& params) OVERRIDE;
-
-  // GaiaAuthConsumer implementation.
-  virtual void OnClientLoginSuccess(
-      const GaiaAuthConsumer::ClientLoginResult& credentials) OVERRIDE;
-  virtual void OnClientLoginFailure(
-      const GoogleServiceAuthError& error) OVERRIDE;
-
- private:
-  friend class CloudPrintServiceProcessHelper;
-  friend class CloudPrintSetupMessageHandler;
-
-  // Use static Run method to get an instance.
-  CloudPrintSetupFlow(const std::string& args,
-                      Profile* profile,
-                      const base::WeakPtr<Delegate>& delegate, bool setup_done);
-
-  // Called CloudPrintSetupMessageHandler when a DOM is attached. This method
-  // is called when the HTML page is fully loaded. We then operate on this
-  // WebUI object directly.
-  void Attach(content::WebUI* web_ui);
-
-  // Called by CloudPrintSetupMessageHandler when user authentication is
-  // registered.
-  void OnUserSubmittedAuth(const std::string& user,
-                           const std::string& password,
-                           const std::string& captcha,
-                           const std::string& access_code);
-
-  // Called by CloudPrintSetupMessageHandler when the user clicks on various
-  // pieces of UI during setup.
-  void OnUserClickedLearnMore();
-  void OnUserClickedPrintTestPage();
-
-  // The following methods control which iframe is visible.
-  void ShowGaiaLogin(const base::DictionaryValue& args);
-  void ShowGaiaSuccessAndSettingUp();
-  void ShowGaiaFailed(const GoogleServiceAuthError& error);
-  void ShowSetupDone();
-  void ExecuteJavascriptInIFrame(const string16& iframe_xpath,
-                                 const string16& js);
-
-  // Pointer to the Web UI. This is provided by CloudPrintSetupMessageHandler
-  // when attached. We do not own the pointer, instead WebUI owns its delegate
-  // (us) and controls our lifetime.
-  content::WebUI* web_ui_;
-
-  // The args to pass to the initial page.
-  std::string dialog_start_args_;
-  Profile* profile_;
-
-  // Fetcher to obtain the Cloud Print token.
-  scoped_ptr<GaiaAuthFetcher> authenticator_;
-  std::string login_;
-  std::string lsid_;
-
-  // The last captcha or error state encountered.
-  GoogleServiceAuthError last_auth_error_;
-
-  // Are we in the done state?
-  bool setup_done_;
-
-  // Handle to the ServiceProcessControl which talks to the service process.
-  ServiceProcessControl* process_control_;
-  base::WeakPtr<Delegate> delegate_;
-
-  DISALLOW_COPY_AND_ASSIGN(CloudPrintSetupFlow);
-};
-
-#endif  // CHROME_BROWSER_PRINTING_CLOUD_PRINT_CLOUD_PRINT_SETUP_FLOW_H_
diff --git a/chrome/browser/printing/cloud_print/cloud_print_setup_handler.cc b/chrome/browser/printing/cloud_print/cloud_print_setup_handler.cc
deleted file mode 100644
index f0a0cba..0000000
--- a/chrome/browser/printing/cloud_print/cloud_print_setup_handler.cc
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/printing/cloud_print/cloud_print_setup_handler.h"
-
-CloudPrintSetupHandler::CloudPrintSetupHandler(Delegate* handler)
-    : handler_(handler) {}
-
-CloudPrintSetupHandler::~CloudPrintSetupHandler() {}
-
-void CloudPrintSetupHandler::OnDialogClosed() {
-  DCHECK(handler_);
-  handler_->OnCloudPrintSetupClosed();
-}
diff --git a/chrome/browser/printing/cloud_print/cloud_print_setup_handler.h b/chrome/browser/printing/cloud_print/cloud_print_setup_handler.h
deleted file mode 100644
index eeab734..0000000
--- a/chrome/browser/printing/cloud_print/cloud_print_setup_handler.h
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_PRINTING_CLOUD_PRINT_CLOUD_PRINT_SETUP_HANDLER_H_
-#define CHROME_BROWSER_PRINTING_CLOUD_PRINT_CLOUD_PRINT_SETUP_HANDLER_H_
-
-#include "base/memory/weak_ptr.h"
-#include "chrome/browser/printing/cloud_print/cloud_print_setup_flow.h"
-
-// Cloud Print setup handler.
-// Provides a weak pointer adapter so that callers of
-// CloudPrintSetupFlow::OpenDialog can still be notified when the dialog
-// completes, but don't have to stick around until the end. Lifetime should be
-// shorter than that of its owner.
-class CloudPrintSetupHandler
-    : public CloudPrintSetupFlow::Delegate,
-      public base::SupportsWeakPtr<CloudPrintSetupHandler> {
- public:
-  class Delegate {
-   public:
-    virtual ~Delegate() {}
-    // Called when the setup dialog is closed.
-    virtual void OnCloudPrintSetupClosed() = 0;
-  };
-
-  explicit CloudPrintSetupHandler(Delegate* handler);
-  virtual ~CloudPrintSetupHandler();
-
-  // CloudPrintSetupFlow::Delegate implementation.
-  virtual void OnDialogClosed() OVERRIDE;
-
- private:
-  Delegate* handler_;
-
-  DISALLOW_COPY_AND_ASSIGN(CloudPrintSetupHandler);
-};
-
-// Workaround for MSVC 2005 not handling inheritance from nested classes well.
-typedef CloudPrintSetupHandler::Delegate CloudPrintSetupHandlerDelegate;
-
-#endif  // CHROME_BROWSER_PRINTING_CLOUD_PRINT_CLOUD_PRINT_SETUP_HANDLER_H_
diff --git a/chrome/browser/printing/cloud_print/cloud_print_setup_message_handler.cc b/chrome/browser/printing/cloud_print/cloud_print_setup_message_handler.cc
deleted file mode 100644
index fb34458..0000000
--- a/chrome/browser/printing/cloud_print/cloud_print_setup_message_handler.cc
+++ /dev/null
@@ -1,67 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/printing/cloud_print/cloud_print_setup_message_handler.h"
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/json/json_reader.h"
-#include "base/json/json_writer.h"
-#include "base/memory/scoped_ptr.h"
-#include "chrome/browser/printing/cloud_print/cloud_print_setup_flow.h"
-#include "content/public/browser/web_ui.h"
-
-void CloudPrintSetupMessageHandler::RegisterMessages() {
-  // Pass the WebUI object to the setup flow.
-  flow_->Attach(web_ui());
-
-  web_ui()->RegisterMessageCallback("SubmitAuth",
-      base::Bind(&CloudPrintSetupMessageHandler::HandleSubmitAuth,
-                 base::Unretained(this)));
-  web_ui()->RegisterMessageCallback("PrintTestPage",
-      base::Bind(&CloudPrintSetupMessageHandler::HandlePrintTestPage,
-                 base::Unretained(this)));
-  web_ui()->RegisterMessageCallback("LearnMore",
-      base::Bind(&CloudPrintSetupMessageHandler::HandleLearnMore,
-                 base::Unretained(this)));
-}
-
-void CloudPrintSetupMessageHandler::HandleSubmitAuth(const ListValue* args) {
-  std::string json;
-  bool ret = args->GetString(0, &json);
-  std::string username, password, captcha, access_code;
-  if (!ret || json.empty()) {
-    NOTREACHED() << "Empty json string";
-    return;
-  }
-
-  scoped_ptr<Value> parsed_value(base::JSONReader::Read(json));
-  if (!parsed_value.get() || !parsed_value->IsType(Value::TYPE_DICTIONARY)) {
-    NOTREACHED() << "Unable to parse auth data";
-    return;
-  }
-
-  DictionaryValue* result = static_cast<DictionaryValue*>(parsed_value.get());
-  if (!result->GetString("user", &username) ||
-      !result->GetString("pass", &password) ||
-      !result->GetString("captcha", &captcha) ||
-      !result->GetString("access_code", &access_code)) {
-    NOTREACHED() << "Unable to parse auth data";
-    return;
-  }
-
-  // Pass the information to the flow.
-  if (flow_)
-    flow_->OnUserSubmittedAuth(username, password, captcha, access_code);
-}
-
-void CloudPrintSetupMessageHandler::HandlePrintTestPage(const ListValue* args) {
-  if (flow_)
-    flow_->OnUserClickedPrintTestPage();
-}
-
-void CloudPrintSetupMessageHandler::HandleLearnMore(const ListValue* args) {
-  if (flow_)
-    flow_->OnUserClickedLearnMore();
-}
diff --git a/chrome/browser/printing/cloud_print/cloud_print_setup_message_handler.h b/chrome/browser/printing/cloud_print/cloud_print_setup_message_handler.h
deleted file mode 100644
index 05ff5c2..0000000
--- a/chrome/browser/printing/cloud_print/cloud_print_setup_message_handler.h
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_PRINTING_CLOUD_PRINT_CLOUD_PRINT_SETUP_MESSAGE_HANDLER_H_
-#define CHROME_BROWSER_PRINTING_CLOUD_PRINT_CLOUD_PRINT_SETUP_MESSAGE_HANDLER_H_
-
-#include <string>
-
-#include "base/values.h"
-#include "content/public/browser/web_ui_message_handler.h"
-
-class CloudPrintSetupFlow;
-
-// This class is used to handle DOM messages from the setup dialog.
-class CloudPrintSetupMessageHandler : public content::WebUIMessageHandler {
- public:
-  explicit CloudPrintSetupMessageHandler(CloudPrintSetupFlow* flow)
-    : flow_(flow) {}
-  virtual ~CloudPrintSetupMessageHandler() {}
-
- protected:
-  // WebUIMessageHandler implementation.
-  virtual void RegisterMessages() OVERRIDE;
-
-  // Callbacks from the page.
-  void HandleSubmitAuth(const ListValue* args);
-  void HandlePrintTestPage(const ListValue* args);
-  void HandleLearnMore(const ListValue* args);
-
- private:
-  CloudPrintSetupFlow* flow_;
-
-  DISALLOW_COPY_AND_ASSIGN(CloudPrintSetupMessageHandler);
-};
-
-#endif  // CHROME_BROWSER_PRINTING_CLOUD_PRINT_CLOUD_PRINT_SETUP_MESSAGE_HANDLER_H_
diff --git a/chrome/browser/printing/cloud_print/cloud_print_setup_source.cc b/chrome/browser/printing/cloud_print/cloud_print_setup_source.cc
deleted file mode 100644
index d098e61..0000000
--- a/chrome/browser/printing/cloud_print/cloud_print_setup_source.cc
+++ /dev/null
@@ -1,152 +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/printing/cloud_print/cloud_print_setup_source.h"
-
-#include "base/memory/ref_counted_memory.h"
-#include "base/message_loop.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/values.h"
-#include "chrome/browser/google/google_util.h"
-#include "chrome/common/url_constants.h"
-#include "googleurl/src/gurl.h"
-#include "grit/browser_resources.h"
-#include "grit/chromium_strings.h"
-#include "grit/generated_resources.h"
-#include "grit/locale_settings.h"
-#include "grit/ui_resources.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "ui/base/resource/resource_bundle.h"
-#include "ui/webui/jstemplate_builder.h"
-#include "ui/webui/web_ui_util.h"
-
-// Define the values of standard URLs.
-const char CloudPrintSetupSource::kInvalidPasswordHelpUrl[] =
-  "https://www.google.com/support/accounts/bin/answer.py?ctx=ch&answer=27444";
-const char CloudPrintSetupSource::kCanNotAccessAccountUrl[] =
-  "https://www.google.com/support/accounts/bin/answer.py?answer=48598";
-const char CloudPrintSetupSource::kCreateNewAccountUrl[] =
-  "https://accounts.google.com/NewAccount?service=chromiumsync";
-
-namespace {
-
-// Utility method to keep dictionary population code streamlined.
-void AddString(DictionaryValue* dictionary,
-               const std::string& key,
-               int resource_id) {
-  dictionary->SetString(key, l10n_util::GetStringUTF16(resource_id));
-}
-
-}  // namespace
-
-CloudPrintSetupSource::CloudPrintSetupSource() {
-}
-
-std::string CloudPrintSetupSource::GetSource() const {
-  return chrome::kChromeUICloudPrintSetupHost;
-}
-
-void CloudPrintSetupSource::StartDataRequest(
-    const std::string& path_raw,
-    int render_process_id,
-    int render_view_id,
-    const content::URLDataSource::GotDataCallback& callback) {
-  const char kCloudPrintSetupPath[] = "cloudprintsetup";
-  const char kCloudPrintGaiaLoginPath[] = "gaialogin";
-  const char kCloudPrintSetupFlowPath[] = "setupflow";
-  const char kCloudPrintSetupDonePath[] = "setupdone";
-
-  DictionaryValue localized_strings;
-  DictionaryValue* dict = &localized_strings;
-
-  std::string response;
-  if (path_raw == kCloudPrintSetupPath) {
-    dict->SetString("header",
-        l10n_util::GetStringFUTF16(IDS_CLOUD_PRINT_SETUP_HEADER,
-        l10n_util::GetStringUTF16(IDS_GOOGLE_CLOUD_PRINT)));
-    AddString(dict, "explain", IDS_CLOUD_PRINT_SETUP_EXPLAIN);
-    AddString(dict, "anywhereheader", IDS_CLOUD_PRINT_SETUP_ANYWHERE_HEADER);
-    AddString(dict, "anywhereexplain", IDS_CLOUD_PRINT_SETUP_ANYWHERE_EXPLAIN);
-    AddString(dict, "printerheader", IDS_CLOUD_PRINT_SETUP_PRINTER_HEADER);
-    AddString(dict, "printerexplain", IDS_CLOUD_PRINT_SETUP_PRINTER_EXPLAIN);
-    AddString(dict, "sharingheader", IDS_CLOUD_PRINT_SETUP_SHARING_HEADER);
-    AddString(dict, "sharingexplain", IDS_CLOUD_PRINT_SETUP_SHARING_EXPLAIN);
-
-    static const base::StringPiece html(ResourceBundle::GetSharedInstance()
-        .GetRawDataResource(IDR_CLOUD_PRINT_SETUP_LOGIN_HTML));
-    webui::SetFontAndTextDirection(dict);
-    response = webui::GetI18nTemplateHtml(html, dict);
-  } else if (path_raw == kCloudPrintGaiaLoginPath) {
-    // Start by setting the per-locale URLs we show on the setup wizard.
-    dict->SetString("invalidpasswordhelpurl",
-                   GetLocalizedUrl(kInvalidPasswordHelpUrl));
-    dict->SetString("cannotaccessaccounturl",
-                   GetLocalizedUrl(kCanNotAccessAccountUrl));
-    dict->SetString("createnewaccounturl",
-                   GetLocalizedUrl(kCreateNewAccountUrl));
-
-    // None of the strings used here currently have sync-specific wording in
-    // them.  There is a unit test to catch if that happens.
-    dict->SetString("introduction", std::string());
-    AddString(dict, "signinprefix", IDS_CLOUD_PRINT_LOGIN_SIGNIN_PREFIX);
-    AddString(dict, "signinsuffix", IDS_CLOUD_PRINT_LOGIN_SIGNIN_SUFFIX);
-    AddString(dict, "cannotbeblank", IDS_CLOUD_PRINT_CANNOT_BE_BLANK);
-    AddString(dict, "emaillabel", IDS_CLOUD_PRINT_LOGIN_EMAIL_SAME_LINE);
-    AddString(dict, "passwordlabel", IDS_CLOUD_PRINT_LOGIN_PASSWORD_SAME_LINE);
-    AddString(dict, "invalidcredentials", IDS_SYNC_INVALID_USER_CREDENTIALS);
-    AddString(dict, "signin", IDS_CLOUD_PRINT_SIGNIN);
-    AddString(dict, "couldnotconnect", IDS_CLOUD_PRINT_LOGIN_COULD_NOT_CONNECT);
-    AddString(dict, "cannotaccessaccount",
-              IDS_CLOUD_PRINT_CANNOT_ACCESS_ACCOUNT);
-    AddString(dict, "createaccount", IDS_CLOUD_PRINT_CREATE_ACCOUNT);
-    AddString(dict, "cancel", IDS_CANCEL);
-    AddString(dict, "settingup", IDS_SYNC_LOGIN_SETTING_UP);
-    AddString(dict, "success", IDS_SYNC_SUCCESS);
-    AddString(dict, "errorsigningin", IDS_SYNC_ERROR_SIGNING_IN);
-    AddString(dict, "captchainstructions",
-              IDS_CLOUD_PRINT_GAIA_CAPTCHA_INSTRUCTIONS);
-    AddString(dict, "invalidaccesscode",
-              IDS_CLOUD_PRINT_INVALID_ACCESS_CODE_LABEL);
-    AddString(dict, "enteraccesscode", IDS_CLOUD_PRINT_ENTER_ACCESS_CODE_LABEL);
-    AddString(dict, "getaccesscodehelp",
-              IDS_CLOUD_PRINT_ACCESS_CODE_HELP_LABEL);
-    AddString(dict, "getaccesscodeurl", IDS_CLOUD_PRINT_GET_ACCESS_CODE_URL);
-
-    static const base::StringPiece html(ResourceBundle::GetSharedInstance()
-        .GetRawDataResource(IDR_GAIA_LOGIN_HTML));
-    webui::SetFontAndTextDirection(dict);
-    response = webui::GetI18nTemplateHtml(html, dict);
-  } else if (path_raw == kCloudPrintSetupDonePath) {
-    AddString(dict, "testpage", IDS_CLOUD_PRINT_SETUP_TEST_PAGE);
-    AddString(dict, "success", IDS_SYNC_SUCCESS);
-    AddString(dict, "okay", IDS_CLOUD_PRINT_SETUP_OK_BUTTON_LABEL);
-    static const base::StringPiece html(ResourceBundle::GetSharedInstance()
-        .GetRawDataResource(IDR_CLOUD_PRINT_SETUP_DONE_HTML));
-    webui::SetFontAndTextDirection(dict);
-    response = webui::GetI18nTemplateHtml(html, dict);
-  } else if (path_raw == kCloudPrintSetupFlowPath) {
-    static const base::StringPiece html(
-        ResourceBundle::GetSharedInstance()
-        .GetRawDataResource(IDR_CLOUD_PRINT_SETUP_FLOW_HTML));
-    response = html.as_string();
-  }
-
-  callback.Run(base::RefCountedString::TakeString(&response));
-}
-
-std::string CloudPrintSetupSource::GetMimeType(const std::string& path) const {
-  return "text/html";
-}
-
-bool CloudPrintSetupSource::ShouldAddContentSecurityPolicy() const {
-  return false;
-}
-
-std::string CloudPrintSetupSource::GetLocalizedUrl(
-    const std::string& url) const {
-  GURL original_url(url);
-  DCHECK(original_url.is_valid());
-  GURL localized_url = google_util::AppendGoogleLocaleParam(original_url);
-  return localized_url.spec();
-}
diff --git a/chrome/browser/printing/cloud_print/cloud_print_setup_source.h b/chrome/browser/printing/cloud_print/cloud_print_setup_source.h
deleted file mode 100644
index ebd8e28..0000000
--- a/chrome/browser/printing/cloud_print/cloud_print_setup_source.h
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_PRINTING_CLOUD_PRINT_CLOUD_PRINT_SETUP_SOURCE_H_
-#define CHROME_BROWSER_PRINTING_CLOUD_PRINT_CLOUD_PRINT_SETUP_SOURCE_H_
-
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "content/public/browser/url_data_source.h"
-
-class CloudPrintSetupSource : public content::URLDataSource {
- public:
-  CloudPrintSetupSource();
-
-  // content::URLDataSource implementation.
-  virtual std::string GetSource() const OVERRIDE;
-  virtual void StartDataRequest(
-      const std::string& path,
-      int render_process_id,
-      int render_view_id,
-      const content::URLDataSource::GotDataCallback& callback) OVERRIDE;
-  virtual std::string GetMimeType(const std::string& path) const OVERRIDE;
-  virtual bool ShouldAddContentSecurityPolicy() const OVERRIDE;
-
-  static const char kInvalidPasswordHelpUrl[];
-  static const char kCanNotAccessAccountUrl[];
-  static const char kCreateNewAccountUrl[];
-
- private:
-  virtual ~CloudPrintSetupSource() {}
-
-  // Takes a string containing an URL and returns an URL containing a CGI
-  // parameter of the form "&hl=xy" where 'xy' is the language code of the
-  // current locale.
-  std::string GetLocalizedUrl(const std::string& url) const;
-
-  DISALLOW_COPY_AND_ASSIGN(CloudPrintSetupSource);
-};
-
-#endif  // CHROME_BROWSER_PRINTING_CLOUD_PRINT_CLOUD_PRINT_SETUP_SOURCE_H_
diff --git a/chrome/browser/printing/cloud_print/cloud_print_setup_source_unittest.cc b/chrome/browser/printing/cloud_print/cloud_print_setup_source_unittest.cc
deleted file mode 100644
index 2df7f82..0000000
--- a/chrome/browser/printing/cloud_print/cloud_print_setup_source_unittest.cc
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "grit/chromium_strings.h"
-#include "grit/generated_resources.h"
-#include "grit/locale_settings.h"
-#include "grit/ui_resources.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/base/l10n/l10n_util.h"
-
-using testing::HasSubstr;
-using testing::Not;
-
-void TestStringStillOkForCloudPrint(int resource_id) {
-  std::string resource_string = l10n_util::GetStringUTF8(resource_id);
-  EXPECT_THAT(resource_string, Not(HasSubstr("Sync")));
-  EXPECT_THAT(resource_string, Not(HasSubstr("sync")));
-}
-
-// This set of strings to test was generated from
-// CloudPrintSetupSource::StartDataRequest.  If any of these trip, notify the
-// cloud printing team and we'll split the strings.
-TEST(CloudPrintResources, SharedStringsCheck) {
-  TestStringStillOkForCloudPrint(IDS_CLOUD_PRINT_LOGIN_SIGNIN_PREFIX);
-  TestStringStillOkForCloudPrint(IDS_CLOUD_PRINT_LOGIN_SIGNIN_SUFFIX);
-  TestStringStillOkForCloudPrint(IDS_CLOUD_PRINT_CANNOT_BE_BLANK);
-  TestStringStillOkForCloudPrint(IDS_CLOUD_PRINT_LOGIN_EMAIL_SAME_LINE);
-  TestStringStillOkForCloudPrint(IDS_CLOUD_PRINT_LOGIN_PASSWORD_SAME_LINE);
-  TestStringStillOkForCloudPrint(IDS_SYNC_INVALID_USER_CREDENTIALS);
-  TestStringStillOkForCloudPrint(IDS_CLOUD_PRINT_SIGNIN);
-  TestStringStillOkForCloudPrint(IDS_CLOUD_PRINT_LOGIN_COULD_NOT_CONNECT);
-  TestStringStillOkForCloudPrint(IDS_CLOUD_PRINT_CANNOT_ACCESS_ACCOUNT);
-  TestStringStillOkForCloudPrint(IDS_CLOUD_PRINT_CREATE_ACCOUNT);
-  TestStringStillOkForCloudPrint(IDS_SYNC_LOGIN_SETTING_UP);
-  TestStringStillOkForCloudPrint(IDS_SYNC_SUCCESS);
-  TestStringStillOkForCloudPrint(IDS_SYNC_ERROR_SIGNING_IN);
-  TestStringStillOkForCloudPrint(IDS_CLOUD_PRINT_GAIA_CAPTCHA_INSTRUCTIONS);
-  TestStringStillOkForCloudPrint(IDS_CLOUD_PRINT_INVALID_ACCESS_CODE_LABEL);
-  TestStringStillOkForCloudPrint(IDS_CLOUD_PRINT_ENTER_ACCESS_CODE_LABEL);
-  TestStringStillOkForCloudPrint(IDS_CLOUD_PRINT_ACCESS_CODE_HELP_LABEL);
-  TestStringStillOkForCloudPrint(IDS_CLOUD_PRINT_GET_ACCESS_CODE_URL);
-  TestStringStillOkForCloudPrint(IDS_SYNC_SUCCESS);
-  TestStringStillOkForCloudPrint(IDS_CLOUD_PRINT_SETUP_OK_BUTTON_LABEL);
-}
diff --git a/chrome/browser/printing/cloud_print/cloud_print_url.cc b/chrome/browser/printing/cloud_print/cloud_print_url.cc
index d056316..2e46123 100644
--- a/chrome/browser/printing/cloud_print/cloud_print_url.cc
+++ b/chrome/browser/printing/cloud_print/cloud_print_url.cc
@@ -14,8 +14,8 @@
 #include "chrome/common/pref_names.h"
 #include "components/user_prefs/pref_registry_syncable.h"
 #include "google_apis/gaia/gaia_urls.h"
-#include "googleurl/src/gurl.h"
 #include "net/base/escape.h"
+#include "url/gurl.h"
 
 // Url must not be matched by "urls" section of
 // cloud_print_app/manifest.json. If it's matched, print driver dialog will
diff --git a/chrome/browser/printing/cloud_print/test/cloud_print_proxy_process_browsertest.cc b/chrome/browser/printing/cloud_print/test/cloud_print_proxy_process_browsertest.cc
index 9fdeaa5..d7a18bc 100644
--- a/chrome/browser/printing/cloud_print/test/cloud_print_proxy_process_browsertest.cc
+++ b/chrome/browser/printing/cloud_print/test/cloud_print_proxy_process_browsertest.cc
@@ -13,7 +13,7 @@
 #include "base/rand_util.h"
 #include "base/test/multiprocess_test.h"
 #include "base/test/test_timeouts.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/printing/cloud_print/cloud_print_proxy_service.h"
 #include "chrome/browser/printing/cloud_print/cloud_print_proxy_service_factory.h"
 #include "chrome/browser/service/service_process_control.h"
diff --git a/chrome/browser/printing/print_dialog_cloud.cc b/chrome/browser/printing/print_dialog_cloud.cc
index 9f16cee..984a4e7 100644
--- a/chrome/browser/printing/print_dialog_cloud.cc
+++ b/chrome/browser/printing/print_dialog_cloud.cc
@@ -682,7 +682,7 @@
                  browser_context, modal_parent, data, print_job_title,
                  print_ticket, file_type));
   if (delete_on_close)
-    file_util::Delete(path_to_file, false);
+    base::Delete(path_to_file, false);
 }
 
 }  // namespace internal_cloud_print_helpers
diff --git a/chrome/browser/printing/print_dialog_gtk.cc b/chrome/browser/printing/print_dialog_gtk.cc
index e4a6e5d..a7bf21c 100644
--- a/chrome/browser/printing/print_dialog_gtk.cc
+++ b/chrome/browser/printing/print_dialog_gtk.cc
@@ -275,7 +275,7 @@
 
   if (!error && !metafile->SaveTo(path_to_pdf_)) {
     LOG(ERROR) << "Saving metafile failed";
-    file_util::Delete(path_to_pdf_, false);
+    base::Delete(path_to_pdf_, false);
     error = true;
   }
 
diff --git a/chrome/browser/printing/print_job.cc b/chrome/browser/printing/print_job.cc
index f71bc39..65b8d3e77 100644
--- a/chrome/browser/printing/print_job.cc
+++ b/chrome/browser/printing/print_job.cc
@@ -9,7 +9,7 @@
 #include "base/message_loop.h"
 #include "base/threading/thread_restrictions.h"
 #include "base/threading/worker_pool.h"
-#include "base/timer.h"
+#include "base/timer/timer.h"
 #include "chrome/browser/printing/print_job_worker.h"
 #include "chrome/common/chrome_notification_types.h"
 #include "content/public/browser/notification_service.h"
diff --git a/chrome/browser/printing/print_preview_dialog_controller.cc b/chrome/browser/printing/print_preview_dialog_controller.cc
index b9413a0..f5d8a57 100644
--- a/chrome/browser/printing/print_preview_dialog_controller.cc
+++ b/chrome/browser/printing/print_preview_dialog_controller.cc
@@ -402,7 +402,7 @@
     // create the popup on the native desktop.
     Browser* current_browser = new Browser(
         Browser::CreateParams(Browser::TYPE_POPUP, profile,
-                              chrome::HOST_DESKTOP_TYPE_NATIVE));
+                              chrome::GetActiveDesktop()));
     if (!current_browser) {
       NOTREACHED() << "Failed to create popup browser window";
       return NULL;
diff --git a/chrome/browser/printing/print_preview_dialog_controller_browsertest.cc b/chrome/browser/printing/print_preview_dialog_controller_browsertest.cc
index ee17e94..9cecc56 100644
--- a/chrome/browser/printing/print_preview_dialog_controller_browsertest.cc
+++ b/chrome/browser/printing/print_preview_dialog_controller_browsertest.cc
@@ -15,7 +15,7 @@
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/notification_types.h"
 #include "content/public/browser/web_contents_observer.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 using content::WebContents;
 
diff --git a/chrome/browser/printing/print_view_manager.cc b/chrome/browser/printing/print_view_manager.cc
index f5efeb7..17666df 100644
--- a/chrome/browser/printing/print_view_manager.cc
+++ b/chrome/browser/printing/print_view_manager.cc
@@ -13,7 +13,7 @@
 #include "base/metrics/histogram.h"
 #include "base/prefs/pref_service.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/timer.h"
+#include "base/timer/timer.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/printing/print_error_dialog.h"
 #include "chrome/browser/printing/print_job.h"
diff --git a/chrome/browser/printing/printing_layout_browsertest.cc b/chrome/browser/printing/printing_layout_browsertest.cc
index 696cfa7..5ba5b83 100644
--- a/chrome/browser/printing/printing_layout_browsertest.cc
+++ b/chrome/browser/printing/printing_layout_browsertest.cc
@@ -53,7 +53,7 @@
 
   virtual void TearDown() OVERRIDE {
     InProcessBrowserTest::TearDown();
-    file_util::Delete(emf_path_, true);
+    base::Delete(emf_path_, true);
   }
 
   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
@@ -221,7 +221,7 @@
               "\" when looking for \"" << verification_name << "\"";
           prn_file = file.value();
           found_prn = true;
-          file_util::Delete(file, false);
+          base::Delete(file, false);
           continue;
         }
         EXPECT_TRUE(false);
diff --git a/chrome/browser/process_singleton_linux.cc b/chrome/browser/process_singleton_linux.cc
index 2164ea0..b68e56d 100644
--- a/chrome/browser/process_singleton_linux.cc
+++ b/chrome/browser/process_singleton_linux.cc
@@ -76,8 +76,8 @@
 #include "base/strings/sys_string_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/platform_thread.h"
-#include "base/time.h"
-#include "base/timer.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
 #if defined(TOOLKIT_GTK)
 #include "chrome/browser/ui/gtk/process_singleton_dialog.h"
 #endif
diff --git a/chrome/browser/process_singleton_win.cc b/chrome/browser/process_singleton_win.cc
index cff14fb..237004a 100644
--- a/chrome/browser/process_singleton_win.cc
+++ b/chrome/browser/process_singleton_win.cc
@@ -15,7 +15,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "base/win/metro.h"
 #include "base/win/registry.h"
 #include "base/win/scoped_handle.h"
@@ -288,7 +288,7 @@
     return PROCESS_NONE;
   }
 
-  switch (chrome::AttemptToNotifyRunningChrome(remote_window_)) {
+  switch (chrome::AttemptToNotifyRunningChrome(remote_window_, false)) {
     case chrome::NOTIFY_SUCCESS:
       return PROCESS_NOTIFIED;
     case chrome::NOTIFY_FAILED:
diff --git a/chrome/browser/profile_resetter/profile_resetter.cc b/chrome/browser/profile_resetter/profile_resetter.cc
index ea601c0..513719f 100644
--- a/chrome/browser/profile_resetter/profile_resetter.cc
+++ b/chrome/browser/profile_resetter/profile_resetter.cc
@@ -5,6 +5,8 @@
 #include "chrome/browser/profile_resetter/profile_resetter.h"
 
 #include "base/prefs/pref_service.h"
+#include "chrome/browser/browsing_data/browsing_data_helper.h"
+#include "chrome/browser/content_settings/host_content_settings_map.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/extension_system.h"
 #include "chrome/browser/extensions/management_policy.h"
@@ -24,14 +26,18 @@
 ProfileResetter::ProfileResetter(Profile* profile)
     : profile_(profile),
       template_url_service_(TemplateURLServiceFactory::GetForProfile(profile_)),
-      pending_reset_flags_(0) {
+      pending_reset_flags_(0),
+      cookies_remover_(NULL) {
   DCHECK(CalledOnValidThread());
   DCHECK(profile_);
   registrar_.Add(this, chrome::NOTIFICATION_TEMPLATE_URL_SERVICE_LOADED,
                  content::Source<TemplateURLService>(template_url_service_));
 }
 
-ProfileResetter::~ProfileResetter() {}
+ProfileResetter::~ProfileResetter() {
+  if (cookies_remover_)
+    cookies_remover_->RemoveObserver(this);
+}
 
 void ProfileResetter::Reset(ProfileResetter::ResettableFlags resettable_flags,
                             const base::Closure& callback) {
@@ -130,16 +136,35 @@
 
 void ProfileResetter::ResetContentSettings() {
   DCHECK(CalledOnValidThread());
-  NOTIMPLEMENTED();
-  // TODO(battre/vabr): Implement
+  PrefService* prefs = profile_->GetPrefs();
+  HostContentSettingsMap* map = profile_->GetHostContentSettingsMap();
+
+  for (int type = 0; type < CONTENT_SETTINGS_NUM_TYPES; ++type) {
+    map->ClearSettingsForOneType(static_cast<ContentSettingsType>(type));
+    if (HostContentSettingsMap::IsSettingAllowedForType(
+            prefs,
+            CONTENT_SETTING_DEFAULT,
+            static_cast<ContentSettingsType>(type)))
+      map->SetDefaultContentSetting(static_cast<ContentSettingsType>(type),
+                                    CONTENT_SETTING_DEFAULT);
+  }
   MarkAsDone(CONTENT_SETTINGS);
 }
 
 void ProfileResetter::ResetCookiesAndSiteData() {
   DCHECK(CalledOnValidThread());
-  NOTIMPLEMENTED();
-  // TODO(battre/vabr): Implement
-  MarkAsDone(COOKIES_AND_SITE_DATA);
+  DCHECK(!cookies_remover_);
+
+  cookies_remover_ = BrowsingDataRemover::CreateForUnboundedRange(profile_);
+  cookies_remover_->AddObserver(this);
+  int remove_mask = BrowsingDataRemover::REMOVE_SITE_DATA |
+                    BrowsingDataRemover::REMOVE_CACHE;
+  PrefService* prefs = profile_->GetPrefs();
+  DCHECK(prefs);
+  // Don't try to clear LSO data if it's not supported.
+  if (!prefs->GetBoolean(prefs::kClearPluginLSODataEnabled))
+    remove_mask &= ~BrowsingDataRemover::REMOVE_PLUGIN_DATA;
+  cookies_remover_->Remove(remove_mask, BrowsingDataHelper::UNPROTECTED_WEB);
 }
 
 void ProfileResetter::ResetExtensions() {
@@ -187,3 +212,8 @@
   if (pending_reset_flags_ & DEFAULT_SEARCH_ENGINE)
     ResetDefaultSearchEngine();
 }
+
+void ProfileResetter::OnBrowsingDataRemoverDone() {
+  cookies_remover_ = NULL;
+  MarkAsDone(COOKIES_AND_SITE_DATA);
+}
diff --git a/chrome/browser/profile_resetter/profile_resetter.h b/chrome/browser/profile_resetter/profile_resetter.h
index 9031f74..492d6f6 100644
--- a/chrome/browser/profile_resetter/profile_resetter.h
+++ b/chrome/browser/profile_resetter/profile_resetter.h
@@ -8,6 +8,7 @@
 #include "base/basictypes.h"
 #include "base/callback.h"
 #include "base/threading/non_thread_safe.h"
+#include "chrome/browser/browsing_data/browsing_data_remover.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
 
@@ -18,7 +19,8 @@
 // It is used in case the profile has been damaged due to malware or bad user
 // settings.
 class ProfileResetter : public base::NonThreadSafe,
-                        public content::NotificationObserver {
+                        public content::NotificationObserver,
+                        public BrowsingDataRemover::Observer {
  public:
   // Flags indicating what aspects of a profile shall be reset.
   enum Resettable {
@@ -70,6 +72,9 @@
                        const content::NotificationSource& source,
                        const content::NotificationDetails& details) OVERRIDE;
 
+  // BrowsingDataRemover::Observer:
+  virtual void OnBrowsingDataRemoverDone() OVERRIDE;
+
   Profile* profile_;
   TemplateURLService* template_url_service_;
 
@@ -82,6 +87,10 @@
 
   content::NotificationRegistrar registrar_;
 
+  // If non-null it means removal is in progress. BrowsingDataRemover takes care
+  // of deleting itself when done.
+  BrowsingDataRemover* cookies_remover_;
+
   DISALLOW_COPY_AND_ASSIGN(ProfileResetter);
 };
 
diff --git a/chrome/browser/profile_resetter/profile_resetter_browsertest.cc b/chrome/browser/profile_resetter/profile_resetter_browsertest.cc
new file mode 100644
index 0000000..f8e0144
--- /dev/null
+++ b/chrome/browser/profile_resetter/profile_resetter_browsertest.cc
@@ -0,0 +1,177 @@
+// 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/profile_resetter/profile_resetter.h"
+
+#include "base/bind.h"
+#include "chrome/browser/profile_resetter/profile_resetter_test_base.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "content/public/test/test_utils.h"
+#include "net/cookies/cookie_store.h"
+#include "net/url_request/url_request_context.h"
+#include "net/url_request/url_request_context_getter.h"
+
+namespace {
+
+const char kCookieDefinition[] = "A=1";
+const char kCookieHostname[] = "http://host1";
+
+using content::BrowserThread;
+
+// RemoveCookieTester provides the user with the ability to set and get a
+// cookie for given profile.
+class RemoveCookieTester {
+ public:
+  explicit RemoveCookieTester(Profile* profile);
+  ~RemoveCookieTester();
+
+  std::string GetCookie(const std::string& host);
+  void AddCookie(const std::string& host, const std::string& definition);
+
+ private:
+  void GetCookieOnIOThread(net::URLRequestContextGetter* context_getter,
+                           const std::string& host);
+  void SetCookieOnIOThread(net::URLRequestContextGetter* context_getter,
+                           const std::string& host,
+                           const std::string& definition);
+  void GetCookieCallback(const std::string& cookies);
+  void SetCookieCallback(bool result);
+
+  void BlockUntilNotified();
+  void Notify();
+
+  std::string last_cookies_;
+  bool waiting_callback_;
+  Profile* profile_;
+  scoped_refptr<content::MessageLoopRunner> runner_;
+
+  DISALLOW_COPY_AND_ASSIGN(RemoveCookieTester);
+};
+
+RemoveCookieTester::RemoveCookieTester(Profile* profile)
+    : waiting_callback_(false),
+      profile_(profile) {
+}
+
+RemoveCookieTester::~RemoveCookieTester() {}
+
+// Returns true, if the given cookie exists in the cookie store.
+std::string RemoveCookieTester::GetCookie(const std::string& host) {
+  last_cookies_.clear();
+  DCHECK(!waiting_callback_);
+  waiting_callback_ = true;
+  BrowserThread::PostTask(
+      BrowserThread::IO, FROM_HERE,
+      base::Bind(&RemoveCookieTester::GetCookieOnIOThread,
+                 base::Unretained(this),
+                 base::Unretained(profile_->GetRequestContext()),
+                 host));
+  BlockUntilNotified();
+  return last_cookies_;
+}
+
+void RemoveCookieTester::AddCookie(const std::string& host,
+                                   const std::string& definition) {
+  DCHECK(!waiting_callback_);
+  waiting_callback_ = true;
+  BrowserThread::PostTask(
+      BrowserThread::IO, FROM_HERE,
+      base::Bind(&RemoveCookieTester::SetCookieOnIOThread,
+                 base::Unretained(this),
+                 base::Unretained(profile_->GetRequestContext()),
+                 host,
+                 definition));
+  BlockUntilNotified();
+}
+
+void RemoveCookieTester::GetCookieOnIOThread(
+    net::URLRequestContextGetter* context_getter,
+    const std::string& host) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+  net::CookieStore* cookie_store = context_getter->
+      GetURLRequestContext()->cookie_store();
+  cookie_store->GetCookiesWithOptionsAsync(
+      GURL(host), net::CookieOptions(),
+      base::Bind(&RemoveCookieTester::GetCookieCallback,
+                 base::Unretained(this)));
+}
+
+void RemoveCookieTester::SetCookieOnIOThread(
+    net::URLRequestContextGetter* context_getter,
+    const std::string& host,
+    const std::string& definition) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+  net::CookieStore* cookie_store = context_getter->
+      GetURLRequestContext()->cookie_store();
+  cookie_store->SetCookieWithOptionsAsync(
+      GURL(host), definition, net::CookieOptions(),
+      base::Bind(&RemoveCookieTester::SetCookieCallback,
+                 base::Unretained(this)));
+}
+
+void RemoveCookieTester::GetCookieCallback(const std::string& cookies) {
+  if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
+    BrowserThread::PostTask(
+        BrowserThread::UI, FROM_HERE,
+        base::Bind(&RemoveCookieTester::GetCookieCallback,
+                   base::Unretained(this), cookies));
+    return;
+  }
+  last_cookies_ = cookies;
+  Notify();
+}
+
+void RemoveCookieTester::SetCookieCallback(bool result) {
+  if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
+    BrowserThread::PostTask(
+        BrowserThread::UI, FROM_HERE,
+        base::Bind(&RemoveCookieTester::SetCookieCallback,
+                   base::Unretained(this), result));
+    return;
+  }
+  ASSERT_TRUE(result);
+  Notify();
+}
+
+void RemoveCookieTester::BlockUntilNotified() {
+  DCHECK(!runner_.get());
+  if (waiting_callback_) {
+    runner_ = new content::MessageLoopRunner;
+    runner_->Run();
+    runner_ = NULL;
+  }
+}
+
+void RemoveCookieTester::Notify() {
+  DCHECK(waiting_callback_);
+  waiting_callback_ = false;
+  if (runner_.get())
+    runner_->Quit();
+}
+
+class ProfileResetTest : public InProcessBrowserTest,
+                         public ProfileResetterTestBase {
+ protected:
+  virtual void SetUpOnMainThread() OVERRIDE {
+    resetter_.reset(new ProfileResetter(browser()->profile()));
+  }
+};
+
+
+IN_PROC_BROWSER_TEST_F(ProfileResetTest, ResetCookiesAndSiteData) {
+  RemoveCookieTester tester(browser()->profile());
+  tester.AddCookie(kCookieHostname, kCookieDefinition);
+  ASSERT_EQ(kCookieDefinition, tester.GetCookie(kCookieHostname));
+
+  resetter_->Reset(ProfileResetter::COOKIES_AND_SITE_DATA,
+                   base::Bind(&ProfileResetterMockObject::StopLoop,
+                              base::Unretained(&mock_object_)));
+  mock_object_.RunLoop();
+
+  EXPECT_EQ("", tester.GetCookie(kCookieHostname));
+}
+
+}  // namespace
diff --git a/chrome/browser/profile_resetter/profile_resetter_test_base.cc b/chrome/browser/profile_resetter/profile_resetter_test_base.cc
new file mode 100644
index 0000000..b239618
--- /dev/null
+++ b/chrome/browser/profile_resetter/profile_resetter_test_base.cc
@@ -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.
+
+#include "chrome/browser/profile_resetter/profile_resetter_test_base.h"
+
+#include "chrome/browser/profile_resetter/profile_resetter.h"
+
+ProfileResetterMockObject::ProfileResetterMockObject() {}
+
+ProfileResetterMockObject::~ProfileResetterMockObject() {}
+
+void ProfileResetterMockObject::RunLoop() {
+  EXPECT_CALL(*this, Callback());
+  runner_ = new content::MessageLoopRunner;
+  runner_->Run();
+}
+
+void ProfileResetterMockObject::StopLoop() {
+  DCHECK(runner_.get());
+  Callback();
+  runner_->Quit();
+}
+
+ProfileResetterTestBase::ProfileResetterTestBase() {}
+
+ProfileResetterTestBase::~ProfileResetterTestBase() {}
diff --git a/chrome/browser/profile_resetter/profile_resetter_test_base.h b/chrome/browser/profile_resetter/profile_resetter_test_base.h
new file mode 100644
index 0000000..ef5744f
--- /dev/null
+++ b/chrome/browser/profile_resetter/profile_resetter_test_base.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_PROFILE_RESETTER_PROFILE_RESETTER_TEST_BASE_H_
+#define CHROME_BROWSER_PROFILE_RESETTER_PROFILE_RESETTER_TEST_BASE_H_
+
+#include "content/public/test/test_utils.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+class ProfileResetter;
+
+// The ProfileResetterMockObject is used to block the thread until
+// ProfileResetter::Reset has completed:
+
+// ProfileResetterMockObject mock_object;
+// resetter_->Reset(ProfileResetter::ALL,
+//                  base::Bind(&ProfileResetterMockObject::StopLoop,
+//                             base::Unretained(&mock_object)));
+// mock_object.RunLoop();
+class ProfileResetterMockObject {
+ public:
+  ProfileResetterMockObject();
+  ~ProfileResetterMockObject();
+
+  void RunLoop();
+  void StopLoop();
+
+ private:
+  MOCK_METHOD0(Callback, void(void));
+
+  scoped_refptr<content::MessageLoopRunner> runner_;
+
+  DISALLOW_COPY_AND_ASSIGN(ProfileResetterMockObject);
+};
+
+// Base class for all ProfileResetter unit tests.
+class ProfileResetterTestBase {
+ public:
+  ProfileResetterTestBase();
+  ~ProfileResetterTestBase();
+
+ protected:
+  testing::StrictMock<ProfileResetterMockObject> mock_object_;
+  scoped_ptr<ProfileResetter> resetter_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ProfileResetterTestBase);
+};
+
+#endif  // CHROME_BROWSER_PROFILE_RESETTER_PROFILE_RESETTER_TEST_BASE_H_
diff --git a/chrome/browser/profile_resetter/profile_resetter_unittest.cc b/chrome/browser/profile_resetter/profile_resetter_unittest.cc
index 8127d75..b625384 100644
--- a/chrome/browser/profile_resetter/profile_resetter_unittest.cc
+++ b/chrome/browser/profile_resetter/profile_resetter_unittest.cc
@@ -4,11 +4,14 @@
 
 #include "chrome/browser/profile_resetter/profile_resetter.h"
 
-#include "base/bind.h"
 #include "base/prefs/pref_service.h"
+#include "chrome/browser/content_settings/host_content_settings_map.h"
 #include "chrome/browser/extensions/extension_service_unittest.h"
 #include "chrome/browser/extensions/tab_helper.h"
+#include "chrome/browser/notifications/desktop_notification_service.h"
+#include "chrome/browser/notifications/desktop_notification_service_factory.h"
 #include "chrome/browser/prefs/session_startup_pref.h"
+#include "chrome/browser/profile_resetter/profile_resetter_test_base.h"
 #include "chrome/browser/search_engines/template_url_service_test_util.h"
 #include "chrome/browser/themes/theme_service.h"
 #include "chrome/browser/themes/theme_service_factory.h"
@@ -17,52 +20,14 @@
 #include "chrome/common/extensions/extension_manifest_constants.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/browser_with_test_window_test.h"
-#include "chrome/test/base/testing_profile.h"
 #include "content/public/browser/web_contents.h"
-#include "content/public/test/test_utils.h"
-#include "testing/gmock/include/gmock/gmock.h"
+
 
 namespace {
 
 using extensions::Extension;
 using extensions::Manifest;
 
-class MockObject {
- public:
-  void RunLoop() {
-    EXPECT_CALL(*this, Callback());
-    runner_ = new content::MessageLoopRunner;
-    runner_->Run();
-  }
-
-  void StopLoop() {
-    DCHECK(runner_.get());
-    Callback();
-    runner_->Quit();
-  }
-
- private:
-  MOCK_METHOD0(Callback, void(void));
-
-  scoped_refptr<content::MessageLoopRunner> runner_;
-};
-
-class ProfileResetterTestBase {
- public:
-  ProfileResetterTestBase();
-  ~ProfileResetterTestBase();
- protected:
-  testing::StrictMock<MockObject> mock_object_;
-  scoped_ptr<ProfileResetter> resetter_;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(ProfileResetterTestBase);
-};
-
-ProfileResetterTestBase::ProfileResetterTestBase() {}
-
-ProfileResetterTestBase::~ProfileResetterTestBase() {}
-
 class ProfileResetterTest : public testing::Test,
                             public ProfileResetterTestBase {
  protected:
@@ -95,9 +60,6 @@
   resetter_.reset(new ProfileResetter(profile_.get()));
 }
 
-// Returns a barebones test Extension object with the specified |name|.  The
-// returned extension will include background permission iff
-// |background_permission| is true.
 scoped_refptr<Extension> CreateExtension(const std::string& name,
                                          const base::FilePath& path,
                                          Manifest::Location location,
@@ -140,10 +102,17 @@
 /********************* Tests *********************/
 
 TEST_F(ProfileResetterTest, ResetDefaultSearchEngine) {
+  PrefService* prefs = test_util_.profile()->GetPrefs();
+  DCHECK(prefs);
+  prefs->SetString(prefs::kLastPromptedGoogleURL, "http://www.foo.com/");
+
   resetter_->Reset(
       ProfileResetter::DEFAULT_SEARCH_ENGINE,
-      base::Bind(&MockObject::StopLoop, base::Unretained(&mock_object_)));
+      base::Bind(&ProfileResetterMockObject::StopLoop,
+                 base::Unretained(&mock_object_)));
   mock_object_.RunLoop();
+
+  EXPECT_EQ("", prefs->GetString(prefs::kLastPromptedGoogleURL));
 }
 
 TEST_F(ProfileResetterTest, ResetHomepage) {
@@ -155,7 +124,8 @@
 
   resetter_->Reset(
       ProfileResetter::HOMEPAGE,
-      base::Bind(&MockObject::StopLoop, base::Unretained(&mock_object_)));
+      base::Bind(&ProfileResetterMockObject::StopLoop,
+                 base::Unretained(&mock_object_)));
   mock_object_.RunLoop();
 
   EXPECT_TRUE(prefs->GetBoolean(prefs::kHomePageIsNewTabPage));
@@ -164,17 +134,102 @@
 }
 
 TEST_F(ProfileResetterTest, ResetContentSettings) {
+  HostContentSettingsMap* host_content_settings_map =
+      test_util_.profile()->GetHostContentSettingsMap();
+  DesktopNotificationService* notification_service =
+      DesktopNotificationServiceFactory::GetForProfile(test_util_.profile());
+  ContentSettingsPattern pattern =
+      ContentSettingsPattern::FromString("[*.]example.org");
+  std::map<ContentSettingsType, ContentSetting> default_settings;
+
+  for (int type = 0; type < CONTENT_SETTINGS_NUM_TYPES; ++type) {
+    if (type == CONTENT_SETTINGS_TYPE_NOTIFICATIONS) {
+      notification_service->SetDefaultContentSetting(CONTENT_SETTING_BLOCK);
+      notification_service->GrantPermission(GURL("http://foo.de"));
+    } else if (type == CONTENT_SETTINGS_TYPE_AUTO_SELECT_CERTIFICATE ||
+               type == CONTENT_SETTINGS_TYPE_MIXEDSCRIPT ||
+               type == CONTENT_SETTINGS_TYPE_PROTOCOL_HANDLERS) {
+      // These types are excluded because one can't call
+      // GetDefaultContentSetting() for them.
+    } else {
+      ContentSettingsType content_type = static_cast<ContentSettingsType>(type);
+      ContentSetting default_setting =
+          host_content_settings_map->GetDefaultContentSetting(content_type,
+                                                              NULL);
+      default_settings[content_type] = default_setting;
+      ContentSetting wildcard_setting =
+          default_setting == CONTENT_SETTING_BLOCK ? CONTENT_SETTING_ALLOW
+                                                   : CONTENT_SETTING_BLOCK;
+      ContentSetting site_setting =
+          default_setting == CONTENT_SETTING_ALLOW ? CONTENT_SETTING_ALLOW
+                                                   : CONTENT_SETTING_BLOCK;
+      if (HostContentSettingsMap::IsSettingAllowedForType(
+              test_util_.profile()->GetPrefs(),
+              wildcard_setting,
+              content_type)) {
+        host_content_settings_map->SetDefaultContentSetting(
+            content_type,
+            wildcard_setting);
+      }
+      if (!HostContentSettingsMap::ContentTypeHasCompoundValue(content_type) &&
+          HostContentSettingsMap::IsValueAllowedForType(
+              test_util_.profile()->GetPrefs(),
+              Value::CreateIntegerValue(site_setting),
+              content_type)) {
+        host_content_settings_map->SetContentSetting(
+            pattern,
+            ContentSettingsPattern::Wildcard(),
+            content_type,
+            std::string(),
+            site_setting);
+        ContentSettingsForOneType host_settings;
+        host_content_settings_map->GetSettingsForOneType(
+            content_type, std::string(), &host_settings);
+        EXPECT_EQ(2U, host_settings.size());
+      }
+    }
+  }
+
   resetter_->Reset(
       ProfileResetter::CONTENT_SETTINGS,
-      base::Bind(&MockObject::StopLoop, base::Unretained(&mock_object_)));
+      base::Bind(&ProfileResetterMockObject::StopLoop,
+                 base::Unretained(&mock_object_)));
   mock_object_.RunLoop();
-}
 
-TEST_F(ProfileResetterTest, ResetCookiesAndSiteData) {
-  resetter_->Reset(
-      ProfileResetter::COOKIES_AND_SITE_DATA,
-      base::Bind(&MockObject::StopLoop, base::Unretained(&mock_object_)));
-  mock_object_.RunLoop();
+  for (int type = 0; type < CONTENT_SETTINGS_NUM_TYPES; ++type) {
+    if (type == CONTENT_SETTINGS_TYPE_NOTIFICATIONS) {
+      EXPECT_EQ(CONTENT_SETTING_ASK,
+                notification_service->GetDefaultContentSetting(NULL));
+      EXPECT_EQ(CONTENT_SETTING_ASK,
+                notification_service->GetContentSetting(GURL("http://foo.de")));
+    } else {
+      ContentSettingsType content_type = static_cast<ContentSettingsType>(type);
+      if (HostContentSettingsMap::ContentTypeHasCompoundValue(content_type) ||
+          type == CONTENT_SETTINGS_TYPE_AUTO_SELECT_CERTIFICATE ||
+          content_type == CONTENT_SETTINGS_TYPE_MIXEDSCRIPT ||
+          content_type == CONTENT_SETTINGS_TYPE_PROTOCOL_HANDLERS)
+        continue;
+      ContentSetting default_setting =
+          host_content_settings_map->GetDefaultContentSetting(content_type,
+                                                              NULL);
+      EXPECT_TRUE(default_settings.count(content_type));
+      EXPECT_EQ(default_settings[content_type], default_setting);
+      if (!HostContentSettingsMap::ContentTypeHasCompoundValue(content_type)) {
+        ContentSetting site_setting =
+            host_content_settings_map->GetContentSetting(
+                GURL("example.org"),
+                GURL(),
+                content_type,
+                std::string());
+        EXPECT_EQ(default_setting, site_setting);
+      }
+
+      ContentSettingsForOneType host_settings;
+      host_content_settings_map->GetSettingsForOneType(
+          content_type, std::string(), &host_settings);
+      EXPECT_EQ(1U, host_settings.size());
+    }
+  }
 }
 
 TEST_F(ExtensionsResetTest, ResetExtensionsByDisabling) {
@@ -216,7 +271,8 @@
 
   resetter_->Reset(
       ProfileResetter::EXTENSIONS,
-      base::Bind(&MockObject::StopLoop, base::Unretained(&mock_object_)));
+      base::Bind(&ProfileResetterMockObject::StopLoop,
+                 base::Unretained(&mock_object_)));
   mock_object_.RunLoop();
 
   EXPECT_EQ(2u, service_->extensions()->size());
@@ -236,7 +292,8 @@
 
   resetter_->Reset(
       ProfileResetter::STARTUP_PAGES,
-      base::Bind(&MockObject::StopLoop, base::Unretained(&mock_object_)));
+      base::Bind(&ProfileResetterMockObject::StopLoop,
+                 base::Unretained(&mock_object_)));
   mock_object_.RunLoop();
 
   startup_pref = SessionStartupPref::GetStartupPref(prefs);
@@ -250,20 +307,20 @@
       base::FilePath(FILE_PATH_LITERAL("//nonexistent")),
       Manifest::INVALID_LOCATION,
       false);
-  content::WebContents* contents1 = CreateWebContents();
-  extensions::TabHelper::CreateForWebContents(contents1);
-  extensions::TabHelper::FromWebContents(contents1)->
+  scoped_ptr<content::WebContents> contents1(CreateWebContents());
+  extensions::TabHelper::CreateForWebContents(contents1.get());
+  extensions::TabHelper::FromWebContents(contents1.get())->
       SetExtensionApp(extension_app.get());
-  content::WebContents* contents2 = CreateWebContents();
-  content::WebContents* contents3 = CreateWebContents();
-  content::WebContents* contents4 = CreateWebContents();
+  scoped_ptr<content::WebContents> contents2(CreateWebContents());
+  scoped_ptr<content::WebContents> contents3(CreateWebContents());
+  scoped_ptr<content::WebContents> contents4(CreateWebContents());
   TabStripModel* tab_strip_model = browser()->tab_strip_model();
 
-  tab_strip_model->AppendWebContents(contents4, true);
-  tab_strip_model->AppendWebContents(contents3, true);
-  tab_strip_model->AppendWebContents(contents2, true);
+  tab_strip_model->AppendWebContents(contents4.get(), true);
+  tab_strip_model->AppendWebContents(contents3.get(), true);
+  tab_strip_model->AppendWebContents(contents2.get(), true);
   tab_strip_model->SetTabPinned(2, true);
-  tab_strip_model->AppendWebContents(contents1, true);
+  tab_strip_model->AppendWebContents(contents1.get(), true);
   tab_strip_model->SetTabPinned(3, true);
 
   EXPECT_EQ(contents2, tab_strip_model->GetWebContentsAt(0));
@@ -274,7 +331,8 @@
 
   resetter_->Reset(
       ProfileResetter::PINNED_TABS,
-      base::Bind(&MockObject::StopLoop, base::Unretained(&mock_object_)));
+      base::Bind(&ProfileResetterMockObject::StopLoop,
+                 base::Unretained(&mock_object_)));
   mock_object_.RunLoop();
 
   EXPECT_EQ(contents1, tab_strip_model->GetWebContentsAt(0));
@@ -288,7 +346,8 @@
   // mock_object_ is a StrictMock, so we verify that it is called only once.
   resetter_->Reset(
       ProfileResetter::DEFAULT_SEARCH_ENGINE | ProfileResetter::HOMEPAGE,
-      base::Bind(&MockObject::StopLoop, base::Unretained(&mock_object_)));
+      base::Bind(&ProfileResetterMockObject::StopLoop,
+                 base::Unretained(&mock_object_)));
   mock_object_.RunLoop();
 }
 
diff --git a/chrome/browser/profiles/avatar_menu_model.cc b/chrome/browser/profiles/avatar_menu_model.cc
index bc9767d..a7e535b 100644
--- a/chrome/browser/profiles/avatar_menu_model.cc
+++ b/chrome/browser/profiles/avatar_menu_model.cc
@@ -238,7 +238,7 @@
   ManagedUserService* service = ManagedUserServiceFactory::GetForProfile(
       browser_->profile());
   if (service->ProfileIsManaged()) {
-    base::string16 custodian = UTF8ToUTF16(service->GetCustodianEmailAddress());
+    base::string16 custodian = UTF8ToUTF16(service->GetCustodianName());
     return l10n_util::GetStringFUTF16(IDS_MANAGED_USER_INFO, custodian);
   }
 #endif
diff --git a/chrome/browser/profiles/avatar_menu_model_browsertest.cc b/chrome/browser/profiles/avatar_menu_model_browsertest.cc
index 816f801..634fe75 100644
--- a/chrome/browser/profiles/avatar_menu_model_browsertest.cc
+++ b/chrome/browser/profiles/avatar_menu_model_browsertest.cc
@@ -30,7 +30,7 @@
   AvatarMenuModel model(&cache, NULL, browser());
 
   BrowserList* browser_list =
-      BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_NATIVE);
+      BrowserList::GetInstance(chrome::GetActiveDesktop());
   EXPECT_EQ(1U, browser_list->size());
   content::WindowedNotificationObserver window_close_observer(
       chrome::NOTIFICATION_BROWSER_CLOSED,
diff --git a/chrome/browser/profiles/avatar_menu_model_unittest.cc b/chrome/browser/profiles/avatar_menu_model_unittest.cc
index fcb5b14..b012827 100644
--- a/chrome/browser/profiles/avatar_menu_model_unittest.cc
+++ b/chrome/browser/profiles/avatar_menu_model_unittest.cc
@@ -4,9 +4,11 @@
 
 #include "chrome/browser/profiles/avatar_menu_model.h"
 
+#include "base/memory/scoped_ptr.h"
 #include "base/metrics/field_trial.h"
 #include "base/strings/string16.h"
 #include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/prefs/pref_service_syncable.h"
 #include "chrome/browser/profiles/avatar_menu_model_observer.h"
 #include "chrome/browser/profiles/profile_info_cache.h"
 #include "chrome/browser/profiles/profile_manager.h"
@@ -60,8 +62,10 @@
   string16 name1(ASCIIToUTF16("Test 1"));
   string16 name2(ASCIIToUTF16("Test 2"));
 
-  manager()->CreateTestingProfile("p1", name1, 0);
-  manager()->CreateTestingProfile("p2", name2, 0);
+  manager()->CreateTestingProfile("p1", scoped_ptr<PrefServiceSyncable>(),
+                                  name1, 0);
+  manager()->CreateTestingProfile("p2", scoped_ptr<PrefServiceSyncable>(),
+                                  name2, 0);
 
   MockObserver observer;
   EXPECT_EQ(0, observer.change_count());
@@ -84,8 +88,10 @@
   string16 name1(ASCIIToUTF16("Test 1"));
   string16 name2(ASCIIToUTF16("Test 2"));
 
-  manager()->CreateTestingProfile("p1", name1, 0);
-  manager()->CreateTestingProfile("p2", name2, 0);
+  manager()->CreateTestingProfile("p1", scoped_ptr<PrefServiceSyncable>(),
+                                  name1, 0);
+  manager()->CreateTestingProfile("p2", scoped_ptr<PrefServiceSyncable>(),
+                                  name2, 0);
 
   MockObserver observer;
   AvatarMenuModel model(manager()->profile_info_cache(), &observer, browser());
@@ -100,8 +106,10 @@
   string16 name2(ASCIIToUTF16("Beta"));
   string16 newname1(ASCIIToUTF16("Gamma"));
 
-  manager()->CreateTestingProfile("p1", name1, 0);
-  manager()->CreateTestingProfile("p2", name2, 0);
+  manager()->CreateTestingProfile("p1", scoped_ptr<PrefServiceSyncable>(),
+                                  name1, 0);
+  manager()->CreateTestingProfile("p2", scoped_ptr<PrefServiceSyncable>(),
+                                  name2, 0);
 
   MockObserver observer;
   AvatarMenuModel model(manager()->profile_info_cache(), &observer, browser());
@@ -134,8 +142,10 @@
   string16 name1(ASCIIToUTF16("Test 1"));
   string16 name2(ASCIIToUTF16("Test 2"));
 
-  manager()->CreateTestingProfile("p1", name1, 0);
-  manager()->CreateTestingProfile("p2", name2, 0);
+  manager()->CreateTestingProfile("p1", scoped_ptr<PrefServiceSyncable>(),
+                                  name1, 0);
+  manager()->CreateTestingProfile("p2", scoped_ptr<PrefServiceSyncable>(),
+                                  name2, 0);
 
   MockObserver observer;
   EXPECT_EQ(0, observer.change_count());
@@ -145,7 +155,8 @@
   EXPECT_EQ(2U, model.GetNumberOfItems());
 
   string16 name3(ASCIIToUTF16("Test 3"));
-  manager()->CreateTestingProfile("p3", name3, 0);
+  manager()->CreateTestingProfile("p3", scoped_ptr<PrefServiceSyncable>(),
+                                  name3, 0);
 
   // Four changes happened via the call to CreateTestingProfile: adding the
   // profile to the cache, setting the user name, rebuilding the list of
@@ -186,7 +197,8 @@
 
 TEST_F(AvatarMenuModelTest, DontShowAvatarMenu) {
   string16 name1(ASCIIToUTF16("Test 1"));
-  manager()->CreateTestingProfile("p1", name1, 0);
+  manager()->CreateTestingProfile("p1", scoped_ptr<PrefServiceSyncable>(),
+                                  name1, 0);
 
   EXPECT_FALSE(AvatarMenuModel::ShouldShowAvatarMenu());
 
@@ -196,7 +208,8 @@
     return;
 
   string16 name2(ASCIIToUTF16("Test 2"));
-  manager()->CreateTestingProfile("p2", name2, 0);
+  manager()->CreateTestingProfile("p2", scoped_ptr<PrefServiceSyncable>(),
+                                  name2, 0);
 
   EXPECT_FALSE(AvatarMenuModel::ShouldShowAvatarMenu());
 }
@@ -209,8 +222,10 @@
   string16 name1(ASCIIToUTF16("Test 1"));
   string16 name2(ASCIIToUTF16("Test 2"));
 
-  manager()->CreateTestingProfile("p1", name1, 0);
-  manager()->CreateTestingProfile("p2", name2, 0);
+  manager()->CreateTestingProfile("p1", scoped_ptr<PrefServiceSyncable>(),
+                                  name1, 0);
+  manager()->CreateTestingProfile("p2", scoped_ptr<PrefServiceSyncable>(),
+                                  name2, 0);
 
 #if defined(OS_CHROMEOS)
   EXPECT_FALSE(AvatarMenuModel::ShouldShowAvatarMenu());
@@ -224,7 +239,8 @@
   if (!ProfileManager::IsMultipleProfilesEnabled())
     return;
 
-  manager()->CreateTestingProfile("p1", ASCIIToUTF16("Test 1"), 0);
+  manager()->CreateTestingProfile("p1", scoped_ptr<PrefServiceSyncable>(),
+                                  ASCIIToUTF16("Test 1"), 0);
 
   // Add a managed user profile.
   ProfileInfoCache* cache = manager()->profile_info_cache();
diff --git a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
index dffbdbe..e5ca157 100644
--- a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
+++ b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
@@ -25,6 +25,7 @@
 #include "chrome/browser/extensions/api/bookmarks/bookmarks_api.h"
 #include "chrome/browser/extensions/api/commands/command_service.h"
 #include "chrome/browser/extensions/api/cookies/cookies_api.h"
+#include "chrome/browser/extensions/api/developer_private/developer_private_api_factory.h"
 #include "chrome/browser/extensions/api/dial/dial_api_factory.h"
 #include "chrome/browser/extensions/api/discovery/suggested_links_registry_factory.h"
 #include "chrome/browser/extensions/api/extension_action/extension_action_api.h"
@@ -62,6 +63,8 @@
 #include "chrome/browser/google/google_url_tracker_factory.h"
 #include "chrome/browser/history/history_service_factory.h"
 #include "chrome/browser/history/shortcuts_backend_factory.h"
+#include "chrome/browser/invalidation/invalidation_service_factory.h"
+#include "chrome/browser/media_galleries/media_galleries_preferences_factory.h"
 #include "chrome/browser/notifications/desktop_notification_service_factory.h"
 #include "chrome/browser/password_manager/password_store_factory.h"
 #include "chrome/browser/plugins/plugin_prefs_factory.h"
@@ -100,6 +103,7 @@
 
 #if defined(ENABLE_CONFIGURATION_POLICY)
 #if defined(OS_CHROMEOS)
+#include "chrome/browser/chromeos/policy/recommendation_restorer_factory.h"
 #include "chrome/browser/chromeos/policy/user_cloud_policy_manager_factory_chromeos.h"
 #include "chrome/browser/chromeos/policy/user_cloud_policy_token_forwarder_factory.h"
 #else
@@ -202,6 +206,7 @@
   extensions::BluetoothAPIFactory::GetInstance();
   extensions::CommandService::GetFactoryInstance();
   extensions::CookiesAPI::GetFactoryInstance();
+  extensions::DeveloperPrivateAPIFactory::GetInstance();
   extensions::DialAPIFactory::GetInstance();
   extensions::ExtensionActionAPI::GetFactoryInstance();
   extensions::ExtensionPrefsFactory::GetInstance();
@@ -255,6 +260,7 @@
   GlobalErrorServiceFactory::GetInstance();
   GoogleURLTrackerFactory::GetInstance();
   HistoryServiceFactory::GetInstance();
+  invalidation::InvalidationServiceFactory::GetInstance();
 #if defined(ENABLE_MANAGED_USERS)
   ManagedUserServiceFactory::GetInstance();
 #endif
@@ -273,6 +279,7 @@
   policy::ProfilePolicyConnectorFactory::GetInstance();
 #if defined(ENABLE_CONFIGURATION_POLICY)
 #if defined(OS_CHROMEOS)
+  policy::RecommendationRestorerFactory::GetInstance();
   policy::UserCloudPolicyManagerFactoryChromeOS::GetInstance();
   policy::UserCloudPolicyTokenForwarderFactory::GetInstance();
 #else
diff --git a/chrome/browser/profiles/gaia_info_update_service.h b/chrome/browser/profiles/gaia_info_update_service.h
index 797cc75..51d54f4 100644
--- a/chrome/browser/profiles/gaia_info_update_service.h
+++ b/chrome/browser/profiles/gaia_info_update_service.h
@@ -9,7 +9,7 @@
 #include "base/gtest_prod_util.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/prefs/pref_member.h"
-#include "base/timer.h"
+#include "base/timer/timer.h"
 #include "chrome/browser/profiles/profile_downloader.h"
 #include "chrome/browser/profiles/profile_downloader_delegate.h"
 #include "components/browser_context_keyed_service/browser_context_keyed_service.h"
diff --git a/chrome/browser/profiles/profile.h b/chrome/browser/profiles/profile.h
index d811021..3364332 100644
--- a/chrome/browser/profiles/profile.h
+++ b/chrome/browser/profiles/profile.h
@@ -67,6 +67,9 @@
 class PrefRegistrySyncable;
 }
 
+// Instead of adding more members to Profile, consider creating a
+// BrowserContextKeyedService. See
+// http://dev.chromium.org/developers/design-documents/profile-architecture
 class Profile : public content::BrowserContext {
  public:
   // Profile services are accessed with the following parameter. This parameter
diff --git a/chrome/browser/profiles/profile_destroyer.h b/chrome/browser/profiles/profile_destroyer.h
index 70a4752..b258377 100644
--- a/chrome/browser/profiles/profile_destroyer.h
+++ b/chrome/browser/profiles/profile_destroyer.h
@@ -8,7 +8,7 @@
 #include <vector>
 
 #include "base/memory/ref_counted.h"
-#include "base/timer.h"
+#include "base/timer/timer.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
 
diff --git a/chrome/browser/profiles/profile_downloader.cc b/chrome/browser/profiles/profile_downloader.cc
index 56ebaf6..1cb0b1f 100644
--- a/chrome/browser/profiles/profile_downloader.cc
+++ b/chrome/browser/profiles/profile_downloader.cc
@@ -28,11 +28,11 @@
 #include "google_apis/gaia/gaia_constants.h"
 #include "google_apis/gaia/gaia_urls.h"
 #include "google_apis/gaia/oauth2_access_token_fetcher.h"
-#include "googleurl/src/gurl.h"
 #include "net/base/load_flags.h"
 #include "net/url_request/url_fetcher.h"
 #include "net/url_request/url_request_status.h"
 #include "skia/ext/image_operations.h"
+#include "url/gurl.h"
 
 using content::BrowserThread;
 
diff --git a/chrome/browser/profiles/profile_downloader.h b/chrome/browser/profiles/profile_downloader.h
index 39483d9..6921618 100644
--- a/chrome/browser/profiles/profile_downloader.h
+++ b/chrome/browser/profiles/profile_downloader.h
@@ -15,9 +15,9 @@
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
 #include "google_apis/gaia/oauth2_access_token_consumer.h"
-#include "googleurl/src/gurl.h"
 #include "net/url_request/url_fetcher_delegate.h"
 #include "third_party/skia/include/core/SkBitmap.h"
+#include "url/gurl.h"
 
 class ProfileDownloaderDelegate;
 class OAuth2AccessTokenFetcher;
diff --git a/chrome/browser/profiles/profile_impl.h b/chrome/browser/profiles/profile_impl.h
index 4ac54a5..9f24987 100644
--- a/chrome/browser/profiles/profile_impl.h
+++ b/chrome/browser/profiles/profile_impl.h
@@ -14,7 +14,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/prefs/pref_change_registrar.h"
-#include "base/timer.h"
+#include "base/timer/timer.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_impl_io_data.h"
 #include "content/public/browser/content_browser_client.h"
diff --git a/chrome/browser/profiles/profile_info_cache.cc b/chrome/browser/profiles/profile_info_cache.cc
index f189844..92398d8 100644
--- a/chrome/browser/profiles/profile_info_cache.cc
+++ b/chrome/browser/profiles/profile_info_cache.cc
@@ -165,7 +165,7 @@
 
 void DeleteBitmap(const base::FilePath& image_path) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
-  file_util::Delete(image_path, false);
+  base::Delete(image_path, false);
 }
 
 }  // namespace
diff --git a/chrome/browser/profiles/profile_io_data.cc b/chrome/browser/profiles/profile_io_data.cc
index 0a0d95b..bca79c5 100644
--- a/chrome/browser/profiles/profile_io_data.cc
+++ b/chrome/browser/profiles/profile_io_data.cc
@@ -569,6 +569,14 @@
   // future to more accurately capture this state.
   chromeos::CrosSettings::Get()->GetBoolean(chromeos::kStatsReportingPref,
                                             &enable_metrics_);
+#elif defined(OS_ANDROID)
+  // TODO(dwkang): rename or unify the pref for UMA once we have conclusion
+  // in crbugs.com/246495.
+  // Android has it's own preferences for metrics / crash uploading.
+  enable_metrics_.Init(prefs::kCrashReportingEnabled,
+                       g_browser_process->local_state());
+  enable_metrics_.MoveToThread(
+      BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO));
 #else
   // Prep the PrefMember and send it to the IO thread, since this value will be
   // read from there.
diff --git a/chrome/browser/profiles/profile_loader.cc b/chrome/browser/profiles/profile_loader.cc
new file mode 100644
index 0000000..f7ada5e
--- /dev/null
+++ b/chrome/browser/profiles/profile_loader.cc
@@ -0,0 +1,99 @@
+// 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/profiles/profile_loader.h"
+
+#include "base/bind.h"
+#include "base/files/file_path.h"
+#include "base/memory/weak_ptr.h"
+#include "chrome/browser/lifetime/application_lifetime.h"
+#include "chrome/browser/profiles/profile_manager.h"
+
+ProfileLoader::ProfileLoader(ProfileManager* profile_manager)
+  : profile_manager_(profile_manager),
+    profile_load_sequence_id_(0),
+    pending_profile_loads_(0),
+    weak_factory_(this) {
+}
+
+ProfileLoader::~ProfileLoader() {
+}
+
+bool ProfileLoader::IsAnyProfileLoading() const {
+  return pending_profile_loads_ > 0;
+}
+
+void ProfileLoader::InvalidatePendingProfileLoads() {
+  ++profile_load_sequence_id_;
+}
+
+void ProfileLoader::LoadProfileInvalidatingOtherLoads(
+    const base::FilePath& profile_file_path,
+    base::Callback<void(Profile*)> callback) {
+  InvalidatePendingProfileLoads();
+
+  Profile* profile = GetProfileByPath(profile_file_path);
+  if (profile) {
+    callback.Run(profile);
+    return;
+  }
+
+  IncrementPendingProfileLoads();
+  CreateProfileAsync(
+      profile_file_path,
+      base::Bind(&ProfileLoader::OnProfileLoaded,
+                 weak_factory_.GetWeakPtr(),
+                 profile_load_sequence_id_,
+                 callback),
+      string16(), string16(), false);
+}
+
+Profile* ProfileLoader::GetProfileByPath(const base::FilePath& path) {
+  return profile_manager_->GetProfileByPath(path);
+}
+
+void ProfileLoader::CreateProfileAsync(
+    const base::FilePath& profile_path,
+    const ProfileManager::CreateCallback& callback,
+    const string16& name,
+    const string16& icon_url,
+    bool is_managed) {
+  profile_manager_->CreateProfileAsync(
+      profile_path, callback, name, icon_url, is_managed);
+}
+
+void ProfileLoader::OnProfileLoaded(int profile_load_sequence_id,
+                                    base::Callback<void(Profile*)> callback,
+                                    Profile* profile,
+                                    Profile::CreateStatus status) {
+  switch (status) {
+    case Profile::CREATE_STATUS_CREATED:
+      break;
+    case Profile::CREATE_STATUS_INITIALIZED:
+      if (profile_load_sequence_id == profile_load_sequence_id_)
+        callback.Run(profile);
+      DecrementPendingProfileLoads();
+      break;
+    case Profile::CREATE_STATUS_LOCAL_FAIL:
+    case Profile::CREATE_STATUS_REMOTE_FAIL:
+    case Profile::CREATE_STATUS_CANCELED:
+      DecrementPendingProfileLoads();
+      break;
+    case Profile::MAX_CREATE_STATUS:
+      NOTREACHED();
+      break;
+  }
+}
+
+void ProfileLoader::IncrementPendingProfileLoads() {
+  pending_profile_loads_++;
+  if (pending_profile_loads_ == 1)
+    chrome::StartKeepAlive();
+}
+
+void ProfileLoader::DecrementPendingProfileLoads() {
+  pending_profile_loads_--;
+  if (pending_profile_loads_ == 0)
+    chrome::EndKeepAlive();
+}
diff --git a/chrome/browser/profiles/profile_loader.h b/chrome/browser/profiles/profile_loader.h
new file mode 100644
index 0000000..b9b9038
--- /dev/null
+++ b/chrome/browser/profiles/profile_loader.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 CHROME_BROWSER_PROFILES_PROFILE_LOADER_H_
+#define CHROME_BROWSER_PROFILES_PROFILE_LOADER_H_
+
+#include "base/callback.h"
+#include "base/memory/weak_ptr.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_manager.h"
+
+namespace base {
+class FilePath;
+}
+
+class ProfileManager;
+
+// This class loads profiles asynchronously and calls the provided callback once
+// the profile is ready. Only the callback for the most recent load request is
+// called, and only if the load was successful.
+//
+// This is useful for loading profiles in response to user interaction where
+// only the latest requested profile is required.
+class ProfileLoader {
+ public:
+  explicit ProfileLoader(ProfileManager* profile_manager);
+  ~ProfileLoader();
+
+  bool IsAnyProfileLoading() const;
+  void InvalidatePendingProfileLoads();
+  void LoadProfileInvalidatingOtherLoads(
+      const base::FilePath& profile_file_path,
+      base::Callback<void(Profile*)> callback);
+
+ protected:
+  // These just call through to the ProfileManager.
+  // Virtual so they can be mocked out in tests.
+  virtual Profile* GetProfileByPath(const base::FilePath& path);
+  virtual void CreateProfileAsync(
+      const base::FilePath& profile_path,
+      const ProfileManager::CreateCallback& callback,
+      const string16& name,
+      const string16& icon_url,
+      bool is_managed);
+
+ private:
+  void OnProfileLoaded(int profile_load_sequence_id,
+                       base::Callback<void(Profile*)> callback,
+                       Profile* profile,
+                       Profile::CreateStatus status);
+
+  void IncrementPendingProfileLoads();
+  void DecrementPendingProfileLoads();
+
+  ProfileManager* profile_manager_;
+  int profile_load_sequence_id_;
+  int pending_profile_loads_;
+
+  base::WeakPtrFactory<ProfileLoader> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(ProfileLoader);
+};
+
+#endif  // CHROME_BROWSER_PROFILES_PROFILE_LOADER_H_
diff --git a/chrome/browser/profiles/profile_loader_unittest.cc b/chrome/browser/profiles/profile_loader_unittest.cc
new file mode 100644
index 0000000..3c3598b
--- /dev/null
+++ b/chrome/browser/profiles/profile_loader_unittest.cc
@@ -0,0 +1,132 @@
+// 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/profiles/profile_loader.h"
+
+#include <map>
+
+#include "base/bind.h"
+#include "base/files/file_path.h"
+#include "base/memory/weak_ptr.h"
+#include "chrome/browser/lifetime/application_lifetime.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_loader.h"
+#include "chrome/test/base/testing_profile.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+using ::testing::_;
+using ::testing::Invoke;
+using ::testing::Return;
+using ::testing::StrictMock;
+using ::testing::WithArgs;
+
+class TestProfileLoader : public ProfileLoader {
+ public:
+  TestProfileLoader() : ProfileLoader(NULL) {}
+  virtual ~TestProfileLoader() {}
+
+  MOCK_METHOD1(GetProfileByPath, Profile*(const base::FilePath&));
+  MOCK_METHOD5(CreateProfileAsync, void(const base::FilePath&,
+                                        const ProfileManager::CreateCallback&,
+                                        const string16&,
+                                        const string16&,
+                                        bool));
+
+  void SetCreateCallback(const base::FilePath& path,
+                         const ProfileManager::CreateCallback& callback) {
+    callbacks_[path] = callback;
+  }
+
+  void RunCreateCallback(const base::FilePath& path,
+                         Profile* profile,
+                         Profile::CreateStatus status) {
+    callbacks_[path].Run(profile, status);
+  }
+
+ private:
+  std::map<base::FilePath, ProfileManager::CreateCallback> callbacks_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestProfileLoader);
+};
+
+class MockCallback : public base::RefCountedThreadSafe<MockCallback> {
+ public:
+  MockCallback();
+  MOCK_METHOD1(Run, void(Profile*));
+
+ protected:
+  friend class base::RefCountedThreadSafe<MockCallback>;
+  virtual ~MockCallback();
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MockCallback);
+};
+
+MockCallback::MockCallback() {}
+MockCallback::~MockCallback() {}
+
+TEST(ProfileLoaderTest, LoadProfileInvalidatingOtherLoads) {
+  TestingProfile profile;
+  base::FilePath fake_profile_path_1 =
+      base::FilePath::FromUTF8Unsafe("fake/profile 1");
+  base::FilePath fake_profile_path_2 =
+      base::FilePath::FromUTF8Unsafe("fake/profile 2");
+
+  TestProfileLoader loader;
+  EXPECT_FALSE(loader.IsAnyProfileLoading());
+
+  // path_1 never loads.
+  EXPECT_CALL(loader, GetProfileByPath(fake_profile_path_1))
+      .WillRepeatedly(Return(static_cast<Profile*>(NULL)));
+  EXPECT_CALL(loader, CreateProfileAsync(fake_profile_path_1, _, _, _, false))
+      .WillRepeatedly(WithArgs<0, 1>(
+          Invoke(&loader, &TestProfileLoader::SetCreateCallback)));
+
+  // path_2 loads after the first request.
+  EXPECT_CALL(loader, GetProfileByPath(fake_profile_path_2))
+      .WillOnce(Return(static_cast<Profile*>(NULL)))
+      .WillRepeatedly(Return(&profile));
+  EXPECT_CALL(loader, CreateProfileAsync(fake_profile_path_2, _, _, _, false))
+      .WillRepeatedly(WithArgs<0, 1>(
+          Invoke(&loader, &TestProfileLoader::SetCreateCallback)));
+
+  // Try to load both paths twice.
+  // path_1_load is never called because it is first invalidated by the load
+  // request for (path_2), and then invalidated manually.
+  // path_2_load is called both times.
+  StrictMock<MockCallback>* path_1_load = new StrictMock<MockCallback>();
+  StrictMock<MockCallback>* path_2_load = new StrictMock<MockCallback>();
+  EXPECT_CALL(*path_2_load, Run(&profile))
+      .Times(2);
+
+  // Try to load path_1.
+  loader.LoadProfileInvalidatingOtherLoads(
+      fake_profile_path_1, base::Bind(&MockCallback::Run, path_1_load));
+  EXPECT_TRUE(loader.IsAnyProfileLoading());
+
+  // Try to load path_2, this invalidates the previous request.
+  loader.LoadProfileInvalidatingOtherLoads(
+      fake_profile_path_2, base::Bind(&MockCallback::Run, path_2_load));
+
+  // Finish the load request for path_1, then for path_2.
+  loader.RunCreateCallback(fake_profile_path_1, &profile,
+                           Profile::CREATE_STATUS_INITIALIZED);
+  loader.RunCreateCallback(fake_profile_path_2, &profile,
+                           Profile::CREATE_STATUS_INITIALIZED);
+  EXPECT_FALSE(loader.IsAnyProfileLoading());
+
+  // The second request for path_2 should return immediately.
+  loader.LoadProfileInvalidatingOtherLoads(
+      fake_profile_path_2, base::Bind(&MockCallback::Run, path_2_load));
+
+  // Make a second request for path_1, and invalidate it.
+  loader.LoadProfileInvalidatingOtherLoads(
+      fake_profile_path_1, base::Bind(&MockCallback::Run, path_1_load));
+  loader.InvalidatePendingProfileLoads();
+}
+
+}  // namespace
diff --git a/chrome/browser/profiles/profile_manager.cc b/chrome/browser/profiles/profile_manager.cc
index 5a06c72..7be5e41 100644
--- a/chrome/browser/profiles/profile_manager.cc
+++ b/chrome/browser/profiles/profile_manager.cc
@@ -34,7 +34,7 @@
 #include "chrome/browser/sync/profile_sync_service.h"
 #include "chrome/browser/sync/profile_sync_service_factory.h"
 #include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/webui/sync_promo/sync_promo_ui.h"
+#include "chrome/browser/ui/sync/sync_promo_ui.h"
 #include "chrome/common/chrome_constants.h"
 #include "chrome/common/chrome_notification_types.h"
 #include "chrome/common/chrome_paths_internal.h"
@@ -161,6 +161,11 @@
   ProfilesToDelete().push_back(path);
 }
 
+bool IsProfileMarkedForDeletion(const base::FilePath& profile_path) {
+  return std::find(ProfilesToDelete().begin(), ProfilesToDelete().end(),
+      profile_path) != ProfilesToDelete().end();
+}
+
 #if defined(OS_CHROMEOS)
 void CheckCryptohomeIsMounted(chromeos::DBusMethodCallStatus call_status,
                               bool is_mounted) {
@@ -197,8 +202,8 @@
     // Delete both the profile directory and its corresponding cache.
     base::FilePath cache_path;
     chrome::GetUserCacheDirectory(*it, &cache_path);
-    file_util::Delete(*it, true);
-    file_util::Delete(cache_path, true);
+    base::Delete(*it, true);
+    base::Delete(cache_path, true);
   }
   ProfilesToDelete().clear();
 }
@@ -494,8 +499,7 @@
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
 
   // Make sure that this profile is not pending deletion.
-  if (std::find(ProfilesToDelete().begin(), ProfilesToDelete().end(),
-      profile_path) != ProfilesToDelete().end()) {
+  if (IsProfileMarkedForDeletion(profile_path)) {
     if (!callback.is_null())
       callback.Run(NULL, Profile::CREATE_STATUS_LOCAL_FAIL);
     return;
@@ -1042,23 +1046,28 @@
     const base::FilePath& profile_dir,
     const CreateCallback& callback) {
   DCHECK(IsMultipleProfilesEnabled());
-
   PrefService* local_state = g_browser_process->local_state();
   ProfileInfoCache& cache = GetProfileInfoCache();
+
   if (profile_dir.BaseName().MaybeAsASCII() ==
       local_state->GetString(prefs::kProfileLastUsed)) {
     // Update the last used profile pref before closing browser windows. This
     // way the correct last used profile is set for any notification observers.
-    std::string last_non_managed_profile;
+    base::FilePath last_non_managed_profile_path;
     for (size_t i = 0; i < cache.GetNumberOfProfiles(); ++i) {
       base::FilePath cur_path = cache.GetPathOfProfileAtIndex(i);
-      if (cur_path != profile_dir && !cache.ProfileIsManagedAtIndex(i)) {
-        last_non_managed_profile = cur_path.BaseName().MaybeAsASCII();
+      // Make sure that this profile is not pending deletion.
+      if (cur_path != profile_dir && !cache.ProfileIsManagedAtIndex(i) &&
+          !IsProfileMarkedForDeletion(cur_path)) {
+        last_non_managed_profile_path = cur_path;
         break;
       }
     }
+
     // If we're deleting the last (non-managed) profile, then create a new
     // profile in its place.
+    const std::string last_non_managed_profile =
+        last_non_managed_profile_path.BaseName().MaybeAsASCII();
     if (last_non_managed_profile.empty()) {
       base::FilePath new_path = GenerateNextProfileDirectoryPath();
       // Make sure the last used profile path is pointing at it. This way the
@@ -1071,13 +1080,62 @@
                          string16(),
                          false);
     } else {
+      // On the Mac, the browser process is not killed when all browser windows
+      // are closed, so just in case we are deleting the active profile, and no
+      // other profile has been loaded, we must pre-load a next one.
+#if defined(OS_MACOSX)
+      CreateProfileAsync(last_non_managed_profile_path,
+                         base::Bind(&ProfileManager::OnNewActiveProfileLoaded,
+                                    base::Unretained(this),
+                                    profile_dir,
+                                    last_non_managed_profile_path,
+                                    callback),
+                         string16(),
+                         string16(),
+                         false);
+      return;
+#else
+      // For OS_MACOSX the pref is updated in the callback to make sure that
+      // it isn't used before the profile is actually loaded.
       local_state->SetString(prefs::kProfileLastUsed, last_non_managed_profile);
+#endif
     }
   }
+  FinishDeletingProfile(profile_dir);
+}
 
+void ProfileManager::OnNewActiveProfileLoaded(
+    const base::FilePath& profile_to_delete_path,
+    const base::FilePath& last_non_managed_profile_path,
+    const CreateCallback& original_callback,
+    Profile* loaded_profile,
+    Profile::CreateStatus status) {
+  DCHECK(status != Profile::CREATE_STATUS_LOCAL_FAIL &&
+         status != Profile::CREATE_STATUS_REMOTE_FAIL);
+
+  // Only run the code if the profile initialization has finished completely.
+  if (status == Profile::CREATE_STATUS_INITIALIZED) {
+    if (IsProfileMarkedForDeletion(last_non_managed_profile_path)) {
+      // If the profile we tried to load as the next active profile has been
+      // deleted, then retry deleting this profile to redo the logic to load
+      // the next available profile.
+      ScheduleProfileForDeletion(profile_to_delete_path, original_callback);
+    } else {
+      // Update the local state as promised in the ScheduleProfileForDeletion.
+      g_browser_process->local_state()->SetString(
+          prefs::kProfileLastUsed,
+          last_non_managed_profile_path.BaseName().MaybeAsASCII());
+      FinishDeletingProfile(profile_to_delete_path);
+    }
+  }
+}
+
+void ProfileManager::FinishDeletingProfile(const base::FilePath& profile_dir) {
+  ProfileInfoCache& cache = GetProfileInfoCache();
   // TODO(sail): Due to bug 88586 we don't delete the profile instance. Once we
   // start deleting the profile instance we need to close background apps too.
   Profile* profile = GetProfileByPath(profile_dir);
+
   if (profile) {
     BrowserList::CloseAllBrowsersWithProfile(profile);
 
diff --git a/chrome/browser/profiles/profile_manager.h b/chrome/browser/profiles/profile_manager.h
index 21f4033..1b2ba42 100644
--- a/chrome/browser/profiles/profile_manager.h
+++ b/chrome/browser/profiles/profile_manager.h
@@ -289,6 +289,9 @@
   // Returns true if the profile was added, false otherwise.
   bool AddProfile(Profile* profile);
 
+  // Schedules the profile at the given path to be deleted on shutdown.
+  void FinishDeletingProfile(const base::FilePath& profile_dir);
+
   // Registers profile with given info. Returns pointer to created ProfileInfo
   // entry.
   ProfileInfo* RegisterProfile(Profile* profile, bool created);
@@ -326,6 +329,17 @@
                     Profile* profile,
                     Profile::CreateStatus status);
 
+  // If the |loaded_profile| has been loaded succesfully (according to |status|)
+  // and isn't already scheduled for deletion, then finishes adding
+  // |profile_to_delete_dir| to the queue of profiles to be deleted, and updates
+  // the kProfileLastUsed preference based on |last_non_managed_profile_path|.
+  void OnNewActiveProfileLoaded(
+      const base::FilePath& profile_to_delete_path,
+      const base::FilePath& last_non_managed_profile_path,
+      const CreateCallback& original_callback,
+      Profile* loaded_profile,
+      Profile::CreateStatus status);
+
   content::NotificationRegistrar registrar_;
 
   // The path to the user data directory (DIR_USER_DATA).
diff --git a/chrome/browser/profiles/profile_manager_unittest.cc b/chrome/browser/profiles/profile_manager_unittest.cc
index adaf53a..dd46660 100644
--- a/chrome/browser/profiles/profile_manager_unittest.cc
+++ b/chrome/browser/profiles/profile_manager_unittest.cc
@@ -15,7 +15,6 @@
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chromeos/settings/cros_settings.h"
-#include "chrome/browser/extensions/event_router_forwarder.h"
 #include "chrome/browser/history/history_service.h"
 #include "chrome/browser/history/history_service_factory.h"
 #include "chrome/browser/io_thread.h"
@@ -97,7 +96,6 @@
 
   ProfileManagerTest()
       : local_state_(TestingBrowserProcess::GetGlobal()),
-        extension_event_router_forwarder_(new extensions::EventRouterForwarder),
         ui_thread_(BrowserThread::UI, &message_loop_),
         db_thread_(BrowserThread::DB, &message_loop_),
         file_thread_(BrowserThread::FILE, &message_loop_) {
@@ -120,6 +118,19 @@
     message_loop_.RunUntilIdle();
   }
 
+  // Helper function to create a profile with |name| for a profile |manager|.
+  void CreateProfileAsync(ProfileManager* manager,
+                          const std::string& name,
+                          MockObserver* mock_observer) {
+    manager->CreateProfileAsync(
+        temp_dir_.path().AppendASCII(name),
+        base::Bind(&MockObserver::OnProfileCreated,
+                   base::Unretained(mock_observer)),
+        UTF8ToUTF16(name),
+        string16(),
+        false);
+  }
+
 #if defined(OS_CHROMEOS)
   chromeos::ScopedTestDeviceSettingsService test_device_settings_service_;
   chromeos::ScopedTestCrosSettings test_cros_settings_;
@@ -128,9 +139,6 @@
   // The path to temporary directory used to contain the test operations.
   base::ScopedTempDir temp_dir_;
   ScopedTestingLocalState local_state_;
-  scoped_refptr<extensions::EventRouterForwarder>
-      extension_event_router_forwarder_;
-
   base::MessageLoopForUI message_loop_;
   content::TestBrowserThread ui_thread_;
   content::TestBrowserThread db_thread_;
@@ -240,17 +248,12 @@
 // Tests asynchronous profile creation mechanism.
 // Crashes: http://crbug.com/89421
 TEST_F(ProfileManagerTest, DISABLED_CreateProfileAsync) {
-  base::FilePath dest_path =
-      temp_dir_.path().Append(FILE_PATH_LITERAL("New Profile"));
-
   MockObserver mock_observer;
   EXPECT_CALL(mock_observer, OnProfileCreated(
       testing::NotNull(), NotFail())).Times(testing::AtLeast(1));
 
-  g_browser_process->profile_manager()->CreateProfileAsync(dest_path,
-      base::Bind(&MockObserver::OnProfileCreated,
-                 base::Unretained(&mock_observer)),
-      string16(), string16(), false);
+  CreateProfileAsync(g_browser_process->profile_manager(),
+                     "New Profile", &mock_observer);
 
   message_loop_.RunUntilIdle();
 }
@@ -262,9 +265,6 @@
 }
 
 TEST_F(ProfileManagerTest, CreateProfileAsyncMultipleRequests) {
-  base::FilePath dest_path =
-      temp_dir_.path().Append(FILE_PATH_LITERAL("New Profile"));
-
   g_created_profile = NULL;
 
   MockObserver mock_observer1;
@@ -278,28 +278,17 @@
       SameNotNull(), NotFail())).Times(testing::AtLeast(1));
 
   ProfileManager* profile_manager = g_browser_process->profile_manager();
-
-  profile_manager->CreateProfileAsync(dest_path,
-      base::Bind(&MockObserver::OnProfileCreated,
-                 base::Unretained(&mock_observer1)),
-                 string16(), string16(), false);
-  profile_manager->CreateProfileAsync(dest_path,
-      base::Bind(&MockObserver::OnProfileCreated,
-                 base::Unretained(&mock_observer2)),
-                 string16(), string16(), false);
-  profile_manager->CreateProfileAsync(dest_path,
-      base::Bind(&MockObserver::OnProfileCreated,
-                 base::Unretained(&mock_observer3)),
-                 string16(), string16(), false);
+  const std::string profile_name = "New Profile";
+  CreateProfileAsync(profile_manager, profile_name, &mock_observer1);
+  CreateProfileAsync(profile_manager, profile_name, &mock_observer2);
+  CreateProfileAsync(profile_manager, profile_name, &mock_observer3);
 
   message_loop_.RunUntilIdle();
 }
 
 TEST_F(ProfileManagerTest, CreateProfilesAsync) {
-  base::FilePath dest_path1 =
-      temp_dir_.path().Append(FILE_PATH_LITERAL("New Profile 1"));
-  base::FilePath dest_path2 =
-      temp_dir_.path().Append(FILE_PATH_LITERAL("New Profile 2"));
+  const std::string profile_name1 = "New Profile 1";
+  const std::string profile_name2 = "New Profile 2";
 
   MockObserver mock_observer;
   EXPECT_CALL(mock_observer, OnProfileCreated(
@@ -307,14 +296,8 @@
 
   ProfileManager* profile_manager = g_browser_process->profile_manager();
 
-  profile_manager->CreateProfileAsync(dest_path1,
-      base::Bind(&MockObserver::OnProfileCreated,
-                 base::Unretained(&mock_observer)),
-                 string16(), string16(), false);
-  profile_manager->CreateProfileAsync(dest_path2,
-      base::Bind(&MockObserver::OnProfileCreated,
-                 base::Unretained(&mock_observer)),
-                 string16(), string16(), false);
+  CreateProfileAsync(profile_manager, profile_name1, &mock_observer);
+  CreateProfileAsync(profile_manager, profile_name2, &mock_observer);
 
   message_loop_.RunUntilIdle();
 }
@@ -475,8 +458,7 @@
   ASSERT_EQ(0U, last_opened_profiles.size());
 
   // Create a browser for profile1.
-  Browser::CreateParams profile1_params(profile1,
-                                        chrome::HOST_DESKTOP_TYPE_NATIVE);
+  Browser::CreateParams profile1_params(profile1, chrome::GetActiveDesktop());
   scoped_ptr<Browser> browser1a(
       chrome::CreateBrowserWithTestWindowForParams(&profile1_params));
 
@@ -485,8 +467,7 @@
   EXPECT_EQ(profile1, last_opened_profiles[0]);
 
   // And for profile2.
-  Browser::CreateParams profile2_params(profile2,
-                                        chrome::HOST_DESKTOP_TYPE_NATIVE);
+  Browser::CreateParams profile2_params(profile2, chrome::GetActiveDesktop());
   scoped_ptr<Browser> browser2(
       chrome::CreateBrowserWithTestWindowForParams(&profile2_params));
 
@@ -539,14 +520,12 @@
   ASSERT_TRUE(profile2);
 
   // Create a browser for profile1.
-  Browser::CreateParams profile1_params(profile1,
-                                        chrome::HOST_DESKTOP_TYPE_NATIVE);
+  Browser::CreateParams profile1_params(profile1, chrome::GetActiveDesktop());
   scoped_ptr<Browser> browser1(
       chrome::CreateBrowserWithTestWindowForParams(&profile1_params));
 
   // And for profile2.
-  Browser::CreateParams profile2_params(profile2,
-                                        chrome::HOST_DESKTOP_TYPE_NATIVE);
+  Browser::CreateParams profile2_params(profile2, chrome::GetActiveDesktop());
   scoped_ptr<Browser> browser2(
       chrome::CreateBrowserWithTestWindowForParams(&profile2_params));
 
@@ -598,8 +577,7 @@
   ASSERT_EQ(0U, last_opened_profiles.size());
 
   // Create a browser for profile1.
-  Browser::CreateParams profile1_params(profile1,
-                                        chrome::HOST_DESKTOP_TYPE_NATIVE);
+  Browser::CreateParams profile1_params(profile1, chrome::GetActiveDesktop());
   scoped_ptr<Browser> browser1(
       chrome::CreateBrowserWithTestWindowForParams(&profile1_params));
 
@@ -608,8 +586,7 @@
   EXPECT_EQ(profile1, last_opened_profiles[0]);
 
   // And for profile2.
-  Browser::CreateParams profile2_params(profile2,
-                                        chrome::HOST_DESKTOP_TYPE_NATIVE);
+  Browser::CreateParams profile2_params(profile2, chrome::GetActiveDesktop());
   scoped_ptr<Browser> browser2a(
       chrome::CreateBrowserWithTestWindowForParams(&profile2_params));
 
@@ -640,3 +617,155 @@
   ASSERT_EQ(0U, last_opened_profiles.size());
 }
 #endif  // !defined(OS_ANDROID)
+
+#if !defined(OS_ANDROID) && !defined(OS_CHROMEOS)
+// There's no Browser object on Android and there's no multi-profiles on Chrome.
+TEST_F(ProfileManagerTest, ActiveProfileDeleted) {
+  ProfileManager* profile_manager = g_browser_process->profile_manager();
+  ASSERT_TRUE(profile_manager);
+
+  // Create and load two profiles.
+  const std::string profile_name1 = "New Profile 1";
+  const std::string profile_name2 = "New Profile 2";
+  base::FilePath dest_path1 =
+      temp_dir_.path().AppendASCII(profile_name1);
+  base::FilePath dest_path2 =
+      temp_dir_.path().AppendASCII(profile_name2);
+
+  MockObserver mock_observer;
+  EXPECT_CALL(mock_observer, OnProfileCreated(
+      testing::NotNull(), NotFail())).Times(testing::AtLeast(3));
+
+  CreateProfileAsync(profile_manager, profile_name1, &mock_observer);
+  CreateProfileAsync(profile_manager, profile_name2, &mock_observer);
+  message_loop_.RunUntilIdle();
+
+  EXPECT_EQ(2u, profile_manager->GetLoadedProfiles().size());
+  EXPECT_EQ(2u, profile_manager->GetProfileInfoCache().GetNumberOfProfiles());
+
+  // Set the active profile.
+  PrefService* local_state = g_browser_process->local_state();
+  local_state->SetString(prefs::kProfileLastUsed, profile_name1);
+
+  // Delete the active profile.
+  profile_manager->ScheduleProfileForDeletion(dest_path1,
+                                              ProfileManager::CreateCallback());
+  // Spin the message loop so that all the callbacks can finish running.
+  message_loop_.RunUntilIdle();
+
+  EXPECT_EQ(dest_path2, profile_manager->GetLastUsedProfile()->GetPath());
+  EXPECT_EQ(profile_name2, local_state->GetString(prefs::kProfileLastUsed));
+}
+#endif  // !defined(OS_ANDROID) && !defined(OS_CHROMEOS)
+
+#if defined(OS_MACOSX)
+// These tests are for a Mac-only code path that assumes the browser
+// process isn't killed when all browser windows are closed.
+TEST_F(ProfileManagerTest, ActiveProfileDeletedNeedsToLoadNextProfile) {
+  ProfileManager* profile_manager = g_browser_process->profile_manager();
+  ASSERT_TRUE(profile_manager);
+
+  // Create and load one profile, and just create a second profile.
+  const std::string profile_name1 = "New Profile 1";
+  const std::string profile_name2 = "New Profile 2";
+  base::FilePath dest_path1 =
+      temp_dir_.path().AppendASCII(profile_name1);
+  base::FilePath dest_path2 =
+      temp_dir_.path().AppendASCII(profile_name2);
+
+  MockObserver mock_observer;
+  EXPECT_CALL(mock_observer, OnProfileCreated(
+      testing::NotNull(), NotFail())).Times(testing::AtLeast(2));
+  CreateProfileAsync(profile_manager, profile_name1, &mock_observer);
+  message_loop_.RunUntilIdle();
+
+  // Track the profile, but don't load it.
+  ProfileInfoCache& cache = profile_manager->GetProfileInfoCache();
+  cache.AddProfileToCache(dest_path2, ASCIIToUTF16(profile_name2),
+                          string16(), 0, false);
+  message_loop_.RunUntilIdle();
+
+  EXPECT_EQ(1u, profile_manager->GetLoadedProfiles().size());
+  EXPECT_EQ(2u, cache.GetNumberOfProfiles());
+
+  // Set the active profile.
+  PrefService* local_state = g_browser_process->local_state();
+  local_state->SetString(prefs::kProfileLastUsed,
+                         dest_path1.BaseName().MaybeAsASCII());
+
+  // Delete the active profile. This should switch and load the unloaded
+  // profile.
+  profile_manager->ScheduleProfileForDeletion(dest_path1,
+                                              ProfileManager::CreateCallback());
+
+  // Spin the message loop so that all the callbacks can finish running.
+  message_loop_.RunUntilIdle();
+
+  EXPECT_EQ(dest_path2, profile_manager->GetLastUsedProfile()->GetPath());
+  EXPECT_EQ(profile_name2, local_state->GetString(prefs::kProfileLastUsed));
+}
+
+// This tests the recursive call in ProfileManager::OnNewActiveProfileLoaded
+// by simulating a scenario in which the profile that is being loaded as
+// the next active profile has also been marked for deletion, so the
+// ProfileManager needs to recursively select a different next profile.
+TEST_F(ProfileManagerTest, ActiveProfileDeletedNextProfileDeletedToo) {
+  ProfileManager* profile_manager = g_browser_process->profile_manager();
+  ASSERT_TRUE(profile_manager);
+
+  // Create and load one profile, and create two more profiles.
+  const std::string profile_name1 = "New Profile 1";
+  const std::string profile_name2 = "New Profile 2";
+  const std::string profile_name3 = "New Profile 3";
+  base::FilePath dest_path1 =
+      temp_dir_.path().AppendASCII(profile_name1);
+  base::FilePath dest_path2 =
+      temp_dir_.path().AppendASCII(profile_name2);
+  base::FilePath dest_path3 =
+      temp_dir_.path().AppendASCII(profile_name3);
+
+  MockObserver mock_observer;
+  EXPECT_CALL(mock_observer, OnProfileCreated(
+      testing::NotNull(), NotFail())).Times(testing::AtLeast(2));
+  CreateProfileAsync(profile_manager, profile_name1, &mock_observer);
+  message_loop_.RunUntilIdle();
+
+  // Create the other profiles, but don't load them. Assign a fake avatar icon
+  // to ensure that profiles in the info cache are sorted by the profile name,
+  // and not randomly by the avatar name.
+  ProfileInfoCache& cache = profile_manager->GetProfileInfoCache();
+  cache.AddProfileToCache(dest_path2, ASCIIToUTF16(profile_name2),
+                          ASCIIToUTF16(profile_name2), 1, false);
+  cache.AddProfileToCache(dest_path3, ASCIIToUTF16(profile_name3),
+                          ASCIIToUTF16(profile_name3), 2, false);
+
+  message_loop_.RunUntilIdle();
+
+  EXPECT_EQ(1u, profile_manager->GetLoadedProfiles().size());
+  EXPECT_EQ(3u, cache.GetNumberOfProfiles());
+
+  // Set the active profile.
+  PrefService* local_state = g_browser_process->local_state();
+  local_state->SetString(prefs::kProfileLastUsed,
+                         dest_path1.BaseName().MaybeAsASCII());
+
+  // Delete the active profile, Profile1.
+  // This will post a CreateProfileAsync message, that tries to load Profile2,
+  // which checks that the profile is not being deleted, and then calls back
+  // FinishDeletingProfile for Profile1.
+  // Try to break this flow by setting the active profile to Profile2 in the
+  // middle (so after the first posted message), and trying to delete Profile2,
+  // so that the ProfileManager has to look for a different profile to load.
+  profile_manager->ScheduleProfileForDeletion(dest_path1,
+                                              ProfileManager::CreateCallback());
+  local_state->SetString(prefs::kProfileLastUsed,
+                         dest_path2.BaseName().MaybeAsASCII());
+  profile_manager->ScheduleProfileForDeletion(dest_path2,
+                                              ProfileManager::CreateCallback());
+  // Spin the message loop so that all the callbacks can finish running.
+  message_loop_.RunUntilIdle();
+
+  EXPECT_EQ(dest_path3, profile_manager->GetLastUsedProfile()->GetPath());
+  EXPECT_EQ(profile_name3, local_state->GetString(prefs::kProfileLastUsed));
+}
+#endif  // !defined(OS_MACOSX)
diff --git a/chrome/browser/profiles/profile_shortcut_manager_unittest_win.cc b/chrome/browser/profiles/profile_shortcut_manager_unittest_win.cc
index c918574..e4eb340 100644
--- a/chrome/browser/profiles/profile_shortcut_manager_unittest_win.cc
+++ b/chrome/browser/profiles/profile_shortcut_manager_unittest_win.cc
@@ -391,7 +391,7 @@
       GetDefaultShortcutPathForProfile(profile_2_name_);
 
   // Delete the shortcut for the first profile, but keep the one for the 2nd.
-  ASSERT_TRUE(file_util::Delete(profile_1_shortcut_path, false));
+  ASSERT_TRUE(base::Delete(profile_1_shortcut_path, false));
   ASSERT_FALSE(file_util::PathExists(profile_1_shortcut_path));
   ASSERT_TRUE(file_util::PathExists(profile_2_shortcut_path));
 
@@ -415,7 +415,7 @@
       GetDefaultShortcutPathForProfile(profile_2_name_);
 
   // Delete the shortcut for the first profile, but keep the one for the 2nd.
-  ASSERT_TRUE(file_util::Delete(profile_1_shortcut_path, false));
+  ASSERT_TRUE(base::Delete(profile_1_shortcut_path, false));
   ASSERT_FALSE(file_util::PathExists(profile_1_shortcut_path));
   ASSERT_TRUE(file_util::PathExists(profile_2_shortcut_path));
 
@@ -444,8 +444,8 @@
       GetDefaultShortcutPathForProfile(profile_3_name_);
 
   // Delete shortcuts for the first two profiles.
-  ASSERT_TRUE(file_util::Delete(profile_1_shortcut_path, false));
-  ASSERT_TRUE(file_util::Delete(profile_2_shortcut_path, false));
+  ASSERT_TRUE(base::Delete(profile_1_shortcut_path, false));
+  ASSERT_TRUE(base::Delete(profile_2_shortcut_path, false));
 
   // Only the shortcut to the third profile should exist.
   ASSERT_FALSE(file_util::PathExists(profile_1_shortcut_path));
@@ -492,7 +492,7 @@
       GetDefaultShortcutPathForProfile(profile_2_name_);
   const base::FilePath profile_2_shortcut_path_2 =
       GetUserShortcutsDirectory().Append(L"MyChrome.lnk");
-  ASSERT_TRUE(file_util::Move(profile_2_shortcut_path_1,
+  ASSERT_TRUE(base::Move(profile_2_shortcut_path_1,
                               profile_2_shortcut_path_2));
 
   // Ensure that a new shortcut does not get made if the old one was renamed.
@@ -503,7 +503,7 @@
                                 profile_2_path_);
 
   // Delete the renamed shortcut and try to create it again, which should work.
-  ASSERT_TRUE(file_util::Delete(profile_2_shortcut_path_2, false));
+  ASSERT_TRUE(base::Delete(profile_2_shortcut_path_2, false));
   EXPECT_FALSE(file_util::PathExists(profile_2_shortcut_path_2));
   profile_shortcut_manager_->CreateProfileShortcut(profile_2_path_);
   RunPendingTasks();
@@ -574,7 +574,7 @@
 
   // Delete the shortcut that got created for this profile and instead make
   // a new one without any command-line flags.
-  ASSERT_TRUE(file_util::Delete(GetDefaultShortcutPathForProfile(string16()),
+  ASSERT_TRUE(base::Delete(GetDefaultShortcutPathForProfile(string16()),
                                 false));
   const base::FilePath regular_shortcut_path =
       CreateRegularShortcutWithName(FROM_HERE,
@@ -592,7 +592,7 @@
 
   // Delete the shortcut that got created for this profile and instead make
   // two new ones without any command-line flags.
-  ASSERT_TRUE(file_util::Delete(GetDefaultShortcutPathForProfile(string16()),
+  ASSERT_TRUE(base::Delete(GetDefaultShortcutPathForProfile(string16()),
                                 false));
   const base::FilePath regular_shortcut_path =
       CreateRegularShortcutWithName(FROM_HERE,
@@ -664,7 +664,7 @@
   // Delete the shortcut and check that the function returns false.
   const base::FilePath profile_2_shortcut_path =
       GetDefaultShortcutPathForProfile(profile_2_name_);
-  ASSERT_TRUE(file_util::Delete(profile_2_shortcut_path, false));
+  ASSERT_TRUE(base::Delete(profile_2_shortcut_path, false));
   EXPECT_FALSE(file_util::PathExists(profile_2_shortcut_path));
   profile_shortcut_manager_->HasProfileShortcuts(profile_2_path_, callback);
   RunPendingTasks();
@@ -752,7 +752,7 @@
       GetDefaultShortcutPathForProfile(profile_2_name_);
 
   // Delete the shortcut for the first profile, but keep the one for the 2nd.
-  ASSERT_TRUE(file_util::Delete(profile_1_shortcut_path, false));
+  ASSERT_TRUE(base::Delete(profile_1_shortcut_path, false));
   ASSERT_FALSE(file_util::PathExists(profile_1_shortcut_path));
   ASSERT_TRUE(file_util::PathExists(profile_2_shortcut_path));
 
diff --git a/chrome/browser/profiles/profile_shortcut_manager_win.cc b/chrome/browser/profiles/profile_shortcut_manager_win.cc
index abfb1d6..239a54e 100644
--- a/chrome/browser/profiles/profile_shortcut_manager_win.cc
+++ b/chrome/browser/profiles/profile_shortcut_manager_win.cc
@@ -255,7 +255,7 @@
 // Renames the given desktop shortcut and informs the shell of this change.
 bool RenameDesktopShortcut(const base::FilePath& old_shortcut_path,
                            const base::FilePath& new_shortcut_path) {
-  if (!file_util::Move(old_shortcut_path, new_shortcut_path))
+  if (!base::Move(old_shortcut_path, new_shortcut_path))
     return false;
 
   // Notify the shell of the rename, which allows the icon to keep its position
@@ -292,7 +292,7 @@
     const base::FilePath possible_new_system_shortcut =
         system_shortcuts_directory.Append(new_shortcut_filename);
     if (file_util::PathExists(possible_new_system_shortcut))
-      file_util::Delete(old_shortcut_path, false);
+      base::Delete(old_shortcut_path, false);
     else if (!RenameDesktopShortcut(old_shortcut_path, new_shortcut_path))
       DLOG(ERROR) << "Could not rename Windows profile desktop shortcut.";
   } else {
@@ -437,9 +437,9 @@
 
   BrowserDistribution* distribution = BrowserDistribution::GetDistribution();
   for (size_t i = 0; i < shortcuts.size(); ++i) {
-    // Use file_util::Delete() instead of ShellUtil::RemoveShortcut(), as the
+    // Use base::Delete() instead of ShellUtil::RemoveShortcut(), as the
     // latter causes non-profile taskbar shortcuts to be unpinned.
-    file_util::Delete(shortcuts[i], false);
+    base::Delete(shortcuts[i], false);
     // Notify the shell that the shortcut was deleted to ensure desktop refresh.
     SHChangeNotify(SHCNE_DELETE, SHCNF_PATH, shortcuts[i].value().c_str(),
                    NULL);
@@ -447,7 +447,7 @@
 
   const base::FilePath icon_path =
       profile_path.AppendASCII(profiles::internal::kProfileIconFileName);
-  file_util::Delete(icon_path, false);
+  base::Delete(icon_path, false);
 
   // If |ensure_shortcuts_remain| is true and deleting this profile caused the
   // last shortcuts to be removed, re-create a regular non-profile shortcut.
@@ -557,8 +557,7 @@
 // static
 bool ProfileShortcutManager::IsFeatureEnabled() {
   return BrowserDistribution::GetDistribution()->CanCreateDesktopShortcuts() &&
-      !CommandLine::ForCurrentProcess()->HasSwitch(switches::kUserDataDir) &&
-      !CommandLine::ForCurrentProcess()->HasSwitch(switches::kShowAppList);
+      !CommandLine::ForCurrentProcess()->HasSwitch(switches::kUserDataDir);
 }
 
 // static
diff --git a/chrome/browser/renderer_host/chrome_render_message_filter.cc b/chrome/browser/renderer_host/chrome_render_message_filter.cc
index 7166497..5ab3fe8 100644
--- a/chrome/browser/renderer_host/chrome_render_message_filter.cc
+++ b/chrome/browser/renderer_host/chrome_render_message_filter.cc
@@ -44,7 +44,7 @@
 #include "content/public/browser/resource_dispatcher_host.h"
 #include "content/public/common/process_type.h"
 #include "extensions/common/constants.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 #if defined(USE_TCMALLOC)
 #include "chrome/browser/browser_about_handler.h"
diff --git a/chrome/browser/renderer_host/chrome_render_widget_host_view_mac_delegate.h b/chrome/browser/renderer_host/chrome_render_widget_host_view_mac_delegate.h
index b13a4e0..b23dcad 100644
--- a/chrome/browser/renderer_host/chrome_render_widget_host_view_mac_delegate.h
+++ b/chrome/browser/renderer_host/chrome_render_widget_host_view_mac_delegate.h
@@ -58,7 +58,6 @@
 - (void)setHasHorizontalScrollbar:(BOOL)hasHorizontalScrollbar;
 - (BOOL)validateUserInterfaceItem:(id<NSValidatedUserInterfaceItem>)item
                       isValidItem:(BOOL*)valid;
-- (void)compositingIOSurfaceCreated;
 
 @end
 
diff --git a/chrome/browser/renderer_host/chrome_render_widget_host_view_mac_delegate.mm b/chrome/browser/renderer_host/chrome_render_widget_host_view_mac_delegate.mm
index 17dac1b..2961093 100644
--- a/chrome/browser/renderer_host/chrome_render_widget_host_view_mac_delegate.mm
+++ b/chrome/browser/renderer_host/chrome_render_widget_host_view_mac_delegate.mm
@@ -17,7 +17,6 @@
 #include "chrome/browser/ui/browser_finder.h"
 #import "chrome/browser/ui/cocoa/browser_window_controller.h"
 #import "chrome/browser/ui/cocoa/history_overlay_controller.h"
-#import "chrome/browser/ui/cocoa/tab_contents/overlayable_contents_controller.h"
 #import "chrome/browser/ui/cocoa/view_id_util.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/spellcheck_messages.h"
@@ -280,14 +279,6 @@
   return NO;
 }
 
-- (void)compositingIOSurfaceCreated {
-  NSView* nativeView = renderWidgetHost_->GetView()->GetNativeView();
-  BrowserWindowController* windowController =
-      [BrowserWindowController browserWindowControllerForView:nativeView];
-  [[windowController overlayableContentsController]
-        activeContentsCompositingIOSurfaceCreated];
-}
-
 // Spellchecking methods
 // The next five methods are implemented here since this class is the first
 // responder for anything in the browser.
diff --git a/chrome/browser/renderer_host/chrome_render_widget_host_view_mac_delegate_browsertest.cc b/chrome/browser/renderer_host/chrome_render_widget_host_view_mac_delegate_browsertest.cc
index 1a0949e..615b577 100644
--- a/chrome/browser/renderer_host/chrome_render_widget_host_view_mac_delegate_browsertest.cc
+++ b/chrome/browser/renderer_host/chrome_render_widget_host_view_mac_delegate_browsertest.cc
@@ -16,8 +16,8 @@
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/browser_test_utils.h"
-#include "googleurl/src/gurl.h"
 #include "net/base/net_util.h"
+#include "url/gurl.h"
 
 class ChromeRenderWidgetHostViewMacDelegateTest : public InProcessBrowserTest {
  public:
diff --git a/chrome/browser/renderer_host/chrome_resource_dispatcher_host_delegate.cc b/chrome/browser/renderer_host/chrome_resource_dispatcher_host_delegate.cc
index 2f33ef2..93df87e 100644
--- a/chrome/browser/renderer_host/chrome_resource_dispatcher_host_delegate.cc
+++ b/chrome/browser/renderer_host/chrome_resource_dispatcher_host_delegate.cc
@@ -207,8 +207,7 @@
     const std::string& method,
     const GURL& url,
     ResourceType::Type resource_type,
-    content::ResourceContext* resource_context,
-    const content::Referrer& referrer) {
+    content::ResourceContext* resource_context) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
 
   // Handle a PREFETCH resource type. If prefetch is disabled, squelch the
diff --git a/chrome/browser/renderer_host/chrome_resource_dispatcher_host_delegate.h b/chrome/browser/renderer_host/chrome_resource_dispatcher_host_delegate.h
index 9afd08a..5e81a17 100644
--- a/chrome/browser/renderer_host/chrome_resource_dispatcher_host_delegate.h
+++ b/chrome/browser/renderer_host/chrome_resource_dispatcher_host_delegate.h
@@ -42,8 +42,7 @@
       const std::string& method,
       const GURL& url,
       ResourceType::Type resource_type,
-      content::ResourceContext* resource_context,
-      const content::Referrer& referrer) OVERRIDE;
+      content::ResourceContext* resource_context) OVERRIDE;
   virtual void RequestBeginning(
       net::URLRequest* request,
       content::ResourceContext* resource_context,
diff --git a/chrome/browser/renderer_host/pepper/OWNERS b/chrome/browser/renderer_host/pepper/OWNERS
index 3abceff..dc19a03 100644
--- a/chrome/browser/renderer_host/pepper/OWNERS
+++ b/chrome/browser/renderer_host/pepper/OWNERS
@@ -1,2 +1,3 @@
+dmichael@chromium.org
 raymes@chromium.org
 yzshen@chromium.org
diff --git a/chrome/browser/renderer_host/pepper/pepper_broker_message_filter.cc b/chrome/browser/renderer_host/pepper/pepper_broker_message_filter.cc
index f5d7dd8..60ffa5c 100644
--- a/chrome/browser/renderer_host/pepper/pepper_broker_message_filter.cc
+++ b/chrome/browser/renderer_host/pepper/pepper_broker_message_filter.cc
@@ -12,11 +12,11 @@
 #include "content/public/browser/browser_ppapi_host.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/render_process_host.h"
-#include "googleurl/src/gurl.h"
 #include "ipc/ipc_message_macros.h"
 #include "ppapi/c/pp_errors.h"
 #include "ppapi/host/dispatch_host_message.h"
 #include "ppapi/proxy/ppapi_messages.h"
+#include "url/gurl.h"
 
 using content::BrowserPpapiHost;
 using content::BrowserThread;
diff --git a/chrome/browser/renderer_host/pepper/pepper_broker_message_filter.h b/chrome/browser/renderer_host/pepper/pepper_broker_message_filter.h
index d59f505..95b40fd 100644
--- a/chrome/browser/renderer_host/pepper/pepper_broker_message_filter.h
+++ b/chrome/browser/renderer_host/pepper/pepper_broker_message_filter.h
@@ -6,9 +6,9 @@
 #define CHROME_BROWSER_RENDERER_HOST_PEPPER_PEPPER_BROKER_MESSAGE_FILTER_H_
 
 #include "base/compiler_specific.h"
-#include "googleurl/src/gurl.h"
 #include "ppapi/c/pp_instance.h"
 #include "ppapi/host/resource_message_filter.h"
+#include "url/gurl.h"
 
 namespace content {
 class BrowserPpapiHost;
diff --git a/chrome/browser/renderer_host/pepper/pepper_crx_file_system_message_filter.h b/chrome/browser/renderer_host/pepper/pepper_crx_file_system_message_filter.h
index b970d11..0ab0c43 100644
--- a/chrome/browser/renderer_host/pepper/pepper_crx_file_system_message_filter.h
+++ b/chrome/browser/renderer_host/pepper/pepper_crx_file_system_message_filter.h
@@ -9,11 +9,11 @@
 #include <string>
 
 #include "base/files/file_path.h"
-#include "googleurl/src/gurl.h"
 #include "ppapi/c/pp_instance.h"
 #include "ppapi/c/pp_resource.h"
 #include "ppapi/host/resource_host.h"
 #include "ppapi/host/resource_message_filter.h"
+#include "url/gurl.h"
 
 class Profile;
 
diff --git a/chrome/browser/renderer_host/pepper/pepper_extensions_common_message_filter.h b/chrome/browser/renderer_host/pepper/pepper_extensions_common_message_filter.h
index d9dae5c..832e859 100644
--- a/chrome/browser/renderer_host/pepper/pepper_extensions_common_message_filter.h
+++ b/chrome/browser/renderer_host/pepper/pepper_extensions_common_message_filter.h
@@ -13,9 +13,9 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/strings/string16.h"
 #include "chrome/browser/extensions/extension_function.h"
-#include "googleurl/src/gurl.h"
 #include "ppapi/c/pp_instance.h"
 #include "ppapi/host/resource_message_filter.h"
+#include "url/gurl.h"
 
 struct ExtensionHostMsg_Request_Params;
 
diff --git a/chrome/browser/renderer_host/pepper/pepper_flash_browser_host.cc b/chrome/browser/renderer_host/pepper/pepper_flash_browser_host.cc
index 186bca3..85849cf 100644
--- a/chrome/browser/renderer_host/pepper/pepper_flash_browser_host.cc
+++ b/chrome/browser/renderer_host/pepper/pepper_flash_browser_host.cc
@@ -4,14 +4,13 @@
 
 #include "chrome/browser/renderer_host/pepper/pepper_flash_browser_host.h"
 
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/content_settings/cookie_settings.h"
 #include "chrome/browser/profiles/profile.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_ppapi_host.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/render_process_host.h"
-#include "googleurl/src/gurl.h"
 #include "ipc/ipc_message_macros.h"
 #include "ppapi/c/pp_errors.h"
 #include "ppapi/c/private/ppb_flash.h"
@@ -19,6 +18,7 @@
 #include "ppapi/proxy/ppapi_messages.h"
 #include "ppapi/proxy/resource_message_params.h"
 #include "ppapi/shared_impl/time_conversion.h"
+#include "url/gurl.h"
 
 #if defined(OS_WIN)
 #include <windows.h>
diff --git a/chrome/browser/renderer_host/pepper/pepper_talk_host.cc b/chrome/browser/renderer_host/pepper/pepper_talk_host.cc
index 5251578..3151e69 100644
--- a/chrome/browser/renderer_host/pepper/pepper_talk_host.cc
+++ b/chrome/browser/renderer_host/pepper/pepper_talk_host.cc
@@ -19,6 +19,7 @@
 #if defined(USE_ASH)
 #include "ash/shell.h"
 #include "ash/shell_window_ids.h"
+#include "ash/system/tray/system_tray_notifier.h"
 #include "chrome/browser/ui/simple_message_box.h"
 #include "ui/aura/window.h"
 #endif
@@ -28,6 +29,7 @@
 namespace {
 
 ppapi::host::ReplyMessageContext GetPermissionOnUIThread(
+    PP_TalkPermission permission,
     int render_process_id,
     int render_view_id,
     ppapi::host::ReplyMessageContext reply) {
@@ -40,13 +42,32 @@
     return reply;  // RVH destroyed while task was pending.
 
 #if defined(USE_ASH)
+  string16 title;
+  string16 message;
+
+  switch (permission) {
+    case PP_TALKPERMISSION_SCREENCAST:
+      title = l10n_util::GetStringUTF16(IDS_GTALK_SCREEN_SHARE_DIALOG_TITLE);
+      message = l10n_util::GetStringUTF16(
+          IDS_GTALK_SCREEN_SHARE_DIALOG_MESSAGE);
+      break;
+    case PP_TALKPERMISSION_REMOTING:
+      title = l10n_util::GetStringUTF16(IDS_GTALK_REMOTING_DIALOG_TITLE);
+      message = l10n_util::GetStringUTF16(
+          IDS_GTALK_REMOTING_DIALOG_MESSAGE);
+      break;
+    case PP_TALKPERMISSION_REMOTING_CONTINUE:
+      title = l10n_util::GetStringUTF16(IDS_GTALK_REMOTING_DIALOG_TITLE);
+      message = l10n_util::GetStringUTF16(
+          IDS_GTALK_REMOTING_CONTINUE_DIALOG_MESSAGE);
+      break;
+    default:
+      NOTREACHED();
+      return reply;
+  }
+
   // TODO(brettw). We should not be grabbing the active toplevel window, we
   // should use the toplevel window associated with the render view.
-  const string16 title = l10n_util::GetStringUTF16(
-      IDS_GTALK_SCREEN_SHARE_DIALOG_TITLE);
-  const string16 message = l10n_util::GetStringUTF16(
-      IDS_GTALK_SCREEN_SHARE_DIALOG_MESSAGE);
-
   aura::Window* parent = ash::Shell::GetContainer(
       ash::Shell::GetActiveRootWindow(),
       ash::internal::kShellWindowId_SystemModalContainer);
@@ -60,6 +81,57 @@
   return reply;
 }
 
+void OnTerminateRemotingEventOnUIThread(const base::Closure& stop_callback) {
+  content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE,
+                                   stop_callback);
+}
+
+ppapi::host::ReplyMessageContext StartRemotingOnUIThread(
+    const base::Closure& stop_callback,
+    int render_process_id,
+    int render_view_id,
+    ppapi::host::ReplyMessageContext reply) {
+  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+  content::RenderViewHost* render_view_host =
+      content::RenderViewHost::FromID(render_process_id, render_view_id);
+  if (!render_view_host) {
+    reply.params.set_result(PP_ERROR_FAILED);
+    return reply;  // RVH destroyed while task was pending.
+  }
+
+#if defined(USE_ASH) && defined(OS_CHROMEOS)
+  base::Closure stop_callback_ui_thread = base::Bind(
+      &OnTerminateRemotingEventOnUIThread,
+      stop_callback);
+
+  ash::Shell::GetInstance()->system_tray_notifier()->NotifyScreenShareStart(
+      stop_callback_ui_thread, base::string16());
+  reply.params.set_result(PP_OK);
+#else
+  NOTIMPLEMENTED();
+  reply.params.set_result(PP_ERROR_NOTSUPPORTED);
+#endif
+  return reply;
+}
+
+void StopRemotingOnUIThread() {
+  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+#if defined(USE_ASH) && defined(OS_CHROMEOS)
+  if (ash::Shell::GetInstance()) {
+    ash::Shell::GetInstance()->system_tray_notifier()->NotifyScreenShareStop();
+  }
+#else
+  NOTIMPLEMENTED();
+#endif
+}
+
+ppapi::host::ReplyMessageContext StopRemotingOnUIThreadWithResult(
+    ppapi::host::ReplyMessageContext reply) {
+  reply.params.set_result(PP_OK);
+  StopRemotingOnUIThread();
+  return reply;
+}
+
 }  // namespace
 
 PepperTalkHost::PepperTalkHost(content::BrowserPpapiHost* host,
@@ -67,10 +139,16 @@
                                PP_Resource resource)
     : ppapi::host::ResourceHost(host->GetPpapiHost(), instance, resource),
       weak_factory_(this),
-      browser_ppapi_host_(host) {
+      browser_ppapi_host_(host),
+      remoting_started_(false) {
 }
 
 PepperTalkHost::~PepperTalkHost() {
+  if (remoting_started_) {
+    content::BrowserThread::PostTask(
+        content::BrowserThread::UI, FROM_HERE,
+        base::Bind(&StopRemotingOnUIThread));
+  }
 }
 
 int32_t PepperTalkHost::OnResourceMessageReceived(
@@ -90,8 +168,8 @@
 int32_t PepperTalkHost::OnRequestPermission(
     ppapi::host::HostMessageContext* context,
     PP_TalkPermission permission) {
-  // TODO(dcaiafa): Implement support for other permission types.
-  if (permission != PP_TALKPERMISSION_SCREENCAST)
+  if (permission < PP_TALKPERMISSION_SCREENCAST ||
+      permission >= PP_TALKPERMISSION_NUM_PERMISSIONS)
     return PP_ERROR_BADARGUMENT;
 
   int render_process_id = 0;
@@ -101,31 +179,73 @@
 
   content::BrowserThread::PostTaskAndReplyWithResult(
       content::BrowserThread::UI, FROM_HERE,
-      base::Bind(&GetPermissionOnUIThread, render_process_id, render_view_id,
-                 context->MakeReplyMessageContext()),
-      base::Bind(&PepperTalkHost::GotTalkPermission,
+      base::Bind(&GetPermissionOnUIThread, permission, render_process_id,
+                 render_view_id, context->MakeReplyMessageContext()),
+      base::Bind(&PepperTalkHost::OnRequestPermissionCompleted,
                  weak_factory_.GetWeakPtr()));
   return PP_OK_COMPLETIONPENDING;
 }
 
-void PepperTalkHost::GotTalkPermission(
+int32_t PepperTalkHost::OnStartRemoting(
+    ppapi::host::HostMessageContext* context) {
+  int render_process_id = 0;
+  int render_view_id = 0;
+  browser_ppapi_host_->GetRenderViewIDsForInstance(
+      pp_instance(), &render_process_id, &render_view_id);
+
+  base::Closure remoting_stop_callback = base::Bind(
+      &PepperTalkHost::OnRemotingStopEvent,
+      weak_factory_.GetWeakPtr());
+
+  content::BrowserThread::PostTaskAndReplyWithResult(
+      content::BrowserThread::UI, FROM_HERE,
+      base::Bind(&StartRemotingOnUIThread, remoting_stop_callback,
+                 render_process_id, render_view_id,
+                 context->MakeReplyMessageContext()),
+      base::Bind(&PepperTalkHost::OnStartRemotingCompleted,
+                 weak_factory_.GetWeakPtr()));
+  return PP_OK_COMPLETIONPENDING;
+}
+
+int32_t PepperTalkHost::OnStopRemoting(
+    ppapi::host::HostMessageContext* context) {
+  content::BrowserThread::PostTaskAndReplyWithResult(
+      content::BrowserThread::UI, FROM_HERE,
+      base::Bind(&StopRemotingOnUIThreadWithResult,
+                 context->MakeReplyMessageContext()),
+      base::Bind(&PepperTalkHost::OnStopRemotingCompleted,
+                 weak_factory_.GetWeakPtr()));
+  return PP_OK_COMPLETIONPENDING;
+}
+
+void PepperTalkHost::OnRemotingStopEvent() {
+  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
+  remoting_started_ = false;
+  host()->SendUnsolicitedReply(
+      pp_resource(), PpapiPluginMsg_Talk_NotifyEvent(PP_TALKEVENT_TERMINATE));
+}
+
+void PepperTalkHost::OnRequestPermissionCompleted(
     ppapi::host::ReplyMessageContext reply) {
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
   host()->SendReply(reply, PpapiPluginMsg_Talk_RequestPermissionReply());
 }
 
-int32_t PepperTalkHost::OnStartRemoting(
-    ppapi::host::HostMessageContext* context) {
-  // TODO(dcaiafa): Request IPC audit when this is implemented
-  NOTIMPLEMENTED();
-  return PP_ERROR_FAILED;
+void PepperTalkHost::OnStartRemotingCompleted(
+    ppapi::host::ReplyMessageContext reply) {
+  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
+  // Remember to hide remoting UI when resource is deleted.
+  if (reply.params.result() == PP_OK)
+    remoting_started_ = true;
+
+  host()->SendReply(reply, PpapiPluginMsg_Talk_StartRemotingReply());
 }
 
-int32_t PepperTalkHost::OnStopRemoting(
-    ppapi::host::HostMessageContext* context) {
-  // TODO(dcaiafa): Request IPC audit when this is implemented
-  NOTIMPLEMENTED();
-  return PP_ERROR_FAILED;
+void PepperTalkHost::OnStopRemotingCompleted(
+    ppapi::host::ReplyMessageContext reply) {
+  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
+  remoting_started_ = false;
+  host()->SendReply(reply, PpapiPluginMsg_Talk_StopRemotingReply());
 }
 
 }  // namespace chrome
diff --git a/chrome/browser/renderer_host/pepper/pepper_talk_host.h b/chrome/browser/renderer_host/pepper/pepper_talk_host.h
index 3b754fd..c5ca13b 100644
--- a/chrome/browser/renderer_host/pepper/pepper_talk_host.h
+++ b/chrome/browser/renderer_host/pepper/pepper_talk_host.h
@@ -29,25 +29,25 @@
                  PP_Resource resource);
   virtual ~PepperTalkHost();
 
+ private:
   // ResourceHost override.
   virtual int32_t OnResourceMessageReceived(
       const IPC::Message& msg,
       ppapi::host::HostMessageContext* context) OVERRIDE;
 
-  // Sends the reply.
-  void GotTalkPermission(ppapi::host::ReplyMessageContext reply);
+  int32_t OnRequestPermission(ppapi::host::HostMessageContext* context,
+                              PP_TalkPermission permission);
+  int32_t OnStartRemoting(ppapi::host::HostMessageContext* context);
+  int32_t OnStopRemoting(ppapi::host::HostMessageContext* context);
+  void OnRemotingStopEvent();
 
- private:
-  int32_t OnRequestPermission(
-      ppapi::host::HostMessageContext* context,
-      PP_TalkPermission permission);
-  int32_t OnStartRemoting(
-      ppapi::host::HostMessageContext* context);
-  int32_t OnStopRemoting(
-      ppapi::host::HostMessageContext* context);
+  void OnRequestPermissionCompleted(ppapi::host::ReplyMessageContext reply);
+  void OnStartRemotingCompleted(ppapi::host::ReplyMessageContext reply);
+  void OnStopRemotingCompleted(ppapi::host::ReplyMessageContext reply);
 
   base::WeakPtrFactory<PepperTalkHost> weak_factory_;
   content::BrowserPpapiHost* browser_ppapi_host_;
+  bool remoting_started_;
 
   DISALLOW_COPY_AND_ASSIGN(PepperTalkHost);
 };
diff --git a/chrome/browser/renderer_host/render_process_host_chrome_browsertest.cc b/chrome/browser/renderer_host/render_process_host_chrome_browsertest.cc
index d92ec09..cdc9e9e 100644
--- a/chrome/browser/renderer_host/render_process_host_chrome_browsertest.cc
+++ b/chrome/browser/renderer_host/render_process_host_chrome_browsertest.cc
@@ -3,11 +3,13 @@
 // found in the LICENSE file.
 
 #include "base/command_line.h"
+#include "base/process_util.h"
 #include "chrome/browser/devtools/devtools_window.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_commands.h"
 #include "chrome/browser/ui/singleton_tabs.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/common/chrome_notification_types.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/test/base/in_process_browser_test.h"
@@ -16,6 +18,7 @@
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_observer.h"
 
 using content::RenderViewHost;
 using content::RenderWidgetHost;
@@ -36,27 +39,17 @@
 }
 
 RenderViewHost* FindFirstDevToolsHost() {
-  content::RenderProcessHost::iterator hosts =
-      content::RenderProcessHost::AllHostsIterator();
-  for (; !hosts.IsAtEnd(); hosts.Advance()) {
-    content::RenderProcessHost* render_process_host = hosts.GetCurrentValue();
-    DCHECK(render_process_host);
-    if (!render_process_host->HasConnection())
+  RenderWidgetHost::List widgets = RenderWidgetHost::GetRenderWidgetHosts();
+  for (size_t i = 0; i < widgets.size(); ++i) {
+    if (!widgets[i]->GetProcess()->HasConnection())
       continue;
-    content::RenderProcessHost::RenderWidgetHostsIterator iter(
-        render_process_host->GetRenderWidgetHostsIterator());
-    for (; !iter.IsAtEnd(); iter.Advance()) {
-      const RenderWidgetHost* widget = iter.GetCurrentValue();
-      DCHECK(widget);
-      if (!widget || !widget->IsRenderView())
-        continue;
-      RenderViewHost* host =
-          RenderViewHost::From(const_cast<RenderWidgetHost*>(widget));
-      WebContents* contents = WebContents::FromRenderViewHost(host);
-      GURL url = contents->GetURL();
-      if (url.SchemeIs(chrome::kChromeDevToolsScheme))
-        return host;
-    }
+    if (!widgets[i]->IsRenderView())
+      continue;
+    RenderViewHost* host = RenderViewHost::From(widgets[i]);
+    WebContents* contents = WebContents::FromRenderViewHost(host);
+    GURL url = contents->GetURL();
+    if (url.SchemeIs(chrome::kChromeDevToolsScheme))
+      return host;
   }
   return NULL;
 }
@@ -362,3 +355,66 @@
   EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
   EXPECT_EQ(host_count, RenderProcessHostCount());
 }
+
+// This class's goal is to close the browser window when a renderer process has
+// crashed. It does so by monitoring WebContents for RenderViewGone event and
+// closing the passed in TabStripModel. This is used in the following test case.
+class WindowDestroyer : public content::WebContentsObserver {
+ public:
+  WindowDestroyer(content::WebContents* web_contents, TabStripModel* model)
+      : content::WebContentsObserver(web_contents),
+        tab_strip_model_(model) {
+  }
+
+  virtual void RenderViewGone(base::TerminationStatus status) OVERRIDE {
+    // Wait for the window to be destroyed, which will ensure all other
+    // RenderViewHost objects are deleted before we return and proceed with
+    // the next iteration of notifications.
+    content::WindowedNotificationObserver observer(
+        chrome::NOTIFICATION_BROWSER_CLOSED,
+        content::NotificationService::AllSources());
+    tab_strip_model_->CloseAllTabs();
+    observer.Wait();
+  }
+
+ private:
+  TabStripModel* tab_strip_model_;
+
+  DISALLOW_COPY_AND_ASSIGN(WindowDestroyer);
+};
+
+// Test to ensure that while iterating through all listeners in
+// RenderProcessHost and invalidating them, we remove them properly and don't
+// access already freed objects. See http://crbug.com/255524.
+IN_PROC_BROWSER_TEST_F(ChromeRenderProcessHostTest,
+                       CloseAllTabsDuringProcessDied) {
+  GURL url(chrome::kChromeUINewTabURL);
+
+  ui_test_utils::NavigateToURL(browser(), url);
+  ui_test_utils::NavigateToURLWithDisposition(
+      browser(), url, NEW_BACKGROUND_TAB,
+      ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
+
+  EXPECT_EQ(2, browser()->tab_strip_model()->count());
+
+  WebContents* wc1 = browser()->tab_strip_model()->GetWebContentsAt(0);
+  WebContents* wc2 = browser()->tab_strip_model()->GetWebContentsAt(1);
+  EXPECT_EQ(wc1->GetRenderProcessHost(), wc2->GetRenderProcessHost());
+
+  // Create an object that will close the window on a process crash.
+  WindowDestroyer destroyer(wc1, browser()->tab_strip_model());
+
+  // Use NOTIFICATION_BROWSER_CLOSED instead of NOTIFICATION_WINDOW_CLOSED,
+  // since the latter is not implemented on OSX and the test will timeout,
+  // causing it to fail.
+  content::WindowedNotificationObserver observer(
+      chrome::NOTIFICATION_BROWSER_CLOSED,
+      content::NotificationService::AllSources());
+
+  // Kill the renderer process, simulating a crash. This should the ProcessDied
+  // method to be called. Alternatively, RenderProcessHost::OnChannelError can
+  // be called to directly force a call to ProcessDied.
+  base::KillProcess(wc1->GetRenderProcessHost()->GetHandle(), -1, true);
+
+  observer.Wait();
+}
diff --git a/chrome/browser/renderer_host/safe_browsing_resource_throttle.h b/chrome/browser/renderer_host/safe_browsing_resource_throttle.h
index 9d46fcc..3a0a16a 100644
--- a/chrome/browser/renderer_host/safe_browsing_resource_throttle.h
+++ b/chrome/browser/renderer_host/safe_browsing_resource_throttle.h
@@ -9,8 +9,8 @@
 #include <vector>
 
 #include "base/memory/ref_counted.h"
-#include "base/time.h"
-#include "base/timer.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
 #include "chrome/browser/safe_browsing/database_manager.h"
 #include "chrome/browser/safe_browsing/ui_manager.h"
 #include "content/public/browser/resource_throttle.h"
diff --git a/chrome/browser/renderer_host/web_cache_manager.cc b/chrome/browser/renderer_host/web_cache_manager.cc
index 812fcca..0136501 100644
--- a/chrome/browser/renderer_host/web_cache_manager.cc
+++ b/chrome/browser/renderer_host/web_cache_manager.cc
@@ -14,7 +14,7 @@
 #include "base/prefs/pref_registry_simple.h"
 #include "base/prefs/pref_service.h"
 #include "base/sys_info.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/common/chrome_constants.h"
 #include "chrome/common/chrome_notification_types.h"
diff --git a/chrome/browser/renderer_host/web_cache_manager.h b/chrome/browser/renderer_host/web_cache_manager.h
index c190752..d142dcc 100644
--- a/chrome/browser/renderer_host/web_cache_manager.h
+++ b/chrome/browser/renderer_host/web_cache_manager.h
@@ -16,7 +16,7 @@
 #include "base/compiler_specific.h"
 #include "base/gtest_prod_util.h"
 #include "base/memory/weak_ptr.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
 #include "third_party/WebKit/public/web/WebCache.h"
diff --git a/chrome/browser/renderer_preferences_util.cc b/chrome/browser/renderer_preferences_util.cc
index c948cd3..a0f57f9 100644
--- a/chrome/browser/renderer_preferences_util.cc
+++ b/chrome/browser/renderer_preferences_util.cc
@@ -108,12 +108,13 @@
 #elif defined(USE_DEFAULT_RENDER_THEME)
   prefs->focus_ring_color = SkColorSetRGB(0x4D, 0x90, 0xFE);
 
+#if !defined(OS_WIN)
   // This color is 0x544d90fe modulated with 0xffffff.
   prefs->active_selection_bg_color = SkColorSetRGB(0xCB, 0xE4, 0xFA);
   prefs->active_selection_fg_color = SK_ColorBLACK;
   prefs->inactive_selection_bg_color = SkColorSetRGB(0xEA, 0xEA, 0xEA);
   prefs->inactive_selection_fg_color = SK_ColorBLACK;
-
+#endif
   // WebKit accepts a single parameter to control the interval over which the
   // cursor is shown or hidden, so divide Views's time for the full cycle by two
   // and then convert to seconds.
diff --git a/chrome/browser/resources/2x/downloads_section.png b/chrome/browser/resources/2x/downloads_section.png
index 9e11256..60d7089 100644
--- a/chrome/browser/resources/2x/downloads_section.png
+++ b/chrome/browser/resources/2x/downloads_section.png
Binary files differ
diff --git a/chrome/browser/resources/2x/ssl_roadblock_icon.png b/chrome/browser/resources/2x/ssl_roadblock_icon.png
index 4c3e693..1182d99 100644
--- a/chrome/browser/resources/2x/ssl_roadblock_icon.png
+++ b/chrome/browser/resources/2x/ssl_roadblock_icon.png
Binary files differ
diff --git a/chrome/browser/resources/2x/twisty_closed.png b/chrome/browser/resources/2x/twisty_closed.png
index 0a186b9..f55c41d 100644
--- a/chrome/browser/resources/2x/twisty_closed.png
+++ b/chrome/browser/resources/2x/twisty_closed.png
Binary files differ
diff --git a/chrome/browser/resources/2x/twisty_closed_rtl.png b/chrome/browser/resources/2x/twisty_closed_rtl.png
index 81ec960..3f5548a 100644
--- a/chrome/browser/resources/2x/twisty_closed_rtl.png
+++ b/chrome/browser/resources/2x/twisty_closed_rtl.png
Binary files differ
diff --git a/chrome/browser/resources/2x/twisty_open.png b/chrome/browser/resources/2x/twisty_open.png
index fc4c976..055eb3b 100644
--- a/chrome/browser/resources/2x/twisty_open.png
+++ b/chrome/browser/resources/2x/twisty_open.png
Binary files differ
diff --git a/chrome/browser/resources/about_welcome_android/images/holo_logo_150.png b/chrome/browser/resources/about_welcome_android/images/holo_logo_150.png
index 5fc9c69..5815344 100644
--- a/chrome/browser/resources/about_welcome_android/images/holo_logo_150.png
+++ b/chrome/browser/resources/about_welcome_android/images/holo_logo_150.png
Binary files differ
diff --git a/chrome/browser/resources/about_welcome_android/images/holo_logo_200.png b/chrome/browser/resources/about_welcome_android/images/holo_logo_200.png
index 2a7ff1b..a3e111d9 100644
--- a/chrome/browser/resources/about_welcome_android/images/holo_logo_200.png
+++ b/chrome/browser/resources/about_welcome_android/images/holo_logo_200.png
Binary files differ
diff --git a/chrome/browser/resources/apps_debugger/images/dev-icon-128.png b/chrome/browser/resources/apps_debugger/images/dev-icon-128.png
index 2c1d6c6..3b046e9 100644
--- a/chrome/browser/resources/apps_debugger/images/dev-icon-128.png
+++ b/chrome/browser/resources/apps_debugger/images/dev-icon-128.png
Binary files differ
diff --git a/chrome/browser/resources/apps_debugger/images/dev-icon-16.png b/chrome/browser/resources/apps_debugger/images/dev-icon-16.png
index dc29b7b..865c23c 100644
--- a/chrome/browser/resources/apps_debugger/images/dev-icon-16.png
+++ b/chrome/browser/resources/apps_debugger/images/dev-icon-16.png
Binary files differ
diff --git a/chrome/browser/resources/apps_debugger/images/run.png b/chrome/browser/resources/apps_debugger/images/run.png
index e0f46ba..811bc92 100644
--- a/chrome/browser/resources/apps_debugger/images/run.png
+++ b/chrome/browser/resources/apps_debugger/images/run.png
Binary files differ
diff --git a/chrome/browser/resources/apps_debugger/js/items_list.js b/chrome/browser/resources/apps_debugger/js/items_list.js
index 01ab1fe..74ddfc8 100644
--- a/chrome/browser/resources/apps_debugger/js/items_list.js
+++ b/chrome/browser/resources/apps_debugger/js/items_list.js
@@ -239,7 +239,7 @@
       if (!item.terminated)
         this.setEnabledCheckbox_(item, node);
       else
-        this.setTerminatedReloadLink_(node, item);
+        this.setTerminatedReloadLink_(item, node);
 
       // Set remove button handler.
       this.setRemoveButton_(item, node);
@@ -312,10 +312,12 @@
      */
     setTerminatedReloadLink_: function(item, el) {
       var terminatedReload = el.querySelector('.terminated-reload-link');
-      terminatedReload.hidden = false;
-      chrome.developerPrivate.reload(item.id, function() {
-        ItemsList.loadItemsInfo();
+      terminatedReload.addEventListener('click', function(e) {
+        chrome.developerPrivate.reload(item.id, function() {
+          ItemsList.loadItemsInfo();
+        });
       });
+      terminatedReload.hidden = false;
     },
 
     /**
diff --git a/chrome/browser/resources/apps_debugger/js/main.js b/chrome/browser/resources/apps_debugger/js/main.js
index 7623db6..2590f8b 100644
--- a/chrome/browser/resources/apps_debugger/js/main.js
+++ b/chrome/browser/resources/apps_debugger/js/main.js
@@ -24,3 +24,7 @@
 chrome.management.onUninstalled.addListener(function() {
   ItemList.loadItemsInfo();
 });
+
+chrome.developerPrivate.onItemStateChanged.addListener(function(response) {
+  ItemList.loadItemsInfo();
+});
diff --git a/chrome/browser/resources/bookmark_manager/images/2x/bookmark_manager_recent.png b/chrome/browser/resources/bookmark_manager/images/2x/bookmark_manager_recent.png
index 697163c..d39e505 100644
--- a/chrome/browser/resources/bookmark_manager/images/2x/bookmark_manager_recent.png
+++ b/chrome/browser/resources/bookmark_manager/images/2x/bookmark_manager_recent.png
Binary files differ
diff --git a/chrome/browser/resources/bookmark_manager/images/2x/bookmark_manager_search.png b/chrome/browser/resources/bookmark_manager/images/2x/bookmark_manager_search.png
index c10e4c0..438c678 100644
--- a/chrome/browser/resources/bookmark_manager/images/2x/bookmark_manager_search.png
+++ b/chrome/browser/resources/bookmark_manager/images/2x/bookmark_manager_search.png
Binary files differ
diff --git a/chrome/browser/resources/bookmark_manager/images/2x/bookmark_manager_search_rtl.png b/chrome/browser/resources/bookmark_manager/images/2x/bookmark_manager_search_rtl.png
index ed38fd3..439055b 100644
--- a/chrome/browser/resources/bookmark_manager/images/2x/bookmark_manager_search_rtl.png
+++ b/chrome/browser/resources/bookmark_manager/images/2x/bookmark_manager_search_rtl.png
Binary files differ
diff --git a/chrome/browser/resources/bookmark_manager/images/2x/bookmarks_section_32.png b/chrome/browser/resources/bookmark_manager/images/2x/bookmarks_section_32.png
index 078f9c0..29cef47 100644
--- a/chrome/browser/resources/bookmark_manager/images/2x/bookmarks_section_32.png
+++ b/chrome/browser/resources/bookmark_manager/images/2x/bookmarks_section_32.png
Binary files differ
diff --git a/chrome/browser/resources/bookmark_manager/images/bookmark_manager_recent.png b/chrome/browser/resources/bookmark_manager/images/bookmark_manager_recent.png
index 01e363a..245042a 100644
--- a/chrome/browser/resources/bookmark_manager/images/bookmark_manager_recent.png
+++ b/chrome/browser/resources/bookmark_manager/images/bookmark_manager_recent.png
Binary files differ
diff --git a/chrome/browser/resources/bookmark_manager/images/bookmark_manager_search.png b/chrome/browser/resources/bookmark_manager/images/bookmark_manager_search.png
index bb0475a..46b88a7 100644
--- a/chrome/browser/resources/bookmark_manager/images/bookmark_manager_search.png
+++ b/chrome/browser/resources/bookmark_manager/images/bookmark_manager_search.png
Binary files differ
diff --git a/chrome/browser/resources/bookmark_manager/images/bookmark_manager_search_rtl.png b/chrome/browser/resources/bookmark_manager/images/bookmark_manager_search_rtl.png
index c2ff6ba..2ad7968 100644
--- a/chrome/browser/resources/bookmark_manager/images/bookmark_manager_search_rtl.png
+++ b/chrome/browser/resources/bookmark_manager/images/bookmark_manager_search_rtl.png
Binary files differ
diff --git a/chrome/browser/resources/bookmark_manager/images/bookmarks_section_32.png b/chrome/browser/resources/bookmark_manager/images/bookmarks_section_32.png
index 5b51a9b..555d340 100644
--- a/chrome/browser/resources/bookmark_manager/images/bookmarks_section_32.png
+++ b/chrome/browser/resources/bookmark_manager/images/bookmarks_section_32.png
Binary files differ
diff --git a/chrome/browser/resources/chrome-logo-faded.png b/chrome/browser/resources/chrome-logo-faded.png
index 7f00073..cc35d42 100644
--- a/chrome/browser/resources/chrome-logo-faded.png
+++ b/chrome/browser/resources/chrome-logo-faded.png
Binary files differ
diff --git a/chrome/browser/resources/chromeos/access_chromevox/manifest.json b/chrome/browser/resources/chromeos/access_chromevox/manifest.json
index f1976fe..2ec96d9 100644
--- a/chrome/browser/resources/chromeos/access_chromevox/manifest.json
+++ b/chrome/browser/resources/chromeos/access_chromevox/manifest.json
@@ -21,8 +21,7 @@
       "all_frames": true,
       "js": [
         "chromeVoxChromePageScript.js"
-      ],
-      "run_at": "document_start"
+      ]
     }
   ],
   "web_accessible_resources": [
diff --git a/chrome/browser/resources/chromeos/detected_sd.png b/chrome/browser/resources/chromeos/detected_sd.png
index f7c475f..fe3cf30 100644
--- a/chrome/browser/resources/chromeos/detected_sd.png
+++ b/chrome/browser/resources/chromeos/detected_sd.png
Binary files differ
diff --git a/chrome/browser/resources/chromeos/detected_usb.png b/chrome/browser/resources/chromeos/detected_usb.png
index e84c44f..653613e 100644
--- a/chrome/browser/resources/chromeos/detected_usb.png
+++ b/chrome/browser/resources/chromeos/detected_usb.png
Binary files differ
diff --git a/chrome/browser/resources/chromeos/images/broken_robot.png b/chrome/browser/resources/chromeos/images/broken_robot.png
index e3bdb6e..78439f2 100644
--- a/chrome/browser/resources/chromeos/images/broken_robot.png
+++ b/chrome/browser/resources/chromeos/images/broken_robot.png
Binary files differ
diff --git a/chrome/browser/resources/chromeos/insert.png b/chrome/browser/resources/chromeos/insert.png
index 37e5f26..829a595 100644
--- a/chrome/browser/resources/chromeos/insert.png
+++ b/chrome/browser/resources/chromeos/insert.png
Binary files differ
diff --git a/chrome/browser/resources/chromeos/keyboard_overlay.js b/chrome/browser/resources/chromeos/keyboard_overlay.js
index 3c19cec..d28515f 100644
--- a/chrome/browser/resources/chromeos/keyboard_overlay.js
+++ b/chrome/browser/resources/chromeos/keyboard_overlay.js
@@ -141,51 +141,6 @@
     delete shortcutDataCache['0<>CTRL<>SHIFT'];
   }
 
-  // TODO(mazda): Clean this up and move these out to the data js.
-  var searchModifierAddShortcuts = {
-    '1<>SEARCH': 'keyboardOverlayF1',
-    '2<>SEARCH': 'keyboardOverlayF2',
-    '3<>SEARCH': 'keyboardOverlayF3',
-    '4<>SEARCH': 'keyboardOverlayF4',
-    '5<>SEARCH': 'keyboardOverlayF5',
-    '6<>SEARCH': 'keyboardOverlayF6',
-    '7<>SEARCH': 'keyboardOverlayF7',
-    '8<>SEARCH': 'keyboardOverlayF8',
-    '9<>SEARCH': 'keyboardOverlayF9',
-    '0<>SEARCH': 'keyboardOverlayF10',
-    '-<>SEARCH': 'keyboardOverlayF11',
-    '=<>SEARCH': 'keyboardOverlayF12',
-    'F1<>SEARCH': 'keyboardOverlayF1',
-    'F2<>SEARCH': 'keyboardOverlayF2',
-    'F3<>SEARCH': 'keyboardOverlayF3',
-    'F4<>SEARCH': 'keyboardOverlayF4',
-    'F5<>SEARCH': 'keyboardOverlayF5',
-    'F6<>SEARCH': 'keyboardOverlayF6',
-    'F7<>SEARCH': 'keyboardOverlayF7',
-    'F8<>SEARCH': 'keyboardOverlayF8',
-    'F9<>SEARCH': 'keyboardOverlayF9',
-    'F10<>SEARCH': 'keyboardOverlayF10',
-    'F11<>SEARCH': 'keyboardOverlayF11',
-    'F12<>SEARCH': 'keyboardOverlayF12',
-    'back<>SEARCH': 'keyboardOverlayF1',
-    'forward<>SEARCH': 'keyboardOverlayF2',
-    'reload<>SEARCH': 'keyboardOverlayF3',
-    'full screen<>SEARCH': 'keyboardOverlayF4',
-    'switch window<>SEARCH': 'keyboardOverlayF5',
-    'bright down<>SEARCH': 'keyboardOverlayF6',
-    'bright up<>SEARCH': 'keyboardOverlayF7',
-    'mute<>SEARCH': 'keyboardOverlayF8',
-    'vol. down<>SEARCH': 'keyboardOverlayF9',
-    'vol. up<>SEARCH': 'keyboardOverlayF10',
-    'backspace<>SEARCH': 'keyboardOverlayDelete',
-    'down<>SEARCH': 'keyboardOverlayPageDown',
-    'right<>SEARCH': 'keyboardOverlayEnd',
-    'up<>SEARCH': 'keyboardOverlayPageUp',
-    'left<>SEARCH': 'keyboardOverlayHome',
-    '.<>SEARCH': 'keyboardOverlayInsert'
-  };
-  for (var key in searchModifierAddShortcuts)
-    shortcutDataCache[key] = searchModifierAddShortcuts[key];
   return shortcutDataCache;
 }
 
diff --git a/chrome/browser/resources/chromeos/keyboard_overlay_data.js b/chrome/browser/resources/chromeos/keyboard_overlay_data.js
index 097d891..235420e 100644
--- a/chrome/browser/resources/chromeos/keyboard_overlay_data.js
+++ b/chrome/browser/resources/chromeos/keyboard_overlay_data.js
@@ -15767,31 +15767,44 @@
     '-<>ALT': 'keyboardOverlayMinimizeWindow',
     '-<>CTRL': 'keyboardOverlayZoomOut',
     '-<>CTRL<>SHIFT': 'keyboardOverlayZoomScreenOut',
+    '-<>SEARCH': 'keyboardOverlayF11',
     '.<>CTRL<>SHIFT': 'keyboardOverlayToggleSpeechInput',
+    '.<>SEARCH': 'keyboardOverlayInsert',
     '/<>ALT<>CTRL': 'keyboardOverlayViewKeyboardOverlay',
     '/<>ALT<>CTRL<>SHIFT': 'keyboardOverlayViewKeyboardOverlay',
     '/<>CTRL': 'keyboardOverlayHelp',
     '/<>CTRL<>SHIFT': 'keyboardOverlayHelp',
     '0<>CTRL': 'keyboardOverlayResetZoom',
     '0<>CTRL<>SHIFT': 'keyboardOverlayResetScreenZoom',
+    '0<>SEARCH': 'keyboardOverlayF10',
     '1<>ALT': 'keyboardOverlayActivateLauncherItem1',
     '1<>CTRL': 'keyboardOverlayActivateTab1',
+    '1<>SEARCH': 'keyboardOverlayF1',
     '2<>ALT': 'keyboardOverlayActivateLauncherItem2',
     '2<>CTRL': 'keyboardOverlayActivateTab2',
+    '2<>SEARCH': 'keyboardOverlayF2',
     '3<>ALT': 'keyboardOverlayActivateLauncherItem3',
     '3<>CTRL': 'keyboardOverlayActivateTab3',
+    '3<>SEARCH': 'keyboardOverlayF3',
     '4<>ALT': 'keyboardOverlayActivateLauncherItem4',
     '4<>CTRL': 'keyboardOverlayActivateTab4',
+    '4<>SEARCH': 'keyboardOverlayF4',
     '5<>ALT': 'keyboardOverlayActivateLauncherItem5',
     '5<>CTRL': 'keyboardOverlayActivateTab5',
+    '5<>SEARCH': 'keyboardOverlayF5',
     '6<>ALT': 'keyboardOverlayActivateLauncherItem6',
     '6<>CTRL': 'keyboardOverlayActivateTab6',
+    '6<>SEARCH': 'keyboardOverlayF6',
     '7<>ALT': 'keyboardOverlayActivateLauncherItem7',
     '7<>CTRL': 'keyboardOverlayActivateTab7',
+    '7<>SEARCH': 'keyboardOverlayF7',
     '8<>ALT': 'keyboardOverlayActivateLauncherItem8',
     '8<>CTRL': 'keyboardOverlayActivateTab8',
+    '8<>SEARCH': 'keyboardOverlayF8',
     '9<>ALT': 'keyboardOverlayActivateLastLauncherItem',
     '9<>CTRL': 'keyboardOverlayActivateLastTab',
+    '9<>SEARCH': 'keyboardOverlayF9',
+    '=<>SEARCH': 'keyboardOverlayF12',
     'ALT<>SEARCH': 'keyboardOverlayToggleCapsLock',
     'ALT<>SHIFT': 'keyboardOverlayCycleThroughInputMethods',
     '[<>ALT': 'keyboardOverlayDockWindowLeft',
@@ -15801,15 +15814,19 @@
     'b<>ALT<>SHIFT': 'keyboardOverlayFocusBookmarks',
     'b<>CTRL<>SHIFT': 'keyboardOverlayToggleBookmarkBar',
     'back<>CTRL': 'keyboardOverlayFocusPreviousPane',
+    'back<>SEARCH': 'keyboardOverlayF1',
     'backspace': 'keyboardOverlayGoBack',
     'backspace<>ALT': 'keyboardOverlayDelete',
     'backspace<>CTRL': 'keyboardOverlayDeleteWord',
     'backspace<>CTRL<>SHIFT': 'keyboardOverlayClearBrowsingDataDialog',
+    'backspace<>SEARCH': 'keyboardOverlayDelete',
     'backspace<>SHIFT': 'keyboardOverlayGoForward',
     'bright down<>ALT': 'keyboardOverlayDecreaseKeyBrightness',
     'bright down<>ALT<>CTRL': 'keyboardOverlayMagnifierDecreaseZoom',
+    'bright down<>SEARCH': 'keyboardOverlayF6',
     'bright up<>ALT': 'keyboardOverlayIncreaseKeyBrightness',
     'bright up<>ALT<>CTRL': 'keyboardOverlayMagnifierIncreaseZoom',
+    'bright up<>SEARCH': 'keyboardOverlayF7',
     'c<>CTRL': 'keyboardOverlayCopy',
     'c<>CTRL<>SHIFT': 'keyboardOverlayDomInspector',
     'd<>ALT': 'keyboardOverlayFocusAddressBar',
@@ -15817,6 +15834,7 @@
     'd<>CTRL<>SHIFT': 'keyboardOverlayBookmarkAllTabs',
     'down<>ALT': 'keyboardOverlayPageDown',
     'down<>ALT<>CTRL': 'keyboardOverlayEnd',
+    'down<>SEARCH': 'keyboardOverlayPageDown',
     'e<>ALT': 'keyboardOverlayShowWrenchMenu',
     'e<>CTRL': 'keyboardOverlayFocusAddressBarInSearchMode',
     'enter<>ALT': 'keyboardOverlayOpenAddressInNewTab',
@@ -15826,6 +15844,8 @@
     'f<>ALT': 'keyboardOverlayShowWrenchMenu',
     'f<>CTRL': 'keyboardOverlayFindText',
     'forward<>CTRL': 'keyboardOverlayFocusNextPane',
+    'forward<>SEARCH': 'keyboardOverlayF2',
+    'full screen<>SEARCH': 'keyboardOverlayF4',
     'g<>CTRL': 'keyboardOverlayFindTextAgain',
     'g<>CTRL<>SHIFT': 'keyboardOverlayFindPreviousText',
     'h<>CTRL': 'keyboardOverlayHistory',
@@ -15840,11 +15860,13 @@
     'left<>ALT': 'keyboardOverlayGoBack',
     'left<>CTRL': 'keyboardOverlayPreviousWord',
     'left<>CTRL<>SHIFT': 'keyboardOverlaySelectWordAtATime',
+    'left<>SEARCH': 'keyboardOverlayEnd',
     'm<>ALT<>SHIFT': 'keyboardOverlayOpenFileManager',
     'm<>CTRL': 'keyboardOverlayMinimizeWindow',
     'maximize<>ALT': 'keyboardOverlaySwapPrimaryMonitor',
     'maximize<>CTRL': 'keyboardOverlayMirrorMonitors',
     'maximize<>SHIFT': 'keyboardOverlayFullScreen',
+    'mute<>SEARCH': 'keyboardOverlayF8',
     'n<>ALT<>SHIFT': 'keyboardOverlayShowMessageCenter',
     'n<>CTRL': 'keyboardOverlayNewWindow',
     'n<>CTRL<>SHIFT': 'keyboardOverlayNewIncognitoWindow',
@@ -15856,15 +15878,18 @@
     'r<>CTRL': 'keyboardOverlayReloadCurrentPage',
     'r<>CTRL<>SHIFT': 'keyboardOverlayReloadIgnoringCache',
     'reload<>CTRL<>SHIFT': 'keyboardOverlayRotateScreen',
+    'reload<>SEARCH': 'keyboardOverlayF3',
     'right<>ALT': 'keyboardOverlayGoForward',
     'right<>CTRL': 'keyboardOverlayNextWord',
     'right<>CTRL<>SHIFT': 'keyboardOverlaySelectWordAtATime',
+    'right<>SEARCH': 'keyboardOverlayHome',
     's<>ALT<>SHIFT': 'keyboardOverlayShowStatusMenu',
     's<>CTRL': 'keyboardOverlaySave',
     'space<>CTRL': 'keyboardOverlaySelectPreviousInputMethod',
     'space<>SHIFT': 'keyboardOverlayScrollUpOnePage',
     'switch window<>CTRL': 'keyboardOverlayTakeScreenshot',
     'switch window<>CTRL<>SHIFT': 'keyboardOverlayScreenshotRegion',
+    'switch window<>SEARCH': 'keyboardOverlayF5',
     't<>ALT<>CTRL': 'keyboardOverlayNewTerminal',
     't<>ALT<>SHIFT': 'keyboardOverlayFocusToolbar',
     't<>CTRL': 'keyboardOverlayNewTab',
@@ -15877,8 +15902,11 @@
     'u<>CTRL<>SHIFT': 'keyboardOverlayInputUnicodeCharacters',
     'up<>ALT': 'keyboardOverlayPageUp',
     'up<>ALT<>CTRL': 'keyboardOverlayHome',
+    'up<>SEARCH': 'keyboardOverlayPageUp',
     'v<>CTRL': 'keyboardOverlayPaste',
     'v<>CTRL<>SHIFT': 'keyboardOverlayPasteAsPlainText',
+    'vol. down<>SEARCH': 'keyboardOverlayF9',
+    'vol. up<>SEARCH': 'keyboardOverlayF10',
     'w<>CTRL': 'keyboardOverlayCloseTab',
     'w<>CTRL<>SHIFT': 'keyboardOverlayCloseWindow',
     'x<>CTRL': 'keyboardOverlayCut',
diff --git a/chrome/browser/resources/chromeos/login/display_manager.js b/chrome/browser/resources/chromeos/login/display_manager.js
index 8539a76..eb87f87 100644
--- a/chrome/browser/resources/chromeos/login/display_manager.js
+++ b/chrome/browser/resources/chromeos/login/display_manager.js
@@ -305,6 +305,8 @@
               innerContainer.classList.remove('animation');
               oldStep.classList.add('hidden');
             }
+            // Refresh defaultControl. It could have changed.
+            var defaultControl = newStep.defaultControl;
             if (defaultControl)
               defaultControl.focus();
           });
@@ -323,6 +325,8 @@
                 innerContainer.removeEventListener('webkitTransitionEnd', f);
                 $('progress-dots').classList.remove('down');
                 chrome.send('loginVisible', ['oobe']);
+                // Refresh defaultControl. It could have changed.
+                var defaultControl = newStep.defaultControl;
                 if (defaultControl)
                   defaultControl.focus();
               });
diff --git a/chrome/browser/resources/chromeos/login/images/chrome_retail_login.png b/chrome/browser/resources/chromeos/login/images/chrome_retail_login.png
index 3b4d9f3..9799d38 100644
--- a/chrome/browser/resources/chromeos/login/images/chrome_retail_login.png
+++ b/chrome/browser/resources/chromeos/login/images/chrome_retail_login.png
Binary files differ
diff --git a/chrome/browser/resources/chromeos/login/login.js b/chrome/browser/resources/chromeos/login/login.js
index 7fcb7a6..edfaef2 100644
--- a/chrome/browser/resources/chromeos/login/login.js
+++ b/chrome/browser/resources/chromeos/login/login.js
@@ -41,7 +41,6 @@
     handleSpokenFeedbackClick: function(e) {},
     handleHighContrastClick: function(e) {},
     handleScreenMagnifierClick: function(e) {},
-    enableContinueButton: function(enable) {},
     setUsageStats: function(checked) {},
     setOemEulaUrl: function(oemEulaUrl) {},
     setUpdateProgress: function(progress) {},
diff --git a/chrome/browser/resources/chromeos/login/oobe.css b/chrome/browser/resources/chromeos/login/oobe.css
index cdad406..a898675 100644
--- a/chrome/browser/resources/chromeos/login/oobe.css
+++ b/chrome/browser/resources/chromeos/login/oobe.css
@@ -37,7 +37,8 @@
   color: buttontext !important;
 }
 
-button.custom-appearance:focus {
+/* ':focus' used twice to increase specificity. */
+button.custom-appearance:focus:focus {
   border-color: rgb(77, 144, 254);
 }
 
@@ -48,6 +49,7 @@
 button.button-fancy {
   min-width: 72px !important;
 }
+
 button.button-blue {
   background-image: -webkit-linear-gradient(rgb(93, 154, 255),
                                             rgb(93, 154, 255) 38%,
diff --git a/chrome/browser/resources/chromeos/login/oobe.js b/chrome/browser/resources/chromeos/login/oobe.js
index 9e41fc3..addeec6 100644
--- a/chrome/browser/resources/chromeos/login/oobe.js
+++ b/chrome/browser/resources/chromeos/login/oobe.js
@@ -160,14 +160,6 @@
     },
 
     /**
-     * Enables/disables continue button.
-     * @param {boolean} enable Should the button be enabled?
-     */
-    enableContinueButton: function(enable) {
-      $('continue-button').disabled = !enable;
-    },
-
-    /**
      * Sets usage statistics checkbox.
      * @param {boolean} checked Is the checkbox checked?
      */
diff --git a/chrome/browser/resources/chromeos/login/oobe_screen_enable_kiosk.js b/chrome/browser/resources/chromeos/login/oobe_screen_enable_kiosk.js
index 4fcf2df..e9ad0b8 100644
--- a/chrome/browser/resources/chromeos/login/oobe_screen_enable_kiosk.js
+++ b/chrome/browser/resources/chromeos/login/oobe_screen_enable_kiosk.js
@@ -67,7 +67,6 @@
       $('kiosk-ok-button').hidden = true;
       $('kiosk-enable-details').textContent =
           loadTimeData.getString('kioskEnableWarningDetails');
-      chrome.send('kioskEnableVisible');
     },
 
     /**
diff --git a/chrome/browser/resources/chromeos/login/oobe_screen_network.js b/chrome/browser/resources/chromeos/login/oobe_screen_network.js
index 37dab68..b6b2798 100644
--- a/chrome/browser/resources/chromeos/login/oobe_screen_network.js
+++ b/chrome/browser/resources/chromeos/login/oobe_screen_network.js
@@ -9,6 +9,7 @@
 login.createScreen('NetworkScreen', 'connect', function() {
   return {
     EXTERNAL_API: [
+      'enableContinueButton',
       'showError'
     ],
 
@@ -37,6 +38,7 @@
 
     onBeforeHide: function() {
       cr.ui.DropDown.hide('networks-list');
+      this.enableContinueButton(false);
     },
 
     /**
@@ -55,8 +57,10 @@
       var buttons = [];
 
       var continueButton = this.ownerDocument.createElement('button');
+      continueButton.disabled = true;
       continueButton.id = 'continue-button';
       continueButton.textContent = loadTimeData.getString('continueButton');
+      continueButton.classList.add('preserve-disabled-state');
       continueButton.addEventListener('click', function(e) {
         chrome.send('networkOnExit');
         e.stopPropagation();
@@ -74,6 +78,14 @@
     },
 
     /**
+     * Enables/disables continue button.
+     * @param {boolean} enable Should the button be enabled?
+     */
+    enableContinueButton: function(enable) {
+      $('continue-button').disabled = !enable;
+    },
+
+    /**
      * Shows the network error message.
      * @param {string} message Message to be shown.
      */
diff --git a/chrome/browser/resources/chromeos/login/oobe_screen_oauth_enrollment.js b/chrome/browser/resources/chromeos/login/oobe_screen_oauth_enrollment.js
index be76d57..2f53251 100644
--- a/chrome/browser/resources/chromeos/login/oobe_screen_oauth_enrollment.js
+++ b/chrome/browser/resources/chromeos/login/oobe_screen_oauth_enrollment.js
@@ -168,10 +168,6 @@
     onBeforeShow: function(data) {
       var url = data.signin_url;
       url += '?gaiaUrl=' + encodeURIComponent(data.gaiaUrl);
-      if (data.test_email) {
-        url += '&test_email=' + encodeURIComponent(data.test_email);
-        url += '&test_password=' + encodeURIComponent(data.test_password);
-      }
       this.signInUrl_ = url;
       this.setIsAutoEnrollment(data.is_auto_enrollment);
       this.preventCancellation_ = data.prevent_cancellation;
diff --git a/chrome/browser/resources/chromeos/login/screen_locally_managed_user_creation.css b/chrome/browser/resources/chromeos/login/screen_locally_managed_user_creation.css
index d46a293..2aa3962 100644
--- a/chrome/browser/resources/chromeos/login/screen_locally_managed_user_creation.css
+++ b/chrome/browser/resources/chromeos/login/screen_locally_managed_user_creation.css
@@ -45,29 +45,6 @@
   line-height: 24px;
 }
 
-#managed-user-creation .progress-dots {
-  position: absolute;
-  text-align: center;
-  top: 560px;
-  width: 100%;
-}
-
-#managed-user-creation .dot-on {
-  background-color: gray;
-  border-radius: 50%;
-  display: inline-block;
-  height: 6px;
-  width: 6px;
-}
-
-#managed-user-creation .dot-off {
-  background-color: lightgray;
-  border-radius: 50%;
-  display: inline-block;
-  height: 6px;
-  width: 6px;
-}
-
 #managed-user-creation strong {
   color: #000;
   font-weight: normal;
@@ -107,25 +84,16 @@
   text-align: center;
 }
 
-#managed-user-creation-intro-text-1,
-#managed-user-creation-intro-text-2 {
-  margin-top: 25px;
-}
-
 #managed-user-creation-intro .below-marketing {
   margin: 40px 40px 0;
 }
 
-#managed-user-creation-created-1 .below-marketing,
-#managed-user-creation-created-2 .below-marketing,
-#managed-user-creation-created-3 .below-marketing {
+#managed-user-creation-created-1 .below-marketing {
   margin: 55px 100px 0;
 }
 
-#managed-user-creation-created-1-text-3,
-#managed-user-creation-created-2-text-2,
-#managed-user-creation-created-3-text-2,
-#managed-user-creation-created-3-text-3 {
+#managed-user-creation-created-1-text-2,
+#managed-user-creation-created-1-text-3 {
   margin-top: 20px;
 }
 
@@ -147,13 +115,11 @@
   padding: 4px 6px;
 }
 
-#managed-user-creation-name-error,
-#managed-user-creation-password-error {
+#managed-user-creation-name-error {
   visibility: hidden;
 }
 
-#managed-user-creation-name-error.error,
-#managed-user-creation-password-error.error {
+#managed-user-creation-name-error.error {
   color: rgb(207, 93, 70);
   padding-left: 28px;
   visibility: visible;
@@ -173,10 +139,19 @@
 }
 
 #managed-user-creation-error {
-  padding: 100px 50px;
+  padding: 175px 120px 0;
   text-align: center;
 }
 
+#managed-user-creation-error .error-icon {
+  -webkit-margin-after: 50px;
+}
+
+#managed-user-creation-error  .error-message-paragraph {
+  -webkit-margin-after: 40px;
+  -webkit-margin-before: 30px;
+}
+
 .screen-control-button {
   margin-left: 10px !important;
 }
@@ -225,11 +200,6 @@
   color: #000;
   font-size: small;
 }
-.manager-pod .managed-user-creation-manager-wrong-password {
-  background: url('chrome://theme/IDR_WARNING') left top /24px no-repeat;
-  color: red;
-  padding-left: 28px;
-}
 
 #managed-user-creation-status {
   margin: 4px 10px;
@@ -256,3 +226,185 @@
   color: #fff;
 }
 
+.manager-pod .password-error,
+#managed-user-creation .password-error,
+#managed-user-creation .duplicate-name {
+  border: 1px solid red !important;
+}
+
+#managed-user-creation-image-picker {
+  margin-top: 16px;
+}
+
+#managed-user-creation-image-grid {
+  -webkit-user-drag: none;
+  -webkit-user-select: none;
+  display: inline-block;
+  height: 264px;
+  margin: 0;
+  outline: none;
+  overflow: hidden;
+  padding: 0;
+  width: 400px;
+}
+
+#managed-user-creation-image-grid img {
+  background-color: white;
+  height: 50px;
+  vertical-align: middle;
+  width: 50px;
+}
+
+#managed-user-creation-image-grid > li {
+  border: 1px solid rgba(0, 0, 0, 0.15);
+  border-radius: 4px;
+  display: inline-block;
+  margin: 4px;
+  padding: 3px;
+}
+
+#managed-user-creation-image-grid [selected] {
+  border: 2px solid rgb(0, 102, 204);
+  padding: 2px;
+}
+
+#managed-user-creation-image-preview {
+  float: right;
+  margin: 4px;
+  max-width: 220px;
+  position: relative;
+}
+
+html[dir=rtl] #managed-user-creation-image-preview {
+  float: left;
+}
+
+#managed-user-creation-image-preview-img {
+  -webkit-transition: -webkit-transform 200ms linear;
+  display: block;
+  max-height: 220px;
+  max-width: 220px;
+}
+
+.camera.live #managed-user-creation-image-preview-img {
+  display: none;
+}
+
+.camera.flip-x #managed-user-creation-image-preview-img {
+  -webkit-transform: rotateY(180deg);
+}
+
+.default-image #managed-user-creation-image-preview-img {
+  background: white;
+  border: solid 1px #cacaca;
+  border-radius: 4px;
+  padding: 2px;
+}
+
+.managed-user-creation-image-stream-area {
+  display: none;
+  padding: 0;
+  position: relative;
+}
+
+.camera.live .managed-user-creation-image-stream-area {
+  display: block;
+}
+
+#managed-user-creation-image-stream-crop {
+  -webkit-transition: -webkit-transform 200ms linear;
+  height: 220px;
+  overflow: hidden;
+  position: relative;
+  width: 220px;
+}
+
+.flip-x #managed-user-creation-image-stream-crop {
+  -webkit-transform: rotateY(180deg);
+}
+
+.managed-user-creation-image-stream {
+  border: solid 1px #cacaca;
+  height: 220px;
+  /* Center image for 4:3 aspect ratio. */
+  left: -16.6%;
+  position: absolute;
+  visibility: hidden;
+}
+
+.online .managed-user-creation-image-stream {
+  visibility: visible;
+}
+
+#managed-user-creation-image-preview-caption {
+  color: dimGray;
+  font-size: smaller;
+  margin: 8px 4px;
+}
+
+.camera #managed-user-creation-image-preview-caption {
+  display: none;
+}
+
+#managed-user-creation-flip-photo {
+  -webkit-transition: opacity 75ms linear;
+  background: url('chrome://theme/IDR_MIRROR_FLIP') no-repeat;
+  border: none;
+  bottom: 44px;  /* 8px + image bottom. */
+  display: block;
+  height: 32px;
+  opacity: 0;
+  position: absolute;
+  right: 8px;
+  width: 32px;
+}
+
+html[dir=rtl] #managed-user-creation-flip-photo {
+  left: 8px;
+  right: auto;
+}
+
+/* "Flip photo" button is hidden during flip animation. */
+.camera.online:not(.animation) #managed-user-creation-flip-photo {
+  opacity: 0.75;
+}
+
+#managed-user-creation-discard-photo,
+#managed-user-creation-take-photo {
+  display: none;
+  height: 25px;
+  margin: 4px 1px;
+  padding: 0;
+  width: 220px;
+}
+
+.camera:not(.live) #managed-user-creation-discard-photo {
+  background: url('chrome://theme/IDR_USER_IMAGE_RECYCLE')
+      no-repeat center 0;
+  display: block;
+}
+
+.camera.live.online #managed-user-creation-take-photo {
+  background: url('chrome://theme/IDR_USER_IMAGE_CAPTURE')
+      no-repeat center -1px;
+  display: block;
+}
+
+#managed-user-creation-image-preview .perspective-box {
+  -webkit-perspective: 600px;
+}
+
+.managed-user-creation-image-stream-area .spinner {
+  display: none;
+  height: 44px;
+  left: 50%;
+  margin-left: -22px;
+  margin-top: -22px;
+  position: absolute;
+  top: 50%;
+  width: 44px;
+}
+
+.camera.live:not(.online) .managed-user-creation-image-stream-area .spinner {
+  display: block;
+}
diff --git a/chrome/browser/resources/chromeos/login/screen_locally_managed_user_creation.html b/chrome/browser/resources/chromeos/login/screen_locally_managed_user_creation.html
index 5bc7010..b912d46 100644
--- a/chrome/browser/resources/chromeos/login/screen_locally_managed_user_creation.html
+++ b/chrome/browser/resources/chromeos/login/screen_locally_managed_user_creation.html
@@ -3,7 +3,7 @@
     <div id="managed-user-creation-intro" class="step-no-logo">
       <div id="managed-user-creation-marketing-intro"
           class="marketing">
-        Marketing placeholder.
+        <img src="chrome://theme/IDR_SUPERVISED_ILLUSTRATION_START">
       </div>
       <div class="below-marketing">
         <div i18n-content="createManagedUserIntroText1"></div>
@@ -48,81 +48,61 @@
           <div class="page-title-explanation inline"
               i18n-content="createManagedUserPasswordExplanation"></div>
         </div>
-      <div id="managed-user-creation-password-block">
-          <div>
-            <input id="managed-user-creation-password" type="password"
-                i18n-values="placeholder:createManagedUserPasswordHint" />
-            <span id="managed-user-creation-password-error" class="no-error">
-            </span>
+        <div id="managed-user-creation-password-block">
+            <div>
+              <input id="managed-user-creation-password" type="password"
+                  i18n-values="placeholder:createManagedUserPasswordHint" />
+            </div>
+            <div>
+              <input id="managed-user-creation-password-confirm"
+                  type="password"
+                  i18n-values="
+                      placeholder:createManagedUserPasswordConfirmHint" />
+            </div>
           </div>
-          <div>
-            <input id="managed-user-creation-password-confirm"
-                type="password"
-                i18n-values="placeholder:createManagedUserPasswordConfirmHint" />
+      </div>
+      <div id="managed-user-creation-image-picker" class="logo-padded-text">
+        <grid id="managed-user-creation-image-grid">
+        </grid>
+        <div id="managed-user-creation-image-preview">
+          <img id="managed-user-creation-image-preview-img" alt="">
+          <div class="managed-user-creation-image-stream-area">
+            <div class="perspective-box">
+              <div id="managed-user-creation-image-stream-crop">
+                <video class="managed-user-creation-image-stream" autoplay>
+                </video>
+              </div>
+            </div>
+            <div class="spinner"></div>
           </div>
+          <p id="managed-user-creation-image-preview-caption"></p>
+          <button id="managed-user-creation-flip-photo"
+              class="custom-appearance"
+              i18n-values="title:flipPhoto"></button>
+          <button id="managed-user-creation-discard-photo"
+              i18n-values="title:discardPhoto"></button>
+          <button id="managed-user-creation-take-photo"
+              i18n-values="title:takePhoto"></button>
         </div>
       </div>
     </div>
     <div id="managed-user-creation-created-1" class="step-no-logo" hidden>
       <div class="marketing">
+        <img src="chrome://theme/IDR_SUPERVISED_ILLUSTRATION_DONE">
       </div>
       <div class="below-marketing">
         <div>
           <div id="managed-user-creation-created-1-text-1"
               class="page-title centred"></div>
-          <div i18n-content="createManagedUserCreated1Text2"
+          <div id="managed-user-creation-created-1-text-2"
               class="page-title centred"></div>
           <div id="managed-user-creation-created-1-text-3"
               class="page-title-explanation centred"></div>
         </div>
       </div>
-      <div class="progress-dots">
-        <div class="dot-on"></div>
-        <div class="dot-off"></div>
-        <div class="dot-off"></div>
-      </div>
-    </div>
-    <div id="managed-user-creation-created-2" class="step-no-logo" hidden>
-      <div class="marketing">
-        Marketing placeholder 2.
-      </div>
-      <div class="below-marketing">
-        <div>
-          <div i18n-content="createManagedUserCreated2Text1"
-              class="page-title centred"></div>
-          <div id="managed-user-creation-created-2-text-2"
-              i18n-content="createManagedUserCreated2Text2"
-              class="page-title-explanation centred"></div>
-        </div>
-      </div>
-      <div class="progress-dots">
-        <div class="dot-off"></div>
-        <div class="dot-on"></div>
-        <div class="dot-off"></div>
-      </div>
-    </div>
-    <div id="managed-user-creation-created-3" class="step-no-logo" hidden>
-      <div class="marketing">
-        Marketing placeholder 3.
-      </div>
-      <div class="below-marketing">
-        <div>
-          <div i18n-content="createManagedUserCreated3Text1"
-              class="page-title centred"></div>
-          <div id="managed-user-creation-created-3-text-2"
-              class="page-title-explanation centred"></div>
-          <div id="managed-user-creation-created-3-text-3"
-              class="page-title-explanation centred"></div>
-        </div>
-      </div>
-      <div class="progress-dots">
-        <div class="dot-off"></div>
-        <div class="dot-off"></div>
-        <div class="dot-on"></div>
-      </div>
     </div>
     <div id="managed-user-creation-error" hidden>
-      <img alt class="error-icon" src="chrome://theme/IDR_FATAL_ERROR">
+      <img alt class="error-icon" src="chrome://theme/IDR_TECHNICAL_ERROR">
       <div id="managed-user-creation-error-title" class="error-title"></div>
       <div id="managed-user-creation-error-text"
           class="error-message-paragraph"></div>
@@ -151,9 +131,6 @@
     <div class="password-block" hidden>
       <input class="managed-user-creation-manager-password" type="password"
           i18n-values="placeholder:createManagedUserManagerPasswordHint" />
-      <span class="managed-user-creation-manager-wrong-password"
-          i18n-content="createManagedUserWrongManagerPasswordText"
-          hidden />
     </div>
   </div>
 </div>
\ No newline at end of file
diff --git a/chrome/browser/resources/chromeos/login/screen_locally_managed_user_creation.js b/chrome/browser/resources/chromeos/login/screen_locally_managed_user_creation.js
index 56e2880..6cec377 100644
--- a/chrome/browser/resources/chromeos/login/screen_locally_managed_user_creation.js
+++ b/chrome/browser/resources/chromeos/login/screen_locally_managed_user_creation.js
@@ -8,6 +8,8 @@
 
 login.createScreen('LocallyManagedUserCreationScreen',
                    'managed-user-creation', function() {
+  var UserImagesGrid = options.UserImagesGrid;
+
   var ManagerPod = cr.ui.define(function() {
     var node = $('managed-user-creation-manager-template').cloneNode(true);
     node.removeAttribute('id');
@@ -34,7 +36,8 @@
       var screen = $('managed-user-creation');
       var managerPod = this;
       var hideManagerPasswordError = function(element) {
-        managerPod.passwordErrorElement.hidden = true;
+        managerPod.passwordElement.classList.remove('password-error');
+        $('bubble').hide();
       };
 
       screen.configureTextInput(
@@ -59,7 +62,12 @@
     },
 
     showPasswordError: function() {
-      this.passwordErrorElement.hidden = false;
+      this.passwordElement.classList.add('password-error');
+      $('bubble').showTextForElement(
+          this.passwordElement,
+          loadTimeData.getString('createManagedUserWrongManagerPasswordText'),
+          cr.ui.Bubble.Attachment.BOTTOM,
+          24, 4);
     },
 
     /**
@@ -102,15 +110,6 @@
     },
 
     /**
-     * Gets password error element.
-     * @type {!HTMLDivElement}
-     */
-    get passwordErrorElement() {
-      return this.
-          querySelector('.managed-user-creation-manager-wrong-password');
-    },
-
-    /**
      * Gets password enclosing block.
      * @type {!HTMLDivElement}
      */
@@ -210,6 +209,8 @@
       'showStatusError',
       'showTutorialPage',
       'showUsernamePage',
+      'setDefaultImages',
+      'setCameraPresent',
     ],
 
     lastVerifiedName_: null,
@@ -234,7 +235,8 @@
       var creationScreen = this;
 
       var hideUserPasswordError = function(element) {
-        creationScreen.passwordErrorVisible = false;
+        $('bubble').hide();
+        $('managed-user-creation-password').classList.remove('password-error');
       };
 
       this.configureTextInput(userNameField,
@@ -244,7 +246,6 @@
                                 passwordField.focus();
                               },
                               this.clearUserNameError_.bind(this));
-
       this.configureTextInput(passwordField,
                               this.updateNextButtonForUser_.bind(this),
                               this.validIfNotEmpty_.bind(this),
@@ -264,6 +265,53 @@
         creationScreen.handleErrorButtonPressed_();
         e.stopPropagation();
       });
+
+      /*
+      TODO(antrim) : this is an explicit code duplications with UserImageScreen.
+      It should be removed by issue 251179.
+      */
+      var imageGrid = this.getScreenElement('image-grid');
+      UserImagesGrid.decorate(imageGrid);
+
+      // Preview image will track the selected item's URL.
+      var previewElement = this.getScreenElement('image-preview');
+      previewElement.oncontextmenu = function(e) { e.preventDefault(); };
+
+      imageGrid.previewElement = previewElement;
+      imageGrid.selectionType = 'default';
+
+      imageGrid.addEventListener('select',
+                                 this.handleSelect_.bind(this));
+      imageGrid.addEventListener('phototaken',
+                                 this.handlePhotoTaken_.bind(this));
+      imageGrid.addEventListener('photoupdated',
+                                 this.handlePhotoUpdated_.bind(this));
+
+      // Set the title for camera item in the grid.
+      imageGrid.setCameraTitles(
+          loadTimeData.getString('takePhoto'),
+          loadTimeData.getString('photoFromCamera'));
+
+      this.getScreenElement('take-photo').addEventListener(
+          'click', this.handleTakePhoto_.bind(this));
+      this.getScreenElement('discard-photo').addEventListener(
+          'click', this.handleDiscardPhoto_.bind(this));
+
+      // Toggle 'animation' class for the duration of WebKit transition.
+      this.getScreenElement('flip-photo').addEventListener(
+          'click', function(e) {
+            previewElement.classList.add('animation');
+            imageGrid.flipPhoto = !imageGrid.flipPhoto;
+          });
+      this.getScreenElement('image-stream-crop').addEventListener(
+          'webkitTransitionEnd', function(e) {
+            previewElement.classList.remove('animation');
+          });
+      this.getScreenElement('image-preview-img').addEventListener(
+          'webkitTransitionEnd', function(e) {
+            previewElement.classList.remove('animation');
+          });
+      chrome.send('supervisedUserGetImages');
     },
 
     buttonIds: [],
@@ -422,7 +470,7 @@
           'gotit',
           'managedUserCreationFlow',
           this.gotItButtonPressed_.bind(this),
-          ['created-1', 'created-2', 'created-3'],
+          ['created-1'],
           ['custom-appearance', 'button-fancy', 'button-blue']));
       return buttons;
     },
@@ -517,8 +565,11 @@
       var userNameField = $('managed-user-creation-name');
       if (userNameField.value == this.lastIncorrectUserName_) {
         this.nameErrorVisible = true;
-        $('managed-user-creation-name-error').textContent = errorText;
-
+        $('bubble').showTextForElement(
+            $('managed-user-creation-name'),
+            errorText,
+            cr.ui.Bubble.Attachment.RIGHT,
+            24, 4);
         this.setButtonDisabledStatus('next', true);
       }
     },
@@ -541,10 +592,14 @@
      * @param {string} errorText - reason why this password is invalid.
      */
     showPasswordError: function(errorText) {
-      $('managed-user-creation-password-error').textContent = errorText;
-      this.passwordErrorVisible = true;
+      $('bubble').showTextForElement(
+          $('managed-user-creation-password'),
+          errorText,
+          cr.ui.Bubble.Attachment.RIGHT,
+          24, 4);
+      $('managed-user-creation-password').classList.add('password-error');
       $('managed-user-creation-password').focus();
-
+      this.disabled = false;
       this.setButtonDisabledStatus('next', true);
     },
 
@@ -553,23 +608,10 @@
      * @type {boolean}
      */
     set nameErrorVisible(value) {
-      $('managed-user-creation-name-error').
-          classList.toggle('error', value);
       $('managed-user-creation-name').
           classList.toggle('duplicate-name', value);
       if (!value)
-        $('managed-user-creation-name-error').textContent = '';
-    },
-
-    /**
-     * True if user name error should be displayed.
-     * @type {boolean}
-     */
-    set passwordErrorVisible(value) {
-      $('managed-user-creation-password-error').
-          classList.toggle('error', value);
-      if (!value)
-        $('managed-user-creation-password-error').textContent = '';
+        $('bubble').hide();
     },
 
     /**
@@ -626,14 +668,10 @@
                        'manager',
                        'username',
                        'error',
-                       'created-1',
-                       'created-2',
-                       'created-3'];
+                       'created-1'];
       var pageButtons = {'intro' : 'start',
                          'error' : 'error',
-                         'created-1' : 'gotit',
-                         'created-2' : 'gotit',
-                         'created-3' : 'gotit'};
+                         'created-1' : 'gotit'};
       this.hideStatus_();
       for (i in pageNames) {
         var pageName = pageNames[i];
@@ -658,6 +696,17 @@
         this.getScreenButton(pageButtons[visiblePage]).focus();
 
       this.currentPage_ = visiblePage;
+
+      if (visiblePage == 'username') {
+        var imageGrid = this.getScreenElement('image-grid');
+        // select some image.
+        var selected = this.imagesData_[
+            Math.floor(Math.random() * this.imagesData_.length)];
+        imageGrid.selectedItemUrl = selected.url;
+        chrome.send('supervisedUserSelectImage',
+                    [selected.url, 'default']);
+        this.getScreenElement('image-grid').redraw();
+      }
     },
 
     setButtonDisabledStatus: function(buttonName, status) {
@@ -666,14 +715,6 @@
     },
 
     gotItButtonPressed_: function() {
-      if (this.currentPage_ == 'created-1') {
-        this.setVisiblePage_('created-2');
-        return;
-      }
-      if (this.currentPage_ == 'created-2') {
-        this.setVisiblePage_('created-3');
-        return;
-      }
       chrome.send('finishLocalManagedUserCreation');
     },
 
@@ -731,6 +772,8 @@
       if (data['managers']) {
         this.loadManagers(data['managers']);
       }
+      var imageGrid = this.getScreenElement('image-grid');
+      imageGrid.updateAndFocus();
     },
 
     /**
@@ -738,6 +781,7 @@
      */
     onBeforeHide: function() {
       $('login-header-bar').signinUIState = SIGNIN_UI_STATE.HIDDEN;
+      this.getScreenElement('image-grid').stopCamera();
     },
 
     /**
@@ -784,7 +828,7 @@
      */
     cancel: function() {
       var notSignedInPages = ['intro', 'manager'];
-      var postCreationPages = ['created-1', 'created-2', 'created-3'];
+      var postCreationPages = ['created-1'];
       if (notSignedInPages.indexOf(this.currentPage_) >= 0) {
         // Make sure no manager password is kept:
         this.managerList_.clearPods();
@@ -807,24 +851,22 @@
       this.updateElementText_('created-1-text-1',
           'createManagedUserCreated1Text1',
           this.context_.managedName);
+      this.updateElementText_('created-1-text-2',
+          'createManagedUserCreated1Text2',
+          loadTimeData.getString('managementURL'), this.context_.managedName);
       this.updateElementText_('created-1-text-3',
           'createManagedUserCreated1Text3',
           managerId);
-      this.updateElementText_('created-3-text-2',
-          'createManagedUserCreated3Text2',
-          loadTimeData.getStringF('managementURL'),
-          managerId);
-      this.updateElementText_('created-3-text-3',
-          'createManagedUserCreated3Text3',
-          managerId);
       this.updateElementText_('name-explanation',
           'createManagedUserNameExplanation',
           managerId);
     },
 
-    updateElementText_: function(localId, templateName, value) {
+    updateElementText_: function(localId, templateName) {
+      var args = Array.prototype.slice.call(arguments);
+      args.shift();
       this.getScreenElement(localId).innerHTML =
-          loadTimeData.getStringF(templateName, value);
+          loadTimeData.getStringF.apply(loadTimeData, args);
     },
 
     showIntroPage: function() {
@@ -835,6 +877,7 @@
       this.lastVerifiedName_ = null;
       this.lastIncorrectUserName_ = null;
       this.passwordErrorVisible = false;
+      $('managed-user-creation-password').classList.remove('password-error');
       this.nameErrorVisible = false;
 
       this.setVisiblePage_('intro');
@@ -863,7 +906,89 @@
     showManagerPasswordError: function() {
       this.disabled = false;
       this.showSelectedManagerPasswordError_();
-    }
+    },
+
+    /*
+    TODO(antrim) : this is an explicit code duplications with UserImageScreen.
+    It should be removed by issue 251179.
+    */
+    /**
+     * Currently selected user image index (take photo button is with zero
+     * index).
+     * @type {number}
+     */
+    selectedUserImage_: -1,
+    imagesData: [],
+
+    setDefaultImages: function(imagesData) {
+      var imageGrid = this.getScreenElement('image-grid');
+      for (var i = 0, data; data = imagesData[i]; i++) {
+        var item = imageGrid.addItem(data.url, data.title);
+        item.type = 'default';
+        item.author = data.author || '';
+        item.website = data.website || '';
+      }
+      this.imagesData_ = imagesData;
+    },
+
+    /**
+     * Handles selection change.
+     * @param {cr.Event} e Selection change event.
+     * @private
+     */
+    handleSelect_: function(e) {
+      var imageGrid = this.getScreenElement('image-grid');
+      if (!(imageGrid.selectionType == 'camera' && imageGrid.cameraLive)) {
+        chrome.send('supervisedUserSelectImage',
+                    [imageGrid.selectedItemUrl, imageGrid.selectionType]);
+      }
+      // Start/stop camera on (de)selection.
+      if (!imageGrid.inProgramSelection &&
+          imageGrid.selectionType != e.oldSelectionType) {
+        if (imageGrid.selectionType == 'camera') {
+          // Programmatic selection of camera item is done in
+          // startCamera callback where streaming is started by itself.
+          imageGrid.startCamera(
+              function() {
+                // Start capture if camera is still the selected item.
+                return imageGrid.selectedItem == imageGrid.cameraImage;
+              });
+        } else {
+          imageGrid.stopCamera();
+        }
+      }
+    },
+
+    /**
+     * Handle photo capture from the live camera stream.
+     */
+    handleTakePhoto_: function(e) {
+      this.getScreenElement('image-grid').takePhoto();
+    },
+
+    handlePhotoTaken_: function(e) {
+      chrome.send('supervisedUserPhotoTaken', [e.dataURL]);
+    },
+
+    /**
+     * Handle photo updated event.
+     * @param {cr.Event} e Event with 'dataURL' property containing a data URL.
+     */
+    handlePhotoUpdated_: function(e) {
+      chrome.send('supervisedUserPhotoTaken', [e.dataURL]);
+    },
+
+    /**
+     * Handle discarding the captured photo.
+     */
+    handleDiscardPhoto_: function(e) {
+      var imageGrid = this.getScreenElement('image-grid');
+      imageGrid.discardPhoto();
+    },
+
+    setCameraPresent: function(present) {
+      this.getScreenElement('image-grid').cameraPresent = present;
+    },
   };
 });
 
diff --git a/chrome/browser/resources/chromeos/login/user_pod_row.css b/chrome/browser/resources/chromeos/login/user_pod_row.css
index 238418d..33d7135 100644
--- a/chrome/browser/resources/chromeos/login/user_pod_row.css
+++ b/chrome/browser/resources/chromeos/login/user_pod_row.css
@@ -14,6 +14,8 @@
   display: -webkit-box;
   max-height: 650px;
   overflow: visible;
+  position: relative;
+  z-index: 0;
 }
 
 podrow[ncolumns='4'] {
@@ -46,8 +48,10 @@
   display: inline-block;
   margin: 0 20px;
   padding: 10px 10px 3px;
+  position: relative;
   vertical-align: middle;
   width: 160px;
+  z-index: 0;
 }
 
 .pod .main-pane {
@@ -65,6 +69,7 @@
   /* Focused pod has the same size no matter how many pods. */
   -webkit-transform: scale(1.0) !important;
   cursor: default;
+  z-index: 1;
 }
 
 .pod .user-image {
@@ -154,11 +159,10 @@
 }
 
 .pod .capslock-hint {
+  bottom: 13px;
   cursor: text;
-  padding: 4px 8px;
   position: absolute;
-  right: 10px;
-  top: 180px;
+  right: 6px;
   visibility: hidden;
   z-index: 1;
 }
@@ -319,13 +323,6 @@
   width: 100%;
 }
 
-html[oobe=old] .pod.focused .action-box-area {
-  /* Track shifting of .user-image on pod focus. */
-  -webkit-transform: translateY(-1px);
-  -webkit-transition: -webkit-transform 140ms ease;
-  opacity: 1;
-}
-
 .signed-in-indicator {
   -webkit-transition: all 140ms ease;
   background: rgba(0, 0, 0, 0.5);
diff --git a/chrome/browser/resources/chromeos/login/user_pod_row.js b/chrome/browser/resources/chromeos/login/user_pod_row.js
index 29a8ab5..5d62216 100644
--- a/chrome/browser/resources/chromeos/login/user_pod_row.js
+++ b/chrome/browser/resources/chromeos/login/user_pod_row.js
@@ -407,7 +407,7 @@
         return;
 
       if (active) {
-        this.actionBoxMenuRemoveElement.hidden = false;
+        this.actionBoxMenuRemoveElement.hidden = !this.user_.canRemove;
         this.actionBoxRemoveManagedUserWarningElement.hidden = true;
 
         // Clear focus first if another pod is focused.
diff --git a/chrome/browser/resources/chromeos/salsa.css b/chrome/browser/resources/chromeos/salsa.css
new file mode 100644
index 0000000..f2c3485
--- /dev/null
+++ b/chrome/browser/resources/chromeos/salsa.css
@@ -0,0 +1,60 @@
+/* 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. */
+
+#entry-list {
+  list-style-type: none;
+  width: 900px;
+}
+
+.entry {
+  width: 100%;
+}
+
+.entry-key {
+  font-size: small;
+}
+
+.entry-value {
+  font-size: small;
+}
+
+.bold {
+  font-weight: bold;
+}
+
+#treatment-header {
+  display: table-cell;
+  padding-right: 20px;
+  vertical-align: middle;
+}
+
+.treatment {
+  display: table-cell;
+  height: 40px;
+  text-align: center;
+  vertical-align: middle;
+  width: 40px;
+}
+
+.selected {
+  border: 2px solid black;
+  border-radius: 20px;
+}
+
+#bounding-box {
+  border: 1px solid black;
+  border-radius: 10px;
+  margin: 50px;
+  padding: 15px;
+  text-align: center;
+  width: 600px;
+}
+
+#instructions {
+  text-align: left;
+}
+
+#treatment-list {
+  display: inline-block;
+}
diff --git a/chrome/browser/resources/chromeos/salsa.html b/chrome/browser/resources/chromeos/salsa.html
new file mode 100644
index 0000000..22cbfb1
--- /dev/null
+++ b/chrome/browser/resources/chromeos/salsa.html
@@ -0,0 +1,47 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>Salsa</title>
+  <link rel="stylesheet" href="salsa.css">
+  <script src="salsa.js"></script>
+</head>
+
+<body>
+<div id="bounding-box">
+  <h1 class="title">Salsa</h1>
+
+  <div id="invalid_treatment_info" hidden>
+    I'm afraid there has been some problem determining which treatments to use
+    for your experiment.  Please try to copy/paste the URL again and refresh
+    this page.  If the problem persists please contact the person running the
+    experiment.
+  </div>
+
+  <div id="valid_treatment_info">
+    <div id="treatment-list">
+      <div id="treatment-header">Available Treatments:</div>
+      <div id="treatment-template" class="treatment" hidden></div>
+    </div>
+  
+    <p class='bold'>Instructions</p>
+  
+    <ul id="instructions">
+      <li> <span class='bold'>Click</span> or use your <span class='bold'>arrow
+      keys</span> to change the selected treatment.
+  
+      <li> Treatments are ordered randomly, so there is no special significance
+      to their labels.
+  
+      <li> When you navigate away from this page your settings will be returned
+      to normal.  If the browser crashes, and/or you experience unusual behavior
+      after this experiment, you can manually reset your settings to their
+      default values at <a href="chrome://gesture">http://gesture</a>.
+    </ul>
+  
+    <p class='bold'>Thank you for your participation!</p>
+  </div>
+</div>
+
+</body>
+</html>
diff --git a/chrome/browser/resources/chromeos/salsa.js b/chrome/browser/resources/chromeos/salsa.js
new file mode 100644
index 0000000..4525b1c
--- /dev/null
+++ b/chrome/browser/resources/chromeos/salsa.js
@@ -0,0 +1,147 @@
+// 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.
+
+// Redefine '$' here rather than including 'cr.js', since this is
+// the only function needed.  This allows this file to be loaded
+// in a browser directly for layout and some testing purposes.
+var $ = function(id) { return document.getElementById(id); };
+
+var currentTreatment = 0;
+var treatments = [];
+
+/**
+ * Take a string of hex like '74657374' and return the ascii version 'test'.
+ * @param {string} str The string of hex characters to convert to ascii
+ * @return {string} The ASCII values of those hex encoded characters
+ */
+function hexToChars(str) {
+  var decoded = '';
+  if (str.length % 2 == 0) {
+    for (var pos = str.length; pos > 0; pos = pos - 2) {
+      var c = String.fromCharCode(parseInt(str.substring(pos - 2, pos), 16));
+      decoded = c + decoded;
+    }
+  }
+  return decoded;
+}
+
+/**
+ * Extract the experiment information out of the encoded URL string.
+ * The format is as follows:
+ * chrome://salsa/#HEX_ENCODED_EXPERIMENT
+ * Experiments are encoded as:
+ *    treatment1+treatment2+...+treatmentn
+ * Each treatment is of the form:
+ *    preference1,preference2,...,preferencen
+ * Each preference is of the form:
+ *    name:value
+ * This function returns an object storing all the parsed data.
+ * @param {string} url The URL to parse the experiment from
+ * @return {list} a list of objects, each representing a single treatment
+ *     and consisting of a set of preference name -> value pairs
+ */
+function parseURL(url) {
+  var match = url.match('#([0-9ABCDEFabcdef]*)');
+  var experimentString = match ? match[1] : '';
+  experimentString = hexToChars(experimentString);
+
+  var treatmentsFound = [];
+  if (experimentString == '')
+    return treatmentsFound;
+
+  var treatmentStrings = experimentString.split('+');
+  for (var i = 0; i < treatmentStrings.length; i++) {
+    var prefStrings = treatmentStrings[i].split(',');
+    treatment = [];
+    for (var j = 0; j < prefStrings.length; j++) {
+      var key = prefStrings[j].split(':')[0];
+      var value = prefStrings[j].split(':')[1];
+      treatment.push({'key': key, 'value': value});
+    }
+    treatmentsFound.push(treatment);
+  }
+
+  return treatmentsFound;
+}
+
+function setPreferenceValue(key, value) {
+  chrome.send('salsaSetPreferenceValue', [key, parseFloat(value)]);
+}
+
+function backupPreferenceValue(key) {
+  chrome.send('salsaBackupPreferenceValue', [key]);
+}
+
+function handleKeyPress(e) {
+  e = e || window.event;
+  var selectedTreatment = currentTreatment;
+
+  if (e.keyCode == '37' || e.keyCode == '38') {
+    selectedTreatment = currentTreatment - 1;
+    if (selectedTreatment < 0)
+      selectedTreatment = 0;
+  } else if (e.keyCode == '39' || e.keyCode == '40') {
+    selectedTreatment = currentTreatment + 1;
+    if (selectedTreatment >= treatments.length)
+      selectedTreatment = treatments.length - 1;
+  }
+
+  if (selectedTreatment != currentTreatment)
+    applyTreatment(selectedTreatment);
+}
+
+function applyTreatment(treatment_number) {
+  if (treatment_number < 0)
+    treatment_number = 0;
+  if (treatment_number >= treatments.length)
+    treatment_number = treatments.length;
+
+  $('treatment' + currentTreatment).className = 'treatment';
+  currentTreatment = treatment_number;
+  $('treatment' + currentTreatment).className = 'selected treatment';
+
+  for (var i = 0; i < treatments[treatment_number].length; i++) {
+    var key = treatments[treatment_number][i].key;
+    var value = treatments[treatment_number][i].value;
+    setPreferenceValue(key, value);
+  }
+}
+
+function initialize() {
+  // Parse the experiment string in the URL.
+  treatments = parseURL(document.URL);
+
+  // Update the available treatments list.
+  for (var i = 0; i < treatments.length; i++) {
+    var newTreatment = $('treatment-template').cloneNode(true);
+    newTreatment.id = 'treatment' + i.toString();
+    newTreatment.removeAttribute('hidden');
+    newTreatment.onclick = function() {
+      applyTreatment(parseInt(this.textContent));
+    };
+    newTreatment.textContent = i.toString();
+    $('treatment-list').appendChild(newTreatment);
+  }
+
+  if (treatments.length > 0) {
+    // Store a copy of the settings right now so you can reset them afterwards.
+    for (var i = 0; i < treatments[0].length; i++)
+      backupPreferenceValue(treatments[0][i].key);
+
+    // Select Treatment 0 to start
+    applyTreatment(0);
+  } else {
+    // Make the error message visible and hide everything else
+    $('invalid_treatment_info').removeAttribute('hidden');
+    var div = $('valid_treatment_info');
+    div.parentNode.removeChild(div);
+  }
+}
+
+/**
+ * A key handler so the user can use the arrow keys to select their treatments.
+ * This should fire any time they press a key
+ */
+document.onkeydown = handleKeyPress;
+document.addEventListener('DOMContentLoaded', initialize);
diff --git a/chrome/browser/resources/chromeos/speech_synthesis/manifest.json b/chrome/browser/resources/chromeos/speech_synthesis/manifest.json
index 6222c68..a756710 100644
--- a/chrome/browser/resources/chromeos/speech_synthesis/manifest.json
+++ b/chrome/browser/resources/chromeos/speech_synthesis/manifest.json
@@ -1,11 +1,16 @@
 {
   "name": "Chrome OS built-in text-to-speech extension",
-  "version": "0.0.1",
+  "version": "0.0.2",
   "description": "Text-to-speech (TTS) voice extension using Native Client technology.",
   "manifest_version": 2,
   "background": {
     "scripts": [
+      "voice_data_hmm_de-DE.js",
+      "voice_data_hmm_en-GB.js",
       "voice_data_hmm_en-US.js",
+      "voice_data_hmm_es-ES.js",
+      "voice_data_hmm_fr-FR.js",
+      "voice_data_hmm_it-IT.js",
       "tts_main.js"
     ]
   },
@@ -17,40 +22,40 @@
   "tts_engine": {
     "voices": [
       {
-        "voice_name": "Chrome OS US English Voice",
-        "lang": "en-US",
-        "gender": "female",
-        "event_types": [ "start", "word", "end", "error" ]
-      },
-      {
-        "voice_name": "Chrome OS UK English Voice",
-        "lang": "en-GB",
-        "gender": "female",
-        "event_types": [ "start", "word", "end", "error" ]
-      },
-      {
-        "voice_name": "Chrome OS French Voice",
+        "voice_name": "Chrome OS French",
         "lang": "fr-FR",
         "gender": "female",
         "event_types": [ "start", "word", "end", "error" ]
       },
       {
-        "voice_name": "Chrome OS Spanish Voice",
-        "lang": "es-ES",
-        "gender": "female",
-        "event_types": [ "start", "word", "end", "error" ]
-      },
-      {
-        "voice_name": "Chrome OS German Voice",
+        "voice_name": "Chrome OS German",
         "lang": "de-DE",
         "gender": "female",
         "event_types": [ "start", "word", "end", "error" ]
       },
       {
-        "voice_name": "Chrome OS Italian Voice",
+        "voice_name": "Chrome OS Italian",
         "lang": "it-IT",
         "gender": "female",
         "event_types": [ "start", "word", "end", "error" ]
+      },
+      {
+        "voice_name": "Chrome OS US English",
+        "lang": "en-US",
+        "gender": "female",
+        "event_types": [ "start", "word", "end", "error" ]
+      },
+      {
+        "voice_name": "Chrome OS British English",
+        "lang": "en-GB",
+        "gender": "female",
+        "event_types": [ "start", "word", "end", "error" ]
+      },
+      {
+        "voice_name": "Chrome OS Spanish",
+        "lang": "es-ES",
+        "gender": "female",
+        "event_types": [ "start", "word", "end", "error" ]
       }
     ]
   }
diff --git a/chrome/browser/resources/chromeos/user_images_grid.js b/chrome/browser/resources/chromeos/user_images_grid.js
index 8e8fc0c..3479d58 100644
--- a/chrome/browser/resources/chromeos/user_images_grid.js
+++ b/chrome/browser/resources/chromeos/user_images_grid.js
@@ -382,8 +382,10 @@
       }
 
       // Set focus to the grid, unless focus is on the OK button.
-      if (!document.activeElement || document.activeElement.tagName != 'BUTTON')
+      if ((!document.activeElement ||
+           document.activeElement.tagName != 'BUTTON') && imageUrl) {
         this.focus();
+      }
     },
 
     /**
diff --git a/chrome/browser/resources/chromeos/wallpaper_manager/images/icon128.png b/chrome/browser/resources/chromeos/wallpaper_manager/images/icon128.png
index 6d973d3..c0abfaf 100644
--- a/chrome/browser/resources/chromeos/wallpaper_manager/images/icon128.png
+++ b/chrome/browser/resources/chromeos/wallpaper_manager/images/icon128.png
Binary files differ
diff --git a/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/2x/add-wallpaper-thumbnail-hover.png b/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/2x/add-wallpaper-thumbnail-hover.png
index c979377..3cbf6aa 100644
--- a/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/2x/add-wallpaper-thumbnail-hover.png
+++ b/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/2x/add-wallpaper-thumbnail-hover.png
Binary files differ
diff --git a/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/2x/add-wallpaper-thumbnail.png b/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/2x/add-wallpaper-thumbnail.png
index 245ab71..710a959 100644
--- a/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/2x/add-wallpaper-thumbnail.png
+++ b/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/2x/add-wallpaper-thumbnail.png
Binary files differ
diff --git a/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/2x/check.png b/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/2x/check.png
index 1612db3..f11047e 100644
--- a/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/2x/check.png
+++ b/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/2x/check.png
Binary files differ
diff --git a/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/2x/close-error-hover.png b/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/2x/close-error-hover.png
index 72d6268..c49f563 100644
--- a/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/2x/close-error-hover.png
+++ b/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/2x/close-error-hover.png
Binary files differ
diff --git a/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/2x/close-error.png b/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/2x/close-error.png
index a65fcfa..efb23e7 100644
--- a/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/2x/close-error.png
+++ b/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/2x/close-error.png
Binary files differ
diff --git a/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/2x/close-white-hover.png b/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/2x/close-white-hover.png
index e3b9421..548fdf4 100644
--- a/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/2x/close-white-hover.png
+++ b/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/2x/close-white-hover.png
Binary files differ
diff --git a/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/2x/close-white.png b/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/2x/close-white.png
index 5c00c56..3e87fa3 100644
--- a/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/2x/close-white.png
+++ b/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/2x/close-white.png
Binary files differ
diff --git a/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/2x/close_bar.png b/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/2x/close_bar.png
index 98ae94c..142adb8 100644
--- a/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/2x/close_bar.png
+++ b/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/2x/close_bar.png
Binary files differ
diff --git a/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/add-wallpaper-thumbnail-hover.png b/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/add-wallpaper-thumbnail-hover.png
index 533decb..7cfb59d 100644
--- a/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/add-wallpaper-thumbnail-hover.png
+++ b/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/add-wallpaper-thumbnail-hover.png
Binary files differ
diff --git a/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/add-wallpaper-thumbnail.png b/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/add-wallpaper-thumbnail.png
index d57a149..0c19c02 100644
--- a/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/add-wallpaper-thumbnail.png
+++ b/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/add-wallpaper-thumbnail.png
Binary files differ
diff --git a/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/check.png b/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/check.png
index 30143d1..d0bb12d 100644
--- a/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/check.png
+++ b/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/check.png
Binary files differ
diff --git a/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/checkbox_checked.png b/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/checkbox_checked.png
index ad8e943..238ce2f 100644
--- a/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/checkbox_checked.png
+++ b/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/checkbox_checked.png
Binary files differ
diff --git a/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/close-error-hover.png b/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/close-error-hover.png
index fe896f9..c3ce1dc 100644
--- a/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/close-error-hover.png
+++ b/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/close-error-hover.png
Binary files differ
diff --git a/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/close-error.png b/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/close-error.png
index 793f60e..02e1f91 100644
--- a/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/close-error.png
+++ b/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/close-error.png
Binary files differ
diff --git a/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/close-white-hover.png b/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/close-white-hover.png
index dd51c6c..e90252b 100644
--- a/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/close-white-hover.png
+++ b/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/close-white-hover.png
Binary files differ
diff --git a/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/close-white.png b/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/close-white.png
index ff9b143..4ac41b2 100644
--- a/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/close-white.png
+++ b/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/close-white.png
Binary files differ
diff --git a/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/close_bar.png b/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/close_bar.png
index 69c9017..e70e5b6 100644
--- a/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/close_bar.png
+++ b/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/close_bar.png
Binary files differ
diff --git a/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/remember.png b/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/remember.png
index e1aeab7..e4381bc 100644
--- a/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/remember.png
+++ b/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/remember.png
Binary files differ
diff --git a/chrome/browser/resources/cloud_print/cell_phone.png b/chrome/browser/resources/cloud_print/cell_phone.png
deleted file mode 100644
index 9925290..0000000
--- a/chrome/browser/resources/cloud_print/cell_phone.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/cloud_print/cloud_print_setup_done.css b/chrome/browser/resources/cloud_print/cloud_print_setup_done.css
deleted file mode 100644
index 5883c75..0000000
--- a/chrome/browser/resources/cloud_print/cloud_print_setup_done.css
+++ /dev/null
@@ -1,47 +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. */
-
-body {
-  -webkit-user-select: none;
-  background: white;
-  margin: 10px 15px;
-}
-
-.cloudprint-success-header {
-  font-size: 1.4em;
-  font-weight: bold;
-}
-
-.cloudprint-success-image {
-  margin: 20px;
-  text-align: center;
-}
-
-#message {
-  font-weight: bold;
-}
-
-.cloudprint-success-footer {
-  bottom: 0;
-  font-size: 1.2em;
-  margin-bottom: 10px;
-  margin-right: 10px;
-  position: fixed;
-  right: 0;
-}
-
-html[dir='rtl'] .cloudprint-success-footer {
-  bottom: 0;
-  left: 0;
-  margin-left: 20px;
-  text-align: left;
-}
-
-.button {
-<if expr="is_macosx">
-  font-size: 12pt;
-</if>
-  min-height: 26px;
-  min-width: 87px;
-}
diff --git a/chrome/browser/resources/cloud_print/cloud_print_setup_done.html b/chrome/browser/resources/cloud_print/cloud_print_setup_done.html
deleted file mode 100644
index 0bfec33..0000000
--- a/chrome/browser/resources/cloud_print/cloud_print_setup_done.html
+++ /dev/null
@@ -1,22 +0,0 @@
-<!DOCTYPE HTML>
-<html i18n-values="dir:textdirection;">
-<head>
-<link rel="stylesheet" type="text/css" href="cloud_print_setup_done.css">
-<script src="chrome://resources/js/cr.js"></script>
-<script src="chrome://resources/js/util.js"></script>
-<script type="text/javascript" src="cloud_print_setup_done.js"></script>
-</head>
-<body i18n-values=".style.fontFamily:fontfamily;.style.fontSize:fontsize">
-  <div class="cloudprint-success-header" i18n-content="success"></div>
-  <div class="cloudprint-success-image">
-    <img src="../../../../ui/webui/resources/images/success.png">
-  </div>
-  <div id="msg-content"></div>
-  <div class="cloudprint-success-footer">
-    <input id="testpage" type="button" class="button" value="Test"
-        i18n-values="value:testpage" onclick="cloudprint.printTestPage()">
-    <input id="close" type="submit" class="button" i18n-values="value:okay"
-        onclick="chrome.send('DialogClose')">
-  </div>
-</body>
-</html>
diff --git a/chrome/browser/resources/cloud_print/cloud_print_setup_done.js b/chrome/browser/resources/cloud_print/cloud_print_setup_done.js
deleted file mode 100644
index aaadabc..0000000
--- a/chrome/browser/resources/cloud_print/cloud_print_setup_done.js
+++ /dev/null
@@ -1,24 +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.
-
-cr.define('cloudprint', function() {
-  function printTestPage() {
-    chrome.send('PrintTestPage');
-    chrome.send('DialogClose');
-  }
-
-  function setMessage(msg) {
-    $('msg-content').innerHTML = msg;
-  }
-
-  function onPageShown() {
-    $('close').focus();
-  }
-
-  return {
-    printTestPage: printTestPage,
-    setMessage: setMessage,
-    onPageShown: onPageShown
-  };
-});
diff --git a/chrome/browser/resources/cloud_print/cloud_print_setup_flow.html b/chrome/browser/resources/cloud_print/cloud_print_setup_flow.html
deleted file mode 100644
index be8a657..0000000
--- a/chrome/browser/resources/cloud_print/cloud_print_setup_flow.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<!DOCTYPE HTML>
-<html i18n-values="dir:textdirection;">
-<head>
-<title></title>
-<script src="chrome://resources/js/cr.js"></script>
-<script src="chrome://resources/js/util.js"></script>
-<script type="text/javascript" src="cloud_print_setup_flow.js"></script>
-</head>
-<body style="margin:0; border:0;" onload="cloudprint.showInitialPage();">
-  <iframe id="cloudprintsetup"
-          src="chrome://cloudprintsetup/cloudprintsetup"
-          frameborder="0" width="100%" scrolling="no" height="100%"
-          style="display:none" tabindex="-1"></iframe>
-  <iframe id="setupdone"
-          src="chrome://cloudprintsetup/setupdone"
-          frameborder="0" width="100%" scrolling="no" height="100%"
-          style="display:none" tabindex="-1"></iframe>
-</body>
-</html>
diff --git a/chrome/browser/resources/cloud_print/cloud_print_setup_flow.js b/chrome/browser/resources/cloud_print/cloud_print_setup_flow.js
deleted file mode 100644
index 25758f1..0000000
--- a/chrome/browser/resources/cloud_print/cloud_print_setup_flow.js
+++ /dev/null
@@ -1,47 +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.
-
-cr.define('cloudprint', function() {
-  function hideAllPages() {
-    var pages = ['cloudprintsetup', 'setupdone'];
-    for (var i = 0; i < pages.length; ++i) {
-      $(pages[i]).style.display = 'none';
-      $(pages[i]).tabIndex = -1;
-    }
-  }
-
-  function showPage(page) {
-    hideAllPages();
-    $(page).style.display = 'block';
-    $(page).tabIndex = 0;
-  }
-
-  function showInitialPage() {
-    var args = JSON.parse(chrome.getVariableValue('dialogArguments'));
-    showPage(args.pageToShow);
-  }
-
-  function showSetupLogin() {
-    showPage('cloudprintsetup');
-  }
-
-  function showSetupDone(width, height) {
-    hideAllPages();
-    var moveByX = (window.innerWidth - width) / 2;
-    var moveByY = (window.innerHeight - height) / 2;
-    var sizeByX = width - window.innerWidth;
-    var sizeByY = height - window.innerHeight;
-    window.moveBy(moveByX, moveByY);
-    window.resizeBy(sizeByX, sizeByY);
-    showPage('setupdone');
-  }
-
-  return {
-    hideAllPages: hideAllPages,
-    showPage: showPage,
-    showInitialPage: showInitialPage,
-    showSetupLogin: showSetupLogin,
-    showSetupDone: showSetupDone
-  };
-});
diff --git a/chrome/browser/resources/cloud_print/cloud_print_setup_login.css b/chrome/browser/resources/cloud_print/cloud_print_setup_login.css
deleted file mode 100644
index 6338db1..0000000
--- a/chrome/browser/resources/cloud_print/cloud_print_setup_login.css
+++ /dev/null
@@ -1,37 +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. */
-
-body {
-  -webkit-user-select: none;
-  background: white;
-  margin: 10px 15px;
-}
-
-.cloudprint-signup {
-  vertical-align: top;
-  width: 60%;
-}
-
-.cloudprint-login {
-  border: 2px;
-  width: 40%;
-}
-
-.cloudprint-header {
-  font-weight: bold;
-}
-
-.cloudprint-item-header {
-  font-size: 0.9em;
-  font-weight: bold;
-}
-
-.cloudprint-item-explain {
-  font-size: 0.9em;
-}
-
-.cloudprint-item-image {
-  padding: 8px;
-  text-align: center;
-}
diff --git a/chrome/browser/resources/cloud_print/cloud_print_setup_login.html b/chrome/browser/resources/cloud_print/cloud_print_setup_login.html
deleted file mode 100644
index 7bfe5b9..0000000
--- a/chrome/browser/resources/cloud_print/cloud_print_setup_login.html
+++ /dev/null
@@ -1,65 +0,0 @@
-<!DOCTYPE HTML>
-<html i18n-values="dir:textdirection;">
-<head>
-<title></title>
-<link rel="stylesheet" type="text/css" href="cloud_print_setup_login.css">
-<script src="chrome://resources/js/cr.js"></script>
-<script src="chrome://resources/js/util.js"></script>
-<script type="text/javascript" src="cloud_print_setup_login.js"></script>
-</head>
-<body i18n-values=".style.fontFamily:fontfamily;.style.fontSize:fontsize"
-      onload="cloudprint.fixUpTemplateLink();">
-  <table class="cloudprint-contents" id="cloudprint-contents">
-    <tbody>
-      <tr>
-        <td class="cloudprint-signup" id="cloudprint-signup">
-          <table class="cloudprint-intro">
-            <tbody>
-              <tr><td><div class="cloudprint-header" id="header"
-                           i18n-content="header"></div></td></tr>
-              <tr><td><div class="cloudprint-explain" id="explain"
-                           i18n-content="explain"></div></td></tr>
-            </tbody>
-          </table>
-          <table class="cloudprint-body">
-            <tbody>
-              <tr>
-                <td class="cloudprint-item-image">
-                  <img src="cell_phone.png"></td>
-                <td>
-                  <div class="cloudprint-item-header" id="anywhere-header"
-                       i18n-content="anywhereheader"></div>
-                  <div class="cloudprint-item-explain" id="anywhere-explain"
-                       i18n-content="anywhereexplain"></div></td>
-              </tr>
-              <tr>
-                <td class="cloudprint-item-image">
-                  <img src="cloud_printer.png"></td>
-                <td>
-                  <div class="cloudprint-item-header" id="printer-header"
-                       i18n-content="printerheader"></div>
-                  <div class="cloudprint-item-explain" id="printer-explain"
-                       i18n-content="printerexplain"></div></td>
-              </tr>
-              <tr>
-                <td class="cloudprint-item-image">
-                  <img src="sharing.png"></td>
-                <td>
-                  <div class="cloudprint-item-header" id="sharing-header"
-                       i18n-content="sharingheader"></div>
-                  <div class="cloudprint-item-explain" id="sharing-explain"
-                       i18n-content="sharingexplain"></div></td>
-              </tr>
-            </tbody>
-          </table>
-        </td>
-        <td class="cloudprint-login">
-          <iframe id="gaialogin" frameborder="0"
-                  width="100%" scrolling="no" height="100%"
-                  src="chrome://cloudprintsetup/gaialogin"></iframe>
-        </td>
-      </tr>
-    </tbody>
-  </table>
-</body>
-</html>
diff --git a/chrome/browser/resources/cloud_print/cloud_print_setup_login.js b/chrome/browser/resources/cloud_print/cloud_print_setup_login.js
deleted file mode 100644
index 13472f2..0000000
--- a/chrome/browser/resources/cloud_print/cloud_print_setup_login.js
+++ /dev/null
@@ -1,37 +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.
-
-cr.define('cloudprint', function() {
-  function learnMore() {
-    chrome.send('LearnMore', ['']);
-    chrome.send('DialogClose', ['']);
-  }
-
-  function fixUpTemplateLink() {
-    var elm = $('anywhere-explain');
-    if (elm)
-      elm.innerHTML = elm.textContent;
-  }
-
-  function showGaiaLogin(args) {
-    frames['gaialogin'].showGaiaLogin(args);
-    new_height = $('cloudprint-signup').offsetHeight;
-    login_height = frames['gaialogin'].document.body.scrollHeight;
-    if (login_height > new_height) {
-      new_height = login_height;
-    }
-    $('cloudprint-contents').style.height = new_height + 4 + 'px';
-  }
-
-  function showGaiaSuccessAndSettingUp() {
-    frames['gaialogin'].showGaiaSuccessAndSettingUp()
-  }
-
-  return {
-    learnMore: learnMore,
-    fixUpTemplateLink: fixUpTemplateLink,
-    showGaiaLogin: showGaiaLogin,
-    showGaiaSuccessAndSettingUp: showGaiaSuccessAndSettingUp
-  };
-});
diff --git a/chrome/browser/resources/cloud_print/cloud_printer.png b/chrome/browser/resources/cloud_print/cloud_printer.png
deleted file mode 100644
index 6f84682..0000000
--- a/chrome/browser/resources/cloud_print/cloud_printer.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/cloud_print/sharing.png b/chrome/browser/resources/cloud_print/sharing.png
deleted file mode 100644
index 6a91ac8..0000000
--- a/chrome/browser/resources/cloud_print/sharing.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/component_extension_resources.grd b/chrome/browser/resources/component_extension_resources.grd
index 067092a..6b254b8 100644
--- a/chrome/browser/resources/component_extension_resources.grd
+++ b/chrome/browser/resources/component_extension_resources.grd
@@ -38,7 +38,6 @@
       <include name="IDR_GAIA_AUTH_SUCCESS" file="gaia_auth/success.html" allowexternalscript="true" type="BINDATA" />
       <include name="IDR_GAIA_AUTH_SUCCESS_JS" file="gaia_auth/success.js" type="BINDATA" />
       <include name="IDR_GAIA_AUTH_UTIL_JS" file="gaia_auth/util.js" type="BINDATA" />
-      <include name="IDR_GAIA_AUTH_TEST_CONTENT_JS" file="gaia_auth/test/content.js" type="BINDATA" />
       <if expr="pp_ifdef('chromeos')">
         <!-- Background page loader  -->
         <include name="IDR_BACKLOADER_BACKGROUND_HTML" file="backloader/background.html" type="BINDATA" />
@@ -87,7 +86,11 @@
         <!-- Images referenced from the manifest or the code -->
         <include name="IDR_FILE_MANAGER_ICON_16" file="file_manager/images/icon16.png" type="BINDATA" />
         <include name="IDR_FILE_MANAGER_ICON_32" file="file_manager/images/icon32.png" type="BINDATA" />
+        <include name="IDR_FILE_MANAGER_ICON_48" file="file_manager/images/icon48.png" type="BINDATA" />
+        <include name="IDR_FILE_MANAGER_ICON_64" file="file_manager/images/icon64.png" type="BINDATA" />
+        <include name="IDR_FILE_MANAGER_ICON_96" file="file_manager/images/icon96.png" type="BINDATA" />
         <include name="IDR_FILE_MANAGER_ICON_128" file="file_manager/images/icon128.png" type="BINDATA" />
+        <include name="IDR_FILE_MANAGER_ICON_256" file="file_manager/images/icon256.png" type="BINDATA" />
 
         <!-- Resources used for non-flattened HTML files. -->
         <include name="IDR_FILE_MANAGER_DRIVE_WELCOME_STYLE" file="file_manager/css/drive_welcome.css" type="BINDATA" />
@@ -111,8 +114,12 @@
         <include name="IDR_FILE_MANAGER_IMG_GALLERY_2X_CURSOR_UPDOWN" file="file_manager/images/gallery/2x/cursor_updown.png" type="BINDATA" />
       </if>
       <if expr="pp_ifdef('image_loader_extension')">
-        <include name="IDR_IMAGE_LOADER_MAIN_JS" file="image_loader/image_loader.js" type="BINDATA" />
-        <include name="IDR_IMAGE_LOADER_CLIENT_JS" file="image_loader/client.js" type="BINDATA" />
+        <include name="IDR_IMAGE_LOADER_IMAGE_LOADER_JS" file="image_loader/image_loader.js" type="BINDATA" />
+        <include name="IDR_IMAGE_LOADER_CACHE_JS" file="image_loader/cache.js" type="BINDATA" />
+        <include name="IDR_IMAGE_LOADER_WORKER_JS" file="image_loader/worker.js" type="BINDATA" />
+        <include name="IDR_IMAGE_LOADER_REQUEST_JS" file="image_loader/request.js" type="BINDATA" />
+        <include name="IDR_IMAGE_LOADER_BACKGROUND_JS" file="image_loader/background.js" type="BINDATA" />
+        <include name="IDR_IMAGE_LOADER_CLIENT_JS" file="image_loader/image_loader_client.js" type="BINDATA" />
       </if>
       <if expr="pp_ifdef('enable_google_now')">
         <include name="IDR_GOOGLE_NOW_BACKGROUND_JS" file="google_now/background.js" type="BINDATA" />
diff --git a/chrome/browser/resources/downloads_section.png b/chrome/browser/resources/downloads_section.png
index 6d82a40..1f59297 100644
--- a/chrome/browser/resources/downloads_section.png
+++ b/chrome/browser/resources/downloads_section.png
Binary files differ
diff --git a/chrome/browser/resources/extensions/extension_list.js b/chrome/browser/resources/extensions/extension_list.js
index ea232a5..f689263 100644
--- a/chrome/browser/resources/extensions/extension_list.js
+++ b/chrome/browser/resources/extensions/extension_list.js
@@ -97,7 +97,10 @@
         node.classList.add('extension-highlight');
 
       var item = node.querySelector('.extension-list-item');
-      item.style.backgroundImage = 'url(' + extension.icon + ')';
+      var extensionIconUrl = extension.icon;
+      if (extension.allow_reload)
+        extensionIconUrl = extension.icon + '?' + Date.now();
+      item.style.backgroundImage = 'url(' + extensionIconUrl + ')';
 
       var title = node.querySelector('.extension-title');
       title.textContent = extension.name;
@@ -239,6 +242,7 @@
       var trash = trashTemplate.cloneNode(true);
       trash.title = loadTimeData.getString('extensionUninstall');
       trash.addEventListener('click', function(e) {
+        butterBarVisibility[extension.id] = false;
         chrome.send('extensionSettingsUninstall', [extension.id]);
       });
       node.querySelector('.enable-controls').appendChild(trash);
diff --git a/chrome/browser/resources/extensions/extensions.js b/chrome/browser/resources/extensions/extensions.js
index 6af2665..e2010cd 100644
--- a/chrome/browser/resources/extensions/extensions.js
+++ b/chrome/browser/resources/extensions/extensions.js
@@ -153,11 +153,6 @@
      */
     handleLoadUnpackedExtension_: function(e) {
       chrome.send('extensionSettingsLoadUnpackedExtension');
-
-      // TODO(jhawkins): Refactor metrics support out of options and use it
-      // in extensions.html.
-      chrome.send('coreOptionsUserMetricsAction',
-                  ['Options_LoadUnpackedExtension']);
     },
 
     /**
@@ -167,7 +162,7 @@
      */
     handlePackExtension_: function(e) {
       ExtensionSettings.showOverlay($('packExtensionOverlay'));
-      chrome.send('coreOptionsUserMetricsAction', ['Options_PackExtension']);
+      chrome.send('metricsHandler:recordAction', ['Options_PackExtension']);
     },
 
     /**
@@ -177,7 +172,7 @@
      */
     showExtensionCommandsConfigUi_: function(e) {
       ExtensionSettings.showOverlay($('extensionCommandsOverlay'));
-      chrome.send('coreOptionsUserMetricsAction',
+      chrome.send('metricsHandler:recordAction',
                   ['Options_ExtensionCommands']);
     },
 
diff --git a/chrome/browser/resources/file_manager/action_choice.html b/chrome/browser/resources/file_manager/action_choice.html
index 91fbd11..4df5eb6 100644
--- a/chrome/browser/resources/file_manager/action_choice.html
+++ b/chrome/browser/resources/file_manager/action_choice.html
@@ -21,7 +21,7 @@
     <!-- Keep the list in sync with action_choice_scripts.js. -->
 
     <!-- Loads the client of the image loader extension -->
-    <script src="chrome-extension://pmfjbimdmchhbnneeidfognadeopoehp/client.js"></script>
+    <script src="chrome-extension://pmfjbimdmchhbnneeidfognadeopoehp/image_loader_client.js"></script>
 
     <script src="chrome://resources/js/load_time_data.js"></script>
     <script src="chrome://resources/js/util.js"></script>
diff --git a/chrome/browser/resources/file_manager/css/common.css b/chrome/browser/resources/file_manager/css/common.css
index 832b47a..03eea6c 100644
--- a/chrome/browser/resources/file_manager/css/common.css
+++ b/chrome/browser/resources/file_manager/css/common.css
@@ -2,6 +2,11 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file. */
 
+/* Special attribute to hide elements. */
+[hidden] {
+  display: none !important;
+}
+
 /* This file contains "borrowed" copy of standard styles. To simplify merging,
  * when altering, please preserve original property value by adding comments. */
 input.common[type='checkbox'],
@@ -112,12 +117,7 @@
 
 .buttonbar {
   display: -webkit-box;
-  height: 35px;
-}
-
-.buttonbar.right {
-  -webkit-box-flex: 1.0;
-  -webkit-box-pack: end;
+  height: 31px;
 }
 
 .buttonbar button:active img {
@@ -176,7 +176,7 @@
 }
 
 menu.chrome-menu[hidden] {
-  display: block;
+  display: block !important;  /* Overrides default [hidden] for animation. */
   opacity: 0;
   pointer-events: none;
   visibility: hidden;
@@ -246,7 +246,10 @@
   display: none;
 }
 
-/* Ok/Cancel style buttons */
+/**
+ * Ok/Cancel style buttons
+ * Height: 31px (content:21px + border:5px * 2)
+ **/
 button,
 input[type='button'],
 input[type='submit'],
@@ -258,16 +261,15 @@
   border: 5px solid transparent;
   border-image: -webkit-image-set(
     url('../images/common/button.png') 1x,
-    url('../images/common/2x/button.png') 2x) 5 5 repeat;
-  box-shadow: inset 0 1px 1px 0 rgb(255, 255, 255);
+    url('../images/common/2x/button.png') 2x) 5 / 5px / 2px repeat;
   box-sizing: content-box;
   color: rgb(34, 34, 34);
   cursor: default;
-  height: 25px;
-  line-height: 25px;
+  height: 21px;
+  line-height: 21px;
   margin: 0;
-  min-height: 25px;
-  min-width: 60px;
+  min-height: 21px;
+  min-width: 55px;
   padding: 0 10px;
   position: relative;
   text-align: center;
@@ -275,7 +277,7 @@
 }
 
 .buttonbar button {
-  -webkit-margin-start: 8px;
+  -webkit-margin-start: 10px;
 }
 
 button:hover,
@@ -284,8 +286,7 @@
 select:hover {
   border-image: -webkit-image-set(
     url('../images/common/button_hover.png') 1x,
-    url('../images/common/2x/button_hover.png') 2x) 5 5 repeat;
-  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
+    url('../images/common/2x/button_hover.png') 2x) 5 / 5px / 2px repeat;
   color: #222;
 }
 
@@ -294,8 +295,7 @@
 input[type='submit']:active {
   border-image: -webkit-image-set(
     url('../images/common/button_pressed.png') 1x,
-    url('../images/common/2x/button_pressed.png') 2x) 5 5 repeat;
-  box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
+    url('../images/common/2x/button_pressed.png') 2x) 5 / 5px / 2px repeat;
   color: #333;
 }
 
@@ -307,12 +307,9 @@
 input[type='submit'][disabled]:hover {
   background-color: rgb(250, 250, 250);
   background-image: none;
-  border: 1px solid rgb(255, 255, 255);
-  border-bottom: 1px solid rgb(180, 180, 180);
-  border-left: 1px solid rgb(220, 220, 220);
-  border-right: 1px solid rgb(200, 200, 200);
-  border-top: 1px solid rgb(220, 220, 220);
-  box-shadow: inset 0 1px 1px 0 rgb(255, 255, 255);
+  border-image: -webkit-image-set(
+    url('../images/common/button.png') 1x,
+    url('../images/common/2x/button.png') 2x) 5 / 5px / 2px repeat;
   color: rgb(150, 150, 150);
 }
 
@@ -441,10 +438,6 @@
   transition: opacity 500ms;
 }
 
-[hidden] {
-  display: none;
-}
-
 .cr-dialog-title {
   -webkit-margin-after: 10px;
   -webkit-margin-end: 20px;
diff --git a/chrome/browser/resources/file_manager/css/drive_welcome.css b/chrome/browser/resources/file_manager/css/drive_welcome.css
index 8f4332c..a3c5ddb 100644
--- a/chrome/browser/resources/file_manager/css/drive_welcome.css
+++ b/chrome/browser/resources/file_manager/css/drive_welcome.css
@@ -125,7 +125,7 @@
   left: 0;
   position: absolute;
   right: 0;
-  top: 28px;  /* Leave room for the file list header. */
+  top: 0;
 }
 
 .dialog-container:not([drive-welcome='page']) .drive-welcome.page {
@@ -139,7 +139,6 @@
 .drive-welcome.page .drive-welcome-wrapper {
   -webkit-box-align: center;
   -webkit-box-orient: vertical;
-  background-position: 0 50px;
   background-size: 520px 173px;
   bottom: 0;
   display: -webkit-box;
diff --git a/chrome/browser/resources/file_manager/css/file_manager.css b/chrome/browser/resources/file_manager/css/file_manager.css
index 1e758ad..184f4f3 100644
--- a/chrome/browser/resources/file_manager/css/file_manager.css
+++ b/chrome/browser/resources/file_manager/css/file_manager.css
@@ -2,6 +2,21 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file. */
 
+/* Special attribute used in HTML to hide elements. */
+body[type='folder'] [invisibleif~='folder'],
+body[type='saveas-file'] [invisibleif~='saveas-file'],
+body[type='open-file'] [invisibleif~='open-file'],
+body[type='open-multi-file'] [invisibleif~='open-multi-file'],
+body[type='full-page'] [invisibleif~='full-page'],
+
+body[type='folder'] [visibleif]:not([visibleif~='folder']),
+body[type='saveas-file'] [visibleif]:not([visibleif~='saveas-file']),
+body[type='open-file'] [visibleif]:not([visibleif~='open-file']),
+body[type='open-multi-file'] [visibleif]:not([visibleif~='open-multi-file']),
+body[type='full-page'] [visibleif]:not([visibleif~='full-page']) {
+  display: none !important;
+}
+
 html {
   height: 100%;
 }
@@ -131,20 +146,6 @@
   white-space: nowrap;
 }
 
-/* The top title of the dialog. */
-.dialog-title {
-  -webkit-padding-start: 15px;
-  background-image: linear-gradient(to bottom, #fff, #f6f6f6);
-  border-bottom: 1px rgb(214, 217, 227) solid;
-  box-sizing: border-box;
-  color: rgb(66, 80, 108);
-  font-size: 15px;
-  font-weight: bold;
-  height: 32px;
-  padding-bottom: 8px;
-  padding-top: 8px;
-}
-
 /* Main part of the dialog between header and footer. */
 .dialog-container {
   -webkit-box-align: stretch;
@@ -223,11 +224,7 @@
 }
 
 #volume-list > * {
-  background-color: rgb(240, 240, 240);
-  background-image: none;
-  border: none;
   height: 40px;
-  margin: 0;
   padding: 0 5px;
 }
 
@@ -250,7 +247,6 @@
 
 #volume-list li.root-item {
   -webkit-box-align: center;
-  border-radius: 0;
   display: -webkit-box;
   line-height: 22px;  /* To accomodate for icons. */
   padding-left: 11px;
@@ -278,7 +274,9 @@
   color: rgb(100, 100, 100);
   height: 47px;
   line-height: 40px;
+  overflow-x: hidden;
   position: absolute;
+  text-overflow: ellipsis;
   width: 100%;
 }
 
@@ -295,14 +293,9 @@
 }
 
 #directory-tree .tree-row {
-  background-color: white;
-  background-image: none;
-  border: none;
-  border-radius: 0;
   cursor: pointer;
   display: -webkit-box;
   line-height: 29px;
-  margin: 0;
   padding: 0 3px;
 }
 
@@ -315,7 +308,6 @@
   height: 37px;
   left: 3px;
   margin: -13px;
-  opacity: 1;
   top: 0;
   vertical-align: middle;
   width: 37px;
@@ -375,8 +367,6 @@
 }
 
 #volume-list .root-item > div.root-eject {
-  /* The transition commented out to work around crbug.com/157813 */
-  /* transition: opacity 70ms linear; */
   background-image: -webkit-image-set(
     url('../images/files/ui/eject.png') 1x,
     url('../images/files/ui/2x/eject.png') 2x);
@@ -386,15 +376,14 @@
   height: 20px;
   margin-right: 6px;
   opacity: 0.7;
+  transition: opacity 70ms linear;
   vertical-align: middle;
   width: 20px;
 }
 
-#directory-tree .tree-row > div.root-eject[hidden] {
-  /* [hidden] has alredy set in dialog.css, but it is overridden by the
-   * selector '.tree-item > .tree-row > * 'in tree.js, hence we need to
-   * override it again. */
-  display: none;
+#volume-list:focus .root-item[selected] > div.root-eject {
+  -webkit-filter: brightness(0) invert();
+  opacity: 1;
 }
 
 #directory-tree .tree-row > div.root-eject:hover {
@@ -438,25 +427,20 @@
 
 .dialog-header #gear-button {
   background-image: -webkit-image-set(
-    url('../images/files/ui/new-ui/topbar_button_settings.png') 1x,
-    url('../images/files/ui/new-ui/2x/topbar_button_settings.png') 2x);
+    url('../images/files/ui/topbar_button_settings.png') 1x,
+    url('../images/files/ui/2x/topbar_button_settings.png') 2x);
 }
 
 .dialog-header #maximize-button {
   background-image: -webkit-image-set(
-    url('../images/files/ui/new-ui/topbar_button_maximize.png') 1x,
-    url('../images/files/ui/new-ui/2x/topbar_button_maximize.png') 2x);
+    url('../images/files/ui/topbar_button_maximize.png') 1x,
+    url('../images/files/ui/2x/topbar_button_maximize.png') 2x);
 }
 
 .dialog-header #close-button {
   background-image: -webkit-image-set(
-    url('../images/files/ui/new-ui/topbar_button_close.png') 1x,
-    url('../images/files/ui/new-ui/2x/topbar_button_close.png') 2x);
-}
-
-body:not([type='full-page']) .dialog-header #close-button,
-body:not([type='full-page']) .dialog-header #maximize-button {
-  display: none;
+    url('../images/files/ui/topbar_button_close.png') 1x,
+    url('../images/files/ui/2x/topbar_button_close.png') 2x);
 }
 
 /* Container for the detail and thumbnail list views. */
@@ -493,18 +477,19 @@
   padding: 10px;
 }
 
-.dialog-footer:not([progress]) .progress-bar,
-.dialog-footer:not([progress]) .preparing-label {
+.progressable:not([progress]) .progress-bar,
+.progressable:not([progress]) .preparing-label {
   display: none;
 }
 
-.dialog-footer[progress] .ok,
-.dialog-footer[progress] #filename-input-box,
-.dialog-footer[progress] #file-type {
+.progressable[progress] .ok,
+.progressable[progress] #filename-input-box,
+.progressable[progress] #preview-lines,
+.progressable[progress] .file-type {
   display: none;
 }
 
-.dialog-footer .progress-bar {
+.progressable .progress-bar {
   -webkit-box-flex: 1;
   -webkit-margin-end: 20px;
   -webkit-margin-start: 20px;
@@ -582,10 +567,6 @@
   white-space: nowrap;
 }
 
-.breadcrumb-path:hover {
-  color: #666;
-}
-
 /* The final breadcrumb, representing the current directory. */
 #search-breadcrumbs .breadcrumb-path.breadcrumb-last {
   color: #141414;
@@ -641,10 +622,11 @@
 
 #search-box,
 #filename-input-box input {
-  border: 1px solid #d9d9d9;
+  border: 1px solid #c8c8c8;
   border-radius: 1px;
-  border-top: 1px solid #c0c0c0;
   box-sizing: border-box;
+  height: 31px;  /* border-box */
+  margin-right: 30px;
 }
 
 #search-box {
@@ -676,10 +658,6 @@
   pointer-events: auto;
 }
 
-#search-box[hidden] {
-  display: none;  /* Required, since overriden by #search-box. */
-}
-
 #search-box::-webkit-search-cancel-button {
   -webkit-appearance: none;
 }
@@ -694,8 +672,8 @@
   -webkit-margin-start: 10px;
   -webkit-order: -1;
   background-image: -webkit-image-set(
-    url('../images/files/ui/new-ui/search_icon_inactive.png') 1x,
-    url('../images/files/ui/new-ui/2x/search_icon_inactive.png') 2x);
+    url('../images/files/ui/search_icon_inactive.png') 1x,
+    url('../images/files/ui/2x/search_icon_inactive.png') 2x);
   background-position: center;
   background-repeat: no-repeat;
   height: 32px;
@@ -707,16 +685,16 @@
 #search-box:focus + #search-icon,
 .has-text #search-icon {
   background: -webkit-image-set(
-    url('../images/files/ui/new-ui/search_icon_active.png') 1x,
-    url('../images/files/ui/new-ui/2x/search_icon_active.png') 2x);
+    url('../images/files/ui/search_icon_active.png') 1x,
+    url('../images/files/ui/2x/search_icon_active.png') 2x);
 }
 
 #search-clear-button {
   -webkit-margin-end: 30px;
   -webkit-margin-start: 10px;
   background-image: -webkit-image-set(
-    url('../images/files/ui/new-ui/search_clear.png') 1x,
-    url('../images/files/ui/new-ui/2x/search_clear.png') 2x);
+    url('../images/files/ui/search_clear.png') 1x,
+    url('../images/files/ui/2x/search_clear.png') 2x);
   background-position: center;
   background-repeat: no-repeat;
   display: none;
@@ -734,14 +712,14 @@
 
 #search-clear-button:hover {
   background-image: -webkit-image-set(
-    url('../images/files/ui/new-ui/search_clear_hover.png') 1x,
-    url('../images/files/ui/new-ui/2x/search_clear_hover.png') 2x);
+    url('../images/files/ui/search_clear_hover.png') 1x,
+    url('../images/files/ui/2x/search_clear_hover.png') 2x);
 }
 
 #search-clear-button:active {
   background-image: -webkit-image-set(
-    url('../images/files/ui/new-ui/search_clear_pressed.png') 1x,
-    url('../images/files/ui/new-ui/2x/search_clear_pressed.png') 2x);
+    url('../images/files/ui/search_clear_pressed.png') 1x,
+    url('../images/files/ui/2x/search_clear_pressed.png') 2x);
 }
 
 .filelist-panel {
@@ -773,9 +751,7 @@
   -webkit-box-sizing: border-box;
   background-color: rgba(255, 255, 255, 0.3);
   border: 2px solid rgba(255, 255, 255, 0.6);
-  border-radius: 0; /* Override the style of cr.ui.List */
   outline: 1px solid rgba(0, 0, 0, 0.1);
-  padding: 0; /* Override the style of cr.ui.List */
   position: absolute;
   z-index: 2;
 }
@@ -834,6 +810,7 @@
 }
 
 .downloads-warning[hidden] {
+  display: -webkit-box !important;  /* Overrides [hidden] for animation. */
   height: 0;
 }
 
@@ -852,7 +829,6 @@
   background-image: url(chrome://resources/images/clouds.png);
   background-repeat: repeat-x;
   background-size: 150px 44px;
-  border-top: 1px solid rgba(0, 0, 0, 0.1);
   color: #333;
   display: -webkit-box;
   font-size: 13px;
@@ -863,9 +839,6 @@
 
 .volume-warning[hidden] {
   border-top-width: 0;
-  /* [hidden] has already set in dialog.css, but it is overridden by the
-   * selector ".volume-warning", hence we need to override it again. */
-  display: none;
   height: 0;
 }
 
@@ -900,31 +873,13 @@
   cursor: pointer;
 }
 
-.breadcrumb-path:not(.breadcrumb-last):hover,
-.breadcrumb-path.accepts {
-  color: rgb(17, 85, 204);
-  text-decoration: underline;
-}
-
-.breadcrumb-path.accepts {
-  -webkit-animation: acceptsBlinkText 200ms linear 1s 3;
-}
-
-@-webkit-keyframes acceptsBlinkText {
-  0% {
-    color: white;
-  }
-  50% {
-  }
-}
-
 .img-container > img {
   -webkit-user-drag: none;
   position: absolute;
 }
 
-.img-container > img:not(.cached) {
-  -webkit-animation: fadeIn 500ms ease-in;
+.img-container > img:not(.cached):not(.drag-thumbnail) {
+  -webkit-animation: fadeIn 250ms linear;
 }
 
 .thumbnail-bottom {
@@ -950,7 +905,6 @@
   -webkit-margin-start: 8px;
   border: 3px solid transparent;  /* Selection will make the border visible. */
   margin-top: 7px;
-  padding: 0;
   position: relative;
 }
 
@@ -1006,19 +960,9 @@
   background-position: 5px center;
   background-repeat: no-repeat;
   background-size: 16px 16px;
-  line-height: 39px;
   padding-left: 26px;
 }
 
-#list-container list > li,
-#list-container grid > *,
-#default-actions-list > * {
-  background-color: transparent;
-  background-image: none;
-  border-color: transparent;
-  border-radius: 0;
-}
-
 #list-container list > li[selected],
 #list-container grid > li[selected],
 #default-actions-list > li[selected] {
@@ -1117,7 +1061,6 @@
 
 /* The cr.ui.Table representing the detailed file list. */
 .detail-table {
-  border: 0;
   width: 100%;
 }
 
@@ -1134,7 +1077,7 @@
   height: 51px;
   left: 0;
   opacity: 1;
-  padding: 0 12px 0 7px;
+  padding: 0 10px 0 7px;
   position: absolute;
   right: 0;
   z-index: 3;
@@ -1152,6 +1095,27 @@
   opacity: 0;
 }
 
+.preview-panel > .left,
+.dialog-footer > .left {
+  -webkit-box-align: center;
+  -webkit-box-flex: 1;
+  -webkit-box-orient: horizontal;
+  display: -webkit-box;
+}
+
+.preview-panel > .right,
+.dialog-footer > .right {
+  -webkit-box-pack: end;
+}
+
+.preview-panel .preparing-label {
+  -webkit-margin-start: 30px;
+}
+
+.preview-panel .progress-bar {
+  -webkit-box-flex: 1;
+}
+
 .preview-thumbnails {
   -webkit-box-orient: horizontal;
   display: -webkit-box;
@@ -1220,21 +1184,13 @@
   opacity: 0;
 }
 
-/* cr.ui.Table has a black focus border by default, which we don't want. */
-.detail-table:focus {
-  border: 0;
-}
-
 /* Table splitter element */
 .table-header-splitter {
-  -webkit-border-start: 1px #d4d4d4 solid;
-  background-color: inherit;
   background-image: -webkit-image-set(
-    url('../images/files/ui/new-ui/vertical_separator.png') 1x,
-    url('../images/files/ui/new-ui/2x/vertical_separator.png') 2x);
+    url('../images/files/ui/vertical_separator.png') 1x,
+    url('../images/files/ui/2x/vertical_separator.png') 2x);
   background-position: center;
   background-repeat: repeat-y;
-  border: none;
   height: 20px;
   top: 10px;
   width: 5px;
@@ -1246,8 +1202,6 @@
 
 /* Container for a table header. */
 .table-header {
-  background-color: transparent;
-  border-bottom: none;
   box-sizing: border-box;
   height: 47px;
 }
@@ -1286,13 +1240,13 @@
 .table-header-label {
   color: rgb(100, 100, 100);
   line-height: 40px;
+  margin: 0 7px;
 }
 
 .table-row-cell > * {
   -webkit-box-align: center;
   -webkit-box-flex: 1;
   -webkit-box-orient: horizontal;
-  margin: 0;
   padding: 0 10px;
 }
 
@@ -1337,8 +1291,8 @@
 #list-container li.table-row .file-checkbox {
   -webkit-appearance: none;
   background-image: -webkit-image-set(
-    url('../images/files/ui/new-ui/select_checkbox.png') 1x,
-    url('../images/files/ui/new-ui/2x/select_checkbox.png') 2x);
+    url('../images/files/ui/select_checkbox.png') 1x,
+    url('../images/files/ui/2x/select_checkbox.png') 2x);
   background-position: center;
   background-repeat: no-repeat;
   border-style: none;
@@ -1358,8 +1312,8 @@
 #list-container .table-header #select-all-checkbox:checked,
 #list-container li.table-row .file-checkbox:checked {
   background-image: -webkit-image-set(
-    url('../images/files/ui/new-ui/select_checkbox_checked.png') 1x,
-    url('../images/files/ui/new-ui/2x/select_checkbox_checked.png') 2x);
+    url('../images/files/ui/select_checkbox_checked.png') 1x,
+    url('../images/files/ui/2x/select_checkbox_checked.png') 2x);
 }
 
 #list-container .table-header #select-all-checkbox:checked,
@@ -1373,14 +1327,8 @@
 
 #list-container li.table-row,
 #default-actions-list li {
-  border-left-width: 0;
-  border-right-width: 0;
-  border-style: none;
   height: 29px;
   line-height: 29px;
-  margin: 0;
-  padding-bottom: 0;
-  padding-top: 0;
 }
 
 /* The icon in the name column. See file_types.css for specific icons. */
@@ -1389,6 +1337,11 @@
   width: 24px;
 }
 
+#detail-table .detail-icon {
+  /* To shift the icon position. */
+  margin-bottom: 2px;
+}
+
 .metadata-item {
   -webkit-box-flex: 1;
   -webkit-box-orient: horizontal;
@@ -1406,13 +1359,13 @@
 
 #delete-button {
   background-image: -webkit-image-set(
-    url('../images/files/ui/new-ui/onbutton_trash.png') 1x,
-    url('../images/files/ui/new-ui/2x/onbutton_trash.png') 2x);
+    url('../images/files/ui/onbutton_trash.png') 1x,
+    url('../images/files/ui/2x/onbutton_trash.png') 2x);
   background-position: center;
   background-repeat: no-repeat;
-  min-width: 25px;  /* overrride */
+  min-width: 21px;  /* overrride */
   padding: 0;  /* overrride */
-  width: 25px;
+  width: 21px;
 }
 
 #delete-button[disabled] {
@@ -1497,13 +1450,6 @@
   display: none;
 }
 
-/* A horizontal spring. */
-.horizontal-spacer {
-  -webkit-box-flex: 1;
-  -webkit-box-orient: horizontal;
-  display: -webkit-box;
-}
-
 /* A vertical spring. */
 .vertical-spacer {
   -webkit-box-flex: 1;
@@ -1514,8 +1460,7 @@
 /* Dimmed items */
 
 body[type='folder'] .file,
-body[drive] .dialog-container[connection='offline'] .dim-offline,
-body[drive] .dialog-container[connection='metered'] .dim-metered {
+body[drive] .dialog-container[connection='offline'] .dim-offline {
   opacity: 0.4;
 }
 
@@ -1558,16 +1503,25 @@
   transition: opacity 200ms ease-in;
 }
 
+#drag-container .drag-contents.for-image  {
+  padding: 2px;
+}
+
 #drag-container .thumbnail-item {
   -webkit-box-orient: horizontal;
   display: -webkit-box;
 }
 
+/* When changing these properties please preserve these conditions:
+   1. width == height (so that the rotated thumbnail does not look off-center)
+   2. width % 8 == 0 (to minimize rounding errors in the centering code) */
 #drag-container .img-container {
   -webkit-box-flex: 0;
   display: -webkit-box;
+  height: 64px;
   overflow: hidden;
   position: relative;
+  width: 64px;
 }
 
 #drag-container .label {
@@ -1581,18 +1535,6 @@
   white-space: nowrap;
 }
 
-#drag-container .drag-contents.drag-image-thumbnail  {
-  padding: 2px;
-}
-
-/* When changing these properties please preserve these conditions:
-   1. width == height (so that the rotated thumbnail does not look off-center)
-   2. width % 8 == 0 (to minimize rounding errors in the centering code) */
-#drag-container .img-container {
-  height: 64px;
-  width: 64px;
-}
-
 menu.file-context-menu {
   z-index: 4;
 }
@@ -1602,13 +1544,6 @@
   font-size: 0;
 }
 
-input.common.pin[type='checkbox']:checked::after {
-  background-image: -webkit-image-set(
-    url('../images/files/ui/pin.png') 1x,
-    url('../images/files/ui/2x/pin.png') 2x);
-  background-position: 4px 0;
-}
-
 div.offline {
   -webkit-box-pack: center;
   display: -webkit-box;
@@ -1700,22 +1635,6 @@
   text-decoration: none;
 }
 
-body[ash] .dialog-title,
-
-body[type='folder'] [invisibleif~='folder'],
-body[type='saveas-file'] [invisibleif~='saveas-file'],
-body[type='open-file'] [invisibleif~='open-file'],
-body[type='open-multi-file'] [invisibleif~='open-multi-file'],
-body[type='full-page'] [invisibleif~='full-page'],
-
-body[type='folder'] [visibleif]:not([visibleif~='folder']),
-body[type='saveas-file'] [visibleif]:not([visibleif~='saveas-file']),
-body[type='open-file'] [visibleif]:not([visibleif~='open-file']),
-body[type='open-multi-file'] [visibleif]:not([visibleif~='open-multi-file']),
-body[type='full-page'] [visibleif]:not([visibleif~='full-page']) {
-  display: none;
-}
-
 .buttonbar > * {
   position: relative;
 }
@@ -1860,12 +1779,7 @@
 
 list.autocomplete-suggestions > li {
   -webkit-box-align: center;
-  background-color: transparent;
-  background-image: none;
-  border: none;
-  border-radius: 0;
   display: -webkit-box;
-  margin: 0;  /* To prevent vertical overflow. */
   padding: 3px 0;
 }
 
@@ -1887,8 +1801,8 @@
 
 list.autocomplete-suggestions > li > div[search-icon] {
   background: -webkit-image-set(
-    url('../images/files/ui/new-ui/search_icon_active.png') 1x,
-    url('../images/files/ui/new-ui/2x/search_icon_active.png') 2x);
+    url('../images/files/ui/search_icon_active.png') 1x,
+    url('../images/files/ui/2x/search_icon_active.png') 2x);
   background-position: center;
   background-repeat: no-repeat;
 }
@@ -1921,28 +1835,28 @@
 
 menuitem#detail-view {
   background-image: -webkit-image-set(
-    url('../images/files/ui/new-ui/button_list_view.png') 1x,
-    url('../images/files/ui/new-ui/2x/button_list_view.png') 2x);
+    url('../images/files/ui/button_list_view.png') 1x,
+    url('../images/files/ui/2x/button_list_view.png') 2x);
 }
 
 menuitem#detail-view[selected]:not([disabled]),
 menuitem#detail-view[lead]:not([disabled]) {
   background-image: -webkit-image-set(
-    url('../images/files/ui/new-ui/button_list_view_white.png') 1x,
-    url('../images/files/ui/new-ui/2x/button_list_view_white.png') 2x);
+    url('../images/files/ui/button_list_view_white.png') 1x,
+    url('../images/files/ui/2x/button_list_view_white.png') 2x);
 }
 
 menuitem#thumbnail-view {
   background-image: -webkit-image-set(
-    url('../images/files/ui/new-ui/button_mosaic_view.png') 1x,
-    url('../images/files/ui/new-ui/2x/button_mosaic_view.png') 2x);
+    url('../images/files/ui/button_mosaic_view.png') 1x,
+    url('../images/files/ui/2x/button_mosaic_view.png') 2x);
 }
 
 menuitem#thumbnail-view[selected]:not([disabled]),
 menuitem#thumbnail-view[lead]:not([disabled]) {
   background-image: -webkit-image-set(
-    url('../images/files/ui/new-ui/button_mosaic_view_white.png') 1x,
-    url('../images/files/ui/new-ui/2x/button_mosaic_view_white.png') 2x);
+    url('../images/files/ui/button_mosaic_view_white.png') 1x,
+    url('../images/files/ui/2x/button_mosaic_view_white.png') 2x);
 }
 
 #iframe-drag-area {
diff --git a/chrome/browser/resources/file_manager/css/file_types.css b/chrome/browser/resources/file_manager/css/file_types.css
index d8e331e..91f5be1 100644
--- a/chrome/browser/resources/file_manager/css/file_types.css
+++ b/chrome/browser/resources/file_manager/css/file_types.css
@@ -5,22 +5,270 @@
 /* Small icons for file types, used in lists and menus. */
 [file-type-icon] {
   background-image: -webkit-image-set(
-    url('chrome://theme/IDR_FILE_MANAGER_IMG_FILETYPE_GENERIC') 1x,
-    url('chrome://theme/IDR_FILE_MANAGER_IMG_FILETYPE_GENERIC@2x') 2x);
+      url('../images/files/file_types/100/generic.png') 1x,
+      url('../images/files/file_types/200/generic.png') 2x);
   background-position: center;
   background-repeat: no-repeat;
 }
 
+tree:focus .tree-item[selected] > .tree-row > [file-type-icon],
+list:focus [selected] [file-type-icon],
+list.autocomplete-suggestions [selected] [file-type-icon] {
+  background-image: -webkit-image-set(
+    url('../images/files/file_types/100/generic_white.png') 1x,
+    url('../images/files/file_types/200/generic_white.png') 2x);
+}
+
 [file-type-icon='archive'] {
   background-image: -webkit-image-set(
-    url('chrome://theme/IDR_FILE_MANAGER_IMG_FILETYPE_ARCHIVE') 1x,
-    url('chrome://theme/IDR_FILE_MANAGER_IMG_FILETYPE_ARCHIVE@2x') 2x);
+    url('../images/files/file_types/100/archive.png') 1x,
+    url('../images/files/file_types/200/archive.png') 2x);
+}
+
+tree:focus .tree-item[selected] > .tree-row > [file-type-icon='archive'],
+list:focus [selected] [file-type-icon='archive'],
+list.autocomplete-suggestions [selected] [file-type-icon='archive'] {
+  background-image: -webkit-image-set(
+    url('../images/files/file_types/100/archive_white.png') 1x,
+    url('../images/files/file_types/200/archive_white.png') 2x);
 }
 
 [file-type-icon='audio'] {
   background-image: -webkit-image-set(
-    url('chrome://theme/IDR_FILE_MANAGER_IMG_FILETYPE_AUDIO') 1x,
-    url('chrome://theme/IDR_FILE_MANAGER_IMG_FILETYPE_AUDIO@2x') 2x);
+    url('../images/files/file_types/100/audio.png') 1x,
+    url('../images/files/file_types/200/audio.png') 2x);
+}
+
+tree:focus .tree-item[selected] > .tree-row > [file-type-icon='audio'],
+list:focus [selected] [file-type-icon='audio'],
+list.autocomplete-suggestions [selected] [file-type-icon='audio'] {
+  background-image: -webkit-image-set(
+    url('../images/files/file_types/100/audio_white.png') 1x,
+    url('../images/files/file_types/200/audio_white.png') 2x);
+}
+
+[file-type-icon='excel'] {
+  background-image: -webkit-image-set(
+    url('../images/files/file_types/100/excel.png') 1x,
+    url('../images/files/file_types/200/excel.png') 2x);
+}
+
+tree:focus .tree-item[selected] > .tree-row > [file-type-icon='excel'],
+list:focus [selected] [file-type-icon='excel'],
+list.autocomplete-suggestions [selected] [file-type-icon='excel'] {
+  background-image: -webkit-image-set(
+    url('../images/files/file_types/100/excel_white.png') 1x,
+    url('../images/files/file_types/200/excel_white.png') 2x);
+}
+
+[file-type-icon='folder'] {
+  background-image: -webkit-image-set(
+    url('../images/files/file_types/100/folder.png') 1x,
+    url('../images/files/file_types/200/folder.png') 2x);
+}
+
+tree:focus .tree-item[selected] > .tree-row > [file-type-icon='folder'],
+list:focus [selected] [file-type-icon='folder'],
+list.autocomplete-suggestions [selected] [file-type-icon='folder'] {
+  background-image: -webkit-image-set(
+    url('../images/files/file_types/100/folder_white.png') 1x,
+    url('../images/files/file_types/200/folder_white.png') 2x);
+}
+
+[file-type-icon='form'] {
+  background-image: -webkit-image-set(
+    url('../images/files/file_types/100/form.png') 1x,
+    url('../images/files/file_types/200/form.png') 2x);
+}
+
+tree:focus .tree-item[selected] > .tree-row > [file-type-icon='form'],
+list:focus [selected] [file-type-icon='form'],
+list.autocomplete-suggestions [selected] [file-type-icon='form'] {
+  background-image: -webkit-image-set(
+    url('../images/files/file_types/100/form_white.png') 1x,
+    url('../images/files/file_types/200/form_white.png') 2x);
+}
+
+[file-type-icon='gdoc'] {
+  background-image: -webkit-image-set(
+    url('../images/files/file_types/100/gdoc.png') 1x,
+    url('../images/files/file_types/200/gdoc.png') 2x);
+}
+
+tree:focus .tree-item[selected] > .tree-row > [file-type-icon='gdoc'],
+list:focus [selected] [file-type-icon='gdoc'],
+list.autocomplete-suggestions [selected] [file-type-icon='gdoc'] {
+  background-image: -webkit-image-set(
+    url('../images/files/file_types/100/gdoc_white.png') 1x,
+    url('../images/files/file_types/200/gdoc_white.png') 2x);
+}
+
+[file-type-icon='gdraw'] {
+  background-image: -webkit-image-set(
+    url('../images/files/file_types/100/gdraw.png') 1x,
+    url('../images/files/file_types/200/gdraw.png') 2x);
+}
+
+tree:focus .tree-item[selected] > .tree-row > [file-type-icon='gdraw'],
+list:focus [selected] [file-type-icon='gdraw'],
+list.autocomplete-suggestions [selected] [file-type-icon='gdraw'] {
+  background-image: -webkit-image-set(
+    url('../images/files/file_types/100/gdraw_white.png') 1x,
+    url('../images/files/file_types/200/gdraw_white.png') 2x);
+}
+
+[file-type-icon='glink'] {
+  background-image: -webkit-image-set(
+    url('../images/files/file_types/100/glink.png') 1x,
+    url('../images/files/file_types/200/glink.png') 2x);
+}
+
+tree:focus .tree-item[selected] > .tree-row > [file-type-icon='glink'],
+list:focus [selected] [file-type-icon='glink'],
+list.autocomplete-suggestions [selected] [file-type-icon='glink'] {
+  background-image: -webkit-image-set(
+    url('../images/files/file_types/100/glink_white.png') 1x,
+    url('../images/files/file_types/200/glink_white.png') 2x);
+}
+
+[file-type-icon='gsheet'] {
+  background-image: -webkit-image-set(
+    url('../images/files/file_types/100/gsheet.png') 1x,
+    url('../images/files/file_types/200/gsheet.png') 2x);
+}
+
+tree:focus .tree-item[selected] > .tree-row > [file-type-icon='gsheet'],
+list:focus [selected] [file-type-icon='gsheet'],
+list.autocomplete-suggestions [selected] [file-type-icon='gsheet'] {
+  background-image: -webkit-image-set(
+    url('../images/files/file_types/100/gsheet_white.png') 1x,
+    url('../images/files/file_types/200/gsheet_white.png') 2x);
+}
+
+[file-type-icon='gslides'] {
+  background-image: -webkit-image-set(
+    url('../images/files/file_types/100/gslides.png') 1x,
+    url('../images/files/file_types/200/gslides.png') 2x);
+}
+
+tree:focus .tree-item[selected] > .tree-row > [file-type-icon='gslides'],
+list:focus [selected] [file-type-icon='gslides'],
+list.autocomplete-suggestions [selected] [file-type-icon='gslides'] {
+  background-image: -webkit-image-set(
+    url('../images/files/file_types/100/gslides_white.png') 1x,
+    url('../images/files/file_types/200/gslides_white.png') 2x);
+}
+
+[file-type-icon='gtable'] {
+  background-image: -webkit-image-set(
+    url('../images/files/file_types/100/gtable.png') 1x,
+    url('../images/files/file_types/200/gtable.png') 2x);
+}
+
+tree:focus .tree-item[selected] > .tree-row > [file-type-icon='gtable'],
+list:focus [selected] [file-type-icon='gtable'],
+list.autocomplete-suggestions [selected] [file-type-icon='gtable'] {
+  background-image: -webkit-image-set(
+    url('../images/files/file_types/100/gtable_white.png') 1x,
+    url('../images/files/file_types/200/gtable_white.png') 2x);
+}
+
+[file-type-icon='image'] {
+  background-image: -webkit-image-set(
+    url('../images/files/file_types/100/image.png') 1x,
+    url('../images/files/file_types/200/image.png') 2x);
+}
+
+tree:focus .tree-item[selected] > .tree-row > [file-type-icon='image'],
+list:focus [selected] [file-type-icon='image'],
+list.autocomplete-suggestions [selected] [file-type-icon='image'] {
+  background-image: -webkit-image-set(
+    url('../images/files/file_types/100/image_white.png') 1x,
+    url('../images/files/file_types/200/image_white.png') 2x);
+}
+
+[file-type-icon='pdf'] {
+  background-image: -webkit-image-set(
+    url('../images/files/file_types/100/pdf.png') 1x,
+    url('../images/files/file_types/200/pdf.png') 2x);
+}
+
+tree:focus .tree-item[selected] > .tree-row > [file-type-icon='pdf'],
+list:focus [selected] [file-type-icon='pdf'],
+list.autocomplete-suggestions [selected] [file-type-icon='pdf'] {
+  background-image: -webkit-image-set(
+    url('../images/files/file_types/100/pdf_white.png') 1x,
+    url('../images/files/file_types/200/pdf_white.png') 2x);
+}
+
+[file-type-icon='ppt'] {
+  background-image: -webkit-image-set(
+    url('../images/files/file_types/100/ppt.png') 1x,
+    url('../images/files/file_types/200/ppt.png') 2x);
+}
+
+tree:focus .tree-item[selected] > .tree-row > [file-type-icon='ppt'],
+list:focus [selected] [file-type-icon='ppt'],
+list.autocomplete-suggestions [selected] [file-type-icon='ppt'] {
+  background-image: -webkit-image-set(
+    url('../images/files/file_types/100/ppt_white.png') 1x,
+    url('../images/files/file_types/200/ppt_white.png') 2x);
+}
+
+[file-type-icon='script'] {
+  background-image: -webkit-image-set(
+    url('../images/files/file_types/100/script.png') 1x,
+    url('../images/files/file_types/200/script.png') 2x);
+}
+
+tree:focus .tree-item[selected] > .tree-row > [file-type-icon='script'],
+list:focus [selected] [file-type-icon='script'],
+list.autocomplete-suggestions [selected] [file-type-icon='script'] {
+  background-image: -webkit-image-set(
+    url('../images/files/file_types/100/script_white.png') 1x,
+    url('../images/files/file_types/200/script_white.png') 2x);
+}
+
+[file-type-icon='sites'] {
+  background-image: -webkit-image-set(
+    url('../images/files/file_types/100/sites.png') 1x,
+    url('../images/files/file_types/200/sites.png') 2x);
+}
+
+tree:focus .tree-item[selected] > .tree-row > [file-type-icon='sites'],
+list:focus [selected] [file-type-icon='sites'],
+list.autocomplete-suggestions [selected] [file-type-icon='sites'] {
+  background-image: -webkit-image-set(
+    url('../images/files/file_types/100/sites_white.png') 1x,
+    url('../images/files/file_types/200/sites_white.png') 2x);
+}
+
+[file-type-icon='video'] {
+  background-image: -webkit-image-set(
+    url('../images/files/file_types/100/video.png') 1x,
+    url('../images/files/file_types/200/video.png') 2x);
+}
+
+tree:focus .tree-item[selected] > .tree-row > [file-type-icon='video'],
+list:focus [selected] [file-type-icon='video'],
+list.autocomplete-suggestions [selected] [file-type-icon='video'] {
+  background-image: -webkit-image-set(
+    url('../images/files/file_types/100/video_white.png') 1x,
+    url('../images/files/file_types/200/video_white.png') 2x);
+}
+
+[file-type-icon='word'] {
+  background-image: -webkit-image-set(
+    url('../images/files/file_types/100/word.png') 1x,
+    url('../images/files/file_types/200/word.png') 2x);
+}
+
+tree:focus .tree-item[selected] > .tree-row > [file-type-icon='word'],
+list:focus [selected] [file-type-icon='word'],
+list.autocomplete-suggestions [selected] [file-type-icon='word'] {
+  background-image: -webkit-image-set(
+    url('../images/files/file_types/100/word_white.png') 1x,
+    url('../images/files/file_types/200/word_white.png') 2x);
 }
 
 [file-type-icon='drive'] {
@@ -29,88 +277,6 @@
     url('chrome://theme/IDR_FILE_MANAGER_IMG_FILETYPE_DRIVE@2x') 2x);
 }
 
-[file-type-icon='excel'] {
-  background-image: -webkit-image-set(
-    url('chrome://theme/IDR_FILE_MANAGER_IMG_FILETYPE_EXCEL') 1x,
-    url('chrome://theme/IDR_FILE_MANAGER_IMG_FILETYPE_EXCEL@2x') 2x);
-}
-
-/* TODO(mtomasz): Move all assets from themes to local resources. */
-/* TODO(mtomasz): Add inverted icons for other file types. */
-[file-type-icon='folder'] {
-  background-image: -webkit-image-set(
-    url('../images/files/ui/new-ui/black_folder.png') 1x,
-    url('../images/files/ui/new-ui/2x/black_folder.png') 2x);
-}
-
-tree:focus .tree-item[selected] > .tree-row > [file-type-icon='folder'],
-list.autocomplete-suggestions li[selected] [file-type-icon='folder'],
-list:focus li[selected] [file-type-icon='folder'] {
-  background-image: -webkit-image-set(
-    url('../images/files/ui/new-ui/white_folder.png') 1x,
-    url('../images/files/ui/new-ui/2x/white_folder.png') 2x);
-}
-
-[file-type-icon='gdoc'] {
-  background-image: -webkit-image-set(
-    url('chrome://theme/IDR_FILE_MANAGER_IMG_FILETYPE_GDOC') 1x,
-    url('chrome://theme/IDR_FILE_MANAGER_IMG_FILETYPE_GDOC@2x') 2x);
-}
-
-[file-type-icon='gdraw'] {
-  background-image: -webkit-image-set(
-    url('chrome://theme/IDR_FILE_MANAGER_IMG_FILETYPE_GDRAW') 1x,
-    url('chrome://theme/IDR_FILE_MANAGER_IMG_FILETYPE_GDRAW@2x') 2x);
-}
-
-[file-type-icon='gsheet'] {
-  background-image: -webkit-image-set(
-    url('chrome://theme/IDR_FILE_MANAGER_IMG_FILETYPE_GSHEET') 1x,
-    url('chrome://theme/IDR_FILE_MANAGER_IMG_FILETYPE_GSHEET@2x') 2x);
-}
-
-[file-type-icon='gslides'] {
-  background-image: -webkit-image-set(
-    url('chrome://theme/IDR_FILE_MANAGER_IMG_FILETYPE_GSLIDES') 1x,
-    url('chrome://theme/IDR_FILE_MANAGER_IMG_FILETYPE_GSLIDES@2x') 2x);
-}
-
-[file-type-icon='gtable'] {
-  background-image: -webkit-image-set(
-    url('chrome://theme/IDR_FILE_MANAGER_IMG_FILETYPE_GTABLE') 1x,
-    url('chrome://theme/IDR_FILE_MANAGER_IMG_FILETYPE_GTABLE@2x') 2x);
-}
-
-[file-type-icon='image'] {
-  background-image: -webkit-image-set(
-    url('chrome://theme/IDR_FILE_MANAGER_IMG_FILETYPE_IMAGE') 1x,
-    url('chrome://theme/IDR_FILE_MANAGER_IMG_FILETYPE_IMAGE@2x') 2x);
-}
-
-[file-type-icon='pdf'] {
-  background-image: -webkit-image-set(
-    url('chrome://theme/IDR_FILE_MANAGER_IMG_FILETYPE_PDF') 1x,
-    url('chrome://theme/IDR_FILE_MANAGER_IMG_FILETYPE_PDF@2x') 2x);
-}
-
-[file-type-icon='ppt'] {
-  background-image: -webkit-image-set(
-    url('chrome://theme/IDR_FILE_MANAGER_IMG_FILETYPE_PPT') 1x,
-    url('chrome://theme/IDR_FILE_MANAGER_IMG_FILETYPE_PPT@2x') 2x);
-}
-
-[file-type-icon='video'] {
-  background-image: -webkit-image-set(
-    url('chrome://theme/IDR_FILE_MANAGER_IMG_FILETYPE_VIDEO') 1x,
-    url('chrome://theme/IDR_FILE_MANAGER_IMG_FILETYPE_VIDEO@2x') 2x);
-}
-
-[file-type-icon='word'] {
-  background-image: -webkit-image-set(
-    url('chrome://theme/IDR_FILE_MANAGER_IMG_FILETYPE_WORD') 1x,
-    url('chrome://theme/IDR_FILE_MANAGER_IMG_FILETYPE_WORD@2x') 2x);
-}
-
 /* Large generic thumbnails, used when a file does not have a thumbnail. */
 [generic-thumbnail] {
   background-image: -webkit-image-set(
@@ -145,181 +311,120 @@
 }
 
 /* Icons for volume types. */
-[volume-type-icon='archive'] {
-  background-image: -webkit-image-set(
-    url('../images/files/volumes/archive.png') 1x,
-    url('../images/files/volumes/2x/archive.png') 2x);
-}
-
-[volume-type-icon='downloads'] {
-  background-image: -webkit-image-set(
-    url('../images/files/volumes/downloads.png') 1x,
-    url('../images/files/volumes/2x/downloads.png') 2x);
-}
-
-[volume-type-icon='drive'] {
-  background-image: -webkit-image-set(
-    url('../images/files/volumes/drive.png') 1x,
-    url('../images/files/volumes/2x/drive.png') 2x);
-}
-
-[volume-type-icon='drive_offline'] {
-  background-image: -webkit-image-set(
-    url('../images/files/volumes/drive_offline.png') 1x,
-    url('../images/files/volumes/2x/drive_offline.png') 2x);
-}
-
-[volume-type-icon='drive_shared_with_me'] {
-  background-image: -webkit-image-set(
-    url('../images/files/volumes/drive_shared.png') 1x,
-    url('../images/files/volumes/2x/drive_shared.png') 2x);
-}
-
-[volume-type-icon='drive_recent'] {
-  background-image: -webkit-image-set(
-    url('../images/files/volumes/drive_recent.png') 1x,
-    url('../images/files/volumes/2x/drive_recent.png') 2x);
-}
-
-[volume-type-icon='removable'] {
-  background-image: -webkit-image-set(
-    url('../images/files/volumes/device_usb.png') 1x,
-    url('../images/files/volumes/2x/device_usb.png') 2x);
-}
-
-[volume-type-icon='removable'][volume-subtype='sd'] {
-  background-image: -webkit-image-set(
-    url('../images/files/volumes/device_sd.png') 1x,
-    url('../images/files/volumes/2x/device_sd.png') 2x);
-}
-
-[volume-type-icon='removable'][volume-subtype='optical'] {
-  background-image: -webkit-image-set(
-    url('../images/files/volumes/device_optical.png') 1x,
-    url('../images/files/volumes/2x/device_optical.png') 2x);
-}
-
-/* TODO(kaznacheev): consider a better icon for volume-subtype=unknown.
-   Also find out if we need an icon for volume-subtype=mobile */
-[volume-type-icon='removable'][volume-subtype='unknown'] {
-  background-image: -webkit-image-set(
-    url('../images/files/volumes/device_hd.png') 1x,
-    url('../images/files/volumes/2x/device_hd.png') 2x);
-}
 
 [volume-type-icon='archive'] {
   background-image: -webkit-image-set(
-    url('../images/files/volumes/new-ui/black_archive.png') 1x,
-    url('../images/files/volumes/new-ui/2x/black_archive.png') 2x);
+    url('../images/files/volumes/black_archive.png') 1x,
+    url('../images/files/volumes/2x/black_archive.png') 2x);
 }
 
 list:focus li[selected] [volume-type-icon='archive'],
 tree:focus .tree-item[selected] > .tree-row > [volume-type-icon='archive'] {
   background-image: -webkit-image-set(
-    url('../images/files/volumes/new-ui/white_archive.png') 1x,
-    url('../images/files/volumes/new-ui/2x/white_archive.png') 2x);
+    url('../images/files/volumes/white_archive.png') 1x,
+    url('../images/files/volumes/2x/white_archive.png') 2x);
 }
 
 [volume-type-icon='downloads'] {
   background-image: -webkit-image-set(
-    url('../images/files/volumes/new-ui/black_downloads.png') 1x,
-    url('../images/files/volumes/new-ui/2x/black_downloads.png') 2x);
+    url('../images/files/volumes/black_downloads.png') 1x,
+    url('../images/files/volumes/2x/black_downloads.png') 2x);
 }
 
 list:focus li[selected] [volume-type-icon='downloads'],
 tree:focus .tree-item[selected] > .tree-row > [volume-type-icon='downloads'] {
   background-image: -webkit-image-set(
-    url('../images/files/volumes/new-ui/white_downloads.png') 1x,
-    url('../images/files/volumes/new-ui/2x/white_downloads.png') 2x);
+    url('../images/files/volumes/white_downloads.png') 1x,
+    url('../images/files/volumes/2x/white_downloads.png') 2x);
 }
 
 [volume-type-icon='drive'] {
   background-image: -webkit-image-set(
-    url('../images/files/volumes/new-ui/black_drive.png') 1x,
-    url('../images/files/volumes/new-ui/2x/black_drive.png') 2x);
+    url('../images/files/volumes/black_drive.png') 1x,
+    url('../images/files/volumes/2x/black_drive.png') 2x);
 }
 
 list:focus li[selected] [volume-type-icon='drive'],
 tree:focus .tree-item[selected] > .tree-row > [volume-type-icon='drive'] {
   background-image: -webkit-image-set(
-    url('../images/files/volumes/new-ui/white_drive.png') 1x,
-    url('../images/files/volumes/new-ui/2x/white_drive.png') 2x);
+    url('../images/files/volumes/white_drive.png') 1x,
+    url('../images/files/volumes/2x/white_drive.png') 2x);
 }
 
 [volume-type-icon='drive_offline'] {
   background-image: -webkit-image-set(
-    url('../images/files/volumes/new-ui/black_offline.png') 1x,
-    url('../images/files/volumes/new-ui/2x/black_offline.png') 2x);
+    url('../images/files/volumes/black_offline.png') 1x,
+    url('../images/files/volumes/2x/black_offline.png') 2x);
 }
 
 list:focus li[selected] [volume-type-icon='drive_offline'],
 tree:focus .tree-item[selected] > .tree-row >
     [volume-type-icon='drive_offline'] {
   background-image: -webkit-image-set(
-    url('../images/files/volumes/new-ui/white_offline.png') 1x,
-    url('../images/files/volumes/new-ui/2x/white_offline.png') 2x);
+    url('../images/files/volumes/white_offline.png') 1x,
+    url('../images/files/volumes/2x/white_offline.png') 2x);
 }
 
 [volume-type-icon='drive_shared_with_me'] {
   background-image: -webkit-image-set(
-    url('../images/files/volumes/new-ui/black_shared.png') 1x,
-    url('../images/files/volumes/new-ui/2x/black_shared.png') 2x);
+    url('../images/files/volumes/black_shared.png') 1x,
+    url('../images/files/volumes/2x/black_shared.png') 2x);
 }
 
 list:focus li[selected] [volume-type-icon='drive_shared_with_me'],
 tree:focus .tree-item[selected] > .tree-row >
     [volume-type-icon='drive_shared_with_me'] {
   background-image: -webkit-image-set(
-    url('../images/files/volumes/new-ui/white_shared.png') 1x,
-    url('../images/files/volumes/new-ui/2x/white_shared.png') 2x);
+    url('../images/files/volumes/white_shared.png') 1x,
+    url('../images/files/volumes/2x/white_shared.png') 2x);
 }
 
 [volume-type-icon='drive_recent'] {
   background-image: -webkit-image-set(
-    url('../images/files/volumes/new-ui/black_recent.png') 1x,
-    url('../images/files/volumes/new-ui/2x/black_recent.png') 2x);
+    url('../images/files/volumes/black_recent.png') 1x,
+    url('../images/files/volumes/2x/black_recent.png') 2x);
 }
 
 list:focus li[selected] [volume-type-icon='drive_recent'],
 tree:focus .tree-item[selected] > .tree-row >
     [volume-type-icon='drive_recent'] {
   background-image: -webkit-image-set(
-    url('../images/files/volumes/new-ui/white_recent.png') 1x,
-    url('../images/files/volumes/new-ui/2x/white_recent.png') 2x);
+    url('../images/files/volumes/white_recent.png') 1x,
+    url('../images/files/volumes/2x/white_recent.png') 2x);
 }
 
 [volume-type-icon='removable'] {
   background-image: -webkit-image-set(
-    url('../images/files/volumes/new-ui/black_usb.png') 1x,
-    url('../images/files/volumes/new-ui/2x/black_usb.png') 2x);
+    url('../images/files/volumes/black_usb.png') 1x,
+    url('../images/files/volumes/2x/black_usb.png') 2x);
 }
 
 list:focus li[selected] [volume-type-icon='removable'],
 tree:focus .tree-item[selected] > .tree-row >
     [volume-type-icon='removable'] {
   background-image: -webkit-image-set(
-    url('../images/files/volumes/new-ui/white_usb.png') 1x,
-    url('../images/files/volumes/new-ui/2x/white_usb.png') 2x);
+    url('../images/files/volumes/white_usb.png') 1x,
+    url('../images/files/volumes/2x/white_usb.png') 2x);
 }
 
 [volume-type-icon='removable'][volume-subtype='sd'] {
   background-image: -webkit-image-set(
-    url('../images/files/volumes/new-ui/black_sd.png') 1x,
-    url('../images/files/volumes/new-ui/2x/black_sd.png') 2x);
+    url('../images/files/volumes/black_sd.png') 1x,
+    url('../images/files/volumes/2x/black_sd.png') 2x);
 }
 
 list:focus li[selected] [volume-type-icon='removable'][volume-subtype='sd'],
 tree:focus .tree-item[selected] > .tree-row >
     [volume-type-icon='removable'][volume-subtype='sd'] {
   background-image: -webkit-image-set(
-    url('../images/files/volumes/new-ui/white_sd.png') 1x,
-    url('../images/files/volumes/new-ui/2x/white_sd.png') 2x);
+    url('../images/files/volumes/white_sd.png') 1x,
+    url('../images/files/volumes/2x/white_sd.png') 2x);
 }
 
 [volume-type-icon='removable'][volume-subtype='optical'] {
   background-image: -webkit-image-set(
-    url('../images/files/volumes/new-ui/black_optical.png') 1x,
-    url('../images/files/volumes/new-ui/2x/black_optical.png') 2x);
+    url('../images/files/volumes/black_optical.png') 1x,
+    url('../images/files/volumes/2x/black_optical.png') 2x);
 }
 
 list:focus div[selected]
@@ -327,8 +432,8 @@
 tree:focus .tree-item[selected] > .tree-row >
     [volume-type-icon='removable'][volume-subtype='optical'] {
   background-image: -webkit-image-set(
-    url('../images/files/volumes/new-ui/white_optical.png') 1x,
-    url('../images/files/volumes/new-ui/2x/white_optical.png') 2x);
+    url('../images/files/volumes/white_optical.png') 1x,
+    url('../images/files/volumes/2x/white_optical.png') 2x);
 }
 
 list:focus li[selected]
@@ -336,16 +441,16 @@
 tree:focus .tree-item[selected] > .tree-row >
     [volume-type-icon='removable'][volume-subtype='optical'] {
   background-image: -webkit-image-set(
-    url('../images/files/volumes/new-ui/white_optical.png') 1x,
-    url('../images/files/volumes/new-ui/2x/white_optical.png') 2x);
+    url('../images/files/volumes/white_optical.png') 1x,
+    url('../images/files/volumes/2x/white_optical.png') 2x);
 }
 
 /* TODO(kaznacheev): consider a better icon for volume-subtype=unknown.
    Also find out if we need an icon for volume-subtype=mobile */
 [volume-type-icon='removable'][volume-subtype='unknown'] {
   background-image: -webkit-image-set(
-    url('../images/files/volumes/new-ui/black_hdd.png') 1x,
-    url('../images/files/volumes/new-ui/2x/black_hdd.png') 2x);
+    url('../images/files/volumes/black_hdd.png') 1x,
+    url('../images/files/volumes/2x/black_hdd.png') 2x);
 }
 
 list:focus li[selected]
@@ -353,6 +458,6 @@
 tree:focus .tree-item[selected] > .tree-row >
     [volume-type-icon='removable'][volume-subtype='unknown'] {
   background-image: -webkit-image-set(
-    url('../images/files/volumes/new-ui/white_hdd.png') 1x,
-    url('../images/files/volumes/new-ui/2x/white_hdd.png') 2x);
+    url('../images/files/volumes/white_hdd.png') 1x,
+    url('../images/files/volumes/2x/white_hdd.png') 2x);
 }
diff --git a/chrome/browser/resources/file_manager/css/gallery.css b/chrome/browser/resources/file_manager/css/gallery.css
index ea005c8..5d2a20a 100644
--- a/chrome/browser/resources/file_manager/css/gallery.css
+++ b/chrome/browser/resources/file_manager/css/gallery.css
@@ -787,14 +787,30 @@
     url('../images/gallery/2x/icon_edit_selected.png') 2x);
 }
 
+.gallery > .toolbar > button.print {
+  background-image: -webkit-image-set(
+    url('../images/gallery/icon_print.png') 1x,
+    url('../images/gallery/2x/icon_print.png') 2x);
+}
+
+.gallery > .toolbar > button.print:active,
+.gallery > .toolbar > button.print[pressed] {
+  background-image: -webkit-image-set(
+    url('../images/gallery/icon_print_selected.png') 1x,
+    url('../images/gallery/2x/icon_print_selected.png') 2x);
+}
+
 .gallery > .toolbar > button.share {
   background-image: -webkit-image-set(
     url('../images/gallery/icon_share.png') 1x,
     url('../images/gallery/2x/icon_share.png') 2x);
 }
 
-.gallery > .toolbar > button.share:hover {
-  background-color: rgba(31, 31, 31, 1);
+.gallery > .toolbar > button.share:active,
+.gallery > .toolbar > button.share[pressed] {
+  background-image: -webkit-image-set(
+    url('../images/gallery/icon_share_selected.png') 1x,
+    url('../images/gallery/2x/icon_share_selected.png') 2x);
 }
 
 .gallery[error] > .toolbar button.edit,
@@ -1352,12 +1368,12 @@
 
 .gallery > .header > .maximize-button {
   background-image: -webkit-image-set(
-    url('../images/files/ui/new-ui/topbar_button_maximize.png') 1x,
-    url('../images/files/ui/new-ui/2x/topbar_button_maximize.png') 2x);
+    url('../images/files/ui/topbar_button_maximize.png') 1x,
+    url('../images/files/ui/2x/topbar_button_maximize.png') 2x);
 }
 
 .gallery > .header > .close-button {
   background-image: -webkit-image-set(
-    url('../images/files/ui/new-ui/topbar_button_close.png') 1x,
-    url('../images/files/ui/new-ui/2x/topbar_button_close.png') 2x);
+    url('../images/files/ui/topbar_button_close.png') 1x,
+    url('../images/files/ui/2x/topbar_button_close.png') 2x);
 }
diff --git a/chrome/browser/resources/file_manager/css/list.css b/chrome/browser/resources/file_manager/css/list.css
new file mode 100644
index 0000000..d102d69
--- /dev/null
+++ b/chrome/browser/resources/file_manager/css/list.css
@@ -0,0 +1,73 @@
+/* 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. */
+
+/* Derived from /ui/webui/resources/css/list.css. */
+
+list,
+grid {
+  display: block;
+  outline: none;
+  overflow: auto;
+  position: relative; /* Make sure that item offsets are relative to the
+                         list. */
+}
+
+list > *,
+grid > * {
+  -webkit-user-select: none;
+  position: relative; /* to allow overlap */
+  text-overflow: ellipsis;
+  white-space: pre;
+}
+
+list > * {
+  display: block;
+}
+
+grid > * {
+  display: inline-block;
+}
+
+list:focus > [lead],
+grid:focus > [lead] {
+  z-index: 2;
+}
+
+list:not([disabled]) > :hover,
+grid:not([disabled]) > :hover {
+  z-index: 1;
+}
+
+list > [selected],
+grid > [selected] {
+  z-index: 2;
+}
+
+list > .spacer,
+grid > .spacer {
+  box-sizing: border-box;
+  display: block;
+  overflow: hidden;
+  visibility: hidden;
+}
+
+list :-webkit-any(
+    input[type='input'],
+    input[type='password'],
+    input[type='search'],
+    input[type='text'],
+    input[type='url']),
+list :-webkit-any(
+    button,
+    input[type='button'],
+    input[type='submit'],
+    select):not(.custom-appearance):not(.link-button) {
+  line-height: normal;
+  vertical-align: middle;
+}
+
+list > [hidden],
+grid > [hidden] {
+  display: none;
+}
diff --git a/chrome/browser/resources/file_manager/css/media_controls.css b/chrome/browser/resources/file_manager/css/media_controls.css
index 7b56adb..98745a0 100644
--- a/chrome/browser/resources/file_manager/css/media_controls.css
+++ b/chrome/browser/resources/file_manager/css/media_controls.css
@@ -536,6 +536,28 @@
   z-index: 2;
 }
 
+.text-banner {
+  background-color: black;
+  border-radius: 10px;
+  color: white;
+  font-size: 18px;
+  left: 50%;
+  margin-left: -250px;
+  opacity: 0;
+  padding: 10px;
+  pointer-events: none;
+  position: absolute;
+  text-align: center;
+  text-shadow: 0 0 10px black;
+  top: 20%;
+  width: 500px;
+  z-index: 2;
+}
+
+.text-banner[visible] {
+  -webkit-animation: text-banner-blowup 3000ms;
+}
+
 .playback-state-icon[state] {
   -webkit-animation: blowup 500ms;
 }
@@ -550,6 +572,25 @@
   }
 }
 
+@-webkit-keyframes text-banner-blowup {
+  from {
+    -webkit-transform: scale(0.5);
+    opacity: 0;
+  }
+  20% {
+    -webkit-transform: scale(1);
+    opacity: 0.75;
+  }
+  80% {
+    -webkit-transform: scale(1);
+    opacity: 0.75;
+  }
+  to {
+    -webkit-transform: scale(3);
+    opacity: 0;
+  }
+}
+
 .playback-state-icon[state='play'] {
   background-image: -webkit-image-set(
     url('../images/media/media_play.png') 1x,
diff --git a/chrome/browser/resources/file_manager/css/table.css b/chrome/browser/resources/file_manager/css/table.css
new file mode 100644
index 0000000..8351699
--- /dev/null
+++ b/chrome/browser/resources/file_manager/css/table.css
@@ -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. */
+
+/* Derived from /ui/webui/resources/css/table.css. */
+
+html.col-resize * {
+  cursor: col-resize !important;
+}
+
+.table[hasElementFocus] > list > [lead] {
+  z-index: 2;
+}
+
+.table-row {
+  display: -webkit-box;
+  text-align: start;
+  width: 100%;
+}
+
+.table-row-cell {
+  display: -webkit-box;
+  overflow: hidden;
+}
+
+.table-row-cell > * {
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+}
+
+.table-header {
+  overflow: hidden;
+  position: relative;
+}
+
+.table-header-inner {
+  -webkit-user-select: none;
+  cursor: default;
+  display: -webkit-box;
+  position: relative;
+  text-align: start;
+}
+
+.table-header-cell {
+  font-weight: normal;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+}
+
+.table-header-label {
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+}
+
+.table-header-splitter {
+  cursor: col-resize;
+  height: 100%;
+  left: 0;
+  position: absolute;
+  top: 0;
+}
diff --git a/chrome/browser/resources/file_manager/css/tree.css b/chrome/browser/resources/file_manager/css/tree.css
new file mode 100644
index 0000000..e151977
--- /dev/null
+++ b/chrome/browser/resources/file_manager/css/tree.css
@@ -0,0 +1,83 @@
+/* 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. */
+
+/* Derived from /ui/webui/resources/css/table.css. */
+
+tree {
+  display: block;
+  outline: none;
+  overflow: auto;
+}
+
+.tree-item > .tree-row {
+  -webkit-user-select: none;
+  cursor: default;
+  position: relative;
+  white-space: nowrap;
+}
+
+.expand-icon {
+  -webkit-transform: rotate(-90deg);
+  -webkit-transition: all 150ms;
+  background-image: -webkit-canvas(tree-triangle);
+  background-position: 50% 50%;
+  background-repeat: no-repeat;
+  background-size: 8px 5px;
+  display: inline-block;
+  height: 16px;
+  position: relative;
+  vertical-align: top;
+}
+
+html[dir=rtl] .expand-icon {
+  -webkit-transform: rotate(90deg);
+}
+
+.tree-item[expanded] > .tree-row > .expand-icon {
+  -webkit-transform: rotate(0);
+  background-image: -webkit-canvas(tree-triangle);
+}
+
+.tree-row .expand-icon {
+  visibility: hidden;
+}
+
+.tree-row[may-have-children] .expand-icon {
+  visibility: visible;
+}
+
+.tree-row[has-children=false] .expand-icon {
+  visibility: hidden;
+}
+
+.tree-row[selected] {
+  z-index: 2;
+}
+
+.tree-children[expanded] {
+  display: block;
+}
+
+.tree-children {
+  display: none;
+}
+
+.tree-item > .tree-row > * {
+  display: inline-block;
+}
+
+.tree-label {
+  white-space: pre;
+}
+
+/* We need to ensure that even empty labels take up space */
+.tree-label:empty::after {
+  content: ' ';
+  white-space: pre;
+}
+
+.tree-rename > .tree-row > .tree-label {
+  -webkit-user-modify: read-write-plaintext-only;
+  -webkit-user-select: auto;
+}
diff --git a/chrome/browser/resources/file_manager/gallery.html b/chrome/browser/resources/file_manager/gallery.html
index f31450c..dfa6941 100644
--- a/chrome/browser/resources/file_manager/gallery.html
+++ b/chrome/browser/resources/file_manager/gallery.html
@@ -24,7 +24,7 @@
     <script src="js/metrics.js"></script>
 
     <!-- Loads the client of the image loader extension -->
-    <script src="chrome-extension://pmfjbimdmchhbnneeidfognadeopoehp/client.js"></script>
+    <script src="chrome-extension://pmfjbimdmchhbnneeidfognadeopoehp/image_loader_client.js"></script>
 
     <script src="chrome://resources/js/cr.js"></script>
     <script src="chrome://resources/js/event_tracker.js"></script>
diff --git a/chrome/browser/resources/file_manager/images/common/2x/bubble_point_white.png b/chrome/browser/resources/file_manager/images/common/2x/bubble_point_white.png
index 970a4bf..643847b 100644
--- a/chrome/browser/resources/file_manager/images/common/2x/bubble_point_white.png
+++ b/chrome/browser/resources/file_manager/images/common/2x/bubble_point_white.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/common/2x/button.png b/chrome/browser/resources/file_manager/images/common/2x/button.png
index 08cef2f..d185c7b 100644
--- a/chrome/browser/resources/file_manager/images/common/2x/button.png
+++ b/chrome/browser/resources/file_manager/images/common/2x/button.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/common/2x/button_hover.png b/chrome/browser/resources/file_manager/images/common/2x/button_hover.png
index cd1dbcd..5de5c7e 100644
--- a/chrome/browser/resources/file_manager/images/common/2x/button_hover.png
+++ b/chrome/browser/resources/file_manager/images/common/2x/button_hover.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/common/2x/button_pressed.png b/chrome/browser/resources/file_manager/images/common/2x/button_pressed.png
index 70b2375..eee68dd 100644
--- a/chrome/browser/resources/file_manager/images/common/2x/button_pressed.png
+++ b/chrome/browser/resources/file_manager/images/common/2x/button_pressed.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/common/2x/check_blue.png b/chrome/browser/resources/file_manager/images/common/2x/check_blue.png
index baae1aa..6f55f5a 100644
--- a/chrome/browser/resources/file_manager/images/common/2x/check_blue.png
+++ b/chrome/browser/resources/file_manager/images/common/2x/check_blue.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/common/2x/check_circled.png b/chrome/browser/resources/file_manager/images/common/2x/check_circled.png
index 67d1c77..5567ac2 100644
--- a/chrome/browser/resources/file_manager/images/common/2x/check_circled.png
+++ b/chrome/browser/resources/file_manager/images/common/2x/check_circled.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/common/2x/check_no_box.png b/chrome/browser/resources/file_manager/images/common/2x/check_no_box.png
index 5c4a1aa..8dddff8 100644
--- a/chrome/browser/resources/file_manager/images/common/2x/check_no_box.png
+++ b/chrome/browser/resources/file_manager/images/common/2x/check_no_box.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/common/2x/checkbox_white_checked.png b/chrome/browser/resources/file_manager/images/common/2x/checkbox_white_checked.png
index 0055b5f..466fa22 100644
--- a/chrome/browser/resources/file_manager/images/common/2x/checkbox_white_checked.png
+++ b/chrome/browser/resources/file_manager/images/common/2x/checkbox_white_checked.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/common/2x/checkbox_white_unchecked.png b/chrome/browser/resources/file_manager/images/common/2x/checkbox_white_unchecked.png
index aa4fbea..88d97d7 100644
--- a/chrome/browser/resources/file_manager/images/common/2x/checkbox_white_unchecked.png
+++ b/chrome/browser/resources/file_manager/images/common/2x/checkbox_white_unchecked.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/common/2x/close_x_gray.png b/chrome/browser/resources/file_manager/images/common/2x/close_x_gray.png
index 0a16850..8a2930a 100644
--- a/chrome/browser/resources/file_manager/images/common/2x/close_x_gray.png
+++ b/chrome/browser/resources/file_manager/images/common/2x/close_x_gray.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/common/2x/disclosure_arrow_dk_grey.png b/chrome/browser/resources/file_manager/images/common/2x/disclosure_arrow_dk_grey.png
index 93c5a31..8f35319 100644
--- a/chrome/browser/resources/file_manager/images/common/2x/disclosure_arrow_dk_grey.png
+++ b/chrome/browser/resources/file_manager/images/common/2x/disclosure_arrow_dk_grey.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/common/bubble_point_white.png b/chrome/browser/resources/file_manager/images/common/bubble_point_white.png
index 0c7d52a..ec5dbe9 100644
--- a/chrome/browser/resources/file_manager/images/common/bubble_point_white.png
+++ b/chrome/browser/resources/file_manager/images/common/bubble_point_white.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/common/button.png b/chrome/browser/resources/file_manager/images/common/button.png
index 997799a..4de5ff0 100644
--- a/chrome/browser/resources/file_manager/images/common/button.png
+++ b/chrome/browser/resources/file_manager/images/common/button.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/common/button_hover.png b/chrome/browser/resources/file_manager/images/common/button_hover.png
index d185e09..c24d7cc 100644
--- a/chrome/browser/resources/file_manager/images/common/button_hover.png
+++ b/chrome/browser/resources/file_manager/images/common/button_hover.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/common/button_pressed.png b/chrome/browser/resources/file_manager/images/common/button_pressed.png
index 782b883..c54d6fe 100644
--- a/chrome/browser/resources/file_manager/images/common/button_pressed.png
+++ b/chrome/browser/resources/file_manager/images/common/button_pressed.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/common/check_blue.png b/chrome/browser/resources/file_manager/images/common/check_blue.png
index 2fb8be2..deff101 100644
--- a/chrome/browser/resources/file_manager/images/common/check_blue.png
+++ b/chrome/browser/resources/file_manager/images/common/check_blue.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/common/check_circled.png b/chrome/browser/resources/file_manager/images/common/check_circled.png
index 7f6fb30..ee787be 100644
--- a/chrome/browser/resources/file_manager/images/common/check_circled.png
+++ b/chrome/browser/resources/file_manager/images/common/check_circled.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/common/check_no_box.png b/chrome/browser/resources/file_manager/images/common/check_no_box.png
index 7af1470..3006dcd 100644
--- a/chrome/browser/resources/file_manager/images/common/check_no_box.png
+++ b/chrome/browser/resources/file_manager/images/common/check_no_box.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/common/checkbox_white_checked.png b/chrome/browser/resources/file_manager/images/common/checkbox_white_checked.png
index ad8e943..c095d6c 100644
--- a/chrome/browser/resources/file_manager/images/common/checkbox_white_checked.png
+++ b/chrome/browser/resources/file_manager/images/common/checkbox_white_checked.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/common/close_x_gray.png b/chrome/browser/resources/file_manager/images/common/close_x_gray.png
index 4a95e5a..3ee375a 100644
--- a/chrome/browser/resources/file_manager/images/common/close_x_gray.png
+++ b/chrome/browser/resources/file_manager/images/common/close_x_gray.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/file_types/100/archive.png b/chrome/browser/resources/file_manager/images/files/file_types/100/archive.png
new file mode 100644
index 0000000..2a054b3
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/file_types/100/archive.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/file_types/100/archive_white.png b/chrome/browser/resources/file_manager/images/files/file_types/100/archive_white.png
new file mode 100644
index 0000000..94ffaf0
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/file_types/100/archive_white.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/file_types/100/audio.png b/chrome/browser/resources/file_manager/images/files/file_types/100/audio.png
new file mode 100644
index 0000000..a5b4ac9
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/file_types/100/audio.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/file_types/100/audio_white.png b/chrome/browser/resources/file_manager/images/files/file_types/100/audio_white.png
new file mode 100644
index 0000000..819e406
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/file_types/100/audio_white.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/file_types/100/chart.png b/chrome/browser/resources/file_manager/images/files/file_types/100/chart.png
new file mode 100644
index 0000000..4f7bfa1
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/file_types/100/chart.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/file_types/100/chart_white.png b/chrome/browser/resources/file_manager/images/files/file_types/100/chart_white.png
new file mode 100644
index 0000000..7500f3f
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/file_types/100/chart_white.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/file_types/100/excel.png b/chrome/browser/resources/file_manager/images/files/file_types/100/excel.png
new file mode 100644
index 0000000..cb27f5c
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/file_types/100/excel.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/file_types/100/excel_white.png b/chrome/browser/resources/file_manager/images/files/file_types/100/excel_white.png
new file mode 100644
index 0000000..0900b09
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/file_types/100/excel_white.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/file_types/100/folder.png b/chrome/browser/resources/file_manager/images/files/file_types/100/folder.png
new file mode 100644
index 0000000..3f6e17f
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/file_types/100/folder.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/file_types/100/folder_white.png b/chrome/browser/resources/file_manager/images/files/file_types/100/folder_white.png
new file mode 100644
index 0000000..9a56eb9
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/file_types/100/folder_white.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/file_types/100/form.png b/chrome/browser/resources/file_manager/images/files/file_types/100/form.png
new file mode 100644
index 0000000..c3d2087
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/file_types/100/form.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/file_types/100/form_white.png b/chrome/browser/resources/file_manager/images/files/file_types/100/form_white.png
new file mode 100644
index 0000000..21c18ad
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/file_types/100/form_white.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/file_types/100/gdoc.png b/chrome/browser/resources/file_manager/images/files/file_types/100/gdoc.png
new file mode 100644
index 0000000..102f1c0
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/file_types/100/gdoc.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/file_types/100/gdoc_white.png b/chrome/browser/resources/file_manager/images/files/file_types/100/gdoc_white.png
new file mode 100644
index 0000000..a66a338
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/file_types/100/gdoc_white.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/file_types/100/gdraw.png b/chrome/browser/resources/file_manager/images/files/file_types/100/gdraw.png
new file mode 100644
index 0000000..b112041
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/file_types/100/gdraw.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/file_types/100/gdraw_white.png b/chrome/browser/resources/file_manager/images/files/file_types/100/gdraw_white.png
new file mode 100644
index 0000000..f92f18b
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/file_types/100/gdraw_white.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/file_types/100/generic.png b/chrome/browser/resources/file_manager/images/files/file_types/100/generic.png
new file mode 100644
index 0000000..bff3cda
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/file_types/100/generic.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/file_types/100/generic_white.png b/chrome/browser/resources/file_manager/images/files/file_types/100/generic_white.png
new file mode 100644
index 0000000..a369f66
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/file_types/100/generic_white.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/file_types/100/glink.png b/chrome/browser/resources/file_manager/images/files/file_types/100/glink.png
new file mode 100644
index 0000000..bff3cda
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/file_types/100/glink.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/file_types/100/glink_white.png b/chrome/browser/resources/file_manager/images/files/file_types/100/glink_white.png
new file mode 100644
index 0000000..a369f66
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/file_types/100/glink_white.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/file_types/100/gsheet.png b/chrome/browser/resources/file_manager/images/files/file_types/100/gsheet.png
new file mode 100644
index 0000000..6fbd46b
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/file_types/100/gsheet.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/file_types/100/gsheet_white.png b/chrome/browser/resources/file_manager/images/files/file_types/100/gsheet_white.png
new file mode 100644
index 0000000..39cf43d
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/file_types/100/gsheet_white.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/file_types/100/gslides.png b/chrome/browser/resources/file_manager/images/files/file_types/100/gslides.png
new file mode 100644
index 0000000..76523cc
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/file_types/100/gslides.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/file_types/100/gslides_white.png b/chrome/browser/resources/file_manager/images/files/file_types/100/gslides_white.png
new file mode 100644
index 0000000..ea14b91
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/file_types/100/gslides_white.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/file_types/100/gtable.png b/chrome/browser/resources/file_manager/images/files/file_types/100/gtable.png
new file mode 100644
index 0000000..a78b26e
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/file_types/100/gtable.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/file_types/100/gtable_white.png b/chrome/browser/resources/file_manager/images/files/file_types/100/gtable_white.png
new file mode 100644
index 0000000..f534641
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/file_types/100/gtable_white.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/file_types/100/image.png b/chrome/browser/resources/file_manager/images/files/file_types/100/image.png
new file mode 100644
index 0000000..9ec2dbd
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/file_types/100/image.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/file_types/100/image_white.png b/chrome/browser/resources/file_manager/images/files/file_types/100/image_white.png
new file mode 100644
index 0000000..739614f
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/file_types/100/image_white.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/file_types/100/pdf.png b/chrome/browser/resources/file_manager/images/files/file_types/100/pdf.png
new file mode 100644
index 0000000..ec6d679
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/file_types/100/pdf.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/file_types/100/pdf_white.png b/chrome/browser/resources/file_manager/images/files/file_types/100/pdf_white.png
new file mode 100644
index 0000000..0768204
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/file_types/100/pdf_white.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/file_types/100/ppt.png b/chrome/browser/resources/file_manager/images/files/file_types/100/ppt.png
new file mode 100644
index 0000000..0a83445
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/file_types/100/ppt.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/file_types/100/ppt_white.png b/chrome/browser/resources/file_manager/images/files/file_types/100/ppt_white.png
new file mode 100644
index 0000000..f18491d
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/file_types/100/ppt_white.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/file_types/100/script.png b/chrome/browser/resources/file_manager/images/files/file_types/100/script.png
new file mode 100644
index 0000000..054f59a
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/file_types/100/script.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/file_types/100/script_white.png b/chrome/browser/resources/file_manager/images/files/file_types/100/script_white.png
new file mode 100644
index 0000000..2760eb8
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/file_types/100/script_white.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/file_types/100/sites.png b/chrome/browser/resources/file_manager/images/files/file_types/100/sites.png
new file mode 100644
index 0000000..e4e0ffe
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/file_types/100/sites.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/file_types/100/sites_white.png b/chrome/browser/resources/file_manager/images/files/file_types/100/sites_white.png
new file mode 100644
index 0000000..11646f8
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/file_types/100/sites_white.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/file_types/100/video.png b/chrome/browser/resources/file_manager/images/files/file_types/100/video.png
new file mode 100644
index 0000000..73b70f6
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/file_types/100/video.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/file_types/100/video_white.png b/chrome/browser/resources/file_manager/images/files/file_types/100/video_white.png
new file mode 100644
index 0000000..ac1c080
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/file_types/100/video_white.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/file_types/100/word.png b/chrome/browser/resources/file_manager/images/files/file_types/100/word.png
new file mode 100644
index 0000000..a2bf315
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/file_types/100/word.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/file_types/100/word_white.png b/chrome/browser/resources/file_manager/images/files/file_types/100/word_white.png
new file mode 100644
index 0000000..9bc0f21
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/file_types/100/word_white.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/file_types/200/archive.png b/chrome/browser/resources/file_manager/images/files/file_types/200/archive.png
new file mode 100644
index 0000000..f514181
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/file_types/200/archive.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/file_types/200/archive_white.png b/chrome/browser/resources/file_manager/images/files/file_types/200/archive_white.png
new file mode 100644
index 0000000..6b522cf
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/file_types/200/archive_white.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/file_types/200/audio.png b/chrome/browser/resources/file_manager/images/files/file_types/200/audio.png
new file mode 100644
index 0000000..ad2f540
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/file_types/200/audio.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/file_types/200/audio_white.png b/chrome/browser/resources/file_manager/images/files/file_types/200/audio_white.png
new file mode 100644
index 0000000..997d610
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/file_types/200/audio_white.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/file_types/200/chart.png b/chrome/browser/resources/file_manager/images/files/file_types/200/chart.png
new file mode 100644
index 0000000..5b03c36
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/file_types/200/chart.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/file_types/200/chart_white.png b/chrome/browser/resources/file_manager/images/files/file_types/200/chart_white.png
new file mode 100644
index 0000000..16a75ee
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/file_types/200/chart_white.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/file_types/200/excel.png b/chrome/browser/resources/file_manager/images/files/file_types/200/excel.png
new file mode 100644
index 0000000..22a4eb5
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/file_types/200/excel.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/file_types/200/excel_white.png b/chrome/browser/resources/file_manager/images/files/file_types/200/excel_white.png
new file mode 100644
index 0000000..bf0a61c
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/file_types/200/excel_white.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/file_types/200/folder.png b/chrome/browser/resources/file_manager/images/files/file_types/200/folder.png
new file mode 100644
index 0000000..782227f
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/file_types/200/folder.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/file_types/200/folder_white.png b/chrome/browser/resources/file_manager/images/files/file_types/200/folder_white.png
new file mode 100644
index 0000000..9124621
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/file_types/200/folder_white.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/file_types/200/form.png b/chrome/browser/resources/file_manager/images/files/file_types/200/form.png
new file mode 100644
index 0000000..7908b55
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/file_types/200/form.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/file_types/200/form_white.png b/chrome/browser/resources/file_manager/images/files/file_types/200/form_white.png
new file mode 100644
index 0000000..540fdc2
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/file_types/200/form_white.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/file_types/200/gdoc.png b/chrome/browser/resources/file_manager/images/files/file_types/200/gdoc.png
new file mode 100644
index 0000000..80ae026
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/file_types/200/gdoc.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/file_types/200/gdoc_white.png b/chrome/browser/resources/file_manager/images/files/file_types/200/gdoc_white.png
new file mode 100644
index 0000000..366180c
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/file_types/200/gdoc_white.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/file_types/200/gdraw.png b/chrome/browser/resources/file_manager/images/files/file_types/200/gdraw.png
new file mode 100644
index 0000000..c36fca6
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/file_types/200/gdraw.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/file_types/200/gdraw_white.png b/chrome/browser/resources/file_manager/images/files/file_types/200/gdraw_white.png
new file mode 100644
index 0000000..98401d9
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/file_types/200/gdraw_white.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/file_types/200/generic.png b/chrome/browser/resources/file_manager/images/files/file_types/200/generic.png
new file mode 100644
index 0000000..8df85a3
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/file_types/200/generic.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/file_types/200/generic_white.png b/chrome/browser/resources/file_manager/images/files/file_types/200/generic_white.png
new file mode 100644
index 0000000..9b9b295
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/file_types/200/generic_white.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/file_types/200/glink.png b/chrome/browser/resources/file_manager/images/files/file_types/200/glink.png
new file mode 100644
index 0000000..8df85a3
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/file_types/200/glink.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/file_types/200/glink_white.png b/chrome/browser/resources/file_manager/images/files/file_types/200/glink_white.png
new file mode 100644
index 0000000..d9a2070
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/file_types/200/glink_white.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/file_types/200/gsheet.png b/chrome/browser/resources/file_manager/images/files/file_types/200/gsheet.png
new file mode 100644
index 0000000..0545e69
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/file_types/200/gsheet.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/file_types/200/gsheet_white.png b/chrome/browser/resources/file_manager/images/files/file_types/200/gsheet_white.png
new file mode 100644
index 0000000..801de01
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/file_types/200/gsheet_white.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/file_types/200/gslides.png b/chrome/browser/resources/file_manager/images/files/file_types/200/gslides.png
new file mode 100644
index 0000000..207b0f2
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/file_types/200/gslides.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/file_types/200/gslides_white.png b/chrome/browser/resources/file_manager/images/files/file_types/200/gslides_white.png
new file mode 100644
index 0000000..b6c24ab
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/file_types/200/gslides_white.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/file_types/200/gtable.png b/chrome/browser/resources/file_manager/images/files/file_types/200/gtable.png
new file mode 100644
index 0000000..fec2061
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/file_types/200/gtable.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/file_types/200/gtable_white.png b/chrome/browser/resources/file_manager/images/files/file_types/200/gtable_white.png
new file mode 100644
index 0000000..8c695c5
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/file_types/200/gtable_white.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/file_types/200/image.png b/chrome/browser/resources/file_manager/images/files/file_types/200/image.png
new file mode 100644
index 0000000..df61101
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/file_types/200/image.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/file_types/200/image_white.png b/chrome/browser/resources/file_manager/images/files/file_types/200/image_white.png
new file mode 100644
index 0000000..46017e6
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/file_types/200/image_white.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/file_types/200/pdf.png b/chrome/browser/resources/file_manager/images/files/file_types/200/pdf.png
new file mode 100644
index 0000000..0f62d9e
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/file_types/200/pdf.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/file_types/200/pdf_white.png b/chrome/browser/resources/file_manager/images/files/file_types/200/pdf_white.png
new file mode 100644
index 0000000..e53bda7
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/file_types/200/pdf_white.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/file_types/200/ppt.png b/chrome/browser/resources/file_manager/images/files/file_types/200/ppt.png
new file mode 100644
index 0000000..31fcd8f
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/file_types/200/ppt.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/file_types/200/ppt_white.png b/chrome/browser/resources/file_manager/images/files/file_types/200/ppt_white.png
new file mode 100644
index 0000000..9824222
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/file_types/200/ppt_white.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/file_types/200/script.png b/chrome/browser/resources/file_manager/images/files/file_types/200/script.png
new file mode 100644
index 0000000..01a2a1a
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/file_types/200/script.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/file_types/200/script_white.png b/chrome/browser/resources/file_manager/images/files/file_types/200/script_white.png
new file mode 100644
index 0000000..b04a210
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/file_types/200/script_white.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/file_types/200/sites.png b/chrome/browser/resources/file_manager/images/files/file_types/200/sites.png
new file mode 100644
index 0000000..541c328
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/file_types/200/sites.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/file_types/200/sites_white.png b/chrome/browser/resources/file_manager/images/files/file_types/200/sites_white.png
new file mode 100644
index 0000000..613e517
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/file_types/200/sites_white.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/file_types/200/video.png b/chrome/browser/resources/file_manager/images/files/file_types/200/video.png
new file mode 100644
index 0000000..a8346a3
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/file_types/200/video.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/file_types/200/video_white.png b/chrome/browser/resources/file_manager/images/files/file_types/200/video_white.png
new file mode 100644
index 0000000..3cbcdba
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/file_types/200/video_white.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/file_types/200/word.png b/chrome/browser/resources/file_manager/images/files/file_types/200/word.png
new file mode 100644
index 0000000..23b78f6
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/file_types/200/word.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/file_types/200/word_white.png b/chrome/browser/resources/file_manager/images/files/file_types/200/word_white.png
new file mode 100644
index 0000000..424ea80
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/file_types/200/word_white.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/2x/black_folder.png b/chrome/browser/resources/file_manager/images/files/ui/2x/black_folder.png
new file mode 100644
index 0000000..febe300
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/ui/2x/black_folder.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/2x/breadcrumb-separator.png b/chrome/browser/resources/file_manager/images/files/ui/2x/breadcrumb-separator.png
index 4d7fe00..dce1f1a 100644
--- a/chrome/browser/resources/file_manager/images/files/ui/2x/breadcrumb-separator.png
+++ b/chrome/browser/resources/file_manager/images/files/ui/2x/breadcrumb-separator.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/2x/button_list_view.png b/chrome/browser/resources/file_manager/images/files/ui/2x/button_list_view.png
new file mode 100644
index 0000000..09aa2fd
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/ui/2x/button_list_view.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/2x/button_list_view_white.png b/chrome/browser/resources/file_manager/images/files/ui/2x/button_list_view_white.png
new file mode 100644
index 0000000..f89199a
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/ui/2x/button_list_view_white.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/2x/button_mosaic_view.png b/chrome/browser/resources/file_manager/images/files/ui/2x/button_mosaic_view.png
new file mode 100644
index 0000000..1961e46
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/ui/2x/button_mosaic_view.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/2x/button_mosaic_view_white.png b/chrome/browser/resources/file_manager/images/files/ui/2x/button_mosaic_view_white.png
new file mode 100644
index 0000000..ad6f856
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/ui/2x/button_mosaic_view_white.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/2x/close_bar.png b/chrome/browser/resources/file_manager/images/files/ui/2x/close_bar.png
index 98ae94c..3f9e452 100644
--- a/chrome/browser/resources/file_manager/images/files/ui/2x/close_bar.png
+++ b/chrome/browser/resources/file_manager/images/files/ui/2x/close_bar.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/2x/disclosure_arrow_dk_grey.png b/chrome/browser/resources/file_manager/images/files/ui/2x/disclosure_arrow_dk_grey.png
deleted file mode 100644
index 93c5a31..0000000
--- a/chrome/browser/resources/file_manager/images/files/ui/2x/disclosure_arrow_dk_grey.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/2x/disclosure_arrow_dk_grey_down.png b/chrome/browser/resources/file_manager/images/files/ui/2x/disclosure_arrow_dk_grey_down.png
deleted file mode 100644
index 55a5f96..0000000
--- a/chrome/browser/resources/file_manager/images/files/ui/2x/disclosure_arrow_dk_grey_down.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/2x/drive_logo.png b/chrome/browser/resources/file_manager/images/files/ui/2x/drive_logo.png
index 6b7ec74..316e8a0 100644
--- a/chrome/browser/resources/file_manager/images/files/ui/2x/drive_logo.png
+++ b/chrome/browser/resources/file_manager/images/files/ui/2x/drive_logo.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/2x/eject.png b/chrome/browser/resources/file_manager/images/files/ui/2x/eject.png
index d9274a2..f764c0c 100644
--- a/chrome/browser/resources/file_manager/images/files/ui/2x/eject.png
+++ b/chrome/browser/resources/file_manager/images/files/ui/2x/eject.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/2x/icon_search.png b/chrome/browser/resources/file_manager/images/files/ui/2x/icon_search.png
index cc95446..99e1053 100644
--- a/chrome/browser/resources/file_manager/images/files/ui/2x/icon_search.png
+++ b/chrome/browser/resources/file_manager/images/files/ui/2x/icon_search.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/2x/offline.png b/chrome/browser/resources/file_manager/images/files/ui/2x/offline.png
index 5f97295..6fe2d25 100644
--- a/chrome/browser/resources/file_manager/images/files/ui/2x/offline.png
+++ b/chrome/browser/resources/file_manager/images/files/ui/2x/offline.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/2x/onbutton_trash.png b/chrome/browser/resources/file_manager/images/files/ui/2x/onbutton_trash.png
new file mode 100644
index 0000000..593f53f
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/ui/2x/onbutton_trash.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/2x/pin.png b/chrome/browser/resources/file_manager/images/files/ui/2x/pin.png
deleted file mode 100644
index e2fc20d..0000000
--- a/chrome/browser/resources/file_manager/images/files/ui/2x/pin.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/2x/recent.png b/chrome/browser/resources/file_manager/images/files/ui/2x/recent.png
deleted file mode 100644
index 3dab9f5..0000000
--- a/chrome/browser/resources/file_manager/images/files/ui/2x/recent.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/2x/search_clear.png b/chrome/browser/resources/file_manager/images/files/ui/2x/search_clear.png
index 1818bb2..a76574a 100644
--- a/chrome/browser/resources/file_manager/images/files/ui/2x/search_clear.png
+++ b/chrome/browser/resources/file_manager/images/files/ui/2x/search_clear.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/2x/search_clear_hover.png b/chrome/browser/resources/file_manager/images/files/ui/2x/search_clear_hover.png
index 04624df..ed7155a 100644
--- a/chrome/browser/resources/file_manager/images/files/ui/2x/search_clear_hover.png
+++ b/chrome/browser/resources/file_manager/images/files/ui/2x/search_clear_hover.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/2x/search_clear_pressed.png b/chrome/browser/resources/file_manager/images/files/ui/2x/search_clear_pressed.png
index 4d0b267..2237a08 100644
--- a/chrome/browser/resources/file_manager/images/files/ui/2x/search_clear_pressed.png
+++ b/chrome/browser/resources/file_manager/images/files/ui/2x/search_clear_pressed.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/2x/search_icon_active.png b/chrome/browser/resources/file_manager/images/files/ui/2x/search_icon_active.png
new file mode 100644
index 0000000..80d733b
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/ui/2x/search_icon_active.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/2x/search_icon_inactive.png b/chrome/browser/resources/file_manager/images/files/ui/2x/search_icon_inactive.png
new file mode 100644
index 0000000..d9e9064
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/ui/2x/search_icon_inactive.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/2x/select_checkbox.png b/chrome/browser/resources/file_manager/images/files/ui/2x/select_checkbox.png
new file mode 100644
index 0000000..e85e010
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/ui/2x/select_checkbox.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/2x/select_checkbox_checked.png b/chrome/browser/resources/file_manager/images/files/ui/2x/select_checkbox_checked.png
new file mode 100644
index 0000000..e879248
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/ui/2x/select_checkbox_checked.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/2x/shared.png b/chrome/browser/resources/file_manager/images/files/ui/2x/shared.png
deleted file mode 100644
index ed4c204..0000000
--- a/chrome/browser/resources/file_manager/images/files/ui/2x/shared.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/2x/sort_asc.png b/chrome/browser/resources/file_manager/images/files/ui/2x/sort_asc.png
index e70f0ba..419b29e 100644
--- a/chrome/browser/resources/file_manager/images/files/ui/2x/sort_asc.png
+++ b/chrome/browser/resources/file_manager/images/files/ui/2x/sort_asc.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/2x/sort_desc.png b/chrome/browser/resources/file_manager/images/files/ui/2x/sort_desc.png
index 51b2b49..a0bfe7a 100644
--- a/chrome/browser/resources/file_manager/images/files/ui/2x/sort_desc.png
+++ b/chrome/browser/resources/file_manager/images/files/ui/2x/sort_desc.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/2x/topbar_button_close.png b/chrome/browser/resources/file_manager/images/files/ui/2x/topbar_button_close.png
new file mode 100644
index 0000000..7a28084
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/ui/2x/topbar_button_close.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/2x/topbar_button_maximize.png b/chrome/browser/resources/file_manager/images/files/ui/2x/topbar_button_maximize.png
new file mode 100644
index 0000000..59377a4
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/ui/2x/topbar_button_maximize.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/2x/topbar_button_settings.png b/chrome/browser/resources/file_manager/images/files/ui/2x/topbar_button_settings.png
new file mode 100644
index 0000000..b474c4c
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/ui/2x/topbar_button_settings.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/new-ui/2x/vertical_separator.png b/chrome/browser/resources/file_manager/images/files/ui/2x/vertical_separator.png
similarity index 100%
rename from chrome/browser/resources/file_manager/images/files/ui/new-ui/2x/vertical_separator.png
rename to chrome/browser/resources/file_manager/images/files/ui/2x/vertical_separator.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/2x/view_list_black.png b/chrome/browser/resources/file_manager/images/files/ui/2x/view_list_black.png
deleted file mode 100644
index 63daca8..0000000
--- a/chrome/browser/resources/file_manager/images/files/ui/2x/view_list_black.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/2x/view_thumbs_black.png b/chrome/browser/resources/file_manager/images/files/ui/2x/view_thumbs_black.png
deleted file mode 100644
index a92e47d..0000000
--- a/chrome/browser/resources/file_manager/images/files/ui/2x/view_thumbs_black.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/2x/warning_icon_square.png b/chrome/browser/resources/file_manager/images/files/ui/2x/warning_icon_square.png
index d151661..52a8b5a 100644
--- a/chrome/browser/resources/file_manager/images/files/ui/2x/warning_icon_square.png
+++ b/chrome/browser/resources/file_manager/images/files/ui/2x/warning_icon_square.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/2x/white_folder.png b/chrome/browser/resources/file_manager/images/files/ui/2x/white_folder.png
new file mode 100644
index 0000000..9124621
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/ui/2x/white_folder.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/black_folder.png b/chrome/browser/resources/file_manager/images/files/ui/black_folder.png
new file mode 100644
index 0000000..539f677
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/ui/black_folder.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/breadcrumb-separator.png b/chrome/browser/resources/file_manager/images/files/ui/breadcrumb-separator.png
index e7ed818..ed94127 100644
--- a/chrome/browser/resources/file_manager/images/files/ui/breadcrumb-separator.png
+++ b/chrome/browser/resources/file_manager/images/files/ui/breadcrumb-separator.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/new-ui/button_list_view.png b/chrome/browser/resources/file_manager/images/files/ui/button_list_view.png
similarity index 100%
rename from chrome/browser/resources/file_manager/images/files/ui/new-ui/button_list_view.png
rename to chrome/browser/resources/file_manager/images/files/ui/button_list_view.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/button_list_view_white.png b/chrome/browser/resources/file_manager/images/files/ui/button_list_view_white.png
new file mode 100644
index 0000000..798df51
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/ui/button_list_view_white.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/new-ui/button_mosaic_view.png b/chrome/browser/resources/file_manager/images/files/ui/button_mosaic_view.png
similarity index 100%
rename from chrome/browser/resources/file_manager/images/files/ui/new-ui/button_mosaic_view.png
rename to chrome/browser/resources/file_manager/images/files/ui/button_mosaic_view.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/button_mosaic_view_white.png b/chrome/browser/resources/file_manager/images/files/ui/button_mosaic_view_white.png
new file mode 100644
index 0000000..9d4d518
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/ui/button_mosaic_view_white.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/close_bar.png b/chrome/browser/resources/file_manager/images/files/ui/close_bar.png
index 69c9017..f723201 100644
--- a/chrome/browser/resources/file_manager/images/files/ui/close_bar.png
+++ b/chrome/browser/resources/file_manager/images/files/ui/close_bar.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/disclosure_arrow_dk_grey.png b/chrome/browser/resources/file_manager/images/files/ui/disclosure_arrow_dk_grey.png
deleted file mode 100644
index dd2f925..0000000
--- a/chrome/browser/resources/file_manager/images/files/ui/disclosure_arrow_dk_grey.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/disclosure_arrow_dk_grey_down.png b/chrome/browser/resources/file_manager/images/files/ui/disclosure_arrow_dk_grey_down.png
deleted file mode 100644
index b1ceb84..0000000
--- a/chrome/browser/resources/file_manager/images/files/ui/disclosure_arrow_dk_grey_down.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/eject.png b/chrome/browser/resources/file_manager/images/files/ui/eject.png
index 731ccdf..dbbdb7f 100644
--- a/chrome/browser/resources/file_manager/images/files/ui/eject.png
+++ b/chrome/browser/resources/file_manager/images/files/ui/eject.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/icon_search.png b/chrome/browser/resources/file_manager/images/files/ui/icon_search.png
deleted file mode 100644
index 505347a..0000000
--- a/chrome/browser/resources/file_manager/images/files/ui/icon_search.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/new-ui/2x/black_folder.png b/chrome/browser/resources/file_manager/images/files/ui/new-ui/2x/black_folder.png
deleted file mode 100644
index f4f1d59..0000000
--- a/chrome/browser/resources/file_manager/images/files/ui/new-ui/2x/black_folder.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/new-ui/2x/button_list_view.png b/chrome/browser/resources/file_manager/images/files/ui/new-ui/2x/button_list_view.png
deleted file mode 100644
index d2185ce..0000000
--- a/chrome/browser/resources/file_manager/images/files/ui/new-ui/2x/button_list_view.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/new-ui/2x/button_list_view_white.png b/chrome/browser/resources/file_manager/images/files/ui/new-ui/2x/button_list_view_white.png
deleted file mode 100644
index 6f637c4..0000000
--- a/chrome/browser/resources/file_manager/images/files/ui/new-ui/2x/button_list_view_white.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/new-ui/2x/button_mosaic_view.png b/chrome/browser/resources/file_manager/images/files/ui/new-ui/2x/button_mosaic_view.png
deleted file mode 100644
index 86313ae..0000000
--- a/chrome/browser/resources/file_manager/images/files/ui/new-ui/2x/button_mosaic_view.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/new-ui/2x/button_mosaic_view_white.png b/chrome/browser/resources/file_manager/images/files/ui/new-ui/2x/button_mosaic_view_white.png
deleted file mode 100644
index ee31e82..0000000
--- a/chrome/browser/resources/file_manager/images/files/ui/new-ui/2x/button_mosaic_view_white.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/new-ui/2x/onbutton_trash.png b/chrome/browser/resources/file_manager/images/files/ui/new-ui/2x/onbutton_trash.png
deleted file mode 100644
index b295f79..0000000
--- a/chrome/browser/resources/file_manager/images/files/ui/new-ui/2x/onbutton_trash.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/new-ui/2x/search_clear.png b/chrome/browser/resources/file_manager/images/files/ui/new-ui/2x/search_clear.png
deleted file mode 100644
index c42a884..0000000
--- a/chrome/browser/resources/file_manager/images/files/ui/new-ui/2x/search_clear.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/new-ui/2x/search_clear_hover.png b/chrome/browser/resources/file_manager/images/files/ui/new-ui/2x/search_clear_hover.png
deleted file mode 100644
index c7166cb..0000000
--- a/chrome/browser/resources/file_manager/images/files/ui/new-ui/2x/search_clear_hover.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/new-ui/2x/search_clear_pressed.png b/chrome/browser/resources/file_manager/images/files/ui/new-ui/2x/search_clear_pressed.png
deleted file mode 100644
index d151fbf..0000000
--- a/chrome/browser/resources/file_manager/images/files/ui/new-ui/2x/search_clear_pressed.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/new-ui/2x/search_icon_active.png b/chrome/browser/resources/file_manager/images/files/ui/new-ui/2x/search_icon_active.png
deleted file mode 100644
index 9791fe6..0000000
--- a/chrome/browser/resources/file_manager/images/files/ui/new-ui/2x/search_icon_active.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/new-ui/2x/search_icon_inactive.png b/chrome/browser/resources/file_manager/images/files/ui/new-ui/2x/search_icon_inactive.png
deleted file mode 100644
index 930ef89..0000000
--- a/chrome/browser/resources/file_manager/images/files/ui/new-ui/2x/search_icon_inactive.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/new-ui/2x/select_checkbox.png b/chrome/browser/resources/file_manager/images/files/ui/new-ui/2x/select_checkbox.png
deleted file mode 100644
index 6504fc1..0000000
--- a/chrome/browser/resources/file_manager/images/files/ui/new-ui/2x/select_checkbox.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/new-ui/2x/select_checkbox_checked.png b/chrome/browser/resources/file_manager/images/files/ui/new-ui/2x/select_checkbox_checked.png
deleted file mode 100644
index e4e477e..0000000
--- a/chrome/browser/resources/file_manager/images/files/ui/new-ui/2x/select_checkbox_checked.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/new-ui/2x/topbar_button_close.png b/chrome/browser/resources/file_manager/images/files/ui/new-ui/2x/topbar_button_close.png
deleted file mode 100644
index 16a0915..0000000
--- a/chrome/browser/resources/file_manager/images/files/ui/new-ui/2x/topbar_button_close.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/new-ui/2x/topbar_button_maximize.png b/chrome/browser/resources/file_manager/images/files/ui/new-ui/2x/topbar_button_maximize.png
deleted file mode 100644
index 4571d62..0000000
--- a/chrome/browser/resources/file_manager/images/files/ui/new-ui/2x/topbar_button_maximize.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/new-ui/2x/topbar_button_settings.png b/chrome/browser/resources/file_manager/images/files/ui/new-ui/2x/topbar_button_settings.png
deleted file mode 100644
index 1905b51..0000000
--- a/chrome/browser/resources/file_manager/images/files/ui/new-ui/2x/topbar_button_settings.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/new-ui/2x/white_folder.png b/chrome/browser/resources/file_manager/images/files/ui/new-ui/2x/white_folder.png
deleted file mode 100644
index 6c16ad9..0000000
--- a/chrome/browser/resources/file_manager/images/files/ui/new-ui/2x/white_folder.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/new-ui/black_folder.png b/chrome/browser/resources/file_manager/images/files/ui/new-ui/black_folder.png
deleted file mode 100644
index 720e832..0000000
--- a/chrome/browser/resources/file_manager/images/files/ui/new-ui/black_folder.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/new-ui/button_list_view_white.png b/chrome/browser/resources/file_manager/images/files/ui/new-ui/button_list_view_white.png
deleted file mode 100644
index 2c5a32c..0000000
--- a/chrome/browser/resources/file_manager/images/files/ui/new-ui/button_list_view_white.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/new-ui/button_mosaic_view_white.png b/chrome/browser/resources/file_manager/images/files/ui/new-ui/button_mosaic_view_white.png
deleted file mode 100644
index 5af9a32..0000000
--- a/chrome/browser/resources/file_manager/images/files/ui/new-ui/button_mosaic_view_white.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/new-ui/onbutton_trash.png b/chrome/browser/resources/file_manager/images/files/ui/new-ui/onbutton_trash.png
deleted file mode 100644
index d704cb2..0000000
--- a/chrome/browser/resources/file_manager/images/files/ui/new-ui/onbutton_trash.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/new-ui/search_clear.png b/chrome/browser/resources/file_manager/images/files/ui/new-ui/search_clear.png
deleted file mode 100644
index 69929d3..0000000
--- a/chrome/browser/resources/file_manager/images/files/ui/new-ui/search_clear.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/new-ui/search_clear_hover.png b/chrome/browser/resources/file_manager/images/files/ui/new-ui/search_clear_hover.png
deleted file mode 100644
index 56df4d5..0000000
--- a/chrome/browser/resources/file_manager/images/files/ui/new-ui/search_clear_hover.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/new-ui/search_clear_pressed.png b/chrome/browser/resources/file_manager/images/files/ui/new-ui/search_clear_pressed.png
deleted file mode 100644
index 7c726b1..0000000
--- a/chrome/browser/resources/file_manager/images/files/ui/new-ui/search_clear_pressed.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/new-ui/search_icon_active.png b/chrome/browser/resources/file_manager/images/files/ui/new-ui/search_icon_active.png
deleted file mode 100644
index a61e72d..0000000
--- a/chrome/browser/resources/file_manager/images/files/ui/new-ui/search_icon_active.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/new-ui/search_icon_inactive.png b/chrome/browser/resources/file_manager/images/files/ui/new-ui/search_icon_inactive.png
deleted file mode 100644
index e574e7d..0000000
--- a/chrome/browser/resources/file_manager/images/files/ui/new-ui/search_icon_inactive.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/new-ui/topbar_button_close.png b/chrome/browser/resources/file_manager/images/files/ui/new-ui/topbar_button_close.png
deleted file mode 100644
index c38b61c..0000000
--- a/chrome/browser/resources/file_manager/images/files/ui/new-ui/topbar_button_close.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/new-ui/topbar_button_maximize.png b/chrome/browser/resources/file_manager/images/files/ui/new-ui/topbar_button_maximize.png
deleted file mode 100644
index f2904ae..0000000
--- a/chrome/browser/resources/file_manager/images/files/ui/new-ui/topbar_button_maximize.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/new-ui/topbar_button_settings.png b/chrome/browser/resources/file_manager/images/files/ui/new-ui/topbar_button_settings.png
deleted file mode 100644
index b935d41..0000000
--- a/chrome/browser/resources/file_manager/images/files/ui/new-ui/topbar_button_settings.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/new-ui/white_folder.png b/chrome/browser/resources/file_manager/images/files/ui/new-ui/white_folder.png
deleted file mode 100644
index 36df268..0000000
--- a/chrome/browser/resources/file_manager/images/files/ui/new-ui/white_folder.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/offline.png b/chrome/browser/resources/file_manager/images/files/ui/offline.png
index 9ebc535..259d3b2 100644
--- a/chrome/browser/resources/file_manager/images/files/ui/offline.png
+++ b/chrome/browser/resources/file_manager/images/files/ui/offline.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/onbutton_trash.png b/chrome/browser/resources/file_manager/images/files/ui/onbutton_trash.png
new file mode 100644
index 0000000..20ab756
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/ui/onbutton_trash.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/pin.png b/chrome/browser/resources/file_manager/images/files/ui/pin.png
deleted file mode 100644
index 38f23cb..0000000
--- a/chrome/browser/resources/file_manager/images/files/ui/pin.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/recent.png b/chrome/browser/resources/file_manager/images/files/ui/recent.png
deleted file mode 100644
index 7f30cfa..0000000
--- a/chrome/browser/resources/file_manager/images/files/ui/recent.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/search_clear.png b/chrome/browser/resources/file_manager/images/files/ui/search_clear.png
index 912df05..6755c4e 100644
--- a/chrome/browser/resources/file_manager/images/files/ui/search_clear.png
+++ b/chrome/browser/resources/file_manager/images/files/ui/search_clear.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/search_clear_hover.png b/chrome/browser/resources/file_manager/images/files/ui/search_clear_hover.png
index c5e1481..bbfd15f 100644
--- a/chrome/browser/resources/file_manager/images/files/ui/search_clear_hover.png
+++ b/chrome/browser/resources/file_manager/images/files/ui/search_clear_hover.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/search_clear_pressed.png b/chrome/browser/resources/file_manager/images/files/ui/search_clear_pressed.png
index cc5bbbe..85f8c11 100644
--- a/chrome/browser/resources/file_manager/images/files/ui/search_clear_pressed.png
+++ b/chrome/browser/resources/file_manager/images/files/ui/search_clear_pressed.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/search_icon_active.png b/chrome/browser/resources/file_manager/images/files/ui/search_icon_active.png
new file mode 100644
index 0000000..f59dfe3
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/ui/search_icon_active.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/search_icon_inactive.png b/chrome/browser/resources/file_manager/images/files/ui/search_icon_inactive.png
new file mode 100644
index 0000000..2f17e7c
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/ui/search_icon_inactive.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/new-ui/select_checkbox.png b/chrome/browser/resources/file_manager/images/files/ui/select_checkbox.png
similarity index 100%
rename from chrome/browser/resources/file_manager/images/files/ui/new-ui/select_checkbox.png
rename to chrome/browser/resources/file_manager/images/files/ui/select_checkbox.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/new-ui/select_checkbox_checked.png b/chrome/browser/resources/file_manager/images/files/ui/select_checkbox_checked.png
similarity index 100%
rename from chrome/browser/resources/file_manager/images/files/ui/new-ui/select_checkbox_checked.png
rename to chrome/browser/resources/file_manager/images/files/ui/select_checkbox_checked.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/settings.svg b/chrome/browser/resources/file_manager/images/files/ui/settings.svg
deleted file mode 100644
index 5e719db..0000000
--- a/chrome/browser/resources/file_manager/images/files/ui/settings.svg
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Generator: Adobe Illustrator 15.0.0, SVG Export Plug-In  -->
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [
-	<!ENTITY ns_flows "http://ns.adobe.com/Flows/1.0/">
-]>
-<svg version="1.1"
-	 xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/"
-	 x="0px" y="0px" width="21px" height="21px" viewBox="0 0 21 21" overflow="visible" enable-background="new 0 0 21 21"
-	 xml:space="preserve">
-<defs>
-</defs>
-<path d="M16.895,11.64C16.96,11.269,17,10.89,17,10.5s-0.04-0.77-0.106-1.14l1.535-1.129l0.183-0.683l-1.5-2.598l-0.684-0.184
-	l-1.738,0.762c-0.581-0.49-1.25-0.875-1.979-1.138L12.5,2.5L12,2H9L8.5,2.499L8.29,4.395C7.562,4.658,6.896,5.043,6.314,5.531
-	L4.571,4.768L3.889,4.951l-1.5,2.598l0.183,0.684l1.535,1.129C4.04,9.731,4,10.111,4,10.5s0.04,0.769,0.106,1.139l-1.535,1.129
-	l-0.183,0.684l1.5,2.598l0.682,0.184l1.744-0.764c0.58,0.488,1.248,0.873,1.975,1.137l0.21,1.896L9,19h3l0.5-0.5l0.21-1.892
-	c0.729-0.263,1.398-0.648,1.979-1.138l1.738,0.762l0.684-0.184l1.499-2.598l-0.181-0.683L16.895,11.64z M14.15,10.5
-	c0,2.016-1.635,3.65-3.65,3.65c-2.016,0-3.65-1.635-3.65-3.65s1.635-3.65,3.65-3.65C12.515,6.85,14.15,8.484,14.15,10.5z"/>
-<rect opacity="0" fill="#4387FD" width="21" height="21"/>
-</svg>
diff --git a/chrome/browser/resources/file_manager/images/files/ui/shared.png b/chrome/browser/resources/file_manager/images/files/ui/shared.png
deleted file mode 100644
index 2c0e161..0000000
--- a/chrome/browser/resources/file_manager/images/files/ui/shared.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/topbar_button_close.png b/chrome/browser/resources/file_manager/images/files/ui/topbar_button_close.png
new file mode 100644
index 0000000..b902560
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/ui/topbar_button_close.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/topbar_button_maximize.png b/chrome/browser/resources/file_manager/images/files/ui/topbar_button_maximize.png
new file mode 100644
index 0000000..3bd557f
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/ui/topbar_button_maximize.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/topbar_button_settings.png b/chrome/browser/resources/file_manager/images/files/ui/topbar_button_settings.png
new file mode 100644
index 0000000..ef0724a
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/ui/topbar_button_settings.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/new-ui/vertical_separator.png b/chrome/browser/resources/file_manager/images/files/ui/vertical_separator.png
similarity index 100%
rename from chrome/browser/resources/file_manager/images/files/ui/new-ui/vertical_separator.png
rename to chrome/browser/resources/file_manager/images/files/ui/vertical_separator.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/view_list_black.png b/chrome/browser/resources/file_manager/images/files/ui/view_list_black.png
deleted file mode 100644
index b350ef1..0000000
--- a/chrome/browser/resources/file_manager/images/files/ui/view_list_black.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/warning_icon_square.png b/chrome/browser/resources/file_manager/images/files/ui/warning_icon_square.png
index d324919..90d6b60 100644
--- a/chrome/browser/resources/file_manager/images/files/ui/warning_icon_square.png
+++ b/chrome/browser/resources/file_manager/images/files/ui/warning_icon_square.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/white_folder.png b/chrome/browser/resources/file_manager/images/files/ui/white_folder.png
new file mode 100644
index 0000000..07b6aa2
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/ui/white_folder.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/2x/archive.png b/chrome/browser/resources/file_manager/images/files/volumes/2x/archive.png
index 681b6a6..b5821d4 100644
--- a/chrome/browser/resources/file_manager/images/files/volumes/2x/archive.png
+++ b/chrome/browser/resources/file_manager/images/files/volumes/2x/archive.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/2x/black_archive.png b/chrome/browser/resources/file_manager/images/files/volumes/2x/black_archive.png
new file mode 100644
index 0000000..6927bdd
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/volumes/2x/black_archive.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/2x/black_downloads.png b/chrome/browser/resources/file_manager/images/files/volumes/2x/black_downloads.png
new file mode 100644
index 0000000..ab37f07
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/volumes/2x/black_downloads.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/2x/black_drive.png b/chrome/browser/resources/file_manager/images/files/volumes/2x/black_drive.png
new file mode 100644
index 0000000..a17a0b1
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/volumes/2x/black_drive.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/2x/black_hdd.png b/chrome/browser/resources/file_manager/images/files/volumes/2x/black_hdd.png
new file mode 100644
index 0000000..e0ec696
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/volumes/2x/black_hdd.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/2x/black_offline.png b/chrome/browser/resources/file_manager/images/files/volumes/2x/black_offline.png
new file mode 100644
index 0000000..87029a9
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/volumes/2x/black_offline.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/2x/black_optical.png b/chrome/browser/resources/file_manager/images/files/volumes/2x/black_optical.png
new file mode 100644
index 0000000..5077474
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/volumes/2x/black_optical.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/2x/black_phone.png b/chrome/browser/resources/file_manager/images/files/volumes/2x/black_phone.png
new file mode 100644
index 0000000..c4521de
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/volumes/2x/black_phone.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/2x/black_recent.png b/chrome/browser/resources/file_manager/images/files/volumes/2x/black_recent.png
new file mode 100644
index 0000000..e1b8621
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/volumes/2x/black_recent.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/2x/black_sd.png b/chrome/browser/resources/file_manager/images/files/volumes/2x/black_sd.png
new file mode 100644
index 0000000..5679089
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/volumes/2x/black_sd.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/2x/black_shared.png b/chrome/browser/resources/file_manager/images/files/volumes/2x/black_shared.png
new file mode 100644
index 0000000..79b9edc
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/volumes/2x/black_shared.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/2x/black_trash.png b/chrome/browser/resources/file_manager/images/files/volumes/2x/black_trash.png
new file mode 100644
index 0000000..67f261f
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/volumes/2x/black_trash.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/2x/black_usb.png b/chrome/browser/resources/file_manager/images/files/volumes/2x/black_usb.png
new file mode 100644
index 0000000..2cceca6
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/volumes/2x/black_usb.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/2x/device_hd.png b/chrome/browser/resources/file_manager/images/files/volumes/2x/device_hd.png
index 6d9dac8..e0ec696 100644
--- a/chrome/browser/resources/file_manager/images/files/volumes/2x/device_hd.png
+++ b/chrome/browser/resources/file_manager/images/files/volumes/2x/device_hd.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/2x/device_optical.png b/chrome/browser/resources/file_manager/images/files/volumes/2x/device_optical.png
index 56b9aa0..5077474 100644
--- a/chrome/browser/resources/file_manager/images/files/volumes/2x/device_optical.png
+++ b/chrome/browser/resources/file_manager/images/files/volumes/2x/device_optical.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/2x/device_sd.png b/chrome/browser/resources/file_manager/images/files/volumes/2x/device_sd.png
index 1b1e941..5679089 100644
--- a/chrome/browser/resources/file_manager/images/files/volumes/2x/device_sd.png
+++ b/chrome/browser/resources/file_manager/images/files/volumes/2x/device_sd.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/2x/device_sd_large.png b/chrome/browser/resources/file_manager/images/files/volumes/2x/device_sd_large.png
index ec69757..6fa0c75 100644
--- a/chrome/browser/resources/file_manager/images/files/volumes/2x/device_sd_large.png
+++ b/chrome/browser/resources/file_manager/images/files/volumes/2x/device_sd_large.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/2x/device_usb.png b/chrome/browser/resources/file_manager/images/files/volumes/2x/device_usb.png
index c3e9921..70e9686 100644
--- a/chrome/browser/resources/file_manager/images/files/volumes/2x/device_usb.png
+++ b/chrome/browser/resources/file_manager/images/files/volumes/2x/device_usb.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/2x/device_usb_large.png b/chrome/browser/resources/file_manager/images/files/volumes/2x/device_usb_large.png
index 4133faf..17a8fee 100644
--- a/chrome/browser/resources/file_manager/images/files/volumes/2x/device_usb_large.png
+++ b/chrome/browser/resources/file_manager/images/files/volumes/2x/device_usb_large.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/2x/downloads.png b/chrome/browser/resources/file_manager/images/files/volumes/2x/downloads.png
index a3c0390..22e6617 100644
--- a/chrome/browser/resources/file_manager/images/files/volumes/2x/downloads.png
+++ b/chrome/browser/resources/file_manager/images/files/volumes/2x/downloads.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/2x/drive.png b/chrome/browser/resources/file_manager/images/files/volumes/2x/drive.png
index fbf0675..a17a0b1 100644
--- a/chrome/browser/resources/file_manager/images/files/volumes/2x/drive.png
+++ b/chrome/browser/resources/file_manager/images/files/volumes/2x/drive.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/2x/drive_offline.png b/chrome/browser/resources/file_manager/images/files/volumes/2x/drive_offline.png
index 800e21d..7598185 100644
--- a/chrome/browser/resources/file_manager/images/files/volumes/2x/drive_offline.png
+++ b/chrome/browser/resources/file_manager/images/files/volumes/2x/drive_offline.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/2x/drive_recent.png b/chrome/browser/resources/file_manager/images/files/volumes/2x/drive_recent.png
index 3dab9f5..756e36a 100644
--- a/chrome/browser/resources/file_manager/images/files/volumes/2x/drive_recent.png
+++ b/chrome/browser/resources/file_manager/images/files/volumes/2x/drive_recent.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/2x/drive_shared.png b/chrome/browser/resources/file_manager/images/files/volumes/2x/drive_shared.png
index ed4c204..c2eb5da 100644
--- a/chrome/browser/resources/file_manager/images/files/volumes/2x/drive_shared.png
+++ b/chrome/browser/resources/file_manager/images/files/volumes/2x/drive_shared.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/2x/folder.png b/chrome/browser/resources/file_manager/images/files/volumes/2x/folder.png
index f4f1d59..01ac492 100644
--- a/chrome/browser/resources/file_manager/images/files/volumes/2x/folder.png
+++ b/chrome/browser/resources/file_manager/images/files/volumes/2x/folder.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/2x/white_archive.png b/chrome/browser/resources/file_manager/images/files/volumes/2x/white_archive.png
new file mode 100644
index 0000000..481c40b
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/volumes/2x/white_archive.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/2x/white_downloads.png b/chrome/browser/resources/file_manager/images/files/volumes/2x/white_downloads.png
new file mode 100644
index 0000000..44a93d5
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/volumes/2x/white_downloads.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/2x/white_drive.png b/chrome/browser/resources/file_manager/images/files/volumes/2x/white_drive.png
new file mode 100644
index 0000000..5f43989
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/volumes/2x/white_drive.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/2x/white_hdd.png b/chrome/browser/resources/file_manager/images/files/volumes/2x/white_hdd.png
new file mode 100644
index 0000000..bc5e8c4
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/volumes/2x/white_hdd.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/2x/white_offline.png b/chrome/browser/resources/file_manager/images/files/volumes/2x/white_offline.png
new file mode 100644
index 0000000..9d65b39
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/volumes/2x/white_offline.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/2x/white_optical.png b/chrome/browser/resources/file_manager/images/files/volumes/2x/white_optical.png
new file mode 100644
index 0000000..c675377
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/volumes/2x/white_optical.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/2x/white_phone.png b/chrome/browser/resources/file_manager/images/files/volumes/2x/white_phone.png
new file mode 100644
index 0000000..2dfb8f2
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/volumes/2x/white_phone.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/2x/white_recent.png b/chrome/browser/resources/file_manager/images/files/volumes/2x/white_recent.png
new file mode 100644
index 0000000..a80eae2
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/volumes/2x/white_recent.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/2x/white_sd.png b/chrome/browser/resources/file_manager/images/files/volumes/2x/white_sd.png
new file mode 100644
index 0000000..282de9a
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/volumes/2x/white_sd.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/2x/white_shared.png b/chrome/browser/resources/file_manager/images/files/volumes/2x/white_shared.png
new file mode 100644
index 0000000..24ea167
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/volumes/2x/white_shared.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/2x/white_trash.png b/chrome/browser/resources/file_manager/images/files/volumes/2x/white_trash.png
new file mode 100644
index 0000000..f6c5ccb
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/volumes/2x/white_trash.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/2x/white_usb.png b/chrome/browser/resources/file_manager/images/files/volumes/2x/white_usb.png
new file mode 100644
index 0000000..f296f4e
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/volumes/2x/white_usb.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/archive.png b/chrome/browser/resources/file_manager/images/files/volumes/archive.png
deleted file mode 100644
index 168be60..0000000
--- a/chrome/browser/resources/file_manager/images/files/volumes/archive.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/black_archive.png b/chrome/browser/resources/file_manager/images/files/volumes/black_archive.png
new file mode 100644
index 0000000..e451420
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/volumes/black_archive.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/black_downloads.png b/chrome/browser/resources/file_manager/images/files/volumes/black_downloads.png
new file mode 100644
index 0000000..e25c875
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/volumes/black_downloads.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/black_drive.png b/chrome/browser/resources/file_manager/images/files/volumes/black_drive.png
new file mode 100644
index 0000000..891ec48
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/volumes/black_drive.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/black_folder.png b/chrome/browser/resources/file_manager/images/files/volumes/black_folder.png
new file mode 100644
index 0000000..539f677
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/volumes/black_folder.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/black_hdd.png b/chrome/browser/resources/file_manager/images/files/volumes/black_hdd.png
new file mode 100644
index 0000000..53c02b4
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/volumes/black_hdd.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/black_offline.png b/chrome/browser/resources/file_manager/images/files/volumes/black_offline.png
new file mode 100644
index 0000000..a07ef0c
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/volumes/black_offline.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/black_optical.png b/chrome/browser/resources/file_manager/images/files/volumes/black_optical.png
new file mode 100644
index 0000000..30a905f
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/volumes/black_optical.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/black_phone.png b/chrome/browser/resources/file_manager/images/files/volumes/black_phone.png
new file mode 100644
index 0000000..aa3aa9d
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/volumes/black_phone.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/black_recent.png b/chrome/browser/resources/file_manager/images/files/volumes/black_recent.png
new file mode 100644
index 0000000..6e5d363
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/volumes/black_recent.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/black_sd.png b/chrome/browser/resources/file_manager/images/files/volumes/black_sd.png
new file mode 100644
index 0000000..f24b4ce
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/volumes/black_sd.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/black_shared.png b/chrome/browser/resources/file_manager/images/files/volumes/black_shared.png
new file mode 100644
index 0000000..63a882f
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/volumes/black_shared.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/black_trash.png b/chrome/browser/resources/file_manager/images/files/volumes/black_trash.png
new file mode 100644
index 0000000..7708ae5
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/volumes/black_trash.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/black_usb.png b/chrome/browser/resources/file_manager/images/files/volumes/black_usb.png
new file mode 100644
index 0000000..ba7ef47
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/volumes/black_usb.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/device_hd.png b/chrome/browser/resources/file_manager/images/files/volumes/device_hd.png
deleted file mode 100644
index cd06b99..0000000
--- a/chrome/browser/resources/file_manager/images/files/volumes/device_hd.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/device_optical.png b/chrome/browser/resources/file_manager/images/files/volumes/device_optical.png
deleted file mode 100644
index 7754c4a..0000000
--- a/chrome/browser/resources/file_manager/images/files/volumes/device_optical.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/device_sd.png b/chrome/browser/resources/file_manager/images/files/volumes/device_sd.png
deleted file mode 100644
index 05c035b..0000000
--- a/chrome/browser/resources/file_manager/images/files/volumes/device_sd.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/device_sd_large.png b/chrome/browser/resources/file_manager/images/files/volumes/device_sd_large.png
index 2026d42..39d2fe9 100644
--- a/chrome/browser/resources/file_manager/images/files/volumes/device_sd_large.png
+++ b/chrome/browser/resources/file_manager/images/files/volumes/device_sd_large.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/device_usb.png b/chrome/browser/resources/file_manager/images/files/volumes/device_usb.png
deleted file mode 100644
index 4d6ca21..0000000
--- a/chrome/browser/resources/file_manager/images/files/volumes/device_usb.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/device_usb_large.png b/chrome/browser/resources/file_manager/images/files/volumes/device_usb_large.png
index e700b9d..6b68508 100644
--- a/chrome/browser/resources/file_manager/images/files/volumes/device_usb_large.png
+++ b/chrome/browser/resources/file_manager/images/files/volumes/device_usb_large.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/downloads.png b/chrome/browser/resources/file_manager/images/files/volumes/downloads.png
deleted file mode 100644
index 49b00a6..0000000
--- a/chrome/browser/resources/file_manager/images/files/volumes/downloads.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/drive.png b/chrome/browser/resources/file_manager/images/files/volumes/drive.png
deleted file mode 100644
index 6f97e26..0000000
--- a/chrome/browser/resources/file_manager/images/files/volumes/drive.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/drive_offline.png b/chrome/browser/resources/file_manager/images/files/volumes/drive_offline.png
deleted file mode 100644
index e3f5ded..0000000
--- a/chrome/browser/resources/file_manager/images/files/volumes/drive_offline.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/drive_recent.png b/chrome/browser/resources/file_manager/images/files/volumes/drive_recent.png
deleted file mode 100644
index 7f30cfa..0000000
--- a/chrome/browser/resources/file_manager/images/files/volumes/drive_recent.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/drive_shared.png b/chrome/browser/resources/file_manager/images/files/volumes/drive_shared.png
deleted file mode 100644
index 2c0e161..0000000
--- a/chrome/browser/resources/file_manager/images/files/volumes/drive_shared.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/folder.png b/chrome/browser/resources/file_manager/images/files/volumes/folder.png
deleted file mode 100644
index 720e832..0000000
--- a/chrome/browser/resources/file_manager/images/files/volumes/folder.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/2x/black_archive.png b/chrome/browser/resources/file_manager/images/files/volumes/new-ui/2x/black_archive.png
deleted file mode 100644
index 681b6a6..0000000
--- a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/2x/black_archive.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/2x/black_downloads.png b/chrome/browser/resources/file_manager/images/files/volumes/new-ui/2x/black_downloads.png
deleted file mode 100644
index a3c0390..0000000
--- a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/2x/black_downloads.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/2x/black_drive.png b/chrome/browser/resources/file_manager/images/files/volumes/new-ui/2x/black_drive.png
deleted file mode 100644
index fbf0675..0000000
--- a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/2x/black_drive.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/2x/black_hdd.png b/chrome/browser/resources/file_manager/images/files/volumes/new-ui/2x/black_hdd.png
deleted file mode 100644
index 6d9dac8..0000000
--- a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/2x/black_hdd.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/2x/black_offline.png b/chrome/browser/resources/file_manager/images/files/volumes/new-ui/2x/black_offline.png
deleted file mode 100644
index 9a49109..0000000
--- a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/2x/black_offline.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/2x/black_optical.png b/chrome/browser/resources/file_manager/images/files/volumes/new-ui/2x/black_optical.png
deleted file mode 100644
index 56b9aa0..0000000
--- a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/2x/black_optical.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/2x/black_phone.png b/chrome/browser/resources/file_manager/images/files/volumes/new-ui/2x/black_phone.png
deleted file mode 100644
index 4305569..0000000
--- a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/2x/black_phone.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/2x/black_recent.png b/chrome/browser/resources/file_manager/images/files/volumes/new-ui/2x/black_recent.png
deleted file mode 100644
index 3dab9f5..0000000
--- a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/2x/black_recent.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/2x/black_sd.png b/chrome/browser/resources/file_manager/images/files/volumes/new-ui/2x/black_sd.png
deleted file mode 100644
index 1b1e941..0000000
--- a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/2x/black_sd.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/2x/black_shared.png b/chrome/browser/resources/file_manager/images/files/volumes/new-ui/2x/black_shared.png
deleted file mode 100644
index eacc3c3..0000000
--- a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/2x/black_shared.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/2x/black_trash.png b/chrome/browser/resources/file_manager/images/files/volumes/new-ui/2x/black_trash.png
deleted file mode 100644
index ea0edd2..0000000
--- a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/2x/black_trash.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/2x/black_usb.png b/chrome/browser/resources/file_manager/images/files/volumes/new-ui/2x/black_usb.png
deleted file mode 100644
index c3e9921..0000000
--- a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/2x/black_usb.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/2x/white_archive.png b/chrome/browser/resources/file_manager/images/files/volumes/new-ui/2x/white_archive.png
deleted file mode 100644
index ebbde23..0000000
--- a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/2x/white_archive.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/2x/white_downloads.png b/chrome/browser/resources/file_manager/images/files/volumes/new-ui/2x/white_downloads.png
deleted file mode 100644
index 5adea77..0000000
--- a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/2x/white_downloads.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/2x/white_drive.png b/chrome/browser/resources/file_manager/images/files/volumes/new-ui/2x/white_drive.png
deleted file mode 100644
index 3037bf6..0000000
--- a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/2x/white_drive.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/2x/white_hdd.png b/chrome/browser/resources/file_manager/images/files/volumes/new-ui/2x/white_hdd.png
deleted file mode 100644
index 1f79d83..0000000
--- a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/2x/white_hdd.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/2x/white_offline.png b/chrome/browser/resources/file_manager/images/files/volumes/new-ui/2x/white_offline.png
deleted file mode 100644
index 64b1bf0..0000000
--- a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/2x/white_offline.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/2x/white_optical.png b/chrome/browser/resources/file_manager/images/files/volumes/new-ui/2x/white_optical.png
deleted file mode 100644
index 71835a8..0000000
--- a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/2x/white_optical.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/2x/white_phone.png b/chrome/browser/resources/file_manager/images/files/volumes/new-ui/2x/white_phone.png
deleted file mode 100644
index e9a671e..0000000
--- a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/2x/white_phone.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/2x/white_recent.png b/chrome/browser/resources/file_manager/images/files/volumes/new-ui/2x/white_recent.png
deleted file mode 100644
index 085129b..0000000
--- a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/2x/white_recent.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/2x/white_sd.png b/chrome/browser/resources/file_manager/images/files/volumes/new-ui/2x/white_sd.png
deleted file mode 100644
index a464785..0000000
--- a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/2x/white_sd.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/2x/white_shared.png b/chrome/browser/resources/file_manager/images/files/volumes/new-ui/2x/white_shared.png
deleted file mode 100644
index 83a97d9..0000000
--- a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/2x/white_shared.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/2x/white_trash.png b/chrome/browser/resources/file_manager/images/files/volumes/new-ui/2x/white_trash.png
deleted file mode 100644
index d84d457..0000000
--- a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/2x/white_trash.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/2x/white_usb.png b/chrome/browser/resources/file_manager/images/files/volumes/new-ui/2x/white_usb.png
deleted file mode 100644
index be3d6b6..0000000
--- a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/2x/white_usb.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/black_archive.png b/chrome/browser/resources/file_manager/images/files/volumes/new-ui/black_archive.png
deleted file mode 100644
index 168be60..0000000
--- a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/black_archive.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/black_downloads.png b/chrome/browser/resources/file_manager/images/files/volumes/new-ui/black_downloads.png
deleted file mode 100644
index 49b00a6..0000000
--- a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/black_downloads.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/black_drive.png b/chrome/browser/resources/file_manager/images/files/volumes/new-ui/black_drive.png
deleted file mode 100644
index 6f97e26..0000000
--- a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/black_drive.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/black_folder.png b/chrome/browser/resources/file_manager/images/files/volumes/new-ui/black_folder.png
deleted file mode 100644
index 720e832..0000000
--- a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/black_folder.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/black_hdd.png b/chrome/browser/resources/file_manager/images/files/volumes/new-ui/black_hdd.png
deleted file mode 100644
index cd06b99..0000000
--- a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/black_hdd.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/black_offline.png b/chrome/browser/resources/file_manager/images/files/volumes/new-ui/black_offline.png
deleted file mode 100644
index e3f5ded..0000000
--- a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/black_offline.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/black_optical.png b/chrome/browser/resources/file_manager/images/files/volumes/new-ui/black_optical.png
deleted file mode 100644
index 7754c4a..0000000
--- a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/black_optical.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/black_phone.png b/chrome/browser/resources/file_manager/images/files/volumes/new-ui/black_phone.png
deleted file mode 100644
index 879f357..0000000
--- a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/black_phone.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/black_recent.png b/chrome/browser/resources/file_manager/images/files/volumes/new-ui/black_recent.png
deleted file mode 100644
index 7f30cfa..0000000
--- a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/black_recent.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/black_sd.png b/chrome/browser/resources/file_manager/images/files/volumes/new-ui/black_sd.png
deleted file mode 100644
index 05c035b..0000000
--- a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/black_sd.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/black_shared.png b/chrome/browser/resources/file_manager/images/files/volumes/new-ui/black_shared.png
deleted file mode 100644
index 2c0e161..0000000
--- a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/black_shared.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/black_trash.png b/chrome/browser/resources/file_manager/images/files/volumes/new-ui/black_trash.png
deleted file mode 100644
index c8884a2..0000000
--- a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/black_trash.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/black_usb.png b/chrome/browser/resources/file_manager/images/files/volumes/new-ui/black_usb.png
deleted file mode 100644
index 4d6ca21..0000000
--- a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/black_usb.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/white_archive.png b/chrome/browser/resources/file_manager/images/files/volumes/new-ui/white_archive.png
deleted file mode 100644
index d1d5ec5..0000000
--- a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/white_archive.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/white_downloads.png b/chrome/browser/resources/file_manager/images/files/volumes/new-ui/white_downloads.png
deleted file mode 100644
index 425a409..0000000
--- a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/white_downloads.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/white_drive.png b/chrome/browser/resources/file_manager/images/files/volumes/new-ui/white_drive.png
deleted file mode 100644
index 5c82040..0000000
--- a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/white_drive.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/white_folder.png b/chrome/browser/resources/file_manager/images/files/volumes/new-ui/white_folder.png
deleted file mode 100644
index 36df268..0000000
--- a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/white_folder.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/white_hdd.png b/chrome/browser/resources/file_manager/images/files/volumes/new-ui/white_hdd.png
deleted file mode 100644
index ec4e69a..0000000
--- a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/white_hdd.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/white_offline.png b/chrome/browser/resources/file_manager/images/files/volumes/new-ui/white_offline.png
deleted file mode 100644
index 1c6b78e..0000000
--- a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/white_offline.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/white_optical.png b/chrome/browser/resources/file_manager/images/files/volumes/new-ui/white_optical.png
deleted file mode 100644
index 9a634ad..0000000
--- a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/white_optical.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/white_recent.png b/chrome/browser/resources/file_manager/images/files/volumes/new-ui/white_recent.png
deleted file mode 100644
index 389b5dd..0000000
--- a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/white_recent.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/white_shared.png b/chrome/browser/resources/file_manager/images/files/volumes/new-ui/white_shared.png
deleted file mode 100644
index 7c6ae4f..0000000
--- a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/white_shared.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/white_archive.png b/chrome/browser/resources/file_manager/images/files/volumes/white_archive.png
new file mode 100644
index 0000000..3b542de
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/volumes/white_archive.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/white_downloads.png b/chrome/browser/resources/file_manager/images/files/volumes/white_downloads.png
new file mode 100644
index 0000000..8b1cfdf
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/volumes/white_downloads.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/white_drive.png b/chrome/browser/resources/file_manager/images/files/volumes/white_drive.png
new file mode 100644
index 0000000..0226fbd
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/volumes/white_drive.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/white_folder.png b/chrome/browser/resources/file_manager/images/files/volumes/white_folder.png
new file mode 100644
index 0000000..07b6aa2
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/volumes/white_folder.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/white_hdd.png b/chrome/browser/resources/file_manager/images/files/volumes/white_hdd.png
new file mode 100644
index 0000000..b7c4a48
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/volumes/white_hdd.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/white_offline.png b/chrome/browser/resources/file_manager/images/files/volumes/white_offline.png
new file mode 100644
index 0000000..503ed67
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/volumes/white_offline.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/white_optical.png b/chrome/browser/resources/file_manager/images/files/volumes/white_optical.png
new file mode 100644
index 0000000..3f13f72
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/volumes/white_optical.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/white_phone.png b/chrome/browser/resources/file_manager/images/files/volumes/white_phone.png
similarity index 100%
rename from chrome/browser/resources/file_manager/images/files/volumes/new-ui/white_phone.png
rename to chrome/browser/resources/file_manager/images/files/volumes/white_phone.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/white_recent.png b/chrome/browser/resources/file_manager/images/files/volumes/white_recent.png
new file mode 100644
index 0000000..23c526a
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/volumes/white_recent.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/white_sd.png b/chrome/browser/resources/file_manager/images/files/volumes/white_sd.png
similarity index 100%
rename from chrome/browser/resources/file_manager/images/files/volumes/new-ui/white_sd.png
rename to chrome/browser/resources/file_manager/images/files/volumes/white_sd.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/white_shared.png b/chrome/browser/resources/file_manager/images/files/volumes/white_shared.png
new file mode 100644
index 0000000..051191e
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/files/volumes/white_shared.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/white_trash.png b/chrome/browser/resources/file_manager/images/files/volumes/white_trash.png
similarity index 100%
rename from chrome/browser/resources/file_manager/images/files/volumes/new-ui/white_trash.png
rename to chrome/browser/resources/file_manager/images/files/volumes/white_trash.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/volumes/new-ui/white_usb.png b/chrome/browser/resources/file_manager/images/files/volumes/white_usb.png
similarity index 100%
rename from chrome/browser/resources/file_manager/images/files/volumes/new-ui/white_usb.png
rename to chrome/browser/resources/file_manager/images/files/volumes/white_usb.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/2x/arrow_left.png b/chrome/browser/resources/file_manager/images/gallery/2x/arrow_left.png
index a53ba28..6e4fb66 100644
--- a/chrome/browser/resources/file_manager/images/gallery/2x/arrow_left.png
+++ b/chrome/browser/resources/file_manager/images/gallery/2x/arrow_left.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/2x/arrow_right.png b/chrome/browser/resources/file_manager/images/gallery/2x/arrow_right.png
index cbc2bd1..6b999c1 100644
--- a/chrome/browser/resources/file_manager/images/gallery/2x/arrow_right.png
+++ b/chrome/browser/resources/file_manager/images/gallery/2x/arrow_right.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/2x/back_to_files.png b/chrome/browser/resources/file_manager/images/gallery/2x/back_to_files.png
index cba6dec..e04d9d3 100644
--- a/chrome/browser/resources/file_manager/images/gallery/2x/back_to_files.png
+++ b/chrome/browser/resources/file_manager/images/gallery/2x/back_to_files.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/2x/bubble_point.png b/chrome/browser/resources/file_manager/images/gallery/2x/bubble_point.png
index 0703116..161e4c0 100644
--- a/chrome/browser/resources/file_manager/images/gallery/2x/bubble_point.png
+++ b/chrome/browser/resources/file_manager/images/gallery/2x/bubble_point.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/2x/butterbar_close_button.png b/chrome/browser/resources/file_manager/images/gallery/2x/butterbar_close_button.png
index 4ec0122..aa6c816 100644
--- a/chrome/browser/resources/file_manager/images/gallery/2x/butterbar_close_button.png
+++ b/chrome/browser/resources/file_manager/images/gallery/2x/butterbar_close_button.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/2x/cursor_crop.png b/chrome/browser/resources/file_manager/images/gallery/2x/cursor_crop.png
index 60816e9..6490950 100644
--- a/chrome/browser/resources/file_manager/images/gallery/2x/cursor_crop.png
+++ b/chrome/browser/resources/file_manager/images/gallery/2x/cursor_crop.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/2x/cursor_leftright.png b/chrome/browser/resources/file_manager/images/gallery/2x/cursor_leftright.png
index 1b7232f..a7ee09c 100644
--- a/chrome/browser/resources/file_manager/images/gallery/2x/cursor_leftright.png
+++ b/chrome/browser/resources/file_manager/images/gallery/2x/cursor_leftright.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/2x/cursor_move.png b/chrome/browser/resources/file_manager/images/gallery/2x/cursor_move.png
index 2f93347..faa3c8a 100644
--- a/chrome/browser/resources/file_manager/images/gallery/2x/cursor_move.png
+++ b/chrome/browser/resources/file_manager/images/gallery/2x/cursor_move.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/2x/cursor_nwse.png b/chrome/browser/resources/file_manager/images/gallery/2x/cursor_nwse.png
index b34ed28..0cd6399 100644
--- a/chrome/browser/resources/file_manager/images/gallery/2x/cursor_nwse.png
+++ b/chrome/browser/resources/file_manager/images/gallery/2x/cursor_nwse.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/2x/cursor_swne.png b/chrome/browser/resources/file_manager/images/gallery/2x/cursor_swne.png
index cc5e2b9..5bdae73 100644
--- a/chrome/browser/resources/file_manager/images/gallery/2x/cursor_swne.png
+++ b/chrome/browser/resources/file_manager/images/gallery/2x/cursor_swne.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/2x/cursor_updown.png b/chrome/browser/resources/file_manager/images/gallery/2x/cursor_updown.png
index e20d130..1e9adfb 100644
--- a/chrome/browser/resources/file_manager/images/gallery/2x/cursor_updown.png
+++ b/chrome/browser/resources/file_manager/images/gallery/2x/cursor_updown.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/2x/icon_1up.png b/chrome/browser/resources/file_manager/images/gallery/2x/icon_1up.png
index d41c095..58cbc28 100644
--- a/chrome/browser/resources/file_manager/images/gallery/2x/icon_1up.png
+++ b/chrome/browser/resources/file_manager/images/gallery/2x/icon_1up.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/2x/icon_1up_selected.png b/chrome/browser/resources/file_manager/images/gallery/2x/icon_1up_selected.png
index 221cc49..a0ca726 100644
--- a/chrome/browser/resources/file_manager/images/gallery/2x/icon_1up_selected.png
+++ b/chrome/browser/resources/file_manager/images/gallery/2x/icon_1up_selected.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/2x/icon_autofix.png b/chrome/browser/resources/file_manager/images/gallery/2x/icon_autofix.png
index b1d7f9f..8ce4917 100644
--- a/chrome/browser/resources/file_manager/images/gallery/2x/icon_autofix.png
+++ b/chrome/browser/resources/file_manager/images/gallery/2x/icon_autofix.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/2x/icon_autofix_selected.png b/chrome/browser/resources/file_manager/images/gallery/2x/icon_autofix_selected.png
index 400826f..8838d5c 100644
--- a/chrome/browser/resources/file_manager/images/gallery/2x/icon_autofix_selected.png
+++ b/chrome/browser/resources/file_manager/images/gallery/2x/icon_autofix_selected.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/2x/icon_brightness.png b/chrome/browser/resources/file_manager/images/gallery/2x/icon_brightness.png
index 65c36c2..ffcd385 100644
--- a/chrome/browser/resources/file_manager/images/gallery/2x/icon_brightness.png
+++ b/chrome/browser/resources/file_manager/images/gallery/2x/icon_brightness.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/2x/icon_brightness_selected.png b/chrome/browser/resources/file_manager/images/gallery/2x/icon_brightness_selected.png
index 007809b..90bf03b 100644
--- a/chrome/browser/resources/file_manager/images/gallery/2x/icon_brightness_selected.png
+++ b/chrome/browser/resources/file_manager/images/gallery/2x/icon_brightness_selected.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/2x/icon_contrast.png b/chrome/browser/resources/file_manager/images/gallery/2x/icon_contrast.png
index 90aec57..eec931d 100644
--- a/chrome/browser/resources/file_manager/images/gallery/2x/icon_contrast.png
+++ b/chrome/browser/resources/file_manager/images/gallery/2x/icon_contrast.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/2x/icon_crop.png b/chrome/browser/resources/file_manager/images/gallery/2x/icon_crop.png
index 1da69fd..7c12fb5 100644
--- a/chrome/browser/resources/file_manager/images/gallery/2x/icon_crop.png
+++ b/chrome/browser/resources/file_manager/images/gallery/2x/icon_crop.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/2x/icon_crop_selected.png b/chrome/browser/resources/file_manager/images/gallery/2x/icon_crop_selected.png
index e9eece7..bb2e9e6 100644
--- a/chrome/browser/resources/file_manager/images/gallery/2x/icon_crop_selected.png
+++ b/chrome/browser/resources/file_manager/images/gallery/2x/icon_crop_selected.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/2x/icon_delete.png b/chrome/browser/resources/file_manager/images/gallery/2x/icon_delete.png
index 2da2506..a55ac6c 100644
--- a/chrome/browser/resources/file_manager/images/gallery/2x/icon_delete.png
+++ b/chrome/browser/resources/file_manager/images/gallery/2x/icon_delete.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/2x/icon_delete_selected.png b/chrome/browser/resources/file_manager/images/gallery/2x/icon_delete_selected.png
index ea00a1b..af54168 100644
--- a/chrome/browser/resources/file_manager/images/gallery/2x/icon_delete_selected.png
+++ b/chrome/browser/resources/file_manager/images/gallery/2x/icon_delete_selected.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/2x/icon_edit.png b/chrome/browser/resources/file_manager/images/gallery/2x/icon_edit.png
index 0502a5d..288bc5b 100644
--- a/chrome/browser/resources/file_manager/images/gallery/2x/icon_edit.png
+++ b/chrome/browser/resources/file_manager/images/gallery/2x/icon_edit.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/2x/icon_edit_selected.png b/chrome/browser/resources/file_manager/images/gallery/2x/icon_edit_selected.png
index a608823..bcf9933 100644
--- a/chrome/browser/resources/file_manager/images/gallery/2x/icon_edit_selected.png
+++ b/chrome/browser/resources/file_manager/images/gallery/2x/icon_edit_selected.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/2x/icon_mosaic.png b/chrome/browser/resources/file_manager/images/gallery/2x/icon_mosaic.png
index eed8a8e..3e1a621 100644
--- a/chrome/browser/resources/file_manager/images/gallery/2x/icon_mosaic.png
+++ b/chrome/browser/resources/file_manager/images/gallery/2x/icon_mosaic.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/2x/icon_mosaic_selected.png b/chrome/browser/resources/file_manager/images/gallery/2x/icon_mosaic_selected.png
index 06214f1..d9e329d 100644
--- a/chrome/browser/resources/file_manager/images/gallery/2x/icon_mosaic_selected.png
+++ b/chrome/browser/resources/file_manager/images/gallery/2x/icon_mosaic_selected.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/2x/icon_print.png b/chrome/browser/resources/file_manager/images/gallery/2x/icon_print.png
new file mode 100644
index 0000000..95923a9
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/gallery/2x/icon_print.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/2x/icon_print_selected.png b/chrome/browser/resources/file_manager/images/gallery/2x/icon_print_selected.png
new file mode 100644
index 0000000..d4ac79f
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/gallery/2x/icon_print_selected.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/2x/icon_redo.png b/chrome/browser/resources/file_manager/images/gallery/2x/icon_redo.png
index 911bb2b..075275d 100644
--- a/chrome/browser/resources/file_manager/images/gallery/2x/icon_redo.png
+++ b/chrome/browser/resources/file_manager/images/gallery/2x/icon_redo.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/2x/icon_redo_selected.png b/chrome/browser/resources/file_manager/images/gallery/2x/icon_redo_selected.png
index fc8c5cb..beed584 100644
--- a/chrome/browser/resources/file_manager/images/gallery/2x/icon_redo_selected.png
+++ b/chrome/browser/resources/file_manager/images/gallery/2x/icon_redo_selected.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/2x/icon_rotate.png b/chrome/browser/resources/file_manager/images/gallery/2x/icon_rotate.png
index eb91968..e7bf684 100644
--- a/chrome/browser/resources/file_manager/images/gallery/2x/icon_rotate.png
+++ b/chrome/browser/resources/file_manager/images/gallery/2x/icon_rotate.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/2x/icon_rotate_left.png b/chrome/browser/resources/file_manager/images/gallery/2x/icon_rotate_left.png
index 4ecb97c..4ebbb68 100644
--- a/chrome/browser/resources/file_manager/images/gallery/2x/icon_rotate_left.png
+++ b/chrome/browser/resources/file_manager/images/gallery/2x/icon_rotate_left.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/2x/icon_rotate_left_selected.png b/chrome/browser/resources/file_manager/images/gallery/2x/icon_rotate_left_selected.png
index 45ba86f..d1b00a7 100644
--- a/chrome/browser/resources/file_manager/images/gallery/2x/icon_rotate_left_selected.png
+++ b/chrome/browser/resources/file_manager/images/gallery/2x/icon_rotate_left_selected.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/2x/icon_rotate_selected.png b/chrome/browser/resources/file_manager/images/gallery/2x/icon_rotate_selected.png
index d60999d..1990a63 100644
--- a/chrome/browser/resources/file_manager/images/gallery/2x/icon_rotate_selected.png
+++ b/chrome/browser/resources/file_manager/images/gallery/2x/icon_rotate_selected.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/2x/icon_share.png b/chrome/browser/resources/file_manager/images/gallery/2x/icon_share.png
index c30463e..b1da6d9 100644
--- a/chrome/browser/resources/file_manager/images/gallery/2x/icon_share.png
+++ b/chrome/browser/resources/file_manager/images/gallery/2x/icon_share.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/2x/icon_share_selected.png b/chrome/browser/resources/file_manager/images/gallery/2x/icon_share_selected.png
index fee6052..b3cd00f 100644
--- a/chrome/browser/resources/file_manager/images/gallery/2x/icon_share_selected.png
+++ b/chrome/browser/resources/file_manager/images/gallery/2x/icon_share_selected.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/2x/icon_slideshow.png b/chrome/browser/resources/file_manager/images/gallery/2x/icon_slideshow.png
index 5b92943..fec87c0 100644
--- a/chrome/browser/resources/file_manager/images/gallery/2x/icon_slideshow.png
+++ b/chrome/browser/resources/file_manager/images/gallery/2x/icon_slideshow.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/2x/icon_slideshow_selected.png b/chrome/browser/resources/file_manager/images/gallery/2x/icon_slideshow_selected.png
index b0a20f4..bde2e41 100644
--- a/chrome/browser/resources/file_manager/images/gallery/2x/icon_slideshow_selected.png
+++ b/chrome/browser/resources/file_manager/images/gallery/2x/icon_slideshow_selected.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/2x/icon_undo.png b/chrome/browser/resources/file_manager/images/gallery/2x/icon_undo.png
index dde66b1..c51fd62 100644
--- a/chrome/browser/resources/file_manager/images/gallery/2x/icon_undo.png
+++ b/chrome/browser/resources/file_manager/images/gallery/2x/icon_undo.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/2x/icon_undo_selected.png b/chrome/browser/resources/file_manager/images/gallery/2x/icon_undo_selected.png
index 4723408..3c838c6 100644
--- a/chrome/browser/resources/file_manager/images/gallery/2x/icon_undo_selected.png
+++ b/chrome/browser/resources/file_manager/images/gallery/2x/icon_undo_selected.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/2x/slider_thumb.png b/chrome/browser/resources/file_manager/images/gallery/2x/slider_thumb.png
index 2554aca..e100da6 100644
--- a/chrome/browser/resources/file_manager/images/gallery/2x/slider_thumb.png
+++ b/chrome/browser/resources/file_manager/images/gallery/2x/slider_thumb.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/2x/slideshow-end.png b/chrome/browser/resources/file_manager/images/gallery/2x/slideshow-end.png
index a1510da..5e19f8d 100644
--- a/chrome/browser/resources/file_manager/images/gallery/2x/slideshow-end.png
+++ b/chrome/browser/resources/file_manager/images/gallery/2x/slideshow-end.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/2x/slideshow-pause.png b/chrome/browser/resources/file_manager/images/gallery/2x/slideshow-pause.png
index 0702bfe..13457d9 100644
--- a/chrome/browser/resources/file_manager/images/gallery/2x/slideshow-pause.png
+++ b/chrome/browser/resources/file_manager/images/gallery/2x/slideshow-pause.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/2x/slideshow-play.png b/chrome/browser/resources/file_manager/images/gallery/2x/slideshow-play.png
index 105573e..aa9bd88 100644
--- a/chrome/browser/resources/file_manager/images/gallery/2x/slideshow-play.png
+++ b/chrome/browser/resources/file_manager/images/gallery/2x/slideshow-play.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/arrow_left.png b/chrome/browser/resources/file_manager/images/gallery/arrow_left.png
index 098a286..85e687a 100644
--- a/chrome/browser/resources/file_manager/images/gallery/arrow_left.png
+++ b/chrome/browser/resources/file_manager/images/gallery/arrow_left.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/arrow_right.png b/chrome/browser/resources/file_manager/images/gallery/arrow_right.png
index 9b7076d..0361556 100644
--- a/chrome/browser/resources/file_manager/images/gallery/arrow_right.png
+++ b/chrome/browser/resources/file_manager/images/gallery/arrow_right.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/back_to_files.png b/chrome/browser/resources/file_manager/images/gallery/back_to_files.png
index c2e898b..96e420a 100644
--- a/chrome/browser/resources/file_manager/images/gallery/back_to_files.png
+++ b/chrome/browser/resources/file_manager/images/gallery/back_to_files.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/bubble_point.png b/chrome/browser/resources/file_manager/images/gallery/bubble_point.png
index d38ffcf..494ddb4 100644
--- a/chrome/browser/resources/file_manager/images/gallery/bubble_point.png
+++ b/chrome/browser/resources/file_manager/images/gallery/bubble_point.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/butterbar_close_button.png b/chrome/browser/resources/file_manager/images/gallery/butterbar_close_button.png
index fe93aa6..bc26727 100644
--- a/chrome/browser/resources/file_manager/images/gallery/butterbar_close_button.png
+++ b/chrome/browser/resources/file_manager/images/gallery/butterbar_close_button.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/cursor_crop.png b/chrome/browser/resources/file_manager/images/gallery/cursor_crop.png
index 63472a5..6084188 100644
--- a/chrome/browser/resources/file_manager/images/gallery/cursor_crop.png
+++ b/chrome/browser/resources/file_manager/images/gallery/cursor_crop.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/cursor_leftright.png b/chrome/browser/resources/file_manager/images/gallery/cursor_leftright.png
index 4b6542f..30eeb03 100644
--- a/chrome/browser/resources/file_manager/images/gallery/cursor_leftright.png
+++ b/chrome/browser/resources/file_manager/images/gallery/cursor_leftright.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/cursor_move.png b/chrome/browser/resources/file_manager/images/gallery/cursor_move.png
index 0f372b8..d1a756d 100644
--- a/chrome/browser/resources/file_manager/images/gallery/cursor_move.png
+++ b/chrome/browser/resources/file_manager/images/gallery/cursor_move.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/cursor_nwse.png b/chrome/browser/resources/file_manager/images/gallery/cursor_nwse.png
index 3067fc1..3f3e33c 100644
--- a/chrome/browser/resources/file_manager/images/gallery/cursor_nwse.png
+++ b/chrome/browser/resources/file_manager/images/gallery/cursor_nwse.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/cursor_swne.png b/chrome/browser/resources/file_manager/images/gallery/cursor_swne.png
index 62276f9..5e34475 100644
--- a/chrome/browser/resources/file_manager/images/gallery/cursor_swne.png
+++ b/chrome/browser/resources/file_manager/images/gallery/cursor_swne.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/cursor_updown.png b/chrome/browser/resources/file_manager/images/gallery/cursor_updown.png
index 09400f4..f3a4224 100644
--- a/chrome/browser/resources/file_manager/images/gallery/cursor_updown.png
+++ b/chrome/browser/resources/file_manager/images/gallery/cursor_updown.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/icon_1up.png b/chrome/browser/resources/file_manager/images/gallery/icon_1up.png
index d8c31fd..546e87a 100644
--- a/chrome/browser/resources/file_manager/images/gallery/icon_1up.png
+++ b/chrome/browser/resources/file_manager/images/gallery/icon_1up.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/icon_1up_selected.png b/chrome/browser/resources/file_manager/images/gallery/icon_1up_selected.png
index 01cc25c..a3043a8 100644
--- a/chrome/browser/resources/file_manager/images/gallery/icon_1up_selected.png
+++ b/chrome/browser/resources/file_manager/images/gallery/icon_1up_selected.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/icon_autofix.png b/chrome/browser/resources/file_manager/images/gallery/icon_autofix.png
index 786cfa2..0fb5b82 100644
--- a/chrome/browser/resources/file_manager/images/gallery/icon_autofix.png
+++ b/chrome/browser/resources/file_manager/images/gallery/icon_autofix.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/icon_autofix_selected.png b/chrome/browser/resources/file_manager/images/gallery/icon_autofix_selected.png
index c55265e..fb5972d 100644
--- a/chrome/browser/resources/file_manager/images/gallery/icon_autofix_selected.png
+++ b/chrome/browser/resources/file_manager/images/gallery/icon_autofix_selected.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/icon_brightness.png b/chrome/browser/resources/file_manager/images/gallery/icon_brightness.png
index 9754fb0..ec9c114 100644
--- a/chrome/browser/resources/file_manager/images/gallery/icon_brightness.png
+++ b/chrome/browser/resources/file_manager/images/gallery/icon_brightness.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/icon_brightness_selected.png b/chrome/browser/resources/file_manager/images/gallery/icon_brightness_selected.png
index 3781f03..6cd4462 100644
--- a/chrome/browser/resources/file_manager/images/gallery/icon_brightness_selected.png
+++ b/chrome/browser/resources/file_manager/images/gallery/icon_brightness_selected.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/icon_contrast.png b/chrome/browser/resources/file_manager/images/gallery/icon_contrast.png
index 7a58059..0188d48 100644
--- a/chrome/browser/resources/file_manager/images/gallery/icon_contrast.png
+++ b/chrome/browser/resources/file_manager/images/gallery/icon_contrast.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/icon_crop.png b/chrome/browser/resources/file_manager/images/gallery/icon_crop.png
index 111b550..efff5ba 100644
--- a/chrome/browser/resources/file_manager/images/gallery/icon_crop.png
+++ b/chrome/browser/resources/file_manager/images/gallery/icon_crop.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/icon_crop_selected.png b/chrome/browser/resources/file_manager/images/gallery/icon_crop_selected.png
index 90c0d31..18b8317 100644
--- a/chrome/browser/resources/file_manager/images/gallery/icon_crop_selected.png
+++ b/chrome/browser/resources/file_manager/images/gallery/icon_crop_selected.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/icon_delete.png b/chrome/browser/resources/file_manager/images/gallery/icon_delete.png
index 5a32b6a..efb132a 100644
--- a/chrome/browser/resources/file_manager/images/gallery/icon_delete.png
+++ b/chrome/browser/resources/file_manager/images/gallery/icon_delete.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/icon_delete_selected.png b/chrome/browser/resources/file_manager/images/gallery/icon_delete_selected.png
index 45fe59e..f2f88d8 100644
--- a/chrome/browser/resources/file_manager/images/gallery/icon_delete_selected.png
+++ b/chrome/browser/resources/file_manager/images/gallery/icon_delete_selected.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/icon_edit.png b/chrome/browser/resources/file_manager/images/gallery/icon_edit.png
index 599dd43..fc72ecf 100644
--- a/chrome/browser/resources/file_manager/images/gallery/icon_edit.png
+++ b/chrome/browser/resources/file_manager/images/gallery/icon_edit.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/icon_edit_selected.png b/chrome/browser/resources/file_manager/images/gallery/icon_edit_selected.png
index 060e41c..61540b5 100644
--- a/chrome/browser/resources/file_manager/images/gallery/icon_edit_selected.png
+++ b/chrome/browser/resources/file_manager/images/gallery/icon_edit_selected.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/icon_mosaic.png b/chrome/browser/resources/file_manager/images/gallery/icon_mosaic.png
index 5291a42..6e49d3c 100644
--- a/chrome/browser/resources/file_manager/images/gallery/icon_mosaic.png
+++ b/chrome/browser/resources/file_manager/images/gallery/icon_mosaic.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/icon_mosaic_selected.png b/chrome/browser/resources/file_manager/images/gallery/icon_mosaic_selected.png
index a17b4c0..86edb6e 100644
--- a/chrome/browser/resources/file_manager/images/gallery/icon_mosaic_selected.png
+++ b/chrome/browser/resources/file_manager/images/gallery/icon_mosaic_selected.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/icon_print.png b/chrome/browser/resources/file_manager/images/gallery/icon_print.png
new file mode 100644
index 0000000..ec5418e
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/gallery/icon_print.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/icon_print_selected.png b/chrome/browser/resources/file_manager/images/gallery/icon_print_selected.png
new file mode 100644
index 0000000..89e302e
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/gallery/icon_print_selected.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/icon_redo.png b/chrome/browser/resources/file_manager/images/gallery/icon_redo.png
index 113a8ea..7b4703b 100644
--- a/chrome/browser/resources/file_manager/images/gallery/icon_redo.png
+++ b/chrome/browser/resources/file_manager/images/gallery/icon_redo.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/icon_redo_selected.png b/chrome/browser/resources/file_manager/images/gallery/icon_redo_selected.png
index b0d6b9b..0022a13 100644
--- a/chrome/browser/resources/file_manager/images/gallery/icon_redo_selected.png
+++ b/chrome/browser/resources/file_manager/images/gallery/icon_redo_selected.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/icon_rotate.png b/chrome/browser/resources/file_manager/images/gallery/icon_rotate.png
index d474022..c60f258 100644
--- a/chrome/browser/resources/file_manager/images/gallery/icon_rotate.png
+++ b/chrome/browser/resources/file_manager/images/gallery/icon_rotate.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/icon_rotate_left.png b/chrome/browser/resources/file_manager/images/gallery/icon_rotate_left.png
index 3fcbe71..3f102f3 100644
--- a/chrome/browser/resources/file_manager/images/gallery/icon_rotate_left.png
+++ b/chrome/browser/resources/file_manager/images/gallery/icon_rotate_left.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/icon_rotate_left_selected.png b/chrome/browser/resources/file_manager/images/gallery/icon_rotate_left_selected.png
index ebd9f16..1e4c1d6 100644
--- a/chrome/browser/resources/file_manager/images/gallery/icon_rotate_left_selected.png
+++ b/chrome/browser/resources/file_manager/images/gallery/icon_rotate_left_selected.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/icon_rotate_selected.png b/chrome/browser/resources/file_manager/images/gallery/icon_rotate_selected.png
index a346263..445350f 100644
--- a/chrome/browser/resources/file_manager/images/gallery/icon_rotate_selected.png
+++ b/chrome/browser/resources/file_manager/images/gallery/icon_rotate_selected.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/icon_share.png b/chrome/browser/resources/file_manager/images/gallery/icon_share.png
index 637b706..36bb221 100644
--- a/chrome/browser/resources/file_manager/images/gallery/icon_share.png
+++ b/chrome/browser/resources/file_manager/images/gallery/icon_share.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/icon_share_selected.png b/chrome/browser/resources/file_manager/images/gallery/icon_share_selected.png
index 19c9207..438e8a2 100644
--- a/chrome/browser/resources/file_manager/images/gallery/icon_share_selected.png
+++ b/chrome/browser/resources/file_manager/images/gallery/icon_share_selected.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/icon_slideshow.png b/chrome/browser/resources/file_manager/images/gallery/icon_slideshow.png
index 6dd5018..72763d4 100644
--- a/chrome/browser/resources/file_manager/images/gallery/icon_slideshow.png
+++ b/chrome/browser/resources/file_manager/images/gallery/icon_slideshow.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/icon_slideshow_selected.png b/chrome/browser/resources/file_manager/images/gallery/icon_slideshow_selected.png
index 1fad233..4f80a48 100644
--- a/chrome/browser/resources/file_manager/images/gallery/icon_slideshow_selected.png
+++ b/chrome/browser/resources/file_manager/images/gallery/icon_slideshow_selected.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/icon_undo.png b/chrome/browser/resources/file_manager/images/gallery/icon_undo.png
index 14d9f92..333c455 100644
--- a/chrome/browser/resources/file_manager/images/gallery/icon_undo.png
+++ b/chrome/browser/resources/file_manager/images/gallery/icon_undo.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/icon_undo_selected.png b/chrome/browser/resources/file_manager/images/gallery/icon_undo_selected.png
index 2c0dd0e..d5d13a7 100644
--- a/chrome/browser/resources/file_manager/images/gallery/icon_undo_selected.png
+++ b/chrome/browser/resources/file_manager/images/gallery/icon_undo_selected.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/slider_thumb.png b/chrome/browser/resources/file_manager/images/gallery/slider_thumb.png
index 0914856..cb2d712 100644
--- a/chrome/browser/resources/file_manager/images/gallery/slider_thumb.png
+++ b/chrome/browser/resources/file_manager/images/gallery/slider_thumb.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/slideshow-end.png b/chrome/browser/resources/file_manager/images/gallery/slideshow-end.png
index d0a4ce3..f437111 100644
--- a/chrome/browser/resources/file_manager/images/gallery/slideshow-end.png
+++ b/chrome/browser/resources/file_manager/images/gallery/slideshow-end.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/slideshow-pause.png b/chrome/browser/resources/file_manager/images/gallery/slideshow-pause.png
index bbf6181..ad3633f 100644
--- a/chrome/browser/resources/file_manager/images/gallery/slideshow-pause.png
+++ b/chrome/browser/resources/file_manager/images/gallery/slideshow-pause.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/gallery/slideshow-play.png b/chrome/browser/resources/file_manager/images/gallery/slideshow-play.png
index 4e5ac86..f949121 100644
--- a/chrome/browser/resources/file_manager/images/gallery/slideshow-play.png
+++ b/chrome/browser/resources/file_manager/images/gallery/slideshow-play.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/icon128.png b/chrome/browser/resources/file_manager/images/icon128.png
index 2c6acb6..d4c6c55 100644
--- a/chrome/browser/resources/file_manager/images/icon128.png
+++ b/chrome/browser/resources/file_manager/images/icon128.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/icon16.png b/chrome/browser/resources/file_manager/images/icon16.png
index e05944e..dc3b8d8 100644
--- a/chrome/browser/resources/file_manager/images/icon16.png
+++ b/chrome/browser/resources/file_manager/images/icon16.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/icon256.png b/chrome/browser/resources/file_manager/images/icon256.png
new file mode 100644
index 0000000..2e50e0f
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/icon256.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/icon32.png b/chrome/browser/resources/file_manager/images/icon32.png
index 739aa02..47b8a55 100644
--- a/chrome/browser/resources/file_manager/images/icon32.png
+++ b/chrome/browser/resources/file_manager/images/icon32.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/icon48.png b/chrome/browser/resources/file_manager/images/icon48.png
new file mode 100644
index 0000000..b3c7dbf
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/icon48.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/icon64.png b/chrome/browser/resources/file_manager/images/icon64.png
index 941073a..3130c1c 100644
--- a/chrome/browser/resources/file_manager/images/icon64.png
+++ b/chrome/browser/resources/file_manager/images/icon64.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/icon96.png b/chrome/browser/resources/file_manager/images/icon96.png
new file mode 100644
index 0000000..fdc1ab1
--- /dev/null
+++ b/chrome/browser/resources/file_manager/images/icon96.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/2x/audio_player.png b/chrome/browser/resources/file_manager/images/media/2x/audio_player.png
index c78b24c..ce5fa1a 100644
--- a/chrome/browser/resources/file_manager/images/media/2x/audio_player.png
+++ b/chrome/browser/resources/file_manager/images/media/2x/audio_player.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/2x/drive.png b/chrome/browser/resources/file_manager/images/media/2x/drive.png
index 1cb63a3..e3b7973 100644
--- a/chrome/browser/resources/file_manager/images/media/2x/drive.png
+++ b/chrome/browser/resources/file_manager/images/media/2x/drive.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/2x/error.png b/chrome/browser/resources/file_manager/images/media/2x/error.png
index 1e08991..3c3213e 100644
--- a/chrome/browser/resources/file_manager/images/media/2x/error.png
+++ b/chrome/browser/resources/file_manager/images/media/2x/error.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/2x/media_close.png b/chrome/browser/resources/file_manager/images/media/2x/media_close.png
index c6f9014..2e19603 100644
--- a/chrome/browser/resources/file_manager/images/media/2x/media_close.png
+++ b/chrome/browser/resources/file_manager/images/media/2x/media_close.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/2x/media_collapse.png b/chrome/browser/resources/file_manager/images/media/2x/media_collapse.png
index df85111..a940061 100644
--- a/chrome/browser/resources/file_manager/images/media/2x/media_collapse.png
+++ b/chrome/browser/resources/file_manager/images/media/2x/media_collapse.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/2x/media_expand.png b/chrome/browser/resources/file_manager/images/media/2x/media_expand.png
index 5abe382..20c2340 100644
--- a/chrome/browser/resources/file_manager/images/media/2x/media_expand.png
+++ b/chrome/browser/resources/file_manager/images/media/2x/media_expand.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/2x/media_fullscreen.png b/chrome/browser/resources/file_manager/images/media/2x/media_fullscreen.png
index c91381e..090c825 100644
--- a/chrome/browser/resources/file_manager/images/media/2x/media_fullscreen.png
+++ b/chrome/browser/resources/file_manager/images/media/2x/media_fullscreen.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/2x/media_fullscreen_disabled.png b/chrome/browser/resources/file_manager/images/media/2x/media_fullscreen_disabled.png
index 256ce8e..96b3f63 100644
--- a/chrome/browser/resources/file_manager/images/media/2x/media_fullscreen_disabled.png
+++ b/chrome/browser/resources/file_manager/images/media/2x/media_fullscreen_disabled.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/2x/media_fullscreen_down.png b/chrome/browser/resources/file_manager/images/media/2x/media_fullscreen_down.png
index ed5bf65..17da8eb 100644
--- a/chrome/browser/resources/file_manager/images/media/2x/media_fullscreen_down.png
+++ b/chrome/browser/resources/file_manager/images/media/2x/media_fullscreen_down.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/2x/media_fullscreen_hover.png b/chrome/browser/resources/file_manager/images/media/2x/media_fullscreen_hover.png
index ba2bad5..25daa4f 100644
--- a/chrome/browser/resources/file_manager/images/media/2x/media_fullscreen_hover.png
+++ b/chrome/browser/resources/file_manager/images/media/2x/media_fullscreen_hover.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/2x/media_loop.png b/chrome/browser/resources/file_manager/images/media/2x/media_loop.png
index 4a9a00a..6bea029 100644
--- a/chrome/browser/resources/file_manager/images/media/2x/media_loop.png
+++ b/chrome/browser/resources/file_manager/images/media/2x/media_loop.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/2x/media_loop_down.png b/chrome/browser/resources/file_manager/images/media/2x/media_loop_down.png
index 411669d..9559554 100644
--- a/chrome/browser/resources/file_manager/images/media/2x/media_loop_down.png
+++ b/chrome/browser/resources/file_manager/images/media/2x/media_loop_down.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/2x/media_loop_hover.png b/chrome/browser/resources/file_manager/images/media/2x/media_loop_hover.png
index a4af6db..cb2af67 100644
--- a/chrome/browser/resources/file_manager/images/media/2x/media_loop_hover.png
+++ b/chrome/browser/resources/file_manager/images/media/2x/media_loop_hover.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/2x/media_next.png b/chrome/browser/resources/file_manager/images/media/2x/media_next.png
index e656e25..012af92 100644
--- a/chrome/browser/resources/file_manager/images/media/2x/media_next.png
+++ b/chrome/browser/resources/file_manager/images/media/2x/media_next.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/2x/media_next_down.png b/chrome/browser/resources/file_manager/images/media/2x/media_next_down.png
index 235a325..79a370b 100644
--- a/chrome/browser/resources/file_manager/images/media/2x/media_next_down.png
+++ b/chrome/browser/resources/file_manager/images/media/2x/media_next_down.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/2x/media_next_hover.png b/chrome/browser/resources/file_manager/images/media/2x/media_next_hover.png
index c9f053b..8705d69 100644
--- a/chrome/browser/resources/file_manager/images/media/2x/media_next_hover.png
+++ b/chrome/browser/resources/file_manager/images/media/2x/media_next_hover.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/2x/media_pause.png b/chrome/browser/resources/file_manager/images/media/2x/media_pause.png
index c254581..acebff9 100644
--- a/chrome/browser/resources/file_manager/images/media/2x/media_pause.png
+++ b/chrome/browser/resources/file_manager/images/media/2x/media_pause.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/2x/media_pause_audio.png b/chrome/browser/resources/file_manager/images/media/2x/media_pause_audio.png
index 15c96c5..7489a7e 100644
--- a/chrome/browser/resources/file_manager/images/media/2x/media_pause_audio.png
+++ b/chrome/browser/resources/file_manager/images/media/2x/media_pause_audio.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/2x/media_pause_audio_down.png b/chrome/browser/resources/file_manager/images/media/2x/media_pause_audio_down.png
index f481c70..eb22b95 100644
--- a/chrome/browser/resources/file_manager/images/media/2x/media_pause_audio_down.png
+++ b/chrome/browser/resources/file_manager/images/media/2x/media_pause_audio_down.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/2x/media_pause_audio_hover.png b/chrome/browser/resources/file_manager/images/media/2x/media_pause_audio_hover.png
index 028792e..944b189 100644
--- a/chrome/browser/resources/file_manager/images/media/2x/media_pause_audio_hover.png
+++ b/chrome/browser/resources/file_manager/images/media/2x/media_pause_audio_hover.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/2x/media_pause_down.png b/chrome/browser/resources/file_manager/images/media/2x/media_pause_down.png
index 02d3d94..6f8f494 100644
--- a/chrome/browser/resources/file_manager/images/media/2x/media_pause_down.png
+++ b/chrome/browser/resources/file_manager/images/media/2x/media_pause_down.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/2x/media_pause_hover.png b/chrome/browser/resources/file_manager/images/media/2x/media_pause_hover.png
index 876963c..beb86f2 100644
--- a/chrome/browser/resources/file_manager/images/media/2x/media_pause_hover.png
+++ b/chrome/browser/resources/file_manager/images/media/2x/media_pause_hover.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/2x/media_play.png b/chrome/browser/resources/file_manager/images/media/2x/media_play.png
index 23fe41c..28e8a25 100644
--- a/chrome/browser/resources/file_manager/images/media/2x/media_play.png
+++ b/chrome/browser/resources/file_manager/images/media/2x/media_play.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/2x/media_play_audio.png b/chrome/browser/resources/file_manager/images/media/2x/media_play_audio.png
index 6e4da5a..b175762 100644
--- a/chrome/browser/resources/file_manager/images/media/2x/media_play_audio.png
+++ b/chrome/browser/resources/file_manager/images/media/2x/media_play_audio.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/2x/media_play_audio_down.png b/chrome/browser/resources/file_manager/images/media/2x/media_play_audio_down.png
index 8bee6e6..01dcc46 100644
--- a/chrome/browser/resources/file_manager/images/media/2x/media_play_audio_down.png
+++ b/chrome/browser/resources/file_manager/images/media/2x/media_play_audio_down.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/2x/media_play_audio_hover.png b/chrome/browser/resources/file_manager/images/media/2x/media_play_audio_hover.png
index 4c4e18a..c64070f 100644
--- a/chrome/browser/resources/file_manager/images/media/2x/media_play_audio_hover.png
+++ b/chrome/browser/resources/file_manager/images/media/2x/media_play_audio_hover.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/2x/media_play_disabled.png b/chrome/browser/resources/file_manager/images/media/2x/media_play_disabled.png
index 114db5a..9d0dd93 100644
--- a/chrome/browser/resources/file_manager/images/media/2x/media_play_disabled.png
+++ b/chrome/browser/resources/file_manager/images/media/2x/media_play_disabled.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/2x/media_play_down.png b/chrome/browser/resources/file_manager/images/media/2x/media_play_down.png
index 21d0ea4..7c68787 100644
--- a/chrome/browser/resources/file_manager/images/media/2x/media_play_down.png
+++ b/chrome/browser/resources/file_manager/images/media/2x/media_play_down.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/2x/media_play_hover.png b/chrome/browser/resources/file_manager/images/media/2x/media_play_hover.png
index 41a7fae..28ca18b 100644
--- a/chrome/browser/resources/file_manager/images/media/2x/media_play_hover.png
+++ b/chrome/browser/resources/file_manager/images/media/2x/media_play_hover.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/2x/media_previous.png b/chrome/browser/resources/file_manager/images/media/2x/media_previous.png
index 6b38df8..6c8d640 100644
--- a/chrome/browser/resources/file_manager/images/media/2x/media_previous.png
+++ b/chrome/browser/resources/file_manager/images/media/2x/media_previous.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/2x/media_previous_down.png b/chrome/browser/resources/file_manager/images/media/2x/media_previous_down.png
index 7143915..9474158 100644
--- a/chrome/browser/resources/file_manager/images/media/2x/media_previous_down.png
+++ b/chrome/browser/resources/file_manager/images/media/2x/media_previous_down.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/2x/media_previous_hover.png b/chrome/browser/resources/file_manager/images/media/2x/media_previous_hover.png
index b481be9..05f5b4a 100644
--- a/chrome/browser/resources/file_manager/images/media/2x/media_previous_hover.png
+++ b/chrome/browser/resources/file_manager/images/media/2x/media_previous_hover.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/2x/media_slider_thumb.png b/chrome/browser/resources/file_manager/images/media/2x/media_slider_thumb.png
index c84ca8c..5a130bd 100644
--- a/chrome/browser/resources/file_manager/images/media/2x/media_slider_thumb.png
+++ b/chrome/browser/resources/file_manager/images/media/2x/media_slider_thumb.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/2x/media_slider_thumb_down.png b/chrome/browser/resources/file_manager/images/media/2x/media_slider_thumb_down.png
index 67a1be4..931850f 100644
--- a/chrome/browser/resources/file_manager/images/media/2x/media_slider_thumb_down.png
+++ b/chrome/browser/resources/file_manager/images/media/2x/media_slider_thumb_down.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/2x/media_slider_thumb_hover.png b/chrome/browser/resources/file_manager/images/media/2x/media_slider_thumb_hover.png
index 6a374f3..9fe30ef 100644
--- a/chrome/browser/resources/file_manager/images/media/2x/media_slider_thumb_hover.png
+++ b/chrome/browser/resources/file_manager/images/media/2x/media_slider_thumb_hover.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/2x/media_sound_disabled.png b/chrome/browser/resources/file_manager/images/media/2x/media_sound_disabled.png
index f1f6a2d..acbaa71 100644
--- a/chrome/browser/resources/file_manager/images/media/2x/media_sound_disabled.png
+++ b/chrome/browser/resources/file_manager/images/media/2x/media_sound_disabled.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/2x/media_sound_disabled_down.png b/chrome/browser/resources/file_manager/images/media/2x/media_sound_disabled_down.png
index 4204819..f594f47 100644
--- a/chrome/browser/resources/file_manager/images/media/2x/media_sound_disabled_down.png
+++ b/chrome/browser/resources/file_manager/images/media/2x/media_sound_disabled_down.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/2x/media_sound_disabled_hover.png b/chrome/browser/resources/file_manager/images/media/2x/media_sound_disabled_hover.png
index f5ae65c..f4cc7b3 100644
--- a/chrome/browser/resources/file_manager/images/media/2x/media_sound_disabled_hover.png
+++ b/chrome/browser/resources/file_manager/images/media/2x/media_sound_disabled_hover.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/2x/media_sound_full.png b/chrome/browser/resources/file_manager/images/media/2x/media_sound_full.png
index 0dd6111..a093e9f 100644
--- a/chrome/browser/resources/file_manager/images/media/2x/media_sound_full.png
+++ b/chrome/browser/resources/file_manager/images/media/2x/media_sound_full.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/2x/media_sound_full_disabled.png b/chrome/browser/resources/file_manager/images/media/2x/media_sound_full_disabled.png
index 142093e..56635f1 100644
--- a/chrome/browser/resources/file_manager/images/media/2x/media_sound_full_disabled.png
+++ b/chrome/browser/resources/file_manager/images/media/2x/media_sound_full_disabled.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/2x/media_sound_full_down.png b/chrome/browser/resources/file_manager/images/media/2x/media_sound_full_down.png
index b7e8e40..90a41ba 100644
--- a/chrome/browser/resources/file_manager/images/media/2x/media_sound_full_down.png
+++ b/chrome/browser/resources/file_manager/images/media/2x/media_sound_full_down.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/2x/media_sound_full_hover.png b/chrome/browser/resources/file_manager/images/media/2x/media_sound_full_hover.png
index 1491a48..e617eab 100644
--- a/chrome/browser/resources/file_manager/images/media/2x/media_sound_full_hover.png
+++ b/chrome/browser/resources/file_manager/images/media/2x/media_sound_full_hover.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/2x/media_sound_level1.png b/chrome/browser/resources/file_manager/images/media/2x/media_sound_level1.png
index abe4ad6..25904c0 100644
--- a/chrome/browser/resources/file_manager/images/media/2x/media_sound_level1.png
+++ b/chrome/browser/resources/file_manager/images/media/2x/media_sound_level1.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/2x/media_sound_level1_down.png b/chrome/browser/resources/file_manager/images/media/2x/media_sound_level1_down.png
index b79992b..0ba2886 100644
--- a/chrome/browser/resources/file_manager/images/media/2x/media_sound_level1_down.png
+++ b/chrome/browser/resources/file_manager/images/media/2x/media_sound_level1_down.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/2x/media_sound_level1_hover.png b/chrome/browser/resources/file_manager/images/media/2x/media_sound_level1_hover.png
index 1fc2f7c..be56fc1 100644
--- a/chrome/browser/resources/file_manager/images/media/2x/media_sound_level1_hover.png
+++ b/chrome/browser/resources/file_manager/images/media/2x/media_sound_level1_hover.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/2x/media_sound_level2.png b/chrome/browser/resources/file_manager/images/media/2x/media_sound_level2.png
index d0f307f..24f7ea8 100644
--- a/chrome/browser/resources/file_manager/images/media/2x/media_sound_level2.png
+++ b/chrome/browser/resources/file_manager/images/media/2x/media_sound_level2.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/2x/media_sound_level2_down.png b/chrome/browser/resources/file_manager/images/media/2x/media_sound_level2_down.png
index cf45b23..34fce54 100644
--- a/chrome/browser/resources/file_manager/images/media/2x/media_sound_level2_down.png
+++ b/chrome/browser/resources/file_manager/images/media/2x/media_sound_level2_down.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/2x/media_sound_level2_hover.png b/chrome/browser/resources/file_manager/images/media/2x/media_sound_level2_hover.png
index d572491..9966a5e 100644
--- a/chrome/browser/resources/file_manager/images/media/2x/media_sound_level2_hover.png
+++ b/chrome/browser/resources/file_manager/images/media/2x/media_sound_level2_hover.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/2x/media_volume_slider_thumb.png b/chrome/browser/resources/file_manager/images/media/2x/media_volume_slider_thumb.png
index 42f7813..c518743 100644
--- a/chrome/browser/resources/file_manager/images/media/2x/media_volume_slider_thumb.png
+++ b/chrome/browser/resources/file_manager/images/media/2x/media_volume_slider_thumb.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/2x/media_volume_slider_thumb_down.png b/chrome/browser/resources/file_manager/images/media/2x/media_volume_slider_thumb_down.png
index fc24add..7967b2d 100644
--- a/chrome/browser/resources/file_manager/images/media/2x/media_volume_slider_thumb_down.png
+++ b/chrome/browser/resources/file_manager/images/media/2x/media_volume_slider_thumb_down.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/2x/media_volume_slider_thumb_hover.png b/chrome/browser/resources/file_manager/images/media/2x/media_volume_slider_thumb_hover.png
index 349665e..ae16119 100644
--- a/chrome/browser/resources/file_manager/images/media/2x/media_volume_slider_thumb_hover.png
+++ b/chrome/browser/resources/file_manager/images/media/2x/media_volume_slider_thumb_hover.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/2x/watch.png b/chrome/browser/resources/file_manager/images/media/2x/watch.png
index 732d4dd..f47751b 100644
--- a/chrome/browser/resources/file_manager/images/media/2x/watch.png
+++ b/chrome/browser/resources/file_manager/images/media/2x/watch.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/audio_player.png b/chrome/browser/resources/file_manager/images/media/audio_player.png
index 68d4a06..9134bde 100644
--- a/chrome/browser/resources/file_manager/images/media/audio_player.png
+++ b/chrome/browser/resources/file_manager/images/media/audio_player.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/drive.png b/chrome/browser/resources/file_manager/images/media/drive.png
index 8d09e30..8f4b64e 100644
--- a/chrome/browser/resources/file_manager/images/media/drive.png
+++ b/chrome/browser/resources/file_manager/images/media/drive.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/error.png b/chrome/browser/resources/file_manager/images/media/error.png
index ee2a851..125c0b7 100644
--- a/chrome/browser/resources/file_manager/images/media/error.png
+++ b/chrome/browser/resources/file_manager/images/media/error.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/media_close.png b/chrome/browser/resources/file_manager/images/media/media_close.png
index d15a815..5980ea7 100644
--- a/chrome/browser/resources/file_manager/images/media/media_close.png
+++ b/chrome/browser/resources/file_manager/images/media/media_close.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/media_collapse.png b/chrome/browser/resources/file_manager/images/media/media_collapse.png
index 4e173c7..3ab1add 100644
--- a/chrome/browser/resources/file_manager/images/media/media_collapse.png
+++ b/chrome/browser/resources/file_manager/images/media/media_collapse.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/media_expand.png b/chrome/browser/resources/file_manager/images/media/media_expand.png
index 31df0d2..a228fbd 100644
--- a/chrome/browser/resources/file_manager/images/media/media_expand.png
+++ b/chrome/browser/resources/file_manager/images/media/media_expand.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/media_fullscreen.png b/chrome/browser/resources/file_manager/images/media/media_fullscreen.png
index 900e0f5..24f2ecf 100644
--- a/chrome/browser/resources/file_manager/images/media/media_fullscreen.png
+++ b/chrome/browser/resources/file_manager/images/media/media_fullscreen.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/media_fullscreen_disabled.png b/chrome/browser/resources/file_manager/images/media/media_fullscreen_disabled.png
index 7c56e0d..bf74390 100644
--- a/chrome/browser/resources/file_manager/images/media/media_fullscreen_disabled.png
+++ b/chrome/browser/resources/file_manager/images/media/media_fullscreen_disabled.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/media_fullscreen_down.png b/chrome/browser/resources/file_manager/images/media/media_fullscreen_down.png
index ff4e453..dd318ce 100644
--- a/chrome/browser/resources/file_manager/images/media/media_fullscreen_down.png
+++ b/chrome/browser/resources/file_manager/images/media/media_fullscreen_down.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/media_fullscreen_hover.png b/chrome/browser/resources/file_manager/images/media/media_fullscreen_hover.png
index 4f675f6..4232739 100644
--- a/chrome/browser/resources/file_manager/images/media/media_fullscreen_hover.png
+++ b/chrome/browser/resources/file_manager/images/media/media_fullscreen_hover.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/media_loop.png b/chrome/browser/resources/file_manager/images/media/media_loop.png
index 51a1b61..f3e35dd 100644
--- a/chrome/browser/resources/file_manager/images/media/media_loop.png
+++ b/chrome/browser/resources/file_manager/images/media/media_loop.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/media_loop_down.png b/chrome/browser/resources/file_manager/images/media/media_loop_down.png
index 4846da6..dda8af5 100644
--- a/chrome/browser/resources/file_manager/images/media/media_loop_down.png
+++ b/chrome/browser/resources/file_manager/images/media/media_loop_down.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/media_loop_hover.png b/chrome/browser/resources/file_manager/images/media/media_loop_hover.png
index 2eae2a4..805d293 100644
--- a/chrome/browser/resources/file_manager/images/media/media_loop_hover.png
+++ b/chrome/browser/resources/file_manager/images/media/media_loop_hover.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/media_next.png b/chrome/browser/resources/file_manager/images/media/media_next.png
index 3daba60..aec4ee6 100644
--- a/chrome/browser/resources/file_manager/images/media/media_next.png
+++ b/chrome/browser/resources/file_manager/images/media/media_next.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/media_next_down.png b/chrome/browser/resources/file_manager/images/media/media_next_down.png
index 4213f20..53cc106 100644
--- a/chrome/browser/resources/file_manager/images/media/media_next_down.png
+++ b/chrome/browser/resources/file_manager/images/media/media_next_down.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/media_next_hover.png b/chrome/browser/resources/file_manager/images/media/media_next_hover.png
index b01dfca..bea50b5 100644
--- a/chrome/browser/resources/file_manager/images/media/media_next_hover.png
+++ b/chrome/browser/resources/file_manager/images/media/media_next_hover.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/media_pause.png b/chrome/browser/resources/file_manager/images/media/media_pause.png
index f4a7982..0a304e4 100644
--- a/chrome/browser/resources/file_manager/images/media/media_pause.png
+++ b/chrome/browser/resources/file_manager/images/media/media_pause.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/media_pause_audio.png b/chrome/browser/resources/file_manager/images/media/media_pause_audio.png
index 45f7d7a..8e2e87b 100644
--- a/chrome/browser/resources/file_manager/images/media/media_pause_audio.png
+++ b/chrome/browser/resources/file_manager/images/media/media_pause_audio.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/media_pause_audio_down.png b/chrome/browser/resources/file_manager/images/media/media_pause_audio_down.png
index 335ba91..1178984 100644
--- a/chrome/browser/resources/file_manager/images/media/media_pause_audio_down.png
+++ b/chrome/browser/resources/file_manager/images/media/media_pause_audio_down.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/media_pause_audio_hover.png b/chrome/browser/resources/file_manager/images/media/media_pause_audio_hover.png
index 33e9b79..52b6bbc 100644
--- a/chrome/browser/resources/file_manager/images/media/media_pause_audio_hover.png
+++ b/chrome/browser/resources/file_manager/images/media/media_pause_audio_hover.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/media_pause_down.png b/chrome/browser/resources/file_manager/images/media/media_pause_down.png
index 36788b8..6e65195 100644
--- a/chrome/browser/resources/file_manager/images/media/media_pause_down.png
+++ b/chrome/browser/resources/file_manager/images/media/media_pause_down.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/media_pause_hover.png b/chrome/browser/resources/file_manager/images/media/media_pause_hover.png
index 612ba37..adf0b28 100644
--- a/chrome/browser/resources/file_manager/images/media/media_pause_hover.png
+++ b/chrome/browser/resources/file_manager/images/media/media_pause_hover.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/media_play.png b/chrome/browser/resources/file_manager/images/media/media_play.png
index a85d940..47bcdc2 100644
--- a/chrome/browser/resources/file_manager/images/media/media_play.png
+++ b/chrome/browser/resources/file_manager/images/media/media_play.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/media_play_audio.png b/chrome/browser/resources/file_manager/images/media/media_play_audio.png
index db8518c..eceaa5b 100644
--- a/chrome/browser/resources/file_manager/images/media/media_play_audio.png
+++ b/chrome/browser/resources/file_manager/images/media/media_play_audio.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/media_play_audio_down.png b/chrome/browser/resources/file_manager/images/media/media_play_audio_down.png
index deb0206..98ebeea 100644
--- a/chrome/browser/resources/file_manager/images/media/media_play_audio_down.png
+++ b/chrome/browser/resources/file_manager/images/media/media_play_audio_down.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/media_play_audio_hover.png b/chrome/browser/resources/file_manager/images/media/media_play_audio_hover.png
index a4a849f..c0867fa 100644
--- a/chrome/browser/resources/file_manager/images/media/media_play_audio_hover.png
+++ b/chrome/browser/resources/file_manager/images/media/media_play_audio_hover.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/media_play_disabled.png b/chrome/browser/resources/file_manager/images/media/media_play_disabled.png
index a0f6a2c..6e96d4c 100644
--- a/chrome/browser/resources/file_manager/images/media/media_play_disabled.png
+++ b/chrome/browser/resources/file_manager/images/media/media_play_disabled.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/media_play_down.png b/chrome/browser/resources/file_manager/images/media/media_play_down.png
index c55d526..1759ec3 100644
--- a/chrome/browser/resources/file_manager/images/media/media_play_down.png
+++ b/chrome/browser/resources/file_manager/images/media/media_play_down.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/media_play_hover.png b/chrome/browser/resources/file_manager/images/media/media_play_hover.png
index fb12b4c..3942d46 100644
--- a/chrome/browser/resources/file_manager/images/media/media_play_hover.png
+++ b/chrome/browser/resources/file_manager/images/media/media_play_hover.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/media_previous.png b/chrome/browser/resources/file_manager/images/media/media_previous.png
index 755ca5e..4fded35 100644
--- a/chrome/browser/resources/file_manager/images/media/media_previous.png
+++ b/chrome/browser/resources/file_manager/images/media/media_previous.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/media_previous_down.png b/chrome/browser/resources/file_manager/images/media/media_previous_down.png
index 1e36380..2c63184 100644
--- a/chrome/browser/resources/file_manager/images/media/media_previous_down.png
+++ b/chrome/browser/resources/file_manager/images/media/media_previous_down.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/media_previous_hover.png b/chrome/browser/resources/file_manager/images/media/media_previous_hover.png
index edfec5a..45ea61b 100644
--- a/chrome/browser/resources/file_manager/images/media/media_previous_hover.png
+++ b/chrome/browser/resources/file_manager/images/media/media_previous_hover.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/media_slider_thumb.png b/chrome/browser/resources/file_manager/images/media/media_slider_thumb.png
index 652f07c..e55b2c2 100644
--- a/chrome/browser/resources/file_manager/images/media/media_slider_thumb.png
+++ b/chrome/browser/resources/file_manager/images/media/media_slider_thumb.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/media_slider_thumb_down.png b/chrome/browser/resources/file_manager/images/media/media_slider_thumb_down.png
index 30198b7..f0b2be7 100644
--- a/chrome/browser/resources/file_manager/images/media/media_slider_thumb_down.png
+++ b/chrome/browser/resources/file_manager/images/media/media_slider_thumb_down.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/media_slider_thumb_hover.png b/chrome/browser/resources/file_manager/images/media/media_slider_thumb_hover.png
index 042ceb1..e216ae6 100644
--- a/chrome/browser/resources/file_manager/images/media/media_slider_thumb_hover.png
+++ b/chrome/browser/resources/file_manager/images/media/media_slider_thumb_hover.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/media_sound_disabled.png b/chrome/browser/resources/file_manager/images/media/media_sound_disabled.png
index 549a826..42126de 100644
--- a/chrome/browser/resources/file_manager/images/media/media_sound_disabled.png
+++ b/chrome/browser/resources/file_manager/images/media/media_sound_disabled.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/media_sound_disabled_down.png b/chrome/browser/resources/file_manager/images/media/media_sound_disabled_down.png
index a5bcc90..2b494b9 100644
--- a/chrome/browser/resources/file_manager/images/media/media_sound_disabled_down.png
+++ b/chrome/browser/resources/file_manager/images/media/media_sound_disabled_down.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/media_sound_disabled_hover.png b/chrome/browser/resources/file_manager/images/media/media_sound_disabled_hover.png
index 8b7b522..5040f80 100644
--- a/chrome/browser/resources/file_manager/images/media/media_sound_disabled_hover.png
+++ b/chrome/browser/resources/file_manager/images/media/media_sound_disabled_hover.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/media_sound_full.png b/chrome/browser/resources/file_manager/images/media/media_sound_full.png
index 9b72b5c..4a03402 100644
--- a/chrome/browser/resources/file_manager/images/media/media_sound_full.png
+++ b/chrome/browser/resources/file_manager/images/media/media_sound_full.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/media_sound_full_disabled.png b/chrome/browser/resources/file_manager/images/media/media_sound_full_disabled.png
index e3d55b0..cef4bc4 100644
--- a/chrome/browser/resources/file_manager/images/media/media_sound_full_disabled.png
+++ b/chrome/browser/resources/file_manager/images/media/media_sound_full_disabled.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/media_sound_full_down.png b/chrome/browser/resources/file_manager/images/media/media_sound_full_down.png
index 558c176..1a185ed 100644
--- a/chrome/browser/resources/file_manager/images/media/media_sound_full_down.png
+++ b/chrome/browser/resources/file_manager/images/media/media_sound_full_down.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/media_sound_full_hover.png b/chrome/browser/resources/file_manager/images/media/media_sound_full_hover.png
index 1dccc1c..d285c01 100644
--- a/chrome/browser/resources/file_manager/images/media/media_sound_full_hover.png
+++ b/chrome/browser/resources/file_manager/images/media/media_sound_full_hover.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/media_sound_level1.png b/chrome/browser/resources/file_manager/images/media/media_sound_level1.png
index 0e1b4f8..2f7ceea 100644
--- a/chrome/browser/resources/file_manager/images/media/media_sound_level1.png
+++ b/chrome/browser/resources/file_manager/images/media/media_sound_level1.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/media_sound_level1_down.png b/chrome/browser/resources/file_manager/images/media/media_sound_level1_down.png
index 19ff4b9..9777c9b 100644
--- a/chrome/browser/resources/file_manager/images/media/media_sound_level1_down.png
+++ b/chrome/browser/resources/file_manager/images/media/media_sound_level1_down.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/media_sound_level1_hover.png b/chrome/browser/resources/file_manager/images/media/media_sound_level1_hover.png
index 94dde01..fdf3bc1 100644
--- a/chrome/browser/resources/file_manager/images/media/media_sound_level1_hover.png
+++ b/chrome/browser/resources/file_manager/images/media/media_sound_level1_hover.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/media_sound_level2.png b/chrome/browser/resources/file_manager/images/media/media_sound_level2.png
index b241d0f..9e69e8b 100644
--- a/chrome/browser/resources/file_manager/images/media/media_sound_level2.png
+++ b/chrome/browser/resources/file_manager/images/media/media_sound_level2.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/media_sound_level2_down.png b/chrome/browser/resources/file_manager/images/media/media_sound_level2_down.png
index 43cf801..422b435 100644
--- a/chrome/browser/resources/file_manager/images/media/media_sound_level2_down.png
+++ b/chrome/browser/resources/file_manager/images/media/media_sound_level2_down.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/media_sound_level2_hover.png b/chrome/browser/resources/file_manager/images/media/media_sound_level2_hover.png
index 6e0bbe8..8bf6157 100644
--- a/chrome/browser/resources/file_manager/images/media/media_sound_level2_hover.png
+++ b/chrome/browser/resources/file_manager/images/media/media_sound_level2_hover.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/media_volume_slider_thumb.png b/chrome/browser/resources/file_manager/images/media/media_volume_slider_thumb.png
index e6ef1d3..a1bf057 100644
--- a/chrome/browser/resources/file_manager/images/media/media_volume_slider_thumb.png
+++ b/chrome/browser/resources/file_manager/images/media/media_volume_slider_thumb.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/media_volume_slider_thumb_down.png b/chrome/browser/resources/file_manager/images/media/media_volume_slider_thumb_down.png
index 6a884e6..a4560f0 100644
--- a/chrome/browser/resources/file_manager/images/media/media_volume_slider_thumb_down.png
+++ b/chrome/browser/resources/file_manager/images/media/media_volume_slider_thumb_down.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/media_volume_slider_thumb_hover.png b/chrome/browser/resources/file_manager/images/media/media_volume_slider_thumb_hover.png
index 129e495..159e2e7 100644
--- a/chrome/browser/resources/file_manager/images/media/media_volume_slider_thumb_hover.png
+++ b/chrome/browser/resources/file_manager/images/media/media_volume_slider_thumb_hover.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/media/watch.png b/chrome/browser/resources/file_manager/images/media/watch.png
index 28d49b2..92b6284 100644
--- a/chrome/browser/resources/file_manager/images/media/watch.png
+++ b/chrome/browser/resources/file_manager/images/media/watch.png
Binary files differ
diff --git a/chrome/browser/resources/file_manager/js/action_choice_scripts.js b/chrome/browser/resources/file_manager/js/action_choice_scripts.js
index ce3090e..2cf5cd8 100644
--- a/chrome/browser/resources/file_manager/js/action_choice_scripts.js
+++ b/chrome/browser/resources/file_manager/js/action_choice_scripts.js
@@ -8,7 +8,7 @@
 // included file but that's all right since any javascript file should start
 // with a copyright comment anyway.
 
-//<include src="../../image_loader/client.js"/>
+//<include src="../../image_loader/image_loader_client.js"/>
 
 //<include src="../../../../../ui/webui/resources/js/load_time_data.js"/>
 //<include src="../../../../../ui/webui/resources/js/util.js"/>
diff --git a/chrome/browser/resources/file_manager/js/background.js b/chrome/browser/resources/file_manager/js/background.js
index c6f057f..294af04 100644
--- a/chrome/browser/resources/file_manager/js/background.js
+++ b/chrome/browser/resources/file_manager/js/background.js
@@ -315,8 +315,12 @@
         // The isFocused() method should always be available, but in case
         // Files.app's failed on some error, wrap it with try catch.
         try {
-          if (appWindows[key].contentWindow.isFocused())
-            return key;
+          if (appWindows[key].contentWindow.isFocused()) {
+            if (opt_callback)
+              opt_callback(key);
+            onTaskCompleted();
+            return;
+          }
         } catch (e) {
           console.error(e.message);
         }
@@ -383,10 +387,12 @@
 }
 
 /**
+ * Executes a file browser task.
+ *
  * @param {string} action Task id.
  * @param {Object} details Details object.
  */
-function executeFileBrowserTask(action, details) {
+function onExecute(action, details) {
   var urls = details.entries.map(function(e) { return e.toURL() });
 
   switch (action) {
@@ -465,9 +471,9 @@
 }
 
 /**
- * Launch the app.
+ * Launches the app.
  */
-function launch() {
+function onLaunched() {
   if (nextFileManagerWindowID == 0) {
     // The app just launched. Remove window state records that are not needed
     // any more.
@@ -487,13 +493,41 @@
 /**
  * Restarted the app, restore windows.
  */
-function restart() {
+function onRestarted() {
   reopenFileManagers();
   audioPlayer.reopen();
   videoPlayer.reopen();
 }
 
 /**
+ * Handles clicks on a custom item on the launcher context menu.
+ * @param {OnClickData} info Event details.
+ */
+function onContextMenuClicked(info) {
+  if (info.menuItemId == 'new-window') {
+    // Find the focused window (if any) and use it's current path for the
+    // new window. If not found, then launch with the default path.
+    for (var key in appWindows) {
+      try {
+        if (appWindows[key].contentWindow.isFocused()) {
+          var appState = {
+            defaultPath: appWindows[key].contentWindow.appState.defaultPath
+          };
+          launchFileManager(appState);
+          return;
+        }
+      } catch (ignore) {
+        // The isFocused method may not be defined during initialization.
+        // Therefore, wrapped with a try-catch block.
+      }
+    }
+
+    // Launch with the default path.
+    launchFileManager();
+  }
+}
+
+/**
  * Closes the background page, if it is not needed.
  */
 function maybeCloseBackgroundPage() {
@@ -502,11 +536,42 @@
     close();
 }
 
-chrome.app.runtime.onLaunched.addListener(launch);
-chrome.app.runtime.onRestarted.addListener(restart);
-
-function addExecuteHandler() {
-  chrome.fileBrowserHandler.onExecute.addListener(executeFileBrowserTask);
+/**
+ * Initializes the context menu. Recreates if already exists.
+ * @param {Object} strings Hash array of strings.
+ */
+function initContextMenu(strings) {
+  try {
+    chrome.contextMenus.remove('new-window');
+  } catch (ignore) {
+    // There is no way to detect if the context menu is already added, therefore
+    // try to recreate it every time.
+  }
+  chrome.contextMenus.create({
+    id: 'new-window',
+    contexts: ['launcher'],
+    title: strings['NEW_WINDOW_BUTTON_LABEL']
+  });
 }
 
-addExecuteHandler();
+/**
+ * Initializes the background page of Files.app.
+ */
+function initApp() {
+  // Initialize handlers.
+  chrome.fileBrowserHandler.onExecute.addListener(onExecute);
+  chrome.app.runtime.onLaunched.addListener(onLaunched);
+  chrome.app.runtime.onRestarted.addListener(onRestarted);
+  chrome.contextMenus.onClicked.addListener(onContextMenuClicked);
+
+  // Fetch strings and initialize the context menu.
+  queue.run(function(callback) {
+    chrome.fileBrowserPrivate.getStrings(function(strings) {
+      initContextMenu(strings);
+      chrome.storage.local.set({strings: strings}, callback);
+    });
+  });
+}
+
+// Initialize Files.app.
+initApp();
diff --git a/chrome/browser/resources/file_manager/js/breadcrumbs_controller.js b/chrome/browser/resources/file_manager/js/breadcrumbs_controller.js
index 5bbb33d..a4df354 100644
--- a/chrome/browser/resources/file_manager/js/breadcrumbs_controller.js
+++ b/chrome/browser/resources/file_manager/js/breadcrumbs_controller.js
@@ -247,7 +247,7 @@
  * @param {string} path Path to directory.
  */
 BreadcrumbsController.prototype.show = function(rootPath, path) {
-  this.bc_.style.display = '-webkit-box';
+  this.bc_.hidden = false;
   this.update(rootPath, path);
 };
 
@@ -255,7 +255,7 @@
  * Hide breadcrumbs div.
  */
 BreadcrumbsController.prototype.hide = function() {
-  this.bc_.style.display = 'none';
+  this.bc_.hidden = true;
 };
 
 /**
diff --git a/chrome/browser/resources/file_manager/js/butter_bar.js b/chrome/browser/resources/file_manager/js/butter_bar.js
index 5557440..69d8187 100644
--- a/chrome/browser/resources/file_manager/js/butter_bar.js
+++ b/chrome/browser/resources/file_manager/js/butter_bar.js
@@ -5,11 +5,6 @@
 'use strict';
 
 /**
- * The amount of time, before a butter bar will hide after the last update.
- */
-var HIDE_DELAY_TIME_MS = 2000;
-
-/**
  * Butter bar is shown on top of the file list and is used to show the copy
  * progress and other messages.
  * @param {HTMLElement} dialogDom FileManager top-level div.
@@ -39,6 +34,15 @@
 }
 
 /**
+ * The default amount of milliseconds time, before a butter bar will hide after
+ * the last update.
+ * @type {number}
+ * @private
+ * @const
+ */
+ButterBar.HIDE_DELAY_TIME_MS_ = 2000;
+
+/**
  * Name of action which should be displayed as an 'x' button instead of
  * link with text.
  * @const
@@ -66,7 +70,9 @@
  * Show butter bar.
  * @param {ButterBar.Mode} mode Butter bar mode.
  * @param {string} message The message to be shown.
- * @param {Object=} opt_options Options: 'actions', 'progress', 'timeout'.
+ * @param {Object=} opt_options Options: 'actions', 'progress', 'timeout'. If
+ *     'timeout' is not specified, HIDE_DELAY_TIME_MS_ is used. If 'timeout' is
+ *     false, the butter bar will not be hidden.
  */
 ButterBar.prototype.show = function(mode, message, opt_options) {
   this.currentMode_ = mode;
@@ -111,9 +117,9 @@
 ButterBar.prototype.showError_ = function(message) {
   // Wait in case there are previous dialogs being closed.
   setTimeout(function() {
-    this.hide_();
     this.alert_.showHtml('',  // Title.
                          message);
+    this.hide_();
   }.bind(this), cr.ui.dialogs.BaseDialog.ANIMATE_STABLE_DURATION);
 };
 
@@ -129,14 +135,6 @@
 
   this.clearHideTimeout_();
 
-  var timeout = ('timeout' in opt_options) ? opt_options.timeout : 10 * 1000;
-  if (timeout) {
-    this.hideTimeout_ = setTimeout(function() {
-      this.hideTimeout_ = null;
-      this.hide_();
-    }.bind(this), timeout);
-  }
-
   var butterMessage = this.butter_.querySelector('.butter-message');
    butterMessage.textContent = message;
   if (message && !this.isVisible_()) {
@@ -157,22 +155,28 @@
   } else {
     butterMessage.classList.remove('single-line');
   }
+
+  if (opt_options.timeout !== false)
+    this.hide_(opt_options.timeout);
 };
 
 /**
- * Hide butter bar. There might be some delay before hiding so that butter bar
+ * Hide butter bar. There might be the delay before hiding so that butter bar
  * would be shown for no less than the minimal time.
- * @param {boolean=} opt_force If true hide immediately, default false.
+ * @param {number=} opt_timeout Delay time in milliseconds before hidding. If it
+ *     is zero, butter bar is hidden immediatelly. If it is not specified,
+ *     HIDE_DELAY_TIME_MS_ is used.
  * @private
  */
-ButterBar.prototype.hide_ = function(opt_force) {
+ButterBar.prototype.hide_ = function(opt_timeout) {
   this.clearHideTimeout_();
 
   if (!this.isVisible_())
     return;
 
-  var delay = HIDE_DELAY_TIME_MS;
-  if (opt_force || delay <= 0) {
+  var delay = typeof opt_timeout != 'undefined' ?
+    opt_timeout : ButterBar.HIDE_DELAY_TIME_MS_;
+  if (delay <= 0) {
     this.currentMode_ = null;
     this.butter_.classList.remove('visible');
     this.butter_.querySelector('.progress-bar').hidden = true;
@@ -180,7 +184,7 @@
     // Reschedule hide to comply with the minimal display time.
     this.hideTimeout_ = setTimeout(function() {
       this.hideTimeout_ = null;
-      this.hide_(true);
+      this.hide_(0);
     }.bind(this), delay);
   }
 };
@@ -237,7 +241,11 @@
  */
 ButterBar.prototype.showProgress_ = function() {
   this.progress_ = this.copyManager_.getStatus();
-  var options = {progress: this.progress_.percentage, actions: {}, timeout: 0};
+  var options = {
+    progress: this.progress_.percentage,
+    actions: {},
+    timeout: false
+  };
 
   var type = this.transferType_();
   var progressString = (this.progress_.pendingItems === 1) ?
@@ -284,7 +292,7 @@
 
     case 'CANCELLED':
       this.show(ButterBar.Mode.DELETE,
-                str(this.transferType_() + '_CANCELLED'), { timeout: 1000 });
+                str(this.transferType_() + '_CANCELLED'));
       break;
 
     case 'ERROR':
@@ -345,7 +353,7 @@
       if (this.currentMode_ == ButterBar.Mode.DELETE)
         this.update_(title);
       else
-        this.show(ButterBar.Mode.DELETE, title, {timeout: 0});
+        this.show(ButterBar.Mode.DELETE, title);
       break;
 
     case 'SUCCESS':
diff --git a/chrome/browser/resources/file_manager/js/directory_model.js b/chrome/browser/resources/file_manager/js/directory_model.js
index 8780e0e..7520201 100644
--- a/chrome/browser/resources/file_manager/js/directory_model.js
+++ b/chrome/browser/resources/file_manager/js/directory_model.js
@@ -803,12 +803,13 @@
 /**
  * Resolves absolute directory path. Handles Drive stub. If the drive is
  * mounting, callbacks will be called after the mount is completed.
+ *
  * @param {string} path Path to the directory.
  * @param {function(DirectoryEntry} successCallback Success callback.
  * @param {function(FileError} errorCallback Error callback.
  */
-DirectoryModel.prototype.resolveDirectory = function(path, successCallback,
-                                                     errorCallback) {
+DirectoryModel.prototype.resolveDirectory = function(
+    path, successCallback, errorCallback) {
   if (PathUtil.getRootType(path) == RootType.DRIVE) {
     var driveStatus = this.volumeManager_.getDriveStatus();
     if (!this.isDriveMounted() &&
@@ -826,8 +827,24 @@
     return;
   }
 
+  var onError = function(error) {
+    // Handle the special case, when in offline mode, and there are no cached
+    // contents on the C++ side. In such case, let's display the stub.
+    // The INVALID_STATE_ERR error code is returned from the drive filesystem
+    // in such situation.
+    //
+    // TODO(mtomasz, hashimoto): Consider rewriting this logic.
+    //     crbug.com/253464.
+    if (PathUtil.getRootType(path) == RootType.DRIVE &&
+        error.code == FileError.INVALID_STATE_ERR) {
+      successCallback(DirectoryModel.fakeDriveEntry_);
+      return;
+    }
+    errorCallback(error);
+  }.bind(this);
+
   this.root_.getDirectory(path, {create: false},
-                          successCallback, errorCallback);
+                          successCallback, onError);
 };
 
 /**
diff --git a/chrome/browser/resources/file_manager/js/directory_tree.js b/chrome/browser/resources/file_manager/js/directory_tree.js
new file mode 100644
index 0000000..69710fb
--- /dev/null
+++ b/chrome/browser/resources/file_manager/js/directory_tree.js
@@ -0,0 +1,723 @@
+// 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.
+
+'use strict';
+
+////////////////////////////////////////////////////////////////////////////////
+// DirectoryTreeUtil
+
+/**
+ * Utility methods. They are intended for use only in this file.
+ */
+var DirectoryTreeUtil = {};
+
+/**
+ * Updates sub-elements of {@code parentElement} reading {@code DirectoryEntry}
+ * with calling {@code iterator}.
+ *
+ * @param {string} changedDirectryPath The path of the changed directory.
+ * @param {DirectoryItem|DirectoryTree} currentDirectoryItem An item to be
+ *     started traversal from.
+ */
+DirectoryTreeUtil.updateChangedDirectoryItem = function(
+    changedDirectryPath, currentDirectoryItem) {
+  if (changedDirectryPath === currentDirectoryItem.entry.fullPath) {
+    currentDirectoryItem.updateSubDirectories(false /* recursive */);
+    return;
+  }
+
+  for (var i = 0; i < currentDirectoryItem.items.length; i++) {
+    var item = currentDirectoryItem.items[i];
+    if (PathUtil.isParentPath(item.entry.fullPath, changedDirectryPath)) {
+      DirectoryTreeUtil.updateChangedDirectoryItem(changedDirectryPath, item);
+      break;
+    }
+  }
+};
+
+/**
+ * Updates sub-elements of {@code parentElement} reading {@code DirectoryEntry}
+ * with calling {@code iterator}.
+ *
+ * @param {DirectoryItem|DirectoryTree} parentElement Parent element of newly
+ *     created items.
+ * @param {function(number): DirectoryEntry} iterator Function which returns
+ *     the n-th Entry in the directory.
+ * @param {DirectoryModel} directoryModel Current DirectoryModel.
+ * @param {boolean} recursive True if the all visible sub-directories are
+ *     updated recursively including left arrows. If false, the update walks
+ *     only immediate child directories without arrows.
+ */
+DirectoryTreeUtil.updateSubElementsFromList = function(
+    parentElement, iterator, directoryModel, recursive) {
+  var index = 0;
+  while (iterator(index)) {
+    var currentEntry = iterator(index);
+    var currentElement = parentElement.items[index];
+
+    if (index >= parentElement.items.length) {
+      var item = new DirectoryItem(currentEntry, parentElement, directoryModel);
+      parentElement.add(item);
+      index++;
+    } else if (currentEntry.fullPath == currentElement.fullPath) {
+      if (recursive && parentElement.expanded)
+        currentElement.updateSubDirectories(true /* recursive */);
+
+      index++;
+    } else if (currentEntry.fullPath < currentElement.fullPath) {
+      var item = new DirectoryItem(currentEntry, parentElement, directoryModel);
+      parentElement.addAt(item, index);
+      index++;
+    } else if (currentEntry.fullPath > currentElement.fullPath) {
+      parentElement.remove(currentElement);
+    }
+  }
+
+  var removedChild;
+  while (removedChild = parentElement.items[index]) {
+    parentElement.remove(removedChild);
+  }
+
+  if (index == 0) {
+    parentElement.hasChildren = false;
+    parentElement.expanded = false;
+  } else {
+    parentElement.hasChildren = true;
+  }
+};
+
+/**
+ * Returns true if the given directory entry is dummy.
+ * @param {DirectoryEntry|Object} dirEntry DirectoryEntry to be checked.
+ * @return {boolean} True if the given directory entry is dummy.
+ */
+DirectoryTreeUtil.isDummyEntry = function(dirEntry) {
+  return !('createReader' in dirEntry);
+};
+
+/**
+ * Finds a parent directory of the {@code path} from the {@code items}, and
+ * invokes the DirectoryItem.selectPath() of the found directory.
+ *
+ * @param {Array.<DirectoryItem>} items Items to be searched.
+ * @param {string} path Path to be searched for.
+ * @return {boolean} True if the parent item is found.
+ */
+DirectoryTreeUtil.searchAndSelectPath = function(items, path) {
+  for (var i = 0; i < items.length; i++) {
+    var item = items[i];
+    if (PathUtil.isParentPath(item.entry.fullPath, path)) {
+      item.selectPath(path);
+      return true;
+    }
+  }
+  return false;
+};
+
+/**
+ * Modifies a list of the directory entries to match the new UI sepc.
+ *
+ * TODO(yoshiki): remove this after the old UI is removed.
+ *
+ * @param {Array.<DirectoryEntry>} entries The list of entty.
+ * @return {Array.<DirectoryEntries>} Modified entries.
+ */
+DirectoryTreeUtil.addAndRemoveDriveSpecialDirs = function(entries) {
+  var modifiedEntries = [];
+  for (var i in entries) {
+    // Removes '/drive/other'.
+    var entry = entries[i];
+    if (entry.fullPath ==
+        (RootDirectory.DRIVE + '/' + DriveSubRootDirectory.OTHER)) {
+      continue;
+    }
+
+    // Changes the label of '/drive/root' to 'My Drive'.
+    if (entry.fullPath == DirectoryModel.fakeDriveEntry_.fullPath) {
+      entry.label = str('DRIVE_MY_DRIVE_LABEL');
+    }
+
+    modifiedEntries.push(entry);
+  }
+
+  // Adds the special directories.
+  var specialDirs = DirectoryModel.FAKE_DRIVE_SPECIAL_SEARCH_ENTRIES;
+  for (var i in specialDirs) {
+    var dir = specialDirs[i];
+    dir['label'] = PathUtil.getRootLabel(dir.fullPath);
+    modifiedEntries.push(dir);
+  }
+  return modifiedEntries;
+};
+
+/**
+ * Retrieves the file list with the latest information.
+ *
+ * @param {DirectoryTree|DirectoryItem} item Parent to be reloaded.
+ * @param {DirectoryModel} dm The directory model.
+ * @param {function(Array.<Entry>)} successCallback Callback on success.
+ * @param {function()=} opt_errorCallback Callback on failure.
+ */
+DirectoryTreeUtil.updateSubDirectories = function(
+    item, dm, successCallback, opt_errorCallback) {
+  // Tries to retrieve new entry if the cached entry is dummy.
+  if (DirectoryTreeUtil.isDummyEntry(item.entry)) {
+    // Fake Drive root.
+    dm.resolveDirectory(
+        item.fullPath,
+        function(entry) {
+          item.dirEntry_ = entry;
+
+          // If the retrieved entry is dummy again, returns with an error.
+          if (DirectoryTreeUtil.isDummyEntry(entry)) {
+            if (opt_errorCallback)
+              opt_errorCallback();
+            return;
+          }
+
+          DirectoryTreeUtil.updateSubDirectories(
+              item, dm, successCallback, opt_errorCallback);
+        },
+        opt_errorCallback || function() {});
+    return;
+  }
+
+  var reader = item.entry.createReader();
+  var entries = [];
+  var readEntry = function() {
+    reader.readEntries(function(results) {
+      if (!results.length) {
+        if (item.entry.fullPath == RootDirectory.DRIVE)
+          successCallback(
+              DirectoryTreeUtil.addAndRemoveDriveSpecialDirs(entries));
+        else
+          successCallback(
+              DirectoryTreeUtil.sortEntries(item.fileFilter_, entries));
+        return;
+      }
+
+      for (var i = 0; i < results.length; i++) {
+        var entry = results[i];
+        if (entry.isDirectory)
+          entries.push(entry);
+      }
+      readEntry();
+    });
+  };
+  readEntry();
+};
+
+/**
+ * Sorts a list of entries.
+ *
+ * @param {FileFilter} fileFilter The file filter.
+ * @param {Array.<Entries>} entries Entries to be sorted.
+ * @return {Array.<Entries>} Sorted entries.
+ */
+DirectoryTreeUtil.sortEntries = function(fileFilter, entries) {
+  entries.sort(function(a, b) {
+    return (a.name.toLowerCase() > b.name.toLowerCase()) ? 1 : -1;
+  });
+  return entries.filter(fileFilter.filter.bind(fileFilter));
+};
+
+/**
+ * Checks if tre tree should be hidden on the given directory.
+ *
+ * @param {string} path Path to be checked.
+ * @return {boolean} True if the tree should NOT be visible on the given
+ *     directory. Otherwise, false.
+ */
+DirectoryTreeUtil.shouldHideTree = function(path) {
+  return !PathUtil.isDriveBasedPath(path);
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// DirectoryItem
+
+/**
+ * A directory in the tree. Each element represents one directory.
+ *
+ * @param {DirectoryEntry} dirEntry DirectoryEntry of this item.
+ * @param {DirectoryItem|DirectoryTree} parentDirItem Parent of this item.
+ * @param {DirectoryModel} directoryModel Current DirectoryModel.
+ * @extends {cr.ui.TreeItem}
+ * @constructor
+ */
+function DirectoryItem(dirEntry, parentDirItem, directoryModel) {
+  var item = cr.doc.createElement('div');
+  DirectoryItem.decorate(item, dirEntry, parentDirItem, directoryModel);
+  return item;
+}
+
+/**
+ * @param {HTMLElement} el Element to be DirectoryItem.
+ * @param {DirectoryEntry} dirEntry DirectoryEntry of this item.
+ * @param {DirectoryItem|DirectoryTree} parentDirItem Parent of this item.
+ * @param {DirectoryModel} directoryModel Current DirectoryModel.
+ */
+DirectoryItem.decorate =
+    function(el, dirEntry, parentDirItem, directoryModel) {
+  el.__proto__ = DirectoryItem.prototype;
+  (/** @type {DirectoryItem} */ el).decorate(
+      dirEntry, parentDirItem, directoryModel);
+};
+
+DirectoryItem.prototype = {
+  __proto__: cr.ui.TreeItem.prototype,
+
+  /**
+   * The DirectoryEntry corresponding to this DirectoryItem. This may be
+   * a dummy DirectoryEntry.
+   * @type {DirectoryEntry|Object}
+   * @override
+   **/
+  get entry() {
+      return this.dirEntry_;
+  },
+
+  /**
+   * The element containing the label text and the icon.
+   * @type {!HTMLElement}
+   * @override
+   **/
+  get labelElement() {
+      return this.firstElementChild.querySelector('.label');
+  }
+};
+
+/**
+ * @param {DirectoryEntry} dirEntry DirectoryEntry of this item.
+ * @param {DirectoryItem|DirectoryTree} parentDirItem Parent of this item.
+ * @param {DirectoryModel} directoryModel Current DirectoryModel.
+ */
+DirectoryItem.prototype.decorate = function(
+    dirEntry, parentDirItem, directoryModel) {
+  var path = dirEntry.fullPath;
+  var label;
+  label = dirEntry.label ? dirEntry.label : dirEntry.name;
+
+  this.className = 'tree-item';
+  this.innerHTML =
+      '<div class="tree-row">' +
+      ' <span class="expand-icon"></span>' +
+      ' <span class="icon"></span>' +
+      ' <span class="label"></span>' +
+      ' <div class="root-eject"></div>' +
+      '</div>' +
+      '<div class="tree-children"></div>';
+  this.setAttribute('role', 'treeitem');
+
+  this.directoryModel_ = directoryModel;
+  this.parent_ = parentDirItem;
+  this.label = label;
+  this.fullPath = path;
+  this.dirEntry_ = dirEntry;
+  this.fileFilter_ = this.directoryModel_.getFileFilter();
+
+  // Sets hasChildren=false tentatively. This will be overridden after
+  // scanning sub-directories in DirectoryTreeUtil.updateSubElementsFromList.
+  this.hasChildren = false;
+
+  this.addEventListener('expand', this.onExpand_.bind(this), false);
+  var volumeManager = VolumeManager.getInstance();
+  var icon = this.querySelector('.icon');
+  icon.classList.add('volume-icon');
+  var iconType = PathUtil.getRootType(path);
+  if (iconType && PathUtil.isRootPath(path))
+    icon.setAttribute('volume-type-icon', iconType);
+  else
+    icon.setAttribute('file-type-icon', 'folder');
+
+  var eject = this.querySelector('.root-eject');
+  eject.hidden = !PathUtil.isUnmountableByUser(path);
+  eject.addEventListener('click',
+      function(event) {
+        event.stopPropagation();
+        if (!PathUtil.isUnmountableByUser(path))
+          return;
+
+        volumeManager.unmount(path, function() {}, function() {});
+      }.bind(this));
+
+  if (parentDirItem.expanded)
+    this.updateSubDirectories(false /* recursive */);
+};
+
+/**
+ * Overrides WebKit's scrollIntoViewIfNeeded, which doesn't work well with
+ * a complex layout. This call is not necessary, so we are ignoring it.
+ *
+ * @param {boolean} unused Unused.
+ * @override
+ */
+DirectoryItem.prototype.scrollIntoViewIfNeeded = function(unused) {
+};
+
+/**
+ * Removes the child node, but without selecting the parent item, to avoid
+ * unintended changing of directories. Removing is done externally, and other
+ * code will navigate to another directory.
+ *
+ * @param {!cr.ui.TreeItem} child The tree item child to remove.
+ * @override
+ */
+DirectoryItem.prototype.remove = function(child) {
+  this.lastElementChild.removeChild(child);
+  if (this.items.length == 0)
+    this.hasChildren = false;
+};
+
+/**
+ * Invoked when the item is being expanded.
+ * @param {!UIEvent} e Event.
+ * @private
+ **/
+DirectoryItem.prototype.onExpand_ = function(e) {
+  this.updateSubDirectories(
+      true /* recursive */,
+      function() {},
+      function() {
+        this.expanded = false;
+      }.bind(this));
+
+  e.stopPropagation();
+};
+
+/**
+ * Retrieves the latest subdirectories and update them on the tree.
+ * @param {boolean} recursive True if the update is recursively.
+ * @param {function()=} opt_successCallback Callback called on success.
+ * @param {function()=} opt_errorCallback Callback called on error.
+ */
+DirectoryItem.prototype.updateSubDirectories = function(
+    recursive, opt_successCallback, opt_errorCallback) {
+  DirectoryTreeUtil.updateSubDirectories(
+      this,
+      this.directoryModel_,
+      function(entries) {
+        this.entries_ = entries;
+        this.redrawSubDirectoryList_(recursive);
+        opt_successCallback && opt_successCallback();
+      }.bind(this),
+      opt_errorCallback);
+};
+
+/**
+ * Redraw subitems with the latest information. The items are sorted in
+ * alphabetical order, case insensitive.
+ * @param {boolean} recursive True if the update is recursively.
+ * @private
+ */
+DirectoryItem.prototype.redrawSubDirectoryList_ = function(recursive) {
+  DirectoryTreeUtil.updateSubElementsFromList(
+      this,
+      function(i) { return this.entries_[i]; }.bind(this),
+      this.directoryModel_,
+      recursive);
+};
+
+/**
+ * Select the item corresponding to the given {@code path}.
+ * @param {string} path Path to be selected.
+ */
+DirectoryItem.prototype.selectPath = function(path) {
+  if (path == this.fullPath) {
+    this.selected = true;
+    return;
+  }
+
+  if (DirectoryTreeUtil.searchAndSelectPath(this.items, path))
+    return;
+
+  // If the path doesn't exist, updates sub directories and tryes again.
+  this.updateSubDirectories(
+      false /* recursive */,
+      DirectoryTreeUtil.searchAndSelectPath.bind(null, this.items, path));
+};
+
+/**
+ * Executes the assigned action as a drop target.
+ */
+DirectoryItem.prototype.doDropTargetAction = function() {
+  this.expanded = true;
+};
+
+/**
+ * Executes the assigned action. DirectoryItem performs changeDirectory.
+ */
+DirectoryItem.prototype.doAction = function() {
+  if (this.fullPath != this.directoryModel_.getCurrentDirPath())
+    this.directoryModel_.changeDirectory(this.fullPath);
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// DirectoryTree
+
+/**
+ * Tree of directories on the sidebar. This element is also the root of items,
+ * in other words, this is the parent of the top-level items.
+ *
+ * @constructor
+ * @extends {cr.ui.Tree}
+ */
+function DirectoryTree() {}
+
+/**
+ * Decorates an element.
+ * @param {HTMLElement} el Element to be DirectoryTree.
+ * @param {DirectoryModel} directoryModel Current DirectoryModel.
+ */
+DirectoryTree.decorate = function(el, directoryModel) {
+  el.__proto__ = DirectoryTree.prototype;
+  (/** @type {DirectoryTree} */ el).decorate(directoryModel);
+};
+
+DirectoryTree.prototype = {
+  __proto__: cr.ui.Tree.prototype,
+
+  // DirectoryTree is always expanded.
+  get expanded() { return true; },
+  /**
+   * @param {boolean} value Not used.
+   */
+  set expanded(value) {},
+
+  /**
+   * The DirectoryEntry corresponding to this DirectoryItem. This may be
+   * a dummy DirectoryEntry.
+   * @type {DirectoryEntry|Object}
+   * @override
+   **/
+  get entry() {
+      return this.dirEntry_;
+  }
+};
+
+/**
+ * Decorates an element.
+ * @param {DirectoryModel} directoryModel Current DirectoryModel.
+ */
+DirectoryTree.prototype.decorate = function(directoryModel) {
+  cr.ui.Tree.prototype.decorate.call(this);
+
+  this.directoryModel_ = directoryModel;
+  this.entries_ = [];
+
+  this.fileFilter_ = this.directoryModel_.getFileFilter();
+  this.fileFilter_.addEventListener('changed',
+                                    this.onFilterChanged_.bind(this));
+  /**
+   * The path of the root directory.
+   * @type {string}
+   */
+  this.fullPath = '/';
+  this.dirEntry_ = null;
+
+  /**
+   * The path of the current directory.
+   * @type {string}
+   */
+  this.currentPath_ = 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;
+      this.selectedItem.doAction();
+      return;
+    }
+  }.bind(this));
+
+  this.privateOnDirectoryChangedBound_ =
+      this.onDirectoryContentChanged_.bind(this);
+  chrome.fileBrowserPrivate.onDirectoryChanged.addListener(
+      this.privateOnDirectoryChangedBound_);
+
+  this.scrollBar_ = MainPanelScrollBar();
+  this.scrollBar_.initialize(this.parentNode, this);
+};
+
+/**
+ * Select the item corresponding to the given path.
+ * @param {string} path Path to be selected.
+ */
+DirectoryTree.prototype.selectPath = function(path) {
+  if ((this.entry && this.entry.fullPath == path) || this.currentPath_ == path)
+    return;
+  this.currentPath_ = path;
+  if (DirectoryTreeUtil.shouldHideTree(path))
+    return;
+
+  this.selectPathInternal_(path);
+};
+
+/**
+ * Select the item corresponding to the given path. This method is used
+ * internally.
+ * @param {string} path Path to be selected.
+ * @private
+ */
+DirectoryTree.prototype.selectPathInternal_ = function(path) {
+  var rootDirPath = PathUtil.getRootPath(path);
+
+  if (PathUtil.isSpecialSearchRoot(rootDirPath) ||
+      PathUtil.getRootType(rootDirPath) == RootType.DRIVE) {
+    rootDirPath = RootDirectory.DRIVE;
+  }
+
+  var onError = function() {
+    this.clearTree_(true);
+  }.bind(this);
+
+  if (this.fullPath != rootDirPath || !this.dirEntry_) {
+    this.fullPath = rootDirPath;
+
+    this.directoryModel_.resolveDirectory(
+        rootDirPath,
+        function(entry) {
+          if (this.fullPath != rootDirPath)
+            return;
+
+          this.dirEntry_ = entry;
+          this.selectPathInternal_(path);
+        }.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);
+  }
+};
+
+/**
+ * Retrieves the latest subdirectories and update them on the tree.
+ * @param {boolean} recursive True if the update is recursively.
+ * @param {function()=} opt_successCallback Callback called on success.
+ * @param {function()=} opt_errorCallback Callback called on error.
+ */
+DirectoryTree.prototype.updateSubDirectories = function(
+    recursive, opt_successCallback, opt_errorCallback) {
+  if (!this.currentPath_)
+    return;
+
+  DirectoryTreeUtil.updateSubDirectories(
+      this,
+      this.directoryModel_,
+      function(entries) {
+        this.entries_ = entries;
+        this.redraw(recursive);
+        if (opt_successCallback)
+          opt_successCallback();
+      }.bind(this),
+      opt_errorCallback);
+};
+
+/**
+ * Redraw the list.
+ * @param {boolean} recursive True if the update is recursively. False if the
+ *     only root items are updated.
+ */
+DirectoryTree.prototype.redraw = function(recursive) {
+  DirectoryTreeUtil.updateSubElementsFromList(
+      this,
+      function(i) { return this.entries_[i]; }.bind(this),
+      this.directoryModel_,
+      recursive);
+};
+
+/**
+ * Invoked when the filter is changed.
+ * @private
+ */
+DirectoryTree.prototype.onFilterChanged_ = function() {
+  // Returns immediately, if the tree is hidden.
+  if (!this.currentPath_ || DirectoryTreeUtil.shouldHideTree(this.currentPath_))
+    return;
+
+  this.redraw(true /* recursive */);
+  cr.dispatchSimpleEvent(this, 'content-updated');
+};
+
+/**
+ * Invoked when a directory is changed.
+ * @param {!UIEvent} event Event.
+ * @private
+ */
+DirectoryTree.prototype.onDirectoryContentChanged_ = function(event) {
+  // Returns immediately, if the tree is hidden.
+  if (!this.currentPath_ || DirectoryTreeUtil.shouldHideTree(this.currentPath_))
+    return;
+
+  if (event.eventType == 'changed') {
+    var path = util.extractFilePath(event.directoryUrl);
+    DirectoryTreeUtil.updateChangedDirectoryItem(path, this);
+  }
+};
+
+/**
+ * Invoked when the current directory is changed.
+ * @param {!UIEvent} event Event.
+ * @private
+ */
+DirectoryTree.prototype.onCurrentDirectoryChanged_ = function(event) {
+  this.selectPath(event.newDirEntry.fullPath);
+};
+
+/**
+ * Returns the path of the selected item.
+ * @return {string} The current path.
+ */
+DirectoryTree.prototype.getCurrentPath = function() {
+  return this.selectedItem ? this.selectedItem.fullPath : null;
+};
+
+/**
+ * Clears the tree.
+ * @param {boolean} redraw Redraw the tree if true.
+ * @private
+ */
+DirectoryTree.prototype.clearTree_ = function(redraw) {
+  this.dirEntry_ = null;
+  this.fullPath = '';
+  this.selectedItem = null;
+  this.entries_ = [];
+
+  if (redraw) {
+    this.redraw(false);
+    cr.dispatchSimpleEvent(this, 'content-updated');
+  }
+};
+
+/**
+ * Sets the margin height for the transparent preview panel at the bottom.
+ * @param {number} margin Margin to be set in px.
+ */
+DirectoryTree.prototype.setBottomMarginForPanel = function(margin) {
+  this.style.paddingBottom = margin + 'px';
+  this.scrollBar_.setBottomMarginForPanel(margin);
+};
+
+/**
+ * Updates the UI after the layout has changed.
+ */
+DirectoryTree.prototype.relayout = function() {
+  cr.dispatchSimpleEvent(this, 'relayout');
+};
diff --git a/chrome/browser/resources/file_manager/js/drag_selector.js b/chrome/browser/resources/file_manager/js/drag_selector.js
index 93bf1c5..9766c6e 100644
--- a/chrome/browser/resources/file_manager/js/drag_selector.js
+++ b/chrome/browser/resources/file_manager/js/drag_selector.js
@@ -238,7 +238,10 @@
       'mousemove', this.onMouseMoveBound_, true);
   this.target_.ownerDocument.removeEventListener(
       'mouseup', this.onMouseUpBound_, true);
+  cr.dispatchSimpleEvent(this.target_, 'dragselectionend');
   this.target_.cachedBounds = null;
-  event.stopPropagation();
   this.target_ = null;
+  // The target may select an item by reacting to the mouseup event.
+  // This surpress to the selecting behavior.
+  event.stopPropagation();
 };
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 d4dbc83..1cf24d7 100644
--- a/chrome/browser/resources/file_manager/js/file_copy_manager.js
+++ b/chrome/browser/resources/file_manager/js/file_copy_manager.js
@@ -120,7 +120,7 @@
     // traversal order, we just keep the ordering.
     if (this.pendingDirectories.length)
       nextEntry = this.pendingDirectories[0];
-    if (this.pendingFiles.length)
+    else if (this.pendingFiles.length)
       nextEntry = this.pendingFiles[0];
   }
   if (nextEntry)
diff --git a/chrome/browser/resources/file_manager/js/file_grid.js b/chrome/browser/resources/file_manager/js/file_grid.js
index afe0c50..281c466 100644
--- a/chrome/browser/resources/file_manager/js/file_grid.js
+++ b/chrome/browser/resources/file_manager/js/file_grid.js
@@ -144,8 +144,10 @@
         new ThumbnailLoader(imageUrl,
                             ThumbnailLoader.LoaderType.IMAGE,
                             metadata,
-                            undefined,
-                            ThumbnailLoader.UseEmbedded.NO_EMBEDDED).
+                            undefined,  // opt_mediaType
+                            FileType.isOnDrive(imageUrl) ?
+                                ThumbnailLoader.UseEmbedded.USE_EMBEDDED :
+                                ThumbnailLoader.UseEmbedded.NO_EMBEDDED).
             load(box,
                 fillMode,
                 ThumbnailLoader.OptimizationMode.DISCARD_DETACHED,
diff --git a/chrome/browser/resources/file_manager/js/file_manager.js b/chrome/browser/resources/file_manager/js/file_manager.js
index fb53dd0..07ce252 100644
--- a/chrome/browser/resources/file_manager/js/file_manager.js
+++ b/chrome/browser/resources/file_manager/js/file_manager.js
@@ -193,9 +193,9 @@
       spaceInnerBar.style.width =
           (100 * usedSpace / sizeStatsResult.totalSizeKB) + '%';
 
-      spaceOuterBar.style.display = '';
+      spaceOuterBar.hidden = false;
     } else {
-      spaceOuterBar.style.display = 'none';
+      spaceOuterBar.hidden = true;
       spaceInfoLabel.textContent = str('FAILED_SPACE_INFO');
     }
   };
@@ -320,9 +320,6 @@
               this.viewOptions_[key] = window.appState.viewOptions[key];
           }
         }
-        // TODO(hirono): Remove this line after the user test.
-        // crbug.com/249242
-        this.noCheckboxes_ = !!this.viewOptions_.noCheckboxes;
         done();
       }.bind(this));
     }.bind(this));
@@ -330,10 +327,8 @@
     // Get the command line option.
     group.add(function(done) {
       chrome.commandLinePrivate.hasSwitch(
-          'file-manager-no-checkboxes', function(flag) {
-        // TODO(hirono): Update this line after the user test.
-        // crbug.com/249242
-        this.noCheckboxes_ = this.noCheckboxes_ || flag;
+          'file-manager-show-checkboxes', function(flag) {
+        this.showCheckboxes_ = flag;
         done();
       }.bind(this));
     }.bind(this));
@@ -583,6 +578,14 @@
     this.hostedButton.checkable = true;
     this.detailViewButton_.checkable = true;
     this.thumbnailViewButton_.checkable = true;
+
+    if (util.platform.runningInBrowser()) {
+      // Supresses the default context menu.
+      this.dialogDom_.addEventListener('contextmenu', function(e) {
+        e.preventDefault();
+        e.stopPropagation();
+      });
+    }
   };
 
   FileManager.prototype.onMaximize = function() {
@@ -630,7 +633,7 @@
         Commands.newFolderCommand, this, this.directoryModel_);
 
     CommandUtil.registerCommand(doc, 'newwindow',
-        Commands.newWindowCommand, this);
+        Commands.newWindowCommand, this, this.directoryModel_);
 
     CommandUtil.registerCommand(doc, 'change-default-app',
         Commands.changeDefaultAppCommand, this);
@@ -678,6 +681,8 @@
     CommandUtil.registerCommand(doc, 'zip-selection',
         Commands.zipSelectionCommand, this, this.directoryModel_);
 
+    CommandUtil.registerCommand(doc, 'share', Commands.shareCommand, this);
+
     CommandUtil.registerCommand(doc, 'search', Commands.searchCommand, this,
         this.dialogDom_.querySelector('#search-box'));
 
@@ -691,6 +696,10 @@
                                   i);
     }
 
+    CommandUtil.registerCommand(doc, 'zoom-in', Commands.zoomInCommand);
+    CommandUtil.registerCommand(doc, 'zoom-out', Commands.zoomOutCommand);
+    CommandUtil.registerCommand(doc, 'zoom-reset', Commands.zoomResetCommand);
+
     CommandUtil.registerCommand(doc, 'cut', Commands.defaultCommand, doc);
     CommandUtil.registerCommand(doc, 'copy', Commands.defaultCommand, doc);
 
@@ -789,11 +798,19 @@
    * @private
    */
   FileManager.prototype.initStrings_ = function(callback) {
-    chrome.fileBrowserPrivate.getStrings(function(strings) {
-      loadTimeData.data = strings;
-      this.loadTimeDataAvailable = true;
-      callback();
-    });
+    // Fetch the strings via the private api if running in the browser window.
+    // Otherwise, read cached strings from the local storage.
+    if (util.platform.runningInBrowser()) {
+      chrome.fileBrowserPrivate.getStrings(function(strings) {
+        loadTimeData.data = strings;
+        callback();
+      });
+    } else {
+      chrome.storage.local.get('strings', function(items) {
+        loadTimeData.data = items['strings'];
+        callback();
+      });
+    }
   };
 
   /**
@@ -832,8 +849,18 @@
 
     this.metadataCache_ = MetadataCache.createFull();
 
-    this.okButton_ = this.dialogDom_.querySelector('.ok');
-    this.cancelButton_ = this.dialogDom_.querySelector('.cancel');
+    this.hasFooterPanel_ =
+        this.dialogType == DialogType.SELECT_SAVEAS_FILE ||
+        this.dialogType == DialogType.SELECT_FOLDER;
+
+    // If the footer panel exists, the buttons are placed there. Otherwise,
+    // the buttons are on the preview panel.
+    var parentPanelOfButtons = this.dialogDom_.querySelector(
+        !this.hasFooterPanel_ ? '.preview-panel' : '.dialog-footer');
+    parentPanelOfButtons.classList.add('button-panel');
+    this.fileTypeSelector_ = parentPanelOfButtons.querySelector('.file-type');
+    this.okButton_ = parentPanelOfButtons.querySelector('.ok');
+    this.cancelButton_ = parentPanelOfButtons.querySelector('.cancel');
 
     // Pre-populate the static localized strings.
     i18nTemplate.process(this.document_, loadTimeData);
@@ -896,7 +923,7 @@
     this.table_ = dom.querySelector('.detail-table');
     this.grid_ = dom.querySelector('.thumbnail-grid');
     this.spinner_ = dom.querySelector('#spinner-with-text');
-    this.showSpinner_(false);
+    this.showSpinner_(true);
 
     this.searchBreadcrumbs_ = new BreadcrumbsController(
          dom.querySelector('#search-breadcrumbs'), this.metadataCache_);
@@ -905,7 +932,7 @@
     this.searchBreadcrumbs_.setHideLast(false);
 
     // Check the option to hide the selecting checkboxes.
-    this.table_.noCheckboxes = this.noCheckboxes_;
+    this.table_.showCheckboxes = this.showCheckboxes_;
 
     var fullPage = this.dialogType == DialogType.FULL_PAGE;
     FileTable.decorate(this.table_, this.metadataCache_, fullPage);
@@ -977,9 +1004,6 @@
     this.dialogDom_.ownerDocument.defaultView.addEventListener(
         'resize', this.onResize_.bind(this));
 
-    if (loadTimeData.getBoolean('ASH'))
-      this.dialogDom_.setAttribute('ash', 'true');
-
     this.filePopup_ = null;
 
     this.searchBoxWrapper_ =
@@ -1066,7 +1090,6 @@
     this.defaultActionMenuItem_.addEventListener('activate',
         this.dispatchSelectionAction_.bind(this));
 
-    this.fileTypeSelector_ = this.dialogDom_.querySelector('#file-type');
     this.initFileTypeFilter_();
 
     util.addIsFocusedMethod();
@@ -1163,6 +1186,9 @@
     var dragEndBound = this.onDragEnd_.bind(this);
     this.table_.list.addEventListener('dragend', dragEndBound);
     this.grid_.addEventListener('dragend', dragEndBound);
+    // This event is published by DragSelector because drag end event is not
+    // published at the end of drag selection.
+    this.table_.list.addEventListener('dragselectionend', dragEndBound);
 
     // TODO(mtomasz, yoshiki): Create sidebar earlier, and here just attach
     // the directory model.
@@ -1250,9 +1276,7 @@
       sortField: sortStatus.field,
       sortDirection: sortStatus.direction,
       columns: [],
-      listType: this.listType_,
-      // TODO(hirono): Remove this line after the user test. crbug.com/249242
-      noCheckboxes: !!this.noCheckboxes_
+      listType: this.listType_
     };
     var cm = this.table_.columnModel;
     for (var i = 0; i < cm.totalSize; i++) {
@@ -1333,11 +1357,11 @@
     if (type == FileManager.ListType.DETAIL) {
       this.table_.dataModel = this.directoryModel_.getFileList();
       this.table_.selectionModel = this.directoryModel_.getFileListSelection();
-      this.table_.style.display = '';
-      this.grid_.style.display = 'none';
+      this.table_.hidden = false;
+      this.grid_.hidden = true;
       this.grid_.selectionModel = this.emptySelectionModel_;
       this.grid_.dataModel = this.emptyDataModel_;
-      this.table_.style.display = '';
+      this.table_.hidden = false;
       /** @type {cr.ui.List} */
       this.currentList_ = this.table_.list;
       this.detailViewButton_.setAttribute('checked', '');
@@ -1347,11 +1371,11 @@
     } else if (type == FileManager.ListType.THUMBNAIL) {
       this.grid_.dataModel = this.directoryModel_.getFileList();
       this.grid_.selectionModel = this.directoryModel_.getFileListSelection();
-      this.grid_.style.display = '';
-      this.table_.style.display = 'none';
+      this.grid_.hidden = false;
+      this.table_.hidden = true;
       this.table_.selectionModel = this.emptySelectionModel_;
       this.table_.dataModel = this.emptyDataModel_;
-      this.grid_.style.display = '';
+      this.grid_.hidden = false;
       /** @type {cr.ui.List} */
       this.currentList_ = this.grid_;
       this.thumbnailViewButton_.setAttribute('checked', '');
@@ -1537,7 +1561,10 @@
       this.grid_.relayout();
     else
       this.table_.relayout();
-    this.directoryTree_.relayout();
+
+    // May not be available during initialization.
+    if (this.directoryTree_)
+      this.directoryTree_.relayout();
 
     // TODO(mtomasz, yoshiki): Initialize volume list earlier, before
     // file system is available.
@@ -1558,11 +1585,8 @@
    */
   FileManager.prototype.onPreviewPanelVisibilityChanged_ = function(visible) {
     var panelHeight = visible ? this.getPreviewPanelHeight_() : 0;
-
-    if (this.listType_ == FileManager.ListType.THUMBNAIL)
-      this.grid_.setBottomMarginForPanel(panelHeight);
-    else
-      this.table_.setBottomMarginForPanel(panelHeight);
+    this.grid_.setBottomMarginForPanel(panelHeight);
+    this.table_.setBottomMarginForPanel(panelHeight);
     this.directoryTree_.setBottomMarginForPanel(panelHeight);
   };
 
@@ -1770,10 +1794,6 @@
     }
 
     this.okButton_.textContent = okLabel;
-
-    var dialogTitle = this.params_.title || defaultTitle;
-    this.dialogDom_.querySelector('.dialog-title').textContent = dialogTitle;
-
     this.dialogDom_.setAttribute('type', this.dialogType);
   };
 
@@ -2164,6 +2184,9 @@
         this.directoryModel_.getCurrentDirEntry();
   };
 
+  /**
+   * Deletes the selected file and directories recursively.
+   */
   FileManager.prototype.deleteSelection = function() {
     // TODO(mtomasz): Remove this temporary dialog. crbug.com/167364
     var entries = this.getSelection().entries;
@@ -2175,6 +2198,17 @@
     }.bind(this));
   };
 
+  /**
+   * Shows the share dialog for the selected file.
+   */
+  FileManager.prototype.shareSelection = function() {
+    // TODO(mtomasz): Implement it. crbug.com/141396
+  };
+
+  /**
+   * Blinks the selection. Used to give feedback when copying or cutting the
+   * selection.
+   */
   FileManager.prototype.blinkSelection = function() {
     var selection = this.getSelection();
     if (!selection || selection.totalCount == 0)
@@ -2615,15 +2649,18 @@
       clearTimeout(this.scanCompletedTimer_);
       this.scanCompletedTimer_ = null;
     }
+
     if (this.scanUpdatedTimer_) {
       clearTimeout(this.scanUpdatedTimer_);
       this.scanUpdatedTimer_ = null;
     }
 
-    this.cancelSpinnerTimeout_();
-    this.showSpinner_(false);
-    this.showSpinnerTimeout_ =
-        setTimeout(this.showSpinner_.bind(this, true), 500);
+    if (!this.spinner_.hidden) {
+      this.cancelSpinnerTimeout_();
+      this.showSpinner_(false);
+      this.showSpinnerTimeout_ =
+          setTimeout(this.showSpinner_.bind(this, true), 500);
+    }
   };
 
   /**
@@ -3072,7 +3109,7 @@
 
     var shade = this.document_.createElement('div');
     shade.className = 'shade';
-    var footer = this.document_.querySelector('.dialog-footer');
+    var footer = this.dialogDom_.querySelector('.button-panel');
     var progress = footer.querySelector('.progress-track');
     progress.style.width = '0%';
     var cancelled = false;
@@ -3802,15 +3839,4 @@
     this.document_.querySelector('#drive-clear-local-cache').canExecuteChange();
     this.document_.querySelector('#drive-reload').canExecuteChange();
   };
-
-  /**
-   * Set the flag to hide the selecting checkboxes.
-   * This is the alternative for about:flags and to be removed.
-   * TODO(hirono): Remove this function after the user test.
-   * @param {boolean} flag If it's true, the selecting checkboxes are hidden.
-   */
-  window.setNoCheckboxesFlag = function(flag) {
-    fileManager.noCheckboxes_ = flag;
-    fileManager.updateStartupPrefs_();
-  };
 })();
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 b05960e..5e1e0b7 100644
--- a/chrome/browser/resources/file_manager/js/file_manager_commands.js
+++ b/chrome/browser/resources/file_manager/js/file_manager_commands.js
@@ -71,6 +71,14 @@
 };
 
 /**
+ * Sets as the command as always enabled.
+ * @param {Event} event Command event to mark.
+ */
+CommandUtil.canExecuteAlways = function(event) {
+  event.canExecute = true;
+};
+
+/**
  * Returns a single selected/passed entry or null.
  * @param {Event} event Command event.
  * @param {FileManager} fileManager FileManager to use.
@@ -239,8 +247,9 @@
   },
   canExecute: function(event, fileManager, directoryModel) {
     event.canExecute = !fileManager.isOnReadonlyDirectory() &&
+                       !fileManager.isRenamingInProgress() &&
                        !directoryModel.isSearching() &&
-                       !fileManager.isRenamingInProgress();
+                       !directoryModel.isScanning();
   }
 };
 
@@ -248,8 +257,13 @@
  * Initiates new window creation.
  */
 Commands.newWindowCommand = {
-  execute: function(event, fileManager) {
-    chrome.fileBrowserPrivate.openNewWindow(document.location.href);
+  execute: function(event, fileManager, directoryModel) {
+    chrome.runtime.getBackgroundPage(function(background) {
+      var appState = {
+        defaultPath: directoryModel.getCurrentDirPath()
+      };
+      background.launchFileManager(appState);
+    });
   },
   canExecute: function(event, fileManager) {
     event.canExecute = (fileManager.dialogType == DialogType.FULL_PAGE);
@@ -263,9 +277,7 @@
   execute: function(event, fileManager) {
     fileManager.showChangeDefaultAppPicker();
   },
-  canExecute: function(event, fileManager) {
-    event.canExecute = true;
-  }
+  canExecute: CommandUtil.canExecuteAlways
 };
 
 /**
@@ -317,13 +329,11 @@
 Commands.volumeHelpCommand = {
   execute: function() {
     if (fileManager.isOnDrive())
-      chrome.tabs.create({ url: FileManager.GOOGLE_DRIVE_HELP });
+      chrome.windows.create({url: FileManager.GOOGLE_DRIVE_HELP});
     else
-      chrome.tabs.create({ url: FileManager.FILES_APP_HELP });
+      chrome.windows.create({url: FileManager.FILES_APP_HELP});
   },
-  canExecute: function(event, fileManager) {
-    event.canExecute = true;
-  }
+  canExecute: CommandUtil.canExecuteAlways
 };
 
 /**
@@ -331,7 +341,7 @@
  */
 Commands.driveBuySpaceCommand = {
   execute: function() {
-    chrome.tabs.create({ url: FileManager.GOOGLE_DRIVE_BUY_STORAGE });
+    chrome.windows.create({url: FileManager.GOOGLE_DRIVE_BUY_STORAGE});
   },
   canExecute: CommandUtil.canExecuteVisibleOnDriveOnly
 };
@@ -361,7 +371,7 @@
  */
 Commands.driveGoToDriveCommand = {
   execute: function() {
-    chrome.tabs.create({ url: FileManager.GOOGLE_DRIVE_ROOT });
+    chrome.windows.create({url: FileManager.GOOGLE_DRIVE_ROOT});
   },
   canExecute: CommandUtil.canExecuteVisibleOnDriveOnly
 };
@@ -418,42 +428,93 @@
 Commands.togglePinnedCommand = {
   execute: function(event, fileManager) {
     var pin = !event.command.checked;
-    var entry = CommandUtil.getSingleEntry(event, fileManager);
-
-    var showError = function(filesystem) {
-      fileManager.alert.showHtml(str('DRIVE_OUT_OF_SPACE_HEADER'),
-          strf('DRIVE_OUT_OF_SPACE_MESSAGE',
-               unescape(entry.name),
-               util.bytesToString(filesystem.size)));
-    };
-
-    var callback = function() {
-      if (chrome.runtime.lastError && pin) {
-        fileManager.metadataCache_.get(entry, 'filesystem', showError);
-      }
-      // We don't have update events yet, so clear the cached data.
-      fileManager.metadataCache_.clear(entry, 'drive');
-      fileManager.metadataCache_.get(entry, 'drive', function(drive) {
-        fileManager.updateMetadataInUI_('drive', [entry.toURL()], [drive]);
-      });
-    };
-
-    chrome.fileBrowserPrivate.pinDriveFile(entry.toURL(), pin, callback);
     event.command.checked = pin;
-  },
-  canExecute: function(event, fileManager) {
-    var entry = CommandUtil.getSingleEntry(event, fileManager);
-    var drive = entry && fileManager.metadataCache_.getCached(entry, 'drive');
+    var entries = this.getTargetEntries_();
+    var currentEntry;
+    var error = false;
+    var steps = {
+      // Pick an entry and pin it.
+      start: function() {
+        // Check if all the entries are pinned or not.
+        if (entries.length == 0)
+          return;
+        currentEntry = entries.shift();
+        chrome.fileBrowserPrivate.pinDriveFile(
+            currentEntry.toURL(),
+            pin,
+            steps.entryPinned);
+      },
 
-    if (!fileManager.isOnDrive() || !entry || entry.isDirectory || !drive ||
-        drive.hosted) {
-      event.canExecute = false;
-      event.command.setHidden(true);
-    } else {
+      // Check the result of pinning
+      entryPinned: function() {
+        // Convert to boolean.
+        error = !!chrome.runtime.lastError;
+        if (error && pin) {
+          fileManager.metadataCache_.get(
+              currentEntry, 'filesystem', steps.showError);
+        }
+        fileManager.metadataCache_.clear(currentEntry, 'drive');
+        fileManager.metadataCache_.get(
+            currentEntry, 'drive', steps.updateUI.bind(this));
+      },
+
+      // Update the user interface accoding to the cache state.
+      updateUI: function(drive) {
+        fileManager.updateMetadataInUI_(
+            'drive', [currentEntry.toURL()], [drive]);
+        if (!error)
+          steps.start();
+      },
+
+      // Show the error
+      showError: function(filesystem) {
+        fileManager.alert.showHtml(str('DRIVE_OUT_OF_SPACE_HEADER'),
+                                   strf('DRIVE_OUT_OF_SPACE_MESSAGE',
+                                        unescape(currentEntry.name),
+                                        util.bytesToString(filesystem.size)));
+      }
+    };
+    steps.start();
+  },
+
+  canExecute: function(event, fileManager) {
+    var entries = this.getTargetEntries_();
+    var checked = true;
+    for (var i = 0; i < entries.length; i++) {
+      checked = checked && entries[i].pinned;
+    }
+    if (entries.length > 0) {
       event.canExecute = true;
       event.command.setHidden(false);
-      event.command.checked = drive.pinned;
+      event.command.checked = checked;
+    } else {
+      event.canExecute = false;
+      event.command.setHidden(true);
     }
+  },
+
+  /**
+   * Obtains target entries from the selection.
+   * If directories are included in the selection, it just returns an empty
+   * array to avoid confusing because pinning directory is not supported
+   * currently.
+   *
+   * @return {Array.<Entry>} Target entries.
+   * @private
+   */
+  getTargetEntries_: function() {
+    var hasDirectory = false;
+    var results = fileManager.getSelection().entries.filter(function(entry) {
+      hasDirectory = hasDirectory || entry.isDirectory;
+      if (!entry || hasDirectory)
+        return false;
+      var metadata = fileManager.metadataCache_.getCached(entry, 'drive');
+        if (!metadata || metadata.hosted)
+          return false;
+      entry.pinned = metadata.pinned;
+      return true;
+    });
+    return hasDirectory ? [] : results;
   }
 };
 
@@ -474,3 +535,49 @@
         selection && selection.totalCount > 0;
   }
 };
+
+/**
+ * Shows the share dialog for the current selection (single only).
+ */
+Commands.shareCommand = {
+  execute: function(event, fileManager) {
+    fileManager.shareSelection();
+  },
+  canExecute: function(event, fileManager) {
+    var selection = fileManager.getSelection();
+    event.canExecute = fileManager.isOnDrive() &&
+        !fileManager.isDriveOffline() &&
+        selection && selection.totalCount == 1;
+    event.command.setHidden(!fileManager.isOnDrive());
+  }
+};
+
+/**
+ * Zoom in to the Files.app.
+ */
+Commands.zoomInCommand = {
+  execute: function(event) {
+    chrome.fileBrowserPrivate.zoom('in');
+  },
+  canExecute: CommandUtil.canExecuteAlways
+};
+
+/**
+ * Zoom out from the Files.app.
+ */
+Commands.zoomOutCommand = {
+  execute: function(event) {
+    chrome.fileBrowserPrivate.zoom('out');
+  },
+  canExecute: CommandUtil.canExecuteAlways
+};
+
+/**
+ * Reset the zoom factor.
+ */
+Commands.zoomResetCommand = {
+  execute: function(event) {
+    chrome.fileBrowserPrivate.zoom('reset');
+  },
+  canExecute: CommandUtil.canExecuteAlways
+};
diff --git a/chrome/browser/resources/file_manager/js/file_selection.js b/chrome/browser/resources/file_manager/js/file_selection.js
index cd7b1ee..5228dca 100644
--- a/chrome/browser/resources/file_manager/js/file_selection.js
+++ b/chrome/browser/resources/file_manager/js/file_selection.js
@@ -325,8 +325,14 @@
 FileSelectionHandler.prototype.updatePreviewPanelVisibility_ = function() {
   var panel = this.previewPanel_;
   var state = panel.getAttribute('visibility');
-  var mustBeVisible = (this.selection.totalCount > 0 ||
-      !PathUtil.isRootPath(this.fileManager_.getCurrentDirectory()));
+  var mustBeVisible =
+       // If one or more files are selected, show the file info.
+      (this.selection.totalCount > 0 ||
+       // If the directory is not root dir, show the directory info.
+       !PathUtil.isRootPath(this.fileManager_.getCurrentDirectory()) ||
+       // On Open File dialog, the preview panel is always shown.
+       this.fileManager_.dialogType == DialogType.SELECT_OPEN_FILE ||
+       this.fileManager_.dialogType == DialogType.SELECT_OPEN_MULTI_FILE);
 
   var stopHidingAndShow = function() {
     clearTimeout(this.hidingTimeout_);
@@ -375,7 +381,7 @@
  * @private
  */
 FileSelectionHandler.prototype.isPreviewPanelVisibile_ = function() {
-  return this.previewPanel_.getAttribute('visibility') != 'hidden';
+  return this.previewPanel_.getAttribute('visibility') == 'visible';
 };
 
 /**
@@ -512,9 +518,10 @@
   if (selection.totalCount == 1) {
     // Shows the breadcrumb list when a file is selected.
     updateTarget = selection.entries[0].fullPath;
-  } else if (selection.totalCount == 0 && !PathUtil.isRootPath(path)) {
-    // Shows the breadcrumb list when no file is selected and the current
-    // directory is non-root path.
+  } else if (selection.totalCount == 0 &&
+             this.isPreviewPanelVisibile_()) {
+    // Shows the breadcrumb list when no file is selected and the preview
+    // panel is visible.
     updateTarget = path;
   }
   this.updatePreviewPanelBreadcrumbs_(updateTarget);
diff --git a/chrome/browser/resources/file_manager/js/file_table.js b/chrome/browser/resources/file_manager/js/file_table.js
index 70dcea8..57f870e 100644
--- a/chrome/browser/resources/file_manager/js/file_table.js
+++ b/chrome/browser/resources/file_manager/js/file_table.js
@@ -240,7 +240,7 @@
 
   var tableColumnModelClass;
   tableColumnModelClass = FileTableColumnModel;
-  if (!self.noCheckboxes) {
+  if (self.showCheckboxes) {
     columns.push(new cr.ui.table.TableColumn('selection',
                                              '',
                                              50, true));
@@ -971,10 +971,9 @@
       li.classList.remove('dim-offline');
     else
       li.classList.add('dim-offline');
-    if (driveProps.availableWhenMetered)
-      li.classList.remove('dim-metered');
-    else
-      li.classList.add('dim-metered');
+    // TODO(mtomasz): Consider adding some vidual indication for files which
+    // are not cached on LTE. Currently we show them as normal files.
+    // crbug.com/246611.
   }
 
   if (driveProps.driveApps.length > 0) {
diff --git a/chrome/browser/resources/file_manager/js/file_tasks.js b/chrome/browser/resources/file_manager/js/file_tasks.js
index 988e50c..329b29b 100644
--- a/chrome/browser/resources/file_manager/js/file_tasks.js
+++ b/chrome/browser/resources/file_manager/js/file_tasks.js
@@ -274,8 +274,10 @@
           if (props && props[0] && props[0].contentMimeType)
             mimeType = props[0].contentMimeType;
 
+          var messageString = extension == 'exe' ? 'NO_ACTION_FOR_EXECUTABLE' :
+                                                   'NO_ACTION_FOR_FILE';
           var webStoreUrl = FileTasks.createWebStoreLink(extension, mimeType);
-          var text = loadTimeData.getStringF('NO_ACTION_FOR_FILE',
+          var text = loadTimeData.getStringF(messageString,
                                              webStoreUrl,
                                              FileTasks.NO_ACTION_FOR_FILE_URL);
           this.fileManager_.alert.showHtml(filename, text, function() {});
diff --git a/chrome/browser/resources/file_manager/js/file_transfer_controller.js b/chrome/browser/resources/file_manager/js/file_transfer_controller.js
index 7424267..1d5a90a 100644
--- a/chrome/browser/resources/file_manager/js/file_transfer_controller.js
+++ b/chrome/browser/resources/file_manager/js/file_transfer_controller.js
@@ -263,7 +263,8 @@
     // Option 2. Thumbnail image available, then render it without
     // a label.
     if (thumbnailImage) {
-      contents.classList.add('drag-image-thumbnail');
+      thumbnailImage.classList.add('drag-thumbnail');
+      contents.classList.add('for-image');
       contents.appendChild(this.preloadedThumbnailImageNode_);
       return container;
     }
@@ -289,7 +290,7 @@
   onDragStart_: function(list, event) {
     // Check if a drag selection should be initiated or not.
     // TODO(hirono): Support drag selection on the grid view. crbug.com/247278
-    if (list.id == 'file-list') {
+    if (list.id == 'file-list' && list.parentNode.id == 'detail-table') {
       if (list.parentNode.shouldStartDragSelection(event)) {
         this.dragSelector_.startDragSelection(list, event);
         return;
@@ -398,22 +399,6 @@
 
   /**
    * @this {FileTransferController}
-   * @param {HTMLElement} breadcrumbsContainer Element which contains target
-   *     breadcrumbs.
-   * @param {Event} event A dragenter event of DOM.
-   */
-  onDragEnterBreadcrumbs_: function(breadcrumbsContainer, event) {
-    event.preventDefault();  // Required to prevent the cursor flicker.
-    this.lastEnteredTarget_ = event.target;
-    var path = breadcrumbsContainer.getTargetPath(event);
-    if (!path)
-      return;
-
-    this.setDropTarget_(event.target, true, event.dataTransfer, path);
-  },
-
-  /**
-   * @this {FileTransferController}
    * @param {cr.ui.List} list Drop target list.
    * @param {Event} event A dragleave event of DOM.
    */
diff --git a/chrome/browser/resources/file_manager/js/image_editor/image_adjust.js b/chrome/browser/resources/file_manager/js/image_editor/image_adjust.js
index 76d70e8..e29aca0 100644
--- a/chrome/browser/resources/file_manager/js/image_editor/image_adjust.js
+++ b/chrome/browser/resources/file_manager/js/image_editor/image_adjust.js
@@ -135,7 +135,7 @@
  * @constructor
  */
 ImageEditor.Mode.Exposure = function() {
-  ImageEditor.Mode.ColorFilter.call(this, 'exposure');
+  ImageEditor.Mode.ColorFilter.call(this, 'exposure', 'GALLERY_EXPOSURE');
 };
 
 ImageEditor.Mode.Exposure.prototype =
@@ -146,8 +146,8 @@
  * @param {ImageEditor.Toolbar} toolbar The toolbar to populate.
  */
 ImageEditor.Mode.Exposure.prototype.createTools = function(toolbar) {
-  toolbar.addRange('brightness', -1, 0, 1, 100);
-  toolbar.addRange('contrast', -1, 0, 1, 100);
+  toolbar.addRange('brightness', 'GALLERY_BRIGHTNESS', -1, 0, 1, 100);
+  toolbar.addRange('contrast', 'GALLERY_CONTRAST', -1, 0, 1, 100);
 };
 
 /**
@@ -155,7 +155,7 @@
  * @constructor
  */
 ImageEditor.Mode.Autofix = function() {
-  ImageEditor.Mode.ColorFilter.call(this, 'autofix');
+  ImageEditor.Mode.ColorFilter.call(this, 'autofix', 'GALLERY_AUTOFIX');
   this.doneMessage_ = 'fixed';
 };
 
@@ -223,8 +223,8 @@
  * @param {ImageEditor.Toolbar} toolbar The toolbar to populate.
  */
 ImageEditor.Mode.Blur.prototype.createTools = function(toolbar) {
-  toolbar.addRange('strength', 0, 0, 1, 100);
-  toolbar.addRange('radius', 1, 1, 3);
+  toolbar.addRange('strength', 'GALLERY_STRENGTH', 0, 0, 1, 100);
+  toolbar.addRange('radius', 'GALLERY_RADIUS', 1, 1, 3);
 };
 
 /**
@@ -243,6 +243,6 @@
  * @param {ImageEditor.Toolbar} toolbar The toolbar to populate.
  */
 ImageEditor.Mode.Sharpen.prototype.createTools = function(toolbar) {
-  toolbar.addRange('strength', 0, 0, 1, 100);
-  toolbar.addRange('radius', 1, 1, 3);
+  toolbar.addRange('strength', 'GALLERY_STRENGTH', 0, 0, 1, 100);
+  toolbar.addRange('radius', 'GALLERY_RADIUS', 1, 1, 3);
 };
diff --git a/chrome/browser/resources/file_manager/js/image_editor/image_editor.js b/chrome/browser/resources/file_manager/js/image_editor/image_editor.js
index 1f42ed0..440a26a 100644
--- a/chrome/browser/resources/file_manager/js/image_editor/image_editor.js
+++ b/chrome/browser/resources/file_manager/js/image_editor/image_editor.js
@@ -261,15 +261,18 @@
 
 /**
  * ImageEditor.Mode represents a modal state dedicated to a specific operation.
- * Inherits from ImageBuffer.Overlay to simplify the drawing of
- * mode-specific tools.
+ * Inherits from ImageBuffer. Overlay to simplify the drawing of mode-specific
+ * tools.
+ *
  * @param {string} name The mode name.
+ * @param {string} title The mode title.
  * @constructor
  */
 
-ImageEditor.Mode = function(name) {
+ImageEditor.Mode = function(name, title) {
   this.name = name;
-  this.message_ = 'enter_when_done';
+  this.title = title;
+  this.message_ = 'GALLERY_ENTER_WHEN_DONE';
 };
 
 ImageEditor.Mode.prototype = {__proto__: ImageBuffer.Overlay.prototype };
@@ -365,12 +368,14 @@
 
 /**
  * One-click editor tool, requires no interaction, just executes the command.
+ *
  * @param {string} name The mode name.
+ * @param {string} title The mode title.
  * @param {Command} command The command to execute on click.
  * @constructor
  */
-ImageEditor.Mode.OneClick = function(name, command) {
-  ImageEditor.Mode.call(this, name);
+ImageEditor.Mode.OneClick = function(name, title, command) {
+  ImageEditor.Mode.call(this, name, title);
   this.instant = true;
   this.command_ = command;
 };
@@ -401,19 +406,28 @@
   this.actionNames_ = [];
 
   var self = this;
-  function createButton(name, handler) {
-    return self.mainToolbar_.addButton(name, handler, name);
+  function createButton(name, title, handler) {
+    return self.mainToolbar_.addButton(name,
+                                       title,
+                                       handler,
+                                       name /* opt_className */);
   }
 
   for (var i = 0; i != this.modes_.length; i++) {
     var mode = this.modes_[i];
-    mode.bind(this, createButton(mode.name, this.enterMode.bind(this, mode)));
+    mode.bind(this, createButton(mode.name,
+                                 mode.title,
+                                 this.enterMode.bind(this, mode)));
   }
 
-  this.undoButton_ = createButton('undo', this.undo.bind(this));
+  this.undoButton_ = createButton('undo',
+                                  'GALLERY_UNDO',
+                                  this.undo.bind(this));
   this.registerAction_('undo');
 
-  this.redoButton_ = createButton('redo', this.redo.bind(this));
+  this.redoButton_ = createButton('redo',
+                                  'GALLERY_REDO',
+                                  this.redo.bind(this));
   this.registerAction_('redo');
 };
 
@@ -921,19 +935,21 @@
 
 /**
  * Add a button.
+ *
  * @param {string} name Button name.
+ * @param {string} title Button title.
  * @param {function} handler onClick handler.
  * @param {string=} opt_class Extra class name.
  * @return {HTMLElement} The added button.
  */
 ImageEditor.Toolbar.prototype.addButton = function(
-    name, handler, opt_class) {
+    name, title, handler, opt_class) {
   var button = this.create_('button');
   if (opt_class) button.classList.add(opt_class);
   var label = this.create_('span');
-  label.textContent = this.displayStringFunction_(name);
+  label.textContent = this.displayStringFunction_(title);
   button.appendChild(label);
-  button.label = this.displayStringFunction_(name);
+  button.label = this.displayStringFunction_(title);
   button.addEventListener('click', handler, false);
   return this.add(button);
 };
@@ -942,6 +958,7 @@
  * Add a range control (scalar value picker).
  *
  * @param {string} name An option name.
+ * @param {string} title An option title.
  * @param {number} min Min value of the option.
  * @param {number} value Default value of the option.
  * @param {number} max Max value of the options.
@@ -951,7 +968,7 @@
  * @return {HTMLElement} Range element.
  */
 ImageEditor.Toolbar.prototype.addRange = function(
-    name, min, value, max, scale, opt_showNumeric) {
+    name, title, min, value, max, scale, opt_showNumeric) {
   var self = this;
 
   scale = scale || 1;
@@ -993,7 +1010,7 @@
   range.setValue(value);
 
   var label = this.create_('div');
-  label.textContent = this.displayStringFunction_(name);
+  label.textContent = this.displayStringFunction_(title);
   label.className = 'label ' + name;
   this.add(label);
   this.add(range);
diff --git a/chrome/browser/resources/file_manager/js/image_editor/image_transform.js b/chrome/browser/resources/file_manager/js/image_editor/image_transform.js
index 8b58e73..de8409f 100644
--- a/chrome/browser/resources/file_manager/js/image_editor/image_transform.js
+++ b/chrome/browser/resources/file_manager/js/image_editor/image_transform.js
@@ -9,7 +9,7 @@
  * @constructor
  */
 ImageEditor.Mode.Crop = function() {
-  ImageEditor.Mode.call(this, 'crop');
+  ImageEditor.Mode.call(this, 'crop', 'GALLERY_CROP');
 };
 
 ImageEditor.Mode.Crop.prototype = {__proto__: ImageEditor.Mode.prototype};
diff --git a/chrome/browser/resources/file_manager/js/image_editor/image_view.js b/chrome/browser/resources/file_manager/js/image_editor/image_view.js
index 4b1f7da..08e6bd7 100644
--- a/chrome/browser/resources/file_manager/js/image_editor/image_view.js
+++ b/chrome/browser/resources/file_manager/js/image_editor/image_view.js
@@ -429,9 +429,8 @@
   }
 
   function displayMainImage(loadType, previewShown, content, opt_error) {
-    if (opt_error) {
+    if (opt_error)
       loadType = ImageView.LOAD_TYPE_ERROR;
-    }
 
     // If we already displayed the preview we should not replace the content if:
     //   1. The full content failed to load.
@@ -550,6 +549,8 @@
     this.videoElement_ = content;
     this.screenImage_ = content;
     this.screenImage_.className = 'image';
+    this.container_.appendChild(this.screenImage_);
+    this.videoElement_.play();
     return;
   }
 
@@ -646,7 +647,6 @@
   if (oldScreenImage)
     ImageUtil.setAttribute(newScreenImage, 'fade', true);
   this.setTransform(newScreenImage, opt_effect, 0 /* instant */);
-  this.container_.appendChild(newScreenImage);
 
   setTimeout(function() {
     this.setTransform(newScreenImage, null,
diff --git a/chrome/browser/resources/file_manager/js/main_scripts.js b/chrome/browser/resources/file_manager/js/main_scripts.js
index dcb39ce..a99f813 100644
--- a/chrome/browser/resources/file_manager/js/main_scripts.js
+++ b/chrome/browser/resources/file_manager/js/main_scripts.js
@@ -24,7 +24,7 @@
 // //so we want to parse it as early as possible.
 //<include src="metrics.js"/>
 //
-//<include src="../../image_loader/client.js"/>
+//<include src="../../image_loader/image_loader_client.js"/>
 //
 //<include src="../../../../../ui/webui/resources/js/load_time_data.js"/>
 //<include src="../../../../../ui/webui/resources/js/cr.js"/>
@@ -77,6 +77,7 @@
 //<include src="butter_bar.js"/>
 //<include src="directory_contents.js"/>
 //<include src="directory_model.js"/>
+//<include src="directory_tree.js"/>
 //<include src="drag_selector.js"/>
 //<include src="drive_banners.js" />
 //<include src="error_dialog.js"/>
@@ -90,7 +91,6 @@
 //<include src="file_transfer_controller.js"/>
 //<include src="file_type.js"/>
 //<include src="scrollbar.js"/>
-//<include src="sidebar.js"/>
 //<include src="tree.css.js"/>
 //<include src="volume_list.js"/>
 //<include src="volume_manager.js"/>
diff --git a/chrome/browser/resources/file_manager/js/media/media_controls.js b/chrome/browser/resources/file_manager/js/media/media_controls.js
index 670900d..ba07c3d 100644
--- a/chrome/browser/resources/file_manager/js/media/media_controls.js
+++ b/chrome/browser/resources/file_manager/js/media/media_controls.js
@@ -161,11 +161,21 @@
 };
 
 /**
+ * Toggle play/pause state on a mouse click on the play/pause button. Can be
+ * called externally. TODO(mtomasz): Remove it. http://www.crbug.com/254318.
+ *
+ * @param {Event=} opt_event Mouse click event.
+ */
+MediaControls.prototype.onPlayButtonClicked = function(opt_event) {
+  this.togglePlayState();
+};
+
+/**
  * @param {HTMLElement=} opt_parent Parent container.
  */
 MediaControls.prototype.initPlayButton = function(opt_parent) {
   this.playButton_ = this.createButton('play media-control',
-      this.togglePlayState.bind(this), opt_parent, 3 /* States. */);
+      this.onPlayButtonClicked.bind(this), opt_parent, 3 /* States. */);
 };
 
 /*
@@ -961,21 +971,21 @@
  *
  * @param {HTMLElement} containerElement The container for the controls.
  * @param {function} onMediaError Function to display an error message.
+ * @param {function(string):string} stringFunction Function providing localized
+ *     strings.
  * @param {function=} opt_fullScreenToggle Function to toggle fullscreen mode.
  * @param {HTMLElement=} opt_stateIconParent The parent for the icon that
  *     gives visual feedback when the playback state changes.
  * @constructor
  */
-function VideoControls(containerElement, onMediaError,
+function VideoControls(containerElement, onMediaError, stringFunction,
    opt_fullScreenToggle, opt_stateIconParent) {
   MediaControls.call(this, containerElement, onMediaError);
+  this.stringFunction_ = stringFunction;
 
   this.container_.classList.add('video-controls');
-
   this.initPlayButton();
-
   this.initTimeControls(true /* show seek mark */);
-
   this.initVolumeControls();
 
   if (opt_fullScreenToggle) {
@@ -986,6 +996,7 @@
   if (opt_stateIconParent) {
     this.stateIcon_ = this.createControl(
         'playback-state-icon', opt_stateIconParent);
+    this.textBanner_ = this.createControl('text-banner', opt_stateIconParent);
   }
 
   var videoControls = this;
@@ -1011,6 +1022,47 @@
 VideoControls.prototype = { __proto__: MediaControls.prototype };
 
 /**
+ * Shows icon feedback for the current state of the video player.
+ * @private
+ */
+VideoControls.prototype.showIconFeedback_ = function() {
+  this.stateIcon_.removeAttribute('state');
+  setTimeout(function() {
+    this.stateIcon_.setAttribute('state', this.isPlaying() ? 'play' : 'pause');
+  }.bind(this), 0);
+};
+
+/**
+ * Shows a text banner.
+ *
+ * @param {string} identifier String identifier.
+ * @private
+ */
+VideoControls.prototype.showTextBanner_ = function(identifier) {
+  this.textBanner_.removeAttribute('visible');
+  this.textBanner_.textContent = this.stringFunction_(identifier);
+  setTimeout(function() {
+    this.textBanner_.setAttribute('visible', 'true');
+  }.bind(this), 0);
+};
+
+/**
+ * Toggle play/pause state on a mouse click on the play/pause button. Can be
+ * called externally.
+ *
+ * @param {Event} event Mouse click event.
+ */
+VideoControls.prototype.onPlayButtonClicked = function(event) {
+  if (event.ctrlKey) {
+    this.toggleLoopedModeWithFeedback(true);
+    if (!this.isPlaying())
+      this.togglePlayState();
+  } else {
+    this.togglePlayState();
+  }
+};
+
+/**
  * Media completion handler.
  */
 VideoControls.prototype.onMediaComplete = function() {
@@ -1019,33 +1071,52 @@
 };
 
 /**
- * Toggle play/pause state and flash an icon over the video.
+ * Toggles the looped mode with feedback.
+ * @param {boolean} on Whether enabled or not.
+ */
+VideoControls.prototype.toggleLoopedModeWithFeedback = function(on) {
+  if (!this.getMedia().duration)
+    return;
+  this.toggleLoopedMode(on);
+  if (on) {
+    // TODO(mtomasz): Simplify, crbug.com/254318.
+    this.showTextBanner_('GALLERY_VIDEO_LOOPED_MODE');
+  }
+};
+
+/**
+ * Toggles the looped mode.
+ * @param {boolean} on Whether enabled or not.
+ */
+VideoControls.prototype.toggleLoopedMode = function(on) {
+  this.getMedia().loop = on;
+};
+
+/**
+ * Toggles play/pause state and flash an icon over the video.
  */
 VideoControls.prototype.togglePlayStateWithFeedback = function() {
   if (!this.getMedia().duration)
     return;
 
   this.togglePlayState();
-
-  this.stateIcon_.removeAttribute('state');
-  setTimeout(function() {
-    this.stateIcon_.setAttribute('state', this.isPlaying() ? 'play' : 'pause');
-  }.bind(this), 0);
+  this.showIconFeedback_();
 };
 
 /**
- * Toggle play/pause state.
+ * Toggles play/pause state.
  */
 VideoControls.prototype.togglePlayState = function() {
   if (this.isPlaying()) {
-    // User gave the Pause command.
+    // User gave the Pause command. Save the state and reset the loop mode.
+    this.toggleLoopedMode(false);
     this.savePosition();
   }
   MediaControls.prototype.togglePlayState.apply(this, arguments);
 };
 
 /**
- * Save the playback position to the persistent storage.
+ * Saves the playback position to the persistent storage.
  * @param {boolean=} opt_sync True if the position must be saved synchronously
  *     (required when closing app windows).
  */
@@ -1079,7 +1150,7 @@
 };
 
 /**
- * Resume the playback position saved in the persistent storage.
+ * Resumes the playback position saved in the persistent storage.
  */
 VideoControls.prototype.restorePlayState = function() {
   if (this.media_.duration >= VideoControls.RESUME_THRESHOLD) {
@@ -1091,7 +1162,7 @@
 };
 
 /**
- * Update style to best fit the size of the container.
+ * Updates style to best fit the size of the container.
  */
 VideoControls.prototype.updateStyle = function() {
   // We assume that the video controls element fills the parent container.
@@ -1115,7 +1186,7 @@
 };
 
 /**
- * Create audio controls.
+ * Creates audio controls.
  *
  * @param {HTMLElement} container Parent container.
  * @param {function(boolean)} advanceTrack Parameter: true=forward.
diff --git a/chrome/browser/resources/file_manager/js/media/media_util.js b/chrome/browser/resources/file_manager/js/media/media_util.js
index db09006..af77c9c 100644
--- a/chrome/browser/resources/file_manager/js/media/media_util.js
+++ b/chrome/browser/resources/file_manager/js/media/media_util.js
@@ -205,6 +205,7 @@
     this.image_.onload = function() {};
     this.image_.onerror = function() {};
     util.cancelLoadImage(this.taskId_);
+    this.taskId_ = null;
   }
 };
 
diff --git a/chrome/browser/resources/file_manager/js/media/util.js b/chrome/browser/resources/file_manager/js/media/util.js
index bddd709..4d3c953 100644
--- a/chrome/browser/resources/file_manager/js/media/util.js
+++ b/chrome/browser/resources/file_manager/js/media/util.js
@@ -44,6 +44,11 @@
   });
 
   this.container_.addEventListener('mousemove', this.onMouseMove_.bind(this));
+  var tools = this.container_.querySelector('.tool');
+  for (var i = 0; i < tools.length; i++) {
+    tools[i].addEventListener('mouseover', this.onToolMouseOver_.bind(this));
+    tools[i].addEventListener('mouseout', this.onToolMouseOut_.bind(this));
+  }
 
   // Show tools when the user touches the screen.
   this.container_.addEventListener(
@@ -69,15 +74,6 @@
 };
 
 /**
- * @param {Element} element DOM element.
- * @return {boolean} True if the element is a tool. Tools should never be hidden
- *   while the mouse is over one of them.
- */
-MouseInactivityWatcher.prototype.isToolElement = function(element) {
-  return element.classList.contains('tool');
-};
-
-/**
  * To be called when the user started activity. Shows the tools
  * and cancels the countdown.
  * @private
@@ -142,19 +138,34 @@
   this.clientX_ = e.clientX;
   this.clientY_ = e.clientY;
 
-  this.mouseOverTool_ = false;
-  for (var elem = e.target; elem != this.container_; elem = elem.parentNode) {
-    if (this.isToolElement(elem)) {
-      this.mouseOverTool_ = true;
-      break;
-    }
-  }
-
   if (this.disabled_)
     return;
 
-  this.activityStarted_();
-  this.activityStopped_();
+  this.kick();
+};
+
+/**
+ * Mouse over handler on a tool element.
+ *
+ * @param {Event} e Event.
+ * @private
+ */
+MouseInactivityWatcher.prototype.onToolMouseOver_ = function(e) {
+  this.mouseOverTool_ = true;
+  if (!this.disabled_)
+    this.kick();
+};
+
+/**
+ * Mouse out handler on a tool element.
+ *
+ * @param {Event} e Event.
+ * @private
+ */
+MouseInactivityWatcher.prototype.onToolMouseOut_ = function(e) {
+  this.mouseOverTool_ = false;
+  if (!this.disabled_)
+    this.kick();
 };
 
 /**
diff --git a/chrome/browser/resources/file_manager/js/media/video_player.js b/chrome/browser/resources/file_manager/js/media/video_player.js
index 040b08f..2a0ca66 100644
--- a/chrome/browser/resources/file_manager/js/media/video_player.js
+++ b/chrome/browser/resources/file_manager/js/media/video_player.js
@@ -50,6 +50,7 @@
   VideoControls.call(this,
       controlsContainer,
       onPlaybackError,
+      loadTimeData.getString.bind(loadTimeData),
       this.toggleFullScreen_.bind(this),
       videoContainer);
 
@@ -71,8 +72,16 @@
     }
   }.bind(this));
 
-  videoContainer.addEventListener('click',
-      this.togglePlayStateWithFeedback.bind(this));
+  // TODO(mtomasz): Simplify. crbug.com/254318.
+  videoContainer.addEventListener('click', function(e) {
+    if (e.ctrlKey) {
+      this.toggleLoopedModeWithFeedback(true);
+      if (!this.isPlaying())
+        this.togglePlayStateWithFeedback();
+    } else {
+      this.togglePlayStateWithFeedback();
+    }
+  }.bind(this));
 
   this.inactivityWatcher_ = new MouseInactivityWatcher(playerContainer);
   this.__defineGetter__('inactivityWatcher', function() {
diff --git a/chrome/browser/resources/file_manager/js/metadata/metadata_dispatcher.js b/chrome/browser/resources/file_manager/js/metadata/metadata_dispatcher.js
index ffa9a39..270282f 100644
--- a/chrome/browser/resources/file_manager/js/metadata/metadata_dispatcher.js
+++ b/chrome/browser/resources/file_manager/js/metadata/metadata_dispatcher.js
@@ -214,7 +214,7 @@
 // the 'this' keyword in lambdas.
 var global = self;
 
-if (global.constructor.name == 'SharedWorkerContext') {
+if (global.constructor.name == 'SharedWorkerGlobalScope') {
   global.addEventListener('connect', function(e) {
     var port = e.ports[0];
     new MetadataDispatcher(port);
diff --git a/chrome/browser/resources/file_manager/js/photo/gallery.js b/chrome/browser/resources/file_manager/js/photo/gallery.js
index 2b1cc2c..c942d75 100644
--- a/chrome/browser/resources/file_manager/js/photo/gallery.js
+++ b/chrome/browser/resources/file_manager/js/photo/gallery.js
@@ -56,16 +56,10 @@
 
   this.dataModel_ = new cr.ui.ArrayDataModel([]);
   this.selectionModel_ = new cr.ui.ListSelectionModel();
+  this.displayStringFunction_ = context.displayStringFunction;
 
-  var strf = context.displayStringFunction;
-  this.displayStringFunction_ = function(id, formatArgs) {
-    var args = Array.prototype.slice.call(arguments);
-    args[0] = 'GALLERY_' + id.toUpperCase();
-    return strf.apply(null, args);
-  };
-
-  this.initListeners_();
   this.initDom_();
+  this.initListeners_();
 }
 
 /**
@@ -326,10 +320,14 @@
     cr.dispatchSimpleEvent(this, 'image-saved');
   }.bind(this));
 
-  var deleteButton = this.createToolbarButton_('delete', 'delete');
-  deleteButton.addEventListener('click', this.onDelete_.bind(this));
+  this.printButton_ = this.createToolbarButton_('print', 'GALLERY_PRINT');
+  this.printButton_.setAttribute('disabled', '');
+  this.printButton_.addEventListener('click', this.print_.bind(this));
 
-  this.shareButton_ = this.createToolbarButton_('share', 'share');
+  var deleteButton = this.createToolbarButton_('delete', 'GALLERY_DELETE');
+  deleteButton.addEventListener('click', this.delete_.bind(this));
+
+  this.shareButton_ = this.createToolbarButton_('share', 'GALLERY_SHARE');
   this.shareButton_.setAttribute('disabled', '');
   this.shareButton_.addEventListener('click', this.toggleShare_.bind(this));
 
@@ -341,22 +339,19 @@
   this.dataModel_.addEventListener('content', this.onContentChange_.bind(this));
 
   this.selectionModel_.addEventListener('change', this.onSelection_.bind(this));
-
   this.slideMode_.addEventListener('useraction', this.onUserAction_.bind(this));
-
-  document.body.setAttribute('new-ui', '');
 };
 
 /**
  * Creates toolbar button.
  *
- * @param {string} clazz Class to add.
+ * @param {string} className Class to add.
  * @param {string} title Button title.
  * @return {HTMLElement} Newly created button.
  * @private
  */
-Gallery.prototype.createToolbarButton_ = function(clazz, title) {
-  var button = util.createChild(this.toolbar_, clazz, 'button');
+Gallery.prototype.createToolbarButton_ = function(className, title) {
+  var button = util.createChild(this.toolbar_, className, 'button');
   button.title = this.displayStringFunction_(title);
   return button;
 };
@@ -506,8 +501,15 @@
     var oppositeMode =
         mode == this.slideMode_ ? this.mosaicMode_ : this.slideMode_;
     this.modeButton_.title =
-        this.displayStringFunction_(oppositeMode.getName());
+        this.displayStringFunction_(oppositeMode.getTitle());
   }
+
+  // Printing is available only in the slide view.
+  if (mode == this.slideMode_)
+    this.printButton_.removeAttribute('disabled');
+  else
+    this.printButton_.setAttribute('disabled', '');
+
   this.container_.setAttribute('mode', this.currentMode_.getName());
   this.updateSelectionAndState_();
 };
@@ -564,10 +566,10 @@
 };
 
 /**
- * Delete event handler.
+ * Deletes the selected items.
  * @private
  */
-Gallery.prototype.onDelete_ = function() {
+Gallery.prototype.delete_ = function() {
   this.onUserAction_();
 
   // Clone the sorted selected indexes array.
@@ -600,12 +602,14 @@
     this.document_.body.addEventListener('keydown', this.keyDownBound_);
   }.bind(this);
 
-  cr.ui.dialogs.BaseDialog.OK_LABEL = this.displayStringFunction_('OK_LABEL');
+  cr.ui.dialogs.BaseDialog.OK_LABEL = this.displayStringFunction_(
+      'GALLERY_OK_LABEL');
   cr.ui.dialogs.BaseDialog.CANCEL_LABEL =
-      this.displayStringFunction_('CANCEL_LABEL');
+      this.displayStringFunction_('GALLERY_CANCEL_LABEL');
   var confirm = new cr.ui.dialogs.ConfirmDialog(this.container_);
-  confirm.show(this.displayStringFunction_(
-      plural ? 'CONFIRM_DELETE_SOME' : 'CONFIRM_DELETE_ONE', param),
+  confirm.show(
+      this.displayStringFunction_(plural ? 'GALLERY_CONFIRM_DELETE_SOME' :
+          'GALLERY_CONFIRM_DELETE_ONE', param),
       function() {
         restoreListener();
         this.selectionModel_.unselectAll();
@@ -623,6 +627,15 @@
 };
 
 /**
+ * Prints the current item.
+ * @private
+ */
+Gallery.prototype.print_ = function() {
+  this.onUserAction_();
+  window.print();
+};
+
+/**
  * @return {Array.<Gallery.Item>} Current selection.
  */
 Gallery.prototype.getSelectedItems = function() {
@@ -709,11 +722,16 @@
 
     case 'U+0056':  // 'v'
       this.slideMode_.startSlideshow(SlideMode.SLIDESHOW_INTERVAL_FIRST, event);
-      return;
+      break;
+
+    case 'Ctrl-U+0050':  // Ctrl+'p' prints the current image.
+      if (this.currentMode_ == this.slideMode_)
+        this.print_();
+      break;
 
     case 'U+007F':  // Delete
     case 'Shift-U+0033':  // Shift+'3' (Delete key might be missing).
-      this.onDelete_();
+      this.delete_();
       break;
   }
 };
@@ -743,7 +761,8 @@
     path = this.context_.curDirEntry.fullPath;
     window.top.document.title = this.context_.curDirEntry.name;
     displayName =
-        this.displayStringFunction_('ITEMS_SELECTED', selectedItems.length);
+        this.displayStringFunction_('GALLERY_ITEMS_SELECTED',
+                                    selectedItems.length);
   }
 
   window.top.util.updateAppState(path,
diff --git a/chrome/browser/resources/file_manager/js/photo/gallery_scripts.js b/chrome/browser/resources/file_manager/js/photo/gallery_scripts.js
index 5725911..6548dd0 100644
--- a/chrome/browser/resources/file_manager/js/photo/gallery_scripts.js
+++ b/chrome/browser/resources/file_manager/js/photo/gallery_scripts.js
@@ -10,7 +10,7 @@
 
 //<include src="../metrics.js">
 
-//<include src="../../../image_loader/client.js"/>
+//<include src="../../../image_loader/image_loader_client.js"/>
 
 //<include src="../../../../../../ui/webui/resources/js/cr.js">
 //<include src="../../../../../../ui/webui/resources/js/event_tracker.js">
diff --git a/chrome/browser/resources/file_manager/js/photo/mosaic_mode.js b/chrome/browser/resources/file_manager/js/photo/mosaic_mode.js
index 9eae8fb..3e6d419 100644
--- a/chrome/browser/resources/file_manager/js/photo/mosaic_mode.js
+++ b/chrome/browser/resources/file_manager/js/photo/mosaic_mode.js
@@ -33,6 +33,11 @@
 MosaicMode.prototype.getName = function() { return 'mosaic' };
 
 /**
+ * @return {string} Mode title.
+ */
+MosaicMode.prototype.getTitle = function() { return 'GALLERY_MOSAIC' };
+
+/**
  * Execute an action (this mode has no busy state).
  * @param {function} action Action to execute.
  */
diff --git a/chrome/browser/resources/file_manager/js/photo/photo_import_scripts.js b/chrome/browser/resources/file_manager/js/photo/photo_import_scripts.js
index 0638e46..c9db07d 100644
--- a/chrome/browser/resources/file_manager/js/photo/photo_import_scripts.js
+++ b/chrome/browser/resources/file_manager/js/photo/photo_import_scripts.js
@@ -8,7 +8,7 @@
 // included file but that's all right since any javascript file should start
 // with a copyright comment anyway.
 
-//<include src="../../../image_loader/client.js"/>
+//<include src="../../../image_loader/image_loader_client.js"/>
 
 //<include src="../../../../../../ui/webui/resources/js/load_time_data.js"/>
 //<include src="../../../../../../ui/webui/resources/js/util.js"/>
diff --git a/chrome/browser/resources/file_manager/js/photo/slide_mode.js b/chrome/browser/resources/file_manager/js/photo/slide_mode.js
index 1cdd6a8..06c2228 100644
--- a/chrome/browser/resources/file_manager/js/photo/slide_mode.js
+++ b/chrome/browser/resources/file_manager/js/photo/slide_mode.js
@@ -63,8 +63,10 @@
   new ImageEditor.Mode.InstantAutofix(),
   new ImageEditor.Mode.Crop(),
   new ImageEditor.Mode.Exposure(),
-  new ImageEditor.Mode.OneClick('rotate_left', new Command.Rotate(-1)),
-  new ImageEditor.Mode.OneClick('rotate_right', new Command.Rotate(1))
+  new ImageEditor.Mode.OneClick(
+      'rotate_left', 'GALLERY_ROTATE_LEFT', new Command.Rotate(-1)),
+  new ImageEditor.Mode.OneClick(
+      'rotate_right', 'GALLERY_ROTATE_RIGHT', new Command.Rotate(1))
 ];
 
 /**
@@ -73,6 +75,11 @@
 SlideMode.prototype.getName = function() { return 'slide' };
 
 /**
+ * @return {string} Mode title.
+ */
+SlideMode.prototype.getTitle = function() { return 'GALLERY_SLIDE' };
+
+/**
  * Initialize the listeners.
  * @private
  */
@@ -97,7 +104,7 @@
       this.toolbar_.querySelector('.filename-spacer'), 'options');
 
   this.savedLabel_ = util.createChild(this.options_, 'saved');
-  this.savedLabel_.textContent = this.displayStringFunction_('saved');
+  this.savedLabel_.textContent = this.displayStringFunction_('GALLERY_SAVED');
 
   var overwriteOriginalBox =
       util.createChild(this.options_, 'overwrite-original');
@@ -116,14 +123,15 @@
 
   var overwriteLabel = util.createChild(overwriteOriginalBox, '', 'label');
   overwriteLabel.textContent =
-      this.displayStringFunction_('overwrite_original');
+      this.displayStringFunction_('GALLERY_OVERWRITE_ORIGINAL');
   overwriteLabel.setAttribute('for', 'overwrite-checkbox');
 
   this.bubble_ = util.createChild(this.toolbar_, 'bubble');
   this.bubble_.hidden = true;
 
   var bubbleContent = util.createChild(this.bubble_);
-  bubbleContent.innerHTML = this.displayStringFunction_('overwrite_bubble');
+  bubbleContent.innerHTML = this.displayStringFunction_(
+      'GALLERY_OVERWRITE_BUBBLE');
 
   util.createChild(this.bubble_, 'pointer bottom', 'span');
 
@@ -136,7 +144,8 @@
   this.mediaToolbar_ = util.createChild(this.mediaSpacer_, 'tool');
   this.mediaControls_ = new VideoControls(
       this.mediaToolbar_,
-      this.showErrorBanner_.bind(this, 'VIDEO_ERROR'),
+      this.showErrorBanner_.bind(this, 'GALLERY_VIDEO_ERROR'),
+      this.displayStringFunction_.bind(this),
       this.toggleFullScreen_.bind(this),
       this.container_);
 
@@ -172,7 +181,7 @@
 
   var slideShowButton = util.createChild(this.toolbar_,
       'button slideshow', 'button');
-  slideShowButton.title = this.displayStringFunction_('slideshow');
+  slideShowButton.title = this.displayStringFunction_('GALLERY_SLIDESHOW');
   slideShowButton.addEventListener('click',
       this.startSlideshow.bind(this, SlideMode.SLIDESHOW_INTERVAL_FIRST));
 
@@ -186,7 +195,7 @@
   // Editor.
 
   this.editButton_ = util.createChild(this.toolbar_, 'button edit', 'button');
-  this.editButton_.title = this.displayStringFunction_('edit');
+  this.editButton_.title = this.displayStringFunction_('GALLERY_EDIT');
   this.editButton_.addEventListener('click', this.toggleEditor.bind(this));
 
   this.editBarSpacer_ = util.createChild(this.toolbar_, 'edit-bar-spacer');
@@ -255,7 +264,7 @@
   if (this.getItemCount_() == 0) {
     this.displayedIndex_ = -1;
     //TODO(kaznacheev) Show this message in the grid mode too.
-    this.showErrorBanner_('NO_IMAGES');
+    this.showErrorBanner_('GALLERY_NO_IMAGES');
     loadDone();
   } else {
     // Remember the selection if it is empty or multiple. It will be restored
@@ -533,7 +542,7 @@
       // No items left. Unload the image and show the banner.
       this.commitItem_(function() {
         this.unloadImage_();
-        this.showErrorBanner_('NO_IMAGES');
+        this.showErrorBanner_('GALLERY_NO_IMAGES');
       }.bind(this));
     }
   }.bind(this), 0);
@@ -636,13 +645,15 @@
     if (loadType == ImageView.LOAD_TYPE_ERROR) {
       // if we have a specific error, then display it
       if (error) {
-        this.showErrorBanner_(error);
+        this.showErrorBanner_('GALLERY_' + error);
       } else {
         // otherwise try to infer general error
-        this.showErrorBanner_(video ? 'VIDEO_ERROR' : 'IMAGE_ERROR');
+        this.showErrorBanner_(
+            video ? 'GALLERY_VIDEO_ERROR' : 'GALLERY_IMAGE_ERROR');
       }
     } else if (loadType == ImageView.LOAD_TYPE_OFFLINE) {
-      this.showErrorBanner_(video ? 'VIDEO_OFFLINE' : 'IMAGE_OFFLINE');
+      this.showErrorBanner_(
+          video ? 'GALLERY_VIDEO_OFFLINE' : 'GALLERY_IMAGE_OFFLINE');
     }
 
     if (video) {
@@ -755,17 +766,26 @@
  */
 SlideMode.prototype.onBeforeUnload = function() {
   if (this.editor_.isBusy())
-    return this.displayStringFunction_('unsaved_changes');
+    return this.displayStringFunction_('GALLERY_UNSAVED_CHANGES');
   return null;
 };
 
 /**
  * Click handler for the image container.
+ *
+ * @param {Event} event Mouse click event.
  * @private
  */
-SlideMode.prototype.onClick_ = function() {
-  if (this.isShowingVideo_())
+SlideMode.prototype.onClick_ = function(event) {
+  if (!this.isShowingVideo_())
+    return;
+  if (event.ctrlKey) {
+    this.mediaControls_.toggleLoopedModeWithFeedback(true);
+    if (!this.mediaControls_.isPlaying())
+      this.mediaControls_.togglePlayStateWithFeedback();
+  } else {
     this.mediaControls_.togglePlayStateWithFeedback();
+  }
 };
 
 /**
@@ -823,7 +843,7 @@
       }
       break;
 
-    case 'U+0045':  // 'e' toggles the editor
+    case 'U+0045':  // 'e' toggles the editor.
       this.toggleEditor(event);
       break;
 
diff --git a/chrome/browser/resources/file_manager/js/scrollbar.js b/chrome/browser/resources/file_manager/js/scrollbar.js
index 8fba774..a81fe8d 100644
--- a/chrome/browser/resources/file_manager/js/scrollbar.js
+++ b/chrome/browser/resources/file_manager/js/scrollbar.js
@@ -79,7 +79,7 @@
   this.view_ = view;
   this.view_.addEventListener('scroll', this.onScroll_.bind(this));
   this.view_.addEventListener('relayout', this.onRelayout_.bind(this));
-  this.domObserver_ = new WebKitMutationObserver(this.onDomChanged_.bind(this));
+  this.domObserver_ = new MutationObserver(this.onDomChanged_.bind(this));
   this.domObserver_.observe(this.view_, {subtree: true, attributes: true});
   this.onRelayout_();
 };
@@ -147,14 +147,20 @@
   }
   var clientSize = this.getClientHeight();
   var totalSize = this.getTotalHeight();
+  // TODO(hirono): Fix the geometric calculation.  crbug.com/253779
   var buttonSize = Math.max(50, clientSize / totalSize * clientSize);
-
   var buttonPosition = this.buttonPressedPosition_ +
       (event.screenY - this.buttonPressedEvent_.screenY);
   // Ensures the scrollbar is in the view.
   buttonPosition =
       Math.max(0, Math.min(buttonPosition, clientSize - buttonSize));
-  var scrollPosition = totalSize * (buttonPosition / clientSize);
+  var scrollPosition;
+  if (clientSize > buttonSize) {
+    scrollPosition = Math.max(totalSize - clientSize, 0) *
+        buttonPosition / (clientSize - buttonSize);
+  } else {
+    scrollPosition = 0;
+  }
 
   this.scrollTop_ = scrollPosition;
   this.view_.scrollTop = scrollPosition;
@@ -191,8 +197,13 @@
   var hidden = totalSize <= clientSize;
 
   var buttonSize = Math.max(50, clientSize / totalSize * clientSize);
-  var buttonPosition = scrollPosition / (totalSize - clientSize) *
-      (clientSize - buttonSize);
+  var buttonPosition;
+  if (clientSize - buttonSize > 0) {
+    buttonPosition = scrollPosition / (totalSize - clientSize) *
+        (clientSize - buttonSize);
+  } else {
+    buttonPosition = 0;
+  }
   var buttonTop = buttonPosition + clientTop;
 
   var time = Date.now();
diff --git a/chrome/browser/resources/file_manager/js/sidebar.js b/chrome/browser/resources/file_manager/js/sidebar.js
deleted file mode 100644
index f38c7a1..0000000
--- a/chrome/browser/resources/file_manager/js/sidebar.js
+++ /dev/null
@@ -1,727 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-'use strict';
-
-// TODO(yoshiki): rename this sidebar.js to directory_tree.js.
-
-////////////////////////////////////////////////////////////////////////////////
-// DirectoryTreeUtil
-
-/**
- * Utility methods. They are intended for use only in this file.
- */
-var DirectoryTreeUtil = {};
-
-/**
- * Updates sub-elements of {@code parentElement} reading {@code DirectoryEntry}
- * with calling {@code iterator}.
- *
- * @param {string} changedDirectryPath The path of the changed directory.
- * @param {DirectoryItem|DirectoryTree} currentDirectoryItem An item to be
- *     started traversal from.
- */
-DirectoryTreeUtil.updateChangedDirectoryItem = function(
-    changedDirectryPath, currentDirectoryItem) {
-  if (changedDirectryPath === currentDirectoryItem.entry.fullPath) {
-    currentDirectoryItem.updateSubDirectories(false /* recursive */);
-    return;
-  }
-
-  for (var i = 0; i < currentDirectoryItem.items.length; i++) {
-    var item = currentDirectoryItem.items[i];
-    if (PathUtil.isParentPath(item.entry.fullPath, changedDirectryPath)) {
-      DirectoryTreeUtil.updateChangedDirectoryItem(changedDirectryPath, item);
-      break;
-    }
-  }
-};
-
-/**
- * Updates sub-elements of {@code parentElement} reading {@code DirectoryEntry}
- * with calling {@code iterator}.
- *
- * @param {DirectoryItem|DirectoryTree} parentElement Parent element of newly
- *     created items.
- * @param {function(number): DirectoryEntry} iterator Function which returns
- *     the n-th Entry in the directory.
- * @param {DirectoryModel} directoryModel Current DirectoryModel.
- * @param {boolean} recursive True if the all visible sub-directories are
- *     updated recursively including left arrows. If false, the update walks
- *     only immediate child directories without arrows.
- */
-DirectoryTreeUtil.updateSubElementsFromList = function(
-    parentElement, iterator, directoryModel, recursive) {
-  var index = 0;
-  while (iterator(index)) {
-    var currentEntry = iterator(index);
-    var currentElement = parentElement.items[index];
-
-    if (index >= parentElement.items.length) {
-      var item = new DirectoryItem(currentEntry, parentElement, directoryModel);
-      parentElement.add(item);
-      index++;
-    } else if (currentEntry.fullPath == currentElement.fullPath) {
-      if (recursive && parentElement.expanded)
-        currentElement.updateSubDirectories(true /* recursive */);
-
-      index++;
-    } else if (currentEntry.fullPath < currentElement.fullPath) {
-      var item = new DirectoryItem(currentEntry, parentElement, directoryModel);
-      parentElement.addAt(item, index);
-      index++;
-    } else if (currentEntry.fullPath > currentElement.fullPath) {
-      parentElement.remove(currentElement);
-    }
-  }
-
-  var removedChild;
-  while (removedChild = parentElement.items[index]) {
-    parentElement.remove(removedChild);
-  }
-
-  if (index == 0) {
-    parentElement.hasChildren = false;
-    parentElement.expanded = false;
-  } else {
-    parentElement.hasChildren = true;
-  }
-};
-
-/**
- * Returns true if the given directory entry is dummy.
- * @param {DirectoryEntry|Object} dirEntry DirectoryEntry to be checked.
- * @return {boolean} True if the given directory entry is dummy.
- */
-DirectoryTreeUtil.isDummyEntry = function(dirEntry) {
-  return !('createReader' in dirEntry);
-};
-
-/**
- * Finds a parent directory of the {@code path} from the {@code items}, and
- * invokes the DirectoryItem.selectPath() of the found directory.
- *
- * @param {Array.<DirectoryItem>} items Items to be searched.
- * @param {string} path Path to be searched for.
- * @return {boolean} True if the parent item is found.
- */
-DirectoryTreeUtil.searchAndSelectPath = function(items, path) {
-  for (var i = 0; i < items.length; i++) {
-    var item = items[i];
-    if (PathUtil.isParentPath(item.entry.fullPath, path)) {
-      item.selectPath(path);
-      return true;
-    }
-  }
-  return false;
-};
-
-/**
- * Modifies a list of the directory entries to match the new UI sepc.
- *
- * TODO(yoshiki): remove this after the old UI is removed.
- *
- * @param {Array.<DirectoryEntry>} entries The list of entty.
- * @return {Array.<DirectoryEntries>} Modified entries.
- */
-DirectoryTreeUtil.addAndRemoveDriveSpecialDirs = function(entries) {
-  var modifiedEntries = [];
-  for (var i in entries) {
-    // Removes '/drive/other'.
-    var entry = entries[i];
-    if (entry.fullPath ==
-        (RootDirectory.DRIVE + '/' + DriveSubRootDirectory.OTHER)) {
-      continue;
-    }
-
-    // Changes the label of '/drive/root' to 'My Drive'.
-    if (entry.fullPath == DirectoryModel.fakeDriveEntry_.fullPath) {
-      entry.label = str('DRIVE_MY_DRIVE_LABEL');
-    }
-
-    modifiedEntries.push(entry);
-  }
-
-  // Adds the special directories.
-  var specialDirs = DirectoryModel.FAKE_DRIVE_SPECIAL_SEARCH_ENTRIES;
-  for (var i in specialDirs) {
-    var dir = specialDirs[i];
-    dir['label'] = PathUtil.getRootLabel(dir.fullPath);
-    modifiedEntries.push(dir);
-  }
-  return modifiedEntries;
-};
-
-/**
- * Retrieves the file list with the latest information.
- *
- * @param {DirectoryTree|DirectoryItem} item Parent to be reloaded.
- * @param {DirectoryModel} dm The directory model.
- * @param {function(Array.<Entry>)} successCallback Callback on success.
- * @param {function()=} opt_errorCallback Callback on failure.
- */
-DirectoryTreeUtil.updateSubDirectories = function(
-    item, dm, successCallback, opt_errorCallback) {
-  // Tries to retrieve new entry if the cached entry is dummy.
-  if (DirectoryTreeUtil.isDummyEntry(item.entry)) {
-    // Fake Drive root.
-    dm.resolveDirectory(
-        item.fullPath,
-        function(entry) {
-          item.dirEntry_ = entry;
-
-          // If the retrieved entry is dummy again, returns with an error.
-          if (DirectoryTreeUtil.isDummyEntry(entry)) {
-            if (opt_errorCallback)
-              opt_errorCallback();
-            return;
-          }
-
-          DirectoryTreeUtil.updateSubDirectories(
-              item, dm, successCallback, opt_errorCallback);
-        },
-        opt_errorCallback);
-    return;
-  }
-
-  var reader = item.entry.createReader();
-  var entries = [];
-  var readEntry = function() {
-    reader.readEntries(function(results) {
-      if (!results.length) {
-        if (item.entry.fullPath == RootDirectory.DRIVE)
-          successCallback(
-              DirectoryTreeUtil.addAndRemoveDriveSpecialDirs(entries));
-        else
-          successCallback(
-              DirectoryTreeUtil.sortEntries(item.fileFilter_, entries));
-        return;
-      }
-
-      for (var i = 0; i < results.length; i++) {
-        var entry = results[i];
-        if (entry.isDirectory)
-          entries.push(entry);
-      }
-      readEntry();
-    });
-  };
-  readEntry();
-};
-
-/**
- * Sorts a list of entries.
- *
- * @param {FileFilter} fileFilter The file filter.
- * @param {Array.<Entries>} entries Entries to be sorted.
- * @return {Array.<Entries>} Sorted entries.
- */
-DirectoryTreeUtil.sortEntries = function(fileFilter, entries) {
-  entries.sort(function(a, b) {
-    return (a.name.toLowerCase() > b.name.toLowerCase()) ? 1 : -1;
-  });
-  return entries.filter(fileFilter.filter.bind(fileFilter));
-};
-
-/**
- * Checks if tre tree should be hidden on the given directory.
- *
- * @param {string} path Path to be checked.
- * @return {boolean} True if the tree should NOT be visible on the given
- *     directory. Otherwise, false.
- */
-DirectoryTreeUtil.shouldHideTree = function(path) {
-  return !PathUtil.isDriveBasedPath(path);
-};
-
-////////////////////////////////////////////////////////////////////////////////
-// DirectoryItem
-
-/**
- * A directory in the tree. Each element represents one directory.
- *
- * @param {DirectoryEntry} dirEntry DirectoryEntry of this item.
- * @param {DirectoryItem|DirectoryTree} parentDirItem Parent of this item.
- * @param {DirectoryModel} directoryModel Current DirectoryModel.
- * @extends {cr.ui.TreeItem}
- * @constructor
- */
-function DirectoryItem(dirEntry, parentDirItem, directoryModel) {
-  var item = cr.doc.createElement('div');
-  DirectoryItem.decorate(item, dirEntry, parentDirItem, directoryModel);
-  return item;
-}
-
-/**
- * @param {HTMLElement} el Element to be DirectoryItem.
- * @param {DirectoryEntry} dirEntry DirectoryEntry of this item.
- * @param {DirectoryItem|DirectoryTree} parentDirItem Parent of this item.
- * @param {DirectoryModel} directoryModel Current DirectoryModel.
- */
-DirectoryItem.decorate =
-    function(el, dirEntry, parentDirItem, directoryModel) {
-  el.__proto__ = DirectoryItem.prototype;
-  (/** @type {DirectoryItem} */ el).decorate(
-      dirEntry, parentDirItem, directoryModel);
-};
-
-DirectoryItem.prototype = {
-  __proto__: cr.ui.TreeItem.prototype,
-
-  /**
-   * The DirectoryEntry corresponding to this DirectoryItem. This may be
-   * a dummy DirectoryEntry.
-   * @type {DirectoryEntry|Object}
-   * @override
-   **/
-  get entry() {
-      return this.dirEntry_;
-  },
-
-  /**
-   * The element containing the label text and the icon.
-   * @type {!HTMLElement}
-   * @override
-   **/
-  get labelElement() {
-      return this.firstElementChild.querySelector('.label');
-  }
-};
-
-/**
- * @param {DirectoryEntry} dirEntry DirectoryEntry of this item.
- * @param {DirectoryItem|DirectoryTree} parentDirItem Parent of this item.
- * @param {DirectoryModel} directoryModel Current DirectoryModel.
- */
-DirectoryItem.prototype.decorate = function(
-    dirEntry, parentDirItem, directoryModel) {
-  var path = dirEntry.fullPath;
-  var label;
-  label = dirEntry.label ? dirEntry.label : dirEntry.name;
-
-  this.className = 'tree-item';
-  this.innerHTML =
-      '<div class="tree-row">' +
-      ' <span class="expand-icon"></span>' +
-      ' <span class="icon"></span>' +
-      ' <span class="label"></span>' +
-      ' <div class="root-eject"></div>' +
-      '</div>' +
-      '<div class="tree-children"></div>';
-  this.setAttribute('role', 'treeitem');
-
-  this.directoryModel_ = directoryModel;
-  this.parent_ = parentDirItem;
-  this.label = label;
-  this.fullPath = path;
-  this.dirEntry_ = dirEntry;
-  this.fileFilter_ = this.directoryModel_.getFileFilter();
-
-  // Sets hasChildren=false tentatively. This will be overridden after
-  // scanning sub-directories in DirectoryTreeUtil.updateSubElementsFromList.
-  this.hasChildren = false;
-
-  this.addEventListener('expand', this.onExpand_.bind(this), false);
-  var volumeManager = VolumeManager.getInstance();
-  var icon = this.querySelector('.icon');
-  icon.classList.add('volume-icon');
-  var iconType = PathUtil.getRootType(path);
-  if (iconType && PathUtil.isRootPath(path))
-    icon.setAttribute('volume-type-icon', iconType);
-  else
-    icon.setAttribute('file-type-icon', 'folder');
-
-  var eject = this.querySelector('.root-eject');
-  eject.hidden = !PathUtil.isUnmountableByUser(path);
-  eject.addEventListener('click',
-      function(event) {
-        event.stopPropagation();
-        if (!PathUtil.isUnmountableByUser(path))
-          return;
-
-        volumeManager.unmount(path, function() {}, function() {});
-      }.bind(this));
-
-  if (parentDirItem.expanded)
-    this.updateSubDirectories(false /* recursive */);
-};
-
-/**
- * Overrides WebKit's scrollIntoViewIfNeeded, which doesn't work well with
- * a complex layout. This call is not necessary, so we are ignoring it.
- *
- * @param {boolean} unused Unused.
- * @override
- */
-DirectoryItem.prototype.scrollIntoViewIfNeeded = function(unused) {
-};
-
-/**
- * Removes the child node, but without selecting the parent item, to avoid
- * unintended changing of directories. Removing is done externally, and other
- * code will navigate to another directory.
- *
- * @param {!cr.ui.TreeItem} child The tree item child to remove.
- * @override
- */
-DirectoryItem.prototype.remove = function(child) {
-  this.lastElementChild.removeChild(child);
-  if (this.items.length == 0)
-    this.hasChildren = false;
-};
-
-/**
- * Invoked when the item is being expanded.
- * @param {!UIEvent} e Event.
- * @private
- **/
-DirectoryItem.prototype.onExpand_ = function(e) {
-  this.updateSubDirectories(
-      true /* recursive */,
-      function() {},
-      function() {
-        this.expanded = false;
-      }.bind(this));
-
-  e.stopPropagation();
-};
-
-/**
- * Retrieves the latest subdirectories and update them on the tree.
- * @param {boolean} recursive True if the update is recursively.
- * @param {function()=} opt_successCallback Callback called on success.
- * @param {function()=} opt_errorCallback Callback called on error.
- */
-DirectoryItem.prototype.updateSubDirectories = function(
-    recursive, opt_successCallback, opt_errorCallback) {
-  DirectoryTreeUtil.updateSubDirectories(
-      this,
-      this.directoryModel_,
-      function(entries) {
-        this.entries_ = entries;
-        this.redrawSubDirectoryList_(recursive);
-        opt_successCallback && opt_successCallback();
-      }.bind(this),
-      opt_errorCallback);
-};
-
-/**
- * Redraw subitems with the latest information. The items are sorted in
- * alphabetical order, case insensitive.
- * @param {boolean} recursive True if the update is recursively.
- * @private
- */
-DirectoryItem.prototype.redrawSubDirectoryList_ = function(recursive) {
-  DirectoryTreeUtil.updateSubElementsFromList(
-      this,
-      function(i) { return this.entries_[i]; }.bind(this),
-      this.directoryModel_,
-      recursive);
-};
-
-/**
- * Select the item corresponding to the given {@code path}.
- * @param {string} path Path to be selected.
- */
-DirectoryItem.prototype.selectPath = function(path) {
-  if (path == this.fullPath) {
-    this.selected = true;
-    return;
-  }
-
-  if (DirectoryTreeUtil.searchAndSelectPath(this.items, path))
-    return;
-
-  // If the path doesn't exist, updates sub directories and tryes again.
-  this.updateSubDirectories(
-      false /* recursive */,
-      DirectoryTreeUtil.searchAndSelectPath.bind(null, this.items, path));
-};
-
-/**
- * Executes the assigned action as a drop target.
- */
-DirectoryItem.prototype.doDropTargetAction = function() {
-  this.expanded = true;
-};
-
-/**
- * Executes the assigned action. DirectoryItem performs changeDirectory.
- */
-DirectoryItem.prototype.doAction = function() {
-  if (this.fullPath != this.directoryModel_.getCurrentDirPath())
-    this.directoryModel_.changeDirectory(this.fullPath);
-};
-
-////////////////////////////////////////////////////////////////////////////////
-// DirectoryTree
-
-/**
- * Tree of directories on the sidebar. This element is also the root of items,
- * in other words, this is the parent of the top-level items.
- *
- * @constructor
- * @extends {cr.ui.Tree}
- */
-function DirectoryTree() {}
-
-/**
- * Decorates an element.
- * @param {HTMLElement} el Element to be DirectoryTree.
- * @param {DirectoryModel} directoryModel Current DirectoryModel.
- */
-DirectoryTree.decorate = function(el, directoryModel) {
-  el.__proto__ = DirectoryTree.prototype;
-  (/** @type {DirectoryTree} */ el).decorate(directoryModel);
-};
-
-DirectoryTree.prototype = {
-  __proto__: cr.ui.Tree.prototype,
-
-  // DirectoryTree is always expanded.
-  get expanded() { return true; },
-  /**
-   * @param {boolean} value Not used.
-   */
-  set expanded(value) {},
-
-  /**
-   * The DirectoryEntry corresponding to this DirectoryItem. This may be
-   * a dummy DirectoryEntry.
-   * @type {DirectoryEntry|Object}
-   * @override
-   **/
-  get entry() {
-      return this.dirEntry_;
-  }
-};
-
-/**
- * Decorates an element.
- * @param {DirectoryModel} directoryModel Current DirectoryModel.
- */
-DirectoryTree.prototype.decorate = function(directoryModel) {
-  cr.ui.Tree.prototype.decorate.call(this);
-
-  this.directoryModel_ = directoryModel;
-  this.entries_ = [];
-
-  this.fileFilter_ = this.directoryModel_.getFileFilter();
-  this.fileFilter_.addEventListener('changed',
-                                    this.onFilterChanged_.bind(this));
-  /**
-   * The path of the root directory.
-   * @type {string}
-   */
-  this.fullPath = '/';
-  this.dirEntry_ = null;
-
-  /**
-   * The path of the current directory.
-   * @type {string}
-   */
-  this.currentPath_ = 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;
-      this.selectedItem.doAction();
-      return;
-    }
-  }.bind(this));
-
-  this.privateOnDirectoryChangedBound_ =
-      this.onDirectoryContentChanged_.bind(this);
-  chrome.fileBrowserPrivate.onDirectoryChanged.addListener(
-      this.privateOnDirectoryChangedBound_);
-
-  this.scrollBar_ = MainPanelScrollBar();
-  this.scrollBar_.initialize(this.parentNode, this);
-};
-
-/**
- * Select the item corresponding to the given path.
- * @param {string} path Path to be selected.
- */
-DirectoryTree.prototype.selectPath = function(path) {
-  if ((this.entry && this.entry.fullPath == path) || this.currentPath_ == path)
-    return;
-  this.currentPath_ = path;
-  if (DirectoryTreeUtil.shouldHideTree(path)) {
-    this.clearTree_(true);
-    return;
-  }
-
-  this.selectPathInternal_(path);
-};
-
-/**
- * Select the item corresponding to the given path. This method is used
- * internally.
- * @param {string} path Path to be selected.
- * @private
- */
-DirectoryTree.prototype.selectPathInternal_ = function(path) {
-  var rootDirPath = PathUtil.getRootPath(path);
-
-  if (PathUtil.isSpecialSearchRoot(rootDirPath) ||
-      PathUtil.getRootType(rootDirPath) == RootType.DRIVE) {
-    rootDirPath = RootDirectory.DRIVE;
-  }
-
-  var onError = function() {
-    this.clearTree_(true);
-  }.bind(this);
-
-  if (this.fullPath != rootDirPath || !this.dirEntry_) {
-    this.fullPath = rootDirPath;
-
-    this.directoryModel_.resolveDirectory(
-        rootDirPath,
-        function(entry) {
-          if (this.fullPath != rootDirPath)
-            return;
-
-          this.dirEntry_ = entry;
-          this.selectPathInternal_(path);
-        }.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);
-  }
-};
-
-/**
- * Retrieves the latest subdirectories and update them on the tree.
- * @param {boolean} recursive True if the update is recursively.
- * @param {function()=} opt_successCallback Callback called on success.
- * @param {function()=} opt_errorCallback Callback called on error.
- */
-DirectoryTree.prototype.updateSubDirectories = function(
-    recursive, opt_successCallback, opt_errorCallback) {
-  if (!this.currentPath_)
-    return;
-
-  DirectoryTreeUtil.updateSubDirectories(
-      this,
-      this.directoryModel_,
-      function(entries) {
-        this.entries_ = entries;
-        this.redraw(recursive);
-        if (opt_successCallback)
-          opt_successCallback();
-      }.bind(this),
-      opt_errorCallback);
-};
-
-/**
- * Redraw the list.
- * @param {boolean} recursive True if the update is recursively. False if the
- *     only root items are updated.
- */
-DirectoryTree.prototype.redraw = function(recursive) {
-  DirectoryTreeUtil.updateSubElementsFromList(
-      this,
-      function(i) { return this.entries_[i]; }.bind(this),
-      this.directoryModel_,
-      recursive);
-};
-
-/**
- * Invoked when the filter is changed.
- * @private
- */
-DirectoryTree.prototype.onFilterChanged_ = function() {
-  // Returns immediately, if the tree is hidden.
-  if (!this.currentPath_ || DirectoryTreeUtil.shouldHideTree(this.currentPath_))
-    return;
-
-  this.redraw(true /* recursive */);
-  cr.dispatchSimpleEvent(this, 'content-updated');
-};
-
-/**
- * Invoked when a directory is changed.
- * @param {!UIEvent} event Event.
- * @private
- */
-DirectoryTree.prototype.onDirectoryContentChanged_ = function(event) {
-  // Returns immediately, if the tree is hidden.
-  if (!this.currentPath_ || DirectoryTreeUtil.shouldHideTree(this.currentPath_))
-    return;
-
-  if (event.eventType == 'changed') {
-    var path = util.extractFilePath(event.directoryUrl);
-    DirectoryTreeUtil.updateChangedDirectoryItem(path, this);
-  }
-};
-
-/**
- * Invoked when the current directory is changed.
- * @param {!UIEvent} event Event.
- * @private
- */
-DirectoryTree.prototype.onCurrentDirectoryChanged_ = function(event) {
-  this.selectPath(event.newDirEntry.fullPath);
-};
-
-/**
- * Returns the path of the selected item.
- * @return {string} The current path.
- */
-DirectoryTree.prototype.getCurrentPath = function() {
-  return this.selectedItem ? this.selectedItem.fullPath : null;
-};
-
-/**
- * Clears the tree.
- * @param {boolean} redraw Redraw the tree if true.
- * @private
- */
-DirectoryTree.prototype.clearTree_ = function(redraw) {
-  this.dirEntry_ = null;
-  this.fullPath = '';
-  this.selectedItem = null;
-  this.entries_ = [];
-
-  if (redraw) {
-    this.redraw(false);
-    cr.dispatchSimpleEvent(this, 'content-updated');
-  }
-};
-
-/**
- * Sets the margin height for the transparent preview panel at the bottom.
- * @param {number} margin Margin to be set in px.
- */
-DirectoryTree.prototype.setBottomMarginForPanel = function(margin) {
-  this.style.paddingBottom = margin + 'px';
-  this.scrollBar_.setBottomMarginForPanel(margin);
-};
-
-/**
- * Updates the UI after the layout has changed.
- */
-DirectoryTree.prototype.relayout = function() {
-  cr.dispatchSimpleEvent(this, 'relayout');
-};
diff --git a/chrome/browser/resources/file_manager/js/util.js b/chrome/browser/resources/file_manager/js/util.js
index 490e736..59ce54e 100644
--- a/chrome/browser/resources/file_manager/js/util.js
+++ b/chrome/browser/resources/file_manager/js/util.js
@@ -755,7 +755,8 @@
  */
 util.platform = {
   /**
-   * @return {boolean} True if Files.app is running via "chrome://files".
+   * @return {boolean} True if Files.app is running via "chrome://files", open
+   * files or select folder dialog. False otherwise.
    */
   runningInBrowser: function() {
     return !window.appID;
@@ -943,12 +944,12 @@
  *     cache.
  */
 util.loadImage = function(image, url, opt_options, opt_isValid) {
-  return ImageLoader.Client.loadToImage(url,
-                                        image,
-                                        opt_options || {},
-                                        function() { },
-                                        function() { image.onerror(); },
-                                        opt_isValid);
+  return ImageLoaderClient.loadToImage(url,
+                                      image,
+                                      opt_options || {},
+                                      function() {},
+                                      function() { image.onerror(); },
+                                      opt_isValid);
 };
 
 /**
@@ -956,7 +957,7 @@
  * @param {number} taskId Task identifier returned by util.loadImage().
  */
 util.cancelLoadImage = function(taskId) {
-  ImageLoader.Client.getInstance().cancel(taskId);
+  ImageLoaderClient.getInstance().cancel(taskId);
 };
 
 /**
diff --git a/chrome/browser/resources/file_manager/main.html b/chrome/browser/resources/file_manager/main.html
index ec4d133..f483621 100644
--- a/chrome/browser/resources/file_manager/main.html
+++ b/chrome/browser/resources/file_manager/main.html
@@ -14,11 +14,11 @@
 
     <meta name="google" value="notranslate">
 
-    <link rel="stylesheet" href="chrome://resources/css/list.css"></link>
-    <link rel="stylesheet" href="chrome://resources/css/tree.css"></link>
-    <link rel="stylesheet" href="chrome://resources/css/table.css"></link>
     <link rel="stylesheet" href="chrome://resources/css/menu.css"></link>
 
+    <link rel="stylesheet" href="css/list.css"></link>
+    <link rel="stylesheet" href="css/table.css"></link>
+    <link rel="stylesheet" href="css/tree.css"></link>
     <link rel="stylesheet" href="css/combobutton.css"></link>
     <link rel="stylesheet" href="css/file_manager.css"></link>
     <link rel="stylesheet" href="css/file_types.css"></link>
@@ -39,7 +39,7 @@
       <script src="js/metrics.js"></script>
 
       <!-- Loads the client of the image loader extension -->
-      <script src="chrome-extension://pmfjbimdmchhbnneeidfognadeopoehp/client.js"></script>
+      <script src="chrome-extension://pmfjbimdmchhbnneeidfognadeopoehp/image_loader_client.js"></script>
 
       <script src="chrome://resources/js/load_time_data.js"></script>
       <script src="chrome://resources/js/cr.js"></script>
@@ -89,6 +89,7 @@
       <script src="js/butter_bar.js"></script>
       <script src="js/directory_contents.js"></script>
       <script src="js/directory_model.js"></script>
+      <script src="js/directory_tree.js"></script>
       <script src="js/drag_selector.js"></script>
       <script src="js/drive_banners.js"></script>
       <script src="js/error_dialog.js"></script>
@@ -102,7 +103,6 @@
       <script src="js/file_transfer_controller.js"></script>
       <script src="js/file_type.js"></script>
       <script src="js/scrollbar.js"></script>
-      <script src="js/sidebar.js"></script>
       <script src="js/tree.css.js"></script>
       <script src="js/volume_manager.js"></script>
       <script src="js/volume_list.js"></script>
@@ -118,7 +118,7 @@
 
   </head>
   <body i18n-values=".style.fontFamily:WEB_FONT_FAMILY;
-                     .style.fontSize:WEB_FONT_SIZE" new-ui>
+                     .style.fontSize:WEB_FONT_SIZE">
     <commands>
       <!-- We have to use U+XXXX notation here according to event.keyIdentifier
            property -->
@@ -168,6 +168,11 @@
       <command id="open-with" i18n-values="label:OPEN_WITH_BUTTON_LABEL">
       <command id="zip-selection"
                i18n-values="label:ZIP_SELECTION_BUTTON_LABEL">
+      <command id="share" i18n-values="label:SHARE_BUTTON_LABEL">
+
+      <command id="zoom-in" shortcut="U+00BB-Ctrl">
+      <command id="zoom-out" shortcut="U+00BD-Ctrl">
+      <command id="zoom-reset" shortcut="U+0030-Ctrl">
     </commands>
 
     <menu id="file-context-menu" class="chrome-menu" showShortcuts>
@@ -177,7 +182,8 @@
                 visibleif="full-page" hidden></menuitem>
       <hr id="default-action-separator" visibleif="full-page" hidden>
       <menuitem command="#toggle-pinned" checkable></menuitem>
-      <hr command="#toggle-pinned">
+      <menuitem command="#share"></menuitem>
+      <hr command="#share">
       <menuitem command="#cut" visibleif="full-page"></menuitem>
       <menuitem command="#copy" visibleif="full-page"></menuitem>
       <menuitem command="#paste" visibleif="full-page"></menuitem>
@@ -239,10 +245,9 @@
         <menuitem command="#cut"></menuitem>
         <menuitem command="#copy"></menuitem>
         <menuitem command="#paste"></menuitem>
-        <menuitem command="#delete"></menuitem>
+        <menuitem command="#delete" i18n-content=DELETE_BUTTON_LABEL></menuitem>
     </menu>
 
-    <div class=dialog-title invisibleif="full-page"></div>
     <div class=dialog-container>
       <div class=dialog-sidebar>
         <div class=dialog-sidebar-header>
@@ -314,16 +319,18 @@
               <div class=downloads-warning hidden></div>
             </div>
           </div>
-          <div class="preview-panel" visibility="hidden">
-            <div>
-              <div class="preview-thumbnails"></div>
-            </div>
-            <div id="preview-lines">
-              <div class="preview-summary">
-                <span class="preview-text"></span>
-                <span class="calculating-size" hidden></span>
+          <div class="preview-panel progressable" visibility="hidden">
+            <div class="left">
+              <div>
+                <div class="preview-thumbnails"></div>
               </div>
-              <div id="search-breadcrumbs" class="breadcrumbs"></div>
+              <div id="preview-lines">
+                <div class="preview-summary">
+                  <span class="preview-text"></span>
+                  <span class="calculating-size" hidden></span>
+                </div>
+                <div id="search-breadcrumbs" class="breadcrumbs"></div>
+              </div>
             </div>
             <div class="right buttonbar" visibleif="full-page">
               <button id="tasks" class="combobutton" menu="#tasks-menu"
@@ -332,30 +339,41 @@
               <button id="delete-button" command="#delete" tabindex="3"
                       i18n-values="aria-label:DELETE_BUTTON_LABEL"></button>
             </div>
+            <div class=preparing-label i18n-content=PREPARING_LABEL></div>
+            <div class=progress-bar>
+              <div class=progress-track></div>
+            </div>
+            <div class="right buttonbar" id="open-panel" visibleif="open-file open-multi-file">
+              <select class="file-type"></select>
+              <button class=ok disabled tabindex="6"></button>
+              <button class=cancel i18n-content=CANCEL_LABEL tabindex="7"></button>
+            </div>
           </div>
           <div id="unmounted-panel"></div>
           <div id="format-panel">
-              <div class="error"></div>
-              <button id="format-button" command="#format"></button>
+            <div class="error"></div>
+            <button id="format-button" command="#format"></button>
           </div>
         </div>
       </div>
     </div>
-    <div class=dialog-footer invisibleif="full-page">
-      <button id="new-folder" i18n-content=NEW_FOLDER_BUTTON_LABEL
-              visibleif="saveas-file folder" command="#newfolder" tabindex="4">
-      </button>
-      <div id="filename-input-box">
-        <div class=filename-label i18n-content=FILENAME_LABEL></div>
-        <input type=text spellcheck=false tabindex="5">
-      </div>
-      <div class=horizontal-spacer></div>
-      <div class=preparing-label i18n-content=PREPARING_LABEL></div>
-      <div class=progress-bar>
-        <div class=progress-track></div>
+    <div class="dialog-footer progressable" visibleif="saveas-file folder">
+      <div class="left">
+        <button id="new-folder" i18n-content=NEW_FOLDER_BUTTON_LABEL
+                visibleif="saveas-file folder" command="#newfolder"
+                tabindex="4">
+        </button>
+        <div id="filename-input-box">
+          <div class=filename-label i18n-content=FILENAME_LABEL></div>
+          <input type=text spellcheck=false tabindex="5">
+        </div>
+        <div class=preparing-label i18n-content=PREPARING_LABEL></div>
+        <div class=progress-bar>
+          <div class=progress-track></div>
+        </div>
       </div>
       <div class="right buttonbar">
-        <select id="file-type"></select>
+        <select class="file-type"></select>
         <button class=ok disabled tabindex="6"></button>
         <button class=cancel i18n-content=CANCEL_LABEL tabindex="7"></button>
       </div>
diff --git a/chrome/browser/resources/file_manager/manifest.json b/chrome/browser/resources/file_manager/manifest.json
index 31d203b..32bbcf8 100644
--- a/chrome/browser/resources/file_manager/manifest.json
+++ b/chrome/browser/resources/file_manager/manifest.json
@@ -8,9 +8,15 @@
   "incognito" : "split",
   "icons": {
     "16": "images/icon16.png",
-    "128": "images/icon128.png"
+    "32": "images/icon32.png",
+    "48": "images/icon48.png",
+    "64": "images/icon64.png",
+    "96": "images/icon96.png",
+    "128": "images/icon128.png",
+    "256": "images/icon256.png"
   },
   "permissions": [
+    "contextMenus",
     "experimental",
     "storage",
     "fileBrowserHandler",
diff --git a/chrome/browser/resources/file_manager/photo_import.html b/chrome/browser/resources/file_manager/photo_import.html
index b59134f..31e1b35 100644
--- a/chrome/browser/resources/file_manager/photo_import.html
+++ b/chrome/browser/resources/file_manager/photo_import.html
@@ -27,7 +27,7 @@
     <!-- Keep the list in sync with photo_import_scripts.js. -->
 
     <!-- Loads the client of the image loader extension -->
-    <script src="chrome-extension://pmfjbimdmchhbnneeidfognadeopoehp/client.js"></script>
+    <script src="chrome-extension://pmfjbimdmchhbnneeidfognadeopoehp/image_loader_client.js"></script>
 
     <script src="chrome://resources/js/load_time_data.js"></script>
     <script src="chrome://resources/js/util.js"></script>
diff --git a/chrome/browser/resources/gaia_auth/main.js b/chrome/browser/resources/gaia_auth/main.js
index eaeec8b..f17f48a 100644
--- a/chrome/browser/resources/gaia_auth/main.js
+++ b/chrome/browser/resources/gaia_auth/main.js
@@ -39,8 +39,6 @@
     this.gaiaUrl_ = params['gaiaUrl'] || this.GAIA_URL;
     this.inputLang_ = params['hl'];
     this.inputEmail_ = params['email'];
-    this.testEmail_ = params['test_email'];
-    this.testPassword_ = params['test_password'];
 
     document.addEventListener('DOMContentLoaded', this.onPageLoad.bind(this));
   },
@@ -64,10 +62,6 @@
       url += '&hl=' + encodeURIComponent(this.inputLang_);
     if (this.inputEmail_)
       url += '&Email=' + encodeURIComponent(this.inputEmail_);
-    if (this.testEmail_)
-      url += '&test_email=' + encodeURIComponent(this.testEmail_);
-    if (this.testPassword_)
-      url += '&test_pwd=' + encodeURIComponent(this.testPassword_);
     return url;
   },
 
diff --git a/chrome/browser/resources/gaia_auth/manifest_test.json b/chrome/browser/resources/gaia_auth/manifest_test.json
deleted file mode 100644
index 7a075de..0000000
--- a/chrome/browser/resources/gaia_auth/manifest_test.json
+++ /dev/null
@@ -1,42 +0,0 @@
-{
-  // chrome-extension://mfffpogegjflfpflabcdkioaeobkgjik/
-  "key": "MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQC4L17nAfeTd6Xhtx96WhQ6DSr8KdHeQmfzgCkieKLCgUkWdwB9G1DCuh0EPMDn1MdtSwUAT7xE36APEzi0X/UpKjOVyX8tCC3aQcLoRAE0aJAvCcGwK7qIaQaczHmHKvPC2lrRdzSoMMTC5esvHX+ZqIBMi123FOL0dGW6OPKzIwIBIw==",
-  "name": "GaiaTestAuthExtension",
-  "version": "0.0.1",
-  "manifest_version": 2,
-  "content_security_policy": "default-src 'self'; script-src 'self'; frame-src 'self' https://insecure.com https://www.google.com/accounts/ https://accounts.google.com https://accounts.youtube.com https://gaiastaging.corp.google.com http://localhost:*",
-  "description": "GAIA Test Component Extension",
-  "content_scripts": [
-    {
-      "matches": [
-          "https://www.google.com/accounts/*",
-          "https://accounts.google.com/*",
-          "https://gaiastaging.corp.google.com/*",
-          "https://insecure.com/*",
-          "http://localhost:*/*"
-      ],
-      "js": ["test/content.js"],
-      "all_frames": true
-    }
-  ],
-  "web_accessible_resources": [
-    "main.css",
-    "main.html",
-    "main.js",
-    "offline.css",
-    "offline.html",
-    "offline.js",
-    "success.html",
-    "success.js",
-    "util.js",
-    "test/content.js"
-  ],
-  "permissions": [
-      "https://insecure.com/*",
-      "https://www.google.com/accounts/*",
-      "https://accounts.google.com/*",
-      "https://gaiastaging.corp.google.com/*",
-      "chrome://oobe/",
-      "http://localhost:*/*"
-  ]
-}
diff --git a/chrome/browser/resources/gaia_auth/test/content.js b/chrome/browser/resources/gaia_auth/test/content.js
deleted file mode 100644
index 1bf055f..0000000
--- a/chrome/browser/resources/gaia_auth/test/content.js
+++ /dev/null
@@ -1,37 +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.
-
-console.log('Test script injected!');
-
-function getQueryParam(key, defaultVal) {
-  if (!defaultVal) defaultVal = '';
-  key = key.replace(/[\[]/, '\\\[').replace(/[\]]/, '\\\]');
-  var regex = new RegExp('[\\?&]' + key + '=([^&#]*)');
-  var qs = regex.exec(window.location.href);
-  if (qs == null)
-    return defaultVal;
-  else
-    return qs[1];
-}
-
-console.log(document.URL);
-if (document.URL.match(/https\:\/\/www\.google\.com\/accounts\/ServiceLogin/) ||
-    document.URL.match(/https\:\/\/accounts\.google\.com\/ServiceLogin/) ||
-    document.URL.match(
-        /https\:\/\/gaiastaging\.corp\.google\.com\/ServiceLogin/) ||
-    document.URL.match(/https\:\/\/insecure\.com\/accounts\/ServiceLogin/) ||
-  document.URL.match(/http\:\/\/localhost(:[0-9]*)?\/ServiceLogin/)) {
-  var testEmail = unescape(getQueryParam('test_email'));
-  var testPassword = unescape(getQueryParam('test_pwd'));
-  var testContinue = unescape(getQueryParam('continue'));
-  console.log('Got test account info: ' + testEmail + '/' + testPassword);
-  document.getElementById('Email').value = testEmail;
-  document.getElementById('Passwd').value = testPassword;
-  document.getElementById('continue').value = testContinue;
-  console.log('Form field changed!');
-  if (testEmail != '') {
-    document.getElementById('signIn').click();
-    console.log('Form submitted!');
-  }
-}
diff --git a/chrome/browser/resources/gaia_auth_host/gaia_auth_host.js b/chrome/browser/resources/gaia_auth_host/gaia_auth_host.js
index 642d5b4..5c421db 100644
--- a/chrome/browser/resources/gaia_auth_host/gaia_auth_host.js
+++ b/chrome/browser/resources/gaia_auth_host/gaia_auth_host.js
@@ -43,9 +43,7 @@
   var SUPPORTED_PARAMS = [
     'gaiaUrl',       // Gaia url to use;
     'hl',            // Language code for the user interface;
-    'email',         // Pre-fill the email field in Gaia UI;
-    'test_email',    // Used for test;
-    'test_password'  // Used for test;
+    'email'          // Pre-fill the email field in Gaia UI;
   ];
 
   /**
diff --git a/chrome/browser/resources/gesture_config.js b/chrome/browser/resources/gesture_config.js
index af6d855..9a28531 100644
--- a/chrome/browser/resources/gesture_config.js
+++ b/chrome/browser/resources/gesture_config.js
@@ -54,7 +54,7 @@
       var units = row.querySelector('.row-units');
 
       label.setAttribute('for', field.key);
-      label.textContent = field.label;
+      label.innerHTML = field.label;
       input.id = field.key;
       input.min = field.min || 0;
 
@@ -227,6 +227,14 @@
       units: ''
     },
     {
+      key: 'scroll_prediction_seconds',
+      label: 'Scroll prediction interval<br>' +
+          '(Enable scroll prediction in ' +
+              '<a href="chrome://flags">chrome://flags</a>)',
+      units: 'seconds',
+      step: 0.01
+    },
+    {
       key: 'min_swipe_speed',
       label: 'Minimum Swipe Speed',
       units: 'pixels/sec.'
diff --git a/chrome/browser/resources/google_now/background.js b/chrome/browser/resources/google_now/background.js
index bd76627..d52d18d 100644
--- a/chrome/browser/resources/google_now/background.js
+++ b/chrome/browser/resources/google_now/background.js
@@ -32,6 +32,9 @@
  */
 var HTTP_OK = 200;
 
+var HTTP_UNAUTHORIZED = 401;
+var HTTP_FORBIDDEN = 403;
+
 /**
  * Initial period for polling for Google Now Notifications cards to use when the
  * period from the server is not available.
@@ -68,6 +71,20 @@
 
 var LOCATION_WATCH_NAME = 'location-watch';
 
+var WELCOME_TOAST_NOTIFICATION_ID = 'enable-now-toast';
+
+/**
+ * The indices of the buttons that are displayed on the welcome toast.
+ * @enum {number}
+ */
+var ToastButtonIndex = {YES: 0, NO: 1};
+
+/**
+ * The action that the user performed on the welcome toast.
+ * @enum {number}
+ */
+var ToastOptionResponse = {CHOSE_YES: 1, CHOSE_NO: 2};
+
 /**
  * Checks if a new task can't be scheduled when another task is already
  * scheduled.
@@ -98,6 +115,8 @@
 var tasks = buildTaskManager(areTasksConflicting);
 
 // Add error processing to API calls.
+tasks.instrumentApiFunction(chrome.identity, 'getAuthToken', 1);
+tasks.instrumentApiFunction(chrome.identity, 'removeCachedAuthToken', 1);
 tasks.instrumentApiFunction(chrome.location.onLocationUpdate, 'addListener', 0);
 tasks.instrumentApiFunction(chrome.notifications, 'create', 2);
 tasks.instrumentApiFunction(chrome.notifications, 'update', 2);
@@ -134,7 +153,9 @@
   DISMISS_REQUEST_SUCCESS: 4,
   LOCATION_REQUEST: 5,
   LOCATION_UPDATE: 6,
-  EVENTS_TOTAL: 7  // EVENTS_TOTAL is not an event; all new events need to be
+  EXTENSION_START: 7,
+  SHOW_WELCOME_TOAST: 8,
+  EVENTS_TOTAL: 9  // EVENTS_TOTAL is not an event; all new events need to be
                    // added before it.
 };
 
@@ -155,6 +176,47 @@
 }
 
 /**
+ * Adds authorization behavior to the request.
+ * @param {XMLHttpRequest} request Server request.
+ * @param {function(boolean)} callbackBoolean Completion callback with 'success'
+ *     parameter.
+ */
+function setAuthorization(request, callbackBoolean) {
+  tasks.debugSetStepName('setAuthorization-getAuthToken');
+  chrome.identity.getAuthToken({interactive: false}, function(token) {
+    var errorMessage =
+        chrome.runtime.lastError && chrome.runtime.lastError.message;
+    console.log('setAuthorization: error=' + errorMessage +
+                ', token=' + (token && 'non-empty'));
+    if (chrome.runtime.lastError || !token) {
+      callbackBoolean(false);
+      return;
+    }
+
+    request.setRequestHeader('Authorization', 'Bearer ' + token);
+
+    // Instrument onloadend to remove stale auth tokens.
+    var originalOnLoadEnd = request.onloadend;
+    request.onloadend = tasks.wrapCallback(function(event) {
+      if (request.status == HTTP_FORBIDDEN ||
+          request.status == HTTP_UNAUTHORIZED) {
+        tasks.debugSetStepName('setAuthorization-removeCachedAuthToken');
+        chrome.identity.removeCachedAuthToken({token: token}, function() {
+          // After purging the token cache, call getAuthToken() again to let
+          // Chrome know about the problem with the token.
+          chrome.identity.getAuthToken({interactive: false}, function() {});
+          originalOnLoadEnd(event);
+        });
+      } else {
+        originalOnLoadEnd(event);
+      }
+    });
+
+    callbackBoolean(true);
+  });
+}
+
+/**
  * Shows a notification and remembers information associated with it.
  * @param {Object} card Google Now card represented as a set of parameters for
  *     showing a Chrome notification.
@@ -343,10 +405,9 @@
       ',' + position.coords.longitude +
       ',' + position.coords.accuracy;
 
-  // TODO(vadimt): Figure out how to send user's identity to the server.
   var request = buildServerRequest('notifications');
 
-  request.onloadend = tasks.wrapCallback(function(event) {
+  request.onloadend = function(event) {
     console.log('requestNotificationCards-onloadend ' + request.status);
     if (request.status == HTTP_OK) {
       recordEvent(DiagnosticEvent.REQUEST_FOR_CARDS_SUCCESS);
@@ -354,10 +415,16 @@
     } else {
       callback();
     }
-  });
+  };
 
-  tasks.debugSetStepName('requestNotificationCards-send-request');
-  request.send(requestParameters);
+  setAuthorization(request, function(success) {
+    if (success) {
+      tasks.debugSetStepName('requestNotificationCards-send-request');
+      request.send(requestParameters);
+    } else {
+      callback();
+    }
+  });
 }
 
 /**
@@ -411,16 +478,22 @@
   var requestParameters = 'id=' + notificationId +
                           '&dismissalAge=' + (Date.now() - dismissalTimeMs);
   var request = buildServerRequest('dismiss');
-  request.onloadend = tasks.wrapCallback(function(event) {
+  request.onloadend = function(event) {
     console.log('requestDismissingCard-onloadend ' + request.status);
     if (request.status == HTTP_OK)
       recordEvent(DiagnosticEvent.DISMISS_REQUEST_SUCCESS);
 
     callbackBoolean(request.status == HTTP_OK);
-  });
+  };
 
-  tasks.debugSetStepName('requestCardDismissal-send-request');
-  request.send(requestParameters);
+  setAuthorization(request, function(success) {
+    if (success) {
+      tasks.debugSetStepName('requestCardDismissal-send-request');
+      request.send(requestParameters);
+    } else {
+      callbackBoolean(false);
+    }
+  });
 }
 
 /**
@@ -522,6 +595,28 @@
 }
 
 /**
+ * Responds to a click of one of the buttons on the welcome toast.
+ * @param {number} buttonIndex The index of the button which was clicked.
+ */
+function onToastNotificationClicked(buttonIndex) {
+  if (buttonIndex == ToastButtonIndex.YES) {
+    chrome.metricsPrivate.recordUserAction('GoogleNow.WelcomeToastClickedYes');
+    storage.set({toastState: ToastOptionResponse.CHOSE_YES});
+
+    // TODO(zturner): Update chrome geolocation setting once the settings
+    // API is in place.
+    startPollingCards();
+  } else {
+    chrome.metricsPrivate.recordUserAction('GoogleNow.WelcomeToastClickedNo');
+    storage.set({toastState: ToastOptionResponse.CHOSE_NO});
+  }
+
+  chrome.notifications.clear(
+      WELCOME_TOAST_NOTIFICATION_ID,
+      function(wasCleared) {});
+}
+
+/**
  * Callback for chrome.notifications.onClosed event.
  * @param {string} notificationId Unique identifier of the notification.
  * @param {boolean} byUser Whether the notification was closed by the user.
@@ -530,6 +625,15 @@
   if (!byUser)
     return;
 
+  if (notificationId == WELCOME_TOAST_NOTIFICATION_ID) {
+    // Even though they only closed the notification without clicking no, treat
+    // it as though they clicked No anwyay, and don't show the toast again.
+    chrome.metricsPrivate.recordUserAction('GoogleNow.WelcomeToastDismissed');
+    storage.set({toastState: ToastOptionResponse.CHOSE_NO});
+    return;
+  }
+
+  // At this point we are guaranteed that the notification is a now card.
   chrome.metricsPrivate.recordUserAction('GoogleNow.Dismissed');
 
   tasks.add(DISMISS_CARD_TASK_NAME, function(callback) {
@@ -557,9 +661,10 @@
 }
 
 /**
- * Initializes the event page on install or on browser startup.
+ * Initializes the polling system to start monitoring location and fetching
+ * cards.
  */
-function initialize() {
+function startPollingCards() {
   // Create an update timer for a case when for some reason location request
   // gets stuck.
   updateCardsAttempts.start(MAXIMUM_POLLING_PERIOD_SECONDS);
@@ -567,6 +672,47 @@
   requestLocation();
 }
 
+/**
+ * Initializes the event page on install or on browser startup.
+ */
+function initialize() {
+  recordEvent(DiagnosticEvent.EXTENSION_START);
+  storage.get('toastState', function(items) {
+    // The toast state might be undefined (e.g. not in storage yet) if this is
+    // the first time ever being prompted.
+
+    // TODO(zturner): Get the value of isGeolocationEnabled from the settings
+    // api and additionally make sure it is true.
+    if (!items.toastState) {
+      showWelcomeToast();
+    } else if (items.toastState == ToastOptionResponse.CHOSE_YES) {
+      startPollingCards();
+    }
+  });
+}
+
+/**
+ * Displays a toast to the user asking if they want to opt in to receiving
+ * Google Now cards.
+ */
+function showWelcomeToast() {
+  recordEvent(DiagnosticEvent.SHOW_WELCOME_TOAST);
+  // TODO(zturner): Localize this once the component extension localization
+  // api is complete.
+  // TODO(zturner): Add icons.
+  var buttons = [{title: 'Yes'}, {title: 'No'}];
+  var options = {
+    type: 'basic',
+    title: 'Enable Google Now Cards',
+    message: 'Would you like to be shown Google Now cards?',
+    iconUrl: 'http://www.gstatic.com/googlenow/chrome/default.png',
+    priority: 2,
+    buttons: buttons
+  };
+  chrome.notifications.create(WELCOME_TOAST_NOTIFICATION_ID, options,
+      function(notificationId) {});
+}
+
 chrome.runtime.onInstalled.addListener(function(details) {
   console.log('onInstalled ' + JSON.stringify(details));
   if (details.reason != 'chrome_update') {
@@ -589,14 +735,18 @@
 
 chrome.notifications.onButtonClicked.addListener(
     function(notificationId, buttonIndex) {
-      chrome.metricsPrivate.recordUserAction(
-          'GoogleNow.ButtonClicked' + buttonIndex);
-      onNotificationClicked(notificationId, function(actionUrls) {
-        if (!Array.isArray(actionUrls.buttonUrls))
-          return undefined;
+      if (notificationId == WELCOME_TOAST_NOTIFICATION_ID) {
+        onToastNotificationClicked(buttonIndex);
+      } else {
+        chrome.metricsPrivate.recordUserAction(
+            'GoogleNow.ButtonClicked' + buttonIndex);
+        onNotificationClicked(notificationId, function(actionUrls) {
+          if (!Array.isArray(actionUrls.buttonUrls))
+            return undefined;
 
-        return actionUrls.buttonUrls[buttonIndex];
-      });
+          return actionUrls.buttonUrls[buttonIndex];
+        });
+      }
     });
 
 chrome.notifications.onClosed.addListener(onNotificationClosed);
diff --git a/chrome/browser/resources/google_now/background_test_util.js b/chrome/browser/resources/google_now/background_test_util.js
new file mode 100644
index 0000000..f59c34e
--- /dev/null
+++ b/chrome/browser/resources/google_now/background_test_util.js
@@ -0,0 +1,25 @@
+// 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.
+
+// Mocks for globals needed for loading background.js.
+
+function emptyMock() {}
+function buildTaskManager() {
+  return {instrumentApiFunction: emptyMock};
+}
+var instrumentApiFunction = emptyMock;
+var buildAttemptManager = emptyMock;
+var emptyListener = {addListener: emptyMock};
+chrome['location'] = {onLocationUpdate: emptyListener};
+chrome['notifications'] = {
+  onButtonClicked: emptyListener,
+  onClicked: emptyListener,
+  onClosed: emptyListener
+};
+chrome['omnibox'] = {onInputEntered: emptyListener};
+chrome['runtime'] = {
+  onInstalled: emptyListener,
+  onStartup: emptyListener
+};
+var storage = {};
diff --git a/chrome/browser/resources/google_now/background_unittest.gtestjs b/chrome/browser/resources/google_now/background_unittest.gtestjs
new file mode 100644
index 0000000..149c51c
--- /dev/null
+++ b/chrome/browser/resources/google_now/background_unittest.gtestjs
@@ -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.
+
+/**
+ * Test fixture for ../background.js.
+ * @constructor
+ * @extends {testing.Test}
+ */
+function GoogleNowBackgroundUnitTest () {
+  testing.Test.call(this);
+}
+
+GoogleNowBackgroundUnitTest.prototype = {
+  __proto__: testing.Test.prototype,
+
+  /** @override */
+  extraLibraries: [
+    'background_test_util.js',
+    'background.js'
+  ]
+};
+
+TEST_F('GoogleNowBackgroundUnitTest', 'AreTasksConflicting', function() {
+  function testTaskPair(newTaskName, scheduledTaskName, expected) {
+    assertTrue(areTasksConflicting(newTaskName, scheduledTaskName) == expected,
+               '(' + newTaskName + ', ' + scheduledTaskName + ')');
+  }
+
+  testTaskPair(UPDATE_CARDS_TASK_NAME, UPDATE_CARDS_TASK_NAME, true);
+  testTaskPair(UPDATE_CARDS_TASK_NAME, DISMISS_CARD_TASK_NAME, false);
+  testTaskPair(UPDATE_CARDS_TASK_NAME, RETRY_DISMISS_TASK_NAME, false);
+
+  testTaskPair(DISMISS_CARD_TASK_NAME, UPDATE_CARDS_TASK_NAME, false);
+  testTaskPair(DISMISS_CARD_TASK_NAME, DISMISS_CARD_TASK_NAME, false);
+  testTaskPair(DISMISS_CARD_TASK_NAME, RETRY_DISMISS_TASK_NAME, false);
+
+  testTaskPair(RETRY_DISMISS_TASK_NAME, UPDATE_CARDS_TASK_NAME, true);
+  testTaskPair(RETRY_DISMISS_TASK_NAME, DISMISS_CARD_TASK_NAME, true);
+  testTaskPair(RETRY_DISMISS_TASK_NAME, RETRY_DISMISS_TASK_NAME, true);
+});
+
diff --git a/chrome/browser/resources/google_now/manifest.json b/chrome/browser/resources/google_now/manifest.json
index 0e92514..21e465e 100644
--- a/chrome/browser/resources/google_now/manifest.json
+++ b/chrome/browser/resources/google_now/manifest.json
@@ -14,7 +14,8 @@
     "tabs",
     // TODO(vadimt): Replace <all_urls> with real URL patterns once we know
     // them.
-    "<all_urls>"
+    "<all_urls>",
+    "identity"
   ],
   "manifest_version": 2,
   "background": {
@@ -22,5 +23,9 @@
     "persistent": false
   },
   // TODO(vadimt): Remove using chrome.omnibox.
-  "omnibox": { "keyword" : "gn_url" }
+  "omnibox": { "keyword" : "gn_url" },
+  "oauth2": {
+    "auto_approve": true,
+    "scopes": ["https://www.googleapis.com/auth/googlenow"]
+  }
 }
diff --git a/chrome/browser/resources/google_now/utility.js b/chrome/browser/resources/google_now/utility.js
index 3ada667..9405bde 100644
--- a/chrome/browser/resources/google_now/utility.js
+++ b/chrome/browser/resources/google_now/utility.js
@@ -152,11 +152,32 @@
    * @param {Error} error Error to report.
    */
   function sendErrorReport(error) {
-    var filteredStack = error.stack.replace(/.*\n/, '');
+    var filteredStack = error.stack.replace(/.*\n/, '\n');
+    var file;
+    var line;
+    var topFrameMatches = filteredStack.match(/\(.*\)/);
+    // topFrameMatches's example:
+    // (chrome-extension://pmofbkohncoogjjhahejjfbppikbjigm/utility.js:308:19)
+    var crashLocation = topFrameMatches && topFrameMatches[0];
+    if (crashLocation) {
+      var topFrameElements =
+          crashLocation.substring(1, crashLocation.length - 1).split(':');
+      // topFrameElements for the above example will look like:
+      // [0] chrome-extension
+      // [1] //pmofbkohncoogjjhahejjfbppikbjigm/utility.js
+      // [2] 308
+      // [3] 19
+      if (topFrameElements.length >= 3) {
+        file = topFrameElements[0] + ':' + topFrameElements[1];
+        line = topFrameElements[2];
+      }
+    }
     var requestParameters =
-        'name=' + escape(error.name) +
-        '&stack=' + escape(filteredStack);
-    var request = buildServerRequest('exception');
+        'error=' + encodeURIComponent(error.name) +
+        '&script=' + encodeURIComponent(file) +
+        '&line=' + encodeURIComponent(line) +
+        '&trace=' + encodeURIComponent(filteredStack);
+    var request = buildServerRequest('jserror');
     request.onloadend = function(event) {
       console.log('sendErrorReport status: ' + request.status);
     };
diff --git a/chrome/browser/resources/help/channel_change_page.css b/chrome/browser/resources/help/channel_change_page.css
new file mode 100644
index 0000000..3ee2f50
--- /dev/null
+++ b/chrome/browser/resources/help/channel_change_page.css
@@ -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.
+ */
+
+#channel-change-page {
+  min-height: 200px;
+  width: 500px;
+}
+
+.channel-change-page-channel label {
+  margin-left: 10px;
+}
+
+.channel-change-page-channel {
+  display: block;
+  margin: 15px 25px;
+}
+
+.show-when-selected-channel-requires-powerwash,
+.show-when-selected-channel-requires-delayed-update,
+.show-when-selected-channel-good,
+.show-when-selected-channel-unstable {
+  display: none !important;
+}
+
+.selected-channel-requires-powerwash
+.show-when-selected-channel-requires-powerwash,
+.selected-channel-requires-delayed-update
+.show-when-selected-channel-requires-delayed-update,
+.selected-channel-good .show-when-selected-channel-good,
+.selected-channel-unstable .show-when-selected-channel-unstable {
+  display: block !important;
+}
diff --git a/chrome/browser/resources/help/channel_change_page.html b/chrome/browser/resources/help/channel_change_page.html
new file mode 100644
index 0000000..0b4de9f
--- /dev/null
+++ b/chrome/browser/resources/help/channel_change_page.html
@@ -0,0 +1,54 @@
+<div id="channel-change-page" class="page">
+  <div class="close-button"></div>
+  <h1 i18n-content="channelChangePageTitle"></h1>
+  <div class="content-area">
+    <div class="channel-change-page-channel">
+      <input id="channel-change-page-stable-optiop"
+          type="radio" name="channel" value="stable-channel">
+      <label for="channel-change-page-stable-optiop" i18n-content="stable">
+      </label>
+    </div>
+    <div class="channel-change-page-channel">
+      <input id="channel-change-page-beta-option"
+          type="radio" name="channel" value="beta-channel">
+      <label for="channel-change-page-beta-option" i18n-content="beta"></label>
+    </div>
+    <div class="channel-change-page-channel">
+      <input id="channel-change-page-dev-option"
+          type="radio" name="channel" value="dev-channel">
+      <label for="channel-change-page-dev-option" i18n-content="dev"></label>
+    </div>
+  </div>
+  <div class="content-area">
+    <div class="show-when-selected-channel-requires-powerwash">
+      <h2 i18n-content="channelChangePagePowerwashTitle"></h2>
+      <div i18n-content="channelChangePagePowerwashMessage"></div>
+    </div>
+    <div class="show-when-selected-channel-requires-delayed-update">
+      <h2 i18n-content="channelChangePageDelayedChangeTitle"></h2>
+      <div i18n-content="channelChangePageDelayedChangeMessage"></div>
+    </div>
+    <div class="show-when-selected-channel-unstable">
+      <h2 i18n-content="channelChangePageUnstableTitle"></h2>
+      <div i18n-content="channelChangePageUnstableMessage"></div>
+    </div>
+  </div>
+  <div class="action-area">
+    <div class="button-strip">
+      <button id="channel-change-page-powerwash-button"
+          class="show-when-selected-channel-requires-powerwash"
+          i18n-content="channelChangePagePowerwashButton">
+      </button>
+      <button id="channel-change-page-change-button"
+          class="show-when-selected-channel-requires-delayed-update
+                 show-when-selected-channel-good
+                 show-when-selected-channel-unstable"
+          i18n-content="channelChangePageChangeButton">
+      </button>
+      <button id="channel-change-page-cancel-button"
+          class="default-button"
+          i18n-content="channelChangePageCancelButton">
+      </button>
+    </div>
+  </div>
+</div>
diff --git a/chrome/browser/resources/help/channel_change_page.js b/chrome/browser/resources/help/channel_change_page.js
new file mode 100644
index 0000000..4f22ce8
--- /dev/null
+++ b/chrome/browser/resources/help/channel_change_page.js
@@ -0,0 +1,237 @@
+// 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.
+
+cr.define('help', function() {
+  /**
+   * Encapsulated handling of the channel change overlay.
+   */
+  function ChannelChangePage() {}
+
+  cr.addSingletonGetter(ChannelChangePage);
+
+  ChannelChangePage.prototype = {
+    __proto__: HTMLDivElement.prototype,
+
+    /**
+     * Name of the channel the device is currently on.
+     * @private
+     */
+    currentChannel_: null,
+
+    /**
+     * Name of the channel the device is supposed to be on.
+     * @private
+     */
+    targetChannel_: null,
+
+    /**
+     * True iff the device is enterprise-managed.
+     * @private
+     */
+    isEnterpriseManaged_: undefined,
+
+    /**
+     * List of the channels names, from the least stable to the most stable.
+     * @private
+     */
+    channelList_: ['dev-channel', 'beta-channel', 'stable-channel'],
+
+    /**
+     * List of the possible ui states.
+     * @private
+     */
+    uiClassTable_: ['selected-channel-requires-powerwash',
+                    'selected-channel-requires-delayed-update',
+                    'selected-channel-good',
+                    'selected-channel-unstable'],
+
+    /**
+     * Perform initial setup.
+     */
+    initialize: function() {
+      var self = this;
+
+      $('channel-change-page-cancel-button').onclick = function() {
+        help.HelpPage.cancelOverlay();
+      };
+
+      var options = this.getAllChannelOptions_();
+      for (var i = 0; i < options.length; i++) {
+        var option = options[i];
+        option.onclick = function() {
+          self.updateUI_(this.value);
+        };
+      }
+
+      $('channel-change-page-powerwash-button').onclick = function() {
+        self.setChannel_(self.getSelectedOption_(), true);
+        help.HelpPage.cancelOverlay();
+      };
+
+      $('channel-change-page-change-button').onclick = function() {
+        self.setChannel_(self.getSelectedOption_(), false);
+        help.HelpPage.cancelOverlay();
+      };
+    },
+
+    /**
+     * Returns the list of all radio buttons responsible for channel selection.
+     * @return {Array.<HTMLInputElement>} Array of radio buttons
+     * @private
+     */
+    getAllChannelOptions_: function() {
+      return $('channel-change-page').querySelectorAll('input[type="radio"]');
+    },
+
+    /**
+     * Returns value of the selected option.
+     * @return {string} Selected channel name or null, if neither
+     *     option is selected.
+     * @private
+     */
+    getSelectedOption_: function() {
+      var options = this.getAllChannelOptions_();
+      for (var i = 0; i < options.length; i++) {
+        var option = options[i];
+        if (option.checked)
+          return option.value;
+      }
+      return null;
+    },
+
+    /**
+     * Updates UI according to selected channel.
+     * @param {string} selectedChannel Selected channel
+     * @private
+     */
+    updateUI_: function(selectedChannel) {
+      var currentStability = this.channelList_.indexOf(this.currentChannel_);
+      var newStability = this.channelList_.indexOf(selectedChannel);
+
+      var newOverlayClass = null;
+
+      if (selectedChannel == this.currentChannel_) {
+        if (this.currentChannel_ != this.targetChannel_) {
+          // Allow user to switch back to the current channel.
+          newOverlayClass = 'selected-channel-good';
+        }
+      } else if (selectedChannel != this.targetChannel_) {
+        // Selected channel isn't equal to the current and target channel.
+        if (newStability > currentStability) {
+          // More stable channel is selected. For customer devices
+          // notify user about powerwash.
+          if (this.isEnterpriseManaged_)
+            newOverlayClass = 'selected-channel-requires-delayed-update';
+          else
+            newOverlayClass = 'selected-channel-requires-powerwash';
+        } else if (selectedChannel == 'dev-channel') {
+          // Warn user about unstable channel.
+          newOverlayClass = 'selected-channel-unstable';
+        } else {
+          // Switching to the less stable channel.
+          newOverlayClass = 'selected-channel-good';
+        }
+      }
+
+      // Switch to the new UI state.
+      for (var i = 0; i < this.uiClassTable_.length; i++)
+          $('channel-change-page').classList.remove(this.uiClassTable_[i]);
+
+      if (newOverlayClass)
+        $('channel-change-page').classList.add(newOverlayClass);
+    },
+
+    /**
+     * Sets the device target channel.
+     * @param {string} channel The name of the target channel
+     * @param {boolean} isPowerwashAllowed True iff powerwash is allowed
+     * @private
+     */
+    setChannel_: function(channel, isPowerwashAllowed) {
+      this.targetChannel_ = channel;
+      this.updateUI_(channel);
+      help.HelpPage.setChannel(channel, isPowerwashAllowed);
+    },
+
+    /**
+     * Updates page UI according to device owhership policy.
+     * @param {boolean} isEnterpriseManaged True if the device is
+     *     enterprise managed
+     * @private
+     */
+    updateIsEnterpriseManaged_: function(isEnterpriseManaged) {
+      this.isEnterpriseManaged_ = isEnterpriseManaged;
+      help.HelpPage.updateChannelChangePageContainerVisibility();
+    },
+
+    /**
+     * Updates name of the current channel, i.e. the name of the
+     * channel the device is currently on.
+     * @param {string} channel The name of the current channel
+     * @private
+     */
+    updateCurrentChannel_: function(channel) {
+     if (this.channelList_.indexOf(channel) < 0)
+        return;
+      this.currentChannel_ = channel;
+
+      var options = this.getAllChannelOptions_();
+      for (var i = 0; i < options.length; i++) {
+        var option = options[i];
+        if (option.value == channel)
+          option.checked = true;
+      }
+      help.HelpPage.updateChannelChangePageContainerVisibility();
+    },
+
+    /**
+     * Updates name of the target channel, i.e. the name of the
+     * channel the device is supposed to be in case of a pending
+     * channel change.
+     * @param {string} channel The name of the target channel
+     * @private
+     */
+    updateTargetChannel_: function(channel) {
+      if (this.channelList_.indexOf(channel) < 0)
+        return;
+      this.targetChannel_ = channel;
+      help.HelpPage.updateChannelChangePageContainerVisibility();
+    },
+
+    /**
+     * @return {boolean} True if the page is ready and can be
+     *     displayed, false otherwise
+     * @private
+     */
+    isPageReady_: function() {
+      if (typeof this.isEnterpriseManaged_ == 'undefined')
+        return false;
+      if (!this.currentChannel_ || !this.targetChannel_)
+        return false;
+      return true;
+    },
+  };
+
+  ChannelChangePage.updateIsEnterpriseManaged = function(isEnterpriseManaged) {
+    ChannelChangePage.getInstance().updateIsEnterpriseManaged_(
+        isEnterpriseManaged);
+  };
+
+  ChannelChangePage.updateCurrentChannel = function(channel) {
+    ChannelChangePage.getInstance().updateCurrentChannel_(channel);
+  };
+
+  ChannelChangePage.updateTargetChannel = function(channel) {
+    ChannelChangePage.getInstance().updateTargetChannel_(channel);
+  };
+
+  ChannelChangePage.isPageReady = function() {
+    return ChannelChangePage.getInstance().isPageReady_();
+  };
+
+  // Export
+  return {
+    ChannelChangePage: ChannelChangePage
+  };
+});
diff --git a/chrome/browser/resources/help/help.css b/chrome/browser/resources/help/help.css
index dff7612..f82eed0 100644
--- a/chrome/browser/resources/help/help.css
+++ b/chrome/browser/resources/help/help.css
@@ -7,6 +7,10 @@
   -webkit-user-select: text;
 }
 
+#overlay .page:not(.showing) {
+  display: none;
+}
+
 #about-container {
   -webkit-box-align: center;
   display: -webkit-box;
@@ -51,15 +55,24 @@
   margin-top: 200px;
 }
 
-#update-status-icon {
+.help-page-icon,
+.help-page-icon-large {
   background-repeat: no-repeat;
   display: inline-block;
-  height: 17px;
   margin-right: 4px;
   vertical-align: top;
+}
+
+.help-page-icon {
+  height: 17px;
   width: 17px;
 }
 
+.help-page-icon-large {
+  height: 22px;
+  width: 22px;
+}
+
 #update-status-icon.up-to-date {
   background-image: url('chrome://theme/IDR_UPDATE_UPTODATE');
   background-size: 17px;
@@ -101,3 +114,33 @@
 #channel-change-confirmation {
   margin-top: 5px;
 }
+
+#change-channel {
+  margin-top: 8px;
+}
+
+#channel-change-disallowed-icon {
+  -webkit-margin-start: 4px;
+  background-image: url('chrome://theme/IDR_CONTROLLED_SETTING_MANDATORY_GRAY');
+  background-size: 17px;
+  vertical-align: middle;
+}
+
+.channel-change-error-bubble {
+  display: -webkit-box;
+}
+
+.channel-change-error-icon {
+  -webkit-margin-start: 4px;
+  background-image:
+      url('chrome://theme/IDR_CONTROLLED_SETTING_MANDATORY_LARGE');
+  background-size: 22px;
+  vertical-align: top;
+}
+
+.channel-change-error-text {
+  -webkit-margin-start: 4px;
+  display: block;
+  vertical-align: top;
+  width: 240px;
+}
diff --git a/chrome/browser/resources/help/help.html b/chrome/browser/resources/help/help.html
index 3f1dbdd..40658fd 100644
--- a/chrome/browser/resources/help/help.html
+++ b/chrome/browser/resources/help/help.html
@@ -6,13 +6,31 @@
   <link rel="stylesheet" href="chrome://resources/css/chrome_shared.css">
   <link rel="stylesheet" href="../uber/uber_shared.css">
   <link rel="stylesheet" href="help.css">
+<if expr="pp_ifdef('chromeos')">
+  <link rel="stylesheet" href="chrome://resources/css/bubble.css">
+  <link rel="stylesheet" href="chrome://resources/css/overlay.css">
+  <link rel="stylesheet" href="channel_change_page.css">
+</if>
+
   <script src="chrome://resources/js/cr.js"></script>
   <script src="chrome://resources/js/load_time_data.js"></script>
   <script src="chrome://resources/js/util.js"></script>
+<if expr="pp_ifdef('chromeos')">
+  <script src="chrome://resources/js/cr/ui.js"></script>
+  <script src="chrome://resources/js/cr/ui/bubble.js"></script>
+  <script src="chrome://resources/js/cr/ui/overlay.js"></script>
+  <script src="chrome://resources/js/event_tracker.js"></script>
+  <script src="chrome://help-frame/channel_change_page.js"></script>
+</if>
   <script src="chrome://help-frame/help.js"></script>
 </head>
 <body class="uber-frame"
     i18n-values=".style.fontFamily:fontfamily;.style.fontSize:fontsize">
+  <div id="overlay-container" class="overlay" hidden>
+<if expr="pp_ifdef('chromeos')">
+    <include src="channel_change_page.html">
+</if>
+  </div>
   <div class="page">
     <header>
       <h1 i18n-content="aboutTitle"></h1>
@@ -40,7 +58,7 @@
 </if>
 <if expr="pp_ifdef('chromeos') or pp_ifdef('_google_chrome') or is_linux">
       <div id="update-status-container" hidden>
-        <div id="update-status-icon" class="up-to-date"></div>
+        <div id="update-status-icon" class="help-page-icon up-to-date"></div>
         <div id="update-status-message-container">
           <div id="update-status-message" i18n-content="updateCheckStarted">
           </div>
@@ -53,11 +71,16 @@
         <button id="promote" i18n-content="promote" hidden></button>
 </if>
         <button id="relaunch" i18n-content="relaunch" hidden></button>
+<if expr="pp_ifdef('chromeos')">
+        <button id="relaunch-and-powerwash"
+            i18n-content="relaunchAndPowerwash" hidden>
+        </button>
+</if>
       </div>
 </if>
 <if expr="pp_ifdef('chromeos')">
       <div id="more-info-container">
-        <section id="channel-changer-container">
+        <section id="channel-changer-container" hidden>
           <h3 i18n-content="channel"></h3>
           <select id="channel-changer">
             <option value="stable-channel" i18n-content="stable"></option>
@@ -66,6 +89,16 @@
           </select>
           <div id="channel-change-confirmation" hidden></div>
         </section>
+        <section id="channel-change-page-container" hidden>
+          <h3 i18n-content="channel"></h3>
+          <div id="current-channel"></div>
+          <button id="change-channel"
+              i18n-content="channelChangeButton" disabled>
+          </button>
+          <div id="channel-change-disallowed-icon"
+              class="help-page-icon" hidden>
+          </div>
+        </section>
         <section>
           <h3 i18n-content="webkit"></h3>
           <div i18n-content="webkitVersion" dir="ltr"></div>
diff --git a/chrome/browser/resources/help/help.js b/chrome/browser/resources/help/help.js
index 7aa3e52..2ed56c1 100644
--- a/chrome/browser/resources/help/help.js
+++ b/chrome/browser/resources/help/help.js
@@ -16,9 +16,41 @@
     __proto__: HTMLDivElement.prototype,
 
     /**
+     * True if after update powerwash button should be displayed.
+     * @private
+     */
+    powerwashAfterUpdate_: false,
+
+    /**
+     * List of the channels names.
+     * @private
+     */
+    channelList_: ['dev-channel', 'beta-channel', 'stable-channel'],
+
+    /**
+     * Bubble for error messages and notifications.
+     * @private
+     */
+    bubble_: null,
+
+    /**
+     * Name of the channel the device is currently on.
+     * @private
+     */
+    currentChannel_: null,
+
+    /**
+     * Name of the channel the device is supposed to be on.
+     * @private
+     */
+    targetChannel_: null,
+
+    /**
      * Perform initial setup.
      */
     initialize: function() {
+      var self = this;
+
       uber.onContentFrameLoaded();
 
       // Set the title.
@@ -51,18 +83,65 @@
       this.maybeSetOnClick_($('relaunch'), function() {
         chrome.send('relaunchNow');
       });
+      if (cr.isChromeOS) {
+        this.maybeSetOnClick_($('relaunch-and-powerwash'), function() {
+          chrome.send('relaunchAndPowerwash');
+        });
+
+        this.channelTable_ = {
+          'stable-channel': {
+              'name': loadTimeData.getString('stable'),
+              'label': loadTimeData.getString('currentChannelStable'),
+          },
+          'beta-channel': {
+              'name': loadTimeData.getString('beta'),
+              'label': loadTimeData.getString('currentChannelBeta')
+          },
+          'dev-channel': {
+              'name': loadTimeData.getString('dev'),
+              'label': loadTimeData.getString('currentChannelDev')
+          }
+        };
+      }
 
       var channelChanger = $('channel-changer');
       if (channelChanger) {
-        this.channelName_ = {
-            'stable-channel': loadTimeData.getString('stable'),
-            'beta-channel': loadTimeData.getString('beta'),
-            'dev-channel': loadTimeData.getString('dev')
-        };
-        var self = this;
         channelChanger.onchange = function(event) {
-          self.setReleaseChannel_(event.target.value);
-        }
+          self.setChannel_(event.target.value, false);
+        };
+      }
+
+      if (cr.isChromeOS) {
+        cr.ui.overlay.globalInitialization();
+        cr.ui.overlay.setupOverlay($('overlay-container'));
+        $('overlay-container').addEventListener('cancelOverlay', function() {
+          self.showOverlay_(null);
+        });
+
+        $('change-channel').onclick = function() {
+          self.showOverlay_($('channel-change-page'));
+        };
+
+        var channelChangeDisallowedError = document.createElement('div');
+        channelChangeDisallowedError.className = 'channel-change-error-bubble';
+
+        var channelChangeDisallowedIcon = document.createElement('div');
+        channelChangeDisallowedIcon.classList.add('help-page-icon-large');
+        channelChangeDisallowedIcon.classList.add('channel-change-error-icon');
+        channelChangeDisallowedError.appendChild(channelChangeDisallowedIcon);
+
+        var channelChangeDisallowedText = document.createElement('div');
+        channelChangeDisallowedText.className = 'channel-change-error-text';
+        channelChangeDisallowedText.textContent =
+            loadTimeData.getString('channelChangeDisallowedMessage');
+        channelChangeDisallowedError.appendChild(channelChangeDisallowedText);
+
+        $('channel-change-disallowed-icon').onclick = function() {
+            self.showBubble_(channelChangeDisallowedError,
+                             $('help-container'),
+                             $('channel-change-disallowed-icon'),
+                             cr.ui.ArrowLocation.TOP_END);
+        };
       }
 
       // Attempt to update.
@@ -70,6 +149,39 @@
     },
 
     /**
+     * Shows the bubble.
+     * @param {HTMLDivElement} content The content of the bubble.
+     * @param {HTMLElement} target The element at which the bubble points.
+     * @param {HTMLElement} domSibling The element after which the bubble is
+     *     added to the DOM.
+     * @param {cr.ui.ArrowLocation} location The arrow location.
+     * @private
+     */
+    showBubble_: function(content, domSibling, target, location) {
+      if (!cr.isChromeOS)
+        return;
+      this.hideBubble_();
+      var bubble = new cr.ui.AutoCloseBubble;
+      bubble.anchorNode = target;
+      bubble.domSibling = domSibling;
+      bubble.arrowLocation = location;
+      bubble.content = content;
+      bubble.show();
+      this.bubble_ = bubble;
+    },
+
+    /**
+     * Hides the bubble.
+     * @private
+     */
+    hideBubble_: function() {
+      if (!cr.isChromeOS)
+        return;
+      if (this.bubble_)
+        this.bubble_.hide();
+    },
+
+    /**
      * Toggles the visible state of the 'More Info' section.
      * @private
      */
@@ -98,25 +210,66 @@
      * @private
      */
     setUpdateImage_: function(state) {
-      $('update-status-icon').className = 'update-icon ' + state;
+      $('update-status-icon').className = 'help-page-icon ' + state;
+    },
+
+    /**
+     * Returns current overlay.
+     * @return {HTMLElement} Current overlay
+     * @private
+     */
+    getCurrentOverlay_: function() {
+      return document.querySelector('#overlay .page.showing');
+    },
+
+    /**
+     * @return {boolean} True, if new channel switcher UI is used,
+     *    false otherwise.
+     * @private
+     */
+    isNewChannelSwitcherUI_: function() {
+      return !loadTimeData.valueExists('disableNewChannelSwitcherUI');
+    },
+
+    /**
+     * @return {boolean} True if target and current channels are not
+     *     null and not equals
+     * @private
+     */
+    channelsDiffer_: function() {
+      var current = this.currentChannel_;
+      var target = this.targetChannel_;
+      return (current != null && target != null && current != target);
     },
 
     /**
      * @private
      */
     setUpdateStatus_: function(status, message) {
+      var channel = this.targetChannel_;
       if (status == 'checking') {
         this.setUpdateImage_('working');
         $('update-status-message').innerHTML =
             loadTimeData.getString('updateCheckStarted');
       } else if (status == 'updating') {
         this.setUpdateImage_('working');
-        $('update-status-message').innerHTML =
-            loadTimeData.getString('updating');
+        if (this.channelsDiffer_()) {
+          $('update-status-message').innerHTML =
+              loadTimeData.getStringF('updatingChannelSwitch',
+                                      this.channelTable_[channel].label);
+        } else {
+          $('update-status-message').innerHTML =
+              loadTimeData.getStringF('updating');
+        }
       } else if (status == 'nearly_updated') {
         this.setUpdateImage_('up-to-date');
-        $('update-status-message').innerHTML =
-            loadTimeData.getString('updateAlmostDone');
+        if (this.channelsDiffer_()) {
+          $('update-status-message').innerHTML =
+              loadTimeData.getString('successfulChannelSwitch');
+        } else {
+          $('update-status-message').innerHTML =
+              loadTimeData.getString('updateAlmostDone');
+        }
       } else if (status == 'updated') {
         this.setUpdateImage_('up-to-date');
         $('update-status-message').innerHTML =
@@ -134,6 +287,14 @@
         if (!cr.isMac)
           $('update-percentage').hidden = status != 'updating';
       }
+
+      if ($('relaunch-and-powerwash')) {
+        // It's allowed to do powerwash only for customer devices,
+        // when user explicitly decides to update to a more stable
+        // channel.
+        $('relaunch-and-powerwash').hidden =
+            !this.powerwashAfterUpdate_ || status != 'nearly_updated';
+      }
     },
 
     /**
@@ -201,14 +362,27 @@
      *     overlays are hidden.
      */
     showOverlay_: function(node) {
-      var currentlyShowingOverlay =
-        document.querySelector('#overlay .page.showing');
+      var currentlyShowingOverlay = this.getCurrentOverlay_();
       if (currentlyShowingOverlay)
         currentlyShowingOverlay.classList.remove('showing');
-
       if (node)
         node.classList.add('showing');
-      $('overlay').hidden = !node;
+      $('overlay-container').hidden = !node;
+    },
+
+    /**
+     * Updates name of the current channel, i.e. the name of the
+     * channel the device is currently on.
+     * @param {string} channel The name of the current channel
+     * @private
+     */
+    updateCurrentChannel_: function(channel) {
+      if (this.channelList_.indexOf(channel) < 0)
+        return;
+      $('current-channel').textContent = loadTimeData.getStringF(
+          'currentChannel', this.channelTable_[channel].label);
+      this.currentChannel_ = channel;
+      help.ChannelChangePage.updateCurrentChannel(channel);
     },
 
     /**
@@ -216,29 +390,24 @@
      * @private
      */
     updateEnableReleaseChannel_: function(enabled) {
-      $('channel-changer-container').hidden = !enabled;
+      this.updateChannelChangerContainerVisibility_(enabled);
+      $('change-channel').disabled = !enabled;
+      $('channel-change-disallowed-icon').hidden = enabled;
     },
 
     /**
+     * Sets the device target channel.
+     * @param {string} channel The name of the target channel
+     * @param {boolean} isPowerwashAllowed True iff powerwash is allowed
      * @private
      */
-    updateSelectedChannel_: function(value) {
-      var options = $('channel-changer').querySelectorAll('option');
-      for (var i = 0; i < options.length; i++) {
-        var option = options[i];
-        if (option.value == value)
-          option.selected = true;
-      }
-    },
-
-    /**
-     * @private
-     */
-    setReleaseChannel_: function(channel) {
-      chrome.send('setReleaseTrack', [channel]);
+    setChannel_: function(channel, isPowerwashAllowed) {
+      this.powerwashAfterUpdate_ = isPowerwashAllowed;
+      this.targetChannel_ = channel;
+      chrome.send('setChannel', [channel, isPowerwashAllowed]);
       $('channel-change-confirmation').hidden = false;
       $('channel-change-confirmation').textContent = loadTimeData.getStringF(
-          'channel-changed', this.channelName_[channel]);
+          'channel-changed', this.channelTable_[channel].name);
     },
 
     /**
@@ -250,6 +419,35 @@
       $('build-date-container').classList.remove('empty');
       $('build-date').textContent = buildDate;
     },
+
+    /**
+     * Updates channel-change-page-container visibility according to
+     * internal state.
+     * @private
+     */
+    updateChannelChangePageContainerVisibility_: function() {
+      if (!this.isNewChannelSwitcherUI_()) {
+        $('channel-change-page-container').hidden = true;
+        return;
+      }
+      $('channel-change-page-container').hidden =
+          !help.ChannelChangePage.isPageReady();
+    },
+
+    /**
+     * Updates channel-changer dropdown visibility if |visible| is
+     * true and new channel switcher UI is disallowed.
+     * @param {boolean} visible True if channel-changer should be
+     *     displayed, false otherwise.
+     * @private
+     */
+    updateChannelChangerContainerVisibility_: function(visible) {
+      if (this.isNewChannelSwitcherUI_()) {
+        $('channel-changer').hidden = true;
+        return;
+      }
+      $('channel-changer').hidden = !visible;
+    },
   };
 
   HelpPage.setUpdateStatus = function(status, message) {
@@ -289,21 +487,43 @@
     HelpPage.getInstance().showOverlay_(node);
   };
 
-  HelpPage.updateSelectedChannel = function(channel) {
-    HelpPage.getInstance().updateSelectedChannel_(channel);
+  HelpPage.cancelOverlay = function() {
+    HelpPage.getInstance().showOverlay_(null);
+  };
+
+  HelpPage.updateIsEnterpriseManaged = function(isEnterpriseManaged) {
+    if (!cr.isChromeOS)
+      return;
+    help.ChannelChangePage.updateIsEnterpriseManaged(isEnterpriseManaged);
+  };
+
+  HelpPage.updateCurrentChannel = function(channel) {
+    if (!cr.isChromeOS)
+      return;
+    HelpPage.getInstance().updateCurrentChannel_(channel);
+  };
+
+  HelpPage.updateTargetChannel = function(channel) {
+    if (!cr.isChromeOS)
+      return;
+    help.ChannelChangePage.updateTargetChannel(channel);
   };
 
   HelpPage.updateEnableReleaseChannel = function(enabled) {
     HelpPage.getInstance().updateEnableReleaseChannel_(enabled);
   };
 
-  HelpPage.setReleaseChannel = function(channel) {
-    HelpPage.getInstance().setReleaseChannel_(channel);
+  HelpPage.setChannel = function(channel, isPowerwashAllowed) {
+    HelpPage.getInstance().setChannel_(channel, isPowerwashAllowed);
   };
 
   HelpPage.setBuildDate = function(buildDate) {
     HelpPage.getInstance().setBuildDate_(buildDate);
-  }
+  };
+
+  HelpPage.updateChannelChangePageContainerVisibility = function() {
+    HelpPage.getInstance().updateChannelChangePageContainerVisibility_();
+  };
 
   // Export
   return {
@@ -316,4 +536,6 @@
  */
 window.onload = function() {
   help.HelpPage.getInstance().initialize();
+  if (cr.isChromeOS)
+    help.ChannelChangePage.getInstance().initialize();
 };
diff --git a/chrome/browser/resources/history/history.css b/chrome/browser/resources/history/history.css
index 9abc363..c929298 100644
--- a/chrome/browser/resources/history/history.css
+++ b/chrome/browser/resources/history/history.css
@@ -342,12 +342,12 @@
 }
 
 .no-checkboxes .entry .time {
-  min-width: 68px;
+  min-width: 73px;
 }
 
 .entry .time {
   color: rgb(151, 156, 160);
-  min-width: 55px;
+  min-width: 60px;
   overflow: hidden;
   text-align: right;
   text-overflow: ellipsis;
diff --git a/chrome/browser/resources/history/history.js b/chrome/browser/resources/history/history.js
index 892cce1..f1eac1f 100644
--- a/chrome/browser/resources/history/history.js
+++ b/chrome/browser/resources/history/history.js
@@ -12,6 +12,10 @@
 // measured in milliseconds.
 /** @const */ var BROWSING_GAP_TIME = 15 * 60 * 1000;
 
+// The largest bucket value for UMA histogram, based on entry ID. All entries
+// with IDs greater than this will be included in this bucket.
+/** @const */ var UMA_MAX_BUCKET_VALUE = 1000;
+
 // TODO(glen): Get rid of these global references, replace with a controller
 //     or just make the classes own more of the page.
 var historyModel;
@@ -53,6 +57,20 @@
   chrome.send('metricsHandler:recordAction', [actionDesc]);
 }
 
+/**
+ * Record a histogram value in UMA. If specified value is larger than the max
+ * bucket value, record the value in the largest bucket.
+ * @param {string} histogram The name of the histogram to be recorded in.
+ * @param {integer} value The value to record in the histogram.
+ */
+
+function recordUmaHistogram(histogram, value) {
+  chrome.send('metricsHandler:recordInHistogram',
+              [histogram,
+              ((value > UMA_MAX_BUCKET_VALUE) ? UMA_MAX_BUCKET_VALUE : value),
+              UMA_MAX_BUCKET_VALUE]);
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 // Visit:
 
@@ -76,7 +94,7 @@
   this.deviceName = result.deviceName;
   this.deviceType = result.deviceType;
 
-  // The id will be set according to when the visit was displayed, not
+  // The ID will be set according to when the visit was displayed, not
   // received. Set to -1 to show that it has not been set yet.
   this.id_ = -1;
 
@@ -180,7 +198,7 @@
     visitEntryWrapper.classList.add('blocked-indicator');
     visitEntryWrapper.appendChild(this.getVisitAttemptDOM_());
   } else {
-    visitEntryWrapper.appendChild(this.getTitleDOM_());
+    visitEntryWrapper.appendChild(this.getTitleDOM_(isSearchResult));
     if (addTitleFavicon)
       this.addFaviconToElement_(visitEntryWrapper);
     visitEntryWrapper.appendChild(domain);
@@ -308,22 +326,33 @@
 /**
  * Returns the DOM element containing a link on the title of the URL for the
  * current visit.
+ * @param {boolean} isSearchResult Whether or not the entry is a search result.
  * @return {Element} DOM representation for the title block.
  * @private
  */
-Visit.prototype.getTitleDOM_ = function() {
+Visit.prototype.getTitleDOM_ = function(isSearchResult) {
   var node = createElementWithClassName('div', 'title');
   var link = document.createElement('a');
   link.href = this.url_;
   link.id = 'id-' + this.id_;
   link.target = '_top';
+  var integerId = parseInt(this.id_, 10);
   link.addEventListener('click', function() {
     recordUmaAction('EntryLinkClick_HistoryPage');
+    // Record the ID of the entry to signify how many entries are above this
+    // link on the page.
+    recordUmaHistogram('HistoryPage.ClickPosition', integerId);
   });
   link.addEventListener('contextmenu', function() {
     recordUmaAction('EntryLinkRightClick_HistoryPage');
   });
 
+  if (isSearchResult) {
+    link.addEventListener('click', function() {
+      recordUmaAction('SearchResultClick_HistoryPage');
+    });
+  }
+
   // Add a tooltip, since it might be ellipsized.
   // TODO(dubroy): Find a way to show the tooltip only when necessary.
   link.title = this.title_;
@@ -1619,6 +1648,12 @@
     checkbox.disabled = true;
     link.classList.add('to-be-removed');
     disabledItems.push(checkbox);
+    var integerId = parseInt(entry.visit.id_, 10);
+    // Record the ID of the entry to signify how many entries are above this
+    // link on the page.
+    recordUmaHistogram('HistoryPage.RemoveEntryPosition', integerId);
+    if (entry.parentNode.className == 'search-results')
+      recordUmaAction('SearchResultRemove_HistoryPage');
   }
 
   function onConfirmRemove() {
diff --git a/chrome/browser/resources/history/history_mobile.css b/chrome/browser/resources/history/history_mobile.css
index f5ee26e..a65c9d5 100644
--- a/chrome/browser/resources/history/history_mobile.css
+++ b/chrome/browser/resources/history/history_mobile.css
@@ -195,7 +195,7 @@
   display: none;
 }
 
-.entry .title-and-domain {
+.entry .visit-entry {
   -webkit-flex: auto;
   -webkit-flex-flow: column;
   -webkit-padding-start: 48px;
@@ -229,7 +229,7 @@
   display: -webkit-box;
 }
 
-.entry .title-and-domain {
+.entry .visit-entry {
   -webkit-box-flex: 1;
   -webkit-box-orient: vertical;
   -webkit-box-pack: center;
@@ -237,6 +237,10 @@
 }
 </if>
 
+.entry .bookmark-section {
+  display: none;
+}
+
 @media only screen and (max-width:600px) {
 
 /* Omit the time on very small screens. */
diff --git a/chrome/browser/resources/identity_internals.js b/chrome/browser/resources/identity_internals.js
index 4e1ea16..7e7a01f 100644
--- a/chrome/browser/resources/identity_internals.js
+++ b/chrome/browser/resources/identity_internals.js
@@ -7,7 +7,7 @@
 
   /**
    * Creates an identity token item.
-   * @param {Object} tokenInfo Object containing token information.
+   * @param {!Object} tokenInfo Object containing token information.
    * @constructor
    */
   function TokenListItem(tokenInfo) {
@@ -24,12 +24,12 @@
     /** @override */
     decorate: function() {
       this.textContent = '';
-      this.id = this.data_.tokenId;
+      this.id = this.data_.accessToken;
 
       var table = this.ownerDocument.createElement('table');
       var tbody = this.ownerDocument.createElement('tbody');
       tbody.appendChild(this.createEntry_(
-          'tokenId', this.data_.tokenId, 'token-id'));
+          'accessToken', this.data_.accessToken, 'access-token'));
       tbody.appendChild(this.createEntry_(
           'extensionName', this.data_.extensionName, 'extension-name'));
       tbody.appendChild(this.createEntry_(
@@ -114,7 +114,7 @@
       revokeButton.classList.add('revoke-button');
       revokeButton.addEventListener('click', function() {
         chrome.send('identityInternalsRevokeToken',
-                    [this.data_.extensionId, this.data_.tokenId]);
+                    [this.data_.extensionId, this.data_.accessToken]);
       }.bind(this));
       revokeButton.textContent = loadTimeData.getString('revoke');
       return revokeButton;
@@ -150,13 +150,13 @@
     /**
      * Removes a token node related to the specifed token ID from both the
      * internals data source as well as the user internface.
-     * @param {string} tokenId The id of the token to remove.
+     * @param {string} accessToken The id of the token to remove.
      * @private
      */
-    removeTokenNode_: function(tokenId) {
+    removeTokenNode_: function(accessToken) {
       var tokenIndex;
       for (var index = 0; index < this.data_.length; index++) {
-        if (this.data_[index].tokenId == tokenId) {
+        if (this.data_[index].accessToken == accessToken) {
           tokenIndex = index;
           break;
         }
@@ -167,7 +167,7 @@
         this.data_.splice(tokenIndex, 1);
 
       // Remove from the user interface.
-      var tokenNode = $(tokenId);
+      var tokenNode = $(accessToken);
       if (tokenNode)
         this.removeChild(tokenNode);
     },
@@ -188,7 +188,7 @@
 
   /**
    * Callback function accepting a list of tokens to be displayed.
-   * @param {Token[]} tokens A list of tokens to be displayed
+   * @param {!Token[]} tokens A list of tokens to be displayed
    */
   function returnTokens(tokens) {
     tokenList_.data_ = tokens;
@@ -197,12 +197,12 @@
 
   /**
    * Callback function that removes a token from UI once it has been revoked.
-   * @param {!Array.<string>} tokenIds Array with a single element, which is a
-   * token ID, of the token to be removed.
+   * @param {!Array.<string>} accessTokens Array with a single element, which is
+   * an access token to be removed.
    */
-  function tokenRevokeDone(tokenIds) {
-    assert(tokenIds.length > 0);
-    tokenList_.removeTokenNode_(tokenIds[0]);
+  function tokenRevokeDone(accessTokens) {
+    assert(accessTokens.length > 0);
+    tokenList_.removeTokenNode_(accessTokens[0]);
   }
 
   // Return an object with all of the exports.
diff --git a/chrome/browser/resources/image_loader/background.js b/chrome/browser/resources/image_loader/background.js
new file mode 100644
index 0000000..028a082
--- /dev/null
+++ b/chrome/browser/resources/image_loader/background.js
@@ -0,0 +1,8 @@
+// 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 strict';
+
+// Load the extension.
+ImageLoader.getInstance();
diff --git a/chrome/browser/resources/image_loader/cache.js b/chrome/browser/resources/image_loader/cache.js
new file mode 100644
index 0000000..dde287c
--- /dev/null
+++ b/chrome/browser/resources/image_loader/cache.js
@@ -0,0 +1,410 @@
+// 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 strict';
+
+/**
+ * Persistent cache storing images in an indexed database on the hard disk.
+ * @constructor
+ */
+function Cache() {
+  /**
+   * IndexedDB database handle.
+   * @type {IDBDatabase}
+   * @private
+   */
+  this.db_ = null;
+}
+
+/**
+ * Cache database name.
+ * @type {string}
+ * @const
+ */
+Cache.DB_NAME = 'image-loader';
+
+/**
+ * Cache database version.
+ * @type {number}
+ * @const
+ */
+Cache.DB_VERSION = 11;
+
+/**
+ * Memory limit for images data in bytes.
+ *
+ * @const
+ * @type {number}
+ */
+Cache.MEMORY_LIMIT = 250 * 1024 * 1024;  // 250 MB.
+
+/**
+ * Minimal amount of memory freed per eviction. Used to limit number of
+ * evictions which are expensive.
+ *
+ * @const
+ * @type {number}
+ */
+Cache.EVICTION_CHUNK_SIZE = 50 * 1024 * 1024;  // 50 MB.
+
+/**
+ * Creates a cache key.
+ *
+ * @param {Object} request Request options.
+ * @return {string} Cache key.
+ */
+Cache.createKey = function(request) {
+  return JSON.stringify({url: request.url,
+                         scale: request.scale,
+                         width: request.width,
+                         height: request.height,
+                         maxWidth: request.maxWidth,
+                         maxHeight: request.maxHeight});
+};
+
+/**
+ * Initializes the cache database.
+ * @param {function()} callback Completion callback.
+ */
+Cache.prototype.initialize = function(callback) {
+  // Establish a connection to the database or (re)create it if not available
+  // or not up to date. After changing the database's schema, increment
+  // Cache.DB_VERSION to force database recreating.
+  var openRequest = window.webkitIndexedDB.open(Cache.DB_NAME,
+                                                Cache.DB_VERSION);
+
+  openRequest.onsuccess = function(e) {
+    this.db_ = e.target.result;
+    callback();
+  }.bind(this);
+
+  openRequest.onerror = callback;
+
+  openRequest.onupgradeneeded = function(e) {
+    console.info('Cache database creating or upgrading.');
+    var db = e.target.result;
+    if (db.objectStoreNames.contains('metadata'))
+      db.deleteObjectStore('metadata');
+    if (db.objectStoreNames.contains('data'))
+      db.deleteObjectStore('data');
+    if (db.objectStoreNames.contains('settings'))
+      db.deleteObjectStore('settings');
+    db.createObjectStore('metadata', {keyPath: 'key'});
+    db.createObjectStore('data', {keyPath: 'key'});
+    db.createObjectStore('settings', {keyPath: 'key'});
+  };
+};
+
+/**
+ * Sets size of the cache.
+ *
+ * @param {number} size Size in bytes.
+ * @param {IDBTransaction=} opt_transaction Transaction to be reused. If not
+ *     provided, then a new one is created.
+ * @private
+ */
+Cache.prototype.setCacheSize_ = function(size, opt_transaction) {
+  var transaction = opt_transaction ||
+      this.db_.transaction(['settings'], 'readwrite');
+  var settingsStore = transaction.objectStore('settings');
+
+  settingsStore.put({key: 'size', value: size});  // Update asynchronously.
+};
+
+/**
+ * Fetches current size of the cache.
+ *
+ * @param {function(number)} onSuccess Callback to return the size.
+ * @param {function()} onFailure Failure callback.
+ * @param {IDBTransaction=} opt_transaction Transaction to be reused. If not
+ *     provided, then a new one is created.
+ * @private
+ */
+Cache.prototype.fetchCacheSize_ = function(
+    onSuccess, onFailure, opt_transaction) {
+  var transaction = opt_transaction ||
+      this.db_.transaction(['settings', 'metadata', 'data'], 'readwrite');
+  var settingsStore = transaction.objectStore('settings');
+  var sizeRequest = settingsStore.get('size');
+
+  sizeRequest.onsuccess = function(e) {
+    if (e.target.result)
+      onSuccess(e.target.result.value);
+    else
+      onSuccess(0);
+  };
+
+  sizeRequest.onerror = function() {
+    console.error('Failed to fetch size from the database.');
+    onFailure();
+  };
+};
+
+/**
+ * Evicts the least used elements in cache to make space for a new image and
+ * updates size of the cache taking into account the upcoming item.
+ *
+ * @param {number} size Requested size.
+ * @param {function()} onSuccess Success callback.
+ * @param {function()} onFailure Failure callback.
+ * @param {IDBTransaction=} opt_transaction Transaction to be reused. If not
+ *     provided, then a new one is created.
+ * @private
+ */
+Cache.prototype.evictCache_ = function(
+    size, onSuccess, onFailure, opt_transaction) {
+  var transaction = opt_transaction ||
+      this.db_.transaction(['settings', 'metadata', 'data'], 'readwrite');
+
+  // Check if the requested size is smaller than the cache size.
+  if (size > Cache.MEMORY_LIMIT) {
+    onFailure();
+    return;
+  }
+
+  var onCacheSize = function(cacheSize) {
+    if (size < Cache.MEMORY_LIMIT - cacheSize) {
+      // Enough space, no need to evict.
+      this.setCacheSize_(cacheSize + size, transaction);
+      onSuccess();
+      return;
+    }
+
+    var bytesToEvict = Math.max(size, Cache.EVICTION_CHUNK_SIZE);
+
+    // Fetch all metadata.
+    var metadataEntries = [];
+    var metadataStore = transaction.objectStore('metadata');
+    var dataStore = transaction.objectStore('data');
+
+    var onEntriesFetched = function() {
+      metadataEntries.sort(function(a, b) {
+        return b.lastLoadTimestamp - a.lastLoadTimestamp;
+      });
+
+      var totalEvicted = 0;
+      while (bytesToEvict > 0) {
+        var entry = metadataEntries.pop();
+        totalEvicted += entry.size;
+        bytesToEvict -= entry.size;
+        metadataStore.delete(entry.key);  // Remove asynchronously.
+        dataStore.delete(entry.key);  // Remove asynchronously.
+      }
+
+      this.setCacheSize_(cacheSize - totalEvicted + size, transaction);
+    }.bind(this);
+
+    metadataStore.openCursor().onsuccess = function(e) {
+      var cursor = event.target.result;
+      if (cursor) {
+        metadataEntries.push(cursor.value);
+        cursor.continue();
+      } else {
+        onEntriesFetched();
+      }
+    };
+  }.bind(this);
+
+  this.fetchCacheSize_(onCacheSize, onFailure, transaction);
+};
+
+/**
+ * Saves an image in the cache.
+ *
+ * @param {string} key Cache key.
+ * @param {string} data Image data.
+ * @param {number} timestamp Last modification timestamp. Used to detect
+ *     if the cache entry becomes out of date.
+ */
+Cache.prototype.saveImage = function(key, data, timestamp) {
+  if (!this.db_) {
+    console.warn('Cache database not available.');
+    return;
+  }
+
+  var onNotFoundInCache = function() {
+    var metadataEntry = {key: key,
+                         timestamp: timestamp,
+                         size: data.length,
+                         lastLoadTimestamp: Date.now()};
+    var dataEntry = {key: key,
+                     data: data};
+
+    var transaction = this.db_.transaction(['settings', 'metadata', 'data'],
+                                          'readwrite');
+    var metadataStore = transaction.objectStore('metadata');
+    var dataStore = transaction.objectStore('data');
+
+    var onCacheEvicted = function() {
+      metadataStore.put(metadataEntry);  // Add asynchronously.
+      dataStore.put(dataEntry);  // Add asynchronously.
+    };
+
+    // Make sure there is enough space in the cache.
+    this.evictCache_(data.length, onCacheEvicted, function() {}, transaction);
+  }.bind(this);
+
+  // Check if the image is already in cache. If not, then save it to cache.
+  this.loadImage(key, timestamp, function() {}, onNotFoundInCache);
+};
+
+/**
+ * Loads an image from the cache (if available) or returns null.
+ *
+ * @param {string} key Cache key.
+ * @param {number} timestamp Last modification timestamp. If different
+ *     that the one in cache, then the entry will be invalidated.
+ * @param {function(<string>)} onSuccess Success callback with the image's data.
+ * @param {function()} onFailure Failure callback.
+ */
+Cache.prototype.loadImage = function(key, timestamp, onSuccess, onFailure) {
+  if (!this.db_) {
+    console.warn('Cache database not available.');
+    onFailure();
+    return;
+  }
+
+  var transaction = this.db_.transaction(['settings', 'metadata', 'data'],
+                                         'readwrite');
+  var metadataStore = transaction.objectStore('metadata');
+  var dataStore = transaction.objectStore('data');
+  var metadataRequest = metadataStore.get(key);
+  var dataRequest = dataStore.get(key);
+
+  var metadataEntry = null;
+  var metadataReceived = false;
+  var dataEntry = null;
+  var dataReceived = false;
+
+  var onPartialSuccess = function() {
+    // Check if all sub-requests have finished.
+    if (!metadataReceived || !dataReceived)
+      return;
+
+    // Check if both entries are available or both unavailable.
+    if (!!metadataEntry != !!dataEntry) {
+      console.warn('Incosistent cache database.');
+      onFailure();
+      return;
+    }
+
+    // Process the responses.
+    if (!metadataEntry) {
+      // The image not found.
+      onFailure();
+    } else if (metadataEntry.timestamp != timestamp) {
+      // The image is not up to date, so remove it.
+      this.removeImage(key, function() {}, function() {}, transaction);
+      onFailure();
+    } else {
+      // The image is available. Update the last load time and return the
+      // image data.
+      metadataEntry.lastLoadTimestamp = Date.now();
+      metadataStore.put(metadataEntry);  // Added asynchronously.
+      onSuccess(dataEntry.data);
+    }
+  }.bind(this);
+
+  metadataRequest.onsuccess = function(e) {
+    if (e.target.result)
+      metadataEntry = e.target.result;
+    metadataReceived = true;
+    onPartialSuccess();
+  };
+
+  dataRequest.onsuccess = function(e) {
+    if (e.target.result)
+      dataEntry = e.target.result;
+    dataReceived = true;
+    onPartialSuccess();
+  };
+
+  metadataRequest.onerror = function() {
+    console.error('Failed to fetch metadata from the database.');
+    metadataReceived = true;
+    onPartialSuccess();
+  };
+
+  dataRequest.onerror = function() {
+    console.error('Failed to fetch image data from the database.');
+    dataReceived = true;
+    onPartialSuccess();
+  };
+};
+
+/**
+ * Removes the image from the cache.
+ *
+ * @param {string} key Cache key.
+ * @param {function()=} opt_onSuccess Success callback.
+ * @param {function()=} opt_onFailure Failure callback.
+ * @param {IDBTransaction=} opt_transaction Transaction to be reused. If not
+ *     provided, then a new one is created.
+ */
+Cache.prototype.removeImage = function(
+    key, opt_onSuccess, opt_onFailure, opt_transaction) {
+  if (!this.db_) {
+    console.warn('Cache database not available.');
+    return;
+  }
+
+  var transaction = opt_transaction ||
+      this.db_.transaction(['settings', 'metadata', 'data'], 'readwrite');
+  var metadataStore = transaction.objectStore('metadata');
+  var dataStore = transaction.objectStore('data');
+
+  var cacheSize = null;
+  var cacheSizeReceived = false;
+  var metadataEntry = null;
+  var metadataReceived = false;
+
+  var onPartialSuccess = function() {
+    if (!cacheSizeReceived || !metadataReceived)
+      return;
+
+    // If either cache size or metadata entry is not available, then it is
+    // an error.
+    if (cacheSize === null || !metadataEntry) {
+      if (opt_onFailure)
+        onFailure();
+      return;
+    }
+
+    if (opt_onSuccess)
+      opt_onSuccess();
+
+    this.setCacheSize_(cacheSize - metadataEntry.size, transaction);
+    metadataStore.delete(key);  // Delete asynchronously.
+    dataStore.delete(key);  // Delete asynchronously.
+  }.bind(this);
+
+  var onCacheSizeFailure = function() {
+    cacheSizeReceived = true;
+  };
+
+  var onCacheSizeSuccess = function(result) {
+    cacheSize = result;
+    cacheSizeReceived = true;
+    onPartialSuccess();
+  };
+
+  // Fetch the current cache size.
+  this.fetchCacheSize_(onCacheSizeSuccess, onCacheSizeFailure, transaction);
+
+  // Receive image's metadata.
+  var metadataRequest = metadataStore.get(key);
+
+  metadataRequest.onsuccess = function(e) {
+    if (e.target.result)
+      metadataEntry = e.target.result;
+    metadataReceived = true;
+    onPartialSuccess();
+  };
+
+  metadataRequest.onerror = function() {
+    console.error('Failed to remove an image.');
+    metadataReceived = true;
+    onPartialSuccess();
+  };
+};
diff --git a/chrome/browser/resources/image_loader/client.js b/chrome/browser/resources/image_loader/client.js
deleted file mode 100644
index 8d80ec7..0000000
--- a/chrome/browser/resources/image_loader/client.js
+++ /dev/null
@@ -1,366 +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.
-
-var ImageLoader = ImageLoader || {};
-
-/**
- * Image loader's extension id.
- * @const
- * @type {string}
- */
-ImageLoader.EXTENSION_ID = 'pmfjbimdmchhbnneeidfognadeopoehp';
-
-/**
- * Client used to connect to the remote ImageLoader extension. Client class runs
- * in the extension, where the client.js is included (eg. Files.app).
- * It sends remote requests using IPC to the ImageLoader class and forwards
- * its responses.
- *
- * Implements cache, which is stored in the calling extension.
- *
- * @constructor
- */
-ImageLoader.Client = function() {
-  /**
-   * Hash array with active tasks.
-   * @type {Object}
-   * @private
-   */
-  this.tasks_ = {};
-
-  /**
-   * @type {number}
-   * @private
-   */
-  this.lastTaskId_ = 0;
-
-  /**
-   * LRU cache for images.
-   * @type {ImageLoader.Client.Cache}
-   * @private
-   */
-  this.cache_ = new ImageLoader.Client.Cache();
-};
-
-/**
- * Returns a singleton instance.
- * @return {ImageLoader.Client} ImageLoader.Client instance.
- */
-ImageLoader.Client.getInstance = function() {
-  if (!ImageLoader.Client.instance_)
-    ImageLoader.Client.instance_ = new ImageLoader.Client();
-  return ImageLoader.Client.instance_;
-};
-
-/**
- * Records binary metrics. Counts for true and false are stored as a histogram.
- * @param {string} name Histogram's name.
- * @param {boolean} value True or false.
- */
-ImageLoader.Client.recordBinary = function(name, value) {
-  chrome.metricsPrivate.recordValue(
-      { metricName: 'ImageLoader.Client.' + name,
-        type: 'histogram-linear',
-        min: 1,  // According to histogram.h, this should be 1 for enums.
-        max: 2,  // Maximum should be exclusive.
-        buckets: 3 },  // Number of buckets: 0, 1 and overflowing 2.
-      value ? 1 : 0);
-};
-
-/**
- * Records percent metrics, stored as a histogram.
- * @param {string} name Histogram's name.
- * @param {number} value Value (0..100).
- */
-ImageLoader.Client.recordPercentage = function(name, value) {
-  chrome.metricsPrivate.recordPercentage('ImageLoader.Client.' + name,
-                                         Math.round(value));
-};
-
-/**
- * Sends a message to the Image Loader extension.
- * @param {Object} request Hash array with request data.
- * @param {function(Object)=} opt_callback Response handling callback.
- *     The response is passed as a hash array.
- * @private
- */
-ImageLoader.Client.sendMessage_ = function(request, opt_callback) {
-  opt_callback = opt_callback || function(response) {};
-  var sendMessage = chrome.runtime ? chrome.runtime.sendMessage :
-                                     chrome.extension.sendMessage;
-  sendMessage(ImageLoader.EXTENSION_ID, request, opt_callback);
-};
-
-/**
- * Handles a message from the remote image loader and calls the registered
- * callback to pass the response back to the requester.
- *
- * @param {Object} message Response message as a hash array.
- * @private
- */
-ImageLoader.Client.prototype.handleMessage_ = function(message) {
-  if (!(message.taskId in this.tasks_)) {
-    // This task has been canceled, but was already fetched, so it's result
-    // should be discarded anyway.
-    return;
-  }
-
-  var task = this.tasks_[message.taskId];
-
-  // Check if the task is still valid.
-  if (task.isValid())
-    task.accept(message);
-
-  delete this.tasks_[message.taskId];
-};
-
-/**
- * Loads and resizes and image. Use opt_isValid to easily cancel requests
- * which are not valid anymore, which will reduce cpu consumption.
- *
- * @param {string} url Url of the requested image.
- * @param {function} callback Callback used to return response.
- * @param {Object=} opt_options Loader options, such as: scale, maxHeight,
- *     width, height and/or cache.
- * @param {function=} opt_isValid Function returning false in case
- *     a request is not valid anymore, eg. parent node has been detached.
- * @return {?number} Remote task id or null if loaded from cache.
- */
-ImageLoader.Client.prototype.load = function(
-    url, callback, opt_options, opt_isValid) {
-  opt_options = opt_options || {};
-  opt_isValid = opt_isValid || function() { return true; };
-
-  // Record cache usage.
-  ImageLoader.Client.recordPercentage('Cache.Usage', this.cache_.getUsage());
-
-  // Cancel old, invalid tasks.
-  var taskKeys = Object.keys(this.tasks_);
-  for (var index = 0; index < taskKeys.length; index++) {
-    var taskKey = taskKeys[index];
-    var task = this.tasks_[taskKey];
-    if (!task.isValid()) {
-      // Cancel this task since it is not valid anymore.
-      this.cancel(taskKey);
-      delete this.tasks_[taskKey];
-    }
-  }
-
-  // Replace the extension id.
-  var sourceId = chrome.i18n.getMessage('@@extension_id');
-  var targetId = ImageLoader.EXTENSION_ID;
-
-  url = url.replace('filesystem:chrome-extension://' + sourceId,
-                    'filesystem:chrome-extension://' + targetId);
-
-  // Try to load from cache, if available.
-  var cacheKey = ImageLoader.Client.Cache.createKey(url, opt_options);
-  if (opt_options.cache) {
-    // Load from cache.
-    ImageLoader.Client.recordBinary('Cached', 1);
-    var cachedData = this.cache_.loadImage(cacheKey, opt_options.timestamp);
-    if (cachedData) {
-      ImageLoader.Client.recordBinary('Cache.HitMiss', 1);
-      callback({status: 'success', data: cachedData});
-      return null;
-    } else {
-      ImageLoader.Client.recordBinary('Cache.HitMiss', 0);
-    }
-  } else {
-    // Remove from cache.
-    ImageLoader.Client.recordBinary('Cached', 0);
-    this.cache_.removeImage(cacheKey);
-  }
-
-  // Not available in cache, performing a request to a remote extension.
-  var request = opt_options;
-  this.lastTaskId_++;
-  var task = {isValid: opt_isValid};
-  this.tasks_[this.lastTaskId_] = task;
-
-  request.url = url;
-  request.taskId = this.lastTaskId_;
-  request.timestamp = opt_options.timestamp;
-
-  ImageLoader.Client.sendMessage_(
-      request,
-      function(result) {
-        // Save to cache.
-        if (result.status == 'success' && opt_options.cache)
-          this.cache_.saveImage(cacheKey, result.data, opt_options.timestamp);
-        callback(result);
-      }.bind(this));
-  return request.taskId;
-};
-
-/**
- * Cancels the request.
- * @param {number} taskId Task id returned by ImageLoader.Client.load().
- */
-ImageLoader.Client.prototype.cancel = function(taskId) {
-  ImageLoader.Client.sendMessage_({taskId: taskId, cancel: true});
-};
-
-/**
- * Least Recently Used (LRU) cache implementation to be used by
- * ImageLoader.Client class. It has memory constraints, so it will never
- * exceed specified memory limit defined in MEMORY_LIMIT.
- *
- * @constructor
- */
-ImageLoader.Client.Cache = function() {
-  this.images_ = [];
-  this.size_ = 0;
-};
-
-/**
- * Memory limit for images data in bytes.
- *
- * @const
- * @type {number}
- */
-ImageLoader.Client.Cache.MEMORY_LIMIT = 20 * 1024 * 1024;  // 20 MB.
-
-/**
- * Creates a cache key.
- *
- * @param {string} url Image url.
- * @param {Object=} opt_options Loader options as a hash array.
- * @return {string} Cache key.
- */
-ImageLoader.Client.Cache.createKey = function(url, opt_options) {
-  opt_options = opt_options || {};
-  return JSON.stringify({url: url,
-                         orientation: opt_options.orientation,
-                         scale: opt_options.scale,
-                         width: opt_options.width,
-                         height: opt_options.height,
-                         maxWidth: opt_options.maxWidth,
-                         maxHeight: opt_options.maxHeight});
-};
-
-/**
- * Evicts the least used elements in cache to make space for a new image.
- *
- * @param {number} size Requested size.
- * @private
- */
-ImageLoader.Client.Cache.prototype.evictCache_ = function(size) {
-  // Sort from the most recent to the oldest.
-  this.images_.sort(function(a, b) {
-    return b.lastLoadTimestamp - a.lastLoadTimestamp;
-  });
-
-  while (this.images_.length > 0 &&
-         (ImageLoader.Client.Cache.MEMORY_LIMIT - this.size_ < size)) {
-    var entry = this.images_.pop();
-    this.size_ -= entry.data.length;
-  }
-};
-
-/**
- * Saves an image in the cache.
- *
- * @param {string} key Cache key.
- * @param {string} data Image data.
- * @param {number=} opt_timestamp Last modification timestamp. Used to detect
- *     if the cache entry becomes out of date.
- */
-ImageLoader.Client.Cache.prototype.saveImage = function(
-    key, data, opt_timestamp) {
-  // If the image is currently in cache, then remove it.
-  if (this.images_[key])
-    this.removeImage(key);
-
-  if (ImageLoader.Client.Cache.MEMORY_LIMIT - this.size_ < data.length) {
-    ImageLoader.Client.recordBinary('Evicted', 1);
-    this.evictCache_(data.length);
-  } else {
-    ImageLoader.Client.recordBinary('Evicted', 0);
-  }
-
-  if (ImageLoader.Client.Cache.MEMORY_LIMIT - this.size_ >= data.length) {
-    this.images_[key] = {lastLoadTimestamp: Date.now(),
-                         timestamp: opt_timestamp ? opt_timestamp : null,
-                         data: data};
-    this.size_ += data.length;
-  }
-};
-
-/**
- * Loads an image from the cache (if available) or returns null.
- *
- * @param {string} key Cache key.
- * @param {number=} opt_timestamp Last modification timestamp. If different
- *     that the one in cache, then the entry will be invalidated.
- * @return {?string} Data of the loaded image or null.
- */
-ImageLoader.Client.Cache.prototype.loadImage = function(key, opt_timestamp) {
-  if (!(key in this.images_))
-    return null;
-
-  var entry = this.images_[key];
-  entry.lastLoadTimestamp = Date.now();
-
-  // Check if the image in cache is up to date. If not, then remove it and
-  // return null.
-  if (entry.timestamp != opt_timestamp) {
-    this.removeImage(key);
-    return null;
-  }
-
-  return entry.data;
-};
-
-/**
- * Returns cache usage.
- * @return {number} Value in percent points (0..100).
- */
-ImageLoader.Client.Cache.prototype.getUsage = function() {
-  return this.size_ / ImageLoader.Client.Cache.MEMORY_LIMIT * 100.0;
-};
-
-/**
- * Removes the image from the cache.
- * @param {string} key Cache key.
- */
-ImageLoader.Client.Cache.prototype.removeImage = function(key) {
-  if (!(key in this.images_))
-    return;
-
-  var entry = this.images_[key];
-  this.size_ -= entry.data.length;
-  delete this.images_[key];
-};
-
-// Helper functions.
-
-/**
- * Loads and resizes and image. Use opt_isValid to easily cancel requests
- * which are not valid anymore, which will reduce cpu consumption.
- *
- * @param {string} url Url of the requested image.
- * @param {Image} image Image node to load the requested picture into.
- * @param {Object} options Loader options, such as: orientation, scale,
- *     maxHeight, width, height and/or cache.
- * @param {function=} onSuccess Callback for success.
- * @param {function=} onError Callback for failure.
- * @param {function=} opt_isValid Function returning false in case
- *     a request is not valid anymore, eg. parent node has been detached.
- * @return {?number} Remote task id or null if loaded from cache.
- */
-ImageLoader.Client.loadToImage = function(url, image, options, onSuccess,
-    onError, opt_isValid) {
-  var callback = function(result) {
-    if (result.status == 'error') {
-      onError();
-      return;
-    }
-    image.src = result.data;
-    onSuccess();
-  };
-
-  return ImageLoader.Client.getInstance().load(
-      url, callback, options, opt_isValid);
-};
diff --git a/chrome/browser/resources/image_loader/image_loader.js b/chrome/browser/resources/image_loader/image_loader.js
index 0424642..3a88d8e 100644
--- a/chrome/browser/resources/image_loader/image_loader.js
+++ b/chrome/browser/resources/image_loader/image_loader.js
@@ -2,40 +2,32 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+'use strict';
+
 /**
  * Loads and resizes an image.
  * @constructor
  */
-var ImageLoader = function() {
-  /**
-   * Hash array of active requests.
-   * @type {Object}
-   * @private
-   */
-  this.requests_ = {};
-
+function ImageLoader() {
   /**
    * Persistent cache object.
-   * @type {ImageLoader.Cache}
+   * @type {Cache}
    * @private
    */
-  this.cache_ = new ImageLoader.Cache();
+  this.cache_ = new Cache();
 
   /**
    * Manages pending requests and runs them in order of priorities.
-   * @type {ImageLoader.Worker}
+   * @type {Worker}
    * @private
    */
-  this.worker_ = new ImageLoader.Worker();
+  this.worker_ = new Worker();
 
-  // Grant permissions to the local file system.
+  // Grant permissions to the local file system and initialize the cache.
   chrome.fileBrowserPrivate.requestFileSystem(function(filesystem) {
-    // TODO(mtomasz): Handle.
-  });
-
-  // Initialize the cache database, then start handling requests.
-  this.cache_.initialize(function() {
-    this.worker_.start();
+    this.cache_.initialize(function() {
+      this.worker_.start();
+    }.bind(this));
   }.bind(this));
 
   chrome.extension.onMessageExternal.addListener(function(request,
@@ -55,7 +47,7 @@
       return this.onMessage_(sender.id, request, failSafeSendResponse);
     }
   }.bind(this));
-};
+}
 
 /**
  * List of extensions allowed to perform image requests.
@@ -81,15 +73,11 @@
   var requestId = senderId + ':' + request.taskId;
   if (request.cancel) {
     // Cancel a task.
-    if (requestId in this.requests_) {
-      this.requests_[requestId].cancel();
-      delete this.requests_[requestId];
-    }
+    this.worker_.remove(requestId);
     return false;  // No callback calls.
   } else {
     // Create a request task and add it to the worker (queue).
-    var requestTask = new ImageLoader.Request(this.cache_, request, callback);
-    this.requests_[requestId] = requestTask;
+    var requestTask = new Request(requestId, this.cache_, request, callback);
     this.worker_.add(requestTask);
     return true;  // Request will call the callback.
   }
@@ -106,6 +94,29 @@
 };
 
 /**
+ * Checks if the options contain any image processing.
+ *
+ * @param {number} width Source width.
+ * @param {number} height Source height.
+ * @param {Object} options Resizing options as a hash array.
+ * @return {boolean} True if yes, false if not.
+ */
+ImageLoader.shouldProcess = function(width, height, options) {
+  var targetDimensions = ImageLoader.resizeDimensions(width, height, options);
+
+  // Dimensions has to be adjusted.
+  if (targetDimensions.width != width || targetDimensions.height != height)
+    return true;
+
+  // Orientation has to be adjusted.
+  if (options.orientation)
+    return true;
+
+  // No changes required.
+  return false;
+};
+
+/**
  * Calculates dimensions taking into account resize options, such as:
  * - scale: for scaling,
  * - maxWidth, maxHeight: for maximum dimensions,
@@ -179,6 +190,8 @@
   var orientation = options.orientation || 0;
 
   // For odd orientation values: 1 (90deg) and 3 (270deg) flip dimensions.
+  var drawImageWidth;
+  var drawImageHeight;
   if (orientation % 2) {
     drawImageWidth = target.height;
     drawImageHeight = target.width;
@@ -199,838 +212,3 @@
       drawImageWidth, drawImageHeight);
   targetContext.restore();
 };
-
-/**
- * Creates and starts downloading and then resizing of the image. Finally,
- * returns the image using the callback.
- *
- * @param {ImageLoader.Cache} cache Cache object.
- * @param {Object} request Request message as a hash array.
- * @param {function} callback Callback used to send the response.
- * @constructor
- */
-ImageLoader.Request = function(cache, request, callback) {
-  /**
-   * @type {ImageLoader.Cache}
-   * @private
-   */
-  this.cache_ = cache;
-
-  /**
-   * @type {Object}
-   * @private
-   */
-  this.request_ = request;
-
-  /**
-   * @type {function}
-   * @private
-   */
-  this.sendResponse_ = callback;
-
-  /**
-   * Temporary image used to download images.
-   * @type {Image}
-   * @private
-   */
-  this.image_ = new Image();
-
-  /**
-   * Used to download remote images using http:// or https:// protocols.
-   * @type {XMLHttpRequest}
-   * @private
-   */
-  this.xhr_ = new XMLHttpRequest();
-
-  /**
-   * Temporary canvas used to resize and compress the image.
-   * @type {HTMLCanvasElement}
-   * @private
-   */
-  this.canvas_ = document.createElement('canvas');
-
-  /**
-   * @type {CanvasRenderingContext2D}
-   * @private
-   */
-  this.context_ = this.canvas_.getContext('2d');
-
-  /**
-   * Callback to be called once downloading is finished.
-   * @type {function()}
-   * @private
-   */
-  this.downloadCallback_ = null;
-};
-
-/**
- * Returns priority of the request. The higher priority, the faster it will
- * be handled. The highest priority is 0. The default one is 2.
- *
- * @return {number} Priority.
- */
-ImageLoader.Request.prototype.getPriority = function() {
-  return (this.request_.priority !== undefined) ? this.request_.priority : 2;
-};
-
-/**
- * Tries to load the image from cache if exists and sends the response.
- *
- * @param {function()} onSuccess Success callback.
- * @param {function()} onFailure Failure callback.
- */
-ImageLoader.Request.prototype.loadFromCacheAndProcess = function(
-    onSuccess, onFailure) {
-  this.loadFromCache_(
-      function(data) {  // Found in cache.
-        this.sendImageData_(data);
-        onSuccess();
-      }.bind(this),
-      onFailure);  // Not found in cache.
-};
-
-/**
- * Tries to download the image, resizes and sends the response.
- * @param {function()} callback Completion callback.
- */
-ImageLoader.Request.prototype.downloadAndProcess = function(callback) {
-  if (this.downloadCallback_)
-    throw new Error('Downloading already started.');
-
-  this.downloadCallback_ = callback;
-  this.downloadOriginal_(this.onImageLoad_.bind(this),
-                         this.onImageError_.bind(this));
-};
-
-/**
- * Fetches the image from the persistent cache.
- *
- * @param {function()} onSuccess Success callback.
- * @param {function()} onFailure Failure callback.
- * @private
- */
-ImageLoader.Request.prototype.loadFromCache_ = function(onSuccess, onFailure) {
-  var cacheKey = ImageLoader.Cache.createKey(this.request_);
-
-  if (!this.request_.cache) {
-    // Cache is disabled for this request; therefore, remove it from cache
-    // if existed.
-    this.cache_.removeImage(cacheKey);
-    onFailure();
-    return;
-  }
-
-  if (!this.request_.timestamp) {
-    // Persistent cache is available only when a timestamp is provided.
-    onFailure();
-    return;
-  }
-
-  this.cache_.loadImage(cacheKey,
-                        this.request_.timestamp,
-                        onSuccess,
-                        onFailure);
-};
-
-/**
- * Saves the image to the persistent cache.
- *
- * @param {string} data The image's data.
- * @private
- */
-ImageLoader.Request.prototype.saveToCache_ = function(data) {
-  if (!this.request_.cache || !this.request_.timestamp) {
-    // Persistent cache is available only when a timestamp is provided.
-    return;
-  }
-
-  var cacheKey = ImageLoader.Cache.createKey(this.request_);
-  this.cache_.saveImage(cacheKey,
-                        data,
-                        this.request_.timestamp);
-};
-
-/**
- * Downloads an image directly or for remote resources using the XmlHttpRequest.
- *
- * @param {function()} onSuccess Success callback.
- * @param {function()} onFailure Failure callback.
- * @private
- */
-ImageLoader.Request.prototype.downloadOriginal_ = function(
-    onSuccess, onFailure) {
-  this.image_.onload = onSuccess;
-  this.image_.onerror = onFailure;
-
-  if (!this.request_.url.match(/^https?:/)) {
-    // Download directly.
-    this.image_.src = this.request_.url;
-    return;
-  }
-
-  // Download using an xhr request.
-  this.xhr_.responseType = 'blob';
-
-  this.xhr_.onerror = this.image_.onerror;
-  this.xhr_.onload = function() {
-    if (this.xhr_.status != 200) {
-      this.image_.onerror();
-      return;
-    }
-
-    // Process returnes data.
-    var reader = new FileReader();
-    reader.onerror = this.image_.onerror;
-    reader.onload = function(e) {
-      this.image_.src = e.target.result;
-    }.bind(this);
-
-    // Load the data to the image as a data url.
-    reader.readAsDataURL(this.xhr_.response);
-  }.bind(this);
-
-  // Perform a xhr request.
-  try {
-    this.xhr_.open('GET', this.request_.url, true);
-    this.xhr_.send();
-  } catch (e) {
-    this.image_.onerror();
-  }
-};
-
-/**
- * Sends the resized image via the callback.
- * @private
- */
-ImageLoader.Request.prototype.sendImage_ = function() {
-  // TODO(mtomasz): Keep format. Never compress using jpeg codec for lossless
-  // images such as png, gif.
-  var pngData = this.canvas_.toDataURL('image/png');
-  var jpegData = this.canvas_.toDataURL('image/jpeg', 0.9);
-  var imageData = pngData.length < jpegData.length * 2 ? pngData : jpegData;
-
-  // Send and store in the persistent cache.
-  this.sendImageData_(imageData);
-  this.saveToCache_(imageData);
-};
-
-/**
- * Sends the resized image via the callback.
- * @param {string} data Compressed image data.
- * @private
- */
-ImageLoader.Request.prototype.sendImageData_ = function(data) {
-  this.sendResponse_({status: 'success',
-                      data: data,
-                      taskId: this.request_.taskId});
-};
-
-/**
- * Handler, when contents are loaded into the image element. Performs resizing
- * and finalizes the request process.
- *
- * @param {function()} callback Completion callback.
- * @private
- */
-ImageLoader.Request.prototype.onImageLoad_ = function(callback) {
-  ImageLoader.resize(this.image_, this.canvas_, this.request_);
-  this.sendImage_();
-  this.cleanup_();
-  this.downloadCallback_();
-};
-
-/**
- * Handler, when loading of the image fails. Sends a failure response and
- * finalizes the request process.
- *
- * @param {function()} callback Completion callback.
- * @private
- */
-ImageLoader.Request.prototype.onImageError_ = function(callback) {
-  this.sendResponse_({status: 'error',
-                      taskId: this.request_.taskId});
-  this.cleanup_();
-  this.downloadCallback_();
-};
-
-/**
- * Cancels the request.
- */
-ImageLoader.Request.prototype.cancel = function() {
-  this.cleanup_();
-
-  // If downloading has started, then call the callback.
-  if (this.downloadCallback_)
-    this.downloadCallback_();
-};
-
-/**
- * Cleans up memory used by this request.
- * @private
- */
-ImageLoader.Request.prototype.cleanup_ = function() {
-  this.image_.onerror = function() {};
-  this.image_.onload = function() {};
-
-  // Transparent 1x1 pixel gif, to force garbage collecting.
-  this.image_.src = 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAA' +
-      'ABAAEAAAICTAEAOw==';
-
-  this.xhr_.onerror = function() {};
-  this.xhr_.onload = function() {};
-  this.xhr_.abort();
-
-  // Dispose memory allocated by Canvas.
-  this.canvas_.width = 0;
-  this.canvas_.height = 0;
-};
-
-/**
- * Worker for requests. Fetches requests from a queue and processes them
- * synchronously, taking into account priorities. The highest priority is 0.
- */
-ImageLoader.Worker = function() {
-  /**
-   * List of requests waiting to be checked. If these items are available in
-   * cache, then they are processed immediately after starting the worker.
-   * However, if they have to be downloaded, then these requests are moved
-   * to pendingRequests_.
-   *
-   * @type {ImageLoader.Request}
-   * @private
-   */
-  this.newRequests_ = [];
-
-  /**
-   * List of pending requests for images to be downloaded.
-   * @type {ImageLoader.Request}
-   * @private
-   */
-  this.pendingRequests_ = [];
-
-  /**
-   * List of requests being processed.
-   * @type {ImageLoader.Request}
-   * @private
-   */
-  this.activeRequests_ = [];
-
-  /**
-   * If the worker has been started.
-   * @type {boolean}
-   * @private
-   */
-  this.started_ = false;
-};
-
-/**
- * Maximum download requests to be run in parallel.
- * @type {number}
- * @const
- */
-ImageLoader.Worker.MAXIMUM_IN_PARALLEL = 5;
-
-/**
- * Adds a request to the internal priority queue and executes it when requests
- * with higher priorities are finished. If the result is cached, then it is
- * processed immediately once the worker is started.
- *
- * @param {ImageLoader.Request} request Request object.
- */
-ImageLoader.Worker.prototype.add = function(request) {
-  if (!this.started_) {
-    this.newRequests_.push(request);
-    return;
-  }
-
-  // Already started, so cache is available. Items available in cache will
-  // be served immediately, other enqueued.
-  this.serveCachedOrEnqueue_(request);
-};
-
-/**
- * Serves cached image or adds the request to the pending list.
- *
- * @param {ImageLoader.Request} request Request object.
- * @private
- */
-ImageLoader.Worker.prototype.serveCachedOrEnqueue_ = function(request) {
-  request.loadFromCacheAndProcess(function() {}, function() {
-    // Not available in cache.
-    this.pendingRequests_.push(request);
-
-    // Sort requests by priorities.
-    this.pendingRequests_.sort(function(a, b) {
-      return a.getPriority() - b.getPriority();
-    });
-
-    // Continue handling the most important requests (if started).
-    if (this.started_)
-      this.continue_();
-  }.bind(this));
-};
-
-/**
- * Starts handling requests.
- */
-ImageLoader.Worker.prototype.start = function() {
-  this.started_ = true;
-
-  // Process tasks added before worker has been started.
-  for (var index = 0; index < this.newRequests_.length; index++) {
-    this.serveCachedOrEnqueue_(this.newRequests_[index]);
-  }
-  this.newRequests_ = [];
-
-  // Start serving enqueued requests.
-  this.continue_();
-};
-
-/**
- * Processes pending requests from the queue. There is no guarantee that
- * all of the tasks will be processed at once.
- *
- * @private
- */
-ImageLoader.Worker.prototype.continue_ = function() {
-  for (var index = 0; index < this.pendingRequests_.length; index++) {
-    var request = this.pendingRequests_[index];
-
-    // Run only up to MAXIMUM_IN_PARALLEL in the same time.
-    if (Object.keys(this.activeRequests_).length ==
-        ImageLoader.Worker.MAXIMUM_IN_PARALLEL) {
-      return;
-    }
-
-    delete this.pendingRequests_.splice(index, 1);
-    this.activeRequests_.push(request);
-
-    request.downloadAndProcess(this.finish_.bind(this, request));
-  }
-};
-
-/**
- * Handles finished requests.
- *
- * @param {ImageLoader.Request} request Finished request.
- * @private
- */
-ImageLoader.Worker.prototype.finish_ = function(request) {
-  var index = this.activeRequests_.indexOf(request);
-  if (index < 0)
-    console.warn('Request not found.');
-  delete this.activeRequests_.splice(index, 1);
-
-  // Continue handling the most important requests (if started).
-  if (this.started_)
-    this.continue_();
-};
-
-/**
- * Persistent cache storing images in an indexed database on the hard disk.
- * @constructor
- */
-ImageLoader.Cache = function() {
-  /**
-   * IndexedDB database handle.
-   * @type {IDBDatabase}
-   * @private
-   */
-  this.db_ = null;
-};
-
-/**
- * Cache database name.
- * @type {string}
- * @const
- */
-ImageLoader.Cache.DB_NAME = 'image-loader';
-
-/**
- * Cache database version.
- * @type {number}
- * @const
- */
-ImageLoader.Cache.DB_VERSION = 11;
-
-/**
- * Memory limit for images data in bytes.
- *
- * @const
- * @type {number}
- */
-ImageLoader.Cache.MEMORY_LIMIT = 250 * 1024 * 1024;  // 250 MB.
-
-/**
- * Minimal amount of memory freed per eviction. Used to limit number of
- * evictions which are expensive.
- *
- * @const
- * @type {number}
- */
-ImageLoader.Cache.EVICTION_CHUNK_SIZE = 50 * 1024 * 1024;  // 50 MB.
-
-/**
- * Creates a cache key.
- *
- * @param {Object} request Request options.
- * @return {string} Cache key.
- */
-ImageLoader.Cache.createKey = function(request) {
-  return JSON.stringify({url: request.url,
-                         scale: request.scale,
-                         width: request.width,
-                         height: request.height,
-                         maxWidth: request.maxWidth,
-                         maxHeight: request.maxHeight});
-};
-
-/**
- * Initializes the cache database.
- * @param {function()} callback Completion callback.
- */
-ImageLoader.Cache.prototype.initialize = function(callback) {
-  // Establish a connection to the database or (re)create it if not available
-  // or not up to date. After changing the database's schema, increment
-  // ImageLoader.Cache.DB_VERSION to force database recreating.
-  var openRequest = window.webkitIndexedDB.open(ImageLoader.Cache.DB_NAME,
-                                                ImageLoader.Cache.DB_VERSION);
-
-  openRequest.onsuccess = function(e) {
-    this.db_ = e.target.result;
-    callback();
-  }.bind(this);
-
-  openRequest.onerror = callback;
-
-  openRequest.onupgradeneeded = function(e) {
-    console.info('Cache database creating or upgrading.');
-    var db = e.target.result;
-    if (db.objectStoreNames.contains('metadata'))
-      db.deleteObjectStore('metadata');
-    if (db.objectStoreNames.contains('data'))
-      db.deleteObjectStore('data');
-    if (db.objectStoreNames.contains('settings'))
-      db.deleteObjectStore('settings');
-    db.createObjectStore('metadata', {keyPath: 'key'});
-    db.createObjectStore('data', {keyPath: 'key'});
-    db.createObjectStore('settings', {keyPath: 'key'});
-  };
-};
-
-/**
- * Sets size of the cache.
- *
- * @param {number} size Size in bytes.
- * @param {IDBTransaction=} opt_transaction Transaction to be reused. If not
- *     provided, then a new one is created.
- * @private
- */
-ImageLoader.Cache.prototype.setCacheSize_ = function(size, opt_transaction) {
-  var transaction = opt_transaction ||
-      this.db_.transaction(['settings'], 'readwrite');
-  var settingsStore = transaction.objectStore('settings');
-
-  settingsStore.put({key: 'size', value: size});  // Update asynchronously.
-};
-
-/**
- * Fetches current size of the cache.
- *
- * @param {function(number)} onSuccess Callback to return the size.
- * @param {function()} onFailure Failure callback.
- * @param {IDBTransaction=} opt_transaction Transaction to be reused. If not
- *     provided, then a new one is created.
- * @private
- */
-ImageLoader.Cache.prototype.fetchCacheSize_ = function(
-    onSuccess, onFailure, opt_transaction) {
-  var transaction = opt_transaction ||
-      this.db_.transaction(['settings', 'metadata', 'data'], 'readwrite');
-  var settingsStore = transaction.objectStore('settings');
-  var sizeRequest = settingsStore.get('size');
-
-  sizeRequest.onsuccess = function(e) {
-    if (e.target.result)
-      onSuccess(e.target.result.value);
-    else
-      onSuccess(0);
-  };
-
-  sizeRequest.onerror = function() {
-    console.error('Failed to fetch size from the database.');
-    onFailure();
-  };
-};
-
-/**
- * Evicts the least used elements in cache to make space for a new image and
- * updates size of the cache taking into account the upcoming item.
- *
- * @param {number} size Requested size.
- * @param {function()} onSuccess Success callback.
- * @param {function()} onFailure Failure callback.
- * @param {IDBTransaction=} opt_transaction Transaction to be reused. If not
- *     provided, then a new one is created.
- * @private
- */
-ImageLoader.Cache.prototype.evictCache_ = function(
-    size, onSuccess, onFailure, opt_transaction) {
-  var transaction = opt_transaction ||
-      this.db_.transaction(['settings', 'metadata', 'data'], 'readwrite');
-
-  // Check if the requested size is smaller than the cache size.
-  if (size > ImageLoader.Cache.MEMORY_LIMIT) {
-    onFailure();
-    return;
-  }
-
-  var onCacheSize = function(cacheSize) {
-    if (size < ImageLoader.Cache.MEMORY_LIMIT - cacheSize) {
-      // Enough space, no need to evict.
-      this.setCacheSize_(cacheSize + size, transaction);
-      onSuccess();
-      return;
-    }
-
-    var bytesToEvict = Math.max(size,
-                                ImageLoader.Cache.EVICTION_CHUNK_SIZE);
-
-    // Fetch all metadata.
-    var metadataEntries = [];
-    var metadataStore = transaction.objectStore('metadata');
-    var dataStore = transaction.objectStore('data');
-
-    var onEntriesFetched = function() {
-      metadataEntries.sort(function(a, b) {
-        return b.lastLoadTimestamp - a.lastLoadTimestamp;
-      });
-
-      var totalEvicted = 0;
-      while (bytesToEvict > 0) {
-        var entry = metadataEntries.pop();
-        totalEvicted += entry.size;
-        bytesToEvict -= entry.size;
-        metadataStore.delete(entry.key);  // Remove asynchronously.
-        dataStore.delete(entry.key);  // Remove asynchronously.
-      }
-
-      this.setCacheSize_(cacheSize - totalEvicted + size, transaction);
-    }.bind(this);
-
-    metadataStore.openCursor().onsuccess = function(e) {
-      var cursor = event.target.result;
-      if (cursor) {
-        metadataEntries.push(cursor.value);
-        cursor.continue();
-      } else {
-        onEntriesFetched();
-      }
-    };
-  }.bind(this);
-
-  this.fetchCacheSize_(onCacheSize, onFailure, transaction);
-};
-
-/**
- * Saves an image in the cache.
- *
- * @param {string} key Cache key.
- * @param {string} data Image data.
- * @param {number} timestamp Last modification timestamp. Used to detect
- *     if the cache entry becomes out of date.
- */
-ImageLoader.Cache.prototype.saveImage = function(key, data, timestamp) {
-  if (!this.db_) {
-    console.warn('Cache database not available.');
-    return;
-  }
-
-  var onNotFoundInCache = function() {
-    var metadataEntry = {key: key,
-                         timestamp: timestamp,
-                         size: data.length,
-                         lastLoadTimestamp: Date.now()};
-    var dataEntry = {key: key,
-                     data: data};
-
-    var transaction = this.db_.transaction(['settings', 'metadata', 'data'],
-                                          'readwrite');
-    var metadataStore = transaction.objectStore('metadata');
-    var dataStore = transaction.objectStore('data');
-
-    var onCacheEvicted = function() {
-      metadataStore.put(metadataEntry);  // Add asynchronously.
-      dataStore.put(dataEntry);  // Add asynchronously.
-    };
-
-    // Make sure there is enough space in the cache.
-    this.evictCache_(data.length, onCacheEvicted, function() {}, transaction);
-  }.bind(this);
-
-  // Check if the image is already in cache. If not, then save it to cache.
-  this.loadImage(key, timestamp, function() {}, onNotFoundInCache);
-};
-
-/**
- * Loads an image from the cache (if available) or returns null.
- *
- * @param {string} key Cache key.
- * @param {number} timestamp Last modification timestamp. If different
- *     that the one in cache, then the entry will be invalidated.
- * @param {function(<string>)} onSuccess Success callback with the image's data.
- * @param {function()} onFailure Failure callback.
- */
-ImageLoader.Cache.prototype.loadImage = function(
-    key, timestamp, onSuccess, onFailure) {
-  if (!this.db_) {
-    console.warn('Cache database not available.');
-    onFailure();
-    return;
-  }
-
-  var transaction = this.db_.transaction(['settings', 'metadata', 'data'],
-                                         'readwrite');
-  var metadataStore = transaction.objectStore('metadata');
-  var dataStore = transaction.objectStore('data');
-  var metadataRequest = metadataStore.get(key);
-  var dataRequest = dataStore.get(key);
-
-  var metadataEntry = null;
-  var metadataReceived = false;
-  var dataEntry = null;
-  var dataReceived = false;
-
-  var onPartialSuccess = function() {
-    // Check if all sub-requests have finished.
-    if (!metadataReceived || !dataReceived)
-      return;
-
-    // Check if both entries are available or both unavailable.
-    if (!!metadataEntry != !!dataEntry) {
-      console.warn('Incosistent cache database.');
-      onFailure();
-      return;
-    }
-
-    // Process the responses.
-    if (!metadataEntry) {
-      // The image not found.
-      onFailure();
-    } else if (metadataEntry.timestamp != timestamp) {
-      // The image is not up to date, so remove it.
-      this.removeImage(key, function() {}, function() {}, transaction);
-      onFailure();
-    } else {
-      // The image is available. Update the last load time and return the
-      // image data.
-      metadataEntry.lastLoadTimestamp = Date.now();
-      metadataStore.put(metadataEntry);  // Added asynchronously.
-      onSuccess(dataEntry.data);
-    }
-  }.bind(this);
-
-  metadataRequest.onsuccess = function(e) {
-    if (e.target.result)
-      metadataEntry = e.target.result;
-    metadataReceived = true;
-    onPartialSuccess();
-  };
-
-  dataRequest.onsuccess = function(e) {
-    if (e.target.result)
-      dataEntry = e.target.result;
-    dataReceived = true;
-    onPartialSuccess();
-  };
-
-  metadataRequest.onerror = function() {
-    console.error('Failed to fetch metadata from the database.');
-    metadataReceived = true;
-    onPartialSuccess();
-  };
-
-  dataRequest.onerror = function() {
-    console.error('Failed to fetch image data from the database.');
-    dataReceived = true;
-    onPartialSuccess();
-  };
-};
-
-/**
- * Removes the image from the cache.
- * @param {string} key Cache key.
- * @param {function()=} opt_onSuccess Success callback.
- * @param {function()=} opt_onFailure Failure callback.
- * @param {IDBTransaction=} opt_transaction Transaction to be reused. If not
- *     provided, then a new one is created.
- */
-ImageLoader.Cache.prototype.removeImage = function(
-    key, opt_onSuccess, opt_onFailure, opt_transaction) {
-  if (!this.db_) {
-    console.warn('Cache database not available.');
-    return;
-  }
-
-  var transaction = opt_transaction ||
-      this.db_.transaction(['settings', 'metadata', 'data'], 'readwrite');
-  var metadataStore = transaction.objectStore('metadata');
-  var dataStore = transaction.objectStore('data');
-
-  var cacheSize = null;
-  var cacheSizeReceived = false;
-  var metadataEntry = null;
-  var metadataReceived = false;
-
-  var onPartialSuccess = function() {
-    if (!cacheSizeReceived || !metadataReceived)
-      return;
-
-    // If either cache size or metadata entry is not available, then it is
-    // an error.
-    if (cacheSize === null || !metadataEntry) {
-      if (opt_onFailure)
-        onFailure();
-      return;
-    }
-
-    if (opt_onSuccess)
-      opt_onSuccess();
-
-    this.setCacheSize_(cacheSize - metadataEntry.size, transaction);
-    metadataStore.delete(key);  // Delete asynchronously.
-    dataStore.delete(key);  // Delete asynchronously.
-  }.bind(this);
-
-  var onCacheSizeFailure = function() {
-    cacheSizeReceived = true;
-  };
-
-  var onCacheSizeSuccess = function(result) {
-    cacheSize = result;
-    cacheSizeReceived = true;
-    onPartialSuccess();
-  };
-
-  // Fetch the current cache size.
-  this.fetchCacheSize_(onCacheSizeSuccess, onCacheSizeFailure, transaction);
-
-  // Receive image's metadata.
-  var metadataRequest = metadataStore.get(key);
-
-  metadataRequest.onsuccess = function(e) {
-    if (e.target.result)
-      metadataEntry = e.target.result;
-    metadataReceived = true;
-    onPartialSuccess();
-  };
-
-  metadataRequest.onerror = function() {
-    console.error('Failed to remove an image.');
-    metadataReceived = true;
-    onPartialSuccess();
-  };
-};
-
-// Load the extension.
-ImageLoader.getInstance();
diff --git a/chrome/browser/resources/image_loader/image_loader_client.js b/chrome/browser/resources/image_loader/image_loader_client.js
new file mode 100644
index 0000000..9baba59
--- /dev/null
+++ b/chrome/browser/resources/image_loader/image_loader_client.js
@@ -0,0 +1,366 @@
+// 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 strict';
+
+/**
+ * Client used to connect to the remote ImageLoader extension. Client class runs
+ * in the extension, where the client.js is included (eg. Files.app).
+ * It sends remote requests using IPC to the ImageLoader class and forwards
+ * its responses.
+ *
+ * Implements cache, which is stored in the calling extension.
+ *
+ * @constructor
+ */
+function ImageLoaderClient() {
+  /**
+   * Hash array with active tasks.
+   * @type {Object}
+   * @private
+   */
+  this.tasks_ = {};
+
+  /**
+   * @type {number}
+   * @private
+   */
+  this.lastTaskId_ = 0;
+
+  /**
+   * LRU cache for images.
+   * @type {ImageLoaderClient.Cache}
+   * @private
+   */
+  this.cache_ = new ImageLoaderClient.Cache();
+}
+
+/**
+ * Image loader's extension id.
+ * @const
+ * @type {string}
+ */
+ImageLoaderClient.EXTENSION_ID = 'pmfjbimdmchhbnneeidfognadeopoehp';
+
+/**
+ * Returns a singleton instance.
+ * @return {Client} Client instance.
+ */
+ImageLoaderClient.getInstance = function() {
+  if (!ImageLoaderClient.instance_)
+    ImageLoaderClient.instance_ = new ImageLoaderClient();
+  return ImageLoaderClient.instance_;
+};
+
+/**
+ * Records binary metrics. Counts for true and false are stored as a histogram.
+ * @param {string} name Histogram's name.
+ * @param {boolean} value True or false.
+ */
+ImageLoaderClient.recordBinary = function(name, value) {
+  chrome.metricsPrivate.recordValue(
+      { metricName: 'ImageLoader.Client.' + name,
+        type: 'histogram-linear',
+        min: 1,  // According to histogram.h, this should be 1 for enums.
+        max: 2,  // Maximum should be exclusive.
+        buckets: 3 },  // Number of buckets: 0, 1 and overflowing 2.
+      value ? 1 : 0);
+};
+
+/**
+ * Records percent metrics, stored as a histogram.
+ * @param {string} name Histogram's name.
+ * @param {number} value Value (0..100).
+ */
+ImageLoaderClient.recordPercentage = function(name, value) {
+  chrome.metricsPrivate.recordPercentage('ImageLoader.Client.' + name,
+                                         Math.round(value));
+};
+
+/**
+ * Sends a message to the Image Loader extension.
+ * @param {Object} request Hash array with request data.
+ * @param {function(Object)=} opt_callback Response handling callback.
+ *     The response is passed as a hash array.
+ * @private
+ */
+ImageLoaderClient.sendMessage_ = function(request, opt_callback) {
+  opt_callback = opt_callback || function(response) {};
+  var sendMessage = chrome.runtime ? chrome.runtime.sendMessage :
+                                     chrome.extension.sendMessage;
+  sendMessage(ImageLoaderClient.EXTENSION_ID, request, opt_callback);
+};
+
+/**
+ * Handles a message from the remote image loader and calls the registered
+ * callback to pass the response back to the requester.
+ *
+ * @param {Object} message Response message as a hash array.
+ * @private
+ */
+ImageLoaderClient.prototype.handleMessage_ = function(message) {
+  if (!(message.taskId in this.tasks_)) {
+    // This task has been canceled, but was already fetched, so it's result
+    // should be discarded anyway.
+    return;
+  }
+
+  var task = this.tasks_[message.taskId];
+
+  // Check if the task is still valid.
+  if (task.isValid())
+    task.accept(message);
+
+  delete this.tasks_[message.taskId];
+};
+
+/**
+ * Loads and resizes and image. Use opt_isValid to easily cancel requests
+ * which are not valid anymore, which will reduce cpu consumption.
+ *
+ * @param {string} url Url of the requested image.
+ * @param {function} callback Callback used to return response.
+ * @param {Object=} opt_options Loader options, such as: scale, maxHeight,
+ *     width, height and/or cache.
+ * @param {function=} opt_isValid Function returning false in case
+ *     a request is not valid anymore, eg. parent node has been detached.
+ * @return {?number} Remote task id or null if loaded from cache.
+ */
+ImageLoaderClient.prototype.load = function(
+    url, callback, opt_options, opt_isValid) {
+  opt_options = opt_options || {};
+  opt_isValid = opt_isValid || function() { return true; };
+
+  // Record cache usage.
+  ImageLoaderClient.recordPercentage('Cache.Usage', this.cache_.getUsage());
+
+  // Cancel old, invalid tasks.
+  var taskKeys = Object.keys(this.tasks_);
+  for (var index = 0; index < taskKeys.length; index++) {
+    var taskKey = taskKeys[index];
+    var task = this.tasks_[taskKey];
+    if (!task.isValid()) {
+      // Cancel this task since it is not valid anymore.
+      this.cancel(taskKey);
+      delete this.tasks_[taskKey];
+    }
+  }
+
+  // Replace the extension id.
+  var sourceId = chrome.i18n.getMessage('@@extension_id');
+  var targetId = ImageLoaderClient.EXTENSION_ID;
+
+  url = url.replace('filesystem:chrome-extension://' + sourceId,
+                    'filesystem:chrome-extension://' + targetId);
+
+  // Try to load from cache, if available.
+  var cacheKey = ImageLoaderClient.Cache.createKey(url, opt_options);
+  if (opt_options.cache) {
+    // Load from cache.
+    ImageLoaderClient.recordBinary('Cached', 1);
+    var cachedData = this.cache_.loadImage(cacheKey, opt_options.timestamp);
+    if (cachedData) {
+      ImageLoaderClient.recordBinary('Cache.HitMiss', 1);
+      callback({status: 'success', data: cachedData});
+      return null;
+    } else {
+      ImageLoaderClient.recordBinary('Cache.HitMiss', 0);
+    }
+  } else {
+    // Remove from cache.
+    ImageLoaderClient.recordBinary('Cached', 0);
+    this.cache_.removeImage(cacheKey);
+  }
+
+  // Not available in cache, performing a request to a remote extension.
+  var request = opt_options;
+  this.lastTaskId_++;
+  var task = {isValid: opt_isValid};
+  this.tasks_[this.lastTaskId_] = task;
+
+  request.url = url;
+  request.taskId = this.lastTaskId_;
+  request.timestamp = opt_options.timestamp;
+
+  ImageLoaderClient.sendMessage_(
+      request,
+      function(result) {
+        // Save to cache.
+        if (result.status == 'success' && opt_options.cache)
+          this.cache_.saveImage(cacheKey, result.data, opt_options.timestamp);
+        callback(result);
+      }.bind(this));
+  return request.taskId;
+};
+
+/**
+ * Cancels the request.
+ * @param {number} taskId Task id returned by ImageLoaderClient.load().
+ */
+ImageLoaderClient.prototype.cancel = function(taskId) {
+  ImageLoaderClient.sendMessage_({taskId: taskId, cancel: true});
+};
+
+/**
+ * Least Recently Used (LRU) cache implementation to be used by
+ * Client class. It has memory constraints, so it will never
+ * exceed specified memory limit defined in MEMORY_LIMIT.
+ *
+ * @constructor
+ */
+ImageLoaderClient.Cache = function() {
+  this.images_ = [];
+  this.size_ = 0;
+};
+
+/**
+ * Memory limit for images data in bytes.
+ *
+ * @const
+ * @type {number}
+ */
+ImageLoaderClient.Cache.MEMORY_LIMIT = 20 * 1024 * 1024;  // 20 MB.
+
+/**
+ * Creates a cache key.
+ *
+ * @param {string} url Image url.
+ * @param {Object=} opt_options Loader options as a hash array.
+ * @return {string} Cache key.
+ */
+ImageLoaderClient.Cache.createKey = function(url, opt_options) {
+  opt_options = opt_options || {};
+  return JSON.stringify({url: url,
+                         orientation: opt_options.orientation,
+                         scale: opt_options.scale,
+                         width: opt_options.width,
+                         height: opt_options.height,
+                         maxWidth: opt_options.maxWidth,
+                         maxHeight: opt_options.maxHeight});
+};
+
+/**
+ * Evicts the least used elements in cache to make space for a new image.
+ *
+ * @param {number} size Requested size.
+ * @private
+ */
+ImageLoaderClient.Cache.prototype.evictCache_ = function(size) {
+  // Sort from the most recent to the oldest.
+  this.images_.sort(function(a, b) {
+    return b.lastLoadTimestamp - a.lastLoadTimestamp;
+  });
+
+  while (this.images_.length > 0 &&
+         (ImageLoaderClient.Cache.MEMORY_LIMIT - this.size_ < size)) {
+    var entry = this.images_.pop();
+    this.size_ -= entry.data.length;
+  }
+};
+
+/**
+ * Saves an image in the cache.
+ *
+ * @param {string} key Cache key.
+ * @param {string} data Image data.
+ * @param {number=} opt_timestamp Last modification timestamp. Used to detect
+ *     if the cache entry becomes out of date.
+ */
+ImageLoaderClient.Cache.prototype.saveImage = function(
+    key, data, opt_timestamp) {
+  // If the image is currently in cache, then remove it.
+  if (this.images_[key])
+    this.removeImage(key);
+
+  if (ImageLoaderClient.Cache.MEMORY_LIMIT - this.size_ < data.length) {
+    ImageLoaderClient.recordBinary('Evicted', 1);
+    this.evictCache_(data.length);
+  } else {
+    ImageLoaderClient.recordBinary('Evicted', 0);
+  }
+
+  if (ImageLoaderClient.Cache.MEMORY_LIMIT - this.size_ >= data.length) {
+    this.images_[key] = {lastLoadTimestamp: Date.now(),
+                         timestamp: opt_timestamp ? opt_timestamp : null,
+                         data: data};
+    this.size_ += data.length;
+  }
+};
+
+/**
+ * Loads an image from the cache (if available) or returns null.
+ *
+ * @param {string} key Cache key.
+ * @param {number=} opt_timestamp Last modification timestamp. If different
+ *     that the one in cache, then the entry will be invalidated.
+ * @return {?string} Data of the loaded image or null.
+ */
+ImageLoaderClient.Cache.prototype.loadImage = function(key, opt_timestamp) {
+  if (!(key in this.images_))
+    return null;
+
+  var entry = this.images_[key];
+  entry.lastLoadTimestamp = Date.now();
+
+  // Check if the image in cache is up to date. If not, then remove it and
+  // return null.
+  if (entry.timestamp != opt_timestamp) {
+    this.removeImage(key);
+    return null;
+  }
+
+  return entry.data;
+};
+
+/**
+ * Returns cache usage.
+ * @return {number} Value in percent points (0..100).
+ */
+ImageLoaderClient.Cache.prototype.getUsage = function() {
+  return this.size_ / ImageLoaderClient.Cache.MEMORY_LIMIT * 100.0;
+};
+
+/**
+ * Removes the image from the cache.
+ * @param {string} key Cache key.
+ */
+ImageLoaderClient.Cache.prototype.removeImage = function(key) {
+  if (!(key in this.images_))
+    return;
+
+  var entry = this.images_[key];
+  this.size_ -= entry.data.length;
+  delete this.images_[key];
+};
+
+// Helper functions.
+
+/**
+ * Loads and resizes and image. Use opt_isValid to easily cancel requests
+ * which are not valid anymore, which will reduce cpu consumption.
+ *
+ * @param {string} url Url of the requested image.
+ * @param {Image} image Image node to load the requested picture into.
+ * @param {Object} options Loader options, such as: orientation, scale,
+ *     maxHeight, width, height and/or cache.
+ * @param {function=} onSuccess Callback for success.
+ * @param {function=} onError Callback for failure.
+ * @param {function=} opt_isValid Function returning false in case
+ *     a request is not valid anymore, eg. parent node has been detached.
+ * @return {?number} Remote task id or null if loaded from cache.
+ */
+ImageLoaderClient.loadToImage = function(
+    url, image, options, onSuccess, onError, opt_isValid) {
+  var callback = function(result) {
+    if (result.status == 'error') {
+      onError();
+      return;
+    }
+    image.src = result.data;
+    onSuccess();
+  };
+
+  return ImageLoaderClient.getInstance().load(
+      url, callback, options, opt_isValid);
+};
diff --git a/chrome/browser/resources/image_loader/manifest.json b/chrome/browser/resources/image_loader/manifest.json
index 712851a..aed686d 100644
--- a/chrome/browser/resources/image_loader/manifest.json
+++ b/chrome/browser/resources/image_loader/manifest.json
@@ -12,10 +12,16 @@
     "https://*.googleusercontent.com",
     "https://drive.google.com"
   ],
-  "content_security_policy": "default-src 'none'; script-src 'self'; style-src 'self' 'unsafe-inline'; frame-src 'self' about:; img-src 'self' chrome://resources chrome://theme data: https://docs.google.com https://*.googleusercontent.com chrome://extension-icon; media-src 'self' https://*.googleusercontent.com; connect-src https://drive.google.com https://*.googleusercontent.com",
+  "content_security_policy": "default-src 'none'; script-src 'self'; style-src 'self' 'unsafe-inline'; frame-src 'self' about:; img-src 'self' chrome://resources chrome://theme data: https://docs.google.com https://*.googleusercontent.com chrome://extension-icon; media-src 'self' https://*.googleusercontent.com; connect-src 'self' https://drive.google.com https://*.googleusercontent.com",
   "background": {
-    "scripts": [ "image_loader.js" ],
+    "scripts": [
+      "image_loader.js",
+      "cache.js",
+      "worker.js",
+      "request.js",
+      "background.js"
+    ],
     "persistent": false
   },
-  "web_accessible_resources": ["client.js"]
+  "web_accessible_resources": ["image_loader_client.js"]
 }
diff --git a/chrome/browser/resources/image_loader/request.js b/chrome/browser/resources/image_loader/request.js
new file mode 100644
index 0000000..46eadc5
--- /dev/null
+++ b/chrome/browser/resources/image_loader/request.js
@@ -0,0 +1,337 @@
+// 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 strict';
+
+/**
+ * Creates and starts downloading and then resizing of the image. Finally,
+ * returns the image using the callback.
+ *
+ * @param {string} id Request ID.
+ * @param {Cache} cache Cache object.
+ * @param {Object} request Request message as a hash array.
+ * @param {function} callback Callback used to send the response.
+ * @constructor
+ */
+function Request(id, cache, request, callback) {
+  /**
+   * @type {string}
+   * @private
+   */
+  this.id_ = id;
+
+  /**
+   * @type {Cache}
+   * @private
+   */
+  this.cache_ = cache;
+
+  /**
+   * @type {Object}
+   * @private
+   */
+  this.request_ = request;
+
+  /**
+   * @type {function}
+   * @private
+   */
+  this.sendResponse_ = callback;
+
+  /**
+   * Temporary image used to download images.
+   * @type {Image}
+   * @private
+   */
+  this.image_ = new Image();
+
+  /**
+   * MIME type of the fetched image.
+   * @type {string}
+   * @private
+   */
+  this.contentType_ = null;
+
+  /**
+   * Used to download remote images using http:// or https:// protocols.
+   * @type {XMLHttpRequest}
+   * @private
+   */
+  this.xhr_ = new XMLHttpRequest();
+
+  /**
+   * Temporary canvas used to resize and compress the image.
+   * @type {HTMLCanvasElement}
+   * @private
+   */
+  this.canvas_ = document.createElement('canvas');
+
+  /**
+   * @type {CanvasRenderingContext2D}
+   * @private
+   */
+  this.context_ = this.canvas_.getContext('2d');
+
+  /**
+   * Callback to be called once downloading is finished.
+   * @type {function()}
+   * @private
+   */
+  this.downloadCallback_ = null;
+}
+
+/**
+ * Returns ID of the request.
+ * @return {string} Request ID.
+ */
+Request.prototype.getId = function() {
+  return this.id_;
+};
+
+/**
+ * Returns priority of the request. The higher priority, the faster it will
+ * be handled. The highest priority is 0. The default one is 2.
+ *
+ * @return {number} Priority.
+ */
+Request.prototype.getPriority = function() {
+  return (this.request_.priority !== undefined) ? this.request_.priority : 2;
+};
+
+/**
+ * Tries to load the image from cache if exists and sends the response.
+ *
+ * @param {function()} onSuccess Success callback.
+ * @param {function()} onFailure Failure callback.
+ */
+Request.prototype.loadFromCacheAndProcess = function(onSuccess, onFailure) {
+  this.loadFromCache_(
+      function(data) {  // Found in cache.
+        this.sendImageData_(data);
+        onSuccess();
+      }.bind(this),
+      onFailure);  // Not found in cache.
+};
+
+/**
+ * Tries to download the image, resizes and sends the response.
+ * @param {function()} callback Completion callback.
+ */
+Request.prototype.downloadAndProcess = function(callback) {
+  if (this.downloadCallback_)
+    throw new Error('Downloading already started.');
+
+  this.downloadCallback_ = callback;
+  this.downloadOriginal_(this.onImageLoad_.bind(this),
+                         this.onImageError_.bind(this));
+};
+
+/**
+ * Fetches the image from the persistent cache.
+ *
+ * @param {function()} onSuccess Success callback.
+ * @param {function()} onFailure Failure callback.
+ * @private
+ */
+Request.prototype.loadFromCache_ = function(onSuccess, onFailure) {
+  var cacheKey = Cache.createKey(this.request_);
+
+  if (!this.request_.cache) {
+    // Cache is disabled for this request; therefore, remove it from cache
+    // if existed.
+    this.cache_.removeImage(cacheKey);
+    onFailure();
+    return;
+  }
+
+  if (!this.request_.timestamp) {
+    // Persistent cache is available only when a timestamp is provided.
+    onFailure();
+    return;
+  }
+
+  this.cache_.loadImage(cacheKey,
+                        this.request_.timestamp,
+                        onSuccess,
+                        onFailure);
+};
+
+/**
+ * Saves the image to the persistent cache.
+ *
+ * @param {string} data The image's data.
+ * @private
+ */
+Request.prototype.saveToCache_ = function(data) {
+  if (!this.request_.cache || !this.request_.timestamp) {
+    // Persistent cache is available only when a timestamp is provided.
+    return;
+  }
+
+  var cacheKey = Cache.createKey(this.request_);
+  this.cache_.saveImage(cacheKey,
+                        data,
+                        this.request_.timestamp);
+};
+
+/**
+ * Downloads an image directly or for remote resources using the XmlHttpRequest.
+ *
+ * @param {function()} onSuccess Success callback.
+ * @param {function()} onFailure Failure callback.
+ * @private
+ */
+Request.prototype.downloadOriginal_ = function(onSuccess, onFailure) {
+  this.image_.onload = onSuccess;
+  this.image_.onerror = onFailure;
+
+  // Download data urls directly since they are not supported by XmlHttpRequest.
+  var dataUrlMatches = this.request_.url.match(/^data:([^,;]*)[,;]/);
+  if (dataUrlMatches) {
+    this.image_.src = this.request_.url;
+    this.contentType_ = dataUrlMatches[1];
+    return;
+  }
+
+  // Download using an xhr request.
+  this.xhr_.responseType = 'blob';
+
+  this.xhr_.onerror = this.image_.onerror;
+  this.xhr_.onload = function() {
+    if (this.xhr_.status != 200) {
+      this.image_.onerror();
+      return;
+    }
+
+    // Process returned data, including the mime type.
+    this.contentType_ = this.xhr_.getResponseHeader('Content-Type');
+    var reader = new FileReader();
+    reader.onerror = this.image_.onerror;
+    reader.onload = function(e) {
+      this.image_.src = e.target.result;
+    }.bind(this);
+
+    // Load the data to the image as a data url.
+    reader.readAsDataURL(this.xhr_.response);
+  }.bind(this);
+
+  // Perform a xhr request.
+  try {
+    this.xhr_.open('GET', this.request_.url, true);
+    this.xhr_.send();
+  } catch (e) {
+    this.image_.onerror();
+  }
+};
+
+/**
+ * Sends the resized image via the callback. If the image has been changed,
+ * then packs the canvas contents, otherwise sends the raw image data.
+ *
+ * @param {boolean} imageChanged Whether the image has been changed.
+ * @private
+ */
+Request.prototype.sendImage_ = function(imageChanged) {
+  var imageData;
+  if (!imageChanged) {
+    // The image hasn't been processed, so the raw data can be directly
+    // forwarded for speed (no need to encode the image again).
+    imageData = this.image_.src;
+  } else {
+    // The image has been resized or rotated, therefore the canvas has to be
+    // encoded to get the correct compressed image data.
+    switch (this.contentType_) {
+      case 'image/gif':
+      case 'image/png':
+      case 'image/svg':
+      case 'image/bmp':
+        imageData = this.canvas_.toDataURL('image/png');
+        break;
+      case 'image/jpeg':
+      default:
+        imageData = this.canvas_.toDataURL('image/jpeg', 0.9);
+    }
+  }
+
+  // Send and store in the persistent cache.
+  this.sendImageData_(imageData);
+  this.saveToCache_(imageData);
+};
+
+/**
+ * Sends the resized image via the callback.
+ * @param {string} data Compressed image data.
+ * @private
+ */
+Request.prototype.sendImageData_ = function(data) {
+  this.sendResponse_({status: 'success',
+                      data: data,
+                      taskId: this.request_.taskId});
+};
+
+/**
+ * Handler, when contents are loaded into the image element. Performs resizing
+ * and finalizes the request process.
+ *
+ * @param {function()} callback Completion callback.
+ * @private
+ */
+Request.prototype.onImageLoad_ = function(callback) {
+  if (ImageLoader.shouldProcess(this.image_.width,
+                                this.image_.height,
+                                this.request_)) {
+    ImageLoader.resize(this.image_, this.canvas_, this.request_);
+    this.sendImage_(true);  // Image changed.
+  } else {
+    this.sendImage_(false);  // Image not changed.
+  }
+  this.cleanup_();
+  this.downloadCallback_();
+};
+
+/**
+ * Handler, when loading of the image fails. Sends a failure response and
+ * finalizes the request process.
+ *
+ * @param {function()} callback Completion callback.
+ * @private
+ */
+Request.prototype.onImageError_ = function(callback) {
+  this.sendResponse_({status: 'error',
+                      taskId: this.request_.taskId});
+  this.cleanup_();
+  this.downloadCallback_();
+};
+
+/**
+ * Cancels the request.
+ */
+Request.prototype.cancel = function() {
+  this.cleanup_();
+
+  // If downloading has started, then call the callback.
+  if (this.downloadCallback_)
+    this.downloadCallback_();
+};
+
+/**
+ * Cleans up memory used by this request.
+ * @private
+ */
+Request.prototype.cleanup_ = function() {
+  this.image_.onerror = function() {};
+  this.image_.onload = function() {};
+
+  // Transparent 1x1 pixel gif, to force garbage collecting.
+  this.image_.src = 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAA' +
+      'ABAAEAAAICTAEAOw==';
+
+  this.xhr_.onerror = function() {};
+  this.xhr_.onload = function() {};
+  this.xhr_.abort();
+
+  // Dispose memory allocated by Canvas.
+  this.canvas_.width = 0;
+  this.canvas_.height = 0;
+};
diff --git a/chrome/browser/resources/image_loader/worker.js b/chrome/browser/resources/image_loader/worker.js
new file mode 100644
index 0000000..c0c29e2
--- /dev/null
+++ b/chrome/browser/resources/image_loader/worker.js
@@ -0,0 +1,175 @@
+// 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 strict';
+
+/**
+ * Worker for requests. Fetches requests from a queue and processes them
+ * synchronously, taking into account priorities. The highest priority is 0.
+ */
+function Worker() {
+  /**
+   * List of requests waiting to be checked. If these items are available in
+   * cache, then they are processed immediately after starting the worker.
+   * However, if they have to be downloaded, then these requests are moved
+   * to pendingRequests_.
+   *
+   * @type {Array.<Request>}
+   * @private
+   */
+  this.newRequests_ = [];
+
+  /**
+   * List of pending requests for images to be downloaded.
+   * @type {Array.<Request>}
+   * @private
+   */
+  this.pendingRequests_ = [];
+
+  /**
+   * List of requests being processed.
+   * @type {Array.<Request>}
+   * @private
+   */
+  this.activeRequests_ = [];
+
+  /**
+   * Hash array of requests being added to the queue, but not finalized yet.
+   * @type {Object}
+   * @private
+   */
+  this.requests_ = {};
+
+  /**
+   * If the worker has been started.
+   * @type {boolean}
+   * @private
+   */
+  this.started_ = false;
+}
+
+/**
+ * Maximum download requests to be run in parallel.
+ * @type {number}
+ * @const
+ */
+Worker.MAXIMUM_IN_PARALLEL = 5;
+
+/**
+ * Adds a request to the internal priority queue and executes it when requests
+ * with higher priorities are finished. If the result is cached, then it is
+ * processed immediately once the worker is started.
+ *
+ * @param {Request} request Request object.
+ */
+Worker.prototype.add = function(request) {
+  if (!this.started_) {
+    this.newRequests_.push(request);
+    this.requests_[request.getId()] = request;
+    return;
+  }
+
+  // Enqueue the request, since already started.
+  this.pendingRequests_.push(request);
+  this.sortPendingRequests_();
+
+  this.continue_();
+};
+
+/**
+ * Removes a request from the worker (if exists).
+ * @param {string} requestId Unique ID of the request.
+ */
+Worker.prototype.remove = function(requestId) {
+  var request = this.requests_[requestId];
+  if (!request)
+    return;
+
+  // Remove from the internal queues with pending tasks.
+  var newIndex = this.pendingRequests_.indexOf(request);
+  if (newIndex != -1)
+    this.newRequests_.splice(newIndex, 1);
+  var cacheCheckIndex = this.cacheCheckRequests_.indexOf(request);
+  if (cacheCheckIndex != -1)
+    this.cacheCheckRequests_.splice(cacheCheckIndex, 1);
+  var pendingIndex = this.pendingRequests_.indexOf(request);
+  if (pendingIndex != -1)
+    this.pendingRequests_.splice(pendingIndex, 1);
+
+  // Cancel the request.
+  request.cancel();
+  delete this.requests_[requestId];
+};
+
+/**
+ * Starts handling requests.
+ */
+Worker.prototype.start = function() {
+  this.started_ = true;
+
+  // Process tasks added before worker has been started.
+  this.pendingRequests_.concat(this.newRequests_);
+  this.sortPendingRequests_();
+  this.newRequests_ = [];
+
+  // Start serving enqueued requests.
+  this.continue_();
+};
+
+/**
+ * Sorts pending requests by priorities.
+ * @private
+ */
+Worker.prototype.sortPendingRequests_ = function() {
+  this.pendingRequests_.sort(function(a, b) {
+    return a.getPriority() - b.getPriority();
+  });
+};
+
+/**
+ * Processes pending requests from the queue. There is no guarantee that
+ * all of the tasks will be processed at once.
+ *
+ * @private
+ */
+Worker.prototype.continue_ = function() {
+  var index = 0;
+  while (index < this.pendingRequests_.length) {
+    var request = this.pendingRequests_[index];
+
+    // Run only up to MAXIMUM_IN_PARALLEL in the same time.
+    if (this.activeRequests_.length == Worker.MAXIMUM_IN_PARALLEL)
+      return;
+
+    this.pendingRequests_.splice(index, 1);
+    this.activeRequests_.push(request);
+
+    // Try to load from cache. If doesn't exist, then download.
+    var currentRequest = request;
+    currentRequest.loadFromCacheAndProcess(
+        this.finish_.bind(this, currentRequest),
+        function() {
+          currentRequest.downloadAndProcess(
+              this.finish_.bind(this, currentRequest));
+        }.bind(this));
+  }
+};
+
+/**
+ * Handles finished requests.
+ *
+ * @param {Request} request Finished request.
+ * @private
+ */
+Worker.prototype.finish_ = function(request) {
+  var index = this.activeRequests_.indexOf(request);
+  if (index < 0)
+    console.warn('Request not found.');
+  this.activeRequests_.splice(index, 1);
+  delete this.requests_[request.getId()];
+
+  // Continue handling the most important requests (if started).
+  if (this.started_)
+    this.continue_();
+};
diff --git a/chrome/browser/resources/local_ntp/images/2x/ntp_google_logo.png b/chrome/browser/resources/local_ntp/images/2x/ntp_google_logo.png
index 9578ee8..ff60013 100644
--- a/chrome/browser/resources/local_ntp/images/2x/ntp_google_logo.png
+++ b/chrome/browser/resources/local_ntp/images/2x/ntp_google_logo.png
Binary files differ
diff --git a/chrome/browser/resources/local_ntp/images/2x/ntp_white_google_logo.png b/chrome/browser/resources/local_ntp/images/2x/ntp_white_google_logo.png
index 9c600b6..2ed4bc9 100644
--- a/chrome/browser/resources/local_ntp/images/2x/ntp_white_google_logo.png
+++ b/chrome/browser/resources/local_ntp/images/2x/ntp_white_google_logo.png
Binary files differ
diff --git a/chrome/browser/resources/local_ntp/images/ntp_google_logo.png b/chrome/browser/resources/local_ntp/images/ntp_google_logo.png
deleted file mode 100644
index 378cffc..0000000
--- a/chrome/browser/resources/local_ntp/images/ntp_google_logo.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/local_ntp/images/ntp_white_google_logo.png b/chrome/browser/resources/local_ntp/images/ntp_white_google_logo.png
deleted file mode 100644
index b42a10f..0000000
--- a/chrome/browser/resources/local_ntp/images/ntp_white_google_logo.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/local_ntp/local_ntp.css b/chrome/browser/resources/local_ntp/local_ntp.css
index 8b80ec2..bd4f319 100644
--- a/chrome/browser/resources/local_ntp/local_ntp.css
+++ b/chrome/browser/resources/local_ntp/local_ntp.css
@@ -12,9 +12,7 @@
 }
 
 #ntp-contents {
-  position: absolute;
   text-align: -webkit-center;
-  width: 100%;
 }
 
 .non-google-page #ntp-contents {
@@ -36,9 +34,9 @@
 }
 
 #logo {
-  background: -webkit-image-set(
-      url(images/google_logo.png) 1x,
-      url(images/2x/google_logo.png) 2x) no-repeat;
+  background-image: url(images/2x/google_logo.png);
+  background-repeat: no-repeat;
+  background-size: 275px 95px;
   height: 95px;
   margin-bottom: 24px;
   margin-top: 157px;
@@ -46,9 +44,7 @@
 }
 
 body.custom-theme #logo {
-  background: -webkit-image-set(
-      url(images/white_google_logo.png) 1x,
-      url(images/2x/white_google_logo.png) 2x) no-repeat;
+  background-image: url(images/2x/white_google_logo.png);
 }
 
 #fakebox {
@@ -313,7 +309,8 @@
 }
 
 #mv-notice-links span:hover,
-#mv-notice-links span:focus {
+#mv-notice-links span:focus,
+#recent-tabs:hover {
   text-decoration: underline;
 }
 
@@ -338,13 +335,34 @@
   bottom: 0;
   color: #fff;
   cursor: default;
+  display: inline-block;
   font-size: 13px;
-  position: absolute;
-  right: 13px;
+  position: fixed;
+  right: 8px;
   text-align: left;
   z-index: -1;
 }
 
-#attribution img {
-  display: block;
+body.rtl #attribution {
+  text-align: right;
 }
+
+#recent-tabs {
+  background: #fff;
+  border: 1px solid #c0c0c0;
+  border-radius: 2px;
+  bottom: 0;
+  color: rgb(17, 85, 204);
+  cursor: pointer;
+  font-family: Arial;
+  font-size: 14px;
+  opacity: 0.9;
+  padding: 3px;
+  position: fixed;
+  right: 8px;
+}
+
+body.rtl #attribution,body.rtl #recent-tabs {
+  left: 8px;
+  right: auto;
+}
\ No newline at end of file
diff --git a/chrome/browser/resources/local_ntp/local_ntp.html b/chrome/browser/resources/local_ntp/local_ntp.html
index 3874aa0..b1c3360 100644
--- a/chrome/browser/resources/local_ntp/local_ntp.html
+++ b/chrome/browser/resources/local_ntp/local_ntp.html
@@ -24,7 +24,7 @@
         </span>
       </div>
     </div>
+    <div id="attribution"><div id="attribution-text"></div></div>
   </div>
-  <div id="attribution"></div>
 </body>
 </html>
diff --git a/chrome/browser/resources/local_ntp/local_ntp.js b/chrome/browser/resources/local_ntp/local_ntp.js
index f5c92d3..6cdd6c5 100644
--- a/chrome/browser/resources/local_ntp/local_ntp.js
+++ b/chrome/browser/resources/local_ntp/local_ntp.js
@@ -53,12 +53,14 @@
  */
 var IDS = {
   ATTRIBUTION: 'attribution',
+  ATTRIBUTION_TEXT: 'attribution-text',
   FAKEBOX: 'fakebox',
   LOGO: 'logo',
   NOTIFICATION: 'mv-notice',
   NOTIFICATION_CLOSE_BUTTON: 'mv-notice-x',
   NOTIFICATION_MESSAGE: 'mv-msg',
   NTP_CONTENTS: 'ntp-contents',
+  RECENT_TABS: 'recent-tabs',
   RESTORE_ALL_LINK: 'mv-restore',
   TILES: 'mv-tiles',
   UNDO_LINK: 'mv-undo'
@@ -89,6 +91,24 @@
 
 
 /**
+ * The JavaScript button event value for a middle click.
+ * @type {number}
+ * @const
+ */
+var MIDDLE_MOUSE_BUTTON = 1;
+
+
+/**
+ * Possible behaviors for navigateContentWindow.
+ * @enum {number}
+ */
+var WindowOpenDisposition = {
+  CURRENT_TAB: 1,
+  NEW_BACKGROUND_TAB: 2
+};
+
+
+/**
  * The container for the tile elements.
  * @type {Element}
  */
@@ -290,6 +310,14 @@
 
 
 /**
+ * Hide most visited tiles for at most this many milliseconds while painting.
+ * @type {number}
+ * @const
+ */
+var MOST_VISITED_PAINT_TIMEOUT_MSEC = 500;
+
+
+/**
  * A Tile is either a rendering of a Most Visited page or "filler" used to
  * pad out the section when not enough pages exist.
  *
@@ -373,8 +401,14 @@
     for (var i = 0; i < MAX_NUM_TILES_TO_SHOW; ++i) {
       tiles.push(createTile(pages[i], i));
     }
-    if (!userInitiatedMostVisitedChange)
+    if (!userInitiatedMostVisitedChange) {
       tilesContainer.hidden = true;
+      window.setTimeout(function() {
+        if (tilesContainer) {
+          tilesContainer.hidden = false;
+        }
+      }, MOST_VISITED_PAINT_TIMEOUT_MSEC);
+    }
     renderTiles();
   }
 }
@@ -409,10 +443,10 @@
       break;
     }
   }
-  if (!userInitiatedMostVisitedChange)
-    tilesContainer.hidden = !ready;
-  if (ready)
+  if (ready) {
+    tilesContainer.hidden = false;
     userInitiatedMostVisitedChange = false;
+  }
 }
 
 
@@ -849,13 +883,24 @@
 
 
 /**
+ * Extract the desired navigation behavior from a click button.
+ * @param {number} button The Event#button property of a click event.
+ * @return {WindowOpenDisposition} The desired behavior for
+ *     navigateContentWindow.
+ */
+function getDispositionFromClickButton(button) {
+  if (button == MIDDLE_MOUSE_BUTTON)
+    return WindowOpenDisposition.NEW_BACKGROUND_TAB;
+  return WindowOpenDisposition.CURRENT_TAB;
+}
+
+
+/**
  * Prepares the New Tab Page by adding listeners, rendering the current
  * theme, the most visited pages section, and Google-specific elements for a
  * Google-provided page.
  */
 function init() {
-  document.title = templateData.title;
-
   tilesContainer = $(IDS.TILES);
   notification = $(IDS.NOTIFICATION);
   attribution = $(IDS.ATTRIBUTION);
@@ -883,6 +928,19 @@
     document.body.classList.add(CLASSES.NON_GOOGLE_PAGE);
   }
 
+  var recentTabsText = templateData.recentTabs;
+  if (recentTabsText) {
+    var recentTabsLink = document.createElement('span');
+    recentTabsLink.id = IDS.RECENT_TABS;
+    recentTabsLink.addEventListener('click', function(event) {
+      ntpApiHandle.navigateContentWindow(
+          'chrome://history', getDispositionFromClickButton(event.button));
+    });
+    recentTabsLink.textContent = recentTabsText;
+    ntpContents.appendChild(recentTabsLink);
+    // Move the attribution up to prevent it from overlapping.
+    attribution.style.bottom = '28px';
+  }
 
   var notificationMessage = $(IDS.NOTIFICATION_MESSAGE);
   notificationMessage.textContent = templateData.thumbnailRemovedNotification;
@@ -894,7 +952,7 @@
   restoreAllLink.addEventListener('click', onRestoreAll);
   registerKeyHandler(restoreAllLink, KEYCODE.ENTER, onUndo);
   restoreAllLink.textContent = templateData.restoreThumbnailsShort;
-  attribution.textContent = templateData.attributionIntro;
+  $(IDS.ATTRIBUTION_TEXT).textContent = templateData.attributionIntro;
 
   var notificationCloseButton = $(IDS.NOTIFICATION_CLOSE_BUTTON);
   notificationCloseButton.addEventListener('click', hideNotification);
diff --git a/chrome/browser/resources/local_omnibox_popup/images/2x/history_icon.png b/chrome/browser/resources/local_omnibox_popup/images/2x/history_icon.png
index bf98e2c..ec5e4ba 100644
--- a/chrome/browser/resources/local_omnibox_popup/images/2x/history_icon.png
+++ b/chrome/browser/resources/local_omnibox_popup/images/2x/history_icon.png
Binary files differ
diff --git a/chrome/browser/resources/local_omnibox_popup/images/2x/page_icon.png b/chrome/browser/resources/local_omnibox_popup/images/2x/page_icon.png
index 0759be8..a7cf3cc 100644
--- a/chrome/browser/resources/local_omnibox_popup/images/2x/page_icon.png
+++ b/chrome/browser/resources/local_omnibox_popup/images/2x/page_icon.png
Binary files differ
diff --git a/chrome/browser/resources/local_omnibox_popup/images/2x/search_icon.png b/chrome/browser/resources/local_omnibox_popup/images/2x/search_icon.png
index c4848be..ac74fd7 100644
--- a/chrome/browser/resources/local_omnibox_popup/images/2x/search_icon.png
+++ b/chrome/browser/resources/local_omnibox_popup/images/2x/search_icon.png
Binary files differ
diff --git a/chrome/browser/resources/local_omnibox_popup/images/history_icon.png b/chrome/browser/resources/local_omnibox_popup/images/history_icon.png
index 1d97f39..6e7f731 100644
--- a/chrome/browser/resources/local_omnibox_popup/images/history_icon.png
+++ b/chrome/browser/resources/local_omnibox_popup/images/history_icon.png
Binary files differ
diff --git a/chrome/browser/resources/local_omnibox_popup/images/page_icon.png b/chrome/browser/resources/local_omnibox_popup/images/page_icon.png
index f5efac3..b782547 100644
--- a/chrome/browser/resources/local_omnibox_popup/images/page_icon.png
+++ b/chrome/browser/resources/local_omnibox_popup/images/page_icon.png
Binary files differ
diff --git a/chrome/browser/resources/local_omnibox_popup/images/search_icon.png b/chrome/browser/resources/local_omnibox_popup/images/search_icon.png
index 33e874e..ed89c7b 100644
--- a/chrome/browser/resources/local_omnibox_popup/images/search_icon.png
+++ b/chrome/browser/resources/local_omnibox_popup/images/search_icon.png
Binary files differ
diff --git a/chrome/browser/resources/managed_mode_block_interstitial.css b/chrome/browser/resources/managed_mode_block_interstitial.css
index 57ac15d..3aded39 100644
--- a/chrome/browser/resources/managed_mode_block_interstitial.css
+++ b/chrome/browser/resources/managed_mode_block_interstitial.css
@@ -26,7 +26,7 @@
 
 h1 {
   color: rgb(102, 102, 102);
-  font-size: 1.5em;
+  font-size: 1.3em;
   font-weight: normal;
   margin: 10px 0 30px 0;
 }
@@ -48,6 +48,7 @@
       url('../../app/theme/default_100_percent/common/error_managed_mode_blocked_page.png') 1x,
       url('../../app/theme/default_200_percent/common/error_managed_mode_blocked_page.png') 2x);
   margin-bottom: 10px;
+  margin-top: 10px;
 }
 
 #content-top {
diff --git a/chrome/browser/resources/media/webrtc_logs.css b/chrome/browser/resources/media/webrtc_logs.css
new file mode 100644
index 0000000..49e6aa9
--- /dev/null
+++ b/chrome/browser/resources/media/webrtc_logs.css
@@ -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. */
+
+body {
+  margin: 20px;
+}
+
+h1 {
+  font-size: 156%;
+  font-weight: bold;
+  margin: 0;
+  padding-bottom: 20px;
+  padding-top: 20px;
+}
+
+html[dir=rtl] h1 {
+  background-position: right;
+}
+
+#log-banner {
+  background-color: rgb(235, 239, 250);
+  border: 1px solid #bbb;
+  border-radius: 2px;
+  font-size: 100%;
+  padding: 4px;
+}
+
+#log-list h3 {
+  font-size: 100%;
+}
+
+#log-list > div > * {
+  margin: 0.75em 0;
+}
+
+#log-list a:visited {
+  color: #666;
+}
+
+#log-list > div:not(:last-child) {
+  border-bottom: 1px solid #bbb;
+}
+
+#disabled-mode h2 {
+  color: rgb(141, 51, 42);
+  font-size: 125%;
+}
diff --git a/chrome/browser/resources/media/webrtc_logs.html b/chrome/browser/resources/media/webrtc_logs.html
new file mode 100644
index 0000000..59517c2
--- /dev/null
+++ b/chrome/browser/resources/media/webrtc_logs.html
@@ -0,0 +1,26 @@
+<!DOCTYPE HTML>
+<html i18n-values="dir:textdirection;">
+<head>
+  <meta charset="utf-8">
+  <title i18n-content="webrtcLogsTitle"></title>
+  <link rel="stylesheet" href="webrtc_logs.css">
+  <script src="chrome://resources/js/load_time_data.js"></script>
+  <script src="chrome://resources/js/util.js"></script>
+  <script src="chrome://webrtc-logs/strings.js"></script>
+  <script src="chrome://webrtc-logs/webrtc_logs.js"></script>
+</head>
+<body i18n-values=".style.fontFamily:fontfamily;.style.fontSize:fontsize">
+  <header><h1 i18n-content="webrtcLogsTitle"></h1></header>
+  <div id="enabled-mode">
+    <h2 id="log-banner"></h2>
+    <div id="log-list"></div>
+    <p id="no-logs" i18n-content="noLogsMessage" hidden></p>
+  </div>
+  <div id="disabled-mode" hidden>
+    <h2 i18n-content="disabledHeader"></h2>
+    <p i18n-values=".innerHTML:disabledMessage"></p>
+  </div>
+  <script src="chrome://resources/js/i18n_template2.js"></script>
+  <script src="chrome://resources/js/jstemplate_compiled.js"></script>
+</body>
+</html>
diff --git a/chrome/browser/resources/media/webrtc_logs.js b/chrome/browser/resources/media/webrtc_logs.js
new file mode 100644
index 0000000..8537551
--- /dev/null
+++ b/chrome/browser/resources/media/webrtc_logs.js
@@ -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.
+
+/**
+ * Requests the list of uploads from the backend.
+ */
+function requestUploads() {
+  chrome.send('requestWebRtcLogsList');
+}
+
+/**
+ * Callback from backend with the list of uploads. Builds the UI.
+ * @param {boolean} enabled Whether or not uploading is enabled.
+ * @param {array} uploads The list of uploads.
+ * @param {string} version The browser version.
+ */
+function updateWebRtcLogsList(enabled, uploads, version) {
+  $('log-banner').textContent = loadTimeData.getStringF('webrtcLogCountFormat',
+                                                        uploads.length);
+
+  var logSection = $('log-list');
+
+  $('enabled-mode').hidden = !enabled;
+  $('disabled-mode').hidden = enabled;
+
+  if (!enabled)
+    return;
+
+  // Clear any previous list.
+  logSection.textContent = '';
+
+  for (var i = 0; i < uploads.length; i++) {
+    var upload = uploads[i];
+
+    var logBlock = document.createElement('div');
+    var title = document.createElement('h3');
+    title.textContent = loadTimeData.getStringF('webrtcLogHeaderFormat',
+                                                upload['id']);
+    logBlock.appendChild(title);
+    var date = document.createElement('p');
+    date.textContent = loadTimeData.getStringF('webrtcLogTimeFormat',
+                                               upload['time']);
+    logBlock.appendChild(date);
+    var linkBlock = document.createElement('p');
+    var link = document.createElement('a');
+    var commentLines = [
+      'Chrome Version: ' + version,
+      // TODO(tbreisacher): fill in the OS automatically?
+      'Operating System: e.g., "Windows 7", "Mac OSX 10.6"',
+      '',
+      'URL (if applicable) where the problem occurred:',
+      '',
+      'Can you reproduce this problem?',
+      '',
+      'What steps will reproduce this problem? (or if it\'s not ' +
+      'reproducible, what were you doing just before the problem)?',
+      '',
+      '1.', '2.', '3.',
+      '',
+      '*Please note that issues filed with no information filled in ' +
+      'above will be marked as WontFix*',
+      '',
+      '****DO NOT CHANGE BELOW THIS LINE****',
+      'report_id:' + upload.id
+    ];
+    var params = {
+      template: 'Defect report from user',
+      comment: commentLines.join('\n'),
+    };
+    var href = 'http://code.google.com/p/chromium/issues/entry';
+    for (var param in params) {
+      href = appendParam(href, param, params[param]);
+    }
+    link.href = href;
+    link.target = '_blank';
+    link.textContent = loadTimeData.getString('bugLinkText');
+    linkBlock.appendChild(link);
+    logBlock.appendChild(linkBlock);
+    logSection.appendChild(logBlock);
+  }
+
+  $('no-logs').hidden = uploads.length != 0;
+}
+
+document.addEventListener('DOMContentLoaded', requestUploads);
diff --git a/chrome/browser/resources/memory_internals/extension_view.css b/chrome/browser/resources/memory_internals/extension_view.css
index 5087d71..98463bc 100644
--- a/chrome/browser/resources/memory_internals/extension_view.css
+++ b/chrome/browser/resources/memory_internals/extension_view.css
@@ -3,19 +3,38 @@
  * found in the LICENSE file. */
 
 #extension-view {
+  border-spacing: 2px;
   width: 100%;
 }
 
-#extension-view tr:nth-child(odd) {
+#extension-view tr:nth-child(odd):not([class='header']) {
   background: rgb(239, 243, 255);
 }
 
 #extension-view td {
+  padding: 0.35em 0.5em 0;
   vertical-align: top;
 }
 
-#extension-view .extension-memory {
+#extension-view .header th {
+  border-bottom: 1px solid rgb(181, 198, 222);
+  padding: 0.35em 0.5em 0;
+  vertical-align: bottom;
+}
+
+#extension-view .extension-id {
   text-align: right;
+  width: 4em;
+}
+
+#extension-view .extension-info {
+  text-align: left;
+}
+
+#extension-view .extension-memory {
+  border-left: 1px solid rgb(181, 198, 222);
+  text-align: right;
+  width: 7em;
 }
 
 #extension-view #extension-template {
diff --git a/chrome/browser/resources/memory_internals/extension_view.html b/chrome/browser/resources/memory_internals/extension_view.html
index 76ddbeb..d142f99 100644
--- a/chrome/browser/resources/memory_internals/extension_view.html
+++ b/chrome/browser/resources/memory_internals/extension_view.html
@@ -3,10 +3,10 @@
      found in the LICENSE file. -->
 <h2>Extensions</h2>
 <table id="extension-view">
-  <tr>
-    <th>PID
-    <th>Name
-    <th>Private Memory [KB]
+  <tr class="header">
+    <th class="extension-id">PID
+    <th class="extension-info">Name
+    <th class="extension-memory">Private Memory [KB]
   <tr id="extension-template">
     <td class="extension-id">
     <td class="extension-info">
diff --git a/chrome/browser/resources/memory_internals/memory_internals.css b/chrome/browser/resources/memory_internals/memory_internals.css
index e13e3ab..fd6ef69 100644
--- a/chrome/browser/resources/memory_internals/memory_internals.css
+++ b/chrome/browser/resources/memory_internals/memory_internals.css
@@ -3,7 +3,7 @@
  * found in the LICENSE file. */
 
 body {
-  font-size: 84%;
+  font-size: 70%;
   margin: 0;
   min-width: 45em;
   padding: 0.75em;
diff --git a/chrome/browser/resources/memory_internals/memory_internals.js b/chrome/browser/resources/memory_internals/memory_internals.js
index 233feb8..c448a6b 100644
--- a/chrome/browser/resources/memory_internals/memory_internals.js
+++ b/chrome/browser/resources/memory_internals/memory_internals.js
@@ -64,9 +64,15 @@
           case 'process-info':
             value = process['type'] + '<br>' + process['titles'].join('<br>');
             break;
-          case 'process-memory':
+          case 'process-memory-private':
             value = process['memory_private'];
             break;
+          case 'process-memory-v8':
+            if (process['v8_alloc'] !== undefined) {
+              value = 'Used : ' + process['v8_used'] + '<br>' +
+                  'Allocated : ' + process['v8_alloc'];
+            }
+            break;
           }
           var col = row.insertCell(-1);
           col.innerHTML = value;
diff --git a/chrome/browser/resources/memory_internals/snapshot_view.css b/chrome/browser/resources/memory_internals/snapshot_view.css
index 4e8edac..4e57b21 100644
--- a/chrome/browser/resources/memory_internals/snapshot_view.css
+++ b/chrome/browser/resources/memory_internals/snapshot_view.css
@@ -3,19 +3,51 @@
  * found in the LICENSE file. */
 
 #snapshot-view {
+  border-spacing: 2px;
   width: 100%;
 }
 
-#snapshot-view tr:nth-child(odd) {
+#snapshot-view tr:nth-child(odd):not([class='header']) {
   background: rgb(239, 243, 255);
 }
 
 #snapshot-view td {
+  padding: 0.35em 0.5em 0;
   vertical-align: top;
 }
 
-#snapshot-view .process-memory {
+#snapshot-view .header th {
+  padding: 0.35em 0.5em 0;
+  vertical-align: bottom;
+}
+
+#snapshot-view .bottom th {
+  border-bottom: 1px solid rgb(181, 198, 222);
+}
+
+#snapshot-view .process-id {
   text-align: right;
+  width: 4em;
+}
+
+#snapshot-view .process-info {
+  text-align: left;
+}
+
+#snapshot-view .process-memory {
+  border-left: 1px solid rgb(181, 198, 222);
+  width: 16em;
+}
+
+#snapshot-view .process-memory-private {
+  border-left: 1px solid rgb(181, 198, 222);
+  text-align: right;
+  width: 6em;
+}
+
+#snapshot-view .process-memory-v8 {
+  text-align: right;
+  width: 10em;
 }
 
 #snapshot-view #process-template {
diff --git a/chrome/browser/resources/memory_internals/snapshot_view.html b/chrome/browser/resources/memory_internals/snapshot_view.html
index cc3b25b..43d041d 100644
--- a/chrome/browser/resources/memory_internals/snapshot_view.html
+++ b/chrome/browser/resources/memory_internals/snapshot_view.html
@@ -6,12 +6,16 @@
 <div id="uptime-view">Uptime: <span id="uptime-value">unknown</span></div>
 
 <table id="snapshot-view">
-  <tr>
-    <th>PID
-    <th>Name
-    <th>Private Memory [KB]
+  <tr class="header">
+    <th rowspan="2" class="process-id">PID
+    <th rowspan="2" class="process-info">Name
+    <th colspan="2" class="process-memory">Memory [KB]
+  <tr class="header bottom">
+    <th class="process-memory-private">Private
+    <th class="process-memory-v8">V8
   <tr id="process-template">
     <td class="process-id">
     <td class="process-info">
-    <td class="process-memory">
+    <td class="process-memory-private">
+    <td class="process-memory-v8">
 </table>
diff --git a/chrome/browser/resources/net_internals/browser_bridge.js b/chrome/browser/resources/net_internals/browser_bridge.js
index f982279..574d4fc 100644
--- a/chrome/browser/resources/net_internals/browser_bridge.js
+++ b/chrome/browser/resources/net_internals/browser_bridge.js
@@ -713,8 +713,10 @@
      *   observer.onSystemLogChanged(systemLogInfo)
      */
     addSystemLogObserver: function(observer, ignoreWhenUnchanged) {
-      this.pollableDataHelpers_.systemLog.addObserver(
-          observer, ignoreWhenUnchanged);
+      if (this.pollableDataHelpers_.systemLog) {
+        this.pollableDataHelpers_.systemLog.addObserver(
+            observer, ignoreWhenUnchanged);
+      }
     },
 
     /**
diff --git a/chrome/browser/resources/net_internals/cros_log_analyzer_view.css b/chrome/browser/resources/net_internals/cros_log_analyzer_view.css
new file mode 100644
index 0000000..098190c
--- /dev/null
+++ b/chrome/browser/resources/net_internals/cros_log_analyzer_view.css
@@ -0,0 +1,234 @@
+ /* 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.
+  */
+
+ #cros-log-analyzer-header {
+  margin-bottom: 20px;
+ }
+
+.cros-log-analyzer-container {
+  background-color: rgb(242, 242, 242);
+  border: 1px solid rgb(220, 220, 220);
+}
+
+#cros-log-analyzer-log-content {
+  border: 1px solid rgb(220, 220, 220);
+  font-size: 11px;
+  height: 300px;
+  line-height: 18px;
+  margin-bottom: -1px;
+  overflow: scroll;
+  padding: 10px;
+  width: 1000px;
+ }
+
+#cros-log-analyzer-filter-container {
+  font-size: 12px;
+  margin-bottom: 5px;
+  padding: 5px 10px;
+  width: 1000px;
+}
+
+#cros-log-analyzer-filter-container p {
+  margin: 10px 0;
+}
+
+#cros-log-analyzer-log-table {
+  table-layout: fixed;
+  width: 950px;
+}
+
+#cros-log-analyzer-log-table td {
+  overflow: hidden;
+  table-layout: fixed;
+  word-wrap: break-word;
+}
+
+.cros-log-analyzer-td-time {
+  width: 100px;
+}
+
+#cros-log-analyzer-log-header-table {
+  font-size: 12px;
+  font-weight: bold;
+  margin-bottom: -1px;
+  text-align: center;
+  width: 1000px;
+}
+
+.cros-log-analyzer-td-pname {
+  text-align: center;
+  width: 120px;
+}
+
+.cros-log-analyzer-td-level {
+  width: 70px;
+}
+
+.cros-log-analyzer-td-level p {
+  border: 1px solid;
+  border-radius: 5px;
+  margin: 0 3px;
+  text-align: center;
+  width: 58px;
+}
+
+.cros-log-analyzer-td-level-error {
+  background-color: rgb(255, 153, 163);
+  color: red;
+}
+
+.cros-log-analyzer-td-level-info {
+  background-color: rgb(195, 227, 250);
+  color: rgb(10, 147, 245);
+  width: 120px;
+}
+
+.cros-log-analyzer-td-level-warning {
+  background-color: rgb(250, 229, 195);
+  color: darkorange;
+}
+
+.cros-log-analyzer-td-level-unknown {
+  color: gray;
+}
+
+.cros-log-analyzer-td-pid {
+  width: 60px;
+}
+
+#cros-log-analyzer-filter-pname {
+  border-bottom: 1px solid rgb(209, 209, 209);
+  padding: 5px 0 10px 0;
+}
+
+#cros-log-analyzer-filter-level {
+  padding: 5px 0 10px 0;
+}
+
+#cros-log-analyzer-search-container {
+  -webkit-margin-start: 760px;
+  border-radius: 5px;
+  font-size: 12px;
+  margin-bottom: 5px;
+  margin-left: 720px;
+  margin-top: -40px;
+  padding: 5px;
+  width: 280px;
+}
+
+#cros-log-analyzer-search-container input {
+  border: 1px solid rgb(220, 220, 220);
+}
+
+#cros-log-analyzer-visualizer-container {
+  border: 1px solid rgb(211, 211, 211);
+  height: 100px;
+  position: relative;
+  width: 1002px;
+}
+
+#cros-log-analyzer-visualizer-timeline {
+  background: gray;
+  opacity: 0.5;
+  position: absolute;
+  top: 0;
+  width: 2px;
+}
+
+.cros-log-analyzer-visualizer-time-display {
+  font-size: 10px;
+  position: absolute;
+  width: 50px;
+}
+
+#cros-log-analyzer-visualizer-reset-btn {
+  border: 1px solid rgb(211, 211, 211);
+  border-radius: 2px;
+  position: absolute;
+  right: 5px;
+  top: 5px;
+}
+
+#cros-log-analyzer-visualizer-tracking-layer {
+  background: none;
+  height: 100%;
+  left: 0;
+  position: absolute;
+  top: 0;
+  width: 100%;
+}
+
+.cros-log-analyzer-visualizer-canvas {
+  left: 0;
+  position: absolute;
+  top: 0;
+}
+
+.cros-log-analyzer-flash {
+  -webkit-animation: fade 1s linear 1;
+}
+
+#cros-log-analyzer-marker-container {
+  background-color: rgb(242, 242, 242);
+  border: 1px solid rgb(211, 211, 211);
+  left: 1030px;
+  min-height: 320px;
+  padding: 10px;
+  position: absolute;
+  top: 63px;
+  width: 200px;
+}
+
+.cros-log-analyzer-marker-history-entry {
+  display: -webkit-flex;
+  height: 20px;
+}
+
+
+.cros-log-analyzer-marker-history-entry * {
+  display: block;
+}
+
+.cros-log-analyzer-marker-history-entry p {
+  font-size: 13px;
+  height: 15px;
+  margin: 0;
+  width: 98px;
+}
+
+.cros-log-analyzer-marker-history-entry a {
+  color: grey;
+  font-size: 11px;
+}
+
+.cros-log-analyzer-marker-history-color-tag {
+  border-radius: 10px;
+  height: 10px;
+  margin: 4px;
+  width: 10px;
+}
+
+.cros-log-analyzer-marker-highlight {
+  font-weight: bold;
+}
+
+#cros-log-analyzer-save-btn {
+  background-color: rgb(211, 211, 211);
+}
+
+@-webkit-keyframes fade {
+  0%
+  {
+    opacity: 1;
+  }
+  50%
+  {
+    opacity: 0;
+  }
+  100%
+  {
+    opacity: 1;
+  }
+}
diff --git a/chrome/browser/resources/net_internals/cros_log_analyzer_view.html b/chrome/browser/resources/net_internals/cros_log_analyzer_view.html
new file mode 100644
index 0000000..a23543c
--- /dev/null
+++ b/chrome/browser/resources/net_internals/cros_log_analyzer_view.html
@@ -0,0 +1,55 @@
+<!-- Log Analyzer -->
+<div id="cros-log-analyzer-tab-content" class="content-box">
+  <div id="cros-log-analyzer-header">
+    Network Log
+  </div>
+  <div id='cros-log-analyzer-search-container'
+      class='cros-log-analyzer-container'>
+    Search:
+    <input type='text' id='cros-log-analyzer-search-input'>
+    <span id='cros-log-analyzer-save-btn'>Save</span>
+  </div>
+  <table id="cros-log-analyzer-log-header-table"
+      class="cros-log-analyzer-container">
+    <tr>
+      <td class="cros-log-analyzer-td-level">Level</td>
+      <td class="cros-log-analyzer-td-time">Time</td>
+      <td class="cros-log-analyzer-td-pname">Process</td>
+      <td class="cros-log-analyzer-td-pid">PID</td>
+      <td class="cros-log-analyzer-td-description">Description</td>
+    </tr>
+  </table>
+  <div id="cros-log-analyzer-log-content">
+    <table id="cros-log-analyzer-log-table">
+    </table>
+  </div>
+  <div id='cros-log-analyzer-marker-container'>
+  </div>
+  <div id='cros-log-analyzer-filter-container'
+      class='cros-log-analyzer-container'>
+    <div id='cros-log-analyzer-filter-pname'>
+    </div>
+    <div id='cros-log-analyzer-filter-level'>
+      Level:
+      <span class="cros-log-analyzer-filter-level-block">
+        <input type='checkbox' id='checkbox-error' checked=true>
+        <label for="checkbox-error">Error</label>
+      </span>
+      <span class="cros-log-analyzer-filter-level-block">
+        <input type='checkbox' id='checkbox-warning' checked=true>
+        <label for="checkbox-warning">Warning</label>
+      </span>
+      <span class="cros-log-analyzer-filter-level-block">
+        <input type='checkbox' id='checkbox-info' checked=true>
+        <label for="checkbox-info">Info</label>
+      </span>
+      <span class="cros-log-analyzer-filter-level-block">
+        <input type='checkbox' id='checkbox-unknown'checked=true>
+        <label for="checkbox-unknown">Unknown</label>
+      </span>
+    </div>
+  </div>
+  <div id="cros-log-analyzer-visualizer-container">
+    <div id="cros-log-analyzer-visualizer-tracking-layer"></div>
+  </div>
+</div>
diff --git a/chrome/browser/resources/net_internals/cros_log_analyzer_view.js b/chrome/browser/resources/net_internals/cros_log_analyzer_view.js
new file mode 100644
index 0000000..fa6927a
--- /dev/null
+++ b/chrome/browser/resources/net_internals/cros_log_analyzer_view.js
@@ -0,0 +1,371 @@
+// 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 view displays the log messages from various resources in an
+ * interactive log analyzer
+ *
+ *   - Filter checkboxes
+ *   - Filter text inputs
+ *   - Display the log by different sections: time|level|process|description
+ *
+ */
+var CrosLogAnalyzerView = (function() {
+  'use strict';
+
+  // Inherits from DivView.
+  var superClass = DivView;
+
+  // Special classes (defined in log_analyzer_view.css)
+  var LOG_CONTAINER_CLASSNAME = 'cros-log-analyzer-container';
+  var LOG_FILTER_PNAME_BLOCK_CLASSNAME = 'cros-log-analyzer-filter-pname-block';
+  var LOG_CELL_HEADER_CLASSNAME = 'cros-log-analyzer-td-head';
+  var LOG_CELL_TIME_CLASSNAME = 'cros-log-analyzer-td-time';
+  var LOG_CELL_PNAME_CLASSNAME = 'cros-log-analyzer-td-pname';
+  var LOG_CELL_PID_CLASSNAME = 'cros-log-analyzer-td-pid';
+  var LOG_CELL_DESCRIPTION_CLASSNAME = 'cros-log-analyzer-td-description';
+  var LOG_CELL_LEVEL_CLASSNAME = 'cros-log-analyzer-td-level';
+  var LOG_CELL_LEVEL_CLASSNAME_LIST = {
+    'Error': 'cros-log-analyzer-td-level-error',
+    'Warning': 'cros-log-analyzer-td-level-warning',
+    'Info': 'cros-log-analyzer-td-level-info',
+    'Unknown': 'cros-log-analyzer-td-level-unknown'
+  };
+
+  /**
+   * @constructor
+   */
+  function CrosLogAnalyzerView() {
+    assertFirstConstructorCall(CrosLogAnalyzerView);
+
+    // Call superclass's constructor.
+    superClass.call(this, CrosLogAnalyzerView.MAIN_BOX_ID);
+
+    // Stores log entry objects
+    this.logEntries = [];
+    // Stores current search query
+    this.currentQuery = '';
+    // Stores raw text data of log
+    this.logData = '';
+    // Stores all the unique process names
+    this.pNames = [];
+    // References to special HTML elements in log_analyzer_view.html
+    this.pNameCheckboxes = {};
+    this.levelCheckboxes = {};
+    this.tableEntries = [];
+
+    this.initialize();
+  }
+
+  CrosLogAnalyzerView.TAB_ID = 'tab-handle-cros-log-analyzer';
+  CrosLogAnalyzerView.TAB_NAME = 'Log Analyzer';
+  CrosLogAnalyzerView.TAB_HASH = '#analyzer';
+
+  // IDs for special HTML elements in log_analyzer_view.html
+  CrosLogAnalyzerView.MAIN_BOX_ID = 'cros-log-analyzer-tab-content';
+  CrosLogAnalyzerView.LOG_TABLE_ID = 'cros-log-analyzer-log-table';
+  CrosLogAnalyzerView.LOG_FILTER_PNAME_ID = 'cros-log-analyzer-filter-pname';
+  CrosLogAnalyzerView.LOG_SEARCH_INPUT_ID = 'cros-log-analyzer-search-input';
+  CrosLogAnalyzerView.LOG_SEARCH_SAVE_BTN_ID = 'cros-log-analyzer-save-btn';
+  CrosLogAnalyzerView.LOG_VISUALIZER_CONTAINER_ID =
+      'cros-log-analyzer-visualizer-container';
+
+  cr.addSingletonGetter(CrosLogAnalyzerView);
+
+  /**
+   * Contains types of logs we are interested in
+   */
+  var LOGS_LIST = {
+    'NETWORK_LOG': 1,
+    'SYSTEM_LOG': 2
+  };
+
+  /**
+   * Contains headers of the log table
+   */
+  var TABLE_HEADERS_LIST = ['Level', 'Time', 'Process', 'PID', 'Description'];
+
+  CrosLogAnalyzerView.prototype = {
+    // Inherit the superclass's methods.
+    __proto__: superClass.prototype,
+
+    /**
+     * Called during the initialization of the View. Adds the system log
+     * listener into Browser_Bridge so that the system log can be retrieved.
+     */
+    initialize: function() {
+      g_browser.addSystemLogObserver(this);
+      $(CrosLogAnalyzerView.LOG_SEARCH_INPUT_ID).addEventListener('keyup',
+          this.onSearchQueryChange_.bind(this));
+      $(CrosLogAnalyzerView.LOG_SEARCH_SAVE_BTN_ID).addEventListener(
+          'click', this.onSaveBtnClicked_.bind(this));
+    },
+
+    /**
+     * Called when the save button is clicked. Saves the current filter query
+     * to the mark history. And highlights the matched text with colors.
+     */
+    onSaveBtnClicked_: function() {
+      this.marker.addMarkHistory(this.currentQuery);
+      // Clears the filter query
+      $(CrosLogAnalyzerView.LOG_SEARCH_INPUT_ID).value = '';
+      this.currentQuery = '';
+      // Refresh the table
+      this.populateTable();
+      this.filterLog();
+    },
+
+    onSearchQueryChange_: function() {
+      var inputField = $(CrosLogAnalyzerView.LOG_SEARCH_INPUT_ID);
+      this.currentQuery = inputField.value;
+      this.filterLog();
+    },
+
+    /**
+     * Creates the log table where each row represents a entry of log.
+     * This function is called if and only if the log is received from system
+     * level.
+     */
+    populateTable: function() {
+      var logTable = $(CrosLogAnalyzerView.LOG_TABLE_ID);
+      logTable.innerHTML = '';
+      this.tableEntries.length = 0;
+      // Create entries
+      for (var i = 0; i < this.logEntries.length; i++) {
+        this.logEntries[i].rowNum = i;
+        var row = this.createTableRow(this.logEntries[i]);
+        logTable.appendChild(row);
+      }
+    },
+
+    /**
+     * Creates the single row of the table where each row is a representation
+     * of the logEntry object.
+     */
+    createTableRow: function(entry) {
+      var row = document.createElement('tr');
+      for (var i = 0; i < 5; i++) {
+        // Creates rows
+        addNode(row, 'td');
+      }
+      var cells = row.childNodes;
+      // Level cell
+      cells[0].className = LOG_CELL_LEVEL_CLASSNAME;
+      var levelTag = addNodeWithText(cells[0], 'p', entry.level);
+      levelTag.className = LOG_CELL_LEVEL_CLASSNAME_LIST[entry.level];
+
+      // Time cell
+      cells[1].className = LOG_CELL_TIME_CLASSNAME;
+      cells[1].textContent = entry.getTime();
+
+      // Process name cell
+      cells[2].className = LOG_CELL_PNAME_CLASSNAME;
+      this.marker.getHighlightedEntry(entry, 'processName', cells[2]);
+
+      // Process ID cell
+      cells[3].className = LOG_CELL_PID_CLASSNAME;
+      this.marker.getHighlightedEntry(entry, 'processID', cells[3]);
+
+      // Description cell
+      cells[4].className = LOG_CELL_DESCRIPTION_CLASSNAME;
+      this.marker.getHighlightedEntry(entry, 'description', cells[4]);
+
+      // Add the row into this.tableEntries for future reference
+      this.tableEntries.push(row);
+      return row;
+    },
+
+    /**
+     * Regenerates the table and filter.
+     */
+    refresh: function() {
+      this.createFilter();
+      this.createLogMaker();
+      this.populateTable();
+      this.createVisualizer();
+    },
+
+    /**
+     * Uses the search query to match the pattern in different fields of entry.
+     */
+    patternMatch: function(entry, pattern) {
+      return entry.processID.match(pattern) ||
+             entry.processName.match(pattern) ||
+             entry.level.match(pattern) ||
+             entry.description.match(pattern);
+    },
+
+    /**
+     * Filters the log to show/hide the rows in the table.
+     * Each logEntry instance has a visibility property. This function
+     * shows or hides the row only based on this property.
+     */
+    filterLog: function() {
+      // Supports regular expression
+      var pattern = new RegExp(this.currentQuery, 'i');
+      for (var i = 0; i < this.logEntries.length; i++) {
+        var entry = this.logEntries[i];
+        // Filters the result by pname and level
+        var pNameCheckbox = this.pNameCheckboxes[entry.processName];
+        var levelCheckbox = this.levelCheckboxes[entry.level];
+        entry.visibility = pNameCheckbox.checked && levelCheckbox.checked &&
+            !this.visualizer.isOutOfBound(entry);
+        if (this.currentQuery) {
+          // If the search query is not empty, filter the result by query
+          entry.visibility = entry.visibility &&
+              this.patternMatch(entry, pattern);
+        }
+        // Changes style of HTML row based on the visibility of logEntry
+        if (entry.visibility) {
+          this.tableEntries[i].style.display = 'table-row';
+        } else {
+          this.tableEntries[i].style.display = 'none';
+        }
+      }
+      this.filterVisualizer();
+    },
+
+    /**
+     * Initializes filter tags and checkboxes. There are two types of filters:
+     * Level and Process. Level filters are static that we have only 4 levels
+     * in total but process filters are dynamically changing based on the log.
+     * The filter layout looks like:
+     *  |-----------------------------------------------------------------|
+     *  |                                                                 |
+     *  |                     Section of process filter                   |
+     *  |                                                                 |
+     *  |-----------------------------------------------------------------|
+     *  |                                                                 |
+     *  |                      Section of level filter                    |
+     *  |                                                                 |
+     *  |-----------------------------------------------------------------|
+     */
+    createFilter: function() {
+      this.createFilterByPName();
+      this.levelCheckboxes = {
+        'Error': $('checkbox-error'),
+        'Warning': $('checkbox-warning'),
+        'Info': $('checkbox-info'),
+        'Unknown': $('checkbox-unknown')
+      };
+
+      for (var level in this.levelCheckboxes) {
+        this.levelCheckboxes[level].addEventListener(
+            'change', this.onFilterChange_.bind(this));
+      }
+    },
+
+    /**
+     * Helper function of createFilter(). Create filter section of
+     * process filters.
+     */
+    createFilterByPName: function() {
+      var filterContainerDiv = $(CrosLogAnalyzerView.LOG_FILTER_PNAME_ID);
+      filterContainerDiv.innerHTML = 'Process: ';
+      for (var i = 0; i < this.pNames.length; i++) {
+        var pNameBlock = this.createPNameBlock(this.pNames[i]);
+        filterContainerDiv.appendChild(pNameBlock);
+      }
+    },
+
+    /**
+     * Helper function of createFilterByPName(). Create a single filter block in
+     * the section of process filters.
+     */
+    createPNameBlock: function(pName) {
+      var block = document.createElement('span');
+      block.className = LOG_FILTER_PNAME_BLOCK_CLASSNAME;
+
+      var tag = document.createElement('label');
+      var span = document.createElement('span');
+      span.textContent = pName;
+
+      var checkbox = document.createElement('input');
+      checkbox.type = 'checkbox';
+      checkbox.name = pName;
+      checkbox.value = pName;
+      checkbox.checked = true;
+      checkbox.addEventListener('change', this.onFilterChange_.bind(this));
+      this.pNameCheckboxes[pName] = checkbox;
+
+      tag.appendChild(checkbox);
+      tag.appendChild(span);
+      block.appendChild(tag);
+
+      return block;
+    },
+
+    /**
+     * Click handler for filter checkboxes. Everytime a checkbox is clicked,
+     * the visibility of related logEntries are changed.
+     */
+    onFilterChange_: function() {
+      this.filterLog();
+    },
+
+    /**
+     * Creates a visualizer that visualizes the logs as a timeline graph
+     * during the initialization of the View.
+     */
+    createVisualizer: function() {
+      this.visualizer = new CrosLogVisualizer(this,
+          CrosLogAnalyzerView.LOG_VISUALIZER_CONTAINER_ID);
+      this.visualizer.updateEvents(this.logEntries);
+    },
+
+    /**
+     * Sync the visibility of log entries with the visualizer.
+     */
+    filterVisualizer: function() {
+      this.visualizer.updateEvents(this.logEntries);
+    },
+
+    /**
+     * Called during the initialization. It creates the log marker that
+     * highlights log text.
+     */
+    createLogMaker: function() {
+      this.marker = new CrosLogMarker(this);
+    },
+
+    /**
+     * Given a row text line of log, a logEntry instance is initialized and used
+     * for parsing. After the text is parsed, we put the instance into
+     * logEntries which is an array for storing. This function is called when
+     * the data is received from Browser Bridge.
+     */
+    addLogEntry: function(logType, textEntry) {
+      var newEntry = new CrosLogEntry();
+      if (logType == LOGS_LIST.NETWORK_LOG) {
+        newEntry.tokenizeNetworkLog(textEntry);
+      } else {
+        //TODO(shinfan): Add more if cases here
+      }
+      this.logEntries.push(newEntry);
+
+      // Record pname
+      var pName = newEntry.processName;
+      if (this.pNames.indexOf(pName) == -1) {
+        this.pNames.push(pName);
+      }
+    },
+
+    /*
+     * Asynchronous call back function from Browser Bridge.
+     */
+    onSystemLogChanged: function(callback) {
+      if (callback.log == this.logData) return;
+      this.logData = callback.log;
+      // Clear the old array by setting length to zero
+      this.logEntries.length = 0;
+      var entries = callback.log.split('\n');
+      for (var i = 1; i < entries.length; i++) {
+        this.addLogEntry(LOGS_LIST.NETWORK_LOG, entries[i]);
+      }
+      this.refresh();
+    }
+  };
+
+  return CrosLogAnalyzerView;
+})();
diff --git a/chrome/browser/resources/net_internals/cros_log_entry.js b/chrome/browser/resources/net_internals/cros_log_entry.js
new file mode 100644
index 0000000..70822a0
--- /dev/null
+++ b/chrome/browser/resources/net_internals/cros_log_entry.js
@@ -0,0 +1,102 @@
+// 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 class stores information of one single entry of log
+ */
+
+var CrosLogEntry = function() {
+
+  /**
+    * @constructor
+    */
+  function CrosLogEntry() {
+    // The entry is visible by default
+    this.visibility = true;
+  }
+
+  CrosLogEntry.prototype = {
+    //------------------------------------------------------------------------
+    // Log input text parser
+    // Parses network log into tokens like time, name, pid
+    // and description.
+    //--------------------------------------------------------------------------
+    tokenizeNetworkLog: function(NetworkLogEntry) {
+      var tokens = NetworkLogEntry.split(' ');
+      var timeTokens = tokens[0].split(/[\s|\:|\-|T|\.]/);
+
+      // List of all parameters for Date Object
+      var year = timeTokens[0];
+      var month = timeTokens[1];
+      var day = timeTokens[2];
+      var hour = timeTokens[3];
+      var minute = timeTokens[4];
+      var second = timeTokens[5];
+      var millisecond = (parseInt(timeTokens[6]) / 1000).toFixed(0);
+      this.time = new Date(year, month, day, hour, minute,
+                           second, millisecond);
+
+      // Parses for process name and ID.
+      var process = tokens[2];
+      if (hasProcessID(process)) {
+        var processTokens = process.split(/[\[|\]]/);
+        this.processName = processTokens[0];
+        this.processID = processTokens[1];
+      } else {
+        this.processName = process.split(/\:/)[0];
+        this.processID = 'Unknown';
+      }
+
+      // Gets level of the log: error|warning|info|unknown if failed.
+      this.level = hasLevelInfo(tokens[3]);
+
+      // Treats the rest of the entry as description.
+      var descriptionStartPoint = NetworkLogEntry.indexOf(tokens[2]) +
+          tokens[2].length;
+      this.description = NetworkLogEntry.substr(descriptionStartPoint);
+    },
+
+    // Represents the Date object as a string.
+    getTime: function() {
+      return this.time.getMonth() + '/' + this.time.getDate() +
+          ' ' + this.time.getHours() + ':' + this.time.getMinutes() +
+          ':' + this.time.getSeconds() + ':' + this.time.getMilliseconds();
+    }
+  };
+
+  /**
+   * Helper function
+   * Takes a token as input and searches for '['.
+   * We assume if the token contains '[' it contains a process ID.
+   *
+   * @param {string} token A token from log
+   * @return {boolean} true if '[' is found
+   */
+  var hasProcessID = function(token) {
+    return token != undefined && token.indexOf('[') != -1;
+  }
+
+  /**
+   * Helper function
+   * Checks if the input token contains level information.
+   *
+   * @param {string} token A token from log
+   * @return {string} Level found in the token
+   */
+  var hasLevelInfo = function(token) {
+    if (token == undefined)
+      return 'Unknown';
+    if (token.toLowerCase().indexOf('err') != -1) {
+      return 'Error';
+    } else if (token.toLowerCase().indexOf('warn') != -1) {
+      return 'Warning';
+    } else if (token.toLowerCase().indexOf('info') != -1) {
+      return 'Info';
+    } else {
+      return 'Unknown';
+    }
+  }
+
+  return CrosLogEntry;
+}();
diff --git a/chrome/browser/resources/net_internals/cros_log_marker.js b/chrome/browser/resources/net_internals/cros_log_marker.js
new file mode 100644
index 0000000..71201e3
--- /dev/null
+++ b/chrome/browser/resources/net_internals/cros_log_marker.js
@@ -0,0 +1,394 @@
+// 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 class stores the filter queries as history and highlight the log text
+ * to increase the readability of the log
+ *
+ *   - Enable / Disable highlights
+ *   - Highlights text with multiple colors
+ *   - Resolve hghlight conficts (A text highlighted by multiple colors) so that
+ *     the latest added highlight always has highest priority to display.
+ *
+ */
+var CrosLogMarker = (function() {
+  'use strict';
+
+  // Special classes (defined in log_analyzer_view.css)
+  var LOG_MARKER_HIGHLIGHT_CLASS = 'cros-log-analyzer-marker-highlight';
+  var LOG_MARKER_CONTAINER_ID = 'cros-log-analyzer-marker-container';
+  var LOG_MARKER_HISTORY_ENTRY_CLASS = 'cros-log-analyzer-marker-history-entry';
+  var LOG_MARKER_HISTORY_COLOR_TAG_CLASS =
+          'cros-log-analyzer-marker-history-color-tag';
+
+  /**
+   * Colors used for highlighting. (Current we support 6 colors)
+   * TODO(shinfan): Add more supoorted colors.
+   */
+  var COLOR_USAGE_SET = {
+    'Crimson': false,
+    'DeepSkyBlue': false,
+    'DarkSeaGreen': false,
+    'GoldenRod': false,
+    'IndianRed': false,
+    'Orange': false
+  };
+  var COLOR_NUMBER = Object.keys(COLOR_USAGE_SET).length;
+
+
+  /**
+   * CrosHighlightTag represents a single highlight tag in text.
+   */
+  var CrosHighlightTag = (function() {
+    /**
+     * @constructor
+     */
+    function CrosHighlightTag(color, field, range, priority) {
+      this.color = color;
+      this.field = field;
+      this.range = range;
+      this.priority = priority;
+      this.enabled = true;
+    }
+
+    return CrosHighlightTag;
+  })();
+
+  /**
+   * @constructor
+   * @param {CrosLogAnalyzerView} logAnalyzerView A reference to
+   *     CrosLogAnalyzerView.
+   */
+  function CrosLogMarker(logAnalyzerView) {
+    this.container = $(LOG_MARKER_CONTAINER_ID);
+    // Stores highlight objects for each entry.
+    this.entryHighlights = [];
+    // Stores all the filter queries.
+    this.markHistory = {};
+    // Object references from CrosLogAnalyzerView.
+    this.logEntries = logAnalyzerView.logEntries;
+    this.logAnalyzerView = logAnalyzerView;
+    // Counts how many highlights are created.
+    this.markCount = 0;
+    for (var i = 0; i < this.logEntries.length; i++) {
+      this.entryHighlights.push([]);
+    }
+  }
+
+  CrosLogMarker.prototype = {
+    /**
+     * Saves the query to the mark history and highlights the text
+     * based on the query.
+     */
+    addMarkHistory: function(query) {
+      // Increases the counter
+      this.markCount += 1;
+
+      // Find an avaiable color.
+      var color = this.pickColor();
+      if (!color) {
+        // If all colors are occupied.
+        alert('You can only add at most ' + COLOR_NUMBER + 'markers.');
+        return;
+      }
+
+      // Updates HTML elements.
+      var historyEntry = addNode(this.container, 'div');
+      historyEntry.className = LOG_MARKER_HISTORY_ENTRY_CLASS;
+
+      // A color tag that indicats the color used.
+      var colorTag = addNode(historyEntry, 'div');
+      colorTag.className = LOG_MARKER_HISTORY_COLOR_TAG_CLASS;
+      colorTag.style.background = color;
+
+      // Displays the query text.
+      var queryText = addNodeWithText(historyEntry, 'p', query);
+      queryText.style.color = color;
+
+      // Adds a button to remove the marker.
+      var removeBtn = addNodeWithText(historyEntry, 'a', 'Remove');
+      removeBtn.addEventListener(
+          'click', this.onRemoveBtnClicked_.bind(this, historyEntry, color));
+
+      // A checkbox that lets user enable and disable the marker.
+      var enableCheckbox = addNode(historyEntry, 'input');
+      enableCheckbox.type = 'checkbox';
+      enableCheckbox.checked = true;
+      enableCheckbox.color = color;
+      enableCheckbox.addEventListener('change',
+          this.onEnableCheckboxChange_.bind(this, enableCheckbox), false);
+
+      // Searches log text for matched patterns and highlights them.
+      this.patternMatch(query, color);
+    },
+
+    /**
+     * Search the text for matched strings
+     */
+    patternMatch: function(query, color) {
+      var pattern = new RegExp(query, 'i');
+      for (var i = 0; i < this.logEntries.length; i++) {
+        var entry = this.logEntries[i];
+        // Search description of each log entry
+        // TODO(shinfan): Add more search fields
+        var positions = this.findPositions(
+            pattern, entry.description);
+        for (var j = 0; j < positions.length; j++) {
+            var pos = positions[j];
+            this.mark(entry, pos, 'description', color);
+        }
+        this.sortHighlightsByStartPosition_(this.entryHighlights[i]);
+      }
+    },
+
+    /**
+     * Highlights the text.
+     * @param {CrosLogEntry} entry The log entry to be highlighted
+     * @param {int|Array} position [start, end]
+     * @param {string} field The field of entry to be highlighted
+     * @param {string} color color used for highlighting
+     */
+    mark: function(entry, position, field, color) {
+      // Creates the highlight object
+      var tag = new CrosHighlightTag(color, field, position, this.markCount);
+      // Add the highlight into entryHighlights
+      this.entryHighlights[entry.rowNum].push(tag);
+    },
+
+    /**
+     * Find the highlight objects that covers the given position
+     * @param {CrosHighlightTag|Array} highlights highlights of a log entry
+     * @param {int} position The target index
+     * @param {string} field The target field
+     * @return {CrosHighlightTag|Array} Highlights that cover the position
+     */
+    getHighlight: function(highlights, index, field) {
+      var res = [];
+      for (var j = 0; j < highlights.length; j++) {
+        var highlight = highlights[j];
+        if (highlight.range[0] <= index &&
+            highlight.range[1] > index &&
+            highlight.field == field &&
+            highlight.enabled) {
+          res.push(highlight);
+        }
+      }
+      /**
+       * Sorts the result by priority so that the highlight with
+       * highest priority comes first.
+       */
+      this.sortHighlightsByPriority_(res);
+      return res;
+    },
+
+    /**
+     * This function highlights the entry by going through the text from left
+     * to right and searching for "key" positions.
+     * A "key" position is a position that one (or more) highlight
+     * starts or ends. We only care about "key" positions because this is where
+     * the text highlight status changes.
+     * At each key position, the function decides if the text between this
+     * position and previous position need to be highlighted and resolves
+     * highlight conflicts.
+     *
+     * @param {CrosLogEntry} entry The entry going to be highlighted.
+     * @param {string} field The specified field of the entry.
+     * @param {DOMElement} parent Parent node.
+     */
+    getHighlightedEntry: function(entry, field, parent) {
+      var rowNum = entry.rowNum;
+      // Get the original text content of the entry (without any highlights).
+      var content = this.logEntries[rowNum][field];
+      var index = 0;
+      while (index < content.length) {
+        var nextIndex = this.getNextIndex(
+            this.entryHighlights[rowNum], index, field, content);
+        // Searches for highlights that have the position in range.
+        var highlights = this.getHighlight(
+            this.entryHighlights[rowNum], index, field);
+        var text = content.substr(index, nextIndex - index);
+        if (highlights.length > 0) {
+          // Always picks the highlight with highest priority.
+          this.addSpan(text, highlights[0].color, parent);
+        } else {
+          addNodeWithText(parent, 'span', text);
+        }
+        index = nextIndex;
+      }
+    },
+
+    /**
+     * A helper function that is used by this.getHightlightedEntry
+     * It returns the first index where a highlight begins or ends from
+     * the given index.
+     * @param {CrosHighlightTag|Array} highlights An array of highlights
+     *     of a log entry.
+     * @param {int} index The start position.
+     * @param {string} field The specified field of entry.
+     *     Other fields are ignored.
+     * @param {string} content The text content of the log entry.
+     * @return {int} The first index where a highlight begins or ends.
+     */
+    getNextIndex: function(highlights, index, field, content) {
+      var minGap = Infinity;
+      var res = -1;
+      for (var i = 0; i < highlights.length; i++) {
+        if (highlights[i].field != field || !highlights[i].enabled)
+          continue;
+        // Distance between current index and the start index of highlight.
+        var gap1 = highlights[i].range[0] - index;
+        // Distance between current index and the end index of highlight.
+        var gap2 = highlights[i].range[1] - index;
+        if (gap1 > 0 && gap1 < minGap) {
+          minGap = gap1;
+          res = highlights[i].range[0];
+        }
+        if (gap2 > 0 && gap2 < minGap) {
+          minGap = gap2;
+          res = highlights[i].range[1];
+        }
+      }
+      // Returns |res| if found. Otherwise returns the end position of the text.
+      return res > 0 ? res : content.length;
+    },
+
+    /**
+     * A helper function that is used by this.getHightlightedEntry.
+     * It adds the HTML label to the text.
+     */
+    addSpan: function(text, color, parent) {
+      var span = addNodeWithText(parent, 'span', text);
+      span.style.color = color;
+      span.className = LOG_MARKER_HIGHLIGHT_CLASS;
+    },
+
+    /**
+     * A helper function that is used by this.getHightlightedEntry.
+     * It adds the HTML label to the text.
+     */
+    pickColor: function() {
+      for (var color in COLOR_USAGE_SET) {
+        if (!COLOR_USAGE_SET[color]) {
+          COLOR_USAGE_SET[color] = true;
+          return color;
+        }
+      }
+      return false;
+    },
+
+    /**
+     * A event handler that enables and disables the corresponding marker.
+     * @private
+     */
+    onEnableCheckboxChange_: function(checkbox) {
+      for (var i = 0; i < this.entryHighlights.length; i++) {
+        for (var j = 0; j < this.entryHighlights[i].length; j++) {
+          if (this.entryHighlights[i][j].color == checkbox.color) {
+            this.entryHighlights[i][j].enabled = checkbox.checked;
+           }
+        }
+      }
+      this.refreshLogTable();
+    },
+
+    /**
+     * A event handlier that removes the marker from history.
+     * @private
+     */
+    onRemoveBtnClicked_: function(entry, color) {
+      entry.parentNode.removeChild(entry);
+      COLOR_USAGE_SET[color] = false;
+      for (var i = 0; i < this.entryHighlights.length; i++) {
+        var highlights = this.entryHighlights[i];
+        while (true) {
+          var index = this.findHighlightByColor_(highlights, color);
+          if (index == -1)
+            break;
+          highlights.splice(index, 1);
+        }
+      }
+      this.refreshLogTable();
+    },
+
+    /**
+     * A helper function that returns the index of first highlight that
+     * has the target color. Otherwise returns -1.
+     * @private
+     */
+    findHighlightByColor_: function(highlights, color) {
+      for (var i = 0; i < highlights.length; i++) {
+        if (highlights[i].color == color)
+          return i;
+      }
+      return -1;
+    },
+
+    /**
+     * Refresh the log table in the CrosLogAnalyzerView.
+     */
+    refreshLogTable: function() {
+      this.logAnalyzerView.populateTable();
+      this.logAnalyzerView.filterLog();
+    },
+
+    /**
+     * A pattern can appear multiple times in a string.
+     * Returns positions of all the appearance.
+     */
+    findPositions: function(pattern, str) {
+      var res = [];
+      str = str.toLowerCase();
+      var match = str.match(pattern);
+      if (!match)
+        return res;
+      for (var i = 0; i < match.length; i++) {
+        var index = 0;
+        while (true) {
+          var start = str.indexOf(match[i].toLowerCase(), index);
+          if (start == -1)
+            break;
+          var end = start + match[i].length;
+          res.push([start, end]);
+          index = end + 1;
+        }
+      }
+      return res;
+    },
+
+    /**
+     * A helper function used in sorting highlights by start position.
+     * @param {HighlightTag} h1, h2 Two highlight tags in the array.
+     * @private
+     */
+    compareStartPosition_: function(h1, h2) {
+      return h1.range[0] - h2.range[0];
+    },
+
+    /**
+     * A helper function used in sorting highlights by priority.
+     * @param {HighlightTag} h1, h2 Two highlight tags in the array.
+     * @private
+     */
+    comparePriority_: function(h1, h2) {
+      return h2.priority - h1.priority;
+    },
+
+    /**
+     * A helper function that sorts the highlights array by start position.
+     * @private
+     */
+    sortHighlightsByStartPosition_: function(highlights) {
+      highlights.sort(this.compareStartPosition_);
+    },
+
+    /**
+     * A helper function that sorts the highlights array by priority.
+     * @private
+     */
+    sortHighlightsByPriority_: function(highlights) {
+      highlights.sort(this.comparePriority_);
+    }
+  };
+
+  return CrosLogMarker;
+})();
diff --git a/chrome/browser/resources/net_internals/cros_log_visualizer.js b/chrome/browser/resources/net_internals/cros_log_visualizer.js
new file mode 100644
index 0000000..40b5475
--- /dev/null
+++ b/chrome/browser/resources/net_internals/cros_log_visualizer.js
@@ -0,0 +1,376 @@
+// 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 visualizer displays the log in a timeline graph
+ *
+ *   - Use HTML5 canvas
+ *   - Can zoom in result by select time range
+ *   - Display different levels of logs in different layers of canvases
+ *
+ */
+var CrosLogVisualizer = (function() {
+  'use strict';
+
+  // HTML attributes of canvas
+  var LOG_VISUALIZER_CANVAS_CLASS = 'cros-log-analyzer-visualizer-canvas';
+  var LOG_VISUALIZER_CANVAS_WIDTH = 980;
+  var LOG_VISUALIZER_CANVAS_HEIGHT = 100;
+
+  // Special HTML classes
+  var LOG_VISUALIZER_TIMELINE_ID = 'cros-log-analyzer-visualizer-timeline';
+  var LOG_VISUALIZER_TIME_DISPLAY_CLASS =
+      'cros-log-analyzer-visualizer-time-display';
+  var LOG_VISUALIZER_RESET_BTN_ID =
+      'cros-log-analyzer-visualizer-reset-btn';
+  var LOG_VISUALIZER_TRACKING_LAYER_ID =
+      'cros-log-analyzer-visualizer-tracking-layer';
+
+  /**
+   * Event level list
+   * This list is used for intialization of canvases. And the canvas
+   * with lowest priority should be created first. Hence the list is
+   * sorted in decreasing order.
+   */
+  var LOG_EVENT_LEVEL_PRIORITY_LIST = {
+    'Unknown': 4,
+    'Warning': 2,
+    'Info': 3,
+    'Error': 1
+  };
+
+  // Color mapping of different levels
+  var LOG_EVENT_COLORS_LIST = {
+    'Error': '#FF99A3',
+    'Warning': '#FAE5C3',
+    'Info': '#C3E3FA',
+    'Unknown': 'gray'
+  };
+
+  /**
+   * @constructor
+   */
+  function CrosLogVisualizer(logAnalyzer, containerID) {
+    /**
+     * Pass the LogAnalyzer in as a reference so the visualizer can
+     * synchrous with the log filter.
+     */
+    this.logAnalyzer = logAnalyzer;
+
+    // If the data is initialized
+    this.dataIntialized = false;
+    // Stores all the log entries as events
+    this.events = [];
+    // A front layer that handles control events
+    this.trackingLayer = this.createTrackingLayer();
+
+    // References to HTML elements
+    this.container = document.getElementById(containerID);
+    this.timeline = this.createTimeline();
+    this.timeDisplay = this.createTimeDisplay();
+    this.btnReset = this.createBtnReset();
+    // Canvases
+    this.canvases = {};
+    for (var level in LOG_EVENT_LEVEL_PRIORITY_LIST) {
+      this.canvases[level] = this.createCanvas();
+      this.container.appendChild(this.canvases[level]);
+    }
+
+    // Append all the elements to the container
+    this.container.appendChild(this.timeline);
+    this.container.appendChild(this.timeDisplay);
+    this.container.appendChild(this.trackingLayer);
+    this.container.appendChild(this.btnReset);
+
+    this.container.addEventListener('webkitAnimationEnd', function() {
+      this.container.classList.remove('cros-log-analyzer-flash');
+    }.bind(this), false);
+  }
+
+  CrosLogVisualizer.prototype = {
+    /**
+     * Called during the initialization of the View. Create a overlay
+     * DIV on top of the canvas that handles the mouse events
+     */
+    createTrackingLayer: function() {
+      var trackingLayer = document.createElement('div');
+      trackingLayer.setAttribute('id', LOG_VISUALIZER_TRACKING_LAYER_ID);
+      trackingLayer.addEventListener('mousemove', this.onHovered_.bind(this));
+      trackingLayer.addEventListener('mousedown', this.onMouseDown_.bind(this));
+      trackingLayer.addEventListener('mouseup', this.onMouseUp_.bind(this));
+      return trackingLayer;
+    },
+
+    /**
+     * This function is called during the initialization of the view.
+     * It creates the timeline that moves along with the mouse on canvas.
+     * When user click, a rectangle can be dragged out to select the range
+     * to zoom.
+     */
+    createTimeline: function() {
+      var timeline = document.createElement('div');
+      timeline.setAttribute('id', LOG_VISUALIZER_TIMELINE_ID);
+      timeline.style.height = LOG_VISUALIZER_CANVAS_HEIGHT + 'px';
+      timeline.addEventListener('mousedown', function(event) { return false; });
+      return timeline;
+    },
+
+    /**
+     * This function is called during the initialization of the view.
+     * It creates a time display that moves with the timeline
+     */
+    createTimeDisplay: function() {
+      var timeDisplay = document.createElement('p');
+      timeDisplay.className = LOG_VISUALIZER_TIME_DISPLAY_CLASS;
+      timeDisplay.style.top = LOG_VISUALIZER_CANVAS_HEIGHT + 'px';
+      return timeDisplay;
+    },
+
+    /**
+     * Called during the initialization of the View. Create a button that
+     * resets the canvas to initial status (without zoom)
+     */
+    createBtnReset: function() {
+      var btnReset = document.createElement('input');
+      btnReset.setAttribute('type', 'button');
+      btnReset.setAttribute('value', 'Reset');
+      btnReset.setAttribute('id', LOG_VISUALIZER_RESET_BTN_ID);
+      btnReset.addEventListener('click', this.reset.bind(this));
+      return btnReset;
+    },
+
+    /**
+     * Called during the initialization of the View. Create a empty canvas
+     * that visualizes log when the data is ready
+     */
+    createCanvas: function() {
+      var canvas = document.createElement('canvas');
+      canvas.width = LOG_VISUALIZER_CANVAS_WIDTH;
+      canvas.height = LOG_VISUALIZER_CANVAS_HEIGHT;
+      canvas.className = LOG_VISUALIZER_CANVAS_CLASS;
+      return canvas;
+    },
+
+    /**
+     * Returns the context of corresponding canvas based on level
+     */
+    getContext: function(level) {
+      return this.canvases[level].getContext('2d');
+    },
+
+    /**
+     * Erases everything from all the canvases
+     */
+    clearCanvas: function() {
+      for (var level in LOG_EVENT_LEVEL_PRIORITY_LIST) {
+        var ctx = this.getContext(level);
+        ctx.clearRect(0, 0, LOG_VISUALIZER_CANVAS_WIDTH,
+            LOG_VISUALIZER_CANVAS_HEIGHT);
+      }
+    },
+
+    /**
+     * Initializes the parameters needed for drawing:
+     *  - lower/upperBound: Time range (Events out of range will be skipped)
+     *  - totalDuration: The length of time range
+     *  - unitDuration: The unit time length per pixel
+     */
+    initialize: function() {
+      if (this.events.length == 0)
+        return;
+      this.dragMode = false;
+      this.dataIntialized = true;
+      this.events.sort(this.compareTime);
+      this.lowerBound = this.events[0].time;
+      this.upperBound = this.events[this.events.length - 1].time;
+      this.totalDuration = Math.abs(this.upperBound.getTime() -
+          this.lowerBound.getTime());
+      this.unitDuration = this.totalDuration / LOG_VISUALIZER_CANVAS_WIDTH;
+    },
+
+    /**
+     * CSS3 fadeIn/fadeOut effects
+     */
+    flashEffect: function() {
+      this.container.classList.add('cros-log-analyzer-flash');
+    },
+
+    /**
+     * Reset the canvas to the initial time range
+     * Redraw everything on the canvas
+     * Fade in/out effects while redrawing
+     */
+    reset: function() {
+      // Reset all the parameters as initial
+      this.initialize();
+      // Reset the visibility of the entries in the log table
+      this.logAnalyzer.filterLog();
+      this.flashEffect();
+     },
+
+    /**
+     * A wrapper function for drawing
+     */
+    drawEvents: function() {
+      if (this.events.length == 0)
+        return;
+      for (var i in this.events) {
+        this.drawEvent(this.events[i]);
+      }
+    },
+
+    /**
+     * The main function that handles drawing on the canvas.
+     * Every event is represented as a vertical line.
+     */
+    drawEvent: function(event) {
+      if (!event.visibility) {
+        // Skip hidden events
+        return;
+      }
+      var ctx = this.getContext(event.level);
+      ctx.beginPath();
+      // Get the x-coordinate of the line
+      var startPosition = this.getPosition(event.time);
+      if (startPosition != this.old) {
+        this.old = startPosition;
+      }
+      ctx.rect(startPosition, 0, 2, LOG_VISUALIZER_CANVAS_HEIGHT);
+      // Get the color of the line
+      ctx.fillStyle = LOG_EVENT_COLORS_LIST[event.level];
+      ctx.fill();
+      ctx.closePath();
+    },
+
+    /**
+     * This function is called every time the graph is zoomed.
+     * It recalculates all the parameters based on the distance and direction
+     * of dragging.
+     */
+    reCalculate: function() {
+      if (this.dragDistance >= 0) {
+        // if user drags to right
+        this.upperBound = new Date((this.timelineLeft + this.dragDistance) *
+            this.unitDuration + this.lowerBound.getTime());
+        this.lowerBound = new Date(this.timelineLeft * this.unitDuration +
+            this.lowerBound.getTime());
+      } else {
+        // if user drags to left
+        this.upperBound = new Date(this.timelineLeft * this.unitDuration +
+            this.lowerBound.getTime());
+        this.lowerBound = new Date((this.timelineLeft + this.dragDistance) *
+            this.unitDuration + this.lowerBound.getTime());
+      }
+      this.totalDuration = this.upperBound.getTime() -
+          this.lowerBound.getTime();
+      this.unitDuration = this.totalDuration / LOG_VISUALIZER_CANVAS_WIDTH;
+    },
+
+    /**
+     * Check if the time of a event is out of bound
+     */
+    isOutOfBound: function(event) {
+      return event.time.getTime() < this.lowerBound.getTime() ||
+              event.time.getTime() > this.upperBound.getTime();
+    },
+
+    /**
+     * This function returns the offset on x-coordinate of canvas based on
+     * the time
+     */
+    getPosition: function(time) {
+      return (time.getTime() - this.lowerBound.getTime()) / this.unitDuration;
+    },
+
+    /**
+     * This function updates the events array and refresh the canvas.
+     */
+    updateEvents: function(newEvents) {
+      this.events.length = 0;
+      for (var i in newEvents) {
+        this.events.push(newEvents[i]);
+      }
+      if (!this.dataIntialized) {
+        this.initialize();
+      }
+      this.clearCanvas();
+      this.drawEvents();
+    },
+
+    /**
+     * This is a helper function that returns the time object based on the
+     * offset of x-coordinate on the canvs.
+     */
+    getOffsetTime: function(offset) {
+      return new Date(this.lowerBound.getTime() + offset * this.unitDuration);
+    },
+
+    /**
+     * This function is triggered when the hovering event is detected
+     * When the mouse is hovering we have two control mode:
+     *  - If it is in drag mode, we need to resize the width of the timeline
+     *  - If not, we need to move the timeline and time display to the
+     * x-coordinate position of the mouse
+     */
+    onHovered_: function(event) {
+      var offsetX = event.offsetX;
+      if (this.lastOffsetX == offsetX) {
+        // If the mouse does not move, we just skip the event
+        return;
+      }
+
+      if (this.dragMode == true) {
+        // If the mouse is in drag mode
+        this.dragDistance = offsetX - this.timelineLeft;
+        if (this.dragDistance >= 0) {
+          // If the mouse is moving right
+          this.timeline.style.width = this.dragDistance + 'px';
+        } else {
+          // If the mouse is moving left
+          this.timeline.style.width = -this.dragDistance + 'px';
+          this.timeline.style.left = offsetX + 'px';
+        }
+      } else {
+        // If the mouse is not in drag mode we just move the timeline
+        this.timeline.style.width = '2px';
+        this.timeline.style.left = offsetX + 'px';
+      }
+
+      // update time display
+      this.timeDisplay.style.left = offsetX + 'px';
+      this.timeDisplay.textContent =
+          this.getOffsetTime(offsetX).toTimeString().substr(0, 8);
+      // update the last offset
+      this.lastOffsetX = offsetX;
+    },
+
+    /**
+     * This function is the handler for the onMouseDown event on the canvas
+     */
+    onMouseDown_: function(event) {
+      // Enter drag mode which let user choose a time range to zoom in
+      this.dragMode = true;
+      this.timelineLeft = event.offsetX;
+      // Create a duration display to indicate the duration of range.
+      this.timeDurationDisplay = this.createTimeDisplay();
+      this.container.appendChild(this.timeDurationDisplay);
+    },
+
+    /**
+     * This function is the handler for the onMouseUp event on the canvas
+     */
+    onMouseUp_: function(event) {
+      // Remove the duration display
+      this.container.removeChild(this.timeDurationDisplay);
+      // End the drag mode
+      this.dragMode = false;
+      // Recalculate the pamameter based on the range user select
+      this.reCalculate();
+      // Filter the log table and hide the entries that are not in the range
+      this.logAnalyzer.filterLog();
+    },
+  };
+
+  return CrosLogVisualizer;
+})();
diff --git a/chrome/browser/resources/net_internals/index.html b/chrome/browser/resources/net_internals/index.html
index 774dbf2..6771cb4 100644
--- a/chrome/browser/resources/net_internals/index.html
+++ b/chrome/browser/resources/net_internals/index.html
@@ -15,6 +15,7 @@
     <link rel="stylesheet" href="timeline_view.css">
     <link rel="stylesheet" href="logs_view.css">
     <link rel="stylesheet" href="chromeos_view.css">
+    <link rel="stylesheet" href="cros_log_analyzer_view.css">
     <script src="chrome://resources/js/util.js"></script>
     <script src="chrome://resources/js/cr.js"></script>
     <script src="chrome://net-internals/index.js"></script>
@@ -43,6 +44,7 @@
       <include src="timeline_view.html"/>
       <include src="logs_view.html"/>
       <include src="chromeos_view.html"/>
+      <include src="cros_log_analyzer_view.html"/>
     </div>
 
     <script src="chrome://resources/js/i18n_template.js"></script>
diff --git a/chrome/browser/resources/net_internals/index.js b/chrome/browser/resources/net_internals/index.js
index f8d7f36..44465fd 100644
--- a/chrome/browser/resources/net_internals/index.js
+++ b/chrome/browser/resources/net_internals/index.js
@@ -48,6 +48,10 @@
 <include src="chromeos_view.js"/>
 <include src="http_pipeline_view.js"/>
 <include src="bandwidth_view.js"/>
+<include src="cros_log_analyzer_view.js"/>
+<include src="cros_log_entry.js"/>
+<include src="cros_log_visualizer.js" />
+<include src="cros_log_marker.js" />
 
 document.addEventListener('DOMContentLoaded', function() {
   MainView.getInstance();  // from main.js
diff --git a/chrome/browser/resources/net_internals/log_view_painter.js b/chrome/browser/resources/net_internals/log_view_painter.js
index 52f2921..eec71b5 100644
--- a/chrome/browser/resources/net_internals/log_view_painter.js
+++ b/chrome/browser/resources/net_internals/log_view_painter.js
@@ -329,6 +329,18 @@
     return;
   }
 
+  if (key == 'quic_error' && typeof value == 'number') {
+    var valueStr = value + ' (' + quicErrorToString(value) + ')';
+    out.writeArrowKeyValue(key, valueStr);
+    return;
+  }
+
+  if (key == 'quic_rst_stream_error' && typeof value == 'number') {
+    var valueStr = value + ' (' + quicRstStreamErrorToString(value) + ')';
+    out.writeArrowKeyValue(key, valueStr);
+    return;
+  }
+
   if (key == 'load_flags' && typeof value == 'number') {
     var valueStr = value + ' (' + getLoadFlagSymbolicString(value) + ')';
     out.writeArrowKeyValue(key, valueStr);
diff --git a/chrome/browser/resources/net_internals/main.js b/chrome/browser/resources/net_internals/main.js
index 22221ae..8cbd37c 100644
--- a/chrome/browser/resources/net_internals/main.js
+++ b/chrome/browser/resources/net_internals/main.js
@@ -15,6 +15,8 @@
 var LogLevelType = null;
 var ClientInfo = null;
 var NetError = null;
+var QuicError = null;
+var QuicRstStreamError = null;
 var LoadFlag = null;
 var LoadState = null;
 var AddressFamily = null;
@@ -192,6 +194,7 @@
       addTab(HttpCacheView);
       addTab(ModulesView);
       addTab(TestView);
+      addTab(CrosLogAnalyzerView);
       addTab(HSTSView);
       addTab(LogsView);
       addTab(BandwidthView);
@@ -200,6 +203,7 @@
 
       this.tabSwitcher_.showMenuItem(LogsView.TAB_ID, cr.isChromeOS);
       this.tabSwitcher_.showMenuItem(CrosView.TAB_ID, cr.isChromeOS);
+      this.tabSwitcher_.showMenuItem(CrosLogAnalyzerView.TAB_ID, cr.isChromeOS);
     },
 
     /**
@@ -301,6 +305,8 @@
   ClientInfo = Constants.clientInfo;
   LoadFlag = Constants.loadFlag;
   NetError = Constants.netError;
+  QuicError = Constants.quicError;
+  QuicRstStreamError = Constants.quicRstStreamError;
   AddressFamily = Constants.addressFamily;
   LoadState = Constants.loadState;
 
@@ -329,7 +335,7 @@
 /**
  * Returns the name for netError.
  *
- * Example: netErrorToString(-105) would return
+ * Example: netErrorToString(-105) should return
  * "ERR_NAME_NOT_RESOLVED".
  * @param {number} netError The net error code.
  * @return {string} The name of the given error.
@@ -342,6 +348,30 @@
 }
 
 /**
+ * Returns the name for quicError.
+ *
+ * Example: quicErrorToString(25) should return
+ * "TIMED_OUT".
+ * @param {number} quicError The QUIC error code.
+ * @return {string} The name of the given error.
+ */
+function quicErrorToString(quicError) {
+  return getKeyWithValue(QuicError, quicError);
+}
+
+/**
+ * Returns the name for quicRstStreamError.
+ *
+ * Example: quicRstStreamErrorToString(3) should return
+ * "BAD_APPLICATION_PAYLOAD".
+ * @param {number} quicRstStreamError The QUIC RST_STREAM error code.
+ * @return {string} The name of the given error.
+ */
+function quicRstStreamErrorToString(quicRstStreamError) {
+  return getKeyWithValue(QuicRstStreamError, quicRstStreamError);
+}
+
+/**
  * Returns a string representation of |family|.
  * @param {number} family An AddressFamily
  * @return {string} A representation of the given family.
diff --git a/chrome/browser/resources/ntp4/app_launcher_promo.png b/chrome/browser/resources/ntp4/app_launcher_promo.png
index 488e17b..79805ed 100644
--- a/chrome/browser/resources/ntp4/app_launcher_promo.png
+++ b/chrome/browser/resources/ntp4/app_launcher_promo.png
Binary files differ
diff --git a/chrome/browser/resources/ntp4/images/2x/app_promo_button.png b/chrome/browser/resources/ntp4/images/2x/app_promo_button.png
index 1439fe7..87a9ac1 100644
--- a/chrome/browser/resources/ntp4/images/2x/app_promo_button.png
+++ b/chrome/browser/resources/ntp4/images/2x/app_promo_button.png
Binary files differ
diff --git a/chrome/browser/resources/ntp4/images/2x/closed_window.png b/chrome/browser/resources/ntp4/images/2x/closed_window.png
index 6e3f93c..ca1fdd8 100644
--- a/chrome/browser/resources/ntp4/images/2x/closed_window.png
+++ b/chrome/browser/resources/ntp4/images/2x/closed_window.png
Binary files differ
diff --git a/chrome/browser/resources/ntp4/images/2x/disclosure_triangle_mask.png b/chrome/browser/resources/ntp4/images/2x/disclosure_triangle_mask.png
index 6b7c478..72b4f2b 100644
--- a/chrome/browser/resources/ntp4/images/2x/disclosure_triangle_mask.png
+++ b/chrome/browser/resources/ntp4/images/2x/disclosure_triangle_mask.png
Binary files differ
diff --git a/chrome/browser/resources/ntp4/images/closed_window.png b/chrome/browser/resources/ntp4/images/closed_window.png
index 04eba16..eab8191 100644
--- a/chrome/browser/resources/ntp4/images/closed_window.png
+++ b/chrome/browser/resources/ntp4/images/closed_window.png
Binary files differ
diff --git a/chrome/browser/resources/ntp4/new_tab.html b/chrome/browser/resources/ntp4/new_tab.html
index 8e81efe..78d921c 100644
--- a/chrome/browser/resources/ntp4/new_tab.html
+++ b/chrome/browser/resources/ntp4/new_tab.html
@@ -96,7 +96,8 @@
   <div id="app-launcher-promo" hidden>
     <div class="apps-promo-text" i18n-content="appsPromoTitle"></div>
     <a href="https://chrome.google.com/webstore/launcher"
-       class="apps-promo-learn-more" i18n-content="learn_more">
+       id="apps-promo-learn-more" class="apps-promo-learn-more"
+       i18n-content="learn_more">
     </a>
     <img src="app_launcher_promo.png">
     <button class="close-button custom-appearance"
diff --git a/chrome/browser/resources/ntp4/new_tab.js b/chrome/browser/resources/ntp4/new_tab.js
index 25643ae..621e044 100644
--- a/chrome/browser/resources/ntp4/new_tab.js
+++ b/chrome/browser/resources/ntp4/new_tab.js
@@ -122,6 +122,8 @@
       if (loadTimeData.getBoolean('showAppLauncherPromo')) {
         $('app-launcher-promo-close-button').addEventListener('click',
             function() { chrome.send('stopShowingAppLauncherPromo'); });
+        $('apps-promo-learn-more').addEventListener('click',
+            function() { chrome.send('onLearnMore'); });
       }
     }
     if (loadTimeData.getBoolean('isDiscoveryInNTPEnabled'))
@@ -244,7 +246,8 @@
 
     var loginContainer = getRequiredElement('login-container');
     loginContainer.addEventListener('click', showSyncLoginUI);
-    chrome.send('initializeSyncLogin');
+    if (loadTimeData.getBoolean('shouldShowSyncLogin'))
+      chrome.send('initializeSyncLogin');
 
     doWhenAllSectionsReady(function() {
       // Tell the slider about the pages.
diff --git a/chrome/browser/resources/ntp_android/OWNERS b/chrome/browser/resources/ntp_android/OWNERS
index d28a429..c7eba94 100644
--- a/chrome/browser/resources/ntp_android/OWNERS
+++ b/chrome/browser/resources/ntp_android/OWNERS
@@ -1,4 +1,2 @@
-jcivelli@chromium.org
-nileshagrawal@chromium.org
 tedchoc@chromium.org
 yfriedman@chromium.org
diff --git a/chrome/browser/resources/ntp_android/images/bookmark_bg_hdpi.png b/chrome/browser/resources/ntp_android/images/bookmark_bg_hdpi.png
index e47df28..cfa6c7b 100644
--- a/chrome/browser/resources/ntp_android/images/bookmark_bg_hdpi.png
+++ b/chrome/browser/resources/ntp_android/images/bookmark_bg_hdpi.png
Binary files differ
diff --git a/chrome/browser/resources/ntp_android/images/bookmark_bg_mdpi.png b/chrome/browser/resources/ntp_android/images/bookmark_bg_mdpi.png
index 382479a..b26489a 100644
--- a/chrome/browser/resources/ntp_android/images/bookmark_bg_mdpi.png
+++ b/chrome/browser/resources/ntp_android/images/bookmark_bg_mdpi.png
Binary files differ
diff --git a/chrome/browser/resources/ntp_android/images/bookmark_bg_tvdpi.png b/chrome/browser/resources/ntp_android/images/bookmark_bg_tvdpi.png
index ad67898..fbd0758 100644
--- a/chrome/browser/resources/ntp_android/images/bookmark_bg_tvdpi.png
+++ b/chrome/browser/resources/ntp_android/images/bookmark_bg_tvdpi.png
Binary files differ
diff --git a/chrome/browser/resources/ntp_android/images/bookmark_bg_xhdpi.png b/chrome/browser/resources/ntp_android/images/bookmark_bg_xhdpi.png
index 3f8d937..a50dbb5 100644
--- a/chrome/browser/resources/ntp_android/images/bookmark_bg_xhdpi.png
+++ b/chrome/browser/resources/ntp_android/images/bookmark_bg_xhdpi.png
Binary files differ
diff --git a/chrome/browser/resources/ntp_android/images/bookmark_border_hdpi.png b/chrome/browser/resources/ntp_android/images/bookmark_border_hdpi.png
index 44fc9ca..6c37481 100644
--- a/chrome/browser/resources/ntp_android/images/bookmark_border_hdpi.png
+++ b/chrome/browser/resources/ntp_android/images/bookmark_border_hdpi.png
Binary files differ
diff --git a/chrome/browser/resources/ntp_android/images/bookmark_border_mdpi.png b/chrome/browser/resources/ntp_android/images/bookmark_border_mdpi.png
index 3381212..3a42c37 100644
--- a/chrome/browser/resources/ntp_android/images/bookmark_border_mdpi.png
+++ b/chrome/browser/resources/ntp_android/images/bookmark_border_mdpi.png
Binary files differ
diff --git a/chrome/browser/resources/ntp_android/images/bookmark_border_tvdpi.png b/chrome/browser/resources/ntp_android/images/bookmark_border_tvdpi.png
index 18a4ca1..175c28c 100644
--- a/chrome/browser/resources/ntp_android/images/bookmark_border_tvdpi.png
+++ b/chrome/browser/resources/ntp_android/images/bookmark_border_tvdpi.png
Binary files differ
diff --git a/chrome/browser/resources/ntp_android/images/bookmark_border_xhdpi.png b/chrome/browser/resources/ntp_android/images/bookmark_border_xhdpi.png
index 62199d9..bf092ef 100644
--- a/chrome/browser/resources/ntp_android/images/bookmark_border_xhdpi.png
+++ b/chrome/browser/resources/ntp_android/images/bookmark_border_xhdpi.png
Binary files differ
diff --git a/chrome/browser/resources/ntp_android/images/bookmark_folder_hdpi.png b/chrome/browser/resources/ntp_android/images/bookmark_folder_hdpi.png
index 1194588..60ed460 100644
--- a/chrome/browser/resources/ntp_android/images/bookmark_folder_hdpi.png
+++ b/chrome/browser/resources/ntp_android/images/bookmark_folder_hdpi.png
Binary files differ
diff --git a/chrome/browser/resources/ntp_android/images/bookmark_folder_mdpi.png b/chrome/browser/resources/ntp_android/images/bookmark_folder_mdpi.png
index 7805a69..d908689 100644
--- a/chrome/browser/resources/ntp_android/images/bookmark_folder_mdpi.png
+++ b/chrome/browser/resources/ntp_android/images/bookmark_folder_mdpi.png
Binary files differ
diff --git a/chrome/browser/resources/ntp_android/images/bookmark_folder_tvdpi.png b/chrome/browser/resources/ntp_android/images/bookmark_folder_tvdpi.png
index 4628b98..1f5d802 100644
--- a/chrome/browser/resources/ntp_android/images/bookmark_folder_tvdpi.png
+++ b/chrome/browser/resources/ntp_android/images/bookmark_folder_tvdpi.png
Binary files differ
diff --git a/chrome/browser/resources/ntp_android/images/bookmark_folder_xhdpi.png b/chrome/browser/resources/ntp_android/images/bookmark_folder_xhdpi.png
index 676bc55..87a8dd3 100644
--- a/chrome/browser/resources/ntp_android/images/bookmark_folder_xhdpi.png
+++ b/chrome/browser/resources/ntp_android/images/bookmark_folder_xhdpi.png
Binary files differ
diff --git a/chrome/browser/resources/ntp_android/images/breadcrumb_hdpi.png b/chrome/browser/resources/ntp_android/images/breadcrumb_hdpi.png
index a75c2e8..faae43a 100644
--- a/chrome/browser/resources/ntp_android/images/breadcrumb_hdpi.png
+++ b/chrome/browser/resources/ntp_android/images/breadcrumb_hdpi.png
Binary files differ
diff --git a/chrome/browser/resources/ntp_android/images/breadcrumb_mdpi.png b/chrome/browser/resources/ntp_android/images/breadcrumb_mdpi.png
index a2c56ca..b9a0305 100644
--- a/chrome/browser/resources/ntp_android/images/breadcrumb_mdpi.png
+++ b/chrome/browser/resources/ntp_android/images/breadcrumb_mdpi.png
Binary files differ
diff --git a/chrome/browser/resources/ntp_android/images/breadcrumb_tvdpi.png b/chrome/browser/resources/ntp_android/images/breadcrumb_tvdpi.png
index 607f2cf..0990077 100644
--- a/chrome/browser/resources/ntp_android/images/breadcrumb_tvdpi.png
+++ b/chrome/browser/resources/ntp_android/images/breadcrumb_tvdpi.png
Binary files differ
diff --git a/chrome/browser/resources/ntp_android/images/breadcrumb_xhdpi.png b/chrome/browser/resources/ntp_android/images/breadcrumb_xhdpi.png
index f698f7e..45edcee 100644
--- a/chrome/browser/resources/ntp_android/images/breadcrumb_xhdpi.png
+++ b/chrome/browser/resources/ntp_android/images/breadcrumb_xhdpi.png
Binary files differ
diff --git a/chrome/browser/resources/ntp_android/images/default_thumbnail.png b/chrome/browser/resources/ntp_android/images/default_thumbnail.png
index 2991999..e2534e0 100644
--- a/chrome/browser/resources/ntp_android/images/default_thumbnail.png
+++ b/chrome/browser/resources/ntp_android/images/default_thumbnail.png
Binary files differ
diff --git a/chrome/browser/resources/ntp_android/images/disclosure_closed_hdpi.png b/chrome/browser/resources/ntp_android/images/disclosure_closed_hdpi.png
index 225a0f3..a0a086a 100644
--- a/chrome/browser/resources/ntp_android/images/disclosure_closed_hdpi.png
+++ b/chrome/browser/resources/ntp_android/images/disclosure_closed_hdpi.png
Binary files differ
diff --git a/chrome/browser/resources/ntp_android/images/disclosure_closed_mdpi.png b/chrome/browser/resources/ntp_android/images/disclosure_closed_mdpi.png
index d2ce368..42e633e 100644
--- a/chrome/browser/resources/ntp_android/images/disclosure_closed_mdpi.png
+++ b/chrome/browser/resources/ntp_android/images/disclosure_closed_mdpi.png
Binary files differ
diff --git a/chrome/browser/resources/ntp_android/images/disclosure_closed_xhdpi.png b/chrome/browser/resources/ntp_android/images/disclosure_closed_xhdpi.png
index 68ba55e..55eab9a 100644
--- a/chrome/browser/resources/ntp_android/images/disclosure_closed_xhdpi.png
+++ b/chrome/browser/resources/ntp_android/images/disclosure_closed_xhdpi.png
Binary files differ
diff --git a/chrome/browser/resources/ntp_android/images/disclosure_open_hdpi.png b/chrome/browser/resources/ntp_android/images/disclosure_open_hdpi.png
index 9f03830..ed5022f 100644
--- a/chrome/browser/resources/ntp_android/images/disclosure_open_hdpi.png
+++ b/chrome/browser/resources/ntp_android/images/disclosure_open_hdpi.png
Binary files differ
diff --git a/chrome/browser/resources/ntp_android/images/disclosure_open_mdpi.png b/chrome/browser/resources/ntp_android/images/disclosure_open_mdpi.png
index 7e33377..b1218a5 100644
--- a/chrome/browser/resources/ntp_android/images/disclosure_open_mdpi.png
+++ b/chrome/browser/resources/ntp_android/images/disclosure_open_mdpi.png
Binary files differ
diff --git a/chrome/browser/resources/ntp_android/images/disclosure_open_xhdpi.png b/chrome/browser/resources/ntp_android/images/disclosure_open_xhdpi.png
index 419ebc4..5a5b56c 100644
--- a/chrome/browser/resources/ntp_android/images/disclosure_open_xhdpi.png
+++ b/chrome/browser/resources/ntp_android/images/disclosure_open_xhdpi.png
Binary files differ
diff --git a/chrome/browser/resources/ntp_android/images/sent_hdpi.png b/chrome/browser/resources/ntp_android/images/sent_hdpi.png
index b9f77e1..4ef1e01 100644
--- a/chrome/browser/resources/ntp_android/images/sent_hdpi.png
+++ b/chrome/browser/resources/ntp_android/images/sent_hdpi.png
Binary files differ
diff --git a/chrome/browser/resources/ntp_android/images/sent_mdpi.png b/chrome/browser/resources/ntp_android/images/sent_mdpi.png
index 351a519..e8631c8 100644
--- a/chrome/browser/resources/ntp_android/images/sent_mdpi.png
+++ b/chrome/browser/resources/ntp_android/images/sent_mdpi.png
Binary files differ
diff --git a/chrome/browser/resources/ntp_android/images/sent_xhdpi.png b/chrome/browser/resources/ntp_android/images/sent_xhdpi.png
index a54a0ec..1f024cb 100644
--- a/chrome/browser/resources/ntp_android/images/sent_xhdpi.png
+++ b/chrome/browser/resources/ntp_android/images/sent_xhdpi.png
Binary files differ
diff --git a/chrome/browser/resources/ntp_android/images/syncfographic_hdpi.png b/chrome/browser/resources/ntp_android/images/syncfographic_hdpi.png
index f54608e..b7f337a 100644
--- a/chrome/browser/resources/ntp_android/images/syncfographic_hdpi.png
+++ b/chrome/browser/resources/ntp_android/images/syncfographic_hdpi.png
Binary files differ
diff --git a/chrome/browser/resources/ntp_android/images/syncfographic_mdpi.png b/chrome/browser/resources/ntp_android/images/syncfographic_mdpi.png
index 580a19c..7bc97e8 100644
--- a/chrome/browser/resources/ntp_android/images/syncfographic_mdpi.png
+++ b/chrome/browser/resources/ntp_android/images/syncfographic_mdpi.png
Binary files differ
diff --git a/chrome/browser/resources/ntp_android/images/syncfographic_sw600dp_hdpi.png b/chrome/browser/resources/ntp_android/images/syncfographic_sw600dp_hdpi.png
index 144fea2..c6c4391 100644
--- a/chrome/browser/resources/ntp_android/images/syncfographic_sw600dp_hdpi.png
+++ b/chrome/browser/resources/ntp_android/images/syncfographic_sw600dp_hdpi.png
Binary files differ
diff --git a/chrome/browser/resources/ntp_android/images/syncfographic_sw600dp_mdpi.png b/chrome/browser/resources/ntp_android/images/syncfographic_sw600dp_mdpi.png
index cc75415..d23a041 100644
--- a/chrome/browser/resources/ntp_android/images/syncfographic_sw600dp_mdpi.png
+++ b/chrome/browser/resources/ntp_android/images/syncfographic_sw600dp_mdpi.png
Binary files differ
diff --git a/chrome/browser/resources/ntp_android/images/syncfographic_sw600dp_xhdpi.png b/chrome/browser/resources/ntp_android/images/syncfographic_sw600dp_xhdpi.png
index 60a8ee4..8ec1bde 100644
--- a/chrome/browser/resources/ntp_android/images/syncfographic_sw600dp_xhdpi.png
+++ b/chrome/browser/resources/ntp_android/images/syncfographic_sw600dp_xhdpi.png
Binary files differ
diff --git a/chrome/browser/resources/ntp_android/images/syncfographic_xhdpi.png b/chrome/browser/resources/ntp_android/images/syncfographic_xhdpi.png
index 51ec233..d6aa146 100644
--- a/chrome/browser/resources/ntp_android/images/syncfographic_xhdpi.png
+++ b/chrome/browser/resources/ntp_android/images/syncfographic_xhdpi.png
Binary files differ
diff --git a/chrome/browser/resources/ntp_android/images/welcome_thumb.png b/chrome/browser/resources/ntp_android/images/welcome_thumb.png
index 7265f13..9997667 100644
--- a/chrome/browser/resources/ntp_android/images/welcome_thumb.png
+++ b/chrome/browser/resources/ntp_android/images/welcome_thumb.png
Binary files differ
diff --git a/chrome/browser/resources/ntp_android/ntp_android.js b/chrome/browser/resources/ntp_android/ntp_android.js
index 4e61603..6fe4548 100644
--- a/chrome/browser/resources/ntp_android/ntp_android.js
+++ b/chrome/browser/resources/ntp_android/ntp_android.js
@@ -373,6 +373,12 @@
 
   function setIncognitoMode(incognito) {
     isIncognito = incognito;
+    if (!isIncognito) {
+      chrome.send('getMostVisited');
+      chrome.send('getRecentlyClosedTabs');
+      chrome.send('getForeignSessions');
+      chrome.send('getPromotions');
+    }
   }
 
   /**
@@ -447,11 +453,6 @@
     // Initialize virtual computers for the sync promo.
     createPromoVirtualComputers();
 
-    chrome.send('getMostVisited');
-    chrome.send('getRecentlyClosedTabs');
-    chrome.send('getForeignSessions');
-    chrome.send('getPromotions');
-
     setCurrentBookmarkFolderData(
         localStorage.getItem(DEFAULT_BOOKMARK_FOLDER_KEY));
 
@@ -707,9 +708,7 @@
       image.onload = function() {
         var w = image.width;
         var h = image.height;
-        var wDip = w / window.devicePixelRatio;
-        var hDip = h / window.devicePixelRatio;
-        if (Math.floor(wDip) <= 16 || Math.floor(hDip) <= 16) {
+        if (Math.floor(w) <= 16 || Math.floor(h) <= 16) {
           // it's a standard favicon (or at least it's small).
           faviconBox.classList.add('document');
 
@@ -740,13 +739,13 @@
         } else {
           // It's an html5 icon (or at least it's larger).
           // Rescale it to be no bigger than 64x64 dip.
-          var maxDip = 64; // DIP
-          if (wDip > maxDip || hDip > maxDip) {
-            var scale = (wDip > hDip) ? (maxDip / wDip) : (maxDip / hDip);
-            wDip *= scale;
-            hDip *= scale;
+          var max = 64;
+          if (w > max || h > max) {
+            var scale = (w > h) ? (max / w) : (max / h);
+            w *= scale;
+            h *= scale;
           }
-          faviconIcon.style.backgroundSize = wDip + 'px ' + hDip + 'px';
+          faviconIcon.style.backgroundSize = w + 'px ' + h + 'px';
         }
       };
       faviconBox.appendChild(faviconIcon);
@@ -1796,6 +1795,9 @@
           // use a section divider.
           var needSectionDivider =
               (tabNum + 1 == tabs.length) && (winNum + 1 < windows.length);
+          tab.icon = tab.icon ||
+            'chrome://session-favicon/size/16@1x/' + tab.url;
+
           openTabsList.push({
             timestamp: tab.timestamp,
             title: tab.title,
@@ -1804,7 +1806,7 @@
             winNum: winNum,
             sessionId: tab.sessionId,
             icon: tab.icon,
-            iconSize: 32,
+            iconSize: 16,
             divider: needSectionDivider ? 'section' : 'standard',
           });
         }
@@ -2202,7 +2204,7 @@
     // 'natural' height and width of the thumbnail
     var thumbHeight = 72;
     var thumbWidth = 108;
-    var labelHeight = 20;
+    var labelHeight = 25;
     var labelWidth = thumbWidth + 20;
     var labelLeft = (thumbWidth - labelWidth) / 2;
     var itemHeight = thumbHeight + labelHeight;
@@ -2214,9 +2216,6 @@
     var itemMarginRight = 20;
 
     var listHeight = 0;
-    // set it to the unscaled size so centerGrid works correctly
-    modifyCssRule('body[device="phone"] .thumbnail-cell',
-        'width', thumbWidth + 'px');
 
     var screenHeight =
         document.documentElement.offsetHeight -
@@ -2225,7 +2224,9 @@
     if (isPortrait()) {
       mostVisitedList.setAttribute(GRID_COLUMNS, '2');
       listHeight = screenHeight * .85;
-      listHeight = listHeight >= 420 ? 420 : listHeight;
+      // Ensure that listHeight is not too small and not too big.
+      listHeight = Math.max(listHeight, (itemHeight * 3) + 20);
+      listHeight = Math.min(listHeight, 420);
       // Size for 3 rows (4 gutters)
       itemMarginTop = (listHeight - (itemHeight * 3)) / 4;
     } else {
@@ -2241,8 +2242,8 @@
         var scale = (screenHeight - 2 * labelHeight -
             targetRemainder) / (2 * thumbHeight);
         // update values based on scale
-        thumbWidth *= scale;
-        thumbHeight *= scale;
+        thumbWidth = Math.round(thumbWidth * scale);
+        thumbHeight = Math.round(thumbHeight * scale);
         labelWidth = thumbWidth + 20;
         itemHeight = thumbHeight + labelHeight;
       }
diff --git a/chrome/browser/resources/options/arrow_next.png b/chrome/browser/resources/options/arrow_next.png
index 2cbf8e6..7d626c0 100644
--- a/chrome/browser/resources/options/arrow_next.png
+++ b/chrome/browser/resources/options/arrow_next.png
Binary files differ
diff --git a/chrome/browser/resources/options/browser_options.html b/chrome/browser/resources/options/browser_options.html
index 19a0c92..d6bfa99 100644
--- a/chrome/browser/resources/options/browser_options.html
+++ b/chrome/browser/resources/options/browser_options.html
@@ -27,18 +27,18 @@
   <section>
     <h3 i18n-content="sectionTitleAppearance"></h3>
     <div class="settings-row">
-      <if expr="pp_ifdef('chromeos')">
+<if expr="pp_ifdef('chromeos')">
       <button id="set-wallpaper" i18n-content="setWallpaper"
           guest-visibility="disabled"></button>
 </if>
-<if expr="not pp_ifdef('toolkit_views') and is_posix and not is_macosx">
+<if expr="not pp_ifdef('chromeos') and is_posix and not is_macosx">
       <button id="themes-gallery" i18n-content="themesGallery"></button>
-      <button id="themes-GTK-button"
-          i18n-content="themesGTKButton"></button>
+      <button id="themes-native-button"
+          i18n-content="themesNativeButton"></button>
       <button id="themes-reset"
           i18n-content="themesSetClassic"></button>
 </if>
-<if expr="pp_ifdef('toolkit_views') or is_win or is_macosx">
+<if expr="pp_ifdef('chromeos') or is_win or is_macosx">
       <button id="themes-gallery" i18n-content="themesGallery"></button>
       <button id="themes-reset" i18n-content="themesReset"></button>
 </if>
@@ -527,7 +527,7 @@
         </span>
       </div>
 <if expr="pp_ifdef('chromeos')">
-      <div class="checkbox" guest-visibility="disabled">
+      <div class="checkbox" id="disable-drive-row" guest-visibility="disabled">
         <span class="controlled-setting-with-label">
           <input id="drive-disabled" type="checkbox"
               pref="gdata.disabled"
@@ -645,22 +645,6 @@
       <div class="option-name">
         <div class="checkbox">
           <span class="controlled-setting-with-label">
-            <input id="accessibility-spoken-feedback-check"
-                pref="settings.accessibility" type="checkbox">
-            <span>
-              <label for="accessibility-spoken-feedback-check"
-                  i18n-content="accessibilitySpokenFeedback">
-              </label>
-              <span class="controlled-setting-indicator"
-                  pref="settings.accessibility">
-              </span>
-            </span>
-          </span>
-        </div>
-      </div>
-      <div class="option-name">
-        <div class="checkbox">
-          <span class="controlled-setting-with-label">
             <input id="accessibility-high-contrast-check"
                 pref="settings.a11y.high_contrast_enabled" type="checkbox">
             <span>
@@ -677,6 +661,22 @@
       <div class="option-name">
         <div class="checkbox">
           <span class="controlled-setting-with-label">
+            <input id="accessibility-spoken-feedback-check"
+                pref="settings.accessibility" type="checkbox">
+            <span>
+              <label for="accessibility-spoken-feedback-check"
+                  i18n-content="accessibilitySpokenFeedback">
+              </label>
+              <span class="controlled-setting-indicator"
+                  pref="settings.accessibility">
+              </span>
+            </span>
+          </span>
+        </div>
+      </div>
+      <div class="option-name">
+        <div class="checkbox">
+          <span class="controlled-setting-with-label">
             <input id="accessibility-screen-magnifier-check"
                 pref="settings.a11y.screen_magnifier" type="checkbox">
             <span>
diff --git a/chrome/browser/resources/options/browser_options.js b/chrome/browser/resources/options/browser_options.js
index 5e4a8fc..ec737b8 100644
--- a/chrome/browser/resources/options/browser_options.js
+++ b/chrome/browser/resources/options/browser_options.js
@@ -148,6 +148,13 @@
         chrome.send('themesReset');
       };
 
+      if (loadTimeData.getBoolean('profileIsManaged')) {
+        if ($('themes-GTK-button'))
+          $('themes-GTK-button').disabled = true;
+        $('themes-reset').disabled = true;
+        $('themes-gallery').disabled = true;
+      }
+
       // Device section (ChromeOS only).
       if (cr.isChromeOS) {
         $('keyboard-settings-button').onclick = function(evt) {
@@ -231,9 +238,9 @@
           chrome.send('coreOptionsUserMetricsAction', ['Import_ShowDlg']);
         };
 
-        if ($('themes-GTK-button')) {
-          $('themes-GTK-button').onclick = function(event) {
-            chrome.send('themesSetGTK');
+        if ($('themes-native-button')) {
+          $('themes-native-button').onclick = function(event) {
+            chrome.send('themesSetNative');
           };
         }
       }
@@ -378,6 +385,9 @@
         $('autoOpenFileTypesResetToDefault').onclick = function(event) {
           chrome.send('autoOpenFileTypesAction');
         };
+      } else {
+        $('disable-drive-row').hidden =
+            UIAccountTweaks.loggedInAsLocallyManagedUser();
       }
 
       // HTTPS/SSL section.
@@ -1072,7 +1082,7 @@
     },
 
     /**
-    * Reports a remote error (e.g., a network error during limited-user
+    * Reports a remote error (e.g., a network error during managed-user
     * registration) to the "create" overlay during profile creation.
     * @private
     */
@@ -1110,9 +1120,10 @@
              'There should always be a current profile, but none found.');
     },
 
-    setGtkThemeButtonEnabled_: function(enabled) {
-      if (!cr.isChromeOS && navigator.platform.match(/linux|BSD/i))
-        $('themes-GTK-button').disabled = !enabled;
+    setNativeThemeButtonEnabled_: function(enabled) {
+      var button = $('themes-native-button');
+      if (button)
+        button.disabled = !enabled;
     },
 
     setThemesResetButtonEnabled_: function(enabled) {
@@ -1461,7 +1472,7 @@
     'setAutoOpenFileTypesDisplayed',
     'setBluetoothState',
     'setFontSize',
-    'setGtkThemeButtonEnabled',
+    'setNativeThemeButtonEnabled',
     'setHighContrastCheckboxState',
     'setMetricsReportingCheckboxState',
     'setMetricsReportingSettingVisibility',
diff --git a/chrome/browser/resources/options/chromeos/2x/warning.png b/chrome/browser/resources/options/chromeos/2x/warning.png
index ac7f050..b28ab36 100644
--- a/chrome/browser/resources/options/chromeos/2x/warning.png
+++ b/chrome/browser/resources/options/chromeos/2x/warning.png
Binary files differ
diff --git a/chrome/browser/resources/options/chromeos/accounts_user_name_edit.js b/chrome/browser/resources/options/chromeos/accounts_user_name_edit.js
index e6e5276..27580e3 100644
--- a/chrome/browser/resources/options/chromeos/accounts_user_name_edit.js
+++ b/chrome/browser/resources/options/chromeos/accounts_user_name_edit.js
@@ -51,7 +51,7 @@
       this.pattern = format1String + '|' + format2String + '|' +
                      format3String;
 
-      this.onkeypress = this.handleKeyPress_.bind(this);
+      this.onkeydown = this.handleKeyDown_.bind(this);
     },
 
 
@@ -104,21 +104,21 @@
     },
 
     /**
-     * Handler for key press event.
+     * Handler for key down event.
      * @private
-     * @param {!Event} e The keypress event object.
+     * @param {!Event} e The keydown event object.
      */
-    handleKeyPress_: function(e) {
-      // Enter
-      if (e.keyCode == 13) {
+    handleKeyDown_: function(e) {
+      if (e.keyIdentifier == 'Enter') {
         var user = this.parse(this.value);
         if (user) {
-          var e = new Event('add');
-          e.user = user;
-          this.dispatchEvent(e);
+          var event = new Event('add');
+          event.user = user;
+          this.dispatchEvent(event);
         }
-
         this.select();
+        // Avoid double-handling so the dialog doesn't close.
+        e.stopPropagation();
       }
     }
   };
diff --git a/chrome/browser/resources/options/chromeos/internet_detail.html b/chrome/browser/resources/options/chromeos/internet_detail.html
index c5287c3..893dbdd 100644
--- a/chrome/browser/resources/options/chromeos/internet_detail.html
+++ b/chrome/browser/resources/options/chromeos/internet_detail.html
@@ -596,8 +596,8 @@
                 </td>
                 <td>
                   <span i18n-content="proxyPort"></span>
-                  <input id="proxy-host-single-port" type="text" data-type="number"
-                      size="4" pref="cros.session.proxy.singlehttpport" disabled>
+                  <input id="proxy-host-single-port" size="4"
+                      pref="cros.session.proxy.singlehttpport" disabled>
                 </td>
               </tr>
             </table>
@@ -616,8 +616,8 @@
                   <span i18n-content="proxyPort"></span>
                 </td>
                 <td>
-                  <input id="proxy-host-port" type="text" data-type="number"
-                       size="4" pref="cros.session.proxy.httpport" disabled>
+                  <input id="proxy-host-port" size="4"
+                      pref="cros.session.proxy.httpport" disabled>
                 </td>
               </tr>
               <tr>
@@ -632,8 +632,8 @@
                   <span i18n-content="proxyPort"></span>
                 </td>
                 <td>
-                  <input id="secure-proxy-port" type="text" data-type="number"
-                       size="4" pref="cros.session.proxy.httpsport" disabled>
+                  <input id="secure-proxy-port" size="4"
+                      pref="cros.session.proxy.httpsport" disabled>
                 </td>
               </tr>
               <tr>
@@ -648,8 +648,8 @@
                   <span i18n-content="proxyPort"></span>
                   </td>
                 <td>
-                  <input id="ftp-proxy-port" type="text" data-type="number"
-                       size="4" pref="cros.session.proxy.ftpport" disabled>
+                  <input id="ftp-proxy-port" size="4"
+                      pref="cros.session.proxy.ftpport" disabled>
                 </td>
               </tr>
               <tr>
@@ -664,7 +664,7 @@
                   <span i18n-content="proxyPort"></span>
                 </td>
                 <td>
-                  <input id="socks-port" type="text" data-type="number" size="4"
+                  <input id="socks-port" size="4"
                       pref="cros.session.proxy.socksport" disabled>
                 </td>
               </tr>
diff --git a/chrome/browser/resources/options/chromeos/internet_detail.js b/chrome/browser/resources/options/chromeos/internet_detail.js
index 6436c5a..4ff8dac 100644
--- a/chrome/browser/resources/options/chromeos/internet_detail.js
+++ b/chrome/browser/resources/options/chromeos/internet_detail.js
@@ -252,6 +252,15 @@
       });
 
       // Proxy
+      ['proxy-host-single-port',
+       'secure-proxy-port',
+       'socks-port',
+       'ftp-proxy-port',
+       'proxy-host-port'
+      ].forEach(function(id) {
+        options.PrefPortNumber.decorate($(id));
+      });
+
       options.proxyexceptions.ProxyExceptions.decorate($('ignored-host-list'));
       $('remove-host').addEventListener('click',
                                         this.handleRemoveProxyExceptions_);
diff --git a/chrome/browser/resources/options/chromeos/overscan_arrows.png b/chrome/browser/resources/options/chromeos/overscan_arrows.png
index 03ad12f..6f3e394 100644
--- a/chrome/browser/resources/options/chromeos/overscan_arrows.png
+++ b/chrome/browser/resources/options/chromeos/overscan_arrows.png
Binary files differ
diff --git a/chrome/browser/resources/options/chromeos/overscan_arrows_2x.png b/chrome/browser/resources/options/chromeos/overscan_arrows_2x.png
index 470c0f0..10171c6 100644
--- a/chrome/browser/resources/options/chromeos/overscan_arrows_2x.png
+++ b/chrome/browser/resources/options/chromeos/overscan_arrows_2x.png
Binary files differ
diff --git a/chrome/browser/resources/options/chromeos/overscan_shift.png b/chrome/browser/resources/options/chromeos/overscan_shift.png
index a5664c8..acdfa07 100644
--- a/chrome/browser/resources/options/chromeos/overscan_shift.png
+++ b/chrome/browser/resources/options/chromeos/overscan_shift.png
Binary files differ
diff --git a/chrome/browser/resources/options/chromeos/overscan_shift_2x.png b/chrome/browser/resources/options/chromeos/overscan_shift_2x.png
index 9391dc7..7d23fdf 100644
--- a/chrome/browser/resources/options/chromeos/overscan_shift_2x.png
+++ b/chrome/browser/resources/options/chromeos/overscan_shift_2x.png
Binary files differ
diff --git a/chrome/browser/resources/options/chromeos/overscan_shift_rtl.png b/chrome/browser/resources/options/chromeos/overscan_shift_rtl.png
index fc2f9ca..0ca89a2 100644
--- a/chrome/browser/resources/options/chromeos/overscan_shift_rtl.png
+++ b/chrome/browser/resources/options/chromeos/overscan_shift_rtl.png
Binary files differ
diff --git a/chrome/browser/resources/options/chromeos/overscan_shift_rtl_2x.png b/chrome/browser/resources/options/chromeos/overscan_shift_rtl_2x.png
index 0e3909f..fb89e2f 100644
--- a/chrome/browser/resources/options/chromeos/overscan_shift_rtl_2x.png
+++ b/chrome/browser/resources/options/chromeos/overscan_shift_rtl_2x.png
Binary files differ
diff --git a/chrome/browser/resources/options/chromeos/warning.png b/chrome/browser/resources/options/chromeos/warning.png
index 18c5821..53713ba 100644
--- a/chrome/browser/resources/options/chromeos/warning.png
+++ b/chrome/browser/resources/options/chromeos/warning.png
Binary files differ
diff --git a/chrome/browser/resources/options/content_settings.js b/chrome/browser/resources/options/content_settings.js
index eeaec37..81f111d 100644
--- a/chrome/browser/resources/options/content_settings.js
+++ b/chrome/browser/resources/options/content_settings.js
@@ -29,8 +29,6 @@
     initializePage: function() {
       OptionsPage.prototype.initializePage.call(this);
 
-      chrome.send('getContentFilterSettings');
-
       var exceptionsButtons =
           this.pageDiv.querySelectorAll('.exceptions-list-button');
       for (var i = 0; i < exceptionsButtons.length; i++) {
diff --git a/chrome/browser/resources/options/language_options.css b/chrome/browser/resources/options/language_options.css
index 6a6eb46..21817c9 100644
--- a/chrome/browser/resources/options/language_options.css
+++ b/chrome/browser/resources/options/language_options.css
@@ -8,7 +8,7 @@
 }
 
 .language-options-lower-left button,
-.language-options-right button {
+#language-options-details button {
   min-width: 70px;
 }
 
@@ -37,22 +37,17 @@
   margin: 10px 0;
 }
 
-.language-options-left,
-.language-options-right {
+#language-options-languages,
+#language-options-details {
   border: 1px solid #ccc;
   height: 400px;
   padding: 0;
   vertical-align: top;
 }
 
-.language-options-left {
+#language-options-languages {
   -webkit-box-orient: vertical;
-<if expr="not is_macosx">
   background-color: rgb(235, 239, 249);
-</if>
-<if expr="is_macosx">
-  background-color: white;
-</if>
   display: -webkit-box;
   width: 300px;
 }
@@ -63,13 +58,13 @@
   padding-bottom: 10px;
 }
 
-.language-options-right {
+#language-options-details {
   /* To share the center line with the left pane. */
   -webkit-margin-start: -1px;
   width: 360px;
 }
 
-.language-options-right h3:not(:first-of-type) {
+#language-options-details h3:not(:first-of-type) {
   margin-top: 24px;
 }
 
@@ -127,6 +122,16 @@
   z-index: 10;
 }
 
+<if expr="is_macosx">
+.language-options[enabled='false'] #language-options-details {
+  display: none;
+}
+
+.language-options[enabled='false'] #language-options-languages {
+  background-color: transparent !important;
+}
+</if>
+
 /* TODO(kochi): This is temporary copy from new_tab.css */
 /* Notification */
 
diff --git a/chrome/browser/resources/options/language_options.html b/chrome/browser/resources/options/language_options.html
index 9a95eab..b9d77c4 100644
--- a/chrome/browser/resources/options/language_options.html
+++ b/chrome/browser/resources/options/language_options.html
@@ -12,8 +12,8 @@
       <div i18n-content="inputMethodInstructions"></div>
 </if>
     </div>
-    <div class="language-options">
-      <div class="language-options-left">
+    <div class="language-options" i18n-values="enabled:enableTranslateSettings">
+      <div id="language-options-languages">
         <h3 i18n-content="languages"></h3>
         <list id="language-options-list"></list>
         <div class="language-options-lower-left">
@@ -23,7 +23,7 @@
         </div>
         <div id="language-options-list-dropmarker"></div>
       </div>
-      <div class="language-options-right">
+      <div id="language-options-details">
         <h3 id="language-options-language-name"></h3>
 <if expr="os == 'win32' or pp_ifdef('chromeos')">
         <div class="language-options-contents">
diff --git a/chrome/browser/resources/options/language_options.js b/chrome/browser/resources/options/language_options.js
index de7e6a1..5250ced 100644
--- a/chrome/browser/resources/options/language_options.js
+++ b/chrome/browser/resources/options/language_options.js
@@ -58,7 +58,7 @@
    * @type {string}
    * @const
    */
-  var TRANSLATE_LANGUAGE_BLACKLIST_PREF = 'translate_language_blacklist';
+  var TRANSLATE_BLOCKED_LANGUAGES_PREF = 'translate_blocked_languages';
 
   /**
    * The preference key that is a string that describes the spell check
@@ -127,7 +127,7 @@
      * @type {Array}
      * @private
      */
-    translateLanguageBlacklist_: [],
+    translateBlockedLanguages_: [],
 
     /**
      * The list of the languages supported by Translate server
@@ -186,8 +186,8 @@
           this.handleDontTranslateCheckboxClick_.bind(this));
 
       Preferences.getInstance().addEventListener(
-          TRANSLATE_LANGUAGE_BLACKLIST_PREF,
-          this.handleTranslateLanguageBlacklistPrefChange_.bind(this));
+          TRANSLATE_BLOCKED_LANGUAGES_PREF,
+          this.handleTranslateBlockedLanguagesPrefChange_.bind(this));
       Preferences.getInstance().addEventListener(SPELL_CHECK_DICTIONARY_PREF,
           this.handleSpellCheckDictionaryPrefChange_.bind(this));
       this.translateSupportedLanguages_ =
@@ -201,10 +201,11 @@
         if (match) {
           var addLanguageCode = match[1];
           $('language-options-list').addLanguage(addLanguageCode);
+          this.addBlockedLanguage_(addLanguageCode);
         } else {
           OptionsPage.navigateToPage('addLanguage');
         }
-      };
+      }.bind(this);
 
       if (!cr.isMac) {
         // Set up the button for editing custom spelling dictionary.
@@ -366,6 +367,42 @@
     },
 
     /**
+     * Adds a language to the preference 'translate_blocked_languages'. If
+     * |langCode| is already added, nothing happens. |langCode| is converted
+     * to a Translate language synonym before added.
+     * @param {string} langCode A language code like 'en'
+     * @private
+     */
+    addBlockedLanguage_: function(langCode) {
+      langCode = this.convertLangCodeForTranslation_(langCode);
+      if (this.translateBlockedLanguages_.indexOf(langCode) == -1) {
+        this.translateBlockedLanguages_.push(langCode);
+        Preferences.setListPref(TRANSLATE_BLOCKED_LANGUAGES_PREF,
+                                this.translateBlockedLanguages_, true);
+      }
+    },
+
+    /**
+     * Removes a language from the preference 'translate_blocked_languages'.
+     * If |langCode| doesn't exist in the preference, nothing happens.
+     * |langCode| is converted to a Translate language synonym before removed.
+     * @param {string} langCode A language code like 'en'
+     * @private
+     */
+    removeBlockedLanguage_: function(langCode) {
+      langCode = this.convertLangCodeForTranslation_(langCode);
+      if (this.translateBlockedLanguages_.indexOf(langCode) != -1) {
+        this.translateBlockedLanguages_ =
+            this.translateBlockedLanguages_.filter(
+                function(langCodeNotTranslated) {
+                  return langCodeNotTranslated != langCode;
+                });
+        Preferences.setListPref(TRANSLATE_BLOCKED_LANGUAGES_PREF,
+                                this.translateBlockedLanguages_, true);
+      }
+    },
+
+    /**
      * Handles OptionsPage's visible property change event.
      * @param {Event} e Property change event.
      * @private
@@ -670,8 +707,22 @@
       }
 
       var checkbox = $('dont-translate-in-this-language');
-      var blacklist = this.translateLanguageBlacklist_;
-      var checked = blacklist.indexOf(convertedLangCode) != -1;
+
+      // If the language corresponds to the default target language (in most
+      // cases, the user's locale language), "Don't Translate" checkbox should
+      // be always checked.
+      var defaultTargetLanguage =
+          loadTimeData.getString('defaultTargetLanguage');
+      if (convertedLangCode == defaultTargetLanguage) {
+        checkbox.disabled = true;
+        checkbox.checked = true;
+        return;
+      }
+
+      checkbox.disabled = false;
+
+      var blockedLanguages = this.translateBlockedLanguages_;
+      var checked = blockedLanguages.indexOf(convertedLangCode) != -1;
       checkbox.checked = checked;
     },
 
@@ -781,19 +832,10 @@
       var languageOptionsList = $('language-options-list');
       var selectedLanguageCode = languageOptionsList.getSelectedLanguageCode();
 
-      var langCode = this.convertLangCodeForTranslation_(selectedLanguageCode);
-      var blacklist = this.translateLanguageBlacklist_;
-      if (checked && blacklist.indexOf(langCode) == -1) {
-        blacklist.push(langCode);
-      } else if (!checked && blacklist.indexOf(langCode) != -1) {
-        blacklist = blacklist.filter(function(blacklistedLangCode) {
-          return blacklistedLangCode != langCode;
-        });
-      }
-      this.translateLanguageBlacklist_ = blacklist;
-
-      Preferences.setListPref(TRANSLATE_LANGUAGE_BLACKLIST_PREF,
-                              this.translateLanguageBlacklist_, true);
+      if (checked)
+        this.addBlockedLanguage_(selectedLanguageCode);
+      else
+        this.removeBlockedLanguage_(selectedLanguageCode);
     },
 
     /**
@@ -832,7 +874,9 @@
       var selectedIndex = languagesSelect.selectedIndex;
       if (selectedIndex >= 0) {
         var selection = languagesSelect.options[selectedIndex];
-        $('language-options-list').addLanguage(String(selection.value));
+        var langCode = String(selection.value);
+        $('language-options-list').addLanguage(langCode);
+        this.addBlockedLanguage_(langCode);
         OptionsPage.closeOverlay();
       }
     },
@@ -862,15 +906,14 @@
      },
 
     /**
-     * Handles translateLanguageBlacklistPref change.
+     * Handles translateBlockedLanguagesPref change.
      * @param {Event} e Change event.
      * @private
      */
-    handleTranslateLanguageBlacklistPrefChange_: function(e) {
+    handleTranslateBlockedLanguagesPrefChange_: function(e) {
       var languageOptionsList = $('language-options-list');
       var selectedLanguageCode = languageOptionsList.getSelectedLanguageCode();
-      this.translateLanguageBlacklist_ = e.value.value;
-
+      this.translateBlockedLanguages_ = e.value.value;
       this.updateDontTranslateCheckbox_(selectedLanguageCode);
     },
 
diff --git a/chrome/browser/resources/options/manage_profile_overlay.css b/chrome/browser/resources/options/manage_profile_overlay.css
index 9596ba3..5b5f093 100644
--- a/chrome/browser/resources/options/manage_profile_overlay.css
+++ b/chrome/browser/resources/options/manage_profile_overlay.css
@@ -102,20 +102,25 @@
   -webkit-margin-end: 10px;
 }
 
-#delete-profile-message {
+#delete-profile-message,
+#delete-managed-profile-addendum {
   -webkit-padding-start: 48px;
   background-repeat: no-repeat;
 }
 
+#delete-managed-profile-addendum {
+  margin-top: 10px;
+}
+
 html[dir='rtl'] #delete-profile-message {
   background-position: right;
 }
 
-#create-profile-limited-not-signed-in {
+#create-profile-managed-not-signed-in {
   color: #999;
 }
 
-#create-profile-limited-not-signed-in-label {
+#create-profile-managed-not-signed-in-label {
   white-space: pre-wrap;
   word-wrap: break-word;
 }
diff --git a/chrome/browser/resources/options/manage_profile_overlay.html b/chrome/browser/resources/options/manage_profile_overlay.html
index f4acc97..39cf3f6 100644
--- a/chrome/browser/resources/options/manage_profile_overlay.html
+++ b/chrome/browser/resources/options/manage_profile_overlay.html
@@ -39,6 +39,9 @@
     <h1 i18n-content="deleteProfileTitle"></h1>
     <div class="content-area">
       <div id="delete-profile-message"></div>
+      <div id="delete-managed-profile-addendum"
+          i18n-values=".innerHTML:deleteManagedProfileAddendum" hidden>
+      </div>
     </div>
     <div class="action-area button-strip">
       <button id="delete-profile-cancel" i18n-content="cancel"></button>
@@ -71,25 +74,28 @@
           </span>
         </label>
       </div>
-      <div id="create-profile-limited-container" class="checkbox" hidden>
+      <div id="create-profile-managed-container" class="checkbox" hidden>
         <label>
-          <input id="create-profile-limited" type="checkbox">
-          <span id="create-profile-limited-signed-in">
-            <span id="create-profile-limited-signed-in-label"></span>
-            <button id="create-profile-limited-signed-in-link"
+          <input id="create-profile-managed" type="checkbox">
+          <span id="create-profile-managed-signed-in">
+            <span id="create-profile-managed-signed-in-label"></span>
+            <button id="create-profile-managed-signed-in-link"
                 class="link-button" i18n-content="learnMore">
             </button>
           </span>
-          <span id="create-profile-limited-not-signed-in" hidden>
-            <span id="create-profile-limited-not-signed-in-label"
-                i18n-content="manageProfilesLimitedNotSignedInLabel">
+          <span id="create-profile-managed-not-signed-in" hidden>
+            <span id="create-profile-managed-not-signed-in-label"
+                i18n-content="manageProfilesManagedNotSignedInLabel">
             </span>
-            <button id="create-profile-limited-not-signed-in-link"
+            <button id="create-profile-managed-not-signed-in-link"
                 class="link-button"
-                i18n-content="manageProfilesLimitedNotSignedInLink">
+                i18n-content="manageProfilesManagedNotSignedInLink">
             </button>
           </span>
         </label>
+        <span id="create-profile-managed-indicator"
+            class="bubble-button controlled-setting-indicator">
+        </span>
       </div>
     </div>
     <div class="action-area">
diff --git a/chrome/browser/resources/options/manage_profile_overlay.js b/chrome/browser/resources/options/manage_profile_overlay.js
index b3b83d4..d27a979 100644
--- a/chrome/browser/resources/options/manage_profile_overlay.js
+++ b/chrome/browser/resources/options/manage_profile_overlay.js
@@ -59,8 +59,9 @@
       };
 
       if (loadTimeData.getBoolean('managedUsersEnabled')) {
-        $('create-profile-limited-container').hidden = false;
+        $('create-profile-managed-container').hidden = false;
       }
+
       $('manage-profile-cancel').onclick =
           $('delete-profile-cancel').onclick = function(event) {
         OptionsPage.closeOverlay();
@@ -76,12 +77,12 @@
         chrome.send('removeProfileShortcut', [self.profileInfo_.filePath]);
       };
 
-      $('create-profile-limited-signed-in-link').onclick = function(event) {
+      $('create-profile-managed-signed-in-link').onclick = function(event) {
         OptionsPage.navigateToPage('managedUserLearnMore');
         return false;
       };
 
-      $('create-profile-limited-not-signed-in-link').onclick = function(event) {
+      $('create-profile-managed-not-signed-in-link').onclick = function(event) {
         // The signin process will open an overlay to configure sync, which
         // would replace this overlay. It's smoother to close this one now.
         // TODO(pamg): Move the sync-setup overlay to a higher layer so this one
@@ -143,8 +144,9 @@
      *     profileInfo = {
      *       name: "Profile Name",
      *       iconURL: "chrome://path/to/icon/image",
-     *       filePath: "/path/to/profile/data/on/disk"
+     *       filePath: "/path/to/profile/data/on/disk",
      *       isCurrentProfile: false,
+     *       isManaged: false
      *     };
      * @param {string} mode A label that specifies the type of dialog
      *     box which is currently being viewed (i.e. 'create' or
@@ -308,7 +310,7 @@
       var name = $('create-profile-name').value;
       var iconUrl = $('create-profile-icon-grid').selectedItem;
       var createShortcut = $('create-shortcut').checked;
-      var isManaged = $('create-profile-limited').checked;
+      var isManaged = $('create-profile-managed').checked;
 
       // 'createProfile' is handled by the BrowserOptionsHandler.
       chrome.send('createProfile',
@@ -370,6 +372,7 @@
           loadTimeData.getStringF('deleteProfileMessage', profileInfo.name);
       $('delete-profile-message').style.backgroundImage = 'url("' +
           profileInfo.iconURL + '")';
+      $('delete-managed-profile-addendum').hidden = !profileInfo.isManaged;
 
       // Because this dialog isn't useful when refreshing or as part of the
       // history, don't create a history entry for it when showing.
@@ -415,12 +418,16 @@
     // Inherit from ManageProfileOverlay.
     __proto__: ManageProfileOverlay.prototype,
 
+    // The signed-in email address of the current profile, or empty if they're
+    // not signed in.
+    signedInEmail_: '',
+
     /**
      * Configures the overlay to the "create user" mode.
      * @override
      */
     didShowPage: function() {
-      chrome.send('requestSignedInText');
+      chrome.send('requestCreateProfileUpdate');
       chrome.send('requestDefaultProfileIcons');
       chrome.send('requestNewProfileDefaults');
 
@@ -439,6 +446,9 @@
       $('create-profile-name-label').hidden = true;
       $('create-profile-name').hidden = true;
       $('create-profile-ok').disabled = true;
+      $('create-profile-managed-signed-in').disabled = true;
+      $('create-profile-managed-signed-in').hidden = true;
+      $('create-profile-managed-not-signed-in').hidden = true;
     },
 
     /** @override */
@@ -470,7 +480,7 @@
       $('create-profile-icon-grid').disabled = inProgress;
       $('create-profile-name').disabled = inProgress;
       $('create-shortcut').disabled = inProgress;
-      $('create-profile-limited').disabled = inProgress;
+      $('create-profile-managed').disabled = inProgress;
       $('create-profile-ok').disabled = inProgress;
 
       $('create-profile-throbber').hidden = !inProgress;
@@ -511,7 +521,7 @@
     },
 
     /**
-     * For new limited users, shows a confirmation page after successfully
+     * For new supervised users, shows a confirmation page after successfully
      * creating a new profile; otherwise, the handler will open a new window.
      * @param {Object} profileInfo An object of the form:
      *     profileInfo = {
@@ -525,6 +535,7 @@
       this.updateCreateInProgress_(false);
       OptionsPage.closeOverlay();
       if (profileInfo.isManaged) {
+        profileInfo.custodianEmail = this.signedInEmail_;
         ManagedUserCreateConfirmOverlay.setProfileInfo(profileInfo);
         OptionsPage.navigateToPage('managedUserCreateConfirm');
       }
@@ -532,20 +543,47 @@
 
     /**
      * Updates the signed-in or not-signed-in UI when in create mode. Called by
-     * the handler in response to the 'requestSignedInText' message.
-     * @param {string} text The text to show for a signed-in user. An empty
-     *     string indicates that the user is not signed in.
+     * the handler in response to the 'requestCreateProfileUpdate' message.
+     * @param {string} email The email address of the currently signed-in user.
+     *     An empty string indicates that the user is not signed in.
      * @private
      */
-    updateSignedInStatus_: function(text) {
-      var isSignedIn = text !== '';
-      $('create-profile-limited-signed-in').hidden = !isSignedIn;
-      $('create-profile-limited-not-signed-in').hidden = isSignedIn;
-      $('create-profile-limited').disabled = !isSignedIn;
-      if (!isSignedIn)
-        $('create-profile-limited').checked = false;
+    updateSignedInStatus_: function(email) {
+      this.signedInEmail_ = email;
+      var isSignedIn = email !== '';
+      $('create-profile-managed-signed-in').hidden = !isSignedIn;
+      $('create-profile-managed-not-signed-in').hidden = isSignedIn;
 
-      $('create-profile-limited-signed-in-label').textContent = text;
+      if (isSignedIn) {
+        $('create-profile-managed-signed-in-label').textContent =
+            loadTimeData.getStringF(
+                'manageProfilesManagedSignedInLabel', email);
+      } else {
+        $('create-profile-managed').checked = false;
+      }
+    },
+
+    /**
+     * Updates the status of the "create managed user" checkbox. Called by the
+     * handler in response to the 'requestCreateProfileUpdate' message or a
+     * change in the (policy-controlled) pref that prohibits creating managed
+     * users, after the signed-in status has been updated.
+     * @param {boolean} allowed True if creating managed users should be
+     *     allowed.
+     * @private
+     */
+    updateManagedUsersAllowed_: function(allowed) {
+      var isSignedIn = this.signedInEmail_ !== '';
+      $('create-profile-managed').disabled = !isSignedIn || !allowed;
+
+      $('create-profile-managed-not-signed-in-link').hidden = !allowed;
+      if (!allowed) {
+        $('create-profile-managed').checked = false;
+        $('create-profile-managed-indicator').setAttribute('controlled-by',
+                                                           'policy');
+      } else {
+        $('create-profile-managed-indicator').removeAttribute('controlled-by');
+      }
     },
   };
 
@@ -556,6 +594,7 @@
     'onRemoteError',
     'onSuccess',
     'updateCreateInProgress',
+    'updateManagedUsersAllowed',
     'updateSignedInStatus',
   ].forEach(function(name) {
     CreateProfileOverlay[name] = function() {
diff --git a/chrome/browser/resources/options/managed_user.png b/chrome/browser/resources/options/managed_user.png
index 1c3446a..e84d850 100644
--- a/chrome/browser/resources/options/managed_user.png
+++ b/chrome/browser/resources/options/managed_user.png
Binary files differ
diff --git a/chrome/browser/resources/options/managed_user_create_confirm.css b/chrome/browser/resources/options/managed_user_create_confirm.css
index 425b103..718d346 100644
--- a/chrome/browser/resources/options/managed_user_create_confirm.css
+++ b/chrome/browser/resources/options/managed_user_create_confirm.css
@@ -3,110 +3,18 @@
  * found in the LICENSE file. */
 
 #managed-user-created {
-  width: 612px;
+  width: 722px;
 }
 
-/* Carousel slides. The way the carousel works is by looking at the currently
- * selected radio box, which tells us which slide is visible now. */
+#managed-user-created-image {
+  background-image: -webkit-image-set(
+      url('../../../../ui/resources/default_100_percent/supervised_illustration_done.png') 1x,
+      url('../../../../ui/resources/default_200_percent/supervised_illustration_done.png') 2x);
+  height: 344px;
+}
 
-.managed-user-created-slide-text {
+#managed-user-created-text {
   margin-top: 10px;
   white-space: pre-wrap;
   word-wrap: break-word;
 }
-
-.managed-user-created-slide-image {
-  height: 177px;  /* Placeholder value */
-}
-
-.managed-user-created-slide:nth-child(1) .managed-user-created-slide-image {
-  background-image: url('managed_user_create_confirm_1.png');
-}
-
-.managed-user-created-slide:nth-child(2) .managed-user-created-slide-image {
-  background-image: url('managed_user_create_confirm_2.png');
-}
-
-.managed-user-created-slide:nth-child(3) .managed-user-created-slide-image {
-  background-image: url('managed_user_create_confirm_3.png');
-}
-
-/* Need to be adjusted to the number of slides. */
-#managed-user-created-slide-deck {
-  /* Number of slides multiplied by 100%. */
-  width: 300%;
-}
-
-#managed-user-created-slide-deck .managed-user-created-slide {
-  float: left;
-  /* 100% divided by number of slides. */
-  width: 33.334%;
-}
-
-#managed-user-created-viewport {
-  overflow: hidden;
-  width: 100%;
-}
-
-html[dir='rtl'] #managed-user-created-slide-deck .managed-user-created-slide {
-  float: right;
-}
-
-.content-area #managed-user-created-slide-deck {
-  -webkit-transition: all 750ms cubic-bezier(0.75, 0.00, 0.25, 1.00);
-}
-
-/* The small circular buttons/indicators. They are labels for the radio boxes
- * that control the slides, so clicking them will actually check the proper
- * radio box for that slide and change the slide. */
-
-#managed-user-created-small-buttons {
-  -webkit-box-flex: 1;
-  -webkit-margin-start: 274px;
-}
-
-#managed-user-created-small-buttons button {
-  background: rgb(186, 186, 186);
-  border-radius: 4px;
-  border-width: 0;
-  display: inline-block;
-  min-height: 8px;
-  min-width: 8px;
-  padding: 0;
-}
-
-#managed-user-created-small-buttons
-    .managed-user-created-small-button-selected {
-  background: rgb(67, 67, 67);
-}
-
-/* Next and previous arrows. */
-
-#managed-user-created-slide-arrows {
-  height: 30px;
-  position: absolute;
-  /* Needs to be adjusted according to the slide image size. */
-  top: 122px;
-  width: 100%;
-}
-
-#managed-user-created-slide-arrows button {
-  border-radius: 15px;
-  border-width: 0;
-  box-shadow: none;
-  height: 30px;
-  min-height: 30px;
-  min-width: 30px;
-  width: 30px;
-}
-
-#managed-user-created-left-slide-arrow {
-  -webkit-transform: scaleX(-1);
-  background: url('arrow_next.png') no-repeat center, white;
-  float: left;
-}
-
-#managed-user-created-right-slide-arrow {
-  background: url('arrow_next.png') no-repeat center, white;
-  float: right;
-}
diff --git a/chrome/browser/resources/options/managed_user_create_confirm.html b/chrome/browser/resources/options/managed_user_create_confirm.html
index e7fdd1f..c7c9b90 100644
--- a/chrome/browser/resources/options/managed_user_create_confirm.html
+++ b/chrome/browser/resources/options/managed_user_create_confirm.html
@@ -1,40 +1,14 @@
 <div id="managed-user-created" class="page" hidden>
   <div class="close-button"></div>
-  <!-- Overlay for the confirmation after creating a limited user. -->
+  <!-- Overlay for the confirmation after creating a supervised user. -->
   <h1 id="managed-user-created-title"></h1>
   <div class="content-area">
-    <div id="managed-user-created-viewport">
-      <div id="managed-user-created-slide-deck">
-        <div class="managed-user-created-slide">
-          <div class="managed-user-created-slide-image"></div>
-          <div class="managed-user-created-slide-text"
-              i18n-values=".innerHTML:managedUserCreateConfirmTextSlide1">
-          </div>
-        </div>
-        <div class="managed-user-created-slide">
-          <div class="managed-user-created-slide-image"></div>
-          <div class="managed-user-created-slide-text"
-              i18n-values=".innerHTML:managedUserCreateConfirmTextSlide2">
-          </div>
-        </div>
-        <div class="managed-user-created-slide">
-          <div class="managed-user-created-slide-image"></div>
-          <div class="managed-user-created-slide-text"
-              i18n-values=".innerHTML:managedUserCreateConfirmTextSlide3">
-          </div>
-        </div>
-      </div>
-    </div>
-  </div>
-  <div id="managed-user-created-slide-arrows">
-    <button id="managed-user-created-left-slide-arrow"></button>
-    <button id="managed-user-created-right-slide-arrow"></button>
+    <div id="managed-user-created-image"></div>
+    <div id="managed-user-created-text"></div>
   </div>
   <div class="action-area button-strip">
-    <div id="managed-user-created-small-buttons">
-    </div>
     <button id="managed-user-created-done"
-        i18n-content="managedUserCreateConfirmDone">
+        i18n-content="managedUserCreatedDone">
     </button>
     <button id="managed-user-created-switch"></button>
   </div>
diff --git a/chrome/browser/resources/options/managed_user_create_confirm.js b/chrome/browser/resources/options/managed_user_create_confirm.js
index 77374d4..88e4701 100644
--- a/chrome/browser/resources/options/managed_user_create_confirm.js
+++ b/chrome/browser/resources/options/managed_user_create_confirm.js
@@ -27,9 +27,6 @@
     // Info about the newly created profile.
     profileInfo_: null,
 
-    // Current shown slide.
-    currentSlide_: 0,
-
     /**
      * Initialize the page.
      */
@@ -46,80 +43,6 @@
         OptionsPage.closeOverlay();
         chrome.send('switchToProfile', [self.profileInfo_.filePath]);
       };
-
-      // Create a small dot button for each slide in the deck and make the
-      // first button active.
-      var numberOfSlides = $('managed-user-created-slide-deck').children.length;
-      for (var i = 0; i < numberOfSlides; i++) {
-        var smallButton = document.createElement('button');
-        $('managed-user-created-small-buttons').appendChild(smallButton);
-        smallButton.onclick = this.setCurrentSlide_.bind(this, i);
-      }
-      $('managed-user-created-small-buttons').children[0].classList.add(
-          'managed-user-created-small-button-selected');
-
-      // Changes the slide in |direction|, where |direction| can be 'Left' or
-      // 'Right'. Changing to the left goes back in LTR and forward in RTL and
-      // vice versa for right.
-      function changeSlide(direction) {
-        // Ignore all events we get while not visible.
-        if (!self.visible)
-          return;
-
-        // Ignore anything other than left and right arrow press.
-        if (direction != 'Left' && direction != 'Right')
-          return;
-
-        var container = $('managed-user-created');
-        var rtl = getComputedStyle(container).direction == 'rtl';
-
-        if ((direction == 'Right' && !rtl) || (direction == 'Left' && rtl))
-          self.setCurrentSlide_(self.currentSlide_ + 1);
-        else
-          self.setCurrentSlide_(self.currentSlide_ - 1);
-      };
-
-      $('managed-user-created-left-slide-arrow').onclick =
-          changeSlide.bind(undefined, 'Left');
-      $('managed-user-created-right-slide-arrow').onclick =
-          changeSlide.bind(undefined, 'Right');
-
-      document.onkeydown = function(event) {
-        changeSlide(event.keyIdentifier);
-      };
-    },
-
-    /**
-     * Reset to slide 1 for the next time this gets opened.
-     * @override
-     */
-    didShowPage: function() {
-      this.setCurrentSlide_(0);
-    },
-
-    /**
-     * Sets the current visible slide to |slide|, where |slide| is the index
-     * and starts from 0.
-     * @param {number} slide The slide to set.
-     * @private
-     */
-    setCurrentSlide_: function(slide) {
-      var numberOfSlides =
-          $('managed-user-created-slide-deck').children.length;
-      var newSlide = (numberOfSlides + slide) % numberOfSlides;
-      // Show the respective slide. The slide is shown by setting the
-      // appropriate negative margin on the slide deck.
-      var margin = '0';
-      if (slide != 0)
-        margin = '-' + newSlide * 100 + '%';
-      $('managed-user-created-slide-deck').style.webkitMarginStart = margin;
-
-      // Update the bottom buttons.
-      $('managed-user-created-small-buttons').children[this.currentSlide_]
-          .classList.toggle('managed-user-created-small-button-selected');
-      $('managed-user-created-small-buttons').children[newSlide]
-          .classList.toggle('managed-user-created-small-button-selected');
-      this.currentSlide_ = newSlide;
     },
 
     /**
@@ -129,17 +52,34 @@
      * @param {Object} info An object of the form:
      *     info = {
      *       name: "Profile Name",
-     *       filePath: "/path/to/profile/data/on/disk"
-     *       isManaged: (true|false),
+     *       filePath: "/path/to/profile/data/on/disk",
+     *       isManaged: (true|false)
+     *       custodianEmail: "example@gmail.com"
      *     };
      * @private
      */
     setProfileInfo_: function(info) {
+      function HTMLEscape(original) {
+        return original.replace(/&/g, '&amp;')
+                       .replace(/</g, '&lt;')
+                       .replace(/>/g, '&gt;')
+                       .replace(/"/g, '&quot;')
+                       .replace(/'/g, '&#39;');
+      }
+
       this.profileInfo_ = info;
       $('managed-user-created-title').textContent =
-          loadTimeData.getStringF('managedUserCreateConfirmTitle', info.name);
+          loadTimeData.getStringF('managedUserCreatedTitle', info.name);
       $('managed-user-created-switch').textContent =
-          loadTimeData.getStringF('managedUserCreateConfirmSwitch', info.name);
+          loadTimeData.getStringF('managedUserCreatedSwitch', info.name);
+
+      // HTML-escape the user-supplied strings before putting them into
+      // innerHTML. This is probably excessive for the email address, but
+      // belt-and-suspenders is cheap here.
+      $('managed-user-created-text').innerHTML =
+          loadTimeData.getStringF('managedUserCreatedText',
+                                  HTMLEscape(info.name),
+                                  HTMLEscape(info.custodianEmail));
     },
   };
 
diff --git a/chrome/browser/resources/options/managed_user_create_confirm.png b/chrome/browser/resources/options/managed_user_create_confirm.png
new file mode 100644
index 0000000..58c2331
--- /dev/null
+++ b/chrome/browser/resources/options/managed_user_create_confirm.png
Binary files differ
diff --git a/chrome/browser/resources/options/managed_user_create_confirm_1.png b/chrome/browser/resources/options/managed_user_create_confirm_1.png
deleted file mode 100644
index 7f40e88..0000000
--- a/chrome/browser/resources/options/managed_user_create_confirm_1.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/options/managed_user_create_confirm_2.png b/chrome/browser/resources/options/managed_user_create_confirm_2.png
deleted file mode 100644
index e230ba4..0000000
--- a/chrome/browser/resources/options/managed_user_create_confirm_2.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/options/managed_user_create_confirm_3.png b/chrome/browser/resources/options/managed_user_create_confirm_3.png
deleted file mode 100644
index 4bdbeec..0000000
--- a/chrome/browser/resources/options/managed_user_create_confirm_3.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/options/managed_user_learn_more.css b/chrome/browser/resources/options/managed_user_learn_more.css
index 6811487..79878ee 100644
--- a/chrome/browser/resources/options/managed_user_learn_more.css
+++ b/chrome/browser/resources/options/managed_user_learn_more.css
@@ -3,7 +3,7 @@
  * found in the LICENSE file. */
 
 #managed-user-learn-more {
-  width: 612px;
+  width: 722px;
 }
 
 #managed-user-learn-more-text {
@@ -13,6 +13,8 @@
 }
 
 #managed-user-learn-more-image {
-  background-image: url('managed_user_learn_more.png');
-  height: 177px;  /* Placeholder value */
+  background-image: -webkit-image-set(
+      url('../../../../ui/resources/default_100_percent/supervised_illustration_start.png') 1x,
+      url('../../../../ui/resources/default_200_percent/supervised_illustration_start.png') 2x);
+  height: 344px;
 }
diff --git a/chrome/browser/resources/options/managed_user_learn_more.html b/chrome/browser/resources/options/managed_user_learn_more.html
index f7cabe6..e0b2c62 100644
--- a/chrome/browser/resources/options/managed_user_learn_more.html
+++ b/chrome/browser/resources/options/managed_user_learn_more.html
@@ -1,6 +1,6 @@
 <div id="managed-user-learn-more" class="page" hidden>
   <div class="close-button"></div>
-  <!-- Overlay for the 'Learn more' link when creating a limited user. -->
+  <!-- Overlay for the 'Learn more' link when creating a supervised user. -->
   <h1 i18n-content="managedUserLearnMoreTitle"></h1>
   <div class="content-area">
     <div id="managed-user-learn-more-image"></div>
diff --git a/chrome/browser/resources/options/managed_user_learn_more.png b/chrome/browser/resources/options/managed_user_learn_more.png
index 4588ef5..8adc52a 100644
--- a/chrome/browser/resources/options/managed_user_learn_more.png
+++ b/chrome/browser/resources/options/managed_user_learn_more.png
Binary files differ
diff --git a/chrome/browser/resources/options/password_manager.html b/chrome/browser/resources/options/password_manager.html
index 9eae961..dfecba6 100644
--- a/chrome/browser/resources/options/password_manager.html
+++ b/chrome/browser/resources/options/password_manager.html
@@ -29,9 +29,7 @@
   </div>
   <div class="action-area">
     <div class="button-strip">
-        <button id="password-manager-confirm" class="default-button"
-            i18n-content="done">
-        </button>
+      <button id="password-manager-confirm" i18n-content="done"></button>
     </div>
   </div>
 </div>
diff --git a/chrome/browser/resources/options/pref_ui.js b/chrome/browser/resources/options/pref_ui.js
index dd33c72..1970800 100644
--- a/chrome/browser/resources/options/pref_ui.js
+++ b/chrome/browser/resources/options/pref_ui.js
@@ -463,6 +463,36 @@
   };
 
   /////////////////////////////////////////////////////////////////////////////
+  // PrefPortNumber class:
+
+  // Define a constructor that uses an input element as its underlying element.
+  var PrefPortNumber = cr.ui.define('input');
+
+  PrefPortNumber.prototype = {
+    // Set up the prototype chain
+    __proto__: PrefTextField.prototype,
+
+    /**
+     * Initialization function for the cr.ui framework.
+     */
+    decorate: function() {
+      var self = this;
+      self.type = 'text';
+      self.dataType = 'text';
+      PrefTextField.prototype.decorate.call(this);
+      self.oninput = function() {
+        // Note that using <input type="number"> is insufficient to restrict
+        // the input as it allows negative numbers and does not limit the
+        // number of charactes typed even if a range is set.  Furthermore,
+        // it sometimes produces strange repaint artifacts.
+        var filtered = self.value.replace(/[^0-9]/g, '');
+        if (filtered != self.value)
+          self.value = filtered;
+      };
+    }
+  };
+
+  /////////////////////////////////////////////////////////////////////////////
   // PrefButton class:
 
   // Define a constructor that uses a button element as its underlying element.
@@ -520,6 +550,7 @@
     PrefRange: PrefRange,
     PrefSelect: PrefSelect,
     PrefTextField: PrefTextField,
+    PrefPortNumber: PrefPortNumber,
     PrefButton: PrefButton
   };
 
diff --git a/chrome/browser/resources/policy.css b/chrome/browser/resources/policy.css
index 990d55f..cdf701d 100644
--- a/chrome/browser/resources/policy.css
+++ b/chrome/browser/resources/policy.css
@@ -56,24 +56,52 @@
 }
 
 #show-unset-container {
+  float: right;
   text-align: right;
 }
 
 html[dir='rtl'] #show-unset-container {
+  float: left;
   text-align: left;
 }
 
+div.reload-policies-button {
+  float: left;
+}
+
+html[dir='rtl'] div.reload-policies-button {
+  float: right;
+}
+
+div.show-unset-checkbox {
+  float: right;
+}
+
+html[dir='rtl'] div.show-unset-checkbox {
+  float: left;
+}
+
+section.reload-show-unset-section {
+  padding-bottom: 30px;
+  padding-top: 15px;
+}
+
+section.status-box-section {
+  clear: both;
+}
+
+div.table-description {
+  color: rgb(100, 100, 100);
+}
+
 div.no-policies-set {
   color: rgb(180, 180, 180);
   font-size: 125%;
-  margin-top: 70px;
+  margin-bottom: 10px;
+  margin-top: 20px;
   text-align: center;
 }
 
-section:not(.empty) > div.no-policies-set {
-  display: none;
-}
-
 table {
   border-collapse: collapse;
   margin-bottom: 5px;
@@ -86,6 +114,14 @@
   display: none;
 }
 
+section:not(.empty) > div.no-policies-set {
+  display: none;
+}
+
+section.policy-table-section {
+  padding-bottom: 10px;
+}
+
 th,
 td {
   border: 1px solid rgb(217, 217, 217);
diff --git a/chrome/browser/resources/policy.html b/chrome/browser/resources/policy.html
index bba2afc..fff1829 100644
--- a/chrome/browser/resources/policy.html
+++ b/chrome/browser/resources/policy.html
@@ -29,33 +29,23 @@
     <header>
       <h1 i18n-content="title"></h1>
     </header>
-    <section>
-      <button id="reload-policies" i18n-content="reloadPolicies"></button>
-    </section>
-    <section id="status" hidden>
-      <h3 i18n-content="status"></h3>
-      <div id="status-box-container"></span>
-    </section>
-    <section class="empty">
-      <h3 i18n-content="title"></h3>
-      <div id="show-unset-container">
+    <section class="reload-show-unset-section">
+      <div class="reload-policies-button">
+        <button id="reload-policies" i18n-content="reloadPolicies"></button>
+      </div>
+      <div id="show-unset-container" class="show-unset-checkbox">
         <label>
           <input id="show-unset" type="checkbox"></input>
           <span i18n-content="showUnset"></span>
         </label>
       </div>
-      <div class="no-policies-set" i18n-content="noPoliciesSet"></div>
-      <table id="policy-table">
-        <thead>
-          <tr>
-            <th i18n-content="headerScope"></th>
-            <th i18n-content="headerLevel"></th>
-            <th i18n-content="headerName"></th>
-            <th i18n-content="headerValue"></th>
-            <th i18n-content="headerStatus"></th>
-          </tr>
-        </thead>
-      </table>
+    </section>
+    <section id="status-section" class="status-box-section" hidden>
+      <h3 i18n-content="status"></h3>
+      <div id="status-box-container"></div>
+    </section>
+    <section id="main-section" class="empty">
+      <!--  This is where policy tables get dynamically added. -->
     </section>
   </div>
   <div hidden>
@@ -104,7 +94,7 @@
               <button class="toggle-expanded-value link-button"></button>
             </div>
           </td>
-          <td>
+          <td class="status-container">
             <div class="status elide"></div>
           </td>
         </tr>
diff --git a/chrome/browser/resources/policy.js b/chrome/browser/resources/policy.js
index 2c52c61..0e1f87d 100644
--- a/chrome/browser/resources/policy.js
+++ b/chrome/browser/resources/policy.js
@@ -155,9 +155,10 @@
       // Determine whether the contents of the value column overflows. The
       // visibility of the contents, replacement link and additional row
       // containing the complete value that depend on this are handled by CSS.
-      this.classList.toggle(
-          'has-overflowed-value',
-          valueContainer.offsetWidth < valueContainer.valueWidth);
+      if (valueContainer.offsetWidth < valueContainer.valueWidth)
+        this.classList.add('has-overflowed-value');
+      else
+        this.classList.remove('has-overflowed-value');
     },
 
     /**
@@ -272,8 +273,10 @@
             policy.unset && !showUnset ||
             policy.name.toLowerCase().indexOf(this.filterPattern_) == -1;
       }
-      this.parentElement.classList.toggle(
-          'empty', !this.querySelector('tbody:not([hidden])'));
+      if (this.querySelector('tbody:not([hidden])'))
+        this.parentElement.classList.remove('empty');
+      else
+        this.parentElement.classList.add('empty');
       setTimeout(this.checkOverflow_.bind(this), 0);
     },
 
@@ -319,7 +322,25 @@
    * @param {Object} names Dictionary containing all known policy names.
    */
   Page.setPolicyNames = function(names) {
-    this.getInstance().policyTable.setPolicyNames(names);
+    var page = this.getInstance();
+
+    // Clear all policy tables.
+    page.mainSection.innerHTML = '';
+    page.policyTables = {};
+
+    // Create tables and set known policy names for Chrome and extensions.
+    if (names.hasOwnProperty('chromePolicyNames')) {
+      var table = page.appendNewTable('chrome', 'Chrome policies', '');
+      table.setPolicyNames(names.chromePolicyNames);
+    }
+
+    if (names.hasOwnProperty('extensionPolicyNames')) {
+      for (var ext in names.extensionPolicyNames) {
+        var table = page.appendNewTable('extension-' + ext,
+            names.extensionPolicyNames[ext].name, 'ID: ' + ext);
+        table.setPolicyNames(names.extensionPolicyNames[ext].policyNames);
+      }
+    }
   };
 
   /**
@@ -329,7 +350,19 @@
    * @param {Object} values Dictionary containing the current policy values.
    */
   Page.setPolicyValues = function(values) {
-    this.getInstance().policyTable.setPolicyValues(values);
+    var page = this.getInstance();
+    if (values.hasOwnProperty('chromePolicies')) {
+      var table = page.policyTables['chrome'];
+      table.setPolicyValues(values.chromePolicies);
+    }
+
+    if (values.hasOwnProperty('extensionPolicies')) {
+      for (var extensionId in values.extensionPolicies) {
+        var table = page.policyTables['extension-' + extensionId];
+        if (table)
+          table.setPolicyValues(values.extensionPolicies[extensionId]);
+      }
+    }
   };
 
   /**
@@ -355,21 +388,29 @@
      */
     initialize: function() {
       uber.onContentFrameLoaded();
-      this.policyTable = $('policy-table');
-      cr.ui.decorate(this.policyTable, PolicyTable);
+
+      this.mainSection = $('main-section');
+      this.policyTables = {};
 
       // Place the initial focus on the filter input field.
       $('filter').focus();
 
       var self = this;
       $('filter').onsearch = function(event) {
-        self.policyTable.setFilterPattern(this.value);
+        for (policyTable in self.policyTables) {
+          self.policyTables[policyTable].setFilterPattern(this.value);
+        }
       };
       $('reload-policies').onclick = function(event) {
         this.disabled = true;
         chrome.send('reloadPolicies');
       };
-      $('show-unset').onchange = this.policyTable.filter.bind(this.policyTable);
+
+      $('show-unset').onchange = function() {
+        for (policyTable in self.policyTables) {
+          self.policyTables[policyTable].filter();
+        }
+      };
 
       // Notify the browser that the page has loaded, causing it to send the
       // list of all known policies, the current policy values and the cloud
@@ -377,6 +418,80 @@
       chrome.send('initialized');
     },
 
+   /**
+     * Creates a new policy table section, adds the section to the page,
+     * and returns the new table from that section.
+     * @param {string} id The key for storing the new table in policyTables.
+     * @param {string} label_title Title for this policy table.
+     * @param {string} label_content Description for the policy table.
+     * @return {Element} The newly created table.
+     */
+    appendNewTable: function(id, label_title, label_content) {
+      var newSection = this.createPolicyTableSection(id, label_title,
+          label_content);
+      this.mainSection.appendChild(newSection);
+      return this.policyTables[id];
+    },
+
+    /**
+     * Creates a new section containing a title, description and table of
+     * policies.
+     * @param {id} id The key for storing the new table in policyTables.
+     * @param {string} label_title Title for this policy table.
+     * @param {string} label_content Description for the policy table.
+     * @return {Element} The newly created section.
+     */
+    createPolicyTableSection: function(id, label_title, label_content) {
+      var section = document.createElement('section');
+      section.setAttribute('class', 'policy-table-section');
+
+      // Add title and description.
+      var title = window.document.createElement('h3');
+      title.textContent = label_title;
+      section.appendChild(title);
+
+      if (label_content) {
+        var description = window.document.createElement('div');
+        description.classList.add('table-description');
+        description.textContent = label_content;
+        section.appendChild(description);
+      }
+
+      // Add 'No Policies Set' element.
+      var noPolicies = window.document.createElement('div');
+      noPolicies.classList.add('no-policies-set');
+      noPolicies.textContent = loadTimeData.getString('noPoliciesSet');
+      section.appendChild(noPolicies);
+
+      // Add table of policies.
+      var newTable = this.createPolicyTable();
+      this.policyTables[id] = newTable;
+      section.appendChild(newTable);
+
+      return section;
+    },
+
+    /**
+     * Creates a new table for displaying policies.
+     * @return {Element} The newly created table.
+     */
+    createPolicyTable: function() {
+      var newTable = window.document.createElement('table');
+      var tableHead = window.document.createElement('thead');
+      var tableRow = window.document.createElement('tr');
+      var tableHeadings = ['headerScope', 'headerLevel',
+                           'headerName', 'headerValue', 'headerStatus'];
+      for (var i = 0; i < tableHeadings.length; i++) {
+        var tableHeader = window.document.createElement('th');
+        tableHeader.textContent = loadTimeData.getString(tableHeadings[i]);
+        tableRow.appendChild(tableHeader);
+      }
+      tableHead.appendChild(tableRow);
+      newTable.appendChild(tableHead);
+      cr.ui.decorate(newTable, PolicyTable);
+      return newTable;
+    },
+
     /**
      * Update the status section of the page to show the current cloud policy
      * status.
@@ -388,7 +503,7 @@
       while (container.firstChild)
         container.removeChild(container.firstChild);
       // Hide the status section.
-      var section = $('status');
+      var section = $('status-section');
       section.hidden = true;
 
       // Add a status box for each scope that has a cloud policy status.
diff --git a/chrome/browser/resources/print_preview/images/cloud.png b/chrome/browser/resources/print_preview/images/cloud.png
index c84d343..0c414ae 100644
--- a/chrome/browser/resources/print_preview/images/cloud.png
+++ b/chrome/browser/resources/print_preview/images/cloud.png
Binary files differ
diff --git a/chrome/browser/resources/print_preview/images/gcp_logo.png b/chrome/browser/resources/print_preview/images/gcp_logo.png
index 1f14375..6c485ba 100644
--- a/chrome/browser/resources/print_preview/images/gcp_logo.png
+++ b/chrome/browser/resources/print_preview/images/gcp_logo.png
Binary files differ
diff --git a/chrome/browser/resources/print_preview/images/google_doc.png b/chrome/browser/resources/print_preview/images/google_doc.png
index 81a0ee6..50e1b7e 100644
--- a/chrome/browser/resources/print_preview/images/google_doc.png
+++ b/chrome/browser/resources/print_preview/images/google_doc.png
Binary files differ
diff --git a/chrome/browser/resources/print_preview/images/mobile.png b/chrome/browser/resources/print_preview/images/mobile.png
index e804e49..8263091 100644
--- a/chrome/browser/resources/print_preview/images/mobile.png
+++ b/chrome/browser/resources/print_preview/images/mobile.png
Binary files differ
diff --git a/chrome/browser/resources/print_preview/images/mobile_shared.png b/chrome/browser/resources/print_preview/images/mobile_shared.png
index d5f9576..33b02de 100644
--- a/chrome/browser/resources/print_preview/images/mobile_shared.png
+++ b/chrome/browser/resources/print_preview/images/mobile_shared.png
Binary files differ
diff --git a/chrome/browser/resources/print_preview/images/pdf.png b/chrome/browser/resources/print_preview/images/pdf.png
index 3ae5c9b..bf49abb 100644
--- a/chrome/browser/resources/print_preview/images/pdf.png
+++ b/chrome/browser/resources/print_preview/images/pdf.png
Binary files differ
diff --git a/chrome/browser/resources/print_preview/images/printer.png b/chrome/browser/resources/print_preview/images/printer.png
index b78cc52..341e47f 100644
--- a/chrome/browser/resources/print_preview/images/printer.png
+++ b/chrome/browser/resources/print_preview/images/printer.png
Binary files differ
diff --git a/chrome/browser/resources/print_preview/images/printer_shared.png b/chrome/browser/resources/print_preview/images/printer_shared.png
index 4b07714..026ed45 100644
--- a/chrome/browser/resources/print_preview/images/printer_shared.png
+++ b/chrome/browser/resources/print_preview/images/printer_shared.png
Binary files differ
diff --git a/chrome/browser/resources/print_preview/images/search.png b/chrome/browser/resources/print_preview/images/search.png
index 2b4b77c..de504e8 100644
--- a/chrome/browser/resources/print_preview/images/search.png
+++ b/chrome/browser/resources/print_preview/images/search.png
Binary files differ
diff --git a/chrome/browser/resources/print_preview/images/third_party.png b/chrome/browser/resources/print_preview/images/third_party.png
index 104ac88..c12de3f 100644
--- a/chrome/browser/resources/print_preview/images/third_party.png
+++ b/chrome/browser/resources/print_preview/images/third_party.png
Binary files differ
diff --git a/chrome/browser/resources/print_preview/images/third_party_fedex.png b/chrome/browser/resources/print_preview/images/third_party_fedex.png
index a87ece3..03d7da8 100644
--- a/chrome/browser/resources/print_preview/images/third_party_fedex.png
+++ b/chrome/browser/resources/print_preview/images/third_party_fedex.png
Binary files differ
diff --git a/chrome/browser/resources/print_preview/print_preview.css b/chrome/browser/resources/print_preview/print_preview.css
index 41cc8fa..ed5424c 100644
--- a/chrome/browser/resources/print_preview/print_preview.css
+++ b/chrome/browser/resources/print_preview/print_preview.css
@@ -4,6 +4,7 @@
 
 html {
   height: 100%;
+  overflow: hidden;
 }
 
 body {
diff --git a/chrome/browser/resources/quick_office/manifest.json b/chrome/browser/resources/quick_office/manifest.json
index 1b08600..e2bb7f6 100644
--- a/chrome/browser/resources/quick_office/manifest.json
+++ b/chrome/browser/resources/quick_office/manifest.json
@@ -59,7 +59,21 @@
     "metricsPrivate",
     "streamsPrivate",
     "unlimitedStorage"],
-  "version": "2.9.2.14",
+  "platforms": [
+    {
+      "nacl_arch": "x86-32",
+      "sub_package_path": "_platform_specific/x86_32/"
+    },
+    {
+      "nacl_arch": "x86-64",
+      "sub_package_path": "_platform_specific/x86_64/"
+    },
+    {
+      "nacl_arch": "arm",
+      "sub_package_path": "_platform_specific/arm/"
+    }
+  ],
+  "version": "2.9.2.35",
   "web_accessible_resources": [
     "views/qowt.html"]
 }
diff --git a/chrome/browser/resources/quick_office/manifest_experimental.json b/chrome/browser/resources/quick_office/manifest_experimental.json
index 69de531..d6de353 100644
--- a/chrome/browser/resources/quick_office/manifest_experimental.json
+++ b/chrome/browser/resources/quick_office/manifest_experimental.json
@@ -60,7 +60,21 @@
     "metricsPrivate",
     "streamsPrivate",
     "unlimitedStorage"],
-  "version": "2.9.2.14",
+  "platforms": [
+    {
+      "nacl_arch": "x86-32",
+      "sub_package_path": "_platform_specific/x86_32/"
+    },
+    {
+      "nacl_arch": "x86-64",
+      "sub_package_path": "_platform_specific/x86_64/"
+    },
+    {
+      "nacl_arch": "arm",
+      "sub_package_path": "_platform_specific/arm/"
+    }
+  ],
+  "version": "2.9.2.35",
   "web_accessible_resources": [
     "views/qowt.html"]
 }
diff --git a/chrome/browser/resources/robot.png b/chrome/browser/resources/robot.png
index d913a52..ea4188a 100644
--- a/chrome/browser/resources/robot.png
+++ b/chrome/browser/resources/robot.png
Binary files differ
diff --git a/chrome/browser/resources/safe_browsing/images/2x/malware_icon_v2.png b/chrome/browser/resources/safe_browsing/images/2x/malware_icon_v2.png
index 8a2db13..a7687b5 100644
--- a/chrome/browser/resources/safe_browsing/images/2x/malware_icon_v2.png
+++ b/chrome/browser/resources/safe_browsing/images/2x/malware_icon_v2.png
Binary files differ
diff --git a/chrome/browser/resources/safe_browsing/images/2x/phishing_icon.png b/chrome/browser/resources/safe_browsing/images/2x/phishing_icon.png
index 83d1c80..b537a01 100644
--- a/chrome/browser/resources/safe_browsing/images/2x/phishing_icon.png
+++ b/chrome/browser/resources/safe_browsing/images/2x/phishing_icon.png
Binary files differ
diff --git a/chrome/browser/resources/safe_browsing/images/2x/subresource_icon.png b/chrome/browser/resources/safe_browsing/images/2x/subresource_icon.png
index a14cf20..c624628 100644
--- a/chrome/browser/resources/safe_browsing/images/2x/subresource_icon.png
+++ b/chrome/browser/resources/safe_browsing/images/2x/subresource_icon.png
Binary files differ
diff --git a/chrome/browser/resources/safe_browsing/images/malware_icon_v2.png b/chrome/browser/resources/safe_browsing/images/malware_icon_v2.png
index edf24b3..15c42ec 100644
--- a/chrome/browser/resources/safe_browsing/images/malware_icon_v2.png
+++ b/chrome/browser/resources/safe_browsing/images/malware_icon_v2.png
Binary files differ
diff --git a/chrome/browser/resources/safe_browsing/images/phishing_icon.png b/chrome/browser/resources/safe_browsing/images/phishing_icon.png
index 4f7db71..e8796a8 100644
--- a/chrome/browser/resources/safe_browsing/images/phishing_icon.png
+++ b/chrome/browser/resources/safe_browsing/images/phishing_icon.png
Binary files differ
diff --git a/chrome/browser/resources/safe_browsing/images/stripe.png b/chrome/browser/resources/safe_browsing/images/stripe.png
index d6bef14..b70145b 100644
--- a/chrome/browser/resources/safe_browsing/images/stripe.png
+++ b/chrome/browser/resources/safe_browsing/images/stripe.png
Binary files differ
diff --git a/chrome/browser/resources/safe_browsing/images/subresource_icon.png b/chrome/browser/resources/safe_browsing/images/subresource_icon.png
index b6a111c..a33c2ca 100644
--- a/chrome/browser/resources/safe_browsing/images/subresource_icon.png
+++ b/chrome/browser/resources/safe_browsing/images/subresource_icon.png
Binary files differ
diff --git a/chrome/browser/resources/ssl/badguy.png b/chrome/browser/resources/ssl/badguy.png
index ad670da..1af24cd 100644
--- a/chrome/browser/resources/ssl/badguy.png
+++ b/chrome/browser/resources/ssl/badguy.png
Binary files differ
diff --git a/chrome/browser/resources/ssl/firefox_fancy_twisty_closed.png b/chrome/browser/resources/ssl/firefox_fancy_twisty_closed.png
index ec15780..1025aea 100644
--- a/chrome/browser/resources/ssl/firefox_fancy_twisty_closed.png
+++ b/chrome/browser/resources/ssl/firefox_fancy_twisty_closed.png
Binary files differ
diff --git a/chrome/browser/resources/ssl/firefox_fancy_twisty_open.png b/chrome/browser/resources/ssl/firefox_fancy_twisty_open.png
index c520db5..7fac7da 100644
--- a/chrome/browser/resources/ssl/firefox_fancy_twisty_open.png
+++ b/chrome/browser/resources/ssl/firefox_fancy_twisty_open.png
Binary files differ
diff --git a/chrome/browser/resources/ssl/firefox_icon.png b/chrome/browser/resources/ssl/firefox_icon.png
index e8ad586..6fdf1e9 100644
--- a/chrome/browser/resources/ssl/firefox_icon.png
+++ b/chrome/browser/resources/ssl/firefox_icon.png
Binary files differ
diff --git a/chrome/browser/resources/ssl/firefox_twisty_closed.png b/chrome/browser/resources/ssl/firefox_twisty_closed.png
index 7da463f..cf17c46 100644
--- a/chrome/browser/resources/ssl/firefox_twisty_closed.png
+++ b/chrome/browser/resources/ssl/firefox_twisty_closed.png
Binary files differ
diff --git a/chrome/browser/resources/ssl/firefox_twisty_open.png b/chrome/browser/resources/ssl/firefox_twisty_open.png
index 44faeed..4e5016f 100644
--- a/chrome/browser/resources/ssl/firefox_twisty_open.png
+++ b/chrome/browser/resources/ssl/firefox_twisty_open.png
Binary files differ
diff --git a/chrome/browser/resources/ssl/policeman.png b/chrome/browser/resources/ssl/policeman.png
index 5dffd35..22a6f64 100644
--- a/chrome/browser/resources/ssl/policeman.png
+++ b/chrome/browser/resources/ssl/policeman.png
Binary files differ
diff --git a/chrome/browser/resources/ssl/roadblock.html b/chrome/browser/resources/ssl/roadblock.html
index 28b77f5..edec5f5 100644
--- a/chrome/browser/resources/ssl/roadblock.html
+++ b/chrome/browser/resources/ssl/roadblock.html
@@ -61,6 +61,18 @@
     text-decoration: underline;
   }
 
+  .test-image {
+    float: right;
+    height: 140px;
+    padding-left: 30px;
+    padding-right: 30px;
+    width: 140px;
+  }
+
+  html[dir='rtl'] .test-image {
+    float: left;
+  }
+
   .title {
     color: #660000;
     font-size: 18pt;
@@ -73,7 +85,7 @@
     display: inline;
   }
   </style>
-
+  <script src="../../../../ui/webui/resources/js/assert.js"></script>
   <script>
     // Should match SSLBlockingPageCommands in ssl_blocking_page.cc.
     var CMD_DONT_PROCEED = 0;
@@ -84,6 +96,7 @@
     var showedMore = false;
     var keyPressState = 0;
     var gainFocus = false;
+    var setupExperiment = false;
 
     function $(o) {
       return document.getElementById(o);
@@ -160,8 +173,21 @@
       });
     }
 
+    function setupIconExperiments() {
+      if (templateData.trialType == '') return;
+      assert(!setupExperiment);
+      setupExperiment = true;
+      var condition = templateData.trialType.split('SSL')[1].toLowerCase();
+      if (/policeman|stoplight|badguy/.test(condition)) {
+        $('trial-' + condition).hidden = false;
+        $('more-info-short').style.webkitMarginEnd = '30px';
+        $('more-info-long').style.webkitMarginEnd = '30px';
+      }
+    }
+
     window.addEventListener('focus', handleFocusEvent);
     document.addEventListener('DOMContentLoaded', setupEvents);
+    document.addEventListener('DOMContentLoaded', setupIconExperiments);
   </script>
 </head>
 <body>
@@ -170,6 +196,18 @@
       <img src="roadblock_icon.png" alt="SSL Error Icon" id="roadblock-icon">
     </div>
     <div class="title" i18n-content="headLine"></div>
+
+    <!-- RHS images for the field trial. -->
+    <div id="trial-badguy" class="test-image" hidden>
+      <img src="badguy.png" alt="Bad guy">
+    </div>
+    <div id="trial-policeman" class="test-image" hidden>
+      <img src="policeman.png" alt="Policeman">
+    </div>
+    <div id="trial-stoplight" class="test-image" hidden>
+      <img src="stoplight.png" alt="Stoplight">
+    </div>
+
     <div class="main" i18n-values=".innerHTML:description;dir:textdirection"></div>
     <div class="main" i18n-values=".innerHTML:reasonForNotProceeding"></div>
     <div class="main">
diff --git a/chrome/browser/resources/ssl/roadblock_background.png b/chrome/browser/resources/ssl/roadblock_background.png
index 61851c1..d562dff 100644
--- a/chrome/browser/resources/ssl/roadblock_background.png
+++ b/chrome/browser/resources/ssl/roadblock_background.png
Binary files differ
diff --git a/chrome/browser/resources/ssl/roadblock_icon.png b/chrome/browser/resources/ssl/roadblock_icon.png
index 7907d24..feab348 100644
--- a/chrome/browser/resources/ssl/roadblock_icon.png
+++ b/chrome/browser/resources/ssl/roadblock_icon.png
Binary files differ
diff --git a/chrome/browser/resources/ssl/stoplight.png b/chrome/browser/resources/ssl/stoplight.png
index c311882..b1eec06 100644
--- a/chrome/browser/resources/ssl/stoplight.png
+++ b/chrome/browser/resources/ssl/stoplight.png
Binary files differ
diff --git a/chrome/browser/resources/ssl/twisty_closed.png b/chrome/browser/resources/ssl/twisty_closed.png
index bb748b8..c19c69e 100644
--- a/chrome/browser/resources/ssl/twisty_closed.png
+++ b/chrome/browser/resources/ssl/twisty_closed.png
Binary files differ
diff --git a/chrome/browser/resources/ssl/twisty_closed_rtl.png b/chrome/browser/resources/ssl/twisty_closed_rtl.png
index 0e9961a..7e796e1 100644
--- a/chrome/browser/resources/ssl/twisty_closed_rtl.png
+++ b/chrome/browser/resources/ssl/twisty_closed_rtl.png
Binary files differ
diff --git a/chrome/browser/resources/ssl/twisty_open.png b/chrome/browser/resources/ssl/twisty_open.png
index 0902be0..6647ea3 100644
--- a/chrome/browser/resources/ssl/twisty_open.png
+++ b/chrome/browser/resources/ssl/twisty_open.png
Binary files differ
diff --git a/chrome/browser/resources/sync_file_system_internals/extension_statuses.html b/chrome/browser/resources/sync_file_system_internals/extension_statuses.html
index a445a7d..51e6871 100644
--- a/chrome/browser/resources/sync_file_system_internals/extension_statuses.html
+++ b/chrome/browser/resources/sync_file_system_internals/extension_statuses.html
@@ -4,7 +4,8 @@
 <table>
   <thead>
     <tr>
-      <td>Extension ID</td>
+      <td>Extension Name</td>
+      <td>ID</td>
       <td>Sync Status</td>
     </tr>
   </thead>
diff --git a/chrome/browser/resources/sync_file_system_internals/extension_statuses.js b/chrome/browser/resources/sync_file_system_internals/extension_statuses.js
index f194312..a31de23 100644
--- a/chrome/browser/resources/sync_file_system_internals/extension_statuses.js
+++ b/chrome/browser/resources/sync_file_system_internals/extension_statuses.js
@@ -33,7 +33,8 @@
 
 /**
  * Handles callback from onGetExtensionStatuses.
- * @param {Array} list of dictionaries containing 'extensionID' and 'status'.
+ * @param {Array} list of dictionaries containing 'extensionName',
+ *     'extensionID, 'status'.
  */
 ExtensionStatuses.onGetExtensionStatuses = function(extensionStatuses) {
   var itemContainer = $('extension-entries');
@@ -42,6 +43,7 @@
   for (var i = 0; i < extensionStatuses.length; i++) {
     var originEntry = extensionStatuses[i];
     var tr = document.createElement('tr');
+    tr.appendChild(createElementFromText('td', originEntry.extensionName));
     tr.appendChild(createElementFromText('td', originEntry.extensionID));
     tr.appendChild(createElementFromText('td', originEntry.status));
     itemContainer.appendChild(tr);
diff --git a/chrome/browser/resources/sync_file_system_internals/file_metadata.html b/chrome/browser/resources/sync_file_system_internals/file_metadata.html
index 40e317e..5c9d3a5 100644
--- a/chrome/browser/resources/sync_file_system_internals/file_metadata.html
+++ b/chrome/browser/resources/sync_file_system_internals/file_metadata.html
@@ -1,17 +1,9 @@
 <script src="chrome://syncfs-internals/file_metadata.js"></script>
 
-<!-- Extension ID Drop down to go here -->
+<select id="extensions-select"></select>
+<button id="refresh-metadata-button">Refresh</button>
 
-<button id="refresh-file-metadata">Refresh</button>
 <table>
-  <thead>
-    <tr>
-      <td>Extension</td>
-      <td>Status</td>
-      <td>Type</td>
-      <td>Title</td>
-      <td>Details</td>
-    </tr>
-  </thead>
+  <thead id="file-metadata-header"></thead>
   <tbody id="file-metadata-entries"></tbody>
 </table>
diff --git a/chrome/browser/resources/sync_file_system_internals/file_metadata.js b/chrome/browser/resources/sync_file_system_internals/file_metadata.js
index 85d2484..efc2196 100644
--- a/chrome/browser/resources/sync_file_system_internals/file_metadata.js
+++ b/chrome/browser/resources/sync_file_system_internals/file_metadata.js
@@ -11,23 +11,89 @@
 var FileMetadata = {};
 
 /**
- * Get File Metadata from handler.
+ * Gets extension data so the select drop down can be filled.
+ */
+function getExtensions() {
+  chrome.send('getExtensions');
+}
+
+/**
+ * Renders result of getFileMetadata as a table.
+ * @param {Array} list of dictionaries containing 'extensionName',
+ *     'extensionID', 'status'.
+ */
+FileMetadata.onGetExtensions = function(extensionStatuses) {
+  var select = $('extensions-select');
+
+  // Record existing drop down extension ID. If it's still there after the
+  // refresh then keep it as the selected value.
+  var oldSelectedExtension = getSelectedExtensionId();
+
+  select.textContent = '';
+  for (var i = 0; i < extensionStatuses.length; i++) {
+    var originEntry = extensionStatuses[i];
+    var tr = document.createElement('tr');
+    var title = originEntry.extensionName + ' [' + originEntry.status + ']';
+    select.options.add(new Option(title, originEntry.extensionID));
+
+    // If option was the previously only selected, make it selected again.
+    if (originEntry.extensionID != oldSelectedExtension)
+      continue;
+    select.options[select.options.length - 1].selected = true;
+  }
+
+  // After drop down has been loaded with options, file metadata can be loaded
+  getFileMetadata();
+}
+
+/**
+ * @return {string} extension ID that's currently selected in drop down box.
+ */
+function getSelectedExtensionId() {
+  var dropDown = $('extensions-select').options;
+  if (dropDown.selectedIndex >= 0)
+    return dropDown[dropDown.selectedIndex].value;
+
+  return null;
+}
+
+/**
+ * Get File Metadata depending on which extension is selected from the drop down
+ * if any.
  */
 function getFileMetadata() {
-  chrome.send('getFileMetadata');
+  var dropDown = $('extensions-select');
+  if (dropDown.options.length === 0) {
+    $('file-metadata-header').textContent = '';
+    $('file-metadata-entries').textContent = 'No file metadata available.';
+    return;
+  }
+
+  var selectedExtensionId = getSelectedExtensionId();
+  chrome.send('getFileMetadata', [selectedExtensionId]);
 }
 
 /**
  * Renders result of getFileMetadata as a table.
  */
 FileMetadata.onGetFileMetadata = function(fileMetadataMap) {
+  var header = $('file-metadata-header');
+  // Only draw the header if it hasn't been drawn yet
+  if (header.children.length === 0) {
+    var tr = document.createElement('tr');
+    tr.appendChild(createElementFromText('td', 'Status'));
+    tr.appendChild(createElementFromText('td', 'Type'));
+    tr.appendChild(createElementFromText('td', 'Title'));
+    tr.appendChild(createElementFromText('td', 'Details'));
+    header.appendChild(tr);
+  }
+
+  // Add row entries.
   var itemContainer = $('file-metadata-entries');
   itemContainer.textContent = '';
-
   for (var i = 0; i < fileMetadataMap.length; i++) {
     var metadatEntry = fileMetadataMap[i];
     var tr = document.createElement('tr');
-    tr.appendChild(createElementFromText('td', metadatEntry.origin));
     tr.appendChild(createElementFromText('td', metadatEntry.status));
     tr.appendChild(createElementFromText('td', metadatEntry.type));
     tr.appendChild(createElementFromText('td', metadatEntry.title));
@@ -50,8 +116,9 @@
 }
 
 function main() {
-  getFileMetadata();
-  $('refresh-file-metadata').addEventListener('click', getFileMetadata);
+  getExtensions();
+  $('refresh-metadata-button').addEventListener('click', getExtensions);
+  $('extensions-select').addEventListener('change', getFileMetadata);
 }
 
 document.addEventListener('DOMContentLoaded', main);
diff --git a/chrome/browser/resources/sync_file_system_internals/main.css b/chrome/browser/resources/sync_file_system_internals/main.css
index 23db141..090c730 100644
--- a/chrome/browser/resources/sync_file_system_internals/main.css
+++ b/chrome/browser/resources/sync_file_system_internals/main.css
@@ -2,6 +2,10 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file. */
 
+* {
+  font-family: Ubuntu, Arial, sans-serif;
+}
+
 tabbox {
   min-height: 650px;
 }
@@ -12,15 +16,25 @@
 
 th,
 td {
+  font-size: 14px;
   padding-left: 0.5em;
   padding-right: 0.5em;
   text-align: left;
 }
 
 thead tr {
+  font-size: 14px;
   font-weight: bold;
 }
 
 tbody tr:nth-child(odd) {
   background: rgb(238, 238, 255);
 }
+
+.log-time {
+  white-space: nowrap;
+}
+
+.log-event.error {
+  background: rgb(255, 220, 220);
+}
diff --git a/chrome/browser/resources/sync_file_system_internals/sync_service.html b/chrome/browser/resources/sync_file_system_internals/sync_service.html
index d8e6ba6..bd45841 100644
--- a/chrome/browser/resources/sync_file_system_internals/sync_service.html
+++ b/chrome/browser/resources/sync_file_system_internals/sync_service.html
@@ -18,8 +18,8 @@
 <table>
   <thead>
     <tr>
-      <td>Time</td>
-      <td>Log Event</td>
+      <td class="log-time">Time</td>
+      <td class="log-event">Log Event</td>
     </tr>
   </thead>
   <tbody id="log-entries"></tbody>
diff --git a/chrome/browser/resources/sync_file_system_internals/sync_service.js b/chrome/browser/resources/sync_file_system_internals/sync_service.js
index 6b49e78..6a8e732 100644
--- a/chrome/browser/resources/sync_file_system_internals/sync_service.js
+++ b/chrome/browser/resources/sync_file_system_internals/sync_service.js
@@ -44,11 +44,16 @@
  * Creates an element named |elementName| containing the content |text|.
  * @param {string} elementName Name of the new element to be created.
  * @param {string} text Text to be contained in the new element.
+ * @param {Object} opt_attributes Optional attribute dictionary for the element.
  * @return {HTMLElement} The newly created HTML element.
  */
-function createElementFromText(elementName, text) {
+function createElementFromText(elementName, text, opt_attributes) {
   var element = document.createElement(elementName);
   element.appendChild(document.createTextNode(text));
+  if (opt_attributes) {
+    for (var key in opt_attributes)
+      element.setAttribute(key, opt_attributes[key]);
+  }
   return element;
 }
 
@@ -68,8 +73,11 @@
   for (var i = 0; i < logEntries.length; i++) {
     var logEntry = logEntries[i];
     var tr = document.createElement('tr');
-    tr.appendChild(createElementFromText('td', logEntry.time));
-    tr.appendChild(createElementFromText('td', logEntry.logEvent));
+    var error = /ERROR/.test(logEntry.logEvent) ? ' error' : '';
+    tr.appendChild(createElementFromText('td', logEntry.time,
+                                         {class: 'log-time'}));
+    tr.appendChild(createElementFromText('td', logEntry.logEvent,
+                                         {class: 'log-event' + error}));
     itemContainer.appendChild(tr);
   }
 }
diff --git a/chrome/browser/resources/sync_internals/data.html b/chrome/browser/resources/sync_internals/data.html
index ed31498..ec3f237 100644
--- a/chrome/browser/resources/sync_internals/data.html
+++ b/chrome/browser/resources/sync_internals/data.html
@@ -13,6 +13,8 @@
 
 <button id="dump-to-file">Dump sync nodes to file</button>
 
+<input type="checkbox" id="include-specifics">include node content <font color="red">WARNING: This is likely to include personal information.</font><br>
+
 <a style="display: none" id="dump-to-file-anchor"></a>
 
 <script src="chrome://sync-internals/data.js"></script>
diff --git a/chrome/browser/resources/sync_internals/data.js b/chrome/browser/resources/sync_internals/data.js
index e2c6045..1e68887 100644
--- a/chrome/browser/resources/sync_internals/data.js
+++ b/chrome/browser/resources/sync_internals/data.js
@@ -32,7 +32,6 @@
   dataDump.textContent = data;
 });
 
-// TODO(mmontgomery): add SPECIFICS as an opt-in.
 var allFields = [
   'ID',
   'IS_UNSYNCED',
@@ -46,6 +45,8 @@
   'IS_DEL',
   'SERVER_IS_DEL',
   'serverModelType',
+  'SERVER_SPECIFICS',
+  'SPECIFICS',
 ];
 
 function versionToDateString(version) {
@@ -65,6 +66,9 @@
     } if (field == 'BASE_VERSION_TIME') {
       var version = node['BASE_VERSION'];
       fieldVal = versionToDateString(version);
+    } else if ((field == 'SERVER_SPECIFICS' || field == 'SPECIFICS') &&
+            $('include-specifics').checked) {
+      fieldVal = JSON.stringify(node[field]);
     } else {
       fieldVal = node[field];
     }
diff --git a/chrome/browser/resources/sync_setup_overlay.html b/chrome/browser/resources/sync_setup_overlay.html
index 3aa0d3e..f0bdfd3 100644
--- a/chrome/browser/resources/sync_setup_overlay.html
+++ b/chrome/browser/resources/sync_setup_overlay.html
@@ -34,7 +34,11 @@
             <select id="sync-select-datatypes">
               <option i18n-content="syncAllDataTypes" selected></option>
               <option i18n-content="chooseDataTypes"></option>
-              <option i18n-content="syncNothing"></option>
+              <!-- The syncNothing element is to be hidden for M29.
+                   TODO(rsimha): Revisit this for M30.
+                   See http://crbug.com/252049.
+              -->
+              <option i18n-content="syncNothing" hidden></option>
             </select>
             <div id="choose-data-types-body">
               <div id="apps-item" class="sync-type-checkbox checkbox">
diff --git a/chrome/browser/resources/task_manager/main.js b/chrome/browser/resources/task_manager/main.js
index 154d399..6a6a046 100644
--- a/chrome/browser/resources/task_manager/main.js
+++ b/chrome/browser/resources/task_manager/main.js
@@ -429,8 +429,6 @@
     var listItem = new cr.ui.ListItem({label: ''});
 
     listItem.className = 'table-row';
-    if (this.opt_.isBackgroundMode && data.isBackgroundResource)
-      listItem.className += ' table-background-row';
 
     for (var i = 0; i < cm.size; i++) {
       var cell = document.createElement('div');
@@ -690,7 +688,6 @@
 function init() {
   var params = parseQueryParams(window.location);
   var opt = {};
-  opt['isBackgroundMode'] = params.background;
   opt['isShowCloseButton'] = params.showclose;
   taskmanager.initialize(document.body, opt);
 }
diff --git a/chrome/browser/resources/task_manager/task_manager.css b/chrome/browser/resources/task_manager/task_manager.css
index e050d56..e77055f 100644
--- a/chrome/browser/resources/task_manager/task_manager.css
+++ b/chrome/browser/resources/task_manager/task_manager.css
@@ -77,13 +77,6 @@
   width: 6px;
 }
 
-.table-background-row {
-  background-color: hsl(34, 91%, 87%);
-  background-image: -webkit-linear-gradient(rgba(255, 255, 255, 0.8),
-                                            rgba(255, 255, 255, 0));
-  border-color: hsl(34, 91%, 65%);
-}
-
 /* Cells in table. */
 .table-row-cell {
   -webkit-box-orient: horizontal;
diff --git a/chrome/browser/resources/translate_internals/prefs.html b/chrome/browser/resources/translate_internals/prefs.html
index 7aba1ad..e04030d 100644
--- a/chrome/browser/resources/translate_internals/prefs.html
+++ b/chrome/browser/resources/translate_internals/prefs.html
@@ -4,8 +4,12 @@
 found in the LICENSE file.
 -->
 <div>
+  <section id="prefs-blocked-languages">
+    <h2>Languages not translated (New)</h2>
+    <ul></ul>
+  </section>
   <section id="prefs-language-blacklist">
-    <h2>Languages not translated</h2>
+    <h2>Languages not translated<span> (Old)</span></h2>
     <ul></ul>
   </section>
   <section id="prefs-site-blacklist">
diff --git a/chrome/browser/resources/translate_internals/translate_internals.js b/chrome/browser/resources/translate_internals/translate_internals.js
index c409715..a0553a6 100644
--- a/chrome/browser/resources/translate_internals/translate_internals.js
+++ b/chrome/browser/resources/translate_internals/translate_internals.js
@@ -25,6 +25,12 @@
 
       var button = $('detection-logs-dump');
       button.addEventListener('click', onDetectionLogsDump);
+
+      var enableTranslateSettings = templateData['enable-translate-settings'];
+      if (!enableTranslateSettings) {
+        $('prefs-blocked-languages').hidden = true;
+        $('prefs-language-blacklist').querySelector('h2 span').hidden = true;
+      }
     }
 
     /**
@@ -101,6 +107,24 @@
      */
     function onPrefsUpdated(detail) {
       var ul;
+
+      ul = document.querySelector('#prefs-blocked-languages ul');
+      ul.innerHTML = '';
+
+      if ('translate_blocked_languages' in detail) {
+        var langs = detail['translate_blocked_languages'];
+
+        langs.forEach(function(langCode) {
+          var text = formatLanguageCode(langCode);
+
+          var li = createLIWithDismissingButton(text, function() {
+            chrome.send('removePrefItem',
+                        ['blocked_languages', langCode]);
+          });
+          ul.appendChild(li);
+        });
+      }
+
       ul = document.querySelector('#prefs-language-blacklist ul');
       ul.innerHTML = '';
 
diff --git a/chrome/browser/resources/twisty_closed.png b/chrome/browser/resources/twisty_closed.png
index bb748b8..c19c69e 100644
--- a/chrome/browser/resources/twisty_closed.png
+++ b/chrome/browser/resources/twisty_closed.png
Binary files differ
diff --git a/chrome/browser/resources/twisty_closed_rtl.png b/chrome/browser/resources/twisty_closed_rtl.png
index 0e9961a..7e796e1 100644
--- a/chrome/browser/resources/twisty_closed_rtl.png
+++ b/chrome/browser/resources/twisty_closed_rtl.png
Binary files differ
diff --git a/chrome/browser/resources/twisty_open.png b/chrome/browser/resources/twisty_open.png
index 0902be0..6647ea3 100644
--- a/chrome/browser/resources/twisty_open.png
+++ b/chrome/browser/resources/twisty_open.png
Binary files differ
diff --git a/chrome/browser/rlz/rlz.cc b/chrome/browser/rlz/rlz.cc
index 968a33c..fc4e7ba 100644
--- a/chrome/browser/rlz/rlz.cc
+++ b/chrome/browser/rlz/rlz.cc
@@ -63,10 +63,6 @@
 const base::TimeDelta kMaxInitDelay = base::TimeDelta::FromSeconds(200);
 const base::TimeDelta kMinInitDelay = base::TimeDelta::FromSeconds(20);
 
-bool IsGoogleUrl(const GURL& url) {
-  return google_util::IsGoogleHomePageUrl(url.possibly_invalid_spec());
-}
-
 bool IsBrandOrganic(const std::string& brand) {
   return brand.empty() || google_util::IsOrganic(brand);
 }
@@ -232,16 +228,17 @@
 
   PrefService* pref_service = profile->GetPrefs();
   bool is_google_homepage = google_util::IsGoogleHomePageUrl(
-      pref_service->GetString(prefs::kHomePage));
+      GURL(pref_service->GetString(prefs::kHomePage)));
 
   bool is_google_in_startpages = false;
   SessionStartupPref session_startup_prefs =
       StartupBrowserCreator::GetSessionStartupPref(
           *CommandLine::ForCurrentProcess(), profile);
   if (session_startup_prefs.type == SessionStartupPref::URLS) {
-    is_google_in_startpages = std::count_if(session_startup_prefs.urls.begin(),
-                                            session_startup_prefs.urls.end(),
-                                            IsGoogleUrl) > 0;
+    is_google_in_startpages =
+        std::count_if(session_startup_prefs.urls.begin(),
+                      session_startup_prefs.urls.end(),
+                      google_util::IsGoogleHomePageUrl) > 0;
   }
 
   if (!InitRlzDelayed(first_run, send_ping_immediately, delay,
diff --git a/chrome/browser/rlz/rlz.h b/chrome/browser/rlz/rlz.h
index e4a361c..d55e05c 100644
--- a/chrome/browser/rlz/rlz.h
+++ b/chrome/browser/rlz/rlz.h
@@ -16,7 +16,7 @@
 #include "base/memory/singleton.h"
 #include "base/strings/string16.h"
 #include "base/threading/sequenced_worker_pool.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
 #include "rlz/lib/rlz_lib.h"
diff --git a/chrome/browser/safe_browsing/browser_feature_extractor.cc b/chrome/browser/safe_browsing/browser_feature_extractor.cc
index 1ebf378..6cfb98f 100644
--- a/chrome/browser/safe_browsing/browser_feature_extractor.cc
+++ b/chrome/browser/safe_browsing/browser_feature_extractor.cc
@@ -12,7 +12,7 @@
 #include "base/format_macros.h"
 #include "base/stl_util.h"
 #include "base/strings/stringprintf.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/common/cancelable_request.h"
 #include "chrome/browser/history/history_service.h"
 #include "chrome/browser/history/history_service_factory.h"
@@ -26,7 +26,7 @@
 #include "content/public/browser/navigation_entry.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/page_transition_types.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 using content::BrowserThread;
 using content::NavigationController;
diff --git a/chrome/browser/safe_browsing/browser_feature_extractor.h b/chrome/browser/safe_browsing/browser_feature_extractor.h
index 6ea8bf1..086e9bb 100644
--- a/chrome/browser/safe_browsing/browser_feature_extractor.h
+++ b/chrome/browser/safe_browsing/browser_feature_extractor.h
@@ -21,12 +21,12 @@
 #include "base/containers/hash_tables.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/sequenced_task_runner_helpers.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/common/cancelable_request.h"
 #include "chrome/browser/history/history_types.h"
 #include "chrome/browser/safe_browsing/safe_browsing_service.h"
 #include "chrome/browser/safe_browsing/ui_manager.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 class HistoryService;
 
diff --git a/chrome/browser/safe_browsing/browser_feature_extractor_unittest.cc b/chrome/browser/safe_browsing/browser_feature_extractor_unittest.cc
index e52cbfd..9c2d444 100644
--- a/chrome/browser/safe_browsing/browser_feature_extractor_unittest.cc
+++ b/chrome/browser/safe_browsing/browser_feature_extractor_unittest.cc
@@ -11,7 +11,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/message_loop.h"
 #include "base/strings/stringprintf.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/history/history_backend.h"
 #include "chrome/browser/history/history_service.h"
 #include "chrome/browser/history/history_service_factory.h"
@@ -28,9 +28,9 @@
 #include "content/public/common/referrer.h"
 #include "content/public/test/test_browser_thread.h"
 #include "content/public/test/web_contents_tester.h"
-#include "googleurl/src/gurl.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
 
 using content::WebContentsTester;
 using testing::Return;
diff --git a/chrome/browser/safe_browsing/client_side_detection_host.cc b/chrome/browser/safe_browsing/client_side_detection_host.cc
index 81cb917..5c5a781 100644
--- a/chrome/browser/safe_browsing/client_side_detection_host.cc
+++ b/chrome/browser/safe_browsing/client_side_detection_host.cc
@@ -35,7 +35,7 @@
 #include "content/public/browser/resource_request_details.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/frame_navigate_params.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 using content::BrowserThread;
 using content::NavigationEntry;
diff --git a/chrome/browser/safe_browsing/client_side_detection_host.h b/chrome/browser/safe_browsing/client_side_detection_host.h
index 70dbbbe..7329f52 100644
--- a/chrome/browser/safe_browsing/client_side_detection_host.h
+++ b/chrome/browser/safe_browsing/client_side_detection_host.h
@@ -17,7 +17,7 @@
 #include "content/public/browser/notification_registrar.h"
 #include "content/public/browser/resource_request_details.h"
 #include "content/public/browser/web_contents_observer.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 namespace safe_browsing {
 class ClientPhishingRequest;
diff --git a/chrome/browser/safe_browsing/client_side_detection_host_unittest.cc b/chrome/browser/safe_browsing/client_side_detection_host_unittest.cc
index 9c2aeed..3a696b5 100644
--- a/chrome/browser/safe_browsing/client_side_detection_host_unittest.cc
+++ b/chrome/browser/safe_browsing/client_side_detection_host_unittest.cc
@@ -23,10 +23,10 @@
 #include "content/public/test/mock_render_process_host.h"
 #include "content/public/test/test_browser_thread.h"
 #include "content/public/test/test_renderer_host.h"
-#include "googleurl/src/gurl.h"
 #include "ipc/ipc_test_sink.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
 
 using ::testing::_;
 using ::testing::DeleteArg;
diff --git a/chrome/browser/safe_browsing/client_side_detection_service.cc b/chrome/browser/safe_browsing/client_side_detection_service.cc
index 87503a6..b0514b3 100644
--- a/chrome/browser/safe_browsing/client_side_detection_service.cc
+++ b/chrome/browser/safe_browsing/client_side_detection_service.cc
@@ -13,7 +13,7 @@
 #include "base/prefs/pref_service.h"
 #include "base/stl_util.h"
 #include "base/strings/string_util.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/chrome_switches.h"
@@ -27,7 +27,6 @@
 #include "content/public/browser/render_process_host.h"
 #include "crypto/sha2.h"
 #include "google_apis/google_api_keys.h"
-#include "googleurl/src/gurl.h"
 #include "net/base/escape.h"
 #include "net/base/load_flags.h"
 #include "net/http/http_response_headers.h"
@@ -35,6 +34,7 @@
 #include "net/url_request/url_fetcher.h"
 #include "net/url_request/url_request_context_getter.h"
 #include "net/url_request/url_request_status.h"
+#include "url/gurl.h"
 
 using content::BrowserThread;
 
diff --git a/chrome/browser/safe_browsing/client_side_detection_service.h b/chrome/browser/safe_browsing/client_side_detection_service.h
index f89de22..ccc3c66 100644
--- a/chrome/browser/safe_browsing/client_side_detection_service.h
+++ b/chrome/browser/safe_browsing/client_side_detection_service.h
@@ -27,12 +27,12 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
-#include "googleurl/src/gurl.h"
 #include "net/base/net_util.h"
 #include "net/url_request/url_fetcher_delegate.h"
+#include "url/gurl.h"
 
 class SafeBrowsingService;
 
diff --git a/chrome/browser/safe_browsing/client_side_detection_service_unittest.cc b/chrome/browser/safe_browsing/client_side_detection_service_unittest.cc
index 87d471e..eb74147 100644
--- a/chrome/browser/safe_browsing/client_side_detection_service_unittest.cc
+++ b/chrome/browser/safe_browsing/client_side_detection_service_unittest.cc
@@ -11,17 +11,17 @@
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/message_loop.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/safe_browsing/client_side_detection_service.h"
 #include "chrome/common/safe_browsing/client_model.pb.h"
 #include "chrome/common/safe_browsing/csd.pb.h"
 #include "content/public/test/test_browser_thread.h"
 #include "crypto/sha2.h"
-#include "googleurl/src/gurl.h"
 #include "net/url_request/test_url_fetcher_factory.h"
 #include "net/url_request/url_request_status.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
 
 using ::testing::_;
 using ::testing::Invoke;
diff --git a/chrome/browser/safe_browsing/database_manager.h b/chrome/browser/safe_browsing/database_manager.h
index 5e9520f..09f64bd 100644
--- a/chrome/browser/safe_browsing/database_manager.h
+++ b/chrome/browser/safe_browsing/database_manager.h
@@ -19,10 +19,10 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/synchronization/lock.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/safe_browsing/protocol_manager.h"
 #include "chrome/browser/safe_browsing/safe_browsing_util.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 class SafeBrowsingService;
 class SafeBrowsingDatabase;
diff --git a/chrome/browser/safe_browsing/download_feedback.cc b/chrome/browser/safe_browsing/download_feedback.cc
index fef426a..6748d2d 100644
--- a/chrome/browser/safe_browsing/download_feedback.cc
+++ b/chrome/browser/safe_browsing/download_feedback.cc
@@ -108,7 +108,9 @@
     uploader_.reset();
   }
 
-  base::FileUtilProxy::Delete(file_task_runner_, file_path_, false,
+  base::FileUtilProxy::Delete(file_task_runner_.get(),
+                              file_path_,
+                              false,
                               base::FileUtilProxy::StatusCallback());
 }
 
@@ -135,15 +137,16 @@
   std::string metadata_string;
   bool ok = report_metadata.SerializeToString(&metadata_string);
   DCHECK(ok);
-  uploader_.reset(TwoPhaseUploader::Create(
-      request_context_getter_,
-      file_task_runner_,
-      url,
-      metadata_string,
-      file_path_,
-      TwoPhaseUploader::ProgressCallback(),
-      base::Bind(&DownloadFeedbackImpl::FinishedUpload, base::Unretained(this),
-                 finish_callback)));
+  uploader_.reset(
+      TwoPhaseUploader::Create(request_context_getter_.get(),
+                               file_task_runner_.get(),
+                               url,
+                               metadata_string,
+                               file_path_,
+                               TwoPhaseUploader::ProgressCallback(),
+                               base::Bind(&DownloadFeedbackImpl::FinishedUpload,
+                                          base::Unretained(this),
+                                          finish_callback)));
   uploader_->Start();
 }
 
diff --git a/chrome/browser/safe_browsing/download_feedback_service.cc b/chrome/browser/safe_browsing/download_feedback_service.cc
index 3e5b378..8c189aa 100644
--- a/chrome/browser/safe_browsing/download_feedback_service.cc
+++ b/chrome/browser/safe_browsing/download_feedback_service.cc
@@ -177,7 +177,9 @@
   if (service) {
     service->BeginFeedback(ping_request, ping_response, path);
   } else {
-    base::FileUtilProxy::Delete(file_task_runner, path, false,
+    base::FileUtilProxy::Delete(file_task_runner.get(),
+                                path,
+                                false,
                                 base::FileUtilProxy::StatusCallback());
   }
 }
@@ -193,9 +195,12 @@
     const std::string& ping_response,
     const base::FilePath& path) {
   DCHECK(CalledOnValidThread());
-  DownloadFeedback* feedback = DownloadFeedback::Create(
-      request_context_getter_, file_task_runner_, path,
-      ping_request, ping_response);
+  DownloadFeedback* feedback =
+      DownloadFeedback::Create(request_context_getter_.get(),
+                               file_task_runner_.get(),
+                               path,
+                               ping_request,
+                               ping_response);
   active_feedback_.push_back(feedback);
   UMA_HISTOGRAM_COUNTS_100("SBDownloadFeedback.ActiveFeedbacks",
                            active_feedback_.size());
diff --git a/chrome/browser/safe_browsing/download_feedback_service_unittest.cc b/chrome/browser/safe_browsing/download_feedback_service_unittest.cc
index 8f0a874..a912a3f 100644
--- a/chrome/browser/safe_browsing/download_feedback_service_unittest.cc
+++ b/chrome/browser/safe_browsing/download_feedback_service_unittest.cc
@@ -208,7 +208,8 @@
   EXPECT_CALL(item, StealDangerousDownload(_))
       .WillOnce(SaveArg<0>(&download_discarded_callback));
 
-  DownloadFeedbackService service(request_context_getter_, file_task_runner_);
+  DownloadFeedbackService service(request_context_getter_.get(),
+                                  file_task_runner_.get());
   service.MaybeStorePingsForDownload(
       DownloadProtectionService::UNCOMMON, &item, ping_request, ping_response);
   ASSERT_TRUE(DownloadFeedbackService::IsEnabledForDownload(item));
@@ -255,7 +256,8 @@
   }
 
   {
-    DownloadFeedbackService service(request_context_getter_, file_task_runner_);
+    DownloadFeedbackService service(request_context_getter_.get(),
+                                    file_task_runner_.get());
     for (size_t i = 0; i < num_downloads; ++i) {
       SCOPED_TRACE(i);
       service.BeginFeedbackForDownload(&item[i]);
@@ -323,7 +325,8 @@
   }
 
   {
-    DownloadFeedbackService service(request_context_getter_, file_task_runner_);
+    DownloadFeedbackService service(request_context_getter_.get(),
+                                    file_task_runner_.get());
     for (size_t i = 0; i < num_downloads; ++i) {
       SCOPED_TRACE(i);
       service.BeginFeedbackForDownload(&item[i]);
diff --git a/chrome/browser/safe_browsing/download_feedback_unittest.cc b/chrome/browser/safe_browsing/download_feedback_unittest.cc
index 4a83868..0054a69 100644
--- a/chrome/browser/safe_browsing/download_feedback_unittest.cc
+++ b/chrome/browser/safe_browsing/download_feedback_unittest.cc
@@ -169,12 +169,12 @@
   CommandLine::ForCurrentProcess()->AppendSwitchASCII(
       switches::kSbDownloadFeedbackURL, kTestFeedbackURL);
 
-  DownloadFeedback* feedback = DownloadFeedback::Create(
-      url_request_context_getter_,
-      file_task_runner_,
-      upload_file_path_,
-      ping_request,
-      ping_response);
+  DownloadFeedback* feedback =
+      DownloadFeedback::Create(url_request_context_getter_.get(),
+                               file_task_runner_.get(),
+                               upload_file_path_,
+                               ping_request,
+                               ping_response);
   EXPECT_FALSE(uploader());
 
   feedback->Start(base::Bind(&DownloadFeedbackTest::FinishCallback,
@@ -216,12 +216,12 @@
   std::string ping_response(
       expected_report_metadata.download_response().SerializeAsString());
 
-  DownloadFeedback* feedback = DownloadFeedback::Create(
-      url_request_context_getter_,
-      file_task_runner_,
-      upload_file_path_,
-      ping_request,
-      ping_response);
+  DownloadFeedback* feedback =
+      DownloadFeedback::Create(url_request_context_getter_.get(),
+                               file_task_runner_.get(),
+                               upload_file_path_,
+                               ping_request,
+                               ping_response);
   EXPECT_FALSE(uploader());
 
   feedback->Start(base::Bind(&DownloadFeedbackTest::FinishCallback,
diff --git a/chrome/browser/safe_browsing/download_protection_service.cc b/chrome/browser/safe_browsing/download_protection_service.cc
index 9fe8380..2c5f590 100644
--- a/chrome/browser/safe_browsing/download_protection_service.cc
+++ b/chrome/browser/safe_browsing/download_protection_service.cc
@@ -16,7 +16,7 @@
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/threading/sequenced_worker_pool.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/safe_browsing/download_feedback_service.h"
 #include "chrome/browser/safe_browsing/safe_browsing_service.h"
 #include "chrome/browser/safe_browsing/sandboxed_zip_analyzer.h"
diff --git a/chrome/browser/safe_browsing/download_protection_service.h b/chrome/browser/safe_browsing/download_protection_service.h
index 045bb2f..48ab04a 100644
--- a/chrome/browser/safe_browsing/download_protection_service.h
+++ b/chrome/browser/safe_browsing/download_protection_service.h
@@ -19,7 +19,7 @@
 #include "base/memory/ref_counted.h"
 #include "chrome/browser/safe_browsing/database_manager.h"
 #include "chrome/browser/safe_browsing/ui_manager.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 
 namespace content {
diff --git a/chrome/browser/safe_browsing/download_protection_service_unittest.cc b/chrome/browser/safe_browsing/download_protection_service_unittest.cc
index e5baf4c..1862107 100644
--- a/chrome/browser/safe_browsing/download_protection_service_unittest.cc
+++ b/chrome/browser/safe_browsing/download_protection_service_unittest.cc
@@ -28,13 +28,13 @@
 #include "chrome/common/safe_browsing/csd.pb.h"
 #include "content/public/test/mock_download_item.h"
 #include "content/public/test/test_browser_thread.h"
-#include "googleurl/src/gurl.h"
 #include "net/cert/x509_certificate.h"
 #include "net/url_request/test_url_fetcher_factory.h"
 #include "net/url_request/url_fetcher_delegate.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/zlib/google/zip.h"
+#include "url/gurl.h"
 
 using ::testing::Assign;
 using ::testing::ContainerEq;
diff --git a/chrome/browser/safe_browsing/malware_details_unittest.cc b/chrome/browser/safe_browsing/malware_details_unittest.cc
index 31f662d..37ada0c 100644
--- a/chrome/browser/safe_browsing/malware_details_unittest.cc
+++ b/chrome/browser/safe_browsing/malware_details_unittest.cc
@@ -7,7 +7,7 @@
 #include "base/bind.h"
 #include "base/pickle.h"
 #include "base/run_loop.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/history/history_backend.h"
 #include "chrome/browser/history/history_service.h"
 #include "chrome/browser/history/history_service_factory.h"
diff --git a/chrome/browser/safe_browsing/ping_manager.h b/chrome/browser/safe_browsing/ping_manager.h
index bdee022..f976cff 100644
--- a/chrome/browser/safe_browsing/ping_manager.h
+++ b/chrome/browser/safe_browsing/ping_manager.h
@@ -15,8 +15,8 @@
 #include "base/memory/scoped_ptr.h"
 #include "chrome/browser/safe_browsing/protocol_manager_helper.h"
 #include "chrome/browser/safe_browsing/safe_browsing_util.h"
-#include "googleurl/src/gurl.h"
 #include "net/url_request/url_fetcher_delegate.h"
+#include "url/gurl.h"
 
 namespace net {
 class URLRequestContextGetter;
diff --git a/chrome/browser/safe_browsing/ping_manager_unittest.cc b/chrome/browser/safe_browsing/ping_manager_unittest.cc
index 8673c24..585b31b 100644
--- a/chrome/browser/safe_browsing/ping_manager_unittest.cc
+++ b/chrome/browser/safe_browsing/ping_manager_unittest.cc
@@ -5,7 +5,7 @@
 
 #include "base/logging.h"
 #include "base/strings/stringprintf.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/safe_browsing/ping_manager.h"
 #include "google_apis/google_api_keys.h"
 #include "net/base/escape.h"
diff --git a/chrome/browser/safe_browsing/protocol_manager.cc b/chrome/browser/safe_browsing/protocol_manager.cc
index ff8856c..6c13779 100644
--- a/chrome/browser/safe_browsing/protocol_manager.cc
+++ b/chrome/browser/safe_browsing/protocol_manager.cc
@@ -14,7 +14,7 @@
 #include "base/stl_util.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
-#include "base/timer.h"
+#include "base/timer/timer.h"
 #include "chrome/browser/safe_browsing/protocol_parser.h"
 #include "chrome/common/chrome_version_info.h"
 #include "chrome/common/env_vars.h"
diff --git a/chrome/browser/safe_browsing/protocol_manager.h b/chrome/browser/safe_browsing/protocol_manager.h
index 9fa2d95..f5555e3 100644
--- a/chrome/browser/safe_browsing/protocol_manager.h
+++ b/chrome/browser/safe_browsing/protocol_manager.h
@@ -22,14 +22,14 @@
 #include "base/gtest_prod_util.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/threading/non_thread_safe.h"
-#include "base/time.h"
-#include "base/timer.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
 #include "chrome/browser/safe_browsing/chunk_range.h"
 #include "chrome/browser/safe_browsing/protocol_manager_helper.h"
 #include "chrome/browser/safe_browsing/protocol_parser.h"
 #include "chrome/browser/safe_browsing/safe_browsing_util.h"
-#include "googleurl/src/gurl.h"
 #include "net/url_request/url_fetcher_delegate.h"
+#include "url/gurl.h"
 
 namespace net {
 class URLFetcher;
diff --git a/chrome/browser/safe_browsing/protocol_manager_unittest.cc b/chrome/browser/safe_browsing/protocol_manager_unittest.cc
index 06af5ad..22854f6 100644
--- a/chrome/browser/safe_browsing/protocol_manager_unittest.cc
+++ b/chrome/browser/safe_browsing/protocol_manager_unittest.cc
@@ -6,7 +6,7 @@
 #include "base/strings/stringprintf.h"
 #include "base/test/test_simple_task_runner.h"
 #include "base/thread_task_runner_handle.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/safe_browsing/protocol_manager.h"
 #include "google_apis/google_api_keys.h"
 #include "net/base/escape.h"
diff --git a/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc b/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc
index e724f31..720836f 100644
--- a/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc
@@ -18,7 +18,7 @@
 #include "base/strings/string_piece.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/google/google_util.h"
diff --git a/chrome/browser/safe_browsing/safe_browsing_blocking_page.h b/chrome/browser/safe_browsing/safe_browsing_blocking_page.h
index b625714..f208d3b 100644
--- a/chrome/browser/safe_browsing/safe_browsing_blocking_page.h
+++ b/chrome/browser/safe_browsing/safe_browsing_blocking_page.h
@@ -33,10 +33,10 @@
 #include <vector>
 
 #include "base/gtest_prod_util.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/safe_browsing/ui_manager.h"
 #include "content/public/browser/interstitial_page_delegate.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 class MalwareDetails;
 class SafeBrowsingBlockingPageFactory;
diff --git a/chrome/browser/safe_browsing/safe_browsing_database.cc b/chrome/browser/safe_browsing/safe_browsing_database.cc
index 39954d6..ce2483c 100644
--- a/chrome/browser/safe_browsing/safe_browsing_database.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_database.cc
@@ -13,12 +13,12 @@
 #include "base/metrics/histogram.h"
 #include "base/metrics/stats_counters.h"
 #include "base/process_util.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/safe_browsing/prefix_set.h"
 #include "chrome/browser/safe_browsing/safe_browsing_store_file.h"
 #include "content/public/browser/browser_thread.h"
 #include "crypto/sha2.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 #if defined(OS_MACOSX)
 #include "base/mac/mac_util.h"
@@ -1486,7 +1486,7 @@
   // TODO(shess): Track failure to delete?
   base::FilePath bloom_filter_filename =
       BloomFilterForFilename(browse_filename_);
-  file_util::Delete(bloom_filter_filename, false);
+  base::Delete(bloom_filter_filename, false);
 
   const base::TimeTicks before = base::TimeTicks::Now();
   browse_prefix_set_.reset(safe_browsing::PrefixSet::LoadFile(
@@ -1522,24 +1522,24 @@
 
   base::FilePath bloom_filter_filename =
       BloomFilterForFilename(browse_filename_);
-  const bool r5 = file_util::Delete(bloom_filter_filename, false);
+  const bool r5 = base::Delete(bloom_filter_filename, false);
   if (!r5)
     RecordFailure(FAILURE_DATABASE_FILTER_DELETE);
 
-  const bool r6 = file_util::Delete(browse_prefix_set_filename_, false);
+  const bool r6 = base::Delete(browse_prefix_set_filename_, false);
   if (!r6)
     RecordFailure(FAILURE_BROWSE_PREFIX_SET_DELETE);
 
-  const bool r7 = file_util::Delete(extension_blacklist_filename_, false);
+  const bool r7 = base::Delete(extension_blacklist_filename_, false);
   if (!r7)
     RecordFailure(FAILURE_EXTENSION_BLACKLIST_DELETE);
 
-  const bool r8 = file_util::Delete(side_effect_free_whitelist_filename_,
+  const bool r8 = base::Delete(side_effect_free_whitelist_filename_,
                                     false);
   if (!r8)
     RecordFailure(FAILURE_SIDE_EFFECT_FREE_WHITELIST_DELETE);
 
-  const bool r9 = file_util::Delete(
+  const bool r9 = base::Delete(
       side_effect_free_whitelist_prefix_set_filename_,
       false);
   if (!r9)
diff --git a/chrome/browser/safe_browsing/safe_browsing_database_unittest.cc b/chrome/browser/safe_browsing/safe_browsing_database_unittest.cc
index ca61644..3b61ce7 100644
--- a/chrome/browser/safe_browsing/safe_browsing_database_unittest.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_database_unittest.cc
@@ -8,17 +8,17 @@
 #include "base/files/scoped_temp_dir.h"
 #include "base/logging.h"
 #include "base/message_loop.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/safe_browsing/safe_browsing_database.h"
 #include "chrome/browser/safe_browsing/safe_browsing_store_file.h"
 #include "chrome/browser/safe_browsing/safe_browsing_store_unittest_helper.h"
 #include "content/public/test/test_browser_thread.h"
 #include "crypto/sha2.h"
-#include "googleurl/src/gurl.h"
 #include "sql/connection.h"
 #include "sql/statement.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/platform_test.h"
+#include "url/gurl.h"
 
 using base::Time;
 using content::BrowserThread;
@@ -1658,7 +1658,7 @@
       &matching_list, &prefix_hits, &full_hashes, now));
 
   // If there is no filter file, the database cannot find malware urls.
-  file_util::Delete(filter_file, false);
+  base::Delete(filter_file, false);
   ASSERT_FALSE(file_util::PathExists(filter_file));
   database_.reset(new SafeBrowsingDatabaseNew);
   database_->Init(database_filename_);
diff --git a/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc b/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc
index 3254a6c..17522f6 100644
--- a/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc
@@ -17,7 +17,7 @@
 #include "base/prefs/pref_service.h"
 #include "base/strings/string_split.h"
 #include "base/test/thread_test_helper.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/prerender/prerender_manager.h"
 #include "chrome/browser/profiles/profile.h"
diff --git a/chrome/browser/safe_browsing/safe_browsing_store.h b/chrome/browser/safe_browsing/safe_browsing_store.h
index 196f6c1..917e357 100644
--- a/chrome/browser/safe_browsing/safe_browsing_store.h
+++ b/chrome/browser/safe_browsing/safe_browsing_store.h
@@ -11,7 +11,7 @@
 #include "base/basictypes.h"
 #include "base/callback_forward.h"
 #include "base/containers/hash_tables.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/safe_browsing/safe_browsing_util.h"
 
 namespace base {
diff --git a/chrome/browser/safe_browsing/safe_browsing_store_file.cc b/chrome/browser/safe_browsing/safe_browsing_store_file.cc
index bdc5232..234716c 100644
--- a/chrome/browser/safe_browsing/safe_browsing_store_file.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_store_file.cc
@@ -186,7 +186,7 @@
                            static_cast<int>(size / 1024));
     }
 
-    if (file_util::Delete(original_filename, false)) {
+    if (base::Delete(original_filename, false)) {
       RecordFormatEvent(FORMAT_EVENT_DELETED_ORIGINAL);
     } else {
       RecordFormatEvent(FORMAT_EVENT_DELETED_ORIGINAL_FAILED);
@@ -196,7 +196,7 @@
     // the weeds.
     const base::FilePath journal_filename(
         current_filename.DirName().AppendASCII("Safe Browsing-journal"));
-    file_util::Delete(journal_filename, false);
+    base::Delete(journal_filename, false);
   }
 }
 
@@ -654,12 +654,12 @@
 
   // Close the file handle and swizzle the file into place.
   new_file_.reset();
-  if (!file_util::Delete(filename_, false) &&
+  if (!base::Delete(filename_, false) &&
       file_util::PathExists(filename_))
     return false;
 
   const base::FilePath new_filename = TemporaryFileForFilename(filename_);
-  if (!file_util::Move(new_filename, filename_))
+  if (!base::Move(new_filename, filename_))
     return false;
 
   // Record counts before swapping to caller.
@@ -735,14 +735,14 @@
 
 // static
 bool SafeBrowsingStoreFile::DeleteStore(const base::FilePath& basename) {
-  if (!file_util::Delete(basename, false) &&
+  if (!base::Delete(basename, false) &&
       file_util::PathExists(basename)) {
     NOTREACHED();
     return false;
   }
 
   const base::FilePath new_filename = TemporaryFileForFilename(basename);
-  if (!file_util::Delete(new_filename, false) &&
+  if (!base::Delete(new_filename, false) &&
       file_util::PathExists(new_filename)) {
     NOTREACHED();
     return false;
@@ -754,7 +754,7 @@
   const base::FilePath journal_filename(
       basename.value() + FILE_PATH_LITERAL("-journal"));
   if (file_util::PathExists(journal_filename))
-    file_util::Delete(journal_filename, false);
+    base::Delete(journal_filename, false);
 
   return true;
 }
diff --git a/chrome/browser/safe_browsing/safe_browsing_test.cc b/chrome/browser/safe_browsing/safe_browsing_test.cc
index b33bc2e..fe2e14e 100644
--- a/chrome/browser/safe_browsing/safe_browsing_test.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_test.cc
@@ -29,7 +29,7 @@
 #include "base/test/test_timeouts.h"
 #include "base/threading/platform_thread.h"
 #include "base/threading/thread.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/safe_browsing/database_manager.h"
diff --git a/chrome/browser/safe_browsing/safe_browsing_util.cc b/chrome/browser/safe_browsing/safe_browsing_util.cc
index c979f2f..53d5a99 100644
--- a/chrome/browser/safe_browsing/safe_browsing_util.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_util.cc
@@ -9,9 +9,9 @@
 #include "base/strings/stringprintf.h"
 #include "chrome/browser/google/google_util.h"
 #include "crypto/sha2.h"
-#include "googleurl/src/gurl.h"
-#include "googleurl/src/url_util.h"
 #include "net/base/escape.h"
+#include "url/gurl.h"
+#include "url/url_util.h"
 
 #if defined(OS_WIN)
 #include "chrome/installer/util/browser_distribution.h"
diff --git a/chrome/browser/safe_browsing/safe_browsing_util_unittest.cc b/chrome/browser/safe_browsing/safe_browsing_util_unittest.cc
index d43c20e..20b033b 100644
--- a/chrome/browser/safe_browsing/safe_browsing_util_unittest.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_util_unittest.cc
@@ -7,8 +7,8 @@
 #include "base/strings/stringprintf.h"
 #include "chrome/browser/safe_browsing/safe_browsing_util.h"
 #include "crypto/sha2.h"
-#include "googleurl/src/gurl.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
 
 namespace {
 
diff --git a/chrome/browser/safe_browsing/sandboxed_zip_analyzer.cc b/chrome/browser/safe_browsing/sandboxed_zip_analyzer.cc
index 3d93e67..6e97585 100644
--- a/chrome/browser/safe_browsing/sandboxed_zip_analyzer.cc
+++ b/chrome/browser/safe_browsing/sandboxed_zip_analyzer.cc
@@ -26,7 +26,10 @@
 SandboxedZipAnalyzer::SandboxedZipAnalyzer(
     const base::FilePath& zip_file,
     const ResultCallback& result_callback)
-    : zip_file_(zip_file), callback_(result_callback) {}
+    : zip_file_(zip_file),
+      callback_(result_callback),
+      callback_called_(false) {
+}
 
 void SandboxedZipAnalyzer::Start() {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
@@ -103,14 +106,11 @@
 void SandboxedZipAnalyzer::OnAnalyzeZipFileFinished(
     const zip_analyzer::Results& results) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-  BrowserThread::PostTask(
-      BrowserThread::UI, FROM_HERE,
-      base::Bind(&SandboxedZipAnalyzer::RunCallback, this, results));
-}
-
-void SandboxedZipAnalyzer::RunCallback(const zip_analyzer::Results& results) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  callback_.Run(results);
+  if (callback_called_)
+    return;
+  BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+                          base::Bind(callback_, results));
+  callback_called_ = true;
 }
 
 void SandboxedZipAnalyzer::StartProcessOnIOThread() {
diff --git a/chrome/browser/safe_browsing/sandboxed_zip_analyzer.h b/chrome/browser/safe_browsing/sandboxed_zip_analyzer.h
index 5936bc0..81c1b90 100644
--- a/chrome/browser/safe_browsing/sandboxed_zip_analyzer.h
+++ b/chrome/browser/safe_browsing/sandboxed_zip_analyzer.h
@@ -19,9 +19,6 @@
 #include "content/public/browser/utility_process_host.h"
 #include "content/public/browser/utility_process_host_client.h"
 
-namespace base {
-class FilePath;
-}
 namespace IPC {
 class Message;
 }
@@ -64,15 +61,14 @@
   // Launches the utility process.  Must run on the IO thread.
   void StartProcessOnIOThread();
 
-  // Runs the caller-supplied callback.
-  void RunCallback(const zip_analyzer::Results& results);
-
   const base::FilePath zip_file_;
   // Once we have opened the file, we store the handle so that we can use it
   // once the utility process has launched.
   base::PlatformFile zip_platform_file_;
   base::WeakPtr<content::UtilityProcessHost> utility_process_host_;
   const ResultCallback callback_;
+  // Initialized on the UI thread, but only accessed on the IO thread.
+  bool callback_called_;
 
   DISALLOW_COPY_AND_ASSIGN(SandboxedZipAnalyzer);
 };
diff --git a/chrome/browser/safe_browsing/two_phase_uploader.h b/chrome/browser/safe_browsing/two_phase_uploader.h
index c10cf7b..1055529 100644
--- a/chrome/browser/safe_browsing/two_phase_uploader.h
+++ b/chrome/browser/safe_browsing/two_phase_uploader.h
@@ -12,8 +12,8 @@
 #include "base/files/file_path.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/threading/non_thread_safe.h"
-#include "googleurl/src/gurl.h"
 #include "net/url_request/url_request_context_getter.h"
+#include "url/gurl.h"
 
 namespace base {
 class TaskRunner;
diff --git a/chrome/browser/safe_browsing/ui_manager.h b/chrome/browser/safe_browsing/ui_manager.h
index b2e394f..5c896ca 100644
--- a/chrome/browser/safe_browsing/ui_manager.h
+++ b/chrome/browser/safe_browsing/ui_manager.h
@@ -15,10 +15,10 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/observer_list.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/safe_browsing/safe_browsing_util.h"
 #include "content/public/browser/notification_observer.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 class SafeBrowsingService;
 
diff --git a/chrome/browser/search/iframe_source.cc b/chrome/browser/search/iframe_source.cc
index d204ee7..58a5c06 100644
--- a/chrome/browser/search/iframe_source.cc
+++ b/chrome/browser/search/iframe_source.cc
@@ -12,10 +12,10 @@
 #include "chrome/common/url_constants.h"
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/web_contents.h"
-#include "googleurl/src/gurl.h"
 #include "grit/browser_resources.h"
 #include "net/url_request/url_request.h"
 #include "ui/base/resource/resource_bundle.h"
+#include "url/gurl.h"
 
 IframeSource::IframeSource() {
 }
diff --git a/chrome/browser/search/iframe_source_unittest.cc b/chrome/browser/search/iframe_source_unittest.cc
index b560c02..ceb80f4 100644
--- a/chrome/browser/search/iframe_source_unittest.cc
+++ b/chrome/browser/search/iframe_source_unittest.cc
@@ -13,11 +13,11 @@
 #include "content/public/browser/resource_request_info.h"
 #include "content/public/test/mock_resource_context.h"
 #include "content/public/test/test_browser_thread.h"
-#include "googleurl/src/gurl.h"
 #include "grit/browser_resources.h"
 #include "net/url_request/url_request.h"
 #include "net/url_request/url_request_context.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
 
 const int kNonInstantRendererPID = 0;
 const char kNonInstantOrigin[] = "http://evil";
diff --git a/chrome/browser/search/instant_extended_context_menu_observer.cc b/chrome/browser/search/instant_extended_context_menu_observer.cc
deleted file mode 100644
index fa42b67..0000000
--- a/chrome/browser/search/instant_extended_context_menu_observer.cc
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/search/instant_extended_context_menu_observer.h"
-
-#include "base/logging.h"
-#include "chrome/app/chrome_command_ids.h"
-#include "chrome/browser/search/search.h"
-
-InstantExtendedContextMenuObserver::InstantExtendedContextMenuObserver(
-    content::WebContents* contents)
-    : is_instant_overlay_(chrome::IsInstantOverlay(contents)) {
-}
-
-InstantExtendedContextMenuObserver::~InstantExtendedContextMenuObserver() {
-}
-
-bool InstantExtendedContextMenuObserver::IsCommandIdSupported(int command_id) {
-  switch (command_id) {
-    case IDC_BACK:
-    case IDC_FORWARD:
-    case IDC_PRINT:
-    case IDC_RELOAD:
-      return is_instant_overlay_;
-    default:
-      return false;
-  }
-}
-
-bool InstantExtendedContextMenuObserver::IsCommandIdEnabled(int command_id) {
-  DCHECK(IsCommandIdSupported(command_id));
-  return false;
-}
diff --git a/chrome/browser/search/instant_extended_context_menu_observer.h b/chrome/browser/search/instant_extended_context_menu_observer.h
deleted file mode 100644
index 4685ce6..0000000
--- a/chrome/browser/search/instant_extended_context_menu_observer.h
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_SEARCH_INSTANT_EXTENDED_CONTEXT_MENU_OBSERVER_H_
-#define CHROME_BROWSER_SEARCH_INSTANT_EXTENDED_CONTEXT_MENU_OBSERVER_H_
-
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "chrome/browser/tab_contents/render_view_context_menu_observer.h"
-
-namespace content {
-class WebContents;
-}
-
-// This class disables menu items which perform poorly in instant extended mode.
-class InstantExtendedContextMenuObserver
-    : public RenderViewContextMenuObserver {
- public:
-  explicit InstantExtendedContextMenuObserver(content::WebContents* contents);
-  virtual ~InstantExtendedContextMenuObserver();
-
-  // RenderViewContextMenuObserver implementation.
-  virtual bool IsCommandIdSupported(int command_id) OVERRIDE;
-  virtual bool IsCommandIdEnabled(int command_id) OVERRIDE;
-
- private:
-  // Whether the source web contents of the context menu corresponds to an
-  // Instant overlay.
-  const bool is_instant_overlay_;
-
-  DISALLOW_COPY_AND_ASSIGN(InstantExtendedContextMenuObserver);
-};
-
-#endif  // CHROME_BROWSER_SEARCH_INSTANT_EXTENDED_CONTEXT_MENU_OBSERVER_H_
diff --git a/chrome/browser/search/instant_io_context.cc b/chrome/browser/search/instant_io_context.cc
index c579f96..650618a 100644
--- a/chrome/browser/search/instant_io_context.cc
+++ b/chrome/browser/search/instant_io_context.cc
@@ -7,8 +7,8 @@
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/resource_context.h"
 #include "content/public/browser/resource_request_info.h"
-#include "googleurl/src/gurl.h"
 #include "net/url_request/url_request.h"
+#include "url/gurl.h"
 
 using content::BrowserThread;
 
diff --git a/chrome/browser/search/instant_service.cc b/chrome/browser/search/instant_service.cc
index ccf8c88..7718bc1 100644
--- a/chrome/browser/search/instant_service.cc
+++ b/chrome/browser/search/instant_service.cc
@@ -8,21 +8,19 @@
 
 #include "base/logging.h"
 #include "base/strings/string_number_conversions.h"
-#include "build/build_config.h"
 #include "chrome/browser/history/history_notifications.h"
 #include "chrome/browser/history/top_sites.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/search/instant_io_context.h"
 #include "chrome/browser/search/instant_service_factory.h"
+#include "chrome/browser/search/instant_service_observer.h"
 #include "chrome/browser/search/local_ntp_source.h"
 #include "chrome/browser/search/most_visited_iframe_source.h"
 #include "chrome/browser/search/search.h"
 #include "chrome/browser/search/suggestion_iframe_source.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/browser_instant_controller.h"
-#include "chrome/browser/ui/browser_list.h"
-#include "chrome/browser/ui/host_desktop.h"
-#include "chrome/browser/ui/search/instant_controller.h"
+#include "chrome/browser/themes/theme_properties.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"
@@ -32,8 +30,12 @@
 #include "content/public/browser/notification_types.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/url_data_source.h"
-#include "googleurl/src/gurl.h"
+#include "grit/theme_resources.h"
 #include "net/url_request/url_request.h"
+#include "ui/gfx/color_utils.h"
+#include "ui/gfx/image/image_skia.h"
+#include "ui/gfx/sys_color_change_listener.h"
+#include "url/gurl.h"
 
 using content::BrowserThread;
 
@@ -65,8 +67,14 @@
 
   // Set up the data sources that Instant uses on the NTP.
 #if defined(ENABLE_THEMES)
+  // Listen for theme installation.
+  registrar_.Add(this, chrome::NOTIFICATION_BROWSER_THEME_CHANGED,
+                 content::Source<ThemeService>(
+                     ThemeServiceFactory::GetForProfile(profile_)));
+
   content::URLDataSource::Add(profile, new ThemeSource(profile));
-#endif
+#endif  // defined(ENABLE_THEMES)
+
   content::URLDataSource::Add(profile, new ThumbnailSource(profile));
   content::URLDataSource::Add(profile, new FaviconSource(
       profile, FaviconSource::FAVICON));
@@ -94,6 +102,14 @@
   return process_ids_.find(process_id) != process_ids_.end();
 }
 
+void InstantService::AddObserver(InstantServiceObserver* observer) {
+  observers_.AddObserver(observer);
+}
+
+void InstantService::RemoveObserver(InstantServiceObserver* observer) {
+  observers_.RemoveObserver(observer);
+}
+
 void InstantService::DeleteMostVisitedItem(const GURL& url) {
   history::TopSites* top_sites = profile_->GetTopSites();
   if (!top_sites)
@@ -118,9 +134,17 @@
   top_sites->ClearBlacklistedURLs();
 }
 
-void InstantService::GetCurrentMostVisitedItems(
-    std::vector<InstantMostVisitedItem>* items) const {
-  *items = most_visited_items_;
+void InstantService::UpdateThemeInfo() {
+  // Update theme background info.
+  // Initialize |theme_info| if necessary.
+  if (!theme_info_)
+    OnThemeChanged(ThemeServiceFactory::GetForProfile(profile_));
+  else
+    OnThemeChanged(NULL);
+}
+
+void InstantService::UpdateMostVisitedItemsInfo() {
+  NotifyAboutMostVisitedItems();
 }
 
 void InstantService::Shutdown() {
@@ -164,6 +188,12 @@
       }
       break;
     }
+#if defined(ENABLE_THEMES)
+    case chrome::NOTIFICATION_BROWSER_THEME_CHANGED: {
+      OnThemeChanged(content::Source<ThemeService>(source).ptr());
+      break;
+    }
+#endif  // defined(ENABLE_THEMES)
     default:
       NOTREACHED() << "Unexpected notification type in InstantService.";
   }
@@ -171,8 +201,6 @@
 
 void InstantService::OnMostVisitedItemsReceived(
     const history::MostVisitedURLList& data) {
-  // Android doesn't use Browser/BrowserList. Do nothing for Android platform.
-#if !defined(OS_ANDROID)
   history::MostVisitedURLList reordered_data(data);
   history::TopSites::MaybeShuffle(&reordered_data);
 
@@ -184,27 +212,90 @@
     item.title = url.title;
     new_most_visited_items.push_back(item);
   }
-  if (chrome::AreMostVisitedItemsEqual(new_most_visited_items,
-                                       most_visited_items_)) {
+
+  most_visited_items_ = new_most_visited_items;
+  NotifyAboutMostVisitedItems();
+}
+
+void InstantService::NotifyAboutMostVisitedItems() {
+  FOR_EACH_OBSERVER(InstantServiceObserver, observers_,
+                    MostVisitedItemsChanged(most_visited_items_));
+}
+
+void InstantService::OnThemeChanged(ThemeService* theme_service) {
+  if (!theme_service) {
+    DCHECK(theme_info_.get());
+    FOR_EACH_OBSERVER(InstantServiceObserver, observers_,
+                      ThemeInfoChanged(*theme_info_));
     return;
   }
 
-  most_visited_items_ = new_most_visited_items;
+  // Get theme information from theme service.
+  theme_info_.reset(new ThemeBackgroundInfo());
 
-  const BrowserList* browser_list =
-      BrowserList::GetInstance(chrome::GetActiveDesktop());
-  for (BrowserList::const_iterator it = browser_list->begin();
-       it != browser_list->end(); ++it) {
-    if ((*it)->profile() != profile_ || !((*it)->instant_controller()))
-      continue;
+  // Set theme background color.
+  SkColor background_color =
+      theme_service->GetColor(ThemeProperties::COLOR_NTP_BACKGROUND);
+  if (gfx::IsInvertedColorScheme())
+    background_color = color_utils::InvertColor(background_color);
 
-    InstantController* controller = (*it)->instant_controller()->instant();
-    if (!controller)
-      continue;
-    // TODO(kmadhusu): It would be cleaner to have each InstantController
-    // register itself as an InstantServiceObserver and push out updates that
-    // way. Refer to crbug.com/246355 for more details.
-    controller->UpdateMostVisitedItems();
+  theme_info_->color_r = SkColorGetR(background_color);
+  theme_info_->color_g = SkColorGetG(background_color);
+  theme_info_->color_b = SkColorGetB(background_color);
+  theme_info_->color_a = SkColorGetA(background_color);
+
+  if (theme_service->HasCustomImage(IDR_THEME_NTP_BACKGROUND)) {
+    // Set theme id for theme background image url.
+    theme_info_->theme_id = theme_service->GetThemeID();
+
+    // Set theme background image horizontal alignment.
+    int alignment = 0;
+    theme_service->GetDisplayProperty(
+        ThemeProperties::NTP_BACKGROUND_ALIGNMENT, &alignment);
+    if (alignment & ThemeProperties::ALIGN_LEFT)
+      theme_info_->image_horizontal_alignment = THEME_BKGRND_IMAGE_ALIGN_LEFT;
+    else if (alignment & ThemeProperties::ALIGN_RIGHT)
+      theme_info_->image_horizontal_alignment = THEME_BKGRND_IMAGE_ALIGN_RIGHT;
+    else
+      theme_info_->image_horizontal_alignment = THEME_BKGRND_IMAGE_ALIGN_CENTER;
+
+    // Set theme background image vertical alignment.
+    if (alignment & ThemeProperties::ALIGN_TOP)
+      theme_info_->image_vertical_alignment = THEME_BKGRND_IMAGE_ALIGN_TOP;
+    else if (alignment & ThemeProperties::ALIGN_BOTTOM)
+      theme_info_->image_vertical_alignment = THEME_BKGRND_IMAGE_ALIGN_BOTTOM;
+    else
+      theme_info_->image_vertical_alignment = THEME_BKGRND_IMAGE_ALIGN_CENTER;
+
+    // Set theme backgorund image tiling.
+    int tiling = 0;
+    theme_service->GetDisplayProperty(ThemeProperties::NTP_BACKGROUND_TILING,
+                                      &tiling);
+    switch (tiling) {
+      case ThemeProperties::NO_REPEAT:
+        theme_info_->image_tiling = THEME_BKGRND_IMAGE_NO_REPEAT;
+        break;
+      case ThemeProperties::REPEAT_X:
+        theme_info_->image_tiling = THEME_BKGRND_IMAGE_REPEAT_X;
+        break;
+      case ThemeProperties::REPEAT_Y:
+        theme_info_->image_tiling = THEME_BKGRND_IMAGE_REPEAT_Y;
+        break;
+      case ThemeProperties::REPEAT:
+        theme_info_->image_tiling = THEME_BKGRND_IMAGE_REPEAT;
+        break;
+    }
+
+    // Set theme background image height.
+    gfx::ImageSkia* image = theme_service->GetImageSkiaNamed(
+        IDR_THEME_NTP_BACKGROUND);
+    DCHECK(image);
+    theme_info_->image_height = image->height();
+
+    theme_info_->has_attribution =
+       theme_service->HasCustomImage(IDR_THEME_NTP_ATTRIBUTION);
   }
-#endif
+
+  FOR_EACH_OBSERVER(InstantServiceObserver, observers_,
+                    ThemeInfoChanged(*theme_info_));
 }
diff --git a/chrome/browser/search/instant_service.h b/chrome/browser/search/instant_service.h
index 4832ded..1e0d6f3 100644
--- a/chrome/browser/search/instant_service.h
+++ b/chrome/browser/search/instant_service.h
@@ -13,7 +13,9 @@
 #include "base/basictypes.h"
 #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/observer_list.h"
 #include "chrome/browser/history/history_types.h"
 #include "chrome/common/instant_types.h"
 #include "components/browser_context_keyed_service/browser_context_keyed_service.h"
@@ -22,7 +24,9 @@
 
 class GURL;
 class InstantIOContext;
+class InstantServiceObserver;
 class Profile;
+class ThemeService;
 
 namespace net {
 class URLRequest;
@@ -40,6 +44,10 @@
   void AddInstantProcess(int process_id);
   bool IsInstantProcess(int process_id) const;
 
+  // Adds/Removes InstantService observers.
+  void AddObserver(InstantServiceObserver* observer);
+  void RemoveObserver(InstantServiceObserver* observer);
+
 #if defined(UNIT_TEST)
   int GetInstantProcessCount() const {
     return process_ids_.size();
@@ -60,9 +68,15 @@
   // Most Visited deletions.
   void UndoAllMostVisitedDeletions();
 
-  // Returns the last added InstantMostVisitedItems.
-  void GetCurrentMostVisitedItems(
-      std::vector<InstantMostVisitedItem>* items) const;
+  // Invoked by the InstantController to update theme information for NTP.
+  //
+  // TODO(kmadhusu): Invoking this from InstantController shouldn't be
+  // necessary. Investigate more and remove this from here.
+  void UpdateThemeInfo();
+
+  // Invoked by the InstantController to update most visited items details for
+  // NTP.
+  void UpdateMostVisitedItemsInfo();
 
  private:
   // Overridden from BrowserContextKeyedService:
@@ -78,6 +92,12 @@
   // SendMostVisitedItems.
   void OnMostVisitedItemsReceived(const history::MostVisitedURLList& data);
 
+  // Notifies the observer about the last known most visited items.
+  void NotifyAboutMostVisitedItems();
+
+  // Theme changed notification handler.
+  void OnThemeChanged(ThemeService* theme_service);
+
   Profile* const profile_;
 
   // The process ids associated with Instant processes.
@@ -86,6 +106,11 @@
   // InstantMostVisitedItems sent to the Instant Pages.
   std::vector<InstantMostVisitedItem> most_visited_items_;
 
+  // Theme-related data for NTP overlay to adopt themes.
+  scoped_ptr<ThemeBackgroundInfo> theme_info_;
+
+  ObserverList<InstantServiceObserver> observers_;
+
   content::NotificationRegistrar registrar_;
 
   scoped_refptr<InstantIOContext> instant_io_context_;
diff --git a/chrome/browser/search/instant_service_observer.h b/chrome/browser/search/instant_service_observer.h
new file mode 100644
index 0000000..c282c93
--- /dev/null
+++ b/chrome/browser/search/instant_service_observer.h
@@ -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.
+
+#ifndef CHROME_BROWSER_SEARCH_INSTANT_SERVICE_OBSERVER_H_
+#define CHROME_BROWSER_SEARCH_INSTANT_SERVICE_OBSERVER_H_
+
+#include <vector>
+
+struct InstantMostVisitedItem;
+struct ThemeBackgroundInfo;
+
+// InstantServiceObserver defines the observer interface for InstantService.
+class InstantServiceObserver {
+ public:
+  // Indicates that the user's custom theme has changed in some way.
+  virtual void ThemeInfoChanged(const ThemeBackgroundInfo&) = 0;
+
+  // Indicates that the most visited items has changed.
+  virtual void MostVisitedItemsChanged(
+      const std::vector<InstantMostVisitedItem>&) = 0;
+
+ protected:
+  virtual ~InstantServiceObserver() {}
+};
+
+#endif  // CHROME_BROWSER_SEARCH_INSTANT_SERVICE_OBSERVER_H_
diff --git a/chrome/browser/search/local_ntp_source.cc b/chrome/browser/search/local_ntp_source.cc
index 6c92cbe..3281a64 100644
--- a/chrome/browser/search/local_ntp_source.cc
+++ b/chrome/browser/search/local_ntp_source.cc
@@ -9,8 +9,9 @@
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/values.h"
+#include "chrome/browser/search/instant_io_context.h"
+#include "chrome/browser/search/search.h"
 #include "chrome/common/url_constants.h"
-#include "googleurl/src/gurl.h"
 #include "grit/browser_resources.h"
 #include "grit/generated_resources.h"
 #include "grit/ui_resources.h"
@@ -18,6 +19,7 @@
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/webui/jstemplate_builder.h"
+#include "url/gurl.h"
 
 namespace {
 
@@ -47,11 +49,8 @@
     IDR_LOCAL_OMNIBOX_POPUP_IMAGES_SEARCH_ICON_PNG, "image/png" },
   { "images/2x/search_icon.png",
     IDR_LOCAL_OMNIBOX_POPUP_IMAGES_2X_SEARCH_ICON_PNG, "image/png" },
-  { "images/google_logo.png", IDR_LOCAL_NTP_IMAGES_LOGO_PNG, "image/png" },
   { "images/2x/google_logo.png",
     IDR_LOCAL_NTP_IMAGES_2X_LOGO_PNG, "image/png" },
-  { "images/white_google_logo.png",
-    IDR_LOCAL_NTP_IMAGES_WHITE_LOGO_PNG, "image/png" },
   { "images/2x/white_google_logo.png",
     IDR_LOCAL_NTP_IMAGES_2X_WHITE_LOGO_PNG, "image/png" },
 };
@@ -71,6 +70,8 @@
 // Returns a JS dictionary of translated strings for the local NTP.
 std::string GetTranslatedStrings() {
   base::DictionaryValue translated_strings;
+  if (chrome::ShouldShowRecentTabsOnNTP())
+    AddString(&translated_strings, "recentTabs", IDS_RECENT_TABS_MENU);
   AddString(&translated_strings, "thumbnailRemovedNotification",
             IDS_NEW_TAB_THUMBNAIL_REMOVED_NOTIFICATION);
   AddString(&translated_strings, "removeThumbnailTooltip",
@@ -135,6 +136,8 @@
 bool LocalNtpSource::ShouldServiceRequest(
     const net::URLRequest* request) const {
   DCHECK(request->url().host() == chrome::kChromeSearchLocalNtpHost);
+  if (!InstantIOContext::ShouldServiceRequest(request))
+    return false;
 
   if (request->url().SchemeIs(chrome::kChromeSearchScheme)) {
     DCHECK(StartsWithASCII(request->url().path(), "/", true));
diff --git a/chrome/browser/search/most_visited_iframe_source.cc b/chrome/browser/search/most_visited_iframe_source.cc
index 132383b..5f9fed9 100644
--- a/chrome/browser/search/most_visited_iframe_source.cc
+++ b/chrome/browser/search/most_visited_iframe_source.cc
@@ -7,9 +7,9 @@
 #include "base/metrics/histogram.h"
 #include "base/strings/string_number_conversions.h"
 #include "chrome/common/url_constants.h"
-#include "googleurl/src/gurl.h"
 #include "grit/browser_resources.h"
 #include "net/base/url_util.h"
+#include "url/gurl.h"
 
 namespace {
 
diff --git a/chrome/browser/search/search.cc b/chrome/browser/search/search.cc
index 1765cee..30cf8be 100644
--- a/chrome/browser/search/search.cc
+++ b/chrome/browser/search/search.cc
@@ -11,6 +11,7 @@
 #include "base/rand_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
+#include "chrome/browser/google/google_util.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/search/instant_service.h"
 #include "chrome/browser/search/instant_service_factory.h"
@@ -20,6 +21,8 @@
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_instant_controller.h"
 #include "chrome/browser/ui/browser_iterator.h"
+#include "chrome/browser/ui/search/search_model.h"
+#include "chrome/browser/ui/search/search_tab_helper.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/url_constants.h"
@@ -62,9 +65,9 @@
 // Sets the default state for the Instant checkbox.
 const char kInstantSearchResultsFlagName[] = "instant";
 
-const char kLocalOnlyFlagName[] = "local_only";
-const char kPreloadLocalOnlyNTPFlagName[] = "preload_local_only_ntp";
 const char kUseRemoteNTPOnStartupFlagName[] = "use_remote_ntp_on_startup";
+const char kShowNtpFlagName[] = "show_ntp";
+const char kRecentTabsOnNTPFlagName[] = "show_recent_tabs";
 
 // Constants for the field trial name and group prefix.
 const char kInstantExtendedFieldTrialName[] = "InstantExtended";
@@ -85,10 +88,13 @@
   return NULL;
 }
 
-GURL TemplateURLRefToGURL(const TemplateURLRef& ref, int start_margin) {
+GURL TemplateURLRefToGURL(const TemplateURLRef& ref,
+                          int start_margin,
+                          bool append_extra_query_params) {
   TemplateURLRef::SearchTermsArgs search_terms_args =
       TemplateURLRef::SearchTermsArgs(string16());
   search_terms_args.omnibox_start_margin = start_margin;
+  search_terms_args.append_extra_query_params = append_extra_query_params;
   return GURL(ref.ReplaceSearchTerms(search_terms_args));
 }
 
@@ -100,22 +106,16 @@
            other_url.SchemeIs(chrome::kHttpScheme)));
 }
 
-bool IsCommandLineInstantURL(const GURL& url) {
-  const CommandLine* cl = CommandLine::ForCurrentProcess();
-  const GURL instant_url(cl->GetSwitchValueASCII(switches::kInstantURL));
-  return instant_url.is_valid() && MatchesOrigin(url, instant_url);
-}
-
 bool MatchesAnySearchURL(const GURL& url, TemplateURL* template_url) {
   GURL search_url =
-      TemplateURLRefToGURL(template_url->url_ref(), kDisableStartMargin);
+      TemplateURLRefToGURL(template_url->url_ref(), kDisableStartMargin, false);
   if (search_url.is_valid() && MatchesOriginAndPath(url, search_url))
     return true;
 
   // "URLCount() - 1" because we already tested url_ref above.
   for (size_t i = 0; i < template_url->URLCount() - 1; ++i) {
     TemplateURLRef ref(template_url, i);
-    search_url = TemplateURLRefToGURL(ref, kDisableStartMargin);
+    search_url = TemplateURLRefToGURL(ref, kDisableStartMargin, false);
     if (search_url.is_valid() && MatchesOriginAndPath(url, search_url))
       return true;
   }
@@ -124,36 +124,121 @@
 }
 
 void RecordInstantExtendedOptInState() {
-  if (!instant_extended_opt_in_state_gate) {
-    instant_extended_opt_in_state_gate = true;
-    OptInState state = INSTANT_EXTENDED_NOT_SET;
-    const CommandLine* command_line = CommandLine::ForCurrentProcess();
-    if (command_line->HasSwitch(
-        switches::kDisableLocalOnlyInstantExtendedAPI)) {
-      if (command_line->HasSwitch(switches::kDisableInstantExtendedAPI)) {
-        state = INSTANT_EXTENDED_OPT_OUT_BOTH;
-      } else {
-        state = INSTANT_EXTENDED_OPT_OUT_LOCAL;
-      }
-    } else if (command_line->HasSwitch(switches::kDisableInstantExtendedAPI)) {
-      state = INSTANT_EXTENDED_OPT_OUT;
-    } else if (command_line->HasSwitch(
-        switches::kEnableLocalOnlyInstantExtendedAPI)) {
-      state = INSTANT_EXTENDED_OPT_IN_LOCAL;
-    } else if (command_line->HasSwitch(switches::kEnableInstantExtendedAPI)) {
-      state = INSTANT_EXTENDED_OPT_IN;
-    }
+  if (instant_extended_opt_in_state_gate)
+    return;
 
-    UMA_HISTOGRAM_ENUMERATION("InstantExtended.OptInState", state,
-                              INSTANT_EXTENDED_OPT_IN_STATE_ENUM_COUNT);
-  }
+  instant_extended_opt_in_state_gate = true;
+  OptInState state = INSTANT_EXTENDED_NOT_SET;
+  const CommandLine* command_line = CommandLine::ForCurrentProcess();
+  if (command_line->HasSwitch(switches::kDisableInstantExtendedAPI))
+    state = INSTANT_EXTENDED_OPT_OUT;
+  else if (command_line->HasSwitch(switches::kEnableInstantExtendedAPI))
+    state = INSTANT_EXTENDED_OPT_IN;
+
+  UMA_HISTOGRAM_ENUMERATION("InstantExtended.NewOptInState", state,
+                            INSTANT_EXTENDED_OPT_IN_STATE_ENUM_COUNT);
 }
 
-// Helper for EmbeddedSearchPageVersion. Does not check if in incognito mode.
-uint64 EmbeddedSearchPageVersionHelper() {
-  // No server-side changes if the local-only Instant Extended is enabled.
-  if (IsLocalOnlyInstantExtendedAPIEnabled())
-    return kEmbeddedPageVersionDisabled;
+// Returns true if |contents| is rendered inside the Instant process for
+// |profile|.
+bool IsRenderedInInstantProcess(const content::WebContents* contents,
+                                Profile* profile) {
+  const content::RenderProcessHost* process_host =
+      contents->GetRenderProcessHost();
+  if (!process_host)
+    return false;
+
+  const InstantService* instant_service =
+      InstantServiceFactory::GetForProfile(profile);
+  if (!instant_service)
+    return false;
+
+  return instant_service->IsInstantProcess(process_host->GetID());
+}
+
+// Returns true if |url| passes some basic checks that must succeed for it to be
+// usable as an instant URL:
+// (1) It contains the search terms replacement key of |template_url|, which is
+//     expected to be the TemplateURL* for the default search provider.
+// (2) Either it has a secure scheme, or else the user has manually specified a
+//     --google-base-url and it uses that base URL.  (This allows testers to use
+//     --google-base-url to point at non-HTTPS servers, which eases testing.)
+bool IsSuitableURLForInstant(const GURL& url, const TemplateURL* template_url) {
+  return template_url->HasSearchTermsReplacementKey(url) &&
+      (url.SchemeIsSecure() ||
+       google_util::StartsWithCommandLineGoogleBaseURL(url));
+}
+
+// Returns true if |url| can be used as an Instant URL for |profile|.
+bool IsInstantURL(const GURL& url, Profile* profile) {
+  if (!url.is_valid())
+    return false;
+
+  TemplateURL* template_url = GetDefaultSearchProviderTemplateURL(profile);
+  if (!template_url)
+    return false;
+
+  const bool extended_api_enabled = IsInstantExtendedAPIEnabled();
+  if (extended_api_enabled && !IsSuitableURLForInstant(url, template_url))
+    return false;
+
+  const TemplateURLRef& instant_url_ref = template_url->instant_url_ref();
+  const GURL instant_url =
+      TemplateURLRefToGURL(instant_url_ref, kDisableStartMargin, false);
+  return instant_url.is_valid() &&
+      (MatchesOriginAndPath(url, instant_url) ||
+       (extended_api_enabled && MatchesAnySearchURL(url, template_url)));
+}
+
+string16 GetSearchTermsImpl(const content::WebContents* contents,
+                            const content::NavigationEntry* entry) {
+  if (!contents || !IsQueryExtractionEnabled())
+    return string16();
+
+  // For security reasons, don't extract search terms if the page is not being
+  // rendered in the privileged Instant renderer process. This is to protect
+  // against a malicious page somehow scripting the search results page and
+  // faking search terms in the URL. Random pages can't get into the Instant
+  // renderer and scripting doesn't work cross-process, so if the page is in
+  // the Instant process, we know it isn't being exploited.
+  // Since iOS and Android doesn't use the instant framework, these checks are
+  // disabled for the two platforms.
+  Profile* profile = Profile::FromBrowserContext(contents->GetBrowserContext());
+#if !defined(OS_IOS) && !defined(OS_ANDROID)
+  if (!IsRenderedInInstantProcess(contents, profile) &&
+      ((entry == contents->GetController().GetLastCommittedEntry()) ||
+       !ShouldAssignURLToInstantRenderer(entry->GetURL(), profile)))
+    return string16();
+#endif  // !defined(OS_IOS) && !defined(OS_ANDROID)
+  // Check to see if search terms have already been extracted.
+  string16 search_terms = GetSearchTermsFromNavigationEntry(entry);
+  if (!search_terms.empty())
+    return search_terms;
+
+  // Otherwise, extract from the URL.
+  return GetSearchTermsFromURL(profile, entry->GetVirtualURL());
+}
+
+}  // namespace
+
+// Negative start-margin values prevent the "es_sm" parameter from being used.
+const int kDisableStartMargin = -1;
+
+bool IsInstantExtendedAPIEnabled() {
+#if defined(OS_IOS) || defined(OS_ANDROID)
+  return false;
+#else
+  // On desktop, query extraction is part of Instant extended, so if one is
+  // enabled, the other is too.
+  RecordInstantExtendedOptInState();
+  return IsQueryExtractionEnabled();
+#endif  // defined(OS_IOS) || defined(OS_ANDROID)
+}
+
+// Determine what embedded search page version to request from the user's
+// default search provider. If 0, the embedded search UI should not be enabled.
+uint64 EmbeddedSearchPageVersion() {
+  RecordInstantExtendedOptInState();
 
   // Check the command-line/about:flags setting first, which should have
   // precedence and allows the trial to not be reported (if it's never queried).
@@ -177,156 +262,15 @@
   return kEmbeddedPageVersionDisabled;
 }
 
-// Returns true if |contents| is rendered inside the Instant process for
-// |profile|.
-bool IsRenderedInInstantProcess(const content::WebContents* contents,
-                                Profile* profile) {
-  const content::RenderProcessHost* process_host =
-      contents->GetRenderProcessHost();
-  if (!process_host)
-    return false;
-
-  const InstantService* instant_service =
-      InstantServiceFactory::GetForProfile(profile);
-  if (!instant_service)
-    return false;
-
-  return instant_service->IsInstantProcess(process_host->GetID());
+bool IsQueryExtractionEnabled() {
+  return EmbeddedSearchPageVersion() != kEmbeddedPageVersionDisabled;
 }
 
-// Returns true if |url| can be used as an Instant URL for |profile|.
-bool IsInstantURL(const GURL& url, Profile* profile) {
-  TemplateURL* template_url = GetDefaultSearchProviderTemplateURL(profile);
-  if (!template_url)
-    return false;
-
-  const TemplateURLRef& instant_url_ref = template_url->instant_url_ref();
-  const bool extended_api_enabled = IsInstantExtendedAPIEnabled();
-  GURL effective_url = url;
-
-  if (IsCommandLineInstantURL(url))
-    effective_url = CoerceCommandLineURLToTemplateURL(url, instant_url_ref,
-                                                      kDisableStartMargin);
-
-  if (!effective_url.is_valid())
-    return false;
-
-  if (extended_api_enabled && !effective_url.SchemeIsSecure())
-    return false;
-
-  if (extended_api_enabled &&
-      !template_url->HasSearchTermsReplacementKey(effective_url))
-    return false;
-
-  const GURL instant_url =
-      TemplateURLRefToGURL(instant_url_ref, kDisableStartMargin);
-  if (!instant_url.is_valid())
-    return false;
-
-  if (MatchesOriginAndPath(effective_url, instant_url))
-    return true;
-
-  if (extended_api_enabled && MatchesAnySearchURL(effective_url, template_url))
-    return true;
-
-  return false;
-}
-
-string16 GetSearchTermsImpl(const content::WebContents* contents,
-                            const content::NavigationEntry* entry) {
-  // For security reasons, don't extract search terms if the page is not being
-  // rendered in the privileged Instant renderer process. This is to protect
-  // against a malicious page somehow scripting the search results page and
-  // faking search terms in the URL. Random pages can't get into the Instant
-  // renderer and scripting doesn't work cross-process, so if the page is in
-  // the Instant process, we know it isn't being exploited.
-  // Since iOS and Android doesn't use the instant framework, these checks are
-  // disabled for the two platforms.
-  Profile* profile = Profile::FromBrowserContext(contents->GetBrowserContext());
-
-  if (!IsQueryExtractionEnabled(profile))
-    return string16();
-
-#if !defined(OS_IOS) && !defined(OS_ANDROID)
-  if (!IsRenderedInInstantProcess(contents, profile) &&
-      (contents->GetController().GetLastCommittedEntry() == entry ||
-       !ShouldAssignURLToInstantRenderer(entry->GetURL(), profile)))
-    return string16();
-#endif  // !defined(OS_IOS) && !defined(OS_ANDROID)
-  // Check to see if search terms have already been extracted.
-  string16 search_terms = GetSearchTermsFromNavigationEntry(entry);
-  if (!search_terms.empty())
-    return search_terms;
-
-  // Otherwise, extract from the URL.
-  return GetSearchTermsFromURL(profile, entry->GetVirtualURL());
-}
-
-}  // namespace
-
-// Negative start-margin values prevent the "es_sm" parameter from being used.
-const int kDisableStartMargin = -1;
-
-bool IsInstantExtendedAPIEnabled() {
-#if defined(OS_IOS) || defined(OS_ANDROID)
-  return false;
-#else
-  // TODO(dougw): Switch to EmbeddedSearchPageVersion after the proper
-  // solution to Issue 232065 has been implemented.
-  return EmbeddedSearchPageVersionHelper() ||
-      IsLocalOnlyInstantExtendedAPIEnabled();
-#endif  // defined(OS_IOS) || defined(OS_ANDROID)
-}
-
-// Determine what embedded search page version to request from the user's
-// default search provider. If 0, the embedded search UI should not be enabled.
-uint64 EmbeddedSearchPageVersion(Profile* profile) {
-  // Disable for incognito. Temporary fix for Issue 232065.
-#if !defined(OS_IOS) && !defined(OS_ANDROID)
-  if (!profile || profile->IsOffTheRecord())
-    return kEmbeddedPageVersionDisabled;
-#endif  // !defined(OS_IOS) && !defined(OS_ANDROID)
-  return EmbeddedSearchPageVersionHelper();
-}
-
-bool IsQueryExtractionEnabled(Profile* profile) {
-  return EmbeddedSearchPageVersion(profile) != kEmbeddedPageVersionDisabled;
-}
-
-bool IsLocalOnlyInstantExtendedAPIEnabled() {
-  RecordInstantExtendedOptInState();
-  const CommandLine* command_line = CommandLine::ForCurrentProcess();
-  if (command_line->HasSwitch(switches::kDisableLocalOnlyInstantExtendedAPI) ||
-      command_line->HasSwitch(switches::kDisableInstantExtendedAPI)) {
-    return false;
-  }
-  if (command_line->HasSwitch(switches::kEnableLocalOnlyInstantExtendedAPI))
-    return true;
-
-  FieldTrialFlags flags;
-  if (GetFieldTrialInfo(
-          base::FieldTrialList::FindFullName(kInstantExtendedFieldTrialName),
-          &flags, NULL)) {
-    return GetBoolValueForFlagWithDefault(kLocalOnlyFlagName, false, flags);
-  }
-  return false;
-}
-
-string16 GetSearchTermsFromURL(Profile* profile, const GURL& in_url) {
-  GURL url(in_url);
+string16 GetSearchTermsFromURL(Profile* profile, const GURL& url) {
   string16 search_terms;
-
   TemplateURL* template_url = GetDefaultSearchProviderTemplateURL(profile);
-  if (!template_url)
-    return string16();
-
-  if (IsCommandLineInstantURL(url))
-    url = CoerceCommandLineURLToTemplateURL(url, template_url->url_ref(),
-                                            kDisableStartMargin);
-
-  if (url.SchemeIsSecure() && template_url->HasSearchTermsReplacementKey(url))
+  if (template_url && IsSuitableURLForInstant(url, template_url))
     template_url->ExtractSearchTermsFromURL(url, &search_terms);
-
   return search_terms;
 }
 
@@ -347,6 +291,15 @@
   if (!entry)
     return string16();
 
+  // Return immediately if the page does not support Instant.
+  const SearchTabHelper* search_tab_helper =
+      SearchTabHelper::FromWebContents(contents);
+  if (search_tab_helper) {
+    const SearchModel* search_model = search_tab_helper->model();
+    if (search_model && search_model->instant_support() == INSTANT_SUPPORT_NO)
+      return string16();
+  }
+
   return GetSearchTermsImpl(contents, entry);
 }
 
@@ -372,11 +325,17 @@
     return false;
 
   Profile* profile = Profile::FromBrowserContext(contents->GetBrowserContext());
-  return IsInstantExtendedAPIEnabled() &&
-         IsRenderedInInstantProcess(contents, profile) &&
-         (IsInstantURL(entry->GetVirtualURL(), profile) ||
-          entry->GetVirtualURL() == GetLocalInstantURL(profile)) &&
-         GetSearchTermsImpl(contents, entry).empty();
+  bool is_instant_url = IsInstantURL(entry->GetVirtualURL(), profile);
+  bool is_local_ntp = entry->GetVirtualURL() == GetLocalInstantURL(profile);
+  if (!IsInstantExtendedAPIEnabled() ||
+      !IsRenderedInInstantProcess(contents, profile) ||
+      !(is_instant_url || is_local_ntp)) {
+    return false;
+  }
+
+  bool has_search_terms = !GetSearchTermsImpl(contents, entry).empty();
+  bool is_online_ntp = is_instant_url && !has_search_terms;
+  return is_online_ntp || is_local_ntp;
 }
 
 void RegisterInstantUserPrefs(user_prefs::PrefRegistrySyncable* registry) {
@@ -424,8 +383,8 @@
 }
 
 bool IsInstantCheckboxEnabled(Profile* profile) {
+  RecordInstantExtendedOptInState();
   return IsInstantExtendedAPIEnabled() &&
-         !IsLocalOnlyInstantExtendedAPIEnabled() &&
          DefaultSearchProviderSupportsInstant(profile) &&
          IsSuggestPrefEnabled(profile);
 }
@@ -451,11 +410,6 @@
   if (!IsInstantExtendedAPIEnabled())
     return l10n_util::GetStringUTF16(IDS_INSTANT_CHECKBOX_NO_EXTENDED_API);
 
-  if (IsLocalOnlyInstantExtendedAPIEnabled()) {
-    return l10n_util::GetStringUTF16(
-        IDS_INSTANT_CHECKBOX_LOCAL_ONLY_EXTENDED_API);
-  }
-
   if (!DefaultSearchProviderSupportsInstant(profile)) {
     const TemplateURL* provider = GetDefaultSearchProviderTemplateURL(profile);
     if (!provider) {
@@ -484,37 +438,25 @@
   if (!IsInstantCheckboxEnabled(profile))
     return GURL();
 
-  const bool extended_api_enabled = IsInstantExtendedAPIEnabled();
-
   // In non-extended mode, the checkbox must be checked.
+  const bool extended_api_enabled = IsInstantExtendedAPIEnabled();
   if (!extended_api_enabled && !IsInstantCheckboxChecked(profile))
     return GURL();
 
   TemplateURL* template_url = GetDefaultSearchProviderTemplateURL(profile);
-  CommandLine* cl = CommandLine::ForCurrentProcess();
-  if (cl->HasSwitch(switches::kInstantURL)) {
-    GURL instant_url(cl->GetSwitchValueASCII(switches::kInstantURL));
-    if (extended_api_enabled) {
-      // Extended mode won't work if the search terms replacement key is absent.
-      GURL coerced_url = CoerceCommandLineURLToTemplateURL(
-          instant_url, template_url->instant_url_ref(), start_margin);
-      if (!template_url->HasSearchTermsReplacementKey(coerced_url))
-        return GURL();
-    }
-    return instant_url;
-  }
-
   GURL instant_url =
-      TemplateURLRefToGURL(template_url->instant_url_ref(), start_margin);
-  if (extended_api_enabled && !instant_url.SchemeIsSecure()) {
-    // Extended mode requires HTTPS. Force it if necessary.
-    const std::string secure_scheme = chrome::kHttpsScheme;
-    GURL::Replacements replacements;
-    replacements.SetSchemeStr(secure_scheme);
-    instant_url = instant_url.ReplaceComponents(replacements);
-  }
+      TemplateURLRefToGURL(template_url->instant_url_ref(), start_margin, true);
 
-  return instant_url;
+  // Extended mode requires HTTPS.  Force it unless the base URL was overridden
+  // on the command line, in which case we allow HTTP (see comments on
+  // IsSuitableURLForInstant()).
+  if (!extended_api_enabled || instant_url.SchemeIsSecure() ||
+      google_util::StartsWithCommandLineGoogleBaseURL(instant_url))
+    return instant_url;
+  GURL::Replacements replacements;
+  const std::string secure_scheme(chrome::kHttpsScheme);
+  replacements.SetSchemeStr(secure_scheme);
+  return instant_url.ReplaceComponents(replacements);
 }
 
 GURL GetLocalInstantURL(Profile* profile) {
@@ -538,7 +480,6 @@
   // precedence and allows the trial to not be reported (if it's never queried).
   const CommandLine* command_line = CommandLine::ForCurrentProcess();
   if (command_line->HasSwitch(switches::kDisableInstantExtendedAPI) ||
-      command_line->HasSwitch(switches::kEnableLocalOnlyInstantExtendedAPI) ||
       command_line->HasSwitch(switches::kEnableLocalFirstLoadNTP)) {
     return false;
   }
@@ -555,17 +496,28 @@
   return false;
 }
 
-bool ShouldPreloadLocalOnlyNTP() {
+bool ShouldShowInstantNTP() {
   FieldTrialFlags flags;
   if (GetFieldTrialInfo(
           base::FieldTrialList::FindFullName(kInstantExtendedFieldTrialName),
           &flags, NULL)) {
-    return GetBoolValueForFlagWithDefault(kPreloadLocalOnlyNTPFlagName, false,
-                                          flags);
+    return GetBoolValueForFlagWithDefault(kShowNtpFlagName, true, flags);
   }
   return true;
 }
 
+bool ShouldShowRecentTabsOnNTP() {
+  FieldTrialFlags flags;
+  if (GetFieldTrialInfo(
+          base::FieldTrialList::FindFullName(kInstantExtendedFieldTrialName),
+          &flags, NULL)) {
+    return GetBoolValueForFlagWithDefault(
+        kRecentTabsOnNTPFlagName, false, flags);
+  }
+
+  return false;
+}
+
 bool MatchesOriginAndPath(const GURL& my_url, const GURL& other_url) {
   return MatchesOrigin(my_url, other_url) && my_url.path() == other_url.path();
 }
@@ -614,16 +566,6 @@
   return timeout_sec;
 }
 
-bool IsInstantOverlay(const content::WebContents* contents) {
-  for (chrome::BrowserIterator it; !it.done(); it.Next()) {
-    if (it->instant_controller() &&
-        it->instant_controller()->instant()->GetOverlayContents() == contents) {
-      return true;
-    }
-  }
-  return false;
-}
-
 bool IsPreloadedInstantExtendedNTP(const content::WebContents* contents) {
   for (chrome::BrowserIterator it; !it.done(); it.Next()) {
     if (it->instant_controller() &&
@@ -714,34 +656,13 @@
   return !!GetUInt64ValueForFlagWithDefault(flag, default_value ? 1 : 0, flags);
 }
 
-// Coerces the commandline Instant URL to look like a template URL, so that we
-// can extract search terms from it.
-GURL CoerceCommandLineURLToTemplateURL(const GURL& instant_url,
-                                       const TemplateURLRef& ref,
-                                       int start_margin) {
-  GURL search_url = TemplateURLRefToGURL(ref, start_margin);
-
-  // NOTE(samarth): GURL returns temporaries which we must save because
-  // GURL::Replacements expects the replacements to live until
-  // ReplaceComponents is called.
-  const std::string search_scheme = chrome::kHttpsScheme;
-  const std::string search_host = search_url.host();
-  const std::string search_port = search_url.port();
-
-  GURL::Replacements replacements;
-  replacements.SetSchemeStr(search_scheme);
-  replacements.SetHostStr(search_host);
-  replacements.SetPortStr(search_port);
-  return instant_url.ReplaceComponents(replacements);
-}
-
 bool DefaultSearchProviderSupportsInstant(Profile* profile) {
   TemplateURL* template_url = GetDefaultSearchProviderTemplateURL(profile);
   if (!template_url)
     return false;
 
   GURL instant_url = TemplateURLRefToGURL(template_url->instant_url_ref(),
-                                          kDisableStartMargin);
+                                          kDisableStartMargin, false);
   // Extended mode instant requires a search terms replacement key.
   return instant_url.is_valid() &&
          (!IsInstantExtendedAPIEnabled() ||
@@ -752,19 +673,4 @@
   instant_extended_opt_in_state_gate = false;
 }
 
-bool AreMostVisitedItemsEqual(
-    const std::vector<InstantMostVisitedItem>& items_a,
-    const std::vector<InstantMostVisitedItem>& items_b) {
-  if (items_a.size() != items_b.size())
-    return false;
-
-  for (size_t i = 0; i < items_b.size(); ++i) {
-    if (items_b[i].url != items_a[i].url ||
-        items_b[i].title != items_a[i].title) {
-      return false;
-    }
-  }
-  return true;
-}
-
 }  // namespace chrome
diff --git a/chrome/browser/search/search.h b/chrome/browser/search/search.h
index d8ae0e5..313f164 100644
--- a/chrome/browser/search/search.h
+++ b/chrome/browser/search/search.h
@@ -11,7 +11,6 @@
 
 #include "base/basictypes.h"
 #include "base/strings/string16.h"
-#include "chrome/common/instant_types.h"
 
 class GURL;
 class Profile;
@@ -30,20 +29,12 @@
 namespace chrome {
 
 enum OptInState {
-  // The user has not manually opted in/out of InstantExtended,
-  // either local or regular. The in/out for local or not may
-  // occur concurrently, but only once for each (local or not).
+  // The user has not manually opted in/out of InstantExtended.
   INSTANT_EXTENDED_NOT_SET,
   // The user has opted-in to InstantExtended.
   INSTANT_EXTENDED_OPT_IN,
   // The user has opted-out of InstantExtended.
   INSTANT_EXTENDED_OPT_OUT,
-  // The user has opted-in to Local InstantExtended.
-  INSTANT_EXTENDED_OPT_IN_LOCAL,
-  // The user has opted-out of Local InstantExtended.
-  INSTANT_EXTENDED_OPT_OUT_LOCAL,
-  // The user has opted-out of both Local and regular InstantExtended.
-  INSTANT_EXTENDED_OPT_OUT_BOTH,
   INSTANT_EXTENDED_OPT_IN_STATE_ENUM_COUNT,
 };
 
@@ -55,16 +46,12 @@
 bool IsInstantExtendedAPIEnabled();
 
 // Returns the value to pass to the &espv CGI parameter when loading the
-// embedded search page from the user's default search provider. Will be
-// 0 if the Instant Extended API is not enabled, or if the local-only Instant
-// Extended API is enabled, or if in incognito mode.
-uint64 EmbeddedSearchPageVersion(Profile* profile);
+// embedded search page from the user's default search provider. Returns 0 if
+// the Instant Extended API is not enabled.
+uint64 EmbeddedSearchPageVersion();
 
 // Returns whether query extraction is enabled.
-bool IsQueryExtractionEnabled(Profile* profile);
-
-// Returns whether the local-only version of Instant Extended API is enabled.
-bool IsLocalOnlyInstantExtendedAPIEnabled();
+bool IsQueryExtractionEnabled();
 
 // Extracts and returns search terms from |url|. Returns empty string if the URL
 // is not secure or doesn't have a search term replacement key.  Does not
@@ -149,8 +136,12 @@
 // to always show the remote NTP on browser startup.
 bool ShouldPreferRemoteNTPOnStartup();
 
-// Should the Instant NTP be preloaded if local-only InstantExtended is enabled.
-bool ShouldPreloadLocalOnlyNTP();
+// Returns true if the Instant NTP should be shown and false if not.
+bool ShouldShowInstantNTP();
+
+// Returns true if the recent tabs link should be shown on the local NTP in
+// field trials.
+bool ShouldShowRecentTabsOnNTP();
 
 // Returns true if |my_url| matches |other_url|.
 bool MatchesOriginAndPath(const GURL& my_url, const GURL& other_url);
@@ -177,9 +168,6 @@
 // InstantLoader.
 int GetInstantLoaderStalenessTimeoutSec();
 
-// Returns true if |contents| corresponds to an Instant overlay.
-bool IsInstantOverlay(const content::WebContents* contents);
-
 // Returns true if |contents| corresponds to a preloaded instant extended NTP.
 bool IsPreloadedInstantExtendedNTP(const content::WebContents* contents);
 
@@ -227,12 +215,6 @@
                                     bool default_value,
                                     const FieldTrialFlags& flags);
 
-// Coerces the commandline Instant URL to look like a template URL, so that we
-// can extract search terms from it. Exposed for testing only.
-GURL CoerceCommandLineURLToTemplateURL(const GURL& instant_url,
-                                       const TemplateURLRef& ref,
-                                       int start_margin);
-
 // Returns whether the default search provider has a valid Instant URL in its
 // template. Exposed for testing only.
 bool DefaultSearchProviderSupportsInstant(Profile* profile);
@@ -241,11 +223,6 @@
 // once.
 void ResetInstantExtendedOptInStateGateForTest();
 
-// Returns true if |items_a| and |items_b| are equal.
-bool AreMostVisitedItemsEqual(
-    const std::vector<InstantMostVisitedItem>& items_a,
-    const std::vector<InstantMostVisitedItem>& items_b);
-
 }  // namespace chrome
 
 #endif  // CHROME_BROWSER_SEARCH_SEARCH_H_
diff --git a/chrome/browser/search/search_unittest.cc b/chrome/browser/search/search_unittest.cc
index d730621..91c6cfc 100644
--- a/chrome/browser/search/search_unittest.cc
+++ b/chrome/browser/search/search_unittest.cc
@@ -9,6 +9,7 @@
 #include "base/metrics/statistics_recorder.h"
 #include "base/prefs/pref_service.h"
 #include "chrome/browser/search/search.h"
+#include "chrome/browser/search_engines/search_terms_data.h"
 #include "chrome/browser/search_engines/template_url_service.h"
 #include "chrome/browser/search_engines/template_url_service_factory.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
@@ -80,17 +81,14 @@
   EXPECT_EQ(ZERO, flags.size());
 }
 
-class InstantExtendedAPIEnabledTest : public BrowserWithTestWindowTest {
+class InstantExtendedAPIEnabledTest : public testing::Test {
  public:
   InstantExtendedAPIEnabledTest() : histogram_(NULL) {
   }
  protected:
-  virtual void SetUp() OVERRIDE {
-    BrowserWithTestWindowTest::SetUp();
-
+  virtual void SetUp() {
     field_trial_list_.reset(new base::FieldTrialList(
         new metrics::SHA1EntropyProvider("42")));
-
     base::StatisticsRecorder::Initialize();
     ResetInstantExtendedOptInStateGateForTest();
     previous_metrics_count_.resize(INSTANT_EXTENDED_OPT_IN_STATE_ENUM_COUNT, 0);
@@ -144,135 +142,31 @@
 TEST_F(InstantExtendedAPIEnabledTest, EnabledViaCommandLineFlag) {
   GetCommandLine()->AppendSwitch(switches::kEnableInstantExtendedAPI);
   EXPECT_TRUE(IsInstantExtendedAPIEnabled());
-  EXPECT_FALSE(IsLocalOnlyInstantExtendedAPIEnabled());
 #if defined(OS_IOS) || defined(OS_ANDROID)
-  EXPECT_EQ(1ul, EmbeddedSearchPageVersion(profile()));
+  EXPECT_EQ(1ul, EmbeddedSearchPageVersion());
 #else
-  EXPECT_EQ(2ul, EmbeddedSearchPageVersion(profile()));
+  EXPECT_EQ(2ul, EmbeddedSearchPageVersion());
 #endif
   ValidateMetrics(INSTANT_EXTENDED_OPT_IN);
 }
 
 TEST_F(InstantExtendedAPIEnabledTest, EnabledViaFinchFlag) {
-  ASSERT_TRUE(base::FieldTrialList::CreateTrialsFromString(
-      "InstantExtended/Group1 espv:42/"));
+  ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial("InstantExtended",
+                                                     "Group1 espv:42"));
   EXPECT_TRUE(IsInstantExtendedAPIEnabled());
-  EXPECT_FALSE(IsLocalOnlyInstantExtendedAPIEnabled());
-  EXPECT_EQ(42ul, EmbeddedSearchPageVersion(profile()));
+  EXPECT_EQ(42ul, EmbeddedSearchPageVersion());
   ValidateMetrics(INSTANT_EXTENDED_NOT_SET);
 }
 
 TEST_F(InstantExtendedAPIEnabledTest, DisabledViaCommandLineFlag) {
   GetCommandLine()->AppendSwitch(switches::kDisableInstantExtendedAPI);
-  ASSERT_TRUE(base::FieldTrialList::CreateTrialsFromString(
-      "InstantExtended/Group1 espv:2/"));
+  ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial("InstantExtended",
+                                                     "Group1 espv:2"));
   EXPECT_FALSE(IsInstantExtendedAPIEnabled());
-  EXPECT_FALSE(IsLocalOnlyInstantExtendedAPIEnabled());
-  EXPECT_EQ(0ul, EmbeddedSearchPageVersion(profile()));
+  EXPECT_EQ(0ul, EmbeddedSearchPageVersion());
   ValidateMetrics(INSTANT_EXTENDED_OPT_OUT);
 }
 
-TEST_F(InstantExtendedAPIEnabledTest, LocalOnlyEnabledViaCommandLineFlag) {
-  GetCommandLine()->AppendSwitch(switches::kEnableLocalOnlyInstantExtendedAPI);
-  EXPECT_TRUE(IsInstantExtendedAPIEnabled());
-  EXPECT_TRUE(IsLocalOnlyInstantExtendedAPIEnabled());
-  EXPECT_EQ(0ul, EmbeddedSearchPageVersion(profile()));
-  ValidateMetrics(INSTANT_EXTENDED_OPT_IN_LOCAL);
-}
-
-TEST_F(InstantExtendedAPIEnabledTest, LocalOnlyEnabledViaFinch) {
-  ASSERT_TRUE(base::FieldTrialList::CreateTrialsFromString(
-      "InstantExtended/Group1 local_only:1/"));
-  EXPECT_TRUE(IsInstantExtendedAPIEnabled());
-  EXPECT_TRUE(IsLocalOnlyInstantExtendedAPIEnabled());
-  EXPECT_EQ(0ul, EmbeddedSearchPageVersion(profile()));
-  ValidateMetrics(INSTANT_EXTENDED_NOT_SET);
-}
-
-TEST_F(InstantExtendedAPIEnabledTest, BothLocalAndRegularOptOutCommandLine) {
-  GetCommandLine()->AppendSwitch(switches::kDisableLocalOnlyInstantExtendedAPI);
-  GetCommandLine()->AppendSwitch(switches::kDisableInstantExtendedAPI);
-  EXPECT_FALSE(IsInstantExtendedAPIEnabled());
-  EXPECT_FALSE(IsLocalOnlyInstantExtendedAPIEnabled());
-  ValidateMetrics(INSTANT_EXTENDED_OPT_OUT_BOTH);
-}
-
-TEST_F(InstantExtendedAPIEnabledTest, BothLocalAndRegularOptInCommandLine) {
-  GetCommandLine()->AppendSwitch(switches::kEnableLocalOnlyInstantExtendedAPI);
-  GetCommandLine()->AppendSwitch(switches::kEnableInstantExtendedAPI);
-  EXPECT_TRUE(IsInstantExtendedAPIEnabled());
-  EXPECT_TRUE(IsLocalOnlyInstantExtendedAPIEnabled());
-  ValidateMetrics(INSTANT_EXTENDED_OPT_IN_LOCAL);
-}
-
-TEST_F(InstantExtendedAPIEnabledTest,
-       LocalOnlyCommandLineTrumpedByCommandLine) {
-  GetCommandLine()->AppendSwitch(switches::kEnableLocalOnlyInstantExtendedAPI);
-  GetCommandLine()->AppendSwitch(switches::kDisableInstantExtendedAPI);
-  EXPECT_FALSE(IsInstantExtendedAPIEnabled());
-  EXPECT_FALSE(IsLocalOnlyInstantExtendedAPIEnabled());
-  EXPECT_EQ(0ul, EmbeddedSearchPageVersion(profile()));
-  ValidateMetrics(INSTANT_EXTENDED_OPT_OUT);
-}
-
-TEST_F(InstantExtendedAPIEnabledTest, LocalOnlyCommandLineTrumpsFinch) {
-  GetCommandLine()->AppendSwitch(switches::kEnableLocalOnlyInstantExtendedAPI);
-  ASSERT_TRUE(base::FieldTrialList::CreateTrialsFromString(
-      "InstantExtended/Group1 espv:2/"));
-  EXPECT_TRUE(IsInstantExtendedAPIEnabled());
-  EXPECT_TRUE(IsLocalOnlyInstantExtendedAPIEnabled());
-  EXPECT_EQ(0ul, EmbeddedSearchPageVersion(profile()));
-  ValidateMetrics(INSTANT_EXTENDED_OPT_IN_LOCAL);
-}
-
-TEST_F(InstantExtendedAPIEnabledTest, LocalOnlyFinchTrumpedByCommandLine) {
-  ASSERT_TRUE(base::FieldTrialList::CreateTrialsFromString(
-      "InstantExtended/Group1 local_only:1/"));
-  GetCommandLine()->AppendSwitch(switches::kDisableInstantExtendedAPI);
-  EXPECT_FALSE(IsInstantExtendedAPIEnabled());
-  EXPECT_FALSE(IsLocalOnlyInstantExtendedAPIEnabled());
-  EXPECT_EQ(0ul, EmbeddedSearchPageVersion(profile()));
-  ValidateMetrics(INSTANT_EXTENDED_OPT_OUT);
-}
-
-TEST_F(InstantExtendedAPIEnabledTest, LocalOnlyFinchTrumpsFinch) {
-  ASSERT_TRUE(base::FieldTrialList::CreateTrialsFromString(
-      "InstantExtended/Group1 espv:1 local_only:1/"));
-  EXPECT_TRUE(IsInstantExtendedAPIEnabled());
-  EXPECT_TRUE(IsLocalOnlyInstantExtendedAPIEnabled());
-  EXPECT_EQ(0ul, EmbeddedSearchPageVersion(profile()));
-  ValidateMetrics(INSTANT_EXTENDED_NOT_SET);
-}
-
-TEST_F(InstantExtendedAPIEnabledTest, LocalOnlyDisabledViaCommandLineFlag) {
-  GetCommandLine()->AppendSwitch(switches::kDisableLocalOnlyInstantExtendedAPI);
-  ASSERT_TRUE(base::FieldTrialList::CreateTrialsFromString(
-      "InstantExtended/Group1 espv:2/"));
-  EXPECT_TRUE(IsInstantExtendedAPIEnabled());
-  EXPECT_FALSE(IsLocalOnlyInstantExtendedAPIEnabled());
-  EXPECT_EQ(2ul, EmbeddedSearchPageVersion(profile()));
-  ValidateMetrics(INSTANT_EXTENDED_OPT_OUT_LOCAL);
-}
-
-class ShouldPreloadLocalOnlyNTPtest : public InstantExtendedAPIEnabledTest {
-};
-
-TEST_F(ShouldPreloadLocalOnlyNTPtest, PreloadByDefault) {
-  EXPECT_TRUE(ShouldPreloadLocalOnlyNTP());
-}
-
-TEST_F(ShouldPreloadLocalOnlyNTPtest, SuppressPreload) {
-  ASSERT_TRUE(base::FieldTrialList::CreateTrialsFromString(
-      "InstantExtended/Group1 preload_local_only_ntp:0/"));
-  EXPECT_FALSE(ShouldPreloadLocalOnlyNTP());
-}
-
-TEST_F(ShouldPreloadLocalOnlyNTPtest, ForcePreload) {
-  ASSERT_TRUE(base::FieldTrialList::CreateTrialsFromString(
-      "InstantExtended/Group1 preload_local_only_ntp:1/"));
-  EXPECT_TRUE(ShouldPreloadLocalOnlyNTP());
-}
-
 class SearchTest : public BrowserWithTestWindowTest {
  protected:
   virtual void SetUp() OVERRIDE {
@@ -398,17 +292,6 @@
   }
 }
 
-TEST_F(SearchTest, CoerceCommandLineURLToTemplateURL) {
-  TemplateURL* template_url =
-      TemplateURLServiceFactory::GetForProfile(profile())->
-          GetDefaultSearchProvider();
-  EXPECT_EQ(
-      GURL("https://foo.com/dev?bar=bar#bar=bar"),
-      CoerceCommandLineURLToTemplateURL(
-          GURL("http://myserver.com:9000/dev?bar=bar#bar=bar"),
-          template_url->instant_url_ref(), kDisableStartMargin));
-}
-
 const SearchTestCase kInstantNTPTestCases[] = {
   {"https://foo.com/instant?strk",         true,  "Valid Instant URL"},
   {"https://foo.com/instant#strk",         true,  "Valid Instant URL"},
@@ -429,16 +312,6 @@
   {"https://bar.com/instant?strk=1",       false, "Random non-search page"},
 };
 
-TEST_F(SearchTest, InstantExtendedEmbeddedSearchDisabledForIncognito) {
-#if !defined(OS_IOS) && !defined(OS_ANDROID)
-  EnableInstantExtendedAPIForTesting();
-  profile()->set_incognito(true);
-  EXPECT_TRUE(IsInstantExtendedAPIEnabled());
-  EXPECT_EQ(0ul, EmbeddedSearchPageVersion(profile()));
-  EXPECT_FALSE(IsQueryExtractionEnabled(profile()));
-#endif  // !defined(OS_IOS) && !defined(OS_ANDROID)
-}
-
 TEST_F(SearchTest, InstantNTPExtendedEnabled) {
   EnableInstantExtendedAPIForTesting();
   AddTab(browser(), GURL("chrome://blank"));
@@ -517,19 +390,6 @@
   EXPECT_EQ(GURL("https://foo.com/instant?foo=foo#foo=foo&strk"),
             GetInstantURL(profile(), kDisableStartMargin));
 
-  // Override the Instant URL on the commandline. Oops, forgot "strk".
-  CommandLine::ForCurrentProcess()->AppendSwitchASCII(
-      switches::kInstantURL,
-      "http://myserver.com:9000/dev?bar=bar#bar=bar");
-  EXPECT_EQ(GURL(), GetInstantURL(profile(), kDisableStartMargin));
-
-  // Override with "strk". For fun, put it in the query, instead of the ref.
-  CommandLine::ForCurrentProcess()->AppendSwitchASCII(
-      switches::kInstantURL,
-      "http://myserver.com:9000/dev?bar=bar&strk#bar=bar");
-  EXPECT_EQ(GURL("http://myserver.com:9000/dev?bar=bar&strk#bar=bar"),
-            GetInstantURL(profile(), kDisableStartMargin));
-
   // Disable suggest. No Instant URL.
   profile()->GetPrefs()->SetBoolean(prefs::kSearchSuggestEnabled, false);
   EXPECT_EQ(GURL(), GetInstantURL(profile(), kDisableStartMargin));
@@ -573,15 +433,6 @@
   profile()->GetPrefs()->SetBoolean(prefs::kSearchInstantEnabled, false);
   EXPECT_TRUE(DefaultSearchProviderSupportsInstant(profile()));
 
-  // Override the Instant URL on the commandline. Oops, forgot "strk".
-  CommandLine::ForCurrentProcess()->AppendSwitchASCII(
-      switches::kInstantURL,
-      "http://myserver.com:9000/dev?bar=bar#bar=bar");
-  EXPECT_EQ(GURL(), GetInstantURL(profile(), kDisableStartMargin));
-
-  // Check that command line overrides don't affect the default search provider.
-  EXPECT_TRUE(DefaultSearchProviderSupportsInstant(profile()));
-
   // Disable suggest. No Instant URL.
   profile()->GetPrefs()->SetBoolean(prefs::kSearchSuggestEnabled, false);
   EXPECT_EQ(GURL(), GetInstantURL(profile(), kDisableStartMargin));
@@ -600,8 +451,8 @@
   EnableInstantExtendedAPIForTesting();
 
   // Enable Instant.
-  ASSERT_TRUE(base::FieldTrialList::CreateTrialsFromString(
-      "InstantExtended/Group1 allow_instant:1/"));
+  ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial("InstantExtended",
+                                                     "Group1 allow_instant:1"));
   ASSERT_TRUE(IsInstantCheckboxVisible());
 
   // Enable suggest.
@@ -691,5 +542,55 @@
   EXPECT_FALSE(IsInstantCheckboxChecked(profile()));
 }
 
+TEST_F(SearchTest, CommandLineOverrides) {
+  EnableInstantExtendedAPIForTesting();
+  profile()->GetPrefs()->SetBoolean(prefs::kSearchInstantEnabled, true);
+
+  // GetLocalInstantURL() should default to the non-Google local NTP.
+  SetSearchProvider(false);
+  GURL local_instant_url(GetLocalInstantURL(profile()));
+  EXPECT_EQ(GURL(chrome::kChromeSearchLocalNtpUrl), local_instant_url);
+
+  TemplateURLService* template_url_service =
+      TemplateURLServiceFactory::GetForProfile(profile());
+  TemplateURLData data;
+  data.SetURL("{google:baseURL}search?q={searchTerms}");
+  data.instant_url = "{google:baseURL}webhp?strk";
+  data.search_terms_replacement_key = "strk";
+  TemplateURL* template_url = new TemplateURL(profile(), data);
+  // Takes ownership of |template_url|.
+  template_url_service->Add(template_url);
+  template_url_service->SetDefaultSearchProvider(template_url);
+
+  // By default, Instant Extended forces the instant URL to be HTTPS, so even if
+  // we set a Google base URL that is HTTP, we should get an HTTPS URL.
+  UIThreadSearchTermsData::SetGoogleBaseURL("http://www.foo.com/");
+  GURL instant_url(GetInstantURL(profile(), kDisableStartMargin));
+  ASSERT_TRUE(instant_url.is_valid());
+  EXPECT_EQ("https://www.foo.com/webhp?strk", instant_url.spec());
+
+  // However, if the Google base URL is specified on the command line, the
+  // instant URL should just use it, even if it's HTTP.
+  UIThreadSearchTermsData::SetGoogleBaseURL(std::string());
+  CommandLine::ForCurrentProcess()->AppendSwitchASCII(switches::kGoogleBaseURL,
+                                                      "http://www.bar.com/");
+  instant_url = GetInstantURL(profile(), kDisableStartMargin);
+  ASSERT_TRUE(instant_url.is_valid());
+  EXPECT_EQ("http://www.bar.com/webhp?strk", instant_url.spec());
+
+  // Similarly, setting a Google base URL on the command line should allow you
+  // to get the Google version of the local NTP, even though search provider's
+  // URL doesn't contain "google".
+  local_instant_url = GetLocalInstantURL(profile());
+  EXPECT_EQ(GURL(chrome::kChromeSearchLocalGoogleNtpUrl), local_instant_url);
+
+  // If we specify extra search query params, they should be inserted into the
+  // query portion of the instant URL.
+  CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+      switches::kExtraSearchQueryParams, "a=b");
+  instant_url = GetInstantURL(profile(), kDisableStartMargin);
+  ASSERT_TRUE(instant_url.is_valid());
+  EXPECT_EQ("http://www.bar.com/webhp?a=b&strk", instant_url.spec());
+}
 
 }  // namespace chrome
diff --git a/chrome/browser/search_engines/OWNERS b/chrome/browser/search_engines/OWNERS
index ac2ccb7..00102bf 100644
--- a/chrome/browser/search_engines/OWNERS
+++ b/chrome/browser/search_engines/OWNERS
@@ -1,3 +1,5 @@
 pkasting@chromium.org
 sky@chromium.org
-stevet@chromium.org
\ No newline at end of file
+stevet@chromium.org
+
+per-file *_android.*=yfriedman@chromium.org
\ No newline at end of file
diff --git a/chrome/browser/search_engines/prepopulated_engines.json b/chrome/browser/search_engines/prepopulated_engines.json
index 7aac2ff..5b16823 100644
--- a/chrome/browser/search_engines/prepopulated_engines.json
+++ b/chrome/browser/search_engines/prepopulated_engines.json
@@ -26,7 +26,7 @@
 
     // Increment this if you change the data in ways that mean users with
     // existing data should get a new version.
-    "kCurrentDataVersion": 56
+    "kCurrentDataVersion": 57
   },
 
   // The following engines are included in country lists and are added to the
@@ -848,7 +848,7 @@
       "keyword": "google.com",
       "favicon_url": "http://www.google.com/favicon.ico",
       "search_url": "{google:baseURL}search?q={searchTerms}&{google:RLZ}{google:originalQueryForSuggestion}{google:assistedQueryStats}{google:searchFieldtrialParameter}{google:searchClient}{google:sourceId}{google:instantExtendedEnabledParameter}{google:omniboxStartMarginParameter}ie={inputEncoding}",
-      "suggest_url": "{google:baseSuggestURL}search?{google:searchFieldtrialParameter}client=chrome&q={searchTerms}&{google:cursorPosition}{google:zeroPrefixUrl}sugkey={google:suggestAPIKeyParameter}",
+      "suggest_url": "{google:baseSuggestURL}search?{google:searchFieldtrialParameter}client={google:suggestClient}&q={searchTerms}&{google:cursorPosition}{google:zeroPrefixUrl}sugkey={google:suggestAPIKeyParameter}",
       "instant_url": "{google:baseURL}webhp?sourceid=chrome-instant&{google:RLZ}{google:instantEnabledParameter}{google:instantExtendedEnabledParameter}{google:ntpIsThemedParameter}{google:omniboxStartMarginParameter}ie={inputEncoding}",
       "alternate_urls": [
         "{google:baseURL}#q={searchTerms}",
diff --git a/chrome/browser/search_engines/search_provider_install_state_message_filter.cc b/chrome/browser/search_engines/search_provider_install_state_message_filter.cc
index 8dd0d78..0704140 100644
--- a/chrome/browser/search_engines/search_provider_install_state_message_filter.cc
+++ b/chrome/browser/search_engines/search_provider_install_state_message_filter.cc
@@ -12,7 +12,7 @@
 #include "content/public/browser/notification_types.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_view_host.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 using content::BrowserThread;
 
diff --git a/chrome/browser/search_engines/search_terms_data.cc b/chrome/browser/search_engines/search_terms_data.cc
index 1d1b3d8..32b6100 100644
--- a/chrome/browser/search_engines/search_terms_data.cc
+++ b/chrome/browser/search_engines/search_terms_data.cc
@@ -19,7 +19,7 @@
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
 #include "content/public/browser/browser_thread.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 #if defined(ENABLE_RLZ)
 #include "chrome/browser/rlz/rlz.h"
@@ -38,11 +38,6 @@
 }
 
 std::string SearchTermsData::GoogleBaseSuggestURLValue() const {
-  std::string base_suggest_url = CommandLine::ForCurrentProcess()->
-      GetSwitchValueASCII(switches::kGoogleBaseSuggestURL);
-  if (!base_suggest_url.empty())
-    return base_suggest_url;
-
   // Start with the Google base URL.
   const GURL base_url(GoogleBaseURLValue());
   DCHECK(base_url.is_valid());
@@ -74,6 +69,10 @@
   return std::string();
 }
 
+std::string SearchTermsData::GetSuggestClient() const {
+  return std::string();
+}
+
 std::string SearchTermsData::InstantEnabledParam() const {
   return std::string();
 }
@@ -100,6 +99,10 @@
       BrowserThread::CurrentlyOn(BrowserThread::UI));
   if (google_base_url_)
     return *google_base_url_;
+  std::string base_url = CommandLine::ForCurrentProcess()->
+      GetSwitchValueASCII(switches::kGoogleBaseURL);
+  if (!base_url.empty())
+    return base_url;
   return profile_ ? GoogleURLTracker::GoogleURL(profile_).spec() :
       SearchTermsData::GoogleBaseURLValue();
 }
@@ -141,6 +144,12 @@
 }
 #endif
 
+std::string UIThreadSearchTermsData::GetSuggestClient() const {
+  DCHECK(!BrowserThread::IsWellKnownThread(BrowserThread::UI) ||
+      BrowserThread::CurrentlyOn(BrowserThread::UI));
+  return chrome::IsInstantExtendedAPIEnabled() ? "chrome-omni" : "chrome";
+}
+
 std::string UIThreadSearchTermsData::InstantEnabledParam() const {
   DCHECK(!BrowserThread::IsWellKnownThread(BrowserThread::UI) ||
          BrowserThread::CurrentlyOn(BrowserThread::UI));
@@ -150,8 +159,7 @@
 std::string UIThreadSearchTermsData::InstantExtendedEnabledParam() const {
   DCHECK(!BrowserThread::IsWellKnownThread(BrowserThread::UI) ||
          BrowserThread::CurrentlyOn(BrowserThread::UI));
-  uint64 instant_extended_api_version =
-      chrome::EmbeddedSearchPageVersion(profile_);
+  uint64 instant_extended_api_version = chrome::EmbeddedSearchPageVersion();
   if (instant_extended_api_version) {
     return std::string(google_util::kInstantExtendedAPIParam) + "=" +
         base::Uint64ToString(instant_extended_api_version) + "&";
diff --git a/chrome/browser/search_engines/search_terms_data.h b/chrome/browser/search_engines/search_terms_data.h
index 2a13fc4..cbd1e7d 100644
--- a/chrome/browser/search_engines/search_terms_data.h
+++ b/chrome/browser/search_engines/search_terms_data.h
@@ -40,6 +40,10 @@
   // implementation returns the empty string.
   virtual std::string GetSearchClient() const;
 
+  // The client parameter passed with Google suggest requests.  This
+  // implementation returns the empty string.
+  virtual std::string GetSuggestClient() const;
+
   // Returns a string indicating whether Instant (in the visible-preview mode)
   // is enabled, suitable for adding as a query string param to the homepage
   // (instant_url) request. Returns an empty string if Instant is disabled, or
@@ -78,6 +82,7 @@
   virtual std::string GetApplicationLocale() const OVERRIDE;
   virtual string16 GetRlzParameterValue() const OVERRIDE;
   virtual std::string GetSearchClient() const OVERRIDE;
+  virtual std::string GetSuggestClient() const OVERRIDE;
   virtual std::string InstantEnabledParam() const OVERRIDE;
   virtual std::string InstantExtendedEnabledParam() const OVERRIDE;
   virtual std::string NTPIsThemedParam() const OVERRIDE;
diff --git a/chrome/browser/search_engines/template_url.cc b/chrome/browser/search_engines/template_url.cc
index 686429c..1ccf6dc 100644
--- a/chrome/browser/search_engines/template_url.cc
+++ b/chrome/browser/search_engines/template_url.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/search_engines/template_url.h"
 
+#include "base/command_line.h"
 #include "base/format_macros.h"
 #include "base/guid.h"
 #include "base/i18n/case_conversion.h"
@@ -18,6 +19,7 @@
 #include "chrome/browser/google/google_util.h"
 #include "chrome/browser/search_engines/search_terms_data.h"
 #include "chrome/browser/search_engines/template_url_service.h"
+#include "chrome/common/chrome_switches.h"
 #include "chrome/common/url_constants.h"
 #include "extensions/common/constants.h"
 #include "google_apis/google_api_keys.h"
@@ -72,6 +74,7 @@
     "google:searchFieldtrialParameter";
 const char kGoogleSourceIdParameter[] = "google:sourceId";
 const char kGoogleSuggestAPIKeyParameter[] = "google:suggestAPIKeyParameter";
+const char kGoogleSuggestClient[] = "google:suggestClient";
 const char kGoogleZeroPrefixUrlParameter[] = "google:zeroPrefixUrl";
 
 // Same as kSearchTermsParameter, with no escaping.
@@ -154,7 +157,8 @@
     : search_terms(search_terms),
       accepted_suggestion(NO_SUGGESTIONS_AVAILABLE),
       cursor_position(string16::npos),
-      omnibox_start_margin(-1) {
+      omnibox_start_margin(-1),
+      append_extra_query_params(false) {
 }
 
 TemplateURLRef::SearchTermsArgs::~SearchTermsArgs() {
@@ -226,155 +230,21 @@
   if (!valid_)
     return std::string();
 
-  if (replacements_.empty())
-    return parsed_url_;
+  std::string url(HandleReplacements(search_terms_args, search_terms_data));
 
-  // Determine if the search terms are in the query or before. We're escaping
-  // space as '+' in the former case and as '%20' in the latter case.
-  bool is_in_query = true;
-  for (Replacements::iterator i = replacements_.begin();
-       i != replacements_.end(); ++i) {
-    if (i->type == SEARCH_TERMS) {
-      string16::size_type query_start = parsed_url_.find('?');
-      is_in_query = query_start != string16::npos &&
-          (static_cast<string16::size_type>(i->index) > query_start);
-      break;
-    }
-  }
-
-  std::string input_encoding;
-  string16 encoded_terms;
-  string16 encoded_original_query;
-  owner_->EncodeSearchTerms(search_terms_args, is_in_query, &input_encoding,
-      &encoded_terms, &encoded_original_query);
-
-  std::string url = parsed_url_;
-
-  // replacements_ is ordered in ascending order, as such we need to iterate
-  // from the back.
-  for (Replacements::reverse_iterator i = replacements_.rbegin();
-       i != replacements_.rend(); ++i) {
-    switch (i->type) {
-      case ENCODING:
-        url.insert(i->index, input_encoding);
-        break;
-
-      case GOOGLE_ASSISTED_QUERY_STATS:
-        if (!search_terms_args.assisted_query_stats.empty()) {
-          // Get the base URL without substituting AQS to avoid infinite
-          // recursion.  We need the URL to find out if it meets all
-          // AQS requirements (e.g. HTTPS protocol check).
-          // See TemplateURLRef::SearchTermsArgs for more details.
-          SearchTermsArgs search_terms_args_without_aqs(search_terms_args);
-          search_terms_args_without_aqs.assisted_query_stats.clear();
-          GURL base_url(ReplaceSearchTermsUsingTermsData(
-              search_terms_args_without_aqs, search_terms_data));
-          if (base_url.SchemeIs(chrome::kHttpsScheme)) {
-            url.insert(i->index,
-                       "aqs=" + search_terms_args.assisted_query_stats + "&");
-          }
-        }
-        break;
-
-      case GOOGLE_BASE_URL:
-        url.insert(i->index, search_terms_data.GoogleBaseURLValue());
-        break;
-
-      case GOOGLE_BASE_SUGGEST_URL:
-        url.insert(i->index, search_terms_data.GoogleBaseSuggestURLValue());
-        break;
-
-      case GOOGLE_CURSOR_POSITION:
-        if (search_terms_args.cursor_position != string16::npos)
-          url.insert(i->index,
-                     base::StringPrintf("cp=%" PRIuS "&",
-                                        search_terms_args.cursor_position));
-        break;
-
-      case GOOGLE_INSTANT_ENABLED:
-        url.insert(i->index, search_terms_data.InstantEnabledParam());
-        break;
-
-      case GOOGLE_INSTANT_EXTENDED_ENABLED:
-        url.insert(i->index, search_terms_data.InstantExtendedEnabledParam());
-        break;
-
-      case GOOGLE_NTP_IS_THEMED:
-        url.insert(i->index, search_terms_data.NTPIsThemedParam());
-        break;
-
-      case GOOGLE_OMNIBOX_START_MARGIN:
-        if (search_terms_args.omnibox_start_margin >= 0) {
-          url.insert(i->index, "es_sm=" +
-              base::IntToString(search_terms_args.omnibox_start_margin) + "&");
-        }
-        break;
-
-      case GOOGLE_ORIGINAL_QUERY_FOR_SUGGESTION:
-        if (search_terms_args.accepted_suggestion >= 0 ||
-            !search_terms_args.assisted_query_stats.empty()) {
-          url.insert(i->index, "oq=" + UTF16ToUTF8(encoded_original_query) +
-                               "&");
-        }
-        break;
-
-      case GOOGLE_RLZ: {
-        // On platforms that don't have RLZ, we still want this branch
-        // to happen so that we replace the RLZ template with the
-        // empty string.  (If we don't handle this case, we hit a
-        // NOTREACHED below.)
-        string16 rlz_string = search_terms_data.GetRlzParameterValue();
-        if (!rlz_string.empty()) {
-          url.insert(i->index, "rlz=" + UTF16ToUTF8(rlz_string) + "&");
-        }
-        break;
-      }
-
-      case GOOGLE_SEARCH_CLIENT: {
-        std::string client = search_terms_data.GetSearchClient();
-        if (!client.empty())
-          url.insert(i->index, "client=" + client + "&");
-        break;
-      }
-
-      case GOOGLE_SEARCH_FIELDTRIAL_GROUP:
-        // We are not currently running any fieldtrials that modulate the search
-        // url.  If we do, then we'd have some conditional insert such as:
-        // url.insert(i->index, used_www ? "gcx=w&" : "gcx=c&");
-        break;
-
-      case GOOGLE_UNESCAPED_SEARCH_TERMS: {
-        std::string unescaped_terms;
-        base::UTF16ToCodepage(search_terms_args.search_terms,
-                              input_encoding.c_str(),
-                              base::OnStringConversionError::SKIP,
-                              &unescaped_terms);
-        url.insert(i->index, std::string(unescaped_terms.begin(),
-                                         unescaped_terms.end()));
-        break;
-      }
-
-      case GOOGLE_ZERO_PREFIX_URL:
-        if (!search_terms_args.zero_prefix_url.empty()) {
-          const std::string& escaped_zero_prefix_url =
-              net::EscapeQueryParamValue(search_terms_args.zero_prefix_url,
-                                         true);
-          url.insert(i->index, "url=" + escaped_zero_prefix_url + "&");
-        }
-
-        break;
-
-      case LANGUAGE:
-        url.insert(i->index, search_terms_data.GetApplicationLocale());
-        break;
-
-      case SEARCH_TERMS:
-        url.insert(i->index, UTF16ToUTF8(encoded_terms));
-        break;
-
-      default:
-        NOTREACHED();
-        break;
+  // If the user specified additional query params on the command line, add
+  // them.
+  if (search_terms_args.append_extra_query_params) {
+    std::string query_params(CommandLine::ForCurrentProcess()->
+        GetSwitchValueASCII(switches::kExtraSearchQueryParams));
+    GURL gurl(url);
+    if (!query_params.empty() && gurl.is_valid()) {
+      GURL::Replacements replacements;
+      const std::string existing_query_params(gurl.query());
+      if (!existing_query_params.empty())
+        query_params += "&" + existing_query_params;
+      replacements.SetQueryStr(query_params);
+      return gurl.ReplaceComponents(replacements).possibly_invalid_spec();
     }
   }
 
@@ -606,6 +476,8 @@
     replacements->push_back(Replacement(GOOGLE_SEARCH_CLIENT, start));
   } else if (parameter == kGoogleSearchFieldtrialParameter) {
     replacements->push_back(Replacement(GOOGLE_SEARCH_FIELDTRIAL_GROUP, start));
+  } else if (parameter == kGoogleSuggestClient) {
+    replacements->push_back(Replacement(GOOGLE_SUGGEST_CLIENT, start));
   } else if (parameter == kGoogleZeroPrefixUrlParameter) {
     replacements->push_back(Replacement(GOOGLE_ZERO_PREFIX_URL, start));
   } else if (parameter == kGoogleSuggestAPIKeyParameter) {
@@ -726,6 +598,168 @@
   path_ = url.path();
 }
 
+std::string TemplateURLRef::HandleReplacements(
+    const SearchTermsArgs& search_terms_args,
+    const SearchTermsData& search_terms_data) const {
+  if (replacements_.empty())
+    return parsed_url_;
+
+  // Determine if the search terms are in the query or before. We're escaping
+  // space as '+' in the former case and as '%20' in the latter case.
+  bool is_in_query = true;
+  for (Replacements::iterator i = replacements_.begin();
+       i != replacements_.end(); ++i) {
+    if (i->type == SEARCH_TERMS) {
+      string16::size_type query_start = parsed_url_.find('?');
+      is_in_query = query_start != string16::npos &&
+          (static_cast<string16::size_type>(i->index) > query_start);
+      break;
+    }
+  }
+
+  std::string input_encoding;
+  string16 encoded_terms;
+  string16 encoded_original_query;
+  owner_->EncodeSearchTerms(search_terms_args, is_in_query, &input_encoding,
+      &encoded_terms, &encoded_original_query);
+
+  std::string url = parsed_url_;
+
+  // replacements_ is ordered in ascending order, as such we need to iterate
+  // from the back.
+  for (Replacements::reverse_iterator i = replacements_.rbegin();
+       i != replacements_.rend(); ++i) {
+    switch (i->type) {
+      case ENCODING:
+        url.insert(i->index, input_encoding);
+        break;
+
+      case GOOGLE_ASSISTED_QUERY_STATS:
+        if (!search_terms_args.assisted_query_stats.empty()) {
+          // Get the base URL without substituting AQS to avoid infinite
+          // recursion.  We need the URL to find out if it meets all
+          // AQS requirements (e.g. HTTPS protocol check).
+          // See TemplateURLRef::SearchTermsArgs for more details.
+          SearchTermsArgs search_terms_args_without_aqs(search_terms_args);
+          search_terms_args_without_aqs.assisted_query_stats.clear();
+          GURL base_url(ReplaceSearchTermsUsingTermsData(
+              search_terms_args_without_aqs, search_terms_data));
+          if (base_url.SchemeIs(chrome::kHttpsScheme)) {
+            url.insert(i->index,
+                       "aqs=" + search_terms_args.assisted_query_stats + "&");
+          }
+        }
+        break;
+
+      case GOOGLE_BASE_URL:
+        url.insert(i->index, search_terms_data.GoogleBaseURLValue());
+        break;
+
+      case GOOGLE_BASE_SUGGEST_URL:
+        url.insert(i->index, search_terms_data.GoogleBaseSuggestURLValue());
+        break;
+
+      case GOOGLE_CURSOR_POSITION:
+        if (search_terms_args.cursor_position != string16::npos)
+          url.insert(i->index,
+                     base::StringPrintf("cp=%" PRIuS "&",
+                                        search_terms_args.cursor_position));
+        break;
+
+      case GOOGLE_INSTANT_ENABLED:
+        url.insert(i->index, search_terms_data.InstantEnabledParam());
+        break;
+
+      case GOOGLE_INSTANT_EXTENDED_ENABLED:
+        url.insert(i->index, search_terms_data.InstantExtendedEnabledParam());
+        break;
+
+      case GOOGLE_NTP_IS_THEMED:
+        url.insert(i->index, search_terms_data.NTPIsThemedParam());
+        break;
+
+      case GOOGLE_OMNIBOX_START_MARGIN:
+        if (search_terms_args.omnibox_start_margin >= 0) {
+          url.insert(i->index, "es_sm=" +
+              base::IntToString(search_terms_args.omnibox_start_margin) + "&");
+        }
+        break;
+
+      case GOOGLE_ORIGINAL_QUERY_FOR_SUGGESTION:
+        if (search_terms_args.accepted_suggestion >= 0 ||
+            !search_terms_args.assisted_query_stats.empty()) {
+          url.insert(i->index, "oq=" + UTF16ToUTF8(encoded_original_query) +
+                               "&");
+        }
+        break;
+
+      case GOOGLE_RLZ: {
+        // On platforms that don't have RLZ, we still want this branch
+        // to happen so that we replace the RLZ template with the
+        // empty string.  (If we don't handle this case, we hit a
+        // NOTREACHED below.)
+        string16 rlz_string = search_terms_data.GetRlzParameterValue();
+        if (!rlz_string.empty()) {
+          url.insert(i->index, "rlz=" + UTF16ToUTF8(rlz_string) + "&");
+        }
+        break;
+      }
+
+      case GOOGLE_SEARCH_CLIENT: {
+        std::string client = search_terms_data.GetSearchClient();
+        if (!client.empty())
+          url.insert(i->index, "client=" + client + "&");
+        break;
+      }
+
+      case GOOGLE_SEARCH_FIELDTRIAL_GROUP:
+        // We are not currently running any fieldtrials that modulate the search
+        // url.  If we do, then we'd have some conditional insert such as:
+        // url.insert(i->index, used_www ? "gcx=w&" : "gcx=c&");
+        break;
+
+      case GOOGLE_SUGGEST_CLIENT:
+        url.insert(i->index, search_terms_data.GetSuggestClient());
+        break;
+
+      case GOOGLE_UNESCAPED_SEARCH_TERMS: {
+        std::string unescaped_terms;
+        base::UTF16ToCodepage(search_terms_args.search_terms,
+                              input_encoding.c_str(),
+                              base::OnStringConversionError::SKIP,
+                              &unescaped_terms);
+        url.insert(i->index, std::string(unescaped_terms.begin(),
+                                         unescaped_terms.end()));
+        break;
+      }
+
+      case GOOGLE_ZERO_PREFIX_URL:
+        if (!search_terms_args.zero_prefix_url.empty()) {
+          const std::string& escaped_zero_prefix_url =
+              net::EscapeQueryParamValue(search_terms_args.zero_prefix_url,
+                                         true);
+          url.insert(i->index, "url=" + escaped_zero_prefix_url + "&");
+        }
+
+        break;
+
+      case LANGUAGE:
+        url.insert(i->index, search_terms_data.GetApplicationLocale());
+        break;
+
+      case SEARCH_TERMS:
+        url.insert(i->index, UTF16ToUTF8(encoded_terms));
+        break;
+
+      default:
+        NOTREACHED();
+        break;
+    }
+  }
+
+  return url;
+}
+
 
 // TemplateURLData ------------------------------------------------------------
 
diff --git a/chrome/browser/search_engines/template_url.h b/chrome/browser/search_engines/template_url.h
index 61b5c45..3eb9f4d 100644
--- a/chrome/browser/search_engines/template_url.h
+++ b/chrome/browser/search_engines/template_url.h
@@ -9,10 +9,10 @@
 #include <vector>
 
 #include "base/gtest_prod_util.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/search_engines/template_url_id.h"
-#include "googleurl/src/gurl.h"
-#include "googleurl/src/url_parse.h"
+#include "url/gurl.h"
+#include "url/url_parse.h"
 
 class Profile;
 class SearchTermsData;
@@ -58,9 +58,11 @@
     ~SearchTermsArgs();
 
     // The search terms (query).
-    const string16 search_terms;
+    string16 search_terms;
+
     // The original (input) query.
     string16 original_query;
+
     // The optional assisted query stats, aka AQS, used for logging purposes.
     // This string contains impressions of all autocomplete matches shown
     // at the query submission time.  For privacy reasons, we require the
@@ -83,6 +85,15 @@
     // The URL of the current webpage to be used for experimental zero-prefix
     // suggestions.
     std::string zero_prefix_url;
+
+    // If set, ReplaceSearchTerms() will automatically append any extra query
+    // params specified via the --extra-search-query-params command-line
+    // argument.  Generally, this should be set when dealing with the search or
+    // instant TemplateURLRefs of the default search engine and the caller cares
+    // about the query portion of the URL.  Since neither TemplateURLRef nor
+    // indeed TemplateURL know whether a TemplateURL is the default search
+    // engine, callers instead must set this manually.
+    bool append_extra_query_params;
   };
 
   TemplateURLRef(TemplateURL* owner, Type type);
@@ -186,6 +197,7 @@
     GOOGLE_RLZ,
     GOOGLE_SEARCH_CLIENT,
     GOOGLE_SEARCH_FIELDTRIAL_GROUP,
+    GOOGLE_SUGGEST_CLIENT,
     GOOGLE_UNESCAPED_SEARCH_TERMS,
     GOOGLE_ZERO_PREFIX_URL,
     LANGUAGE,
@@ -243,6 +255,13 @@
   void ParseHostAndSearchTermKey(
       const SearchTermsData& search_terms_data) const;
 
+  // Replaces all replacements in |parsed_url_| with their actual values and
+  // returns the result.  This is the main functionality of
+  // ReplaceSearchTermsUsingTermsData().
+  std::string HandleReplacements(
+      const SearchTermsArgs& search_terms_args,
+      const SearchTermsData& search_terms_data) const;
+
   // The TemplateURL that contains us.  This should outlive us.
   TemplateURL* const owner_;
 
diff --git a/chrome/browser/search_engines/template_url_fetcher_unittest.cc b/chrome/browser/search_engines/template_url_fetcher_unittest.cc
index c174a51..9120251 100644
--- a/chrome/browser/search_engines/template_url_fetcher_unittest.cc
+++ b/chrome/browser/search_engines/template_url_fetcher_unittest.cc
@@ -15,9 +15,9 @@
 #include "chrome/browser/search_engines/template_url_service_test_util.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/test/base/testing_profile.h"
-#include "googleurl/src/gurl.h"
-#include "net/test/spawned_test_server/spawned_test_server.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
 
 class TemplateURLFetcherTest;
 
@@ -53,10 +53,11 @@
 
     profile->CreateRequestContext();
     ASSERT_TRUE(profile->GetRequestContext());
-    ASSERT_TRUE(test_server_.Start());
+    ASSERT_TRUE(test_server_.InitializeAndWaitUntilReady());
   }
 
   virtual void TearDown() OVERRIDE {
+    ASSERT_TRUE(test_server_.ShutdownAndWaitUntilComplete());
     test_util_.TearDown();
   }
 
@@ -78,7 +79,7 @@
   void WaitForDownloadToFinish();
 
   TemplateURLServiceTestUtil test_util_;
-  net::SpawnedTestServer test_server_;
+  net::test_server::EmbeddedTestServer test_server_;
 
   // The last TemplateURL to come from a callback.
   scoped_ptr<TemplateURL> last_callback_template_url_;
@@ -108,12 +109,16 @@
 }
 
 TemplateURLFetcherTest::TemplateURLFetcherTest()
-    : test_server_(net::SpawnedTestServer::TYPE_HTTP,
-                   net::SpawnedTestServer::kLocalhost,
-                   base::FilePath(FILE_PATH_LITERAL("chrome/test/data"))),
+    : test_server_(
+        content::BrowserThread::GetMessageLoopProxyForThread(
+            content::BrowserThread::IO)),
       callbacks_destroyed_(0),
       add_provider_called_(0),
       waiting_for_download_(false) {
+  base::FilePath src_dir;
+  CHECK(PathService::Get(base::DIR_SOURCE_ROOT, &src_dir));
+  test_server_.ServeFilesFromDirectory(
+      src_dir.AppendASCII("chrome/test/data"));
 }
 
 void TemplateURLFetcherTest::DestroyedCallback(
@@ -145,7 +150,7 @@
   }
 
   // Start the fetch.
-  GURL osdd_url = test_server_.GetURL("files/" + osdd_file_name);
+  GURL osdd_url = test_server_.GetURL("/" + osdd_file_name);
   GURL favicon_url;
   TemplateURLFetcherFactory::GetForProfile(
       test_util_.profile())->ScheduleDownload(
diff --git a/chrome/browser/search_engines/template_url_parser.cc b/chrome/browser/search_engines/template_url_parser.cc
index 121e539..64978a7 100644
--- a/chrome/browser/search_engines/template_url_parser.cc
+++ b/chrome/browser/search_engines/template_url_parser.cc
@@ -17,10 +17,10 @@
 #include "chrome/browser/search_engines/template_url.h"
 #include "chrome/browser/search_engines/template_url_service.h"
 #include "chrome/common/url_constants.h"
-#include "googleurl/src/gurl.h"
 #include "libxml/parser.h"
 #include "libxml/xmlwriter.h"
 #include "ui/gfx/favicon_size.h"
+#include "url/gurl.h"
 
 namespace {
 
diff --git a/chrome/browser/search_engines/template_url_prepopulate_data.cc b/chrome/browser/search_engines/template_url_prepopulate_data.cc
index 07438a9..aa3032e 100644
--- a/chrome/browser/search_engines/template_url_prepopulate_data.cc
+++ b/chrome/browser/search_engines/template_url_prepopulate_data.cc
@@ -28,10 +28,10 @@
 #include "chrome/common/pref_names.h"
 #include "components/user_prefs/pref_registry_syncable.h"
 #include "content/public/browser/browser_thread.h"
-#include "googleurl/src/gurl.h"
 #include "grit/generated_resources.h"
 #include "grit/theme_resources.h"
 #include "ui/base/l10n/l10n_util.h"
+#include "url/gurl.h"
 
 #if defined(OS_WIN)
 #undef IN  // On Windows, windef.h defines this, which screws up "India" cases.
@@ -618,7 +618,7 @@
 #elif defined(OS_MACOSX)
 
 int GetCurrentCountryID() {
-  base::mac::ScopedCFTypeRef<CFLocaleRef> locale(CFLocaleCopyCurrent());
+  base::ScopedCFTypeRef<CFLocaleRef> locale(CFLocaleCopyCurrent());
   CFStringRef country = (CFStringRef)CFLocaleGetValue(locale.get(),
                                                       kCFLocaleCountryCode);
   if (!country)
diff --git a/chrome/browser/search_engines/template_url_prepopulate_data_unittest.cc b/chrome/browser/search_engines/template_url_prepopulate_data_unittest.cc
index 115abc7..1c1245b 100644
--- a/chrome/browser/search_engines/template_url_prepopulate_data_unittest.cc
+++ b/chrome/browser/search_engines/template_url_prepopulate_data_unittest.cc
@@ -304,15 +304,25 @@
               TemplateURLPrepopulateData::GetEngineType(kYahooURLs[i]));
   }
   // URLs for engines not present in country-specific lists.
-  std::string kNigmaURL = "http://www.nigma.ru/?s={searchTerms}&arg1=value1";
   EXPECT_EQ(SEARCH_ENGINE_NIGMA,
-            TemplateURLPrepopulateData::GetEngineType(kNigmaURL));
+            TemplateURLPrepopulateData::GetEngineType(
+                "http://www.nigma.ru/?s={searchTerms}&arg1=value1"));
   // Search URL for which no prepopulated search provider exists.
-  std::string kExampleSearchURL = "http://example.net/search?q={searchTerms}";
   EXPECT_EQ(SEARCH_ENGINE_OTHER,
-            TemplateURLPrepopulateData::GetEngineType(kExampleSearchURL));
+            TemplateURLPrepopulateData::GetEngineType(
+                "http://example.net/search?q={searchTerms}"));
   EXPECT_EQ(SEARCH_ENGINE_OTHER,
             TemplateURLPrepopulateData::GetEngineType("invalid:search:url"));
+
+  // URL that doesn't look Google-related, but matches a Google base URL
+  // specified on the command line.
+  const std::string foo_url("http://www.foo.com/search?q={searchTerms}");
+  EXPECT_EQ(SEARCH_ENGINE_OTHER,
+            TemplateURLPrepopulateData::GetEngineType(foo_url));
+  CommandLine::ForCurrentProcess()->AppendSwitchASCII(switches::kGoogleBaseURL,
+                                                      "http://www.foo.com/");
+  EXPECT_EQ(SEARCH_ENGINE_GOOGLE,
+            TemplateURLPrepopulateData::GetEngineType(foo_url));
 }
 
 TEST(TemplateURLPrepopulateDataTest, GetLogoURLGoogle) {
diff --git a/chrome/browser/search_engines/template_url_service.cc b/chrome/browser/search_engines/template_url_service.cc
index 9c5ab3c..b809632 100644
--- a/chrome/browser/search_engines/template_url_service.cc
+++ b/chrome/browser/search_engines/template_url_service.cc
@@ -18,7 +18,7 @@
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/google/google_url_tracker.h"
 #include "chrome/browser/history/history_notifications.h"
 #include "chrome/browser/history/history_service.h"
@@ -410,7 +410,7 @@
 void TemplateURLService::FindMatchingKeywords(
     const string16& prefix,
     bool support_replacement_only,
-    std::vector<string16>* matches) const {
+    TemplateURLVector* matches) const {
   // Sanity check args.
   if (prefix.empty())
     return;
@@ -434,7 +434,7 @@
   for (KeywordToTemplateMap::const_iterator i(match_range.first);
        i != match_range.second; ++i) {
     if (!support_replacement_only || i->second->url_ref().SupportsReplacement())
-      matches->push_back(i->first);
+      matches->push_back(i->second);
   }
 }
 
@@ -890,8 +890,10 @@
     const tracked_objects::Location& from_here,
     const syncer::SyncChangeList& change_list) {
   if (!models_associated_) {
-    syncer::SyncError error(FROM_HERE, "Models not yet associated.",
-                    syncer::SEARCH_ENGINES);
+    syncer::SyncError error(FROM_HERE,
+                            syncer::SyncError::DATATYPE_ERROR,
+                            "Models not yet associated.",
+                            syncer::SEARCH_ENGINES);
     return error;
   }
   DCHECK(loaded_);
@@ -1391,7 +1393,12 @@
       data.short_name = UTF8ToUTF16(initializers[i].content);
       data.SetKeyword(UTF8ToUTF16(initializers[i].keyword));
       data.SetURL(osd_url);
-      AddNoNotify(new TemplateURL(profile_, data), true);
+      TemplateURL* template_url = new TemplateURL(profile_, data);
+      AddNoNotify(template_url, true);
+
+      // Set the first provided identifier to be the default.
+      if (i == 0)
+        SetDefaultSearchProviderNoNotify(template_url);
     }
   }
 
diff --git a/chrome/browser/search_engines/template_url_service.h b/chrome/browser/search_engines/template_url_service.h
index 83826d5..724f771 100644
--- a/chrome/browser/search_engines/template_url_service.h
+++ b/chrome/browser/search_engines/template_url_service.h
@@ -118,12 +118,12 @@
                          const GURL& url,
                          TemplateURL** template_url_to_replace);
 
-  // Returns (in |matches|) all keywords beginning with |prefix|, sorted
-  // shortest-first. If support_replacement_only is true, only keywords that
-  // support replacement are returned.
+  // Returns (in |matches|) all TemplateURLs whose keywords begin with |prefix|,
+  // sorted shortest keyword-first. If |support_replacement_only| is true, only
+  // TemplateURLs that support replacement are returned.
   void FindMatchingKeywords(const string16& prefix,
                             bool support_replacement_only,
-                            std::vector<string16>* matches) const;
+                            TemplateURLVector* matches) const;
 
   // Looks up |keyword| and returns the element it maps to.  Returns NULL if
   // the keyword was not found.
diff --git a/chrome/browser/search_engines/template_url_service_android.cc b/chrome/browser/search_engines/template_url_service_android.cc
index 6229549..1081a03 100644
--- a/chrome/browser/search_engines/template_url_service_android.cc
+++ b/chrome/browser/search_engines/template_url_service_android.cc
@@ -95,12 +95,18 @@
   return template_url_service_->GetTemplateURLs().size();
 }
 
+jboolean TemplateUrlServiceAndroid::IsSearchProviderManaged(JNIEnv* env,
+                                                            jobject obj) {
+  return template_url_service_->is_default_search_managed();
+}
+
 base::android::ScopedJavaLocalRef<jobject>
 TemplateUrlServiceAndroid::GetPrepopulatedTemplateUrlAt(JNIEnv* env,
                                                         jobject obj,
                                                         jint index) {
   TemplateURL* template_url = template_url_service_->GetTemplateURLs()[index];
-  if (!IsPrepopulatedTemplate(template_url))
+  if (!IsPrepopulatedTemplate(template_url) &&
+      !template_url->created_by_policy())
    return ScopedJavaLocalRef<jobject>();
 
   return Java_TemplateUrl_create(
diff --git a/chrome/browser/search_engines/template_url_service_android.h b/chrome/browser/search_engines/template_url_service_android.h
index b02cf76..97336e8 100644
--- a/chrome/browser/search_engines/template_url_service_android.h
+++ b/chrome/browser/search_engines/template_url_service_android.h
@@ -28,6 +28,7 @@
   jboolean IsLoaded(JNIEnv* env, jobject obj);
   base::android::ScopedJavaLocalRef<jobject>
       GetPrepopulatedTemplateUrlAt(JNIEnv* env, jobject obj, jint index);
+  jboolean IsSearchProviderManaged(JNIEnv* env, jobject obj);
 
   // NotificationObserver:
   virtual void Observe(int type,
diff --git a/chrome/browser/search_engines/template_url_service_factory.cc b/chrome/browser/search_engines/template_url_service_factory.cc
index 3b1c8d7..30391fe 100644
--- a/chrome/browser/search_engines/template_url_service_factory.cc
+++ b/chrome/browser/search_engines/template_url_service_factory.cc
@@ -102,11 +102,7 @@
 
 content::BrowserContext* TemplateURLServiceFactory::GetBrowserContextToUse(
     content::BrowserContext* context) const {
-  // TODO(dougw): We need a separate instance of TemplateURLService in
-  // incognito profiles so that search-term-replacement can be disabled in
-  // incognito (see crbug.com/232065). Switch back to a shared instance once
-  // this is no longer necessary.
-  return chrome::GetBrowserContextOwnInstanceInIncognito(context);
+  return chrome::GetBrowserContextRedirectedInIncognito(context);
 }
 
 bool TemplateURLServiceFactory::ServiceIsNULLWhileTesting() const {
diff --git a/chrome/browser/search_engines/template_url_service_sync_unittest.cc b/chrome/browser/search_engines/template_url_service_sync_unittest.cc
index 72fc3a0..0e0c549 100644
--- a/chrome/browser/search_engines/template_url_service_sync_unittest.cc
+++ b/chrome/browser/search_engines/template_url_service_sync_unittest.cc
@@ -6,7 +6,7 @@
 #include "base/memory/scoped_vector.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/search_engines/search_terms_data.h"
 #include "chrome/browser/search_engines/template_url.h"
 #include "chrome/browser/search_engines/template_url_prepopulate_data.h"
@@ -124,7 +124,10 @@
     const syncer::SyncChangeList& change_list) {
   if (erroneous_)
     return syncer::SyncError(
-        FROM_HERE, "Some error.", syncer::SEARCH_ENGINES);
+        FROM_HERE,
+        syncer::SyncError::DATATYPE_ERROR,
+        "Some error.",
+        syncer::SEARCH_ENGINES);
 
   change_map_.erase(change_map_.begin(), change_map_.end());
   for (syncer::SyncChangeList::const_iterator iter = change_list.begin();
diff --git a/chrome/browser/search_engines/template_url_service_unittest.cc b/chrome/browser/search_engines/template_url_service_unittest.cc
index 68e845f..94026be 100644
--- a/chrome/browser/search_engines/template_url_service_unittest.cc
+++ b/chrome/browser/search_engines/template_url_service_unittest.cc
@@ -12,7 +12,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/mock_time_provider.h"
 #include "base/threading/thread.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/history/history_notifications.h"
 #include "chrome/browser/history/history_service.h"
 #include "chrome/browser/history/history_service_factory.h"
diff --git a/chrome/browser/search_engines/template_url_unittest.cc b/chrome/browser/search_engines/template_url_unittest.cc
index cffbb59..2f8b6c4 100644
--- a/chrome/browser/search_engines/template_url_unittest.cc
+++ b/chrome/browser/search_engines/template_url_unittest.cc
@@ -3,12 +3,14 @@
 // found in the LICENSE file.
 
 #include "base/base_paths.h"
+#include "base/command_line.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/rlz/rlz.h"
 #include "chrome/browser/search_engines/search_terms_data.h"
 #include "chrome/browser/search_engines/template_url.h"
+#include "chrome/common/chrome_switches.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 #if defined(ENABLE_RLZ)
@@ -1032,3 +1034,38 @@
       GURL("http://google.com/alt/?q=#q=123"), search_terms, &result));
   EXPECT_EQ(GURL("http://google.com/alt/?q=#q=Bob Morane"), result);
 }
+
+// Test the |append_extra_query_params| field of SearchTermsArgs.
+TEST_F(TemplateURLTest, ExtraQueryParams) {
+  UIThreadSearchTermsData::SetGoogleBaseURL("http://www.google.com/");
+  TemplateURLData data;
+  // Pick a URL with replacements before, during, and after the query, to ensure
+  // we don't goof up any of them.
+  data.SetURL("{google:baseURL}search?q={searchTerms}"
+      "#{google:originalQueryForSuggestion}x");
+  TemplateURL url(NULL, data);
+
+  // Baseline: no command-line args, no |append_extra_query_params| flag.
+  TemplateURLRef::SearchTermsArgs search_terms(ASCIIToUTF16("abc"));
+  search_terms.original_query = ASCIIToUTF16("def");
+  search_terms.accepted_suggestion = 0;
+  EXPECT_EQ("http://www.google.com/search?q=abc#oq=def&x",
+            url.url_ref().ReplaceSearchTerms(search_terms));
+
+  // Set the flag.  Since there are no command-line args, this should have no
+  // effect.
+  search_terms.append_extra_query_params = true;
+  EXPECT_EQ("http://www.google.com/search?q=abc#oq=def&x",
+            url.url_ref().ReplaceSearchTerms(search_terms));
+
+  // Now append the command-line arg.  This should be inserted into the query.
+  CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+      switches::kExtraSearchQueryParams, "a=b");
+  EXPECT_EQ("http://www.google.com/search?a=b&q=abc#oq=def&x",
+            url.url_ref().ReplaceSearchTerms(search_terms));
+
+  // Turn off the flag.  Now the command-line arg should be ignored again.
+  search_terms.append_extra_query_params = false;
+  EXPECT_EQ("http://www.google.com/search?q=abc#oq=def&x",
+            url.url_ref().ReplaceSearchTerms(search_terms));
+}
diff --git a/chrome/browser/search_engines/util.cc b/chrome/browser/search_engines/util.cc
index 5e7d285..6aa478e 100644
--- a/chrome/browser/search_engines/util.cc
+++ b/chrome/browser/search_engines/util.cc
@@ -12,7 +12,7 @@
 #include "base/logging.h"
 #include "base/memory/scoped_vector.h"
 #include "base/prefs/pref_service.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/search_engines/template_url.h"
 #include "chrome/browser/search_engines/template_url_prepopulate_data.h"
@@ -39,6 +39,21 @@
   return default_provider->short_name();
 }
 
+GURL GetDefaultSearchURLForSearchTerms(Profile* profile,
+                                       const string16& terms) {
+  DCHECK(profile);
+  const TemplateURL* default_provider =
+      TemplateURLServiceFactory::GetForProfile(profile)->
+      GetDefaultSearchProvider();
+  if (!default_provider)
+    return GURL();
+  const TemplateURLRef& search_url = default_provider->url_ref();
+  DCHECK(search_url.SupportsReplacement());
+  TemplateURLRef::SearchTermsArgs search_terms_args(terms);
+  search_terms_args.append_extra_query_params = true;
+  return GURL(search_url.ReplaceSearchTerms(search_terms_args));
+}
+
 void RemoveDuplicatePrepopulateIDs(
     WebDataService* service,
     const ScopedVector<TemplateURL>& prepopulated_urls,
diff --git a/chrome/browser/search_engines/util.h b/chrome/browser/search_engines/util.h
index 912748d..b496e2a 100644
--- a/chrome/browser/search_engines/util.h
+++ b/chrome/browser/search_engines/util.h
@@ -23,6 +23,10 @@
 // none is set. |profile| may be NULL.
 string16 GetDefaultSearchEngineName(Profile* profile);
 
+// Returns a GURL that searches for |terms| using the default search engine of
+// |profile|.
+GURL GetDefaultSearchURLForSearchTerms(Profile* profile, const string16& terms);
+
 // Modifies |prepopulated_url| so that it contains user-modified fields from
 // |original_turl|. Both URLs must have the same prepopulate_id.
 void MergeIntoPrepopulatedEngineData(TemplateURLData* prepopulated_url,
diff --git a/chrome/browser/service/service_process_control_mac.mm b/chrome/browser/service/service_process_control_mac.mm
index 5cd05d6..96c0e8b 100644
--- a/chrome/browser/service/service_process_control_mac.mm
+++ b/chrome/browser/service/service_process_control_mac.mm
@@ -14,7 +14,7 @@
 using content::BrowserThread;
 
 void ServiceProcessControl::Launcher::DoRun() {
-  base::mac::ScopedCFTypeRef<CFDictionaryRef> launchd_plist(
+  base::ScopedCFTypeRef<CFDictionaryRef> launchd_plist(
       CreateServiceProcessLaunchdPlist(cmd_line_.get(), false));
   CFErrorRef error = NULL;
   if (!GTMSMJobSubmit(launchd_plist, &error)) {
diff --git a/chrome/browser/sessions/base_session_service.h b/chrome/browser/sessions/base_session_service.h
index 67175a5..be2c258 100644
--- a/chrome/browser/sessions/base_session_service.h
+++ b/chrome/browser/sessions/base_session_service.h
@@ -16,7 +16,7 @@
 #include "chrome/browser/common/cancelable_request.h"
 #include "chrome/browser/sessions/session_id.h"
 #include "chrome/common/cancelable_task_tracker.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 class Profile;
 class SessionBackend;
diff --git a/chrome/browser/sessions/persistent_tab_restore_service.cc b/chrome/browser/sessions/persistent_tab_restore_service.cc
index 39ae99f..d02f25a 100644
--- a/chrome/browser/sessions/persistent_tab_restore_service.cc
+++ b/chrome/browser/sessions/persistent_tab_restore_service.cc
@@ -15,7 +15,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_vector.h"
 #include "base/stl_util.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/common/cancelable_request.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/sessions/base_session_service.h"
diff --git a/chrome/browser/sessions/session_backend.cc b/chrome/browser/sessions/session_backend.cc
index 9492b75..90e6a38 100644
--- a/chrome/browser/sessions/session_backend.cc
+++ b/chrome/browser/sessions/session_backend.cc
@@ -265,7 +265,7 @@
 
 void SessionBackend::DeleteLastSession() {
   Init();
-  file_util::Delete(GetLastSessionPath(), false);
+  base::Delete(GetLastSessionPath(), false);
 }
 
 void SessionBackend::MoveCurrentSessionToLastSession() {
@@ -275,7 +275,7 @@
   const base::FilePath current_session_path = GetCurrentSessionPath();
   const base::FilePath last_session_path = GetLastSessionPath();
   if (file_util::PathExists(last_session_path))
-    file_util::Delete(last_session_path, false);
+    base::Delete(last_session_path, false);
   if (file_util::PathExists(current_session_path)) {
     int64 file_size;
     if (file_util::GetFileSize(current_session_path, &file_size)) {
@@ -287,12 +287,11 @@
                              static_cast<int>(file_size / 1024));
       }
     }
-    last_session_valid_ = file_util::Move(current_session_path,
-                                          last_session_path);
+    last_session_valid_ = base::Move(current_session_path, last_session_path);
   }
 
   if (file_util::PathExists(current_session_path))
-    file_util::Delete(current_session_path, false);
+    base::Delete(current_session_path, false);
 
   // Create and open the file for the current session.
   ResetFile();
diff --git a/chrome/browser/sessions/session_id.h b/chrome/browser/sessions/session_id.h
index f4d103b..dd9d02d 100644
--- a/chrome/browser/sessions/session_id.h
+++ b/chrome/browser/sessions/session_id.h
@@ -7,8 +7,6 @@
 
 #include "base/basictypes.h"
 
-class Browser;
-
 namespace content {
 class WebContents;
 }
diff --git a/chrome/browser/sessions/session_restore_browsertest.cc b/chrome/browser/sessions/session_restore_browsertest.cc
index 81790e8..a5b0e8e 100644
--- a/chrome/browser/sessions/session_restore_browsertest.cc
+++ b/chrome/browser/sessions/session_restore_browsertest.cc
@@ -5,7 +5,7 @@
 #include "base/command_line.h"
 #include "base/files/file_path.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/defaults.h"
 #include "chrome/browser/first_run/first_run.h"
@@ -52,10 +52,7 @@
 
 class SessionRestoreTest : public InProcessBrowserTest {
  public:
-  SessionRestoreTest()
-      : native_browser_list(BrowserList::GetInstance(
-                                chrome::HOST_DESKTOP_TYPE_NATIVE)) {
-  }
+  SessionRestoreTest() : active_browser_list_(NULL) {}
 
  protected:
 #if defined(OS_CHROMEOS)
@@ -67,6 +64,8 @@
 #endif
 
   virtual void SetUpOnMainThread() OVERRIDE {
+    active_browser_list_ = BrowserList::GetInstance(chrome::GetActiveDesktop());
+
     SessionStartupPref pref(SessionStartupPref::LAST);
     SessionStartupPref::SetStartupPref(browser()->profile(), pref);
 #if defined(OS_CHROMEOS) || defined(OS_MACOSX)
@@ -81,6 +80,8 @@
       helper.ReleaseService();
     }
 #endif
+
+    InProcessBrowserTest::SetUpOnMainThread();
   }
 
   virtual bool SetUpUserDataDirectory() OVERRIDE {
@@ -165,7 +166,7 @@
   }
 
   void AssertOneWindowWithOneTab(Browser* browser) {
-    ASSERT_EQ(1u, native_browser_list->size());
+    ASSERT_EQ(1u, active_browser_list_->size());
     ASSERT_EQ(1, browser->tab_strip_model()->count());
   }
 
@@ -185,8 +186,7 @@
   GURL url2_;
   GURL url3_;
 
-  // The SessionRestore browser tests only uses the native desktop for now.
-  const BrowserList* native_browser_list;
+  const BrowserList* active_browser_list_;
 };
 
 #if defined(OS_CHROMEOS)
@@ -582,7 +582,7 @@
       profile, browser()->host_desktop_type(), session.begin(), session.end());
   Browser* new_browser = window_observer.WaitForSingleNewBrowser();
   ASSERT_TRUE(new_browser);
-  ASSERT_EQ(2u, native_browser_list->size());
+  ASSERT_EQ(2u, active_browser_list_->size());
   ASSERT_EQ(2, new_browser->tab_strip_model()->count());
 
   content::WebContents* web_contents_1 =
@@ -615,7 +615,7 @@
   ui_test_utils::NavigateToURL(browser(), url2_);
 
   Browser* new_browser = QuitBrowserAndRestore(browser(), 1);
-  ASSERT_EQ(1u, native_browser_list->size());
+  ASSERT_EQ(1u, active_browser_list_->size());
   ASSERT_EQ(url2_,
             new_browser->tab_strip_model()->GetActiveWebContents()->GetURL());
   GoBack(new_browser);
@@ -632,7 +632,7 @@
             old_tab->GetRenderViewHost()->GetEnabledBindings());
 
   Browser* new_browser = QuitBrowserAndRestore(browser(), 1);
-  ASSERT_EQ(1u, native_browser_list->size());
+  ASSERT_EQ(1u, active_browser_list_->size());
   const content::WebContents* new_tab =
       new_browser->tab_strip_model()->GetActiveWebContents();
   EXPECT_EQ(webui_url, new_tab->GetURL());
@@ -649,7 +649,7 @@
             old_tab->GetRenderViewHost()->GetEnabledBindings());
 
   Browser* new_browser = QuitBrowserAndRestore(browser(), 1);
-  ASSERT_EQ(1u, native_browser_list->size());
+  ASSERT_EQ(1u, active_browser_list_->size());
   const content::WebContents* new_tab =
       new_browser->tab_strip_model()->GetActiveWebContents();
   EXPECT_EQ(webui_url, new_tab->GetURL());
@@ -664,7 +664,7 @@
 
   GoBack(browser());
   Browser* new_browser = QuitBrowserAndRestore(browser(), 1);
-  ASSERT_EQ(1u, native_browser_list->size());
+  ASSERT_EQ(1u, active_browser_list_->size());
   ASSERT_EQ(url2_,
             new_browser->tab_strip_model()->GetActiveWebContents()->GetURL());
   GoForward(new_browser);
@@ -698,7 +698,7 @@
 
   GoBack(browser());
   Browser* new_browser = QuitBrowserAndRestore(browser(), 1);
-  ASSERT_EQ(1u, native_browser_list->size());
+  ASSERT_EQ(1u, active_browser_list_->size());
   ASSERT_EQ(1, new_browser->tab_strip_model()->count());
 
   // Check that back and forward work as expected.
@@ -729,7 +729,7 @@
 
   Browser* new_browser = QuitBrowserAndRestore(browser(), 2);
 
-  ASSERT_EQ(1u, native_browser_list->size());
+  ASSERT_EQ(1u, active_browser_list_->size());
   ASSERT_EQ(2, new_browser->tab_strip_model()->count());
   ASSERT_EQ(1, new_browser->tab_strip_model()->active_index());
   ASSERT_EQ(url2_,
@@ -811,7 +811,7 @@
       Browser::CreateParams(Browser::TYPE_POPUP, browser()->profile(),
                             browser()->host_desktop_type()));
   popup->window()->Show();
-  ASSERT_EQ(2u, native_browser_list->size());
+  ASSERT_EQ(2u, active_browser_list_->size());
 
   ui_test_utils::NavigateToURL(popup, url1_);
 
@@ -823,10 +823,10 @@
   // Restart and make sure we have two windows.
   QuitBrowserAndRestore(browser(), 1);
 
-  ASSERT_EQ(2u, native_browser_list->size());
+  ASSERT_EQ(2u, active_browser_list_->size());
 
-  Browser* browser1 = native_browser_list->get(0);
-  Browser* browser2 = native_browser_list->get(1);
+  Browser* browser1 = active_browser_list_->get(0);
+  Browser* browser2 = active_browser_list_->get(1);
 
   Browser::Type type1 = browser1->type();
   Browser::Type type2 = browser2->type();
@@ -862,7 +862,7 @@
   base::LaunchProcess(app_launch_arguments, base::LaunchOptions(), NULL);
 
   Browser* app_window = window_observer.WaitForSingleNewBrowser();
-  ASSERT_EQ(2u, native_browser_list->size());
+  ASSERT_EQ(2u, active_browser_list_->size());
 
   // Close the first window. The only window left is the App window.
   CloseBrowserSynchronously(browser());
@@ -887,10 +887,10 @@
       browser(), GURL(content::kAboutBlankURL), NEW_WINDOW,
       ui_test_utils::BROWSER_TEST_WAIT_FOR_BROWSER);
 
-  ASSERT_EQ(2u, native_browser_list->size());
+  ASSERT_EQ(2u, active_browser_list_->size());
 
   // Close it.
-  Browser* new_window = native_browser_list->get(1);
+  Browser* new_window = active_browser_list_->get(1);
   CloseBrowserSynchronously(new_window);
 
   // Restart and make sure we have only one window with one tab and the url
@@ -949,7 +949,7 @@
 
   // Kill the original browser then open a new one to trigger a restore.
   Browser* new_browser = QuitBrowserAndRestore(browser(), 1);
-  ASSERT_EQ(1u, native_browser_list->size());
+  ASSERT_EQ(1u, active_browser_list_->size());
   ASSERT_EQ(2, new_browser->tab_strip_model()->count());
   ASSERT_EQ(1, new_browser->tab_strip_model()->active_index());
 
@@ -983,7 +983,7 @@
 
   // This will also initiate a session restore, but we're not interested in it.
   Browser* new_browser = QuitBrowserAndRestore(browser(), 1);
-  ASSERT_EQ(1u, native_browser_list->size());
+  ASSERT_EQ(1u, active_browser_list_->size());
   ASSERT_EQ(2, new_browser->tab_strip_model()->count());
   ASSERT_EQ(0, new_browser->tab_strip_model()->active_index());
   // Close the pinned tab.
@@ -1021,7 +1021,7 @@
 
   // Restore the session by calling chrome::Navigate().
   Browser* new_browser = QuitBrowserAndRestoreWithURL(browser(), 3, url3_);
-  ASSERT_EQ(1u, native_browser_list->size());
+  ASSERT_EQ(1u, active_browser_list_->size());
   ASSERT_EQ(3, new_browser->tab_strip_model()->count());
   // Navigated url should be the active tab.
   ASSERT_EQ(url3_,
@@ -1042,7 +1042,7 @@
 
   // This will also initiate a session restore, but we're not interested in it.
   Browser* new_browser = QuitBrowserAndRestore(browser(), 1);
-  ASSERT_EQ(1u, native_browser_list->size());
+  ASSERT_EQ(1u, active_browser_list_->size());
   ASSERT_EQ(2, new_browser->tab_strip_model()->count());
   ASSERT_EQ(1, new_browser->tab_strip_model()->active_index());
   // Close the first tab.
@@ -1077,7 +1077,7 @@
   std::string session_storage_persistent_id =
       controller->GetDefaultSessionStorageNamespace()->persistent_id();
   Browser* new_browser = QuitBrowserAndRestore(browser(), 1);
-  ASSERT_EQ(1u, native_browser_list->size());
+  ASSERT_EQ(1u, active_browser_list_->size());
   ASSERT_EQ(url1_,
             new_browser->tab_strip_model()->GetActiveWebContents()->GetURL());
   content::NavigationController* new_controller =
@@ -1122,6 +1122,6 @@
 
   // Quit and restore. Check that no extra tabs were created.
   Browser* new_browser = QuitBrowserAndRestore(browser(), 1);
-  ASSERT_EQ(1u, native_browser_list->size());
+  ASSERT_EQ(1u, active_browser_list_->size());
   EXPECT_EQ(1, new_browser->tab_strip_model()->count());
 }
diff --git a/chrome/browser/sessions/session_service.h b/chrome/browser/sessions/session_service.h
index 69992e4..9e8b0ca 100644
--- a/chrome/browser/sessions/session_service.h
+++ b/chrome/browser/sessions/session_service.h
@@ -11,7 +11,7 @@
 #include "base/basictypes.h"
 #include "base/callback.h"
 #include "base/memory/scoped_vector.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/defaults.h"
 #include "chrome/browser/sessions/base_session_service.h"
 #include "chrome/browser/sessions/session_id.h"
diff --git a/chrome/browser/sessions/session_service_unittest.cc b/chrome/browser/sessions/session_service_unittest.cc
index b878b3d..4ed982b 100644
--- a/chrome/browser/sessions/session_service_unittest.cc
+++ b/chrome/browser/sessions/session_service_unittest.cc
@@ -12,7 +12,7 @@
 #include "base/stl_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/defaults.h"
 #include "chrome/browser/sessions/session_backend.h"
 #include "chrome/browser/sessions/session_service.h"
@@ -29,9 +29,6 @@
 #include "content/public/browser/notification_service.h"
 #include "content/public/common/page_state.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/WebKit/public/platform/WebData.h"
-#include "third_party/WebKit/public/platform/WebHTTPBody.h"
-#include "third_party/WebKit/public/web/WebHistoryItem.h"
 
 using content::NavigationEntry;
 using sessions::SerializedNavigationEntry;
diff --git a/chrome/browser/sessions/session_types.h b/chrome/browser/sessions/session_types.h
index c83c104..ac664d6 100644
--- a/chrome/browser/sessions/session_types.h
+++ b/chrome/browser/sessions/session_types.h
@@ -11,14 +11,14 @@
 
 #include "base/memory/scoped_ptr.h"
 #include "base/strings/string16.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/sessions/session_id.h"
 #include "components/sessions/serialized_navigation_entry.h"
 #include "content/public/common/page_transition_types.h"
-#include "googleurl/src/gurl.h"
 #include "sync/protocol/session_specifics.pb.h"
 #include "ui/base/ui_base_types.h"
 #include "ui/gfx/rect.h"
+#include "url/gurl.h"
 
 namespace content {
 class BrowserContext;
diff --git a/chrome/browser/sessions/session_types_unittest.cc b/chrome/browser/sessions/session_types_unittest.cc
index 90ae78d..6442fbe 100644
--- a/chrome/browser/sessions/session_types_unittest.cc
+++ b/chrome/browser/sessions/session_types_unittest.cc
@@ -11,7 +11,7 @@
 #include "base/strings/string16.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/search/search.h"
 #include "chrome/browser/sessions/session_types.h"
 #include "components/sessions/serialized_navigation_entry_test_helper.h"
@@ -19,11 +19,11 @@
 #include "content/public/browser/navigation_entry.h"
 #include "content/public/common/page_transition_types.h"
 #include "content/public/common/referrer.h"
-#include "googleurl/src/gurl.h"
 #include "sync/protocol/session_specifics.pb.h"
 #include "sync/util/time.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/WebKit/public/platform/WebReferrerPolicy.h"
+#include "url/gurl.h"
 
 namespace {
 
diff --git a/chrome/browser/sessions/tab_restore_browsertest.cc b/chrome/browser/sessions/tab_restore_browsertest.cc
index 9d9389c..1dfa94b 100644
--- a/chrome/browser/sessions/tab_restore_browsertest.cc
+++ b/chrome/browser/sessions/tab_restore_browsertest.cc
@@ -26,16 +26,14 @@
 #include "content/public/browser/page_navigator.h"
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/web_contents.h"
-#include "googleurl/src/gurl.h"
 #include "net/base/net_util.h"
-#include "net/test/spawned_test_server/spawned_test_server.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
 #include "third_party/WebKit/public/web/WebFindOptions.h"
+#include "url/gurl.h"
 
 class TabRestoreTest : public InProcessBrowserTest {
  public:
-  TabRestoreTest()
-      : native_browser_list(BrowserList::GetInstance(
-                                chrome::HOST_DESKTOP_TYPE_NATIVE)) {
+  TabRestoreTest() : active_browser_list_(NULL) {
     url1_ = ui_test_utils::GetTestUrl(
         base::FilePath().AppendASCII("session_history"),
         base::FilePath().AppendASCII("bot1.html"));
@@ -45,10 +43,15 @@
   }
 
  protected:
+  virtual void SetUpOnMainThread() OVERRIDE {
+    active_browser_list_ = BrowserList::GetInstance(chrome::GetActiveDesktop());
+    InProcessBrowserTest::SetUpOnMainThread();
+  }
+
   Browser* GetBrowser(int index) {
 
-    CHECK(static_cast<int>(native_browser_list->size()) > index);
-    return native_browser_list->get(index);
+    CHECK(static_cast<int>(active_browser_list_->size()) > index);
+    return active_browser_list_->get(index);
   }
 
   // Adds tabs to the given browser, all navigated to url1_. Returns
@@ -83,14 +86,14 @@
   // window (since the index is 0-based).
   void RestoreTab(int expected_window_index,
                   int expected_tabstrip_index) {
-    int window_count = static_cast<int>(native_browser_list->size());
+    int window_count = static_cast<int>(active_browser_list_->size());
     ASSERT_GT(window_count, 0);
 
     bool expect_new_window = (expected_window_index == window_count);
 
     Browser* browser;
     if (expect_new_window) {
-      browser = native_browser_list->get(0);
+      browser = active_browser_list_->get(0);
     } else {
       browser = GetBrowser(expected_window_index);
     }
@@ -109,7 +112,7 @@
     tab_loaded_observer.Wait();
 
     if (expect_new_window) {
-      int new_window_count = static_cast<int>(native_browser_list->size());
+      int new_window_count = static_cast<int>(active_browser_list_->size());
       EXPECT_EQ(++window_count, new_window_count);
       browser = GetBrowser(expected_window_index);
     } else {
@@ -147,8 +150,7 @@
   GURL url1_;
   GURL url2_;
 
-  // The TabRestore browser tests only uses the native desktop for now.
-  const BrowserList* native_browser_list;
+  const BrowserList* active_browser_list_;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(TabRestoreTest);
@@ -208,7 +210,7 @@
   ui_test_utils::NavigateToURLWithDisposition(
       browser(), GURL(chrome::kChromeUINewTabURL), NEW_WINDOW,
       ui_test_utils::BROWSER_TEST_WAIT_FOR_BROWSER);
-  EXPECT_EQ(2u, native_browser_list->size());
+  EXPECT_EQ(2u, active_browser_list_->size());
 
   // Restore tab into original browser.
   ASSERT_NO_FATAL_FAILURE(RestoreTab(0, closed_tab_index));
@@ -232,7 +234,7 @@
   ui_test_utils::NavigateToURLWithDisposition(
       browser(), GURL(chrome::kChromeUINewTabURL), NEW_WINDOW,
       ui_test_utils::BROWSER_TEST_WAIT_FOR_BROWSER);
-  EXPECT_EQ(2u, native_browser_list->size());
+  EXPECT_EQ(2u, active_browser_list_->size());
 
   // Close the final tab in the first browser.
   content::WindowedNotificationObserver window_observer(
@@ -295,7 +297,7 @@
   ui_test_utils::NavigateToURLWithDisposition(
       browser(), GURL(chrome::kChromeUINewTabURL), NEW_WINDOW,
       ui_test_utils::BROWSER_TEST_WAIT_FOR_BROWSER);
-  EXPECT_EQ(2u, native_browser_list->size());
+  EXPECT_EQ(2u, active_browser_list_->size());
 
   // Close the first browser.
   content::WindowedNotificationObserver observer(
@@ -303,7 +305,7 @@
       content::NotificationService::AllSources());
   chrome::CloseWindow(browser());
   observer.Wait();
-  EXPECT_EQ(1u, native_browser_list->size());
+  EXPECT_EQ(1u, active_browser_list_->size());
 
   // Restore the first window. The expected_tabstrip_index (second argument)
   // indicates the expected active tab.
@@ -333,7 +335,7 @@
   ui_test_utils::NavigateToURLWithDisposition(
       browser(), GURL(chrome::kChromeUINewTabURL), NEW_WINDOW,
       ui_test_utils::BROWSER_TEST_WAIT_FOR_BROWSER);
-  EXPECT_EQ(2u, native_browser_list->size());
+  EXPECT_EQ(2u, active_browser_list_->size());
 
   // Close all but one tab in the first browser, left to right.
   while (browser()->tab_strip_model()->count() > 1)
@@ -345,7 +347,7 @@
       content::NotificationService::AllSources());
   CloseTab(0);
   observer.Wait();
-  EXPECT_EQ(1u, native_browser_list->size());
+  EXPECT_EQ(1u, active_browser_list_->size());
 
   // Restore the last-closed tab into a new window.
   ASSERT_NO_FATAL_FAILURE(RestoreTab(1, 0));
@@ -364,10 +366,10 @@
 // Tests that a duplicate history entry is not created when we restore a page
 // to an existing SiteInstance.  (Bug 1230446)
 IN_PROC_BROWSER_TEST_F(TabRestoreTest, RestoreWithExistingSiteInstance) {
-  ASSERT_TRUE(test_server()->Start());
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
 
-  GURL http_url1(test_server()->GetURL("files/title1.html"));
-  GURL http_url2(test_server()->GetURL("files/title2.html"));
+  GURL http_url1(embedded_test_server()->GetURL("/title1.html"));
+  GURL http_url2(embedded_test_server()->GetURL("/title2.html"));
   int tab_count = browser()->tab_strip_model()->count();
 
   // Add a tab
@@ -421,10 +423,10 @@
 // already exists.  (Bug 1204135)
 IN_PROC_BROWSER_TEST_F(TabRestoreTest,
                        MAYBE_RestoreCrossSiteWithExistingSiteInstance) {
-  ASSERT_TRUE(test_server()->Start());
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
 
-  GURL http_url1(test_server()->GetURL("files/title1.html"));
-  GURL http_url2(test_server()->GetURL("files/title2.html"));
+  GURL http_url1(embedded_test_server()->GetURL("/title1.html"));
+  GURL http_url2(embedded_test_server()->GetURL("/title2.html"));
 
   int tab_count = browser()->tab_strip_model()->count();
 
@@ -477,11 +479,11 @@
 
 IN_PROC_BROWSER_TEST_F(TabRestoreTest, RestoreWindow) {
   // Create a new window.
-  size_t window_count = native_browser_list->size();
+  size_t window_count = active_browser_list_->size();
   ui_test_utils::NavigateToURLWithDisposition(
       browser(), GURL(chrome::kChromeUINewTabURL), NEW_WINDOW,
       ui_test_utils::BROWSER_TEST_WAIT_FOR_BROWSER);
-  EXPECT_EQ(++window_count, native_browser_list->size());
+  EXPECT_EQ(++window_count, active_browser_list_->size());
 
   // Create two more tabs, one with url1, the other url2.
   int initial_tab_count = browser()->tab_strip_model()->count();
@@ -498,7 +500,7 @@
       content::NotificationService::AllSources());
   chrome::CloseWindow(browser());
   close_window_observer.Wait();
-  EXPECT_EQ(window_count - 1, native_browser_list->size());
+  EXPECT_EQ(window_count - 1, active_browser_list_->size());
 
   // Restore the window.
   content::WindowedNotificationObserver open_window_observer(
@@ -507,9 +509,9 @@
   content::WindowedNotificationObserver load_stop_observer(
       content::NOTIFICATION_LOAD_STOP,
       content::NotificationService::AllSources());
-  chrome::RestoreTab(native_browser_list->get(0));
+  chrome::RestoreTab(active_browser_list_->get(0));
   open_window_observer.Wait();
-  EXPECT_EQ(window_count, native_browser_list->size());
+  EXPECT_EQ(window_count, active_browser_list_->size());
 
   Browser* browser = GetBrowser(1);
   EXPECT_EQ(initial_tab_count + 2, browser->tab_strip_model()->count());
@@ -552,9 +554,9 @@
 // Restore tab with special URL in its navigation history, go back to that
 // entry and see that it loads properly. See http://crbug.com/31905
 IN_PROC_BROWSER_TEST_F(TabRestoreTest, RestoreTabWithSpecialURLOnBack) {
-  ASSERT_TRUE(test_server()->Start());
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
 
-  const GURL http_url(test_server()->GetURL("files/title1.html"));
+  const GURL http_url(embedded_test_server()->GetURL("/title1.html"));
 
   // Navigate new tab to a special URL.
   ui_test_utils::NavigateToURLWithDisposition(
diff --git a/chrome/browser/sessions/tab_restore_service.h b/chrome/browser/sessions/tab_restore_service.h
index 210ba2f..e230def 100644
--- a/chrome/browser/sessions/tab_restore_service.h
+++ b/chrome/browser/sessions/tab_restore_service.h
@@ -10,7 +10,7 @@
 #include <vector>
 
 #include "base/memory/ref_counted.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/sessions/session_id.h"
 #include "chrome/browser/sessions/session_types.h"
 #include "chrome/browser/ui/host_desktop.h"
diff --git a/chrome/browser/sessions/tab_restore_service_helper.h b/chrome/browser/sessions/tab_restore_service_helper.h
index f173648..3eacc60 100644
--- a/chrome/browser/sessions/tab_restore_service_helper.h
+++ b/chrome/browser/sessions/tab_restore_service_helper.h
@@ -9,7 +9,7 @@
 
 #include "base/basictypes.h"
 #include "base/observer_list.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/sessions/session_id.h"
 #include "chrome/browser/sessions/session_types.h"
 #include "chrome/browser/sessions/tab_restore_service.h"
diff --git a/chrome/browser/shell_integration.h b/chrome/browser/shell_integration.h
index 09a7945..9abd195 100644
--- a/chrome/browser/shell_integration.h
+++ b/chrome/browser/shell_integration.h
@@ -11,8 +11,8 @@
 #include "base/files/file_path.h"
 #include "base/memory/ref_counted.h"
 #include "base/strings/string16.h"
-#include "googleurl/src/gurl.h"
 #include "ui/gfx/image/image_family.h"
+#include "url/gurl.h"
 
 class CommandLine;
 
diff --git a/chrome/browser/shell_integration_linux.cc b/chrome/browser/shell_integration_linux.cc
index b843abc..8ef3320 100644
--- a/chrome/browser/shell_integration_linux.cc
+++ b/chrome/browser/shell_integration_linux.cc
@@ -36,8 +36,8 @@
 #include "chrome/browser/web_applications/web_app.h"
 #include "chrome/common/chrome_constants.h"
 #include "content/public/browser/browser_thread.h"
-#include "googleurl/src/gurl.h"
 #include "ui/gfx/image/image_family.h"
+#include "url/gurl.h"
 
 using content::BrowserThread;
 
@@ -170,7 +170,7 @@
 void DeleteShortcutOnDesktop(const base::FilePath& shortcut_filename) {
   base::FilePath desktop_path;
   if (PathService::Get(base::DIR_USER_DESKTOP, &desktop_path))
-    file_util::Delete(desktop_path.Append(shortcut_filename), false);
+    base::Delete(desktop_path.Append(shortcut_filename), false);
 }
 
 // Creates a shortcut with |shortcut_filename| and |contents| in the system
@@ -438,6 +438,22 @@
   return nodisplay;
 }
 
+// Gets the path to the Chrome executable or wrapper script.
+// Returns an empty path if the executable path could not be found.
+base::FilePath GetChromeExePath() {
+  // Try to get the name of the wrapper script that launched Chrome.
+  scoped_ptr<base::Environment> environment(base::Environment::Create());
+  std::string wrapper_script;
+  if (environment->GetVar("CHROME_WRAPPER", &wrapper_script)) {
+    return base::FilePath(wrapper_script);
+  }
+
+  // Just return the name of the executable path for Chrome.
+  base::FilePath chrome_exe_path;
+  PathService::Get(base::FILE_EXE, &chrome_exe_path);
+  return chrome_exe_path;
+}
+
 } // namespace
 
 // static
@@ -786,9 +802,8 @@
 
   bool success = true;
 
-  // Get the path to the Chrome executable.
-  base::FilePath chrome_exe_path;
-  if (!PathService::Get(base::FILE_EXE, &chrome_exe_path)) {
+  base::FilePath chrome_exe_path = GetChromeExePath();
+  if (chrome_exe_path.empty()) {
     LOG(WARNING) << "Could not get executable path.";
     return false;
   }
diff --git a/chrome/browser/shell_integration_linux.h b/chrome/browser/shell_integration_linux.h
index 4cf64c9..2618cf8 100644
--- a/chrome/browser/shell_integration_linux.h
+++ b/chrome/browser/shell_integration_linux.h
@@ -10,7 +10,7 @@
 #include "base/basictypes.h"
 #include "base/files/file_path.h"
 #include "chrome/browser/shell_integration.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 namespace base {
 class Environment;
diff --git a/chrome/browser/shell_integration_unittest.cc b/chrome/browser/shell_integration_unittest.cc
index 141daee..2d524a4 100644
--- a/chrome/browser/shell_integration_unittest.cc
+++ b/chrome/browser/shell_integration_unittest.cc
@@ -19,8 +19,8 @@
 #include "chrome/browser/web_applications/web_app.h"
 #include "chrome/common/chrome_constants.h"
 #include "content/public/test/test_browser_thread.h"
-#include "googleurl/src/gurl.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
 
 #if defined(OS_POSIX) && !defined(OS_MACOSX)
 #include "base/environment.h"
diff --git a/chrome/browser/shell_integration_win.cc b/chrome/browser/shell_integration_win.cc
index 8184442..c30dc78 100644
--- a/chrome/browser/shell_integration_win.cc
+++ b/chrome/browser/shell_integration_win.cc
@@ -23,6 +23,7 @@
 #include "base/win/scoped_propvariant.h"
 #include "base/win/shortcut.h"
 #include "base/win/windows_version.h"
+#include "chrome/browser/policy/policy_path_parser.h"
 #include "chrome/browser/web_applications/web_app.h"
 #include "chrome/common/chrome_constants.h"
 #include "chrome/common/chrome_paths_internal.h"
@@ -96,6 +97,8 @@
     user_data_dir = command_line.GetSwitchValuePath(switches::kUserDataDir);
   else
     chrome::GetDefaultUserDataDirectory(&user_data_dir);
+  // Adjust with any policy that overrides any other way to set the path.
+  policy::path_parser::CheckUserDataDirPolicy(&user_data_dir);
   DCHECK(!user_data_dir.empty());
 
   base::FilePath profile_subdir;
diff --git a/chrome/browser/signin/DEPS b/chrome/browser/signin/DEPS
index 26c5415..05965ba 100644
--- a/chrome/browser/signin/DEPS
+++ b/chrome/browser/signin/DEPS
@@ -35,7 +35,6 @@
   "!chrome/common/chrome_notification_types.h",
   "!chrome/common/chrome_switches.h",
   "!chrome/common/chrome_version_info.h",
-  "!chrome/common/extensions/extension_messages.h",
   "!chrome/common/pref_names.h",
   "!chrome/common/url_constants.h",
 ]
@@ -48,8 +47,8 @@
     "!chrome/browser/sync/profile_sync_service_mock.h",
     "!chrome/browser/ui/browser.h",
     "!chrome/browser/ui/singleton_tabs.h",
+    "!chrome/browser/ui/sync/sync_promo_ui.h",
     "!chrome/browser/ui/tabs/tab_strip_model.h",
-    "!chrome/browser/ui/webui/sync_promo/sync_promo_ui.h",
   ],
 
   # These files are staying in //chrome so no need to limit.
diff --git a/chrome/browser/signin/chrome_signin_manager_delegate.cc b/chrome/browser/signin/chrome_signin_manager_delegate.cc
index 71689b9..3354d98 100644
--- a/chrome/browser/signin/chrome_signin_manager_delegate.cc
+++ b/chrome/browser/signin/chrome_signin_manager_delegate.cc
@@ -5,7 +5,7 @@
 #include "chrome/browser/signin/chrome_signin_manager_delegate.h"
 
 #include "chrome/browser/content_settings/cookie_settings.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 namespace {
 
diff --git a/chrome/browser/signin/oauth2_token_service.cc b/chrome/browser/signin/oauth2_token_service.cc
index e21911d..8564175 100644
--- a/chrome/browser/signin/oauth2_token_service.cc
+++ b/chrome/browser/signin/oauth2_token_service.cc
@@ -11,8 +11,8 @@
 #include "base/message_loop.h"
 #include "base/rand_util.h"
 #include "base/stl_util.h"
-#include "base/time.h"
-#include "base/timer.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
 #include "content/public/browser/browser_thread.h"
 #include "google_apis/gaia/gaia_urls.h"
 #include "google_apis/gaia/google_service_auth_error.h"
@@ -20,21 +20,7 @@
 #include "google_apis/gaia/oauth2_access_token_fetcher.h"
 #include "net/url_request/url_request_context_getter.h"
 
-namespace {
-
-// Maximum number of retries in fetching an OAuth2 access token.
-const int kMaxFetchRetryNum = 5;
-
-// Returns an exponential backoff in milliseconds including randomness less than
-// 1000 ms when retrying fetching an OAuth2 access token.
-int64 ComputeExponentialBackOffMilliseconds(int retry_num) {
-  DCHECK(retry_num < kMaxFetchRetryNum);
-  int64 exponential_backoff_in_seconds = 1 << retry_num;
-  // Returns a backoff with randomness < 1000ms
-  return (exponential_backoff_in_seconds + base::RandDouble()) * 1000;
-}
-
-}  // namespace
+int OAuth2TokenService::max_fetch_retry_num_ = 5;
 
 OAuth2TokenService::RequestImpl::RequestImpl(
     OAuth2TokenService::Consumer* consumer)
@@ -119,7 +105,9 @@
           base::WeakPtr<RequestImpl> waiting_request);
   void Start();
   void InformWaitingRequests();
+  void InformWaitingRequestsAndDelete();
   static bool ShouldRetry(const GoogleServiceAuthError& error);
+  int64 ComputeExponentialBackOffMilliseconds(int retry_num);
 
   // |oauth2_token_service_| remains valid for the life of this Fetcher, since
   // this Fetcher is destructed in the dtor of the OAuth2TokenService or is
@@ -209,18 +197,14 @@
                                             scopes_,
                                             access_token_,
                                             expiration_date_);
-  // Deregisters itself from the service to prevent more waiting requests to
-  // be added when it calls back the waiting requests.
-  oauth2_token_service_->OnFetchComplete(this);
-  InformWaitingRequests();
-  base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
+  InformWaitingRequestsAndDelete();
 }
 
 void OAuth2TokenService::Fetcher::OnGetTokenFailure(
     const GoogleServiceAuthError& error) {
   fetcher_.reset();
 
-  if (ShouldRetry(error) && retry_number_ < kMaxFetchRetryNum) {
+  if (ShouldRetry(error) && retry_number_ < max_fetch_retry_num_) {
     int64 backoff = ComputeExponentialBackOffMilliseconds(retry_number_);
     ++retry_number_;
     retry_timer_.Stop();
@@ -231,14 +215,18 @@
     return;
   }
 
-  // Fetch completes.
   error_ = error;
+  InformWaitingRequestsAndDelete();
+}
 
-  // Deregisters itself from the service to prevent more waiting requests to be
-  // added when it calls back the waiting requests.
-  oauth2_token_service_->OnFetchComplete(this);
-  InformWaitingRequests();
-  base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
+// Returns an exponential backoff in milliseconds including randomness less than
+// 1000 ms when retrying fetching an OAuth2 access token.
+int64 OAuth2TokenService::Fetcher::ComputeExponentialBackOffMilliseconds(
+    int retry_num) {
+  DCHECK(retry_num < max_fetch_retry_num_);
+  int64 exponential_backoff_in_seconds = 1 << retry_num;
+  // Returns a backoff with randomness < 1000ms
+  return (exponential_backoff_in_seconds + base::RandDouble()) * 1000;
 }
 
 // static
@@ -261,6 +249,14 @@
   waiting_requests_.clear();
 }
 
+void OAuth2TokenService::Fetcher::InformWaitingRequestsAndDelete() {
+  // Deregisters itself from the service to prevent more waiting requests to
+  // be added when it calls back the waiting requests.
+  oauth2_token_service_->OnFetchComplete(this);
+  InformWaitingRequests();
+  base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
+}
+
 void OAuth2TokenService::Fetcher::AddWaitingRequest(
     base::WeakPtr<OAuth2TokenService::RequestImpl> waiting_request) {
   waiting_requests_.push_back(waiting_request);
@@ -325,9 +321,9 @@
   if (HasCacheEntry(scopes))
     return StartCacheLookupRequest(scopes, consumer);
 
-  // Makes sure there is a pending fetcher for |scopes| and |refresh_token|.
-  // Adds |request| to the waiting request list of this fetcher so |request|
-  // will be called back when this fetcher finishes fetching.
+  // If there is already a pending fetcher for |scopes| and |refresh_token|,
+  // simply register this |request| for those results rather than starting
+  // a new fetcher.
   FetchParameters fetch_parameters = std::make_pair(refresh_token, scopes);
   std::map<FetchParameters, Fetcher*>::iterator iter =
       pending_fetchers_.find(fetch_parameters);
@@ -335,6 +331,7 @@
     iter->second->AddWaitingRequest(request->AsWeakPtr());
     return request.PassAs<Request>();
   }
+
   pending_fetchers_[fetch_parameters] =
       Fetcher::CreateAndStart(this,
                               request_context_getter_.get(),
@@ -463,3 +460,9 @@
 int OAuth2TokenService::cache_size_for_testing() const {
   return token_cache_.size();
 }
+
+void OAuth2TokenService::set_max_authorization_token_fetch_retries_for_testing(
+    int max_retries) {
+  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+  max_fetch_retry_num_ = max_retries;
+}
diff --git a/chrome/browser/signin/oauth2_token_service.h b/chrome/browser/signin/oauth2_token_service.h
index e96b9c1..150e6ca 100644
--- a/chrome/browser/signin/oauth2_token_service.h
+++ b/chrome/browser/signin/oauth2_token_service.h
@@ -13,7 +13,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
-#include "base/time.h"
+#include "base/time/time.h"
 
 namespace base {
 class Time;
@@ -100,8 +100,29 @@
 
   // Return the current number of entries in the cache.
   int cache_size_for_testing() const;
+  void set_max_authorization_token_fetch_retries_for_testing(int max_retries);
 
  protected:
+  // Implements a cancelable |OAuth2TokenService::Request|, which should be
+  // operated on the UI thread.
+  // TODO(davidroche): move this out of header file.
+  class RequestImpl : public base::SupportsWeakPtr<RequestImpl>,
+                      public Request {
+   public:
+    // |consumer| is required to outlive this.
+    explicit RequestImpl(Consumer* consumer);
+    virtual ~RequestImpl();
+
+    // Informs |consumer_| that this request is completed.
+    void InformConsumer(const GoogleServiceAuthError& error,
+                        const std::string& access_token,
+                        const base::Time& expiration_date);
+
+   private:
+    // |consumer_| to call back when this request completes.
+    Consumer* const consumer_;
+  };
+
   // Subclasses should return the refresh token maintained.
   // If no token is available, return an empty string.
   virtual std::string GetRefreshToken() = 0;
@@ -122,32 +143,13 @@
   bool HasCacheEntry(const ScopeSet& scopes);
 
   // Posts a task to fire the Consumer callback with the cached token.  Must
-  // only be called if HasCacheEntry() returns true.
+  // Must only be called if HasCacheEntry() returns true.
   scoped_ptr<Request> StartCacheLookupRequest(const ScopeSet& scopes,
                                               Consumer* consumer);
 
   // Clears the internal token cache.
   void ClearCache();
 
-  // Implements a cancelable |OAuth2TokenService::Request|, which should be
-  // operated on the UI thread.
-  class RequestImpl : public base::SupportsWeakPtr<RequestImpl>,
-                      public Request {
-   public:
-    // |consumer| is required to outlive this.
-    explicit RequestImpl(Consumer* consumer);
-    virtual ~RequestImpl();
-
-    // Informs |consumer_| that this request is completed.
-    void InformConsumer(const GoogleServiceAuthError& error,
-                        const std::string& access_token,
-                        const base::Time& expiration_date);
-
-   private:
-    // |consumer_| to call back when this request completes.
-    Consumer* const consumer_;
-  };
-
  private:
   // Class that fetches an OAuth2 access token for a given set of scopes and
   // OAuth2 refresh token.
@@ -189,6 +191,8 @@
   // A map from fetch parameters to a fetcher that is fetching an OAuth2 access
   // token using these parameters.
   std::map<FetchParameters, Fetcher*> pending_fetchers_;
+  // Maximum number of retries in fetching an OAuth2 access token.
+  static int max_fetch_retry_num_;
 
   DISALLOW_COPY_AND_ASSIGN(OAuth2TokenService);
 };
diff --git a/chrome/browser/signin/profile_oauth2_token_service.cc b/chrome/browser/signin/profile_oauth2_token_service.cc
index 7d34b2d..fd6799b 100644
--- a/chrome/browser/signin/profile_oauth2_token_service.cc
+++ b/chrome/browser/signin/profile_oauth2_token_service.cc
@@ -7,7 +7,7 @@
 #include "base/bind.h"
 #include "base/message_loop.h"
 #include "base/stl_util.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/signin/signin_manager.h"
 #include "chrome/browser/signin/signin_manager_factory.h"
diff --git a/chrome/browser/signin/signin_browsertest.cc b/chrome/browser/signin/signin_browsertest.cc
index ca8e34f..14ee972 100644
--- a/chrome/browser/signin/signin_browsertest.cc
+++ b/chrome/browser/signin/signin_browsertest.cc
@@ -5,20 +5,22 @@
 #ifndef CHROME_BROWSER_SIGNIN_SIGNIN_BROWSERTEST_H_
 #define CHROME_BROWSER_SIGNIN_SIGNIN_BROWSERTEST_H_
 
+#include "base/command_line.h"
 #include "chrome/browser/signin/signin_manager.h"
 #include "chrome/browser/signin/signin_manager_factory.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/singleton_tabs.h"
+#include "chrome/browser/ui/sync/sync_promo_ui.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/webui/signin/login_ui_service.h"
 #include "chrome/browser/ui/webui/signin/login_ui_service_factory.h"
-#include "chrome/browser/ui/webui/sync_promo/sync_promo_ui.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/web_contents.h"
+#include "content/public/common/content_switches.h"
 #include "google_apis/gaia/gaia_urls.h"
 #include "net/url_request/test_url_fetcher_factory.h"
 
@@ -28,6 +30,23 @@
 
 class SigninBrowserTest : public InProcessBrowserTest {
  public:
+  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
+    https_server_.reset(new net::SpawnedTestServer(
+        net::SpawnedTestServer::TYPE_HTTPS,
+        net::SpawnedTestServer::kLocalhost,
+        base::FilePath(FILE_PATH_LITERAL("chrome/test/data"))));
+    ASSERT_TRUE(https_server_->Start());
+
+    // Add a host resolver rule to map all outgoing requests to the test server.
+    // This allows us to use "real" hostnames in URLs, which we can use to
+    // create arbitrary SiteInstances.
+    command_line->AppendSwitchASCII(
+        switches::kHostResolverRules,
+        "MAP * " + https_server_->host_port_pair().ToString() +
+            ",EXCLUDE localhost");
+    command_line->AppendSwitch(switches::kIgnoreCertificateErrors);
+  }
+
   virtual void SetUp() OVERRIDE {
     factory_.reset(new net::URLFetcherImplFactory());
     fake_factory_.reset(new net::FakeURLFetcherFactory(factory_.get()));
@@ -59,8 +78,18 @@
 
   // The URLFetcherImplFactory instance used to instantiate |fake_factory_|.
   scoped_ptr<net::URLFetcherImplFactory> factory_;
+
+  scoped_ptr<net::SpawnedTestServer> https_server_;
 };
 
+// If the one-click-signin feature is not enabled (e.g Chrome OS), we
+// never grant signin privileges to any renderer processes.
+#if defined(ENABLE_ONE_CLICK_SIGNIN)
+const bool kOneClickSigninEnabled = true;
+#else
+const bool kOneClickSigninEnabled = false;
+#endif
+
 // Disabled on Windows due to flakiness. http://crbug.com/249055
 #if defined(OS_WIN)
 #define MAYBE_ProcessIsolation DISABLED_ProcessIsolation
@@ -68,14 +97,6 @@
 #define MAYBE_ProcessIsolation ProcessIsolation
 #endif
 IN_PROC_BROWSER_TEST_F(SigninBrowserTest, MAYBE_ProcessIsolation) {
-  // If the one-click-signin feature is not enabled (e.g Chrome OS), we
-  // never grant signin privileges to any renderer processes.
-#if defined(ENABLE_ONE_CLICK_SIGNIN)
-  const bool kOneClickSigninEnabled = true;
-#else
-  const bool kOneClickSigninEnabled = false;
-#endif
-
   SigninManager* signin = SigninManagerFactory::GetForProfile(
       browser()->profile());
   EXPECT_FALSE(signin->HasSigninProcess());
@@ -118,4 +139,26 @@
       active_tab->GetRenderProcessHost()->GetID()));
 }
 
+IN_PROC_BROWSER_TEST_F(SigninBrowserTest, NotTrustedAfterRedirect) {
+  SigninManager* signin = SigninManagerFactory::GetForProfile(
+      browser()->profile());
+  EXPECT_FALSE(signin->HasSigninProcess());
+
+  GURL url = SyncPromoUI::GetSyncPromoURL(SyncPromoUI::SOURCE_NTP_LINK, true);
+  ui_test_utils::NavigateToURL(browser(), url);
+  EXPECT_EQ(kOneClickSigninEnabled, signin->HasSigninProcess());
+
+  // Navigating in a different tab should not affect the sign-in process.
+  ui_test_utils::NavigateToURLWithDisposition(
+      browser(), GURL(kNonSigninURL), NEW_BACKGROUND_TAB,
+      ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
+  EXPECT_EQ(kOneClickSigninEnabled, signin->HasSigninProcess());
+
+  // Navigating away should clear the sign-in process.
+  GURL redirect_url("https://accounts.google.com/server-redirect?"
+      "https://foo.com?service=chromiumsync");
+  ui_test_utils::NavigateToURL(browser(), redirect_url);
+  EXPECT_FALSE(signin->HasSigninProcess());
+}
+
 #endif  // CHROME_BROWSER_SIGNIN_SIGNIN_BROWSERTEST_H_
diff --git a/chrome/browser/signin/signin_global_error_unittest.cc b/chrome/browser/signin/signin_global_error_unittest.cc
index 51b96e2..e0aeba0 100644
--- a/chrome/browser/signin/signin_global_error_unittest.cc
+++ b/chrome/browser/signin/signin_global_error_unittest.cc
@@ -107,6 +107,8 @@
     { GoogleServiceAuthError::TWO_FACTOR, true },
     { GoogleServiceAuthError::REQUEST_CANCELED, true },
     { GoogleServiceAuthError::HOSTED_NOT_ALLOWED, true },
+    { GoogleServiceAuthError::UNEXPECTED_SERVICE_RESPONSE, true },
+    { GoogleServiceAuthError::SERVICE_ERROR, true },
   };
   COMPILE_ASSERT(ARRAYSIZE_UNSAFE(table) == GoogleServiceAuthError::NUM_STATES,
       kTable_size_does_not_match_number_of_auth_error_types);
diff --git a/chrome/browser/signin/signin_internals_util.cc b/chrome/browser/signin/signin_internals_util.cc
index 0fa8863..00737b6 100644
--- a/chrome/browser/signin/signin_internals_util.cc
+++ b/chrome/browser/signin/signin_internals_util.cc
@@ -8,9 +8,9 @@
 
 #include "base/logging.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/common/chrome_version_info.h"
-#include "chrome/common/extensions/extension_messages.h"
 #include "chrome/common/url_constants.h"
 #include "content/public/browser/web_contents.h"
 #include "crypto/sha2.h"
diff --git a/chrome/browser/signin/signin_manager.cc b/chrome/browser/signin/signin_manager.cc
index 68479d4..4ca5da1 100644
--- a/chrome/browser/signin/signin_manager.cc
+++ b/chrome/browser/signin/signin_manager.cc
@@ -13,7 +13,7 @@
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/profiles/profile_io_data.h"
 #include "chrome/browser/signin/about_signin_internals.h"
 #include "chrome/browser/signin/about_signin_internals_factory.h"
@@ -103,6 +103,10 @@
                  content::Source<content::RenderProcessHost>(process));
 }
 
+void SigninManager::ClearSigninProcess() {
+  signin_process_id_ = kInvalidProcessId;
+}
+
 bool SigninManager::IsSigninProcess(int process_id) const {
   return process_id == signin_process_id_;
 }
diff --git a/chrome/browser/signin/signin_manager.h b/chrome/browser/signin/signin_manager.h
index 9a8d3dc..4ae4c2f 100644
--- a/chrome/browser/signin/signin_manager.h
+++ b/chrome/browser/signin/signin_manager.h
@@ -186,6 +186,7 @@
   // OneClickSigninHelper).  All of this tracking state is reset once the
   // renderer process terminates.
   void SetSigninProcess(int process_id);
+  void ClearSigninProcess();
   bool IsSigninProcess(int process_id) const;
   bool HasSigninProcess() const;
 
diff --git a/chrome/browser/signin/signin_ui_util.cc b/chrome/browser/signin/signin_ui_util.cc
index 9bb6499..95396be 100644
--- a/chrome/browser/signin/signin_ui_util.cc
+++ b/chrome/browser/signin/signin_ui_util.cc
@@ -28,13 +28,22 @@
 namespace signin_ui_util {
 
 GlobalError* GetSignedInServiceError(Profile* profile) {
+  std::vector<GlobalError*> errors = GetSignedInServiceErrors(profile);
+  if (errors.empty())
+    return NULL;
+  return errors[0];
+}
+
+std::vector<GlobalError*> GetSignedInServiceErrors(Profile* profile) {
+  std::vector<GlobalError*> errors;
+
   // Auth errors have the highest priority - after that, individual service
   // errors.
   SigninManagerBase* signin_manager =
       SigninManagerFactory::GetForProfile(profile);
   SigninGlobalError* signin_error = signin_manager->signin_global_error();
   if (signin_error && signin_error->HasMenuItem())
-    return signin_error;
+    errors.push_back(signin_error);
 
   // No auth error - now try other services. Currently the list is just hard-
   // coded but in the future if we add more we can create some kind of
@@ -44,9 +53,10 @@
         ProfileSyncServiceFactory::GetForProfile(profile);
     SyncGlobalError* error = service->sync_global_error();
     if (error && error->HasMenuItem())
-      return error;
+      errors.push_back(error);
   }
-  return NULL;
+
+  return errors;
 }
 
 string16 GetSigninMenuLabel(Profile* profile) {
diff --git a/chrome/browser/signin/signin_ui_util.h b/chrome/browser/signin/signin_ui_util.h
index decae32..3e63e1a 100644
--- a/chrome/browser/signin/signin_ui_util.h
+++ b/chrome/browser/signin/signin_ui_util.h
@@ -5,6 +5,8 @@
 #ifndef CHROME_BROWSER_SIGNIN_SIGNIN_UI_UTIL_H_
 #define CHROME_BROWSER_SIGNIN_SIGNIN_UI_UTIL_H_
 
+#include <vector>
+
 #include "base/strings/string16.h"
 
 class GlobalError;
@@ -19,6 +21,9 @@
 // object associated with that service, or NULL if no errors are reported.
 GlobalError* GetSignedInServiceError(Profile* profile);
 
+// Returns all errors reported by signed in services.
+std::vector<GlobalError*> GetSignedInServiceErrors(Profile* profile);
+
 // Return the label that should be displayed in the signin menu (i.e.
 // "Sign in to Chromium", "Signin Error...", etc).
 string16 GetSigninMenuLabel(Profile* profile);
diff --git a/chrome/browser/signin/ubertoken_fetcher.cc b/chrome/browser/signin/ubertoken_fetcher.cc
index b722f12..4cf5d39 100644
--- a/chrome/browser/signin/ubertoken_fetcher.cc
+++ b/chrome/browser/signin/ubertoken_fetcher.cc
@@ -2,12 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "chrome/browser/signin/ubertoken_fetcher.h"
+
+#include <vector>
+
 #include "base/logging.h"
 #include "base/strings/stringprintf.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/signin/token_service.h"
 #include "chrome/browser/signin/token_service_factory.h"
-#include "chrome/browser/signin/ubertoken_fetcher.h"
 #include "chrome/common/chrome_notification_types.h"
 #include "google_apis/gaia/gaia_constants.h"
 #include "google_apis/gaia/gaia_urls.h"
@@ -47,9 +50,11 @@
   client_info.client_id = urls->oauth2_chrome_client_id();
   client_info.client_secret = urls->oauth2_chrome_client_secret();
   gaia_oauth_client_.reset(new gaia::GaiaOAuthClient(
-      urls->oauth2_token_url(), profile_->GetRequestContext()));
+      profile_->GetRequestContext()));
+  std::vector<std::string> empty_scope_list;  // (Use scope from refresh token.)
   gaia_oauth_client_->RefreshToken(
-      client_info, token_service->GetOAuth2LoginRefreshToken(), 1, this);
+      client_info, token_service->GetOAuth2LoginRefreshToken(),
+      empty_scope_list, 1, this);
 }
 
 void UbertokenFetcher::Observe(int type,
diff --git a/chrome/browser/speech/tts_controller.h b/chrome/browser/speech/tts_controller.h
index b55600a..18cbcd9 100644
--- a/chrome/browser/speech/tts_controller.h
+++ b/chrome/browser/speech/tts_controller.h
@@ -12,7 +12,7 @@
 
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/singleton.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 class Utterance;
 class TtsPlatformImpl;
diff --git a/chrome/browser/speech/tts_mac.mm b/chrome/browser/speech/tts_mac.mm
index bdb9b1c..a5a8aec 100644
--- a/chrome/browser/speech/tts_mac.mm
+++ b/chrome/browser/speech/tts_mac.mm
@@ -4,7 +4,7 @@
 
 #include <string>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "base/memory/singleton.h"
 #include "base/strings/sys_string_conversions.h"
 #include "base/values.h"
@@ -38,7 +38,7 @@
 //    crash when trying to call willSpeakWord.
 @interface SingleUseSpeechSynthesizer : NSSpeechSynthesizer {
  @private
-  scoped_nsobject<NSString> utterance_;
+  base::scoped_nsobject<NSString> utterance_;
   bool didSpeak_;
 }
 
@@ -85,8 +85,8 @@
   TtsPlatformImplMac();
   virtual ~TtsPlatformImplMac();
 
-  scoped_nsobject<SingleUseSpeechSynthesizer> speech_synthesizer_;
-  scoped_nsobject<ChromeTtsDelegate> delegate_;
+  base::scoped_nsobject<SingleUseSpeechSynthesizer> speech_synthesizer_;
+  base::scoped_nsobject<ChromeTtsDelegate> delegate_;
   int utterance_id_;
   std::string utterance_;
   bool sent_start_event_;
diff --git a/chrome/browser/spellchecker/feedback_sender.cc b/chrome/browser/spellchecker/feedback_sender.cc
index 3b72c69..c250cf4 100644
--- a/chrome/browser/spellchecker/feedback_sender.cc
+++ b/chrome/browser/spellchecker/feedback_sender.cc
@@ -155,6 +155,8 @@
 
 void FeedbackSender::SelectedSuggestion(uint32 hash, int suggestion_index) {
   Misspelling* misspelling = feedback_.GetMisspelling(hash);
+  // GetMisspelling() returns null for flushed feedback. Feedback is flushed
+  // when the session expires every |kSessionHours| hours.
   if (!misspelling)
     return;
   misspelling->action.type = SpellcheckAction::TYPE_SELECT;
@@ -164,6 +166,8 @@
 
 void FeedbackSender::AddedToDictionary(uint32 hash) {
   Misspelling* misspelling = feedback_.GetMisspelling(hash);
+  // GetMisspelling() returns null for flushed feedback. Feedback is flushed
+  // when the session expires every |kSessionHours| hours.
   if (!misspelling)
     return;
   misspelling->action.type = SpellcheckAction::TYPE_ADD_TO_DICT;
@@ -181,8 +185,19 @@
   }
 }
 
+void FeedbackSender::RecordInDictionary(uint32 hash) {
+  Misspelling* misspelling = feedback_.GetMisspelling(hash);
+  // GetMisspelling() returns null for flushed feedback. Feedback is flushed
+  // when the session expires every |kSessionHours| hours.
+  if (!misspelling)
+    return;
+  misspelling->action.type = SpellcheckAction::TYPE_IN_DICTIONARY;
+}
+
 void FeedbackSender::IgnoredSuggestions(uint32 hash) {
   Misspelling* misspelling = feedback_.GetMisspelling(hash);
+  // GetMisspelling() returns null for flushed feedback. Feedback is flushed
+  // when the session expires every |kSessionHours| hours.
   if (!misspelling)
     return;
   misspelling->action.type = SpellcheckAction::TYPE_PENDING_IGNORE;
@@ -192,6 +207,8 @@
 void FeedbackSender::ManuallyCorrected(uint32 hash,
                                        const string16& correction) {
   Misspelling* misspelling = feedback_.GetMisspelling(hash);
+  // GetMisspelling() returns null for flushed feedback. Feedback is flushed
+  // when the session expires every |kSessionHours| hours.
   if (!misspelling)
     return;
   misspelling->action.type = SpellcheckAction::TYPE_MANUALLY_CORRECTED;
diff --git a/chrome/browser/spellchecker/feedback_sender.h b/chrome/browser/spellchecker/feedback_sender.h
index dbcaba2..286008f 100644
--- a/chrome/browser/spellchecker/feedback_sender.h
+++ b/chrome/browser/spellchecker/feedback_sender.h
@@ -11,14 +11,13 @@
 
 #include "base/memory/scoped_vector.h"
 #include "base/memory/weak_ptr.h"
-#include "base/timer.h"
+#include "base/timer/timer.h"
 #include "chrome/browser/spellchecker/feedback.h"
 #include "chrome/browser/spellchecker/misspelling.h"
-#include "googleurl/src/gurl.h"
 #include "net/url_request/url_fetcher_delegate.h"
+#include "url/gurl.h"
 
 class SpellCheckMarker;
-class SpellingServiceFeedbackTest;
 struct SpellCheckResult;
 
 namespace net {
@@ -58,6 +57,10 @@
   // the list of suggestions.
   void ManuallyCorrected(uint32 hash, const string16& correction);
 
+  // Records that user has the misspelling in the custom dictionary. The user
+  // will never see the spellcheck suggestions for the misspelling.
+  void RecordInDictionary(uint32 hash);
+
   // Receives document markers for renderer with process ID |render_process_id|
   // when the renderer responds to a RequestDocumentMarkers() call. Finalizes
   // feedback for the markers that are gone from the renderer. Sends feedback
diff --git a/chrome/browser/spellchecker/feedback_sender_unittest.cc b/chrome/browser/spellchecker/feedback_sender_unittest.cc
index 262b009..5504005 100644
--- a/chrome/browser/spellchecker/feedback_sender_unittest.cc
+++ b/chrome/browser/spellchecker/feedback_sender_unittest.cc
@@ -43,6 +43,18 @@
                           ASCIIToUTF16("Hello"));
 }
 
+// Returns the number of times that |needle| appears in |haystack| without
+// overlaps. For example, CountOccurences("bananana", "nana") returns 1.
+int CountOccurences(const std::string& haystack, const std::string& needle) {
+  int number_of_occurrences = 0;
+  for (size_t pos = haystack.find(needle);
+       pos != std::string::npos;
+       pos = haystack.find(needle, pos + needle.length())) {
+    ++number_of_occurrences;
+  }
+  return number_of_occurrences;
+}
+
 }  // namespace
 
 class FeedbackSenderTest : public testing::Test {
@@ -70,6 +82,7 @@
   content::TestBrowserThread ui_thread_;
   scoped_ptr<base::FieldTrialList> field_trial_list_;
   scoped_refptr<base::FieldTrial> field_trial_;
+  net::TestURLFetcherFactory fetchers_;
 
  protected:
   uint32 AddPendingFeedback() {
@@ -85,30 +98,55 @@
         base::TimeDelta::FromHours(chrome::spellcheck_common::kSessionHours);
   }
 
-  net::TestURLFetcher* GetFetcher() {
-    return fetchers_.GetFetcherByID(kUrlFetcherId);
+  bool UploadDataContains(const std::string& data) const {
+    const net::TestURLFetcher* fetcher =
+        fetchers_.GetFetcherByID(kUrlFetcherId);
+    return fetcher && CountOccurences(fetcher->upload_data(), data) > 0;
   }
 
-  net::TestURLFetcherFactory fetchers_;
+  bool UploadDataContains(const std::string& data,
+                          int number_of_occurrences) const {
+    const net::TestURLFetcher* fetcher =
+        fetchers_.GetFetcherByID(kUrlFetcherId);
+    return fetcher && CountOccurences(fetcher->upload_data(), data) ==
+                          number_of_occurrences;
+  }
+
+  // Returns true if the feedback sender would be uploading data now. Otherwise
+  // returns false. The test does not open network connections.
+  bool IsUploadingData() const {
+    return !!fetchers_.GetFetcherByID(kUrlFetcherId);
+  }
+
+  void ClearUploadData() {
+    fetchers_.RemoveFetcherFromMap(kUrlFetcherId);
+  }
+
+  std::string GetUploadData() const {
+    const net::TestURLFetcher* fetcher =
+        fetchers_.GetFetcherByID(kUrlFetcherId);
+    return fetcher ? fetcher->upload_data() : std::string();
+  }
+
   scoped_ptr<spellcheck::FeedbackSender> feedback_;
 };
 
 // Do not send data if there's no feedback.
 TEST_F(FeedbackSenderTest, NoFeedback) {
-  EXPECT_EQ(NULL, GetFetcher());
+  EXPECT_FALSE(IsUploadingData());
   feedback_->OnReceiveDocumentMarkers(kRendererProcessId,
                                       std::vector<uint32>());
-  EXPECT_EQ(NULL, GetFetcher());
+  EXPECT_FALSE(IsUploadingData());
 }
 
 // Do not send data if not aware of which markers are still in the document.
 TEST_F(FeedbackSenderTest, NoDocumentMarkersReceived) {
-  EXPECT_EQ(NULL, GetFetcher());
+  EXPECT_FALSE(IsUploadingData());
   uint32 hash = AddPendingFeedback();
-  EXPECT_EQ(NULL, GetFetcher());
+  EXPECT_FALSE(IsUploadingData());
   static const int kSuggestionIndex = 1;
   feedback_->SelectedSuggestion(hash, kSuggestionIndex);
-  EXPECT_EQ(NULL, GetFetcher());
+  EXPECT_FALSE(IsUploadingData());
 }
 
 // Send PENDING feedback message if the marker is still in the document, and the
@@ -117,10 +155,7 @@
   uint32 hash = AddPendingFeedback();
   feedback_->OnReceiveDocumentMarkers(kRendererProcessId,
                                       std::vector<uint32>(1, hash));
-  net::TestURLFetcher* fetcher = GetFetcher();
-  EXPECT_NE(std::string::npos,
-            fetcher->upload_data().find("\"actionType\":\"PENDING\""))
-      << fetcher->upload_data();
+  EXPECT_TRUE(UploadDataContains("\"actionType\":\"PENDING\""));
 }
 
 // Send NO_ACTION feedback message if the marker has been removed from the
@@ -129,26 +164,18 @@
   AddPendingFeedback();
   feedback_->OnReceiveDocumentMarkers(kRendererProcessId,
                                       std::vector<uint32>());
-  net::TestURLFetcher* fetcher = GetFetcher();
-  EXPECT_NE(std::string::npos,
-            fetcher->upload_data().find("\"actionType\":\"NO_ACTION\""))
-      << fetcher->upload_data();
+  EXPECT_TRUE(UploadDataContains("\"actionType\":\"NO_ACTION\""));
 }
 
 // Send SELECT feedback message if the user has selected a spelling suggestion.
 TEST_F(FeedbackSenderTest, SelectFeedback) {
   uint32 hash = AddPendingFeedback();
-  static const int kSuggestion = 0;
-  feedback_->SelectedSuggestion(hash, kSuggestion);
+  static const int kSuggestionIndex = 0;
+  feedback_->SelectedSuggestion(hash, kSuggestionIndex);
   feedback_->OnReceiveDocumentMarkers(kRendererProcessId,
                                       std::vector<uint32>());
-  net::TestURLFetcher* fetcher = GetFetcher();
-  EXPECT_NE(std::string::npos,
-            fetcher->upload_data().find("\"actionType\":\"SELECT\""))
-      << fetcher->upload_data();
-  EXPECT_NE(std::string::npos,
-            fetcher->upload_data().find("\"actionTargetIndex\":" + kSuggestion))
-      << fetcher->upload_data();
+  EXPECT_TRUE(UploadDataContains("\"actionType\":\"SELECT\""));
+  EXPECT_TRUE(UploadDataContains("\"actionTargetIndex\":" + kSuggestionIndex));
 }
 
 // Send ADD_TO_DICT feedback message if the user has added the misspelled word
@@ -158,10 +185,17 @@
   feedback_->AddedToDictionary(hash);
   feedback_->OnReceiveDocumentMarkers(kRendererProcessId,
                                       std::vector<uint32>());
-  net::TestURLFetcher* fetcher = GetFetcher();
-  EXPECT_NE(std::string::npos,
-            fetcher->upload_data().find("\"actionType\":\"ADD_TO_DICT\""))
-      << fetcher->upload_data();
+  EXPECT_TRUE(UploadDataContains("\"actionType\":\"ADD_TO_DICT\""));
+}
+
+// Send IN_DICTIONARY feedback message if the user has the misspelled word in
+// the custom dictionary.
+TEST_F(FeedbackSenderTest, InDictionaryFeedback) {
+  uint32 hash = AddPendingFeedback();
+  feedback_->RecordInDictionary(hash);
+  feedback_->OnReceiveDocumentMarkers(kRendererProcessId,
+                                      std::vector<uint32>());
+  EXPECT_TRUE(UploadDataContains("\"actionType\":\"IN_DICTIONARY\""));
 }
 
 // Send PENDING feedback message if the user saw the spelling suggestion, but
@@ -171,10 +205,7 @@
   feedback_->IgnoredSuggestions(hash);
   feedback_->OnReceiveDocumentMarkers(kRendererProcessId,
                                       std::vector<uint32>(1, hash));
-  net::TestURLFetcher* fetcher = GetFetcher();
-  EXPECT_NE(std::string::npos,
-            fetcher->upload_data().find("\"actionType\":\"PENDING\""))
-      << fetcher->upload_data();
+  EXPECT_TRUE(UploadDataContains("\"actionType\":\"PENDING\""));
 }
 
 // Send IGNORE feedback message if the user saw the spelling suggestion, but
@@ -184,10 +215,7 @@
   feedback_->IgnoredSuggestions(hash);
   feedback_->OnReceiveDocumentMarkers(kRendererProcessId,
                                       std::vector<uint32>());
-  net::TestURLFetcher* fetcher = GetFetcher();
-  EXPECT_NE(std::string::npos,
-            fetcher->upload_data().find("\"actionType\":\"IGNORE\""))
-      << fetcher->upload_data();
+  EXPECT_TRUE(UploadDataContains("\"actionType\":\"IGNORE\""));
 }
 
 // Send MANUALLY_CORRECTED feedback message if the user manually corrected the
@@ -198,15 +226,9 @@
   feedback_->ManuallyCorrected(hash, ASCIIToUTF16(kManualCorrection));
   feedback_->OnReceiveDocumentMarkers(kRendererProcessId,
                                       std::vector<uint32>());
-  net::TestURLFetcher* fetcher = GetFetcher();
-  EXPECT_NE(
-      std::string::npos,
-      fetcher->upload_data().find("\"actionType\":\"MANUALLY_CORRECTED\""))
-      << fetcher->upload_data();
-  EXPECT_NE(std::string::npos,
-            fetcher->upload_data().find("\"actionTargetValue\":\"" +
-                                        kManualCorrection + "\""))
-      << fetcher->upload_data();
+  EXPECT_TRUE(UploadDataContains("\"actionType\":\"MANUALLY_CORRECTED\""));
+  EXPECT_TRUE(UploadDataContains("\"actionTargetValue\":\"" +
+                                 kManualCorrection + "\""));
 }
 
 // Send feedback messages in batch.
@@ -226,11 +248,7 @@
       &results, kRendererProcessId, kText, std::vector<SpellCheckMarker>());
   feedback_->OnReceiveDocumentMarkers(kRendererProcessId,
                                       std::vector<uint32>());
-  net::TestURLFetcher* fetcher = GetFetcher();
-  size_t pos = fetcher->upload_data().find("\"actionType\":\"NO_ACTION\"");
-  EXPECT_NE(std::string::npos, pos) << fetcher->upload_data();
-  pos = fetcher->upload_data().find("\"actionType\":\"NO_ACTION\"", pos + 1);
-  EXPECT_NE(std::string::npos, pos) << fetcher->upload_data();
+  EXPECT_TRUE(UploadDataContains("\"actionType\":\"NO_ACTION\"", 2));
 }
 
 // Send a series of PENDING feedback messages and one final NO_ACTION feedback
@@ -240,37 +258,25 @@
   std::vector<uint32> remaining_markers(1, hash);
 
   feedback_->OnReceiveDocumentMarkers(kRendererProcessId, remaining_markers);
-  net::TestURLFetcher* fetcher = GetFetcher();
-  EXPECT_NE(std::string::npos,
-            fetcher->upload_data().find("\"actionType\":\"PENDING\""))
-      << fetcher->upload_data();
+  EXPECT_TRUE(UploadDataContains("\"actionType\":\"PENDING\""));
   std::string hash_string = base::StringPrintf("\"suggestionId\":\"%u\"", hash);
-  EXPECT_NE(std::string::npos, fetcher->upload_data().find(hash_string))
-      << fetcher->upload_data();
-  fetchers_.RemoveFetcherFromMap(kUrlFetcherId);
+  EXPECT_TRUE(UploadDataContains(hash_string));
+  ClearUploadData();
 
   feedback_->OnReceiveDocumentMarkers(kRendererProcessId, remaining_markers);
-  fetcher = GetFetcher();
-  EXPECT_NE(std::string::npos,
-            fetcher->upload_data().find("\"actionType\":\"PENDING\""))
-      << fetcher->upload_data();
-  EXPECT_NE(std::string::npos, fetcher->upload_data().find(hash_string))
-      << fetcher->upload_data();
-  fetchers_.RemoveFetcherFromMap(kUrlFetcherId);
+  EXPECT_TRUE(UploadDataContains("\"actionType\":\"PENDING\""));
+  EXPECT_TRUE(UploadDataContains(hash_string));
+  ClearUploadData();
 
   feedback_->OnReceiveDocumentMarkers(kRendererProcessId,
                                       std::vector<uint32>());
-  fetcher = GetFetcher();
-  EXPECT_NE(std::string::npos,
-            fetcher->upload_data().find("\"actionType\":\"NO_ACTION\""))
-      << fetcher->upload_data();
-  EXPECT_NE(std::string::npos, fetcher->upload_data().find(hash_string))
-      << fetcher->upload_data();
-  fetchers_.RemoveFetcherFromMap(kUrlFetcherId);
+  EXPECT_TRUE(UploadDataContains("\"actionType\":\"NO_ACTION\""));
+  EXPECT_TRUE(UploadDataContains(hash_string));
+  ClearUploadData();
 
   feedback_->OnReceiveDocumentMarkers(kRendererProcessId,
                                       std::vector<uint32>());
-  EXPECT_EQ(NULL, GetFetcher());
+  EXPECT_FALSE(IsUploadingData());
 }
 
 // When a session expires:
@@ -291,40 +297,26 @@
   std::vector<uint32> remaining_markers(1, original_hash);
 
   feedback_->OnReceiveDocumentMarkers(kRendererProcessId, remaining_markers);
-  net::TestURLFetcher* fetcher = GetFetcher();
-  EXPECT_EQ(std::string::npos,
-            fetcher->upload_data().find("\"actionType\":\"NO_ACTION\""))
-      << fetcher->upload_data();
-  EXPECT_NE(std::string::npos,
-            fetcher->upload_data().find("\"actionType\":\"PENDING\""))
-      << fetcher->upload_data();
+  EXPECT_FALSE(UploadDataContains("\"actionType\":\"NO_ACTION\""));
+  EXPECT_TRUE(UploadDataContains("\"actionType\":\"PENDING\""));
   std::string original_hash_string =
       base::StringPrintf("\"suggestionId\":\"%u\"", original_hash);
-  EXPECT_NE(std::string::npos,
-            fetcher->upload_data().find(original_hash_string))
-      << fetcher->upload_data();
-  fetchers_.RemoveFetcherFromMap(kUrlFetcherId);
+  EXPECT_TRUE(UploadDataContains(original_hash_string));
+  ClearUploadData();
 
   ExpireSession();
 
   // Last message batch in the current session has only finalized messages.
   feedback_->OnReceiveDocumentMarkers(kRendererProcessId, remaining_markers);
-  fetcher = GetFetcher();
-  EXPECT_NE(std::string::npos,
-            fetcher->upload_data().find("\"actionType\":\"NO_ACTION\""))
-      << fetcher->upload_data();
-  EXPECT_EQ(std::string::npos,
-            fetcher->upload_data().find("\"actionType\":\"PENDING\""))
-      << fetcher->upload_data();
-  EXPECT_NE(std::string::npos,
-            fetcher->upload_data().find(original_hash_string))
-      << fetcher->upload_data();
-  fetchers_.RemoveFetcherFromMap(kUrlFetcherId);
+  EXPECT_TRUE(UploadDataContains("\"actionType\":\"NO_ACTION\""));
+  EXPECT_FALSE(UploadDataContains("\"actionType\":\"PENDING\""));
+  EXPECT_TRUE(UploadDataContains(original_hash_string));
+  ClearUploadData();
 
   // The next session starts on the next spellchecker request. Until then,
   // there's no more feedback sent.
   feedback_->OnReceiveDocumentMarkers(kRendererProcessId, remaining_markers);
-  EXPECT_EQ(NULL, GetFetcher());
+  EXPECT_FALSE(IsUploadingData());
 
   // The first spellcheck request after session expiration creates different
   // document marker hash identifiers.
@@ -343,20 +335,12 @@
   // The first feedback message batch in session |i + 1| has the new document
   // marker hash identifiers.
   feedback_->OnReceiveDocumentMarkers(kRendererProcessId, remaining_markers);
-  fetcher = GetFetcher();
-  EXPECT_EQ(std::string::npos,
-            fetcher->upload_data().find("\"actionType\":\"NO_ACTION\""))
-      << fetcher->upload_data();
-  EXPECT_NE(std::string::npos,
-            fetcher->upload_data().find("\"actionType\":\"PENDING\""))
-      << fetcher->upload_data();
-  EXPECT_EQ(std::string::npos,
-            fetcher->upload_data().find(original_hash_string))
-      << fetcher->upload_data();
+  EXPECT_FALSE(UploadDataContains("\"actionType\":\"NO_ACTION\""));
+  EXPECT_TRUE(UploadDataContains("\"actionType\":\"PENDING\""));
+  EXPECT_FALSE(UploadDataContains(original_hash_string));
   std::string updated_hash_string =
       base::StringPrintf("\"suggestionId\":\"%u\"", updated_hash);
-  EXPECT_NE(std::string::npos, fetcher->upload_data().find(updated_hash_string))
-      << fetcher->upload_data();
+  EXPECT_TRUE(UploadDataContains(updated_hash_string));
 }
 
 // First message in session has an indicator.
@@ -365,19 +349,13 @@
   AddPendingFeedback();
   feedback_->OnReceiveDocumentMarkers(kRendererProcessId,
                                       std::vector<uint32>());
-  net::TestURLFetcher* fetcher = GetFetcher();
-  EXPECT_NE(std::string::npos,
-            fetcher->upload_data().find("\"isFirstInSession\":true"))
-      << fetcher->upload_data();
+  EXPECT_TRUE(UploadDataContains("\"isFirstInSession\":true"));
 
   // Session 1, message 2
   AddPendingFeedback();
   feedback_->OnReceiveDocumentMarkers(kRendererProcessId,
                                       std::vector<uint32>());
-  fetcher = GetFetcher();
-  EXPECT_NE(std::string::npos,
-            fetcher->upload_data().find("\"isFirstInSession\":false"))
-      << fetcher->upload_data();
+  EXPECT_TRUE(UploadDataContains("\"isFirstInSession\":false"));
 
   ExpireSession();
 
@@ -385,45 +363,29 @@
   AddPendingFeedback();
   feedback_->OnReceiveDocumentMarkers(kRendererProcessId,
                                       std::vector<uint32>());
-  fetcher = GetFetcher();
-  EXPECT_NE(std::string::npos,
-            fetcher->upload_data().find("\"isFirstInSession\":false"))
-      << fetcher->upload_data();
+  EXPECT_TRUE(UploadDataContains("\"isFirstInSession\":false"));
 
   // Session 2, message 1
   AddPendingFeedback();
   feedback_->OnReceiveDocumentMarkers(kRendererProcessId,
                                       std::vector<uint32>());
-  fetcher = GetFetcher();
-  EXPECT_NE(std::string::npos,
-            fetcher->upload_data().find("\"isFirstInSession\":true"))
-      << fetcher->upload_data();
+  EXPECT_TRUE(UploadDataContains("\"isFirstInSession\":true"));
 
   // Session 2, message 2
   AddPendingFeedback();
   feedback_->OnReceiveDocumentMarkers(kRendererProcessId,
                                       std::vector<uint32>());
-  fetcher = GetFetcher();
-  EXPECT_NE(std::string::npos,
-            fetcher->upload_data().find("\"isFirstInSession\":false"))
-      << fetcher->upload_data();
+  EXPECT_TRUE(UploadDataContains("\"isFirstInSession\":false"));
 }
 
 // Flush all feedback when the spellcheck language and country change.
 TEST_F(FeedbackSenderTest, OnLanguageCountryChange) {
   AddPendingFeedback();
   feedback_->OnLanguageCountryChange("pt", "BR");
-  net::TestURLFetcher* fetcher = GetFetcher();
-  EXPECT_NE(std::string::npos,
-            fetcher->upload_data().find("\"language\":\"en\""))
-      << fetcher->upload_data();
-
+  EXPECT_TRUE(UploadDataContains("\"language\":\"en\""));
   AddPendingFeedback();
   feedback_->OnLanguageCountryChange("en", "US");
-  fetcher = GetFetcher();
-  EXPECT_NE(std::string::npos,
-            fetcher->upload_data().find("\"language\":\"pt\""))
-      << fetcher->upload_data();
+  EXPECT_TRUE(UploadDataContains("\"language\":\"pt\""));
 }
 
 // The field names and types should correspond to the API.
@@ -431,7 +393,7 @@
   AddPendingFeedback();
   feedback_->OnReceiveDocumentMarkers(kRendererProcessId,
                                       std::vector<uint32>());
-  std::string actual_data = GetFetcher()->upload_data();
+  std::string actual_data = GetUploadData();
   scoped_ptr<base::DictionaryValue> actual(
       static_cast<base::DictionaryValue*>(base::JSONReader::Read(actual_data)));
   actual->SetString("params.key", "TestDummyKey");
@@ -481,22 +443,6 @@
   EXPECT_EQ(hash, results[0].hash);
 }
 
-namespace {
-
-// Returns the number of times that |needle| appears in |haystack| without
-// overlaps. For example, CountOccurences("bananana", "nana") returns 1.
-int CountOccurences(const std::string& haystack, const std::string& needle) {
-  int number_of_occurences = 0;
-  size_t pos = haystack.find(needle);
-  while (pos != std::string::npos) {
-    ++number_of_occurences;
-    pos = haystack.find(needle, pos + needle.length());
-  }
-  return number_of_occurences;
-}
-
-}  // namespace
-
 // Adding a word to dictionary should trigger ADD_TO_DICT feedback for every
 // occurrence of that word.
 TEST_F(FeedbackSenderTest, MultipleAddToDictFeedback) {
@@ -525,20 +471,14 @@
     remaining_markers.push_back(results[i].hash);
   feedback_->OnReceiveDocumentMarkers(last_renderer_process_id,
                                       remaining_markers);
-  net::TestURLFetcher* fetcher = GetFetcher();
-  EXPECT_EQ(2, CountOccurences(fetcher->upload_data(), "PENDING"))
-      << fetcher->upload_data();
-  EXPECT_EQ(0, CountOccurences(fetcher->upload_data(), "ADD_TO_DICT"))
-      << fetcher->upload_data();
+  EXPECT_TRUE(UploadDataContains("PENDING", 2));
+  EXPECT_FALSE(UploadDataContains("ADD_TO_DICT"));
 
   feedback_->AddedToDictionary(results[0].hash);
   feedback_->OnReceiveDocumentMarkers(last_renderer_process_id,
                                       remaining_markers);
-  fetcher = GetFetcher();
-  EXPECT_EQ(0, CountOccurences(fetcher->upload_data(), "PENDING"))
-      << fetcher->upload_data();
-  EXPECT_EQ(2, CountOccurences(fetcher->upload_data(), "ADD_TO_DICT"))
-      << fetcher->upload_data();
+  EXPECT_FALSE(UploadDataContains("PENDING"));
+  EXPECT_TRUE(UploadDataContains("ADD_TO_DICT", 2));
 }
 
 // ADD_TO_DICT feedback for multiple occurrences of a word should trigger only
@@ -551,11 +491,8 @@
   feedback_->AddedToDictionary(add_to_dict_hash);
   feedback_->OnReceiveDocumentMarkers(kRendererProcessId,
                                       std::vector<uint32>());
-  net::TestURLFetcher* fetcher = GetFetcher();
-  EXPECT_EQ(1, CountOccurences(fetcher->upload_data(), "SELECT"))
-      << fetcher->upload_data();
-  EXPECT_EQ(2, CountOccurences(fetcher->upload_data(), "ADD_TO_DICT"))
-      << fetcher->upload_data();
+  EXPECT_TRUE(UploadDataContains("SELECT", 1));
+  EXPECT_TRUE(UploadDataContains("ADD_TO_DICT", 2));
 }
 
 }  // namespace spellcheck
diff --git a/chrome/browser/spellchecker/misspelling.h b/chrome/browser/spellchecker/misspelling.h
index 9a9d0fe..7cd331b 100644
--- a/chrome/browser/spellchecker/misspelling.h
+++ b/chrome/browser/spellchecker/misspelling.h
@@ -7,7 +7,7 @@
 
 #include <vector>
 
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/spellchecker/spellcheck_action.h"
 
 // Spellcheck misspelling.
diff --git a/chrome/browser/spellchecker/spellcheck_custom_dictionary.cc b/chrome/browser/spellchecker/spellcheck_custom_dictionary.cc
index 0cd0c7c..c3d2484 100644
--- a/chrome/browser/spellchecker/spellcheck_custom_dictionary.cc
+++ b/chrome/browser/spellchecker/spellcheck_custom_dictionary.cc
@@ -261,7 +261,7 @@
   return result == VALID_CHANGE;
 }
 
-bool SpellcheckCustomDictionary::HasWord(const std::string& word) {
+bool SpellcheckCustomDictionary::HasWord(const std::string& word) const {
   return !!words_.count(word);
 }
 
diff --git a/chrome/browser/spellchecker/spellcheck_custom_dictionary.h b/chrome/browser/spellchecker/spellcheck_custom_dictionary.h
index e54b6fa..848022a 100644
--- a/chrome/browser/spellchecker/spellcheck_custom_dictionary.h
+++ b/chrome/browser/spellchecker/spellcheck_custom_dictionary.h
@@ -91,7 +91,7 @@
   bool RemoveWord(const std::string& word);
 
   // Returns true if the dictionary contains |word|. Otherwise returns false.
-  bool HasWord(const std::string& word);
+  bool HasWord(const std::string& word) const;
 
   // Adds |observer| to be notified of dictionary events and changes.
   void AddObserver(Observer* observer);
diff --git a/chrome/browser/spellchecker/spellcheck_custom_dictionary_unittest.cc b/chrome/browser/spellchecker/spellcheck_custom_dictionary_unittest.cc
index d196f65..58c3d1b 100644
--- a/chrome/browser/spellchecker/spellcheck_custom_dictionary_unittest.cc
+++ b/chrome/browser/spellchecker/spellcheck_custom_dictionary_unittest.cc
@@ -154,7 +154,10 @@
       const tracked_objects::Location& location,
       const std::string& message) OVERRIDE {
     (*error_counter_)++;
-    return syncer::SyncError(location, message, syncer::DICTIONARY);
+    return syncer::SyncError(location,
+                             syncer::SyncError::DATATYPE_ERROR,
+                             message,
+                             syncer::DICTIONARY);
   }
 
  private:
diff --git a/chrome/browser/spellchecker/spellcheck_host_metrics.h b/chrome/browser/spellchecker/spellcheck_host_metrics.h
index bc36792..53f4e42 100644
--- a/chrome/browser/spellchecker/spellcheck_host_metrics.h
+++ b/chrome/browser/spellchecker/spellcheck_host_metrics.h
@@ -9,8 +9,8 @@
 #include <vector>
 
 #include "base/containers/hash_tables.h"
-#include "base/time.h"
-#include "base/timer.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
 
 // A helper object for recording spell-check related histograms.
 // This class encapsulates histogram names and metrics API.
diff --git a/chrome/browser/spellchecker/spellcheck_hunspell_dictionary.cc b/chrome/browser/spellchecker/spellcheck_hunspell_dictionary.cc
index 44a166d..a6f5169 100644
--- a/chrome/browser/spellchecker/spellcheck_hunspell_dictionary.cc
+++ b/chrome/browser/spellchecker/spellcheck_hunspell_dictionary.cc
@@ -9,18 +9,18 @@
 #include "base/logging.h"
 #include "base/message_loop.h"
 #include "base/path_service.h"
-#include "chrome/browser/spellchecker/spellcheck_service.h"
 #include "chrome/browser/spellchecker/spellcheck_platform_mac.h"
+#include "chrome/browser/spellchecker/spellcheck_service.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/spellcheck_common.h"
 #include "chrome/common/spellcheck_messages.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/render_process_host.h"
-#include "googleurl/src/gurl.h"
 #include "net/base/load_flags.h"
 #include "net/url_request/url_fetcher.h"
 #include "net/url_request/url_request_context_getter.h"
 #include "third_party/hunspell/google/bdict.h"
+#include "url/gurl.h"
 
 using content::BrowserThread;
 
@@ -101,7 +101,7 @@
         NULL,
         NULL);
   } else {
-    file_util::Delete(file->path, false);
+    base::Delete(file->path, false);
   }
 
   return file.Pass();
@@ -148,7 +148,7 @@
 #endif
 
     if (!success) {
-      file_util::Delete(path, false);
+      base::Delete(path, false);
       return false;
     }
   }
diff --git a/chrome/browser/spellchecker/spellcheck_message_filter.cc b/chrome/browser/spellchecker/spellcheck_message_filter.cc
index 091a66e..e58be59 100644
--- a/chrome/browser/spellchecker/spellcheck_message_filter.cc
+++ b/chrome/browser/spellchecker/spellcheck_message_filter.cc
@@ -9,6 +9,7 @@
 
 #include "base/bind.h"
 #include "base/prefs/pref_service.h"
+#include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/spellchecker/spellcheck_factory.h"
 #include "chrome/browser/spellchecker/spellcheck_host_metrics.h"
@@ -87,23 +88,18 @@
 
 void SpellCheckMessageFilter::OnNotifyChecked(const string16& word,
                                               bool misspelled) {
-  content::RenderProcessHost* host =
-      content::RenderProcessHost::FromID(render_process_id_);
-  if (!host)
-    return;  // Teardown.
-  // Delegates to SpellCheckHost which tracks the stats of our spellchecker.
-  Profile* profile = Profile::FromBrowserContext(host->GetBrowserContext());
-  SpellcheckService* spellcheck_service =
-      SpellcheckServiceFactory::GetForProfile(profile);
-  DCHECK(spellcheck_service);
-  if (spellcheck_service->GetMetrics())
-    spellcheck_service->GetMetrics()->RecordCheckedWordStats(word, misspelled);
+  SpellcheckService* spellcheck = GetSpellcheckService();
+  // Spellcheck service may not be available for a renderer process that is
+  // shutting down.
+  if (!spellcheck)
+    return;
+  if (spellcheck->GetMetrics())
+    spellcheck->GetMetrics()->RecordCheckedWordStats(word, misspelled);
 }
 
 void SpellCheckMessageFilter::OnRespondDocumentMarkers(
     const std::vector<uint32>& markers) {
-  SpellcheckService* spellcheck =
-      SpellcheckServiceFactory::GetForRenderProcessId(render_process_id_);
+  SpellcheckService* spellcheck = GetSpellcheckService();
   // Spellcheck service may not be available for a renderer process that is
   // shutting down.
   if (!spellcheck)
@@ -137,12 +133,34 @@
     bool success,
     const string16& text,
     const std::vector<SpellCheckResult>& results) {
-  SpellcheckService* spellcheck =
-      SpellcheckServiceFactory::GetForRenderProcessId(render_process_id_);
-  DCHECK(spellcheck);
+  SpellcheckService* spellcheck = GetSpellcheckService();
+  // Spellcheck service may not be available for a renderer process that is
+  // shutting down.
+  if (!spellcheck)
+    return;
   std::vector<SpellCheckResult> results_copy = results;
   spellcheck->GetFeedbackSender()->OnSpellcheckResults(
       &results_copy, render_process_id_, text, markers);
+
+  // Erase custom dictionary words from the spellcheck results and record
+  // in-dictionary feedback.
+  std::vector<SpellCheckResult>::iterator write_iter;
+  std::vector<SpellCheckResult>::iterator iter;
+  std::string text_copy = UTF16ToUTF8(text);
+  for (iter = write_iter = results_copy.begin();
+       iter != results_copy.end();
+       ++iter) {
+    if (spellcheck->GetCustomDictionary()->HasWord(
+            text_copy.substr(iter->location, iter->length))) {
+      spellcheck->GetFeedbackSender()->RecordInDictionary(iter->hash);
+    } else {
+      if (write_iter != iter)
+        *write_iter = *iter;
+      ++write_iter;
+    }
+  }
+  results_copy.erase(write_iter, results_copy.end());
+
   Send(new SpellCheckMsg_RespondSpellingService(
       route_id, identifier, success, text, results_copy));
 }
@@ -171,3 +189,7 @@
                markers));
 }
 #endif
+
+SpellcheckService* SpellCheckMessageFilter::GetSpellcheckService() const {
+  return SpellcheckServiceFactory::GetForRenderProcessId(render_process_id_);
+}
diff --git a/chrome/browser/spellchecker/spellcheck_message_filter.h b/chrome/browser/spellchecker/spellcheck_message_filter.h
index 77c8306..885aab1 100644
--- a/chrome/browser/spellchecker/spellcheck_message_filter.h
+++ b/chrome/browser/spellchecker/spellcheck_message_filter.h
@@ -11,6 +11,7 @@
 #include "content/public/browser/browser_message_filter.h"
 
 class SpellCheckMarker;
+class SpellcheckService;
 struct SpellCheckResult;
 
 // A message filter implementation that receives spell checker requests from
@@ -27,6 +28,8 @@
                                  bool* message_was_ok) OVERRIDE;
 
  private:
+  friend class TestingSpellCheckMessageFilter;
+
   virtual ~SpellCheckMessageFilter();
 
   void OnSpellCheckerRequestDictionary();
@@ -61,6 +64,9 @@
       const std::vector<SpellCheckMarker>& markers);
 #endif
 
+  // Can be overridden for testing.
+  virtual SpellcheckService* GetSpellcheckService() const;
+
   int render_process_id_;
 
   // A JSON-RPC client that calls the Spelling service in the background.
diff --git a/chrome/browser/spellchecker/spellcheck_message_filter_unittest.cc b/chrome/browser/spellchecker/spellcheck_message_filter_unittest.cc
index 3407dbd..d0fb26f 100644
--- a/chrome/browser/spellchecker/spellcheck_message_filter_unittest.cc
+++ b/chrome/browser/spellchecker/spellcheck_message_filter_unittest.cc
@@ -2,12 +2,58 @@
 // 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 "chrome/browser/spellchecker/spellcheck_factory.h"
 #include "chrome/browser/spellchecker/spellcheck_message_filter.h"
+#include "chrome/browser/spellchecker/spellcheck_service.h"
+#include "chrome/common/spellcheck_marker.h"
 #include "chrome/common/spellcheck_messages.h"
-#include "content/public/browser/browser_thread.h"
+#include "chrome/test/base/testing_profile.h"
+#include "content/public/test/test_browser_thread.h"
 #include "ipc/ipc_message.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+class TestingSpellCheckMessageFilter : public SpellCheckMessageFilter {
+ public:
+  TestingSpellCheckMessageFilter()
+      : SpellCheckMessageFilter(0),
+        ui_thread_(content::BrowserThread::UI, &message_loop_),
+        spellcheck_(new SpellcheckService(&profile_)) {}
+
+  virtual bool Send(IPC::Message* message) OVERRIDE {
+    sent_messages.push_back(message);
+    return true;
+  }
+
+  virtual SpellcheckService* GetSpellcheckService() const OVERRIDE {
+    return spellcheck_.get();
+  }
+
+#if !defined(OS_MACOSX)
+  void OnTextCheckComplete(int route_id,
+                           int identifier,
+                           const std::vector<SpellCheckMarker>& markers,
+                           bool success,
+                           const string16& text,
+                           const std::vector<SpellCheckResult>& results) {
+    SpellCheckMessageFilter::OnTextCheckComplete(
+        route_id, identifier, markers, success, text, results);
+  }
+#endif
+
+  ScopedVector<IPC::Message> sent_messages;
+
+ private:
+  virtual ~TestingSpellCheckMessageFilter() {}
+
+  base::MessageLoop message_loop_;
+  content::TestBrowserThread ui_thread_;
+  TestingProfile profile_;
+  scoped_ptr<SpellcheckService> spellcheck_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestingSpellCheckMessageFilter);
+};
+
 TEST(SpellCheckMessageFilterTest, TestOverrideThread) {
   static const uint32 kSpellcheckMessages[] = {
     SpellCheckHostMsg_RequestDictionary::ID,
@@ -17,9 +63,10 @@
     SpellCheckHostMsg_CallSpellingService::ID,
 #endif
   };
-  scoped_refptr<SpellCheckMessageFilter> filter(new SpellCheckMessageFilter(0));
   content::BrowserThread::ID thread;
   IPC::Message message;
+  scoped_refptr<TestingSpellCheckMessageFilter> filter(
+      new TestingSpellCheckMessageFilter);
   for (size_t i = 0; i < arraysize(kSpellcheckMessages); ++i) {
     message.SetHeaderValues(
         0, kSpellcheckMessages[i], IPC::Message::PRIORITY_NORMAL);
@@ -28,3 +75,75 @@
     EXPECT_EQ(content::BrowserThread::UI, thread);
   }
 }
+
+#if !defined(OS_MACOSX)
+TEST(SpellCheckMessageFilterTest, OnTextCheckCompleteTestCustomDictionary) {
+  static const std::string kCustomWord = "Helllo";
+  static const int kRouteId = 0;
+  static const int kCallbackId = 0;
+  static const std::vector<SpellCheckMarker> kMarkers;
+  static const string16 kText = ASCIIToUTF16("Helllo warld.");
+  static const bool kSuccess = true;
+  static const SpellCheckResult::Type kType = SpellCheckResult::SPELLING;
+  static const int kLocation = 7;
+  static const int kLength = 5;
+  static const string16 kReplacement = ASCIIToUTF16("world");
+
+  std::vector<SpellCheckResult> results;
+  results.push_back(SpellCheckResult(
+      SpellCheckResult::SPELLING, 0, 6, ASCIIToUTF16("Hello")));
+  results.push_back(SpellCheckResult(kType, kLocation, kLength, kReplacement));
+
+  scoped_refptr<TestingSpellCheckMessageFilter> filter(
+      new TestingSpellCheckMessageFilter);
+  filter->GetSpellcheckService()->GetCustomDictionary()->AddWord(kCustomWord);
+  filter->OnTextCheckComplete(
+      kRouteId, kCallbackId, kMarkers, kSuccess, kText, results);
+  EXPECT_EQ(static_cast<size_t>(1), filter->sent_messages.size());
+
+  int sent_identifier = -1;
+  bool sent_success = false;
+  string16 sent_text;
+  std::vector<SpellCheckResult> sent_results;
+  bool ok = SpellCheckMsg_RespondSpellingService::Read(filter->sent_messages[0],
+                                                       &sent_identifier,
+                                                       &sent_success,
+                                                       &sent_text,
+                                                       &sent_results);
+  EXPECT_TRUE(ok);
+  EXPECT_EQ(kCallbackId, sent_identifier);
+  EXPECT_EQ(kSuccess, sent_success);
+  EXPECT_EQ(kText, sent_text);
+  EXPECT_EQ(static_cast<size_t>(1), sent_results.size());
+  EXPECT_EQ(kType, sent_results[0].type);
+  EXPECT_EQ(kLocation, sent_results[0].location);
+  EXPECT_EQ(kLength, sent_results[0].length);
+  EXPECT_EQ(kReplacement, sent_results[0].replacement);
+}
+
+TEST(SpellCheckMessageFilterTest, OnTextCheckCompleteTest) {
+  std::vector<SpellCheckResult> results;
+  results.push_back(SpellCheckResult(
+      SpellCheckResult::SPELLING, 0, 6, ASCIIToUTF16("Hello")));
+  results.push_back(SpellCheckResult(
+      SpellCheckResult::SPELLING, 7, 7, ASCIIToUTF16("world")));
+
+  scoped_refptr<TestingSpellCheckMessageFilter> filter(
+      new TestingSpellCheckMessageFilter);
+  filter->OnTextCheckComplete(1, 1, std::vector<SpellCheckMarker>(),
+      true,  ASCIIToUTF16("Helllo walrd"), results);
+  EXPECT_EQ(static_cast<size_t>(1), filter->sent_messages.size());
+
+  int sent_identifier = -1;
+  bool sent_success = false;
+  string16 sent_text;
+  std::vector<SpellCheckResult> sent_results;
+  bool ok = SpellCheckMsg_RespondSpellingService::Read(filter->sent_messages[0],
+                                                       &sent_identifier,
+                                                       &sent_success,
+                                                       &sent_text,
+                                                       &sent_results);
+  EXPECT_TRUE(ok);
+  EXPECT_EQ(static_cast<size_t>(2), sent_results.size());
+}
+#endif
diff --git a/chrome/browser/spellchecker/spellcheck_platform_mac.mm b/chrome/browser/spellchecker/spellcheck_platform_mac.mm
index d64238c..297219a 100644
--- a/chrome/browser/spellchecker/spellcheck_platform_mac.mm
+++ b/chrome/browser/spellchecker/spellcheck_platform_mac.mm
@@ -15,7 +15,7 @@
 #include "base/mac/scoped_nsexception_enabler.h"
 #include "base/metrics/histogram.h"
 #include "base/strings/sys_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/common/spellcheck_common.h"
 #include "chrome/common/spellcheck_messages.h"
 #include "chrome/common/spellcheck_result.h"
diff --git a/chrome/browser/spellchecker/spellcheck_service_browsertest.cc b/chrome/browser/spellchecker/spellcheck_service_browsertest.cc
index cf7b64f..5130600 100644
--- a/chrome/browser/spellchecker/spellcheck_service_browsertest.cc
+++ b/chrome/browser/spellchecker/spellcheck_service_browsertest.cc
@@ -12,7 +12,7 @@
 #include "chrome/common/spellcheck_common.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 namespace {
 
@@ -80,6 +80,6 @@
             SpellcheckService::GetStatusEvent());
   if (file_util::PathExists(bdict_path)) {
     ADD_FAILURE();
-    EXPECT_TRUE(file_util::Delete(bdict_path, true));
+    EXPECT_TRUE(base::Delete(bdict_path, true));
   }
 }
diff --git a/chrome/browser/ssl/ssl_add_cert_handler_mac.mm b/chrome/browser/ssl/ssl_add_cert_handler_mac.mm
index d12e477..a2906f9 100644
--- a/chrome/browser/ssl/ssl_add_cert_handler_mac.mm
+++ b/chrome/browser/ssl/ssl_add_cert_handler_mac.mm
@@ -8,7 +8,6 @@
 #include <SecurityInterface/SFCertificateView.h>
 
 #include "base/logging.h"
-#include "base/memory/scoped_nsobject.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/cocoa/last_active_browser_cocoa.h"
diff --git a/chrome/browser/ssl/ssl_blocking_page.cc b/chrome/browser/ssl/ssl_blocking_page.cc
index 625dab8..5b45b35 100644
--- a/chrome/browser/ssl/ssl_blocking_page.cc
+++ b/chrome/browser/ssl/ssl_blocking_page.cc
@@ -158,6 +158,9 @@
 const char kCondition16Firefox[] = "Condition16SSLFirefox";
 const char kCondition17FancyFirefox[] = "Condition17SSLFancyFirefox";
 const char kCondition18NoImages[] = "Condition18SSLNoImages";
+const char kCondition19Policeman[] = "Condition19SSLPoliceman";
+const char kCondition20Stoplight[] = "Condition20SSLStoplight";
+const char kCondition21Badguy[] = "Condition21SSLBadguy";
 
 }  // namespace
 
diff --git a/chrome/browser/ssl/ssl_blocking_page.h b/chrome/browser/ssl/ssl_blocking_page.h
index bf22613..e0e6d61 100644
--- a/chrome/browser/ssl/ssl_blocking_page.h
+++ b/chrome/browser/ssl/ssl_blocking_page.h
@@ -10,10 +10,10 @@
 
 #include "base/callback.h"
 #include "base/strings/string16.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "content/public/browser/interstitial_page_delegate.h"
-#include "googleurl/src/gurl.h"
 #include "net/ssl/ssl_info.h"
+#include "url/gurl.h"
 
 namespace base {
 class DictionaryValue;
diff --git a/chrome/browser/ssl/ssl_browser_tests.cc b/chrome/browser/ssl/ssl_browser_tests.cc
index 8399a03..1c0c5e1 100644
--- a/chrome/browser/ssl/ssl_browser_tests.cc
+++ b/chrome/browser/ssl/ssl_browser_tests.cc
@@ -8,7 +8,7 @@
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/content_settings/host_content_settings_map.h"
 #include "chrome/browser/profiles/profile.h"
diff --git a/chrome/browser/ssl/ssl_client_certificate_selector_test.cc b/chrome/browser/ssl/ssl_client_certificate_selector_test.cc
index 8ac9321..da8e463 100644
--- a/chrome/browser/ssl/ssl_client_certificate_selector_test.cc
+++ b/chrome/browser/ssl/ssl_client_certificate_selector_test.cc
@@ -81,8 +81,7 @@
   url_request_ = MakeURLRequest(url_request_context_getter_.get());
 
   auth_requestor_ = new StrictMock<SSLClientAuthRequestorMock>(
-      url_request_,
-      cert_request_info_);
+      url_request_, cert_request_info_.get());
 
   io_loop_finished_event_.Signal();
 }
diff --git a/chrome/browser/ssl/ssl_error_info.cc b/chrome/browser/ssl/ssl_error_info.cc
index 0d1cfe8..a6860dd 100644
--- a/chrome/browser/ssl/ssl_error_info.cc
+++ b/chrome/browser/ssl/ssl_error_info.cc
@@ -8,7 +8,6 @@
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/common/time_format.h"
 #include "content/public/browser/cert_store.h"
-#include "googleurl/src/gurl.h"
 #include "grit/chromium_strings.h"
 #include "grit/generated_resources.h"
 #include "net/base/escape.h"
@@ -16,6 +15,7 @@
 #include "net/cert/cert_status_flags.h"
 #include "net/ssl/ssl_info.h"
 #include "ui/base/l10n/l10n_util.h"
+#include "url/gurl.h"
 
 SSLErrorInfo::SSLErrorInfo(const string16& title,
                            const string16& details,
diff --git a/chrome/browser/status_icons/status_icon.cc b/chrome/browser/status_icons/status_icon.cc
index 5398f74..00270d2 100644
--- a/chrome/browser/status_icons/status_icon.cc
+++ b/chrome/browser/status_icons/status_icon.cc
@@ -29,7 +29,16 @@
   FOR_EACH_OBSERVER(StatusIconObserver, observers_, OnStatusIconClicked());
 }
 
+#if defined(OS_WIN)
+void StatusIcon::DispatchBalloonClickEvent() {
+  FOR_EACH_OBSERVER(StatusIconObserver, observers_, OnBalloonClicked());
+}
+#endif
+
 void StatusIcon::SetContextMenu(ui::MenuModel* menu) {
+  // The UI may been showing a menu for the current model, don't destroy it
+  // until we've notified the UI of the change.
+  scoped_ptr<ui::MenuModel> old_menu = context_menu_contents_.Pass();
   context_menu_contents_.reset(menu);
   UpdatePlatformContextMenu(menu);
 }
diff --git a/chrome/browser/status_icons/status_icon.h b/chrome/browser/status_icons/status_icon.h
index 0303946..8d846a5 100644
--- a/chrome/browser/status_icons/status_icon.h
+++ b/chrome/browser/status_icons/status_icon.h
@@ -56,6 +56,9 @@
 
   // Dispatches a click event to the observers.
   void DispatchClickEvent();
+#if defined(OS_WIN)
+  void DispatchBalloonClickEvent();
+#endif
 
  protected:
   // Invoked after a call to SetContextMenu() to let the platform-specific
diff --git a/chrome/browser/status_icons/status_icon_observer.h b/chrome/browser/status_icons/status_icon_observer.h
index 28ee3d8..4183567 100644
--- a/chrome/browser/status_icons/status_icon_observer.h
+++ b/chrome/browser/status_icons/status_icon_observer.h
@@ -16,6 +16,13 @@
   // This will only be fired for this platform if no context menu is present.
   virtual void OnStatusIconClicked() = 0;
 
+#if defined(OS_WIN)
+  // Called when the user clicks on a balloon generated for a system tray icon.
+  // TODO(dewittj): Implement on platforms other than Windows.  Currently this
+  // event will never fire on non-Windows platforms.
+  virtual void OnBalloonClicked() {}
+#endif
+
  protected:
   virtual ~StatusIconObserver() {}
 };
diff --git a/chrome/browser/storage_monitor/image_capture_device.h b/chrome/browser/storage_monitor/image_capture_device.h
index 0860d9d..82fd1b5 100644
--- a/chrome/browser/storage_monitor/image_capture_device.h
+++ b/chrome/browser/storage_monitor/image_capture_device.h
@@ -11,8 +11,8 @@
 #include "base/files/file_path.h"
 #include "base/mac/cocoa_protocols.h"
 #include "base/mac/foundation_util.h"
+#include "base/mac/scoped_nsobject.h"
 #include "base/memory/ref_counted.h"
-#include "base/memory/scoped_nsobject.h"
 #include "base/memory/weak_ptr.h"
 #include "base/platform_file.h"
 #include "base/strings/string_util.h"
@@ -58,7 +58,7 @@
 @interface ImageCaptureDevice
     : NSObject<ICCameraDeviceDelegate, ICCameraDeviceDownloadDelegate> {
  @private
-  scoped_nsobject<ICCameraDevice> camera_;
+  base::scoped_nsobject<ICCameraDevice> camera_;
   base::WeakPtr<ImageCaptureDeviceListener> listener_;
   bool closing_;
 }
diff --git a/chrome/browser/storage_monitor/image_capture_device.mm b/chrome/browser/storage_monitor/image_capture_device.mm
index 15fb913..7a4fe86 100644
--- a/chrome/browser/storage_monitor/image_capture_device.mm
+++ b/chrome/browser/storage_monitor/image_capture_device.mm
@@ -13,7 +13,7 @@
                 const base::FilePath& desired_filename,
                 base::PlatformFileError* result) {
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
-  bool success = file_util::ReplaceFile(downloaded_filename, desired_filename);
+  bool success = base::ReplaceFile(downloaded_filename, desired_filename, NULL);
   *result = success ? base::PLATFORM_FILE_OK
                     : base::PLATFORM_FILE_ERROR_NOT_FOUND;
 }
diff --git a/chrome/browser/storage_monitor/image_capture_device_manager.h b/chrome/browser/storage_monitor/image_capture_device_manager.h
index 22297c9..bc8c09e 100644
--- a/chrome/browser/storage_monitor/image_capture_device_manager.h
+++ b/chrome/browser/storage_monitor/image_capture_device_manager.h
@@ -8,7 +8,7 @@
 #import <Foundation/Foundation.h>
 #include <string>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "chrome/browser/storage_monitor/storage_monitor.h"
 
 @protocol ICDeviceBrowserDelegate;
@@ -39,7 +39,7 @@
   void SetNotifications(StorageMonitor::Receiver* notifications);
 
  private:
-  scoped_nsobject<ImageCaptureDeviceManagerImpl> device_browser_;
+  base::scoped_nsobject<ImageCaptureDeviceManagerImpl> device_browser_;
 };
 
 }  // namespace chrome
diff --git a/chrome/browser/storage_monitor/image_capture_device_manager.mm b/chrome/browser/storage_monitor/image_capture_device_manager.mm
index cfd5057..91191b4 100644
--- a/chrome/browser/storage_monitor/image_capture_device_manager.mm
+++ b/chrome/browser/storage_monitor/image_capture_device_manager.mm
@@ -25,8 +25,8 @@
 @interface ImageCaptureDeviceManagerImpl
     : NSObject<ICDeviceBrowserDelegate> {
  @private
-  scoped_nsobject<ICDeviceBrowser> deviceBrowser_;
-  scoped_nsobject<NSMutableArray> cameras_;
+  base::scoped_nsobject<ICDeviceBrowser> deviceBrowser_;
+  base::scoped_nsobject<NSMutableArray> cameras_;
 
   // Guaranteed to outlive this class.
   // TODO(gbillock): Update when ownership chains go up through
diff --git a/chrome/browser/storage_monitor/image_capture_device_manager_unittest.mm b/chrome/browser/storage_monitor/image_capture_device_manager_unittest.mm
index 2b3a16a..f55576f 100644
--- a/chrome/browser/storage_monitor/image_capture_device_manager_unittest.mm
+++ b/chrome/browser/storage_monitor/image_capture_device_manager_unittest.mm
@@ -45,7 +45,7 @@
 
 @interface MockICCameraDevice : ICCameraDevice {
  @private
-  scoped_nsobject<NSMutableArray> allMediaFiles_;
+  base::scoped_nsobject<NSMutableArray> allMediaFiles_;
 }
 
 - (void)addMediaFile:(ICCameraFile*)file;
@@ -129,7 +129,7 @@
 
 @interface MockICCameraFolder : ICCameraFolder {
  @private
-  scoped_nsobject<NSString> name_;
+  base::scoped_nsobject<NSString> name_;
 }
 
 - (id)initWithName:(NSString*)name;
@@ -157,9 +157,9 @@
 
 @interface MockICCameraFile : ICCameraFile {
  @private
-  scoped_nsobject<NSString> name_;
-  scoped_nsobject<NSDate> date_;
-  scoped_nsobject<MockICCameraFolder> parent_;
+  base::scoped_nsobject<NSString> name_;
+  base::scoped_nsobject<NSDate> date_;
+  base::scoped_nsobject<MockICCameraFolder> parent_;
 }
 
 - (id)init:(NSString*)name;
@@ -262,7 +262,7 @@
   MockICCameraDevice* AttachDevice(
       chrome::ImageCaptureDeviceManager* manager) {
     // Ownership will be passed to the device browser delegate.
-    scoped_nsobject<MockICCameraDevice> device(
+    base::scoped_nsobject<MockICCameraDevice> device(
         [[MockICCameraDevice alloc] init]);
     id<ICDeviceBrowserDelegate> delegate = manager->device_browser();
     [delegate deviceBrowser:nil didAddDevice:device moreComing:NO];
@@ -305,17 +305,16 @@
   EXPECT_FALSE(chrome::ImageCaptureDeviceManager::deviceForUUID(
       "nonexistent"));
 
-  scoped_nsobject<ImageCaptureDevice> camera(
-      [chrome::ImageCaptureDeviceManager::deviceForUUID(kDeviceId)
-          retain]);
+  base::scoped_nsobject<ImageCaptureDevice> camera(
+      [chrome::ImageCaptureDeviceManager::deviceForUUID(kDeviceId) retain]);
 
   [camera setListener:listener_.AsWeakPtr()];
   [camera open];
 
-  scoped_nsobject<MockICCameraFile> picture1(
+  base::scoped_nsobject<MockICCameraFile> picture1(
       [[MockICCameraFile alloc] init:@"pic1"]);
   [camera cameraDevice:nil didAddItem:picture1];
-  scoped_nsobject<MockICCameraFile> picture2(
+  base::scoped_nsobject<MockICCameraFile> picture2(
       [[MockICCameraFile alloc] init:@"pic2"]);
   [camera cameraDevice:nil didAddItem:picture2];
   ASSERT_EQ(2U, listener_.items().size());
@@ -339,9 +338,8 @@
   manager.SetNotifications(monitor_.receiver());
   ICCameraDevice* device = AttachDevice(&manager);
 
-  scoped_nsobject<ImageCaptureDevice> camera(
-      [chrome::ImageCaptureDeviceManager::deviceForUUID(kDeviceId)
-          retain]);
+  base::scoped_nsobject<ImageCaptureDevice> camera(
+      [chrome::ImageCaptureDeviceManager::deviceForUUID(kDeviceId) retain]);
 
   [camera setListener:listener_.AsWeakPtr()];
   [camera open];
@@ -359,18 +357,16 @@
   manager.SetNotifications(monitor_.receiver());
   MockICCameraDevice* device = AttachDevice(&manager);
 
-  scoped_nsobject<ImageCaptureDevice> camera(
-      [chrome::ImageCaptureDeviceManager::deviceForUUID(kDeviceId)
-          retain]);
+  base::scoped_nsobject<ImageCaptureDevice> camera(
+      [chrome::ImageCaptureDeviceManager::deviceForUUID(kDeviceId) retain]);
 
   [camera setListener:listener_.AsWeakPtr()];
   [camera open];
 
   std::string kTestFileName("pic1");
 
-  scoped_nsobject<MockICCameraFile> picture1(
-      [[MockICCameraFile alloc]
-          init:base::SysUTF8ToNSString(kTestFileName)]);
+  base::scoped_nsobject<MockICCameraFile> picture1(
+      [[MockICCameraFile alloc] init:base::SysUTF8ToNSString(kTestFileName)]);
   [device addMediaFile:picture1];
   [camera cameraDevice:nil didAddItem:picture1];
 
@@ -417,17 +413,15 @@
   manager.SetNotifications(monitor_.receiver());
   MockICCameraDevice* device = AttachDevice(&manager);
 
-  scoped_nsobject<ImageCaptureDevice> camera(
-      [chrome::ImageCaptureDeviceManager::deviceForUUID(kDeviceId)
-          retain]);
+  base::scoped_nsobject<ImageCaptureDevice> camera(
+      [chrome::ImageCaptureDeviceManager::deviceForUUID(kDeviceId) retain]);
 
   [camera setListener:listener_.AsWeakPtr()];
   [camera open];
 
   std::string kTestFileName("pic1");
-  scoped_nsobject<MockICCameraFile> picture1(
-      [[MockICCameraFile alloc]
-          init:base::SysUTF8ToNSString(kTestFileName)]);
+  base::scoped_nsobject<MockICCameraFile> picture1(
+      [[MockICCameraFile alloc] init:base::SysUTF8ToNSString(kTestFileName)]);
   [picture1 setParent:base::SysUTF8ToNSString("dir")];
   [device addMediaFile:picture1];
   [camera cameraDevice:nil didAddItem:picture1];
diff --git a/chrome/browser/storage_monitor/media_storage_util.cc b/chrome/browser/storage_monitor/media_storage_util.cc
index 9b1e812..785440c 100644
--- a/chrome/browser/storage_monitor/media_storage_util.cc
+++ b/chrome/browser/storage_monitor/media_storage_util.cc
@@ -49,17 +49,6 @@
 
 typedef std::vector<StorageInfo> StorageInfoList;
 
-bool IsRemovableStorageAttached(const std::string& id) {
-  StorageInfoList devices =
-      StorageMonitor::GetInstance()->GetAllAvailableStorages();
-  for (StorageInfoList::const_iterator it = devices.begin();
-       it != devices.end(); ++it) {
-    if (StorageInfo::IsRemovableDevice(id) && it->device_id() == id)
-      return true;
-  }
-  return false;
-}
-
 base::FilePath::StringType FindRemovableStorageLocationById(
     const std::string& device_id) {
   StorageInfoList devices =
@@ -95,7 +84,7 @@
       continue;
     }
 
-    if (!IsRemovableStorageAttached(*it))
+    if (!MediaStorageUtil::IsRemovableStorageAttached(*it))
       missing_devices.insert(*it);
   }
 
@@ -252,4 +241,15 @@
                             DEVICE_INFO_BUCKET_BOUNDARY);
 }
 
+bool MediaStorageUtil::IsRemovableStorageAttached(const std::string& id) {
+  StorageInfoList devices =
+      StorageMonitor::GetInstance()->GetAllAvailableStorages();
+  for (StorageInfoList::const_iterator it = devices.begin();
+       it != devices.end(); ++it) {
+    if (StorageInfo::IsRemovableDevice(id) && it->device_id() == id)
+      return true;
+  }
+  return false;
+}
+
 }  // namespace chrome
diff --git a/chrome/browser/storage_monitor/media_storage_util.h b/chrome/browser/storage_monitor/media_storage_util.h
index d1f7d7d..c627403 100644
--- a/chrome/browser/storage_monitor/media_storage_util.h
+++ b/chrome/browser/storage_monitor/media_storage_util.h
@@ -57,6 +57,10 @@
                                         const std::string& device_uuid,
                                         const string16& device_label);
 
+  // Returns true if the |id| is both a removable device and also
+  // currently attached.
+  static bool IsRemovableStorageAttached(const std::string& id);
+
  private:
   DISALLOW_IMPLICIT_CONSTRUCTORS(MediaStorageUtil);
 };
diff --git a/chrome/browser/storage_monitor/storage_monitor.cc b/chrome/browser/storage_monitor/storage_monitor.cc
index 0513739..6d27d3b 100644
--- a/chrome/browser/storage_monitor/storage_monitor.cc
+++ b/chrome/browser/storage_monitor/storage_monitor.cc
@@ -61,7 +61,7 @@
   return results;
 }
 
-void StorageMonitor::Initialize(base::Closure callback) {
+void StorageMonitor::EnsureInitialized(base::Closure callback) {
   DCHECK(thread_checker_.CalledOnValidThread());
   if (initialized_) {
     if (!callback.is_null())
diff --git a/chrome/browser/storage_monitor/storage_monitor.h b/chrome/browser/storage_monitor/storage_monitor.h
index dfed9e8..5661c80 100644
--- a/chrome/browser/storage_monitor/storage_monitor.h
+++ b/chrome/browser/storage_monitor/storage_monitor.h
@@ -72,14 +72,14 @@
   // somewhat shorter than a process Singleton.
   static StorageMonitor* GetInstance();
 
-  // Initialize the storage monitor. The provided callback, if non-null,
-  // will be called when initialization is complete. If initialization has
-  // already completed, this callback will be invoked within the calling stack.
-  // Before the callback is run, calls to |GetAllAvailableStorages| and
+  // Ensures that the storage monitor is initialized. The provided callback, If
+  // non-null, will be called when initialization is complete. If initialization
+  // has already completed, this callback will be invoked within the calling
+  // stack. Before the callback is run, calls to |GetAllAvailableStorages| and
   // |GetStorageInfoForPath| may not return the correct results. In addition,
   // registered observers will not be notified on device attachment/detachment.
   // Should be invoked on the UI thread; callbacks will be run on the UI thread.
-  void Initialize(base::Closure callback);
+  void EnsureInitialized(base::Closure callback);
 
   // Return true if the storage monitor has already been initialized.
   bool IsInitialized();
diff --git a/chrome/browser/storage_monitor/storage_monitor_linux_unittest.cc b/chrome/browser/storage_monitor/storage_monitor_linux_unittest.cc
index 55fc877..a8c82a5 100644
--- a/chrome/browser/storage_monitor/storage_monitor_linux_unittest.cc
+++ b/chrome/browser/storage_monitor/storage_monitor_linux_unittest.cc
@@ -235,7 +235,7 @@
   void RemoveDCIMDirFromMountPoint(const std::string& dir) {
     base::FilePath dcim =
         scoped_temp_dir_.path().AppendASCII(dir).Append(kDCIMDirectoryName);
-    file_util::Delete(dcim, false);
+    base::Delete(dcim, false);
   }
 
   MockRemovableStorageObserver& observer() {
@@ -558,7 +558,7 @@
   MtabTestData test_data5[] = {
     MtabTestData(kDeviceNoDCIM, test_path_b.value(), kValidFS),
   };
-  file_util::Delete(test_path_b.Append(kDCIMDirectoryName), false);
+  base::Delete(test_path_b.Append(kDCIMDirectoryName), false);
   AppendToMtabAndRunLoop(test_data5, arraysize(test_data5));
   EXPECT_EQ(4, observer().attach_calls());
   EXPECT_EQ(2, observer().detach_calls());
diff --git a/chrome/browser/storage_monitor/storage_monitor_mac.h b/chrome/browser/storage_monitor/storage_monitor_mac.h
index 383f089..e313119 100644
--- a/chrome/browser/storage_monitor/storage_monitor_mac.h
+++ b/chrome/browser/storage_monitor/storage_monitor_mac.h
@@ -58,7 +58,7 @@
   bool FindDiskWithMountPoint(const base::FilePath& mount_point,
                               StorageInfo* info) const;
 
-  base::mac::ScopedCFTypeRef<DASessionRef> session_;
+  base::ScopedCFTypeRef<DASessionRef> session_;
   // Maps disk bsd names to disk info objects. This map tracks all mountable
   // devices on the system, though only notifications for removable devices are
   // posted.
diff --git a/chrome/browser/storage_monitor/storage_monitor_mac.mm b/chrome/browser/storage_monitor/storage_monitor_mac.mm
index 9c5ca63..346f958 100644
--- a/chrome/browser/storage_monitor/storage_monitor_mac.mm
+++ b/chrome/browser/storage_monitor/storage_monitor_mac.mm
@@ -74,7 +74,7 @@
       dict, kDADiskDescriptionVolumeUUIDKey);
   std::string unique_id;
   if (uuid) {
-    base::mac::ScopedCFTypeRef<CFStringRef> uuid_string(
+    base::ScopedCFTypeRef<CFStringRef> uuid_string(
         CFUUIDCreateString(NULL, uuid));
     if (uuid_string.get())
       unique_id = base::SysCFStringRefToUTF8(uuid_string);
@@ -105,7 +105,7 @@
 
 void GetDiskInfoAndUpdateOnFileThread(
     const base::WeakPtr<StorageMonitorMac>& monitor,
-    base::mac::ScopedCFTypeRef<CFDictionaryRef> dict,
+    base::ScopedCFTypeRef<CFDictionaryRef> dict,
     StorageMonitorMac::UpdateType update_type) {
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
 
@@ -125,7 +125,7 @@
 struct EjectDiskOptions {
   std::string bsd_name;
   base::Callback<void(StorageMonitor::EjectStatus)> callback;
-  base::mac::ScopedCFTypeRef<DADiskRef> disk;
+  base::ScopedCFTypeRef<DADiskRef> disk;
 };
 
 void PostEjectCallback(DADiskRef disk,
@@ -289,7 +289,7 @@
 
   receiver()->ProcessDetach(device_id);
 
-  base::mac::ScopedCFTypeRef<DADiskRef> disk(
+  base::ScopedCFTypeRef<DADiskRef> disk(
       DADiskCreateFromBSDName(NULL, session_, bsd_name.c_str()));
   if (!disk.get()) {
     callback.Run(StorageMonitor::EJECT_FAILURE);
@@ -337,7 +337,7 @@
 
   pending_disk_updates_++;
 
-  base::mac::ScopedCFTypeRef<CFDictionaryRef> dict(DADiskCopyDescription(disk));
+  base::ScopedCFTypeRef<CFDictionaryRef> dict(DADiskCopyDescription(disk));
   content::BrowserThread::PostTask(
       content::BrowserThread::FILE,
       FROM_HERE,
diff --git a/chrome/browser/storage_monitor/storage_monitor_unittest.cc b/chrome/browser/storage_monitor/storage_monitor_unittest.cc
index 8acce30..9be3a50 100644
--- a/chrome/browser/storage_monitor/storage_monitor_unittest.cc
+++ b/chrome/browser/storage_monitor/storage_monitor_unittest.cc
@@ -17,8 +17,8 @@
   EXPECT_FALSE(monitor.init_called_);
 
   base::WaitableEvent event(false, false);
-  monitor.Initialize(base::Bind(&base::WaitableEvent::Signal,
-                                base::Unretained(&event)));
+  monitor.EnsureInitialized(base::Bind(&base::WaitableEvent::Signal,
+                                       base::Unretained(&event)));
   EXPECT_TRUE(monitor.init_called_);
   EXPECT_FALSE(event.IsSignaled());
   monitor.MarkInitialized();
diff --git a/chrome/browser/storage_monitor/test_storage_monitor_win.cc b/chrome/browser/storage_monitor/test_storage_monitor_win.cc
index dafb597..e78b5e6 100644
--- a/chrome/browser/storage_monitor/test_storage_monitor_win.cc
+++ b/chrome/browser/storage_monitor/test_storage_monitor_win.cc
@@ -32,5 +32,9 @@
   return volume_mount_watcher_.get();
 }
 
+StorageMonitor::Receiver* TestStorageMonitorWin::receiver() const {
+  return StorageMonitor::receiver();
+}
+
 }  // namespace test
 }  // namespace chrome
diff --git a/chrome/browser/storage_monitor/test_storage_monitor_win.h b/chrome/browser/storage_monitor/test_storage_monitor_win.h
index bb29d9f..f7608eb 100644
--- a/chrome/browser/storage_monitor/test_storage_monitor_win.h
+++ b/chrome/browser/storage_monitor/test_storage_monitor_win.h
@@ -31,6 +31,8 @@
 
   VolumeMountWatcherWin* volume_mount_watcher();
 
+  virtual Receiver* receiver() const OVERRIDE;
+
  private:
   DISALLOW_COPY_AND_ASSIGN(TestStorageMonitorWin);
 };
diff --git a/chrome/browser/storage_monitor/volume_mount_watcher_win.cc b/chrome/browser/storage_monitor/volume_mount_watcher_win.cc
index 121c3ce..a4e19f2 100644
--- a/chrome/browser/storage_monitor/volume_mount_watcher_win.cc
+++ b/chrome/browser/storage_monitor/volume_mount_watcher_win.cc
@@ -18,7 +18,7 @@
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/task_runner_util.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "base/win/scoped_handle.h"
 #include "chrome/browser/storage_monitor/media_storage_util.h"
 #include "chrome/browser/storage_monitor/storage_info.h"
diff --git a/chrome/browser/sync/glue/android_invalidator_bridge.cc b/chrome/browser/sync/glue/android_invalidator_bridge.cc
deleted file mode 100644
index 31cd87e..0000000
--- a/chrome/browser/sync/glue/android_invalidator_bridge.cc
+++ /dev/null
@@ -1,219 +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/sync/glue/android_invalidator_bridge.h"
-
-#include "base/bind.h"
-#include "base/location.h"
-#include "base/logging.h"
-#include "base/memory/scoped_ptr.h"
-#include "chrome/common/chrome_notification_types.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/notification_service.h"
-#include "sync/internal_api/public/base/model_type.h"
-#include "sync/notifier/invalidation_handler.h"
-#include "sync/notifier/invalidator_registrar.h"
-
-using content::BrowserThread;
-
-namespace browser_sync {
-
-class AndroidInvalidatorBridge::Core
-    : public base::RefCountedThreadSafe<Core> {
- public:
-  // Created on UI thread.
-  explicit Core(
-      const scoped_refptr<base::SequencedTaskRunner>& sync_task_runner);
-
-  // All member functions below must be called on the sync task runner.
-
-  void InitializeOnSyncThread();
-  void CleanupOnSyncThread();
-
-  void RegisterHandler(syncer::InvalidationHandler* handler);
-  void UpdateRegisteredIds(syncer::InvalidationHandler* handler,
-                           const syncer::ObjectIdSet& ids);
-  void UnregisterHandler(syncer::InvalidationHandler* handler);
-
-  void EmitInvalidation(
-      const syncer::ObjectIdInvalidationMap& invalidation_map);
-
-  bool IsHandlerRegisteredForTest(syncer::InvalidationHandler* handler) const;
-  syncer::ObjectIdSet GetRegisteredIdsForTest(
-      syncer::InvalidationHandler* handler) const;
-
- private:
-  friend class base::RefCountedThreadSafe<Core>;
-
-  // Destroyed on the UI thread or on |sync_task_runner_|.
-  ~Core();
-
-  const scoped_refptr<base::SequencedTaskRunner> sync_task_runner_;
-
-  // Used only on |sync_task_runner_|.
-  scoped_ptr<syncer::InvalidatorRegistrar> invalidator_registrar_;
-};
-
-AndroidInvalidatorBridge::Core::Core(
-    const scoped_refptr<base::SequencedTaskRunner>& sync_task_runner)
-    : sync_task_runner_(sync_task_runner) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  DCHECK(sync_task_runner_.get());
-}
-
-AndroidInvalidatorBridge::Core::~Core() {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) ||
-         sync_task_runner_->RunsTasksOnCurrentThread());
-  DCHECK(!invalidator_registrar_.get());
-}
-
-void AndroidInvalidatorBridge::Core::InitializeOnSyncThread() {
-  invalidator_registrar_.reset(new syncer::InvalidatorRegistrar());
-}
-
-void AndroidInvalidatorBridge::Core::CleanupOnSyncThread() {
-  invalidator_registrar_.reset();
-}
-
-void AndroidInvalidatorBridge::Core::RegisterHandler(
-    syncer::InvalidationHandler* handler) {
-  DCHECK(sync_task_runner_->RunsTasksOnCurrentThread());
-  invalidator_registrar_->RegisterHandler(handler);
-}
-
-void AndroidInvalidatorBridge::Core::UpdateRegisteredIds(
-    syncer::InvalidationHandler* handler,
-    const syncer::ObjectIdSet& ids) {
-  DCHECK(sync_task_runner_->RunsTasksOnCurrentThread());
-  invalidator_registrar_->UpdateRegisteredIds(handler, ids);
-}
-
-void AndroidInvalidatorBridge::Core::UnregisterHandler(
-    syncer::InvalidationHandler* handler) {
-  DCHECK(sync_task_runner_->RunsTasksOnCurrentThread());
-  invalidator_registrar_->UnregisterHandler(handler);
-}
-
-void AndroidInvalidatorBridge::Core::EmitInvalidation(
-    const syncer::ObjectIdInvalidationMap& invalidation_map) {
-  DCHECK(sync_task_runner_->RunsTasksOnCurrentThread());
-  const syncer::ObjectIdInvalidationMap& effective_invalidation_map =
-      invalidation_map.empty() ?
-      ObjectIdSetToInvalidationMap(
-          invalidator_registrar_->GetAllRegisteredIds(), std::string()) :
-      invalidation_map;
-
-  invalidator_registrar_->DispatchInvalidationsToHandlers(
-      effective_invalidation_map);
-}
-
-bool AndroidInvalidatorBridge::Core::IsHandlerRegisteredForTest(
-    syncer::InvalidationHandler* handler) const {
-  DCHECK(sync_task_runner_->RunsTasksOnCurrentThread());
-  return invalidator_registrar_->IsHandlerRegisteredForTest(handler);
-}
-
-syncer::ObjectIdSet
-AndroidInvalidatorBridge::Core::GetRegisteredIdsForTest(
-    syncer::InvalidationHandler* handler) const {
-  DCHECK(sync_task_runner_->RunsTasksOnCurrentThread());
-  return invalidator_registrar_->GetRegisteredIds(handler);
-}
-
-AndroidInvalidatorBridge::AndroidInvalidatorBridge(
-    const Profile* profile,
-    const scoped_refptr<base::SequencedTaskRunner>& sync_task_runner)
-    : sync_task_runner_(sync_task_runner),
-      core_(new Core(sync_task_runner_)) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  DCHECK(profile);
-  registrar_.Add(this, chrome::NOTIFICATION_SYNC_REFRESH_REMOTE,
-                 content::Source<Profile>(profile));
-
-  if (!sync_task_runner_->PostTask(
-          FROM_HERE, base::Bind(&Core::InitializeOnSyncThread, core_))) {
-    NOTREACHED();
-  }
-}
-
-AndroidInvalidatorBridge::~AndroidInvalidatorBridge() {}
-
-void AndroidInvalidatorBridge::StopForShutdown() {
-  if (!sync_task_runner_->PostTask(
-          FROM_HERE, base::Bind(&Core::CleanupOnSyncThread, core_))) {
-    NOTREACHED();
-  }
-}
-
-void AndroidInvalidatorBridge::RegisterHandler(
-    syncer::InvalidationHandler* handler) {
-  DCHECK(sync_task_runner_->RunsTasksOnCurrentThread());
-  core_->RegisterHandler(handler);
-}
-
-void AndroidInvalidatorBridge::UpdateRegisteredIds(
-    syncer::InvalidationHandler* handler,
-    const syncer::ObjectIdSet& ids) {
-  DCHECK(sync_task_runner_->RunsTasksOnCurrentThread());
-  core_->UpdateRegisteredIds(handler, ids);
-}
-
-void AndroidInvalidatorBridge::UnregisterHandler(
-    syncer::InvalidationHandler* handler) {
-  DCHECK(sync_task_runner_->RunsTasksOnCurrentThread());
-  core_->UnregisterHandler(handler);
-}
-
-void AndroidInvalidatorBridge::Acknowledge(
-    const invalidation::ObjectId& id, const syncer::AckHandle& ack_handle) {
-  // Do nothing.
-}
-
-syncer::InvalidatorState AndroidInvalidatorBridge::GetInvalidatorState() const {
-  return syncer::INVALIDATIONS_ENABLED;
-}
-
-void AndroidInvalidatorBridge::UpdateCredentials(
-    const std::string& email, const std::string& token) { }
-
-void AndroidInvalidatorBridge::SendInvalidation(
-    const syncer::ObjectIdInvalidationMap& invalidation_map) { }
-
-bool AndroidInvalidatorBridge::IsHandlerRegisteredForTest(
-    syncer::InvalidationHandler* handler) const {
-  DCHECK(sync_task_runner_->RunsTasksOnCurrentThread());
-  return core_->IsHandlerRegisteredForTest(handler);
-}
-
-syncer::ObjectIdSet AndroidInvalidatorBridge::GetRegisteredIdsForTest(
-    syncer::InvalidationHandler* handler) const {
-  DCHECK(sync_task_runner_->RunsTasksOnCurrentThread());
-  return core_->GetRegisteredIdsForTest(handler);
-}
-
-void AndroidInvalidatorBridge::Observe(
-    int type,
-    const content::NotificationSource& source,
-    const content::NotificationDetails& details) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  DCHECK_EQ(type, chrome::NOTIFICATION_SYNC_REFRESH_REMOTE);
-
-  // TODO(akalin): Use ObjectIdInvalidationMap here instead.  We'll have to
-  // make sure all emitters of the relevant notifications also use
-  // ObjectIdInvalidationMap.
-  content::Details<const syncer::ModelTypeInvalidationMap>
-      state_details(details);
-  const syncer::ModelTypeInvalidationMap& invalidation_map =
-      *(state_details.ptr());
-  if (!sync_task_runner_->PostTask(
-          FROM_HERE,
-          base::Bind(&Core::EmitInvalidation,
-                     core_,
-                     ModelTypeInvalidationMapToObjectIdInvalidationMap(
-                         invalidation_map)))) {
-    NOTREACHED();
-  }
-}
-
-}  // namespace browser_sync
diff --git a/chrome/browser/sync/glue/android_invalidator_bridge.h b/chrome/browser/sync/glue/android_invalidator_bridge.h
deleted file mode 100644
index ec1baae..0000000
--- a/chrome/browser/sync/glue/android_invalidator_bridge.h
+++ /dev/null
@@ -1,85 +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_SYNC_GLUE_ANDROID_INVALIDATOR_BRIDGE_H_
-#define CHROME_BROWSER_SYNC_GLUE_ANDROID_INVALIDATOR_BRIDGE_H_
-
-#include "base/compiler_specific.h"
-#include "base/memory/ref_counted.h"
-#include "base/sequenced_task_runner.h"
-#include "content/public/browser/notification_observer.h"
-#include "content/public/browser/notification_registrar.h"
-#include "sync/notifier/invalidator.h"
-
-class Profile;
-
-namespace syncer {
-class InvalidationHandler;
-}  // namespace
-
-namespace browser_sync {
-
-// A bridge that converts Chrome events on the UI thread to sync
-// notifications on the sync task runner.
-//
-// Listens to NOTIFICATION_SYNC_REFRESH_REMOTE (on the UI thread) and triggers
-// each observer's OnIncomingNotification method on these notifications (on the
-// sync task runner).  Android clients receive invalidations through this
-// mechanism exclusively, hence the name.
-class AndroidInvalidatorBridge
-    : public content::NotificationObserver, syncer::Invalidator {
- public:
-  // Must be created and destroyed on the UI thread.
-  AndroidInvalidatorBridge(
-      const Profile* profile,
-      const scoped_refptr<base::SequencedTaskRunner>& sync_task_runner);
-  virtual ~AndroidInvalidatorBridge();
-
-  // Must be called on the UI thread while the sync task runner is still
-  // around.  No other member functions on the sync thread may be called after
-  // this is called.
-  void StopForShutdown();
-
-  // Invalidator implementation.  Must be called on the sync task runner.
-  virtual void RegisterHandler(syncer::InvalidationHandler* handler) OVERRIDE;
-  virtual void UpdateRegisteredIds(syncer::InvalidationHandler* handler,
-                                   const syncer::ObjectIdSet& ids) OVERRIDE;
-  virtual void UnregisterHandler(syncer::InvalidationHandler* handler) OVERRIDE;
-  virtual void Acknowledge(const invalidation::ObjectId& id,
-                           const syncer::AckHandle& ack_handle) OVERRIDE;
-  virtual syncer::InvalidatorState GetInvalidatorState() const OVERRIDE;
-
-  // The following members of the Invalidator interface are not applicable to
-  // this invalidator and are implemented as no-ops.
-  virtual void UpdateCredentials(
-      const std::string& email, const std::string& token) OVERRIDE;
-  virtual void SendInvalidation(
-      const syncer::ObjectIdInvalidationMap& invalidation_map) OVERRIDE;
-
-  bool IsHandlerRegisteredForTest(
-      syncer::InvalidationHandler* handler) const;
-  syncer::ObjectIdSet GetRegisteredIdsForTest(
-      syncer::InvalidationHandler* handler) const;
-
-  // NotificationObserver implementation. Called on UI thread.
-  virtual void Observe(int type,
-                       const content::NotificationSource& source,
-                       const content::NotificationDetails& details) OVERRIDE;
-
- private:
-  // Inner class to hold all the bits used on |sync_task_runner_|.
-  class Core;
-
-  const scoped_refptr<base::SequencedTaskRunner> sync_task_runner_;
-
-  // Created on the UI thread, used only on |sync_task_runner_|.
-  const scoped_refptr<Core> core_;
-
-  // Used only on the UI thread.
-  content::NotificationRegistrar registrar_;
-};
-
-}  // namespace browser_sync
-
-#endif  // CHROME_BROWSER_SYNC_GLUE_ANDROID_INVALIDATOR_BRIDGE_H_
diff --git a/chrome/browser/sync/glue/android_invalidator_bridge_proxy.cc b/chrome/browser/sync/glue/android_invalidator_bridge_proxy.cc
deleted file mode 100644
index 8ed4053..0000000
--- a/chrome/browser/sync/glue/android_invalidator_bridge_proxy.cc
+++ /dev/null
@@ -1,59 +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/sync/glue/android_invalidator_bridge_proxy.h"
-
-#include "chrome/browser/sync/glue/android_invalidator_bridge.h"
-
-using std::string;
-using syncer::InvalidatorState;
-
-namespace browser_sync {
-
-AndroidInvalidatorBridgeProxy::AndroidInvalidatorBridgeProxy(
-    AndroidInvalidatorBridge* bridge)
-    : bridge_(bridge) {
-  DCHECK(bridge_);
-}
-
-AndroidInvalidatorBridgeProxy::~AndroidInvalidatorBridgeProxy() {
-}
-
-void AndroidInvalidatorBridgeProxy::RegisterHandler(
-    syncer::InvalidationHandler* handler) {
-  bridge_->RegisterHandler(handler);
-}
-
-void AndroidInvalidatorBridgeProxy::UpdateRegisteredIds(
-    syncer::InvalidationHandler* handler,
-    const syncer::ObjectIdSet& ids) {
-  bridge_->UpdateRegisteredIds(handler, ids);
-}
-
-InvalidatorState AndroidInvalidatorBridgeProxy::GetInvalidatorState() const {
-  return bridge_->GetInvalidatorState();
-}
-
-void AndroidInvalidatorBridgeProxy::UnregisterHandler(
-    syncer::InvalidationHandler* handler) {
-  bridge_->UnregisterHandler(handler);
-}
-
-void AndroidInvalidatorBridgeProxy::Acknowledge(
-    const invalidation::ObjectId& id,
-    const syncer::AckHandle& ack_handle) {
-  bridge_->Acknowledge(id, ack_handle);
-}
-
-void AndroidInvalidatorBridgeProxy::UpdateCredentials(
-    const string& email, const string& token) {
-  bridge_->UpdateCredentials(email, token);
-}
-
-void AndroidInvalidatorBridgeProxy::SendInvalidation(
-    const syncer::ObjectIdInvalidationMap& invalidation_map) {
-  bridge_->SendInvalidation(invalidation_map);
-}
-
-}  // namespace browser_sync
diff --git a/chrome/browser/sync/glue/android_invalidator_bridge_proxy.h b/chrome/browser/sync/glue/android_invalidator_bridge_proxy.h
deleted file mode 100644
index 98c623e..0000000
--- a/chrome/browser/sync/glue/android_invalidator_bridge_proxy.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 CHROME_BROWSER_SYNC_GLUE_ANDROID_INVALIDATOR_BRIDGE_PROXY_H_
-#define CHROME_BROWSER_SYNC_GLUE_ANDROID_INVALIDATOR_BRIDGE_PROXY_H_
-
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "sync/notifier/invalidator.h"
-
-namespace browser_sync {
-
-class AndroidInvalidatorBridge;
-
-// This class implements the Invalidator interface by wrapping (but not taking
-// ownership of) an AndroidInvalidatorBridge.  This is useful because the
-// SyncManager currently expects to take ownership of its invalidator, but it is
-// not prepared to take ownership of the UI-thread-owned
-// AndroidInvalidatorBridge.  So we use this class to wrap the
-// AndroidInvalidator and allow the SyncManager to own it instead.
-class AndroidInvalidatorBridgeProxy : public syncer::Invalidator {
- public:
-  // Does not take ownership of |bridge|.
-  explicit AndroidInvalidatorBridgeProxy(AndroidInvalidatorBridge* bridge);
-  virtual ~AndroidInvalidatorBridgeProxy();
-
-  // Invalidator implementation. Passes through all calls to the bridge.
-  virtual void RegisterHandler(syncer::InvalidationHandler* handler) OVERRIDE;
-  virtual void UpdateRegisteredIds(syncer::InvalidationHandler * handler,
-                                   const syncer::ObjectIdSet& ids) OVERRIDE;
-  virtual void UnregisterHandler(syncer::InvalidationHandler* handler) OVERRIDE;
-  virtual void Acknowledge(const invalidation::ObjectId& id,
-                           const syncer::AckHandle& ack_handle) OVERRIDE;
-  virtual syncer::InvalidatorState GetInvalidatorState() const OVERRIDE;
-  virtual void UpdateCredentials(
-      const std::string& email, const std::string& token) OVERRIDE;
-  virtual void SendInvalidation(
-      const syncer::ObjectIdInvalidationMap& invalidation_map) OVERRIDE;
-
- private:
-  // The notification bridge that we forward to but don't own.
-  AndroidInvalidatorBridge* const bridge_;
-
-  DISALLOW_COPY_AND_ASSIGN(AndroidInvalidatorBridgeProxy);
-};
-
-}  // namespace browser_sync
-
-#endif  // CHROME_BROWSER_SYNC_GLUE_ANDROID_INVALIDATOR_BRIDGE_PROXY_H_
diff --git a/chrome/browser/sync/glue/autofill_data_type_controller.cc b/chrome/browser/sync/glue/autofill_data_type_controller.cc
index 6703779..3c8f0cf 100644
--- a/chrome/browser/sync/glue/autofill_data_type_controller.cc
+++ b/chrome/browser/sync/glue/autofill_data_type_controller.cc
@@ -11,7 +11,7 @@
 #include "chrome/browser/sync/profile_sync_service.h"
 #include "chrome/browser/sync/profile_sync_service_factory.h"
 #include "chrome/browser/webdata/autocomplete_syncable_service.h"
-#include "components/autofill/browser/webdata/autofill_webdata_service.h"
+#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
 #include "content/public/browser/browser_thread.h"
 #include "sync/api/sync_error.h"
 #include "sync/internal_api/public/util/experiments.h"
diff --git a/chrome/browser/sync/glue/autofill_data_type_controller_unittest.cc b/chrome/browser/sync/glue/autofill_data_type_controller_unittest.cc
index ce020f9..a52c3a4 100644
--- a/chrome/browser/sync/glue/autofill_data_type_controller_unittest.cc
+++ b/chrome/browser/sync/glue/autofill_data_type_controller_unittest.cc
@@ -19,7 +19,7 @@
 #include "chrome/browser/webdata/web_data_service_factory.h"
 #include "chrome/common/chrome_notification_types.h"
 #include "chrome/test/base/profile_mock.h"
-#include "components/autofill/browser/webdata/autofill_webdata_service.h"
+#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
 #include "components/webdata/common/web_data_service_test_util.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/notification_source.h"
diff --git a/chrome/browser/sync/glue/autofill_profile_data_type_controller.cc b/chrome/browser/sync/glue/autofill_profile_data_type_controller.cc
index a508a84..e089532 100644
--- a/chrome/browser/sync/glue/autofill_profile_data_type_controller.cc
+++ b/chrome/browser/sync/glue/autofill_profile_data_type_controller.cc
@@ -10,8 +10,8 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/sync/profile_sync_components_factory.h"
 #include "chrome/browser/sync/profile_sync_service.h"
-#include "components/autofill/browser/personal_data_manager.h"
-#include "components/autofill/browser/webdata/autofill_webdata_service.h"
+#include "components/autofill/core/browser/personal_data_manager.h"
+#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
 #include "content/public/browser/browser_thread.h"
 #include "sync/api/sync_error.h"
 #include "sync/api/syncable_service.h"
diff --git a/chrome/browser/sync/glue/autofill_profile_data_type_controller.h b/chrome/browser/sync/glue/autofill_profile_data_type_controller.h
index 3e00748..b4a175e 100644
--- a/chrome/browser/sync/glue/autofill_profile_data_type_controller.h
+++ b/chrome/browser/sync/glue/autofill_profile_data_type_controller.h
@@ -9,7 +9,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/scoped_observer.h"
 #include "chrome/browser/sync/glue/non_ui_data_type_controller.h"
-#include "components/autofill/browser/personal_data_manager_observer.h"
+#include "components/autofill/core/browser/personal_data_manager_observer.h"
 
 namespace autofill {
 class PersonalDataManager;
diff --git a/chrome/browser/sync/glue/backend_data_type_configurer.h b/chrome/browser/sync/glue/backend_data_type_configurer.h
index 308dee6..eb4d93e 100644
--- a/chrome/browser/sync/glue/backend_data_type_configurer.h
+++ b/chrome/browser/sync/glue/backend_data_type_configurer.h
@@ -24,6 +24,8 @@
     CONFIGURE_INACTIVE,   // Already configured or to be configured in future.
                           // Data of such types is left as it is, no
                           // downloading or purging.
+    CONFIGURE_CLEAN,      // Actively being configured but requiring unapply
+                          // and GetUpdates first (e.g. for persistence errors).
     DISABLED,             // Not syncing. Disabled by user.
     FATAL,                // Not syncing due to unrecoverable error.
     CRYPTO,               // Not syncing due to a cryptographer error.
diff --git a/chrome/browser/sync/glue/bookmark_data_type_controller_unittest.cc b/chrome/browser/sync/glue/bookmark_data_type_controller_unittest.cc
index 2703dbc..e581409 100644
--- a/chrome/browser/sync/glue/bookmark_data_type_controller_unittest.cc
+++ b/chrome/browser/sync/glue/bookmark_data_type_controller_unittest.cc
@@ -259,8 +259,9 @@
       WillRepeatedly(DoAll(SetArgumentPointee<0>(true), Return(true)));
   EXPECT_CALL(*model_associator_, AssociateModels(_, _)).
       WillRepeatedly(Return(syncer::SyncError(FROM_HERE,
-                                     "error",
-                                     syncer::BOOKMARKS)));
+                                              syncer::SyncError::DATATYPE_ERROR,
+                                              "error",
+                                              syncer::BOOKMARKS)));
 
   EXPECT_CALL(start_callback_,
               Run(DataTypeController::ASSOCIATION_FAILED, _, _));
diff --git a/chrome/browser/sync/glue/bookmark_model_associator.cc b/chrome/browser/sync/glue/bookmark_model_associator.cc
index 846d3e2..c5b5434 100644
--- a/chrome/browser/sync/glue/bookmark_model_associator.cc
+++ b/chrome/browser/sync/glue/bookmark_model_associator.cc
@@ -9,9 +9,11 @@
 #include "base/bind.h"
 #include "base/command_line.h"
 #include "base/containers/hash_tables.h"
+#include "base/format_macros.h"
 #include "base/location.h"
 #include "base/message_loop.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/bookmarks/bookmark_model.h"
 #include "chrome/browser/profiles/profile.h"
@@ -364,7 +366,10 @@
 syncer::SyncError BookmarkModelAssociator::AssociateModels(
     syncer::SyncMergeResult* local_merge_result,
     syncer::SyncMergeResult* syncer_merge_result) {
-  CheckModelSyncState(local_merge_result, syncer_merge_result);
+  syncer::SyncError error = CheckModelSyncState(local_merge_result,
+                                                syncer_merge_result);
+  if (error.IsSet())
+    return error;
 
   scoped_ptr<ScopedAssociationUpdater> association_updater(
       new ScopedAssociationUpdater(bookmark_model_));
@@ -702,16 +707,16 @@
       trans.GetCryptographer()->is_ready();
 }
 
-void BookmarkModelAssociator::CheckModelSyncState(
+syncer::SyncError BookmarkModelAssociator::CheckModelSyncState(
     syncer::SyncMergeResult* local_merge_result,
     syncer::SyncMergeResult* syncer_merge_result) const {
   std::string version_str;
   if (bookmark_model_->root_node()->GetMetaInfo(kBookmarkTransactionVersionKey,
                                                 &version_str)) {
     syncer::ReadTransaction trans(FROM_HERE, user_share_);
-    int64 native_version;
+    int64 native_version = syncer::syncable::kInvalidTransactionVersion;
     if (!base::StringToInt64(version_str, &native_version))
-      return;
+      return syncer::SyncError();
     local_merge_result->set_pre_association_version(native_version);
 
     int64 sync_version = trans.GetModelVersion(syncer::BOOKMARKS);
@@ -721,11 +726,27 @@
       UMA_HISTOGRAM_ENUMERATION("Sync.LocalModelOutOfSync",
                                 ModelTypeToHistogramInt(syncer::BOOKMARKS),
                                 syncer::MODEL_TYPE_COUNT);
+
       // Clear version on bookmark model so that we only report error once.
       bookmark_model_->DeleteNodeMetaInfo(bookmark_model_->root_node(),
                                           kBookmarkTransactionVersionKey);
+
+      // If the native version is higher, there was a sync persistence failure,
+      // and we need to delay association until after a GetUpdates.
+      if (sync_version < native_version) {
+        std::string message = base::StringPrintf(
+            "Native version (%" PRId64 ") does not match sync version (%"
+                PRId64 ")",
+            native_version,
+            sync_version);
+        return syncer::SyncError(FROM_HERE,
+                                 syncer::SyncError::PERSISTENCE_ERROR,
+                                 message,
+                                 syncer::BOOKMARKS);
+      }
     }
   }
+  return syncer::SyncError();
 }
 
 }  // namespace browser_sync
diff --git a/chrome/browser/sync/glue/bookmark_model_associator.h b/chrome/browser/sync/glue/bookmark_model_associator.h
index 8a0ff5f..cf348b7 100644
--- a/chrome/browser/sync/glue/bookmark_model_associator.h
+++ b/chrome/browser/sync/glue/bookmark_model_associator.h
@@ -141,8 +141,11 @@
 
   // Check whether bookmark model and sync model are synced by comparing
   // their transaction versions.
-  void CheckModelSyncState(syncer::SyncMergeResult* local_merge_result,
-                           syncer::SyncMergeResult* syncer_merge_result) const;
+  // Returns a PERSISTENCE_ERROR if a transaction mismatch was detected where
+  // the native model has a newer transaction verison.
+  syncer::SyncError CheckModelSyncState(
+      syncer::SyncMergeResult* local_merge_result,
+      syncer::SyncMergeResult* syncer_merge_result) const;
 
   BookmarkModel* bookmark_model_;
   Profile* profile_;
diff --git a/chrome/browser/sync/glue/browser_thread_model_worker_unittest.cc b/chrome/browser/sync/glue/browser_thread_model_worker_unittest.cc
index aa6f4b7..031bcb1 100644
--- a/chrome/browser/sync/glue/browser_thread_model_worker_unittest.cc
+++ b/chrome/browser/sync/glue/browser_thread_model_worker_unittest.cc
@@ -9,7 +9,7 @@
 #include "base/message_loop.h"
 #include "base/test/test_timeouts.h"
 #include "base/threading/thread.h"
-#include "base/timer.h"
+#include "base/timer/timer.h"
 #include "chrome/browser/sync/glue/browser_thread_model_worker.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/chrome/browser/sync/glue/data_type_controller.cc b/chrome/browser/sync/glue/data_type_controller.cc
index 71095ab..cb56478 100644
--- a/chrome/browser/sync/glue/data_type_controller.cc
+++ b/chrome/browser/sync/glue/data_type_controller.cc
@@ -23,7 +23,10 @@
     const std::string& message,
     syncer::ModelType type) {
   ChromeReportUnrecoverableError();
-  return syncer::SyncError(location, message, type);
+  return syncer::SyncError(location,
+                           syncer::SyncError::DATATYPE_ERROR,
+                           message,
+                           type);
 }
 
 void DataTypeController::RecordUnrecoverableError(
diff --git a/chrome/browser/sync/glue/data_type_manager_impl.cc b/chrome/browser/sync/glue/data_type_manager_impl.cc
index 01f8fcb..87daedb 100644
--- a/chrome/browser/sync/glue/data_type_manager_impl.cc
+++ b/chrome/browser/sync/glue/data_type_manager_impl.cc
@@ -35,9 +35,11 @@
   FailedDataTypesHandler::TypeErrorMap crypto_errors;
   for (syncer::ModelTypeSet::Iterator iter = encrypted_types.First();
          iter.Good(); iter.Inc()) {
-    crypto_errors[iter.Get()] = syncer::SyncError(FROM_HERE,
-                                                  "Cryptographer not ready.",
-                                                  iter.Get());
+    crypto_errors[iter.Get()] = syncer::SyncError(
+        FROM_HERE,
+        syncer::SyncError::CRYPTO_ERROR,
+        "",
+        iter.Get());
   }
   return crypto_errors;
 }
@@ -139,13 +141,21 @@
   // 3. Flip |types_being_configured| to CONFIGURE_ACTIVE.
   // 4. Set non-enabled user types as DISABLED.
   // 5. Set the fatal and crypto types to their respective states.
-  syncer::ModelTypeSet fatal_types;
-  syncer::ModelTypeSet crypto_types;
-  fatal_types = failed_data_types_handler_->GetFatalErrorTypes();
-  crypto_types = failed_data_types_handler_->GetCryptoErrorTypes();
+  syncer::ModelTypeSet error_types =
+      failed_data_types_handler_->GetFailedTypes();
+  syncer::ModelTypeSet fatal_types =
+      failed_data_types_handler_->GetFatalErrorTypes();
+  syncer::ModelTypeSet crypto_types =
+      failed_data_types_handler_->GetCryptoErrorTypes();
+
+  // Types with persistence errors are only purged/resynced when they're
+  // actively being configured.
+  syncer::ModelTypeSet persistence_types =
+      failed_data_types_handler_->GetPersistenceErrorTypes();
+  persistence_types.RetainAll(types_being_configured);
+
   syncer::ModelTypeSet enabled_types = last_requested_types_;
-  enabled_types.RemoveAll(fatal_types);
-  enabled_types.RemoveAll(crypto_types);
+  enabled_types.RemoveAll(error_types);
   syncer::ModelTypeSet disabled_types =
       syncer::Difference(
           syncer::Union(syncer::UserTypes(), syncer::ControlTypes()),
@@ -164,6 +174,9 @@
       BackendDataTypeConfigurer::CONFIGURE_ACTIVE, to_configure,
       &config_state_map);
   BackendDataTypeConfigurer::SetDataTypesState(
+      BackendDataTypeConfigurer::CONFIGURE_CLEAN, persistence_types,
+        &config_state_map);
+  BackendDataTypeConfigurer::SetDataTypesState(
       BackendDataTypeConfigurer::DISABLED, disabled_types,
       &config_state_map);
   BackendDataTypeConfigurer::SetDataTypesState(
@@ -187,9 +200,7 @@
         failed_data_types_handler_->GetCryptoErrorTypes());
     FailedDataTypesHandler::TypeErrorMap crypto_errors =
         GenerateCryptoErrorsForTypes(encrypted_types);
-    failed_data_types_handler_->UpdateFailedDataTypes(
-        crypto_errors,
-        FailedDataTypesHandler::CRYPTO);
+    failed_data_types_handler_->UpdateFailedDataTypes(crypto_errors);
   } else {
     failed_data_types_handler_->ResetCryptoErrors();
   }
@@ -222,16 +233,23 @@
       BuildDataTypeConfigStateMap(download_types_queue_.front()),
       base::Bind(&DataTypeManagerImpl::DownloadReady,
                  weak_ptr_factory_.GetWeakPtr(),
-                 base::Time::Now(), syncer::ModelTypeSet()),
+                 base::Time::Now(),
+                 download_types_queue_.front(),
+                 syncer::ModelTypeSet()),
       base::Bind(&DataTypeManagerImpl::OnDownloadRetry,
                  weak_ptr_factory_.GetWeakPtr()));
 }
 
-TypeSetPriorityList DataTypeManagerImpl::PrioritizeTypes(
-    const syncer::ModelTypeSet& types) {
+syncer::ModelTypeSet DataTypeManagerImpl::GetPriorityTypes() const {
   syncer::ModelTypeSet high_priority_types;
   high_priority_types.PutAll(syncer::ControlTypes());
   high_priority_types.PutAll(syncer::PriorityUserTypes());
+  return high_priority_types;
+}
+
+TypeSetPriorityList DataTypeManagerImpl::PrioritizeTypes(
+    const syncer::ModelTypeSet& types) {
+  syncer::ModelTypeSet high_priority_types = GetPriorityTypes();
   high_priority_types.RetainAll(types);
 
   syncer::ModelTypeSet low_priority_types =
@@ -280,11 +298,16 @@
 
 void DataTypeManagerImpl::DownloadReady(
     base::Time download_start_time,
+    syncer::ModelTypeSet types_to_download,
     syncer::ModelTypeSet high_priority_types_before,
     syncer::ModelTypeSet first_sync_types,
     syncer::ModelTypeSet failed_configuration_types) {
   DCHECK(state_ == DOWNLOAD_PENDING || state_ == CONFIGURING);
 
+  // Persistence errors are reset after each backend configuration attempt
+  // during which they would have been purged.
+  failed_data_types_handler_->ResetPersistenceErrorsFrom(types_to_download);
+
   // Ignore |failed_configuration_types| if we need to reconfigure
   // anyway.
   if (needs_reconfigure_) {
@@ -298,7 +321,9 @@
     std::string error_msg =
         "Configuration failed for types " +
         syncer::ModelTypeSetToString(failed_configuration_types);
-    syncer::SyncError error(FROM_HERE, error_msg,
+    syncer::SyncError error(FROM_HERE,
+                            syncer::SyncError::UNRECOVERABLE_ERROR,
+                            error_msg,
                             failed_configuration_types.First().Get());
     Abort(UNRECOVERABLE_ERROR, error);
     return;
@@ -307,8 +332,11 @@
   state_ = CONFIGURING;
 
   // Pop and associate download-ready types.
-  syncer::ModelTypeSet ready_types = download_types_queue_.front();
+  syncer::ModelTypeSet ready_types = types_to_download;
   download_types_queue_.pop();
+  syncer::ModelTypeSet new_types_to_download;
+  if (!download_types_queue_.empty())
+    new_types_to_download = download_types_queue_.front();
 
   AssociationTypesInfo association_info;
   association_info.types = ready_types;
@@ -321,13 +349,14 @@
     StartNextAssociation();
 
   // Download types of low priority while configuring types of high priority.
-  if (!download_types_queue_.empty()) {
+  if (!new_types_to_download.Empty()) {
     configurer_->ConfigureDataTypes(
         last_configure_reason_,
-        BuildDataTypeConfigStateMap(download_types_queue_.front()),
+        BuildDataTypeConfigStateMap(new_types_to_download),
         base::Bind(&DataTypeManagerImpl::DownloadReady,
                    weak_ptr_factory_.GetWeakPtr(),
                    base::Time::Now(),
+                   new_types_to_download,
                    syncer::Union(ready_types, high_priority_types_before)),
         base::Bind(&DataTypeManagerImpl::OnDownloadRetry,
                    weak_ptr_factory_.GetWeakPtr()));
@@ -394,15 +423,12 @@
           failed_data_types_handler_->GetCryptoErrorTypes());
       FailedDataTypesHandler::TypeErrorMap crypto_errors =
           GenerateCryptoErrorsForTypes(encrypted_types);
-      failed_data_types_handler_->UpdateFailedDataTypes(
-          crypto_errors,
-          FailedDataTypesHandler::CRYPTO);
+      failed_data_types_handler_->UpdateFailedDataTypes(crypto_errors);
     }
     if (!result.failed_data_types.empty()) {
       needs_reconfigure_ = true;
       failed_data_types_handler_->UpdateFailedDataTypes(
-          result.failed_data_types,
-          FailedDataTypesHandler::STARTUP);
+          result.failed_data_types);
     }
   }
 
@@ -489,7 +515,7 @@
   DCHECK_NE(OK, status);
   std::map<syncer::ModelType, syncer::SyncError> errors;
   if (error.IsSet())
-    errors[error.type()] = error;
+    errors[error.model_type()] = error;
   ConfigureResult result(status,
                          last_requested_types_,
                          errors,
diff --git a/chrome/browser/sync/glue/data_type_manager_impl.h b/chrome/browser/sync/glue/data_type_manager_impl.h
index c2fb91b..762e34e 100644
--- a/chrome/browser/sync/glue/data_type_manager_impl.h
+++ b/chrome/browser/sync/glue/data_type_manager_impl.h
@@ -14,7 +14,7 @@
 #include "base/basictypes.h"
 #include "base/compiler_specific.h"
 #include "base/memory/weak_ptr.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/sync/glue/backend_data_type_configurer.h"
 #include "chrome/browser/sync/glue/model_association_manager.h"
 
@@ -73,22 +73,27 @@
     return &model_association_manager_;
   }
 
- protected:
-  // Divide |types| into sets by their priorities and return the sets from
-  // high priority to low priority.
-  virtual TypeSetPriorityList PrioritizeTypes(
-      const syncer::ModelTypeSet& types);
-
  private:
+  friend class TestDataTypeManager;
+
   // Abort configuration and stop all data types due to configuration errors.
   void Abort(ConfigureStatus status,
              const syncer::SyncError& error);
 
+  // Returns the priority types (control + priority user types).
+  // Virtual for overriding during tests.
+  virtual syncer::ModelTypeSet GetPriorityTypes() const;
+
+  // Divide |types| into sets by their priorities and return the sets from
+  // high priority to low priority.
+  TypeSetPriorityList PrioritizeTypes(const syncer::ModelTypeSet& types);
+
   // Post a task to reconfigure when no downloading or association are running.
   void ProcessReconfigure();
 
   void Restart(syncer::ConfigureReason reason);
   void DownloadReady(base::Time download_start_time,
+                     syncer::ModelTypeSet types_to_download,
                      syncer::ModelTypeSet high_priority_types_before,
                      syncer::ModelTypeSet first_sync_types,
                      syncer::ModelTypeSet failed_configuration_types);
diff --git a/chrome/browser/sync/glue/data_type_manager_impl_unittest.cc b/chrome/browser/sync/glue/data_type_manager_impl_unittest.cc
index a341d61..999c684 100644
--- a/chrome/browser/sync/glue/data_type_manager_impl_unittest.cc
+++ b/chrome/browser/sync/glue/data_type_manager_impl_unittest.cc
@@ -41,6 +41,19 @@
   return result.status;
 }
 
+syncer::ModelTypeSet PriorityTypes() {
+  syncer::ModelTypeSet result = syncer::ControlTypes();
+  result.Put(syncer::MANAGED_USERS);
+  return result;
+}
+
+// Helper for unioning with control types.
+syncer::ModelTypeSet AddPriorityTypesTo(syncer::ModelTypeSet types) {
+  syncer::ModelTypeSet result = PriorityTypes();
+  result.PutAll(types);
+  return result;
+}
+
 // Fake BackendDataTypeConfigurer implementation that simply stores away the
 // callback passed into ConfigureDataTypes.
 class FakeBackendDataTypeConfigurer : public BackendDataTypeConfigurer {
@@ -124,6 +137,8 @@
   return encrypted_types_;
 }
 
+} // namespace
+
 class TestDataTypeManager : public DataTypeManagerImpl {
  public:
   TestDataTypeManager(
@@ -139,26 +154,19 @@
                             encryption_handler,
                             configurer,
                             observer,
-                            failed_data_types_handler) {}
+                            failed_data_types_handler),
+        custom_priority_types_(PriorityTypes()) {}
 
-  void set_priority_list(const TypeSetPriorityList& list) {
-    priority_list_ = list;
-  }
-
- protected:
-  virtual TypeSetPriorityList PrioritizeTypes(
-      const syncer::ModelTypeSet& types) OVERRIDE {
-    TypeSetPriorityList result;
-    if (priority_list_.empty()) {
-      result.push(types);
-    } else {
-      result = priority_list_;
-    }
-    return result;
+  void set_priority_types(const syncer::ModelTypeSet& priority_types) {
+    custom_priority_types_ = priority_types;
   }
 
  private:
-  TypeSetPriorityList priority_list_;
+  virtual syncer::ModelTypeSet GetPriorityTypes() const OVERRIDE {
+    return custom_priority_types_;
+  }
+
+  syncer::ModelTypeSet custom_priority_types_;
 };
 
 // The actual test harness class, parametrized on nigori state (i.e., tests are
@@ -264,6 +272,7 @@
 // downloading, finish starting the controller, and then stop the DTM.
 TEST_F(SyncDataTypeManagerImplTest, ConfigureOne) {
   AddController(BOOKMARKS);
+  dtm_->set_priority_types(AddPriorityTypesTo(syncer::ModelTypeSet(BOOKMARKS)));
 
   SetConfigureStartExpectation();
   SetConfigureDoneExpectation(DataTypeManager::OK);
@@ -286,6 +295,8 @@
 TEST_F(SyncDataTypeManagerImplTest, ConfigureSlowLoadingType) {
   AddController(BOOKMARKS);
   AddController(APPS);
+  dtm_->set_priority_types(
+      AddPriorityTypesTo(syncer::ModelTypeSet(BOOKMARKS, APPS)));
 
   GetController(BOOKMARKS)->SetDelayModelLoad();
 
@@ -331,6 +342,7 @@
 // download callback even after the DTM is stopped and destroyed.
 TEST_F(SyncDataTypeManagerImplTest, ConfigureOneStopWhileDownloadPending) {
   AddController(BOOKMARKS);
+  dtm_->set_priority_types(AddPriorityTypesTo(syncer::ModelTypeSet(BOOKMARKS)));
 
   {
     SetConfigureStartExpectation();
@@ -352,6 +364,7 @@
 // controller even after the DTM is stopped and destroyed.
 TEST_F(SyncDataTypeManagerImplTest, ConfigureOneStopWhileStartingModel) {
   AddController(BOOKMARKS);
+  dtm_->set_priority_types(AddPriorityTypesTo(syncer::ModelTypeSet(BOOKMARKS)));
 
   {
     SetConfigureStartExpectation();
@@ -378,6 +391,8 @@
 // destroyed.
 TEST_F(SyncDataTypeManagerImplTest, ConfigureOneStopWhileAssociating) {
   AddController(BOOKMARKS);
+  dtm_->set_priority_types(AddPriorityTypesTo(syncer::ModelTypeSet(BOOKMARKS)));
+
   {
     SetConfigureStartExpectation();
     SetConfigureDoneExpectation(DataTypeManager::ABORTED);
@@ -405,6 +420,7 @@
 //   5) Stop the DTM.
 TEST_F(SyncDataTypeManagerImplTest, OneWaitingForCrypto) {
   AddController(PASSWORDS);
+  dtm_->set_priority_types(AddPriorityTypesTo(syncer::ModelTypeSet(PASSWORDS)));
 
   SetConfigureStartExpectation();
   SetConfigureDoneExpectation(DataTypeManager::PARTIAL_SUCCESS);
@@ -445,6 +461,8 @@
 TEST_F(SyncDataTypeManagerImplTest, ConfigureOneThenBoth) {
   AddController(BOOKMARKS);
   AddController(PREFERENCES);
+  dtm_->set_priority_types(
+      AddPriorityTypesTo(syncer::ModelTypeSet(BOOKMARKS, PREFERENCES)));
 
   SetConfigureStartExpectation();
   SetConfigureDoneExpectation(DataTypeManager::OK);
@@ -494,6 +512,8 @@
 TEST_F(SyncDataTypeManagerImplTest, ConfigureOneThenSwitch) {
   AddController(BOOKMARKS);
   AddController(PREFERENCES);
+  dtm_->set_priority_types(
+      AddPriorityTypesTo(syncer::ModelTypeSet(BOOKMARKS, PREFERENCES)));
 
   SetConfigureStartExpectation();
   SetConfigureDoneExpectation(DataTypeManager::OK);
@@ -543,6 +563,8 @@
 TEST_F(SyncDataTypeManagerImplTest, ConfigureWhileOneInFlight) {
   AddController(BOOKMARKS);
   AddController(PREFERENCES);
+  dtm_->set_priority_types(
+      AddPriorityTypesTo(syncer::ModelTypeSet(BOOKMARKS, PREFERENCES)));
 
   SetConfigureStartExpectation();
   SetConfigureDoneExpectation(DataTypeManager::OK);
@@ -581,6 +603,7 @@
 // The unrecoverable error should cause the DTM to stop.
 TEST_F(SyncDataTypeManagerImplTest, OneFailingController) {
   AddController(BOOKMARKS);
+  dtm_->set_priority_types(AddPriorityTypesTo(syncer::ModelTypeSet(BOOKMARKS)));
 
   SetConfigureStartExpectation();
   SetConfigureDoneExpectation(DataTypeManager::UNRECOVERABLE_ERROR);
@@ -607,6 +630,8 @@
 TEST_F(SyncDataTypeManagerImplTest, SecondControllerFails) {
   AddController(BOOKMARKS);
   AddController(PREFERENCES);
+  dtm_->set_priority_types(
+      AddPriorityTypesTo(syncer::ModelTypeSet(BOOKMARKS, PREFERENCES)));
 
   SetConfigureStartExpectation();
   SetConfigureDoneExpectation(DataTypeManager::UNRECOVERABLE_ERROR);
@@ -645,6 +670,8 @@
 TEST_F(SyncDataTypeManagerImplTest, OneControllerFailsAssociation) {
   AddController(BOOKMARKS);
   AddController(PREFERENCES);
+  dtm_->set_priority_types(
+      AddPriorityTypesTo(syncer::ModelTypeSet(BOOKMARKS, PREFERENCES)));
 
   SetConfigureStartExpectation();
   SetConfigureDoneExpectation(DataTypeManager::PARTIAL_SUCCESS);
@@ -686,6 +713,8 @@
 TEST_F(SyncDataTypeManagerImplTest, ConfigureWhileDownloadPending) {
   AddController(BOOKMARKS);
   AddController(PREFERENCES);
+  dtm_->set_priority_types(
+      AddPriorityTypesTo(syncer::ModelTypeSet(BOOKMARKS, PREFERENCES)));
 
   SetConfigureStartExpectation();
   SetConfigureDoneExpectation(DataTypeManager::OK);
@@ -731,6 +760,8 @@
 TEST_F(SyncDataTypeManagerImplTest, ConfigureWhileDownloadPendingWithFailure) {
   AddController(BOOKMARKS);
   AddController(PREFERENCES);
+  dtm_->set_priority_types(
+      AddPriorityTypesTo(syncer::ModelTypeSet(BOOKMARKS, PREFERENCES)));
 
   SetConfigureStartExpectation();
   SetConfigureDoneExpectation(DataTypeManager::OK);
@@ -766,6 +797,7 @@
 // operations that would be invoked by the BackendMigrator.
 TEST_F(SyncDataTypeManagerImplTest, MigrateAll) {
   AddController(BOOKMARKS);
+  dtm_->set_priority_types(AddPriorityTypesTo(syncer::ModelTypeSet(BOOKMARKS)));
 
   SetConfigureStartExpectation();
   SetConfigureDoneExpectation(DataTypeManager::OK);
@@ -808,6 +840,8 @@
 TEST_F(SyncDataTypeManagerImplTest, ConfigureDuringPurge) {
   AddController(BOOKMARKS);
   AddController(PREFERENCES);
+  dtm_->set_priority_types(
+      AddPriorityTypesTo(syncer::ModelTypeSet(BOOKMARKS, PREFERENCES)));
 
   // Initial configure.
   SetConfigureStartExpectation();
@@ -855,18 +889,19 @@
 TEST_F(SyncDataTypeManagerImplTest, PrioritizedConfiguration) {
   AddController(BOOKMARKS);
   AddController(PREFERENCES);
+  dtm_->set_priority_types(
+      AddPriorityTypesTo(syncer::ModelTypeSet(BOOKMARKS, PREFERENCES)));
 
-  TypeSetPriorityList priority_list;
-  priority_list.push(ModelTypeSet(PREFERENCES));
-  priority_list.push(ModelTypeSet(BOOKMARKS));
-  dtm_->set_priority_list(priority_list);
+  dtm_->set_priority_types(
+      AddPriorityTypesTo(syncer::ModelTypeSet(PREFERENCES)));
 
   // Initial configure.
   SetConfigureStartExpectation();
   SetConfigureDoneExpectation(DataTypeManager::OK);
 
   // Initially only PREFERENCES is configured.
-  configurer_.set_expected_configure_types(ModelTypeSet(PREFERENCES));
+  configurer_.set_expected_configure_types(
+      AddPriorityTypesTo(ModelTypeSet(PREFERENCES)));
   Configure(dtm_.get(), ModelTypeSet(BOOKMARKS, PREFERENCES));
   EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
 
@@ -888,17 +923,16 @@
   AddController(PREFERENCES);
   AddController(APPS);
 
-  TypeSetPriorityList priority_list;
-  priority_list.push(ModelTypeSet(PREFERENCES));
-  priority_list.push(ModelTypeSet(BOOKMARKS));
-  dtm_->set_priority_list(priority_list);
+  dtm_->set_priority_types(
+      AddPriorityTypesTo(syncer::ModelTypeSet(PREFERENCES)));
 
   // Initial configure.
   SetConfigureStartExpectation();
   SetConfigureDoneExpectation(DataTypeManager::OK);
 
   // Reconfigure while associating PREFERENCES and downloading BOOKMARKS.
-  configurer_.set_expected_configure_types(ModelTypeSet(PREFERENCES));
+  configurer_.set_expected_configure_types(
+      AddPriorityTypesTo(ModelTypeSet(PREFERENCES)));
   Configure(dtm_.get(), ModelTypeSet(BOOKMARKS, PREFERENCES));
   EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
 
@@ -907,14 +941,13 @@
   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
 
   // Enable syncing for APPS.
-  priority_list.back() = ModelTypeSet(BOOKMARKS, APPS);
-  dtm_->set_priority_list(priority_list);
   Configure(dtm_.get(), ModelTypeSet(BOOKMARKS, PREFERENCES, APPS));
   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
 
   // Reconfiguration starts after downloading and association of previous
   // types finish.
-  configurer_.set_expected_configure_types(ModelTypeSet(PREFERENCES));
+  configurer_.set_expected_configure_types(
+      AddPriorityTypesTo(ModelTypeSet(PREFERENCES)));
   FinishDownload(*dtm_, ModelTypeSet(BOOKMARKS), ModelTypeSet());
   GetController(PREFERENCES)->FinishStart(DataTypeController::OK);
   EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
@@ -937,17 +970,16 @@
   AddController(BOOKMARKS);
   AddController(PREFERENCES);
 
-  TypeSetPriorityList priority_list;
-  priority_list.push(ModelTypeSet(PREFERENCES));
-  priority_list.push(ModelTypeSet(BOOKMARKS));
-  dtm_->set_priority_list(priority_list);
+  dtm_->set_priority_types(
+      AddPriorityTypesTo(syncer::ModelTypeSet(PREFERENCES)));
 
   // Initial configure.
   SetConfigureStartExpectation();
   SetConfigureDoneExpectation(DataTypeManager::ABORTED);
 
   // Initially only PREFERENCES is configured.
-  configurer_.set_expected_configure_types(ModelTypeSet(PREFERENCES));
+  configurer_.set_expected_configure_types(
+      AddPriorityTypesTo(ModelTypeSet(PREFERENCES)));
   Configure(dtm_.get(), ModelTypeSet(BOOKMARKS, PREFERENCES));
   EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
 
@@ -972,17 +1004,16 @@
   AddController(BOOKMARKS);
   AddController(PREFERENCES);
 
-  TypeSetPriorityList priority_list;
-  priority_list.push(ModelTypeSet(PREFERENCES));
-  priority_list.push(ModelTypeSet(BOOKMARKS));
-  dtm_->set_priority_list(priority_list);
+  dtm_->set_priority_types(
+      AddPriorityTypesTo(syncer::ModelTypeSet(PREFERENCES)));
 
   // Initial configure.
   SetConfigureStartExpectation();
   SetConfigureDoneExpectation(DataTypeManager::UNRECOVERABLE_ERROR);
 
   // Initially only PREFERENCES is configured.
-  configurer_.set_expected_configure_types(ModelTypeSet(PREFERENCES));
+  configurer_.set_expected_configure_types(
+      AddPriorityTypesTo(ModelTypeSet(PREFERENCES)));
   Configure(dtm_.get(), ModelTypeSet(BOOKMARKS, PREFERENCES));
   EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
 
@@ -1004,21 +1035,20 @@
   EXPECT_EQ(DataTypeController::NOT_RUNNING, GetController(BOOKMARKS)->state());
 }
 
-TEST_F(SyncDataTypeManagerImplTest, PrioritizedConfigurationAssociationError) {
-  AddController(BOOKMARKS);
-  AddController(PREFERENCES);
+TEST_F(SyncDataTypeManagerImplTest, HighPriorityAssociationFailure) {
+  AddController(PREFERENCES);   // Will fail.
+  AddController(BOOKMARKS);     // Will succeed.
 
-  TypeSetPriorityList priority_list;
-  priority_list.push(ModelTypeSet(PREFERENCES));
-  priority_list.push(ModelTypeSet(BOOKMARKS));
-  dtm_->set_priority_list(priority_list);
+  dtm_->set_priority_types(
+      AddPriorityTypesTo(syncer::ModelTypeSet(PREFERENCES)));
 
   // Initial configure.
   SetConfigureStartExpectation();
-  SetConfigureDoneExpectation(DataTypeManager::UNRECOVERABLE_ERROR);
+  SetConfigureDoneExpectation(DataTypeManager::PARTIAL_SUCCESS);
 
   // Initially only PREFERENCES is configured.
-  configurer_.set_expected_configure_types(ModelTypeSet(PREFERENCES));
+  configurer_.set_expected_configure_types(
+      AddPriorityTypesTo(ModelTypeSet(PREFERENCES)));
   Configure(dtm_.get(), ModelTypeSet(BOOKMARKS, PREFERENCES));
   EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
 
@@ -1034,13 +1064,76 @@
 
   // Make PREFERENCES association fail.
   GetController(PREFERENCES)->FinishStart(
-      DataTypeController::UNRECOVERABLE_ERROR);
-  EXPECT_EQ(DataTypeManager::STOPPED, dtm_->state());
+      DataTypeController::ASSOCIATION_FAILED);
+  EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
+
+  // Reconfigure without PREFERENCES after the BOOKMARKS download completes,
+  // then reconfigure with BOOKMARKS.
+  configurer_.set_expected_configure_types(PriorityTypes());
+  FinishDownload(*dtm_, ModelTypeSet(BOOKMARKS), ModelTypeSet());
+  configurer_.set_expected_configure_types(ModelTypeSet(BOOKMARKS));
+  FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
+
+  // Reconfigure with BOOKMARKS.
+  FinishDownload(*dtm_, ModelTypeSet(BOOKMARKS), ModelTypeSet());
+  EXPECT_EQ(DataTypeController::ASSOCIATING,
+            GetController(BOOKMARKS)->state());
+  GetController(BOOKMARKS)->FinishStart(DataTypeController::OK);
+
+  EXPECT_EQ(DataTypeManager::CONFIGURED, dtm_->state());
   EXPECT_EQ(DataTypeController::NOT_RUNNING,
             GetController(PREFERENCES)->state());
-  EXPECT_EQ(DataTypeController::NOT_RUNNING, GetController(BOOKMARKS)->state());
+  EXPECT_EQ(DataTypeController::RUNNING, GetController(BOOKMARKS)->state());
 }
 
-}  // namespace
+TEST_F(SyncDataTypeManagerImplTest, LowPriorityAssociationFailure) {
+  AddController(PREFERENCES);  // Will succeed.
+  AddController(BOOKMARKS);    // Will fail.
+
+  dtm_->set_priority_types(
+      AddPriorityTypesTo(syncer::ModelTypeSet(PREFERENCES)));
+
+  // Initial configure.
+  SetConfigureStartExpectation();
+  SetConfigureDoneExpectation(DataTypeManager::PARTIAL_SUCCESS);
+
+  // Initially only PREFERENCES is configured.
+  configurer_.set_expected_configure_types(
+      AddPriorityTypesTo(ModelTypeSet(PREFERENCES)));
+  Configure(dtm_.get(), ModelTypeSet(BOOKMARKS, PREFERENCES));
+  EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
+
+  // BOOKMARKS is configured after download of PREFERENCES finishes.
+  configurer_.set_expected_configure_types(ModelTypeSet(BOOKMARKS));
+  FinishDownload(*dtm_, ModelTypeSet(PREFERENCES), ModelTypeSet());
+  EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
+
+  // PERFERENCES controller is associating while BOOKMARKS is downloading.
+  EXPECT_EQ(DataTypeController::ASSOCIATING,
+            GetController(PREFERENCES)->state());
+  EXPECT_EQ(DataTypeController::NOT_RUNNING, GetController(BOOKMARKS)->state());
+
+  // BOOKMARKS finishes downloading and PREFERENCES finishes associating.
+  FinishDownload(*dtm_, ModelTypeSet(BOOKMARKS), ModelTypeSet());
+  GetController(PREFERENCES)->FinishStart(DataTypeController::OK);
+  EXPECT_EQ(DataTypeController::RUNNING, GetController(PREFERENCES)->state());
+
+  // Make BOOKMARKS association fail, which triggers reconfigure with only
+  // PREFERENCES.
+  configurer_.set_expected_configure_types(
+      AddPriorityTypesTo(ModelTypeSet(PREFERENCES)));
+  GetController(BOOKMARKS)->FinishStart(
+      DataTypeController::ASSOCIATION_FAILED);
+  EXPECT_EQ(DataTypeController::NOT_RUNNING,
+            GetController(BOOKMARKS)->state());
+  EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm_->state());
+
+  // Finish configuration with only PREFERENCES.
+  FinishDownload(*dtm_, ModelTypeSet(PREFERENCES), ModelTypeSet());
+  EXPECT_EQ(DataTypeManager::CONFIGURED, dtm_->state());
+  EXPECT_EQ(DataTypeController::RUNNING, GetController(PREFERENCES)->state());
+  EXPECT_EQ(DataTypeController::NOT_RUNNING,
+            GetController(BOOKMARKS)->state());
+}
 
 }  // namespace browser_sync
diff --git a/chrome/browser/sync/glue/failed_data_types_handler.cc b/chrome/browser/sync/glue/failed_data_types_handler.cc
index 594911f..ada738c 100644
--- a/chrome/browser/sync/glue/failed_data_types_handler.cc
+++ b/chrome/browser/sync/glue/failed_data_types_handler.cc
@@ -30,40 +30,57 @@
 FailedDataTypesHandler::~FailedDataTypesHandler() {
 }
 
-bool FailedDataTypesHandler::UpdateFailedDataTypes(
-    const TypeErrorMap& errors,
-    FailureType failure_type) {
-  if (failure_type == RUNTIME) {
-    runtime_errors_.insert(errors.begin(), errors.end());
-  } else if (failure_type == STARTUP) {
-    startup_errors_.insert(errors.begin(), errors.end());
-  } else if (failure_type == CRYPTO) {
-    crypto_errors_.insert(errors.begin(), errors.end());
-  } else {
-    NOTREACHED();
-  }
+bool FailedDataTypesHandler::UpdateFailedDataTypes(const TypeErrorMap& errors) {
+  if (errors.empty())
+    return false;
 
-  return !errors.empty();
+  for (TypeErrorMap::const_iterator iter = errors.begin(); iter != errors.end();
+       ++iter) {
+    syncer::SyncError::ErrorType failure_type = iter->second.error_type();
+    switch (failure_type) {
+      case syncer::SyncError::UNRECOVERABLE_ERROR:
+      case syncer::SyncError::DATATYPE_ERROR:
+        fatal_errors_.insert(*iter);
+        break;
+      case syncer::SyncError::CRYPTO_ERROR:
+        crypto_errors_.insert(*iter);
+        break;
+      case syncer::SyncError::PERSISTENCE_ERROR:
+        persistence_errors_.insert(*iter);
+        break;
+      default:
+        NOTREACHED();
+    }
+  }
+  return true;
 }
 
 void FailedDataTypesHandler::Reset() {
-  startup_errors_.clear();
-  runtime_errors_.clear();
+  fatal_errors_.clear();
   crypto_errors_.clear();
+  persistence_errors_.clear();
 }
 
 void FailedDataTypesHandler::ResetCryptoErrors() {
   crypto_errors_.clear();
 }
 
+void FailedDataTypesHandler::ResetPersistenceErrorsFrom(
+    syncer::ModelTypeSet purged_types) {
+  for (syncer::ModelTypeSet::Iterator iter = purged_types.First(); iter.Good();
+       iter.Inc()) {
+    persistence_errors_.erase(iter.Get());
+  }
+}
+
 FailedDataTypesHandler::TypeErrorMap FailedDataTypesHandler::GetAllErrors()
     const {
   TypeErrorMap result;
 
   if (AnyFailedDataType()) {
-    result = startup_errors_;
-    result.insert(runtime_errors_.begin(), runtime_errors_.end());
+    result = fatal_errors_;
     result.insert(crypto_errors_.begin(), crypto_errors_.end());
+    result.insert(persistence_errors_.begin(), persistence_errors_.end());
   }
   return result;
 }
@@ -75,9 +92,7 @@
 }
 
 syncer::ModelTypeSet FailedDataTypesHandler::GetFatalErrorTypes() const {
-  syncer::ModelTypeSet result = GetTypesFromErrorMap(startup_errors_);
-  result.PutAll(GetTypesFromErrorMap(runtime_errors_));
-  return result;
+  return GetTypesFromErrorMap(fatal_errors_);;
 }
 
 syncer::ModelTypeSet FailedDataTypesHandler::GetCryptoErrorTypes() const {
@@ -85,9 +100,15 @@
   return result;
 }
 
+syncer::ModelTypeSet FailedDataTypesHandler::GetPersistenceErrorTypes() const {
+  syncer::ModelTypeSet result = GetTypesFromErrorMap(persistence_errors_);
+  return result;
+}
+
 bool FailedDataTypesHandler::AnyFailedDataType() const {
-  return (!startup_errors_.empty() || !runtime_errors_.empty() ||
-          !crypto_errors_.empty());
+  // Note: persistence errors are not failed types. They just trigger automatic
+  // unapply + getupdates, at which point they are associated like normal.
+  return !fatal_errors_.empty() || !crypto_errors_.empty();
 }
 
 }  // namespace browser_sync
diff --git a/chrome/browser/sync/glue/failed_data_types_handler.h b/chrome/browser/sync/glue/failed_data_types_handler.h
index 1998cd8..0b86fd8 100644
--- a/chrome/browser/sync/glue/failed_data_types_handler.h
+++ b/chrome/browser/sync/glue/failed_data_types_handler.h
@@ -14,25 +14,14 @@
 // Class to keep track of data types that have encountered an error during sync.
 class FailedDataTypesHandler {
  public:
-  enum FailureType {
-    // The dataype failed at startup.
-    STARTUP,
-
-    // The datatype encountered a runtime error.
-    RUNTIME,
-
-    // The datatype encountered a cryptographer related error.
-    CRYPTO
-  };
   typedef std::map<syncer::ModelType, syncer::SyncError> TypeErrorMap;
 
   explicit FailedDataTypesHandler();
   ~FailedDataTypesHandler();
 
-  // Called with the result of sync configuration. The types with errors
-  // are obtained from the |result|.
-  bool UpdateFailedDataTypes(const TypeErrorMap& errors,
-                             FailureType failure_type);
+  // Update the failed datatypes. Types will be added to their corresponding
+  // error map based on their |error_type()|.
+  bool UpdateFailedDataTypes(const TypeErrorMap& errors);
 
   // Resets the current set of data type errors.
   void Reset();
@@ -40,6 +29,9 @@
   // Resets the set of types with cryptographer errors.
   void ResetCryptoErrors();
 
+  // Resets those persistence errors that intersect with |purged_types|.
+  void ResetPersistenceErrorsFrom(syncer::ModelTypeSet purged_types);
+
   // Returns a list of all the errors this class has recorded.
   TypeErrorMap GetAllErrors() const;
 
@@ -52,19 +44,24 @@
   // Returns the types that are failing due to cryptographer errors.
   syncer::ModelTypeSet GetCryptoErrorTypes() const;
 
+  // Returns the types that are failing due to persistence errors.
+  syncer::ModelTypeSet GetPersistenceErrorTypes() const;
+
  private:
   // Returns true if there are any types with errors.
   bool AnyFailedDataType() const;
 
-  // List of data types that failed at startup due to association errors.
-  TypeErrorMap startup_errors_;
-
-  // List of data types that failed at runtime.
-  TypeErrorMap runtime_errors_;
+  // List of data types that failed at startup due to association errors or
+  // runtime due to data type errors.
+  TypeErrorMap fatal_errors_;
 
   // List of data types that failed due to the cryptographer not being ready.
   TypeErrorMap crypto_errors_;
 
+  // List of data type that failed because sync did not persist the newest
+  // version of their data.
+  TypeErrorMap persistence_errors_;
+
   DISALLOW_COPY_AND_ASSIGN(FailedDataTypesHandler);
 };
 
diff --git a/chrome/browser/sync/glue/fake_data_type_controller.cc b/chrome/browser/sync/glue/fake_data_type_controller.cc
index d424a1a..f21f27b 100644
--- a/chrome/browser/sync/glue/fake_data_type_controller.cc
+++ b/chrome/browser/sync/glue/fake_data_type_controller.cc
@@ -64,11 +64,17 @@
   } else if (result == ASSOCIATION_FAILED) {
     state_ = DISABLED;
     local_merge_result.set_error(
-        syncer::SyncError(FROM_HERE, "Association failed", type()));
+        syncer::SyncError(FROM_HERE,
+                          syncer::SyncError::DATATYPE_ERROR,
+                          "Association failed",
+                          type()));
   } else {
     state_ = NOT_RUNNING;
     local_merge_result.set_error(
-        syncer::SyncError(FROM_HERE, "Fake error", type()));
+        syncer::SyncError(FROM_HERE,
+                          syncer::SyncError::DATATYPE_ERROR,
+                          "Fake error",
+                          type()));
   }
   StartCallback start_callback = last_start_callback_;
   last_start_callback_.Reset();
@@ -89,7 +95,10 @@
 
   // The DTM still expects |last_start_callback_| to be called back.
   if (!last_start_callback_.is_null()) {
-    syncer::SyncError error(FROM_HERE, "Fake error", type_);
+    syncer::SyncError error(FROM_HERE,
+                            syncer::SyncError::DATATYPE_ERROR,
+                            "Fake error",
+                            type_);
     syncer::SyncMergeResult local_merge_result(type_);
     local_merge_result.set_error(error);
     last_start_callback_.Run(ABORTED,
diff --git a/chrome/browser/sync/glue/favicon_cache.cc b/chrome/browser/sync/glue/favicon_cache.cc
index 4111f32..58416fc 100644
--- a/chrome/browser/sync/glue/favicon_cache.cc
+++ b/chrome/browser/sync/glue/favicon_cache.cc
@@ -326,6 +326,7 @@
   if (!favicon_images_sync_processor_.get() ||
       !favicon_tracking_sync_processor_.get()) {
     return syncer::SyncError(FROM_HERE,
+                             syncer::SyncError::DATATYPE_ERROR,
                              "One or both favicon types disabled.",
                              change_list[0].sync_data().GetDataType());
   }
diff --git a/chrome/browser/sync/glue/favicon_cache.h b/chrome/browser/sync/glue/favicon_cache.h
index 4dea3c7..a273aa0 100644
--- a/chrome/browser/sync/glue/favicon_cache.h
+++ b/chrome/browser/sync/glue/favicon_cache.h
@@ -20,10 +20,10 @@
 #include "chrome/common/cancelable_task_tracker.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
-#include "googleurl/src/gurl.h"
 #include "sync/api/sync_change.h"
 #include "sync/api/sync_error_factory.h"
 #include "sync/api/syncable_service.h"
+#include "url/gurl.h"
 
 class Profile;
 
diff --git a/chrome/browser/sync/glue/favicon_cache_unittest.cc b/chrome/browser/sync/glue/favicon_cache_unittest.cc
index cde093c..697f371 100644
--- a/chrome/browser/sync/glue/favicon_cache_unittest.cc
+++ b/chrome/browser/sync/glue/favicon_cache_unittest.cc
@@ -77,7 +77,10 @@
     const syncer::SyncChangeList& change_list) {
   if (erroneous_) {
     return syncer::SyncError(
-        FROM_HERE, "Some error.", change_list[0].sync_data().GetDataType());
+        FROM_HERE,
+        syncer::SyncError::DATATYPE_ERROR,
+        "Some error.",
+        change_list[0].sync_data().GetDataType());
   }
 
   change_list_.insert(change_list_.end(),
diff --git a/chrome/browser/sync/glue/frontend_data_type_controller.cc b/chrome/browser/sync/glue/frontend_data_type_controller.cc
index c3b0cf6..043ca23 100644
--- a/chrome/browser/sync/glue/frontend_data_type_controller.cc
+++ b/chrome/browser/sync/glue/frontend_data_type_controller.cc
@@ -40,7 +40,9 @@
   DCHECK(!model_load_callback.is_null());
 
   if (state_ != NOT_RUNNING) {
-    model_load_callback.Run(type(), syncer::SyncError(FROM_HERE,
+    model_load_callback.Run(type(),
+                            syncer::SyncError(FROM_HERE,
+                                              syncer::SyncError::DATATYPE_ERROR,
                                               "Model already running",
                                               type()));
     return;
@@ -170,7 +172,10 @@
 
   bool sync_has_nodes = false;
   if (!model_associator()->SyncModelHasUserCreatedNodes(&sync_has_nodes)) {
-    syncer::SyncError error(FROM_HERE, "Failed to load sync nodes", type());
+    syncer::SyncError error(FROM_HERE,
+                            syncer::SyncError::UNRECOVERABLE_ERROR,
+                            "Failed to load sync nodes",
+                            type());
     local_merge_result.set_error(error);
     StartDone(UNRECOVERABLE_ERROR, local_merge_result, syncer_merge_result);
     return false;
@@ -223,7 +228,9 @@
   state_ = NOT_RUNNING;
   ModelLoadCallback model_load_callback = model_load_callback_;
   model_load_callback_.Reset();
-  model_load_callback.Run(type(), syncer::SyncError(FROM_HERE,
+  model_load_callback.Run(type(),
+                          syncer::SyncError(FROM_HERE,
+                                            syncer::SyncError::DATATYPE_ERROR,
                                             "Aborted",
                                             type()));
 }
diff --git a/chrome/browser/sync/glue/frontend_data_type_controller_unittest.cc b/chrome/browser/sync/glue/frontend_data_type_controller_unittest.cc
index c9422a3..12c1923 100644
--- a/chrome/browser/sync/glue/frontend_data_type_controller_unittest.cc
+++ b/chrome/browser/sync/glue/frontend_data_type_controller_unittest.cc
@@ -209,8 +209,9 @@
       WillOnce(DoAll(SetArgumentPointee<0>(true), Return(true)));
   EXPECT_CALL(*model_associator_, AssociateModels(_, _)).
       WillOnce(Return(syncer::SyncError(FROM_HERE,
-                                "error",
-                                syncer::BOOKMARKS)));
+                                        syncer::SyncError::DATATYPE_ERROR,
+                                        "error",
+                                        syncer::BOOKMARKS)));
 
   EXPECT_CALL(*dtc_mock_.get(), RecordAssociationTime(_));
   SetStartFailExpectations(DataTypeController::ASSOCIATION_FAILED);
diff --git a/chrome/browser/sync/glue/generic_change_processor.cc b/chrome/browser/sync/glue/generic_change_processor.cc
index cf1daa8..591e717 100644
--- a/chrome/browser/sync/glue/generic_change_processor.cc
+++ b/chrome/browser/sync/glue/generic_change_processor.cc
@@ -83,7 +83,10 @@
     return;
   if (!local_service_.get()) {
     syncer::ModelType type = syncer_changes_[0].sync_data().GetDataType();
-    syncer::SyncError error(FROM_HERE, "Local service destroyed.", type);
+    syncer::SyncError error(FROM_HERE,
+                            syncer::SyncError::DATATYPE_ERROR,
+                            "Local service destroyed.",
+                            type);
     error_handler()->OnSingleDatatypeUnrecoverableError(error.location(),
                                                         error.message());
     return;
@@ -107,9 +110,11 @@
   if (root.InitByTagLookup(syncer::ModelTypeToRootTag(type)) !=
           syncer::BaseNode::INIT_OK) {
     syncer::SyncError error(FROM_HERE,
-                    "Server did not create the top-level " + type_name +
-                    " node. We might be running against an out-of-date server.",
-                    type);
+                            syncer::SyncError::DATATYPE_ERROR,
+                            "Server did not create the top-level " + type_name +
+                                " node. We might be running against an out-of-"
+                                "date server.",
+                            type);
     return error;
   }
 
@@ -125,8 +130,10 @@
     if (sync_child_node.InitByIdLookup(*it) !=
             syncer::BaseNode::INIT_OK) {
       syncer::SyncError error(FROM_HERE,
-                      "Failed to fetch child node for type " + type_name + ".",
-                       type);
+                              syncer::SyncError::DATATYPE_ERROR,
+                              "Failed to fetch child node for type " +
+                                  type_name + ".",
+                              type);
       return error;
     }
     current_sync_data->push_back(syncer::SyncData::CreateRemoteData(
@@ -221,6 +228,7 @@
     if (tag.empty()) {
       syncer::SyncError error(
           FROM_HERE,
+          syncer::SyncError::DATATYPE_ERROR,
           "Failed to delete " + type_str + " node. Local data, empty tag. " +
               change.location().ToString(),
           type);
@@ -297,8 +305,10 @@
               syncer::ModelTypeToRootTag(change.sync_data().GetDataType())) !=
                   syncer::BaseNode::INIT_OK) {
         syncer::SyncError error(FROM_HERE,
-                        "Failed to look up root node for type " + type_str,
-                        type);
+                                syncer::SyncError::DATATYPE_ERROR,
+                                "Failed to look up root node for type " +
+                                    type_str,
+                                type);
         error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE,
                                                             error.message());
         NOTREACHED();
@@ -461,6 +471,7 @@
     } else {
       syncer::SyncError error(
           FROM_HERE,
+          syncer::SyncError::DATATYPE_ERROR,
           "Received unset SyncChange in the change processor, " +
               change.location().ToString(),
           type);
diff --git a/chrome/browser/sync/glue/generic_change_processor_unittest.cc b/chrome/browser/sync/glue/generic_change_processor_unittest.cc
index d245a8b..bb90a50 100644
--- a/chrome/browser/sync/glue/generic_change_processor_unittest.cc
+++ b/chrome/browser/sync/glue/generic_change_processor_unittest.cc
@@ -29,7 +29,7 @@
   static const syncer::ModelType kType = syncer::PREFERENCES;
 
   GenericChangeProcessorTest() :
-      loop(base::MessageLoop::TYPE_UI),
+      loop_(base::MessageLoop::TYPE_UI),
       sync_merge_result_(kType),
       merge_result_ptr_factory_(&sync_merge_result_),
       syncable_service_ptr_factory_(&fake_syncable_service_) {
@@ -70,7 +70,7 @@
   }
 
  private:
-  base::MessageLoop loop;
+  base::MessageLoop loop_;
 
   syncer::SyncMergeResult sync_merge_result_;
   base::WeakPtrFactory<syncer::SyncMergeResult> merge_result_ptr_factory_;
diff --git a/chrome/browser/sync/glue/model_association_manager.cc b/chrome/browser/sync/glue/model_association_manager.cc
index 4049523..28f245e 100644
--- a/chrome/browser/sync/glue/model_association_manager.cc
+++ b/chrome/browser/sync/glue/model_association_manager.cc
@@ -150,7 +150,8 @@
   needs_crypto_types_.Clear();
   state_ = INITIALIZED_TO_CONFIGURE;
 
-  DVLOG(1) << "ModelAssociationManager: Initializing";
+  DVLOG(1) << "ModelAssociationManager: Initializing for "
+           << syncer::ModelTypeSetToString(desired_types);
 
   // Stop the types that are still loading from the previous configuration.
   // If they are enabled we will start them here once again.
@@ -217,7 +218,6 @@
 }
 
 void ModelAssociationManager::StopDisabledTypes() {
-  DCHECK_EQ(state_, INITIALIZED_TO_CONFIGURE);
   DVLOG(1) << "ModelAssociationManager: Stopping disabled types.";
   // Stop requested data types.
   for (size_t i = 0; i < needs_stop_.size(); ++i) {
@@ -231,7 +231,7 @@
   bool need_to_call_model_association_done = false;
   DVLOG(1) << "ModelAssociationManager: Stopping MAM";
   if (state_ == CONFIGURING) {
-    DVLOG(1) << "ModelAssociationManager: In the middle of configuratio while"
+    DVLOG(1) << "ModelAssociationManager: In the middle of configuration while"
              << " stopping";
     state_ = ABORTED;
     DCHECK(currently_associating_ != NULL ||
@@ -311,11 +311,11 @@
 void ModelAssociationManager::AppendToFailedDatatypesAndLogError(
     DataTypeController::StartResult result,
     const syncer::SyncError& error) {
-  failed_data_types_info_[error.type()] = error;
+  failed_data_types_info_[error.model_type()] = error;
   LOG(ERROR) << "Failed to associate models for "
-             << syncer::ModelTypeToString(error.type());
+             << syncer::ModelTypeToString(error.model_type());
   UMA_HISTOGRAM_ENUMERATION("Sync.ConfigureFailed",
-                            ModelTypeToHistogramInt(error.type()),
+                            ModelTypeToHistogramInt(error.model_type()),
                             syncer::MODEL_TYPE_COUNT);
 }
 
@@ -386,7 +386,7 @@
   // Any other result requires reconfiguration. Pass it on through the callback.
   LOG(ERROR) << "Failed to configure " << started_dtc->name();
   DCHECK(local_merge_result.error().IsSet());
-  DCHECK_EQ(started_dtc->type(), local_merge_result.error().type());
+  DCHECK_EQ(started_dtc->type(), local_merge_result.error().model_type());
   DataTypeManager::ConfigureStatus configure_status =
       DataTypeManager::ABORTED;
   switch (start_result) {
@@ -435,7 +435,7 @@
     return;
   }
 
-  DVLOG(1) << "ModelAssociationManager: All types have models loaded."
+  DVLOG(1) << "ModelAssociationManager: All types have models loaded. "
           << "Moving on to StartAssociatingNextType.";
 
   // If all controllers have their |LoadModels| invoked then pass onto
@@ -490,7 +490,7 @@
     NOTREACHED();
     return;
   } else if (state_ == IDLE) {
-    DVLOG(1) << "ModelAssociationManager: Models loaded after configure cycle"
+    DVLOG(1) << "ModelAssociationManager: Models loaded after configure cycle. "
             << "Informing DTM";
     // This datatype finished loading after the deadline imposed by the
     // originating configuration cycle. Inform the DataTypeManager that the
@@ -526,7 +526,19 @@
     return;
   }
 
-  // We are done with this cycle of association.
+  // We are done with this cycle of association. Stop any failed types now.
+  needs_stop_.clear();
+  for (DataTypeController::TypeMap::const_iterator it = controllers_->begin();
+       it != controllers_->end(); ++it) {
+    DataTypeController* dtc = (*it).second.get();
+    if (failed_data_types_info_.count(dtc->type()) > 0 &&
+        dtc->state() != DataTypeController::NOT_RUNNING) {
+      needs_stop_.push_back(dtc);
+      DVLOG(1) << "ModelTypeToString: Will stop " << dtc->name();
+    }
+  }
+  StopDisabledTypes();
+
   state_ = IDLE;
 
   DataTypeManager::ConfigureStatus configure_status = DataTypeManager::OK;
diff --git a/chrome/browser/sync/glue/model_association_manager.h b/chrome/browser/sync/glue/model_association_manager.h
index 5d4ed25..94576c8 100644
--- a/chrome/browser/sync/glue/model_association_manager.h
+++ b/chrome/browser/sync/glue/model_association_manager.h
@@ -8,7 +8,7 @@
 #include <map>
 
 #include "base/memory/weak_ptr.h"
-#include "base/timer.h"
+#include "base/timer/timer.h"
 
 #include "chrome/browser/sync/glue/data_type_manager.h"
 #include "sync/internal_api/public/data_type_association_stats.h"
diff --git a/chrome/browser/sync/glue/model_association_manager_unittest.cc b/chrome/browser/sync/glue/model_association_manager_unittest.cc
index a36596f..2d9c131 100644
--- a/chrome/browser/sync/glue/model_association_manager_unittest.cc
+++ b/chrome/browser/sync/glue/model_association_manager_unittest.cc
@@ -171,7 +171,10 @@
   syncer::ModelTypeSet types;
   types.Put(syncer::BOOKMARKS);
   std::map<syncer::ModelType, syncer::SyncError> errors;
-  syncer::SyncError error(FROM_HERE, "Failed", syncer::BOOKMARKS);
+  syncer::SyncError error(FROM_HERE,
+                          syncer::SyncError::DATATYPE_ERROR,
+                          "Failed",
+                          syncer::BOOKMARKS);
   errors[syncer::BOOKMARKS] = error;
   DataTypeManager::ConfigureResult expected_result(
       DataTypeManager::PARTIAL_SUCCESS,
@@ -190,6 +193,8 @@
             DataTypeController::ASSOCIATING);
   GetController(controllers_, syncer::BOOKMARKS)->FinishStart(
       DataTypeController::ASSOCIATION_FAILED);
+  EXPECT_EQ(GetController(controllers_, syncer::BOOKMARKS)->state(),
+            DataTypeController::NOT_RUNNING);
 }
 
 // Ensure configuring stops when a type returns a unrecoverable error.
@@ -202,7 +207,10 @@
   syncer::ModelTypeSet types;
   types.Put(syncer::BOOKMARKS);
   std::map<syncer::ModelType, syncer::SyncError> errors;
-  syncer::SyncError error(FROM_HERE, "Failed", syncer::BOOKMARKS);
+  syncer::SyncError error(FROM_HERE,
+                          syncer::SyncError::DATATYPE_ERROR,
+                          "Failed",
+                          syncer::BOOKMARKS);
   errors[syncer::BOOKMARKS] = error;
   DataTypeManager::ConfigureResult expected_result(
       DataTypeManager::UNRECOVERABLE_ERROR,
diff --git a/chrome/browser/sync/glue/non_frontend_data_type_controller.cc b/chrome/browser/sync/glue/non_frontend_data_type_controller.cc
index 1ff03e4..56a07f3 100644
--- a/chrome/browser/sync/glue/non_frontend_data_type_controller.cc
+++ b/chrome/browser/sync/glue/non_frontend_data_type_controller.cc
@@ -48,7 +48,9 @@
   start_association_called_.Reset();
   start_models_failed_ = false;
   if (state_ != NOT_RUNNING) {
-    model_load_callback.Run(type(), syncer::SyncError(FROM_HERE,
+    model_load_callback.Run(type(),
+                            syncer::SyncError(FROM_HERE,
+                                              syncer::SyncError::DATATYPE_ERROR,
                                               "Model already loaded",
                                               type()));
     return;
@@ -63,7 +65,9 @@
     // get a false it means they failed.
     DCHECK(state_ == NOT_RUNNING || state_ == MODEL_STARTING
            || state_ == DISABLED);
-    model_load_callback.Run(type(), syncer::SyncError(FROM_HERE,
+    model_load_callback.Run(type(),
+                            syncer::SyncError(FROM_HERE,
+                                              syncer::SyncError::DATATYPE_ERROR,
                                               "Failed loading",
                                               type()));
     return;
@@ -88,7 +92,9 @@
   start_callback_ = start_callback;
   if (!StartAssociationAsync()) {
     syncer::SyncError error(
-        FROM_HERE, "Failed to post StartAssociation", type());
+        FROM_HERE,
+        syncer::SyncError::DATATYPE_ERROR,
+        "Failed to post StartAssociation", type());
     syncer::SyncMergeResult local_merge_result(type());
     local_merge_result.set_error(error);
     StartDoneImpl(ASSOCIATION_FAILED,
@@ -418,7 +424,10 @@
 
   bool sync_has_nodes = false;
   if (!model_associator_->SyncModelHasUserCreatedNodes(&sync_has_nodes)) {
-    syncer::SyncError error(FROM_HERE, "Failed to load sync nodes", type());
+    syncer::SyncError error(FROM_HERE,
+                            syncer::SyncError::UNRECOVERABLE_ERROR,
+                            "Failed to load sync nodes",
+                            type());
     local_merge_result.set_error(error);
     StartDone(UNRECOVERABLE_ERROR,
               local_merge_result,
diff --git a/chrome/browser/sync/glue/non_frontend_data_type_controller_unittest.cc b/chrome/browser/sync/glue/non_frontend_data_type_controller_unittest.cc
index fa64025..2c6a1d6 100644
--- a/chrome/browser/sync/glue/non_frontend_data_type_controller_unittest.cc
+++ b/chrome/browser/sync/glue/non_frontend_data_type_controller_unittest.cc
@@ -250,7 +250,10 @@
       WillOnce(DoAll(SetArgumentPointee<0>(true), Return(true)));
   EXPECT_CALL(*model_associator_, AssociateModels(_, _)).
       WillOnce(
-          Return(syncer::SyncError(FROM_HERE, "Error", syncer::BOOKMARKS)));
+          Return(syncer::SyncError(FROM_HERE,
+                                   syncer::SyncError::DATATYPE_ERROR,
+                                   "Error",
+                                   syncer::BOOKMARKS)));
   EXPECT_CALL(*dtc_mock_.get(), RecordAssociationTime(_));
   SetStartFailExpectations(DataTypeController::ASSOCIATION_FAILED);
   // Set up association to fail with an association failed error.
diff --git a/chrome/browser/sync/glue/non_ui_data_type_controller.cc b/chrome/browser/sync/glue/non_ui_data_type_controller.cc
index 6cb7516..48c3023 100644
--- a/chrome/browser/sync/glue/non_ui_data_type_controller.cc
+++ b/chrome/browser/sync/glue/non_ui_data_type_controller.cc
@@ -35,9 +35,11 @@
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   DCHECK(!model_load_callback.is_null());
   if (state() != NOT_RUNNING) {
-    model_load_callback.Run(type(), syncer::SyncError(FROM_HERE,
-                                                      "Model already running",
-                                                      type()));
+    model_load_callback.Run(type(),
+                            syncer::SyncError(FROM_HERE,
+                                              syncer::SyncError::DATATYPE_ERROR,
+                                              "Model already running",
+                                              type()));
     return;
   }
 
@@ -92,7 +94,10 @@
   start_callback_ = start_callback;
   if (!StartAssociationAsync()) {
     syncer::SyncError error(
-        FROM_HERE, "Failed to post StartAssociation", type());
+        FROM_HERE,
+        syncer::SyncError::DATATYPE_ERROR,
+        "Failed to post StartAssociation",
+        type());
     syncer::SyncMergeResult local_merge_result(type());
     local_merge_result.set_error(error);
     StartDoneImpl(ASSOCIATION_FAILED,
@@ -273,9 +278,11 @@
   StopModels();
   ModelLoadCallback model_load_callback = model_load_callback_;
   model_load_callback_.Reset();
-  model_load_callback.Run(type(), syncer::SyncError(FROM_HERE,
-                                                    "ABORTED",
-                                                    type()));
+  model_load_callback.Run(type(),
+                          syncer::SyncError(FROM_HERE,
+                                            syncer::SyncError::DATATYPE_ERROR,
+                                            "ABORTED",
+                                            type()));
 }
 
 void NonUIDataTypeController::DisableImpl(
@@ -323,7 +330,10 @@
       type(),
       weak_ptr_factory.GetWeakPtr());
   if (!local_service_.get()) {
-    syncer::SyncError error(FROM_HERE, "Failed to connect to syncer.", type());
+    syncer::SyncError error(FROM_HERE,
+                            syncer::SyncError::DATATYPE_ERROR,
+                            "Failed to connect to syncer.",
+                            type());
     local_merge_result.set_error(error);
     StartDone(ASSOCIATION_FAILED,
               local_merge_result,
@@ -340,7 +350,10 @@
 
   bool sync_has_nodes = false;
   if (!shared_change_processor->SyncModelHasUserCreatedNodes(&sync_has_nodes)) {
-    syncer::SyncError error(FROM_HERE, "Failed to load sync nodes", type());
+    syncer::SyncError error(FROM_HERE,
+                            syncer::SyncError::UNRECOVERABLE_ERROR,
+                            "Failed to load sync nodes",
+                            type());
     local_merge_result.set_error(error);
     StartDone(UNRECOVERABLE_ERROR,
               local_merge_result,
@@ -418,4 +431,4 @@
   local_service_.reset();
 }
 
-}  // namepsace browser_sync
+}  // namespace browser_sync
diff --git a/chrome/browser/sync/glue/non_ui_data_type_controller_unittest.cc b/chrome/browser/sync/glue/non_ui_data_type_controller_unittest.cc
index 43107da..f546bf6 100644
--- a/chrome/browser/sync/glue/non_ui_data_type_controller_unittest.cc
+++ b/chrome/browser/sync/glue/non_ui_data_type_controller_unittest.cc
@@ -323,7 +323,9 @@
   EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state());
   syncable_service_.set_merge_data_and_start_syncing_error(
       syncer::SyncError(FROM_HERE,
-                        "Sync Error", non_ui_dtc_->type()));
+                        syncer::SyncError::DATATYPE_ERROR,
+                        "Sync Error",
+                        non_ui_dtc_->type()));
   Start();
   WaitForDTC();
   EXPECT_EQ(DataTypeController::DISABLED, non_ui_dtc_->state());
@@ -381,7 +383,10 @@
                       SetArgumentPointee<0>(true),
                       Return(true)));
   EXPECT_CALL(*change_processor_.get(), GetSyncData(_)).WillOnce(
-      Return(syncer::SyncError(FROM_HERE, "Disconnected.", AUTOFILL_PROFILE)));
+      Return(syncer::SyncError(FROM_HERE,
+                               syncer::SyncError::DATATYPE_ERROR,
+                               "Disconnected.",
+                               AUTOFILL_PROFILE)));
   EXPECT_CALL(*change_processor_.get(), Disconnect())
       .WillOnce(DoAll(SignalEvent(&pause_db_thread), Return(true)));
   EXPECT_CALL(service_, DeactivateDataType(_));
diff --git a/chrome/browser/sync/glue/password_model_associator.cc b/chrome/browser/sync/glue/password_model_associator.cc
index 118d9af..f034c47 100644
--- a/chrome/browser/sync/glue/password_model_associator.cc
+++ b/chrome/browser/sync/glue/password_model_associator.cc
@@ -7,6 +7,7 @@
 #include <set>
 
 #include "base/location.h"
+#include "base/metrics/histogram.h"
 #include "base/stl_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/password_manager/password_store.h"
@@ -63,10 +64,16 @@
   if (!password_store_->FillAutofillableLogins(&passwords) ||
       !password_store_->FillBlacklistLogins(&passwords)) {
     STLDeleteElements(&passwords);
-    return error_handler_->CreateAndUploadError(
-        FROM_HERE,
-        "Could not get the password entries.",
-        model_type());
+
+    // Password store often fails to load passwords. Track failures with UMA.
+    // (http://crbug.com/249000)
+    UMA_HISTOGRAM_ENUMERATION("Sync.LocalDataFailedToLoad",
+                              ModelTypeToHistogramInt(syncer::PASSWORDS),
+                              syncer::MODEL_TYPE_COUNT);
+    return syncer::SyncError(FROM_HERE,
+                             syncer::SyncError::DATATYPE_ERROR,
+                             "Could not get the password entries.",
+                             model_type());
   }
 
   std::set<std::string> current_passwords;
diff --git a/chrome/browser/sync/glue/search_engine_data_type_controller_unittest.cc b/chrome/browser/sync/glue/search_engine_data_type_controller_unittest.cc
index 978c329..1e2a360 100644
--- a/chrome/browser/sync/glue/search_engine_data_type_controller_unittest.cc
+++ b/chrome/browser/sync/glue/search_engine_data_type_controller_unittest.cc
@@ -164,7 +164,10 @@
   EXPECT_CALL(start_callback_,
               Run(DataTypeController::ASSOCIATION_FAILED, _, _));
   syncable_service_.set_merge_data_and_start_syncing_error(
-      syncer::SyncError(FROM_HERE, "Error", syncer::SEARCH_ENGINES));
+      syncer::SyncError(FROM_HERE,
+                        syncer::SyncError::DATATYPE_ERROR,
+                        "Error",
+                        syncer::SEARCH_ENGINES));
 
   Start();
   EXPECT_EQ(DataTypeController::DISABLED, search_engine_dtc_->state());
diff --git a/chrome/browser/sync/glue/session_model_associator.h b/chrome/browser/sync/glue/session_model_associator.h
index 615a1d1..4778c44 100644
--- a/chrome/browser/sync/glue/session_model_associator.h
+++ b/chrome/browser/sync/glue/session_model_associator.h
@@ -16,7 +16,7 @@
 #include "base/memory/linked_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/threading/non_thread_safe.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/sessions/session_id.h"
 #include "chrome/browser/sessions/session_service.h"
 #include "chrome/browser/sessions/session_types.h"
diff --git a/chrome/browser/sync/glue/session_model_associator_unittest.cc b/chrome/browser/sync/glue/session_model_associator_unittest.cc
index f63e44b..34c01a1 100644
--- a/chrome/browser/sync/glue/session_model_associator_unittest.cc
+++ b/chrome/browser/sync/glue/session_model_associator_unittest.cc
@@ -20,11 +20,11 @@
 #include "content/public/browser/notification_service.h"
 #include "content/public/common/page_transition_types.h"
 #include "content/public/test/test_browser_thread.h"
-#include "googleurl/src/gurl.h"
 #include "sync/protocol/session_specifics.pb.h"
 #include "sync/util/time.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
 
 using content::BrowserThread;
 using sessions::SerializedNavigationEntry;
diff --git a/chrome/browser/sync/glue/shared_change_processor.cc b/chrome/browser/sync/glue/shared_change_processor.cc
index 0dd0833..abe7070 100644
--- a/chrome/browser/sync/glue/shared_change_processor.cc
+++ b/chrome/browser/sync/glue/shared_change_processor.cc
@@ -95,7 +95,10 @@
   DCHECK(backend_loop_->BelongsToCurrentThread());
   AutoLock lock(monitor_lock_);
   if (disconnected_) {
-    syncer::SyncError error(FROM_HERE, "Change processor disconnected.", type_);
+    syncer::SyncError error(FROM_HERE,
+                            syncer::SyncError::DATATYPE_ERROR,
+                            "Change processor disconnected.",
+                            type_);
     return error;
   }
   return generic_change_processor_->GetSyncDataForType(type_,
@@ -122,7 +125,10 @@
   if (disconnected_) {
     // The DTC that disconnects us must ensure it posts a StopSyncing task.
     // If we reach this, it means it just hasn't executed yet.
-    syncer::SyncError error(FROM_HERE, "Change processor disconnected.", type_);
+    syncer::SyncError error(FROM_HERE,
+                            syncer::SyncError::DATATYPE_ERROR,
+                            "Change processor disconnected.",
+                            type_);
     return error;
   }
   return generic_change_processor_->ProcessSyncChanges(
@@ -173,7 +179,10 @@
   if (!disconnected_) {
     return error_handler_->CreateAndUploadError(location, message, type_);
   } else {
-    return syncer::SyncError(location, message, type_);
+    return syncer::SyncError(location,
+                             syncer::SyncError::DATATYPE_ERROR,
+                             message,
+                             type_);
   }
 }
 
diff --git a/chrome/browser/sync/glue/sync_backend_host.cc b/chrome/browser/sync/glue/sync_backend_host.cc
index 907b176..870c4d5 100644
--- a/chrome/browser/sync/glue/sync_backend_host.cc
+++ b/chrome/browser/sync/glue/sync_backend_host.cc
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "build/build_config.h"
-
 #include "chrome/browser/sync/glue/sync_backend_host.h"
 
 #include <algorithm>
@@ -18,16 +16,15 @@
 #include "base/metrics/histogram.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/thread_restrictions.h"
-#include "base/timer.h"
+#include "base/timer/timer.h"
 #include "base/tracked_objects.h"
 #include "build/build_config.h"
-#include "chrome/browser/invalidation/invalidator_storage.h"
+#include "chrome/browser/invalidation/invalidation_service.h"
+#include "chrome/browser/invalidation/invalidation_service_factory.h"
 #include "chrome/browser/net/network_time_tracker.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/signin/token_service.h"
 #include "chrome/browser/signin/token_service_factory.h"
-#include "chrome/browser/sync/glue/android_invalidator_bridge.h"
-#include "chrome/browser/sync/glue/android_invalidator_bridge_proxy.h"
 #include "chrome/browser/sync/glue/change_processor.h"
 #include "chrome/browser/sync/glue/chrome_encryptor.h"
 #include "chrome/browser/sync/glue/device_info.h"
@@ -56,11 +53,14 @@
 #include "sync/internal_api/public/sync_manager_factory.h"
 #include "sync/internal_api/public/util/experiments.h"
 #include "sync/internal_api/public/util/sync_string_conversions.h"
-#include "sync/notifier/invalidator.h"
 #include "sync/protocol/encryption.pb.h"
 #include "sync/protocol/sync.pb.h"
 #include "sync/util/nigori.h"
 
+#if defined(ENABLE_MANAGED_USERS)
+#include "chrome/browser/managed_mode/managed_user_service.h"
+#endif
+
 static const int kSaveChangesIntervalSeconds = 10;
 static const base::FilePath::CharType kSyncDataFolderName[] =
     FILE_PATH_LITERAL("Sync Data");
@@ -85,9 +85,9 @@
   DoConfigureSyncerTypes() {}
   ~DoConfigureSyncerTypes() {}
   syncer::ModelTypeSet to_download;
+  syncer::ModelTypeSet to_purge;
   syncer::ModelTypeSet to_journal;
   syncer::ModelTypeSet to_unapply;
-  syncer::ModelTypeSet to_ignore;
 };
 
 }  // namespace
@@ -102,8 +102,7 @@
 class SyncBackendHost::Core
     : public base::RefCountedThreadSafe<SyncBackendHost::Core>,
       public syncer::SyncEncryptionHandler::Observer,
-      public syncer::SyncManager::Observer,
-      public syncer::InvalidationHandler {
+      public syncer::SyncManager::Observer {
  public:
   Core(const std::string& name,
        const base::FilePath& sync_data_folder_path,
@@ -144,11 +143,12 @@
   virtual void OnPassphraseTypeChanged(syncer::PassphraseType type,
                                        base::Time passphrase_time) OVERRIDE;
 
-  // syncer::InvalidationHandler implementation.
-  virtual void OnInvalidatorStateChange(
-      syncer::InvalidatorState state) OVERRIDE;
-  virtual void OnIncomingInvalidation(
-      const syncer::ObjectIdInvalidationMap& invalidation_map) OVERRIDE;
+  // Forwards an invalidation state change to the sync manager.
+  void DoOnInvalidatorStateChange(syncer::InvalidatorState state);
+
+  // Forwards an invalidation to the sync manager.
+  void DoOnIncomingInvalidation(
+      syncer::ObjectIdInvalidationMap invalidation_map);
 
   // Note:
   //
@@ -165,15 +165,6 @@
   // SyncBackendHost::UpdateCredentials.
   void DoUpdateCredentials(const syncer::SyncCredentials& credentials);
 
-  // Called to update the given registered ids on behalf of
-  // SyncBackendHost::UpdateRegisteredInvalidationIds.
-  void DoUpdateRegisteredInvalidationIds(const syncer::ObjectIdSet& ids);
-
-  // Called to acknowledge an invalidation on behalf of
-  // SyncBackendHost::AcknowledgeInvalidation.
-  void DoAcknowledgeInvalidation(const invalidation::ObjectId& id,
-                                 const syncer::AckHandle& ack_handle);
-
   // Called to tell the syncapi to start syncing (generally after
   // initialization and authentication).
   void DoStartSyncing(const syncer::ModelSafeRoutingInfo& routing_info);
@@ -304,69 +295,13 @@
   // The top-level syncapi entry point.  Lives on the sync thread.
   scoped_ptr<syncer::SyncManager> sync_manager_;
 
-  // Whether or not we registered with |sync_manager_| as an invalidation
-  // handler.  Necessary since we may end up trying to unregister before we
-  // register in tests (in synchronous initialization mode).
-  //
-  // TODO(akalin): Fix this behavior (see http://crbug.com/140354).
-  bool registered_as_invalidation_handler_;
-
   DISALLOW_COPY_AND_ASSIGN(Core);
 };
 
-namespace {
-
-// Parses the given command line for notifier options.
-notifier::NotifierOptions ParseNotifierOptions(
-    const CommandLine& command_line,
-    const scoped_refptr<net::URLRequestContextGetter>&
-        request_context_getter) {
-  notifier::NotifierOptions notifier_options;
-  notifier_options.request_context_getter = request_context_getter;
-  if (!command_line.HasSwitch(switches::kSyncDisableOAuth2Token))
-    notifier_options.auth_mechanism = "X-OAUTH2";
-
-  if (command_line.HasSwitch(switches::kSyncNotificationHostPort)) {
-    notifier_options.xmpp_host_port =
-        net::HostPortPair::FromString(
-            command_line.GetSwitchValueASCII(
-                switches::kSyncNotificationHostPort));
-    DVLOG(1) << "Using " << notifier_options.xmpp_host_port.ToString()
-             << " for test sync notification server.";
-  }
-
-  notifier_options.try_ssltcp_first =
-      command_line.HasSwitch(switches::kSyncTrySsltcpFirstForXmpp);
-  DVLOG_IF(1, notifier_options.try_ssltcp_first)
-      << "Trying SSL/TCP port before XMPP port for notifications.";
-
-  notifier_options.invalidate_xmpp_login =
-      command_line.HasSwitch(switches::kSyncInvalidateXmppLogin);
-  DVLOG_IF(1, notifier_options.invalidate_xmpp_login)
-      << "Invalidating sync XMPP login.";
-
-  notifier_options.allow_insecure_connection =
-      command_line.HasSwitch(switches::kSyncAllowInsecureXmppConnection);
-  DVLOG_IF(1, notifier_options.allow_insecure_connection)
-      << "Allowing insecure XMPP connections.";
-
-  if (command_line.HasSwitch(switches::kSyncNotificationMethod)) {
-    const std::string notification_method_str(
-        command_line.GetSwitchValueASCII(switches::kSyncNotificationMethod));
-    notifier_options.notification_method =
-        notifier::StringToNotificationMethod(notification_method_str);
-  }
-
-  return notifier_options;
-}
-
-}  // namespace
-
 SyncBackendHost::SyncBackendHost(
     const std::string& name,
     Profile* profile,
-    const base::WeakPtr<SyncPrefs>& sync_prefs,
-    const base::WeakPtr<invalidation::InvalidatorStorage>& invalidator_storage)
+    const base::WeakPtr<SyncPrefs>& sync_prefs)
     : weak_ptr_factory_(this),
       sync_thread_("Chrome_SyncThread"),
       frontend_loop_(base::MessageLoop::current()),
@@ -376,13 +311,10 @@
                      weak_ptr_factory_.GetWeakPtr())),
       initialization_state_(NOT_ATTEMPTED),
       sync_prefs_(sync_prefs),
-      invalidator_factory_(
-          ParseNotifierOptions(*CommandLine::ForCurrentProcess(),
-                               profile_->GetRequestContext()),
-          content::GetUserAgent(GURL()),
-          invalidator_storage),
       frontend_(NULL),
-      cached_passphrase_type_(syncer::IMPLICIT_PASSPHRASE) {
+      cached_passphrase_type_(syncer::IMPLICIT_PASSPHRASE),
+      invalidator_(
+          invalidation::InvalidationServiceFactory::GetForProfile(profile)) {
 }
 
 SyncBackendHost::SyncBackendHost(Profile* profile)
@@ -392,18 +324,12 @@
       profile_(profile),
       name_("Unknown"),
       initialization_state_(NOT_ATTEMPTED),
-      invalidator_factory_(
-          ParseNotifierOptions(*CommandLine::ForCurrentProcess(),
-                               profile_->GetRequestContext()),
-          content::GetUserAgent(GURL()),
-          base::WeakPtr<syncer::InvalidationStateTracker>()),
       frontend_(NULL),
       cached_passphrase_type_(syncer::IMPLICIT_PASSPHRASE) {
 }
 
 SyncBackendHost::~SyncBackendHost() {
   DCHECK(!core_.get() && !frontend_) << "Must call Shutdown before destructor.";
-  DCHECK(!android_invalidator_bridge_.get());
   DCHECK(!registrar_.get());
 }
 
@@ -435,10 +361,6 @@
   if (!sync_thread_.Start())
     return;
 
-  android_invalidator_bridge_.reset(
-      new AndroidInvalidatorBridge(
-          profile_, sync_thread_.message_loop_proxy()));
-
   frontend_ = frontend;
   DCHECK(frontend);
 
@@ -461,6 +383,8 @@
         InternalComponentsFactoryImpl::BACKOFF_SHORT_INITIAL_RETRY_OVERRIDE;
   }
 
+  invalidator_->RegisterInvalidationHandler(this);
+
   initialization_state_ = CREATING_SYNC_MANAGER;
   InitCore(DoInitializeOptions(
       sync_thread_.message_loop(),
@@ -474,8 +398,7 @@
                  make_scoped_refptr(profile_->GetRequestContext()),
                  NetworkTimeTracker::BuildNotifierUpdateCallback()),
       credentials,
-      android_invalidator_bridge_.get(),
-      &invalidator_factory_,
+      invalidator_->GetInvalidatorClientId(),
       sync_manager_factory,
       delete_sync_data_folder,
       sync_prefs_->GetEncryptionBootstrapToken(),
@@ -493,24 +416,6 @@
                  credentials));
 }
 
-void SyncBackendHost::UpdateRegisteredInvalidationIds(
-    const syncer::ObjectIdSet& ids) {
-  DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
-  DCHECK(sync_thread_.IsRunning());
-  sync_thread_.message_loop()->PostTask(FROM_HERE,
-      base::Bind(&SyncBackendHost::Core::DoUpdateRegisteredInvalidationIds,
-                 core_.get(), ids));
-}
-
-void SyncBackendHost::AcknowledgeInvalidation(
-    const invalidation::ObjectId& id, const syncer::AckHandle& ack_handle) {
-  DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
-  DCHECK(sync_thread_.IsRunning());
-  sync_thread_.message_loop()->PostTask(FROM_HERE,
-      base::Bind(&SyncBackendHost::Core::DoAcknowledgeInvalidation,
-                 core_.get(), id, ack_handle));
-}
-
 void SyncBackendHost::StartSyncingWithServer() {
   SDVLOG(1) << "SyncBackendHost::StartSyncingWithServer called.";
 
@@ -654,14 +559,17 @@
   // StopSyncingForShutdown() (which nulls out |frontend_|) should be
   // called first.
   DCHECK(!frontend_);
+
+  if (sync_disabled)
+    invalidator_->UpdateRegisteredInvalidationIds(this, syncer::ObjectIdSet());
+  invalidator_->UnregisterInvalidationHandler(this);
+  invalidator_ = NULL;
+
   // TODO(tim): DCHECK(registrar_->StoppedOnUIThread()) would be nice.
   if (sync_thread_.IsRunning()) {
     sync_thread_.message_loop()->PostTask(FROM_HERE,
         base::Bind(&SyncBackendHost::Core::DoShutdown, core_.get(),
                    sync_disabled));
-
-    if (android_invalidator_bridge_)
-      android_invalidator_bridge_->StopForShutdown();
   }
 
   // Stop will return once the thread exits, which will be after DoShutdown
@@ -687,7 +595,6 @@
 
   registrar_.reset();
   js_backend_.Reset();
-  android_invalidator_bridge_.reset();
   core_ = NULL;  // Releases reference to core_.
 }
 
@@ -720,6 +627,8 @@
   // backend because configuration requests are never aborted; they are retried
   // until they succeed or the backend is shut down.
 
+  syncer::ModelTypeSet previous_types = registrar_->GetLastConfiguredTypes();
+
   syncer::ModelTypeSet disabled_types =
       GetDataTypesInState(DISABLED, config_state_map);
   syncer::ModelTypeSet fatal_types =
@@ -728,11 +637,14 @@
       GetDataTypesInState(CRYPTO, config_state_map);
   disabled_types.PutAll(fatal_types);
   disabled_types.PutAll(crypto_types);
+  syncer::ModelTypeSet active_types =
+      GetDataTypesInState(CONFIGURE_ACTIVE, config_state_map);
+  syncer::ModelTypeSet clean_first_types =
+      GetDataTypesInState(CONFIGURE_CLEAN, config_state_map);
   syncer::ModelTypeSet types_to_download = registrar_->ConfigureDataTypes(
-      GetDataTypesInState(CONFIGURE_ACTIVE, config_state_map),
+      syncer::Union(active_types, clean_first_types),
       disabled_types);
-  syncer::ModelTypeSet inactive_types =
-      GetDataTypesInState(CONFIGURE_INACTIVE, config_state_map);
+  types_to_download.PutAll(clean_first_types);
   types_to_download.RemoveAll(syncer::ProxyTypes());
   if (!types_to_download.Empty())
     types_to_download.Put(syncer::NIGORI);
@@ -762,6 +674,17 @@
   syncer::ModelSafeRoutingInfo routing_info;
   registrar_->GetModelSafeRoutingInfo(&routing_info);
 
+  syncer::ModelTypeSet current_types = registrar_->GetLastConfiguredTypes();
+  syncer::ModelTypeSet types_to_purge =
+      syncer::Difference(previous_types, current_types);
+  syncer::ModelTypeSet inactive_types =
+      GetDataTypesInState(CONFIGURE_INACTIVE, config_state_map);
+  types_to_purge.RemoveAll(inactive_types);
+
+  DCHECK(syncer::Intersection(current_types, fatal_types).Empty());
+  DCHECK(syncer::Intersection(current_types, crypto_types).Empty());
+  DCHECK(current_types.HasAll(types_to_download));
+
   SDVLOG(1) << "Types "
             << syncer::ModelTypeSetToString(types_to_download)
             << " added; calling DoConfigureSyncer";
@@ -779,8 +702,9 @@
   //   touched.
   RequestConfigureSyncer(reason,
                          types_to_download,
+                         types_to_purge,
                          fatal_types,
-                         crypto_types,
+                         syncer::Union(crypto_types, clean_first_types),
                          inactive_types,
                          routing_info,
                          ready_task,
@@ -862,6 +786,7 @@
 void SyncBackendHost::RequestConfigureSyncer(
     syncer::ConfigureReason reason,
     syncer::ModelTypeSet to_download,
+    syncer::ModelTypeSet to_purge,
     syncer::ModelTypeSet to_journal,
     syncer::ModelTypeSet to_unapply,
     syncer::ModelTypeSet to_ignore,
@@ -871,9 +796,9 @@
     const base::Closure& retry_callback) {
   DoConfigureSyncerTypes config_types;
   config_types.to_download = to_download;
+  config_types.to_purge = to_purge;
   config_types.to_journal = to_journal;
   config_types.to_unapply = to_unapply;
-  config_types.to_ignore = to_ignore;
   sync_thread_.message_loop()->PostTask(FROM_HERE,
        base::Bind(&SyncBackendHost::Core::DoConfigureSyncer,
                   core_.get(),
@@ -885,13 +810,18 @@
 }
 
 void SyncBackendHost::FinishConfigureDataTypesOnFrontendLoop(
+    const syncer::ModelTypeSet enabled_types,
     const syncer::ModelTypeSet succeeded_configuration_types,
     const syncer::ModelTypeSet failed_configuration_types,
     const base::Callback<void(syncer::ModelTypeSet,
                               syncer::ModelTypeSet)>& ready_task) {
   if (!frontend_)
     return;
-  DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
+
+  invalidator_->UpdateRegisteredInvalidationIds(
+      this,
+      ModelTypeSetToObjectIdSet(enabled_types));
+
   if (!ready_task.is_null())
     ready_task.Run(succeeded_configuration_types, failed_configuration_types);
 }
@@ -922,6 +852,10 @@
        syncer::CONFIGURE_REASON_NEWLY_ENABLED_DATA_TYPE :
        syncer::CONFIGURE_REASON_NEW_CLIENT);
 
+  // Fake a state change to initialize the SyncManager's cached invalidator
+  // state.
+  OnInvalidatorStateChange(invalidator_->GetInvalidatorState());
+
   // Kick off the next step in SyncBackendHost initialization by downloading
   // any necessary control types.
   sync_thread_.message_loop()->PostTask(
@@ -958,8 +892,7 @@
     const GURL& service_url,
     MakeHttpBridgeFactoryFn make_http_bridge_factory_fn,
     const syncer::SyncCredentials& credentials,
-    AndroidInvalidatorBridge* android_invalidator_bridge,
-    syncer::InvalidatorFactory* invalidator_factory,
+    const std::string& invalidator_client_id,
     syncer::SyncManagerFactory* sync_manager_factory,
     bool delete_sync_data_folder,
     const std::string& restored_key_for_bootstrapping,
@@ -978,8 +911,7 @@
       service_url(service_url),
       make_http_bridge_factory_fn(make_http_bridge_factory_fn),
       credentials(credentials),
-      android_invalidator_bridge(android_invalidator_bridge),
-      invalidator_factory(invalidator_factory),
+      invalidator_client_id(invalidator_client_id),
       sync_manager_factory(sync_manager_factory),
       delete_sync_data_folder(delete_sync_data_folder),
       restored_key_for_bootstrapping(restored_key_for_bootstrapping),
@@ -1001,8 +933,7 @@
       sync_data_folder_path_(sync_data_folder_path),
       host_(backend),
       sync_loop_(NULL),
-      registrar_(NULL),
-      registered_as_invalidation_handler_(false) {
+      registrar_(NULL) {
   DCHECK(backend.get());
 }
 
@@ -1033,10 +964,14 @@
             << syncer::ModelTypeSetToString(new_control_types)
             << " added; calling ConfigureSyncer";
 
+  syncer::ModelTypeSet types_to_purge =
+      syncer::Difference(syncer::ModelTypeSet::All(),
+                         GetRoutingInfoTypes(routing_info));
+
   sync_manager_->ConfigureSyncer(
       reason,
       new_control_types,
-      syncer::ModelTypeSet(),
+      types_to_purge,
       syncer::ModelTypeSet(),
       syncer::ModelTypeSet(),
       routing_info,
@@ -1197,24 +1132,16 @@
       sync_error);
 }
 
-void SyncBackendHost::Core::OnInvalidatorStateChange(
+void SyncBackendHost::Core::DoOnInvalidatorStateChange(
     syncer::InvalidatorState state) {
-  if (!sync_loop_)
-    return;
   DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
-  host_.Call(FROM_HERE,
-             &SyncBackendHost::HandleInvalidatorStateChangeOnFrontendLoop,
-             state);
+  sync_manager_->OnInvalidatorStateChange(state);
 }
 
-void SyncBackendHost::Core::OnIncomingInvalidation(
-    const syncer::ObjectIdInvalidationMap& invalidation_map) {
-  if (!sync_loop_)
-    return;
+void SyncBackendHost::Core::DoOnIncomingInvalidation(
+    syncer::ObjectIdInvalidationMap invalidation_map) {
   DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
-  host_.Call(FROM_HERE,
-             &SyncBackendHost::HandleIncomingInvalidationOnFrontendLoop,
-             invalidation_map);
+  sync_manager_->OnIncomingInvalidation(invalidation_map);
 }
 
 void SyncBackendHost::Core::DoInitialize(const DoInitializeOptions& options) {
@@ -1240,43 +1167,31 @@
 
   sync_manager_ = options.sync_manager_factory->CreateSyncManager(name_);
   sync_manager_->AddObserver(this);
-  sync_manager_->Init(
-      sync_data_folder_path_,
-      options.event_handler,
-      options.service_url.host() + options.service_url.path(),
-      options.service_url.EffectiveIntPort(),
-      options.service_url.SchemeIsSecure(),
-      options.make_http_bridge_factory_fn.Run().Pass(),
-      options.workers,
-      options.extensions_activity_monitor,
-      options.registrar /* as SyncManager::ChangeDelegate */,
-      options.credentials,
-#if defined(OS_ANDROID)
-      scoped_ptr<syncer::Invalidator>(
-          new AndroidInvalidatorBridgeProxy(
-              options.android_invalidator_bridge)),
-#else
-      scoped_ptr<syncer::Invalidator>(
-          options.invalidator_factory->CreateInvalidator()),
-#endif
-      options.invalidator_factory->GetInvalidatorClientId(),
-      options.restored_key_for_bootstrapping,
-      options.restored_keystore_key_for_bootstrapping,
-      scoped_ptr<InternalComponentsFactory>(
-          options.internal_components_factory),
-      &encryptor_,
-      options.unrecoverable_error_handler,
-      options.report_unrecoverable_error_function,
-      options.use_oauth2_token);
+  sync_manager_->Init(sync_data_folder_path_,
+                      options.event_handler,
+                      options.service_url.host() + options.service_url.path(),
+                      options.service_url.EffectiveIntPort(),
+                      options.service_url.SchemeIsSecure(),
+                      options.make_http_bridge_factory_fn.Run().Pass(),
+                      options.workers,
+                      options.extensions_activity_monitor,
+                      options.registrar /* as SyncManager::ChangeDelegate */,
+                      options.credentials,
+                      options.invalidator_client_id,
+                      options.restored_key_for_bootstrapping,
+                      options.restored_keystore_key_for_bootstrapping,
+                      scoped_ptr<InternalComponentsFactory>(
+                          options.internal_components_factory),
+                      &encryptor_,
+                      options.unrecoverable_error_handler,
+                      options.report_unrecoverable_error_function,
+                      options.use_oauth2_token);
 
   // |sync_manager_| may end up being NULL here in tests (in
   // synchronous initialization mode).
   //
   // TODO(akalin): Fix this behavior (see http://crbug.com/140354).
   if (sync_manager_) {
-    sync_manager_->RegisterInvalidationHandler(this);
-    registered_as_invalidation_handler_ = true;
-
     // Now check the command line to see if we need to simulate an
     // unrecoverable error for testing purpose. Note the error is thrown
     // only if the initialization succeeded. Also it makes sense to use this
@@ -1302,31 +1217,6 @@
   }
 }
 
-void SyncBackendHost::Core::DoUpdateRegisteredInvalidationIds(
-    const syncer::ObjectIdSet& ids) {
-  DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
-  // |sync_manager_| may end up being NULL here in tests (in
-  // synchronous initialization mode) since this is called during
-  // shutdown.
-  //
-  // TODO(akalin): Fix this behavior (see http://crbug.com/140354).
-  if (sync_manager_) {
-    sync_manager_->UpdateRegisteredInvalidationIds(this, ids);
-  }
-}
-
-void SyncBackendHost::Core::DoAcknowledgeInvalidation(
-    const invalidation::ObjectId& id, const syncer::AckHandle& ack_handle) {
-  DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
-  // |sync_manager_| may end up being NULL here in tests (in
-  // synchronous initialization mode).
-  //
-  // TODO(akalin): Fix this behavior (see http://crbug.com/140354).
-  if (sync_manager_) {
-    sync_manager_->AcknowledgeInvalidation(id, ack_handle);
-  }
-}
-
 void SyncBackendHost::Core::DoStartSyncing(
     const syncer::ModelSafeRoutingInfo& routing_info) {
   DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
@@ -1436,10 +1326,6 @@
   DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
   if (sync_manager_) {
     save_changes_timer_.reset();
-    if (registered_as_invalidation_handler_) {
-      sync_manager_->UnregisterInvalidationHandler(this);
-      registered_as_invalidation_handler_ = false;
-    }
     sync_manager_->RemoveObserver(this);
     sync_manager_->ShutdownOnSyncThread();
     sync_manager_.reset();
@@ -1457,9 +1343,9 @@
   sync_manager_->ConfigureSyncer(
       reason,
       config_types.to_download,
+      config_types.to_purge,
       config_types.to_journal,
       config_types.to_unapply,
-      config_types.to_ignore,
       routing_info,
       base::Bind(&SyncBackendHost::Core::DoFinishConfigureDataTypes,
                  this,
@@ -1481,7 +1367,6 @@
   registrar_->GetModelSafeRoutingInfo(&routing_info);
   syncer::ModelTypeSet enabled_types = GetRoutingInfoTypes(routing_info);
   enabled_types.RemoveAll(syncer::ProxyTypes());
-  sync_manager_->UpdateEnabledTypes(enabled_types);
 
   const syncer::ModelTypeSet failed_configuration_types =
       Difference(types_to_config, sync_manager_->InitialSyncEndedTypes());
@@ -1489,7 +1374,9 @@
       Difference(types_to_config, failed_configuration_types);
   host_.Call(FROM_HERE,
              &SyncBackendHost::FinishConfigureDataTypesOnFrontendLoop,
-             succeeded_configuration_types, failed_configuration_types,
+             enabled_types,
+             succeeded_configuration_types,
+             failed_configuration_types,
              ready_task);
 }
 
@@ -1504,7 +1391,7 @@
 void SyncBackendHost::Core::DeleteSyncDataFolder() {
   DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
   if (file_util::DirectoryExists(sync_data_folder_path_)) {
-    if (!file_util::Delete(sync_data_folder_path_, true))
+    if (!base::Delete(sync_data_folder_path_, true))
       SLOG(DFATAL) << "Could not delete the Sync Data folder.";
   }
 }
@@ -1619,20 +1506,30 @@
   frontend_->OnActionableError(sync_error);
 }
 
-void SyncBackendHost::HandleInvalidatorStateChangeOnFrontendLoop(
-    syncer::InvalidatorState state) {
-  if (!frontend_)
-    return;
-  DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
-  frontend_->OnInvalidatorStateChange(state);
+void SyncBackendHost::OnInvalidatorStateChange(syncer::InvalidatorState state) {
+  sync_thread_.message_loop()->PostTask(
+      FROM_HERE,
+      base::Bind(&SyncBackendHost::Core::DoOnInvalidatorStateChange,
+                 core_.get(),
+                 state));
 }
 
-void SyncBackendHost::HandleIncomingInvalidationOnFrontendLoop(
+void SyncBackendHost::OnIncomingInvalidation(
     const syncer::ObjectIdInvalidationMap& invalidation_map) {
-  if (!frontend_)
-    return;
-  DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
-  frontend_->OnIncomingInvalidation(invalidation_map);
+  // TODO(dcheng): Acknowledge immediately for now. Fix this once the
+  // invalidator doesn't repeatedly ping for unacknowledged invaliations, since
+  // it conflicts with the sync scheduler's internal backoff algorithm.
+  // See http://crbug.com/124149 for more information.
+  for (syncer::ObjectIdInvalidationMap::const_iterator it =
+       invalidation_map.begin(); it != invalidation_map.end(); ++it) {
+    invalidator_->AcknowledgeInvalidation(it->first, it->second.ack_handle);
+  }
+
+  sync_thread_.message_loop()->PostTask(
+      FROM_HERE,
+      base::Bind(&SyncBackendHost::Core::DoOnIncomingInvalidation,
+                 core_.get(),
+                 invalidation_map));
 }
 
 bool SyncBackendHost::CheckPassphraseAgainstCachedPendingKeys(
diff --git a/chrome/browser/sync/glue/sync_backend_host.h b/chrome/browser/sync/glue/sync_backend_host.h
index fa5a46c..7b054a8 100644
--- a/chrome/browser/sync/glue/sync_backend_host.h
+++ b/chrome/browser/sync/glue/sync_backend_host.h
@@ -14,12 +14,12 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/threading/thread.h"
+#include "chrome/browser/invalidation/invalidation_service.h"
 #include "chrome/browser/sync/glue/backend_data_type_configurer.h"
 #include "chrome/browser/sync/glue/chrome_extensions_activity_monitor.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
 #include "google_apis/gaia/google_service_auth_error.h"
-#include "googleurl/src/gurl.h"
 #include "sync/internal_api/public/base/model_type.h"
 #include "sync/internal_api/public/configure_reason.h"
 #include "sync/internal_api/public/engine/model_safe_worker.h"
@@ -30,9 +30,9 @@
 #include "sync/internal_api/public/util/unrecoverable_error_handler.h"
 #include "sync/internal_api/public/util/weak_handle.h"
 #include "sync/notifier/invalidation_handler.h"
-#include "sync/notifier/invalidator_factory.h"
 #include "sync/protocol/encryption.pb.h"
 #include "sync/protocol/sync_protocol_error.h"
+#include "url/gurl.h"
 
 class Profile;
 
@@ -44,14 +44,10 @@
 class SyncManagerFactory;
 }
 
-namespace invalidation {
-class InvalidatorStorage;
-}
-
 namespace browser_sync {
 
-class AndroidInvalidatorBridge;
 class ChangeProcessor;
+class InvalidatorStorage;
 class SyncBackendRegistrar;
 class SyncPrefs;
 class SyncedDeviceTracker;
@@ -62,7 +58,7 @@
 // activity.
 // NOTE: All methods will be invoked by a SyncBackendHost on the same thread
 // used to create that SyncBackendHost.
-class SyncFrontend : public syncer::InvalidationHandler {
+class SyncFrontend {
  public:
   SyncFrontend() {}
 
@@ -153,7 +149,8 @@
 // that the SyncFrontend is only accessed on the UI loop.
 class SyncBackendHost
     : public BackendDataTypeConfigurer,
-      public content::NotificationObserver {
+      public content::NotificationObserver,
+      public syncer::InvalidationHandler {
  public:
   typedef syncer::SyncStatus Status;
 
@@ -164,10 +161,7 @@
   SyncBackendHost(
       const std::string& name,
       Profile* profile,
-      const base::WeakPtr<SyncPrefs>& sync_prefs,
-      // TODO(tim): Temporary, remove when bug 124137 finished.
-      const base::WeakPtr<invalidation::InvalidatorStorage>&
-          invalidator_storage);
+      const base::WeakPtr<SyncPrefs>& sync_prefs);
 
   // For testing.
   // TODO(skrul): Extract an interface so this is not needed.
@@ -194,14 +188,6 @@
   // Called on |frontend_loop| to update SyncCredentials.
   virtual void UpdateCredentials(const syncer::SyncCredentials& credentials);
 
-  // Registers the underlying frontend for the given IDs to the underlying
-  // notifier.  This lasts until StopSyncingForShutdown() is called.
-  void UpdateRegisteredInvalidationIds(const syncer::ObjectIdSet& ids);
-
-  // Forwards an invalidation acknowledgement to the underlying notifier.
-  void AcknowledgeInvalidation(const invalidation::ObjectId& id,
-                               const syncer::AckHandle& ack_handle);
-
   // This starts the SyncerThread running a Syncer object to communicate with
   // sync servers.  Until this is called, no changes will leave or enter this
   // browser from the cloud / sync servers.
@@ -325,8 +311,7 @@
         const GURL& service_url,
         MakeHttpBridgeFactoryFn make_http_bridge_factory_fn,
         const syncer::SyncCredentials& credentials,
-        AndroidInvalidatorBridge* android_invalidator_bridge,
-        syncer::InvalidatorFactory* invalidator_factory,
+        const std::string& invalidator_client_id,
         syncer::SyncManagerFactory* sync_manager_factory,
         bool delete_sync_data_folder,
         const std::string& restored_key_for_bootstrapping,
@@ -348,8 +333,7 @@
     // Overridden by tests.
     MakeHttpBridgeFactoryFn make_http_bridge_factory_fn;
     syncer::SyncCredentials credentials;
-    AndroidInvalidatorBridge* const android_invalidator_bridge;
-    syncer::InvalidatorFactory* const invalidator_factory;
+    const std::string invalidator_client_id;
     syncer::SyncManagerFactory* const sync_manager_factory;
     std::string lsid;
     bool delete_sync_data_folder;
@@ -370,6 +354,7 @@
   virtual void RequestConfigureSyncer(
       syncer::ConfigureReason reason,
       syncer::ModelTypeSet to_download,
+      syncer::ModelTypeSet to_purge,
       syncer::ModelTypeSet to_journal,
       syncer::ModelTypeSet to_unapply,
       syncer::ModelTypeSet to_ignore,
@@ -380,6 +365,7 @@
 
   // Called when the syncer has finished performing a configuration.
   void FinishConfigureDataTypesOnFrontendLoop(
+      const syncer::ModelTypeSet enabled_types,
       const syncer::ModelTypeSet succeeded_configuration_types,
       const syncer::ModelTypeSet failed_configuration_types,
       const base::Callback<void(syncer::ModelTypeSet,
@@ -512,6 +498,12 @@
     const content::NotificationSource& source,
     const content::NotificationDetails& details) OVERRIDE;
 
+  // InvalidationHandler implementation.
+  virtual void OnInvalidatorStateChange(
+      syncer::InvalidatorState state) OVERRIDE;
+  virtual void OnIncomingInvalidation(
+      const syncer::ObjectIdInvalidationMap& invalidation_map) OVERRIDE;
+
   // Handles stopping the core's SyncManager, accounting for whether
   // initialization is done yet.
   void StopSyncManagerForShutdown(const base::Closure& closure);
@@ -539,10 +531,6 @@
 
   const base::WeakPtr<SyncPrefs> sync_prefs_;
 
-  scoped_ptr<AndroidInvalidatorBridge> android_invalidator_bridge_;
-
-  syncer::InvalidatorFactory invalidator_factory_;
-
   ChromeExtensionsActivityMonitor extensions_activity_monitor_;
 
   scoped_ptr<SyncBackendRegistrar> registrar_;
@@ -580,6 +568,8 @@
   syncer::WeakHandle<syncer::JsBackend> js_backend_;
   syncer::WeakHandle<syncer::DataTypeDebugInfoListener> debug_info_listener_;
 
+  invalidation::InvalidationService* invalidator_;
+
   DISALLOW_COPY_AND_ASSIGN(SyncBackendHost);
 };
 
diff --git a/chrome/browser/sync/glue/sync_backend_host_unittest.cc b/chrome/browser/sync/glue/sync_backend_host_unittest.cc
index da3cc97..9f8542b 100644
--- a/chrome/browser/sync/glue/sync_backend_host_unittest.cc
+++ b/chrome/browser/sync/glue/sync_backend_host_unittest.cc
@@ -22,7 +22,6 @@
 #include "content/public/browser/notification_service.h"
 #include "content/public/test/test_browser_thread.h"
 #include "google/cacheinvalidation/include/types.h"
-#include "googleurl/src/gurl.h"
 #include "net/url_request/test_url_fetcher_factory.h"
 #include "sync/internal_api/public/base/model_type.h"
 #include "sync/internal_api/public/engine/model_safe_worker.h"
@@ -36,6 +35,7 @@
 #include "sync/util/test_unrecoverable_error_handler.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
 
 using content::BrowserThread;
 using syncer::FakeSyncManager;
@@ -146,13 +146,10 @@
     profile_.reset(new TestingProfile());
     profile_->CreateRequestContext();
     sync_prefs_.reset(new SyncPrefs(profile_->GetPrefs()));
-    invalidator_storage_.reset(new invalidation::InvalidatorStorage(
-        profile_->GetPrefs()));
     backend_.reset(new SyncBackendHost(
         profile_->GetDebugName(),
         profile_.get(),
-        sync_prefs_->AsWeakPtr(),
-        invalidator_storage_->AsWeakPtr()));
+        sync_prefs_->AsWeakPtr()));
     credentials_.email = "user@example.com";
     credentials_.sync_token = "sync_token";
 
@@ -178,7 +175,6 @@
     }
     backend_.reset();
     sync_prefs_.reset();
-    invalidator_storage_.reset();
     profile_.reset();
     // Pump messages posted by the sync thread (which may end up
     // posting on the IO thread).
@@ -266,7 +262,6 @@
   syncer::TestUnrecoverableErrorHandler handler_;
   scoped_ptr<TestingProfile> profile_;
   scoped_ptr<SyncPrefs> sync_prefs_;
-  scoped_ptr<invalidation::InvalidatorStorage> invalidator_storage_;
   scoped_ptr<SyncBackendHost> backend_;
   FakeSyncManager* fake_manager_;
   FakeSyncManagerFactory fake_manager_factory_;
@@ -594,76 +589,6 @@
       enabled_types_).Empty());
 }
 
-// Register for some IDs and trigger an invalidation.  This should
-// propagate all the way to the frontend.
-TEST_F(SyncBackendHostTest, Invalidate) {
-  InitializeBackend(true);
-
-  syncer::ObjectIdSet ids;
-  ids.insert(invalidation::ObjectId(1, "id1"));
-  ids.insert(invalidation::ObjectId(2, "id2"));
-  const syncer::ObjectIdInvalidationMap& invalidation_map =
-      syncer::ObjectIdSetToInvalidationMap(ids, "payload");
-
-  EXPECT_CALL(
-      mock_frontend_,
-      OnIncomingInvalidation(invalidation_map))
-      .WillOnce(InvokeWithoutArgs(QuitMessageLoop));
-
-  backend_->UpdateRegisteredInvalidationIds(ids);
-  fake_manager_->Invalidate(invalidation_map);
-  ui_loop_.PostDelayedTask(
-      FROM_HERE, ui_loop_.QuitClosure(), TestTimeouts::action_timeout());
-  ui_loop_.Run();
-}
-
-// Register for some IDs and update the invalidator state.  This
-// should propagate all the way to the frontend.
-TEST_F(SyncBackendHostTest, UpdateInvalidatorState) {
-  InitializeBackend(true);
-
-  EXPECT_CALL(mock_frontend_,
-              OnInvalidatorStateChange(syncer::INVALIDATIONS_ENABLED))
-      .WillOnce(InvokeWithoutArgs(QuitMessageLoop));
-
-  syncer::ObjectIdSet ids;
-  ids.insert(invalidation::ObjectId(3, "id3"));
-  backend_->UpdateRegisteredInvalidationIds(ids);
-  fake_manager_->UpdateInvalidatorState(syncer::INVALIDATIONS_ENABLED);
-  ui_loop_.PostDelayedTask(
-      FROM_HERE, ui_loop_.QuitClosure(), TestTimeouts::action_timeout());
-  ui_loop_.Run();
-}
-
-// Call StopSyncingForShutdown() on the backend and fire some invalidations
-// before calling Shutdown().  Then start up and shut down the backend again.
-// Those notifications shouldn't propagate to the frontend.
-TEST_F(SyncBackendHostTest, InvalidationsAfterStopSyncingForShutdown) {
-  InitializeBackend(true);
-
-  syncer::ObjectIdSet ids;
-  ids.insert(invalidation::ObjectId(5, "id5"));
-  backend_->UpdateRegisteredInvalidationIds(ids);
-
-  backend_->StopSyncingForShutdown();
-
-  // Should not trigger anything.
-  fake_manager_->UpdateInvalidatorState(syncer::TRANSIENT_INVALIDATION_ERROR);
-  fake_manager_->UpdateInvalidatorState(syncer::INVALIDATIONS_ENABLED);
-  const syncer::ObjectIdInvalidationMap& invalidation_map =
-      syncer::ObjectIdSetToInvalidationMap(ids, "payload");
-  fake_manager_->Invalidate(invalidation_map);
-
-  // Make sure the above calls take effect before we continue.
-  fake_manager_->WaitForSyncThread();
-
-  backend_->Shutdown(false);
-  backend_.reset();
-
-  TearDown();
-  SetUp();
-}
-
 // Ensure the device info tracker is initialized properly on startup.
 TEST_F(SyncBackendHostTest, InitializeDeviceInfo) {
   ASSERT_EQ(NULL, backend_->GetSyncedDeviceTracker());
@@ -691,8 +616,9 @@
   // any old types.
   InitializeBackend(true);
   EXPECT_TRUE(fake_manager_->GetAndResetDownloadedTypes().Equals(new_types));
-  EXPECT_TRUE(Intersection(fake_manager_->GetAndResetCleanedTypes(),
-                           enabled_types_).Empty());
+  EXPECT_TRUE(fake_manager_->GetAndResetCleanedTypes().Equals(
+                  Difference(syncer::ModelTypeSet::All(),
+                             enabled_types_)));
   EXPECT_TRUE(fake_manager_->InitialSyncEndedTypes().Equals(enabled_types_));
   EXPECT_TRUE(fake_manager_->GetTypesWithEmptyProgressMarkerToken(
       enabled_types_).Empty());
diff --git a/chrome/browser/sync/glue/sync_backend_registrar.cc b/chrome/browser/sync/glue/sync_backend_registrar.cc
index 5d99b0d..69898b1 100644
--- a/chrome/browser/sync/glue/sync_backend_registrar.cc
+++ b/chrome/browser/sync/glue/sync_backend_registrar.cc
@@ -85,6 +85,11 @@
   }
 }
 
+SyncBackendRegistrar::~SyncBackendRegistrar() {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  DCHECK(stopped_on_ui_thread_);
+}
+
 void SyncBackendRegistrar::SetInitialTypes(syncer::ModelTypeSet initial_types) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   base::AutoLock lock(lock_);
@@ -112,11 +117,8 @@
         << "Password store not initialized, cannot sync passwords";
     routing_info_.erase(syncer::PASSWORDS);
   }
-}
 
-SyncBackendRegistrar::~SyncBackendRegistrar() {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  DCHECK(stopped_on_ui_thread_);
+  last_configured_types_ = syncer::GetRoutingInfoTypes(routing_info_);
 }
 
 bool SyncBackendRegistrar::IsNigoriEnabled() const {
@@ -165,10 +167,15 @@
            << syncer::ModelTypeSetToString(types_to_remove)
            << " to get new routing info "
            <<syncer::ModelSafeRoutingInfoToString(routing_info_);
+  last_configured_types_ = syncer::GetRoutingInfoTypes(routing_info_);
 
   return newly_added_types;
 }
 
+syncer::ModelTypeSet SyncBackendRegistrar::GetLastConfiguredTypes() const {
+  return last_configured_types_;
+}
+
 void SyncBackendRegistrar::StopOnUIThread() {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   DCHECK(!stopped_on_ui_thread_);
diff --git a/chrome/browser/sync/glue/sync_backend_registrar.h b/chrome/browser/sync/glue/sync_backend_registrar.h
index 31b1310..f7ea1fb 100644
--- a/chrome/browser/sync/glue/sync_backend_registrar.h
+++ b/chrome/browser/sync/glue/sync_backend_registrar.h
@@ -43,11 +43,6 @@
                        Profile* profile,
                        base::MessageLoop* sync_loop);
 
-  // Informs the SyncBackendRegistrar of the currently enabled set of types.
-  // These types will be placed in the passive group.  This function should be
-  // called exactly once during startup.
-  void SetInitialTypes(syncer::ModelTypeSet initial_types);
-
   // SyncBackendRegistrar must be destroyed as follows:
   //
   //   1) On the sync thread, call OnSyncerShutdownComplete() after
@@ -61,6 +56,11 @@
   // thread which the syncer pushes changes to).
   virtual ~SyncBackendRegistrar();
 
+  // Informs the SyncBackendRegistrar of the currently enabled set of types.
+  // These types will be placed in the passive group.  This function should be
+  // called exactly once during startup.
+  void SetInitialTypes(syncer::ModelTypeSet initial_types);
+
   // Returns whether or not we are currently syncing encryption keys.
   // Must be called on the UI thread.
   bool IsNigoriEnabled() const;
@@ -74,6 +74,11 @@
       syncer::ModelTypeSet types_to_add,
       syncer::ModelTypeSet types_to_remove);
 
+  // Returns the set of enabled types as of the last configuration. Note that
+  // this might be different from the current types in the routing info due
+  // to DeactiveDataType being called separately from ConfigureDataTypes.
+  syncer::ModelTypeSet GetLastConfiguredTypes() const;
+
   // Must be called from the UI thread. (See destructor comment.)
   void StopOnUIThread();
 
@@ -160,6 +165,10 @@
   // The change processors that handle the different data types.
   std::map<syncer::ModelType, ChangeProcessor*> processors_;
 
+  // The types that were enabled as of the last configuration. Updated on each
+  // call to ConfigureDataTypes as well as SetInitialTypes.
+  syncer::ModelTypeSet last_configured_types_;
+
   DISALLOW_COPY_AND_ASSIGN(SyncBackendRegistrar);
 };
 
diff --git a/chrome/browser/sync/glue/sync_backend_registrar_unittest.cc b/chrome/browser/sync/glue/sync_backend_registrar_unittest.cc
index 3761067..979f9a5 100644
--- a/chrome/browser/sync/glue/sync_backend_registrar_unittest.cc
+++ b/chrome/browser/sync/glue/sync_backend_registrar_unittest.cc
@@ -128,6 +128,7 @@
     ExpectRoutingInfo(&registrar, expected_routing_info);
   }
   ExpectHasProcessorsForTypes(registrar, ModelTypeSet());
+  EXPECT_TRUE(types1.Equals(registrar.GetLastConfiguredTypes()));
 
   // Add and remove.
   const ModelTypeSet types2(PREFERENCES, THEMES);
@@ -139,11 +140,13 @@
     ExpectRoutingInfo(&registrar, expected_routing_info);
   }
   ExpectHasProcessorsForTypes(registrar, ModelTypeSet());
+  EXPECT_TRUE(types2.Equals(registrar.GetLastConfiguredTypes()));
 
   // Remove.
   EXPECT_TRUE(registrar.ConfigureDataTypes(ModelTypeSet(), types2).Empty());
   ExpectRoutingInfo(&registrar, syncer::ModelSafeRoutingInfo());
   ExpectHasProcessorsForTypes(registrar, ModelTypeSet());
+  EXPECT_TRUE(ModelTypeSet().Equals(registrar.GetLastConfiguredTypes()));
 
   registrar.OnSyncerShutdownComplete();
   registrar.StopOnUIThread();
diff --git a/chrome/browser/sync/glue/synced_device_tracker.cc b/chrome/browser/sync/glue/synced_device_tracker.cc
index d502541..59fa12a 100644
--- a/chrome/browser/sync/glue/synced_device_tracker.cc
+++ b/chrome/browser/sync/glue/synced_device_tracker.cc
@@ -91,6 +91,44 @@
                      specifics.device_type()));
 }
 
+void SyncedDeviceTracker::GetAllSyncedDeviceInfo(
+    ScopedVector<DeviceInfo>* device_info) const {
+  if (device_info == NULL)
+    return;
+
+  device_info->clear();
+
+  syncer::ReadTransaction trans(FROM_HERE, user_share_);
+  syncer::ReadNode root_node(&trans);
+
+  if (root_node.InitByTagLookup(
+          syncer::ModelTypeToRootTag(syncer::DEVICE_INFO)) !=
+      syncer::BaseNode::INIT_OK) {
+    return;
+  }
+
+  // Get all the children of the root node and use the child id to read
+  // device info for devices.
+  std::vector<int64> children;
+  root_node.GetChildIds(&children);
+
+  for (std::vector<int64>::const_iterator it = children.begin();
+       it != children.end(); ++it) {
+    syncer::ReadNode node(&trans);
+    if (node.InitByIdLookup(*it) != syncer::BaseNode::INIT_OK)
+      return;
+
+    const sync_pb::DeviceInfoSpecifics& specifics =
+        node.GetDeviceInfoSpecifics();
+    device_info->push_back(
+        new DeviceInfo(specifics.client_name(),
+                       specifics.chrome_version(),
+                       specifics.sync_user_agent(),
+                       specifics.device_type()));
+
+  }
+}
+
 void SyncedDeviceTracker::InitLocalDeviceInfo(const base::Closure& callback) {
   DeviceInfo::CreateLocalDeviceInfo(
       base::Bind(&SyncedDeviceTracker::InitLocalDeviceInfoContinuation,
@@ -111,10 +149,16 @@
   specifics.set_sync_user_agent(info.sync_user_agent());
   specifics.set_device_type(info.device_type());
 
+  WriteDeviceInfo(specifics, local_device_info_tag_);
+}
+
+void SyncedDeviceTracker::WriteDeviceInfo(
+    const sync_pb::DeviceInfoSpecifics& specifics,
+    const std::string& tag) {
   syncer::WriteTransaction trans(FROM_HERE, user_share_);
   syncer::WriteNode node(&trans);
 
-  if (node.InitByClientTagLookup(syncer::DEVICE_INFO, local_device_info_tag_) ==
+  if (node.InitByClientTagLookup(syncer::DEVICE_INFO, tag) ==
       syncer::BaseNode::INIT_OK) {
     node.SetDeviceInfoSpecifics(specifics);
     node.SetTitle(UTF8ToWide(specifics.client_name()));
@@ -128,7 +172,7 @@
     syncer::WriteNode::InitUniqueByCreationResult create_result =
         new_node.InitUniqueByCreation(syncer::DEVICE_INFO,
                                       type_root,
-                                      local_device_info_tag_);
+                                      tag);
     DCHECK_EQ(syncer::WriteNode::INIT_SUCCESS, create_result);
     new_node.SetDeviceInfoSpecifics(specifics);
     new_node.SetTitle(UTF8ToWide(specifics.client_name()));
diff --git a/chrome/browser/sync/glue/synced_device_tracker.h b/chrome/browser/sync/glue/synced_device_tracker.h
index 929591f..877d833 100644
--- a/chrome/browser/sync/glue/synced_device_tracker.h
+++ b/chrome/browser/sync/glue/synced_device_tracker.h
@@ -9,6 +9,7 @@
 
 #include "base/basictypes.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/memory/scoped_vector.h"
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/sync/glue/change_processor.h"
 
@@ -42,6 +43,8 @@
   virtual void InitLocalDeviceInfo(const base::Closure& callback);
   virtual scoped_ptr<DeviceInfo> ReadDeviceInfo(
       const std::string& client_id) const;
+  virtual void GetAllSyncedDeviceInfo(
+      ScopedVector<DeviceInfo>* device_info) const;
 
  private:
   friend class SyncedDeviceTrackerTest;
@@ -52,6 +55,11 @@
   // Helper to write specifics into our node.  Also useful for testing.
   void WriteLocalDeviceInfo(const DeviceInfo& info);
 
+  // Helper to write arbitrary device info. Useful for writing local device
+  // info and also used by test cases to write arbitrary device infos.
+  void WriteDeviceInfo(const sync_pb::DeviceInfoSpecifics& specifics,
+                       const std::string& tag);
+
   base::WeakPtrFactory<SyncedDeviceTracker> weak_factory_;
 
   syncer::UserShare* user_share_;
diff --git a/chrome/browser/sync/glue/synced_device_tracker_unittest.cc b/chrome/browser/sync/glue/synced_device_tracker_unittest.cc
index 2af2780..94e79f0 100644
--- a/chrome/browser/sync/glue/synced_device_tracker_unittest.cc
+++ b/chrome/browser/sync/glue/synced_device_tracker_unittest.cc
@@ -4,7 +4,9 @@
 
 #include <string>
 
+#include "base/guid.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/memory/scoped_vector.h"
 #include "base/message_loop.h"
 #include "base/run_loop.h"
 #include "chrome/browser/sync/glue/device_info.h"
@@ -18,6 +20,21 @@
 
 namespace browser_sync {
 
+namespace {
+
+void ConvertDeviceInfoSpecifics(
+    const DeviceInfo& device_info,
+    const std::string& guid,
+    sync_pb::DeviceInfoSpecifics* specifics) {
+  specifics->set_cache_guid(guid);
+  specifics->set_client_name(device_info.client_name());
+  specifics->set_chrome_version(device_info.chrome_version());
+  specifics->set_sync_user_agent(device_info.sync_user_agent());
+  specifics->set_device_type(device_info.device_type());
+}
+
+}  // namespace
+
 class SyncedDeviceTrackerTest : public ::testing::Test {
  protected:
   SyncedDeviceTrackerTest() : transaction_count_baseline_(0) { }
@@ -52,6 +69,13 @@
     synced_device_tracker_->WriteLocalDeviceInfo(info);
   }
 
+  void WriteDeviceInfo(const DeviceInfo& device_info,
+                       const std::string& guid) {
+    sync_pb::DeviceInfoSpecifics specifics;
+    ConvertDeviceInfoSpecifics(device_info, guid, &specifics);
+    synced_device_tracker_->WriteDeviceInfo(specifics, guid);
+  }
+
   void ResetObservedChangesCounter() {
     transaction_count_baseline_ = GetTotalTransactionsCount();
   }
@@ -155,6 +179,31 @@
   EXPECT_EQ(1, GetObservedChangesCounter());
 }
 
+// Test retrieving DeviceInfos for all the syncing devices.
+TEST_F(SyncedDeviceTrackerTest, GetAllDeviceInfo) {
+  DeviceInfo device_info1(
+      "abc Device", "XYZ v1", "XYZ SyncAgent v1",
+      sync_pb::SyncEnums_DeviceType_TYPE_LINUX);
+
+  std::string guid1 = base::GenerateGUID();
+
+  DeviceInfo device_info2(
+      "def Device", "XYZ v2", "XYZ SyncAgent v2",
+      sync_pb::SyncEnums_DeviceType_TYPE_LINUX);
+
+  std::string guid2 = base::GenerateGUID();
+
+  WriteDeviceInfo(device_info1, guid1);
+  WriteDeviceInfo(device_info2, guid2);
+
+  ScopedVector<DeviceInfo> device_info;
+  synced_device_tracker_->GetAllSyncedDeviceInfo(&device_info);
+
+  EXPECT_EQ(device_info.size(), 2U);
+  EXPECT_TRUE(device_info[0]->Equals(device_info1));
+  EXPECT_TRUE(device_info[1]->Equals(device_info2));
+}
+
 }  // namespace
 
 }  // namespace browser_sync
diff --git a/chrome/browser/sync/glue/synced_session.h b/chrome/browser/sync/glue/synced_session.h
index 80ff9be..5582945 100644
--- a/chrome/browser/sync/glue/synced_session.h
+++ b/chrome/browser/sync/glue/synced_session.h
@@ -8,7 +8,7 @@
 #include <map>
 #include <string>
 
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/sessions/session_id.h"
 #include "chrome/browser/sessions/session_types.h"
 
diff --git a/chrome/browser/sync/glue/typed_url_model_associator_unittest.cc b/chrome/browser/sync/glue/typed_url_model_associator_unittest.cc
index f3d1849..39d3de2 100644
--- a/chrome/browser/sync/glue/typed_url_model_associator_unittest.cc
+++ b/chrome/browser/sync/glue/typed_url_model_associator_unittest.cc
@@ -8,14 +8,14 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/test/test_timeouts.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/history/history_types.h"
 #include "chrome/browser/sync/glue/typed_url_model_associator.h"
 #include "chrome/browser/sync/profile_sync_service_mock.h"
 #include "content/public/test/test_browser_thread.h"
-#include "googleurl/src/gurl.h"
 #include "sync/protocol/typed_url_specifics.pb.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
 
 using browser_sync::TypedUrlModelAssociator;
 using content::BrowserThread;
diff --git a/chrome/browser/sync/glue/ui_data_type_controller.cc b/chrome/browser/sync/glue/ui_data_type_controller.cc
index 830999e..1ed6b86 100644
--- a/chrome/browser/sync/glue/ui_data_type_controller.cc
+++ b/chrome/browser/sync/glue/ui_data_type_controller.cc
@@ -55,7 +55,9 @@
   DCHECK(!model_load_callback.is_null());
   DCHECK(syncer::IsRealDataType(type_));
   if (state_ != NOT_RUNNING) {
-    model_load_callback.Run(type(), syncer::SyncError(FROM_HERE,
+    model_load_callback.Run(type(),
+                            syncer::SyncError(FROM_HERE,
+                                              syncer::SyncError::DATATYPE_ERROR,
                                               "Model already loaded",
                                               type()));
     return;
@@ -131,7 +133,10 @@
       type(),
       weak_ptr_factory.GetWeakPtr());
   if (!local_service_.get()) {
-    syncer::SyncError error(FROM_HERE, "Failed to connect to syncer.", type());
+    syncer::SyncError error(FROM_HERE,
+                            syncer::SyncError::DATATYPE_ERROR,
+                            "Failed to connect to syncer.",
+                            type());
     local_merge_result.set_error(error);
     StartDone(ASSOCIATION_FAILED,
               local_merge_result,
@@ -149,7 +154,10 @@
   bool sync_has_nodes = false;
   if (!shared_change_processor_->SyncModelHasUserCreatedNodes(
           &sync_has_nodes)) {
-    syncer::SyncError error(FROM_HERE, "Failed to load sync nodes", type());
+    syncer::SyncError error(FROM_HERE,
+                            syncer::SyncError::UNRECOVERABLE_ERROR,
+                            "Failed to load sync nodes",
+                            type());
     local_merge_result.set_error(error);
     StartDone(UNRECOVERABLE_ERROR,
               local_merge_result,
@@ -207,7 +215,9 @@
 
   ModelLoadCallback model_load_callback = model_load_callback_;
   model_load_callback_.Reset();
-  model_load_callback.Run(type(), syncer::SyncError(FROM_HERE,
+  model_load_callback.Run(type(),
+                          syncer::SyncError(FROM_HERE,
+                                            syncer::SyncError::DATATYPE_ERROR,
                                             "Aborted",
                                             type()));
 }
diff --git a/chrome/browser/sync/glue/ui_data_type_controller_unittest.cc b/chrome/browser/sync/glue/ui_data_type_controller_unittest.cc
index ce64106..5edb108 100644
--- a/chrome/browser/sync/glue/ui_data_type_controller_unittest.cc
+++ b/chrome/browser/sync/glue/ui_data_type_controller_unittest.cc
@@ -166,7 +166,10 @@
   EXPECT_CALL(start_callback_,
               Run(DataTypeController::ASSOCIATION_FAILED, _, _));
   syncable_service_.set_merge_data_and_start_syncing_error(
-      syncer::SyncError(FROM_HERE, "Error", type_));
+      syncer::SyncError(FROM_HERE,
+                        syncer::SyncError::DATATYPE_ERROR,
+                        "Error",
+                        type_));
 
   EXPECT_EQ(DataTypeController::NOT_RUNNING, preference_dtc_->state());
   EXPECT_FALSE(syncable_service_.syncing());
diff --git a/chrome/browser/sync/profile_sync_components_factory_impl.cc b/chrome/browser/sync/profile_sync_components_factory_impl.cc
index 5c997c3..8a4cbec 100644
--- a/chrome/browser/sync/profile_sync_components_factory_impl.cc
+++ b/chrome/browser/sync/profile_sync_components_factory_impl.cc
@@ -4,13 +4,16 @@
 
 #include "base/command_line.h"
 #include "build/build_config.h"
+#include "chrome/browser/about_flags.h"
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
+#include "chrome/browser/browser_process.h"
 #include "chrome/browser/extensions/api/storage/settings_frontend.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/extension_system.h"
 #include "chrome/browser/extensions/extension_system_factory.h"
 #include "chrome/browser/history/history_service.h"
 #include "chrome/browser/history/history_service_factory.h"
+#include "chrome/browser/pref_service_flags_storage.h"
 #include "chrome/browser/prefs/pref_model_associator.h"
 #include "chrome/browser/prefs/pref_service_syncable.h"
 #include "chrome/browser/profiles/profile.h"
@@ -55,7 +58,7 @@
 #include "chrome/browser/webdata/autofill_profile_syncable_service.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
-#include "components/autofill/browser/webdata/autofill_webdata_service.h"
+#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
 #include "content/public/browser/browser_thread.h"
 #include "sync/api/syncable_service.h"
 
@@ -103,20 +106,6 @@
 using browser_sync::UIDataTypeController;
 using content::BrowserThread;
 
-namespace {
-// Based on command line switches, make the call to use SyncedNotifications or
-// not.
-// TODO(petewil): Remove this when the SyncedNotifications feature is ready
-// to be turned on by default, and just use a disable switch instead then.
-bool UseSyncedNotifications(CommandLine* command_line) {
-  if (command_line->HasSwitch(switches::kDisableSyncSyncedNotifications))
-    return false;
-  if (command_line->HasSwitch(switches::kEnableSyncSyncedNotifications))
-    return true;
-  return false;
-}
-}  // namespace
-
 ProfileSyncComponentsFactoryImpl::ProfileSyncComponentsFactoryImpl(
     Profile* profile, CommandLine* command_line)
     : profile_(profile),
@@ -185,7 +174,19 @@
         new SessionDataTypeController(this, profile_, pss));
   }
 
+  // Migrate sync flags that should be prefs.
+  // TODO(pastarmovj): Remove this code once enough time has passed to not need
+  // to migrate anymore.
+  about_flags::PrefServiceFlagsStorage flags_storage(
+      g_browser_process->local_state());
   if (command_line_->HasSwitch(switches::kEnableSyncFavicons)) {
+    profile_->GetPrefs()->SetBoolean(prefs::kSyncFaviconsEnabled, true);
+    about_flags::SetExperimentEnabled(&flags_storage,
+                                      syncer::kFaviconSyncFlag,
+                                      false);
+  }
+
+  if (profile_->GetPrefs()->GetBoolean(prefs::kSyncFaviconsEnabled)) {
     pss->RegisterDataTypeController(
         new UIDataTypeController(syncer::FAVICON_IMAGES,
                                  this,
@@ -268,13 +269,16 @@
             syncer::APP_SETTINGS, this, profile_, pss));
   }
 
+#if !defined(OS_ANDROID)
   // Synced Notifications sync datatype is disabled by default.
   // TODO(petewil): Switch to enabled by default once datatype support is done.
-  if (UseSyncedNotifications(command_line_)) {
+  if (notifier::ChromeNotifierServiceFactory::UseSyncedNotifications(
+          command_line_)) {
     pss->RegisterDataTypeController(
         new UIDataTypeController(
             syncer::SYNCED_NOTIFICATIONS, this, profile_, pss));
   }
+#endif
 
 #if defined(OS_LINUX) || defined(OS_WIN) || defined(OS_CHROMEOS)
   // Dictionary sync is enabled by default.
diff --git a/chrome/browser/sync/profile_sync_components_factory_impl.h b/chrome/browser/sync/profile_sync_components_factory_impl.h
index 03295c2..2de940b 100644
--- a/chrome/browser/sync/profile_sync_components_factory_impl.h
+++ b/chrome/browser/sync/profile_sync_components_factory_impl.h
@@ -10,7 +10,7 @@
 #include "base/basictypes.h"
 #include "base/compiler_specific.h"
 #include "chrome/browser/sync/profile_sync_components_factory.h"
-#include "components/autofill/browser/webdata/autofill_webdata_service.h"
+#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
 
 
 class CommandLine;
diff --git a/chrome/browser/sync/profile_sync_service.cc b/chrome/browser/sync/profile_sync_service.cc
index bbc69cf..26f26d1 100644
--- a/chrome/browser/sync/profile_sync_service.cc
+++ b/chrome/browser/sync/profile_sync_service.cc
@@ -22,11 +22,9 @@
 #include "base/strings/stringprintf.h"
 #include "base/threading/thread_restrictions.h"
 #include "build/build_config.h"
-#include "chrome/browser/about_flags.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/defaults.h"
 #include "chrome/browser/net/chrome_cookie_notification_details.h"
-#include "chrome/browser/pref_service_flags_storage.h"
 #include "chrome/browser/prefs/pref_service_syncable.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/signin/about_signin_internals.h"
@@ -68,6 +66,7 @@
 #include "google_apis/gaia/gaia_constants.h"
 #include "grit/generated_resources.h"
 #include "net/cookies/cookie_monster.h"
+#include "net/url_request/url_request_context_getter.h"
 #include "sync/api/sync_error.h"
 #include "sync/internal_api/public/configure_reason.h"
 #include "sync/internal_api/public/sync_encryption_handler.h"
@@ -75,8 +74,6 @@
 #include "sync/internal_api/public/util/sync_string_conversions.h"
 #include "sync/js/js_arg_list.h"
 #include "sync/js/js_event_details.h"
-#include "sync/notifier/invalidator_registrar.h"
-#include "sync/notifier/invalidator_state.h"
 #include "sync/util/cryptographer.h"
 #include "ui/base/l10n/l10n_util.h"
 
@@ -116,10 +113,11 @@
 
 static const char* kOAuth2Scopes[] = {
   GaiaConstants::kChromeSyncOAuth2Scope,
-  // GoogleTalk scope is needed for notifications.
-  GaiaConstants::kGoogleTalkOAuth2Scope
 };
 
+static const char* kManagedOAuth2Scopes[] = {
+  GaiaConstants::kChromeSyncManagedOAuth2Scope
+};
 
 static const char* kSyncUnrecoverableErrorHistogram =
     "Sync.UnrecoverableErrors";
@@ -169,7 +167,6 @@
       profile_(profile),
       // |profile| may be NULL in unit tests.
       sync_prefs_(profile_ ? profile_->GetPrefs() : NULL),
-      invalidator_storage_(profile_ ? profile_->GetPrefs(): NULL),
       sync_service_url_(kDevServerUrl),
       data_type_requested_sync_startup_(false),
       is_first_time_sync_configure_(false),
@@ -186,7 +183,6 @@
       auto_start_enabled_(start_behavior == AUTO_START),
       configure_status_(DataTypeManager::UNKNOWN),
       setup_in_progress_(false),
-      invalidator_state_(syncer::DEFAULT_INVALIDATION_ERROR),
       request_access_token_backoff_(&kRequestAccessTokenBackoffPolicy) {
   // By default, dev, canary, and unbranded Chromium users will go to the
   // development servers. Development servers have more features than standard
@@ -239,9 +235,6 @@
 }
 
 void ProfileSyncService::Initialize() {
-  DCHECK(!invalidator_registrar_.get());
-  invalidator_registrar_.reset(new syncer::InvalidatorRegistrar());
-
   InitSettings();
 
   // We clear this here (vs Shutdown) because we want to remember that an error
@@ -506,8 +499,7 @@
 void ProfileSyncService::CreateBackend() {
   backend_.reset(
       new SyncBackendHost(profile_->GetDebugName(),
-                          profile_, sync_prefs_.AsWeakPtr(),
-                          invalidator_storage_.AsWeakPtr()));
+                          profile_, sync_prefs_.AsWeakPtr()));
 }
 
 bool ProfileSyncService::IsEncryptedDatatypeEnabled() const {
@@ -633,60 +625,6 @@
   // we'll want to start from a fresh SyncDB, so delete any old one that might
   // be there.
   InitializeBackend(!HasSyncSetupCompleted());
-
-  // |backend_| may end up being NULL here in tests (in synchronous
-  // initialization mode).
-  //
-  // TODO(akalin): Fix this horribly non-intuitive behavior (see
-  // http://crbug.com/140354).
-  if (backend_) {
-    backend_->UpdateRegisteredInvalidationIds(
-        invalidator_registrar_->GetAllRegisteredIds());
-    for (AckHandleReplayQueue::const_iterator it = ack_replay_queue_.begin();
-         it != ack_replay_queue_.end(); ++it) {
-      backend_->AcknowledgeInvalidation(it->first, it->second);
-    }
-    ack_replay_queue_.clear();
-  }
-}
-
-void ProfileSyncService::RegisterInvalidationHandler(
-    syncer::InvalidationHandler* handler) {
-  invalidator_registrar_->RegisterHandler(handler);
-}
-
-void ProfileSyncService::UpdateRegisteredInvalidationIds(
-    syncer::InvalidationHandler* handler,
-    const syncer::ObjectIdSet& ids) {
-  invalidator_registrar_->UpdateRegisteredIds(handler, ids);
-
-  // If |backend_| is NULL, its registered IDs will be updated when
-  // it's created and initialized.
-  if (backend_) {
-    backend_->UpdateRegisteredInvalidationIds(
-        invalidator_registrar_->GetAllRegisteredIds());
-  }
-}
-
-void ProfileSyncService::UnregisterInvalidationHandler(
-    syncer::InvalidationHandler* handler) {
-  invalidator_registrar_->UnregisterHandler(handler);
-}
-
-void ProfileSyncService::AcknowledgeInvalidation(
-    const invalidation::ObjectId& id,
-    const syncer::AckHandle& ack_handle) {
-  if (backend_) {
-    backend_->AcknowledgeInvalidation(id, ack_handle);
-  } else {
-    // If |backend_| is NULL, save the acknowledgements to replay when
-    // it's created and initialized.
-    ack_replay_queue_.push_back(std::make_pair(id, ack_handle));
-  }
-}
-
-syncer::InvalidatorState ProfileSyncService::GetInvalidatorState() const {
-  return invalidator_registrar_->GetInvalidatorState();
 }
 
 void ProfileSyncService::OnGetTokenSuccess(
@@ -750,23 +688,7 @@
   }
 }
 
-void ProfileSyncService::EmitInvalidationForTest(
-    const invalidation::ObjectId& id,
-    const std::string& payload) {
-  syncer::ObjectIdSet notify_ids;
-  notify_ids.insert(id);
-
-  const syncer::ObjectIdInvalidationMap& invalidation_map =
-      ObjectIdSetToInvalidationMap(notify_ids, payload);
-  OnIncomingInvalidation(invalidation_map);
-}
-
 void ProfileSyncService::Shutdown() {
-  DCHECK(invalidator_registrar_.get());
-  // Reset |invalidator_registrar_| first so that ShutdownImpl cannot
-  // use it.
-  invalidator_registrar_.reset();
-
   if (signin_)
     signin_->signin_global_error()->RemoveProvider(this);
 
@@ -821,9 +743,6 @@
   expect_sync_configuration_aborted_ = false;
   is_auth_in_progress_ = false;
   backend_initialized_ = false;
-  // NULL if we're called from Shutdown().
-  if (invalidator_registrar_)
-    UpdateInvalidatorRegistrarState();
   cached_passphrase_.clear();
   encryption_pending_ = false;
   encrypt_everything_ = false;
@@ -848,7 +767,6 @@
   // Clear prefs (including SyncSetupHasCompleted) before shutting down so
   // PSS clients don't think we're set up while we're shutting down.
   sync_prefs_.ClearPreferences();
-  invalidator_storage_.Clear();
   ClearUnrecoverableError();
   ShutdownImpl(true);
 }
@@ -870,6 +788,11 @@
   FOR_EACH_OBSERVER(Observer, observers_, OnStateChanged());
   // TODO(akalin): Make an Observer subclass that listens and does the
   // event routing.
+  sync_js_controller_.HandleJsEvent("onServiceStateChanged", JsEventDetails());
+}
+
+void ProfileSyncService::NotifySyncCycleCompleted() {
+  FOR_EACH_OBSERVER(Observer, observers_, OnSyncCycleCompleted());
   sync_js_controller_.HandleJsEvent(
       "onServiceStateChanged", JsEventDetails());
 }
@@ -887,14 +810,6 @@
   unrecoverable_error_location_ = tracked_objects::Location();
 }
 
-// static
-// TODO(sync): Consider having syncer::Experiments provide this.
-std::string ProfileSyncService::GetExperimentNameForDataType(
-    syncer::ModelType data_type) {
-  NOTREACHED();
-  return std::string();
-}
-
 void ProfileSyncService::RegisterNewDataType(syncer::ModelType data_type) {
   if (data_type_controllers_.count(data_type) > 0)
     return;
@@ -945,33 +860,23 @@
   // passed onto the change processor.
   DeactivateDataType(type);
 
-  syncer::SyncError error(from_here, message, type);
+  syncer::SyncError error(from_here,
+                          syncer::SyncError::DATATYPE_ERROR,
+                          message,
+                          type);
 
   std::map<syncer::ModelType, syncer::SyncError> errors;
   errors[type] = error;
 
   // Update this before posting a task. So if a configure happens before
   // the task that we are going to post, this type would still be disabled.
-  failed_data_types_handler_.UpdateFailedDataTypes(
-      errors,
-      FailedDataTypesHandler::RUNTIME);
+  failed_data_types_handler_.UpdateFailedDataTypes(errors);
 
   base::MessageLoop::current()->PostTask(FROM_HERE,
       base::Bind(&ProfileSyncService::ReconfigureDatatypeManager,
                  weak_factory_.GetWeakPtr()));
 }
 
-void ProfileSyncService::OnInvalidatorStateChange(
-    syncer::InvalidatorState state) {
-  invalidator_state_ = state;
-  UpdateInvalidatorRegistrarState();
-}
-
-void ProfileSyncService::OnIncomingInvalidation(
-    const syncer::ObjectIdInvalidationMap& invalidation_map) {
-  invalidator_registrar_->DispatchInvalidationsToHandlers(invalidation_map);
-}
-
 void ProfileSyncService::OnBackendInitialized(
     const syncer::WeakHandle<syncer::JsBackend>& js_backend,
     const syncer::WeakHandle<syncer::DataTypeDebugInfoListener>&
@@ -1015,7 +920,6 @@
   }
 
   backend_initialized_ = true;
-  UpdateInvalidatorRegistrarState();
 
   sync_js_controller_.AttachJsBackend(js_backend);
   debug_info_listener_ = debug_info_listener;
@@ -1064,7 +968,7 @@
                    GetSessionModelAssociator()->AsWeakPtr()));
   }
   DVLOG(2) << "Notifying observers sync cycle completed";
-  NotifyObservers();
+  NotifySyncCycleCompleted();
 }
 
 void ProfileSyncService::OnExperimentsChanged(
@@ -1091,24 +995,11 @@
            << syncer::ModelTypeSetToString(to_add);
   DVLOG(2) << "Enabling types: " << syncer::ModelTypeSetToString(to_register);
 
-  about_flags::PrefServiceFlagsStorage flags_storage_(
-      g_browser_process->local_state());
-
   for (syncer::ModelTypeSet::Iterator it = to_register.First();
        it.Good(); it.Inc()) {
     // Received notice to enable experimental type. Check if the type is
     // registered, and if not register a new datatype controller.
     RegisterNewDataType(it.Get());
-    // Enable the about:flags switch for the experimental type so we don't have
-    // to always perform this reconfiguration. Once we set this, the type will
-    // remain registered on restart, so we will no longer go down this code
-    // path.
-    std::string experiment_name = GetExperimentNameForDataType(it.Get());
-    if (experiment_name.empty())
-      continue;
-    about_flags::SetExperimentEnabled(&flags_storage_,
-                                      experiment_name,
-                                      true);
   }
 
   // Check if the user has "Keep Everything Synced" enabled. If so, we want
@@ -1130,18 +1021,8 @@
     }
   }
 
-  // Now enable any non-datatype features.
-  if (experiments.keystore_encryption) {
-    about_flags::SetExperimentEnabled(&flags_storage_,
-                                      syncer::kKeystoreEncryptionFlag,
-                                      true);
-  }
-
-  if (experiments.favicon_sync) {
-    about_flags::SetExperimentEnabled(&flags_storage_,
-                                      syncer::kFaviconSyncFlag,
-                                      true);
-  }
+  if (experiments.favicon_sync)
+    profile_->GetPrefs()->SetBoolean(prefs::kSyncFaviconsEnabled, true);
 
   current_experiments_ = experiments;
 }
@@ -1183,10 +1064,10 @@
 void ProfileSyncService::OnConnectionStatusChange(
     syncer::ConnectionStatus status) {
   if (use_oauth2_token_ && status == syncer::CONNECTION_AUTH_ERROR) {
-    // Sync or Tango server returned error indicating that access token is
-    // invalid. It could be either expired or access is revoked. Let's request
-    // another access token and if access is revoked then request for token will
-    // fail with corresponding error.
+    // Sync server returned error indicating that access token is invalid. It
+    // could be either expired or access is revoked. Let's request another
+    // access token and if access is revoked then request for token will fail
+    // with corresponding error.
     RequestAccessToken();
   } else {
     const GoogleServiceAuthError auth_error =
@@ -1321,8 +1202,12 @@
       break;
     case syncer::DISABLE_SYNC_ON_CLIENT:
       OnStopSyncingPermanently();
-      // TODO(rsimha): Re-evaluate whether to also sign out the user here after
-      // a dashboard clear. See http://crbug.com/240436.
+#if !defined(OS_CHROMEOS)
+      // On desktop Chrome, sign out the user after a dashboard clear.
+      // TODO(rsimha): Revisit this for M30. See http://crbug.com/252049.
+      if (!auto_start_enabled_)  // Skip sign out on ChromeOS/Android.
+        SigninManagerFactory::GetForProfile(profile_)->SignOut();
+#endif
       break;
     case syncer::STOP_SYNC_FOR_DISABLED_ACCOUNT:
       // Sync disabled by domain admin. we should stop syncing until next
@@ -1393,7 +1278,7 @@
     std::string message =
         "Sync configuration failed with status " +
         DataTypeManager::ConfigureStatusToString(configure_status_) +
-        " during " + syncer::ModelTypeToString(error.type()) +
+        " during " + syncer::ModelTypeToString(error.model_type()) +
         ": " + error.message();
     LOG(ERROR) << "ProfileSyncService error: " << message;
     OnInternalUnrecoverableError(error.location(),
@@ -1923,8 +1808,18 @@
     return;
   request_access_token_retry_timer_.Stop();
   OAuth2TokenService::ScopeSet oauth2_scopes;
-  for (size_t i = 0; i < arraysize(kOAuth2Scopes); i++)
-    oauth2_scopes.insert(kOAuth2Scopes[i]);
+  bool is_managed = false;
+#if defined(ENABLE_MANAGED_USERS)
+  is_managed = ManagedUserService::ProfileIsManaged(profile_);
+#endif
+  if (is_managed) {
+    for (size_t i = 0; i < arraysize(kManagedOAuth2Scopes); i++)
+      oauth2_scopes.insert(kManagedOAuth2Scopes[i]);
+  } else {
+    for (size_t i = 0; i < arraysize(kOAuth2Scopes); i++)
+      oauth2_scopes.insert(kOAuth2Scopes[i]);
+  }
+
   OAuth2TokenService* token_service =
       ProfileOAuth2TokenServiceFactory::GetForProfile(profile_);
   // Invalidate previous token, otherwise token service will return the same
@@ -2201,17 +2096,6 @@
   OnUnrecoverableErrorImpl(from_here, message, delete_sync_database);
 }
 
-void ProfileSyncService::UpdateInvalidatorRegistrarState() {
-  const syncer::InvalidatorState effective_state =
-      backend_initialized_ ?
-      invalidator_state_ : syncer::TRANSIENT_INVALIDATION_ERROR;
-  DVLOG(1) << "New invalidator state: "
-           << syncer::InvalidatorStateToString(invalidator_state_)
-           << ", effective state: "
-           << syncer::InvalidatorStateToString(effective_state);
-  invalidator_registrar_->UpdateInvalidatorState(effective_state);
-}
-
 std::string ProfileSyncService::GetEffectiveUsername() {
 #if defined(ENABLE_MANAGED_USERS)
   if (ManagedUserService::ProfileIsManaged(profile_)) {
diff --git a/chrome/browser/sync/profile_sync_service.h b/chrome/browser/sync/profile_sync_service.h
index 6dd6797..18dc129 100644
--- a/chrome/browser/sync/profile_sync_service.h
+++ b/chrome/browser/sync/profile_sync_service.h
@@ -17,10 +17,8 @@
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
 #include "base/strings/string16.h"
-#include "base/time.h"
-#include "base/timer.h"
-#include "chrome/browser/invalidation/invalidation_frontend.h"
-#include "chrome/browser/invalidation/invalidator_storage.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
 #include "chrome/browser/signin/oauth2_token_service.h"
 #include "chrome/browser/signin/signin_global_error.h"
 #include "chrome/browser/sync/backend_unrecoverable_error_handler.h"
@@ -38,7 +36,6 @@
 #include "content/public/browser/notification_registrar.h"
 #include "content/public/browser/notification_types.h"
 #include "google_apis/gaia/google_service_auth_error.h"
-#include "googleurl/src/gurl.h"
 #include "net/base/backoff_entry.h"
 #include "sync/internal_api/public/base/model_type.h"
 #include "sync/internal_api/public/engine/model_safe_worker.h"
@@ -46,6 +43,7 @@
 #include "sync/internal_api/public/util/experiments.h"
 #include "sync/internal_api/public/util/unrecoverable_error_handler.h"
 #include "sync/js/sync_js_controller.h"
+#include "url/gurl.h"
 
 class Profile;
 class ProfileSyncComponentsFactory;
@@ -65,7 +63,6 @@
 
 namespace syncer {
 class BaseTransaction;
-class InvalidatorRegistrar;
 struct SyncCredentials;
 struct UserShare;
 }
@@ -165,7 +162,6 @@
                            public syncer::UnrecoverableErrorHandler,
                            public content::NotificationObserver,
                            public BrowserContextKeyedService,
-                           public invalidation::InvalidationFrontend,
                            public browser_sync::DataTypeEncryptionHandler,
                            public OAuth2TokenService::Consumer {
  public:
@@ -288,12 +284,6 @@
   // Disables sync for user. Use ShowLoginDialog to enable.
   virtual void DisableForUser();
 
-  // syncer::InvalidationHandler implementation (via SyncFrontend).
-  virtual void OnInvalidatorStateChange(
-      syncer::InvalidatorState state) OVERRIDE;
-  virtual void OnIncomingInvalidation(
-      const syncer::ObjectIdInvalidationMap& invalidation_map) OVERRIDE;
-
   // SyncFrontend implementation.
   virtual void OnBackendInitialized(
       const syncer::WeakHandle<syncer::JsBackend>& js_backend,
@@ -600,21 +590,6 @@
   // The set of currently enabled sync experiments.
   const syncer::Experiments& current_experiments() const;
 
-  // InvalidationFrontend implementation.  It is an error to have
-  // registered handlers when Shutdown() is called.
-  virtual void RegisterInvalidationHandler(
-      syncer::InvalidationHandler* handler) OVERRIDE;
-  virtual void UpdateRegisteredInvalidationIds(
-      syncer::InvalidationHandler* handler,
-      const syncer::ObjectIdSet& ids) OVERRIDE;
-  virtual void UnregisterInvalidationHandler(
-      syncer::InvalidationHandler* handler) OVERRIDE;
-  virtual void AcknowledgeInvalidation(
-      const invalidation::ObjectId& id,
-      const syncer::AckHandle& ack_handle) OVERRIDE;
-
-  virtual syncer::InvalidatorState GetInvalidatorState() const OVERRIDE;
-
   // OAuth2TokenService::Consumer implementation
   virtual void OnGetTokenSuccess(
       const OAuth2TokenService::Request* request,
@@ -628,11 +603,6 @@
   // once (before this object is destroyed).
   virtual void Shutdown() OVERRIDE;
 
-  // Simulate an incoming notification for the given id and payload.
-  void EmitInvalidationForTest(
-      const invalidation::ObjectId& id,
-      const std::string& payload);
-
   // Called when a datatype (SyncableService) has a need for sync to start
   // ASAP, presumably because a local change event has occurred but we're
   // still in deferred start mode, meaning the SyncableService hasn't been
@@ -703,8 +673,6 @@
     ERROR_REASON_ACTIONABLE_ERROR,
     ERROR_REASON_LIMIT
   };
-  typedef std::vector<std::pair<invalidation::ObjectId,
-                                syncer::AckHandle> > AckHandleReplayQueue;
   friend class ProfileSyncServicePasswordTest;
   friend class SyncTest;
   friend class TestProfileSyncService;
@@ -751,6 +719,7 @@
   void UpdateLastSyncedTime();
 
   void NotifyObservers();
+  void NotifySyncCycleCompleted();
 
   void ClearStaleErrors();
 
@@ -800,11 +769,6 @@
                                     bool delete_sync_database,
                                     UnrecoverableErrorReason reason);
 
-  // Must be called every time |backend_initialized_| or
-  // |invalidator_state_| is changed (but only if
-  // |invalidator_registrar_| is not NULL).
-  void UpdateInvalidatorRegistrarState();
-
   // Returns the username (in form of an email address) that should be used in
   // the credentials.
   std::string GetEffectiveUsername();
@@ -819,9 +783,6 @@
   // preferences.
   browser_sync::SyncPrefs sync_prefs_;
 
-  // TODO(tim): Move this to InvalidationService, once it exists. Bug 124137.
-  invalidation::InvalidatorStorage invalidator_storage_;
-
   // TODO(ncarter): Put this in a profile, once there is UI for it.
   // This specifies where to find the sync server.
   GURL sync_service_url_;
@@ -942,18 +903,6 @@
   // Factory the backend will use to build the SyncManager.
   syncer::SyncManagerFactory sync_manager_factory_;
 
-  // Holds the current invalidator state as updated by
-  // OnInvalidatorStateChange().  Note that this is different from the
-  // state known by |invalidator_registrar_| (See
-  // UpdateInvalidatorState()).
-  syncer::InvalidatorState invalidator_state_;
-
-  // Dispatches invalidations to handlers.  Set in Initialize() and
-  // unset in Shutdown().
-  scoped_ptr<syncer::InvalidatorRegistrar> invalidator_registrar_;
-  // Queues any acknowledgements received while the backend is uninitialized.
-  AckHandleReplayQueue ack_replay_queue_;
-
   // Sync's internal debug info listener. Used to record datatype configuration
   // and association information.
   syncer::WeakHandle<syncer::DataTypeDebugInfoListener> debug_info_listener_;
diff --git a/chrome/browser/sync/profile_sync_service_android.cc b/chrome/browser/sync/profile_sync_service_android.cc
index b6edff6..7886477 100644
--- a/chrome/browser/sync/profile_sync_service_android.cc
+++ b/chrome/browser/sync/profile_sync_service_android.cc
@@ -13,7 +13,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/prefs/pref_service.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/signin/oauth2_token_service.h"
@@ -60,7 +60,6 @@
 ProfileSyncServiceAndroid::ProfileSyncServiceAndroid(JNIEnv* env, jobject obj)
     : profile_(NULL),
       sync_service_(NULL),
-      sync_prefs_(NULL),
       weak_java_profile_sync_service_(env, obj) {
   if (g_browser_process == NULL ||
       g_browser_process->profile_manager() == NULL) {
diff --git a/chrome/browser/sync/profile_sync_service_android.h b/chrome/browser/sync/profile_sync_service_android.h
index d16a530..b8027b4 100644
--- a/chrome/browser/sync/profile_sync_service_android.h
+++ b/chrome/browser/sync/profile_sync_service_android.h
@@ -11,7 +11,7 @@
 #include "base/android/jni_helper.h"
 #include "base/callback.h"
 #include "base/compiler_specific.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/sync/profile_sync_service_observer.h"
 #include "chrome/browser/sync/sync_prefs.h"
 #include "google_apis/gaia/google_service_auth_error.h"
diff --git a/chrome/browser/sync/profile_sync_service_autofill_unittest.cc b/chrome/browser/sync/profile_sync_service_autofill_unittest.cc
index 8fa2fea..9868af7 100644
--- a/chrome/browser/sync/profile_sync_service_autofill_unittest.cc
+++ b/chrome/browser/sync/profile_sync_service_autofill_unittest.cc
@@ -19,7 +19,7 @@
 #include "base/strings/string16.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/synchronization/waitable_event.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/autofill/personal_data_manager_factory.h"
 #include "chrome/browser/signin/signin_manager.h"
 #include "chrome/browser/signin/signin_manager_factory.h"
@@ -38,12 +38,12 @@
 #include "chrome/browser/webdata/autocomplete_syncable_service.h"
 #include "chrome/browser/webdata/autofill_profile_syncable_service.h"
 #include "chrome/browser/webdata/web_data_service_factory.h"
-#include "components/autofill/browser/autofill_common_test.h"
-#include "components/autofill/browser/personal_data_manager.h"
-#include "components/autofill/browser/webdata/autofill_change.h"
-#include "components/autofill/browser/webdata/autofill_entry.h"
-#include "components/autofill/browser/webdata/autofill_table.h"
-#include "components/autofill/browser/webdata/autofill_webdata_service.h"
+#include "components/autofill/core/browser/autofill_common_test.h"
+#include "components/autofill/core/browser/personal_data_manager.h"
+#include "components/autofill/core/browser/webdata/autofill_change.h"
+#include "components/autofill/core/browser/webdata/autofill_entry.h"
+#include "components/autofill/core/browser/webdata/autofill_table.h"
+#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
 #include "components/webdata/common/web_data_service_test_util.h"
 #include "components/webdata/common/web_database.h"
 #include "content/public/test/test_browser_thread.h"
@@ -565,7 +565,7 @@
     AbstractAutofillFactory* factory = GetFactory(type);
     SigninManagerBase* signin =
         SigninManagerFactory::GetForProfile(profile_.get());
-    signin->SetAuthenticatedUsername("test_user");
+    signin->SetAuthenticatedUsername("test_user@gmail.com");
     sync_service_ = static_cast<TestProfileSyncService*>(
         ProfileSyncServiceFactory::GetInstance()->SetTestingFactoryAndUse(
             profile_.get(), &TestProfileSyncService::BuildAutoStartAsyncInit));
diff --git a/chrome/browser/sync/profile_sync_service_bookmark_unittest.cc b/chrome/browser/sync/profile_sync_service_bookmark_unittest.cc
index d620f91..7991284 100644
--- a/chrome/browser/sync/profile_sync_service_bookmark_unittest.cc
+++ b/chrome/browser/sync/profile_sync_service_bookmark_unittest.cc
@@ -21,7 +21,7 @@
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/bookmarks/base_bookmark_model_observer.h"
 #include "chrome/browser/bookmarks/bookmark_model.h"
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
@@ -427,10 +427,8 @@
     return true;
   }
 
-  void StartSync() {
-    test_user_share_.Reload();
-
-    ASSERT_TRUE(CreatePermanentBookmarkNodes());
+  bool AssociateModels() {
+    DCHECK(!model_associator_);
 
     // Set up model associator.
     model_associator_.reset(new BookmarkModelAssociator(
@@ -448,7 +446,10 @@
     syncer::SyncError error = model_associator_->AssociateModels(
         &local_merge_result_,
         &syncer_merge_result_);
-    EXPECT_FALSE(error.IsSet());
+    if (error.IsSet())
+      return false;
+
+    base::MessageLoop::current()->RunUntilIdle();
 
     // Verify the merge results were calculated properly.
     EXPECT_EQ(local_count_before,
@@ -467,8 +468,14 @@
               local_merge_result_.num_items_after_association());
     EXPECT_EQ(GetSyncBookmarkCount(),
               syncer_merge_result_.num_items_after_association());
+    return true;
+  }
 
-    base::MessageLoop::current()->RunUntilIdle();
+  void StartSync() {
+    test_user_share_.Reload();
+
+    ASSERT_TRUE(CreatePermanentBookmarkNodes());
+    ASSERT_TRUE(AssociateModels());
 
     // Set up change processor.
     change_processor_.reset(
@@ -1744,7 +1751,15 @@
   TearDown();
   SetUp();
 
-  StartSync();
+  // First attempt fails due to a persistence error.
+  EXPECT_TRUE(CreatePermanentBookmarkNodes());
+  EXPECT_FALSE(AssociateModels());
+
+  // Second attempt succeeds due to the previous error resetting the native
+  // transaction version.
+  model_associator_.reset();
+  EXPECT_TRUE(CreatePermanentBookmarkNodes());
+  EXPECT_TRUE(AssociateModels());
 
   // Make sure we're back in sync.  In real life, the user would need
   // to reauthenticate before this happens, but in the test, authentication
@@ -1918,6 +1933,43 @@
   ExpectTransactionVersionMatch(model_->mobile_node(), initial_versions);
 }
 
+// Test that sync persistence errors are detected and trigger a failed
+// association.
+TEST_F(ProfileSyncServiceBookmarkTestWithData, PersistenceError) {
+  LoadBookmarkModel(DELETE_EXISTING_STORAGE, DONT_SAVE_TO_STORAGE);
+  StartSync();
+  WriteTestDataToBookmarkModel();
+  base::MessageLoop::current()->RunUntilIdle();
+
+  BookmarkNodeVersionMap initial_versions;
+
+  // Verify transaction versions in sync model and bookmark model (saved as
+  // transaction version of root node) are equal after
+  // WriteTestDataToBookmarkModel() created bookmarks.
+  {
+    syncer::ReadTransaction trans(FROM_HERE, test_user_share_.user_share());
+    EXPECT_GT(trans.GetModelVersion(syncer::BOOKMARKS), 0);
+    GetTransactionVersions(model_->root_node(), &initial_versions);
+    EXPECT_EQ(trans.GetModelVersion(syncer::BOOKMARKS),
+              initial_versions[model_->root_node()->id()]);
+  }
+  ExpectTransactionVersionMatch(model_->bookmark_bar_node(),
+                                BookmarkNodeVersionMap());
+  ExpectTransactionVersionMatch(model_->other_node(),
+                                BookmarkNodeVersionMap());
+  ExpectTransactionVersionMatch(model_->mobile_node(),
+                                BookmarkNodeVersionMap());
+
+  // Now shut down sync and artificially increment the native model's version.
+  StopSync();
+  int64 root_version = initial_versions[model_->root_node()->id()];
+  model_->SetNodeMetaInfo(model_->root_node(), kBookmarkTransactionVersionKey,
+                          base::Int64ToString(root_version+1));
+
+  // Upon association, bookmarks should fail to associate.
+  EXPECT_FALSE(AssociateModels());
+}
+
 }  // namespace
 
 }  // namespace browser_sync
diff --git a/chrome/browser/sync/profile_sync_service_factory.cc b/chrome/browser/sync/profile_sync_service_factory.cc
index f43c988..d41da39 100644
--- a/chrome/browser/sync/profile_sync_service_factory.cc
+++ b/chrome/browser/sync/profile_sync_service_factory.cc
@@ -12,6 +12,7 @@
 #include "chrome/browser/defaults.h"
 #include "chrome/browser/extensions/extension_system_factory.h"
 #include "chrome/browser/history/history_service_factory.h"
+#include "chrome/browser/invalidation/invalidation_service_factory.h"
 #include "chrome/browser/password_manager/password_store_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
@@ -64,6 +65,7 @@
   DependsOn(HistoryServiceFactory::GetInstance());
   DependsOn(BookmarkModelFactory::GetInstance());
   DependsOn(AboutSigninInternalsFactory::GetInstance());
+  DependsOn(invalidation::InvalidationServiceFactory::GetInstance());
 
   // The following have not been converted to BrowserContextKeyedServices yet,
   // and for now they are explicitly destroyed after the
diff --git a/chrome/browser/sync/profile_sync_service_harness.cc b/chrome/browser/sync/profile_sync_service_harness.cc
index ee77cb7..47b7434 100644
--- a/chrome/browser/sync/profile_sync_service_harness.cc
+++ b/chrome/browser/sync/profile_sync_service_harness.cc
@@ -21,6 +21,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/message_loop.h"
 #include "base/prefs/pref_service.h"
+#include "chrome/browser/invalidation/p2p_invalidation_service.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/signin/signin_manager_base.h"
 #include "chrome/browser/signin/token_service.h"
@@ -38,6 +39,7 @@
 #include "sync/internal_api/public/util/sync_string_conversions.h"
 
 using syncer::sessions::SyncSessionSnapshot;
+using invalidation::P2PInvalidationService;
 
 // TODO(rsimha): Remove the following lines once crbug.com/91863 is fixed.
 // The amount of time for which we wait for a live sync operation to complete.
@@ -106,14 +108,36 @@
   return !did_timeout_;
 }
 
+// static
+ProfileSyncServiceHarness* ProfileSyncServiceHarness::Create(
+    Profile* profile,
+    const std::string& username,
+    const std::string& password) {
+  return new ProfileSyncServiceHarness(profile, username, password, NULL);
+}
+
+// static
+ProfileSyncServiceHarness* ProfileSyncServiceHarness::CreateForIntegrationTest(
+    Profile* profile,
+    const std::string& username,
+    const std::string& password,
+    P2PInvalidationService* p2p_invalidation_service) {
+  return new ProfileSyncServiceHarness(profile,
+                                       username,
+                                       password,
+                                       p2p_invalidation_service);
+}
+
 ProfileSyncServiceHarness::ProfileSyncServiceHarness(
     Profile* profile,
     const std::string& username,
-    const std::string& password)
+    const std::string& password,
+    P2PInvalidationService* p2p_invalidation_service)
     : waiting_for_encryption_type_(syncer::UNSPECIFIED),
       wait_state_(INITIAL_WAIT_STATE),
       profile_(profile),
       service_(NULL),
+      p2p_invalidation_service_(p2p_invalidation_service),
       progress_marker_partner_(NULL),
       username_(username),
       password_(password),
@@ -133,17 +157,6 @@
     service_->RemoveObserver(this);
 }
 
-// static
-ProfileSyncServiceHarness* ProfileSyncServiceHarness::CreateAndAttach(
-    Profile* profile) {
-  ProfileSyncServiceFactory* f = ProfileSyncServiceFactory::GetInstance();
-  if (!f->HasProfileSyncService(profile)) {
-    NOTREACHED() << "Profile has never signed into sync.";
-    return NULL;
-  }
-  return new ProfileSyncServiceHarness(profile, std::string(), std::string());
-}
-
 void ProfileSyncServiceHarness::SetCredentials(const std::string& username,
                                                const std::string& password) {
   username_ = username;
@@ -482,6 +495,21 @@
   RunStateChangeMachine();
 }
 
+void ProfileSyncServiceHarness::OnSyncCycleCompleted() {
+  // Integration tests still use p2p notifications.
+  const SyncSessionSnapshot& snap = GetLastSessionSnapshot();
+  bool is_notifiable_commit =
+      (snap.model_neutral_state().num_successful_commits > 0);
+  if (is_notifiable_commit && p2p_invalidation_service_) {
+    const syncer::ObjectIdInvalidationMap& invalidation_map =
+        ModelTypeInvalidationMapToObjectIdInvalidationMap(
+            snap.source().types);
+    p2p_invalidation_service_->SendInvalidation(invalidation_map);
+  }
+
+  OnStateChanged();
+}
+
 void ProfileSyncServiceHarness::OnMigrationStateChange() {
   // Update migration state.
   if (HasPendingBackendMigration()) {
diff --git a/chrome/browser/sync/profile_sync_service_harness.h b/chrome/browser/sync/profile_sync_service_harness.h
index 42594ba..a43e8a6 100644
--- a/chrome/browser/sync/profile_sync_service_harness.h
+++ b/chrome/browser/sync/profile_sync_service_harness.h
@@ -18,6 +18,10 @@
 
 class Profile;
 
+namespace invalidation {
+class P2PInvalidationService;
+}
+
 namespace browser_sync {
 namespace sessions {
 class SyncSessionSnapshot;
@@ -33,17 +37,19 @@
     : public ProfileSyncServiceObserver,
       public browser_sync::MigrationObserver {
  public:
-  ProfileSyncServiceHarness(Profile* profile,
-                            const std::string& username,
-                            const std::string& password);
+  static ProfileSyncServiceHarness* Create(
+      Profile* profile,
+      const std::string& username,
+      const std::string& password);
+
+  static ProfileSyncServiceHarness* CreateForIntegrationTest(
+      Profile* profile,
+      const std::string& username,
+      const std::string& password,
+      invalidation::P2PInvalidationService* invalidation_service);
 
   virtual ~ProfileSyncServiceHarness();
 
-  // Creates a ProfileSyncServiceHarness object and attaches it to |profile|, a
-  // profile that is assumed to have been signed into sync in the past. Caller
-  // takes ownership.
-  static ProfileSyncServiceHarness* CreateAndAttach(Profile* profile);
-
   // Sets the GAIA credentials with which to sign in to sync.
   void SetCredentials(const std::string& username, const std::string& password);
 
@@ -62,6 +68,7 @@
 
   // ProfileSyncServiceObserver implementation.
   virtual void OnStateChanged() OVERRIDE;
+  virtual void OnSyncCycleCompleted() OVERRIDE;
 
   // MigrationObserver implementation.
   virtual void OnMigrationStateChange() OVERRIDE;
@@ -270,6 +277,12 @@
     NUMBER_OF_STATES,
   };
 
+  ProfileSyncServiceHarness(
+      Profile* profile,
+      const std::string& username,
+      const std::string& password,
+      invalidation::P2PInvalidationService* invalidation_service);
+
   // Listen to migration events if the migrator has been initialized
   // and we're not already listening.  Returns true if we started
   // listening.
@@ -334,6 +347,9 @@
   // ProfileSyncService object associated with |profile_|.
   ProfileSyncService* service_;
 
+  // P2PInvalidationService associated with |profile_|.
+  invalidation::P2PInvalidationService* p2p_invalidation_service_;
+
   // The harness of the client whose update progress marker we're expecting
   // eventually match.
   ProfileSyncServiceHarness* progress_marker_partner_;
diff --git a/chrome/browser/sync/profile_sync_service_observer.cc b/chrome/browser/sync/profile_sync_service_observer.cc
new file mode 100644
index 0000000..9a8bde7
--- /dev/null
+++ b/chrome/browser/sync/profile_sync_service_observer.cc
@@ -0,0 +1,9 @@
+// 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/profile_sync_service_observer.h"
+
+void ProfileSyncServiceObserver::OnSyncCycleCompleted() {
+  OnStateChanged();
+}
diff --git a/chrome/browser/sync/profile_sync_service_observer.h b/chrome/browser/sync/profile_sync_service_observer.h
index de8c997..9916c5d 100644
--- a/chrome/browser/sync/profile_sync_service_observer.h
+++ b/chrome/browser/sync/profile_sync_service_observer.h
@@ -16,6 +16,11 @@
   // - The sync servers are unavailable at this time.
   // - Credentials are now in flight for authentication.
   virtual void OnStateChanged() = 0;
+
+  // If a client wishes to handle sync cycle completed events in a special way,
+  // they can use this function.  By default, it re-routes to OnStateChanged().
+  virtual void OnSyncCycleCompleted();
+
  protected:
   virtual ~ProfileSyncServiceObserver() { }
 };
diff --git a/chrome/browser/sync/profile_sync_service_password_unittest.cc b/chrome/browser/sync/profile_sync_service_password_unittest.cc
index b8fd5d7..22686b4 100644
--- a/chrome/browser/sync/profile_sync_service_password_unittest.cc
+++ b/chrome/browser/sync/profile_sync_service_password_unittest.cc
@@ -12,7 +12,8 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/test/test_timeouts.h"
-#include "base/time.h"
+#include "base/time/time.h"
+#include "chrome/browser/invalidation/invalidation_service_factory.h"
 #include "chrome/browser/password_manager/mock_password_store.h"
 #include "chrome/browser/password_manager/password_store.h"
 #include "chrome/browser/password_manager/password_store_factory.h"
@@ -153,18 +154,22 @@
 
   virtual void SetUp() {
     AbstractProfileSyncServiceTest::SetUp();
-    profile_.CreateRequestContext();
+    profile_.reset(new ProfileMock);
+    profile_->CreateRequestContext();
+    invalidation::InvalidationServiceFactory::GetInstance()->
+        SetBuildOnlyFakeInvalidatorsForTest(true);
     password_store_ = static_cast<MockPasswordStore*>(
         PasswordStoreFactory::GetInstance()->SetTestingFactoryAndUse(
-            &profile_, MockPasswordStore::Build).get());
+            profile_.get(), MockPasswordStore::Build).get());
   }
 
   virtual void TearDown() {
     if (password_store_.get())
       password_store_->ShutdownOnUIThread();
       ProfileSyncServiceFactory::GetInstance()->SetTestingFactory(
-          &profile_, NULL);
-      profile_.ResetRequestContext();
+          profile_.get(), NULL);
+      profile_->ResetRequestContext();
+      profile_.reset();
       AbstractProfileSyncServiceTest::TearDown();
   }
 
@@ -184,18 +189,18 @@
                         const base::Closure& node_callback) {
     if (!sync_service_) {
       SigninManagerBase* signin =
-          SigninManagerFactory::GetForProfile(&profile_);
-      signin->SetAuthenticatedUsername("test_user");
+          SigninManagerFactory::GetForProfile(profile_.get());
+      signin->SetAuthenticatedUsername("test_user@gmail.com");
       token_service_ = static_cast<TokenService*>(
           TokenServiceFactory::GetInstance()->SetTestingFactoryAndUse(
-              &profile_, BuildTokenService));
+              profile_.get(), BuildTokenService));
       ProfileOAuth2TokenServiceFactory::GetInstance()->SetTestingFactory(
-          &profile_, FakeOAuth2TokenService::BuildTokenService);
+          profile_.get(), FakeOAuth2TokenService::BuildTokenService);
 
       PasswordTestProfileSyncService* sync =
           static_cast<PasswordTestProfileSyncService*>(
               ProfileSyncServiceFactory::GetInstance()->
-                  SetTestingFactoryAndUse(&profile_,
+                  SetTestingFactoryAndUse(profile_.get(),
                       &PasswordTestProfileSyncService::Build));
       sync->set_backend_init_callback(root_callback);
       sync->set_passphrase_accept_callback(node_callback);
@@ -207,7 +212,7 @@
       sync_service_->ChangePreferredDataTypes(preferred_types);
       PasswordDataTypeController* data_type_controller =
           new PasswordDataTypeController(sync_service_->factory(),
-                                         &profile_,
+                                         profile_.get(),
                                          sync_service_);
       ProfileSyncComponentsFactoryMock* components =
           sync_service_->components_factory_mock();
@@ -311,7 +316,7 @@
   }
 
   content::MockNotificationObserver observer_;
-  ProfileMock profile_;
+  scoped_ptr<ProfileMock> profile_;
   scoped_refptr<MockPasswordStore> password_store_;
   content::NotificationRegistrar registrar_;
 };
@@ -353,7 +358,7 @@
 TEST_F(ProfileSyncServicePasswordTest, MAYBE_FailPasswordStoreLoad) {
   password_store_ = static_cast<NullPasswordStore*>(
       PasswordStoreFactory::GetInstance()->SetTestingFactoryAndUse(
-          &profile_, NullPasswordStore::Build).get());
+          profile_.get(), NullPasswordStore::Build).get());
   StartSyncService(base::Closure(), base::Closure());
   EXPECT_FALSE(sync_service_->HasUnrecoverableError());
   syncer::ModelTypeSet failed_types =
diff --git a/chrome/browser/sync/profile_sync_service_preference_unittest.cc b/chrome/browser/sync/profile_sync_service_preference_unittest.cc
index 66bc938..076a7fb 100644
--- a/chrome/browser/sync/profile_sync_service_preference_unittest.cc
+++ b/chrome/browser/sync/profile_sync_service_preference_unittest.cc
@@ -13,6 +13,7 @@
 #include "base/location.h"
 #include "base/stl_util.h"
 #include "base/strings/string_piece.h"
+#include "chrome/browser/invalidation/invalidation_service_factory.h"
 #include "chrome/browser/prefs/pref_model_associator.h"
 #include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/signin/signin_manager.h"
@@ -124,6 +125,8 @@
     AbstractProfileSyncServiceTest::SetUp();
     profile_.reset(new TestingProfile());
     profile_->CreateRequestContext();
+    invalidation::InvalidationServiceFactory::GetInstance()->
+        SetBuildOnlyFakeInvalidatorsForTest(true);
     prefs_ = profile_->GetTestingPrefService();
 
     prefs_->registry()->RegisterStringPref(
diff --git a/chrome/browser/sync/profile_sync_service_session_unittest.cc b/chrome/browser/sync/profile_sync_service_session_unittest.cc
index beb23f5..c42edc2 100644
--- a/chrome/browser/sync/profile_sync_service_session_unittest.cc
+++ b/chrome/browser/sync/profile_sync_service_session_unittest.cc
@@ -15,7 +15,8 @@
 #include "base/message_loop.h"
 #include "base/stl_util.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
+#include "chrome/browser/invalidation/invalidation_service_factory.h"
 #include "chrome/browser/signin/signin_manager.h"
 #include "chrome/browser/signin/signin_manager_factory.h"
 #include "chrome/browser/signin/token_service_factory.h"
@@ -41,7 +42,6 @@
 #include "content/public/browser/notification_service.h"
 #include "content/public/test/test_browser_thread.h"
 #include "google_apis/gaia/gaia_constants.h"
-#include "googleurl/src/gurl.h"
 #include "sync/internal_api/public/base/model_type.h"
 #include "sync/internal_api/public/change_record.h"
 #include "sync/internal_api/public/read_node.h"
@@ -54,6 +54,7 @@
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/ui_base_types.h"
+#include "url/gurl.h"
 
 using browser_sync::SessionChangeProcessor;
 using browser_sync::SessionDataTypeController;
@@ -205,6 +206,8 @@
     // Don't want the profile to create a real ProfileSyncService.
     ProfileSyncServiceFactory::GetInstance()->SetTestingFactory(profile,
                                                                 NULL);
+    invalidation::InvalidationServiceFactory::GetInstance()->
+        SetBuildOnlyFakeInvalidatorsForTest(true);
     return profile;
   }
 
diff --git a/chrome/browser/sync/profile_sync_service_startup_unittest.cc b/chrome/browser/sync/profile_sync_service_startup_unittest.cc
index 2bb87ab..dc58aa8 100644
--- a/chrome/browser/sync/profile_sync_service_startup_unittest.cc
+++ b/chrome/browser/sync/profile_sync_service_startup_unittest.cc
@@ -168,7 +168,7 @@
     SigninManagerBase* signin =
         SigninManagerFactory::GetForProfile(profile);
     profile->GetPrefs()->SetString(prefs::kGoogleServicesUsername,
-                                   "test_user");
+                                   "test_user@gmail.com");
     signin->Initialize(profile, NULL);
     EXPECT_FALSE(signin->GetAuthenticatedUsername().empty());
     return new TestProfileSyncService(
@@ -216,9 +216,9 @@
 
   // Simulate successful signin as test_user.
   profile_->GetPrefs()->SetString(prefs::kGoogleServicesUsername,
-                                  "test_user");
-  sync_->signin()->SetAuthenticatedUsername("test_user");
-  GoogleServiceSigninSuccessDetails details("test_user", "");
+                                  "test_user@gmail.com");
+  sync_->signin()->SetAuthenticatedUsername("test_user@gmail.com");
+  GoogleServiceSigninSuccessDetails details("test_user@gmail.com", "");
   content::NotificationService::current()->Notify(
       chrome::NOTIFICATION_GOOGLE_SIGNIN_SUCCESSFUL,
       content::Source<Profile>(profile_.get()),
@@ -263,9 +263,9 @@
 
   // Simulate successful signin as test_user.
   profile_->GetPrefs()->SetString(prefs::kGoogleServicesUsername,
-                                  "test_user");
-  sync_->signin()->SetAuthenticatedUsername("test_user");
-  GoogleServiceSigninSuccessDetails details("test_user", "");
+                                  "test_user@gmail.com");
+  sync_->signin()->SetAuthenticatedUsername("test_user@gmail.com");
+  GoogleServiceSigninSuccessDetails details("test_user@gmail.com", "");
   content::NotificationService::current()->Notify(
       chrome::NOTIFICATION_GOOGLE_SIGNIN_SUCCESSFUL,
       content::Source<Profile>(profile_.get()),
@@ -284,7 +284,7 @@
 // TODO(pavely): Reenable test once android is switched to oauth2.
 TEST_F(ProfileSyncServiceStartupTest, DISABLED_StartInvalidCredentials) {
   profile_->GetPrefs()->SetString(prefs::kGoogleServicesUsername,
-                                  "test_user");
+                                  "test_user@gmail.com");
   SigninManagerFactory::GetForProfile(
       profile_.get())->Initialize(profile_.get(), NULL);
   CreateSyncService();
@@ -313,7 +313,8 @@
   sync_->SetSetupInProgress(true);
 
   // Simulate successful signin.
-  GoogleServiceSigninSuccessDetails details("test_user", std::string());
+  GoogleServiceSigninSuccessDetails details("test_user@gmail.com",
+                                            std::string());
   content::NotificationService::current()->Notify(
         chrome::NOTIFICATION_GOOGLE_SIGNIN_SUCCESSFUL,
         content::Source<Profile>(profile_.get()),
@@ -367,7 +368,8 @@
 
 TEST_F(ProfileSyncServiceStartupTest, StartNormal) {
   // Pre load the tokens
-  profile_->GetPrefs()->SetString(prefs::kGoogleServicesUsername, "test_user");
+  profile_->GetPrefs()->SetString(prefs::kGoogleServicesUsername,
+                                  "test_user@gmail.com");
   SigninManagerFactory::GetForProfile(profile_.get())->Initialize(
       profile_.get(), NULL);
   CreateSyncService();
@@ -400,7 +402,8 @@
   }
 
   // Pre load the tokens
-  profile_->GetPrefs()->SetString(prefs::kGoogleServicesUsername, "test_user");
+  profile_->GetPrefs()->SetString(prefs::kGoogleServicesUsername,
+                                  "test_user@gmail.com");
   SigninManagerFactory::GetForProfile(profile_.get())->Initialize(
       profile_.get(), NULL);
   CreateSyncService();
@@ -429,7 +432,8 @@
   profile_->GetPrefs()->SetBoolean(prefs::kSyncKeepEverythingSynced, false);
 
   // Pre load the tokens
-  profile_->GetPrefs()->SetString(prefs::kGoogleServicesUsername, "test_user");
+  profile_->GetPrefs()->SetString(prefs::kGoogleServicesUsername,
+                                  "test_user@gmail.com");
   SigninManagerFactory::GetForProfile(profile_.get())->Initialize(
       profile_.get(), NULL);
   CreateSyncService();
@@ -451,7 +455,8 @@
 
 TEST_F(ProfileSyncServiceStartupTest, ManagedStartup) {
   // Service should not be started by Initialize() since it's managed.
-  profile_->GetPrefs()->SetString(prefs::kGoogleServicesUsername, "test_user");
+  profile_->GetPrefs()->SetString(prefs::kGoogleServicesUsername,
+                                  "test_user@gmail.com");
   SigninManagerFactory::GetForProfile(profile_.get())->Initialize(
       profile_.get(), NULL);
   CreateSyncService();
@@ -468,7 +473,8 @@
 }
 
 TEST_F(ProfileSyncServiceStartupTest, SwitchManaged) {
-  profile_->GetPrefs()->SetString(prefs::kGoogleServicesUsername, "test_user");
+  profile_->GetPrefs()->SetString(prefs::kGoogleServicesUsername,
+                                  "test_user@gmail.com");
   SigninManagerFactory::GetForProfile(profile_.get())->Initialize(
       profile_.get(), NULL);
   CreateSyncService();
@@ -499,14 +505,18 @@
 }
 
 TEST_F(ProfileSyncServiceStartupTest, StartFailure) {
-  profile_->GetPrefs()->SetString(prefs::kGoogleServicesUsername, "test_user");
+  profile_->GetPrefs()->SetString(prefs::kGoogleServicesUsername,
+                                  "test_user@gmail.com");
   SigninManagerFactory::GetForProfile(profile_.get())->Initialize(
       profile_.get(), NULL);
   CreateSyncService();
   DataTypeManagerMock* data_type_manager = SetUpDataTypeManager();
   DataTypeManager::ConfigureStatus status = DataTypeManager::ABORTED;
   syncer::SyncError error(
-      FROM_HERE, "Association failed.", syncer::BOOKMARKS);
+      FROM_HERE,
+      syncer::SyncError::DATATYPE_ERROR,
+      "Association failed.",
+      syncer::BOOKMARKS);
   std::map<syncer::ModelType, syncer::SyncError> errors;
   errors[syncer::BOOKMARKS] = error;
   DataTypeManager::ConfigureResult result(
@@ -532,7 +542,8 @@
 
 TEST_F(ProfileSyncServiceStartupTest, StartDownloadFailed) {
   // Pre load the tokens
-  profile_->GetPrefs()->SetString(prefs::kGoogleServicesUsername, "test_user");
+  profile_->GetPrefs()->SetString(prefs::kGoogleServicesUsername,
+                                  "test_user@gmail.com");
   SigninManagerFactory::GetForProfile(profile_.get())->Initialize(
       profile_.get(), NULL);
   CreateSyncService();
diff --git a/chrome/browser/sync/profile_sync_service_typed_url_unittest.cc b/chrome/browser/sync/profile_sync_service_typed_url_unittest.cc
index 47808bc..aedffb0 100644
--- a/chrome/browser/sync/profile_sync_service_typed_url_unittest.cc
+++ b/chrome/browser/sync/profile_sync_service_typed_url_unittest.cc
@@ -14,13 +14,14 @@
 #include "base/strings/string16.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/thread.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/history/history_backend.h"
 #include "chrome/browser/history/history_db_task.h"
 #include "chrome/browser/history/history_notifications.h"
 #include "chrome/browser/history/history_service.h"
 #include "chrome/browser/history/history_service_factory.h"
 #include "chrome/browser/history/history_types.h"
+#include "chrome/browser/invalidation/invalidation_service_factory.h"
 #include "chrome/browser/signin/signin_manager.h"
 #include "chrome/browser/signin/signin_manager_factory.h"
 #include "chrome/browser/signin/token_service_factory.h"
@@ -42,13 +43,13 @@
 #include "components/browser_context_keyed_service/refcounted_browser_context_keyed_service.h"
 #include "content/public/browser/notification_service.h"
 #include "google_apis/gaia/gaia_constants.h"
-#include "googleurl/src/gurl.h"
 #include "sync/internal_api/public/read_node.h"
 #include "sync/internal_api/public/read_transaction.h"
 #include "sync/internal_api/public/write_node.h"
 #include "sync/internal_api/public/write_transaction.h"
 #include "sync/protocol/typed_url_specifics.pb.h"
 #include "testing/gmock/include/gmock/gmock.h"
+#include "url/gurl.h"
 
 using base::Time;
 using base::Thread;
@@ -173,11 +174,14 @@
 
   virtual void SetUp() {
     AbstractProfileSyncServiceTest::SetUp();
-    profile_.CreateRequestContext();
+    profile_.reset(new ProfileMock);
+    profile_->CreateRequestContext();
+    invalidation::InvalidationServiceFactory::GetInstance()->
+        SetBuildOnlyFakeInvalidatorsForTest(true);
     history_backend_ = new HistoryBackendMock();
     history_service_ = static_cast<HistoryServiceMock*>(
         HistoryServiceFactory::GetInstance()->SetTestingFactoryAndUse(
-            &profile_, BuildHistoryService));
+            profile_.get(), BuildHistoryService));
     EXPECT_CALL((*history_service_), ScheduleDBTask(_, _))
         .WillRepeatedly(RunTaskOnDBThread(&history_thread_,
                                           history_backend_.get()));
@@ -188,9 +192,10 @@
     history_backend_ = NULL;
     history_service_ = NULL;
     ProfileSyncServiceFactory::GetInstance()->SetTestingFactory(
-        &profile_, NULL);
+        profile_.get(), NULL);
     history_thread_.Stop();
-    profile_.ResetRequestContext();
+    profile_->ResetRequestContext();
+    profile_.reset();
     AbstractProfileSyncServiceTest::TearDown();
   }
 
@@ -198,26 +203,27 @@
     TypedUrlModelAssociator* model_associator = NULL;
     if (!sync_service_) {
       SigninManagerBase* signin =
-          SigninManagerFactory::GetForProfile(&profile_);
+          SigninManagerFactory::GetForProfile(profile_.get());
       signin->SetAuthenticatedUsername("test");
       token_service_ = static_cast<TokenService*>(
           TokenServiceFactory::GetInstance()->SetTestingFactoryAndUse(
-              &profile_, BuildTokenService));
+              profile_.get(), BuildTokenService));
       ProfileOAuth2TokenServiceFactory::GetInstance()->SetTestingFactory(
-          &profile_, FakeOAuth2TokenService::BuildTokenService);
+          profile_.get(), FakeOAuth2TokenService::BuildTokenService);
       sync_service_ = static_cast<TestProfileSyncService*>(
           ProfileSyncServiceFactory::GetInstance()->SetTestingFactoryAndUse(
-              &profile_, &TestProfileSyncService::BuildAutoStartAsyncInit));
+              profile_.get(),
+              &TestProfileSyncService::BuildAutoStartAsyncInit));
       sync_service_->set_backend_init_callback(callback);
       ProfileSyncComponentsFactoryMock* components =
           sync_service_->components_factory_mock();
       TypedUrlDataTypeController* data_type_controller =
           new TypedUrlDataTypeController(components,
-                                         &profile_,
+                                         profile_.get(),
                                          sync_service_);
 
       EXPECT_CALL(*components, CreateTypedUrlSyncComponents(_, _, _)).
-          WillOnce(MakeTypedUrlSyncComponents(&profile_,
+          WillOnce(MakeTypedUrlSyncComponents(profile_.get(),
                                               sync_service_,
                                               history_backend_.get(),
                                               data_type_controller,
@@ -310,7 +316,7 @@
 
   Thread history_thread_;
 
-  ProfileMock profile_;
+  scoped_ptr<ProfileMock> profile_;
   scoped_refptr<HistoryBackendMock> history_backend_;
   HistoryServiceMock* history_service_;
   browser_sync::DataTypeErrorHandlerMock error_handler_;
@@ -560,7 +566,7 @@
   details.changed_urls.push_back(added_entry);
   scoped_refptr<ThreadNotifier> notifier(new ThreadNotifier(&history_thread_));
   notifier->Notify(chrome::NOTIFICATION_HISTORY_URLS_MODIFIED,
-                   content::Source<Profile>(&profile_),
+                   content::Source<Profile>(profile_.get()),
                    content::Details<history::URLsModifiedDetails>(&details));
 
   history::URLRows new_sync_entries;
@@ -590,7 +596,7 @@
   details.changed_urls.push_back(added_entry);
   scoped_refptr<ThreadNotifier> notifier(new ThreadNotifier(&history_thread_));
   notifier->Notify(chrome::NOTIFICATION_HISTORY_URLS_MODIFIED,
-                   content::Source<Profile>(&profile_),
+                   content::Source<Profile>(profile_.get()),
                    content::Details<history::URLsModifiedDetails>(&details));
 
   std::vector<history::URLRow> new_sync_entries;
@@ -627,7 +633,7 @@
   details.changed_urls.push_back(updated_entry);
   scoped_refptr<ThreadNotifier> notifier(new ThreadNotifier(&history_thread_));
   notifier->Notify(chrome::NOTIFICATION_HISTORY_URLS_MODIFIED,
-                   content::Source<Profile>(&profile_),
+                   content::Source<Profile>(profile_.get()),
                    content::Details<history::URLsModifiedDetails>(&details));
 
   history::URLRows new_sync_entries;
@@ -655,7 +661,7 @@
   details.transition = content::PAGE_TRANSITION_TYPED;
   scoped_refptr<ThreadNotifier> notifier(new ThreadNotifier(&history_thread_));
   notifier->Notify(chrome::NOTIFICATION_HISTORY_URL_VISITED,
-                   content::Source<Profile>(&profile_),
+                   content::Source<Profile>(profile_.get()),
                    content::Details<history::URLVisitedDetails>(&details));
 
   history::URLRows new_sync_entries;
@@ -693,7 +699,7 @@
   details.transition = content::PAGE_TRANSITION_TYPED;
   scoped_refptr<ThreadNotifier> notifier(new ThreadNotifier(&history_thread_));
   notifier->Notify(chrome::NOTIFICATION_HISTORY_URL_VISITED,
-                   content::Source<Profile>(&profile_),
+                   content::Source<Profile>(profile_.get()),
                    content::Details<history::URLVisitedDetails>(&details));
 
   history::URLRows new_sync_entries;
@@ -733,7 +739,7 @@
   details.transition = content::PAGE_TRANSITION_RELOAD;
   scoped_refptr<ThreadNotifier> notifier(new ThreadNotifier(&history_thread_));
   notifier->Notify(chrome::NOTIFICATION_HISTORY_URL_VISITED,
-                   content::Source<Profile>(&profile_),
+                   content::Source<Profile>(profile_.get()),
                    content::Details<history::URLVisitedDetails>(&details));
 
   GetTypedUrlsFromSyncDB(&new_sync_entries);
@@ -750,7 +756,7 @@
   details.row = twelve_visits;
   details.transition = content::PAGE_TRANSITION_TYPED;
   notifier->Notify(chrome::NOTIFICATION_HISTORY_URL_VISITED,
-                   content::Source<Profile>(&profile_),
+                   content::Source<Profile>(profile_.get()),
                    content::Details<history::URLVisitedDetails>(&details));
   GetTypedUrlsFromSyncDB(&new_sync_entries);
   // Should be no changes to the sync DB from this notification.
@@ -765,7 +771,7 @@
   details.row = twenty_visits;
   details.transition = content::PAGE_TRANSITION_TYPED;
   notifier->Notify(chrome::NOTIFICATION_HISTORY_URL_VISITED,
-                   content::Source<Profile>(&profile_),
+                   content::Source<Profile>(profile_.get()),
                    content::Details<history::URLVisitedDetails>(&details));
   GetTypedUrlsFromSyncDB(&new_sync_entries);
   ASSERT_EQ(1U, new_sync_entries.size());
@@ -799,7 +805,7 @@
   changes.rows.push_back(history::URLRow(GURL("http://mine.com")));
   scoped_refptr<ThreadNotifier> notifier(new ThreadNotifier(&history_thread_));
   notifier->Notify(chrome::NOTIFICATION_HISTORY_URLS_DELETED,
-                   content::Source<Profile>(&profile_),
+                   content::Source<Profile>(profile_.get()),
                    content::Details<history::URLsDeletedDetails>(&changes));
 
   history::URLRows new_sync_entries;
@@ -837,7 +843,7 @@
   changes.rows.push_back(history::URLRow(GURL("http://mine.com")));
   scoped_refptr<ThreadNotifier> notifier(new ThreadNotifier(&history_thread_));
   notifier->Notify(chrome::NOTIFICATION_HISTORY_URLS_DELETED,
-                   content::Source<Profile>(&profile_),
+                   content::Source<Profile>(profile_.get()),
                    content::Details<history::URLsDeletedDetails>(&changes));
 
   history::URLRows new_sync_entries;
@@ -876,7 +882,7 @@
   changes.all_history = true;
   scoped_refptr<ThreadNotifier> notifier(new ThreadNotifier(&history_thread_));
   notifier->Notify(chrome::NOTIFICATION_HISTORY_URLS_DELETED,
-                   content::Source<Profile>(&profile_),
+                   content::Source<Profile>(profile_.get()),
                    content::Details<history::URLsDeletedDetails>(&changes));
 
   GetTypedUrlsFromSyncDB(&new_sync_entries);
@@ -937,9 +943,11 @@
   sync_entries.push_back(sync_entry);
 
   EXPECT_CALL(error_handler_, CreateAndUploadError(_, _, _)).
-              WillOnce(Return(syncer::SyncError(FROM_HERE,
-                                        "Unit test",
-                                        syncer::TYPED_URLS)));
+              WillOnce(Return(syncer::SyncError(
+                                  FROM_HERE,
+                                  syncer::SyncError::DATATYPE_ERROR,
+                                  "Unit test",
+                                  syncer::TYPED_URLS)));
   StartSyncService(base::Bind(&AddTypedUrlEntries, this, sync_entries));
   // Errors getting typed URLs will cause an unrecoverable error (since we can
   // do *nothing* in that case).
@@ -991,7 +999,7 @@
   details.changed_urls.push_back(new_file_entry);
   scoped_refptr<ThreadNotifier> notifier(new ThreadNotifier(&history_thread_));
   notifier->Notify(chrome::NOTIFICATION_HISTORY_URLS_MODIFIED,
-                   content::Source<Profile>(&profile_),
+                   content::Source<Profile>(profile_.get()),
                    content::Details<history::URLsModifiedDetails>(&details));
 
   history::URLRows new_sync_entries;
@@ -1044,7 +1052,7 @@
   details.changed_urls.push_back(localhost_ip_entry);
   scoped_refptr<ThreadNotifier> notifier(new ThreadNotifier(&history_thread_));
   notifier->Notify(chrome::NOTIFICATION_HISTORY_URLS_MODIFIED,
-                   content::Source<Profile>(&profile_),
+                   content::Source<Profile>(profile_.get()),
                    content::Details<history::URLsModifiedDetails>(&details));
 
   history::URLRows new_sync_entries;
diff --git a/chrome/browser/sync/profile_sync_service_unittest.cc b/chrome/browser/sync/profile_sync_service_unittest.cc
index 3280634..6e7bbe7 100644
--- a/chrome/browser/sync/profile_sync_service_unittest.cc
+++ b/chrome/browser/sync/profile_sync_service_unittest.cc
@@ -8,6 +8,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/message_loop.h"
 #include "base/values.h"
+#include "chrome/browser/invalidation/invalidation_service_factory.h"
 #include "chrome/browser/signin/signin_manager.h"
 #include "chrome/browser/signin/signin_manager_factory.h"
 #include "chrome/browser/signin/token_service.h"
@@ -26,10 +27,6 @@
 #include "sync/js/js_arg_list.h"
 #include "sync/js/js_event_details.h"
 #include "sync/js/js_test_util.h"
-#include "sync/notifier/fake_invalidation_handler.h"
-#include "sync/notifier/invalidator.h"
-#include "sync/notifier/invalidator_test_template.h"
-#include "sync/notifier/object_id_invalidation_map_test_util.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -64,6 +61,8 @@
     io_thread_.StartIOThread();
     profile.reset(new TestingProfile());
     profile->CreateRequestContext();
+    invalidation::InvalidationServiceFactory::GetInstance()->
+        SetBuildOnlyFakeInvalidatorsForTest(true);
   }
 
   void TearDown() {
@@ -357,7 +356,7 @@
   StrictMock<syncer::MockJsReplyHandler> reply_handler;
 
   ListValue arg_list1;
-  arg_list1.Append(Value::CreateStringValue("TRANSIENT_INVALIDATION_ERROR"));
+  arg_list1.Append(Value::CreateStringValue("INVALIDATIONS_ENABLED"));
   syncer::JsArgList args1(&arg_list1);
   EXPECT_CALL(reply_handler,
               HandleJsReply("getNotificationState", HasArgs(args1)));
@@ -381,7 +380,7 @@
   StrictMock<syncer::MockJsReplyHandler> reply_handler;
 
   ListValue arg_list1;
-  arg_list1.Append(Value::CreateStringValue("TRANSIENT_INVALIDATION_ERROR"));
+  arg_list1.Append(Value::CreateStringValue("INVALIDATIONS_ENABLED"));
   syncer::JsArgList args1(&arg_list1);
   EXPECT_CALL(reply_handler,
               HandleJsReply("getNotificationState", HasArgs(args1)));
@@ -467,178 +466,5 @@
   EXPECT_FALSE(harness_.service->sync_initialized());
 }
 
-// Register a handler with the ProfileSyncService, and disable and
-// reenable sync.  The handler should get notified of the state
-// changes.
-// Flaky on all platforms. http://crbug.com/154491
-TEST_F(ProfileSyncServiceTest, DISABLED_DisableInvalidationsOnStop) {
-  harness_.StartSyncServiceAndSetInitialSyncEnded(
-      true, true, true, true, syncer::STORAGE_IN_MEMORY);
-
-  syncer::FakeInvalidationHandler handler;
-  harness_.service->RegisterInvalidationHandler(&handler);
-
-  SyncBackendHostForProfileSyncTest* const backend =
-      harness_.service->GetBackendForTest();
-
-  backend->EmitOnInvalidatorStateChange(syncer::INVALIDATIONS_ENABLED);
-  EXPECT_EQ(syncer::INVALIDATIONS_ENABLED, handler.GetInvalidatorState());
-
-  harness_.service->StopAndSuppress();
-  EXPECT_EQ(syncer::TRANSIENT_INVALIDATION_ERROR,
-            handler.GetInvalidatorState());
-
-  harness_.service->UnsuppressAndStart();
-  EXPECT_EQ(syncer::INVALIDATIONS_ENABLED, handler.GetInvalidatorState());
-
-  harness_.service->UnregisterInvalidationHandler(&handler);
-}
-
-// Register for some IDs with the ProfileSyncService, restart sync,
-// and trigger some invalidation messages.  They should still be
-// received by the handler.
-TEST_F(ProfileSyncServiceTest, UpdateRegisteredInvalidationIdsPersistence) {
-  harness_.StartSyncService();
-
-  syncer::ObjectIdSet ids;
-  ids.insert(invalidation::ObjectId(3, "id3"));
-  const syncer::ObjectIdInvalidationMap& states =
-      syncer::ObjectIdSetToInvalidationMap(ids, "payload");
-
-  syncer::FakeInvalidationHandler handler;
-
-  harness_.service->RegisterInvalidationHandler(&handler);
-  harness_.service->UpdateRegisteredInvalidationIds(&handler, ids);
-
-  harness_.service->StopAndSuppress();
-  harness_.service->UnsuppressAndStart();
-
-  SyncBackendHostForProfileSyncTest* const backend =
-      harness_.service->GetBackendForTest();
-
-  backend->EmitOnInvalidatorStateChange(syncer::INVALIDATIONS_ENABLED);
-  EXPECT_EQ(syncer::INVALIDATIONS_ENABLED, handler.GetInvalidatorState());
-
-  backend->EmitOnIncomingInvalidation(states);
-  EXPECT_THAT(states, Eq(handler.GetLastInvalidationMap()));
-
-  backend->EmitOnInvalidatorStateChange(syncer::TRANSIENT_INVALIDATION_ERROR);
-  EXPECT_EQ(syncer::TRANSIENT_INVALIDATION_ERROR,
-            handler.GetInvalidatorState());
-
-  harness_.service->UnregisterInvalidationHandler(&handler);
-}
-
-// Thin Invalidator wrapper around ProfileSyncService.
-class ProfileSyncServiceInvalidator : public syncer::Invalidator {
- public:
-  explicit ProfileSyncServiceInvalidator(ProfileSyncService* service)
-      : service_(service) {}
-
-  virtual ~ProfileSyncServiceInvalidator() {}
-
-  // Invalidator implementation.
-  virtual void RegisterHandler(syncer::InvalidationHandler* handler) OVERRIDE {
-    service_->RegisterInvalidationHandler(handler);
-  }
-
-  virtual void UpdateRegisteredIds(syncer::InvalidationHandler* handler,
-                                   const syncer::ObjectIdSet& ids) OVERRIDE {
-    service_->UpdateRegisteredInvalidationIds(handler, ids);
-  }
-
-  virtual void UnregisterHandler(
-      syncer::InvalidationHandler* handler) OVERRIDE {
-    service_->UnregisterInvalidationHandler(handler);
-  }
-
-  virtual void Acknowledge(const invalidation::ObjectId& id,
-                           const syncer::AckHandle& ack_handle) OVERRIDE {
-    // Do nothing.
-  }
-
-  virtual syncer::InvalidatorState GetInvalidatorState() const OVERRIDE {
-    return service_->GetInvalidatorState();
-  }
-
-  virtual void UpdateCredentials(
-      const std::string& email, const std::string& token) OVERRIDE {
-    // Do nothing.
-  }
-
-  virtual void SendInvalidation(
-      const syncer::ObjectIdInvalidationMap& invalidation_map) OVERRIDE {
-    // Do nothing.
-  }
-
- private:
-  ProfileSyncService* const service_;
-
-  DISALLOW_COPY_AND_ASSIGN(ProfileSyncServiceInvalidator);
-};
-
 }  // namespace
-
-
-// ProfileSyncServiceInvalidatorTestDelegate has to be visible from
-// the syncer namespace (where InvalidatorTest lives).
-class ProfileSyncServiceInvalidatorTestDelegate {
- public:
-  ProfileSyncServiceInvalidatorTestDelegate() {}
-
-  ~ProfileSyncServiceInvalidatorTestDelegate() {
-    DestroyInvalidator();
-  }
-
-  void CreateInvalidator(
-      const std::string& invalidation_client_id,
-      const std::string& initial_state,
-      const base::WeakPtr<syncer::InvalidationStateTracker>&
-          invalidation_state_tracker) {
-    DCHECK(!invalidator_.get());
-    harness_.SetUp();
-    harness_.StartSyncService();
-    invalidator_.reset(
-        new ProfileSyncServiceInvalidator(harness_.service.get()));
-  }
-
-  ProfileSyncServiceInvalidator* GetInvalidator() {
-    return invalidator_.get();
-  }
-
-  void DestroyInvalidator() {
-    invalidator_.reset();
-    harness_.TearDown();
-  }
-
-  void WaitForInvalidator() {
-    // Do nothing.
-  }
-
-  void TriggerOnInvalidatorStateChange(syncer::InvalidatorState state) {
-    harness_.service->GetBackendForTest()->EmitOnInvalidatorStateChange(state);
-  }
-
-  void TriggerOnIncomingInvalidation(
-      const syncer::ObjectIdInvalidationMap& invalidation_map) {
-    harness_.service->GetBackendForTest()->EmitOnIncomingInvalidation(
-        invalidation_map);
-  }
-
- private:
-  ProfileSyncServiceTestHarness harness_;
-  scoped_ptr<ProfileSyncServiceInvalidator> invalidator_;
-};
-
 }  // namespace browser_sync
-
-namespace syncer {
-namespace {
-
-// ProfileSyncService should behave just like an invalidator.
-INSTANTIATE_TYPED_TEST_CASE_P(
-    ProfileSyncServiceInvalidatorTest, InvalidatorTest,
-    ::browser_sync::ProfileSyncServiceInvalidatorTestDelegate);
-
-}  // namespace
-}  // namespace syncer
diff --git a/chrome/browser/sync/resources/gaia_login.css b/chrome/browser/sync/resources/gaia_login.css
deleted file mode 100644
index b59959a..0000000
--- a/chrome/browser/sync/resources/gaia_login.css
+++ /dev/null
@@ -1,163 +0,0 @@
-body {
-  -webkit-user-select: none;
-  background-color: #fff;
-  margin-bottom: 6px;
-  margin-top: 6px;
-}
-
-a:link {
-  color: #00c;
-}
-
-a:visited {
-  color: #551a8b;
-}
-
-a:active {
-  color: #f00;
-}
-
-hr {
-  background-color: #ddd;
-  border: 0;
-  height: 1px;
-  margin: 5px;
-  text-align: left;
-  width: 100%;
-}
-
-input[type='button'],
-input[type='submit'] {
-  min-height: 26px;
-  min-width: 87px;
-}
-
-.end-aligned {
-  text-align: end;
-}
-
-#gaia-account-text {
-  font-weight: bold;
-  position: relative;
-  top: -7px;
-}
-
-#email-readonly {
-  font-size: 10pt;
-  font-weight: bold;
-}
-
-div.errormsg {
-  color: red;
-  font-size: smaller;
-}
-
-font.errormsg {
-  color: red;
-  font-size: smaller;
-}
-
-div.errormsgspacer {
-  min-height: 1em;
-}
-
-font.errormsgspacer {
-  font-size: smaller;
-}
-
-#gaia-login-form {
-  margin-bottom: 0;
-}
-
-#captcha-wrapper {
-  background: no-repeat;
-  background-color: #e8eefa;
-  background-position: center;
-  background-size: 200px 70px;
-  display: block;
-}
-
-#captcha-image {
-  height: 70px;
-  width: 200px;
-}
-
-#logging-in-throbber {
-  margin: 0 10px;
-}
-
-.bottom-padded-cell {
-  padding-bottom: 3px;
-}
-
-.no-vertical-padding {
-  padding-bottom: 0;
-  padding-top: 0;
-}
-
-#cancel-space-no-captcha {
-  height: 22px;
-}
-
-#top-blurb {
-  font-size: 11pt;
-  line-height: 1.5em;
-}
-
-#top-blurb-error {
-  background-color: #eeb939;
-  border-radius: 4px;
-  font-size: 11pt;
-  font-weight: bold;
-  margin-bottom: 10px;
-  margin-left: auto;
-  margin-right: auto;
-  padding: 4px 10px;
-  text-align: center;
-  visibility: hidden;
-  width: 70%;
-}
-
-#content-table {
-  background-color: #fff;
-  border: #c3d9ff 1px solid;
-  padding: 2px;
-}
-
-.access-code-row > td {
-  padding-bottom: 1px;
-  text-align: center;
-}
-
-#access-code-label-row > td {
-  padding-top: 6px;
-}
-
-.gaia-le-lbl,
-.gaia-le-val,
-.gaia-le-rem,
-.gaia-captchahtml-desc
-.gaia-captchahtml-cmt {
-  font-size: smaller;
-}
-
-.gaia-captchahtml-cmt {
-  font-style: italic;
-}
-
-.gaia-le-fpwd,
-.gaia-le-chusr {
-  font-size: 70%;
-}
-
-#password-row {
-  margin-top: 2px;
-}
-
-#action-area {
-  margin-top: 2px;
-}
-
-#errormsg-0-access-code {
-  text-align: center;
-}
diff --git a/chrome/browser/sync/resources/gaia_login.html b/chrome/browser/sync/resources/gaia_login.html
deleted file mode 100644
index 41be8b7..0000000
--- a/chrome/browser/sync/resources/gaia_login.html
+++ /dev/null
@@ -1,207 +0,0 @@
-<html i18n-values="dir:textdirection;">
-<head>
-<link rel="stylesheet" href="gaia_login.css">
-<link rel="stylesheet" href="chrome://resources/css/throbber.css">
-<script src="gaia_login.js"></script>
-</head>
-<body i18n-values=".style.fontFamily:fontfamily;.style.fontSize:fontsize">
-<div>
-  <div>
-    <div id="top-blurb-error">
-      <span id="error-signing-in" i18n-content="errorsigningin"></span>
-      <span id="error-custom" hidden></span>
-    </div>
-    <form id="gaia-login-form">
-      <div id="gaia-login-box">
-        <table id="content-table" cellspacing="0"
-            cellpadding="5" width="75%" border="0" align="center">
-          <tr>
-            <td valign="top" style="text-align:center" nowrap="nowrap"
-                bgcolor="#e8eefa">
-              <div>
-                <table id="gaia-table" align="center" border="0"
-                    cellpadding="1" cellspacing="0">
-                  <tr>
-                    <td colspan="2" align="center">
-                      <div>
-                        <div>
-                          <span class="gaia-le-lbl" i18n-content="signinprefix">
-                          </span>
-                        </div>
-                        <div>
-                          <span id="gaia-logo">
-                            <img src="google_transparent.png" alt="Google">
-                          </span>
-                          <span id="gaia-account-text"
-                              i18n-content="signinsuffix"></span>
-                        </div>
-                      </div>
-                    </td>
-                  </tr>
-                  <tr>
-                    <td colspan="2" align="center"> </td>
-                  </tr>
-                  <tr id="email-row">
-                    <td nowrap="nowrap">
-                      <div class="end-aligned">
-                        <span class="gaia-le-lbl" i18n-content="emaillabel">
-                        </span>
-                      </div>
-                    </td>
-                    <td>
-                      <input id="email" type="text" name="email" size="18"
-                          value="" class='gaia-le-val'>
-                      <span id="email-readonly" hidden></span>
-                    </td>
-                  </tr>
-                  <tr id="access-code-label-row" class="access-code-row" hidden>
-                    <td colspan="2">
-                      <span class="gaia-le-lbl"
-                          i18n-content="enteraccesscode"></span>
-                    </td>
-                  </tr>
-                  <tr id="access-code-help-row" class="access-code-row" hidden>
-                    <td colspan="2" class="gaia-le-fpwd">
-                      <a i18n-values="href:getaccesscodeurl"
-                          i18n-content="getaccesscodehelp" target="_blank">
-                      </a>
-                    </td>
-                  <tr>
-                    <td></td>
-                    <td>
-                      <div id="errormsg-0-email" class="errormsg" hidden
-                          i18n-content="cannotbeblank">
-                      </div>
-                    </td>
-                  </tr>
-                  <tr id="password-row">
-                    <td class="end-aligned">
-                      <span class="gaia-le-lbl"
-                          i18n-content="passwordlabel"></span>
-                    </td>
-                    <td>
-                      <input id="passwd" type="password" name="passwd" size="18"
-                          class="gaia-le-val">
-                    </td>
-                  </tr>
-                  <tr id="access-code-input-row" class="access-code-row" hidden>
-                    <td colspan="2">
-                      <input id="access-code" type="password" name="accessCode"
-                          size="18" class="gaia-le-val">
-                    </td>
-                  </tr>
-                  <tr>
-                    <td></td>
-                    <td>
-                      <div class="errormsgspacer">
-                        <div id="errormsg-0-password" class="errormsg" hidden
-                            i18n-content="cannotbeblank">
-                        </div>
-                        <div id="errormsg-1-password" class="errormsg" hidden>
-                          <span i18n-content="invalidcredentials"></span>
-                          <!-- Brackets are intentional -->
-                          [<a i18n-values="href:invalidpasswordhelpurl"
-                               target="_blank">?</a>]
-                        </div>
-                        <div id="errormsg-0-access-code" class="errormsg" hidden
-                            i18n-content="invalidaccesscode">
-                        </div>
-                      </div>
-                    </td>
-                  </tr>
-                  <tr>
-                    <td colspan="2">
-                      <div id="captcha-div" hidden>
-                        <table cellpadding="1" cellspacing="0" border="0">
-                          <tbody>
-                            <tr>
-                              <td colspan="2" align="center"
-                                  class="bottom-padded-cell">
-                                <font size="-1">
-                                  <span i18n-content="captchainstructions">
-                                  </span>
-                                </font>
-                              </td>
-                            </tr>
-                            <tr>
-                              <td colspan="2" align="center"
-                                  class="bottom-padded-cell">
-                                <span id="captcha-wrapper">
-                                  <div id="captcha-image"></div>
-                                </span>
-                              </td>
-                            </tr>
-                            <tr>
-                              <td colspan="2" align="center">
-                                <input id="captcha-value" type="text"
-                                    name="captchaValue" size="18" value=""
-                                    class="gaia-le-val">
-                              </td>
-                            </tr>
-                          </tbody>
-                        </table>
-                      </div>
-                    </td>
-                  </tr>
-                  <tr>
-                    <td colspan="2" align="center">
-                      <div id="errormsg-0-connection" class="errormsg" hidden
-                          i18n-content="couldnotconnect">
-                      </div>
-                    </td>
-                  </tr>
-                  <tr id="action-area">
-                    <td colspan="2">
-                      <table align="center" cellpadding="0"
-                          cellspacing="0">
-                        <tr>
-                          <td>
-                            <div id="logging-in-throbber" hidden>
-                              <div class="throbber"></div>
-                            </div>
-                          </td>
-                          <td class="no-vertical-padding">
-                            <input id="sign-in" type="submit" name="signIn"
-                                i18n-values="value:signin">
-                            <input id="gaia-cancel" type="button"
-                                name="cancel"
-                                i18n-values="value:cancel">
-                          </td>
-                        </tr>
-                      </table>
-                    </td>
-                  </tr>
-                  <tr id="ga-fprow">
-                    <td colspan="2" height="16.0" class="gaia-le-fpwd"
-                        align="center" valign="bottom">
-                      <a i18n-values="href:cannotaccessaccounturl"
-                          target="_blank"
-                          i18n-content="cannotaccessaccount">
-                      </a>
-                    </td>
-                  </tr>
-                  <tr>
-                    <td id="create-account-cell" colspan="2" height="16.0"
-                        class="gaia-le-fpwd" align="center" valign="bottom">
-                      <div id="create-account-div">
-                        <a i18n-values="href:createnewaccounturl"
-                            i18n-content="createaccount" target="_blank">
-                        </a>
-                      </div>
-                   </td>
-                  </tr>
-                </table>
-              </div>
-            </td>
-          </tr>
-        </table>
-      </div>
-    </form>
-  </div>
-  <div>
-    <div id="cancel-space-no-captcha" colspan="2">
-    </div>
-  </div>
-</div>
-</body>
-</html>
diff --git a/chrome/browser/sync/resources/gaia_login.js b/chrome/browser/sync/resources/gaia_login.js
deleted file mode 100644
index 5ce1b48..0000000
--- a/chrome/browser/sync/resources/gaia_login.js
+++ /dev/null
@@ -1,249 +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.
-
-// Variable to track if a captcha challenge was issued. If this gets set to
-// true, it stays that way until we are told about successful login from
-// the browser.  This means subsequent errors (like invalid password) are
-// rendered in the captcha state, which is basically identical except we
-// don't show the top error blurb "Error Signing in" or the "Create
-// account" link.
-var g_is_captcha_challenge_active = false;
-
-// Taken from new_tab.js.
-// TODO(tim): Can this be unified?
-function url(s) {
-  // http://www.w3.org/TR/css3-values/#uris
-  // Parentheses, commas, whitespace characters, single quotes (') and
-  // double quotes (") appearing in a URI must be escaped with a backslash
-  var s2 = s.replace(/(\(|\)|\,|\s|\'|\"|\\)/g, '\\$1');
-  // WebKit has a bug when it comes to URLs that end with \
-  // https://bugs.webkit.org/show_bug.cgi?id=28885
-  if (/\\\\$/.test(s2)) {
-    // Add a space to work around the WebKit bug.
-    s2 += ' ';
-  }
-  return 'url("' + s2 + '")';
-}
-
-function gaia_setFocus() {
-  var form = document.getElementById('gaia-login-form');
-  if (form.email && (form.email.value == null || form.email.value == '')) {
-    form.email.focus();
-  } else if (form.passwd) {
-    form.passwd.focus();
-  }
-}
-
-function showGaiaLogin(args) {
-  document.getElementById('logging-in-throbber').hidden = true;
-
-  document.getElementById('email').disabled = false;
-  document.getElementById('passwd').disabled = false;
-
-  var f = document.getElementById('gaia-login-form');
-  if (f) {
-    if (args.user != undefined) {
-      if (f.email.value != args.user)
-        f.passwd.value = ''; // Reset the password field
-      f.email.value = args.user;
-    }
-
-    var editable_user = args.editable_user;
-    f.email.hidden = !editable_user;
-    var emailReadonly = document.getElementById('email-readonly');
-    emailReadonly.hidden = editable_user;
-    emailReadonly.textContent = f.email.value;
-    setElementVisible('create-account-div', editable_user);
-    f.accessCode.disabled = true;
-  }
-
-  if (1 == args.error) {
-    var access_code = document.getElementById('access-code');
-    if (access_code.value && access_code.value != '') {
-      setElementVisible('errormsg-0-access-code', true);
-      showAccessCodeRequired();
-    } else {
-      setElementVisible('errormsg-1-password', true);
-    }
-    setBlurbError(args.error_message);
-  } else if (3 == args.error) {
-    setElementVisible('errormsg-0-connection', true);
-    setBlurbError(args.error_message);
-  } else if (4 == args.error) {
-    showCaptcha(args);
-  } else if (8 == args.error) {
-    showAccessCodeRequired();
-  } else if (args.error_message) {
-    setBlurbError(args.error_message);
-  }
-
-  document.getElementById('sign-in').disabled = false;
-  document.getElementById('sign-in').value = templateData['signin'];
-  gaia_setFocus();
-}
-
-function showCaptcha(args) {
-  g_is_captcha_challenge_active = true;
-
-  // The captcha takes up lots of space, so make room.
-  $('top-blurb-error').hidden = true;
-  setElementVisible('top-blurb', false);
-  setElementVisible('create-account-div', false);
-  document.getElementById('create-account-cell').height = 0;
-
-  // It's showtime for the captcha now.
-  setElementVisible('captcha-div', true);
-  document.getElementById('email').disabled = true;
-  document.getElementById('passwd').disabled = false;
-  document.getElementById('captcha-value').disabled = false;
-  document.getElementById('captcha-wrapper').style.backgroundImage =
-      url(args.captchaUrl);
-}
-
-function showAccessCodeRequired() {
-  setElementVisible('password-row', false);
-  setElementVisible('email-row', false);
-  document.getElementById('create-account-cell').style.visibility = 'hidden';
-
-  setElementVisible('access-code-label-row', true);
-  setElementVisible('access-code-input-row', true);
-  setElementVisible('access-code-help-row', true);
-  document.getElementById('access-code').disabled = false;
-}
-
-function CloseDialog() {
-  chrome.send('DialogClose', ['']);
-}
-
-function showGaiaSuccessAndClose() {
-  document.getElementById('sign-in').value = templateData['success'];
-  setTimeout(CloseDialog, 1600);
-}
-
-function showGaiaSuccessAndSettingUp() {
-  document.getElementById('sign-in').value = templateData['settingup'];
-}
-
-/**
- * DOMContentLoaded handler, sets up the page.
- */
-function load() {
-  var acct_text = document.getElementById('gaia-account-text');
-  var translated_text = acct_text.textContent;
-  var posGoogle = translated_text.indexOf('Google');
-  if (posGoogle != -1) {
-    var ltr = templateData['textdirection'] == 'ltr';
-    var googleIsAtEndOfSentence = posGoogle != 0;
-    if (googleIsAtEndOfSentence == ltr) {
-      // We're in ltr and in the translation the word 'Google' is AFTER the
-      // word 'Account' OR we're in rtl and 'Google' is BEFORE 'Account'.
-      var logo_div = document.getElementById('gaia-logo');
-      logo_div.parentNode.appendChild(logo_div);
-    }
-    acct_text.textContent = translated_text.replace('Google','');
-  }
-
-  var loginForm = document.getElementById('gaia-login-form');
-  loginForm.onsubmit = function() {
-    sendCredentialsAndClose();
-    return false;
-  };
-
-  var gaiaCancel = document.getElementById('gaia-cancel');
-  gaiaCancel.onclick = function() {
-    CloseDialog();
-  };
-
-  var args = JSON.parse(chrome.getVariableValue("dialogArguments"));
-  showGaiaLogin(args);
-}
-
-function sendCredentialsAndClose() {
-  if (!setErrorVisibility())
-    return false;
-
-  document.getElementById('email').disabled = true;
-  document.getElementById('passwd').disabled = true;
-  document.getElementById('captcha-value').disabled = true;
-  document.getElementById('access-code').disabled = true;
-
-  document.getElementById('logging-in-throbber').hidden = false;
-
-  var f = document.getElementById('gaia-login-form');
-  var result = JSON.stringify({'user' : f.email.value,
-                               'pass' : f.passwd.value,
-                               'captcha' : f.captchaValue.value,
-                               'access_code' : f.accessCode.value});
-  document.getElementById('sign-in').disabled = true;
-  chrome.send('SubmitAuth', [result]);
-}
-
-function setElementVisible(id, display) {
-  var d = document.getElementById(id);
-  if (d)
-    d.hidden = !display;
-}
-
-function hideBlurb() {
-  setElementVisible('top-blurb', false);
-}
-
-function setBlurbError(error_message) {
-  if (g_is_captcha_challenge_active)
-    return;  // No blurb in captcha challenge mode.
-  if (error_message) {
-    document.getElementById('error-signing-in').hidden = true;
-    document.getElementById('error-custom').hidden = false;
-    document.getElementById('error-custom').textContent = error_message;
-  } else {
-    document.getElementById('error-signing-in').hidden = false;
-    document.getElementById('error-custom').hidden = true;
-  }
-  document.getElementById('top-blurb-error').hidden = false;
-  document.getElementById('email').disabled = false;
-  document.getElementById('passwd').disabled = false;
-}
-
-function resetErrorVisibility() {
-  setElementVisible('errormsg-0-email', false);
-  setElementVisible('errormsg-0-password', false);
-  setElementVisible('errormsg-1-password', false);
-  setElementVisible('errormsg-0-connection', false);
-  setElementVisible('errormsg-0-access-code', false);
-}
-
-function setErrorVisibility() {
-  resetErrorVisibility();
-  var f = document.getElementById('gaia-login-form');
-  if (null == f.email.value || '' == f.email.value) {
-    setElementVisible('errormsg-0-email', true);
-    setBlurbError();
-    return false;
-  }
-  if (null == f.passwd.value || '' == f.passwd.value) {
-    setElementVisible('errormsg-0-password', true);
-    setBlurbError();
-    return false;
-  }
-  if (!f.accessCode.disabled && (null == f.accessCode.value ||
-      '' == f.accessCode.value)) {
-    setElementVisible('errormsg-0-password', true);
-    return false;
-  }
-  return true;
-}
-
-function onPreCreateAccount() {
-  return true;
-}
-
-function onPreLogin() {
-  if (window['onlogin'] != null) {
-    return onlogin();
-  } else {
-    return true;
-  }
-}
-
-document.addEventListener('DOMContentLoaded', load);
diff --git a/chrome/browser/sync/resources/gaia_login_test.html b/chrome/browser/sync/resources/gaia_login_test.html
deleted file mode 100644
index c3b5875..0000000
--- a/chrome/browser/sync/resources/gaia_login_test.html
+++ /dev/null
@@ -1,123 +0,0 @@
-<!DOCTYPE html>
-<html>
-<!--
-This page is a simple testing environment for gaia_login.html to help
-iterate on the design without having to compile and launch the
-browser.  Note that you must supply the "--allow-file-access-from-files"
-for the chrome you are using to load this page for this to work.
--->
-<style>
-body {
-  background-color: #d0d0d0;
-}
-
-#iframe {
-  height: 375px;
-  width: 421px;
-  border: 0px;
-  float: left;
-}
-#options {
-  float: left;
-}
-
-</style>
-<script>
-function gel(id) {
-  return document.getElementById(id);
-}
-
-function get_selected_value(el) {
-  for (var i = 0; i < el.length; ++i) {
-    if (el[i].checked)
-      return el[i].value;
-  }
-  return null;
-}
-
-function set_up_testing() {
-  var win = window.frames[0];
-  var doc = win.document;
-  var form = gel("form");
-  form.addEventListener("change", function() { update(); }, true);
-
-  win.JSON = {};
-  win.JSON.parse = function() {
-    return {
-      error: get_selected_value(form.error),
-      user: "homer@gmail.com",
-      captchaUrl: "https://accounts.google.com/Captcha"
-    };
-  };
-
-  console.log(win.JSON.parse());
-
-  set_text("introduction",
-           "Chromium sync makes it easy to share your data (such as " +
-           "bookmarks and preferences) between your computers. Chromium " +
-           "synchronizes your data by storing it online with Google when " +
-           "you login with your Google Account.");
-  set_text("settingupsync", "Setting up sync");
-  set_text("errorsigningin", "Error signing in.");
-  set_text("signinsuffix", "Account");
-  set_text("emaillabel", "Email:");
-  set_text("cannotbeblank", "cannotbeblank");
-  set_text("passwordlabel", "Password:");
-  set_text("invalidcredentials", "Invalid user name or password.");
-  set_text("captchainstructions",
-           "Enter the correct password above and then type the characters " +
-           "you see in the picture below.");
-  set_text("couldnotconnect", "Could not connect to the server");
-  set_text("value:signin", "Sign in");
-  set_text("href:cannotaccessaccounturl", "href:cannotaccessaccounturl");
-  set_text("cannotaccessaccount", "I cannot access my account");
-  set_text("href:createnewaccounturl", "href:createnewaccounturl");
-  set_text("createaccount", "Create a Google account");
-  set_text("value:cancel", "Cancel");
-
-  function set_text(id, text) {
-    if (id.indexOf(":") >= 0) {
-      var node = doc.evaluate("//*[@i18n-values='" + id + "']",
-                              doc,
-                              null,
-                              XPathResult.FIRST_ORDERED_NODE_TYPE,
-                              null).singleNodeValue;
-      node.setAttribute(id.split(":")[0], text);
-    } else {
-      var node = doc.evaluate("//*[@i18n-content='" + id + "']",
-                              doc,
-                              null,
-                              XPathResult.FIRST_ORDERED_NODE_TYPE,
-                              null).singleNodeValue;
-      node.innerHTML = text;
-    }
-  }
-
-  win.initForm();
-}
-
-function update() {
-  window.frames[0].document.location.reload();
-}
-
-</script>
-<body>
-<div>
-<iframe
-  id="iframe"
-  src="gaia_login.html"
-  onload="set_up_testing()">
-</iframe>
-<div id="options">
-<form id="form" name="form">
-<p>
-  <input type="radio" name="error" value="" checked> No Error
-  <input type="radio" name="error" value="1"> Bad Password
-  <input type="radio" name="error" value="3"> Lost Connection
-  <input type="radio" name="error" value="4"> Captcha
-</p>
-</form>
-</div>
-</div>
-</body>
-</html>
diff --git a/chrome/browser/sync/resources/google_transparent.png b/chrome/browser/sync/resources/google_transparent.png
deleted file mode 100644
index 026969e..0000000
--- a/chrome/browser/sync/resources/google_transparent.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/sync/retry_verifier.h b/chrome/browser/sync/retry_verifier.h
index 77219bf..7d8d3e9 100644
--- a/chrome/browser/sync/retry_verifier.h
+++ b/chrome/browser/sync/retry_verifier.h
@@ -5,7 +5,7 @@
 #ifndef CHROME_BROWSER_SYNC_RETRY_VERIFIER_H_
 #define CHROME_BROWSER_SYNC_RETRY_VERIFIER_H_
 
-#include "base/time.h"
+#include "base/time/time.h"
 
 // TODO(akalin): Move this to somewhere in sync/ and make
 // sync/engine/polling_constants.h private.
diff --git a/chrome/browser/sync/sync_prefs.cc b/chrome/browser/sync/sync_prefs.cc
index 2bfbc71..66fd680 100644
--- a/chrome/browser/sync/sync_prefs.cc
+++ b/chrome/browser/sync/sync_prefs.cc
@@ -111,6 +111,12 @@
       std::string(),
       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
 
+  // Keeps track whether server experiments have been switched on for that user.
+  registry->RegisterBooleanPref(
+      prefs::kSyncFaviconsEnabled,
+      false,
+      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
+
   // We will start prompting people about new data types after the launch of
   // SESSIONS - all previously launched data types are treated as if they are
   // already acknowledged.
diff --git a/chrome/browser/sync/sync_prefs.h b/chrome/browser/sync/sync_prefs.h
index 4fa9cee..21ae4e8 100644
--- a/chrome/browser/sync/sync_prefs.h
+++ b/chrome/browser/sync/sync_prefs.h
@@ -11,7 +11,7 @@
 #include "base/observer_list.h"
 #include "base/prefs/pref_member.h"
 #include "base/threading/non_thread_safe.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "sync/internal_api/public/base/model_type.h"
 #include "sync/notifier/invalidation_state_tracker.h"
 
diff --git a/chrome/browser/sync/sync_prefs_unittest.cc b/chrome/browser/sync/sync_prefs_unittest.cc
index 042df83..2320726 100644
--- a/chrome/browser/sync/sync_prefs_unittest.cc
+++ b/chrome/browser/sync/sync_prefs_unittest.cc
@@ -6,7 +6,7 @@
 
 #include "base/command_line.h"
 #include "base/message_loop.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/testing_pref_service_syncable.h"
diff --git a/chrome/browser/sync/sync_ui_util.cc b/chrome/browser/sync/sync_ui_util.cc
index 46aebd5..645bc4c 100644
--- a/chrome/browser/sync/sync_ui_util.cc
+++ b/chrome/browser/sync/sync_ui_util.cc
@@ -56,10 +56,8 @@
                                         user_name);
     } else if (service->IsStartSuppressed()) {
       // User is signed in, but sync has been stopped.
-      return l10n_util::GetStringFUTF16(
-          IDS_SIGNED_IN_WITH_SYNC_SUPPRESSED,
-          user_name,
-          ASCIIToUTF16(chrome::kSyncGoogleDashboardURL));
+      return l10n_util::GetStringFUTF16(IDS_SIGNED_IN_WITH_SYNC_SUPPRESSED,
+                                        user_name);
     }
   }
 
@@ -253,8 +251,7 @@
       if (status_label) {
         string16 label = l10n_util::GetStringFUTF16(
                              IDS_SIGNED_IN_WITH_SYNC_SUPPRESSED,
-                             UTF8ToUTF16(signin.GetAuthenticatedUsername()),
-                             ASCIIToUTF16(chrome::kSyncGoogleDashboardURL));
+                             UTF8ToUTF16(signin.GetAuthenticatedUsername()));
         status_label->assign(label);
         result_type = PRE_SYNCED;
       }
diff --git a/chrome/browser/sync/test/integration/autofill_helper.cc b/chrome/browser/sync/test/integration/autofill_helper.cc
index 944e8fa..bc9bf3e 100644
--- a/chrome/browser/sync/test/integration/autofill_helper.cc
+++ b/chrome/browser/sync/test/integration/autofill_helper.cc
@@ -11,14 +11,14 @@
 #include "chrome/browser/sync/test/integration/sync_datatype_helper.h"
 #include "chrome/browser/sync/test/integration/sync_test.h"
 #include "chrome/common/chrome_notification_types.h"
-#include "components/autofill/browser/autofill_common_test.h"
-#include "components/autofill/browser/autofill_profile.h"
-#include "components/autofill/browser/autofill_type.h"
-#include "components/autofill/browser/personal_data_manager.h"
-#include "components/autofill/browser/personal_data_manager_observer.h"
-#include "components/autofill/browser/webdata/autofill_entry.h"
-#include "components/autofill/browser/webdata/autofill_table.h"
-#include "components/autofill/browser/webdata/autofill_webdata_service.h"
+#include "components/autofill/core/browser/autofill_common_test.h"
+#include "components/autofill/core/browser/autofill_profile.h"
+#include "components/autofill/core/browser/autofill_type.h"
+#include "components/autofill/core/browser/personal_data_manager.h"
+#include "components/autofill/core/browser/personal_data_manager_observer.h"
+#include "components/autofill/core/browser/webdata/autofill_entry.h"
+#include "components/autofill/core/browser/webdata/autofill_table.h"
+#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
 #include "components/autofill/core/common/form_field_data.h"
 #include "components/webdata/common/web_database.h"
 
diff --git a/chrome/browser/sync/test/integration/bookmarks_helper.h b/chrome/browser/sync/test/integration/bookmarks_helper.h
index 286974f..f1a62e8 100644
--- a/chrome/browser/sync/test/integration/bookmarks_helper.h
+++ b/chrome/browser/sync/test/integration/bookmarks_helper.h
@@ -11,9 +11,9 @@
 
 #include "base/compiler_specific.h"
 #include "chrome/browser/bookmarks/bookmark_model.h"
-#include "googleurl/src/gurl.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/skia/include/core/SkBitmap.h"
+#include "url/gurl.h"
 
 class GURL;
 
diff --git a/chrome/browser/sync/test/integration/passwords_helper.cc b/chrome/browser/sync/test/integration/passwords_helper.cc
index e72133f..739d294 100644
--- a/chrome/browser/sync/test/integration/passwords_helper.cc
+++ b/chrome/browser/sync/test/integration/passwords_helper.cc
@@ -8,7 +8,7 @@
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/synchronization/waitable_event.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/password_manager/password_form_data.h"
 #include "chrome/browser/password_manager/password_store.h"
 #include "chrome/browser/password_manager/password_store_consumer.h"
diff --git a/chrome/browser/sync/test/integration/performance/autofill_sync_perf_test.cc b/chrome/browser/sync/test/integration/performance/autofill_sync_perf_test.cc
index 5f97f2b..49d79ad 100644
--- a/chrome/browser/sync/test/integration/performance/autofill_sync_perf_test.cc
+++ b/chrome/browser/sync/test/integration/performance/autofill_sync_perf_test.cc
@@ -9,9 +9,9 @@
 #include "chrome/browser/sync/test/integration/bookmarks_helper.h"
 #include "chrome/browser/sync/test/integration/performance/sync_timing_helper.h"
 #include "chrome/browser/sync/test/integration/sync_test.h"
-#include "components/autofill/browser/autofill_common_test.h"
-#include "components/autofill/browser/autofill_profile.h"
-#include "components/autofill/browser/webdata/autofill_entry.h"
+#include "components/autofill/core/browser/autofill_common_test.h"
+#include "components/autofill/core/browser/autofill_profile.h"
+#include "components/autofill/core/browser/webdata/autofill_entry.h"
 
 using autofill::AutofillFieldType;
 using autofill::AutofillKey;
diff --git a/chrome/browser/sync/test/integration/performance/sync_timing_helper.cc b/chrome/browser/sync/test/integration/performance/sync_timing_helper.cc
index 6a0b4ee..5e7eb26 100644
--- a/chrome/browser/sync/test/integration/performance/sync_timing_helper.cc
+++ b/chrome/browser/sync/test/integration/performance/sync_timing_helper.cc
@@ -5,7 +5,7 @@
 #include "chrome/browser/sync/test/integration/performance/sync_timing_helper.h"
 
 #include "base/strings/string_number_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/sync/profile_sync_service_harness.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/chrome/browser/sync/test/integration/search_engines_helper.cc b/chrome/browser/sync/test/integration/search_engines_helper.cc
index 8e82def..3838d22 100644
--- a/chrome/browser/sync/test/integration/search_engines_helper.cc
+++ b/chrome/browser/sync/test/integration/search_engines_helper.cc
@@ -9,7 +9,7 @@
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/search_engines/template_url.h"
 #include "chrome/browser/search_engines/template_url_service.h"
diff --git a/chrome/browser/sync/test/integration/sessions_helper.cc b/chrome/browser/sync/test/integration/sessions_helper.cc
index da843cb..fa90917 100644
--- a/chrome/browser/sync/test/integration/sessions_helper.cc
+++ b/chrome/browser/sync/test/integration/sessions_helper.cc
@@ -8,7 +8,7 @@
 
 #include "base/stl_util.h"
 #include "base/test/test_timeouts.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/sync/glue/session_model_associator.h"
 #include "chrome/browser/sync/profile_sync_service.h"
@@ -18,7 +18,7 @@
 #include "chrome/browser/sync/test/integration/sync_test.h"
 #include "chrome/browser/ui/singleton_tabs.h"
 #include "chrome/test/base/ui_test_utils.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 using sync_datatype_helper::test;
 
diff --git a/chrome/browser/sync/test/integration/sync_test.cc b/chrome/browser/sync/test/integration/sync_test.cc
index cdbe54c..8d75d64 100644
--- a/chrome/browser/sync/test/integration/sync_test.cc
+++ b/chrome/browser/sync/test/integration/sync_test.cc
@@ -21,6 +21,8 @@
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
 #include "chrome/browser/google/google_url_tracker.h"
 #include "chrome/browser/history/history_service_factory.h"
+#include "chrome/browser/invalidation/invalidation_service_factory.h"
+#include "chrome/browser/invalidation/p2p_invalidation_service.h"
 #include "chrome/browser/lifetime/application_lifetime.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
@@ -41,7 +43,6 @@
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/test_browser_thread.h"
 #include "google_apis/gaia/gaia_urls.h"
-#include "googleurl/src/gurl.h"
 #include "net/base/escape.h"
 #include "net/base/load_flags.h"
 #include "net/base/network_change_notifier.h"
@@ -58,8 +59,10 @@
 #include "sync/engine/sync_scheduler_impl.h"
 #include "sync/notifier/p2p_invalidator.h"
 #include "sync/protocol/sync.pb.h"
+#include "url/gurl.h"
 
 using content::BrowserThread;
+using invalidation::InvalidationServiceFactory;
 
 namespace switches {
 const char kPasswordFileForTest[] = "password-file-for-test";
@@ -196,19 +199,10 @@
 }
 
 void SyncTest::AddTestSwitches(CommandLine* cl) {
-  // TODO(rsimha): Until we implement a fake Tango server against which tests
-  // can run, we need to set the --sync-notification-method to "p2p".
-  if (!cl->HasSwitch(switches::kSyncNotificationMethod))
-    cl->AppendSwitchASCII(switches::kSyncNotificationMethod, "p2p");
-
   // Disable non-essential access of external network resources.
   if (!cl->HasSwitch(switches::kDisableBackgroundNetworking))
     cl->AppendSwitch(switches::kDisableBackgroundNetworking);
 
-  // TODO(sync): remove this once keystore encryption is enabled by default.
-  if (!cl->HasSwitch(switches::kSyncKeystoreEncryption))
-    cl->AppendSwitch(switches::kSyncKeystoreEncryption);
-
   if (!cl->HasSwitch(switches::kSyncShortInitialRetryOverride))
     cl->AppendSwitch(switches::kSyncShortInitialRetryOverride);
 
@@ -306,18 +300,26 @@
                                           << index << ".";
 
   browsers_[index] = new Browser(Browser::CreateParams(
-      GetProfile(index), chrome::HOST_DESKTOP_TYPE_NATIVE));
+      GetProfile(index), chrome::GetActiveDesktop()));
   EXPECT_FALSE(GetBrowser(index) == NULL) << "Could not create Browser "
                                           << index << ".";
 
+  invalidation::P2PInvalidationService* p2p_invalidation_service =
+      InvalidationServiceFactory::GetInstance()->
+          BuildAndUseP2PInvalidationServiceForTest(GetProfile(index));
+  p2p_invalidation_service->UpdateCredentials(username_, password_);
+
   // Make sure the ProfileSyncService has been created before creating the
   // ProfileSyncServiceHarness - some tests expect the ProfileSyncService to
   // already exist.
   ProfileSyncServiceFactory::GetForProfile(GetProfile(index));
 
-  clients_[index] = new ProfileSyncServiceHarness(GetProfile(index),
-                                                  username_,
-                                                  password_);
+  clients_[index] =
+      ProfileSyncServiceHarness::CreateForIntegrationTest(
+          GetProfile(index),
+          username_,
+          password_,
+          p2p_invalidation_service);
   EXPECT_FALSE(GetClient(index) == NULL) << "Could not create Client "
                                          << index << ".";
 
diff --git a/chrome/browser/sync/test/integration/two_client_autofill_sync_test.cc b/chrome/browser/sync/test/integration/two_client_autofill_sync_test.cc
index 412ffa9..49ea529 100644
--- a/chrome/browser/sync/test/integration/two_client_autofill_sync_test.cc
+++ b/chrome/browser/sync/test/integration/two_client_autofill_sync_test.cc
@@ -7,11 +7,11 @@
 #include "chrome/browser/sync/test/integration/autofill_helper.h"
 #include "chrome/browser/sync/test/integration/bookmarks_helper.h"
 #include "chrome/browser/sync/test/integration/sync_test.h"
-#include "components/autofill/browser/autofill_profile.h"
-#include "components/autofill/browser/credit_card.h"
-#include "components/autofill/browser/personal_data_manager.h"
-#include "components/autofill/browser/webdata/autofill_entry.h"
-#include "components/autofill/browser/webdata/autofill_table.h"
+#include "components/autofill/core/browser/autofill_profile.h"
+#include "components/autofill/core/browser/credit_card.h"
+#include "components/autofill/core/browser/personal_data_manager.h"
+#include "components/autofill/core/browser/webdata/autofill_entry.h"
+#include "components/autofill/core/browser/webdata/autofill_table.h"
 
 using autofill::AutofillKey;
 using autofill::AutofillTable;
diff --git a/chrome/browser/sync/test/integration/two_client_preferences_sync_test.cc b/chrome/browser/sync/test/integration/two_client_preferences_sync_test.cc
index 83e6936..8ed733c5 100644
--- a/chrome/browser/sync/test/integration/two_client_preferences_sync_test.cc
+++ b/chrome/browser/sync/test/integration/two_client_preferences_sync_test.cc
@@ -401,18 +401,18 @@
 
   TranslatePrefs translate_client0_prefs(GetPrefs(0));
   TranslatePrefs translate_client1_prefs(GetPrefs(1));
-  ASSERT_FALSE(translate_client0_prefs.IsLanguageBlacklisted("fr"));
-  translate_client0_prefs.BlacklistLanguage("fr");
-  ASSERT_TRUE(translate_client0_prefs.IsLanguageBlacklisted("fr"));
+  ASSERT_FALSE(translate_client0_prefs.IsBlockedLanguage("fr"));
+  translate_client0_prefs.BlockLanguage("fr");
+  ASSERT_TRUE(translate_client0_prefs.IsBlockedLanguage("fr"));
 
   ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1)));
-  ASSERT_TRUE(translate_client1_prefs.IsLanguageBlacklisted("fr"));
+  ASSERT_TRUE(translate_client1_prefs.IsBlockedLanguage("fr"));
 
-  translate_client0_prefs.RemoveLanguageFromBlacklist("fr");
-  ASSERT_FALSE(translate_client0_prefs.IsLanguageBlacklisted("fr"));
+  translate_client0_prefs.UnblockLanguage("fr");
+  ASSERT_FALSE(translate_client0_prefs.IsBlockedLanguage("fr"));
 
   ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1)));
-  ASSERT_FALSE(translate_client1_prefs.IsLanguageBlacklisted("fr"));
+  ASSERT_FALSE(translate_client1_prefs.IsBlockedLanguage("fr"));
 }
 
 // TCM ID - 7307195.
diff --git a/chrome/browser/sync/test/integration/typed_urls_helper.cc b/chrome/browser/sync/test/integration/typed_urls_helper.cc
index 205dec0..c297fef 100644
--- a/chrome/browser/sync/test/integration/typed_urls_helper.cc
+++ b/chrome/browser/sync/test/integration/typed_urls_helper.cc
@@ -7,7 +7,7 @@
 #include "base/compiler_specific.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/synchronization/waitable_event.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/common/cancelable_request.h"
 #include "chrome/browser/history/history_backend.h"
 #include "chrome/browser/history/history_db_task.h"
diff --git a/chrome/browser/sync/test_profile_sync_service.cc b/chrome/browser/sync/test_profile_sync_service.cc
index 0937065..dac67f2 100644
--- a/chrome/browser/sync/test_profile_sync_service.cc
+++ b/chrome/browser/sync/test_profile_sync_service.cc
@@ -36,7 +36,6 @@
 SyncBackendHostForProfileSyncTest::SyncBackendHostForProfileSyncTest(
     Profile* profile,
     const base::WeakPtr<SyncPrefs>& sync_prefs,
-    const base::WeakPtr<invalidation::InvalidatorStorage>& invalidator_storage,
     syncer::TestIdFactory& id_factory,
     base::Closure& callback,
     bool set_initial_sync_ended_on_init,
@@ -44,7 +43,7 @@
     bool fail_initial_download,
     syncer::StorageOption storage_option)
     : browser_sync::SyncBackendHost(
-        profile->GetDebugName(), profile, sync_prefs, invalidator_storage),
+        profile->GetDebugName(), profile, sync_prefs),
       weak_ptr_factory_(this),
       id_factory_(id_factory),
       callback_(callback),
@@ -104,6 +103,7 @@
 void SyncBackendHostForProfileSyncTest::RequestConfigureSyncer(
     syncer::ConfigureReason reason,
     syncer::ModelTypeSet to_download,
+    syncer::ModelTypeSet to_purge,
     syncer::ModelTypeSet to_journal,
     syncer::ModelTypeSet to_unapply,
     syncer::ModelTypeSet to_ignore,
@@ -115,8 +115,13 @@
   if (fail_initial_download_)
     failed_configuration_types = to_download;
 
+  // The first parameter there should be the set of enabled types.  That's not
+  // something we have access to from this strange test harness.  We'll just
+  // send back the list of newly configured types instead and hope it doesn't
+  // break anything.
   FinishConfigureDataTypesOnFrontendLoop(
       syncer::Difference(to_download, failed_configuration_types),
+      syncer::Difference(to_download, failed_configuration_types),
       failed_configuration_types,
       ready_task);
 }
@@ -178,16 +183,6 @@
   }
 }
 
-void SyncBackendHostForProfileSyncTest::EmitOnInvalidatorStateChange(
-    syncer::InvalidatorState state) {
-  frontend()->OnInvalidatorStateChange(state);
-}
-
-void SyncBackendHostForProfileSyncTest::EmitOnIncomingInvalidation(
-    const syncer::ObjectIdInvalidationMap& invalidation_map) {
-  frontend()->OnIncomingInvalidation(invalidation_map);
-}
-
 void SyncBackendHostForProfileSyncTest::ContinueInitialization(
     const syncer::WeakHandle<syncer::JsBackend>& js_backend,
     const syncer::WeakHandle<syncer::DataTypeDebugInfoListener>&
@@ -310,7 +305,6 @@
   backend_.reset(new browser_sync::SyncBackendHostForProfileSyncTest(
       profile(),
       sync_prefs_.AsWeakPtr(),
-      invalidator_storage_.AsWeakPtr(),
       id_factory_,
       callback_,
       set_initial_sync_ended_on_init_,
diff --git a/chrome/browser/sync/test_profile_sync_service.h b/chrome/browser/sync/test_profile_sync_service.h
index dd76f2c..41d2687 100644
--- a/chrome/browser/sync/test_profile_sync_service.h
+++ b/chrome/browser/sync/test_profile_sync_service.h
@@ -46,8 +46,6 @@
   SyncBackendHostForProfileSyncTest(
       Profile* profile,
       const base::WeakPtr<SyncPrefs>& sync_prefs,
-      const base::WeakPtr<invalidation::InvalidatorStorage>&
-          invalidator_storage,
       syncer::TestIdFactory& id_factory,
       base::Closure& callback,
       bool set_initial_sync_ended_on_init,
@@ -64,6 +62,7 @@
   virtual void RequestConfigureSyncer(
       syncer::ConfigureReason reason,
       syncer::ModelTypeSet to_download,
+      syncer::ModelTypeSet to_purge,
       syncer::ModelTypeSet to_journal,
       syncer::ModelTypeSet to_unapply,
       syncer::ModelTypeSet to_ignore,
@@ -80,10 +79,6 @@
 
   static void SetHistoryServiceExpectations(ProfileMock* profile);
 
-  void EmitOnInvalidatorStateChange(syncer::InvalidatorState state);
-  void EmitOnIncomingInvalidation(
-      const syncer::ObjectIdInvalidationMap& invalidation_map);
-
  protected:
   virtual void InitCore(const DoInitializeOptions& options) OVERRIDE;
 
diff --git a/chrome/browser/sync_file_system/conflict_resolution_policy.h b/chrome/browser/sync_file_system/conflict_resolution_policy.h
index 2fee089..648ed2c 100644
--- a/chrome/browser/sync_file_system/conflict_resolution_policy.h
+++ b/chrome/browser/sync_file_system/conflict_resolution_policy.h
@@ -9,15 +9,15 @@
 
 enum ConflictResolutionPolicy {
   // Resolution policy unknown or not initialized. Usually indicates an error.
-  CONFLICT_RESOLUTION_UNKNOWN,
+  CONFLICT_RESOLUTION_POLICY_UNKNOWN,
 
   // The service automatically resolves a conflict by choosing the one
   // that is updated more recently.
-  CONFLICT_RESOLUTION_LAST_WRITE_WIN,
+  CONFLICT_RESOLUTION_POLICY_LAST_WRITE_WIN,
 
   // The service does nothing and just leaves conflicting files in
   // 'conflicted' state.
-  CONFLICT_RESOLUTION_MANUAL,
+  CONFLICT_RESOLUTION_POLICY_MANUAL,
 };
 
 }  // namespace sync_file_system
diff --git a/chrome/browser/sync_file_system/conflict_resolution_resolver.cc b/chrome/browser/sync_file_system/conflict_resolution_resolver.cc
new file mode 100644
index 0000000..50fed10
--- /dev/null
+++ b/chrome/browser/sync_file_system/conflict_resolution_resolver.cc
@@ -0,0 +1,47 @@
+// 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/conflict_resolution_resolver.h"
+
+#include "base/logging.h"
+#include "base/time/time.h"
+
+namespace sync_file_system {
+
+ConflictResolutionResolver::ConflictResolutionResolver(
+    ConflictResolutionPolicy policy)
+    : policy_(policy) {}
+
+ConflictResolutionResolver::~ConflictResolutionResolver() {}
+
+ConflictResolution ConflictResolutionResolver::Resolve(
+      SyncFileType local_file_type,
+      const base::Time& local_update_time,
+      SyncFileType remote_file_type,
+      const base::Time& remote_update_time) {
+  // Currently we always prioritize directories over files regardless of
+  // conflict resolution policy.
+  if (remote_file_type == SYNC_FILE_TYPE_DIRECTORY)
+    return CONFLICT_RESOLUTION_REMOTE_WIN;
+
+  if (policy_ == CONFLICT_RESOLUTION_POLICY_MANUAL)
+    return CONFLICT_RESOLUTION_MARK_CONFLICT;
+
+  // Remote time is null, cannot determine the resolution.
+  if (remote_update_time.is_null())
+    return CONFLICT_RESOLUTION_UNKNOWN;
+
+  // Local time should be always given.
+  DCHECK(!local_update_time.is_null());
+
+  DCHECK_EQ(CONFLICT_RESOLUTION_POLICY_LAST_WRITE_WIN, policy_);
+  if (local_update_time >= remote_update_time ||
+      remote_file_type == SYNC_FILE_TYPE_UNKNOWN) {
+    return CONFLICT_RESOLUTION_LOCAL_WIN;
+  }
+
+  return CONFLICT_RESOLUTION_REMOTE_WIN;
+}
+
+}  // namespace sync_file_system
diff --git a/chrome/browser/sync_file_system/conflict_resolution_resolver.h b/chrome/browser/sync_file_system/conflict_resolution_resolver.h
new file mode 100644
index 0000000..da07149
--- /dev/null
+++ b/chrome/browser/sync_file_system/conflict_resolution_resolver.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 CHROME_BROWSER_SYNC_FILE_SYSTEM_CONFLICT_RESOLUTION_RESOLVER_H_
+#define CHROME_BROWSER_SYNC_FILE_SYSTEM_CONFLICT_RESOLUTION_RESOLVER_H_
+
+#include "chrome/browser/sync_file_system/conflict_resolution_policy.h"
+#include "webkit/browser/fileapi/syncable/sync_file_type.h"
+
+namespace base {
+class Time;
+}
+
+namespace sync_file_system {
+
+enum ConflictResolution {
+  CONFLICT_RESOLUTION_UNKNOWN,
+  CONFLICT_RESOLUTION_MARK_CONFLICT,
+  CONFLICT_RESOLUTION_LOCAL_WIN,
+  CONFLICT_RESOLUTION_REMOTE_WIN,
+};
+
+class ConflictResolutionResolver {
+ public:
+  explicit ConflictResolutionResolver(ConflictResolutionPolicy policy);
+  ~ConflictResolutionResolver();
+
+  // Determine the ConflictResolution.
+  // This may return CONFLICT_RESOLUTION_UNKNOWN if NULL |remote_update_time|
+  // is given.
+  // It is invalid to give NULL |local_update_time|.
+  ConflictResolution Resolve(
+        SyncFileType local_file_type,
+        const base::Time& local_update_time,
+        SyncFileType remote_file_type,
+        const base::Time& remote_update_time);
+
+  ConflictResolutionPolicy policy() const { return policy_; }
+  void set_policy(ConflictResolutionPolicy policy) { policy_ = policy; }
+
+ private:
+  ConflictResolutionPolicy policy_;
+};
+
+}  // namespace sync_file_system
+
+#endif  // CHROME_BROWSER_SYNC_FILE_SYSTEM_CONFLICT_RESOLUTION_RESOLVER_H_
diff --git a/chrome/browser/sync_file_system/drive/api_util.cc b/chrome/browser/sync_file_system/drive/api_util.cc
deleted file mode 100644
index 01aaa41..0000000
--- a/chrome/browser/sync_file_system/drive/api_util.cc
+++ /dev/null
@@ -1,1077 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/sync_file_system/drive/api_util.h"
-
-#include <algorithm>
-#include <functional>
-#include <sstream>
-#include <string>
-
-#include "base/strings/string_util.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/values.h"
-#include "chrome/browser/drive/drive_api_service.h"
-#include "chrome/browser/drive/drive_uploader.h"
-#include "chrome/browser/drive/gdata_wapi_service.h"
-#include "chrome/browser/google_apis/drive_api_parser.h"
-#include "chrome/browser/google_apis/drive_api_util.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/sync_file_system/drive_file_sync_util.h"
-#include "chrome/browser/sync_file_system/logger.h"
-#include "chrome/common/extensions/extension.h"
-#include "extensions/common/constants.h"
-#include "net/base/mime_util.h"
-#include "webkit/browser/fileapi/syncable/syncable_file_system_util.h"
-
-namespace sync_file_system {
-namespace drive {
-
-namespace {
-
-enum ParentType {
-  PARENT_TYPE_ROOT_OR_EMPTY,
-  PARENT_TYPE_DIRECTORY,
-};
-
-const char kSyncRootDirectoryName[] = "Chrome Syncable FileSystem";
-const char kSyncRootDirectoryNameDev[] = "Chrome Syncable FileSystem Dev";
-const char kMimeTypeOctetStream[] = "application/octet-stream";
-
-// This path is not actually used but is required by DriveUploaderInterface.
-const base::FilePath::CharType kDummyDrivePath[] =
-    FILE_PATH_LITERAL("/dummy/drive/path");
-
-const char kFakeServerBaseUrl[] = "https://fake_server/";
-
-void EmptyGDataErrorCodeCallback(google_apis::GDataErrorCode error) {}
-
-bool HasParentLinkTo(const ScopedVector<google_apis::Link>& links,
-                     const std::string& parent_resource_id,
-                     ParentType parent_type) {
-  bool has_parent = false;
-
-  for (ScopedVector<google_apis::Link>::const_iterator itr = links.begin();
-       itr != links.end(); ++itr) {
-    if ((*itr)->type() == google_apis::Link::LINK_PARENT) {
-      has_parent = true;
-      if (google_apis::drive::util::ExtractResourceIdFromUrl((*itr)->href()) ==
-          parent_resource_id)
-        return true;
-    }
-  }
-
-  return parent_type == PARENT_TYPE_ROOT_OR_EMPTY && !has_parent;
-}
-
-struct TitleAndParentQuery
-    : std::unary_function<const google_apis::ResourceEntry*, bool> {
-  TitleAndParentQuery(const std::string& title,
-                      const std::string& parent_resource_id,
-                      ParentType parent_type)
-      : title(title),
-        parent_resource_id(parent_resource_id),
-        parent_type(parent_type) {}
-
-  bool operator()(const google_apis::ResourceEntry* entry) const {
-    return entry->title() == title &&
-           HasParentLinkTo(entry->links(), parent_resource_id, parent_type);
-  }
-
-  const std::string& title;
-  const std::string& parent_resource_id;
-  ParentType parent_type;
-};
-
-void FilterEntriesByTitleAndParent(
-    ScopedVector<google_apis::ResourceEntry>* entries,
-    const std::string& title,
-    const std::string& parent_resource_id,
-    ParentType parent_type) {
-  typedef ScopedVector<google_apis::ResourceEntry>::iterator iterator;
-  iterator itr = std::partition(entries->begin(),
-                                entries->end(),
-                                TitleAndParentQuery(title,
-                                                    parent_resource_id,
-                                                    parent_type));
-  entries->erase(itr, entries->end());
-}
-
-google_apis::ResourceEntry* GetDocumentByTitleAndParent(
-    const ScopedVector<google_apis::ResourceEntry>& entries,
-    const std::string& title,
-    const std::string& parent_resource_id,
-    ParentType parent_type) {
-  typedef ScopedVector<google_apis::ResourceEntry>::const_iterator iterator;
-  iterator found =
-      std::find_if(entries.begin(),
-                   entries.end(),
-                   TitleAndParentQuery(title, parent_resource_id, parent_type));
-  if (found != entries.end())
-    return *found;
-  return NULL;
-}
-
-void EntryAdapterForEnsureTitleUniqueness(
-    scoped_ptr<google_apis::ResourceEntry> entry,
-    const APIUtil::EnsureUniquenessCallback& callback,
-    APIUtil::EnsureUniquenessStatus status,
-    google_apis::GDataErrorCode error) {
-  callback.Run(error, status, entry.Pass());
-}
-
-void UploadResultAdapter(const APIUtil::ResourceEntryCallback& callback,
-                         google_apis::GDataErrorCode error,
-                         const GURL& upload_location,
-                         scoped_ptr<google_apis::ResourceEntry> entry) {
-  callback.Run(error, entry.Pass());
-}
-
-}  // namespace
-
-APIUtil::APIUtil(Profile* profile)
-    : wapi_url_generator_(
-          GURL(google_apis::GDataWapiUrlGenerator::kBaseUrlForProduction)),
-      drive_api_url_generator_(
-          GURL(google_apis::DriveApiUrlGenerator::kBaseUrlForProduction)),
-      upload_next_key_(0) {
-  if (IsDriveAPIDisabled()) {
-    drive_service_.reset(new google_apis::GDataWapiService(
-        profile->GetRequestContext(),
-        GURL(google_apis::GDataWapiUrlGenerator::kBaseUrlForProduction),
-        std::string() /* custom_user_agent */));
-  } else {
-    drive_service_.reset(new google_apis::DriveAPIService(
-        profile->GetRequestContext(),
-        GURL(google_apis::DriveApiUrlGenerator::kBaseUrlForProduction),
-        std::string() /* custom_user_agent */));
-  }
-
-  drive_service_->Initialize(profile);
-  drive_service_->AddObserver(this);
-  net::NetworkChangeNotifier::AddConnectionTypeObserver(this);
-
-  drive_uploader_.reset(new google_apis::DriveUploader(drive_service_.get()));
-}
-
-scoped_ptr<APIUtil> APIUtil::CreateForTesting(
-    Profile* profile,
-    scoped_ptr<google_apis::DriveServiceInterface> drive_service,
-    scoped_ptr<google_apis::DriveUploaderInterface> drive_uploader) {
-  return make_scoped_ptr(new APIUtil(
-      profile,
-      GURL(kFakeServerBaseUrl),
-      drive_service.Pass(),
-      drive_uploader.Pass()));
-}
-
-APIUtil::APIUtil(Profile* profile,
-                 const GURL& base_url,
-                 scoped_ptr<google_apis::DriveServiceInterface> drive_service,
-                 scoped_ptr<google_apis::DriveUploaderInterface> drive_uploader)
-    : wapi_url_generator_(base_url),
-      drive_api_url_generator_(base_url),
-      upload_next_key_(0) {
-  drive_service_ = drive_service.Pass();
-  drive_service_->Initialize(profile);
-  drive_service_->AddObserver(this);
-  net::NetworkChangeNotifier::AddConnectionTypeObserver(this);
-
-  drive_uploader_ = drive_uploader.Pass();
-}
-
-APIUtil::~APIUtil() {
-  DCHECK(CalledOnValidThread());
-  net::NetworkChangeNotifier::RemoveConnectionTypeObserver(this);
-  drive_service_->RemoveObserver(this);
-}
-
-void APIUtil::AddObserver(APIUtilObserver* observer) {
-  DCHECK(CalledOnValidThread());
-  observers_.AddObserver(observer);
-}
-
-void APIUtil::RemoveObserver(APIUtilObserver* observer) {
-  DCHECK(CalledOnValidThread());
-  observers_.RemoveObserver(observer);
-}
-
-void APIUtil::GetDriveRootResourceId(const GDataErrorCallback& callback) {
-  DCHECK(CalledOnValidThread());
-  DCHECK(!IsDriveAPIDisabled());
-  DVLOG(2) << "Getting resource id for Drive root";
-
-  drive_service_->GetAboutResource(
-      base::Bind(&APIUtil::DidGetDriveRootResourceId, AsWeakPtr(), callback));
-}
-
-void APIUtil::DidGetDriveRootResourceId(
-    const GDataErrorCallback& callback,
-    google_apis::GDataErrorCode error,
-    scoped_ptr<google_apis::AboutResource> about_resource) {
-  DCHECK(CalledOnValidThread());
-
-  if (error != google_apis::HTTP_SUCCESS) {
-    DVLOG(2) << "Error on getting resource id for Drive root: " << error;
-    callback.Run(error);
-    return;
-  }
-
-  DCHECK(about_resource);
-  root_resource_id_ = about_resource->root_folder_id();
-  DCHECK(!root_resource_id_.empty());
-  DVLOG(2) << "Got resource id for Drive root: " << root_resource_id_;
-  callback.Run(error);
-}
-
-void APIUtil::GetDriveDirectoryForSyncRoot(const ResourceIdCallback& callback) {
-  DCHECK(CalledOnValidThread());
-
-  if (GetRootResourceId().empty()) {
-    GetDriveRootResourceId(
-        base::Bind(&APIUtil::DidGetDriveRootResourceIdForGetSyncRoot,
-                   AsWeakPtr(), callback));
-    return;
-  }
-
-  DVLOG(2) << "Getting Drive directory for SyncRoot";
-  std::string directory_name(GetSyncRootDirectoryName());
-  SearchByTitle(directory_name,
-                std::string(),
-                base::Bind(&APIUtil::DidGetDirectory,
-                           AsWeakPtr(),
-                           std::string(),
-                           directory_name,
-                           callback));
-}
-
-void APIUtil::DidGetDriveRootResourceIdForGetSyncRoot(
-    const ResourceIdCallback& callback,
-    google_apis::GDataErrorCode error) {
-  DCHECK(CalledOnValidThread());
-  if (error != google_apis::HTTP_SUCCESS) {
-    DVLOG(2) << "Error on getting Drive directory for SyncRoot: " << error;
-    callback.Run(error, std::string());
-    return;
-  }
-  GetDriveDirectoryForSyncRoot(callback);
-}
-
-void APIUtil::GetDriveDirectoryForOrigin(
-    const std::string& sync_root_resource_id,
-    const GURL& origin,
-    const ResourceIdCallback& callback) {
-  DCHECK(CalledOnValidThread());
-  DVLOG(2) << "Getting Drive directory for Origin: " << origin;
-
-  std::string directory_name(OriginToDirectoryTitle(origin));
-  SearchByTitle(directory_name,
-                sync_root_resource_id,
-                base::Bind(&APIUtil::DidGetDirectory,
-                           AsWeakPtr(),
-                           sync_root_resource_id,
-                           directory_name,
-                           callback));
-}
-
-void APIUtil::DidGetDirectory(const std::string& parent_resource_id,
-                              const std::string& directory_name,
-                              const ResourceIdCallback& callback,
-                              google_apis::GDataErrorCode error,
-                              scoped_ptr<google_apis::ResourceList> feed) {
-  DCHECK(CalledOnValidThread());
-  DCHECK(IsStringASCII(directory_name));
-
-  if (error != google_apis::HTTP_SUCCESS) {
-    DVLOG(2) << "Error on getting Drive directory: " << error;
-    callback.Run(error, std::string());
-    return;
-  }
-
-  std::string resource_id;
-  ParentType parent_type = PARENT_TYPE_DIRECTORY;
-  if (parent_resource_id.empty()) {
-    resource_id = GetRootResourceId();
-    DCHECK(!resource_id.empty());
-    parent_type = PARENT_TYPE_ROOT_OR_EMPTY;
-  } else {
-    resource_id = parent_resource_id;
-  }
-  std::string title(directory_name);
-  google_apis::ResourceEntry* entry = GetDocumentByTitleAndParent(
-      feed->entries(), title, resource_id, parent_type);
-  if (!entry) {
-    DVLOG(2) << "Directory not found. Creating: " << directory_name;
-    drive_service_->AddNewDirectory(resource_id,
-                                    directory_name,
-                                    base::Bind(&APIUtil::DidCreateDirectory,
-                                               AsWeakPtr(),
-                                               parent_resource_id,
-                                               title,
-                                               callback));
-    return;
-  }
-  DVLOG(2) << "Found Drive directory.";
-
-  // TODO(tzik): Handle error.
-  DCHECK_EQ(google_apis::ENTRY_KIND_FOLDER, entry->kind());
-  DCHECK_EQ(directory_name, entry->title());
-
-  if (entry->title() == GetSyncRootDirectoryName())
-    EnsureSyncRootIsNotInMyDrive(entry->resource_id());
-
-  callback.Run(error, entry->resource_id());
-}
-
-void APIUtil::DidCreateDirectory(const std::string& parent_resource_id,
-                                 const std::string& title,
-                                 const ResourceIdCallback& callback,
-                                 google_apis::GDataErrorCode error,
-                                 scoped_ptr<google_apis::ResourceEntry> entry) {
-  DCHECK(CalledOnValidThread());
-
-  if (error != google_apis::HTTP_SUCCESS &&
-      error != google_apis::HTTP_CREATED) {
-    DVLOG(2) << "Error on creating Drive directory: " << error;
-    callback.Run(error, std::string());
-    return;
-  }
-  DVLOG(2) << "Created Drive directory.";
-
-  DCHECK(entry);
-  // Check if any other client creates a directory with same title.
-  EnsureTitleUniqueness(
-      parent_resource_id,
-      title,
-      base::Bind(&APIUtil::DidEnsureUniquenessForCreateDirectory,
-                 AsWeakPtr(),
-                 callback));
-}
-
-void APIUtil::DidEnsureUniquenessForCreateDirectory(
-    const ResourceIdCallback& callback,
-    google_apis::GDataErrorCode error,
-    EnsureUniquenessStatus status,
-    scoped_ptr<google_apis::ResourceEntry> entry) {
-  DCHECK(CalledOnValidThread());
-
-  if (error != google_apis::HTTP_SUCCESS) {
-    callback.Run(error, std::string());
-    return;
-  }
-
-  if (status == NO_DUPLICATES_FOUND)
-    error = google_apis::HTTP_CREATED;
-
-  DCHECK(entry) << "No entry: " << error;
-
-  if (!entry->is_folder()) {
-    // TODO(kinuko): Fix this. http://crbug.com/237090
-    util::Log(
-        logging::LOG_ERROR,
-        FROM_HERE,
-        "A file is left for CreateDirectory due to file-folder conflict!");
-    callback.Run(google_apis::HTTP_CONFLICT, std::string());
-    return;
-  }
-
-  if (entry->title() == GetSyncRootDirectoryName())
-    EnsureSyncRootIsNotInMyDrive(entry->resource_id());
-
-  callback.Run(error, entry->resource_id());
-}
-
-void APIUtil::GetLargestChangeStamp(const ChangeStampCallback& callback) {
-  DCHECK(CalledOnValidThread());
-  DVLOG(2) << "Getting largest change id";
-
-  drive_service_->GetAboutResource(
-      base::Bind(&APIUtil::DidGetLargestChangeStamp, AsWeakPtr(), callback));
-}
-
-void APIUtil::GetResourceEntry(const std::string& resource_id,
-                               const ResourceEntryCallback& callback) {
-  DCHECK(CalledOnValidThread());
-  DVLOG(2) << "Getting ResourceEntry for: " << resource_id;
-
-  drive_service_->GetResourceEntry(
-      resource_id,
-      base::Bind(&APIUtil::DidGetResourceEntry, AsWeakPtr(), callback));
-}
-
-void APIUtil::DidGetLargestChangeStamp(
-    const ChangeStampCallback& callback,
-    google_apis::GDataErrorCode error,
-    scoped_ptr<google_apis::AboutResource> about_resource) {
-  DCHECK(CalledOnValidThread());
-
-  int64 largest_change_id = 0;
-  if (error == google_apis::HTTP_SUCCESS) {
-    DCHECK(about_resource);
-    largest_change_id = about_resource->largest_change_id();
-    root_resource_id_ = about_resource->root_folder_id();
-    DVLOG(2) << "Got largest change id: " << largest_change_id;
-  } else {
-    DVLOG(2) << "Error on getting largest change id: " << error;
-  }
-
-  callback.Run(error, largest_change_id);
-}
-
-void APIUtil::SearchByTitle(const std::string& title,
-                            const std::string& directory_resource_id,
-                            const ResourceListCallback& callback) {
-  DCHECK(CalledOnValidThread());
-  DCHECK(!title.empty());
-  DVLOG(2) << "Searching resources in the directory [" << directory_resource_id
-           << "] with title [" << title << "]";
-
-  drive_service_->SearchByTitle(
-      title,
-      directory_resource_id,
-      base::Bind(&APIUtil::DidGetResourceList, AsWeakPtr(), callback));
-}
-
-void APIUtil::ListFiles(const std::string& directory_resource_id,
-                        const ResourceListCallback& callback) {
-  DCHECK(CalledOnValidThread());
-  DVLOG(2) << "Listing resources in the directory [" << directory_resource_id
-           << "]";
-
-  drive_service_->GetResourceListInDirectory(directory_resource_id, callback);
-}
-
-void APIUtil::ListChanges(int64 start_changestamp,
-                          const ResourceListCallback& callback) {
-  DCHECK(CalledOnValidThread());
-  DVLOG(2) << "Listing changes since: " << start_changestamp;
-
-  drive_service_->GetChangeList(
-      start_changestamp,
-      base::Bind(&APIUtil::DidGetResourceList, AsWeakPtr(), callback));
-}
-
-void APIUtil::ContinueListing(const GURL& feed_url,
-                              const ResourceListCallback& callback) {
-  DCHECK(CalledOnValidThread());
-  DVLOG(2) << "Continue listing on feed: " << feed_url;
-
-  drive_service_->ContinueGetResourceList(
-      feed_url,
-      base::Bind(&APIUtil::DidGetResourceList, AsWeakPtr(), callback));
-}
-
-void APIUtil::DownloadFile(const std::string& resource_id,
-                           const std::string& local_file_md5,
-                           const base::FilePath& local_file_path,
-                           const DownloadFileCallback& callback) {
-  DCHECK(CalledOnValidThread());
-  DVLOG(2) << "Downloading file [" << resource_id << "]";
-
-  drive_service_->GetResourceEntry(
-      resource_id,
-      base::Bind(&APIUtil::DidGetResourceEntry,
-                 AsWeakPtr(),
-                 base::Bind(&APIUtil::DownloadFileInternal,
-                            AsWeakPtr(),
-                            local_file_md5,
-                            local_file_path,
-                            callback)));
-}
-
-void APIUtil::UploadNewFile(const std::string& directory_resource_id,
-                            const base::FilePath& local_file_path,
-                            const std::string& title,
-                            const UploadFileCallback& callback) {
-  DCHECK(CalledOnValidThread());
-  DVLOG(2) << "Uploading new file into the directory [" << directory_resource_id
-           << "] with title [" << title << "]";
-
-  std::string mime_type;
-  if (!net::GetWellKnownMimeTypeFromExtension(local_file_path.Extension(),
-                                              &mime_type))
-    mime_type = kMimeTypeOctetStream;
-
-  UploadKey upload_key = RegisterUploadCallback(callback);
-  ResourceEntryCallback did_upload_callback =
-      base::Bind(&APIUtil::DidUploadNewFile,
-                 AsWeakPtr(),
-                 directory_resource_id,
-                 title,
-                 upload_key);
-  drive_uploader_->UploadNewFile(
-      directory_resource_id,
-      base::FilePath(kDummyDrivePath),
-      local_file_path,
-      title,
-      mime_type,
-      base::Bind(&UploadResultAdapter, did_upload_callback),
-      google_apis::ProgressCallback());
-}
-
-void APIUtil::UploadExistingFile(const std::string& resource_id,
-                                 const std::string& remote_file_md5,
-                                 const base::FilePath& local_file_path,
-                                 const UploadFileCallback& callback) {
-  DCHECK(CalledOnValidThread());
-  DVLOG(2) << "Uploading existing file [" << resource_id << "]";
-  drive_service_->GetResourceEntry(
-      resource_id,
-      base::Bind(&APIUtil::DidGetResourceEntry,
-                 AsWeakPtr(),
-                 base::Bind(&APIUtil::UploadExistingFileInternal,
-                            AsWeakPtr(),
-                            remote_file_md5,
-                            local_file_path,
-                            callback)));
-}
-
-void APIUtil::CreateDirectory(const std::string& parent_resource_id,
-                              const std::string& title,
-                              const ResourceIdCallback& callback) {
-  DCHECK(CalledOnValidThread());
-  // TODO(kinuko): This will call EnsureTitleUniqueness and will delete
-  // directories if there're duplicated directories. This must be ok
-  // for current design but we'll need to merge directories when we support
-  // 'real' directories.
-  drive_service_->AddNewDirectory(parent_resource_id,
-                                  title,
-                                  base::Bind(&APIUtil::DidCreateDirectory,
-                                             AsWeakPtr(),
-                                             parent_resource_id,
-                                             title,
-                                             callback));
-}
-
-void APIUtil::DeleteFile(const std::string& resource_id,
-                         const std::string& remote_file_md5,
-                         const GDataErrorCallback& callback) {
-  DCHECK(CalledOnValidThread());
-  DVLOG(2) << "Deleting file: " << resource_id;
-
-  // Load actual remote_file_md5 to check for conflict before deletion.
-  if (!remote_file_md5.empty()) {
-    drive_service_->GetResourceEntry(
-        resource_id,
-        base::Bind(&APIUtil::DidGetResourceEntry,
-                   AsWeakPtr(),
-                   base::Bind(&APIUtil::DeleteFileInternal,
-                              AsWeakPtr(),
-                              remote_file_md5,
-                              callback)));
-    return;
-  }
-
-  // Expected remote_file_md5 is empty so do a force delete.
-  drive_service_->DeleteResource(
-      resource_id,
-      std::string(),
-      base::Bind(&APIUtil::DidDeleteFile, AsWeakPtr(), callback));
-  return;
-}
-
-GURL APIUtil::ResourceIdToResourceLink(const std::string& resource_id) const {
-  return IsDriveAPIDisabled()
-      ? wapi_url_generator_.GenerateEditUrl(resource_id)
-      : drive_api_url_generator_.GetFileUrl(resource_id);
-}
-
-void APIUtil::EnsureSyncRootIsNotInMyDrive(
-    const std::string& sync_root_resource_id) {
-  DCHECK(CalledOnValidThread());
-
-  if (GetRootResourceId().empty()) {
-    GetDriveRootResourceId(
-        base::Bind(&APIUtil::DidGetDriveRootResourceIdForEnsureSyncRoot,
-                   AsWeakPtr(), sync_root_resource_id));
-    return;
-  }
-
-  DVLOG(2) << "Ensuring the sync root directory is not in 'My Drive'.";
-  drive_service_->RemoveResourceFromDirectory(
-      GetRootResourceId(),
-      sync_root_resource_id,
-      base::Bind(&EmptyGDataErrorCodeCallback));
-}
-
-void APIUtil::DidGetDriveRootResourceIdForEnsureSyncRoot(
-    const std::string& sync_root_resource_id,
-    google_apis::GDataErrorCode error) {
-  DCHECK(CalledOnValidThread());
-
-  if (error != google_apis::HTTP_SUCCESS) {
-    DVLOG(2) << "Error on ensuring the sync root directory is not in"
-             << " 'My Drive': " << error;
-    // Give up ensuring the sync root directory is not in 'My Drive'. This will
-    // be retried at some point.
-    return;
-  }
-
-  DCHECK(!GetRootResourceId().empty());
-  EnsureSyncRootIsNotInMyDrive(sync_root_resource_id);
-}
-
-// static
-// TODO(calvinlo): Delete this when Sync Directory Operations are supported by
-// default.
-std::string APIUtil::GetSyncRootDirectoryName() {
-  return IsSyncFSDirectoryOperationEnabled() ? kSyncRootDirectoryNameDev
-                                             : kSyncRootDirectoryName;
-}
-
-// static
-std::string APIUtil::OriginToDirectoryTitle(const GURL& origin) {
-  DCHECK(origin.SchemeIs(extensions::kExtensionScheme));
-  return origin.host();
-}
-
-// static
-GURL APIUtil::DirectoryTitleToOrigin(const std::string& title) {
-  return extensions::Extension::GetBaseURLFromExtensionId(title);
-}
-
-void APIUtil::OnReadyToSendRequests() {
-  DCHECK(CalledOnValidThread());
-  FOR_EACH_OBSERVER(APIUtilObserver, observers_, OnAuthenticated());
-}
-
-void APIUtil::OnConnectionTypeChanged(
-    net::NetworkChangeNotifier::ConnectionType type) {
-  DCHECK(CalledOnValidThread());
-  if (type != net::NetworkChangeNotifier::CONNECTION_NONE) {
-    FOR_EACH_OBSERVER(APIUtilObserver, observers_, OnNetworkConnected());
-    return;
-  }
-  // We're now disconnected, reset the drive_uploader_ to force stop
-  // uploading, otherwise the uploader may get stuck.
-  // TODO(kinuko): Check the uploader behavior if it's the expected behavior
-  // (http://crbug.com/223818)
-  CancelAllUploads(google_apis::GDATA_NO_CONNECTION);
-}
-
-void APIUtil::DidGetResourceList(
-    const ResourceListCallback& callback,
-    google_apis::GDataErrorCode error,
-    scoped_ptr<google_apis::ResourceList> resource_list) {
-  DCHECK(CalledOnValidThread());
-
-  if (error != google_apis::HTTP_SUCCESS) {
-    DVLOG(2) << "Error on listing resource: " << error;
-    callback.Run(error, scoped_ptr<google_apis::ResourceList>());
-    return;
-  }
-
-  DVLOG(2) << "Got resource list";
-  DCHECK(resource_list);
-  callback.Run(error, resource_list.Pass());
-}
-
-void APIUtil::DidGetResourceEntry(
-    const ResourceEntryCallback& callback,
-    google_apis::GDataErrorCode error,
-    scoped_ptr<google_apis::ResourceEntry> entry) {
-  DCHECK(CalledOnValidThread());
-
-  if (error != google_apis::HTTP_SUCCESS) {
-    DVLOG(2) << "Error on getting resource entry:" << error;
-    callback.Run(error, scoped_ptr<google_apis::ResourceEntry>());
-    return;
-  }
-
-  DVLOG(2) << "Got resource entry";
-  DCHECK(entry);
-  callback.Run(error, entry.Pass());
-}
-
-void APIUtil::DownloadFileInternal(
-    const std::string& local_file_md5,
-    const base::FilePath& local_file_path,
-    const DownloadFileCallback& callback,
-    google_apis::GDataErrorCode error,
-    scoped_ptr<google_apis::ResourceEntry> entry) {
-  DCHECK(CalledOnValidThread());
-
-  if (error != google_apis::HTTP_SUCCESS) {
-    DVLOG(2) << "Error on getting resource entry for download";
-    callback.Run(error, std::string(), 0, base::Time());
-    return;
-  }
-  DCHECK(entry);
-
-  DVLOG(2) << "Got resource entry for download";
-  // If local file and remote file are same, cancel the download.
-  if (local_file_md5 == entry->file_md5()) {
-    callback.Run(google_apis::HTTP_NOT_MODIFIED,
-                 local_file_md5,
-                 entry->file_size(),
-                 entry->updated_time());
-    return;
-  }
-
-  DVLOG(2) << "Downloading file: " << entry->resource_id();
-  const GURL& download_url = entry->download_url();
-  drive_service_->DownloadFile(base::FilePath(kDummyDrivePath),
-                               local_file_path,
-                               download_url,
-                               base::Bind(&APIUtil::DidDownloadFile,
-                                          AsWeakPtr(),
-                                          base::Passed(&entry),
-                                          callback),
-                               google_apis::GetContentCallback(),
-                               google_apis::ProgressCallback());
-}
-
-void APIUtil::DidDownloadFile(scoped_ptr<google_apis::ResourceEntry> entry,
-                              const DownloadFileCallback& callback,
-                              google_apis::GDataErrorCode error,
-                              const base::FilePath& downloaded_file_path) {
-  DCHECK(CalledOnValidThread());
-  if (error == google_apis::HTTP_SUCCESS)
-    DVLOG(2) << "Download completed";
-  else
-    DVLOG(2) << "Error on downloading file: " << error;
-
-  callback.Run(
-      error, entry->file_md5(), entry->file_size(), entry->updated_time());
-}
-
-void APIUtil::DidUploadNewFile(const std::string& parent_resource_id,
-                               const std::string& title,
-                               UploadKey upload_key,
-                               google_apis::GDataErrorCode error,
-                               scoped_ptr<google_apis::ResourceEntry> entry) {
-  UploadFileCallback callback = GetAndUnregisterUploadCallback(upload_key);
-  DCHECK(!callback.is_null());
-  if (error != google_apis::HTTP_SUCCESS &&
-      error != google_apis::HTTP_CREATED) {
-    DVLOG(2) << "Error on uploading new file: " << error;
-    callback.Run(error, std::string(), std::string());
-    return;
-  }
-
-  DVLOG(2) << "Upload completed";
-  EnsureTitleUniqueness(parent_resource_id,
-                        title,
-                        base::Bind(&APIUtil::DidEnsureUniquenessForCreateFile,
-                                   AsWeakPtr(),
-                                   entry->resource_id(),
-                                   callback));
-}
-
-void APIUtil::DidEnsureUniquenessForCreateFile(
-    const std::string& expected_resource_id,
-    const UploadFileCallback& callback,
-    google_apis::GDataErrorCode error,
-    EnsureUniquenessStatus status,
-    scoped_ptr<google_apis::ResourceEntry> entry) {
-  if (error != google_apis::HTTP_SUCCESS) {
-    DVLOG(2) << "Error on uploading new file: " << error;
-    callback.Run(error, std::string(), std::string());
-    return;
-  }
-
-  switch (status) {
-    case NO_DUPLICATES_FOUND:
-      // The file was uploaded successfully and no conflict was detected.
-      DCHECK(entry);
-      DVLOG(2) << "No conflict detected on uploading new file";
-      callback.Run(
-          google_apis::HTTP_CREATED, entry->resource_id(), entry->file_md5());
-      return;
-
-    case RESOLVED_DUPLICATES:
-      // The file was uploaded successfully but a conflict was detected.
-      // The duplicated file was deleted successfully.
-      DCHECK(entry);
-      if (entry->resource_id() != expected_resource_id) {
-        // TODO(kinuko): We should check local vs remote md5 here.
-        DVLOG(2) << "Conflict detected on uploading new file";
-        callback.Run(google_apis::HTTP_CONFLICT,
-                     entry->resource_id(),
-                     entry->file_md5());
-        return;
-      }
-
-      DVLOG(2) << "Conflict detected on uploading new file and resolved";
-      callback.Run(
-          google_apis::HTTP_CREATED, entry->resource_id(), entry->file_md5());
-      return;
-
-    default:
-      NOTREACHED() << "Unknown status from EnsureTitleUniqueness:" << status
-                   << " for " << expected_resource_id;
-  }
-}
-
-void APIUtil::UploadExistingFileInternal(
-    const std::string& remote_file_md5,
-    const base::FilePath& local_file_path,
-    const UploadFileCallback& callback,
-    google_apis::GDataErrorCode error,
-    scoped_ptr<google_apis::ResourceEntry> entry) {
-  DCHECK(CalledOnValidThread());
-
-  if (error != google_apis::HTTP_SUCCESS) {
-    DVLOG(2) << "Error on uploading existing file: " << error;
-    callback.Run(error, std::string(), std::string());
-    return;
-  }
-  DCHECK(entry);
-
-  // If remote file's hash value is different from the expected one, conflict
-  // might have occurred.
-  if (!remote_file_md5.empty() && remote_file_md5 != entry->file_md5()) {
-    DVLOG(2) << "Conflict detected before uploading existing file";
-    callback.Run(google_apis::HTTP_CONFLICT, std::string(), std::string());
-    return;
-  }
-
-  std::string mime_type;
-  if (!net::GetWellKnownMimeTypeFromExtension(local_file_path.Extension(),
-                                              &mime_type))
-    mime_type = kMimeTypeOctetStream;
-
-  UploadKey upload_key = RegisterUploadCallback(callback);
-  ResourceEntryCallback did_upload_callback =
-      base::Bind(&APIUtil::DidUploadExistingFile, AsWeakPtr(), upload_key);
-  drive_uploader_->UploadExistingFile(
-      entry->resource_id(),
-      base::FilePath(kDummyDrivePath),
-      local_file_path,
-      mime_type,
-      entry->etag(),
-      base::Bind(&UploadResultAdapter, did_upload_callback),
-      google_apis::ProgressCallback());
-}
-
-bool APIUtil::IsAuthenticated() const {
-  return drive_service_->HasRefreshToken();
-}
-
-void APIUtil::DidUploadExistingFile(
-    UploadKey upload_key,
-    google_apis::GDataErrorCode error,
-    scoped_ptr<google_apis::ResourceEntry> entry) {
-  DCHECK(CalledOnValidThread());
-  UploadFileCallback callback = GetAndUnregisterUploadCallback(upload_key);
-  DCHECK(!callback.is_null());
-  if (error != google_apis::HTTP_SUCCESS) {
-    DVLOG(2) << "Error on uploading existing file: " << error;
-    callback.Run(error, std::string(), std::string());
-    return;
-  }
-
-  DCHECK(entry);
-  DVLOG(2) << "Upload completed";
-  callback.Run(error, entry->resource_id(), entry->file_md5());
-}
-
-void APIUtil::DeleteFileInternal(const std::string& remote_file_md5,
-                                 const GDataErrorCallback& callback,
-                                 google_apis::GDataErrorCode error,
-                                 scoped_ptr<google_apis::ResourceEntry> entry) {
-  DCHECK(CalledOnValidThread());
-
-  if (error != google_apis::HTTP_SUCCESS) {
-    DVLOG(2) << "Error on getting resource entry for deleting file: " << error;
-    callback.Run(error);
-    return;
-  }
-  DCHECK(entry);
-
-  // If remote file's hash value is different from the expected one, conflict
-  // might have occurred.
-  if (!remote_file_md5.empty() && remote_file_md5 != entry->file_md5()) {
-    DVLOG(2) << "Conflict detected before deleting file";
-    callback.Run(google_apis::HTTP_CONFLICT);
-    return;
-  }
-  DVLOG(2) << "Got resource entry for deleting file";
-
-  // Move the file to trash (don't delete it completely).
-  drive_service_->DeleteResource(
-      entry->resource_id(),
-      entry->etag(),
-      base::Bind(&APIUtil::DidDeleteFile, AsWeakPtr(), callback));
-}
-
-void APIUtil::DidDeleteFile(const GDataErrorCallback& callback,
-                            google_apis::GDataErrorCode error) {
-  DCHECK(CalledOnValidThread());
-  if (error == google_apis::HTTP_SUCCESS)
-    DVLOG(2) << "Deletion completed";
-  else
-    DVLOG(2) << "Error on deleting file: " << error;
-
-  callback.Run(error);
-}
-
-void APIUtil::EnsureTitleUniqueness(const std::string& parent_resource_id,
-                                    const std::string& expected_title,
-                                    const EnsureUniquenessCallback& callback) {
-  DCHECK(CalledOnValidThread());
-  DVLOG(2) << "Checking if there's no conflict on entry creation";
-
-  const google_apis::GetResourceListCallback& bound_callback =
-      base::Bind(&APIUtil::DidListEntriesToEnsureUniqueness,
-                 AsWeakPtr(),
-                 parent_resource_id,
-                 expected_title,
-                 callback);
-
-  SearchByTitle(expected_title, parent_resource_id, bound_callback);
-}
-
-void APIUtil::DidListEntriesToEnsureUniqueness(
-    const std::string& parent_resource_id,
-    const std::string& expected_title,
-    const EnsureUniquenessCallback& callback,
-    google_apis::GDataErrorCode error,
-    scoped_ptr<google_apis::ResourceList> feed) {
-  DCHECK(CalledOnValidThread());
-
-  if (error != google_apis::HTTP_SUCCESS) {
-    DVLOG(2) << "Error on listing resource for ensuring title uniqueness";
-    callback.Run(
-        error, NO_DUPLICATES_FOUND, scoped_ptr<google_apis::ResourceEntry>());
-    return;
-  }
-  DVLOG(2) << "Got resource list for ensuring title uniqueness";
-
-  // This filtering is needed only on WAPI. Once we move to Drive API we can
-  // drop this.
-  std::string resource_id;
-  ParentType parent_type = PARENT_TYPE_DIRECTORY;
-  if (parent_resource_id.empty()) {
-    resource_id = GetRootResourceId();
-    DCHECK(!resource_id.empty());
-    parent_type = PARENT_TYPE_ROOT_OR_EMPTY;
-  } else {
-    resource_id = parent_resource_id;
-  }
-  ScopedVector<google_apis::ResourceEntry> entries;
-  entries.swap(*feed->mutable_entries());
-  FilterEntriesByTitleAndParent(
-      &entries, expected_title, resource_id, parent_type);
-
-  if (entries.empty()) {
-    DVLOG(2) << "Uploaded file is not found";
-    callback.Run(google_apis::HTTP_NOT_FOUND,
-                 NO_DUPLICATES_FOUND,
-                 scoped_ptr<google_apis::ResourceEntry>());
-    return;
-  }
-
-  if (entries.size() >= 2) {
-    DVLOG(2) << "Conflict detected on creating entry";
-    for (size_t i = 0; i < entries.size() - 1; ++i) {
-      // TODO(tzik): Replace published_time with creation time after we move to
-      // Drive API.
-      if (entries[i]->published_time() < entries.back()->published_time())
-        std::swap(entries[i], entries.back());
-    }
-
-    scoped_ptr<google_apis::ResourceEntry> earliest_entry(entries.back());
-    entries.back() = NULL;
-    entries.get().pop_back();
-
-    DeleteEntriesForEnsuringTitleUniqueness(
-        entries.Pass(),
-        base::Bind(&EntryAdapterForEnsureTitleUniqueness,
-                   base::Passed(&earliest_entry),
-                   callback,
-                   RESOLVED_DUPLICATES));
-    return;
-  }
-
-  DVLOG(2) << "no conflict detected";
-  DCHECK_EQ(1u, entries.size());
-  scoped_ptr<google_apis::ResourceEntry> entry(entries.front());
-  entries.weak_clear();
-
-  callback.Run(google_apis::HTTP_SUCCESS, NO_DUPLICATES_FOUND, entry.Pass());
-}
-
-void APIUtil::DeleteEntriesForEnsuringTitleUniqueness(
-    ScopedVector<google_apis::ResourceEntry> entries,
-    const GDataErrorCallback& callback) {
-  DCHECK(CalledOnValidThread());
-  DVLOG(2) << "Cleaning up conflict on entry creation";
-
-  if (entries.empty()) {
-    callback.Run(google_apis::HTTP_SUCCESS);
-    return;
-  }
-
-  scoped_ptr<google_apis::ResourceEntry> entry(entries.back());
-  entries.back() = NULL;
-  entries.get().pop_back();
-
-  // We don't care conflicts here as other clients may be also deleting this
-  // file, so passing an empty etag.
-  drive_service_->DeleteResource(
-      entry->resource_id(),
-      std::string(),  // empty etag
-      base::Bind(&APIUtil::DidDeleteEntriesForEnsuringTitleUniqueness,
-                 AsWeakPtr(),
-                 base::Passed(&entries),
-                 callback));
-}
-
-void APIUtil::DidDeleteEntriesForEnsuringTitleUniqueness(
-    ScopedVector<google_apis::ResourceEntry> entries,
-    const GDataErrorCallback& callback,
-    google_apis::GDataErrorCode error) {
-  DCHECK(CalledOnValidThread());
-
-  if (error != google_apis::HTTP_SUCCESS &&
-      error != google_apis::HTTP_NOT_FOUND) {
-    DVLOG(2) << "Error on deleting file: " << error;
-    callback.Run(error);
-    return;
-  }
-
-  DVLOG(2) << "Deletion completed";
-  DeleteEntriesForEnsuringTitleUniqueness(entries.Pass(), callback);
-}
-
-APIUtil::UploadKey APIUtil::RegisterUploadCallback(
-    const UploadFileCallback& callback) {
-  const bool inserted = upload_callback_map_.insert(
-      std::make_pair(upload_next_key_, callback)).second;
-  CHECK(inserted);
-  return upload_next_key_++;
-}
-
-APIUtil::UploadFileCallback APIUtil::GetAndUnregisterUploadCallback(
-    UploadKey key) {
-  UploadFileCallback callback;
-  UploadCallbackMap::iterator found = upload_callback_map_.find(key);
-  if (found == upload_callback_map_.end())
-    return callback;
-  callback = found->second;
-  upload_callback_map_.erase(found);
-  return callback;
-}
-
-void APIUtil::CancelAllUploads(google_apis::GDataErrorCode error) {
-  if (upload_callback_map_.empty())
-    return;
-  for (UploadCallbackMap::iterator iter = upload_callback_map_.begin();
-       iter != upload_callback_map_.end();
-       ++iter) {
-    iter->second.Run(error, std::string(), std::string());
-  }
-  upload_callback_map_.clear();
-  drive_uploader_.reset(new google_apis::DriveUploader(drive_service_.get()));
-}
-
-std::string APIUtil::GetRootResourceId() const {
-  if (IsDriveAPIDisabled())
-    return drive_service_->GetRootResourceId();
-  return root_resource_id_;
-}
-
-}  // namespace drive
-}  // namespace sync_file_system
diff --git a/chrome/browser/sync_file_system/drive/api_util.h b/chrome/browser/sync_file_system/drive/api_util.h
deleted file mode 100644
index 23359a0..0000000
--- a/chrome/browser/sync_file_system/drive/api_util.h
+++ /dev/null
@@ -1,255 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_SYNC_FILE_SYSTEM_DRIVE_API_UTIL_H_
-#define CHROME_BROWSER_SYNC_FILE_SYSTEM_DRIVE_API_UTIL_H_
-
-#include <map>
-#include <string>
-
-#include "base/memory/weak_ptr.h"
-#include "chrome/browser/drive/drive_service_interface.h"
-#include "chrome/browser/google_apis/drive_api_url_generator.h"
-#include "chrome/browser/google_apis/gdata_wapi_url_generator.h"
-#include "chrome/browser/sync_file_system/drive/api_util_interface.h"
-#include "net/base/network_change_notifier.h"
-
-class GURL;
-class Profile;
-
-namespace google_apis { class DriveUploaderInterface; }
-
-namespace sync_file_system {
-namespace drive {
-
-// This class is responsible for talking to the Drive service to get and put
-// Drive directories, files and metadata.
-// This class is owned by DriveFileSyncService.
-class APIUtil : public drive::APIUtilInterface,
-                public google_apis::DriveServiceObserver,
-                public net::NetworkChangeNotifier::ConnectionTypeObserver,
-                public base::NonThreadSafe,
-                public base::SupportsWeakPtr<APIUtil> {
- public:
-  // The resulting status of EnsureTitleUniqueness.
-  enum EnsureUniquenessStatus {
-    NO_DUPLICATES_FOUND,
-    RESOLVED_DUPLICATES,
-  };
-
-  typedef base::Callback<void(google_apis::GDataErrorCode,
-                              EnsureUniquenessStatus status,
-                              scoped_ptr<google_apis::ResourceEntry> entry)>
-      EnsureUniquenessCallback;
-
-  explicit APIUtil(Profile* profile);
-  virtual ~APIUtil();
-
-  virtual void AddObserver(APIUtilObserver* observer) OVERRIDE;
-  virtual void RemoveObserver(APIUtilObserver* observer) OVERRIDE;
-
-  static scoped_ptr<APIUtil> CreateForTesting(
-      Profile* profile,
-      scoped_ptr<google_apis::DriveServiceInterface> drive_service,
-      scoped_ptr<google_apis::DriveUploaderInterface> drive_uploader);
-
-  // APIUtilInterface overrides.
-  virtual void GetDriveDirectoryForSyncRoot(const ResourceIdCallback& callback)
-      OVERRIDE;
-  virtual void GetDriveDirectoryForOrigin(
-      const std::string& sync_root_resource_id,
-      const GURL& origin,
-      const ResourceIdCallback& callback) OVERRIDE;
-  virtual void GetLargestChangeStamp(const ChangeStampCallback& callback)
-      OVERRIDE;
-  virtual void GetResourceEntry(const std::string& resource_id,
-                                const ResourceEntryCallback& callback) OVERRIDE;
-  virtual void ListFiles(const std::string& directory_resource_id,
-                         const ResourceListCallback& callback) OVERRIDE;
-  virtual void ListChanges(int64 start_changestamp,
-                           const ResourceListCallback& callback) OVERRIDE;
-  virtual void ContinueListing(const GURL& feed_url,
-                               const ResourceListCallback& callback) OVERRIDE;
-  virtual void DownloadFile(const std::string& resource_id,
-                            const std::string& local_file_md5,
-                            const base::FilePath& local_file_path,
-                            const DownloadFileCallback& callback) OVERRIDE;
-  virtual void UploadNewFile(const std::string& directory_resource_id,
-                             const base::FilePath& local_file_path,
-                             const std::string& title,
-                             const UploadFileCallback& callback) OVERRIDE;
-  virtual void UploadExistingFile(const std::string& resource_id,
-                                  const std::string& remote_file_md5,
-                                  const base::FilePath& local_file_path,
-                                  const UploadFileCallback& callback) OVERRIDE;
-  virtual void CreateDirectory(const std::string& parent_resource_id,
-                               const std::string& title,
-                               const ResourceIdCallback& callback) OVERRIDE;
-  virtual bool IsAuthenticated() const OVERRIDE;
-  virtual void DeleteFile(const std::string& resource_id,
-                          const std::string& remote_file_md5,
-                          const GDataErrorCallback& callback) OVERRIDE;
-  virtual GURL ResourceIdToResourceLink(const std::string& resource_id) const
-      OVERRIDE;
-  virtual void EnsureSyncRootIsNotInMyDrive(
-      const std::string& sync_root_resource_id) OVERRIDE;
-
-  static std::string GetSyncRootDirectoryName();
-  static std::string OriginToDirectoryTitle(const GURL& origin);
-  static GURL DirectoryTitleToOrigin(const std::string& title);
-
-  // DriveServiceObserver overrides.
-  virtual void OnReadyToSendRequests() OVERRIDE;
-
-  // ConnectionTypeObserver overrides.
-  virtual void OnConnectionTypeChanged(
-      net::NetworkChangeNotifier::ConnectionType type) OVERRIDE;
-
- private:
-  typedef int64 UploadKey;
-  typedef std::map<UploadKey, UploadFileCallback> UploadCallbackMap;
-
-  friend class APIUtilTest;
-  friend class DriveFileSyncServiceMockTest;
-
-  // Constructor for test use.
-  APIUtil(Profile* profile,
-          const GURL& base_url,
-          scoped_ptr<google_apis::DriveServiceInterface> drive_service,
-          scoped_ptr<google_apis::DriveUploaderInterface> drive_uploader);
-
-  void GetDriveRootResourceId(const GDataErrorCallback& callback);
-  void DidGetDriveRootResourceId(
-      const GDataErrorCallback& callback,
-      google_apis::GDataErrorCode error,
-      scoped_ptr<google_apis::AboutResource> about_resource);
-
-  void DidGetDriveRootResourceIdForGetSyncRoot(
-      const ResourceIdCallback& callback,
-      google_apis::GDataErrorCode error);
-
-  void DidGetDirectory(const std::string& parent_resource_id,
-                       const std::string& directory_name,
-                       const ResourceIdCallback& callback,
-                       google_apis::GDataErrorCode error,
-                       scoped_ptr<google_apis::ResourceList> feed);
-
-  void DidCreateDirectory(const std::string& parent_resource_id,
-                          const std::string& title,
-                          const ResourceIdCallback& callback,
-                          google_apis::GDataErrorCode error,
-                          scoped_ptr<google_apis::ResourceEntry> entry);
-
-  void DidEnsureUniquenessForCreateDirectory(
-      const ResourceIdCallback& callback,
-      google_apis::GDataErrorCode error,
-      EnsureUniquenessStatus status,
-      scoped_ptr<google_apis::ResourceEntry> entry);
-
-  void SearchByTitle(const std::string& title,
-                     const std::string& directory_resource_id,
-                     const ResourceListCallback& callback);
-
-  void DidGetLargestChangeStamp(
-      const ChangeStampCallback& callback,
-      google_apis::GDataErrorCode error,
-      scoped_ptr<google_apis::AboutResource> about_resource);
-
-  void DidGetDriveRootResourceIdForEnsureSyncRoot(
-      const std::string& sync_root_resource_id,
-      google_apis::GDataErrorCode error);
-
-  void DidGetResourceList(const ResourceListCallback& callback,
-                          google_apis::GDataErrorCode error,
-                          scoped_ptr<google_apis::ResourceList> resource_list);
-
-  void DidGetResourceEntry(const ResourceEntryCallback& callback,
-                           google_apis::GDataErrorCode error,
-                           scoped_ptr<google_apis::ResourceEntry> entry);
-
-  void DownloadFileInternal(const std::string& local_file_md5,
-                            const base::FilePath& local_file_path,
-                            const DownloadFileCallback& callback,
-                            google_apis::GDataErrorCode error,
-                            scoped_ptr<google_apis::ResourceEntry> entry);
-
-  void DidDownloadFile(scoped_ptr<google_apis::ResourceEntry> entry,
-                       const DownloadFileCallback& callback,
-                       google_apis::GDataErrorCode error,
-                       const base::FilePath& downloaded_file_path);
-
-  void DidUploadNewFile(const std::string& parent_resource_id,
-                        const std::string& title,
-                        UploadKey upload_key,
-                        google_apis::GDataErrorCode error,
-                        scoped_ptr<google_apis::ResourceEntry> entry);
-
-  void DidEnsureUniquenessForCreateFile(
-      const std::string& expected_resource_id,
-      const UploadFileCallback& callback,
-      google_apis::GDataErrorCode error,
-      EnsureUniquenessStatus status,
-      scoped_ptr<google_apis::ResourceEntry> entry);
-
-  void UploadExistingFileInternal(const std::string& remote_file_md5,
-                                  const base::FilePath& local_file_path,
-                                  const UploadFileCallback& callback,
-                                  google_apis::GDataErrorCode error,
-                                  scoped_ptr<google_apis::ResourceEntry> entry);
-
-  void DidUploadExistingFile(UploadKey upload_key,
-                             google_apis::GDataErrorCode error,
-                             scoped_ptr<google_apis::ResourceEntry> entry);
-
-  void DeleteFileInternal(const std::string& remote_file_md5,
-                          const GDataErrorCallback& callback,
-                          google_apis::GDataErrorCode error,
-                          scoped_ptr<google_apis::ResourceEntry> entry);
-
-  void DidDeleteFile(const GDataErrorCallback& callback,
-                     google_apis::GDataErrorCode error);
-
-  void EnsureTitleUniqueness(const std::string& parent_resource_id,
-                             const std::string& expected_title,
-                             const EnsureUniquenessCallback& callback);
-  void DidListEntriesToEnsureUniqueness(
-      const std::string& parent_resource_id,
-      const std::string& expected_title,
-      const EnsureUniquenessCallback& callback,
-      google_apis::GDataErrorCode error,
-      scoped_ptr<google_apis::ResourceList> feed);
-  void DeleteEntriesForEnsuringTitleUniqueness(
-      ScopedVector<google_apis::ResourceEntry> entries,
-      const GDataErrorCallback& callback);
-  void DidDeleteEntriesForEnsuringTitleUniqueness(
-      ScopedVector<google_apis::ResourceEntry> entries,
-      const GDataErrorCallback& callback,
-      google_apis::GDataErrorCode error);
-
-  UploadKey RegisterUploadCallback(const UploadFileCallback& callback);
-  UploadFileCallback GetAndUnregisterUploadCallback(UploadKey key);
-  void CancelAllUploads(google_apis::GDataErrorCode error);
-
-  std::string GetRootResourceId() const;
-
-  scoped_ptr<google_apis::DriveServiceInterface> drive_service_;
-  scoped_ptr<google_apis::DriveUploaderInterface> drive_uploader_;
-
-  google_apis::GDataWapiUrlGenerator wapi_url_generator_;
-  google_apis::DriveApiUrlGenerator drive_api_url_generator_;
-
-  UploadCallbackMap upload_callback_map_;
-  UploadKey upload_next_key_;
-
-  std::string root_resource_id_;
-
-  ObserverList<APIUtilObserver> observers_;
-
-  DISALLOW_COPY_AND_ASSIGN(APIUtil);
-};
-
-}  // namespace drive
-}  // namespace sync_file_system
-
-#endif  // CHROME_BROWSER_SYNC_FILE_SYSTEM_DRIVE_API_UTIL_H_
diff --git a/chrome/browser/sync_file_system/drive/api_util_interface.h b/chrome/browser/sync_file_system/drive/api_util_interface.h
deleted file mode 100644
index 0758774..0000000
--- a/chrome/browser/sync_file_system/drive/api_util_interface.h
+++ /dev/null
@@ -1,198 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_SYNC_FILE_SYSTEM_DRIVE_API_UTIL_INTERFACE_H_
-#define CHROME_BROWSER_SYNC_FILE_SYSTEM_DRIVE_API_UTIL_INTERFACE_H_
-
-#include <string>
-
-#include "base/callback_forward.h"
-#include "chrome/browser/google_apis/gdata_errorcode.h"
-#include "chrome/browser/google_apis/gdata_wapi_parser.h"
-
-class GURL;
-class Profile;
-
-namespace base {
-class Time;
-}
-
-namespace google_apis {
-class DriveUploaderInterface;
-}
-
-namespace sync_file_system {
-namespace drive {
-
-class APIUtilObserver {
- public:
-  APIUtilObserver() {}
-  virtual ~APIUtilObserver() {}
-  virtual void OnAuthenticated() = 0;
-  virtual void OnNetworkConnected() = 0;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(APIUtilObserver);
-};
-
-// The implementation of this class is responsible for talking to the Drive
-// service to get and put Drive directories, files and metadata.
-// This class is owned by DriveFileSyncService.
-class APIUtilInterface {
- public:
-  typedef base::Callback<void(google_apis::GDataErrorCode error)>
-      GDataErrorCallback;
-  typedef base::Callback<void(google_apis::GDataErrorCode error,
-                              const std::string& file_md5,
-                              int64 file_size,
-                              const base::Time& last_updated)>
-      DownloadFileCallback;
-  typedef base::Callback<void(google_apis::GDataErrorCode error,
-                              const std::string& resource_id,
-                              const std::string& file_md5)> UploadFileCallback;
-  typedef base::Callback<
-      void(google_apis::GDataErrorCode error, const std::string& resource_id)>
-      ResourceIdCallback;
-  typedef base::Callback<void(google_apis::GDataErrorCode error,
-                              int64 changestamp)> ChangeStampCallback;
-  typedef base::Callback<void(google_apis::GDataErrorCode error,
-                              scoped_ptr<google_apis::ResourceList> feed)>
-      ResourceListCallback;
-  typedef base::Callback<void(google_apis::GDataErrorCode error,
-                              scoped_ptr<google_apis::ResourceEntry> entry)>
-      ResourceEntryCallback;
-
-  APIUtilInterface() {}
-  virtual ~APIUtilInterface() {}
-
-  virtual void AddObserver(APIUtilObserver* observer) = 0;
-  virtual void RemoveObserver(APIUtilObserver* observer) = 0;
-
-  // Fetches Resource ID of the directory where we should place all files to
-  // sync.  Upon completion, invokes |callback|.
-  // If the directory does not exist on the server this also creates
-  // the directory.
-  //
-  // Returns HTTP_SUCCESS if the directory already exists.
-  // Returns HTTP_CREATED if the directory was not found and created.
-  virtual void GetDriveDirectoryForSyncRoot(
-      const ResourceIdCallback& callback) = 0;
-
-  // Fetches Resource ID of the directory for the |origin|.
-  // Upon completion, invokes |callback|.
-  // If the directory does not exist on the server this also creates
-  // the directory.
-  //
-  // Returns HTTP_SUCCESS if the directory already exists.
-  // Returns HTTP_CREATED if the directory was not found and created.
-  virtual void GetDriveDirectoryForOrigin(
-      const std::string& sync_root_resource_id,
-      const GURL& origin,
-      const ResourceIdCallback& callback) = 0;
-
-  // Fetches the largest changestamp for the signed-in account.
-  // Upon completion, invokes |callback|.
-  virtual void GetLargestChangeStamp(const ChangeStampCallback& callback) = 0;
-
-  // Fetches the resource entry for the file identified by |resource_id|.
-  // Upon completion, invokes |callback|.
-  virtual void GetResourceEntry(const std::string& resource_id,
-                                const ResourceEntryCallback& callback) = 0;
-
-  // Lists files in the directory identified by |resource_id|.
-  // Upon completion, invokes |callback|.
-  // The result may be chunked and may have successive results. The caller needs
-  // to call ContunueListing with the result of GetNextFeedURL to get complete
-  // list of files.
-  virtual void ListFiles(const std::string& directory_resource_id,
-                         const ResourceListCallback& callback) = 0;
-
-  // Lists changes that happened after |start_changestamp|.
-  // Upon completion, invokes |callback|.
-  // The result may be chunked and may have successive results. The caller needs
-  // to call ContunueListing with the result of GetNextFeedURL to get complete
-  // list of changes.
-  virtual void ListChanges(int64 start_changestamp,
-                           const ResourceListCallback& callback) = 0;
-
-  // Fetches the next chunk of ResourceList identified by |feed_url|.
-  // Upon completion, invokes |callback|.
-  virtual void ContinueListing(const GURL& feed_url,
-                               const ResourceListCallback& callback) = 0;
-
-  // Downloads the file identified by |resource_id| from Drive to
-  // |local_file_path|.
-  // |local_file_md5| represents the hash value of the local file to be updated.
-  // If |local_file_md5| is equal to remote file's value, cancels the download
-  // and invokes |callback| with GDataErrorCode::HTTP_NOT_MODIFIED immediately.
-  // When there is no local file to be updated, |local_file_md5| should be
-  // empty.
-  virtual void DownloadFile(const std::string& resource_id,
-                            const std::string& local_file_md5,
-                            const base::FilePath& local_file_path,
-                            const DownloadFileCallback& callback) = 0;
-
-  // Uploads the new file |local_file_path| with specified |title| into the
-  // directory identified by |directory_resource_id|.
-  // Upon completion, invokes |callback| and returns HTTP_CREATED if the file
-  // is created.
-  virtual void UploadNewFile(const std::string& directory_resource_id,
-                             const base::FilePath& local_file_path,
-                             const std::string& title,
-                             const UploadFileCallback& callback) = 0;
-
-  // Uploads the existing file identified by |local_file_path|.
-  // |remote_file_md5| represents the expected hash value of the file to be
-  // updated on Drive. If |remote_file_md5| is different from the actual value,
-  // cancels the upload and invokes |callback| with
-  // GDataErrorCode::HTTP_CONFLICT immediately.
-  // Returns HTTP_SUCCESS if the file uploaded successfully.
-  virtual void UploadExistingFile(const std::string& resource_id,
-                                  const std::string& remote_file_md5,
-                                  const base::FilePath& local_file_path,
-                                  const UploadFileCallback& callback) = 0;
-
-  // Creates a new directory with specified |title| into the directory
-  // identified by |parent_resource_id|.
-  // Upon completion, invokes |callback| and returns HTTP_CREATED if
-  // the directory is created.
-  virtual void CreateDirectory(const std::string& parent_resource_id,
-                               const std::string& title,
-                               const ResourceIdCallback& callback) = 0;
-
-  // Returns true if the user is authenticated.
-  virtual bool IsAuthenticated() const = 0;
-
-  // Deletes the file identified by |resource_id|.
-  // A directory is considered a file and will cause a recursive delete if
-  // given as the |resource_id|.
-  // TODO(tzik): Rename this function to DeleteResource.
-  //
-  // |remote_file_md5| represents the expected hash value of the file to be
-  // deleted from Drive. If |remote_file_md5| is empty, then it's implied that
-  // the file should be deleted on the remote side regardless. If
-  // |remote_file_md5| is not empty and is different from the actual value,
-  // the deletion operation is canceled and the |callback| with
-  // GDataErrorCode::HTTP_CONFLICT is invoked immediately.
-  virtual void DeleteFile(const std::string& resource_id,
-                          const std::string& remote_file_md5,
-                          const GDataErrorCallback& callback) = 0;
-
-  // Converts |resource_id| to corresponing resource link.
-  virtual GURL ResourceIdToResourceLink(
-      const std::string& resource_id) const = 0;
-
-  // Ensures the sync root directory is not in 'My Drive'. Even if the directory
-  // is in directories other than 'My Drive', it will not be removed from there.
-  virtual void EnsureSyncRootIsNotInMyDrive(
-      const std::string& sync_root_resource_id) = 0;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(APIUtilInterface);
-};
-
-}  // namespace drive
-}  // namespace sync_file_system
-
-#endif  // CHROME_BROWSER_SYNC_FILE_SYSTEM_DRIVE_API_UTIL_INTERFACE_H_
diff --git a/chrome/browser/sync_file_system/drive/api_util_unittest.cc b/chrome/browser/sync_file_system/drive/api_util_unittest.cc
deleted file mode 100644
index f67f054..0000000
--- a/chrome/browser/sync_file_system/drive/api_util_unittest.cc
+++ /dev/null
@@ -1,849 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/sync_file_system/drive/api_util.h"
-
-#include "base/json/json_reader.h"
-#include "base/location.h"
-#include "base/message_loop.h"
-#include "base/message_loop/message_loop_proxy.h"
-#include "base/values.h"
-#include "chrome/browser/drive/drive_uploader.h"
-#include "chrome/browser/drive/fake_drive_service.h"
-#include "chrome/browser/google_apis/drive_api_parser.h"
-#include "chrome/browser/google_apis/gdata_errorcode.h"
-#include "chrome/browser/google_apis/test_util.h"
-#include "chrome/browser/sync_file_system/drive_file_sync_util.h"
-#include "chrome/test/base/testing_profile.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/test/test_browser_thread.h"
-#include "net/base/escape.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-#define FPL(x) FILE_PATH_LITERAL(x)
-
-using google_apis::FakeDriveService;
-using google_apis::ResourceEntry;
-using google_apis::ResourceList;
-using google_apis::DriveServiceInterface;
-using google_apis::DriveUploaderInterface;
-using google_apis::GDataErrorCode;
-using google_apis::Link;
-using google_apis::test_util::LoadJSONFile;
-
-namespace sync_file_system {
-namespace drive {
-
-namespace {
-
-const char kOrigin[] = "chrome-extension://example";
-const char kOriginDirectoryName[] = "example";
-const char kOriginDirectoryResourceId[] = "folder:origin_directory_resource_id";
-const char kSyncRootResourceId[] = "folder:sync_root_resource_id";
-
-void EmptyResourceEntryCallback(GDataErrorCode error,
-                                scoped_ptr<ResourceEntry> entry) {}
-
-void VerifyTitleUniqueness(const tracked_objects::Location& from_here,
-                           const std::string& resource_id,
-                           google_apis::DriveEntryKind kind,
-                           GDataErrorCode error,
-                           scoped_ptr<ResourceList> resource_list) {
-  std::string location(" failed at " + from_here.ToString());
-  ASSERT_FALSE(resource_id.empty()) << location;
-  ASSERT_EQ(google_apis::HTTP_SUCCESS, error) << location;
-  ASSERT_TRUE(resource_list) << location;
-
-  const ScopedVector<ResourceEntry>& entries = resource_list->entries();
-  ASSERT_EQ(1u, entries.size());
-  EXPECT_EQ(resource_id, entries[0]->resource_id());
-  switch (kind) {
-    case google_apis::ENTRY_KIND_FOLDER:
-      EXPECT_TRUE(entries[0]->is_folder()) << location;
-      return;
-    case google_apis::ENTRY_KIND_FILE:
-      EXPECT_TRUE(entries[0]->is_file()) << location;
-      return;
-    default:
-      NOTREACHED() << "Unexpected DriveEntryKind: " << kind << location;
-      return;
-  }
-}
-
-void VerifyFileDeletion(const tracked_objects::Location& from_here,
-                        GDataErrorCode error,
-                        scoped_ptr<ResourceList> resource_list) {
-  std::string location(" failed at " + from_here.ToString());
-  ASSERT_EQ(google_apis::HTTP_SUCCESS, error) << location;
-  ASSERT_TRUE(resource_list) << location;
-  EXPECT_TRUE(resource_list->entries().empty()) << location;
-}
-
-class FakeDriveServiceWrapper : public FakeDriveService {
- public:
-  FakeDriveServiceWrapper() : make_directory_conflict_(false) {};
-  virtual ~FakeDriveServiceWrapper() {};
-
-  // DriveServiceInterface overrides.
-  virtual google_apis::CancelCallback AddNewDirectory(
-      const std::string& parent_resource_id,
-      const std::string& directory_name,
-      const google_apis::GetResourceEntryCallback& callback) OVERRIDE {
-    if (make_directory_conflict_) {
-      FakeDriveService::AddNewDirectory(
-          parent_resource_id,
-          directory_name,
-          base::Bind(&EmptyResourceEntryCallback));
-    }
-    return FakeDriveService::AddNewDirectory(
-        parent_resource_id, directory_name, callback);
-  }
-
-  void set_make_directory_conflict(bool enable) {
-    make_directory_conflict_ = enable;
-  }
-
- private:
-  bool make_directory_conflict_;
-
-  DISALLOW_COPY_AND_ASSIGN(FakeDriveServiceWrapper);
-};
-
-// A fake implementation of DriveUploaderInterface, which provides fake
-// behaviors for file uploading.
-class FakeDriveUploader : public DriveUploaderInterface {
- public:
-  explicit FakeDriveUploader(FakeDriveServiceWrapper* fake_drive_service)
-      : fake_drive_service_(fake_drive_service),
-        make_file_conflict_(false) {}
-  virtual ~FakeDriveUploader() {}
-
-  // DriveUploaderInterface overrides.
-
-  // Pretends that a new file was uploaded successfully, and returns the
-  // contents of "chromeos/gdata/file_entry.json" to the caller.
-  virtual google_apis::CancelCallback UploadNewFile(
-      const std::string& parent_resource_id,
-      const base::FilePath& drive_file_path,
-      const base::FilePath& local_file_path,
-      const std::string& title,
-      const std::string& content_type,
-      const google_apis::UploadCompletionCallback& callback,
-      const google_apis::ProgressCallback& progress_callback) OVERRIDE {
-    DCHECK(!callback.is_null());
-
-    scoped_ptr<base::Value> file_entry_data(
-        LoadJSONFile("chromeos/gdata/file_entry.json"));
-    scoped_ptr<ResourceEntry> file_entry(
-        ResourceEntry::ExtractAndParse(*file_entry_data));
-
-    if (make_file_conflict_) {
-      fake_drive_service_->LoadResourceListForWapi(
-          "chromeos/sync_file_system/conflict_with_file.json");
-    } else {
-      fake_drive_service_->LoadResourceListForWapi(
-          "chromeos/sync_file_system/upload_new_file.json");
-    }
-
-    base::MessageLoopProxy::current()->PostTask(
-        FROM_HERE,
-        base::Bind(callback,
-                   google_apis::HTTP_SUCCESS,
-                   GURL(),
-                   base::Passed(&file_entry)));
-    return google_apis::CancelCallback();
-  }
-
-  // Pretends that an existing file ("file:resource_id") was uploaded
-  // successfully, and returns the contents of "chromeos/gdata/file_entry.json"
-  // to the caller.
-  virtual google_apis::CancelCallback UploadExistingFile(
-      const std::string& resource_id,
-      const base::FilePath& drive_file_path,
-      const base::FilePath& local_file_path,
-      const std::string& content_type,
-      const std::string& etag,
-      const google_apis::UploadCompletionCallback& callback,
-      const google_apis::ProgressCallback& progress_callback) OVERRIDE {
-    DCHECK(!callback.is_null());
-
-    scoped_ptr<base::Value> file_entry_data(
-        LoadJSONFile("chromeos/gdata/file_entry.json"));
-    scoped_ptr<ResourceEntry> file_entry(
-        ResourceEntry::ExtractAndParse(*file_entry_data));
-
-    base::MessageLoopProxy::current()->PostTask(
-        FROM_HERE,
-        base::Bind(callback,
-                   google_apis::HTTP_SUCCESS,
-                   GURL(),
-                   base::Passed(&file_entry)));
-    return google_apis::CancelCallback();
-  }
-
-  // At the moment, sync file system doesn't support resuming of the uploading.
-  // So this method shouldn't be reached.
-  virtual google_apis::CancelCallback ResumeUploadFile(
-      const GURL& upload_location,
-      const base::FilePath& drive_file_path,
-      const base::FilePath& local_file_path,
-      const std::string& content_type,
-      const google_apis::UploadCompletionCallback& callback,
-      const google_apis::ProgressCallback& progress_callback) OVERRIDE {
-    NOTREACHED();
-    return google_apis::CancelCallback();
-  }
-
-  void set_make_file_conflict(bool enable) {
-    make_file_conflict_ = enable;
-  }
-
- private:
-  FakeDriveServiceWrapper* fake_drive_service_;
-  bool make_file_conflict_;
-
-  DISALLOW_COPY_AND_ASSIGN(FakeDriveUploader);
-};
-
-}  // namespace
-
-class APIUtilTest : public testing::Test {
- public:
-  APIUtilTest() : ui_thread_(content::BrowserThread::UI, &message_loop_),
-                  fake_drive_service_(NULL),
-                  fake_drive_uploader_(NULL) {}
-
-  virtual void SetUp() OVERRIDE {
-    SetDisableDriveAPI(true);
-
-    fake_drive_service_ = new FakeDriveServiceWrapper;
-    fake_drive_uploader_ = new FakeDriveUploader(fake_drive_service_);
-
-    api_util_ = APIUtil::CreateForTesting(
-        &profile_,
-        scoped_ptr<DriveServiceInterface>(fake_drive_service_),
-        scoped_ptr<DriveUploaderInterface>(fake_drive_uploader_));
-  }
-
-  virtual void TearDown() OVERRIDE {
-    api_util_.reset();
-    SetDisableDriveAPI(false);
-  }
-
- protected:
-  std::string GetRootResourceId() { return api_util_->GetRootResourceId(); }
-
-  APIUtil* api_util() { return api_util_.get(); }
-
-  FakeDriveServiceWrapper* fake_drive_service() {
-    return fake_drive_service_;
-  }
-
-  FakeDriveUploader* fake_drive_uploader() {
-    return fake_drive_uploader_;
-  }
-
-  base::MessageLoop* message_loop() { return &message_loop_; }
-
- private:
-  base::MessageLoop message_loop_;
-  content::TestBrowserThread ui_thread_;
-
-  TestingProfile profile_;
-  scoped_ptr<APIUtil> api_util_;
-  FakeDriveServiceWrapper* fake_drive_service_;
-  FakeDriveUploader* fake_drive_uploader_;
-
-  DISALLOW_COPY_AND_ASSIGN(APIUtilTest);
-};
-
-void DidGetResourceID(bool* done_out,
-                      GDataErrorCode* error_out,
-                      std::string* resource_id_out,
-                      GDataErrorCode error,
-                      const std::string& resource_id) {
-  EXPECT_FALSE(*done_out);
-  *done_out = true;
-  *error_out = error;
-  *resource_id_out = resource_id;
-}
-
-#if !defined(OS_ANDROID)
-
-void DidGetLargestChangeStamp(bool* done_out,
-                              GDataErrorCode* error_out,
-                              int64* largest_changestamp_out,
-                              GDataErrorCode error,
-                              int64 largest_changestamp) {
-  EXPECT_FALSE(*done_out);
-  *done_out = true;
-  *error_out = error;
-  *largest_changestamp_out = largest_changestamp;
-}
-
-void DidGetResourceList(bool* done_out,
-                        GDataErrorCode* error_out,
-                        scoped_ptr<ResourceList>* document_feed_out,
-                        GDataErrorCode error,
-                        scoped_ptr<ResourceList> document_feed) {
-  EXPECT_FALSE(*done_out);
-  *done_out = true;
-  *error_out = error;
-  *document_feed_out = document_feed.Pass();
-}
-
-void DidDownloadFile(bool* done_out,
-                     std::string* expected_file_md5_out,
-                     GDataErrorCode* error_out,
-                     GDataErrorCode error,
-                     const std::string& file_md5,
-                     int64 file_size,
-                     const base::Time& updated_time) {
-  EXPECT_FALSE(*done_out);
-  *done_out = true;
-  *error_out = error;
-  *expected_file_md5_out = file_md5;
-}
-
-void DidUploadFile(bool* done_out,
-                   GDataErrorCode* error_out,
-                   std::string* resource_id_out,
-                   GDataErrorCode error,
-                   const std::string& resource_id,
-                   const std::string& file_md5) {
-  EXPECT_FALSE(*done_out);
-  *done_out = true;
-  *error_out = error;
-  *resource_id_out = resource_id;
-}
-
-void DidDeleteFile(bool* done_out,
-                   GDataErrorCode* error_out,
-                   GDataErrorCode error) {
-  EXPECT_FALSE(*done_out);
-  *done_out = true;
-  *error_out = error;
-}
-
-TEST_F(APIUtilTest, GetSyncRoot) {
-  fake_drive_service()->LoadResourceListForWapi(
-      "chromeos/sync_file_system/sync_root_found.json");
-
-  bool done = false;
-  GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
-  std::string resource_id;
-  api_util()->GetDriveDirectoryForSyncRoot(
-      base::Bind(&DidGetResourceID, &done, &error, &resource_id));
-  message_loop()->RunUntilIdle();
-
-  EXPECT_TRUE(done);
-  EXPECT_EQ(google_apis::HTTP_SUCCESS, error);
-  EXPECT_EQ(kSyncRootResourceId, resource_id);
-}
-
-TEST_F(APIUtilTest, CreateSyncRoot) {
-  fake_drive_service()->LoadResourceListForWapi(
-      "chromeos/sync_file_system/sync_root_not_found.json");
-
-  bool done = false;
-  GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
-  std::string resource_id;
-  api_util()->GetDriveDirectoryForSyncRoot(
-      base::Bind(&DidGetResourceID, &done, &error, &resource_id));
-  message_loop()->RunUntilIdle();
-
-  EXPECT_TRUE(done);
-  EXPECT_EQ(google_apis::HTTP_CREATED, error);
-  EXPECT_FALSE(resource_id.empty());
-
-  fake_drive_service()->SearchByTitle(
-      APIUtil::GetSyncRootDirectoryName(),
-      std::string(),  // directory_resource_id
-      base::Bind(&VerifyTitleUniqueness,
-                 FROM_HERE,
-                 resource_id,
-                 google_apis::ENTRY_KIND_FOLDER));
-  message_loop()->RunUntilIdle();
-}
-
-TEST_F(APIUtilTest, CreateSyncRoot_Conflict) {
-  fake_drive_service()->LoadResourceListForWapi(
-      "chromeos/sync_file_system/sync_root_not_found.json");
-  fake_drive_service()->set_make_directory_conflict(true);
-
-  bool done = false;
-  GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
-  std::string resource_id;
-  api_util()->GetDriveDirectoryForSyncRoot(
-      base::Bind(&DidGetResourceID, &done, &error, &resource_id));
-  message_loop()->RunUntilIdle();
-
-  EXPECT_TRUE(done);
-  EXPECT_EQ(google_apis::HTTP_SUCCESS, error);
-  EXPECT_FALSE(resource_id.empty());
-
-  // Verify that there is no duplicated directory on the remote side.
-  fake_drive_service()->SearchByTitle(
-      APIUtil::GetSyncRootDirectoryName(),
-      std::string(),  // directory_resource_id
-      base::Bind(&VerifyTitleUniqueness,
-                 FROM_HERE,
-                 resource_id,
-                 google_apis::ENTRY_KIND_FOLDER));
-  message_loop()->RunUntilIdle();
-}
-
-TEST_F(APIUtilTest, GetOriginDirectory) {
-  fake_drive_service()->LoadResourceListForWapi(
-      "chromeos/sync_file_system/origin_directory_found.json");
-
-  bool done = false;
-  GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
-  std::string resource_id;
-  api_util()->GetDriveDirectoryForOrigin(
-      kSyncRootResourceId,
-      GURL(kOrigin),
-      base::Bind(&DidGetResourceID, &done, &error, &resource_id));
-  message_loop()->RunUntilIdle();
-
-  EXPECT_TRUE(done);
-  EXPECT_EQ(google_apis::HTTP_SUCCESS, error);
-  EXPECT_EQ(kOriginDirectoryResourceId, resource_id);
-}
-
-TEST_F(APIUtilTest, CreateOriginDirectory) {
-  fake_drive_service()->LoadResourceListForWapi(
-      "chromeos/sync_file_system/sync_root_found.json");
-
-  bool done = false;
-  GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
-  std::string resource_id;
-  api_util()->GetDriveDirectoryForOrigin(
-      kSyncRootResourceId,
-      GURL(kOrigin),
-      base::Bind(&DidGetResourceID, &done, &error, &resource_id));
-  message_loop()->RunUntilIdle();
-
-  EXPECT_TRUE(done);
-  EXPECT_EQ(google_apis::HTTP_CREATED, error);
-  EXPECT_FALSE(resource_id.empty());
-
-  fake_drive_service()->SearchByTitle(
-      kOriginDirectoryName,
-      kSyncRootResourceId,
-      base::Bind(&VerifyTitleUniqueness,
-                 FROM_HERE,
-                 resource_id,
-                 google_apis::ENTRY_KIND_FOLDER));
-  message_loop()->RunUntilIdle();
-}
-
-TEST_F(APIUtilTest, CreateOriginDirectory_Conflict) {
-  fake_drive_service()->LoadResourceListForWapi(
-      "chromeos/sync_file_system/sync_root_found.json");
-  fake_drive_service()->set_make_directory_conflict(true);
-
-  bool done = false;
-  GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
-  std::string resource_id;
-  api_util()->GetDriveDirectoryForOrigin(
-      kSyncRootResourceId,
-      GURL(kOrigin),
-      base::Bind(&DidGetResourceID, &done, &error, &resource_id));
-  message_loop()->RunUntilIdle();
-
-  EXPECT_TRUE(done);
-  EXPECT_EQ(google_apis::HTTP_SUCCESS, error);
-  EXPECT_FALSE(resource_id.empty());
-
-  // Verify that there is no duplicated directory on the remote side.
-  fake_drive_service()->SearchByTitle(
-      kOriginDirectoryName,
-      kSyncRootResourceId,
-      base::Bind(&VerifyTitleUniqueness,
-                 FROM_HERE,
-                 resource_id,
-                 google_apis::ENTRY_KIND_FOLDER));
-  message_loop()->RunUntilIdle();
-}
-
-TEST_F(APIUtilTest, GetLargestChangeStamp) {
-  fake_drive_service()->LoadAccountMetadataForWapi(
-      "chromeos/sync_file_system/account_metadata.json");
-
-  bool done = false;
-  GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
-  int64 largest_changestamp = -1;
-  api_util()->GetLargestChangeStamp(base::Bind(
-      &DidGetLargestChangeStamp, &done, &error, &largest_changestamp));
-  message_loop()->RunUntilIdle();
-
-  EXPECT_TRUE(done);
-  EXPECT_EQ(google_apis::HTTP_SUCCESS, error);
-  EXPECT_EQ(654321, largest_changestamp);
-}
-
-TEST_F(APIUtilTest, ListFiles) {
-  fake_drive_service()->LoadResourceListForWapi(
-      "chromeos/sync_file_system/listing_files_in_directory.json");
-
-  fake_drive_service()->set_default_max_results(1);
-
-  bool done = false;
-  GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
-  scoped_ptr<ResourceList> document_feed;
-  api_util()->ListFiles(
-      kOriginDirectoryResourceId,
-      base::Bind(&DidGetResourceList, &done, &error, &document_feed));
-  message_loop()->RunUntilIdle();
-
-  EXPECT_TRUE(done);
-  EXPECT_EQ(google_apis::HTTP_SUCCESS, error);
-  EXPECT_FALSE(document_feed->entries().empty());
-
-  GURL feed_url;
-  ASSERT_TRUE(document_feed->GetNextFeedURL(&feed_url));
-
-  done = false;
-  error = google_apis::GDATA_OTHER_ERROR;
-  document_feed.reset();
-
-  api_util()->ContinueListing(
-      feed_url, base::Bind(&DidGetResourceList, &done, &error, &document_feed));
-  message_loop()->RunUntilIdle();
-
-  EXPECT_TRUE(done);
-  EXPECT_EQ(google_apis::HTTP_SUCCESS, error);
-  EXPECT_FALSE(document_feed->entries().empty());
-}
-
-TEST_F(APIUtilTest, ListChanges) {
-  const int64 kStartChangestamp = 123456;
-
-  fake_drive_service()->LoadResourceListForWapi(
-      "chromeos/sync_file_system/listing_files_in_directory.json");
-
-  bool done = false;
-  GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
-  scoped_ptr<ResourceList> document_feed;
-  api_util()->ListFiles(
-      kOriginDirectoryResourceId,
-      base::Bind(&DidGetResourceList, &done, &error, &document_feed));
-  message_loop()->RunUntilIdle();
-
-  EXPECT_TRUE(done);
-  EXPECT_EQ(google_apis::HTTP_SUCCESS, error);
-  EXPECT_FALSE(document_feed->entries().empty());
-
-  done = false;
-  error = google_apis::GDATA_OTHER_ERROR;
-  document_feed.reset();
-  api_util()->ListChanges(
-      kStartChangestamp,
-      base::Bind(&DidGetResourceList, &done, &error, &document_feed));
-  message_loop()->RunUntilIdle();
-
-  EXPECT_TRUE(done);
-  EXPECT_EQ(google_apis::HTTP_SUCCESS, error);
-  EXPECT_FALSE(document_feed->entries().empty());
-}
-
-TEST_F(APIUtilTest, DownloadFile) {
-  const std::string kResourceId = "file:file_resource_id";
-  const std::string kLocalFileMD5 = "123456";
-  const std::string kExpectedFileMD5 = "3b4382ebefec6e743578c76bbd0575ce";
-
-  fake_drive_service()->LoadResourceListForWapi(
-      "chromeos/sync_file_system/listing_files_in_directory.json");
-
-  base::ScopedTempDir temp_dir;
-  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
-  const base::FilePath kOutputFilePath = temp_dir.path().AppendASCII("file");
-
-  bool done = false;
-  std::string file_md5;
-  GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
-  api_util()->DownloadFile(
-      kResourceId,
-      kLocalFileMD5,
-      kOutputFilePath,
-      base::Bind(&DidDownloadFile, &done, &file_md5, &error));
-  message_loop()->RunUntilIdle();
-
-  EXPECT_TRUE(done);
-  EXPECT_EQ(kExpectedFileMD5, file_md5);
-  EXPECT_EQ(google_apis::HTTP_SUCCESS, error);
-}
-
-TEST_F(APIUtilTest, DownloadFileInNotModified) {
-  const std::string kResourceId = "file:file_resource_id";
-
-  // Since local file's hash value is equal to remote file's one, it is expected
-  // to cancel download the file and to return NOT_MODIFIED status code.
-  const std::string kLocalFileMD5 = "3b4382ebefec6e743578c76bbd0575ce";
-
-  fake_drive_service()->LoadResourceListForWapi(
-      "chromeos/sync_file_system/listing_files_in_directory.json");
-
-  base::ScopedTempDir temp_dir;
-  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
-  const base::FilePath kOutputFilePath = temp_dir.path().AppendASCII("file");
-
-  bool done = false;
-  std::string file_md5;
-  GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
-  api_util()->DownloadFile(
-      kResourceId,
-      kLocalFileMD5,
-      kOutputFilePath,
-      base::Bind(&DidDownloadFile, &done, &file_md5, &error));
-  message_loop()->RunUntilIdle();
-
-  EXPECT_TRUE(done);
-  EXPECT_EQ(kLocalFileMD5, file_md5);
-  EXPECT_EQ(google_apis::HTTP_NOT_MODIFIED, error);
-}
-
-TEST_F(APIUtilTest, UploadNewFile) {
-  const base::FilePath kLocalFilePath(FPL("/tmp/dir/file"));
-
-  fake_drive_service()->LoadResourceListForWapi(
-      "chromeos/sync_file_system/listing_files_in_directory.json");
-
-  scoped_ptr<base::Value> file_entry_data(
-      LoadJSONFile("chromeos/gdata/file_entry.json"));
-  scoped_ptr<ResourceEntry> expected_file_entry(
-      ResourceEntry::ExtractAndParse(*file_entry_data));
-
-  bool done = false;
-  GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
-  std::string resource_id;
-  api_util()->UploadNewFile(
-      kOriginDirectoryResourceId,
-      kLocalFilePath,
-      expected_file_entry->title(),
-      base::Bind(&DidUploadFile, &done, &error, &resource_id));
-  message_loop()->RunUntilIdle();
-
-  EXPECT_TRUE(done);
-  EXPECT_EQ(google_apis::HTTP_CREATED, error);
-  EXPECT_EQ(expected_file_entry->resource_id(), resource_id);
-
-  fake_drive_service()->SearchByTitle(
-      expected_file_entry->title(),
-      kOriginDirectoryResourceId,
-      base::Bind(&VerifyTitleUniqueness,
-                 FROM_HERE,
-                 expected_file_entry->resource_id(),
-                 google_apis::ENTRY_KIND_FILE));
-  message_loop()->RunUntilIdle();
-}
-
-TEST_F(APIUtilTest, UploadNewFile_ConflictWithFile) {
-  const base::FilePath kLocalFilePath(FPL("/tmp/dir/file"));
-
-  fake_drive_service()->LoadResourceListForWapi(
-      "chromeos/sync_file_system/upload_new_file.json");
-
-  scoped_ptr<base::Value> file_entry_data(
-      LoadJSONFile("chromeos/gdata/file_entry.json"));
-  scoped_ptr<ResourceEntry> expected_file_entry(
-      ResourceEntry::ExtractAndParse(*file_entry_data));
-
-  fake_drive_uploader()->set_make_file_conflict(true);
-
-  bool done = false;
-  GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
-  std::string resource_id;
-  api_util()->UploadNewFile(
-      kOriginDirectoryResourceId,
-      kLocalFilePath,
-      expected_file_entry->title(),
-      base::Bind(&DidUploadFile, &done, &error, &resource_id));
-  message_loop()->RunUntilIdle();
-
-  // HTTP_CONFLICT error must be returned with empty resource_id.
-  EXPECT_TRUE(done);
-  EXPECT_EQ(google_apis::HTTP_CONFLICT, error);
-  EXPECT_EQ("file:file_duplicated_resource_id", resource_id);
-
-  // Verify that there is no duplicated file on the remote side.
-  fake_drive_service()->SearchByTitle(
-      expected_file_entry->title(),
-      kOriginDirectoryResourceId,
-      base::Bind(&VerifyTitleUniqueness,
-                 FROM_HERE,
-                 resource_id,
-                 google_apis::ENTRY_KIND_FILE));
-  message_loop()->RunUntilIdle();
-}
-
-TEST_F(APIUtilTest, UploadExistingFile) {
-  const base::FilePath kLocalFilePath(FPL("/tmp/dir/file"));
-
-  fake_drive_service()->LoadResourceListForWapi(
-      "chromeos/sync_file_system/upload_new_file.json");
-
-  scoped_ptr<base::Value> file_entry_data(
-      LoadJSONFile("chromeos/gdata/file_entry.json"));
-  scoped_ptr<ResourceEntry> existing_file_entry(
-      ResourceEntry::ExtractAndParse(*file_entry_data));
-
-  bool done = false;
-  GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
-  std::string resource_id;
-  api_util()->UploadExistingFile(
-      existing_file_entry->resource_id(),
-      existing_file_entry->file_md5(),
-      kLocalFilePath,
-      base::Bind(&DidUploadFile, &done, &error, &resource_id));
-  message_loop()->RunUntilIdle();
-
-  EXPECT_TRUE(done);
-  EXPECT_EQ(google_apis::HTTP_SUCCESS, error);
-  EXPECT_EQ(existing_file_entry->resource_id(), resource_id);
-
-  fake_drive_service()->SearchByTitle(
-      existing_file_entry->title(),
-      kOriginDirectoryResourceId,
-      base::Bind(&VerifyTitleUniqueness,
-                 FROM_HERE,
-                 existing_file_entry->resource_id(),
-                 google_apis::ENTRY_KIND_FILE));
-  message_loop()->RunUntilIdle();
-}
-
-TEST_F(APIUtilTest, UploadExistingFileInConflict) {
-  const std::string kResourceId = "file:resource_id";
-  const base::FilePath kLocalFilePath(FPL("/tmp/dir/file"));
-
-  // Since remote file's hash value is different from the expected one, it is
-  // expected to cancel upload the file and to return CONFLICT status code.
-  const std::string kExpectedRemoteFileMD5 = "123456";
-
-  fake_drive_service()->LoadResourceListForWapi(
-      "chromeos/sync_file_system/upload_new_file.json");
-
-  scoped_ptr<base::Value> file_entry_data(
-      LoadJSONFile("chromeos/gdata/file_entry.json"));
-  scoped_ptr<ResourceEntry> existing_file_entry(
-      ResourceEntry::ExtractAndParse(*file_entry_data));
-
-  bool done = false;
-  GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
-  std::string resource_id;
-  api_util()->UploadExistingFile(
-      existing_file_entry->resource_id(),
-      kExpectedRemoteFileMD5,
-      kLocalFilePath,
-      base::Bind(&DidUploadFile, &done, &error, &resource_id));
-  message_loop()->RunUntilIdle();
-
-  EXPECT_TRUE(done);
-  EXPECT_EQ(google_apis::HTTP_CONFLICT, error);
-  EXPECT_TRUE(resource_id.empty());
-
-  // Verify that there is no duplicated file on the remote side.
-  fake_drive_service()->SearchByTitle(
-      existing_file_entry->title(),
-      kOriginDirectoryResourceId,
-      base::Bind(&VerifyTitleUniqueness,
-                 FROM_HERE,
-                 existing_file_entry->resource_id(),
-                 google_apis::ENTRY_KIND_FILE));
-  message_loop()->RunUntilIdle();
-}
-
-TEST_F(APIUtilTest, DeleteFile) {
-  const std::string kFileTitle = "testfile";
-  const std::string kResourceId = "file:file_resource_id";
-  const std::string kExpectedRemoteFileMD5 = "3b4382ebefec6e743578c76bbd0575ce";
-
-  fake_drive_service()->LoadResourceListForWapi(
-      "chromeos/sync_file_system/listing_files_in_directory.json");
-
-  bool done = false;
-  GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
-  std::string resource_id;
-  api_util()->DeleteFile(kResourceId,
-                         kExpectedRemoteFileMD5,
-                         base::Bind(&DidDeleteFile, &done, &error));
-  message_loop()->RunUntilIdle();
-
-  EXPECT_TRUE(done);
-  EXPECT_EQ(google_apis::HTTP_SUCCESS, error);
-
-  fake_drive_service()->SearchByTitle(
-      kFileTitle,
-      kOriginDirectoryResourceId,
-      base::Bind(&VerifyFileDeletion, FROM_HERE));
-  message_loop()->RunUntilIdle();
-}
-
-TEST_F(APIUtilTest, DeleteFileInConflict) {
-  const std::string kFileTitle = "testfile";
-  const std::string kResourceId = "file:file_resource_id";
-
-  fake_drive_service()->LoadResourceListForWapi(
-      "chromeos/sync_file_system/listing_files_in_directory.json");
-
-  // Since remote file's hash value is different from the expected one, it is
-  // expected to cancel delete the file and to return CONFLICT status code.
-  const std::string kExpectedRemoteFileMD5 = "123456";
-
-  bool done = false;
-  GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
-  std::string resource_id;
-  api_util()->DeleteFile(kResourceId,
-                         kExpectedRemoteFileMD5,
-                         base::Bind(&DidDeleteFile, &done, &error));
-  message_loop()->RunUntilIdle();
-
-  EXPECT_TRUE(done);
-  EXPECT_EQ(google_apis::HTTP_CONFLICT, error);
-
-  // Verify that the conflict file was not deleted on the remote side.
-  fake_drive_service()->SearchByTitle(
-      kFileTitle,
-      kOriginDirectoryResourceId,
-      base::Bind(&VerifyTitleUniqueness,
-                 FROM_HERE,
-                 kResourceId,
-                 google_apis::ENTRY_KIND_FILE));
-  message_loop()->RunUntilIdle();
-}
-
-TEST_F(APIUtilTest, CreateDirectory) {
-  const std::string kDirectoryTitle("directory");
-
-  fake_drive_service()->LoadResourceListForWapi(
-      "chromeos/sync_file_system/origin_directory_found.json");
-
-  bool done = false;
-  GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
-  std::string resource_id;
-  api_util()->CreateDirectory(
-      kOriginDirectoryResourceId,
-      kDirectoryTitle,
-      base::Bind(&DidGetResourceID, &done, &error, &resource_id));
-  message_loop()->RunUntilIdle();
-
-  EXPECT_TRUE(done);
-  EXPECT_EQ(google_apis::HTTP_CREATED, error);
-  EXPECT_FALSE(resource_id.empty());
-
-  fake_drive_service()->SearchByTitle(
-      kDirectoryTitle,
-      kOriginDirectoryResourceId,
-      base::Bind(&VerifyTitleUniqueness,
-                 FROM_HERE,
-                 resource_id,
-                 google_apis::ENTRY_KIND_FOLDER));
-  message_loop()->RunUntilIdle();
-}
-
-#endif  // !defined(OS_ANDROID)
-
-}  // namespace drive
-}  // namespace sync_file_system
diff --git a/chrome/browser/sync_file_system/drive/fake_api_util.cc b/chrome/browser/sync_file_system/drive/fake_api_util.cc
deleted file mode 100644
index f7e21b4..0000000
--- a/chrome/browser/sync_file_system/drive/fake_api_util.cc
+++ /dev/null
@@ -1,272 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/sync_file_system/drive/fake_api_util.h"
-
-#include <algorithm>
-
-#include "base/bind.h"
-#include "base/location.h"
-#include "base/message_loop/message_loop_proxy.h"
-#include "chrome/browser/google_apis/drive_entry_kinds.h"
-
-namespace sync_file_system {
-namespace drive {
-
-bool FakeAPIUtil::RemoteResourceComparator::operator()(
-    const RemoteResource& left,
-    const RemoteResource& right) {
-  if (left.parent_resource_id != right.parent_resource_id)
-    return left.parent_resource_id < right.parent_resource_id;
-  if (left.parent_title != right.parent_title)
-    return left.parent_title < right.parent_title;
-  if (left.title != right.title)
-    return left.title < right.title;
-  if (left.resource_id != right.resource_id)
-    return left.resource_id < right.resource_id;
-  if (left.md5_checksum != right.md5_checksum)
-    return left.md5_checksum < right.md5_checksum;
-  if (left.deleted != right.deleted)
-    return left.deleted < right.deleted;
-  return left.changestamp < right.changestamp;
-}
-
-struct FakeAPIUtil::ChangeStampComparator {
-  bool operator()(const google_apis::ResourceEntry* left,
-                  const google_apis::ResourceEntry* right) {
-    return left->changestamp() < right->changestamp();
-  }
-};
-
-FakeAPIUtil::RemoteResource::RemoteResource()
-    : type(SYNC_FILE_TYPE_UNKNOWN), deleted(false), changestamp(0) {}
-
-FakeAPIUtil::RemoteResource::RemoteResource(
-    const std::string& parent_resource_id,
-    const std::string& parent_title,
-    const std::string& title,
-    const std::string& resource_id,
-    const std::string& md5_checksum,
-    SyncFileType type,
-    bool deleted,
-    int64 changestamp)
-    : parent_resource_id(parent_resource_id),
-      parent_title(parent_title),
-      title(title),
-      resource_id(resource_id),
-      md5_checksum(md5_checksum),
-      type(type),
-      deleted(deleted),
-      changestamp(changestamp) {}
-
-FakeAPIUtil::RemoteResource::~RemoteResource() {}
-
-FakeAPIUtil::FakeAPIUtil()
-    : largest_changestamp_(0),
-      url_generator_(
-          GURL(google_apis::GDataWapiUrlGenerator::kBaseUrlForProduction)) {}
-
-FakeAPIUtil::~FakeAPIUtil() {}
-
-void FakeAPIUtil::AddObserver(APIUtilObserver* observer) {}
-
-void FakeAPIUtil::RemoveObserver(APIUtilObserver* observer) {}
-
-void FakeAPIUtil::GetDriveDirectoryForSyncRoot(
-    const ResourceIdCallback& callback) {
-  base::MessageLoopProxy::current()->PostTask(
-      FROM_HERE,
-      base::Bind(callback,
-                 google_apis::HTTP_SUCCESS,
-                 "folder: sync_root_resource_id"));
-}
-
-void FakeAPIUtil::GetDriveDirectoryForOrigin(
-    const std::string& sync_root_resource_id,
-    const GURL& origin,
-    const ResourceIdCallback& callback) {
-  base::MessageLoopProxy::current()->PostTask(
-      FROM_HERE,
-      base::Bind(callback,
-                 google_apis::HTTP_SUCCESS,
-                 "folder resource_id for " + origin.host()));
-}
-
-void FakeAPIUtil::GetLargestChangeStamp(const ChangeStampCallback& callback) {
-  base::MessageLoopProxy::current()->PostTask(
-      FROM_HERE,
-      base::Bind(callback, google_apis::HTTP_SUCCESS, largest_changestamp_));
-}
-
-void FakeAPIUtil::GetResourceEntry(const std::string& resource_id,
-                                   const ResourceEntryCallback& callback) {
-  NOTREACHED();
-}
-
-void FakeAPIUtil::ListFiles(const std::string& directory_resource_id,
-                            const ResourceListCallback& callback) {
-  ListChanges(0, callback);
-}
-
-void FakeAPIUtil::ListChanges(int64 start_changestamp,
-                              const ResourceListCallback& callback) {
-  scoped_ptr<google_apis::ResourceList> change_feed(
-      new google_apis::ResourceList());
-
-  ScopedVector<google_apis::ResourceEntry> entries;
-  typedef RemoteResourceByResourceId::const_iterator iterator;
-  for (iterator itr = remote_resources_.begin();
-       itr != remote_resources_.end(); ++itr) {
-    if (itr->second.changestamp < start_changestamp)
-      continue;
-    scoped_ptr<google_apis::ResourceEntry> entry(
-        CreateResourceEntry(itr->second));
-    entries.push_back(entry.release());
-  }
-
-  std::sort(entries.begin(), entries.end(), ChangeStampComparator());
-
-  change_feed->set_entries(&entries);
-  change_feed->set_largest_changestamp(largest_changestamp_);
-
-  base::MessageLoopProxy::current()->PostTask(
-      FROM_HERE,
-      base::Bind(
-          callback, google_apis::HTTP_SUCCESS, base::Passed(&change_feed)));
-}
-
-void FakeAPIUtil::ContinueListing(const GURL& feed_url,
-                                  const ResourceListCallback& callback) {
-  NOTREACHED();
-}
-
-void FakeAPIUtil::DownloadFile(const std::string& resource_id,
-                               const std::string& local_file_md5,
-                               const base::FilePath& local_file_path,
-                               const DownloadFileCallback& callback) {
-  RemoteResourceByResourceId::iterator found =
-      remote_resources_.find(resource_id);
-  std::string file_md5;
-  int64 file_size = 0;
-  base::Time updated_time;
-  google_apis::GDataErrorCode error = google_apis::HTTP_NOT_FOUND;
-
-  if (found != remote_resources_.end() && !found->second.deleted) {
-    scoped_ptr<google_apis::ResourceEntry> entry(
-        CreateResourceEntry(found->second));
-    file_md5 = entry->file_md5();
-    file_size = entry->file_size();
-    updated_time = entry->updated_time();
-    error = google_apis::HTTP_SUCCESS;
-  }
-
-  base::MessageLoopProxy::current()->PostTask(
-      FROM_HERE,
-      base::Bind(callback, error, file_md5, file_size, updated_time));
-}
-
-void FakeAPIUtil::UploadNewFile(const std::string& directory_resource_id,
-                                const base::FilePath& local_file_path,
-                                const std::string& title,
-                                const UploadFileCallback& callback) {
-  NOTREACHED();
-}
-
-void FakeAPIUtil::UploadExistingFile(const std::string& resource_id,
-                                     const std::string& remote_file_md5,
-                                     const base::FilePath& local_file_path,
-                                     const UploadFileCallback& callback) {
-  NOTREACHED();
-}
-
-void FakeAPIUtil::CreateDirectory(const std::string& parent_resource_id,
-                                  const std::string& title,
-                                  const ResourceIdCallback& callback) {
-  NOTREACHED();
-}
-
-bool FakeAPIUtil::IsAuthenticated() const { return true; }
-
-void FakeAPIUtil::DeleteFile(const std::string& resource_id,
-                             const std::string& remote_file_md5,
-                             const GDataErrorCallback& callback) {
-  if (!ContainsKey(remote_resources_, resource_id)) {
-    base::MessageLoopProxy::current()->PostTask(
-        FROM_HERE,
-        base::Bind(callback, google_apis::HTTP_NOT_FOUND));
-    return;
-  }
-
-  const RemoteResource& deleted_directory = remote_resources_[resource_id];
-  PushRemoteChange(deleted_directory.parent_resource_id,
-                   deleted_directory.parent_title,
-                   deleted_directory.title,
-                   deleted_directory.resource_id,
-                   deleted_directory.md5_checksum,
-                   SYNC_FILE_TYPE_UNKNOWN,
-                   true /* deleted */);
-
-  base::MessageLoopProxy::current()->PostTask(
-      FROM_HERE,
-      base::Bind(callback, google_apis::HTTP_SUCCESS));
-}
-
-GURL FakeAPIUtil::ResourceIdToResourceLink(
-    const std::string& resource_id) const {
-  return url_generator_.GenerateEditUrl(resource_id);
-}
-
-void FakeAPIUtil::EnsureSyncRootIsNotInMyDrive(
-    const std::string& sync_root_resource_id) {
-  // Nothing to do.
-}
-
-void FakeAPIUtil::PushRemoteChange(const std::string& parent_resource_id,
-                                   const std::string& parent_title,
-                                   const std::string& title,
-                                   const std::string& resource_id,
-                                   const std::string& md5,
-                                   SyncFileType type,
-                                   bool deleted) {
-  remote_resources_[resource_id] = RemoteResource(
-      parent_resource_id, parent_title, title, resource_id,
-      md5, type, deleted, ++largest_changestamp_);
-}
-
-scoped_ptr<google_apis::ResourceEntry> FakeAPIUtil::CreateResourceEntry(
-    const RemoteResource& resource) const {
-  scoped_ptr<google_apis::ResourceEntry> entry(
-      new google_apis::ResourceEntry());
-  ScopedVector<google_apis::Link> parent_links;
-  scoped_ptr<google_apis::Link> link(new google_apis::Link());
-
-  link->set_type(google_apis::Link::LINK_PARENT);
-  link->set_href(ResourceIdToResourceLink(resource.parent_resource_id));
-  link->set_title(resource.parent_title);
-  parent_links.push_back(link.release());
-
-  entry->set_links(&parent_links);
-  entry->set_title(resource.title);
-  entry->set_resource_id(resource.resource_id);
-  entry->set_file_md5(resource.md5_checksum);
-  entry->set_deleted(resource.deleted);
-  entry->set_changestamp(resource.changestamp);
-
-  switch (resource.type) {
-    case SYNC_FILE_TYPE_FILE:
-      entry->set_kind(google_apis::ENTRY_KIND_FILE);
-      break;
-    case SYNC_FILE_TYPE_DIRECTORY:
-      entry->set_kind(google_apis::ENTRY_KIND_FOLDER);
-      break;
-    case SYNC_FILE_TYPE_UNKNOWN:
-      entry->set_kind(google_apis::ENTRY_KIND_UNKNOWN);
-      break;
-  }
-
-  return entry.Pass();
-}
-
-}  // namespace drive
-}  // namespace sync_file_system
diff --git a/chrome/browser/sync_file_system/drive/fake_api_util.h b/chrome/browser/sync_file_system/drive/fake_api_util.h
deleted file mode 100644
index 17096fd..0000000
--- a/chrome/browser/sync_file_system/drive/fake_api_util.h
+++ /dev/null
@@ -1,132 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_SYNC_FILE_SYSTEM_DRIVE_FAKE_API_UTIL_H_
-#define CHROME_BROWSER_SYNC_FILE_SYSTEM_DRIVE_FAKE_API_UTIL_H_
-
-#include <map>
-#include <string>
-
-#include "chrome/browser/google_apis/drive_api_parser.h"
-#include "chrome/browser/google_apis/gdata_wapi_parser.h"
-#include "chrome/browser/google_apis/gdata_wapi_url_generator.h"
-#include "chrome/browser/sync_file_system/drive/api_util_interface.h"
-#include "webkit/browser/fileapi/syncable/sync_file_type.h"
-
-class GURL;
-class Profile;
-
-namespace google_apis {
-class ResourceEntry;
-}
-
-namespace sync_file_system {
-namespace drive {
-
-class FakeAPIUtil : public APIUtilInterface {
- public:
-  struct RemoteResource {
-    std::string parent_resource_id;
-    std::string parent_title;
-    std::string title;
-    std::string resource_id;
-    std::string md5_checksum;
-    SyncFileType type;
-    bool deleted;
-    int64 changestamp;
-
-    RemoteResource();
-    RemoteResource(const std::string& parent_resource_id,
-                   const std::string& parent_title,
-                   const std::string& title,
-                   const std::string& resource_id,
-                   const std::string& md5_checksum,
-                   SyncFileType type,
-                   bool deleted,
-                   int64 changestamp);
-    ~RemoteResource();
-  };
-
-  struct RemoteResourceComparator {
-    // Returns lexicographical order referring all members.
-    bool operator()(const RemoteResource& left, const RemoteResource& right);
-  };
-
-  typedef std::map<std::string, RemoteResource> RemoteResourceByResourceId;
-
-  FakeAPIUtil();
-  virtual ~FakeAPIUtil();
-
-  // APIUtilInterface overrides.
-  virtual void AddObserver(APIUtilObserver* observer) OVERRIDE;
-  virtual void RemoveObserver(APIUtilObserver* observer) OVERRIDE;
-  virtual void GetDriveDirectoryForSyncRoot(
-      const ResourceIdCallback& callback) OVERRIDE;
-  virtual void GetDriveDirectoryForOrigin(
-      const std::string& sync_root_resource_id,
-      const GURL& origin,
-      const ResourceIdCallback& callback) OVERRIDE;
-  virtual void GetLargestChangeStamp(
-      const ChangeStampCallback& callback) OVERRIDE;
-  virtual void GetResourceEntry(const std::string& resource_id,
-                                const ResourceEntryCallback& callback) OVERRIDE;
-  virtual void ListFiles(const std::string& directory_resource_id,
-                         const ResourceListCallback& callback) OVERRIDE;
-  virtual void ListChanges(int64 start_changestamp,
-                           const ResourceListCallback& callback) OVERRIDE;
-  virtual void ContinueListing(const GURL& feed_url,
-                               const ResourceListCallback& callback) OVERRIDE;
-  virtual void DownloadFile(const std::string& resource_id,
-                            const std::string& local_file_md5,
-                            const base::FilePath& local_file_path,
-                            const DownloadFileCallback& callback) OVERRIDE;
-  virtual void UploadNewFile(const std::string& directory_resource_id,
-                             const base::FilePath& local_file_path,
-                             const std::string& title,
-                             const UploadFileCallback& callback) OVERRIDE;
-  virtual void UploadExistingFile(const std::string& resource_id,
-                                  const std::string& remote_file_md5,
-                                  const base::FilePath& local_file_path,
-                                  const UploadFileCallback& callback) OVERRIDE;
-  virtual void CreateDirectory(const std::string& parent_resource_id,
-                               const std::string& title,
-                               const ResourceIdCallback& callback) OVERRIDE;
-  virtual bool IsAuthenticated() const OVERRIDE;
-  virtual void DeleteFile(const std::string& resource_id,
-                          const std::string& remote_file_md5,
-                          const GDataErrorCallback& callback) OVERRIDE;
-  virtual GURL ResourceIdToResourceLink(
-      const std::string& resource_id) const OVERRIDE;
-  virtual void EnsureSyncRootIsNotInMyDrive(
-      const std::string& sync_root_resource_id) OVERRIDE;
-
-  void PushRemoteChange(const std::string& parent_resource_id,
-                        const std::string& parent_title,
-                        const std::string& title,
-                        const std::string& resource_id,
-                        const std::string& md5,
-                        SyncFileType type,
-                        bool deleted);
-
-  const RemoteResourceByResourceId& remote_resources() const {
-    return remote_resources_;
-  }
-
- private:
-  struct ChangeStampComparator;
-  RemoteResourceByResourceId remote_resources_;
-
-  scoped_ptr<google_apis::ResourceEntry> CreateResourceEntry(
-      const RemoteResource& resource_id) const;
-
-  int64 largest_changestamp_;
-  google_apis::GDataWapiUrlGenerator url_generator_;
-
-  DISALLOW_COPY_AND_ASSIGN(FakeAPIUtil);
-};
-
-}  // namespace drive
-}  // namespace sync_file_system
-
-#endif  // CHROME_BROWSER_SYNC_FILE_SYSTEM_DRIVE_FAKE_API_UTIL_H_
diff --git a/chrome/browser/sync_file_system/drive/fake_api_util_unittest.cc b/chrome/browser/sync_file_system/drive/fake_api_util_unittest.cc
deleted file mode 100644
index ba146a2..0000000
--- a/chrome/browser/sync_file_system/drive/fake_api_util_unittest.cc
+++ /dev/null
@@ -1,141 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/sync_file_system/drive/fake_api_util.h"
-
-#include <string>
-
-#include "base/bind.h"
-#include "base/files/file_path.h"
-#include "base/message_loop.h"
-#include "chrome/browser/google_apis/gdata_errorcode.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace sync_file_system {
-namespace drive {
-
-namespace {
-
-void DidDownloadFile(google_apis::GDataErrorCode* error_out,
-                     std::string* file_md5_out,
-                     google_apis::GDataErrorCode error,
-                     const std::string& file_md5,
-                     int64 file_size,
-                     const base::Time& updated_time) {
-  *error_out = error;
-  *file_md5_out = file_md5;
-}
-
-void DidGetChangeList(google_apis::GDataErrorCode* error_out,
-                      scoped_ptr<google_apis::ResourceList>* change_list_out,
-                      google_apis::GDataErrorCode error,
-                      scoped_ptr<google_apis::ResourceList> change_list) {
-  *error_out = error;
-  *change_list_out = change_list.Pass();
-}
-
-void DidDeleteFile(google_apis::GDataErrorCode* error_out,
-                   google_apis::GDataErrorCode error) {
-  *error_out = error;
-}
-
-}  // namespace
-
-TEST(FakeAPIUtilTest, ChangeSquashTest) {
-  base::MessageLoop message_loop;
-  FakeAPIUtil api_util;
-  std::string kParentResourceId("parent resource id");
-  std::string kParentTitle("app-id");
-  std::string kTitle1("title 1");
-  std::string kTitle2("title 2");
-  std::string kTitle3("title 3");
-  std::string kResourceId1("resource id 1");
-  std::string kResourceId2("resource id 2");
-  std::string kMD5_1("md5 1");
-  std::string kMD5_2("md5 2");
-  std::string kMD5_3("md5 3");
-  base::FilePath kTempFilePath(FILE_PATH_LITERAL("tmp_file"));
-
-  api_util.PushRemoteChange(kParentResourceId,
-                            kParentTitle,
-                            kTitle1,
-                            kResourceId1,
-                            kMD5_1,
-                            SYNC_FILE_TYPE_FILE,
-                            false /* deleted */);
-  api_util.PushRemoteChange(kParentResourceId,
-                            kParentTitle,
-                            kTitle1,
-                            kResourceId1,
-                            kMD5_1,
-                            SYNC_FILE_TYPE_FILE,
-                            false /* deleted */);
-  api_util.PushRemoteChange(kParentResourceId,
-                            kParentTitle,
-                            kTitle1,
-                            kResourceId1,
-                            kMD5_1,
-                            SYNC_FILE_TYPE_FILE,
-                            true /* deleted */);
-  api_util.PushRemoteChange(kParentResourceId,
-                            kParentTitle,
-                            kTitle2,
-                            kResourceId2,
-                            kMD5_2,
-                            SYNC_FILE_TYPE_FILE,
-                            false /* deleted */);
-  api_util.PushRemoteChange(kParentResourceId,
-                            kParentTitle,
-                            kTitle3,
-                            kResourceId2,
-                            kMD5_3,
-                            SYNC_FILE_TYPE_FILE,
-                            false /* deleted */);
-
-  google_apis::GDataErrorCode error;
-  std::string md5;
-  api_util.DownloadFile(kResourceId1,
-                        kMD5_1,
-                        kTempFilePath,
-                        base::Bind(DidDownloadFile, &error, &md5));
-  message_loop.RunUntilIdle();
-  EXPECT_EQ(google_apis::HTTP_NOT_FOUND, error);
-  EXPECT_TRUE(md5.empty());
-
-  scoped_ptr<google_apis::ResourceList> change_list;
-  api_util.ListChanges(0, base::Bind(&DidGetChangeList, &error, &change_list));
-  message_loop.RunUntilIdle();
-  EXPECT_EQ(2u, change_list->entries().size());
-
-  EXPECT_EQ(kResourceId1, change_list->entries()[0]->resource_id());
-  EXPECT_TRUE(change_list->entries()[0]->deleted());
-
-  EXPECT_EQ(kResourceId2, change_list->entries()[1]->resource_id());
-  EXPECT_EQ(kMD5_3, change_list->entries()[1]->file_md5());
-  EXPECT_FALSE(change_list->entries()[1]->deleted());
-}
-
-TEST(FakeAPIUtilTest, DeleteFile) {
-  base::MessageLoop message_loop;
-  FakeAPIUtil api_util;
-  std::string resource_id = "resource_id_to_be_deleted";
-  api_util.PushRemoteChange("parent_id",
-                            "parent_title",
-                            "resource_title",
-                            resource_id,
-                            "resource_md5",
-                            SYNC_FILE_TYPE_FILE,
-                            false /* deleted */);
-
-  google_apis::GDataErrorCode error = google_apis::HTTP_NOT_FOUND;
-  api_util.DeleteFile(
-      resource_id, std::string(), base::Bind(&DidDeleteFile, &error));
-  message_loop.RunUntilIdle();
-
-  EXPECT_EQ(google_apis::HTTP_SUCCESS, error);
-  EXPECT_TRUE(api_util.remote_resources().find(resource_id)->second.deleted);
-}
-
-}  // namespace drive
-}  // namespace sync_file_system
diff --git a/chrome/browser/sync_file_system/drive/local_change_processor_delegate.cc b/chrome/browser/sync_file_system/drive/local_change_processor_delegate.cc
deleted file mode 100644
index 4c1d5f5..0000000
--- a/chrome/browser/sync_file_system/drive/local_change_processor_delegate.cc
+++ /dev/null
@@ -1,591 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/sync_file_system/drive/local_change_processor_delegate.h"
-
-#include "base/bind.h"
-#include "base/callback.h"
-#include "chrome/browser/sync_file_system/drive/api_util.h"
-#include "chrome/browser/sync_file_system/drive_file_sync_service.h"
-#include "chrome/browser/sync_file_system/drive_metadata_store.h"
-#include "chrome/browser/sync_file_system/logger.h"
-#include "webkit/browser/fileapi/syncable/syncable_file_system_util.h"
-
-namespace sync_file_system {
-namespace drive {
-
-LocalChangeProcessorDelegate::LocalChangeProcessorDelegate(
-    DriveFileSyncService* sync_service,
-    const FileChange& local_change,
-    const base::FilePath& local_path,
-    const SyncFileMetadata& local_metadata,
-    const fileapi::FileSystemURL& url)
-    : sync_service_(sync_service),
-      operation_(SYNC_OPERATION_NONE),
-      url_(url),
-      local_change_(local_change),
-      local_path_(local_path),
-      local_metadata_(local_metadata),
-      has_drive_metadata_(false),
-      has_remote_change_(false),
-      weak_factory_(this) {}
-
-LocalChangeProcessorDelegate::~LocalChangeProcessorDelegate() {}
-
-void LocalChangeProcessorDelegate::Run(const SyncStatusCallback& callback) {
-  // TODO(nhiroki): support directory operations (http://crbug.com/161442).
-  DCHECK(IsSyncFSDirectoryOperationEnabled() || !local_change_.IsDirectory());
-  operation_ = SYNC_OPERATION_NONE;
-
-  has_drive_metadata_ =
-      metadata_store()->ReadEntry(url_, &drive_metadata_) == SYNC_STATUS_OK;
-
-  if (!has_drive_metadata_)
-    drive_metadata_.set_md5_checksum(std::string());
-
-  sync_service_->EnsureOriginRootDirectory(
-      url_.origin(),
-      base::Bind(&LocalChangeProcessorDelegate::DidGetOriginRoot,
-                 weak_factory_.GetWeakPtr(),
-                 callback));
-}
-
-void LocalChangeProcessorDelegate::DidGetOriginRoot(
-    const SyncStatusCallback& callback,
-    SyncStatusCode status,
-    const std::string& origin_resource_id) {
-  if (status != SYNC_STATUS_OK) {
-    callback.Run(status);
-    return;
-  }
-
-  origin_resource_id_ = origin_resource_id;
-
-  has_remote_change_ =
-      remote_change_handler()->GetChangeForURL(url_, &remote_change_);
-  if (has_remote_change_ && drive_metadata_.resource_id().empty())
-    drive_metadata_.set_resource_id(remote_change_.resource_id);
-
-  SyncFileType remote_file_type =
-      has_remote_change_ ? remote_change_.change.file_type() :
-      has_drive_metadata_ ?
-          DriveFileSyncService::DriveMetadataResourceTypeToSyncFileType(
-              drive_metadata_.type())
-      : SYNC_FILE_TYPE_UNKNOWN;
-
-  DCHECK_EQ(SYNC_OPERATION_NONE, operation_);
-  operation_ = LocalSyncOperationResolver::Resolve(
-      local_change_,
-      has_remote_change_ ? &remote_change_.change : NULL,
-      has_drive_metadata_ ? &drive_metadata_ : NULL);
-
-  util::Log(logging::LOG_VERBOSE, FROM_HERE,
-            "ApplyLocalChange for %s local_change:%s ===> %s",
-            url_.DebugString().c_str(),
-            local_change_.DebugString().c_str(),
-            SyncOperationTypeToString(operation_));
-
-  switch (operation_) {
-    case SYNC_OPERATION_ADD_FILE:
-      UploadNewFile(callback);
-      return;
-    case SYNC_OPERATION_ADD_DIRECTORY:
-      CreateDirectory(callback);
-      return;
-    case SYNC_OPERATION_UPDATE_FILE:
-      UploadExistingFile(callback);
-      return;
-    case SYNC_OPERATION_DELETE:
-      Delete(callback);
-      return;
-    case SYNC_OPERATION_NONE:
-      callback.Run(SYNC_STATUS_OK);
-      return;
-    case SYNC_OPERATION_CONFLICT:
-      HandleConflict(callback);
-      return;
-    case SYNC_OPERATION_RESOLVE_TO_LOCAL:
-      ResolveToLocal(callback);
-      return;
-    case SYNC_OPERATION_RESOLVE_TO_REMOTE:
-      ResolveToRemote(callback, remote_file_type);
-      return;
-    case SYNC_OPERATION_DELETE_METADATA:
-      DeleteMetadata(base::Bind(
-          &LocalChangeProcessorDelegate::DidApplyLocalChange,
-          weak_factory_.GetWeakPtr(), callback, google_apis::HTTP_SUCCESS));
-      return;
-    case SYNC_OPERATION_FAIL: {
-      callback.Run(SYNC_STATUS_FAILED);
-      return;
-    }
-  }
-  NOTREACHED();
-  callback.Run(SYNC_STATUS_FAILED);
-}
-
-void LocalChangeProcessorDelegate::UploadNewFile(
-    const SyncStatusCallback& callback) {
-  api_util()->UploadNewFile(
-      origin_resource_id_,
-      local_path_,
-      DriveFileSyncService::PathToTitle(url_.path()),
-      base::Bind(&LocalChangeProcessorDelegate::DidUploadNewFile,
-                 weak_factory_.GetWeakPtr(), callback));
-}
-
-void LocalChangeProcessorDelegate::DidUploadNewFile(
-    const SyncStatusCallback& callback,
-    google_apis::GDataErrorCode error,
-    const std::string& resource_id,
-    const std::string& md5) {
-  switch (error) {
-    case google_apis::HTTP_CREATED:
-      UpdateMetadata(
-          resource_id, md5, DriveMetadata::RESOURCE_TYPE_FILE,
-          base::Bind(&LocalChangeProcessorDelegate::DidApplyLocalChange,
-                     weak_factory_.GetWeakPtr(), callback, error));
-      sync_service_->NotifyObserversFileStatusChanged(
-          url_,
-          SYNC_FILE_STATUS_SYNCED,
-          SYNC_ACTION_ADDED,
-          SYNC_DIRECTION_LOCAL_TO_REMOTE);
-      return;
-    case google_apis::HTTP_CONFLICT:
-      HandleCreationConflict(resource_id, DriveMetadata::RESOURCE_TYPE_FILE,
-                             callback);
-      return;
-    default:
-      callback.Run(GDataErrorCodeToSyncStatusCodeWrapper(error));
-  }
-}
-
-void LocalChangeProcessorDelegate::CreateDirectory(
-    const SyncStatusCallback& callback) {
-  DCHECK(IsSyncFSDirectoryOperationEnabled());
-  api_util()->CreateDirectory(
-      origin_resource_id_,
-      DriveFileSyncService::PathToTitle(url_.path()),
-      base::Bind(&LocalChangeProcessorDelegate::DidCreateDirectory,
-                 weak_factory_.GetWeakPtr(), callback));
-}
-
-void LocalChangeProcessorDelegate::DidCreateDirectory(
-    const SyncStatusCallback& callback,
-    google_apis::GDataErrorCode error,
-    const std::string& resource_id) {
-  switch (error) {
-    case google_apis::HTTP_SUCCESS:
-    case google_apis::HTTP_CREATED: {
-      UpdateMetadata(
-          resource_id, std::string(), DriveMetadata::RESOURCE_TYPE_FOLDER,
-          base::Bind(&LocalChangeProcessorDelegate::DidApplyLocalChange,
-                     weak_factory_.GetWeakPtr(), callback, error));
-      sync_service_->NotifyObserversFileStatusChanged(
-          url_,
-          SYNC_FILE_STATUS_SYNCED,
-          SYNC_ACTION_ADDED,
-          SYNC_DIRECTION_LOCAL_TO_REMOTE);
-      return;
-    }
-
-    case google_apis::HTTP_CONFLICT:
-      // There were conflicts and a file was left.
-      // TODO(kinuko): Handle the latter case (http://crbug.com/237090).
-      // Fall-through
-
-    default:
-      callback.Run(GDataErrorCodeToSyncStatusCodeWrapper(error));
-  }
-}
-
-void LocalChangeProcessorDelegate::UploadExistingFile(
-    const SyncStatusCallback& callback) {
-  DCHECK(has_drive_metadata_);
-  if (drive_metadata_.resource_id().empty()) {
-    UploadNewFile(callback);
-    return;
-  }
-
-  api_util()->UploadExistingFile(
-      drive_metadata_.resource_id(),
-      drive_metadata_.md5_checksum(),
-      local_path_,
-      base::Bind(&LocalChangeProcessorDelegate::DidUploadExistingFile,
-                 weak_factory_.GetWeakPtr(), callback));
-}
-
-void LocalChangeProcessorDelegate::DidUploadExistingFile(
-    const SyncStatusCallback& callback,
-    google_apis::GDataErrorCode error,
-    const std::string& resource_id,
-    const std::string& md5) {
-  DCHECK(has_drive_metadata_);
-  switch (error) {
-    case google_apis::HTTP_SUCCESS:
-      UpdateMetadata(
-          resource_id, md5, DriveMetadata::RESOURCE_TYPE_FILE,
-          base::Bind(&LocalChangeProcessorDelegate::DidApplyLocalChange,
-                     weak_factory_.GetWeakPtr(), callback, error));
-      sync_service_->NotifyObserversFileStatusChanged(
-          url_,
-          SYNC_FILE_STATUS_SYNCED,
-          SYNC_ACTION_UPDATED,
-          SYNC_DIRECTION_LOCAL_TO_REMOTE);
-      return;
-    case google_apis::HTTP_CONFLICT:
-      HandleConflict(callback);
-      return;
-    case google_apis::HTTP_NOT_MODIFIED:
-      DidApplyLocalChange(callback,
-                          google_apis::HTTP_SUCCESS, SYNC_STATUS_OK);
-      return;
-    case google_apis::HTTP_NOT_FOUND:
-      UploadNewFile(callback);
-      return;
-    default: {
-      const SyncStatusCode status =
-          GDataErrorCodeToSyncStatusCodeWrapper(error);
-      DCHECK_NE(SYNC_STATUS_OK, status);
-      callback.Run(status);
-      return;
-    }
-  }
-}
-
-void LocalChangeProcessorDelegate::Delete(
-    const SyncStatusCallback& callback) {
-  if (!has_drive_metadata_) {
-    callback.Run(SYNC_STATUS_OK);
-    return;
-  }
-
-  if (drive_metadata_.resource_id().empty()) {
-    DidDelete(callback, google_apis::HTTP_NOT_FOUND);
-    return;
-  }
-
-  api_util()->DeleteFile(
-      drive_metadata_.resource_id(),
-      drive_metadata_.md5_checksum(),
-      base::Bind(&LocalChangeProcessorDelegate::DidDelete,
-                 weak_factory_.GetWeakPtr(), callback));
-}
-
-void LocalChangeProcessorDelegate::DidDelete(
-    const SyncStatusCallback& callback,
-    google_apis::GDataErrorCode error) {
-  DCHECK(has_drive_metadata_);
-
-  switch (error) {
-    case google_apis::HTTP_SUCCESS:
-    case google_apis::HTTP_NOT_FOUND:
-      DeleteMetadata(base::Bind(
-          &LocalChangeProcessorDelegate::DidApplyLocalChange,
-          weak_factory_.GetWeakPtr(), callback, google_apis::HTTP_SUCCESS));
-      sync_service_->NotifyObserversFileStatusChanged(
-          url_,
-          SYNC_FILE_STATUS_SYNCED,
-          SYNC_ACTION_DELETED,
-          SYNC_DIRECTION_LOCAL_TO_REMOTE);
-      return;
-    case google_apis::HTTP_PRECONDITION:
-    case google_apis::HTTP_CONFLICT:
-      // Delete |drive_metadata| on the conflict case.
-      // Conflicted remote change should be applied as a future remote change.
-      DeleteMetadata(base::Bind(
-          &LocalChangeProcessorDelegate::DidDeleteMetadataForDeletionConflict,
-          weak_factory_.GetWeakPtr(), callback));
-      sync_service_->NotifyObserversFileStatusChanged(
-          url_,
-          SYNC_FILE_STATUS_SYNCED,
-          SYNC_ACTION_DELETED,
-          SYNC_DIRECTION_LOCAL_TO_REMOTE);
-      return;
-    default: {
-      const SyncStatusCode status =
-          GDataErrorCodeToSyncStatusCodeWrapper(error);
-      DCHECK_NE(SYNC_STATUS_OK, status);
-      callback.Run(status);
-      return;
-    }
-  }
-}
-
-void LocalChangeProcessorDelegate::DidDeleteMetadataForDeletionConflict(
-    const SyncStatusCallback& callback,
-    SyncStatusCode status) {
-  callback.Run(SYNC_STATUS_OK);
-}
-
-void LocalChangeProcessorDelegate::ResolveToLocal(
-    const SyncStatusCallback& callback) {
-  if (drive_metadata_.resource_id().empty()) {
-    DidDeleteFileToResolveToLocal(callback, google_apis::HTTP_NOT_FOUND);
-    return;
-  }
-
-  api_util()->DeleteFile(
-      drive_metadata_.resource_id(),
-      drive_metadata_.md5_checksum(),
-      base::Bind(
-          &LocalChangeProcessorDelegate::DidDeleteFileToResolveToLocal,
-          weak_factory_.GetWeakPtr(), callback));
-}
-
-void LocalChangeProcessorDelegate::DidDeleteFileToResolveToLocal(
-    const SyncStatusCallback& callback,
-    google_apis::GDataErrorCode error) {
-  if (error != google_apis::HTTP_SUCCESS &&
-      error != google_apis::HTTP_NOT_FOUND) {
-    callback.Run(GDataErrorCodeToSyncStatusCodeWrapper(error));
-    return;
-  }
-
-  DCHECK_NE(SYNC_FILE_TYPE_UNKNOWN, local_metadata_.file_type);
-  if (local_metadata_.file_type == SYNC_FILE_TYPE_FILE) {
-    UploadNewFile(callback);
-    return;
-  }
-
-  DCHECK(IsSyncFSDirectoryOperationEnabled());
-  DCHECK_EQ(SYNC_FILE_TYPE_DIRECTORY, local_metadata_.file_type);
-  CreateDirectory(callback);
-}
-
-void LocalChangeProcessorDelegate::ResolveToRemote(
-    const SyncStatusCallback& callback,
-    SyncFileType remote_file_type) {
-  // Mark the file as to-be-fetched.
-  DCHECK(!drive_metadata_.resource_id().empty());
-
-  SetMetadataToBeFetched(
-      DriveFileSyncService::SyncFileTypeToDriveMetadataResourceType(
-          remote_file_type),
-      base::Bind(&LocalChangeProcessorDelegate::DidResolveToRemote,
-                 weak_factory_.GetWeakPtr(), callback));
-  // The synced notification will be dispatched when the remote file is
-  // downloaded.
-}
-
-void LocalChangeProcessorDelegate::DidResolveToRemote(
-    const SyncStatusCallback& callback,
-    SyncStatusCode status) {
-  DCHECK(has_drive_metadata_);
-  if (status != SYNC_STATUS_OK) {
-    callback.Run(status);
-    return;
-  }
-
-  SyncFileType file_type = SYNC_FILE_TYPE_FILE;
-  if (drive_metadata_.type() == DriveMetadata::RESOURCE_TYPE_FOLDER)
-    file_type = SYNC_FILE_TYPE_DIRECTORY;
-  sync_service_->AppendFetchChange(
-      url_.origin(), url_.path(), drive_metadata_.resource_id(), file_type);
-  callback.Run(status);
-}
-
-void LocalChangeProcessorDelegate::DidApplyLocalChange(
-    const SyncStatusCallback& callback,
-    const google_apis::GDataErrorCode error,
-    SyncStatusCode status) {
-  if ((operation_ == SYNC_OPERATION_DELETE ||
-       operation_ == SYNC_OPERATION_DELETE_METADATA) &&
-      (status == SYNC_FILE_ERROR_NOT_FOUND ||
-       status == SYNC_DATABASE_ERROR_NOT_FOUND)) {
-    status = SYNC_STATUS_OK;
-  }
-
-  if (status == SYNC_STATUS_OK) {
-    remote_change_handler()->RemoveChangeForURL(url_);
-    status = GDataErrorCodeToSyncStatusCodeWrapper(error);
-  }
-  callback.Run(status);
-}
-
-void LocalChangeProcessorDelegate::UpdateMetadata(
-    const std::string& resource_id,
-    const std::string& md5,
-    DriveMetadata::ResourceType type,
-    const SyncStatusCallback& callback) {
-  has_drive_metadata_ = true;
-  drive_metadata_.set_resource_id(resource_id);
-  drive_metadata_.set_md5_checksum(md5);
-  drive_metadata_.set_conflicted(false);
-  drive_metadata_.set_to_be_fetched(false);
-  drive_metadata_.set_type(type);
-  metadata_store()->UpdateEntry(url_, drive_metadata_, callback);
-}
-
-void LocalChangeProcessorDelegate::ResetMetadataMD5(
-    const SyncStatusCallback& callback) {
-  has_drive_metadata_ = true;
-  drive_metadata_.set_md5_checksum(std::string());
-  metadata_store()->UpdateEntry(url_, drive_metadata_, callback);
-}
-
-void LocalChangeProcessorDelegate::SetMetadataToBeFetched(
-    DriveMetadata::ResourceType type,
-    const SyncStatusCallback& callback) {
-  has_drive_metadata_ = true;
-  drive_metadata_.set_md5_checksum(std::string());
-  drive_metadata_.set_conflicted(false);
-  drive_metadata_.set_to_be_fetched(true);
-  drive_metadata_.set_type(type);
-  metadata_store()->UpdateEntry(url_, drive_metadata_, callback);
-}
-
-void LocalChangeProcessorDelegate::SetMetadataConflict(
-    const SyncStatusCallback& callback) {
-  has_drive_metadata_ = true;
-  drive_metadata_.set_conflicted(true);
-  drive_metadata_.set_to_be_fetched(false);
-  metadata_store()->UpdateEntry(url_, drive_metadata_, callback);
-}
-
-void LocalChangeProcessorDelegate::DeleteMetadata(
-    const SyncStatusCallback& callback) {
-  metadata_store()->DeleteEntry(url_, callback);
-}
-
-void LocalChangeProcessorDelegate::HandleCreationConflict(
-    const std::string& resource_id,
-    DriveMetadata::ResourceType type,
-    const SyncStatusCallback& callback) {
-  // File-file conflict is found.
-  // Populates a fake drive_metadata and set has_drive_metadata = true.
-  // In HandleConflictLocalSync:
-  // - If conflict_resolution is manual, we'll change conflicted to true
-  //   and save the metadata.
-  // - Otherwise we'll save the metadata with empty md5 and will start
-  //   over local sync as UploadExistingFile.
-  drive_metadata_.set_resource_id(resource_id);
-  drive_metadata_.set_md5_checksum(std::string());
-  drive_metadata_.set_conflicted(false);
-  drive_metadata_.set_to_be_fetched(false);
-  drive_metadata_.set_type(type);
-  has_drive_metadata_ = true;
-  HandleConflict(callback);
-}
-
-void LocalChangeProcessorDelegate::HandleConflict(
-    const SyncStatusCallback& callback) {
-  DCHECK(!drive_metadata_.resource_id().empty());
-  api_util()->GetResourceEntry(
-      drive_metadata_.resource_id(),
-      base::Bind(
-          &LocalChangeProcessorDelegate::DidGetEntryForConflictResolution,
-          weak_factory_.GetWeakPtr(), callback));
-}
-
-void LocalChangeProcessorDelegate::DidGetEntryForConflictResolution(
-    const SyncStatusCallback& callback,
-    google_apis::GDataErrorCode error,
-    scoped_ptr<google_apis::ResourceEntry> entry) {
-  SyncFileType remote_file_type = SYNC_FILE_TYPE_UNKNOWN;
-  DriveFileSyncService::ConflictResolutionResult resolution;
-
-  if (error != google_apis::HTTP_SUCCESS) {
-    resolution = DriveFileSyncService::CONFLICT_RESOLUTION_LOCAL_WIN;
-  } else {
-    SyncFileType local_file_type = local_metadata_.file_type;
-    base::Time local_modification_time = local_metadata_.last_modified;
-
-    base::Time remote_modification_time = entry->updated_time();
-    if (entry->is_file())
-      remote_file_type = SYNC_FILE_TYPE_FILE;
-    else if (entry->is_folder())
-      remote_file_type = SYNC_FILE_TYPE_DIRECTORY;
-    else
-      remote_file_type = SYNC_FILE_TYPE_UNKNOWN;
-
-    resolution = sync_service_->ResolveConflictForLocalSync(
-        local_file_type, local_modification_time,
-        remote_file_type, remote_modification_time);
-  }
-
-  switch (resolution) {
-    case DriveFileSyncService::CONFLICT_RESOLUTION_MARK_CONFLICT:
-      HandleManualResolutionCase(callback);
-      return;
-    case DriveFileSyncService::CONFLICT_RESOLUTION_LOCAL_WIN:
-      HandleLocalWinCase(callback);
-      return;
-    case DriveFileSyncService::CONFLICT_RESOLUTION_REMOTE_WIN:
-      HandleRemoteWinCase(callback, remote_file_type);
-      return;
-  }
-  NOTREACHED();
-  callback.Run(SYNC_STATUS_FAILED);
-}
-
-void LocalChangeProcessorDelegate::HandleManualResolutionCase(
-    const SyncStatusCallback& callback) {
-  if (drive_metadata_.conflicted()) {
-    callback.Run(SYNC_STATUS_HAS_CONFLICT);
-    return;
-  }
-
-  SetMetadataConflict(
-      base::Bind(&LocalChangeProcessorDelegate::DidApplyLocalChange,
-                 weak_factory_.GetWeakPtr(), callback,
-                 google_apis::HTTP_CONFLICT));
-}
-
-void LocalChangeProcessorDelegate::HandleLocalWinCase(
-    const SyncStatusCallback& callback) {
-  util::Log(logging::LOG_VERBOSE, FROM_HERE,
-            "Resolving conflict for local sync: %s: LOCAL WIN",
-            url_.DebugString().c_str());
-
-  DCHECK(!drive_metadata_.resource_id().empty());
-  if (!has_drive_metadata_) {
-    StartOver(callback, SYNC_STATUS_OK);
-    return;
-  }
-
-  ResetMetadataMD5(base::Bind(&LocalChangeProcessorDelegate::StartOver,
-                              weak_factory_.GetWeakPtr(), callback));
-}
-
-void LocalChangeProcessorDelegate::HandleRemoteWinCase(
-    const SyncStatusCallback& callback,
-    SyncFileType remote_file_type) {
-  util::Log(logging::LOG_VERBOSE, FROM_HERE,
-            "Resolving conflict for local sync: %s: REMOTE WIN",
-            url_.DebugString().c_str());
-  ResolveToRemote(callback, remote_file_type);
-}
-
-void LocalChangeProcessorDelegate::StartOver(const SyncStatusCallback& callback,
-                                             SyncStatusCode status) {
-  if (status != SYNC_STATUS_OK) {
-    callback.Run(status);
-    return;
-  }
-
-  remote_change_handler()->RemoveChangeForURL(url_);
-  Run(callback);
-}
-
-SyncStatusCode
-LocalChangeProcessorDelegate::GDataErrorCodeToSyncStatusCodeWrapper(
-    google_apis::GDataErrorCode error) {
-  return sync_service_->GDataErrorCodeToSyncStatusCodeWrapper(error);
-}
-
-DriveMetadataStore* LocalChangeProcessorDelegate::metadata_store() {
-  return sync_service_->metadata_store_.get();
-}
-
-APIUtilInterface* LocalChangeProcessorDelegate::api_util() {
-  return sync_service_->api_util_.get();
-}
-
-RemoteChangeHandler* LocalChangeProcessorDelegate::remote_change_handler() {
-  return &sync_service_->remote_change_handler_;
-}
-
-}  // namespace drive
-}  // namespace sync_file_system
diff --git a/chrome/browser/sync_file_system/drive/local_change_processor_delegate.h b/chrome/browser/sync_file_system/drive/local_change_processor_delegate.h
deleted file mode 100644
index d9450cf..0000000
--- a/chrome/browser/sync_file_system/drive/local_change_processor_delegate.h
+++ /dev/null
@@ -1,140 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_SYNC_FILE_SYSTEM_DRIVE_LOCAL_CHANGE_PROCESSOR_DELEGATE_H_
-#define CHROME_BROWSER_SYNC_FILE_SYSTEM_DRIVE_LOCAL_CHANGE_PROCESSOR_DELEGATE_H_
-
-#include "base/callback.h"
-#include "base/memory/weak_ptr.h"
-#include "chrome/browser/sync_file_system/drive_file_sync_service.h"
-#include "chrome/browser/sync_file_system/sync_file_system.pb.h"
-#include "webkit/browser/fileapi/file_system_url.h"
-#include "webkit/browser/fileapi/syncable/file_change.h"
-#include "webkit/browser/fileapi/syncable/sync_callbacks.h"
-#include "webkit/browser/fileapi/syncable/sync_file_metadata.h"
-
-namespace sync_file_system {
-
-class DriveMetadataStore;
-
-namespace drive {
-
-class APIUtil;
-
-// This class handles ApplyLocalChange in LocalChangeProcessor, and its instance
-// represents single ApplyLocalChange operation.
-// The caller is responsible to own the instance, and can cancel operation by
-// deleting the instance or |sync_service|.
-class LocalChangeProcessorDelegate {
- public:
-  typedef RemoteChangeHandler::RemoteChange RemoteChange;
-
-  LocalChangeProcessorDelegate(
-      DriveFileSyncService* sync_service,
-      const FileChange& change,
-      const base::FilePath& local_file_path,
-      const SyncFileMetadata& local_file_metadata,
-      const fileapi::FileSystemURL& url);
-  ~LocalChangeProcessorDelegate();
-
-  void Run(const SyncStatusCallback& callback);
-
- private:
-  void DidGetOriginRoot(const SyncStatusCallback& callback,
-                        SyncStatusCode status,
-                        const std::string& resource_id);
-  void UploadNewFile(const SyncStatusCallback& callback);
-  void DidUploadNewFile(const SyncStatusCallback& callback,
-                        google_apis::GDataErrorCode error,
-                        const std::string& resource_id,
-                        const std::string& md5);
-  void CreateDirectory(const SyncStatusCallback& callback);
-  void DidCreateDirectory(
-      const SyncStatusCallback& callback,
-      google_apis::GDataErrorCode error,
-      const std::string& resource_id);
-  void UploadExistingFile(const SyncStatusCallback& callback);
-  void DidUploadExistingFile(
-      const SyncStatusCallback& callback,
-      google_apis::GDataErrorCode error,
-      const std::string& resource_id,
-      const std::string& md5);
-  void Delete(const SyncStatusCallback& callback);
-  void DidDelete(const SyncStatusCallback& callback,
-                 google_apis::GDataErrorCode error);
-  void DidDeleteMetadataForDeletionConflict(
-      const SyncStatusCallback& callback,
-      SyncStatusCode status);
-  void ResolveToLocal(const SyncStatusCallback& callback);
-  void DidDeleteFileToResolveToLocal(
-      const SyncStatusCallback& callback,
-      google_apis::GDataErrorCode error);
-  void ResolveToRemote(const SyncStatusCallback& callback,
-                       SyncFileType remote_file_type);
-  void DidResolveToRemote(const SyncStatusCallback& callback,
-                          SyncStatusCode status);
-  void DidApplyLocalChange(
-      const SyncStatusCallback& callback,
-      const google_apis::GDataErrorCode error,
-      SyncStatusCode status);
-
-  // Metadata manipulation.
-  void UpdateMetadata(const std::string& resource_id,
-                      const std::string& md5,
-                      DriveMetadata::ResourceType type,
-                      const SyncStatusCallback& callback);
-  void ResetMetadataMD5(const SyncStatusCallback& callback);
-  void SetMetadataToBeFetched(DriveMetadata::ResourceType type,
-                              const SyncStatusCallback& callback);
-  void DeleteMetadata(const SyncStatusCallback& callback);
-  void SetMetadataConflict(const SyncStatusCallback& callback);
-
-  // Conflict handling.
-  void HandleCreationConflict(
-      const std::string& resource_id,
-      DriveMetadata::ResourceType type,
-      const SyncStatusCallback& callback);
-  void HandleConflict(const SyncStatusCallback& callback);
-  void DidGetEntryForConflictResolution(
-      const SyncStatusCallback& callback,
-      google_apis::GDataErrorCode error,
-      scoped_ptr<google_apis::ResourceEntry> entry);
-
-  void HandleManualResolutionCase(const SyncStatusCallback& callback);
-  void HandleLocalWinCase(const SyncStatusCallback& callback);
-  void HandleRemoteWinCase(const SyncStatusCallback& callback,
-                           SyncFileType remote_file_type);
-  void StartOver(const SyncStatusCallback& callback, SyncStatusCode status);
-
-  SyncStatusCode GDataErrorCodeToSyncStatusCodeWrapper(
-      google_apis::GDataErrorCode error);
-
-  DriveMetadataStore* metadata_store();
-  drive::APIUtilInterface* api_util();
-  RemoteChangeHandler* remote_change_handler();
-
-  DriveFileSyncService* sync_service_;  // Not owned.
-
-  SyncOperationType operation_;
-
-  fileapi::FileSystemURL url_;
-  FileChange local_change_;
-  base::FilePath local_path_;
-  SyncFileMetadata local_metadata_;
-  DriveMetadata drive_metadata_;
-  bool has_drive_metadata_;
-  RemoteChange remote_change_;
-  bool has_remote_change_;
-
-  std::string origin_resource_id_;
-
-  base::WeakPtrFactory<LocalChangeProcessorDelegate> weak_factory_;
-
-  DISALLOW_COPY_AND_ASSIGN(LocalChangeProcessorDelegate);
-};
-
-}  // namespace drive
-}  // namespace sync_file_system
-
-#endif  // CHROME_BROWSER_SYNC_FILE_SYSTEM_DRIVE_LOCAL_CHANGE_PROCESSOR_DELEGATE_H_
diff --git a/chrome/browser/sync_file_system/drive/metadata_db_migration_util.cc b/chrome/browser/sync_file_system/drive/metadata_db_migration_util.cc
deleted file mode 100644
index 96099c1..0000000
--- a/chrome/browser/sync_file_system/drive/metadata_db_migration_util.cc
+++ /dev/null
@@ -1,251 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/sync_file_system/drive/metadata_db_migration_util.h"
-
-#include "base/files/file_path.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/strings/string_util.h"
-#include "googleurl/src/gurl.h"
-#include "third_party/leveldatabase/src/include/leveldb/write_batch.h"
-#include "webkit/browser/fileapi/file_system_url.h"
-#include "webkit/common/fileapi/file_system_types.h"
-
-namespace sync_file_system {
-namespace drive {
-
-namespace {
-
-const base::FilePath::CharType kV0FormatPathPrefix[] =
-    FILE_PATH_LITERAL("drive/");
-const char kWapiFileIdPrefix[] = "file:";
-const char kWapiFolderIdPrefix[] = "folder:";
-
-std::string RemovePrefix(const std::string& str, const std::string& prefix) {
-  if (StartsWithASCII(str, prefix, true))
-    return std::string(str.begin() + prefix.size(), str.end());
-  return str;
-}
-
-}  // namespace
-
-bool ParseV0FormatFileSystemURL(const GURL& url,
-                                GURL* origin,
-                                base::FilePath* path) {
-  fileapi::FileSystemType mount_type;
-  base::FilePath virtual_path;
-
-  if (!fileapi::FileSystemURL::ParseFileSystemSchemeURL(
-          url, origin, &mount_type, &virtual_path) ||
-      mount_type != fileapi::kFileSystemTypeExternal) {
-    NOTREACHED() << "Failed to parse filesystem scheme URL " << url.spec();
-    return false;
-  }
-
-  base::FilePath::StringType prefix =
-      base::FilePath(kV0FormatPathPrefix).NormalizePathSeparators().value();
-  if (virtual_path.value().substr(0, prefix.size()) != prefix)
-    return false;
-
-  *path = base::FilePath(virtual_path.value().substr(prefix.size()));
-  return true;
-}
-
-std::string AddWapiFilePrefix(const std::string& resource_id) {
-  DCHECK(!StartsWithASCII(resource_id, kWapiFileIdPrefix, true));
-  DCHECK(!StartsWithASCII(resource_id, kWapiFolderIdPrefix, true));
-
-  if (resource_id.empty() ||
-      StartsWithASCII(resource_id, kWapiFileIdPrefix, true) ||
-      StartsWithASCII(resource_id, kWapiFolderIdPrefix, true))
-    return resource_id;
-  return kWapiFileIdPrefix + resource_id;
-}
-
-std::string AddWapiFolderPrefix(const std::string& resource_id) {
-  DCHECK(!StartsWithASCII(resource_id, kWapiFileIdPrefix, true));
-  DCHECK(!StartsWithASCII(resource_id, kWapiFolderIdPrefix, true));
-
-  if (resource_id.empty() ||
-      StartsWithASCII(resource_id, kWapiFileIdPrefix, true) ||
-      StartsWithASCII(resource_id, kWapiFolderIdPrefix, true))
-    return resource_id;
-  return kWapiFolderIdPrefix + resource_id;
-}
-
-std::string AddWapiIdPrefix(const std::string& resource_id,
-                            DriveMetadata_ResourceType type) {
-  switch (type) {
-    case DriveMetadata_ResourceType_RESOURCE_TYPE_FILE:
-      return AddWapiFilePrefix(resource_id);
-    case DriveMetadata_ResourceType_RESOURCE_TYPE_FOLDER:
-      return AddWapiFolderPrefix(resource_id);
-  }
-  NOTREACHED();
-  return resource_id;
-}
-
-std::string RemoveWapiIdPrefix(const std::string& resource_id) {
-  if (StartsWithASCII(resource_id, kWapiFileIdPrefix, true))
-    return RemovePrefix(resource_id, kWapiFileIdPrefix);
-  if (StartsWithASCII(resource_id, kWapiFolderIdPrefix, true))
-    return RemovePrefix(resource_id, kWapiFolderIdPrefix);
-  return resource_id;
-}
-
-SyncStatusCode MigrateDatabaseFromV0ToV1(leveldb::DB* db) {
-  // Version 0 database format:
-  //   key: "CHANGE_STAMP"
-  //   value: <Largest Changestamp>
-  //
-  //   key: "SYNC_ROOT_DIR"
-  //   value: <Resource ID of the sync root directory>
-  //
-  //   key: "METADATA: " +
-  //        <FileSystemURL serialized by SerializeSyncableFileSystemURL>
-  //   value: <Serialized DriveMetadata>
-  //
-  //   key: "BSYNC_ORIGIN: " + <URL string of a batch sync origin>
-  //   value: <Resource ID of the drive directory for the origin>
-  //
-  //   key: "ISYNC_ORIGIN: " + <URL string of a incremental sync origin>
-  //   value: <Resource ID of the drive directory for the origin>
-  //
-  // Version 1 database format (changed keys/fields are marked with '*'):
-  // * key: "VERSION" (new)
-  // * value: 1
-  //
-  //   key: "CHANGE_STAMP"
-  //   value: <Largest Changestamp>
-  //
-  //   key: "SYNC_ROOT_DIR"
-  //   value: <Resource ID of the sync root directory>
-  //
-  // * key: "METADATA: " + <Origin and URL> (changed)
-  // * value: <Serialized DriveMetadata>
-  //
-  //   key: "BSYNC_ORIGIN: " + <URL string of a batch sync origin>
-  //   value: <Resource ID of the drive directory for the origin>
-  //
-  //   key: "ISYNC_ORIGIN: " + <URL string of a incremental sync origin>
-  //   value: <Resource ID of the drive directory for the origin>
-  //
-  //   key: "DISABLED_ORIGIN: " + <URL string of a disabled origin>
-  //   value: <Resource ID of the drive directory for the origin>
-
-  const char kDatabaseVersionKey[] = "VERSION";
-  const char kDriveMetadataKeyPrefix[] = "METADATA: ";
-  const char kMetadataKeySeparator = ' ';
-
-  leveldb::WriteBatch write_batch;
-  write_batch.Put(kDatabaseVersionKey, "1");
-
-  scoped_ptr<leveldb::Iterator> itr(db->NewIterator(leveldb::ReadOptions()));
-  for (itr->Seek(kDriveMetadataKeyPrefix); itr->Valid(); itr->Next()) {
-    std::string key = itr->key().ToString();
-    if (!StartsWithASCII(key, kDriveMetadataKeyPrefix, true))
-      break;
-    std::string serialized_url(RemovePrefix(key, kDriveMetadataKeyPrefix));
-
-    GURL origin;
-    base::FilePath path;
-    bool success = ParseV0FormatFileSystemURL(
-        GURL(serialized_url), &origin, &path);
-    DCHECK(success) << serialized_url;
-    std::string new_key = kDriveMetadataKeyPrefix + origin.spec() +
-        kMetadataKeySeparator + path.AsUTF8Unsafe();
-
-    write_batch.Put(new_key, itr->value());
-    write_batch.Delete(key);
-  }
-
-  return LevelDBStatusToSyncStatusCode(
-      db->Write(leveldb::WriteOptions(), &write_batch));
-}
-
-SyncStatusCode MigrateDatabaseFromV1ToV2(leveldb::DB* db) {
-  // Strips prefix of WAPI resource ID, and discards batch sync origins.
-  // (i.e. "file:xxxx" => "xxxx", "folder:yyyy" => "yyyy")
-  //
-  // Version 2 database format (changed keys/fields are marked with '*'):
-  //   key: "VERSION"
-  // * value: 2
-  //
-  //   key: "CHANGE_STAMP"
-  //   value: <Largest Changestamp>
-  //
-  //   key: "SYNC_ROOT_DIR"
-  // * value: <Resource ID of the sync root directory> (striped)
-  //
-  //   key: "METADATA: " + <Origin and URL>
-  // * value: <Serialized DriveMetadata> (stripped)
-  //
-  // * key: "BSYNC_ORIGIN: " + <URL string of a batch sync origin> (deleted)
-  // * value: <Resource ID of the drive directory for the origin> (deleted)
-  //
-  //   key: "ISYNC_ORIGIN: " + <URL string of a incremental sync origin>
-  // * value: <Resource ID of the drive directory for the origin> (stripped)
-  //
-  //   key: "DISABLED_ORIGIN: " + <URL string of a disabled origin>
-  // * value: <Resource ID of the drive directory for the origin> (stripped)
-
-  const char kDatabaseVersionKey[] = "VERSION";
-  const char kSyncRootDirectoryKey[] = "SYNC_ROOT_DIR";
-  const char kDriveMetadataKeyPrefix[] = "METADATA: ";
-  const char kDriveBatchSyncOriginKeyPrefix[] = "BSYNC_ORIGIN: ";
-  const char kDriveIncrementalSyncOriginKeyPrefix[] = "ISYNC_ORIGIN: ";
-  const char kDriveDisabledOriginKeyPrefix[] = "DISABLED_ORIGIN: ";
-
-  leveldb::WriteBatch write_batch;
-  write_batch.Put(kDatabaseVersionKey, "2");
-
-  scoped_ptr<leveldb::Iterator> itr(db->NewIterator(leveldb::ReadOptions()));
-  for (itr->SeekToFirst(); itr->Valid(); itr->Next()) {
-    std::string key = itr->key().ToString();
-
-    // Strip resource id for the sync root directory.
-    if (StartsWithASCII(key, kSyncRootDirectoryKey, true)) {
-      write_batch.Put(key, RemoveWapiIdPrefix(itr->value().ToString()));
-      continue;
-    }
-
-    // Strip resource ids in the drive metadata.
-    if (StartsWithASCII(key, kDriveMetadataKeyPrefix, true)) {
-      DriveMetadata metadata;
-      bool success = metadata.ParseFromString(itr->value().ToString());
-      DCHECK(success);
-
-      metadata.set_resource_id(RemoveWapiIdPrefix(metadata.resource_id()));
-      std::string metadata_string;
-      metadata.SerializeToString(&metadata_string);
-
-      write_batch.Put(key, metadata_string);
-      continue;
-    }
-
-    // Deprecate legacy batch sync origin entries that are no longer needed.
-    if (StartsWithASCII(key, kDriveBatchSyncOriginKeyPrefix, true)) {
-      write_batch.Delete(key);
-      continue;
-    }
-
-    // Strip resource ids of the incremental sync origins.
-    if (StartsWithASCII(key, kDriveIncrementalSyncOriginKeyPrefix, true)) {
-      write_batch.Put(key, RemoveWapiIdPrefix(itr->value().ToString()));
-      continue;
-    }
-
-    // Strip resource ids of the disabled sync origins.
-    if (StartsWithASCII(key, kDriveDisabledOriginKeyPrefix, true)) {
-      write_batch.Put(key, RemoveWapiIdPrefix(itr->value().ToString()));
-      continue;
-    }
-  }
-
-  return LevelDBStatusToSyncStatusCode(
-      db->Write(leveldb::WriteOptions(), &write_batch));
-}
-
-}  // namespace drive
-}  // namespace sync_file_system
diff --git a/chrome/browser/sync_file_system/drive/metadata_db_migration_util.h b/chrome/browser/sync_file_system/drive/metadata_db_migration_util.h
deleted file mode 100644
index 62f5a6d..0000000
--- a/chrome/browser/sync_file_system/drive/metadata_db_migration_util.h
+++ /dev/null
@@ -1,64 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_SYNC_FILE_SYSTEM_DRIVE_METADATA_DB_MIGRATION_UTIL_H_
-#define CHROME_BROWSER_SYNC_FILE_SYSTEM_DRIVE_METADATA_DB_MIGRATION_UTIL_H_
-
-#include <string>
-
-#include "chrome/browser/sync_file_system/sync_file_system.pb.h"
-#include "third_party/leveldatabase/src/include/leveldb/db.h"
-#include "webkit/browser/fileapi/syncable/sync_status_code.h"
-
-class GURL;
-
-namespace sync_file_system {
-namespace drive {
-
-// Parses a filesystem URL which contains 'drive' as a service name
-// (a.k.a. V0-format filesystem URL).
-//
-// When you parse V0-format filesystem URL, you should use this function instead
-// of DeserializeSyncableFileSystemURL() since 'drive' service name is no longer
-// used and the deserializer cannot parse the unregistered service name.
-//
-// EXAMPLE:
-// Assume following argument is given.
-//   url: 'filesystem:http://www.example.com/external/drive/foo/bar'
-// returns
-//   origin: 'http://www.example.com/'
-//   path:   'foo/bar'
-bool ParseV0FormatFileSystemURL(const GURL& url,
-                                GURL* origin,
-                                base::FilePath* path);
-
-// Adds "file:" prefix to WAPI resource ID.
-// EXAMPLE:  "xxx" => "file:xxx"
-std::string AddWapiFilePrefix(const std::string& resource_id);
-
-// Adds "folder:" prefix to WAPI resource ID.
-// EXAMPLE:  "xxx" => "folder:xxx"
-std::string AddWapiFolderPrefix(const std::string& resource_id);
-
-// Adds a prefix corresponding to the given |type|.
-std::string AddWapiIdPrefix(const std::string& resource_id,
-                            DriveMetadata_ResourceType type);
-
-// Removes a prefix from WAPI resource ID.
-// EXAMPLE:
-//   "file:xxx"    =>  "xxx"
-//   "folder:yyy"  =>  "yyy"
-//   "zzz"         =>  "zzz"
-std::string RemoveWapiIdPrefix(const std::string& resource_id);
-
-// Migrate |db| schema from version 0 to version 1.
-SyncStatusCode MigrateDatabaseFromV0ToV1(leveldb::DB* db);
-
-// Migrate |db| schema from version 1 to version 2.
-SyncStatusCode MigrateDatabaseFromV1ToV2(leveldb::DB* db);
-
-}  // namespace drive
-}  // namespace sync_file_system
-
-#endif  // CHROME_BROWSER_SYNC_FILE_SYSTEM_DRIVE_METADATA_DB_MIGRATION_UTIL_H_
diff --git a/chrome/browser/sync_file_system/drive/metadata_db_migration_util_unittest.cc b/chrome/browser/sync_file_system/drive/metadata_db_migration_util_unittest.cc
deleted file mode 100644
index 52769b6..0000000
--- a/chrome/browser/sync_file_system/drive/metadata_db_migration_util_unittest.cc
+++ /dev/null
@@ -1,309 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/sync_file_system/drive/metadata_db_migration_util.h"
-
-#include "base/files/scoped_temp_dir.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_util.h"
-#include "chrome/browser/sync_file_system/drive_metadata_store.h"
-#include "googleurl/src/gurl.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/leveldatabase/src/include/leveldb/db.h"
-#include "third_party/leveldatabase/src/include/leveldb/write_batch.h"
-#include "webkit/browser/fileapi/external_mount_points.h"
-#include "webkit/browser/fileapi/syncable/syncable_file_system_util.h"
-#include "webkit/common/fileapi/file_system_util.h"
-
-#define FPL FILE_PATH_LITERAL
-
-namespace sync_file_system {
-namespace drive {
-
-namespace {
-
-const char kV0ServiceName[] = "drive";
-
-bool CreateV0SerializedSyncableFileSystemURL(
-    const GURL& origin,
-    const base::FilePath& path,
-    std::string* serialized_url) {
-  fileapi::ScopedExternalFileSystem scoped_fs(
-      kV0ServiceName, fileapi::kFileSystemTypeSyncable, base::FilePath());
-
-  fileapi::FileSystemURL url =
-      fileapi::ExternalMountPoints::GetSystemInstance()->
-          CreateExternalFileSystemURL(origin, kV0ServiceName, path);
-  if (!url.is_valid())
-    return false;
-  *serialized_url = fileapi::GetExternalFileSystemRootURIString(
-        origin, kV0ServiceName) + url.path().AsUTF8Unsafe();
-  return true;
-}
-
-}  // namespace
-
-TEST(DriveMetadataDBMigrationUtilTest, ParseV0FormatFileSystemURL) {
-  const GURL kOrigin("chrome-extension://example");
-  const base::FilePath kFile(FPL("foo bar"));
-
-  std::string serialized_url;
-  ASSERT_TRUE(CreateV0SerializedSyncableFileSystemURL(
-      kOrigin, kFile, &serialized_url));
-
-  GURL origin;
-  base::FilePath path;
-  EXPECT_TRUE(ParseV0FormatFileSystemURL(GURL(serialized_url), &origin, &path));
-  EXPECT_EQ(kOrigin, origin);
-  EXPECT_EQ(kFile, path);
-}
-
-TEST(DriveMetadataDBMigrationUtilTest, AddWapiIdPrefix) {
-  DriveMetadata_ResourceType type_file =
-      DriveMetadata_ResourceType_RESOURCE_TYPE_FILE;
-  DriveMetadata_ResourceType type_folder =
-      DriveMetadata_ResourceType_RESOURCE_TYPE_FOLDER;
-
-  EXPECT_EQ("file:xxx", AddWapiFilePrefix("xxx"));
-  EXPECT_EQ("folder:yyy", AddWapiFolderPrefix("yyy"));
-  EXPECT_EQ("file:xxx", AddWapiIdPrefix("xxx", type_file));
-  EXPECT_EQ("folder:yyy", AddWapiIdPrefix("yyy", type_folder));
-
-  EXPECT_EQ("", AddWapiFilePrefix(""));
-  EXPECT_EQ("", AddWapiFolderPrefix(""));
-  EXPECT_EQ("", AddWapiIdPrefix("", type_file));
-  EXPECT_EQ("", AddWapiIdPrefix("", type_folder));
-}
-
-TEST(DriveMetadataDBMigrationUtilTest, RemoveWapiIdPrefix) {
-  EXPECT_EQ("xxx", RemoveWapiIdPrefix("xxx"));
-  EXPECT_EQ("yyy", RemoveWapiIdPrefix("file:yyy"));
-  EXPECT_EQ("zzz", RemoveWapiIdPrefix("folder:zzz"));
-
-  EXPECT_EQ("", RemoveWapiIdPrefix(""));
-  EXPECT_EQ("foo:xxx", RemoveWapiIdPrefix("foo:xxx"));
-}
-
-TEST(DriveMetadataDBMigrationUtilTest, MigrationFromV0) {
-  const char kDatabaseVersionKey[] = "VERSION";
-  const char kChangeStampKey[] = "CHANGE_STAMP";
-  const char kSyncRootDirectoryKey[] = "SYNC_ROOT_DIR";
-  const char kDriveMetadataKeyPrefix[] = "METADATA: ";
-  const char kDriveBatchSyncOriginKeyPrefix[] = "BSYNC_ORIGIN: ";
-  const char kDriveIncrementalSyncOriginKeyPrefix[] = "ISYNC_ORIGIN: ";
-
-  const GURL kOrigin1("chrome-extension://example1");
-  const GURL kOrigin2("chrome-extension://example2");
-  const std::string kSyncRootResourceId("folder:sync_root_resource_id");
-  const std::string kResourceId1("folder:hoge");
-  const std::string kResourceId2("folder:fuga");
-  const std::string kFileResourceId("file:piyo");
-  const base::FilePath kFile(FPL("foo bar"));
-  const std::string kFileMD5("file_md5");
-
-  base::ScopedTempDir base_dir;
-  ASSERT_TRUE(base_dir.CreateUniqueTempDir());
-
-  leveldb::Options options;
-  options.create_if_missing = true;
-  leveldb::DB* db_ptr = NULL;
-  std::string db_dir = fileapi::FilePathToString(
-      base_dir.path().Append(DriveMetadataStore::kDatabaseName));
-  leveldb::Status status = leveldb::DB::Open(options, db_dir, &db_ptr);
-
-  scoped_ptr<leveldb::DB> db(db_ptr);
-  ASSERT_TRUE(status.ok());
-
-  // Setup the database with the schema version 0.
-  leveldb::WriteBatch batch;
-  batch.Put(kChangeStampKey, "1");
-  batch.Put(kSyncRootDirectoryKey, kSyncRootResourceId);
-
-  // Setup drive metadata.
-  DriveMetadata drive_metadata;
-  drive_metadata.set_resource_id(kFileResourceId);
-  drive_metadata.set_md5_checksum(kFileMD5);
-  drive_metadata.set_conflicted(false);
-  drive_metadata.set_to_be_fetched(false);
-
-  std::string serialized_url;
-  ASSERT_TRUE(CreateV0SerializedSyncableFileSystemURL(
-      kOrigin1, kFile, &serialized_url));
-  std::string metadata_string;
-  drive_metadata.SerializeToString(&metadata_string);
-  batch.Put(kDriveMetadataKeyPrefix + serialized_url, metadata_string);
-
-  // Setup batch sync origin and incremental sync origin.
-  batch.Put(kDriveBatchSyncOriginKeyPrefix + kOrigin1.spec(), kResourceId1);
-  batch.Put(kDriveIncrementalSyncOriginKeyPrefix + kOrigin2.spec(),
-            kResourceId2);
-
-  status = db->Write(leveldb::WriteOptions(), &batch);
-  EXPECT_EQ(SYNC_STATUS_OK, LevelDBStatusToSyncStatusCode(status));
-
-  // Migrate the database.
-  drive::MigrateDatabaseFromV0ToV1(db.get());
-
-  scoped_ptr<leveldb::Iterator> itr(db->NewIterator(leveldb::ReadOptions()));
-
-  // Verify DB schema version.
-  int64 database_version = 0;
-  itr->Seek(kDatabaseVersionKey);
-  EXPECT_TRUE(itr->Valid());
-  EXPECT_TRUE(base::StringToInt64(itr->value().ToString(), &database_version));
-  EXPECT_EQ(1, database_version);
-
-  // Verify the largest changestamp.
-  int64 changestamp = 0;
-  itr->Seek(kChangeStampKey);
-  EXPECT_TRUE(itr->Valid());
-  EXPECT_TRUE(base::StringToInt64(itr->value().ToString(), &changestamp));
-  EXPECT_EQ(1, changestamp);
-
-  // Verify the sync root directory.
-  itr->Seek(kSyncRootDirectoryKey);
-  EXPECT_TRUE(itr->Valid());
-  EXPECT_EQ(kSyncRootResourceId, itr->value().ToString());
-
-  // Verify the metadata.
-  itr->Seek(kDriveMetadataKeyPrefix);
-  EXPECT_TRUE(itr->Valid());
-  DriveMetadata metadata;
-  EXPECT_TRUE(metadata.ParseFromString(itr->value().ToString()));
-  EXPECT_EQ(kFileResourceId, metadata.resource_id());
-  EXPECT_EQ(kFileMD5, metadata.md5_checksum());
-  EXPECT_FALSE(metadata.conflicted());
-  EXPECT_FALSE(metadata.to_be_fetched());
-
-  // Verify the batch sync origin.
-  itr->Seek(kDriveBatchSyncOriginKeyPrefix);
-  EXPECT_TRUE(itr->Valid());
-  EXPECT_EQ(kResourceId1, itr->value().ToString());
-
-  // Verify the incremental sync origin.
-  itr->Seek(kDriveIncrementalSyncOriginKeyPrefix);
-  EXPECT_TRUE(itr->Valid());
-  EXPECT_EQ(kResourceId2, itr->value().ToString());
-}
-
-TEST(DriveMetadataDBMigrationUtilTest, MigrationFromV1) {
-  const char kDatabaseVersionKey[] = "VERSION";
-  const char kChangeStampKey[] = "CHANGE_STAMP";
-  const char kSyncRootDirectoryKey[] = "SYNC_ROOT_DIR";
-  const char kDriveMetadataKeyPrefix[] = "METADATA: ";
-  const char kMetadataKeySeparator = ' ';
-  const char kDriveBatchSyncOriginKeyPrefix[] = "BSYNC_ORIGIN: ";
-  const char kDriveIncrementalSyncOriginKeyPrefix[] = "ISYNC_ORIGIN: ";
-  const char kDriveDisabledOriginKeyPrefix[] = "DISABLED_ORIGIN: ";
-
-  const GURL kOrigin1("chrome-extension://example1");
-  const GURL kOrigin2("chrome-extension://example2");
-  const GURL kOrigin3("chrome-extension://example3");
-
-  const std::string kSyncRootResourceId("folder:sync_root_resource_id");
-  const std::string kResourceId1("folder:hoge");
-  const std::string kResourceId2("folder:fuga");
-  const std::string kResourceId3("folder:hogera");
-  const std::string kFileResourceId("file:piyo");
-  const base::FilePath kFile(FPL("foo bar"));
-  const std::string kFileMD5("file_md5");
-
-  RegisterSyncableFileSystem();
-
-  base::ScopedTempDir base_dir;
-  ASSERT_TRUE(base_dir.CreateUniqueTempDir());
-
-  leveldb::Options options;
-  options.create_if_missing = true;
-  leveldb::DB* db_ptr = NULL;
-  std::string db_dir = fileapi::FilePathToString(
-      base_dir.path().Append(DriveMetadataStore::kDatabaseName));
-  leveldb::Status status = leveldb::DB::Open(options, db_dir, &db_ptr);
-
-  scoped_ptr<leveldb::DB> db(db_ptr);
-  ASSERT_TRUE(status.ok());
-
-  // Setup the database with the schema version 1.
-  leveldb::WriteBatch batch;
-  batch.Put(kDatabaseVersionKey, "1");
-  batch.Put(kChangeStampKey, "1");
-  batch.Put(kSyncRootDirectoryKey, kSyncRootResourceId);
-
-  fileapi::FileSystemURL url = CreateSyncableFileSystemURL(kOrigin1, kFile);
-
-  // Setup drive metadata.
-  DriveMetadata drive_metadata;
-  drive_metadata.set_resource_id(kFileResourceId);
-  drive_metadata.set_md5_checksum(kFileMD5);
-  drive_metadata.set_conflicted(false);
-  drive_metadata.set_to_be_fetched(false);
-  std::string metadata_string;
-  drive_metadata.SerializeToString(&metadata_string);
-  std::string metadata_key = kDriveMetadataKeyPrefix + kOrigin1.spec() +
-                             kMetadataKeySeparator + url.path().AsUTF8Unsafe();
-  batch.Put(metadata_key, metadata_string);
-
-  // Setup origins.
-  batch.Put(kDriveBatchSyncOriginKeyPrefix + kOrigin1.spec(), kResourceId1);
-  batch.Put(kDriveIncrementalSyncOriginKeyPrefix + kOrigin2.spec(),
-            kResourceId2);
-  batch.Put(kDriveDisabledOriginKeyPrefix + kOrigin3.spec(), kResourceId3);
-
-  status = db->Write(leveldb::WriteOptions(), &batch);
-  EXPECT_EQ(SYNC_STATUS_OK, LevelDBStatusToSyncStatusCode(status));
-
-  RevokeSyncableFileSystem();
-
-  // Migrate the database.
-  drive::MigrateDatabaseFromV1ToV2(db.get());
-
-  scoped_ptr<leveldb::Iterator> itr(db->NewIterator(leveldb::ReadOptions()));
-
-  // Verify DB schema version.
-  int64 database_version = 0;
-  itr->Seek(kDatabaseVersionKey);
-  EXPECT_TRUE(itr->Valid());
-  EXPECT_TRUE(base::StringToInt64(itr->value().ToString(), &database_version));
-  EXPECT_EQ(2, database_version);
-
-  // Verify the largest changestamp.
-  int64 changestamp = 0;
-  itr->Seek(kChangeStampKey);
-  EXPECT_TRUE(itr->Valid());
-  EXPECT_TRUE(base::StringToInt64(itr->value().ToString(), &changestamp));
-  EXPECT_EQ(1, changestamp);
-
-  // Verify the sync root directory.
-  itr->Seek(kSyncRootDirectoryKey);
-  EXPECT_TRUE(itr->Valid());
-  EXPECT_EQ(RemoveWapiIdPrefix(kSyncRootResourceId), itr->value().ToString());
-
-  // Verify the metadata.
-  itr->Seek(kDriveMetadataKeyPrefix);
-  EXPECT_TRUE(itr->Valid());
-  DriveMetadata metadata;
-  EXPECT_TRUE(metadata.ParseFromString(itr->value().ToString()));
-  EXPECT_EQ(RemoveWapiIdPrefix(kFileResourceId), metadata.resource_id());
-  EXPECT_EQ(kFileMD5, metadata.md5_checksum());
-  EXPECT_FALSE(metadata.conflicted());
-  EXPECT_FALSE(metadata.to_be_fetched());
-
-  // Verify the batch sync origin.
-  itr->Seek(kDriveBatchSyncOriginKeyPrefix);
-  EXPECT_FALSE(StartsWithASCII(kDriveBatchSyncOriginKeyPrefix,
-                               itr->key().ToString(), true));
-
-  // Verify the incremental sync origin.
-  itr->Seek(kDriveIncrementalSyncOriginKeyPrefix);
-  EXPECT_TRUE(itr->Valid());
-  EXPECT_EQ(RemoveWapiIdPrefix(kResourceId2), itr->value().ToString());
-
-  // Verify the disabled origin.
-  itr->Seek(kDriveDisabledOriginKeyPrefix);
-  EXPECT_TRUE(itr->Valid());
-  EXPECT_EQ(RemoveWapiIdPrefix(kResourceId3), itr->value().ToString());
-}
-
-}  // namespace drive
-}  // namespace sync_file_system
diff --git a/chrome/browser/sync_file_system/drive_backend/OWNERS b/chrome/browser/sync_file_system/drive_backend/OWNERS
new file mode 100644
index 0000000..25402fd
--- /dev/null
+++ b/chrome/browser/sync_file_system/drive_backend/OWNERS
@@ -0,0 +1 @@
+nhiroki@chromium.org
diff --git a/chrome/browser/sync_file_system/drive_backend/api_util.cc b/chrome/browser/sync_file_system/drive_backend/api_util.cc
new file mode 100644
index 0000000..e131b82
--- /dev/null
+++ b/chrome/browser/sync_file_system/drive_backend/api_util.cc
@@ -0,0 +1,1087 @@
+// 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/api_util.h"
+
+#include <algorithm>
+#include <functional>
+#include <sstream>
+#include <string>
+
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/threading/sequenced_worker_pool.h"
+#include "base/values.h"
+#include "chrome/browser/drive/drive_api_service.h"
+#include "chrome/browser/drive/drive_api_util.h"
+#include "chrome/browser/drive/drive_uploader.h"
+#include "chrome/browser/drive/gdata_wapi_service.h"
+#include "chrome/browser/google_apis/drive_api_parser.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/sync_file_system/drive_file_sync_util.h"
+#include "chrome/browser/sync_file_system/logger.h"
+#include "chrome/common/extensions/extension.h"
+#include "content/public/browser/browser_thread.h"
+#include "extensions/common/constants.h"
+#include "net/base/mime_util.h"
+#include "webkit/browser/fileapi/syncable/syncable_file_system_util.h"
+
+namespace sync_file_system {
+namespace drive_backend {
+
+namespace {
+
+enum ParentType {
+  PARENT_TYPE_ROOT_OR_EMPTY,
+  PARENT_TYPE_DIRECTORY,
+};
+
+const char kSyncRootDirectoryName[] = "Chrome Syncable FileSystem";
+const char kSyncRootDirectoryNameDev[] = "Chrome Syncable FileSystem Dev";
+const char kMimeTypeOctetStream[] = "application/octet-stream";
+
+const char kFakeServerBaseUrl[] = "https://fake_server/";
+const char kFakeDownloadServerBaseUrl[] = "https://fake_download_server/";
+
+void EmptyGDataErrorCodeCallback(google_apis::GDataErrorCode error) {}
+
+bool HasParentLinkTo(const ScopedVector<google_apis::Link>& links,
+                     const std::string& parent_resource_id,
+                     ParentType parent_type) {
+  bool has_parent = false;
+
+  for (ScopedVector<google_apis::Link>::const_iterator itr = links.begin();
+       itr != links.end(); ++itr) {
+    if ((*itr)->type() == google_apis::Link::LINK_PARENT) {
+      has_parent = true;
+      if (drive::util::ExtractResourceIdFromUrl((*itr)->href()) ==
+          parent_resource_id)
+        return true;
+    }
+  }
+
+  return parent_type == PARENT_TYPE_ROOT_OR_EMPTY && !has_parent;
+}
+
+struct TitleAndParentQuery
+    : std::unary_function<const google_apis::ResourceEntry*, bool> {
+  TitleAndParentQuery(const std::string& title,
+                      const std::string& parent_resource_id,
+                      ParentType parent_type)
+      : title(title),
+        parent_resource_id(parent_resource_id),
+        parent_type(parent_type) {}
+
+  bool operator()(const google_apis::ResourceEntry* entry) const {
+    return entry->title() == title &&
+           HasParentLinkTo(entry->links(), parent_resource_id, parent_type);
+  }
+
+  const std::string& title;
+  const std::string& parent_resource_id;
+  ParentType parent_type;
+};
+
+void FilterEntriesByTitleAndParent(
+    ScopedVector<google_apis::ResourceEntry>* entries,
+    const std::string& title,
+    const std::string& parent_resource_id,
+    ParentType parent_type) {
+  typedef ScopedVector<google_apis::ResourceEntry>::iterator iterator;
+  iterator itr = std::partition(entries->begin(),
+                                entries->end(),
+                                TitleAndParentQuery(title,
+                                                    parent_resource_id,
+                                                    parent_type));
+  entries->erase(itr, entries->end());
+}
+
+google_apis::ResourceEntry* GetDocumentByTitleAndParent(
+    const ScopedVector<google_apis::ResourceEntry>& entries,
+    const std::string& title,
+    const std::string& parent_resource_id,
+    ParentType parent_type) {
+  typedef ScopedVector<google_apis::ResourceEntry>::const_iterator iterator;
+  iterator found =
+      std::find_if(entries.begin(),
+                   entries.end(),
+                   TitleAndParentQuery(title, parent_resource_id, parent_type));
+  if (found != entries.end())
+    return *found;
+  return NULL;
+}
+
+void EntryAdapterForEnsureTitleUniqueness(
+    scoped_ptr<google_apis::ResourceEntry> entry,
+    const APIUtil::EnsureUniquenessCallback& callback,
+    APIUtil::EnsureUniquenessStatus status,
+    google_apis::GDataErrorCode error) {
+  callback.Run(error, status, entry.Pass());
+}
+
+void UploadResultAdapter(const APIUtil::ResourceEntryCallback& callback,
+                         google_apis::GDataErrorCode error,
+                         const GURL& upload_location,
+                         scoped_ptr<google_apis::ResourceEntry> entry) {
+  callback.Run(error, entry.Pass());
+}
+
+std::string GetMimeTypeFromTitle(const std::string& title) {
+  base::FilePath::StringType extension =
+      base::FilePath::FromUTF8Unsafe(title).Extension();
+  std::string mime_type;
+  if (extension.empty() ||
+      !net::GetWellKnownMimeTypeFromExtension(extension.substr(1), &mime_type))
+    return kMimeTypeOctetStream;
+  return mime_type;
+}
+
+}  // namespace
+
+APIUtil::APIUtil(Profile* profile)
+    : wapi_url_generator_(
+          GURL(google_apis::GDataWapiUrlGenerator::kBaseUrlForProduction),
+          GURL(google_apis::GDataWapiUrlGenerator::
+               kBaseDownloadUrlForProduction)),
+      drive_api_url_generator_(
+          GURL(google_apis::DriveApiUrlGenerator::kBaseUrlForProduction),
+          GURL(google_apis::DriveApiUrlGenerator::
+               kBaseDownloadUrlForProduction)),
+      upload_next_key_(0) {
+  if (IsDriveAPIDisabled()) {
+    drive_service_.reset(new drive::GDataWapiService(
+        profile->GetRequestContext(),
+        content::BrowserThread::GetBlockingPool(),
+        GURL(google_apis::GDataWapiUrlGenerator::kBaseUrlForProduction),
+        GURL(google_apis::GDataWapiUrlGenerator::kBaseDownloadUrlForProduction),
+        std::string() /* custom_user_agent */));
+  } else {
+    drive_service_.reset(new drive::DriveAPIService(
+        profile->GetRequestContext(),
+        content::BrowserThread::GetBlockingPool(),
+        GURL(google_apis::DriveApiUrlGenerator::kBaseUrlForProduction),
+        GURL(google_apis::DriveApiUrlGenerator::kBaseDownloadUrlForProduction),
+        std::string() /* custom_user_agent */));
+  }
+
+  drive_service_->Initialize(profile);
+  drive_service_->AddObserver(this);
+  net::NetworkChangeNotifier::AddConnectionTypeObserver(this);
+
+  drive_uploader_.reset(new drive::DriveUploader(
+      drive_service_.get(), content::BrowserThread::GetBlockingPool()));
+}
+
+scoped_ptr<APIUtil> APIUtil::CreateForTesting(
+    Profile* profile,
+    scoped_ptr<drive::DriveServiceInterface> drive_service,
+    scoped_ptr<drive::DriveUploaderInterface> drive_uploader) {
+  return make_scoped_ptr(new APIUtil(
+      profile,
+      GURL(kFakeServerBaseUrl),
+      GURL(kFakeDownloadServerBaseUrl),
+      drive_service.Pass(),
+      drive_uploader.Pass()));
+}
+
+APIUtil::APIUtil(Profile* profile,
+                 const GURL& base_url,
+                 const GURL& base_download_url,
+                 scoped_ptr<drive::DriveServiceInterface> drive_service,
+                 scoped_ptr<drive::DriveUploaderInterface> drive_uploader)
+    : wapi_url_generator_(base_url, base_download_url),
+      drive_api_url_generator_(base_url, base_download_url),
+      upload_next_key_(0) {
+  drive_service_ = drive_service.Pass();
+  drive_service_->Initialize(profile);
+  drive_service_->AddObserver(this);
+  net::NetworkChangeNotifier::AddConnectionTypeObserver(this);
+
+  drive_uploader_ = drive_uploader.Pass();
+}
+
+APIUtil::~APIUtil() {
+  DCHECK(CalledOnValidThread());
+  net::NetworkChangeNotifier::RemoveConnectionTypeObserver(this);
+  drive_service_->RemoveObserver(this);
+}
+
+void APIUtil::AddObserver(APIUtilObserver* observer) {
+  DCHECK(CalledOnValidThread());
+  observers_.AddObserver(observer);
+}
+
+void APIUtil::RemoveObserver(APIUtilObserver* observer) {
+  DCHECK(CalledOnValidThread());
+  observers_.RemoveObserver(observer);
+}
+
+void APIUtil::GetDriveRootResourceId(const GDataErrorCallback& callback) {
+  DCHECK(CalledOnValidThread());
+  DCHECK(!IsDriveAPIDisabled());
+  DVLOG(2) << "Getting resource id for Drive root";
+
+  drive_service_->GetAboutResource(
+      base::Bind(&APIUtil::DidGetDriveRootResourceId, AsWeakPtr(), callback));
+}
+
+void APIUtil::DidGetDriveRootResourceId(
+    const GDataErrorCallback& callback,
+    google_apis::GDataErrorCode error,
+    scoped_ptr<google_apis::AboutResource> about_resource) {
+  DCHECK(CalledOnValidThread());
+
+  if (error != google_apis::HTTP_SUCCESS) {
+    DVLOG(2) << "Error on getting resource id for Drive root: " << error;
+    callback.Run(error);
+    return;
+  }
+
+  DCHECK(about_resource);
+  root_resource_id_ = about_resource->root_folder_id();
+  DCHECK(!root_resource_id_.empty());
+  DVLOG(2) << "Got resource id for Drive root: " << root_resource_id_;
+  callback.Run(error);
+}
+
+void APIUtil::GetDriveDirectoryForSyncRoot(const ResourceIdCallback& callback) {
+  DCHECK(CalledOnValidThread());
+
+  if (GetRootResourceId().empty()) {
+    GetDriveRootResourceId(
+        base::Bind(&APIUtil::DidGetDriveRootResourceIdForGetSyncRoot,
+                   AsWeakPtr(), callback));
+    return;
+  }
+
+  DVLOG(2) << "Getting Drive directory for SyncRoot";
+  std::string directory_name(GetSyncRootDirectoryName());
+  SearchByTitle(directory_name,
+                std::string(),
+                base::Bind(&APIUtil::DidGetDirectory,
+                           AsWeakPtr(),
+                           std::string(),
+                           directory_name,
+                           callback));
+}
+
+void APIUtil::DidGetDriveRootResourceIdForGetSyncRoot(
+    const ResourceIdCallback& callback,
+    google_apis::GDataErrorCode error) {
+  DCHECK(CalledOnValidThread());
+  if (error != google_apis::HTTP_SUCCESS) {
+    DVLOG(2) << "Error on getting Drive directory for SyncRoot: " << error;
+    callback.Run(error, std::string());
+    return;
+  }
+  GetDriveDirectoryForSyncRoot(callback);
+}
+
+void APIUtil::GetDriveDirectoryForOrigin(
+    const std::string& sync_root_resource_id,
+    const GURL& origin,
+    const ResourceIdCallback& callback) {
+  DCHECK(CalledOnValidThread());
+  DVLOG(2) << "Getting Drive directory for Origin: " << origin;
+
+  std::string directory_name(OriginToDirectoryTitle(origin));
+  SearchByTitle(directory_name,
+                sync_root_resource_id,
+                base::Bind(&APIUtil::DidGetDirectory,
+                           AsWeakPtr(),
+                           sync_root_resource_id,
+                           directory_name,
+                           callback));
+}
+
+void APIUtil::DidGetDirectory(const std::string& parent_resource_id,
+                              const std::string& directory_name,
+                              const ResourceIdCallback& callback,
+                              google_apis::GDataErrorCode error,
+                              scoped_ptr<google_apis::ResourceList> feed) {
+  DCHECK(CalledOnValidThread());
+  DCHECK(IsStringASCII(directory_name));
+
+  if (error != google_apis::HTTP_SUCCESS) {
+    DVLOG(2) << "Error on getting Drive directory: " << error;
+    callback.Run(error, std::string());
+    return;
+  }
+
+  std::string resource_id;
+  ParentType parent_type = PARENT_TYPE_DIRECTORY;
+  if (parent_resource_id.empty()) {
+    resource_id = GetRootResourceId();
+    DCHECK(!resource_id.empty());
+    parent_type = PARENT_TYPE_ROOT_OR_EMPTY;
+  } else {
+    resource_id = parent_resource_id;
+  }
+  std::string title(directory_name);
+  google_apis::ResourceEntry* entry = GetDocumentByTitleAndParent(
+      feed->entries(), title, resource_id, parent_type);
+  if (!entry) {
+    DVLOG(2) << "Directory not found. Creating: " << directory_name;
+    drive_service_->AddNewDirectory(resource_id,
+                                    directory_name,
+                                    base::Bind(&APIUtil::DidCreateDirectory,
+                                               AsWeakPtr(),
+                                               parent_resource_id,
+                                               title,
+                                               callback));
+    return;
+  }
+  DVLOG(2) << "Found Drive directory.";
+
+  // TODO(tzik): Handle error.
+  DCHECK_EQ(google_apis::ENTRY_KIND_FOLDER, entry->kind());
+  DCHECK_EQ(directory_name, entry->title());
+
+  if (entry->title() == GetSyncRootDirectoryName())
+    EnsureSyncRootIsNotInMyDrive(entry->resource_id());
+
+  callback.Run(error, entry->resource_id());
+}
+
+void APIUtil::DidCreateDirectory(const std::string& parent_resource_id,
+                                 const std::string& title,
+                                 const ResourceIdCallback& callback,
+                                 google_apis::GDataErrorCode error,
+                                 scoped_ptr<google_apis::ResourceEntry> entry) {
+  DCHECK(CalledOnValidThread());
+
+  if (error != google_apis::HTTP_SUCCESS &&
+      error != google_apis::HTTP_CREATED) {
+    DVLOG(2) << "Error on creating Drive directory: " << error;
+    callback.Run(error, std::string());
+    return;
+  }
+  DVLOG(2) << "Created Drive directory.";
+
+  DCHECK(entry);
+  // Check if any other client creates a directory with same title.
+  EnsureTitleUniqueness(
+      parent_resource_id,
+      title,
+      base::Bind(&APIUtil::DidEnsureUniquenessForCreateDirectory,
+                 AsWeakPtr(),
+                 callback));
+}
+
+void APIUtil::DidEnsureUniquenessForCreateDirectory(
+    const ResourceIdCallback& callback,
+    google_apis::GDataErrorCode error,
+    EnsureUniquenessStatus status,
+    scoped_ptr<google_apis::ResourceEntry> entry) {
+  DCHECK(CalledOnValidThread());
+
+  if (error != google_apis::HTTP_SUCCESS) {
+    callback.Run(error, std::string());
+    return;
+  }
+
+  if (status == NO_DUPLICATES_FOUND)
+    error = google_apis::HTTP_CREATED;
+
+  DCHECK(entry) << "No entry: " << error;
+
+  if (!entry->is_folder()) {
+    // TODO(kinuko): Fix this. http://crbug.com/237090
+    util::Log(
+        logging::LOG_ERROR,
+        FROM_HERE,
+        "A file is left for CreateDirectory due to file-folder conflict!");
+    callback.Run(google_apis::HTTP_CONFLICT, std::string());
+    return;
+  }
+
+  if (entry->title() == GetSyncRootDirectoryName())
+    EnsureSyncRootIsNotInMyDrive(entry->resource_id());
+
+  callback.Run(error, entry->resource_id());
+}
+
+void APIUtil::GetLargestChangeStamp(const ChangeStampCallback& callback) {
+  DCHECK(CalledOnValidThread());
+  DVLOG(2) << "Getting largest change id";
+
+  drive_service_->GetAboutResource(
+      base::Bind(&APIUtil::DidGetLargestChangeStamp, AsWeakPtr(), callback));
+}
+
+void APIUtil::GetResourceEntry(const std::string& resource_id,
+                               const ResourceEntryCallback& callback) {
+  DCHECK(CalledOnValidThread());
+  DVLOG(2) << "Getting ResourceEntry for: " << resource_id;
+
+  drive_service_->GetResourceEntry(
+      resource_id,
+      base::Bind(&APIUtil::DidGetResourceEntry, AsWeakPtr(), callback));
+}
+
+void APIUtil::DidGetLargestChangeStamp(
+    const ChangeStampCallback& callback,
+    google_apis::GDataErrorCode error,
+    scoped_ptr<google_apis::AboutResource> about_resource) {
+  DCHECK(CalledOnValidThread());
+
+  int64 largest_change_id = 0;
+  if (error == google_apis::HTTP_SUCCESS) {
+    DCHECK(about_resource);
+    largest_change_id = about_resource->largest_change_id();
+    root_resource_id_ = about_resource->root_folder_id();
+    DVLOG(2) << "Got largest change id: " << largest_change_id;
+  } else {
+    DVLOG(2) << "Error on getting largest change id: " << error;
+  }
+
+  callback.Run(error, largest_change_id);
+}
+
+void APIUtil::SearchByTitle(const std::string& title,
+                            const std::string& directory_resource_id,
+                            const ResourceListCallback& callback) {
+  DCHECK(CalledOnValidThread());
+  DCHECK(!title.empty());
+  DVLOG(2) << "Searching resources in the directory [" << directory_resource_id
+           << "] with title [" << title << "]";
+
+  drive_service_->SearchByTitle(
+      title,
+      directory_resource_id,
+      base::Bind(&APIUtil::DidGetResourceList, AsWeakPtr(), callback));
+}
+
+void APIUtil::ListFiles(const std::string& directory_resource_id,
+                        const ResourceListCallback& callback) {
+  DCHECK(CalledOnValidThread());
+  DVLOG(2) << "Listing resources in the directory [" << directory_resource_id
+           << "]";
+
+  drive_service_->GetResourceListInDirectory(directory_resource_id, callback);
+}
+
+void APIUtil::ListChanges(int64 start_changestamp,
+                          const ResourceListCallback& callback) {
+  DCHECK(CalledOnValidThread());
+  DVLOG(2) << "Listing changes since: " << start_changestamp;
+
+  drive_service_->GetChangeList(
+      start_changestamp,
+      base::Bind(&APIUtil::DidGetResourceList, AsWeakPtr(), callback));
+}
+
+void APIUtil::ContinueListing(const GURL& feed_url,
+                              const ResourceListCallback& callback) {
+  DCHECK(CalledOnValidThread());
+  DVLOG(2) << "Continue listing on feed: " << feed_url;
+
+  drive_service_->ContinueGetResourceList(
+      feed_url,
+      base::Bind(&APIUtil::DidGetResourceList, AsWeakPtr(), callback));
+}
+
+void APIUtil::DownloadFile(const std::string& resource_id,
+                           const std::string& local_file_md5,
+                           const base::FilePath& local_file_path,
+                           const DownloadFileCallback& callback) {
+  DCHECK(CalledOnValidThread());
+  DVLOG(2) << "Downloading file [" << resource_id << "]";
+
+  drive_service_->GetResourceEntry(
+      resource_id,
+      base::Bind(&APIUtil::DidGetResourceEntry,
+                 AsWeakPtr(),
+                 base::Bind(&APIUtil::DownloadFileInternal,
+                            AsWeakPtr(),
+                            local_file_md5,
+                            local_file_path,
+                            callback)));
+}
+
+void APIUtil::UploadNewFile(const std::string& directory_resource_id,
+                            const base::FilePath& local_file_path,
+                            const std::string& title,
+                            const UploadFileCallback& callback) {
+  DCHECK(CalledOnValidThread());
+  DVLOG(2) << "Uploading new file into the directory [" << directory_resource_id
+           << "] with title [" << title << "]";
+
+  std::string mime_type = GetMimeTypeFromTitle(title);
+  UploadKey upload_key = RegisterUploadCallback(callback);
+  ResourceEntryCallback did_upload_callback =
+      base::Bind(&APIUtil::DidUploadNewFile,
+                 AsWeakPtr(),
+                 directory_resource_id,
+                 title,
+                 upload_key);
+  drive_uploader_->UploadNewFile(
+      directory_resource_id,
+      local_file_path,
+      title,
+      mime_type,
+      base::Bind(&UploadResultAdapter, did_upload_callback),
+      google_apis::ProgressCallback());
+}
+
+void APIUtil::UploadExistingFile(const std::string& resource_id,
+                                 const std::string& remote_file_md5,
+                                 const base::FilePath& local_file_path,
+                                 const UploadFileCallback& callback) {
+  DCHECK(CalledOnValidThread());
+  DVLOG(2) << "Uploading existing file [" << resource_id << "]";
+  drive_service_->GetResourceEntry(
+      resource_id,
+      base::Bind(&APIUtil::DidGetResourceEntry,
+                 AsWeakPtr(),
+                 base::Bind(&APIUtil::UploadExistingFileInternal,
+                            AsWeakPtr(),
+                            remote_file_md5,
+                            local_file_path,
+                            callback)));
+}
+
+void APIUtil::CreateDirectory(const std::string& parent_resource_id,
+                              const std::string& title,
+                              const ResourceIdCallback& callback) {
+  DCHECK(CalledOnValidThread());
+  // TODO(kinuko): This will call EnsureTitleUniqueness and will delete
+  // directories if there're duplicated directories. This must be ok
+  // for current design but we'll need to merge directories when we support
+  // 'real' directories.
+  drive_service_->AddNewDirectory(parent_resource_id,
+                                  title,
+                                  base::Bind(&APIUtil::DidCreateDirectory,
+                                             AsWeakPtr(),
+                                             parent_resource_id,
+                                             title,
+                                             callback));
+}
+
+void APIUtil::DeleteFile(const std::string& resource_id,
+                         const std::string& remote_file_md5,
+                         const GDataErrorCallback& callback) {
+  DCHECK(CalledOnValidThread());
+  DVLOG(2) << "Deleting file: " << resource_id;
+
+  // Load actual remote_file_md5 to check for conflict before deletion.
+  if (!remote_file_md5.empty()) {
+    drive_service_->GetResourceEntry(
+        resource_id,
+        base::Bind(&APIUtil::DidGetResourceEntry,
+                   AsWeakPtr(),
+                   base::Bind(&APIUtil::DeleteFileInternal,
+                              AsWeakPtr(),
+                              remote_file_md5,
+                              callback)));
+    return;
+  }
+
+  // Expected remote_file_md5 is empty so do a force delete.
+  drive_service_->DeleteResource(
+      resource_id,
+      std::string(),
+      base::Bind(&APIUtil::DidDeleteFile, AsWeakPtr(), callback));
+  return;
+}
+
+GURL APIUtil::ResourceIdToResourceLink(const std::string& resource_id) const {
+  return IsDriveAPIDisabled()
+      ? wapi_url_generator_.GenerateEditUrl(resource_id)
+      : drive_api_url_generator_.GetFileUrl(resource_id);
+}
+
+void APIUtil::EnsureSyncRootIsNotInMyDrive(
+    const std::string& sync_root_resource_id) {
+  DCHECK(CalledOnValidThread());
+
+  if (GetRootResourceId().empty()) {
+    GetDriveRootResourceId(
+        base::Bind(&APIUtil::DidGetDriveRootResourceIdForEnsureSyncRoot,
+                   AsWeakPtr(), sync_root_resource_id));
+    return;
+  }
+
+  DVLOG(2) << "Ensuring the sync root directory is not in 'My Drive'.";
+  drive_service_->RemoveResourceFromDirectory(
+      GetRootResourceId(),
+      sync_root_resource_id,
+      base::Bind(&EmptyGDataErrorCodeCallback));
+}
+
+void APIUtil::DidGetDriveRootResourceIdForEnsureSyncRoot(
+    const std::string& sync_root_resource_id,
+    google_apis::GDataErrorCode error) {
+  DCHECK(CalledOnValidThread());
+
+  if (error != google_apis::HTTP_SUCCESS) {
+    DVLOG(2) << "Error on ensuring the sync root directory is not in"
+             << " 'My Drive': " << error;
+    // Give up ensuring the sync root directory is not in 'My Drive'. This will
+    // be retried at some point.
+    return;
+  }
+
+  DCHECK(!GetRootResourceId().empty());
+  EnsureSyncRootIsNotInMyDrive(sync_root_resource_id);
+}
+
+// static
+// TODO(calvinlo): Delete this when Sync Directory Operations are supported by
+// default.
+std::string APIUtil::GetSyncRootDirectoryName() {
+  return IsSyncFSDirectoryOperationEnabled() ? kSyncRootDirectoryNameDev
+                                             : kSyncRootDirectoryName;
+}
+
+// static
+std::string APIUtil::OriginToDirectoryTitle(const GURL& origin) {
+  DCHECK(origin.SchemeIs(extensions::kExtensionScheme));
+  return origin.host();
+}
+
+// static
+GURL APIUtil::DirectoryTitleToOrigin(const std::string& title) {
+  return extensions::Extension::GetBaseURLFromExtensionId(title);
+}
+
+void APIUtil::OnReadyToSendRequests() {
+  DCHECK(CalledOnValidThread());
+  FOR_EACH_OBSERVER(APIUtilObserver, observers_, OnAuthenticated());
+}
+
+void APIUtil::OnConnectionTypeChanged(
+    net::NetworkChangeNotifier::ConnectionType type) {
+  DCHECK(CalledOnValidThread());
+  if (type != net::NetworkChangeNotifier::CONNECTION_NONE) {
+    FOR_EACH_OBSERVER(APIUtilObserver, observers_, OnNetworkConnected());
+    return;
+  }
+  // We're now disconnected, reset the drive_uploader_ to force stop
+  // uploading, otherwise the uploader may get stuck.
+  // TODO(kinuko): Check the uploader behavior if it's the expected behavior
+  // (http://crbug.com/223818)
+  CancelAllUploads(google_apis::GDATA_NO_CONNECTION);
+}
+
+void APIUtil::DidGetResourceList(
+    const ResourceListCallback& callback,
+    google_apis::GDataErrorCode error,
+    scoped_ptr<google_apis::ResourceList> resource_list) {
+  DCHECK(CalledOnValidThread());
+
+  if (error != google_apis::HTTP_SUCCESS) {
+    DVLOG(2) << "Error on listing resource: " << error;
+    callback.Run(error, scoped_ptr<google_apis::ResourceList>());
+    return;
+  }
+
+  DVLOG(2) << "Got resource list";
+  DCHECK(resource_list);
+  callback.Run(error, resource_list.Pass());
+}
+
+void APIUtil::DidGetResourceEntry(
+    const ResourceEntryCallback& callback,
+    google_apis::GDataErrorCode error,
+    scoped_ptr<google_apis::ResourceEntry> entry) {
+  DCHECK(CalledOnValidThread());
+
+  if (error != google_apis::HTTP_SUCCESS) {
+    DVLOG(2) << "Error on getting resource entry:" << error;
+    callback.Run(error, scoped_ptr<google_apis::ResourceEntry>());
+    return;
+  }
+
+  DVLOG(2) << "Got resource entry";
+  DCHECK(entry);
+  callback.Run(error, entry.Pass());
+}
+
+void APIUtil::DownloadFileInternal(
+    const std::string& local_file_md5,
+    const base::FilePath& local_file_path,
+    const DownloadFileCallback& callback,
+    google_apis::GDataErrorCode error,
+    scoped_ptr<google_apis::ResourceEntry> entry) {
+  DCHECK(CalledOnValidThread());
+
+  if (error != google_apis::HTTP_SUCCESS) {
+    DVLOG(2) << "Error on getting resource entry for download";
+    callback.Run(error, std::string(), 0, base::Time());
+    return;
+  }
+  DCHECK(entry);
+
+  DVLOG(2) << "Got resource entry for download";
+  // If local file and remote file are same, cancel the download.
+  if (local_file_md5 == entry->file_md5()) {
+    callback.Run(google_apis::HTTP_NOT_MODIFIED,
+                 local_file_md5,
+                 entry->file_size(),
+                 entry->updated_time());
+    return;
+  }
+
+  DVLOG(2) << "Downloading file: " << entry->resource_id();
+  const std::string& resource_id = entry->resource_id();
+  drive_service_->DownloadFile(local_file_path,
+                               resource_id,
+                               base::Bind(&APIUtil::DidDownloadFile,
+                                          AsWeakPtr(),
+                                          base::Passed(&entry),
+                                          callback),
+                               google_apis::GetContentCallback(),
+                               google_apis::ProgressCallback());
+}
+
+void APIUtil::DidDownloadFile(scoped_ptr<google_apis::ResourceEntry> entry,
+                              const DownloadFileCallback& callback,
+                              google_apis::GDataErrorCode error,
+                              const base::FilePath& downloaded_file_path) {
+  DCHECK(CalledOnValidThread());
+  if (error == google_apis::HTTP_SUCCESS)
+    DVLOG(2) << "Download completed";
+  else
+    DVLOG(2) << "Error on downloading file: " << error;
+
+  callback.Run(
+      error, entry->file_md5(), entry->file_size(), entry->updated_time());
+}
+
+void APIUtil::DidUploadNewFile(const std::string& parent_resource_id,
+                               const std::string& title,
+                               UploadKey upload_key,
+                               google_apis::GDataErrorCode error,
+                               scoped_ptr<google_apis::ResourceEntry> entry) {
+  UploadFileCallback callback = GetAndUnregisterUploadCallback(upload_key);
+  DCHECK(!callback.is_null());
+  if (error != google_apis::HTTP_SUCCESS &&
+      error != google_apis::HTTP_CREATED) {
+    DVLOG(2) << "Error on uploading new file: " << error;
+    callback.Run(error, std::string(), std::string());
+    return;
+  }
+
+  DVLOG(2) << "Upload completed";
+  EnsureTitleUniqueness(parent_resource_id,
+                        title,
+                        base::Bind(&APIUtil::DidEnsureUniquenessForCreateFile,
+                                   AsWeakPtr(),
+                                   entry->resource_id(),
+                                   callback));
+}
+
+void APIUtil::DidEnsureUniquenessForCreateFile(
+    const std::string& expected_resource_id,
+    const UploadFileCallback& callback,
+    google_apis::GDataErrorCode error,
+    EnsureUniquenessStatus status,
+    scoped_ptr<google_apis::ResourceEntry> entry) {
+  if (error != google_apis::HTTP_SUCCESS) {
+    DVLOG(2) << "Error on uploading new file: " << error;
+    callback.Run(error, std::string(), std::string());
+    return;
+  }
+
+  switch (status) {
+    case NO_DUPLICATES_FOUND:
+      // The file was uploaded successfully and no conflict was detected.
+      DCHECK(entry);
+      DVLOG(2) << "No conflict detected on uploading new file";
+      callback.Run(
+          google_apis::HTTP_CREATED, entry->resource_id(), entry->file_md5());
+      return;
+
+    case RESOLVED_DUPLICATES:
+      // The file was uploaded successfully but a conflict was detected.
+      // The duplicated file was deleted successfully.
+      DCHECK(entry);
+      if (entry->resource_id() != expected_resource_id) {
+        // TODO(kinuko): We should check local vs remote md5 here.
+        DVLOG(2) << "Conflict detected on uploading new file";
+        callback.Run(google_apis::HTTP_CONFLICT,
+                     entry->resource_id(),
+                     entry->file_md5());
+        return;
+      }
+
+      DVLOG(2) << "Conflict detected on uploading new file and resolved";
+      callback.Run(
+          google_apis::HTTP_CREATED, entry->resource_id(), entry->file_md5());
+      return;
+
+    default:
+      NOTREACHED() << "Unknown status from EnsureTitleUniqueness:" << status
+                   << " for " << expected_resource_id;
+  }
+}
+
+void APIUtil::UploadExistingFileInternal(
+    const std::string& remote_file_md5,
+    const base::FilePath& local_file_path,
+    const UploadFileCallback& callback,
+    google_apis::GDataErrorCode error,
+    scoped_ptr<google_apis::ResourceEntry> entry) {
+  DCHECK(CalledOnValidThread());
+
+  if (error != google_apis::HTTP_SUCCESS) {
+    DVLOG(2) << "Error on uploading existing file: " << error;
+    callback.Run(error, std::string(), std::string());
+    return;
+  }
+  DCHECK(entry);
+
+  // If remote file's hash value is different from the expected one, conflict
+  // might have occurred.
+  if (!remote_file_md5.empty() && remote_file_md5 != entry->file_md5()) {
+    DVLOG(2) << "Conflict detected before uploading existing file";
+    callback.Run(google_apis::HTTP_CONFLICT, std::string(), std::string());
+    return;
+  }
+
+  std::string mime_type = GetMimeTypeFromTitle(entry->title());
+  UploadKey upload_key = RegisterUploadCallback(callback);
+  ResourceEntryCallback did_upload_callback =
+      base::Bind(&APIUtil::DidUploadExistingFile, AsWeakPtr(), upload_key);
+  drive_uploader_->UploadExistingFile(
+      entry->resource_id(),
+      local_file_path,
+      mime_type,
+      entry->etag(),
+      base::Bind(&UploadResultAdapter, did_upload_callback),
+      google_apis::ProgressCallback());
+}
+
+bool APIUtil::IsAuthenticated() const {
+  return drive_service_->HasRefreshToken();
+}
+
+void APIUtil::DidUploadExistingFile(
+    UploadKey upload_key,
+    google_apis::GDataErrorCode error,
+    scoped_ptr<google_apis::ResourceEntry> entry) {
+  DCHECK(CalledOnValidThread());
+  UploadFileCallback callback = GetAndUnregisterUploadCallback(upload_key);
+  DCHECK(!callback.is_null());
+  if (error != google_apis::HTTP_SUCCESS) {
+    DVLOG(2) << "Error on uploading existing file: " << error;
+    callback.Run(error, std::string(), std::string());
+    return;
+  }
+
+  DCHECK(entry);
+  DVLOG(2) << "Upload completed";
+  callback.Run(error, entry->resource_id(), entry->file_md5());
+}
+
+void APIUtil::DeleteFileInternal(const std::string& remote_file_md5,
+                                 const GDataErrorCallback& callback,
+                                 google_apis::GDataErrorCode error,
+                                 scoped_ptr<google_apis::ResourceEntry> entry) {
+  DCHECK(CalledOnValidThread());
+
+  if (error != google_apis::HTTP_SUCCESS) {
+    DVLOG(2) << "Error on getting resource entry for deleting file: " << error;
+    callback.Run(error);
+    return;
+  }
+  DCHECK(entry);
+
+  // If remote file's hash value is different from the expected one, conflict
+  // might have occurred.
+  if (!remote_file_md5.empty() && remote_file_md5 != entry->file_md5()) {
+    DVLOG(2) << "Conflict detected before deleting file";
+    callback.Run(google_apis::HTTP_CONFLICT);
+    return;
+  }
+  DVLOG(2) << "Got resource entry for deleting file";
+
+  // Move the file to trash (don't delete it completely).
+  drive_service_->DeleteResource(
+      entry->resource_id(),
+      entry->etag(),
+      base::Bind(&APIUtil::DidDeleteFile, AsWeakPtr(), callback));
+}
+
+void APIUtil::DidDeleteFile(const GDataErrorCallback& callback,
+                            google_apis::GDataErrorCode error) {
+  DCHECK(CalledOnValidThread());
+  if (error == google_apis::HTTP_SUCCESS)
+    DVLOG(2) << "Deletion completed";
+  else
+    DVLOG(2) << "Error on deleting file: " << error;
+
+  callback.Run(error);
+}
+
+void APIUtil::EnsureTitleUniqueness(const std::string& parent_resource_id,
+                                    const std::string& expected_title,
+                                    const EnsureUniquenessCallback& callback) {
+  DCHECK(CalledOnValidThread());
+  DVLOG(2) << "Checking if there's no conflict on entry creation";
+
+  const google_apis::GetResourceListCallback& bound_callback =
+      base::Bind(&APIUtil::DidListEntriesToEnsureUniqueness,
+                 AsWeakPtr(),
+                 parent_resource_id,
+                 expected_title,
+                 callback);
+
+  SearchByTitle(expected_title, parent_resource_id, bound_callback);
+}
+
+void APIUtil::DidListEntriesToEnsureUniqueness(
+    const std::string& parent_resource_id,
+    const std::string& expected_title,
+    const EnsureUniquenessCallback& callback,
+    google_apis::GDataErrorCode error,
+    scoped_ptr<google_apis::ResourceList> feed) {
+  DCHECK(CalledOnValidThread());
+
+  if (error != google_apis::HTTP_SUCCESS) {
+    DVLOG(2) << "Error on listing resource for ensuring title uniqueness";
+    callback.Run(
+        error, NO_DUPLICATES_FOUND, scoped_ptr<google_apis::ResourceEntry>());
+    return;
+  }
+  DVLOG(2) << "Got resource list for ensuring title uniqueness";
+
+  // This filtering is needed only on WAPI. Once we move to Drive API we can
+  // drop this.
+  std::string resource_id;
+  ParentType parent_type = PARENT_TYPE_DIRECTORY;
+  if (parent_resource_id.empty()) {
+    resource_id = GetRootResourceId();
+    DCHECK(!resource_id.empty());
+    parent_type = PARENT_TYPE_ROOT_OR_EMPTY;
+  } else {
+    resource_id = parent_resource_id;
+  }
+  ScopedVector<google_apis::ResourceEntry> entries;
+  entries.swap(*feed->mutable_entries());
+  FilterEntriesByTitleAndParent(
+      &entries, expected_title, resource_id, parent_type);
+
+  if (entries.empty()) {
+    DVLOG(2) << "Uploaded file is not found";
+    callback.Run(google_apis::HTTP_NOT_FOUND,
+                 NO_DUPLICATES_FOUND,
+                 scoped_ptr<google_apis::ResourceEntry>());
+    return;
+  }
+
+  if (entries.size() >= 2) {
+    DVLOG(2) << "Conflict detected on creating entry";
+    for (size_t i = 0; i < entries.size() - 1; ++i) {
+      // TODO(tzik): Replace published_time with creation time after we move to
+      // Drive API.
+      if (entries[i]->published_time() < entries.back()->published_time())
+        std::swap(entries[i], entries.back());
+    }
+
+    scoped_ptr<google_apis::ResourceEntry> earliest_entry(entries.back());
+    entries.back() = NULL;
+    entries.get().pop_back();
+
+    DeleteEntriesForEnsuringTitleUniqueness(
+        entries.Pass(),
+        base::Bind(&EntryAdapterForEnsureTitleUniqueness,
+                   base::Passed(&earliest_entry),
+                   callback,
+                   RESOLVED_DUPLICATES));
+    return;
+  }
+
+  DVLOG(2) << "no conflict detected";
+  DCHECK_EQ(1u, entries.size());
+  scoped_ptr<google_apis::ResourceEntry> entry(entries.front());
+  entries.weak_clear();
+
+  callback.Run(google_apis::HTTP_SUCCESS, NO_DUPLICATES_FOUND, entry.Pass());
+}
+
+void APIUtil::DeleteEntriesForEnsuringTitleUniqueness(
+    ScopedVector<google_apis::ResourceEntry> entries,
+    const GDataErrorCallback& callback) {
+  DCHECK(CalledOnValidThread());
+  DVLOG(2) << "Cleaning up conflict on entry creation";
+
+  if (entries.empty()) {
+    callback.Run(google_apis::HTTP_SUCCESS);
+    return;
+  }
+
+  scoped_ptr<google_apis::ResourceEntry> entry(entries.back());
+  entries.back() = NULL;
+  entries.get().pop_back();
+
+  // We don't care conflicts here as other clients may be also deleting this
+  // file, so passing an empty etag.
+  drive_service_->DeleteResource(
+      entry->resource_id(),
+      std::string(),  // empty etag
+      base::Bind(&APIUtil::DidDeleteEntriesForEnsuringTitleUniqueness,
+                 AsWeakPtr(),
+                 base::Passed(&entries),
+                 callback));
+}
+
+void APIUtil::DidDeleteEntriesForEnsuringTitleUniqueness(
+    ScopedVector<google_apis::ResourceEntry> entries,
+    const GDataErrorCallback& callback,
+    google_apis::GDataErrorCode error) {
+  DCHECK(CalledOnValidThread());
+
+  if (error != google_apis::HTTP_SUCCESS &&
+      error != google_apis::HTTP_NOT_FOUND) {
+    DVLOG(2) << "Error on deleting file: " << error;
+    callback.Run(error);
+    return;
+  }
+
+  DVLOG(2) << "Deletion completed";
+  DeleteEntriesForEnsuringTitleUniqueness(entries.Pass(), callback);
+}
+
+APIUtil::UploadKey APIUtil::RegisterUploadCallback(
+    const UploadFileCallback& callback) {
+  const bool inserted = upload_callback_map_.insert(
+      std::make_pair(upload_next_key_, callback)).second;
+  CHECK(inserted);
+  return upload_next_key_++;
+}
+
+APIUtil::UploadFileCallback APIUtil::GetAndUnregisterUploadCallback(
+    UploadKey key) {
+  UploadFileCallback callback;
+  UploadCallbackMap::iterator found = upload_callback_map_.find(key);
+  if (found == upload_callback_map_.end())
+    return callback;
+  callback = found->second;
+  upload_callback_map_.erase(found);
+  return callback;
+}
+
+void APIUtil::CancelAllUploads(google_apis::GDataErrorCode error) {
+  if (upload_callback_map_.empty())
+    return;
+  for (UploadCallbackMap::iterator iter = upload_callback_map_.begin();
+       iter != upload_callback_map_.end();
+       ++iter) {
+    iter->second.Run(error, std::string(), std::string());
+  }
+  upload_callback_map_.clear();
+  drive_uploader_.reset(new drive::DriveUploader(
+      drive_service_.get(), content::BrowserThread::GetBlockingPool()));
+}
+
+std::string APIUtil::GetRootResourceId() const {
+  if (IsDriveAPIDisabled())
+    return drive_service_->GetRootResourceId();
+  return root_resource_id_;
+}
+
+}  // namespace drive_backend
+}  // namespace sync_file_system
diff --git a/chrome/browser/sync_file_system/drive_backend/api_util.h b/chrome/browser/sync_file_system/drive_backend/api_util.h
new file mode 100644
index 0000000..8c17628
--- /dev/null
+++ b/chrome/browser/sync_file_system/drive_backend/api_util.h
@@ -0,0 +1,256 @@
+// 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_API_UTIL_H_
+#define CHROME_BROWSER_SYNC_FILE_SYSTEM_DRIVE_BACKEND_API_UTIL_H_
+
+#include <map>
+#include <string>
+
+#include "base/memory/weak_ptr.h"
+#include "base/threading/non_thread_safe.h"
+#include "chrome/browser/drive/drive_service_interface.h"
+#include "chrome/browser/google_apis/drive_api_url_generator.h"
+#include "chrome/browser/google_apis/gdata_wapi_url_generator.h"
+#include "chrome/browser/sync_file_system/drive_backend/api_util_interface.h"
+#include "net/base/network_change_notifier.h"
+
+class GURL;
+class Profile;
+
+namespace drive { class DriveUploaderInterface; }
+
+namespace sync_file_system {
+namespace drive_backend {
+
+// This class is responsible for talking to the Drive service to get and put
+// Drive directories, files and metadata.
+// This class is owned by DriveFileSyncService.
+class APIUtil : public APIUtilInterface,
+                public drive::DriveServiceObserver,
+                public net::NetworkChangeNotifier::ConnectionTypeObserver,
+                public base::NonThreadSafe,
+                public base::SupportsWeakPtr<APIUtil> {
+ public:
+  // The resulting status of EnsureTitleUniqueness.
+  enum EnsureUniquenessStatus {
+    NO_DUPLICATES_FOUND,
+    RESOLVED_DUPLICATES,
+  };
+
+  typedef base::Callback<void(google_apis::GDataErrorCode,
+                              EnsureUniquenessStatus status,
+                              scoped_ptr<google_apis::ResourceEntry> entry)>
+      EnsureUniquenessCallback;
+
+  explicit APIUtil(Profile* profile);
+  virtual ~APIUtil();
+
+  virtual void AddObserver(APIUtilObserver* observer) OVERRIDE;
+  virtual void RemoveObserver(APIUtilObserver* observer) OVERRIDE;
+
+  static scoped_ptr<APIUtil> CreateForTesting(
+      Profile* profile,
+      scoped_ptr<drive::DriveServiceInterface> drive_service,
+      scoped_ptr<drive::DriveUploaderInterface> drive_uploader);
+
+  // APIUtilInterface overrides.
+  virtual void GetDriveDirectoryForSyncRoot(const ResourceIdCallback& callback)
+      OVERRIDE;
+  virtual void GetDriveDirectoryForOrigin(
+      const std::string& sync_root_resource_id,
+      const GURL& origin,
+      const ResourceIdCallback& callback) OVERRIDE;
+  virtual void GetLargestChangeStamp(const ChangeStampCallback& callback)
+      OVERRIDE;
+  virtual void GetResourceEntry(const std::string& resource_id,
+                                const ResourceEntryCallback& callback) OVERRIDE;
+  virtual void ListFiles(const std::string& directory_resource_id,
+                         const ResourceListCallback& callback) OVERRIDE;
+  virtual void ListChanges(int64 start_changestamp,
+                           const ResourceListCallback& callback) OVERRIDE;
+  virtual void ContinueListing(const GURL& feed_url,
+                               const ResourceListCallback& callback) OVERRIDE;
+  virtual void DownloadFile(const std::string& resource_id,
+                            const std::string& local_file_md5,
+                            const base::FilePath& local_file_path,
+                            const DownloadFileCallback& callback) OVERRIDE;
+  virtual void UploadNewFile(const std::string& directory_resource_id,
+                             const base::FilePath& local_file_path,
+                             const std::string& title,
+                             const UploadFileCallback& callback) OVERRIDE;
+  virtual void UploadExistingFile(const std::string& resource_id,
+                                  const std::string& remote_file_md5,
+                                  const base::FilePath& local_file_path,
+                                  const UploadFileCallback& callback) OVERRIDE;
+  virtual void CreateDirectory(const std::string& parent_resource_id,
+                               const std::string& title,
+                               const ResourceIdCallback& callback) OVERRIDE;
+  virtual bool IsAuthenticated() const OVERRIDE;
+  virtual void DeleteFile(const std::string& resource_id,
+                          const std::string& remote_file_md5,
+                          const GDataErrorCallback& callback) OVERRIDE;
+  virtual GURL ResourceIdToResourceLink(const std::string& resource_id) const
+      OVERRIDE;
+  virtual void EnsureSyncRootIsNotInMyDrive(
+      const std::string& sync_root_resource_id) OVERRIDE;
+
+  static std::string GetSyncRootDirectoryName();
+  static std::string OriginToDirectoryTitle(const GURL& origin);
+  static GURL DirectoryTitleToOrigin(const std::string& title);
+
+  // DriveServiceObserver overrides.
+  virtual void OnReadyToSendRequests() OVERRIDE;
+
+  // ConnectionTypeObserver overrides.
+  virtual void OnConnectionTypeChanged(
+      net::NetworkChangeNotifier::ConnectionType type) OVERRIDE;
+
+ private:
+  typedef int64 UploadKey;
+  typedef std::map<UploadKey, UploadFileCallback> UploadCallbackMap;
+
+  friend class APIUtilTest;
+
+  // Constructor for test use.
+  APIUtil(Profile* profile,
+          const GURL& base_url,
+          const GURL& base_download_url,
+          scoped_ptr<drive::DriveServiceInterface> drive_service,
+          scoped_ptr<drive::DriveUploaderInterface> drive_uploader);
+
+  void GetDriveRootResourceId(const GDataErrorCallback& callback);
+  void DidGetDriveRootResourceId(
+      const GDataErrorCallback& callback,
+      google_apis::GDataErrorCode error,
+      scoped_ptr<google_apis::AboutResource> about_resource);
+
+  void DidGetDriveRootResourceIdForGetSyncRoot(
+      const ResourceIdCallback& callback,
+      google_apis::GDataErrorCode error);
+
+  void DidGetDirectory(const std::string& parent_resource_id,
+                       const std::string& directory_name,
+                       const ResourceIdCallback& callback,
+                       google_apis::GDataErrorCode error,
+                       scoped_ptr<google_apis::ResourceList> feed);
+
+  void DidCreateDirectory(const std::string& parent_resource_id,
+                          const std::string& title,
+                          const ResourceIdCallback& callback,
+                          google_apis::GDataErrorCode error,
+                          scoped_ptr<google_apis::ResourceEntry> entry);
+
+  void DidEnsureUniquenessForCreateDirectory(
+      const ResourceIdCallback& callback,
+      google_apis::GDataErrorCode error,
+      EnsureUniquenessStatus status,
+      scoped_ptr<google_apis::ResourceEntry> entry);
+
+  void SearchByTitle(const std::string& title,
+                     const std::string& directory_resource_id,
+                     const ResourceListCallback& callback);
+
+  void DidGetLargestChangeStamp(
+      const ChangeStampCallback& callback,
+      google_apis::GDataErrorCode error,
+      scoped_ptr<google_apis::AboutResource> about_resource);
+
+  void DidGetDriveRootResourceIdForEnsureSyncRoot(
+      const std::string& sync_root_resource_id,
+      google_apis::GDataErrorCode error);
+
+  void DidGetResourceList(const ResourceListCallback& callback,
+                          google_apis::GDataErrorCode error,
+                          scoped_ptr<google_apis::ResourceList> resource_list);
+
+  void DidGetResourceEntry(const ResourceEntryCallback& callback,
+                           google_apis::GDataErrorCode error,
+                           scoped_ptr<google_apis::ResourceEntry> entry);
+
+  void DownloadFileInternal(const std::string& local_file_md5,
+                            const base::FilePath& local_file_path,
+                            const DownloadFileCallback& callback,
+                            google_apis::GDataErrorCode error,
+                            scoped_ptr<google_apis::ResourceEntry> entry);
+
+  void DidDownloadFile(scoped_ptr<google_apis::ResourceEntry> entry,
+                       const DownloadFileCallback& callback,
+                       google_apis::GDataErrorCode error,
+                       const base::FilePath& downloaded_file_path);
+
+  void DidUploadNewFile(const std::string& parent_resource_id,
+                        const std::string& title,
+                        UploadKey upload_key,
+                        google_apis::GDataErrorCode error,
+                        scoped_ptr<google_apis::ResourceEntry> entry);
+
+  void DidEnsureUniquenessForCreateFile(
+      const std::string& expected_resource_id,
+      const UploadFileCallback& callback,
+      google_apis::GDataErrorCode error,
+      EnsureUniquenessStatus status,
+      scoped_ptr<google_apis::ResourceEntry> entry);
+
+  void UploadExistingFileInternal(const std::string& remote_file_md5,
+                                  const base::FilePath& local_file_path,
+                                  const UploadFileCallback& callback,
+                                  google_apis::GDataErrorCode error,
+                                  scoped_ptr<google_apis::ResourceEntry> entry);
+
+  void DidUploadExistingFile(UploadKey upload_key,
+                             google_apis::GDataErrorCode error,
+                             scoped_ptr<google_apis::ResourceEntry> entry);
+
+  void DeleteFileInternal(const std::string& remote_file_md5,
+                          const GDataErrorCallback& callback,
+                          google_apis::GDataErrorCode error,
+                          scoped_ptr<google_apis::ResourceEntry> entry);
+
+  void DidDeleteFile(const GDataErrorCallback& callback,
+                     google_apis::GDataErrorCode error);
+
+  void EnsureTitleUniqueness(const std::string& parent_resource_id,
+                             const std::string& expected_title,
+                             const EnsureUniquenessCallback& callback);
+  void DidListEntriesToEnsureUniqueness(
+      const std::string& parent_resource_id,
+      const std::string& expected_title,
+      const EnsureUniquenessCallback& callback,
+      google_apis::GDataErrorCode error,
+      scoped_ptr<google_apis::ResourceList> feed);
+  void DeleteEntriesForEnsuringTitleUniqueness(
+      ScopedVector<google_apis::ResourceEntry> entries,
+      const GDataErrorCallback& callback);
+  void DidDeleteEntriesForEnsuringTitleUniqueness(
+      ScopedVector<google_apis::ResourceEntry> entries,
+      const GDataErrorCallback& callback,
+      google_apis::GDataErrorCode error);
+
+  UploadKey RegisterUploadCallback(const UploadFileCallback& callback);
+  UploadFileCallback GetAndUnregisterUploadCallback(UploadKey key);
+  void CancelAllUploads(google_apis::GDataErrorCode error);
+
+  std::string GetRootResourceId() const;
+
+  scoped_ptr<drive::DriveServiceInterface> drive_service_;
+  scoped_ptr<drive::DriveUploaderInterface> drive_uploader_;
+
+  google_apis::GDataWapiUrlGenerator wapi_url_generator_;
+  google_apis::DriveApiUrlGenerator drive_api_url_generator_;
+
+  UploadCallbackMap upload_callback_map_;
+  UploadKey upload_next_key_;
+
+  std::string root_resource_id_;
+
+  ObserverList<APIUtilObserver> observers_;
+
+  DISALLOW_COPY_AND_ASSIGN(APIUtil);
+};
+
+}  // namespace drive_backend
+}  // namespace sync_file_system
+
+#endif  // CHROME_BROWSER_SYNC_FILE_SYSTEM_DRIVE_BACKEND_API_UTIL_H_
diff --git a/chrome/browser/sync_file_system/drive_backend/api_util_interface.h b/chrome/browser/sync_file_system/drive_backend/api_util_interface.h
new file mode 100644
index 0000000..46867f2
--- /dev/null
+++ b/chrome/browser/sync_file_system/drive_backend/api_util_interface.h
@@ -0,0 +1,198 @@
+// 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_API_UTIL_INTERFACE_H_
+#define CHROME_BROWSER_SYNC_FILE_SYSTEM_DRIVE_BACKEND_API_UTIL_INTERFACE_H_
+
+#include <string>
+
+#include "base/callback_forward.h"
+#include "chrome/browser/google_apis/gdata_errorcode.h"
+#include "chrome/browser/google_apis/gdata_wapi_parser.h"
+
+class GURL;
+class Profile;
+
+namespace base {
+class Time;
+}
+
+namespace google_apis {
+class DriveUploaderInterface;
+}
+
+namespace sync_file_system {
+namespace drive_backend {
+
+class APIUtilObserver {
+ public:
+  APIUtilObserver() {}
+  virtual ~APIUtilObserver() {}
+  virtual void OnAuthenticated() = 0;
+  virtual void OnNetworkConnected() = 0;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(APIUtilObserver);
+};
+
+// The implementation of this class is responsible for talking to the Drive
+// service to get and put Drive directories, files and metadata.
+// This class is owned by DriveFileSyncService.
+class APIUtilInterface {
+ public:
+  typedef base::Callback<void(google_apis::GDataErrorCode error)>
+      GDataErrorCallback;
+  typedef base::Callback<void(google_apis::GDataErrorCode error,
+                              const std::string& file_md5,
+                              int64 file_size,
+                              const base::Time& last_updated)>
+      DownloadFileCallback;
+  typedef base::Callback<void(google_apis::GDataErrorCode error,
+                              const std::string& resource_id,
+                              const std::string& file_md5)> UploadFileCallback;
+  typedef base::Callback<
+      void(google_apis::GDataErrorCode error, const std::string& resource_id)>
+      ResourceIdCallback;
+  typedef base::Callback<void(google_apis::GDataErrorCode error,
+                              int64 changestamp)> ChangeStampCallback;
+  typedef base::Callback<void(google_apis::GDataErrorCode error,
+                              scoped_ptr<google_apis::ResourceList> feed)>
+      ResourceListCallback;
+  typedef base::Callback<void(google_apis::GDataErrorCode error,
+                              scoped_ptr<google_apis::ResourceEntry> entry)>
+      ResourceEntryCallback;
+
+  APIUtilInterface() {}
+  virtual ~APIUtilInterface() {}
+
+  virtual void AddObserver(APIUtilObserver* observer) = 0;
+  virtual void RemoveObserver(APIUtilObserver* observer) = 0;
+
+  // Fetches Resource ID of the directory where we should place all files to
+  // sync.  Upon completion, invokes |callback|.
+  // If the directory does not exist on the server this also creates
+  // the directory.
+  //
+  // Returns HTTP_SUCCESS if the directory already exists.
+  // Returns HTTP_CREATED if the directory was not found and created.
+  virtual void GetDriveDirectoryForSyncRoot(
+      const ResourceIdCallback& callback) = 0;
+
+  // Fetches Resource ID of the directory for the |origin|.
+  // Upon completion, invokes |callback|.
+  // If the directory does not exist on the server this also creates
+  // the directory.
+  //
+  // Returns HTTP_SUCCESS if the directory already exists.
+  // Returns HTTP_CREATED if the directory was not found and created.
+  virtual void GetDriveDirectoryForOrigin(
+      const std::string& sync_root_resource_id,
+      const GURL& origin,
+      const ResourceIdCallback& callback) = 0;
+
+  // Fetches the largest changestamp for the signed-in account.
+  // Upon completion, invokes |callback|.
+  virtual void GetLargestChangeStamp(const ChangeStampCallback& callback) = 0;
+
+  // Fetches the resource entry for the file identified by |resource_id|.
+  // Upon completion, invokes |callback|.
+  virtual void GetResourceEntry(const std::string& resource_id,
+                                const ResourceEntryCallback& callback) = 0;
+
+  // Lists files in the directory identified by |resource_id|.
+  // Upon completion, invokes |callback|.
+  // The result may be chunked and may have successive results. The caller needs
+  // to call ContunueListing with the result of GetNextFeedURL to get complete
+  // list of files.
+  virtual void ListFiles(const std::string& directory_resource_id,
+                         const ResourceListCallback& callback) = 0;
+
+  // Lists changes that happened after |start_changestamp|.
+  // Upon completion, invokes |callback|.
+  // The result may be chunked and may have successive results. The caller needs
+  // to call ContunueListing with the result of GetNextFeedURL to get complete
+  // list of changes.
+  virtual void ListChanges(int64 start_changestamp,
+                           const ResourceListCallback& callback) = 0;
+
+  // Fetches the next chunk of ResourceList identified by |feed_url|.
+  // Upon completion, invokes |callback|.
+  virtual void ContinueListing(const GURL& feed_url,
+                               const ResourceListCallback& callback) = 0;
+
+  // Downloads the file identified by |resource_id| from Drive to
+  // |local_file_path|.
+  // |local_file_md5| represents the hash value of the local file to be updated.
+  // If |local_file_md5| is equal to remote file's value, cancels the download
+  // and invokes |callback| with GDataErrorCode::HTTP_NOT_MODIFIED immediately.
+  // When there is no local file to be updated, |local_file_md5| should be
+  // empty.
+  virtual void DownloadFile(const std::string& resource_id,
+                            const std::string& local_file_md5,
+                            const base::FilePath& local_file_path,
+                            const DownloadFileCallback& callback) = 0;
+
+  // Uploads the new file |local_file_path| with specified |title| into the
+  // directory identified by |directory_resource_id|.
+  // Upon completion, invokes |callback| and returns HTTP_CREATED if the file
+  // is created.
+  virtual void UploadNewFile(const std::string& directory_resource_id,
+                             const base::FilePath& local_file_path,
+                             const std::string& title,
+                             const UploadFileCallback& callback) = 0;
+
+  // Uploads the existing file identified by |local_file_path|.
+  // |remote_file_md5| represents the expected hash value of the file to be
+  // updated on Drive. If |remote_file_md5| is different from the actual value,
+  // cancels the upload and invokes |callback| with
+  // GDataErrorCode::HTTP_CONFLICT immediately.
+  // Returns HTTP_SUCCESS if the file uploaded successfully.
+  virtual void UploadExistingFile(const std::string& resource_id,
+                                  const std::string& remote_file_md5,
+                                  const base::FilePath& local_file_path,
+                                  const UploadFileCallback& callback) = 0;
+
+  // Creates a new directory with specified |title| into the directory
+  // identified by |parent_resource_id|.
+  // Upon completion, invokes |callback| and returns HTTP_CREATED if
+  // the directory is created.
+  virtual void CreateDirectory(const std::string& parent_resource_id,
+                               const std::string& title,
+                               const ResourceIdCallback& callback) = 0;
+
+  // Returns true if the user is authenticated.
+  virtual bool IsAuthenticated() const = 0;
+
+  // Deletes the file identified by |resource_id|.
+  // A directory is considered a file and will cause a recursive delete if
+  // given as the |resource_id|.
+  // TODO(tzik): Rename this function to DeleteResource.
+  //
+  // |remote_file_md5| represents the expected hash value of the file to be
+  // deleted from Drive. If |remote_file_md5| is empty, then it's implied that
+  // the file should be deleted on the remote side regardless. If
+  // |remote_file_md5| is not empty and is different from the actual value,
+  // the deletion operation is canceled and the |callback| with
+  // GDataErrorCode::HTTP_CONFLICT is invoked immediately.
+  virtual void DeleteFile(const std::string& resource_id,
+                          const std::string& remote_file_md5,
+                          const GDataErrorCallback& callback) = 0;
+
+  // Converts |resource_id| to corresponing resource link.
+  virtual GURL ResourceIdToResourceLink(
+      const std::string& resource_id) const = 0;
+
+  // Ensures the sync root directory is not in 'My Drive'. Even if the directory
+  // is in directories other than 'My Drive', it will not be removed from there.
+  virtual void EnsureSyncRootIsNotInMyDrive(
+      const std::string& sync_root_resource_id) = 0;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(APIUtilInterface);
+};
+
+}  // namespace drive_backend
+}  // namespace sync_file_system
+
+#endif  // CHROME_BROWSER_SYNC_FILE_SYSTEM_DRIVE_BACKEND_API_UTIL_INTERFACE_H_
diff --git a/chrome/browser/sync_file_system/drive_backend/api_util_unittest.cc b/chrome/browser/sync_file_system/drive_backend/api_util_unittest.cc
new file mode 100644
index 0000000..af75d06
--- /dev/null
+++ b/chrome/browser/sync_file_system/drive_backend/api_util_unittest.cc
@@ -0,0 +1,1161 @@
+// 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/api_util.h"
+
+#include "base/location.h"
+#include "base/message_loop/message_loop.h"
+#include "base/message_loop/message_loop_proxy.h"
+#include "base/strings/stringprintf.h"
+#include "base/values.h"
+#include "chrome/browser/drive/drive_uploader.h"
+#include "chrome/browser/drive/fake_drive_service.h"
+#include "chrome/browser/google_apis/drive_api_parser.h"
+#include "chrome/browser/google_apis/gdata_errorcode.h"
+#include "chrome/browser/google_apis/test_util.h"
+#include "chrome/browser/sync_file_system/drive_file_sync_util.h"
+#include "chrome/test/base/testing_profile.h"
+#include "content/public/test/test_browser_thread.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "net/base/escape.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#define FPL(x) FILE_PATH_LITERAL(x)
+
+using drive::DriveServiceInterface;
+using drive::DriveUploaderInterface;
+using drive::FakeDriveService;
+using drive::UploadCompletionCallback;
+using google_apis::GDataErrorCode;
+using google_apis::ProgressCallback;
+using google_apis::ResourceEntry;
+using google_apis::ResourceList;
+
+namespace sync_file_system {
+namespace drive_backend {
+
+namespace {
+
+const char kOrigin[] = "chrome-extension://example";
+const char kOriginDirectoryName[] = "example";
+
+void DidRemoveResourceFromDirectory(GDataErrorCode error) {
+  ASSERT_EQ(google_apis::HTTP_SUCCESS, error);
+}
+
+void DidAddFileOrDirectoryForMakingConflict(GDataErrorCode error,
+                                            scoped_ptr<ResourceEntry> entry) {
+  ASSERT_EQ(google_apis::HTTP_CREATED, error);
+  ASSERT_TRUE(entry);
+}
+
+void DidAddNewDirectory(std::string* resource_id_out,
+                        GDataErrorCode error,
+                        scoped_ptr<ResourceEntry> entry) {
+  ASSERT_TRUE(resource_id_out);
+  ASSERT_EQ(google_apis::HTTP_CREATED, error);
+  ASSERT_TRUE(entry);
+  *resource_id_out = entry->resource_id();
+}
+
+void DidAddNewFile(std::string* resource_id_out,
+                   std::string* file_md5_out,
+                   GDataErrorCode error,
+                   scoped_ptr<ResourceEntry> entry) {
+  ASSERT_TRUE(resource_id_out);
+  ASSERT_TRUE(file_md5_out);
+  ASSERT_EQ(google_apis::HTTP_CREATED, error);
+  ASSERT_TRUE(entry);
+  *resource_id_out = entry->resource_id();
+  *file_md5_out = entry->file_md5();
+}
+
+void DidAddFileForUploadNew(
+    const UploadCompletionCallback& callback,
+    GDataErrorCode error,
+    scoped_ptr<ResourceEntry> entry) {
+  ASSERT_EQ(google_apis::HTTP_CREATED, error);
+  ASSERT_TRUE(entry);
+  base::MessageLoopProxy::current()->PostTask(
+      FROM_HERE,
+      base::Bind(callback,
+                 google_apis::HTTP_SUCCESS,
+                 GURL(),
+                 base::Passed(&entry)));
+}
+
+void DidGetResourceEntryForUploadExisting(
+    const UploadCompletionCallback& callback,
+    GDataErrorCode error,
+    scoped_ptr<ResourceEntry> entry) {
+  ASSERT_EQ(google_apis::HTTP_SUCCESS, error);
+  ASSERT_TRUE(entry);
+  base::MessageLoopProxy::current()->PostTask(
+      FROM_HERE,
+      base::Bind(callback,
+                 google_apis::HTTP_SUCCESS,
+                 GURL(),
+                 base::Passed(&entry)));
+}
+
+void VerifyTitleUniqueness(const tracked_objects::Location& from_here,
+                           const std::string& resource_id,
+                           google_apis::DriveEntryKind kind,
+                           GDataErrorCode error,
+                           scoped_ptr<ResourceList> resource_list) {
+  std::string location(" failed at " + from_here.ToString());
+  ASSERT_FALSE(resource_id.empty()) << location;
+  ASSERT_EQ(google_apis::HTTP_SUCCESS, error) << location;
+  ASSERT_TRUE(resource_list) << location;
+
+  const ScopedVector<ResourceEntry>& entries = resource_list->entries();
+  ASSERT_EQ(1u, entries.size());
+  EXPECT_EQ(resource_id, entries[0]->resource_id());
+  switch (kind) {
+    case google_apis::ENTRY_KIND_FOLDER:
+      EXPECT_TRUE(entries[0]->is_folder()) << location;
+      return;
+    case google_apis::ENTRY_KIND_FILE:
+      EXPECT_TRUE(entries[0]->is_file()) << location;
+      return;
+    default:
+      NOTREACHED() << "Unexpected DriveEntryKind: " << kind << location;
+      return;
+  }
+}
+
+void VerifyFileDeletion(const tracked_objects::Location& from_here,
+                        GDataErrorCode error,
+                        scoped_ptr<ResourceList> resource_list) {
+  std::string location(" failed at " + from_here.ToString());
+  ASSERT_EQ(google_apis::HTTP_SUCCESS, error) << location;
+  ASSERT_TRUE(resource_list) << location;
+  EXPECT_TRUE(resource_list->entries().empty()) << location;
+}
+
+class FakeDriveServiceWrapper : public FakeDriveService {
+ public:
+  FakeDriveServiceWrapper() : make_directory_conflict_(false) {};
+  virtual ~FakeDriveServiceWrapper() {};
+
+  // DriveServiceInterface overrides.
+  virtual google_apis::CancelCallback AddNewDirectory(
+      const std::string& parent_resource_id,
+      const std::string& directory_name,
+      const google_apis::GetResourceEntryCallback& callback) OVERRIDE {
+    if (make_directory_conflict_) {
+      FakeDriveService::AddNewDirectory(
+          parent_resource_id,
+          directory_name,
+          base::Bind(&DidAddFileOrDirectoryForMakingConflict));
+    }
+    return FakeDriveService::AddNewDirectory(
+        parent_resource_id, directory_name, callback);
+  }
+
+  void set_make_directory_conflict(bool enable) {
+    make_directory_conflict_ = enable;
+  }
+
+ private:
+  bool make_directory_conflict_;
+
+  DISALLOW_COPY_AND_ASSIGN(FakeDriveServiceWrapper);
+};
+
+// A fake implementation of DriveUploaderInterface, which provides fake
+// behaviors for file uploading.
+class FakeDriveUploader : public DriveUploaderInterface {
+ public:
+  explicit FakeDriveUploader(FakeDriveServiceWrapper* fake_drive_service)
+      : fake_drive_service_(fake_drive_service),
+        make_file_conflict_(false) {}
+  virtual ~FakeDriveUploader() {}
+
+  // DriveUploaderInterface overrides.
+
+  // Proxies a request to upload a new file to FakeDriveService, and returns the
+  // resource entry to the caller.
+  virtual google_apis::CancelCallback UploadNewFile(
+      const std::string& parent_resource_id,
+      const base::FilePath& local_file_path,
+      const std::string& title,
+      const std::string& content_type,
+      const UploadCompletionCallback& callback,
+      const ProgressCallback& progress_callback) OVERRIDE {
+    DCHECK(!callback.is_null());
+    const std::string kFileContent = "test content";
+
+    if (make_file_conflict_) {
+      fake_drive_service_->AddNewFile(
+          content_type,
+          kFileContent,
+          parent_resource_id,
+          title,
+          false,  // shared_with_me
+          base::Bind(&DidAddFileOrDirectoryForMakingConflict));
+    }
+
+    fake_drive_service_->AddNewFile(
+        content_type,
+        kFileContent,
+        parent_resource_id,
+        title,
+        false,  // shared_with_me
+        base::Bind(&DidAddFileForUploadNew, callback));
+    base::MessageLoop::current()->RunUntilIdle();
+
+    return google_apis::CancelCallback();
+  }
+
+  // Pretends that an existing file |resource_id| was uploaded successfully, and
+  // returns a resource entry to the caller.
+  virtual google_apis::CancelCallback UploadExistingFile(
+      const std::string& resource_id,
+      const base::FilePath& local_file_path,
+      const std::string& content_type,
+      const std::string& etag,
+      const UploadCompletionCallback& callback,
+      const ProgressCallback& progress_callback) OVERRIDE {
+    DCHECK(!callback.is_null());
+    return fake_drive_service_->GetResourceEntry(
+        resource_id,
+        base::Bind(&DidGetResourceEntryForUploadExisting, callback));
+  }
+
+  // At the moment, sync file system doesn't support resuming of the uploading.
+  // So this method shouldn't be reached.
+  virtual google_apis::CancelCallback ResumeUploadFile(
+      const GURL& upload_location,
+      const base::FilePath& local_file_path,
+      const std::string& content_type,
+      const UploadCompletionCallback& callback,
+      const ProgressCallback& progress_callback) OVERRIDE {
+    NOTREACHED();
+    return google_apis::CancelCallback();
+  }
+
+  void set_make_file_conflict(bool enable) {
+    make_file_conflict_ = enable;
+  }
+
+ private:
+  FakeDriveServiceWrapper* fake_drive_service_;
+  bool make_file_conflict_;
+
+  DISALLOW_COPY_AND_ASSIGN(FakeDriveUploader);
+};
+
+}  // namespace
+
+class APIUtilTest : public testing::Test {
+ public:
+  APIUtilTest() : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP),
+                  fake_drive_service_(NULL),
+                  fake_drive_uploader_(NULL) {}
+
+  virtual void SetUp() OVERRIDE {
+    fake_drive_service_ = new FakeDriveServiceWrapper;
+    fake_drive_uploader_ = new FakeDriveUploader(fake_drive_service_);
+
+    api_util_ = APIUtil::CreateForTesting(
+        &profile_,
+        scoped_ptr<DriveServiceInterface>(fake_drive_service_),
+        scoped_ptr<DriveUploaderInterface>(fake_drive_uploader_));
+
+    fake_drive_service_->LoadResourceListForWapi(
+        "sync_file_system/initialize.json");
+  }
+
+  virtual void TearDown() OVERRIDE {
+    api_util_.reset();
+  }
+
+ protected:
+  void SetUpSyncRootDirectory() {
+    fake_drive_service()->AddNewDirectory(
+        fake_drive_service_->GetRootResourceId(),
+        APIUtil::GetSyncRootDirectoryName(),
+        base::Bind(&DidAddNewDirectory, &sync_root_resource_id_));
+    base::MessageLoop::current()->RunUntilIdle();
+
+    ASSERT_TRUE(!sync_root_resource_id_.empty());
+    fake_drive_service()->RemoveResourceFromDirectory(
+        fake_drive_service_->GetRootResourceId(),
+        sync_root_resource_id_,
+        base::Bind(&DidRemoveResourceFromDirectory));
+    base::MessageLoop::current()->RunUntilIdle();
+  }
+
+  void SetUpOriginRootDirectory() {
+    ASSERT_TRUE(!sync_root_resource_id_.empty());
+    fake_drive_service()->AddNewDirectory(
+        GetSyncRootResourceId(),
+        kOriginDirectoryName,
+        base::Bind(&DidAddNewDirectory, &origin_root_resource_id_));
+    base::MessageLoop::current()->RunUntilIdle();
+  }
+
+  void SetUpFile(const std::string& content_data,
+                 const std::string& title,
+                 std::string* resource_id_out,
+                 std::string* file_md5_out) {
+    ASSERT_TRUE(!origin_root_resource_id_.empty());
+    ASSERT_TRUE(resource_id_out);
+    ASSERT_TRUE(file_md5_out);
+    fake_drive_service()->AddNewFile(
+        "text/plain",
+        content_data,
+        origin_root_resource_id_,
+        title,
+        false,  // shared_with_me
+        base::Bind(&DidAddNewFile, resource_id_out, file_md5_out));
+    base::MessageLoop::current()->RunUntilIdle();
+  }
+
+  std::string GetSyncRootResourceId() {
+    DCHECK(!sync_root_resource_id_.empty());
+    return sync_root_resource_id_;
+  }
+
+  std::string GetOriginRootResourceId() {
+    DCHECK(!origin_root_resource_id_.empty());
+    return origin_root_resource_id_;
+  }
+
+  APIUtil* api_util() { return api_util_.get(); }
+
+  FakeDriveServiceWrapper* fake_drive_service() {
+    return fake_drive_service_;
+  }
+
+  FakeDriveUploader* fake_drive_uploader() {
+    return fake_drive_uploader_;
+  }
+
+  void TestGetSyncRoot();
+  void TestCreateSyncRoot();
+  void TestCreateSyncRoot_Conflict();
+  void TestGetOriginDirectory();
+  void TestCreateOriginDirectory();
+  void TestCreateOriginDirectory_Conflict();
+  void TestGetLargestChangeStamp();
+  void TestListFiles();
+  void TestListChanges();
+  void TestDownloadFile();
+  void TestDownloadFileInNotModified();
+  void TestUploadNewFile();
+  void TestUploadNewFile_ConflictWithFile();
+  void TestUploadExistingFile();
+  void TestUploadExistingFileInConflict();
+  void TestDeleteFile();
+  void TestDeleteFileInConflict();
+  void TestCreateDirectory();
+
+ private:
+  content::TestBrowserThreadBundle thread_bundle_;
+
+  std::string sync_root_resource_id_;
+  std::string origin_root_resource_id_;
+
+  TestingProfile profile_;
+  scoped_ptr<APIUtil> api_util_;
+  FakeDriveServiceWrapper* fake_drive_service_;
+  FakeDriveUploader* fake_drive_uploader_;
+
+  DISALLOW_COPY_AND_ASSIGN(APIUtilTest);
+};
+
+void DidGetResourceID(bool* done_out,
+                      GDataErrorCode* error_out,
+                      std::string* resource_id_out,
+                      GDataErrorCode error,
+                      const std::string& resource_id) {
+  EXPECT_FALSE(*done_out);
+  *done_out = true;
+  *error_out = error;
+  *resource_id_out = resource_id;
+}
+
+#if !defined(OS_ANDROID)
+
+void DidGetLargestChangeStamp(bool* done_out,
+                              GDataErrorCode* error_out,
+                              int64* largest_changestamp_out,
+                              GDataErrorCode error,
+                              int64 largest_changestamp) {
+  EXPECT_FALSE(*done_out);
+  *done_out = true;
+  *error_out = error;
+  *largest_changestamp_out = largest_changestamp;
+}
+
+void DidGetResourceList(bool* done_out,
+                        GDataErrorCode* error_out,
+                        scoped_ptr<ResourceList>* document_feed_out,
+                        GDataErrorCode error,
+                        scoped_ptr<ResourceList> document_feed) {
+  EXPECT_FALSE(*done_out);
+  *done_out = true;
+  *error_out = error;
+  *document_feed_out = document_feed.Pass();
+}
+
+void DidDownloadFile(bool* done_out,
+                     std::string* expected_file_md5_out,
+                     GDataErrorCode* error_out,
+                     GDataErrorCode error,
+                     const std::string& file_md5,
+                     int64 file_size,
+                     const base::Time& updated_time) {
+  EXPECT_FALSE(*done_out);
+  *done_out = true;
+  *error_out = error;
+  *expected_file_md5_out = file_md5;
+}
+
+void DidUploadFile(bool* done_out,
+                   GDataErrorCode* error_out,
+                   std::string* resource_id_out,
+                   GDataErrorCode error,
+                   const std::string& resource_id,
+                   const std::string& file_md5) {
+  EXPECT_FALSE(*done_out);
+  *done_out = true;
+  *error_out = error;
+  *resource_id_out = resource_id;
+}
+
+void DidDeleteFile(bool* done_out,
+                   GDataErrorCode* error_out,
+                   GDataErrorCode error) {
+  EXPECT_FALSE(*done_out);
+  *done_out = true;
+  *error_out = error;
+}
+
+void APIUtilTest::TestGetSyncRoot() {
+  fake_drive_service()->LoadAccountMetadataForWapi(
+      "sync_file_system/account_metadata.json");
+  SetUpSyncRootDirectory();
+
+  bool done = false;
+  GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
+  std::string resource_id;
+  api_util()->GetDriveDirectoryForSyncRoot(
+      base::Bind(&DidGetResourceID, &done, &error, &resource_id));
+  base::MessageLoop::current()->RunUntilIdle();
+
+  EXPECT_TRUE(done);
+  EXPECT_EQ(google_apis::HTTP_SUCCESS, error);
+  EXPECT_EQ(GetSyncRootResourceId(), resource_id);
+}
+
+void APIUtilTest::TestCreateSyncRoot() {
+  fake_drive_service()->LoadAccountMetadataForWapi(
+      "sync_file_system/account_metadata.json");
+  bool done = false;
+  GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
+  std::string resource_id;
+  api_util()->GetDriveDirectoryForSyncRoot(
+      base::Bind(&DidGetResourceID, &done, &error, &resource_id));
+  base::MessageLoop::current()->RunUntilIdle();
+
+  EXPECT_TRUE(done);
+  EXPECT_EQ(google_apis::HTTP_CREATED, error);
+  EXPECT_FALSE(resource_id.empty());
+
+  fake_drive_service()->SearchByTitle(
+      APIUtil::GetSyncRootDirectoryName(),
+      std::string(),  // directory_resource_id
+      base::Bind(&VerifyTitleUniqueness,
+                 FROM_HERE,
+                 resource_id,
+                 google_apis::ENTRY_KIND_FOLDER));
+  base::MessageLoop::current()->RunUntilIdle();
+}
+
+void APIUtilTest::TestCreateSyncRoot_Conflict() {
+  fake_drive_service()->LoadAccountMetadataForWapi(
+      "sync_file_system/account_metadata.json");
+  fake_drive_service()->set_make_directory_conflict(true);
+
+  bool done = false;
+  GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
+  std::string resource_id;
+  api_util()->GetDriveDirectoryForSyncRoot(
+      base::Bind(&DidGetResourceID, &done, &error, &resource_id));
+  base::MessageLoop::current()->RunUntilIdle();
+
+  EXPECT_TRUE(done);
+  EXPECT_EQ(google_apis::HTTP_SUCCESS, error);
+  EXPECT_FALSE(resource_id.empty());
+
+  // Verify that there is no duplicated directory on the remote side.
+  fake_drive_service()->SearchByTitle(
+      APIUtil::GetSyncRootDirectoryName(),
+      std::string(),  // directory_resource_id
+      base::Bind(&VerifyTitleUniqueness,
+                 FROM_HERE,
+                 resource_id,
+                 google_apis::ENTRY_KIND_FOLDER));
+  base::MessageLoop::current()->RunUntilIdle();
+}
+
+void APIUtilTest::TestGetOriginDirectory() {
+  SetUpSyncRootDirectory();
+  SetUpOriginRootDirectory();
+
+  bool done = false;
+  GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
+  std::string resource_id;
+  api_util()->GetDriveDirectoryForOrigin(
+      GetSyncRootResourceId(),
+      GURL(kOrigin),
+      base::Bind(&DidGetResourceID, &done, &error, &resource_id));
+  base::MessageLoop::current()->RunUntilIdle();
+
+  EXPECT_TRUE(done);
+  EXPECT_EQ(google_apis::HTTP_SUCCESS, error);
+  EXPECT_EQ(GetOriginRootResourceId(), resource_id);
+}
+
+void APIUtilTest::TestCreateOriginDirectory() {
+  SetUpSyncRootDirectory();
+
+  bool done = false;
+  GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
+  std::string resource_id;
+  api_util()->GetDriveDirectoryForOrigin(
+      GetSyncRootResourceId(),
+      GURL(kOrigin),
+      base::Bind(&DidGetResourceID, &done, &error, &resource_id));
+  base::MessageLoop::current()->RunUntilIdle();
+
+  EXPECT_TRUE(done);
+  EXPECT_EQ(google_apis::HTTP_CREATED, error);
+  EXPECT_FALSE(resource_id.empty());
+
+  fake_drive_service()->SearchByTitle(
+      kOriginDirectoryName,
+      GetSyncRootResourceId(),
+      base::Bind(&VerifyTitleUniqueness,
+                 FROM_HERE,
+                 resource_id,
+                 google_apis::ENTRY_KIND_FOLDER));
+  base::MessageLoop::current()->RunUntilIdle();
+}
+
+void APIUtilTest::TestCreateOriginDirectory_Conflict() {
+  SetUpSyncRootDirectory();
+  fake_drive_service()->set_make_directory_conflict(true);
+
+  bool done = false;
+  GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
+  std::string resource_id;
+  api_util()->GetDriveDirectoryForOrigin(
+      GetSyncRootResourceId(),
+      GURL(kOrigin),
+      base::Bind(&DidGetResourceID, &done, &error, &resource_id));
+  base::MessageLoop::current()->RunUntilIdle();
+
+  EXPECT_TRUE(done);
+  EXPECT_EQ(google_apis::HTTP_SUCCESS, error);
+  EXPECT_FALSE(resource_id.empty());
+
+  // Verify that there is no duplicated directory on the remote side.
+  fake_drive_service()->SearchByTitle(
+      kOriginDirectoryName,
+      GetSyncRootResourceId(),
+      base::Bind(&VerifyTitleUniqueness,
+                 FROM_HERE,
+                 resource_id,
+                 google_apis::ENTRY_KIND_FOLDER));
+  base::MessageLoop::current()->RunUntilIdle();
+}
+
+void APIUtilTest::TestGetLargestChangeStamp() {
+  fake_drive_service()->LoadAccountMetadataForWapi(
+      "sync_file_system/account_metadata.json");
+
+  bool done = false;
+  GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
+  int64 largest_changestamp = -1;
+  api_util()->GetLargestChangeStamp(base::Bind(
+      &DidGetLargestChangeStamp, &done, &error, &largest_changestamp));
+  base::MessageLoop::current()->RunUntilIdle();
+
+  EXPECT_TRUE(done);
+  EXPECT_EQ(google_apis::HTTP_SUCCESS, error);
+  EXPECT_EQ(654321, largest_changestamp);
+}
+
+void APIUtilTest::TestListFiles() {
+  fake_drive_service()->set_default_max_results(3);
+
+  SetUpSyncRootDirectory();
+  SetUpOriginRootDirectory();
+
+  int kNumberOfFiles = 5;
+  for (int i = 0; i < kNumberOfFiles; ++i) {
+    std::string file_resource_id;
+    std::string file_md5;
+    std::string file_content = base::StringPrintf("test content %d", i);
+    std::string file_title = base::StringPrintf("test_%d.txt", i);
+    SetUpFile(file_content, file_title, &file_resource_id, &file_md5);
+  }
+
+  bool done = false;
+  GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
+  scoped_ptr<ResourceList> document_feed;
+  api_util()->ListFiles(
+      GetOriginRootResourceId(),
+      base::Bind(&DidGetResourceList, &done, &error, &document_feed));
+  base::MessageLoop::current()->RunUntilIdle();
+
+  EXPECT_TRUE(done);
+  EXPECT_EQ(google_apis::HTTP_SUCCESS, error);
+  EXPECT_EQ(3U, document_feed->entries().size());
+
+  GURL feed_url;
+  ASSERT_TRUE(document_feed->GetNextFeedURL(&feed_url));
+
+  done = false;
+  error = google_apis::GDATA_OTHER_ERROR;
+  document_feed.reset();
+
+  api_util()->ContinueListing(
+      feed_url, base::Bind(&DidGetResourceList, &done, &error, &document_feed));
+  base::MessageLoop::current()->RunUntilIdle();
+
+  EXPECT_TRUE(done);
+  EXPECT_EQ(google_apis::HTTP_SUCCESS, error);
+  EXPECT_EQ(2U, document_feed->entries().size());
+}
+
+void APIUtilTest::TestListChanges() {
+  const int64 kStartChangestamp = 6;
+
+  SetUpSyncRootDirectory();
+  SetUpOriginRootDirectory();
+
+  // Files should have changestamp #4+ since creating the sync root directory is
+  // #1, moving it out of 'My Drive' is #2, and creating the origin root
+  // directory is #3.
+  const int kNumberOfFiles = 5;
+  for (int i = 0; i < kNumberOfFiles; ++i) {
+    std::string file_resource_id;
+    std::string file_md5;
+    std::string file_content = base::StringPrintf("test content %d", i);
+    std::string file_title = base::StringPrintf("test_%d.txt", i);
+    SetUpFile(file_content, file_title, &file_resource_id, &file_md5);
+  }
+
+  bool done = false;
+  GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
+  scoped_ptr<ResourceList> document_feed;
+  api_util()->ListFiles(
+      GetOriginRootResourceId(),
+      base::Bind(&DidGetResourceList, &done, &error, &document_feed));
+  base::MessageLoop::current()->RunUntilIdle();
+
+  EXPECT_TRUE(done);
+  EXPECT_EQ(google_apis::HTTP_SUCCESS, error);
+  EXPECT_EQ(5U, document_feed->entries().size());
+
+  done = false;
+  error = google_apis::GDATA_OTHER_ERROR;
+  document_feed.reset();
+  api_util()->ListChanges(
+      kStartChangestamp,
+      base::Bind(&DidGetResourceList, &done, &error, &document_feed));
+  base::MessageLoop::current()->RunUntilIdle();
+
+  // There should be 3 files which have changestamp #6+.
+  EXPECT_TRUE(done);
+  EXPECT_EQ(google_apis::HTTP_SUCCESS, error);
+  EXPECT_EQ(3U, document_feed->entries().size());
+}
+
+void APIUtilTest::TestDownloadFile() {
+  const std::string kFileContent = "test content";
+  const std::string kFileTitle = "test.txt";
+
+  SetUpSyncRootDirectory();
+  SetUpOriginRootDirectory();
+  std::string file_resource_id;
+  std::string file_md5;
+  SetUpFile(kFileContent, kFileTitle, &file_resource_id, &file_md5);
+
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  const base::FilePath kOutputFilePath =
+      temp_dir.path().AppendASCII(kFileTitle);
+
+  bool done = false;
+  std::string downloaded_file_md5;
+  GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
+  api_util()->DownloadFile(
+      file_resource_id,
+      "",  // local_file_md5
+      kOutputFilePath,
+      base::Bind(&DidDownloadFile, &done, &downloaded_file_md5, &error));
+  base::MessageLoop::current()->RunUntilIdle();
+
+  EXPECT_TRUE(done);
+  EXPECT_EQ(file_md5, downloaded_file_md5);
+  EXPECT_EQ(google_apis::HTTP_SUCCESS, error);
+}
+
+void APIUtilTest::TestDownloadFileInNotModified() {
+  const std::string kFileContent = "test content";
+  const std::string kFileTitle = "test.txt";
+
+  SetUpSyncRootDirectory();
+  SetUpOriginRootDirectory();
+  std::string file_resource_id;
+  std::string file_md5;
+  SetUpFile(kFileContent, kFileTitle, &file_resource_id, &file_md5);
+
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  const base::FilePath kOutputFilePath =
+      temp_dir.path().AppendASCII(kFileTitle);
+
+  bool done = false;
+  std::string downloaded_file_md5;
+  GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
+
+  // Since local file's hash value is equal to remote file's one, it is expected
+  // to cancel download the file and to return NOT_MODIFIED status code.
+  api_util()->DownloadFile(
+      file_resource_id,
+      file_md5,
+      kOutputFilePath,
+      base::Bind(&DidDownloadFile, &done, &downloaded_file_md5, &error));
+  base::MessageLoop::current()->RunUntilIdle();
+
+  EXPECT_TRUE(done);
+  EXPECT_EQ(google_apis::HTTP_NOT_MODIFIED, error);
+  // TODO(nhiroki): Compare |file_md5| and |downloaded_file_md5| after making
+  // FakeDriveService::AddNewEntry set the correct MD5.
+}
+
+void APIUtilTest::TestUploadNewFile() {
+  const std::string kFileTitle = "test.txt";
+  const base::FilePath kLocalFilePath(FPL("/tmp/dir/file"));
+
+  SetUpSyncRootDirectory();
+  SetUpOriginRootDirectory();
+
+  bool done = false;
+  GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
+  std::string resource_id;
+  api_util()->UploadNewFile(
+      GetOriginRootResourceId(),
+      kLocalFilePath,
+      kFileTitle,
+      base::Bind(&DidUploadFile, &done, &error, &resource_id));
+  base::MessageLoop::current()->RunUntilIdle();
+
+  EXPECT_TRUE(done);
+  EXPECT_EQ(google_apis::HTTP_CREATED, error);
+  EXPECT_TRUE(!resource_id.empty());
+
+  fake_drive_service()->SearchByTitle(
+      kFileTitle,
+      GetOriginRootResourceId(),
+      base::Bind(&VerifyTitleUniqueness,
+                 FROM_HERE,
+                 resource_id,
+                 google_apis::ENTRY_KIND_FILE));
+  base::MessageLoop::current()->RunUntilIdle();
+}
+
+void APIUtilTest::TestUploadNewFile_ConflictWithFile() {
+  const std::string kFileTitle = "test.txt";
+  const base::FilePath kLocalFilePath(FPL("/tmp/dir/file"));
+
+  fake_drive_uploader()->set_make_file_conflict(true);
+
+  SetUpSyncRootDirectory();
+  SetUpOriginRootDirectory();
+
+  bool done = false;
+  GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
+  std::string resource_id;
+  api_util()->UploadNewFile(
+      GetOriginRootResourceId(),
+      kLocalFilePath,
+      kFileTitle,
+      base::Bind(&DidUploadFile, &done, &error, &resource_id));
+  base::MessageLoop::current()->RunUntilIdle();
+
+  // HTTP_CONFLICT error must be returned with empty resource_id.
+  EXPECT_TRUE(done);
+  EXPECT_EQ(google_apis::HTTP_CONFLICT, error);
+  EXPECT_TRUE(!resource_id.empty());
+
+  // Verify that there is no duplicated file on the remote side.
+  fake_drive_service()->SearchByTitle(
+      kFileTitle,
+      GetOriginRootResourceId(),
+      base::Bind(&VerifyTitleUniqueness,
+                 FROM_HERE,
+                 resource_id,
+                 google_apis::ENTRY_KIND_FILE));
+  base::MessageLoop::current()->RunUntilIdle();
+}
+
+void APIUtilTest::TestUploadExistingFile() {
+  const base::FilePath kLocalFilePath(FPL("/tmp/dir/file"));
+  const std::string kFileContent = "test content";
+  const std::string kFileTitle = "test.txt";
+
+  SetUpSyncRootDirectory();
+  SetUpOriginRootDirectory();
+  std::string file_resource_id;
+  std::string file_md5;
+  SetUpFile(kFileContent, kFileTitle, &file_resource_id, &file_md5);
+
+  bool done = false;
+  GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
+  std::string resource_id;
+  api_util()->UploadExistingFile(
+      file_resource_id,
+      file_md5,
+      kLocalFilePath,
+      base::Bind(&DidUploadFile, &done, &error, &resource_id));
+  base::MessageLoop::current()->RunUntilIdle();
+
+  EXPECT_TRUE(done);
+  EXPECT_EQ(google_apis::HTTP_SUCCESS, error);
+  EXPECT_EQ(file_resource_id, resource_id);
+
+  fake_drive_service()->SearchByTitle(
+      kFileTitle,
+      GetOriginRootResourceId(),
+      base::Bind(&VerifyTitleUniqueness,
+                 FROM_HERE,
+                 file_resource_id,
+                 google_apis::ENTRY_KIND_FILE));
+  base::MessageLoop::current()->RunUntilIdle();
+}
+
+void APIUtilTest::TestUploadExistingFileInConflict() {
+  const base::FilePath kLocalFilePath(FPL("/tmp/dir/file"));
+  const std::string kFileContent = "test content";
+  const std::string kFileTitle = "test.txt";
+
+  SetUpSyncRootDirectory();
+  SetUpOriginRootDirectory();
+  std::string file_resource_id;
+  std::string file_md5;
+  SetUpFile(kFileContent, kFileTitle, &file_resource_id, &file_md5);
+
+  // Since remote file's hash value is different from the expected one, it is
+  // expected to cancel upload the file and to return CONFLICT status code.
+  const std::string kExpectedRemoteFileMD5 = "123456";
+
+  bool done = false;
+  GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
+  std::string resource_id;
+  api_util()->UploadExistingFile(
+      file_resource_id,
+      kExpectedRemoteFileMD5,
+      kLocalFilePath,
+      base::Bind(&DidUploadFile, &done, &error, &resource_id));
+  base::MessageLoop::current()->RunUntilIdle();
+
+  EXPECT_TRUE(done);
+  EXPECT_EQ(google_apis::HTTP_CONFLICT, error);
+  EXPECT_TRUE(resource_id.empty());
+
+  // Verify that there is no duplicated file on the remote side.
+  fake_drive_service()->SearchByTitle(
+      kFileTitle,
+      GetOriginRootResourceId(),
+      base::Bind(&VerifyTitleUniqueness,
+                 FROM_HERE,
+                 file_resource_id,
+                 google_apis::ENTRY_KIND_FILE));
+  base::MessageLoop::current()->RunUntilIdle();
+}
+
+void APIUtilTest::TestDeleteFile() {
+  const std::string kFileContent = "test content";
+  const std::string kFileTitle = "test.txt";
+
+  SetUpSyncRootDirectory();
+  SetUpOriginRootDirectory();
+  std::string file_resource_id;
+  std::string file_md5;
+  SetUpFile(kFileContent, kFileTitle, &file_resource_id, &file_md5);
+
+  bool done = false;
+  GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
+  std::string resource_id;
+  api_util()->DeleteFile(file_resource_id,
+                         file_md5,
+                         base::Bind(&DidDeleteFile, &done, &error));
+  base::MessageLoop::current()->RunUntilIdle();
+
+  EXPECT_TRUE(done);
+  EXPECT_EQ(google_apis::HTTP_SUCCESS, error);
+
+  fake_drive_service()->SearchByTitle(
+      kFileTitle,
+      GetOriginRootResourceId(),
+      base::Bind(&VerifyFileDeletion, FROM_HERE));
+  base::MessageLoop::current()->RunUntilIdle();
+}
+
+void APIUtilTest::TestDeleteFileInConflict() {
+  const std::string kFileContent = "test content";
+  const std::string kFileTitle = "test.txt";
+
+  SetUpSyncRootDirectory();
+  SetUpOriginRootDirectory();
+  std::string file_resource_id;
+  std::string file_md5;
+  SetUpFile(kFileContent, kFileTitle, &file_resource_id, &file_md5);
+
+  // Since remote file's hash value is different from the expected one, it is
+  // expected to cancel delete the file and to return CONFLICT status code.
+  const std::string kExpectedRemoteFileMD5 = "123456";
+
+  bool done = false;
+  GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
+  api_util()->DeleteFile(file_resource_id,
+                         kExpectedRemoteFileMD5,
+                         base::Bind(&DidDeleteFile, &done, &error));
+  base::MessageLoop::current()->RunUntilIdle();
+
+  EXPECT_TRUE(done);
+  EXPECT_EQ(google_apis::HTTP_CONFLICT, error);
+
+  // Verify that the conflict file was not deleted on the remote side.
+  fake_drive_service()->SearchByTitle(
+      kFileTitle,
+      GetOriginRootResourceId(),
+      base::Bind(&VerifyTitleUniqueness,
+                 FROM_HERE,
+                 file_resource_id,
+                 google_apis::ENTRY_KIND_FILE));
+  base::MessageLoop::current()->RunUntilIdle();
+}
+
+void APIUtilTest::TestCreateDirectory() {
+  const std::string kDirectoryTitle("directory");
+
+  SetUpSyncRootDirectory();
+  SetUpOriginRootDirectory();
+
+  bool done = false;
+  GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
+  std::string resource_id;
+  api_util()->CreateDirectory(
+      GetOriginRootResourceId(),
+      kDirectoryTitle,
+      base::Bind(&DidGetResourceID, &done, &error, &resource_id));
+  base::MessageLoop::current()->RunUntilIdle();
+
+  EXPECT_TRUE(done);
+  EXPECT_EQ(google_apis::HTTP_CREATED, error);
+  EXPECT_FALSE(resource_id.empty());
+
+  fake_drive_service()->SearchByTitle(
+      kDirectoryTitle,
+      GetOriginRootResourceId(),
+      base::Bind(&VerifyTitleUniqueness,
+                 FROM_HERE,
+                 resource_id,
+                 google_apis::ENTRY_KIND_FOLDER));
+  base::MessageLoop::current()->RunUntilIdle();
+}
+
+TEST_F(APIUtilTest, GetSyncRoot) {
+  ASSERT_FALSE(IsDriveAPIDisabled());
+  TestGetSyncRoot();
+}
+
+TEST_F(APIUtilTest, GetSyncRoot_WAPI) {
+  ScopedDisableDriveAPI disable_drive_api;
+  TestGetSyncRoot();
+}
+
+TEST_F(APIUtilTest, CreateSyncRoot) {
+  ASSERT_FALSE(IsDriveAPIDisabled());
+  TestCreateSyncRoot();
+}
+
+TEST_F(APIUtilTest, CreateSyncRoot_WAPI) {
+  ScopedDisableDriveAPI disable_drive_api;
+  TestCreateSyncRoot();
+}
+
+TEST_F(APIUtilTest, CreateSyncRoot_Conflict) {
+  ASSERT_FALSE(IsDriveAPIDisabled());
+  TestCreateSyncRoot_Conflict();
+}
+
+TEST_F(APIUtilTest, CreateSyncRoot_Conflict_WAPI) {
+  ScopedDisableDriveAPI disable_drive_api;
+  TestCreateSyncRoot_Conflict();
+}
+
+TEST_F(APIUtilTest, GetOriginDirectory) {
+  ASSERT_FALSE(IsDriveAPIDisabled());
+  TestGetOriginDirectory();
+}
+
+TEST_F(APIUtilTest, GetOriginDirectory_WAPI) {
+  ScopedDisableDriveAPI disable_drive_api;
+  TestGetOriginDirectory();
+}
+
+TEST_F(APIUtilTest, CreateOriginDirectory) {
+  ASSERT_FALSE(IsDriveAPIDisabled());
+  TestCreateOriginDirectory();
+}
+
+TEST_F(APIUtilTest, CreateOriginDirectory_WAPI) {
+  ScopedDisableDriveAPI disable_drive_api;
+  TestCreateOriginDirectory();
+}
+
+TEST_F(APIUtilTest, CreateOriginDirectory_Conflict) {
+  ASSERT_FALSE(IsDriveAPIDisabled());
+  TestCreateOriginDirectory_Conflict();
+}
+
+TEST_F(APIUtilTest, CreateOriginDirectory_Conflict_WAPI) {
+  ScopedDisableDriveAPI disable_drive_api;
+  TestCreateOriginDirectory_Conflict();
+}
+
+TEST_F(APIUtilTest, GetLargestChangeStamp) {
+  ASSERT_FALSE(IsDriveAPIDisabled());
+  TestGetLargestChangeStamp();
+}
+
+TEST_F(APIUtilTest, GetLargestChangeStamp_WAPI) {
+  ScopedDisableDriveAPI disable_drive_api;
+  TestGetLargestChangeStamp();
+}
+
+TEST_F(APIUtilTest, ListFiles) {
+  ASSERT_FALSE(IsDriveAPIDisabled());
+  TestListFiles();
+}
+
+TEST_F(APIUtilTest, ListFiles_WAPI) {
+  ScopedDisableDriveAPI disable_drive_api;
+  TestListFiles();
+}
+
+TEST_F(APIUtilTest, ListChanges) {
+  ASSERT_FALSE(IsDriveAPIDisabled());
+  TestListChanges();
+}
+
+TEST_F(APIUtilTest, ListChanges_WAPI) {
+  ScopedDisableDriveAPI disable_drive_api;
+  TestListChanges();
+}
+
+TEST_F(APIUtilTest, DownloadFile) {
+  ASSERT_FALSE(IsDriveAPIDisabled());
+  TestDownloadFile();
+}
+
+TEST_F(APIUtilTest, DownloadFile_WAPI) {
+  ScopedDisableDriveAPI disable_drive_api;
+  TestDownloadFile();
+}
+
+TEST_F(APIUtilTest, DownloadFileInNotModified) {
+  ASSERT_FALSE(IsDriveAPIDisabled());
+  TestDownloadFileInNotModified();
+}
+
+TEST_F(APIUtilTest, DownloadFileInNotModified_WAPI) {
+  ScopedDisableDriveAPI disable_drive_api;
+  TestDownloadFileInNotModified();
+}
+
+TEST_F(APIUtilTest, UploadNewFile) {
+  ASSERT_FALSE(IsDriveAPIDisabled());
+  TestUploadNewFile();
+}
+
+TEST_F(APIUtilTest, UploadNewFile_WAPI) {
+  ScopedDisableDriveAPI disable_drive_api;
+  TestUploadNewFile();
+}
+
+TEST_F(APIUtilTest, UploadNewFile_ConflictWithFile) {
+  ASSERT_FALSE(IsDriveAPIDisabled());
+  TestUploadNewFile_ConflictWithFile();
+}
+
+TEST_F(APIUtilTest, UploadNewFile_ConflictWithFile_WAPI) {
+  ScopedDisableDriveAPI disable_drive_api;
+  TestUploadNewFile_ConflictWithFile();
+}
+
+TEST_F(APIUtilTest, UploadExistingFile) {
+  ASSERT_FALSE(IsDriveAPIDisabled());
+  TestUploadExistingFile();
+}
+
+TEST_F(APIUtilTest, UploadExistingFile_WAPI) {
+  ScopedDisableDriveAPI disable_drive_api;
+  TestUploadExistingFile();
+}
+
+TEST_F(APIUtilTest, UploadExistingFileInConflict) {
+  ASSERT_FALSE(IsDriveAPIDisabled());
+  TestUploadExistingFileInConflict();
+}
+
+TEST_F(APIUtilTest, UploadExistingFileInConflict_WAPI) {
+  ScopedDisableDriveAPI disable_drive_api;
+  TestUploadExistingFileInConflict();
+}
+
+TEST_F(APIUtilTest, DeleteFile) {
+  ASSERT_FALSE(IsDriveAPIDisabled());
+  TestDeleteFile();
+}
+
+TEST_F(APIUtilTest, DeleteFile_WAPI) {
+  ScopedDisableDriveAPI disable_drive_api;
+  TestDeleteFile();
+}
+
+TEST_F(APIUtilTest, DeleteFileInConflict) {
+  ASSERT_FALSE(IsDriveAPIDisabled());
+  TestDeleteFileInConflict();
+}
+
+TEST_F(APIUtilTest, DeleteFileInConflict_WAPI) {
+  ScopedDisableDriveAPI disable_drive_api;
+  TestDeleteFileInConflict();
+}
+
+TEST_F(APIUtilTest, CreateDirectory) {
+  ASSERT_FALSE(IsDriveAPIDisabled());
+  TestCreateDirectory();
+}
+
+TEST_F(APIUtilTest, CreateDirectory_WAPI) {
+  ScopedDisableDriveAPI disable_drive_api;
+  TestCreateDirectory();
+}
+
+#endif  // !defined(OS_ANDROID)
+
+}  // namespace drive_backend
+}  // namespace sync_file_system
diff --git a/chrome/browser/sync_file_system/drive_backend/fake_api_util.cc b/chrome/browser/sync_file_system/drive_backend/fake_api_util.cc
new file mode 100644
index 0000000..c8e01a1
--- /dev/null
+++ b/chrome/browser/sync_file_system/drive_backend/fake_api_util.cc
@@ -0,0 +1,274 @@
+// 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/fake_api_util.h"
+
+#include <algorithm>
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/message_loop/message_loop_proxy.h"
+#include "chrome/browser/google_apis/drive_entry_kinds.h"
+
+namespace sync_file_system {
+namespace drive_backend {
+
+bool FakeAPIUtil::RemoteResourceComparator::operator()(
+    const RemoteResource& left,
+    const RemoteResource& right) {
+  if (left.parent_resource_id != right.parent_resource_id)
+    return left.parent_resource_id < right.parent_resource_id;
+  if (left.parent_title != right.parent_title)
+    return left.parent_title < right.parent_title;
+  if (left.title != right.title)
+    return left.title < right.title;
+  if (left.resource_id != right.resource_id)
+    return left.resource_id < right.resource_id;
+  if (left.md5_checksum != right.md5_checksum)
+    return left.md5_checksum < right.md5_checksum;
+  if (left.deleted != right.deleted)
+    return left.deleted < right.deleted;
+  return left.changestamp < right.changestamp;
+}
+
+struct FakeAPIUtil::ChangeStampComparator {
+  bool operator()(const google_apis::ResourceEntry* left,
+                  const google_apis::ResourceEntry* right) {
+    return left->changestamp() < right->changestamp();
+  }
+};
+
+FakeAPIUtil::RemoteResource::RemoteResource()
+    : type(SYNC_FILE_TYPE_UNKNOWN), deleted(false), changestamp(0) {}
+
+FakeAPIUtil::RemoteResource::RemoteResource(
+    const std::string& parent_resource_id,
+    const std::string& parent_title,
+    const std::string& title,
+    const std::string& resource_id,
+    const std::string& md5_checksum,
+    SyncFileType type,
+    bool deleted,
+    int64 changestamp)
+    : parent_resource_id(parent_resource_id),
+      parent_title(parent_title),
+      title(title),
+      resource_id(resource_id),
+      md5_checksum(md5_checksum),
+      type(type),
+      deleted(deleted),
+      changestamp(changestamp) {}
+
+FakeAPIUtil::RemoteResource::~RemoteResource() {}
+
+FakeAPIUtil::FakeAPIUtil()
+    : largest_changestamp_(0),
+      url_generator_(
+          GURL(google_apis::GDataWapiUrlGenerator::kBaseUrlForProduction),
+          GURL(google_apis::GDataWapiUrlGenerator::
+               kBaseDownloadUrlForProduction)) {}
+
+FakeAPIUtil::~FakeAPIUtil() {}
+
+void FakeAPIUtil::AddObserver(APIUtilObserver* observer) {}
+
+void FakeAPIUtil::RemoveObserver(APIUtilObserver* observer) {}
+
+void FakeAPIUtil::GetDriveDirectoryForSyncRoot(
+    const ResourceIdCallback& callback) {
+  base::MessageLoopProxy::current()->PostTask(
+      FROM_HERE,
+      base::Bind(callback,
+                 google_apis::HTTP_SUCCESS,
+                 "folder: sync_root_resource_id"));
+}
+
+void FakeAPIUtil::GetDriveDirectoryForOrigin(
+    const std::string& sync_root_resource_id,
+    const GURL& origin,
+    const ResourceIdCallback& callback) {
+  base::MessageLoopProxy::current()->PostTask(
+      FROM_HERE,
+      base::Bind(callback,
+                 google_apis::HTTP_SUCCESS,
+                 "folder resource_id for " + origin.host()));
+}
+
+void FakeAPIUtil::GetLargestChangeStamp(const ChangeStampCallback& callback) {
+  base::MessageLoopProxy::current()->PostTask(
+      FROM_HERE,
+      base::Bind(callback, google_apis::HTTP_SUCCESS, largest_changestamp_));
+}
+
+void FakeAPIUtil::GetResourceEntry(const std::string& resource_id,
+                                   const ResourceEntryCallback& callback) {
+  NOTREACHED();
+}
+
+void FakeAPIUtil::ListFiles(const std::string& directory_resource_id,
+                            const ResourceListCallback& callback) {
+  ListChanges(0, callback);
+}
+
+void FakeAPIUtil::ListChanges(int64 start_changestamp,
+                              const ResourceListCallback& callback) {
+  scoped_ptr<google_apis::ResourceList> change_feed(
+      new google_apis::ResourceList());
+
+  ScopedVector<google_apis::ResourceEntry> entries;
+  typedef RemoteResourceByResourceId::const_iterator iterator;
+  for (iterator itr = remote_resources_.begin();
+       itr != remote_resources_.end(); ++itr) {
+    if (itr->second.changestamp < start_changestamp)
+      continue;
+    scoped_ptr<google_apis::ResourceEntry> entry(
+        CreateResourceEntry(itr->second));
+    entries.push_back(entry.release());
+  }
+
+  std::sort(entries.begin(), entries.end(), ChangeStampComparator());
+
+  change_feed->set_entries(&entries);
+  change_feed->set_largest_changestamp(largest_changestamp_);
+
+  base::MessageLoopProxy::current()->PostTask(
+      FROM_HERE,
+      base::Bind(
+          callback, google_apis::HTTP_SUCCESS, base::Passed(&change_feed)));
+}
+
+void FakeAPIUtil::ContinueListing(const GURL& feed_url,
+                                  const ResourceListCallback& callback) {
+  NOTREACHED();
+}
+
+void FakeAPIUtil::DownloadFile(const std::string& resource_id,
+                               const std::string& local_file_md5,
+                               const base::FilePath& local_file_path,
+                               const DownloadFileCallback& callback) {
+  RemoteResourceByResourceId::iterator found =
+      remote_resources_.find(resource_id);
+  std::string file_md5;
+  int64 file_size = 0;
+  base::Time updated_time;
+  google_apis::GDataErrorCode error = google_apis::HTTP_NOT_FOUND;
+
+  if (found != remote_resources_.end() && !found->second.deleted) {
+    scoped_ptr<google_apis::ResourceEntry> entry(
+        CreateResourceEntry(found->second));
+    file_md5 = entry->file_md5();
+    file_size = entry->file_size();
+    updated_time = entry->updated_time();
+    error = google_apis::HTTP_SUCCESS;
+  }
+
+  base::MessageLoopProxy::current()->PostTask(
+      FROM_HERE,
+      base::Bind(callback, error, file_md5, file_size, updated_time));
+}
+
+void FakeAPIUtil::UploadNewFile(const std::string& directory_resource_id,
+                                const base::FilePath& local_file_path,
+                                const std::string& title,
+                                const UploadFileCallback& callback) {
+  NOTREACHED();
+}
+
+void FakeAPIUtil::UploadExistingFile(const std::string& resource_id,
+                                     const std::string& remote_file_md5,
+                                     const base::FilePath& local_file_path,
+                                     const UploadFileCallback& callback) {
+  NOTREACHED();
+}
+
+void FakeAPIUtil::CreateDirectory(const std::string& parent_resource_id,
+                                  const std::string& title,
+                                  const ResourceIdCallback& callback) {
+  NOTREACHED();
+}
+
+bool FakeAPIUtil::IsAuthenticated() const { return true; }
+
+void FakeAPIUtil::DeleteFile(const std::string& resource_id,
+                             const std::string& remote_file_md5,
+                             const GDataErrorCallback& callback) {
+  if (!ContainsKey(remote_resources_, resource_id)) {
+    base::MessageLoopProxy::current()->PostTask(
+        FROM_HERE,
+        base::Bind(callback, google_apis::HTTP_NOT_FOUND));
+    return;
+  }
+
+  const RemoteResource& deleted_directory = remote_resources_[resource_id];
+  PushRemoteChange(deleted_directory.parent_resource_id,
+                   deleted_directory.parent_title,
+                   deleted_directory.title,
+                   deleted_directory.resource_id,
+                   deleted_directory.md5_checksum,
+                   SYNC_FILE_TYPE_UNKNOWN,
+                   true /* deleted */);
+
+  base::MessageLoopProxy::current()->PostTask(
+      FROM_HERE,
+      base::Bind(callback, google_apis::HTTP_SUCCESS));
+}
+
+GURL FakeAPIUtil::ResourceIdToResourceLink(
+    const std::string& resource_id) const {
+  return url_generator_.GenerateEditUrl(resource_id);
+}
+
+void FakeAPIUtil::EnsureSyncRootIsNotInMyDrive(
+    const std::string& sync_root_resource_id) {
+  // Nothing to do.
+}
+
+void FakeAPIUtil::PushRemoteChange(const std::string& parent_resource_id,
+                                   const std::string& parent_title,
+                                   const std::string& title,
+                                   const std::string& resource_id,
+                                   const std::string& md5,
+                                   SyncFileType type,
+                                   bool deleted) {
+  remote_resources_[resource_id] = RemoteResource(
+      parent_resource_id, parent_title, title, resource_id,
+      md5, type, deleted, ++largest_changestamp_);
+}
+
+scoped_ptr<google_apis::ResourceEntry> FakeAPIUtil::CreateResourceEntry(
+    const RemoteResource& resource) const {
+  scoped_ptr<google_apis::ResourceEntry> entry(
+      new google_apis::ResourceEntry());
+  ScopedVector<google_apis::Link> parent_links;
+  scoped_ptr<google_apis::Link> link(new google_apis::Link());
+
+  link->set_type(google_apis::Link::LINK_PARENT);
+  link->set_href(ResourceIdToResourceLink(resource.parent_resource_id));
+  link->set_title(resource.parent_title);
+  parent_links.push_back(link.release());
+
+  entry->set_links(&parent_links);
+  entry->set_title(resource.title);
+  entry->set_resource_id(resource.resource_id);
+  entry->set_file_md5(resource.md5_checksum);
+  entry->set_deleted(resource.deleted);
+  entry->set_changestamp(resource.changestamp);
+
+  switch (resource.type) {
+    case SYNC_FILE_TYPE_FILE:
+      entry->set_kind(google_apis::ENTRY_KIND_FILE);
+      break;
+    case SYNC_FILE_TYPE_DIRECTORY:
+      entry->set_kind(google_apis::ENTRY_KIND_FOLDER);
+      break;
+    case SYNC_FILE_TYPE_UNKNOWN:
+      entry->set_kind(google_apis::ENTRY_KIND_UNKNOWN);
+      break;
+  }
+
+  return entry.Pass();
+}
+
+}  // namespace drive_backend
+}  // namespace sync_file_system
diff --git a/chrome/browser/sync_file_system/drive_backend/fake_api_util.h b/chrome/browser/sync_file_system/drive_backend/fake_api_util.h
new file mode 100644
index 0000000..52c201e
--- /dev/null
+++ b/chrome/browser/sync_file_system/drive_backend/fake_api_util.h
@@ -0,0 +1,132 @@
+// 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_FAKE_API_UTIL_H_
+#define CHROME_BROWSER_SYNC_FILE_SYSTEM_DRIVE_BACKEND_FAKE_API_UTIL_H_
+
+#include <map>
+#include <string>
+
+#include "chrome/browser/google_apis/drive_api_parser.h"
+#include "chrome/browser/google_apis/gdata_wapi_parser.h"
+#include "chrome/browser/google_apis/gdata_wapi_url_generator.h"
+#include "chrome/browser/sync_file_system/drive_backend/api_util_interface.h"
+#include "webkit/browser/fileapi/syncable/sync_file_type.h"
+
+class GURL;
+class Profile;
+
+namespace google_apis {
+class ResourceEntry;
+}
+
+namespace sync_file_system {
+namespace drive_backend {
+
+class FakeAPIUtil : public APIUtilInterface {
+ public:
+  struct RemoteResource {
+    std::string parent_resource_id;
+    std::string parent_title;
+    std::string title;
+    std::string resource_id;
+    std::string md5_checksum;
+    SyncFileType type;
+    bool deleted;
+    int64 changestamp;
+
+    RemoteResource();
+    RemoteResource(const std::string& parent_resource_id,
+                   const std::string& parent_title,
+                   const std::string& title,
+                   const std::string& resource_id,
+                   const std::string& md5_checksum,
+                   SyncFileType type,
+                   bool deleted,
+                   int64 changestamp);
+    ~RemoteResource();
+  };
+
+  struct RemoteResourceComparator {
+    // Returns lexicographical order referring all members.
+    bool operator()(const RemoteResource& left, const RemoteResource& right);
+  };
+
+  typedef std::map<std::string, RemoteResource> RemoteResourceByResourceId;
+
+  FakeAPIUtil();
+  virtual ~FakeAPIUtil();
+
+  // APIUtilInterface overrides.
+  virtual void AddObserver(APIUtilObserver* observer) OVERRIDE;
+  virtual void RemoveObserver(APIUtilObserver* observer) OVERRIDE;
+  virtual void GetDriveDirectoryForSyncRoot(
+      const ResourceIdCallback& callback) OVERRIDE;
+  virtual void GetDriveDirectoryForOrigin(
+      const std::string& sync_root_resource_id,
+      const GURL& origin,
+      const ResourceIdCallback& callback) OVERRIDE;
+  virtual void GetLargestChangeStamp(
+      const ChangeStampCallback& callback) OVERRIDE;
+  virtual void GetResourceEntry(const std::string& resource_id,
+                                const ResourceEntryCallback& callback) OVERRIDE;
+  virtual void ListFiles(const std::string& directory_resource_id,
+                         const ResourceListCallback& callback) OVERRIDE;
+  virtual void ListChanges(int64 start_changestamp,
+                           const ResourceListCallback& callback) OVERRIDE;
+  virtual void ContinueListing(const GURL& feed_url,
+                               const ResourceListCallback& callback) OVERRIDE;
+  virtual void DownloadFile(const std::string& resource_id,
+                            const std::string& local_file_md5,
+                            const base::FilePath& local_file_path,
+                            const DownloadFileCallback& callback) OVERRIDE;
+  virtual void UploadNewFile(const std::string& directory_resource_id,
+                             const base::FilePath& local_file_path,
+                             const std::string& title,
+                             const UploadFileCallback& callback) OVERRIDE;
+  virtual void UploadExistingFile(const std::string& resource_id,
+                                  const std::string& remote_file_md5,
+                                  const base::FilePath& local_file_path,
+                                  const UploadFileCallback& callback) OVERRIDE;
+  virtual void CreateDirectory(const std::string& parent_resource_id,
+                               const std::string& title,
+                               const ResourceIdCallback& callback) OVERRIDE;
+  virtual bool IsAuthenticated() const OVERRIDE;
+  virtual void DeleteFile(const std::string& resource_id,
+                          const std::string& remote_file_md5,
+                          const GDataErrorCallback& callback) OVERRIDE;
+  virtual GURL ResourceIdToResourceLink(
+      const std::string& resource_id) const OVERRIDE;
+  virtual void EnsureSyncRootIsNotInMyDrive(
+      const std::string& sync_root_resource_id) OVERRIDE;
+
+  void PushRemoteChange(const std::string& parent_resource_id,
+                        const std::string& parent_title,
+                        const std::string& title,
+                        const std::string& resource_id,
+                        const std::string& md5,
+                        SyncFileType type,
+                        bool deleted);
+
+  const RemoteResourceByResourceId& remote_resources() const {
+    return remote_resources_;
+  }
+
+ private:
+  struct ChangeStampComparator;
+  RemoteResourceByResourceId remote_resources_;
+
+  scoped_ptr<google_apis::ResourceEntry> CreateResourceEntry(
+      const RemoteResource& resource_id) const;
+
+  int64 largest_changestamp_;
+  google_apis::GDataWapiUrlGenerator url_generator_;
+
+  DISALLOW_COPY_AND_ASSIGN(FakeAPIUtil);
+};
+
+}  // namespace drive_backend
+}  // namespace sync_file_system
+
+#endif  // CHROME_BROWSER_SYNC_FILE_SYSTEM_DRIVE_BACKEND_FAKE_API_UTIL_H_
diff --git a/chrome/browser/sync_file_system/drive_backend/fake_api_util_unittest.cc b/chrome/browser/sync_file_system/drive_backend/fake_api_util_unittest.cc
new file mode 100644
index 0000000..641505f
--- /dev/null
+++ b/chrome/browser/sync_file_system/drive_backend/fake_api_util_unittest.cc
@@ -0,0 +1,141 @@
+// 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/fake_api_util.h"
+
+#include <string>
+
+#include "base/bind.h"
+#include "base/files/file_path.h"
+#include "base/message_loop.h"
+#include "chrome/browser/google_apis/gdata_errorcode.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace sync_file_system {
+namespace drive_backend {
+
+namespace {
+
+void DidDownloadFile(google_apis::GDataErrorCode* error_out,
+                     std::string* file_md5_out,
+                     google_apis::GDataErrorCode error,
+                     const std::string& file_md5,
+                     int64 file_size,
+                     const base::Time& updated_time) {
+  *error_out = error;
+  *file_md5_out = file_md5;
+}
+
+void DidGetChangeList(google_apis::GDataErrorCode* error_out,
+                      scoped_ptr<google_apis::ResourceList>* change_list_out,
+                      google_apis::GDataErrorCode error,
+                      scoped_ptr<google_apis::ResourceList> change_list) {
+  *error_out = error;
+  *change_list_out = change_list.Pass();
+}
+
+void DidDeleteFile(google_apis::GDataErrorCode* error_out,
+                   google_apis::GDataErrorCode error) {
+  *error_out = error;
+}
+
+}  // namespace
+
+TEST(FakeAPIUtilTest, ChangeSquashTest) {
+  base::MessageLoop message_loop;
+  FakeAPIUtil api_util;
+  std::string kParentResourceId("parent resource id");
+  std::string kParentTitle("app-id");
+  std::string kTitle1("title 1");
+  std::string kTitle2("title 2");
+  std::string kTitle3("title 3");
+  std::string kResourceId1("resource id 1");
+  std::string kResourceId2("resource id 2");
+  std::string kMD5_1("md5 1");
+  std::string kMD5_2("md5 2");
+  std::string kMD5_3("md5 3");
+  base::FilePath kTempFilePath(FILE_PATH_LITERAL("tmp_file"));
+
+  api_util.PushRemoteChange(kParentResourceId,
+                            kParentTitle,
+                            kTitle1,
+                            kResourceId1,
+                            kMD5_1,
+                            SYNC_FILE_TYPE_FILE,
+                            false /* deleted */);
+  api_util.PushRemoteChange(kParentResourceId,
+                            kParentTitle,
+                            kTitle1,
+                            kResourceId1,
+                            kMD5_1,
+                            SYNC_FILE_TYPE_FILE,
+                            false /* deleted */);
+  api_util.PushRemoteChange(kParentResourceId,
+                            kParentTitle,
+                            kTitle1,
+                            kResourceId1,
+                            kMD5_1,
+                            SYNC_FILE_TYPE_FILE,
+                            true /* deleted */);
+  api_util.PushRemoteChange(kParentResourceId,
+                            kParentTitle,
+                            kTitle2,
+                            kResourceId2,
+                            kMD5_2,
+                            SYNC_FILE_TYPE_FILE,
+                            false /* deleted */);
+  api_util.PushRemoteChange(kParentResourceId,
+                            kParentTitle,
+                            kTitle3,
+                            kResourceId2,
+                            kMD5_3,
+                            SYNC_FILE_TYPE_FILE,
+                            false /* deleted */);
+
+  google_apis::GDataErrorCode error;
+  std::string md5;
+  api_util.DownloadFile(kResourceId1,
+                        kMD5_1,
+                        kTempFilePath,
+                        base::Bind(DidDownloadFile, &error, &md5));
+  message_loop.RunUntilIdle();
+  EXPECT_EQ(google_apis::HTTP_NOT_FOUND, error);
+  EXPECT_TRUE(md5.empty());
+
+  scoped_ptr<google_apis::ResourceList> change_list;
+  api_util.ListChanges(0, base::Bind(&DidGetChangeList, &error, &change_list));
+  message_loop.RunUntilIdle();
+  EXPECT_EQ(2u, change_list->entries().size());
+
+  EXPECT_EQ(kResourceId1, change_list->entries()[0]->resource_id());
+  EXPECT_TRUE(change_list->entries()[0]->deleted());
+
+  EXPECT_EQ(kResourceId2, change_list->entries()[1]->resource_id());
+  EXPECT_EQ(kMD5_3, change_list->entries()[1]->file_md5());
+  EXPECT_FALSE(change_list->entries()[1]->deleted());
+}
+
+TEST(FakeAPIUtilTest, DeleteFile) {
+  base::MessageLoop message_loop;
+  FakeAPIUtil api_util;
+  std::string resource_id = "resource_id_to_be_deleted";
+  api_util.PushRemoteChange("parent_id",
+                            "parent_title",
+                            "resource_title",
+                            resource_id,
+                            "resource_md5",
+                            SYNC_FILE_TYPE_FILE,
+                            false /* deleted */);
+
+  google_apis::GDataErrorCode error = google_apis::HTTP_NOT_FOUND;
+  api_util.DeleteFile(
+      resource_id, std::string(), base::Bind(&DidDeleteFile, &error));
+  message_loop.RunUntilIdle();
+
+  EXPECT_EQ(google_apis::HTTP_SUCCESS, error);
+  EXPECT_TRUE(api_util.remote_resources().find(resource_id)->second.deleted);
+}
+
+}  // namespace drive_backend
+}  // namespace sync_file_system
diff --git a/chrome/browser/sync_file_system/drive_backend/fake_drive_service_helper.cc b/chrome/browser/sync_file_system/drive_backend/fake_drive_service_helper.cc
new file mode 100644
index 0000000..89924b9
--- /dev/null
+++ b/chrome/browser/sync_file_system/drive_backend/fake_drive_service_helper.cc
@@ -0,0 +1,313 @@
+// 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/fake_drive_service_helper.h"
+
+#include "base/bind.h"
+#include "base/file_util.h"
+#include "base/message_loop.h"
+#include "base/threading/sequenced_worker_pool.h"
+#include "chrome/browser/sync_file_system/drive_backend/api_util.h"
+#include "content/public/test/test_browser_thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "webkit/browser/fileapi/file_system_url.h"
+#include "webkit/browser/fileapi/syncable/sync_status_code.h"
+
+#define FPL(path) FILE_PATH_LITERAL(path)
+
+using google_apis::GDataErrorCode;
+using google_apis::ResourceEntry;
+using google_apis::ResourceList;
+
+namespace sync_file_system {
+namespace drive_backend {
+
+namespace {
+
+void ResourceEntryResultCallback(GDataErrorCode* error_out,
+                                 scoped_ptr<ResourceEntry>* entry_out,
+                                 GDataErrorCode error,
+                                 scoped_ptr<ResourceEntry> entry) {
+  ASSERT_TRUE(error_out);
+  ASSERT_TRUE(entry_out);
+  *error_out = error;
+  *entry_out = entry.Pass();
+}
+
+void UploadResultCallback(GDataErrorCode* error_out,
+                          scoped_ptr<ResourceEntry>* entry_out,
+                          GDataErrorCode error,
+                          const GURL& upload_location,
+                          scoped_ptr<ResourceEntry> entry) {
+  ASSERT_TRUE(error_out);
+  ASSERT_TRUE(entry_out);
+  *error_out = error;
+  *entry_out = entry.Pass();
+}
+
+void ResourceListResultCallback(GDataErrorCode* error_out,
+                                scoped_ptr<ResourceList>* list_out,
+                                GDataErrorCode error,
+                                scoped_ptr<ResourceList> list) {
+  ASSERT_TRUE(error_out);
+  ASSERT_TRUE(list_out);
+  *error_out = error;
+  *list_out = list.Pass();
+}
+
+void GDataErrorResultCallback(GDataErrorCode* error_out,
+                              GDataErrorCode error) {
+  ASSERT_TRUE(error_out);
+  *error_out = error;
+}
+
+void DownloadResultCallback(GDataErrorCode* error_out,
+                            GDataErrorCode error,
+                            const base::FilePath& local_file) {
+  ASSERT_TRUE(error_out);
+  *error_out = error;
+}
+
+}  // namespace
+
+FakeDriveServiceHelper::FakeDriveServiceHelper(
+    drive::FakeDriveService* fake_drive_service,
+    drive::DriveUploaderInterface* drive_uploader)
+    : fake_drive_service_(fake_drive_service),
+      drive_uploader_(drive_uploader) {
+  Initialize();
+}
+
+FakeDriveServiceHelper::~FakeDriveServiceHelper() {
+}
+
+GDataErrorCode FakeDriveServiceHelper::AddOrphanedFolder(
+    const std::string& title,
+    std::string* folder_id) {
+  EXPECT_TRUE(folder_id);
+
+  std::string root_folder_id = fake_drive_service_->GetRootResourceId();
+  GDataErrorCode error = AddFolder(root_folder_id, title, folder_id);
+  if (error != google_apis::HTTP_CREATED)
+    return error;
+
+  error = google_apis::GDATA_OTHER_ERROR;
+  fake_drive_service_->RemoveResourceFromDirectory(
+      root_folder_id, *folder_id,
+      base::Bind(&GDataErrorResultCallback, &error));
+  FlushMessageLoop();
+
+  if (error != google_apis::HTTP_SUCCESS)
+    return error;
+  return google_apis::HTTP_CREATED;
+}
+
+GDataErrorCode FakeDriveServiceHelper::AddFolder(
+    const std::string& parent_folder_id,
+    const std::string& title,
+    std::string* folder_id) {
+  EXPECT_TRUE(folder_id);
+
+  GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
+  scoped_ptr<ResourceEntry> folder;
+  fake_drive_service_->AddNewDirectory(
+      parent_folder_id, title,
+      base::Bind(&ResourceEntryResultCallback, &error, &folder));
+  FlushMessageLoop();
+
+  if (error == google_apis::HTTP_CREATED)
+    *folder_id = folder->resource_id();
+  return error;
+}
+
+GDataErrorCode FakeDriveServiceHelper::AddFile(
+    const std::string& parent_folder_id,
+    const std::string& title,
+    const std::string& content,
+    std::string* file_id) {
+  EXPECT_TRUE(file_id);
+  base::FilePath temp_file = WriteToTempFile(content);
+
+  GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
+  scoped_ptr<ResourceEntry> file;
+  drive_uploader_->UploadNewFile(
+      parent_folder_id, temp_file, title,
+      "application/octet-stream",
+      base::Bind(&UploadResultCallback, &error, &file),
+      google_apis::ProgressCallback());
+  FlushMessageLoop();
+
+  if (error == google_apis::HTTP_SUCCESS)
+    *file_id = file->resource_id();
+  return error;
+}
+
+GDataErrorCode FakeDriveServiceHelper::UpdateFile(
+    const std::string& file_id,
+    const std::string& content) {
+  base::FilePath temp_file = WriteToTempFile(content);
+  GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
+  scoped_ptr<ResourceEntry> file;
+  drive_uploader_->UploadExistingFile(
+      file_id, temp_file,
+      "application/octet-stream",
+      std::string(),  // etag
+      base::Bind(&UploadResultCallback, &error, &file),
+      google_apis::ProgressCallback());
+  FlushMessageLoop();
+  return error;
+}
+
+GDataErrorCode FakeDriveServiceHelper::RemoveResource(
+    const std::string& file_id) {
+  GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
+  fake_drive_service_->DeleteResource(
+      file_id,
+      std::string(), // etag
+      base::Bind(&GDataErrorResultCallback, &error));
+  FlushMessageLoop();
+  return error;
+}
+
+GDataErrorCode FakeDriveServiceHelper::GetSyncRootFolderID(
+    std::string* sync_root_folder_id) {
+  GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
+  scoped_ptr<ResourceList> resource_list;
+  fake_drive_service_->SearchByTitle(
+      APIUtil::GetSyncRootDirectoryName(), std::string(),
+      base::Bind(&ResourceListResultCallback, &error, &resource_list));
+  FlushMessageLoop();
+  if (error != google_apis::HTTP_SUCCESS)
+    return error;
+
+  const ScopedVector<ResourceEntry>& entries = resource_list->entries();
+  for (ScopedVector<ResourceEntry>::const_iterator itr = entries.begin();
+       itr != entries.end(); ++itr) {
+    const ResourceEntry& entry = **itr;
+    if (!entry.GetLinkByType(google_apis::Link::LINK_PARENT)) {
+      *sync_root_folder_id = entry.resource_id();
+      return google_apis::HTTP_SUCCESS;
+    }
+  }
+  return google_apis::HTTP_NOT_FOUND;
+}
+
+GDataErrorCode FakeDriveServiceHelper::ListFilesInFolder(
+    const std::string& folder_id,
+    ScopedVector<ResourceEntry>* entries) {
+  GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
+  scoped_ptr<ResourceList> list;
+  fake_drive_service_->GetResourceListInDirectory(
+      folder_id,
+      base::Bind(&ResourceListResultCallback, &error, &list));
+  FlushMessageLoop();
+  if (error != google_apis::HTTP_SUCCESS)
+    return error;
+
+  return CompleteListing(list.Pass(), entries);
+}
+
+GDataErrorCode FakeDriveServiceHelper::SearchByTitle(
+    const std::string& folder_id,
+    const std::string& title,
+    ScopedVector<ResourceEntry>* entries) {
+  GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
+  scoped_ptr<ResourceList> list;
+  fake_drive_service_->SearchByTitle(
+      title, folder_id,
+      base::Bind(&ResourceListResultCallback, &error, &list));
+  FlushMessageLoop();
+  if (error != google_apis::HTTP_SUCCESS)
+    return error;
+
+  return CompleteListing(list.Pass(), entries);
+}
+
+GDataErrorCode FakeDriveServiceHelper::GetResourceEntry(
+    const std::string& file_id,
+    scoped_ptr<ResourceEntry>* entry) {
+  GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
+  fake_drive_service_->GetResourceEntry(
+      file_id,
+      base::Bind(&ResourceEntryResultCallback, &error, entry));
+  FlushMessageLoop();
+  return error;
+}
+
+GDataErrorCode FakeDriveServiceHelper::ReadFile(
+    const std::string& file_id,
+    std::string* file_content) {
+  scoped_ptr<google_apis::ResourceEntry> file;
+  GDataErrorCode error = GetResourceEntry(file_id, &file);
+  if (error != google_apis::HTTP_SUCCESS)
+    return error;
+  if (!file)
+    return google_apis::GDATA_PARSE_ERROR;
+
+  error = google_apis::GDATA_OTHER_ERROR;
+  base::FilePath temp_file;
+  EXPECT_TRUE(file_util::CreateTemporaryFileInDir(temp_dir_, &temp_file));
+  fake_drive_service_->DownloadFile(
+      temp_file, file->resource_id(),
+      base::Bind(&DownloadResultCallback, &error),
+      google_apis::GetContentCallback(),
+      google_apis::ProgressCallback());
+  FlushMessageLoop();
+  if (error != google_apis::HTTP_SUCCESS)
+    return error;
+
+  return file_util::ReadFileToString(temp_file, file_content)
+      ? google_apis::HTTP_SUCCESS : google_apis::GDATA_FILE_ERROR;
+}
+
+GDataErrorCode FakeDriveServiceHelper::CompleteListing(
+    scoped_ptr<ResourceList> list,
+    ScopedVector<ResourceEntry>* entries) {
+  while (true) {
+    entries->reserve(entries->size() + list->entries().size());
+    for (ScopedVector<ResourceEntry>::iterator itr =
+         list->mutable_entries()->begin();
+         itr != list->mutable_entries()->end(); ++itr) {
+      entries->push_back(*itr);
+      *itr = NULL;
+    }
+
+    GURL next_feed;
+    if (!list->GetNextFeedURL(&next_feed))
+      return google_apis::HTTP_SUCCESS;
+
+    GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
+    list.reset();
+    fake_drive_service_->ContinueGetResourceList(
+        next_feed,
+        base::Bind(&ResourceListResultCallback, &error, &list));
+    FlushMessageLoop();
+    if (error != google_apis::HTTP_SUCCESS)
+      return error;
+  }
+}
+
+void FakeDriveServiceHelper::Initialize() {
+  ASSERT_TRUE(base_dir_.CreateUniqueTempDir());
+  temp_dir_ = base_dir_.path().Append(FPL("tmp"));
+  ASSERT_TRUE(file_util::CreateDirectory(temp_dir_));
+}
+
+base::FilePath FakeDriveServiceHelper::WriteToTempFile(
+    const std::string& content) {
+  base::FilePath temp_file;
+  EXPECT_TRUE(file_util::CreateTemporaryFileInDir(temp_dir_, &temp_file));
+  EXPECT_EQ(static_cast<int>(content.size()),
+            file_util::WriteFile(temp_file, content.data(), content.size()));
+  return temp_file;
+}
+
+void FakeDriveServiceHelper::FlushMessageLoop() {
+  base::MessageLoop::current()->RunUntilIdle();
+  content::BrowserThread::GetBlockingPool()->FlushForTesting();
+  base::MessageLoop::current()->RunUntilIdle();
+}
+
+}  // namespace drive_backend
+}  // namespace sync_file_system
diff --git a/chrome/browser/sync_file_system/drive_backend/fake_drive_service_helper.h b/chrome/browser/sync_file_system/drive_backend/fake_drive_service_helper.h
new file mode 100644
index 0000000..6e1b6c0
--- /dev/null
+++ b/chrome/browser/sync_file_system/drive_backend/fake_drive_service_helper.h
@@ -0,0 +1,84 @@
+// 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_FAKE_DRIVE_SERVICE_HELPER_H_
+#define CHROME_BROWSER_SYNC_FILE_SYSTEM_DRIVE_BACKEND_FAKE_DRIVE_SERVICE_HELPER_H_
+
+#include <string>
+
+#include "base/files/scoped_temp_dir.h"
+#include "chrome/browser/drive/drive_uploader.h"
+#include "chrome/browser/drive/fake_drive_service.h"
+#include "chrome/browser/google_apis/gdata_wapi_parser.h"
+
+namespace base {
+class FilePath;
+}
+
+namespace sync_file_system {
+namespace drive_backend {
+
+class FakeDriveServiceHelper {
+ public:
+  FakeDriveServiceHelper(drive::FakeDriveService* fake_drive_service,
+                         drive::DriveUploaderInterface* drive_uploader);
+  virtual ~FakeDriveServiceHelper();
+
+  google_apis::GDataErrorCode AddOrphanedFolder(
+      const std::string& title,
+      std::string* folder_id);
+  google_apis::GDataErrorCode AddFolder(
+      const std::string& parent_folder_id,
+      const std::string& title,
+      std::string* folder_id);
+  google_apis::GDataErrorCode AddFile(
+      const std::string& parent_folder_id,
+      const std::string& title,
+      const std::string& content,
+      std::string* file_id);
+  google_apis::GDataErrorCode UpdateFile(
+      const std::string& file_id,
+      const std::string& content);
+  google_apis::GDataErrorCode RemoveResource(
+      const std::string& file_id);
+  google_apis::GDataErrorCode GetSyncRootFolderID(
+      std::string* sync_root_folder_id);
+  google_apis::GDataErrorCode ListFilesInFolder(
+      const std::string& folder_id,
+      ScopedVector<google_apis::ResourceEntry>* entries);
+  google_apis::GDataErrorCode SearchByTitle(
+      const std::string& folder_id,
+      const std::string& title,
+      ScopedVector<google_apis::ResourceEntry>* entries);
+  google_apis::GDataErrorCode GetResourceEntry(
+      const std::string& file_id,
+      scoped_ptr<google_apis::ResourceEntry>* entry);
+  google_apis::GDataErrorCode ReadFile(
+      const std::string& file_id,
+      std::string* file_content);
+
+  base::FilePath base_dir_path() { return base_dir_.path(); }
+
+ private:
+  google_apis::GDataErrorCode CompleteListing(
+      scoped_ptr<google_apis::ResourceList> list,
+      ScopedVector<google_apis::ResourceEntry> * entries);
+
+  void Initialize();
+
+  base::FilePath WriteToTempFile(const std::string& content);
+  void FlushMessageLoop();
+
+  base::ScopedTempDir base_dir_;
+  base::FilePath temp_dir_;
+
+  // Not own.
+  drive::FakeDriveService* fake_drive_service_;
+  drive::DriveUploaderInterface* drive_uploader_;
+};
+
+}  // namespace drive_backend
+}  // namespace sync_file_system
+
+#endif  // CHROME_BROWSER_SYNC_FILE_SYSTEM_DRIVE_BACKEND_FAKE_DRIVE_SERVICE_HELPER_H_
diff --git a/chrome/browser/sync_file_system/drive_backend/local_sync_delegate.cc b/chrome/browser/sync_file_system/drive_backend/local_sync_delegate.cc
new file mode 100644
index 0000000..b85adcd
--- /dev/null
+++ b/chrome/browser/sync_file_system/drive_backend/local_sync_delegate.cc
@@ -0,0 +1,604 @@
+// 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/local_sync_delegate.h"
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "chrome/browser/sync_file_system/conflict_resolution_resolver.h"
+#include "chrome/browser/sync_file_system/drive_backend/api_util.h"
+#include "chrome/browser/sync_file_system/drive_file_sync_service.h"
+#include "chrome/browser/sync_file_system/drive_metadata_store.h"
+#include "chrome/browser/sync_file_system/logger.h"
+#include "webkit/browser/fileapi/syncable/syncable_file_system_util.h"
+
+namespace sync_file_system {
+namespace drive_backend {
+
+LocalSyncDelegate::LocalSyncDelegate(
+    DriveFileSyncService* sync_service,
+    const FileChange& local_change,
+    const base::FilePath& local_path,
+    const SyncFileMetadata& local_metadata,
+    const fileapi::FileSystemURL& url)
+    : sync_service_(sync_service),
+      operation_(SYNC_OPERATION_NONE),
+      url_(url),
+      local_change_(local_change),
+      local_path_(local_path),
+      local_metadata_(local_metadata),
+      has_drive_metadata_(false),
+      has_remote_change_(false),
+      weak_factory_(this) {}
+
+LocalSyncDelegate::~LocalSyncDelegate() {}
+
+void LocalSyncDelegate::Run(const SyncStatusCallback& callback) {
+  // TODO(nhiroki): support directory operations (http://crbug.com/161442).
+  DCHECK(IsSyncFSDirectoryOperationEnabled() || !local_change_.IsDirectory());
+  operation_ = SYNC_OPERATION_NONE;
+
+  has_drive_metadata_ =
+      metadata_store()->ReadEntry(url_, &drive_metadata_) == SYNC_STATUS_OK;
+
+  if (!has_drive_metadata_)
+    drive_metadata_.set_md5_checksum(std::string());
+
+  sync_service_->EnsureOriginRootDirectory(
+      url_.origin(),
+      base::Bind(&LocalSyncDelegate::DidGetOriginRoot,
+                 weak_factory_.GetWeakPtr(),
+                 callback));
+}
+
+void LocalSyncDelegate::DidGetOriginRoot(
+    const SyncStatusCallback& callback,
+    SyncStatusCode status,
+    const std::string& origin_resource_id) {
+  if (status != SYNC_STATUS_OK) {
+    callback.Run(status);
+    return;
+  }
+
+  origin_resource_id_ = origin_resource_id;
+
+  has_remote_change_ =
+      remote_change_handler()->GetChangeForURL(url_, &remote_change_);
+  if (has_remote_change_ && drive_metadata_.resource_id().empty())
+    drive_metadata_.set_resource_id(remote_change_.resource_id);
+
+  SyncFileType remote_file_type =
+      has_remote_change_ ? remote_change_.change.file_type() :
+      has_drive_metadata_ ?
+          DriveFileSyncService::DriveMetadataResourceTypeToSyncFileType(
+              drive_metadata_.type())
+      : SYNC_FILE_TYPE_UNKNOWN;
+
+  DCHECK_EQ(SYNC_OPERATION_NONE, operation_);
+  operation_ = LocalSyncOperationResolver::Resolve(
+      local_change_,
+      has_remote_change_ ? &remote_change_.change : NULL,
+      has_drive_metadata_ ? &drive_metadata_ : NULL);
+
+  util::Log(logging::LOG_VERBOSE, FROM_HERE,
+            "ApplyLocalChange for %s local_change:%s ===> %s",
+            url_.DebugString().c_str(),
+            local_change_.DebugString().c_str(),
+            SyncOperationTypeToString(operation_));
+
+  switch (operation_) {
+    case SYNC_OPERATION_ADD_FILE:
+      UploadNewFile(callback);
+      return;
+    case SYNC_OPERATION_ADD_DIRECTORY:
+      CreateDirectory(callback);
+      return;
+    case SYNC_OPERATION_UPDATE_FILE:
+      UploadExistingFile(callback);
+      return;
+    case SYNC_OPERATION_DELETE:
+      Delete(callback);
+      return;
+    case SYNC_OPERATION_NONE:
+      callback.Run(SYNC_STATUS_OK);
+      return;
+    case SYNC_OPERATION_CONFLICT:
+      HandleConflict(callback);
+      return;
+    case SYNC_OPERATION_RESOLVE_TO_LOCAL:
+      ResolveToLocal(callback);
+      return;
+    case SYNC_OPERATION_RESOLVE_TO_REMOTE:
+      ResolveToRemote(callback, remote_file_type);
+      return;
+    case SYNC_OPERATION_DELETE_METADATA:
+      DeleteMetadata(base::Bind(
+          &LocalSyncDelegate::DidApplyLocalChange,
+          weak_factory_.GetWeakPtr(), callback, google_apis::HTTP_SUCCESS));
+      return;
+    case SYNC_OPERATION_FAIL: {
+      callback.Run(SYNC_STATUS_FAILED);
+      return;
+    }
+  }
+  NOTREACHED();
+  callback.Run(SYNC_STATUS_FAILED);
+}
+
+void LocalSyncDelegate::UploadNewFile(const SyncStatusCallback& callback) {
+  api_util()->UploadNewFile(
+      origin_resource_id_,
+      local_path_,
+      DriveFileSyncService::PathToTitle(url_.path()),
+      base::Bind(&LocalSyncDelegate::DidUploadNewFile,
+                 weak_factory_.GetWeakPtr(), callback));
+}
+
+void LocalSyncDelegate::DidUploadNewFile(
+    const SyncStatusCallback& callback,
+    google_apis::GDataErrorCode error,
+    const std::string& resource_id,
+    const std::string& md5) {
+  switch (error) {
+    case google_apis::HTTP_CREATED:
+      UpdateMetadata(
+          resource_id, md5, DriveMetadata::RESOURCE_TYPE_FILE,
+          base::Bind(&LocalSyncDelegate::DidApplyLocalChange,
+                     weak_factory_.GetWeakPtr(), callback, error));
+      sync_service_->NotifyObserversFileStatusChanged(
+          url_,
+          SYNC_FILE_STATUS_SYNCED,
+          SYNC_ACTION_ADDED,
+          SYNC_DIRECTION_LOCAL_TO_REMOTE);
+      return;
+    case google_apis::HTTP_CONFLICT:
+      HandleCreationConflict(resource_id, DriveMetadata::RESOURCE_TYPE_FILE,
+                             callback);
+      return;
+    default:
+      callback.Run(GDataErrorCodeToSyncStatusCodeWrapper(error));
+  }
+}
+
+void LocalSyncDelegate::CreateDirectory(const SyncStatusCallback& callback) {
+  DCHECK(IsSyncFSDirectoryOperationEnabled());
+  api_util()->CreateDirectory(
+      origin_resource_id_,
+      DriveFileSyncService::PathToTitle(url_.path()),
+      base::Bind(&LocalSyncDelegate::DidCreateDirectory,
+                 weak_factory_.GetWeakPtr(), callback));
+}
+
+void LocalSyncDelegate::DidCreateDirectory(
+    const SyncStatusCallback& callback,
+    google_apis::GDataErrorCode error,
+    const std::string& resource_id) {
+  switch (error) {
+    case google_apis::HTTP_SUCCESS:
+    case google_apis::HTTP_CREATED: {
+      UpdateMetadata(
+          resource_id, std::string(), DriveMetadata::RESOURCE_TYPE_FOLDER,
+          base::Bind(&LocalSyncDelegate::DidApplyLocalChange,
+                     weak_factory_.GetWeakPtr(), callback, error));
+      sync_service_->NotifyObserversFileStatusChanged(
+          url_,
+          SYNC_FILE_STATUS_SYNCED,
+          SYNC_ACTION_ADDED,
+          SYNC_DIRECTION_LOCAL_TO_REMOTE);
+      return;
+    }
+
+    case google_apis::HTTP_CONFLICT:
+      // There were conflicts and a file was left.
+      // TODO(kinuko): Handle the latter case (http://crbug.com/237090).
+      // Fall-through
+
+    default:
+      callback.Run(GDataErrorCodeToSyncStatusCodeWrapper(error));
+  }
+}
+
+void LocalSyncDelegate::UploadExistingFile(const SyncStatusCallback& callback) {
+  DCHECK(has_drive_metadata_);
+  if (drive_metadata_.resource_id().empty()) {
+    UploadNewFile(callback);
+    return;
+  }
+
+  api_util()->UploadExistingFile(
+      drive_metadata_.resource_id(),
+      drive_metadata_.md5_checksum(),
+      local_path_,
+      base::Bind(&LocalSyncDelegate::DidUploadExistingFile,
+                 weak_factory_.GetWeakPtr(), callback));
+}
+
+void LocalSyncDelegate::DidUploadExistingFile(
+    const SyncStatusCallback& callback,
+    google_apis::GDataErrorCode error,
+    const std::string& resource_id,
+    const std::string& md5) {
+  DCHECK(has_drive_metadata_);
+  switch (error) {
+    case google_apis::HTTP_SUCCESS:
+      UpdateMetadata(
+          resource_id, md5, DriveMetadata::RESOURCE_TYPE_FILE,
+          base::Bind(&LocalSyncDelegate::DidApplyLocalChange,
+                     weak_factory_.GetWeakPtr(), callback, error));
+      sync_service_->NotifyObserversFileStatusChanged(
+          url_,
+          SYNC_FILE_STATUS_SYNCED,
+          SYNC_ACTION_UPDATED,
+          SYNC_DIRECTION_LOCAL_TO_REMOTE);
+      return;
+    case google_apis::HTTP_CONFLICT:
+      HandleConflict(callback);
+      return;
+    case google_apis::HTTP_NOT_MODIFIED:
+      DidApplyLocalChange(callback,
+                          google_apis::HTTP_SUCCESS, SYNC_STATUS_OK);
+      return;
+    case google_apis::HTTP_NOT_FOUND:
+      UploadNewFile(callback);
+      return;
+    default: {
+      const SyncStatusCode status =
+          GDataErrorCodeToSyncStatusCodeWrapper(error);
+      DCHECK_NE(SYNC_STATUS_OK, status);
+      callback.Run(status);
+      return;
+    }
+  }
+}
+
+void LocalSyncDelegate::Delete(const SyncStatusCallback& callback) {
+  if (!has_drive_metadata_) {
+    callback.Run(SYNC_STATUS_OK);
+    return;
+  }
+
+  if (drive_metadata_.resource_id().empty()) {
+    DidDelete(callback, google_apis::HTTP_NOT_FOUND);
+    return;
+  }
+
+  api_util()->DeleteFile(
+      drive_metadata_.resource_id(),
+      drive_metadata_.md5_checksum(),
+      base::Bind(&LocalSyncDelegate::DidDelete,
+                 weak_factory_.GetWeakPtr(), callback));
+}
+
+void LocalSyncDelegate::DidDelete(
+    const SyncStatusCallback& callback,
+    google_apis::GDataErrorCode error) {
+  DCHECK(has_drive_metadata_);
+
+  switch (error) {
+    case google_apis::HTTP_SUCCESS:
+    case google_apis::HTTP_NOT_FOUND:
+      DeleteMetadata(base::Bind(
+          &LocalSyncDelegate::DidApplyLocalChange,
+          weak_factory_.GetWeakPtr(), callback, google_apis::HTTP_SUCCESS));
+      sync_service_->NotifyObserversFileStatusChanged(
+          url_,
+          SYNC_FILE_STATUS_SYNCED,
+          SYNC_ACTION_DELETED,
+          SYNC_DIRECTION_LOCAL_TO_REMOTE);
+      return;
+    case google_apis::HTTP_PRECONDITION:
+    case google_apis::HTTP_CONFLICT:
+      // Delete |drive_metadata| on the conflict case.
+      // Conflicted remote change should be applied as a future remote change.
+      DeleteMetadata(base::Bind(
+          &LocalSyncDelegate::DidDeleteMetadataForDeletionConflict,
+          weak_factory_.GetWeakPtr(), callback));
+      sync_service_->NotifyObserversFileStatusChanged(
+          url_,
+          SYNC_FILE_STATUS_SYNCED,
+          SYNC_ACTION_DELETED,
+          SYNC_DIRECTION_LOCAL_TO_REMOTE);
+      return;
+    default: {
+      const SyncStatusCode status =
+          GDataErrorCodeToSyncStatusCodeWrapper(error);
+      DCHECK_NE(SYNC_STATUS_OK, status);
+      callback.Run(status);
+      return;
+    }
+  }
+}
+
+void LocalSyncDelegate::DidDeleteMetadataForDeletionConflict(
+    const SyncStatusCallback& callback,
+    SyncStatusCode status) {
+  callback.Run(SYNC_STATUS_OK);
+}
+
+void LocalSyncDelegate::ResolveToLocal(const SyncStatusCallback& callback) {
+  if (drive_metadata_.resource_id().empty()) {
+    DidDeleteFileToResolveToLocal(callback, google_apis::HTTP_NOT_FOUND);
+    return;
+  }
+
+  api_util()->DeleteFile(
+      drive_metadata_.resource_id(),
+      drive_metadata_.md5_checksum(),
+      base::Bind(
+          &LocalSyncDelegate::DidDeleteFileToResolveToLocal,
+          weak_factory_.GetWeakPtr(), callback));
+}
+
+void LocalSyncDelegate::DidDeleteFileToResolveToLocal(
+    const SyncStatusCallback& callback,
+    google_apis::GDataErrorCode error) {
+  if (error != google_apis::HTTP_SUCCESS &&
+      error != google_apis::HTTP_NOT_FOUND) {
+    callback.Run(GDataErrorCodeToSyncStatusCodeWrapper(error));
+    return;
+  }
+
+  DCHECK_NE(SYNC_FILE_TYPE_UNKNOWN, local_metadata_.file_type);
+  if (local_metadata_.file_type == SYNC_FILE_TYPE_FILE) {
+    UploadNewFile(callback);
+    return;
+  }
+
+  DCHECK(IsSyncFSDirectoryOperationEnabled());
+  DCHECK_EQ(SYNC_FILE_TYPE_DIRECTORY, local_metadata_.file_type);
+  CreateDirectory(callback);
+}
+
+void LocalSyncDelegate::ResolveToRemote(
+    const SyncStatusCallback& callback,
+    SyncFileType remote_file_type) {
+  // Mark the file as to-be-fetched.
+  DCHECK(!drive_metadata_.resource_id().empty());
+
+  SetMetadataToBeFetched(
+      DriveFileSyncService::SyncFileTypeToDriveMetadataResourceType(
+          remote_file_type),
+      base::Bind(&LocalSyncDelegate::DidResolveToRemote,
+                 weak_factory_.GetWeakPtr(), callback));
+  // The synced notification will be dispatched when the remote file is
+  // downloaded.
+}
+
+void LocalSyncDelegate::DidResolveToRemote(
+    const SyncStatusCallback& callback,
+    SyncStatusCode status) {
+  DCHECK(has_drive_metadata_);
+  if (status != SYNC_STATUS_OK) {
+    callback.Run(status);
+    return;
+  }
+
+  SyncFileType file_type = SYNC_FILE_TYPE_FILE;
+  if (drive_metadata_.type() == DriveMetadata::RESOURCE_TYPE_FOLDER)
+    file_type = SYNC_FILE_TYPE_DIRECTORY;
+  sync_service_->AppendFetchChange(
+      url_.origin(), url_.path(), drive_metadata_.resource_id(), file_type);
+  callback.Run(status);
+}
+
+void LocalSyncDelegate::DidApplyLocalChange(
+    const SyncStatusCallback& callback,
+    const google_apis::GDataErrorCode error,
+    SyncStatusCode status) {
+  if ((operation_ == SYNC_OPERATION_DELETE ||
+       operation_ == SYNC_OPERATION_DELETE_METADATA) &&
+      (status == SYNC_FILE_ERROR_NOT_FOUND ||
+       status == SYNC_DATABASE_ERROR_NOT_FOUND)) {
+    status = SYNC_STATUS_OK;
+  }
+
+  if (status == SYNC_STATUS_OK) {
+    remote_change_handler()->RemoveChangeForURL(url_);
+    status = GDataErrorCodeToSyncStatusCodeWrapper(error);
+  }
+  callback.Run(status);
+}
+
+void LocalSyncDelegate::UpdateMetadata(
+    const std::string& resource_id,
+    const std::string& md5,
+    DriveMetadata::ResourceType type,
+    const SyncStatusCallback& callback) {
+  has_drive_metadata_ = true;
+  drive_metadata_.set_resource_id(resource_id);
+  drive_metadata_.set_md5_checksum(md5);
+  drive_metadata_.set_conflicted(false);
+  drive_metadata_.set_to_be_fetched(false);
+  drive_metadata_.set_type(type);
+  metadata_store()->UpdateEntry(url_, drive_metadata_, callback);
+}
+
+void LocalSyncDelegate::ResetMetadataMD5(const SyncStatusCallback& callback) {
+  has_drive_metadata_ = true;
+  drive_metadata_.set_md5_checksum(std::string());
+  metadata_store()->UpdateEntry(url_, drive_metadata_, callback);
+}
+
+void LocalSyncDelegate::SetMetadataToBeFetched(
+    DriveMetadata::ResourceType type,
+    const SyncStatusCallback& callback) {
+  has_drive_metadata_ = true;
+  drive_metadata_.set_md5_checksum(std::string());
+  drive_metadata_.set_conflicted(false);
+  drive_metadata_.set_to_be_fetched(true);
+  drive_metadata_.set_type(type);
+  metadata_store()->UpdateEntry(url_, drive_metadata_, callback);
+}
+
+void LocalSyncDelegate::SetMetadataConflict(
+    const SyncStatusCallback& callback) {
+  has_drive_metadata_ = true;
+  drive_metadata_.set_conflicted(true);
+  drive_metadata_.set_to_be_fetched(false);
+  metadata_store()->UpdateEntry(url_, drive_metadata_, callback);
+}
+
+void LocalSyncDelegate::DeleteMetadata(const SyncStatusCallback& callback) {
+  metadata_store()->DeleteEntry(url_, callback);
+}
+
+void LocalSyncDelegate::HandleCreationConflict(
+    const std::string& resource_id,
+    DriveMetadata::ResourceType type,
+    const SyncStatusCallback& callback) {
+  // File-file conflict is found.
+  // Populates a fake drive_metadata and set has_drive_metadata = true.
+  // In HandleConflictLocalSync:
+  // - If conflict_resolution is manual, we'll change conflicted to true
+  //   and save the metadata.
+  // - Otherwise we'll save the metadata with empty md5 and will start
+  //   over local sync as UploadExistingFile.
+  drive_metadata_.set_resource_id(resource_id);
+  drive_metadata_.set_md5_checksum(std::string());
+  drive_metadata_.set_conflicted(false);
+  drive_metadata_.set_to_be_fetched(false);
+  drive_metadata_.set_type(type);
+  has_drive_metadata_ = true;
+  HandleConflict(callback);
+}
+
+void LocalSyncDelegate::HandleConflict(const SyncStatusCallback& callback) {
+  DCHECK(!drive_metadata_.resource_id().empty());
+  api_util()->GetResourceEntry(
+      drive_metadata_.resource_id(),
+      base::Bind(
+          &LocalSyncDelegate::DidGetEntryForConflictResolution,
+          weak_factory_.GetWeakPtr(), callback));
+}
+
+void LocalSyncDelegate::DidGetEntryForConflictResolution(
+    const SyncStatusCallback& callback,
+    google_apis::GDataErrorCode error,
+    scoped_ptr<google_apis::ResourceEntry> entry) {
+  SyncFileType remote_file_type = SYNC_FILE_TYPE_UNKNOWN;
+  ConflictResolution resolution = CONFLICT_RESOLUTION_UNKNOWN;
+
+  if (error != google_apis::HTTP_SUCCESS ||
+      entry->updated_time().is_null()) {
+    resolution = CONFLICT_RESOLUTION_LOCAL_WIN;
+  } else {
+    SyncFileType local_file_type = local_metadata_.file_type;
+    base::Time local_modification_time = local_metadata_.last_modified;
+    base::Time remote_modification_time = entry->updated_time();
+    if (entry->is_file())
+      remote_file_type = SYNC_FILE_TYPE_FILE;
+    else if (entry->is_folder())
+      remote_file_type = SYNC_FILE_TYPE_DIRECTORY;
+    else
+      remote_file_type = SYNC_FILE_TYPE_UNKNOWN;
+
+    resolution = conflict_resolution_resolver()->Resolve(
+        local_file_type, local_modification_time,
+        remote_file_type, remote_modification_time);
+  }
+
+  switch (resolution) {
+    case CONFLICT_RESOLUTION_MARK_CONFLICT:
+      HandleManualResolutionCase(callback);
+      return;
+    case CONFLICT_RESOLUTION_LOCAL_WIN:
+      HandleLocalWinCase(callback);
+      return;
+    case CONFLICT_RESOLUTION_REMOTE_WIN:
+      HandleRemoteWinCase(callback, remote_file_type);
+      return;
+    case CONFLICT_RESOLUTION_UNKNOWN:
+      NOTREACHED();
+  }
+  NOTREACHED();
+  callback.Run(SYNC_STATUS_FAILED);
+}
+
+void LocalSyncDelegate::HandleManualResolutionCase(
+    const SyncStatusCallback& callback) {
+  if (drive_metadata_.conflicted()) {
+    callback.Run(SYNC_STATUS_HAS_CONFLICT);
+    return;
+  }
+
+  SetMetadataConflict(base::Bind(&LocalSyncDelegate::NotifyConflict,
+                                 weak_factory_.GetWeakPtr(), callback));
+}
+
+void LocalSyncDelegate::NotifyConflict(const SyncStatusCallback& callback,
+                                       SyncStatusCode status) {
+  if (status != SYNC_STATUS_OK) {
+    callback.Run(status);
+    return;
+  }
+
+  sync_service_->NotifyObserversFileStatusChanged(
+      url_,
+      SYNC_FILE_STATUS_CONFLICTING,
+      SYNC_ACTION_NONE,
+      SYNC_DIRECTION_NONE);
+
+  DidApplyLocalChange(callback, google_apis::HTTP_CONFLICT, status);
+}
+
+void LocalSyncDelegate::HandleLocalWinCase(
+    const SyncStatusCallback& callback) {
+  util::Log(logging::LOG_VERBOSE, FROM_HERE,
+            "Resolving conflict for local sync: %s: LOCAL WIN",
+            url_.DebugString().c_str());
+
+  DCHECK(!drive_metadata_.resource_id().empty());
+  if (!has_drive_metadata_) {
+    StartOver(callback, SYNC_STATUS_OK);
+    return;
+  }
+
+  ResetMetadataMD5(base::Bind(&LocalSyncDelegate::StartOver,
+                              weak_factory_.GetWeakPtr(), callback));
+}
+
+void LocalSyncDelegate::HandleRemoteWinCase(
+    const SyncStatusCallback& callback,
+    SyncFileType remote_file_type) {
+  util::Log(logging::LOG_VERBOSE, FROM_HERE,
+            "Resolving conflict for local sync: %s: REMOTE WIN",
+            url_.DebugString().c_str());
+  ResolveToRemote(callback, remote_file_type);
+}
+
+void LocalSyncDelegate::StartOver(const SyncStatusCallback& callback,
+                                             SyncStatusCode status) {
+  if (status != SYNC_STATUS_OK) {
+    callback.Run(status);
+    return;
+  }
+
+  remote_change_handler()->RemoveChangeForURL(url_);
+  Run(callback);
+}
+
+SyncStatusCode
+LocalSyncDelegate::GDataErrorCodeToSyncStatusCodeWrapper(
+    google_apis::GDataErrorCode error) {
+  return sync_service_->GDataErrorCodeToSyncStatusCodeWrapper(error);
+}
+
+DriveMetadataStore* LocalSyncDelegate::metadata_store() {
+  return sync_service_->metadata_store_.get();
+}
+
+APIUtilInterface* LocalSyncDelegate::api_util() {
+  return sync_service_->api_util_.get();
+}
+
+RemoteChangeHandler* LocalSyncDelegate::remote_change_handler() {
+  return &sync_service_->remote_change_handler_;
+}
+
+ConflictResolutionResolver* LocalSyncDelegate::conflict_resolution_resolver() {
+  return &sync_service_->conflict_resolution_resolver_;
+}
+
+}  // namespace drive_backend
+}  // namespace sync_file_system
diff --git a/chrome/browser/sync_file_system/drive_backend/local_sync_delegate.h b/chrome/browser/sync_file_system/drive_backend/local_sync_delegate.h
new file mode 100644
index 0000000..6ba2089
--- /dev/null
+++ b/chrome/browser/sync_file_system/drive_backend/local_sync_delegate.h
@@ -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.
+
+#ifndef CHROME_BROWSER_SYNC_FILE_SYSTEM_DRIVE_BACKEND_LOCAL_SYNC_DELEGATE_H_
+#define CHROME_BROWSER_SYNC_FILE_SYSTEM_DRIVE_BACKEND_LOCAL_SYNC_DELEGATE_H_
+
+#include "base/callback.h"
+#include "base/memory/weak_ptr.h"
+#include "chrome/browser/sync_file_system/drive_file_sync_service.h"
+#include "chrome/browser/sync_file_system/sync_file_system.pb.h"
+#include "webkit/browser/fileapi/file_system_url.h"
+#include "webkit/browser/fileapi/syncable/file_change.h"
+#include "webkit/browser/fileapi/syncable/sync_callbacks.h"
+#include "webkit/browser/fileapi/syncable/sync_file_metadata.h"
+
+namespace sync_file_system {
+
+class ConflictResolutionResolver;
+class DriveMetadataStore;
+
+namespace drive_backend {
+
+class APIUtil;
+
+// This class handles ApplyLocalChange in LocalChangeProcessor, and its instance
+// represents single ApplyLocalChange operation.
+// The caller is responsible to own the instance, and can cancel operation by
+// deleting the instance or |sync_service|.
+class LocalSyncDelegate {
+ public:
+  typedef RemoteChangeHandler::RemoteChange RemoteChange;
+
+  LocalSyncDelegate(DriveFileSyncService* sync_service,
+                    const FileChange& change,
+                    const base::FilePath& local_file_path,
+                    const SyncFileMetadata& local_file_metadata,
+                    const fileapi::FileSystemURL& url);
+  ~LocalSyncDelegate();
+
+  void Run(const SyncStatusCallback& callback);
+
+ private:
+  void DidGetOriginRoot(const SyncStatusCallback& callback,
+                        SyncStatusCode status,
+                        const std::string& resource_id);
+  void UploadNewFile(const SyncStatusCallback& callback);
+  void DidUploadNewFile(const SyncStatusCallback& callback,
+                        google_apis::GDataErrorCode error,
+                        const std::string& resource_id,
+                        const std::string& md5);
+  void CreateDirectory(const SyncStatusCallback& callback);
+  void DidCreateDirectory(
+      const SyncStatusCallback& callback,
+      google_apis::GDataErrorCode error,
+      const std::string& resource_id);
+  void UploadExistingFile(const SyncStatusCallback& callback);
+  void DidUploadExistingFile(
+      const SyncStatusCallback& callback,
+      google_apis::GDataErrorCode error,
+      const std::string& resource_id,
+      const std::string& md5);
+  void Delete(const SyncStatusCallback& callback);
+  void DidDelete(const SyncStatusCallback& callback,
+                 google_apis::GDataErrorCode error);
+  void DidDeleteMetadataForDeletionConflict(
+      const SyncStatusCallback& callback,
+      SyncStatusCode status);
+  void ResolveToLocal(const SyncStatusCallback& callback);
+  void DidDeleteFileToResolveToLocal(
+      const SyncStatusCallback& callback,
+      google_apis::GDataErrorCode error);
+  void ResolveToRemote(const SyncStatusCallback& callback,
+                       SyncFileType remote_file_type);
+  void DidResolveToRemote(const SyncStatusCallback& callback,
+                          SyncStatusCode status);
+  void DidApplyLocalChange(
+      const SyncStatusCallback& callback,
+      const google_apis::GDataErrorCode error,
+      SyncStatusCode status);
+
+  // Metadata manipulation.
+  void UpdateMetadata(const std::string& resource_id,
+                      const std::string& md5,
+                      DriveMetadata::ResourceType type,
+                      const SyncStatusCallback& callback);
+  void ResetMetadataMD5(const SyncStatusCallback& callback);
+  void SetMetadataToBeFetched(DriveMetadata::ResourceType type,
+                              const SyncStatusCallback& callback);
+  void DeleteMetadata(const SyncStatusCallback& callback);
+  void SetMetadataConflict(const SyncStatusCallback& callback);
+
+  // Conflict handling.
+  void HandleCreationConflict(
+      const std::string& resource_id,
+      DriveMetadata::ResourceType type,
+      const SyncStatusCallback& callback);
+  void HandleConflict(const SyncStatusCallback& callback);
+  void DidGetEntryForConflictResolution(
+      const SyncStatusCallback& callback,
+      google_apis::GDataErrorCode error,
+      scoped_ptr<google_apis::ResourceEntry> entry);
+
+  void HandleManualResolutionCase(const SyncStatusCallback& callback);
+  void NotifyConflict(const SyncStatusCallback& callback,
+                      SyncStatusCode status);
+
+  void HandleLocalWinCase(const SyncStatusCallback& callback);
+  void HandleRemoteWinCase(const SyncStatusCallback& callback,
+                           SyncFileType remote_file_type);
+  void StartOver(const SyncStatusCallback& callback, SyncStatusCode status);
+
+  SyncStatusCode GDataErrorCodeToSyncStatusCodeWrapper(
+      google_apis::GDataErrorCode error);
+
+  DriveMetadataStore* metadata_store();
+  APIUtilInterface* api_util();
+  RemoteChangeHandler* remote_change_handler();
+  ConflictResolutionResolver* conflict_resolution_resolver();
+
+  DriveFileSyncService* sync_service_;  // Not owned.
+
+  SyncOperationType operation_;
+
+  fileapi::FileSystemURL url_;
+  FileChange local_change_;
+  base::FilePath local_path_;
+  SyncFileMetadata local_metadata_;
+  DriveMetadata drive_metadata_;
+  bool has_drive_metadata_;
+  RemoteChange remote_change_;
+  bool has_remote_change_;
+
+  std::string origin_resource_id_;
+
+  base::WeakPtrFactory<LocalSyncDelegate> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(LocalSyncDelegate);
+};
+
+}  // namespace drive_backend
+}  // namespace sync_file_system
+
+#endif  // CHROME_BROWSER_SYNC_FILE_SYSTEM_DRIVE_BACKEND_LOCAL_SYNC_DELEGATE_H_
diff --git a/chrome/browser/sync_file_system/drive_backend/metadata_database.cc b/chrome/browser/sync_file_system/drive_backend/metadata_database.cc
new file mode 100644
index 0000000..6e52b51
--- /dev/null
+++ b/chrome/browser/sync_file_system/drive_backend/metadata_database.cc
@@ -0,0 +1,105 @@
+// 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/metadata_database.h"
+
+#include "chrome/browser/google_apis/drive_api_parser.h"
+
+namespace sync_file_system {
+namespace drive_backend {
+
+MetadataDatabase::MetadataDatabase(base::SequencedTaskRunner* task_runner) {
+  NOTIMPLEMENTED();
+}
+
+MetadataDatabase::~MetadataDatabase() {
+}
+
+void MetadataDatabase::Initialize(const base::FilePath& database_dir,
+                                  const SyncStatusCallback& callback) {
+  NOTIMPLEMENTED();
+}
+
+int64 MetadataDatabase::GetLargestChangeID() const {
+  NOTIMPLEMENTED();
+  return 0;
+}
+
+void MetadataDatabase::RegisterApp(const std::string& app_id,
+                                   const std::string& folder_id,
+                                   const SyncStatusCallback& callback) {
+  NOTIMPLEMENTED();
+}
+
+void MetadataDatabase::DisableApp(const std::string& app_id,
+                                 const SyncStatusCallback& callback) {
+  NOTIMPLEMENTED();
+}
+
+void MetadataDatabase::EnableApp(const std::string& app_id,
+                                 const SyncStatusCallback& callback) {
+  NOTIMPLEMENTED();
+}
+
+void MetadataDatabase::UnregisterApp(const std::string& app_id,
+                                     const SyncStatusCallback& callback) {
+  NOTIMPLEMENTED();
+}
+
+bool MetadataDatabase::FindAppRootFolder(const std::string& app_id,
+                                         DriveFileMetadata* folder) const {
+  NOTIMPLEMENTED();
+  return false;
+}
+
+bool MetadataDatabase::FindFileByFileID(const std::string& file_id,
+                                        DriveFileMetadata* metadata) const {
+  NOTIMPLEMENTED();
+  return false;
+}
+
+size_t MetadataDatabase::FindFilesByParentAndTitle(
+    const std::string& file_id,
+    const std::string& title,
+    ScopedVector<DriveFileMetadata>* files) const {
+  NOTIMPLEMENTED();
+  return 0;
+}
+
+bool MetadataDatabase::FindActiveFileByParentAndTitle(
+    const std::string& folder_id,
+    const std::string& title,
+    DriveFileMetadata* file) const {
+  NOTIMPLEMENTED();
+  return false;
+}
+
+bool MetadataDatabase::FindActiveFileByPath(const std::string& app_id,
+                                            const base::FilePath& path,
+                                            DriveFileMetadata* file) const {
+  NOTIMPLEMENTED();
+  return false;
+}
+
+bool MetadataDatabase::ConstructPathForFile(const std::string& file_id,
+                                            base::FilePath* path) const {
+  NOTIMPLEMENTED();
+  return false;
+}
+
+void MetadataDatabase::UpdateByChangeList(
+    ScopedVector<google_apis::ChangeResource> changes,
+    const SyncStatusCallback& callback) {
+  NOTIMPLEMENTED();
+}
+
+void MetadataDatabase::PopulateFolder(
+    const std::string& folder_id,
+    ScopedVector<google_apis::ResourceEntry> children,
+    const SyncStatusCallback& callback) {
+  NOTIMPLEMENTED();
+}
+
+}  // namespace drive_backend
+}  // namespace sync_file_system
diff --git a/chrome/browser/sync_file_system/drive_backend/metadata_database.h b/chrome/browser/sync_file_system/drive_backend/metadata_database.h
new file mode 100644
index 0000000..967950a
--- /dev/null
+++ b/chrome/browser/sync_file_system/drive_backend/metadata_database.h
@@ -0,0 +1,133 @@
+// 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_METADATA_DATABASE_H_
+#define CHROME_BROWSER_SYNC_FILE_SYSTEM_DRIVE_BACKEND_METADATA_DATABASE_H_
+
+#include "base/callback_forward.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/scoped_vector.h"
+#include "webkit/browser/fileapi/syncable/sync_callbacks.h"
+#include "webkit/browser/fileapi/syncable/sync_status_code.h"
+
+namespace base {
+class FilePath;
+class SequencedTaskRunner;
+}
+
+namespace leveldb {
+class DB;
+class WriteBatch;
+}
+
+namespace google_apis {
+class ChangeResource;
+class FileResource;
+class ResourceEntry;
+}
+
+namespace sync_file_system {
+namespace drive_backend {
+
+class ServiceMetadata;
+class DriveFileMetadata;
+struct InitializeInfo;
+
+// This class holds a snapshot of the server side metadata.
+class MetadataDatabase {
+ public:
+  explicit MetadataDatabase(base::SequencedTaskRunner* task_runner);
+  ~MetadataDatabase();
+
+  // Initializes the internal database and loads its content to memory.
+  // This function works asynchronously.
+  void Initialize(const base::FilePath& database_path,
+                  const SyncStatusCallback& callback);
+
+  int64 GetLargestChangeID() const;
+
+  // Registers existing folder as the app-root for |app_id|.  The folder
+  // must be an inactive folder that does not yet associated to any App.
+  // This method associates the folder with |app_id| and activates it.
+  void RegisterApp(const std::string& app_id,
+                   const std::string& folder_id,
+                   const SyncStatusCallback& callback);
+
+  // Inactivates the folder associated to the app to disable |app_id|.
+  // Does nothing if |app_id| is already disabled.
+  void DisableApp(const std::string& app_id,
+                  const SyncStatusCallback& callback);
+
+  // Activates the folder associated to |app_id| to enable |app_id|.
+  // Does nothing if |app_id| is already enabled.
+  void EnableApp(const std::string& app_id,
+                 const SyncStatusCallback& callback);
+
+  // Unregister the folder as the app-root for |app_id|.  If |app_id| does not
+  // exist, does nothing.
+  void UnregisterApp(const std::string& app_id,
+                     const SyncStatusCallback& callback);
+
+  // Finds the app-root folder for |app_id|.  Returns true if exists.
+  // Copies the result to |folder| if it is non-NULL.
+  bool FindAppRootFolder(const std::string& app_id,
+                         DriveFileMetadata* folder) const;
+
+  // Finds file by |file_id|.  Returns true if the file was found.
+  // Copies the DriveFileMetadata instance identified by |file_id| into
+  // |file| if exists and |file| is non-NULL.
+  bool FindFileByFileID(const std::string& file_id,
+                        DriveFileMetadata* file) const;
+
+  // Finds files by |title| under the folder identified by |folder_id|, and
+  // returns the number of the files.
+  // Copies the DriveFileMetadata instances to |files| if it is non-NULL.
+  size_t FindFilesByParentAndTitle(
+      const std::string& folder_id,
+      const std::string& title,
+      ScopedVector<DriveFileMetadata>* files) const;
+
+  // Finds active file by |title| under the folder identified by |folder_id|.
+  // Returns true if the file exists.
+  bool FindActiveFileByParentAndTitle(
+      const std::string& folder_id,
+      const std::string& title,
+      DriveFileMetadata* file) const;
+
+  // Finds the active file identified by |app_id| and |path|, which must be
+  // unique.  Returns true if the file was found.
+  // Copies the DriveFileMetadata instance into |file| if the file is found and
+  // |file| is non-NULL.
+  // |path| must be an absolute path in |app_id|. (i.e. relative to the app-root
+  // folder.)
+  bool FindActiveFileByPath(const std::string& app_id,
+                            const base::FilePath& path,
+                            DriveFileMetadata* file) const;
+
+  // Looks up FilePath from FileID.  Returns true on success.
+  // |path| must be non-NULL.
+  bool ConstructPathForFile(const std::string& file_id,
+                            base::FilePath* path) const;
+
+  // Updates database by |changes|.
+  // Marks dirty for each changed file if the file has the metadata in the
+  // database.  Adds new metadata to track the file if the file doesn't have
+  // the metadata and its parent folder has the active metadata.
+  void UpdateByChangeList(ScopedVector<google_apis::ChangeResource> changes,
+                          const SyncStatusCallback& callback);
+
+  // Populates |folder| with |children|.  Each |children| initially has empty
+  // |synced_details| and |remote_details|.
+  void PopulateFolder(const std::string& folder_id,
+                      ScopedVector<google_apis::ResourceEntry> children,
+                      const SyncStatusCallback& callback);
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MetadataDatabase);
+};
+
+}  // namespace drive_backend
+}  // namespace sync_file_system
+
+#endif  // CHROME_BROWSER_SYNC_FILE_SYSTEM_DRIVE_BACKEND_METADATA_DATABASE_H_
diff --git a/chrome/browser/sync_file_system/drive_backend/metadata_database.proto b/chrome/browser/sync_file_system/drive_backend/metadata_database.proto
new file mode 100644
index 0000000..05a9c81
--- /dev/null
+++ b/chrome/browser/sync_file_system/drive_backend/metadata_database.proto
@@ -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.
+//
+// Protocol buffer definitions for Drive backend of Syncable FileSystem.
+
+syntax = "proto2";
+
+option optimize_for = LITE_RUNTIME;
+
+package sync_file_system.drive_backend;
+
+enum FileKind {
+  KIND_UNSUPPORTED = 0;
+  KIND_FILE = 1;
+  KIND_FOLDER = 2;
+}
+
+message ServiceMetadata {
+  optional int64 largest_change_id = 1 [default = 0];
+  optional string sync_root_folder_id = 2;
+}
+
+message DriveFileMetadata {
+  // File ID of the remote file/folder which the DriveFileMetadata tracks.
+  required string file_id = 1;
+  required string parent_folder_id = 2;
+
+  optional string app_id = 3;
+  optional bool is_app_root = 4;
+
+  // Holds details of file/folder metadata.
+  message Details {
+    repeated string parent_folder_id = 1;
+    optional string title = 2;
+    optional FileKind kind = 3;
+    optional string md5 = 4;
+    optional string etag = 5;
+
+    // Creation time and modification time of the resource.
+    // Serialized by Time::ToInternalValue.
+    optional int64 creation_time = 6;
+    optional int64 modification_time = 7;
+
+    optional bool deleted = 8;
+    optional int64 change_id = 9;
+  }
+
+  // |synced_details| holds the file details snapshot when the file was
+  // fetched through remote-to-local update.
+  // This should contain same value as remote_details if |dirty| is false.
+  optional Details synced_details = 5;
+
+  // |remote_details| holds the latest file details that may not yet be
+  // applied to local metadata.
+  // This should be updated by each listed ChangeResource.
+  optional Details remote_details = 6;
+
+  // True if the file is changed since the last update for this file.
+  optional bool dirty = 7;
+
+  // True if the DriveFileMetadata is active.
+  // Remote file content update should only be applied for active
+  // DriveFileMetadata.
+  // Active DriveFileMetadata must have a unique title under its parent.
+  optional bool active = 8;
+
+  // Valid only for folders.
+  // True indicates the folder contents has not yet been fetched.
+  optional bool needs_folder_listing = 9;
+}
diff --git a/chrome/browser/sync_file_system/drive_backend/metadata_db_migration_util.cc b/chrome/browser/sync_file_system/drive_backend/metadata_db_migration_util.cc
new file mode 100644
index 0000000..d7dda53
--- /dev/null
+++ b/chrome/browser/sync_file_system/drive_backend/metadata_db_migration_util.cc
@@ -0,0 +1,251 @@
+// 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/metadata_db_migration_util.h"
+
+#include "base/files/file_path.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string_util.h"
+#include "third_party/leveldatabase/src/include/leveldb/write_batch.h"
+#include "url/gurl.h"
+#include "webkit/browser/fileapi/file_system_url.h"
+#include "webkit/common/fileapi/file_system_types.h"
+
+namespace sync_file_system {
+namespace drive_backend {
+
+namespace {
+
+const base::FilePath::CharType kV0FormatPathPrefix[] =
+    FILE_PATH_LITERAL("drive/");
+const char kWapiFileIdPrefix[] = "file:";
+const char kWapiFolderIdPrefix[] = "folder:";
+
+std::string RemovePrefix(const std::string& str, const std::string& prefix) {
+  if (StartsWithASCII(str, prefix, true))
+    return std::string(str.begin() + prefix.size(), str.end());
+  return str;
+}
+
+}  // namespace
+
+bool ParseV0FormatFileSystemURL(const GURL& url,
+                                GURL* origin,
+                                base::FilePath* path) {
+  fileapi::FileSystemType mount_type;
+  base::FilePath virtual_path;
+
+  if (!fileapi::FileSystemURL::ParseFileSystemSchemeURL(
+          url, origin, &mount_type, &virtual_path) ||
+      mount_type != fileapi::kFileSystemTypeExternal) {
+    NOTREACHED() << "Failed to parse filesystem scheme URL " << url.spec();
+    return false;
+  }
+
+  base::FilePath::StringType prefix =
+      base::FilePath(kV0FormatPathPrefix).NormalizePathSeparators().value();
+  if (virtual_path.value().substr(0, prefix.size()) != prefix)
+    return false;
+
+  *path = base::FilePath(virtual_path.value().substr(prefix.size()));
+  return true;
+}
+
+std::string AddWapiFilePrefix(const std::string& resource_id) {
+  DCHECK(!StartsWithASCII(resource_id, kWapiFileIdPrefix, true));
+  DCHECK(!StartsWithASCII(resource_id, kWapiFolderIdPrefix, true));
+
+  if (resource_id.empty() ||
+      StartsWithASCII(resource_id, kWapiFileIdPrefix, true) ||
+      StartsWithASCII(resource_id, kWapiFolderIdPrefix, true))
+    return resource_id;
+  return kWapiFileIdPrefix + resource_id;
+}
+
+std::string AddWapiFolderPrefix(const std::string& resource_id) {
+  DCHECK(!StartsWithASCII(resource_id, kWapiFileIdPrefix, true));
+  DCHECK(!StartsWithASCII(resource_id, kWapiFolderIdPrefix, true));
+
+  if (resource_id.empty() ||
+      StartsWithASCII(resource_id, kWapiFileIdPrefix, true) ||
+      StartsWithASCII(resource_id, kWapiFolderIdPrefix, true))
+    return resource_id;
+  return kWapiFolderIdPrefix + resource_id;
+}
+
+std::string AddWapiIdPrefix(const std::string& resource_id,
+                            DriveMetadata_ResourceType type) {
+  switch (type) {
+    case DriveMetadata_ResourceType_RESOURCE_TYPE_FILE:
+      return AddWapiFilePrefix(resource_id);
+    case DriveMetadata_ResourceType_RESOURCE_TYPE_FOLDER:
+      return AddWapiFolderPrefix(resource_id);
+  }
+  NOTREACHED();
+  return resource_id;
+}
+
+std::string RemoveWapiIdPrefix(const std::string& resource_id) {
+  if (StartsWithASCII(resource_id, kWapiFileIdPrefix, true))
+    return RemovePrefix(resource_id, kWapiFileIdPrefix);
+  if (StartsWithASCII(resource_id, kWapiFolderIdPrefix, true))
+    return RemovePrefix(resource_id, kWapiFolderIdPrefix);
+  return resource_id;
+}
+
+SyncStatusCode MigrateDatabaseFromV0ToV1(leveldb::DB* db) {
+  // Version 0 database format:
+  //   key: "CHANGE_STAMP"
+  //   value: <Largest Changestamp>
+  //
+  //   key: "SYNC_ROOT_DIR"
+  //   value: <Resource ID of the sync root directory>
+  //
+  //   key: "METADATA: " +
+  //        <FileSystemURL serialized by SerializeSyncableFileSystemURL>
+  //   value: <Serialized DriveMetadata>
+  //
+  //   key: "BSYNC_ORIGIN: " + <URL string of a batch sync origin>
+  //   value: <Resource ID of the drive directory for the origin>
+  //
+  //   key: "ISYNC_ORIGIN: " + <URL string of a incremental sync origin>
+  //   value: <Resource ID of the drive directory for the origin>
+  //
+  // Version 1 database format (changed keys/fields are marked with '*'):
+  // * key: "VERSION" (new)
+  // * value: 1
+  //
+  //   key: "CHANGE_STAMP"
+  //   value: <Largest Changestamp>
+  //
+  //   key: "SYNC_ROOT_DIR"
+  //   value: <Resource ID of the sync root directory>
+  //
+  // * key: "METADATA: " + <Origin and URL> (changed)
+  // * value: <Serialized DriveMetadata>
+  //
+  //   key: "BSYNC_ORIGIN: " + <URL string of a batch sync origin>
+  //   value: <Resource ID of the drive directory for the origin>
+  //
+  //   key: "ISYNC_ORIGIN: " + <URL string of a incremental sync origin>
+  //   value: <Resource ID of the drive directory for the origin>
+  //
+  //   key: "DISABLED_ORIGIN: " + <URL string of a disabled origin>
+  //   value: <Resource ID of the drive directory for the origin>
+
+  const char kDatabaseVersionKey[] = "VERSION";
+  const char kDriveMetadataKeyPrefix[] = "METADATA: ";
+  const char kMetadataKeySeparator = ' ';
+
+  leveldb::WriteBatch write_batch;
+  write_batch.Put(kDatabaseVersionKey, "1");
+
+  scoped_ptr<leveldb::Iterator> itr(db->NewIterator(leveldb::ReadOptions()));
+  for (itr->Seek(kDriveMetadataKeyPrefix); itr->Valid(); itr->Next()) {
+    std::string key = itr->key().ToString();
+    if (!StartsWithASCII(key, kDriveMetadataKeyPrefix, true))
+      break;
+    std::string serialized_url(RemovePrefix(key, kDriveMetadataKeyPrefix));
+
+    GURL origin;
+    base::FilePath path;
+    bool success = ParseV0FormatFileSystemURL(
+        GURL(serialized_url), &origin, &path);
+    DCHECK(success) << serialized_url;
+    std::string new_key = kDriveMetadataKeyPrefix + origin.spec() +
+        kMetadataKeySeparator + path.AsUTF8Unsafe();
+
+    write_batch.Put(new_key, itr->value());
+    write_batch.Delete(key);
+  }
+
+  return LevelDBStatusToSyncStatusCode(
+      db->Write(leveldb::WriteOptions(), &write_batch));
+}
+
+SyncStatusCode MigrateDatabaseFromV1ToV2(leveldb::DB* db) {
+  // Strips prefix of WAPI resource ID, and discards batch sync origins.
+  // (i.e. "file:xxxx" => "xxxx", "folder:yyyy" => "yyyy")
+  //
+  // Version 2 database format (changed keys/fields are marked with '*'):
+  //   key: "VERSION"
+  // * value: 2
+  //
+  //   key: "CHANGE_STAMP"
+  //   value: <Largest Changestamp>
+  //
+  //   key: "SYNC_ROOT_DIR"
+  // * value: <Resource ID of the sync root directory> (striped)
+  //
+  //   key: "METADATA: " + <Origin and URL>
+  // * value: <Serialized DriveMetadata> (stripped)
+  //
+  // * key: "BSYNC_ORIGIN: " + <URL string of a batch sync origin> (deleted)
+  // * value: <Resource ID of the drive directory for the origin> (deleted)
+  //
+  //   key: "ISYNC_ORIGIN: " + <URL string of a incremental sync origin>
+  // * value: <Resource ID of the drive directory for the origin> (stripped)
+  //
+  //   key: "DISABLED_ORIGIN: " + <URL string of a disabled origin>
+  // * value: <Resource ID of the drive directory for the origin> (stripped)
+
+  const char kDatabaseVersionKey[] = "VERSION";
+  const char kSyncRootDirectoryKey[] = "SYNC_ROOT_DIR";
+  const char kDriveMetadataKeyPrefix[] = "METADATA: ";
+  const char kDriveBatchSyncOriginKeyPrefix[] = "BSYNC_ORIGIN: ";
+  const char kDriveIncrementalSyncOriginKeyPrefix[] = "ISYNC_ORIGIN: ";
+  const char kDriveDisabledOriginKeyPrefix[] = "DISABLED_ORIGIN: ";
+
+  leveldb::WriteBatch write_batch;
+  write_batch.Put(kDatabaseVersionKey, "2");
+
+  scoped_ptr<leveldb::Iterator> itr(db->NewIterator(leveldb::ReadOptions()));
+  for (itr->SeekToFirst(); itr->Valid(); itr->Next()) {
+    std::string key = itr->key().ToString();
+
+    // Strip resource id for the sync root directory.
+    if (StartsWithASCII(key, kSyncRootDirectoryKey, true)) {
+      write_batch.Put(key, RemoveWapiIdPrefix(itr->value().ToString()));
+      continue;
+    }
+
+    // Strip resource ids in the drive metadata.
+    if (StartsWithASCII(key, kDriveMetadataKeyPrefix, true)) {
+      DriveMetadata metadata;
+      bool success = metadata.ParseFromString(itr->value().ToString());
+      DCHECK(success);
+
+      metadata.set_resource_id(RemoveWapiIdPrefix(metadata.resource_id()));
+      std::string metadata_string;
+      metadata.SerializeToString(&metadata_string);
+
+      write_batch.Put(key, metadata_string);
+      continue;
+    }
+
+    // Deprecate legacy batch sync origin entries that are no longer needed.
+    if (StartsWithASCII(key, kDriveBatchSyncOriginKeyPrefix, true)) {
+      write_batch.Delete(key);
+      continue;
+    }
+
+    // Strip resource ids of the incremental sync origins.
+    if (StartsWithASCII(key, kDriveIncrementalSyncOriginKeyPrefix, true)) {
+      write_batch.Put(key, RemoveWapiIdPrefix(itr->value().ToString()));
+      continue;
+    }
+
+    // Strip resource ids of the disabled sync origins.
+    if (StartsWithASCII(key, kDriveDisabledOriginKeyPrefix, true)) {
+      write_batch.Put(key, RemoveWapiIdPrefix(itr->value().ToString()));
+      continue;
+    }
+  }
+
+  return LevelDBStatusToSyncStatusCode(
+      db->Write(leveldb::WriteOptions(), &write_batch));
+}
+
+}  // namespace drive_backend
+}  // namespace sync_file_system
diff --git a/chrome/browser/sync_file_system/drive_backend/metadata_db_migration_util.h b/chrome/browser/sync_file_system/drive_backend/metadata_db_migration_util.h
new file mode 100644
index 0000000..9379d0a
--- /dev/null
+++ b/chrome/browser/sync_file_system/drive_backend/metadata_db_migration_util.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 CHROME_BROWSER_SYNC_FILE_SYSTEM_DRIVE_BACKEND_METADATA_DB_MIGRATION_UTIL_H_
+#define CHROME_BROWSER_SYNC_FILE_SYSTEM_DRIVE_BACKEND_METADATA_DB_MIGRATION_UTIL_H_
+
+#include <string>
+
+#include "chrome/browser/sync_file_system/sync_file_system.pb.h"
+#include "third_party/leveldatabase/src/include/leveldb/db.h"
+#include "webkit/browser/fileapi/syncable/sync_status_code.h"
+
+class GURL;
+
+namespace sync_file_system {
+namespace drive_backend {
+
+// Parses a filesystem URL which contains 'drive' as a service name
+// (a.k.a. V0-format filesystem URL).
+//
+// When you parse V0-format filesystem URL, you should use this function instead
+// of DeserializeSyncableFileSystemURL() since 'drive' service name is no longer
+// used and the deserializer cannot parse the unregistered service name.
+//
+// EXAMPLE:
+// Assume following argument is given.
+//   url: 'filesystem:http://www.example.com/external/drive/foo/bar'
+// returns
+//   origin: 'http://www.example.com/'
+//   path:   'foo/bar'
+bool ParseV0FormatFileSystemURL(const GURL& url,
+                                GURL* origin,
+                                base::FilePath* path);
+
+// Adds "file:" prefix to WAPI resource ID.
+// EXAMPLE:  "xxx" => "file:xxx"
+std::string AddWapiFilePrefix(const std::string& resource_id);
+
+// Adds "folder:" prefix to WAPI resource ID.
+// EXAMPLE:  "xxx" => "folder:xxx"
+std::string AddWapiFolderPrefix(const std::string& resource_id);
+
+// Adds a prefix corresponding to the given |type|.
+std::string AddWapiIdPrefix(const std::string& resource_id,
+                            DriveMetadata_ResourceType type);
+
+// Removes a prefix from WAPI resource ID.
+// EXAMPLE:
+//   "file:xxx"    =>  "xxx"
+//   "folder:yyy"  =>  "yyy"
+//   "zzz"         =>  "zzz"
+std::string RemoveWapiIdPrefix(const std::string& resource_id);
+
+// Migrate |db| schema from version 0 to version 1.
+SyncStatusCode MigrateDatabaseFromV0ToV1(leveldb::DB* db);
+
+// Migrate |db| schema from version 1 to version 2.
+SyncStatusCode MigrateDatabaseFromV1ToV2(leveldb::DB* db);
+
+}  // namespace drive_backend
+}  // namespace sync_file_system
+
+#endif  // CHROME_BROWSER_SYNC_FILE_SYSTEM_DRIVE_BACKEND_METADATA_DB_MIGRATION_UTIL_H_
diff --git a/chrome/browser/sync_file_system/drive_backend/metadata_db_migration_util_unittest.cc b/chrome/browser/sync_file_system/drive_backend/metadata_db_migration_util_unittest.cc
new file mode 100644
index 0000000..71099ff
--- /dev/null
+++ b/chrome/browser/sync_file_system/drive_backend/metadata_db_migration_util_unittest.cc
@@ -0,0 +1,309 @@
+// 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/metadata_db_migration_util.h"
+
+#include "base/files/scoped_temp_dir.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "chrome/browser/sync_file_system/drive_metadata_store.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/leveldatabase/src/include/leveldb/db.h"
+#include "third_party/leveldatabase/src/include/leveldb/write_batch.h"
+#include "url/gurl.h"
+#include "webkit/browser/fileapi/external_mount_points.h"
+#include "webkit/browser/fileapi/syncable/syncable_file_system_util.h"
+#include "webkit/common/fileapi/file_system_util.h"
+
+#define FPL FILE_PATH_LITERAL
+
+namespace sync_file_system {
+namespace drive_backend {
+
+namespace {
+
+const char kV0ServiceName[] = "drive";
+
+bool CreateV0SerializedSyncableFileSystemURL(
+    const GURL& origin,
+    const base::FilePath& path,
+    std::string* serialized_url) {
+  fileapi::ScopedExternalFileSystem scoped_fs(
+      kV0ServiceName, fileapi::kFileSystemTypeSyncable, base::FilePath());
+
+  fileapi::FileSystemURL url =
+      fileapi::ExternalMountPoints::GetSystemInstance()->
+          CreateExternalFileSystemURL(origin, kV0ServiceName, path);
+  if (!url.is_valid())
+    return false;
+  *serialized_url = fileapi::GetExternalFileSystemRootURIString(
+        origin, kV0ServiceName) + url.path().AsUTF8Unsafe();
+  return true;
+}
+
+}  // namespace
+
+TEST(DriveMetadataDBMigrationUtilTest, ParseV0FormatFileSystemURL) {
+  const GURL kOrigin("chrome-extension://example");
+  const base::FilePath kFile(FPL("foo bar"));
+
+  std::string serialized_url;
+  ASSERT_TRUE(CreateV0SerializedSyncableFileSystemURL(
+      kOrigin, kFile, &serialized_url));
+
+  GURL origin;
+  base::FilePath path;
+  EXPECT_TRUE(ParseV0FormatFileSystemURL(GURL(serialized_url), &origin, &path));
+  EXPECT_EQ(kOrigin, origin);
+  EXPECT_EQ(kFile, path);
+}
+
+TEST(DriveMetadataDBMigrationUtilTest, AddWapiIdPrefix) {
+  DriveMetadata_ResourceType type_file =
+      DriveMetadata_ResourceType_RESOURCE_TYPE_FILE;
+  DriveMetadata_ResourceType type_folder =
+      DriveMetadata_ResourceType_RESOURCE_TYPE_FOLDER;
+
+  EXPECT_EQ("file:xxx", AddWapiFilePrefix("xxx"));
+  EXPECT_EQ("folder:yyy", AddWapiFolderPrefix("yyy"));
+  EXPECT_EQ("file:xxx", AddWapiIdPrefix("xxx", type_file));
+  EXPECT_EQ("folder:yyy", AddWapiIdPrefix("yyy", type_folder));
+
+  EXPECT_EQ("", AddWapiFilePrefix(""));
+  EXPECT_EQ("", AddWapiFolderPrefix(""));
+  EXPECT_EQ("", AddWapiIdPrefix("", type_file));
+  EXPECT_EQ("", AddWapiIdPrefix("", type_folder));
+}
+
+TEST(DriveMetadataDBMigrationUtilTest, RemoveWapiIdPrefix) {
+  EXPECT_EQ("xxx", RemoveWapiIdPrefix("xxx"));
+  EXPECT_EQ("yyy", RemoveWapiIdPrefix("file:yyy"));
+  EXPECT_EQ("zzz", RemoveWapiIdPrefix("folder:zzz"));
+
+  EXPECT_EQ("", RemoveWapiIdPrefix(""));
+  EXPECT_EQ("foo:xxx", RemoveWapiIdPrefix("foo:xxx"));
+}
+
+TEST(DriveMetadataDBMigrationUtilTest, MigrationFromV0) {
+  const char kDatabaseVersionKey[] = "VERSION";
+  const char kChangeStampKey[] = "CHANGE_STAMP";
+  const char kSyncRootDirectoryKey[] = "SYNC_ROOT_DIR";
+  const char kDriveMetadataKeyPrefix[] = "METADATA: ";
+  const char kDriveBatchSyncOriginKeyPrefix[] = "BSYNC_ORIGIN: ";
+  const char kDriveIncrementalSyncOriginKeyPrefix[] = "ISYNC_ORIGIN: ";
+
+  const GURL kOrigin1("chrome-extension://example1");
+  const GURL kOrigin2("chrome-extension://example2");
+  const std::string kSyncRootResourceId("folder:sync_root_resource_id");
+  const std::string kResourceId1("folder:hoge");
+  const std::string kResourceId2("folder:fuga");
+  const std::string kFileResourceId("file:piyo");
+  const base::FilePath kFile(FPL("foo bar"));
+  const std::string kFileMD5("file_md5");
+
+  base::ScopedTempDir base_dir;
+  ASSERT_TRUE(base_dir.CreateUniqueTempDir());
+
+  leveldb::Options options;
+  options.create_if_missing = true;
+  leveldb::DB* db_ptr = NULL;
+  std::string db_dir = fileapi::FilePathToString(
+      base_dir.path().Append(DriveMetadataStore::kDatabaseName));
+  leveldb::Status status = leveldb::DB::Open(options, db_dir, &db_ptr);
+
+  scoped_ptr<leveldb::DB> db(db_ptr);
+  ASSERT_TRUE(status.ok());
+
+  // Setup the database with the schema version 0.
+  leveldb::WriteBatch batch;
+  batch.Put(kChangeStampKey, "1");
+  batch.Put(kSyncRootDirectoryKey, kSyncRootResourceId);
+
+  // Setup drive metadata.
+  DriveMetadata drive_metadata;
+  drive_metadata.set_resource_id(kFileResourceId);
+  drive_metadata.set_md5_checksum(kFileMD5);
+  drive_metadata.set_conflicted(false);
+  drive_metadata.set_to_be_fetched(false);
+
+  std::string serialized_url;
+  ASSERT_TRUE(CreateV0SerializedSyncableFileSystemURL(
+      kOrigin1, kFile, &serialized_url));
+  std::string metadata_string;
+  drive_metadata.SerializeToString(&metadata_string);
+  batch.Put(kDriveMetadataKeyPrefix + serialized_url, metadata_string);
+
+  // Setup batch sync origin and incremental sync origin.
+  batch.Put(kDriveBatchSyncOriginKeyPrefix + kOrigin1.spec(), kResourceId1);
+  batch.Put(kDriveIncrementalSyncOriginKeyPrefix + kOrigin2.spec(),
+            kResourceId2);
+
+  status = db->Write(leveldb::WriteOptions(), &batch);
+  EXPECT_EQ(SYNC_STATUS_OK, LevelDBStatusToSyncStatusCode(status));
+
+  // Migrate the database.
+  MigrateDatabaseFromV0ToV1(db.get());
+
+  scoped_ptr<leveldb::Iterator> itr(db->NewIterator(leveldb::ReadOptions()));
+
+  // Verify DB schema version.
+  int64 database_version = 0;
+  itr->Seek(kDatabaseVersionKey);
+  EXPECT_TRUE(itr->Valid());
+  EXPECT_TRUE(base::StringToInt64(itr->value().ToString(), &database_version));
+  EXPECT_EQ(1, database_version);
+
+  // Verify the largest changestamp.
+  int64 changestamp = 0;
+  itr->Seek(kChangeStampKey);
+  EXPECT_TRUE(itr->Valid());
+  EXPECT_TRUE(base::StringToInt64(itr->value().ToString(), &changestamp));
+  EXPECT_EQ(1, changestamp);
+
+  // Verify the sync root directory.
+  itr->Seek(kSyncRootDirectoryKey);
+  EXPECT_TRUE(itr->Valid());
+  EXPECT_EQ(kSyncRootResourceId, itr->value().ToString());
+
+  // Verify the metadata.
+  itr->Seek(kDriveMetadataKeyPrefix);
+  EXPECT_TRUE(itr->Valid());
+  DriveMetadata metadata;
+  EXPECT_TRUE(metadata.ParseFromString(itr->value().ToString()));
+  EXPECT_EQ(kFileResourceId, metadata.resource_id());
+  EXPECT_EQ(kFileMD5, metadata.md5_checksum());
+  EXPECT_FALSE(metadata.conflicted());
+  EXPECT_FALSE(metadata.to_be_fetched());
+
+  // Verify the batch sync origin.
+  itr->Seek(kDriveBatchSyncOriginKeyPrefix);
+  EXPECT_TRUE(itr->Valid());
+  EXPECT_EQ(kResourceId1, itr->value().ToString());
+
+  // Verify the incremental sync origin.
+  itr->Seek(kDriveIncrementalSyncOriginKeyPrefix);
+  EXPECT_TRUE(itr->Valid());
+  EXPECT_EQ(kResourceId2, itr->value().ToString());
+}
+
+TEST(DriveMetadataDBMigrationUtilTest, MigrationFromV1) {
+  const char kDatabaseVersionKey[] = "VERSION";
+  const char kChangeStampKey[] = "CHANGE_STAMP";
+  const char kSyncRootDirectoryKey[] = "SYNC_ROOT_DIR";
+  const char kDriveMetadataKeyPrefix[] = "METADATA: ";
+  const char kMetadataKeySeparator = ' ';
+  const char kDriveBatchSyncOriginKeyPrefix[] = "BSYNC_ORIGIN: ";
+  const char kDriveIncrementalSyncOriginKeyPrefix[] = "ISYNC_ORIGIN: ";
+  const char kDriveDisabledOriginKeyPrefix[] = "DISABLED_ORIGIN: ";
+
+  const GURL kOrigin1("chrome-extension://example1");
+  const GURL kOrigin2("chrome-extension://example2");
+  const GURL kOrigin3("chrome-extension://example3");
+
+  const std::string kSyncRootResourceId("folder:sync_root_resource_id");
+  const std::string kResourceId1("folder:hoge");
+  const std::string kResourceId2("folder:fuga");
+  const std::string kResourceId3("folder:hogera");
+  const std::string kFileResourceId("file:piyo");
+  const base::FilePath kFile(FPL("foo bar"));
+  const std::string kFileMD5("file_md5");
+
+  RegisterSyncableFileSystem();
+
+  base::ScopedTempDir base_dir;
+  ASSERT_TRUE(base_dir.CreateUniqueTempDir());
+
+  leveldb::Options options;
+  options.create_if_missing = true;
+  leveldb::DB* db_ptr = NULL;
+  std::string db_dir = fileapi::FilePathToString(
+      base_dir.path().Append(DriveMetadataStore::kDatabaseName));
+  leveldb::Status status = leveldb::DB::Open(options, db_dir, &db_ptr);
+
+  scoped_ptr<leveldb::DB> db(db_ptr);
+  ASSERT_TRUE(status.ok());
+
+  // Setup the database with the schema version 1.
+  leveldb::WriteBatch batch;
+  batch.Put(kDatabaseVersionKey, "1");
+  batch.Put(kChangeStampKey, "1");
+  batch.Put(kSyncRootDirectoryKey, kSyncRootResourceId);
+
+  fileapi::FileSystemURL url = CreateSyncableFileSystemURL(kOrigin1, kFile);
+
+  // Setup drive metadata.
+  DriveMetadata drive_metadata;
+  drive_metadata.set_resource_id(kFileResourceId);
+  drive_metadata.set_md5_checksum(kFileMD5);
+  drive_metadata.set_conflicted(false);
+  drive_metadata.set_to_be_fetched(false);
+  std::string metadata_string;
+  drive_metadata.SerializeToString(&metadata_string);
+  std::string metadata_key = kDriveMetadataKeyPrefix + kOrigin1.spec() +
+                             kMetadataKeySeparator + url.path().AsUTF8Unsafe();
+  batch.Put(metadata_key, metadata_string);
+
+  // Setup origins.
+  batch.Put(kDriveBatchSyncOriginKeyPrefix + kOrigin1.spec(), kResourceId1);
+  batch.Put(kDriveIncrementalSyncOriginKeyPrefix + kOrigin2.spec(),
+            kResourceId2);
+  batch.Put(kDriveDisabledOriginKeyPrefix + kOrigin3.spec(), kResourceId3);
+
+  status = db->Write(leveldb::WriteOptions(), &batch);
+  EXPECT_EQ(SYNC_STATUS_OK, LevelDBStatusToSyncStatusCode(status));
+
+  RevokeSyncableFileSystem();
+
+  // Migrate the database.
+  MigrateDatabaseFromV1ToV2(db.get());
+
+  scoped_ptr<leveldb::Iterator> itr(db->NewIterator(leveldb::ReadOptions()));
+
+  // Verify DB schema version.
+  int64 database_version = 0;
+  itr->Seek(kDatabaseVersionKey);
+  EXPECT_TRUE(itr->Valid());
+  EXPECT_TRUE(base::StringToInt64(itr->value().ToString(), &database_version));
+  EXPECT_EQ(2, database_version);
+
+  // Verify the largest changestamp.
+  int64 changestamp = 0;
+  itr->Seek(kChangeStampKey);
+  EXPECT_TRUE(itr->Valid());
+  EXPECT_TRUE(base::StringToInt64(itr->value().ToString(), &changestamp));
+  EXPECT_EQ(1, changestamp);
+
+  // Verify the sync root directory.
+  itr->Seek(kSyncRootDirectoryKey);
+  EXPECT_TRUE(itr->Valid());
+  EXPECT_EQ(RemoveWapiIdPrefix(kSyncRootResourceId), itr->value().ToString());
+
+  // Verify the metadata.
+  itr->Seek(kDriveMetadataKeyPrefix);
+  EXPECT_TRUE(itr->Valid());
+  DriveMetadata metadata;
+  EXPECT_TRUE(metadata.ParseFromString(itr->value().ToString()));
+  EXPECT_EQ(RemoveWapiIdPrefix(kFileResourceId), metadata.resource_id());
+  EXPECT_EQ(kFileMD5, metadata.md5_checksum());
+  EXPECT_FALSE(metadata.conflicted());
+  EXPECT_FALSE(metadata.to_be_fetched());
+
+  // Verify the batch sync origin.
+  itr->Seek(kDriveBatchSyncOriginKeyPrefix);
+  EXPECT_FALSE(StartsWithASCII(kDriveBatchSyncOriginKeyPrefix,
+                               itr->key().ToString(), true));
+
+  // Verify the incremental sync origin.
+  itr->Seek(kDriveIncrementalSyncOriginKeyPrefix);
+  EXPECT_TRUE(itr->Valid());
+  EXPECT_EQ(RemoveWapiIdPrefix(kResourceId2), itr->value().ToString());
+
+  // Verify the disabled origin.
+  itr->Seek(kDriveDisabledOriginKeyPrefix);
+  EXPECT_TRUE(itr->Valid());
+  EXPECT_EQ(RemoveWapiIdPrefix(kResourceId3), itr->value().ToString());
+}
+
+}  // namespace drive_backend
+}  // namespace sync_file_system
diff --git a/chrome/browser/sync_file_system/drive_backend/remote_sync_delegate.cc b/chrome/browser/sync_file_system/drive_backend/remote_sync_delegate.cc
new file mode 100644
index 0000000..511b3d8
--- /dev/null
+++ b/chrome/browser/sync_file_system/drive_backend/remote_sync_delegate.cc
@@ -0,0 +1,518 @@
+// 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/remote_sync_delegate.h"
+
+#include "base/file_util.h"
+#include "chrome/browser/sync_file_system/logger.h"
+#include "chrome/browser/sync_file_system/remote_change_processor.h"
+#include "chrome/browser/sync_file_system/remote_sync_operation_resolver.h"
+#include "content/public/browser/browser_thread.h"
+#include "webkit/browser/fileapi/syncable/syncable_file_system_util.h"
+
+using fileapi::FileSystemURL;
+
+namespace {
+
+bool CreateTemporaryFile(const base::FilePath& dir_path,
+                         webkit_blob::ScopedFile* temp_file) {
+  base::FilePath temp_file_path;
+  const bool success = file_util::CreateDirectory(dir_path) &&
+      file_util::CreateTemporaryFileInDir(dir_path, &temp_file_path);
+  if (!success)
+    return success;
+  *temp_file =
+      webkit_blob::ScopedFile(temp_file_path,
+                              webkit_blob::ScopedFile::DELETE_ON_SCOPE_OUT,
+                              base::MessageLoopProxy::current().get());
+  return success;
+}
+
+void EmptyStatusCallback(sync_file_system::SyncStatusCode status) {}
+
+}  // namespace
+
+namespace sync_file_system {
+namespace drive_backend {
+
+RemoteSyncDelegate::RemoteSyncDelegate(
+    DriveFileSyncService* sync_service,
+    const RemoteChange& remote_change)
+    : sync_service_(sync_service),
+      remote_change_(remote_change),
+      sync_action_(SYNC_ACTION_NONE),
+      metadata_updated_(false),
+      clear_local_changes_(true) {
+}
+
+RemoteSyncDelegate::~RemoteSyncDelegate() {}
+
+void RemoteSyncDelegate::Run(const SyncStatusCallback& callback) {
+  util::Log(logging::LOG_VERBOSE, FROM_HERE,
+            "ProcessRemoteChange for %s change:%s",
+            url().DebugString().c_str(),
+            remote_file_change().DebugString().c_str());
+
+  remote_change_processor()->PrepareForProcessRemoteChange(
+      url(),
+      base::Bind(&RemoteSyncDelegate::DidPrepareForProcessRemoteChange,
+                 AsWeakPtr(), callback));
+}
+
+void RemoteSyncDelegate::DidPrepareForProcessRemoteChange(
+    const SyncStatusCallback& callback,
+    SyncStatusCode status,
+    const SyncFileMetadata& metadata,
+    const FileChangeList& local_changes) {
+  if (status != SYNC_STATUS_OK) {
+    AbortSync(callback, status);
+    return;
+  }
+
+  local_metadata_ = metadata;
+  status = metadata_store()->ReadEntry(url(), &drive_metadata_);
+  DCHECK(status == SYNC_STATUS_OK || status == SYNC_DATABASE_ERROR_NOT_FOUND);
+
+  bool missing_db_entry = (status != SYNC_STATUS_OK);
+  if (missing_db_entry) {
+    drive_metadata_.set_resource_id(remote_change_.resource_id);
+    drive_metadata_.set_md5_checksum(std::string());
+    drive_metadata_.set_conflicted(false);
+    drive_metadata_.set_to_be_fetched(false);
+  }
+  bool missing_local_file = (metadata.file_type == SYNC_FILE_TYPE_UNKNOWN);
+
+  if (drive_metadata_.resource_id().empty()) {
+    // This (missing_db_entry is false but resource_id is empty) could
+    // happen when the remote file gets deleted (this clears resource_id
+    // in drive_metadata) but then a file is added with the same name.
+    drive_metadata_.set_resource_id(remote_change_.resource_id);
+  }
+
+  SyncOperationType operation =
+      RemoteSyncOperationResolver::Resolve(remote_file_change(),
+                                           local_changes,
+                                           local_metadata_.file_type,
+                                           drive_metadata_.conflicted());
+
+  util::Log(logging::LOG_VERBOSE, FROM_HERE,
+            "ProcessRemoteChange for %s %s%sremote_change: %s ==> %s",
+            url().DebugString().c_str(),
+            drive_metadata_.conflicted() ? " (conflicted)" : " ",
+            missing_local_file ? " (missing local file)" : " ",
+            remote_file_change().DebugString().c_str(),
+            SyncOperationTypeToString(operation));
+  DCHECK_NE(SYNC_OPERATION_FAIL, operation);
+
+  switch (operation) {
+    case SYNC_OPERATION_ADD_FILE:
+    case SYNC_OPERATION_ADD_DIRECTORY:
+      sync_action_ = SYNC_ACTION_ADDED;
+      break;
+    case SYNC_OPERATION_UPDATE_FILE:
+      sync_action_ = SYNC_ACTION_UPDATED;
+      break;
+    case SYNC_OPERATION_DELETE:
+      sync_action_ = SYNC_ACTION_DELETED;
+      break;
+    case SYNC_OPERATION_NONE:
+    case SYNC_OPERATION_DELETE_METADATA:
+      sync_action_ = SYNC_ACTION_NONE;
+      break;
+    default:
+      break;
+  }
+
+  switch (operation) {
+    case SYNC_OPERATION_ADD_FILE:
+    case SYNC_OPERATION_UPDATE_FILE:
+      DownloadFile(callback);
+      return;
+    case SYNC_OPERATION_ADD_DIRECTORY:
+    case SYNC_OPERATION_DELETE:
+      ApplyRemoteChange(callback);
+      return;
+    case SYNC_OPERATION_NONE:
+      CompleteSync(callback, SYNC_STATUS_OK);
+      return;
+    case SYNC_OPERATION_CONFLICT:
+      HandleConflict(callback, remote_file_change().file_type());
+      return;
+    case SYNC_OPERATION_RESOLVE_TO_LOCAL:
+      ResolveToLocal(callback);
+      return;
+    case SYNC_OPERATION_RESOLVE_TO_REMOTE:
+      ResolveToRemote(callback);
+      return;
+    case SYNC_OPERATION_DELETE_METADATA:
+      if (missing_db_entry)
+        CompleteSync(callback, SYNC_STATUS_OK);
+      else
+        DeleteMetadata(callback);
+      return;
+    case SYNC_OPERATION_FAIL:
+      AbortSync(callback, SYNC_STATUS_FAILED);
+      return;
+  }
+  NOTREACHED();
+  AbortSync(callback, SYNC_STATUS_FAILED);
+}
+
+void RemoteSyncDelegate::ApplyRemoteChange(const SyncStatusCallback& callback) {
+  remote_change_processor()->ApplyRemoteChange(
+      remote_file_change(), temporary_file_.path(), url(),
+      base::Bind(&RemoteSyncDelegate::DidApplyRemoteChange, AsWeakPtr(),
+                 callback));
+}
+
+void RemoteSyncDelegate::DidApplyRemoteChange(
+    const SyncStatusCallback& callback,
+    SyncStatusCode status) {
+  if (status != SYNC_STATUS_OK) {
+    AbortSync(callback, status);
+    return;
+  }
+
+  if (remote_file_change().IsDelete()) {
+    DeleteMetadata(callback);
+    return;
+  }
+
+  drive_metadata_.set_resource_id(remote_change_.resource_id);
+  drive_metadata_.set_conflicted(false);
+  if (remote_file_change().IsFile()) {
+    drive_metadata_.set_type(DriveMetadata::RESOURCE_TYPE_FILE);
+  } else {
+    DCHECK(IsSyncFSDirectoryOperationEnabled());
+    drive_metadata_.set_type(DriveMetadata::RESOURCE_TYPE_FOLDER);
+  }
+
+  metadata_store()->UpdateEntry(
+      url(), drive_metadata_,
+      base::Bind(&RemoteSyncDelegate::CompleteSync,
+                 AsWeakPtr(), callback));
+}
+
+void RemoteSyncDelegate::DeleteMetadata(const SyncStatusCallback& callback) {
+  metadata_store()->DeleteEntry(
+      url(),
+      base::Bind(&RemoteSyncDelegate::CompleteSync, AsWeakPtr(), callback));
+}
+
+void RemoteSyncDelegate::DownloadFile(const SyncStatusCallback& callback) {
+  content::BrowserThread::PostTaskAndReplyWithResult(
+      content::BrowserThread::FILE, FROM_HERE,
+      base::Bind(&CreateTemporaryFile,
+                 sync_service_->temporary_file_dir_,
+                 &temporary_file_),
+      base::Bind(&RemoteSyncDelegate::DidGetTemporaryFileForDownload,
+                 AsWeakPtr(), callback));
+}
+
+void RemoteSyncDelegate::DidGetTemporaryFileForDownload(
+    const SyncStatusCallback& callback,
+    bool success) {
+  if (!success) {
+    AbortSync(callback, SYNC_FILE_ERROR_FAILED);
+    return;
+  }
+
+  DCHECK(!temporary_file_.path().empty());
+
+  // We should not use the md5 in metadata for FETCH type to avoid the download
+  // finishes due to NOT_MODIFIED.
+  std::string md5_checksum;
+  if (!drive_metadata_.to_be_fetched())
+    md5_checksum = drive_metadata_.md5_checksum();
+
+  api_util()->DownloadFile(
+      remote_change_.resource_id,
+      md5_checksum,
+      temporary_file_.path(),
+      base::Bind(&RemoteSyncDelegate::DidDownloadFile,
+                 AsWeakPtr(),
+                 callback));
+}
+
+void RemoteSyncDelegate::DidDownloadFile(
+    const SyncStatusCallback& callback,
+    google_apis::GDataErrorCode error,
+    const std::string& md5_checksum,
+    int64 file_size,
+    const base::Time& updated_time) {
+  if (error == google_apis::HTTP_NOT_MODIFIED) {
+    sync_action_ = SYNC_ACTION_NONE;
+    DidApplyRemoteChange(callback, SYNC_STATUS_OK);
+    return;
+  }
+
+  SyncStatusCode status = GDataErrorCodeToSyncStatusCodeWrapper(error);
+  if (status != SYNC_STATUS_OK) {
+    AbortSync(callback, status);
+    return;
+  }
+
+  drive_metadata_.set_md5_checksum(md5_checksum);
+  remote_change_processor()->ApplyRemoteChange(
+      remote_file_change(), temporary_file_.path(), url(),
+      base::Bind(&RemoteSyncDelegate::DidApplyRemoteChange,
+                 AsWeakPtr(), callback));
+}
+
+void RemoteSyncDelegate::HandleConflict(
+    const SyncStatusCallback& callback,
+    SyncFileType remote_file_type) {
+  ConflictResolution resolution = conflict_resolution_resolver()->Resolve(
+      remote_file_type,
+      remote_change_.updated_time,
+      local_metadata_.file_type,
+      local_metadata_.last_modified);
+
+  switch (resolution) {
+    case CONFLICT_RESOLUTION_LOCAL_WIN:
+      HandleLocalWin(callback);
+      return;
+    case CONFLICT_RESOLUTION_REMOTE_WIN:
+      HandleRemoteWin(callback, remote_file_type);
+      return;
+    case CONFLICT_RESOLUTION_MARK_CONFLICT:
+      HandleManualResolutionCase(callback);
+      return;
+    case CONFLICT_RESOLUTION_UNKNOWN:
+      // Get remote file time and call this method again.
+      api_util()->GetResourceEntry(
+          remote_change_.resource_id,
+          base::Bind(
+              &RemoteSyncDelegate::DidGetEntryForConflictResolution,
+              AsWeakPtr(), callback));
+      return;
+  }
+  NOTREACHED();
+  AbortSync(callback, SYNC_STATUS_FAILED);
+}
+
+void RemoteSyncDelegate::HandleLocalWin(
+    const SyncStatusCallback& callback) {
+  util::Log(logging::LOG_VERBOSE, FROM_HERE,
+            "Resolving conflict for remote sync: %s: LOCAL WIN",
+            url().DebugString().c_str());
+  ResolveToLocal(callback);
+}
+
+void RemoteSyncDelegate::HandleRemoteWin(
+    const SyncStatusCallback& callback,
+    SyncFileType remote_file_type) {
+  // Make sure we reset the conflict flag and start over the remote sync
+  // with empty local changes.
+  util::Log(logging::LOG_VERBOSE, FROM_HERE,
+            "Resolving conflict for remote sync: %s: REMOTE WIN",
+            url().DebugString().c_str());
+
+  drive_metadata_.set_conflicted(false);
+  drive_metadata_.set_to_be_fetched(false);
+  drive_metadata_.set_type(
+      DriveFileSyncService::SyncFileTypeToDriveMetadataResourceType(
+          remote_file_type));
+  metadata_store()->UpdateEntry(
+      url(), drive_metadata_,
+      base::Bind(&RemoteSyncDelegate::StartOver, AsWeakPtr(), callback));
+}
+
+void RemoteSyncDelegate::HandleManualResolutionCase(
+    const SyncStatusCallback& callback) {
+  sync_action_ = SYNC_ACTION_NONE;
+  sync_service_->MarkConflict(
+      url(), &drive_metadata_,
+      base::Bind(&RemoteSyncDelegate::CompleteSync, AsWeakPtr(), callback));
+}
+
+void RemoteSyncDelegate::DidGetEntryForConflictResolution(
+    const SyncStatusCallback& callback,
+    google_apis::GDataErrorCode error,
+    scoped_ptr<google_apis::ResourceEntry> entry) {
+  SyncStatusCode status = GDataErrorCodeToSyncStatusCodeWrapper(error);
+  if (status != SYNC_STATUS_OK || entry->updated_time().is_null()) {
+    HandleLocalWin(callback);
+    return;
+  }
+
+  SyncFileType file_type = SYNC_FILE_TYPE_UNKNOWN;
+  if (entry->is_file())
+    file_type = SYNC_FILE_TYPE_FILE;
+  if (entry->is_folder())
+    file_type = SYNC_FILE_TYPE_DIRECTORY;
+
+  remote_change_.updated_time = entry->updated_time();
+  HandleConflict(callback, file_type);
+}
+
+void RemoteSyncDelegate::ResolveToLocal(
+    const SyncStatusCallback& callback) {
+  sync_action_ = SYNC_ACTION_NONE;
+  clear_local_changes_ = false;
+
+  // Re-add a fake local change to resolve it later in next LocalSync.
+  remote_change_processor()->RecordFakeLocalChange(
+      url(),
+      FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
+                 local_metadata_.file_type),
+      base::Bind(&RemoteSyncDelegate::DidResolveToLocal,
+                 AsWeakPtr(), callback));
+}
+
+void RemoteSyncDelegate::DidResolveToLocal(
+    const SyncStatusCallback& callback,
+    SyncStatusCode status) {
+  if (status != SYNC_STATUS_OK) {
+    DCHECK_NE(SYNC_STATUS_HAS_CONFLICT, status);
+    AbortSync(callback, status);
+    return;
+  }
+
+  if (remote_file_change().IsDelete()) {
+    metadata_store()->DeleteEntry(
+        url(),
+        base::Bind(&RemoteSyncDelegate::CompleteSync,
+                   AsWeakPtr(), callback));
+  } else {
+    DCHECK(!remote_change_.resource_id.empty());
+    drive_metadata_.set_resource_id(remote_change_.resource_id);
+    drive_metadata_.set_conflicted(false);
+    drive_metadata_.set_to_be_fetched(false);
+    drive_metadata_.set_md5_checksum(std::string());
+    metadata_store()->UpdateEntry(
+        url(), drive_metadata_,
+        base::Bind(&RemoteSyncDelegate::CompleteSync,
+                   AsWeakPtr(), callback));
+  }
+}
+
+void RemoteSyncDelegate::ResolveToRemote(
+    const SyncStatusCallback& callback) {
+  drive_metadata_.set_conflicted(false);
+  drive_metadata_.set_to_be_fetched(true);
+  metadata_store()->UpdateEntry(
+      url(), drive_metadata_,
+      base::Bind(&RemoteSyncDelegate::DidResolveToRemote,
+                 AsWeakPtr(), callback));
+}
+
+void RemoteSyncDelegate::DidResolveToRemote(
+    const SyncStatusCallback& callback,
+    SyncStatusCode status) {
+  if (status != SYNC_STATUS_OK) {
+    AbortSync(callback, status);
+    return;
+  }
+
+  sync_action_ = SYNC_ACTION_ADDED;
+  if (remote_file_change().file_type() == SYNC_FILE_TYPE_FILE) {
+    DownloadFile(callback);
+    return;
+  }
+
+  // ApplyRemoteChange should replace any existing local file or
+  // directory with remote_change_.
+  ApplyRemoteChange(callback);
+}
+
+void RemoteSyncDelegate::StartOver(
+    const SyncStatusCallback& callback,
+    SyncStatusCode status) {
+  DidPrepareForProcessRemoteChange(
+      callback, status, local_metadata_, FileChangeList());
+}
+
+void RemoteSyncDelegate::CompleteSync(
+    const SyncStatusCallback& callback,
+    SyncStatusCode status) {
+  if (status != SYNC_STATUS_OK) {
+    AbortSync(callback, status);
+    return;
+  }
+
+  sync_service_->RemoveRemoteChange(url());
+
+  if (drive_metadata_.to_be_fetched()) {
+    // Clear |to_be_fetched| flag since we completed fetching the remote change
+    // and applying it to the local file.
+    DCHECK(!drive_metadata_.conflicted());
+    drive_metadata_.set_conflicted(false);
+    drive_metadata_.set_to_be_fetched(false);
+    metadata_store()->UpdateEntry(url(), drive_metadata_,
+                                  base::Bind(&EmptyStatusCallback));
+  }
+
+  if (remote_change_.changestamp > 0) {
+    DCHECK(metadata_store()->IsIncrementalSyncOrigin(url().origin()));
+    metadata_store()->SetLargestChangeStamp(
+        remote_change_.changestamp,
+        base::Bind(&RemoteSyncDelegate::DidFinish, AsWeakPtr(), callback));
+    return;
+  }
+
+  if (drive_metadata_.conflicted())
+    status = SYNC_STATUS_HAS_CONFLICT;
+
+  DidFinish(callback, status);
+}
+
+void RemoteSyncDelegate::AbortSync(
+    const SyncStatusCallback& callback,
+    SyncStatusCode status) {
+  DidFinish(callback, status);
+}
+
+void RemoteSyncDelegate::DidFinish(
+    const SyncStatusCallback& callback,
+    SyncStatusCode status) {
+  // Clear the local changes. If the operation was resolve-to-local, we should
+  // not clear them here since we added the fake local change to sync with the
+  // remote file.
+  if (clear_local_changes_) {
+    clear_local_changes_ = false;
+    remote_change_processor()->ClearLocalChanges(
+        url(), base::Bind(&RemoteSyncDelegate::DidFinish,
+                          AsWeakPtr(), callback, status));
+    return;
+  }
+
+  if (status == SYNC_STATUS_OK && sync_action_ != SYNC_ACTION_NONE) {
+    sync_service_->NotifyObserversFileStatusChanged(
+        url(),
+        SYNC_FILE_STATUS_SYNCED,
+        sync_action_,
+        SYNC_DIRECTION_REMOTE_TO_LOCAL);
+  }
+
+  callback.Run(status);
+}
+
+SyncStatusCode RemoteSyncDelegate::GDataErrorCodeToSyncStatusCodeWrapper(
+    google_apis::GDataErrorCode error) {
+  return sync_service_->GDataErrorCodeToSyncStatusCodeWrapper(error);
+}
+
+DriveMetadataStore* RemoteSyncDelegate::metadata_store() {
+  return sync_service_->metadata_store_.get();
+}
+
+APIUtilInterface* RemoteSyncDelegate::api_util() {
+  return sync_service_->api_util_.get();
+}
+
+RemoteChangeHandler* RemoteSyncDelegate::remote_change_handler() {
+  return &sync_service_->remote_change_handler_;
+}
+
+RemoteChangeProcessor* RemoteSyncDelegate::remote_change_processor() {
+  return sync_service_->remote_change_processor_;
+}
+
+ConflictResolutionResolver* RemoteSyncDelegate::conflict_resolution_resolver() {
+  return &sync_service_->conflict_resolution_resolver_;
+}
+
+}  // namespace drive_backend
+}  // namespace sync_file_system
diff --git a/chrome/browser/sync_file_system/drive_backend/remote_sync_delegate.h b/chrome/browser/sync_file_system/drive_backend/remote_sync_delegate.h
new file mode 100644
index 0000000..3037c90
--- /dev/null
+++ b/chrome/browser/sync_file_system/drive_backend/remote_sync_delegate.h
@@ -0,0 +1,121 @@
+// 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_REMOTE_SYNC_DELEGATE_H_
+#define CHROME_BROWSER_SYNC_FILE_SYSTEM_DRIVE_BACKEND_REMOTE_SYNC_DELEGATE_H_
+
+#include "base/callback.h"
+#include "base/memory/weak_ptr.h"
+#include "chrome/browser/sync_file_system/drive_backend/api_util.h"
+#include "chrome/browser/sync_file_system/drive_file_sync_service.h"
+#include "chrome/browser/sync_file_system/drive_metadata_store.h"
+#include "chrome/browser/sync_file_system/sync_action.h"
+#include "chrome/browser/sync_file_system/sync_file_system.pb.h"
+#include "webkit/browser/fileapi/file_system_url.h"
+#include "webkit/browser/fileapi/syncable/file_change.h"
+#include "webkit/browser/fileapi/syncable/sync_callbacks.h"
+#include "webkit/browser/fileapi/syncable/sync_file_metadata.h"
+#include "webkit/common/blob/scoped_file.h"
+
+namespace sync_file_system {
+
+class DriveMetadataStore;
+class RemoteChangeProcessor;
+
+namespace drive_backend {
+
+class APIUtil;
+
+// This class handles RemoteFileSyncService::ProcessRemoteChange for drive
+// backend, and its instance represents single ProcessRemoteChange operation.
+// The caller is responsible to own the instance, and can cancel operation by
+// deleting the instance.
+class RemoteSyncDelegate : public base::SupportsWeakPtr<RemoteSyncDelegate> {
+ public:
+  typedef RemoteChangeHandler::RemoteChange RemoteChange;
+
+  RemoteSyncDelegate(
+      DriveFileSyncService* sync_service,
+      const RemoteChange& remote_change);
+  virtual ~RemoteSyncDelegate();
+
+  void Run(const SyncStatusCallback& callback);
+
+  const fileapi::FileSystemURL& url() const { return remote_change_.url; }
+
+ private:
+  void DidPrepareForProcessRemoteChange(const SyncStatusCallback& callback,
+                                        SyncStatusCode status,
+                                        const SyncFileMetadata& metadata,
+                                        const FileChangeList& local_changes);
+  void ApplyRemoteChange(const SyncStatusCallback& callback);
+  void DidApplyRemoteChange(const SyncStatusCallback& callback,
+                            SyncStatusCode status);
+  void DeleteMetadata(const SyncStatusCallback& callback);
+  void DownloadFile(const SyncStatusCallback& callback);
+  void DidGetTemporaryFileForDownload(const SyncStatusCallback& callback,
+                                      bool success);
+  void DidDownloadFile(const SyncStatusCallback& callback,
+                       google_apis::GDataErrorCode error,
+                       const std::string& md5_checksum,
+                       int64 file_size,
+                       const base::Time& updated_time);
+  void HandleConflict(const SyncStatusCallback& callback,
+                      SyncFileType remote_file_type);
+  void HandleLocalWin(const SyncStatusCallback& callback);
+  void HandleRemoteWin(const SyncStatusCallback& callback,
+                       SyncFileType remote_file_type);
+  void HandleManualResolutionCase(const SyncStatusCallback& callback);
+  void DidGetEntryForConflictResolution(
+      const SyncStatusCallback& callback,
+      google_apis::GDataErrorCode error,
+      scoped_ptr<google_apis::ResourceEntry> entry);
+  void ResolveToLocal(const SyncStatusCallback& callback);
+  void DidResolveToLocal(const SyncStatusCallback& callback,
+                         SyncStatusCode status);
+  void ResolveToRemote(const SyncStatusCallback& callback);
+  void DidResolveToRemote(const SyncStatusCallback& callback,
+                          SyncStatusCode status);
+  void StartOver(const SyncStatusCallback& callback,
+                 SyncStatusCode status);
+
+  void CompleteSync(const SyncStatusCallback& callback,
+                    SyncStatusCode status);
+  void AbortSync(const SyncStatusCallback& callback,
+                 SyncStatusCode status);
+  void DidFinish(const SyncStatusCallback& callback,
+                 SyncStatusCode status);
+
+  SyncStatusCode GDataErrorCodeToSyncStatusCodeWrapper(
+      google_apis::GDataErrorCode error);
+
+  DriveMetadataStore* metadata_store();
+  APIUtilInterface* api_util();
+  RemoteChangeHandler* remote_change_handler();
+  RemoteChangeProcessor* remote_change_processor();
+  ConflictResolutionResolver* conflict_resolution_resolver();
+
+  const FileChange& remote_file_change() const { return remote_change_.change; }
+
+  DriveFileSyncService* sync_service_;  // Not owned.
+
+  RemoteChange remote_change_;
+  DriveMetadata drive_metadata_;
+  SyncFileMetadata local_metadata_;
+  webkit_blob::ScopedFile temporary_file_;
+  std::string md5_checksum_;
+  SyncAction sync_action_;
+  bool metadata_updated_;
+  bool clear_local_changes_;
+
+  std::string origin_resource_id_;
+
+  DISALLOW_COPY_AND_ASSIGN(RemoteSyncDelegate);
+};
+
+}  // namespace drive_backend
+
+}  // namespace sync_file_system
+
+#endif  // CHROME_BROWSER_SYNC_FILE_SYSTEM_DRIVE_BACKEND_REMOTE_SYNC_DELEGATE_H_
diff --git a/chrome/browser/sync_file_system/drive_file_sync_service.cc b/chrome/browser/sync_file_system/drive_file_sync_service.cc
index 8659491..ce50f1c 100644
--- a/chrome/browser/sync_file_system/drive_file_sync_service.cc
+++ b/chrome/browser/sync_file_system/drive_file_sync_service.cc
@@ -15,22 +15,20 @@
 #include "base/message_loop/message_loop_proxy.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
+#include "chrome/browser/drive/drive_api_util.h"
 #include "chrome/browser/drive/drive_notification_manager.h"
 #include "chrome/browser/drive/drive_notification_manager_factory.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/extension_system.h"
-#include "chrome/browser/google_apis/drive_api_util.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/sync_file_system/conflict_resolution_policy.h"
-#include "chrome/browser/sync_file_system/drive/api_util.h"
-#include "chrome/browser/sync_file_system/drive/local_change_processor_delegate.h"
+#include "chrome/browser/sync_file_system/drive_backend/api_util.h"
+#include "chrome/browser/sync_file_system/drive_backend/local_sync_delegate.h"
+#include "chrome/browser/sync_file_system/drive_backend/remote_sync_delegate.h"
 #include "chrome/browser/sync_file_system/drive_file_sync_util.h"
 #include "chrome/browser/sync_file_system/drive_metadata_store.h"
 #include "chrome/browser/sync_file_system/file_status_observer.h"
 #include "chrome/browser/sync_file_system/logger.h"
 #include "chrome/browser/sync_file_system/remote_change_handler.h"
-#include "chrome/browser/sync_file_system/remote_change_processor.h"
-#include "chrome/browser/sync_file_system/remote_sync_operation_resolver.h"
 #include "chrome/browser/sync_file_system/sync_file_system.pb.h"
 #include "chrome/common/extensions/extension.h"
 #include "content/public/browser/browser_thread.h"
@@ -46,7 +44,6 @@
 
 namespace sync_file_system {
 
-typedef DriveFileSyncService::ConflictResolutionResult ConflictResolutionResult;
 typedef RemoteFileSyncService::OriginStatusMap OriginStatusMap;
 
 namespace {
@@ -78,42 +75,10 @@
 
 void EmptyStatusCallback(SyncStatusCode status) {}
 
-void SyncFileCallbackAdapter(
-    const SyncStatusCallback& status_callback,
-    const SyncFileCallback& callback,
-    SyncStatusCode status,
-    const FileSystemURL& url) {
-  status_callback.Run(status);
-  callback.Run(status, url);
-}
-
 }  // namespace
 
 ConflictResolutionPolicy DriveFileSyncService::kDefaultPolicy =
-    CONFLICT_RESOLUTION_LAST_WRITE_WIN;
-
-struct DriveFileSyncService::ProcessRemoteChangeParam {
-  RemoteChangeHandler::RemoteChange remote_change;
-  SyncFileCallback callback;
-
-  DriveMetadata drive_metadata;
-  SyncFileMetadata local_metadata;
-  bool metadata_updated;
-  webkit_blob::ScopedFile temporary_file;
-  std::string md5_checksum;
-  SyncAction sync_action;
-  bool clear_local_changes;
-
-  ProcessRemoteChangeParam(
-      const RemoteChangeHandler::RemoteChange& remote_change,
-      const SyncFileCallback& callback)
-      : remote_change(remote_change),
-        callback(callback),
-        metadata_updated(false),
-        sync_action(SYNC_ACTION_NONE),
-        clear_local_changes(true) {
-  }
-};
+    CONFLICT_RESOLUTION_POLICY_LAST_WRITE_WIN;
 
 // DriveFileSyncService ------------------------------------------------------
 
@@ -121,8 +86,8 @@
   if (api_util_)
     api_util_->RemoveObserver(this);
 
-  google_apis::DriveNotificationManager* drive_notification_manager =
-      google_apis::DriveNotificationManagerFactory::GetForProfile(profile_);
+  ::drive::DriveNotificationManager* drive_notification_manager =
+      ::drive::DriveNotificationManagerFactory::GetForProfile(profile_);
   if (drive_notification_manager)
     drive_notification_manager->RemoveObserver(this);
 }
@@ -141,7 +106,7 @@
 scoped_ptr<DriveFileSyncService> DriveFileSyncService::CreateForTesting(
     Profile* profile,
     const base::FilePath& base_dir,
-    scoped_ptr<drive::APIUtilInterface> api_util,
+    scoped_ptr<drive_backend::APIUtilInterface> api_util,
     scoped_ptr<DriveMetadataStore> metadata_store) {
   scoped_ptr<DriveFileSyncService> service(new DriveFileSyncService(profile));
   scoped_ptr<SyncTaskManager> task_manager(
@@ -156,7 +121,7 @@
   return service.Pass();
 }
 
-scoped_ptr<drive::APIUtilInterface>
+scoped_ptr<drive_backend::APIUtilInterface>
 DriveFileSyncService::DestroyAndPassAPIUtilForTesting(
     scoped_ptr<DriveFileSyncService> sync_service) {
   return sync_service->api_util_.Pass();
@@ -271,9 +236,10 @@
 }
 
 void DriveFileSyncService::GetFileMetadataMap(
-    OriginFileMetadataMap* metadata_map) {
+    const GURL& origin,
+    FileMetadataMap* metadata_map) {
   DCHECK(metadata_map);
-  metadata_store_->GetFileMetadataMap(metadata_map);
+  metadata_store_->GetFileMetadataMap(origin, metadata_map);
 }
 
 void DriveFileSyncService::SetSyncEnabled(bool enabled) {
@@ -292,14 +258,14 @@
 }
 
 SyncStatusCode DriveFileSyncService::SetConflictResolutionPolicy(
-    ConflictResolutionPolicy resolution) {
-  conflict_resolution_ = resolution;
+    ConflictResolutionPolicy policy) {
+  conflict_resolution_resolver_.set_policy(policy);
   return SYNC_STATUS_OK;
 }
 
 ConflictResolutionPolicy
 DriveFileSyncService::GetConflictResolutionPolicy() const {
-  return conflict_resolution_;
+  return conflict_resolution_resolver_.policy();
 }
 
 void DriveFileSyncService::ApplyLocalChange(
@@ -347,7 +313,7 @@
       may_have_unfetched_changes_(false),
       remote_change_processor_(NULL),
       last_gdata_error_(google_apis::HTTP_SUCCESS),
-      conflict_resolution_(kDefaultPolicy) {
+      conflict_resolution_resolver_(kDefaultPolicy) {
 }
 
 void DriveFileSyncService::Initialize(
@@ -362,7 +328,7 @@
   temporary_file_dir_ =
       profile_->GetPath().Append(GetSyncFileSystemDir()).Append(kTempDirName);
 
-  api_util_.reset(new drive::APIUtil(profile_));
+  api_util_.reset(new drive_backend::APIUtil(profile_));
   api_util_->AddObserver(this);
 
   metadata_store_.reset(new DriveMetadataStore(
@@ -378,7 +344,7 @@
 void DriveFileSyncService::InitializeForTesting(
     scoped_ptr<SyncTaskManager> task_manager,
     const base::FilePath& base_dir,
-    scoped_ptr<drive::APIUtilInterface> api_util,
+    scoped_ptr<drive_backend::APIUtilInterface> api_util,
     scoped_ptr<DriveMetadataStore> metadata_store,
     const SyncStatusCallback& callback) {
   DCHECK(!metadata_store_);
@@ -437,8 +403,8 @@
   callback.Run(status);
   may_have_unfetched_changes_ = true;
 
-  google_apis::DriveNotificationManager* drive_notification_manager =
-      google_apis::DriveNotificationManagerFactory::GetForProfile(profile_);
+  ::drive::DriveNotificationManager* drive_notification_manager =
+      ::drive::DriveNotificationManagerFactory::GetForProfile(profile_);
   if (drive_notification_manager)
     drive_notification_manager->AddObserver(this);
 }
@@ -595,16 +561,17 @@
     const SyncStatusCallback& completion_callback) {
   DCHECK(remote_change_processor_);
 
-  SyncFileCallback callback =
-      base::Bind(&SyncFileCallbackAdapter, completion_callback, sync_callback);
+  SyncStatusCallback callback = base::Bind(
+      &DriveFileSyncService::DidProcessRemoteChange, AsWeakPtr(),
+      sync_callback, completion_callback);
 
-  if (!remote_change_handler_.HasChanges()) {
-    callback.Run(SYNC_STATUS_NO_CHANGE_TO_SYNC, FileSystemURL());
+  if (GetCurrentState() == REMOTE_SERVICE_DISABLED) {
+    callback.Run(SYNC_STATUS_SYNC_DISABLED);
     return;
   }
 
-  if (GetCurrentState() == REMOTE_SERVICE_DISABLED) {
-    callback.Run(SYNC_STATUS_SYNC_DISABLED, FileSystemURL());
+  if (!remote_change_handler_.HasChanges()) {
+    callback.Run(SYNC_STATUS_NO_CHANGE_TO_SYNC);
     return;
   }
 
@@ -613,17 +580,10 @@
       remote_change_handler_.GetChange(&remote_change);
   DCHECK(has_remote_change);
 
-  util::Log(logging::LOG_VERBOSE, FROM_HERE,
-            "ProcessRemoteChange for %s change:%s",
-            remote_change.url.DebugString().c_str(),
-            remote_change.change.DebugString().c_str());
-
-  scoped_ptr<ProcessRemoteChangeParam> param(new ProcessRemoteChangeParam(
-      remote_change, callback));
-  remote_change_processor_->PrepareForProcessRemoteChange(
-      remote_change.url,
-      base::Bind(&DriveFileSyncService::DidPrepareForProcessRemoteChange,
-                 AsWeakPtr(), base::Passed(&param)));
+  DCHECK(!running_remote_sync_task_);
+  running_remote_sync_task_.reset(new drive_backend::RemoteSyncDelegate(
+      this, remote_change));
+  running_remote_sync_task_->Run(callback);
 }
 
 void DriveFileSyncService::DoApplyLocalChange(
@@ -646,7 +606,7 @@
   }
 
   DCHECK(!running_local_sync_task_);
-  running_local_sync_task_.reset(new drive::LocalChangeProcessorDelegate(
+  running_local_sync_task_.reset(new drive_backend::LocalSyncDelegate(
       this, local_file_change, local_file_path, local_file_metadata, url));
   running_local_sync_task_->Run(base::Bind(
       &DriveFileSyncService::DidApplyLocalChange, AsWeakPtr(), callback));
@@ -847,27 +807,17 @@
   callback.Run(SYNC_STATUS_OK);
 }
 
-// TODO(tzik): Factor out this conflict resolution function.
-ConflictResolutionResult DriveFileSyncService::ResolveConflictForLocalSync(
-    SyncFileType local_file_type,
-    const base::Time& local_updated_time,
-    SyncFileType remote_file_type,
-    const base::Time& remote_updated_time) {
-  // Currently we always prioritize directories over files regardless of
-  // conflict resolution policy.
-  if (remote_file_type == SYNC_FILE_TYPE_DIRECTORY)
-    return CONFLICT_RESOLUTION_REMOTE_WIN;
+void DriveFileSyncService::DidProcessRemoteChange(
+    const SyncFileCallback& sync_callback,
+    const SyncStatusCallback& completion_callback,
+    SyncStatusCode status) {
+  fileapi::FileSystemURL url;
+  if (running_remote_sync_task_)
+    url = running_remote_sync_task_->url();
+  running_remote_sync_task_.reset();
 
-  if (conflict_resolution_ == CONFLICT_RESOLUTION_MANUAL)
-    return CONFLICT_RESOLUTION_MARK_CONFLICT;
-
-  DCHECK_EQ(CONFLICT_RESOLUTION_LAST_WRITE_WIN, conflict_resolution_);
-  if (local_updated_time >= remote_updated_time ||
-      remote_file_type == SYNC_FILE_TYPE_UNKNOWN) {
-    return CONFLICT_RESOLUTION_LOCAL_WIN;
-  }
-
-  return CONFLICT_RESOLUTION_REMOTE_WIN;
+  completion_callback.Run(status);
+  sync_callback.Run(status, url);
 }
 
 void DriveFileSyncService::DidApplyLocalChange(
@@ -877,414 +827,6 @@
   callback.Run(status);
 }
 
-void DriveFileSyncService::DidPrepareForProcessRemoteChange(
-    scoped_ptr<ProcessRemoteChangeParam> param,
-    SyncStatusCode status,
-    const SyncFileMetadata& metadata,
-    const FileChangeList& local_changes) {
-  if (status != SYNC_STATUS_OK) {
-    AbortRemoteSync(param.Pass(), status);
-    return;
-  }
-
-  param->local_metadata = metadata;
-  const FileSystemURL& url = param->remote_change.url;
-  const DriveMetadata& drive_metadata = param->drive_metadata;
-  const FileChange& remote_file_change = param->remote_change.change;
-
-  status = metadata_store_->ReadEntry(param->remote_change.url,
-                                      &param->drive_metadata);
-  DCHECK(status == SYNC_STATUS_OK || status == SYNC_DATABASE_ERROR_NOT_FOUND);
-
-  bool missing_db_entry = (status != SYNC_STATUS_OK);
-  if (missing_db_entry) {
-    param->drive_metadata.set_resource_id(param->remote_change.resource_id);
-    param->drive_metadata.set_md5_checksum(std::string());
-    param->drive_metadata.set_conflicted(false);
-    param->drive_metadata.set_to_be_fetched(false);
-  }
-  bool missing_local_file = (metadata.file_type == SYNC_FILE_TYPE_UNKNOWN);
-
-  SyncOperationType operation =
-      RemoteSyncOperationResolver::Resolve(remote_file_change,
-                                           local_changes,
-                                           param->local_metadata.file_type,
-                                           param->drive_metadata.conflicted());
-
-  util::Log(logging::LOG_VERBOSE, FROM_HERE,
-            "ProcessRemoteChange for %s %s%sremote_change: %s ==> %s",
-            url.DebugString().c_str(),
-            param->drive_metadata.conflicted() ? " (conflicted)" : " ",
-            missing_local_file ? " (missing local file)" : " ",
-            remote_file_change.DebugString().c_str(),
-            SyncOperationTypeToString(operation));
-  DCHECK_NE(SYNC_OPERATION_FAIL, operation);
-
-  switch (operation) {
-    case SYNC_OPERATION_ADD_FILE:
-    case SYNC_OPERATION_ADD_DIRECTORY:
-      param->sync_action = SYNC_ACTION_ADDED;
-      break;
-    case SYNC_OPERATION_UPDATE_FILE:
-      param->sync_action = SYNC_ACTION_UPDATED;
-      break;
-    case SYNC_OPERATION_DELETE:
-      param->sync_action = SYNC_ACTION_DELETED;
-      break;
-    case SYNC_OPERATION_NONE:
-    case SYNC_OPERATION_DELETE_METADATA:
-      param->sync_action = SYNC_ACTION_NONE;
-      break;
-    default:
-      break;
-  }
-
-  switch (operation) {
-    case SYNC_OPERATION_ADD_FILE:
-    case SYNC_OPERATION_UPDATE_FILE:
-      DownloadForRemoteSync(param.Pass());
-      return;
-    case SYNC_OPERATION_ADD_DIRECTORY:
-    case SYNC_OPERATION_DELETE: {
-      const FileChange& file_change = remote_file_change;
-      remote_change_processor_->ApplyRemoteChange(
-          file_change, base::FilePath(), url,
-          base::Bind(&DriveFileSyncService::DidApplyRemoteChange, AsWeakPtr(),
-                     base::Passed(&param)));
-      return;
-    }
-    case SYNC_OPERATION_NONE:
-      CompleteRemoteSync(param.Pass(), SYNC_STATUS_OK);
-      return;
-    case SYNC_OPERATION_CONFLICT:
-      HandleConflictForRemoteSync(param.Pass(), base::Time(),
-                                  remote_file_change.file_type(),
-                                  SYNC_STATUS_OK);
-      return;
-    case SYNC_OPERATION_RESOLVE_TO_LOCAL:
-      ResolveConflictToLocalForRemoteSync(param.Pass());
-      return;
-    case SYNC_OPERATION_RESOLVE_TO_REMOTE: {
-      const FileSystemURL& url = param->remote_change.url;
-      param->drive_metadata.set_conflicted(false);
-      param->drive_metadata.set_to_be_fetched(true);
-      metadata_store_->UpdateEntry(
-          url, drive_metadata, base::Bind(&EmptyStatusCallback));
-      param->sync_action = SYNC_ACTION_ADDED;
-      if (param->remote_change.change.file_type() == SYNC_FILE_TYPE_FILE) {
-        DownloadForRemoteSync(param.Pass());
-        return;
-      }
-
-      // |remote_change_processor| should replace any existing file or directory
-      // on ApplyRemoteChange call.
-      const FileChange& file_change = remote_file_change;
-      remote_change_processor_->ApplyRemoteChange(
-          file_change, base::FilePath(), url,
-          base::Bind(&DriveFileSyncService::DidApplyRemoteChange, AsWeakPtr(),
-                     base::Passed(&param)));
-      return;
-    }
-    case SYNC_OPERATION_DELETE_METADATA:
-      if (missing_db_entry)
-        CompleteRemoteSync(param.Pass(), SYNC_STATUS_OK);
-      else
-        DeleteMetadataForRemoteSync(param.Pass());
-      return;
-    case SYNC_OPERATION_FAIL:
-      AbortRemoteSync(param.Pass(), SYNC_STATUS_FAILED);
-      return;
-  }
-  NOTREACHED();
-  AbortRemoteSync(param.Pass(), SYNC_STATUS_FAILED);
-}
-
-void DriveFileSyncService::DidResolveConflictToLocalChange(
-    scoped_ptr<ProcessRemoteChangeParam> param,
-    SyncStatusCode status) {
-  if (status != SYNC_STATUS_OK) {
-    DCHECK_NE(SYNC_STATUS_HAS_CONFLICT, status);
-    AbortRemoteSync(param.Pass(), status);
-    return;
-  }
-
-  const FileSystemURL& url = param->remote_change.url;
-  if (param->remote_change.change.IsDelete()) {
-    metadata_store_->DeleteEntry(
-        url,
-        base::Bind(&DriveFileSyncService::CompleteRemoteSync,
-                   AsWeakPtr(), base::Passed(&param)));
-  } else {
-    DriveMetadata& drive_metadata = param->drive_metadata;
-    DCHECK(!param->remote_change.resource_id.empty());
-    drive_metadata.set_resource_id(param->remote_change.resource_id);
-    drive_metadata.set_conflicted(false);
-    drive_metadata.set_to_be_fetched(false);
-    drive_metadata.set_md5_checksum(std::string());
-    metadata_store_->UpdateEntry(
-        url, drive_metadata,
-        base::Bind(&DriveFileSyncService::CompleteRemoteSync,
-                   AsWeakPtr(), base::Passed(&param)));
-  }
-}
-
-void DriveFileSyncService::DownloadForRemoteSync(
-    scoped_ptr<ProcessRemoteChangeParam> param) {
-  webkit_blob::ScopedFile* temporary_file = &param->temporary_file;
-  content::BrowserThread::PostTaskAndReplyWithResult(
-      content::BrowserThread::FILE, FROM_HERE,
-      base::Bind(&CreateTemporaryFile, temporary_file_dir_, temporary_file),
-      base::Bind(&DriveFileSyncService::DidGetTemporaryFileForDownload,
-                 AsWeakPtr(), base::Passed(&param)));
-}
-
-void DriveFileSyncService::DidGetTemporaryFileForDownload(
-    scoped_ptr<ProcessRemoteChangeParam> param,
-    bool success) {
-  if (!success) {
-    AbortRemoteSync(param.Pass(), SYNC_FILE_ERROR_FAILED);
-    return;
-  }
-
-  const base::FilePath& temporary_file_path = param->temporary_file.path();
-  std::string resource_id = param->remote_change.resource_id;
-  DCHECK(!temporary_file_path.empty());
-
-  // We should not use the md5 in metadata for FETCH type to avoid the download
-  // finishes due to NOT_MODIFIED.
-  std::string md5_checksum;
-  if (!param->drive_metadata.to_be_fetched())
-    md5_checksum = param->drive_metadata.md5_checksum();
-  api_util_->DownloadFile(
-      resource_id,
-      md5_checksum,
-      temporary_file_path,
-      base::Bind(&DriveFileSyncService::DidDownloadFileForRemoteSync,
-                 AsWeakPtr(),
-                 base::Passed(&param)));
-}
-
-void DriveFileSyncService::DidDownloadFileForRemoteSync(
-    scoped_ptr<ProcessRemoteChangeParam> param,
-    google_apis::GDataErrorCode error,
-    const std::string& md5_checksum,
-    int64 file_size,
-    const base::Time& updated_time) {
-  if (error == google_apis::HTTP_NOT_MODIFIED) {
-    param->sync_action = SYNC_ACTION_NONE;
-    DidApplyRemoteChange(param.Pass(), SYNC_STATUS_OK);
-    return;
-  }
-
-  SyncStatusCode status = GDataErrorCodeToSyncStatusCodeWrapper(error);
-  if (status != SYNC_STATUS_OK) {
-    AbortRemoteSync(param.Pass(), status);
-    return;
-  }
-
-  param->drive_metadata.set_md5_checksum(md5_checksum);
-  const FileChange& change = param->remote_change.change;
-  const base::FilePath& temporary_file_path = param->temporary_file.path();
-  const FileSystemURL& url = param->remote_change.url;
-  remote_change_processor_->ApplyRemoteChange(
-      change, temporary_file_path, url,
-      base::Bind(&DriveFileSyncService::DidApplyRemoteChange,
-                 AsWeakPtr(), base::Passed(&param)));
-}
-
-void DriveFileSyncService::DidApplyRemoteChange(
-    scoped_ptr<ProcessRemoteChangeParam> param,
-    SyncStatusCode status) {
-  if (status != SYNC_STATUS_OK) {
-    AbortRemoteSync(param.Pass(), status);
-    return;
-  }
-
-  fileapi::FileSystemURL url = param->remote_change.url;
-  if (param->remote_change.change.IsDelete()) {
-    DeleteMetadataForRemoteSync(param.Pass());
-    return;
-  }
-
-  const DriveMetadata& drive_metadata = param->drive_metadata;
-  param->drive_metadata.set_resource_id(param->remote_change.resource_id);
-  param->drive_metadata.set_conflicted(false);
-  if (param->remote_change.change.IsFile()) {
-    param->drive_metadata.set_type(DriveMetadata::RESOURCE_TYPE_FILE);
-  } else {
-    DCHECK(IsSyncFSDirectoryOperationEnabled());
-    param->drive_metadata.set_type(DriveMetadata::RESOURCE_TYPE_FOLDER);
-  }
-
-  metadata_store_->UpdateEntry(
-      url, drive_metadata,
-      base::Bind(&DriveFileSyncService::CompleteRemoteSync,
-                 AsWeakPtr(), base::Passed(&param)));
-}
-
-void DriveFileSyncService::DeleteMetadataForRemoteSync(
-    scoped_ptr<ProcessRemoteChangeParam> param) {
-  fileapi::FileSystemURL url = param->remote_change.url;
-  metadata_store_->DeleteEntry(
-      url,
-      base::Bind(&DriveFileSyncService::CompleteRemoteSync,
-                 AsWeakPtr(), base::Passed(&param)));
-}
-
-void DriveFileSyncService::CompleteRemoteSync(
-    scoped_ptr<ProcessRemoteChangeParam> param,
-    SyncStatusCode status) {
-  if (status != SYNC_STATUS_OK) {
-    AbortRemoteSync(param.Pass(), status);
-    return;
-  }
-
-  RemoveRemoteChange(param->remote_change.url);
-
-  if (param->drive_metadata.to_be_fetched()) {
-    // Clear |to_be_fetched| flag since we completed fetching the remote change
-    // and applying it to the local file.
-    DCHECK(!param->drive_metadata.conflicted());
-    param->drive_metadata.set_conflicted(false);
-    param->drive_metadata.set_to_be_fetched(false);
-    metadata_store_->UpdateEntry(
-        param->remote_change.url, param->drive_metadata,
-        base::Bind(&EmptyStatusCallback));
-  }
-
-  GURL origin = param->remote_change.url.origin();
-  int64 changestamp = param->remote_change.changestamp;
-  if (changestamp > 0) {
-    DCHECK(metadata_store_->IsIncrementalSyncOrigin(origin));
-    metadata_store_->SetLargestChangeStamp(
-        changestamp,
-        base::Bind(&DriveFileSyncService::FinalizeRemoteSync,
-                   AsWeakPtr(), base::Passed(&param)));
-    return;
-  }
-
-  if (param->drive_metadata.conflicted())
-    status = SYNC_STATUS_HAS_CONFLICT;
-
-  FinalizeRemoteSync(param.Pass(), status);
-}
-
-void DriveFileSyncService::AbortRemoteSync(
-    scoped_ptr<ProcessRemoteChangeParam> param,
-    SyncStatusCode status) {
-  FinalizeRemoteSync(param.Pass(), status);
-}
-
-void DriveFileSyncService::FinalizeRemoteSync(
-    scoped_ptr<ProcessRemoteChangeParam> param,
-    SyncStatusCode status) {
-  // Clear the local changes. If the operation was resolve-to-local, we should
-  // not clear them here since we added the fake local change to sync with the
-  // remote file.
-  if (param->clear_local_changes) {
-    const FileSystemURL& url = param->remote_change.url;
-    param->clear_local_changes = false;
-    remote_change_processor_->ClearLocalChanges(
-        url, base::Bind(&DriveFileSyncService::FinalizeRemoteSync,
-                        AsWeakPtr(), base::Passed(&param), status));
-    return;
-  }
-
-  param->callback.Run(status, param->remote_change.url);
-  if (status == SYNC_STATUS_OK && param->sync_action != SYNC_ACTION_NONE) {
-    NotifyObserversFileStatusChanged(param->remote_change.url,
-                                     SYNC_FILE_STATUS_SYNCED,
-                                     param->sync_action,
-                                     SYNC_DIRECTION_REMOTE_TO_LOCAL);
-  }
-}
-
-void DriveFileSyncService::HandleConflictForRemoteSync(
-    scoped_ptr<ProcessRemoteChangeParam> param,
-    const base::Time& remote_updated_time,
-    SyncFileType remote_file_type,
-    SyncStatusCode status) {
-  if (status != SYNC_STATUS_OK) {
-    AbortRemoteSync(param.Pass(), status);
-    return;
-  }
-  if (!remote_updated_time.is_null())
-    param->remote_change.updated_time = remote_updated_time;
-  DCHECK(param);
-  const FileSystemURL& url = param->remote_change.url;
-  SyncFileMetadata& local_metadata = param->local_metadata;
-  DriveMetadata& drive_metadata = param->drive_metadata;
-  if (conflict_resolution_ == CONFLICT_RESOLUTION_MANUAL) {
-    param->sync_action = SYNC_ACTION_NONE;
-    MarkConflict(url, &drive_metadata,
-                 base::Bind(&DriveFileSyncService::CompleteRemoteSync,
-                            AsWeakPtr(), base::Passed(&param)));
-    return;
-  }
-
-  DCHECK_EQ(CONFLICT_RESOLUTION_LAST_WRITE_WIN, conflict_resolution_);
-  if (param->remote_change.updated_time.is_null()) {
-    // Get remote file time and call this method again.
-    api_util_->GetResourceEntry(
-        param->remote_change.resource_id,
-        base::Bind(
-            &DriveFileSyncService::DidGetRemoteFileMetadataForRemoteUpdatedTime,
-            AsWeakPtr(),
-            base::Bind(&DriveFileSyncService::HandleConflictForRemoteSync,
-                       AsWeakPtr(),
-                       base::Passed(&param))));
-    return;
-  }
-  if (local_metadata.last_modified >= param->remote_change.updated_time) {
-    // Local win case.
-    util::Log(logging::LOG_VERBOSE, FROM_HERE,
-              "Resolving conflict for remote sync: %s: LOCAL WIN",
-              url.DebugString().c_str());
-    ResolveConflictToLocalForRemoteSync(param.Pass());
-    return;
-  }
-  // Remote win case.
-  // Make sure we reset the conflict flag and start over the remote sync
-  // with empty local changes.
-  util::Log(logging::LOG_VERBOSE, FROM_HERE,
-            "Resolving conflict for remote sync: %s: REMOTE WIN",
-            url.DebugString().c_str());
-  drive_metadata.set_conflicted(false);
-  drive_metadata.set_to_be_fetched(false);
-  drive_metadata.set_type(
-      SyncFileTypeToDriveMetadataResourceType(remote_file_type));
-  metadata_store_->UpdateEntry(
-      url, drive_metadata,
-      base::Bind(&DriveFileSyncService::StartOverRemoteSync,
-                 AsWeakPtr(), base::Passed(&param)));
-  return;
-}
-
-void DriveFileSyncService::ResolveConflictToLocalForRemoteSync(
-    scoped_ptr<ProcessRemoteChangeParam> param) {
-  DCHECK(param);
-  const FileSystemURL& url = param->remote_change.url;
-  param->sync_action = SYNC_ACTION_NONE;
-  param->clear_local_changes = false;
-
-  // Re-add a fake local change to resolve it later in next LocalSync.
-  SyncFileType local_file_type = param->local_metadata.file_type;
-  remote_change_processor_->RecordFakeLocalChange(
-      url,
-      FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE, local_file_type),
-      base::Bind(&DriveFileSyncService::DidResolveConflictToLocalChange,
-                 AsWeakPtr(), base::Passed(&param)));
-}
-
-void DriveFileSyncService::StartOverRemoteSync(
-    scoped_ptr<ProcessRemoteChangeParam> param,
-    SyncStatusCode status) {
-  DCHECK(param);
-  SyncFileMetadata& local_metadata = param->local_metadata;
-  DidPrepareForProcessRemoteChange(
-      param.Pass(), status, local_metadata, FileChangeList());
-}
-
 bool DriveFileSyncService::AppendRemoteChange(
     const GURL& origin,
     const google_apis::ResourceEntry& entry,
@@ -1427,46 +969,28 @@
     DriveMetadata* drive_metadata,
     const SyncStatusCallback& callback) {
   DCHECK(drive_metadata);
-  if (drive_metadata->resource_id().empty()) {
-    // If the file does not have valid drive_metadata in the metadata store
-    // we must have a pending remote change entry.
-    RemoteChangeHandler::RemoteChange remote_change;
-    const bool has_remote_change =
-        remote_change_handler_.GetChangeForURL(url, &remote_change);
-    DCHECK(has_remote_change);
-    drive_metadata->set_resource_id(remote_change.resource_id);
-    drive_metadata->set_md5_checksum(std::string());
-  }
+  DCHECK(!drive_metadata->resource_id().empty());
   drive_metadata->set_conflicted(true);
   drive_metadata->set_to_be_fetched(false);
-  metadata_store_->UpdateEntry(url, *drive_metadata, callback);
+  metadata_store_->UpdateEntry(
+      url, *drive_metadata, base::Bind(
+          &DriveFileSyncService::NotifyConflict,
+          AsWeakPtr(), url, callback));
+}
+
+void DriveFileSyncService::NotifyConflict(
+    const fileapi::FileSystemURL& url,
+    const SyncStatusCallback& callback,
+    SyncStatusCode status) {
+  if (status != SYNC_STATUS_OK) {
+    callback.Run(status);
+    return;
+  }
   NotifyObserversFileStatusChanged(url,
                                    SYNC_FILE_STATUS_CONFLICTING,
                                    SYNC_ACTION_NONE,
                                    SYNC_DIRECTION_NONE);
-}
-
-void DriveFileSyncService::DidGetRemoteFileMetadataForRemoteUpdatedTime(
-    const UpdatedTimeCallback& callback,
-    google_apis::GDataErrorCode error,
-    scoped_ptr<google_apis::ResourceEntry> entry) {
-  SyncStatusCode status = GDataErrorCodeToSyncStatusCodeWrapper(error);
-  if (status == SYNC_FILE_ERROR_NOT_FOUND) {
-    // Returns with very old (time==0.0) last modified date
-    // so that last-write-win policy will just use the other (local) version.
-    callback.Run(base::Time::FromDoubleT(0.0),
-                 SYNC_FILE_TYPE_UNKNOWN, SYNC_STATUS_OK);
-    return;
-  }
-
-  SyncFileType file_type = SYNC_FILE_TYPE_UNKNOWN;
-  if (entry->is_file())
-    file_type = SYNC_FILE_TYPE_FILE;
-  if (entry->is_folder())
-    file_type = SYNC_FILE_TYPE_DIRECTORY;
-
-  // If |file_type| is unknown, just use the other (local) version.
-  callback.Run(entry->updated_time(), file_type, status);
+  callback.Run(status);
 }
 
 SyncStatusCode DriveFileSyncService::GDataErrorCodeToSyncStatusCodeWrapper(
@@ -1500,9 +1024,7 @@
 }
 
 void DriveFileSyncService::OnNotificationReceived() {
-  util::Log(logging::LOG_INFO,
-            FROM_HERE,
-            "Notification received to check for Google Drive updates");
+  VLOG(2) << "Notification received to check for Google Drive updates";
 
   // Likely indicating the network is enabled again.
   UpdateServiceState(REMOTE_SERVICE_OK, "Got push notification for Drive.");
@@ -1513,10 +1035,7 @@
 }
 
 void DriveFileSyncService::OnPushNotificationEnabled(bool enabled) {
-  const char* status = (enabled ? "enabled" : "disabled");
-  util::Log(logging::LOG_INFO,
-            FROM_HERE,
-            "XMPP Push notification is %s", status);
+  VLOG(2) << "XMPP Push notification is " << (enabled ? "enabled" : "disabled");
 }
 
 void DriveFileSyncService::MaybeScheduleNextTask() {
@@ -1684,7 +1203,7 @@
       continue;
 
     std::string resource_id(
-        google_apis::drive::util::ExtractResourceIdFromUrl((*itr)->href()));
+        ::drive::util::ExtractResourceIdFromUrl((*itr)->href()));
     if (resource_id.empty())
       continue;
 
diff --git a/chrome/browser/sync_file_system/drive_file_sync_service.h b/chrome/browser/sync_file_system/drive_file_sync_service.h
index 70b2013..d892ed4 100644
--- a/chrome/browser/sync_file_system/drive_file_sync_service.h
+++ b/chrome/browser/sync_file_system/drive_file_sync_service.h
@@ -16,19 +16,20 @@
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
 #include "base/threading/non_thread_safe.h"
-#include "chrome/browser/google_apis/drive_notification_observer.h"
-#include "chrome/browser/sync_file_system/drive/api_util_interface.h"
+#include "chrome/browser/drive/drive_notification_observer.h"
+#include "chrome/browser/sync_file_system/conflict_resolution_resolver.h"
+#include "chrome/browser/sync_file_system/drive_backend/api_util_interface.h"
 #include "chrome/browser/sync_file_system/drive_metadata_store.h"
 #include "chrome/browser/sync_file_system/local_change_processor.h"
 #include "chrome/browser/sync_file_system/local_sync_operation_resolver.h"
 #include "chrome/browser/sync_file_system/remote_change_handler.h"
 #include "chrome/browser/sync_file_system/remote_file_sync_service.h"
+#include "chrome/browser/sync_file_system/sync_action.h"
+#include "chrome/browser/sync_file_system/sync_direction.h"
 #include "chrome/browser/sync_file_system/sync_file_system.pb.h"
 #include "chrome/browser/sync_file_system/sync_task_manager.h"
 #include "webkit/browser/fileapi/syncable/file_change.h"
-#include "webkit/browser/fileapi/syncable/sync_action.h"
 #include "webkit/browser/fileapi/syncable/sync_callbacks.h"
-#include "webkit/browser/fileapi/syncable/sync_direction.h"
 #include "webkit/browser/fileapi/syncable/sync_status_code.h"
 
 class ExtensionService;
@@ -43,8 +44,9 @@
 
 namespace sync_file_system {
 
-namespace drive {
-class LocalChangeProcessorDelegate;
+namespace drive_backend {
+class LocalSyncDelegate;
+class RemoteSyncDelegate;
 }
 
 class SyncTaskManager;
@@ -53,18 +55,12 @@
 // Owned by SyncFileSystemService (which is a per-profile object).
 class DriveFileSyncService : public RemoteFileSyncService,
                              public LocalChangeProcessor,
-                             public drive::APIUtilObserver,
+                             public drive_backend::APIUtilObserver,
                              public SyncTaskManager::Client,
                              public base::NonThreadSafe,
                              public base::SupportsWeakPtr<DriveFileSyncService>,
-                             public google_apis::DriveNotificationObserver {
+                             public ::drive::DriveNotificationObserver {
  public:
-  enum ConflictResolutionResult {
-    CONFLICT_RESOLUTION_MARK_CONFLICT,
-    CONFLICT_RESOLUTION_LOCAL_WIN,
-    CONFLICT_RESOLUTION_REMOTE_WIN,
-  };
-
   typedef base::Callback<void(const SyncStatusCallback& callback)> Task;
 
   static ConflictResolutionPolicy kDefaultPolicy;
@@ -79,13 +75,14 @@
   static scoped_ptr<DriveFileSyncService> CreateForTesting(
       Profile* profile,
       const base::FilePath& base_dir,
-      scoped_ptr<drive::APIUtilInterface> api_util,
+      scoped_ptr<drive_backend::APIUtilInterface> api_util,
       scoped_ptr<DriveMetadataStore> metadata_store);
 
   // Destroys |sync_service| and passes the ownership of |sync_client| to caller
   // for testing.
-  static scoped_ptr<drive::APIUtilInterface> DestroyAndPassAPIUtilForTesting(
-      scoped_ptr<DriveFileSyncService> sync_service);
+  static scoped_ptr<drive_backend::APIUtilInterface>
+      DestroyAndPassAPIUtilForTesting(
+          scoped_ptr<DriveFileSyncService> sync_service);
 
   // RemoteFileSyncService overrides.
   virtual void AddServiceObserver(Observer* observer) OVERRIDE;
@@ -112,10 +109,11 @@
   virtual bool IsConflicting(const fileapi::FileSystemURL& url) OVERRIDE;
   virtual RemoteServiceState GetCurrentState() const OVERRIDE;
   virtual void GetOriginStatusMap(OriginStatusMap* status_map) OVERRIDE;
-  virtual void GetFileMetadataMap(OriginFileMetadataMap* metadata_map) OVERRIDE;
+  virtual void GetFileMetadataMap(const GURL& origin,
+                                  FileMetadataMap* metadata_map) OVERRIDE;
   virtual void SetSyncEnabled(bool enabled) OVERRIDE;
   virtual SyncStatusCode SetConflictResolutionPolicy(
-      ConflictResolutionPolicy resolution) OVERRIDE;
+      ConflictResolutionPolicy policy) OVERRIDE;
   virtual ConflictResolutionPolicy GetConflictResolutionPolicy() const OVERRIDE;
 
   // LocalChangeProcessor overrides.
@@ -130,7 +128,7 @@
   virtual void OnAuthenticated() OVERRIDE;
   virtual void OnNetworkConnected() OVERRIDE;
 
-  // google_apis::DriveNotificationObserver implementation.
+  // ::drive::DriveNotificationObserver implementation.
   virtual void OnNotificationReceived() OVERRIDE;
   virtual void OnPushNotificationEnabled(bool enabled) OVERRIDE;
 
@@ -147,17 +145,15 @@
 
  private:
   friend class SyncTaskManager;
-  friend class drive::LocalChangeProcessorDelegate;
+  friend class drive_backend::LocalSyncDelegate;
+  friend class drive_backend::RemoteSyncDelegate;
 
-  friend class DriveFileSyncServiceMockTest;
+  friend class DriveFileSyncServiceFakeTest;
   friend class DriveFileSyncServiceSyncTest;
   friend class DriveFileSyncServiceTest;
   struct ApplyLocalChangeParam;
   struct ProcessRemoteChangeParam;
 
-  typedef base::Callback<void(const base::Time& time,
-                              SyncFileType remote_file_type,
-                              SyncStatusCode status)> UpdatedTimeCallback;
   typedef base::Callback<
       void(SyncStatusCode status,
            const std::string& resource_id)> ResourceIdCallback;
@@ -166,11 +162,12 @@
 
   void Initialize(scoped_ptr<SyncTaskManager> task_manager,
                   const SyncStatusCallback& callback);
-  void InitializeForTesting(scoped_ptr<SyncTaskManager> task_manager,
-                            const base::FilePath& base_dir,
-                            scoped_ptr<drive::APIUtilInterface> sync_client,
-                            scoped_ptr<DriveMetadataStore> metadata_store,
-                            const SyncStatusCallback& callback);
+  void InitializeForTesting(
+      scoped_ptr<SyncTaskManager> task_manager,
+      const base::FilePath& base_dir,
+      scoped_ptr<drive_backend::APIUtilInterface> sync_client,
+      scoped_ptr<DriveMetadataStore> metadata_store,
+      const SyncStatusCallback& callback);
 
   void DidInitializeMetadataStore(const SyncStatusCallback& callback,
                                   SyncStatusCode status,
@@ -213,15 +210,6 @@
       const fileapi::FileSystemURL& url,
       const SyncStatusCallback& callback);
 
-  // Local synchronization related methods.
-  ConflictResolutionResult ResolveConflictForLocalSync(
-      SyncFileType local_file_type,
-      const base::Time& local_update_time,
-      SyncFileType remote_file_type,
-      const base::Time& remote_update_time);
-  void DidApplyLocalChange(const SyncStatusCallback& callback,
-                           SyncStatusCode status);
-
   void UpdateRegisteredOrigins();
 
   void StartBatchSync(const SyncStatusCallback& callback);
@@ -249,53 +237,11 @@
       google_apis::GDataErrorCode error,
       scoped_ptr<google_apis::ResourceList> feed);
 
-  // Remote synchronization related methods.
-  void DidPrepareForProcessRemoteChange(
-      scoped_ptr<ProcessRemoteChangeParam> param,
-      SyncStatusCode status,
-      const SyncFileMetadata& metadata,
-      const FileChangeList& changes);
-  void DidResolveConflictToLocalChange(
-      scoped_ptr<ProcessRemoteChangeParam> param,
-      SyncStatusCode status);
-  void DownloadForRemoteSync(
-      scoped_ptr<ProcessRemoteChangeParam> param);
-  void DidGetTemporaryFileForDownload(
-      scoped_ptr<ProcessRemoteChangeParam> param,
-      bool success);
-  void DidDownloadFileForRemoteSync(
-      scoped_ptr<ProcessRemoteChangeParam> param,
-      google_apis::GDataErrorCode error,
-      const std::string& md5_checksum,
-      int64 file_size,
-      const base::Time& updated_time);
-  void DidApplyRemoteChange(
-      scoped_ptr<ProcessRemoteChangeParam> param,
-      SyncStatusCode status);
-  void DidCleanUpForRemoteSync(
-      scoped_ptr<ProcessRemoteChangeParam> param,
-      bool success);
-  void DeleteMetadataForRemoteSync(
-      scoped_ptr<ProcessRemoteChangeParam> param);
-  void CompleteRemoteSync(
-      scoped_ptr<ProcessRemoteChangeParam> param,
-      SyncStatusCode status);
-  void AbortRemoteSync(
-      scoped_ptr<ProcessRemoteChangeParam> param,
-      SyncStatusCode status);
-  void FinalizeRemoteSync(
-      scoped_ptr<ProcessRemoteChangeParam> param,
-      SyncStatusCode status);
-  void HandleConflictForRemoteSync(
-      scoped_ptr<ProcessRemoteChangeParam> param,
-      const base::Time& remote_updated_time,
-      SyncFileType remote_file_change,
-      SyncStatusCode status);
-  void ResolveConflictToLocalForRemoteSync(
-      scoped_ptr<ProcessRemoteChangeParam> param);
-  void StartOverRemoteSync(
-      scoped_ptr<ProcessRemoteChangeParam> param,
-      SyncStatusCode status);
+  void DidProcessRemoteChange(const SyncFileCallback& sync_callback,
+                              const SyncStatusCallback& completion_callback,
+                              SyncStatusCode status);
+  void DidApplyLocalChange(const SyncStatusCallback& callback,
+                           SyncStatusCode status);
 
   // Returns true if |pending_changes_| was updated.
   bool AppendRemoteChange(
@@ -319,14 +265,15 @@
   void RemoveRemoteChange(const fileapi::FileSystemURL& url);
   void MaybeMarkAsIncrementalSyncOrigin(const GURL& origin);
 
+  // TODO(kinuko,tzik): Move this out of DriveFileSyncService.
   void MarkConflict(
       const fileapi::FileSystemURL& url,
       DriveMetadata* drive_metadata,
       const SyncStatusCallback& callback);
-  void DidGetRemoteFileMetadataForRemoteUpdatedTime(
-      const UpdatedTimeCallback& callback,
-      google_apis::GDataErrorCode error,
-      scoped_ptr<google_apis::ResourceEntry> entry);
+  void NotifyConflict(
+      const fileapi::FileSystemURL& url,
+      const SyncStatusCallback& callback,
+      SyncStatusCode status);
 
   // A wrapper implementation to GDataErrorCodeToSyncStatusCode which returns
   // authentication error if the user is not signed in.
@@ -380,13 +327,14 @@
   std::string sync_root_resource_id();
 
   scoped_ptr<DriveMetadataStore> metadata_store_;
-  scoped_ptr<drive::APIUtilInterface> api_util_;
+  scoped_ptr<drive_backend::APIUtilInterface> api_util_;
 
   Profile* profile_;
 
   scoped_ptr<SyncTaskManager> task_manager_;
 
-  scoped_ptr<drive::LocalChangeProcessorDelegate> running_local_sync_task_;
+  scoped_ptr<drive_backend::LocalSyncDelegate> running_local_sync_task_;
+  scoped_ptr<drive_backend::RemoteSyncDelegate> running_remote_sync_task_;
 
   // The current remote service state. This does NOT reflect the
   // sync_enabled_ flag, while GetCurrentState() DOES reflect the flag
@@ -424,7 +372,7 @@
 
   google_apis::GDataErrorCode last_gdata_error_;
 
-  ConflictResolutionPolicy conflict_resolution_;
+  ConflictResolutionResolver conflict_resolution_resolver_;
 
   DISALLOW_COPY_AND_ASSIGN(DriveFileSyncService);
 };
diff --git a/chrome/browser/sync_file_system/drive_file_sync_service_fake_unittest.cc b/chrome/browser/sync_file_system/drive_file_sync_service_fake_unittest.cc
new file mode 100644
index 0000000..4eb71c7
--- /dev/null
+++ b/chrome/browser/sync_file_system/drive_file_sync_service_fake_unittest.cc
@@ -0,0 +1,844 @@
+// 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_file_sync_service.h"
+
+#include <utility>
+
+#include "base/command_line.h"
+#include "base/message_loop/message_loop.h"
+#include "base/message_loop/message_loop_proxy.h"
+#include "chrome/browser/drive/drive_uploader.h"
+#include "chrome/browser/drive/fake_drive_service.h"
+#include "chrome/browser/extensions/test_extension_service.h"
+#include "chrome/browser/extensions/test_extension_system.h"
+#include "chrome/browser/google_apis/drive_api_parser.h"
+#include "chrome/browser/google_apis/gdata_errorcode.h"
+#include "chrome/browser/google_apis/gdata_wapi_parser.h"
+#include "chrome/browser/google_apis/test_util.h"
+#include "chrome/browser/sync_file_system/drive_backend/api_util.h"
+#include "chrome/browser/sync_file_system/drive_backend/fake_drive_service_helper.h"
+#include "chrome/browser/sync_file_system/drive_file_sync_util.h"
+#include "chrome/browser/sync_file_system/drive_metadata_store.h"
+#include "chrome/browser/sync_file_system/file_status_observer.h"
+#include "chrome/browser/sync_file_system/mock_remote_change_processor.h"
+#include "chrome/browser/sync_file_system/sync_direction.h"
+#include "chrome/browser/sync_file_system/sync_file_system.pb.h"
+#include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/extension_builder.h"
+#include "chrome/test/base/testing_profile.h"
+#include "content/public/test/test_browser_thread.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "extensions/common/id_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "webkit/browser/fileapi/syncable/sync_file_metadata.h"
+#include "webkit/browser/fileapi/syncable/syncable_file_system_util.h"
+#include "webkit/common/fileapi/file_system_util.h"
+
+#if defined(OS_CHROMEOS)
+#include "chrome/browser/chromeos/login/user_manager.h"
+#include "chrome/browser/chromeos/settings/cros_settings.h"
+#include "chrome/browser/chromeos/settings/device_settings_service.h"
+#endif
+
+#define FPL(x) FILE_PATH_LITERAL(x)
+
+using ::testing::StrictMock;
+using ::testing::_;
+
+using ::drive::DriveServiceInterface;
+using ::drive::DriveUploaderInterface;
+using ::drive::FakeDriveService;
+
+using extensions::Extension;
+using extensions::DictionaryBuilder;
+using google_apis::GDataErrorCode;
+using google_apis::ResourceEntry;
+
+namespace sync_file_system {
+
+using drive_backend::APIUtil;
+using drive_backend::APIUtilInterface;
+using drive_backend::FakeDriveServiceHelper;
+
+namespace {
+
+const char kExtensionName1[] = "example1";
+const char kExtensionName2[] = "example2";
+
+void DidInitialize(bool* done, SyncStatusCode status, bool created) {
+  EXPECT_FALSE(*done);
+  *done = true;
+  EXPECT_EQ(SYNC_STATUS_OK, status);
+  EXPECT_TRUE(created);
+}
+
+void DidProcessRemoteChange(SyncStatusCode* status_out,
+                            fileapi::FileSystemURL* url_out,
+                            SyncStatusCode status,
+                            const fileapi::FileSystemURL& url) {
+  ASSERT_TRUE(status_out);
+  ASSERT_TRUE(url_out);
+  *status_out = status;
+  *url_out = url;
+}
+
+void ExpectEqStatus(bool* done,
+                    SyncStatusCode expected,
+                    SyncStatusCode actual) {
+  EXPECT_FALSE(*done);
+  *done = true;
+  EXPECT_EQ(expected, actual);
+}
+
+// Mocks adding an installed extension to ExtensionService.
+scoped_refptr<const extensions::Extension> AddTestExtension(
+    ExtensionService* extension_service,
+    const base::FilePath::StringType& extension_name) {
+  std::string id = extensions::id_util::GenerateIdForPath(
+      base::FilePath(extension_name));
+
+  scoped_refptr<const Extension> extension =
+      extensions::ExtensionBuilder().SetManifest(
+          DictionaryBuilder()
+            .Set("name", extension_name)
+            .Set("version", "1.0"))
+          .SetID(id)
+      .Build();
+  extension_service->AddExtension(extension.get());
+  return extension;
+}
+
+// Converts extension_name to extension ID.
+std::string ExtensionNameToId(const std::string& extension_name) {
+  base::FilePath path = base::FilePath::FromUTF8Unsafe(extension_name);
+  return extensions::id_util::GenerateIdForPath(path);
+}
+
+// Converts extension_name to GURL version.
+GURL ExtensionNameToGURL(const std::string& extension_name) {
+  return extensions::Extension::GetBaseURLFromExtensionId(
+      ExtensionNameToId(extension_name));
+}
+
+ACTION(InvokeCompletionCallback) {
+  base::MessageLoopProxy::current()->PostTask(FROM_HERE, arg1);
+}
+
+ACTION(PrepareForRemoteChange_Busy) {
+  base::MessageLoopProxy::current()->PostTask(
+      FROM_HERE,
+      base::Bind(arg1,
+                 SYNC_STATUS_FILE_BUSY,
+                 SyncFileMetadata(),
+                 FileChangeList()));
+}
+
+ACTION(PrepareForRemoteChange_NotFound) {
+  base::MessageLoopProxy::current()->PostTask(
+      FROM_HERE,
+      base::Bind(arg1,
+                 SYNC_STATUS_OK,
+                 SyncFileMetadata(SYNC_FILE_TYPE_UNKNOWN, 0, base::Time()),
+                 FileChangeList()));
+}
+
+ACTION(PrepareForRemoteChange_NotModified) {
+  base::MessageLoopProxy::current()->PostTask(
+      FROM_HERE,
+      base::Bind(arg1,
+                 SYNC_STATUS_OK,
+                 SyncFileMetadata(SYNC_FILE_TYPE_FILE, 0, base::Time()),
+                 FileChangeList()));
+}
+
+ACTION(InvokeDidApplyRemoteChange) {
+  base::MessageLoopProxy::current()->PostTask(
+      FROM_HERE, base::Bind(arg3, SYNC_STATUS_OK));
+}
+
+}  // namespace
+
+class MockFileStatusObserver: public FileStatusObserver {
+ public:
+  MockFileStatusObserver() {}
+  virtual ~MockFileStatusObserver() {}
+
+  MOCK_METHOD4(OnFileStatusChanged,
+               void(const fileapi::FileSystemURL& url,
+                    SyncFileStatus sync_status,
+                    SyncAction action_taken,
+                    SyncDirection direction));
+};
+
+class DriveFileSyncServiceFakeTest : public testing::Test {
+ public:
+  DriveFileSyncServiceFakeTest()
+      : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP),
+        fake_drive_service_(NULL) {
+  }
+
+  virtual void SetUp() OVERRIDE {
+    profile_.reset(new TestingProfile());
+
+    // Add TestExtensionSystem with registered ExtensionIds used in tests.
+    extensions::TestExtensionSystem* extension_system(
+        static_cast<extensions::TestExtensionSystem*>(
+            extensions::ExtensionSystem::Get(profile_.get())));
+    extension_system->CreateExtensionService(
+        CommandLine::ForCurrentProcess(), base::FilePath(), false);
+    extension_service_ = extension_system->Get(
+        profile_.get())->extension_service();
+
+    AddTestExtension(extension_service_, FPL("example1"));
+    AddTestExtension(extension_service_, FPL("example2"));
+
+    RegisterSyncableFileSystem();
+
+    fake_drive_service_ = new FakeDriveService;
+    DriveUploaderInterface* drive_uploader = new ::drive::DriveUploader(
+        fake_drive_service_, base::MessageLoopProxy::current().get());
+
+    fake_drive_helper_.reset(new FakeDriveServiceHelper(
+        fake_drive_service_, drive_uploader));
+
+    api_util_ = APIUtil::CreateForTesting(
+        profile_.get(),
+        scoped_ptr<DriveServiceInterface>(fake_drive_service_),
+        scoped_ptr<DriveUploaderInterface>(drive_uploader)).Pass();
+    metadata_store_.reset(new DriveMetadataStore(
+        fake_drive_helper_->base_dir_path(),
+        base::MessageLoopProxy::current().get()));
+
+    bool done = false;
+    metadata_store_->Initialize(base::Bind(&DidInitialize, &done));
+    base::MessageLoop::current()->RunUntilIdle();
+    EXPECT_TRUE(done);
+
+    fake_drive_service_->LoadResourceListForWapi(
+        "sync_file_system/initialize.json");
+    fake_drive_service()->LoadAccountMetadataForWapi(
+        "sync_file_system/account_metadata.json");
+
+    // Setup the sync root directory.
+    EXPECT_EQ(google_apis::HTTP_CREATED,
+              fake_drive_helper_->AddOrphanedFolder(
+                  APIUtil::GetSyncRootDirectoryName(),
+                  &sync_root_resource_id_));
+    metadata_store()->SetSyncRootDirectory(sync_root_resource_id_);
+  }
+
+  void SetUpDriveSyncService(bool enabled) {
+    sync_service_ = DriveFileSyncService::CreateForTesting(
+        profile_.get(),
+        fake_drive_helper_->base_dir_path(),
+        api_util_.PassAs<APIUtilInterface>(),
+        metadata_store_.Pass()).Pass();
+    sync_service_->AddFileStatusObserver(&mock_file_status_observer_);
+    sync_service_->SetRemoteChangeProcessor(mock_remote_processor());
+    sync_service_->SetSyncEnabled(enabled);
+    base::MessageLoop::current()->RunUntilIdle();
+  }
+
+  virtual void TearDown() OVERRIDE {
+    if (sync_service_) {
+      sync_service_.reset();
+    }
+
+    metadata_store_.reset();
+    api_util_.reset();
+    fake_drive_service_ = NULL;
+
+    RevokeSyncableFileSystem();
+
+    extension_service_ = NULL;
+    profile_.reset();
+    base::MessageLoop::current()->RunUntilIdle();
+  }
+
+  void SetSyncEnabled(bool enabled) {
+    sync_service_->SetSyncEnabled(enabled);
+  }
+
+ protected:
+  void EnableExtension(const std::string& extension_id) {
+    extension_service_->EnableExtension(extension_id);
+  }
+
+  void DisableExtension(const std::string& extension_id) {
+    extension_service_->DisableExtension(
+        extension_id, extensions::Extension::DISABLE_NONE);
+  }
+
+  void UninstallExtension(const std::string& extension_id) {
+    // Call UnloadExtension instead of UninstallExtension since it does
+    // unnecessary cleanup (e.g. deleting extension data) and emits warnings.
+    extension_service_->UnloadExtension(
+        extension_id, extension_misc::UNLOAD_REASON_UNINSTALL);
+  }
+
+  void UpdateRegisteredOrigins() {
+    sync_service_->UpdateRegisteredOrigins();
+    // Wait for completion of uninstalling origin.
+    base::MessageLoop::current()->RunUntilIdle();
+  }
+
+  void VerifySizeOfRegisteredOrigins(size_t b_size,
+                                     size_t i_size,
+                                     size_t d_size) {
+    EXPECT_EQ(b_size, pending_batch_sync_origins()->size());
+    EXPECT_EQ(i_size, metadata_store()->incremental_sync_origins().size());
+    EXPECT_EQ(d_size, metadata_store()->disabled_origins().size());
+  }
+
+  APIUtilInterface* api_util() {
+    if (api_util_)
+      return api_util_.get();
+    return sync_service_->api_util_.get();
+  }
+
+  DriveMetadataStore* metadata_store() {
+    if (metadata_store_)
+      return metadata_store_.get();
+    return sync_service_->metadata_store_.get();
+  }
+
+  FakeDriveService* fake_drive_service() {
+    return fake_drive_service_;
+  }
+
+  StrictMock<MockFileStatusObserver>* mock_file_status_observer() {
+    return &mock_file_status_observer_;
+  }
+
+  StrictMock<MockRemoteChangeProcessor>* mock_remote_processor() {
+    return &mock_remote_processor_;
+  }
+
+  DriveFileSyncService* sync_service() { return sync_service_.get(); }
+  std::map<GURL, std::string>* pending_batch_sync_origins() {
+    return &(sync_service()->pending_batch_sync_origins_);
+  }
+
+  const RemoteChangeHandler& remote_change_handler() const {
+    return sync_service_->remote_change_handler_;
+  }
+
+  fileapi::FileSystemURL CreateURL(const GURL& origin,
+                                   const std::string& filename) {
+    return CreateSyncableFileSystemURL(
+        origin, base::FilePath::FromUTF8Unsafe(filename));
+  }
+
+  void ProcessRemoteChange(SyncStatusCode expected_status,
+                           const fileapi::FileSystemURL& expected_url,
+                           SyncFileStatus expected_sync_file_status,
+                           SyncAction expected_sync_action,
+                           SyncDirection expected_sync_direction) {
+    SyncStatusCode actual_status = SYNC_STATUS_UNKNOWN;
+    fileapi::FileSystemURL actual_url;
+
+    if (expected_sync_file_status != SYNC_FILE_STATUS_UNKNOWN) {
+      EXPECT_CALL(*mock_file_status_observer(),
+                  OnFileStatusChanged(expected_url,
+                                      expected_sync_file_status,
+                                      expected_sync_action,
+                                      expected_sync_direction))
+          .Times(1);
+    }
+
+    sync_service_->ProcessRemoteChange(
+        base::Bind(&DidProcessRemoteChange, &actual_status, &actual_url));
+    base::MessageLoop::current()->RunUntilIdle();
+
+    EXPECT_EQ(expected_status, actual_status);
+    EXPECT_EQ(expected_url, actual_url);
+  }
+
+  bool AppendIncrementalRemoteChangeByResourceId(
+      const std::string& resource_id,
+      const GURL& origin) {
+    scoped_ptr<ResourceEntry> entry;
+    EXPECT_EQ(google_apis::HTTP_SUCCESS,
+              fake_drive_helper_->GetResourceEntry(resource_id, &entry));
+    return sync_service_->AppendRemoteChange(origin, *entry, 12345);
+  }
+
+  bool AppendIncrementalRemoteChange(
+      const GURL& origin,
+      const base::FilePath& path,
+      bool is_deleted,
+      const std::string& resource_id,
+      int64 changestamp,
+      const std::string& remote_file_md5) {
+    return sync_service_->AppendRemoteChangeInternal(
+        origin, path, is_deleted, resource_id,
+        changestamp, remote_file_md5, base::Time(),
+        SYNC_FILE_TYPE_FILE);
+  }
+
+  std::string SetUpOriginRootDirectory(const char* extension_name) {
+    EXPECT_TRUE(!sync_root_resource_id_.empty());
+
+    std::string origin_root_resource_id;
+    EXPECT_EQ(google_apis::HTTP_CREATED,
+              fake_drive_helper_->AddFolder(
+                  sync_root_resource_id_,
+                  ExtensionNameToId(extension_name),
+                  &origin_root_resource_id));
+
+    metadata_store()->AddIncrementalSyncOrigin(
+        ExtensionNameToGURL(extension_name), origin_root_resource_id);
+    return origin_root_resource_id;
+  }
+
+  void TestRegisterNewOrigin();
+  void TestRegisterExistingOrigin();
+  void TestRegisterOriginWithSyncDisabled();
+  void TestUnregisterOrigin();
+  void TestUpdateRegisteredOrigins();
+  void TestRemoteChange_NoChange();
+  void TestRemoteChange_Busy();
+  void TestRemoteChange_NewFile();
+  void TestRemoteChange_UpdateFile();
+  void TestRemoteChange_Override();
+  void TestRemoteChange_Folder();
+
+ private:
+  content::TestBrowserThreadBundle thread_bundle_;
+
+  scoped_ptr<TestingProfile> profile_;
+
+  std::string sync_root_resource_id_;
+
+#if defined OS_CHROMEOS
+  chromeos::ScopedTestDeviceSettingsService test_device_settings_service_;
+  chromeos::ScopedTestCrosSettings test_cros_settings_;
+  chromeos::ScopedTestUserManager test_user_manager_;
+#endif
+
+  scoped_ptr<DriveFileSyncService> sync_service_;
+
+  // Not owned.
+  ExtensionService* extension_service_;
+
+  FakeDriveService* fake_drive_service_;
+  scoped_ptr<FakeDriveServiceHelper> fake_drive_helper_;
+
+  StrictMock<MockFileStatusObserver> mock_file_status_observer_;
+  StrictMock<MockRemoteChangeProcessor> mock_remote_processor_;
+
+  scoped_ptr<APIUtil> api_util_;
+  scoped_ptr<DriveMetadataStore> metadata_store_;
+
+  DISALLOW_COPY_AND_ASSIGN(DriveFileSyncServiceFakeTest);
+};
+
+#if !defined(OS_ANDROID)
+
+void DriveFileSyncServiceFakeTest::TestRegisterNewOrigin() {
+  SetUpDriveSyncService(true);
+  bool done = false;
+  sync_service()->RegisterOriginForTrackingChanges(
+      ExtensionNameToGURL(kExtensionName1),
+      base::Bind(&ExpectEqStatus, &done, SYNC_STATUS_OK));
+  base::MessageLoop::current()->RunUntilIdle();
+  EXPECT_TRUE(done);
+
+  VerifySizeOfRegisteredOrigins(0u, 1u, 0u);
+  EXPECT_TRUE(!remote_change_handler().HasChanges());
+}
+
+void DriveFileSyncServiceFakeTest::TestRegisterExistingOrigin() {
+  const std::string origin_resource_id =
+      SetUpOriginRootDirectory(kExtensionName1);
+
+  std::string file_id;
+  EXPECT_EQ(google_apis::HTTP_SUCCESS,
+            fake_drive_helper_->AddFile(
+                origin_resource_id, "1.txt", "data1", &file_id));
+  EXPECT_EQ(google_apis::HTTP_SUCCESS,
+            fake_drive_helper_->AddFile(
+                origin_resource_id, "2.txt", "data2", &file_id));
+  EXPECT_EQ(google_apis::HTTP_SUCCESS,
+            fake_drive_helper_->AddFile(
+                origin_resource_id, "3.txt", "data3", &file_id));
+
+  SetUpDriveSyncService(true);
+
+  bool done = false;
+  sync_service()->RegisterOriginForTrackingChanges(
+      ExtensionNameToGURL(kExtensionName1),
+      base::Bind(&ExpectEqStatus, &done, SYNC_STATUS_OK));
+  base::MessageLoop::current()->RunUntilIdle();
+  EXPECT_TRUE(done);
+
+  // The origin should be registered as an incremental sync origin.
+  VerifySizeOfRegisteredOrigins(0u, 1u, 0u);
+
+  // There are 3 items to sync.
+  EXPECT_EQ(3u, remote_change_handler().ChangesSize());
+}
+
+void DriveFileSyncServiceFakeTest::TestRegisterOriginWithSyncDisabled() {
+  // Usually the sync service starts here, but since we're setting up a drive
+  // service with sync disabled sync doesn't start (while register origin should
+  // still return OK).
+  SetUpDriveSyncService(false);
+
+  bool done = false;
+  sync_service()->RegisterOriginForTrackingChanges(
+      ExtensionNameToGURL(kExtensionName1),
+      base::Bind(&ExpectEqStatus, &done, SYNC_STATUS_OK));
+  base::MessageLoop::current()->RunUntilIdle();
+  EXPECT_TRUE(done);
+
+  // We must not have started batch sync for the newly registered origin,
+  // so it should still be in the batch_sync_origins.
+  VerifySizeOfRegisteredOrigins(1u, 0u, 0u);
+  EXPECT_TRUE(!remote_change_handler().HasChanges());
+}
+
+void DriveFileSyncServiceFakeTest::TestUnregisterOrigin() {
+  SetUpOriginRootDirectory(kExtensionName1);
+  SetUpOriginRootDirectory(kExtensionName2);
+
+  SetUpDriveSyncService(true);
+
+  VerifySizeOfRegisteredOrigins(0u, 2u, 0u);
+  EXPECT_EQ(0u, remote_change_handler().ChangesSize());
+
+  bool done = false;
+  sync_service()->UnregisterOriginForTrackingChanges(
+      ExtensionNameToGURL(kExtensionName1),
+      base::Bind(&ExpectEqStatus, &done, SYNC_STATUS_OK));
+  base::MessageLoop::current()->RunUntilIdle();
+  EXPECT_TRUE(done);
+
+  VerifySizeOfRegisteredOrigins(0u, 1u, 0u);
+  EXPECT_TRUE(!remote_change_handler().HasChanges());
+}
+
+void DriveFileSyncServiceFakeTest::TestUpdateRegisteredOrigins() {
+  SetUpOriginRootDirectory(kExtensionName1);
+  SetUpOriginRootDirectory(kExtensionName2);
+  SetUpDriveSyncService(true);
+
+  // [1] Both extensions and origins are enabled. Nothing to do.
+  VerifySizeOfRegisteredOrigins(0u, 2u, 0u);
+  UpdateRegisteredOrigins();
+  VerifySizeOfRegisteredOrigins(0u, 2u, 0u);
+
+  // [2] Extension 1 should move to disabled list.
+  DisableExtension(ExtensionNameToId(kExtensionName1));
+  UpdateRegisteredOrigins();
+  VerifySizeOfRegisteredOrigins(0u, 1u, 1u);
+
+  // [3] Make sure that state remains the same, nothing should change.
+  UpdateRegisteredOrigins();
+  VerifySizeOfRegisteredOrigins(0u, 1u, 1u);
+
+  // [4] Uninstall Extension 2.
+  UninstallExtension(ExtensionNameToId(kExtensionName2));
+  UpdateRegisteredOrigins();
+  VerifySizeOfRegisteredOrigins(0u, 0u, 1u);
+
+  // [5] Re-enable Extension 1. It moves back to batch and not to incremental.
+  EnableExtension(ExtensionNameToId(kExtensionName1));
+  UpdateRegisteredOrigins();
+  VerifySizeOfRegisteredOrigins(1u, 0u, 0u);
+}
+
+void DriveFileSyncServiceFakeTest::TestRemoteChange_NoChange() {
+  SetUpDriveSyncService(true);
+
+  ProcessRemoteChange(SYNC_STATUS_NO_CHANGE_TO_SYNC,
+                      fileapi::FileSystemURL(),
+                      SYNC_FILE_STATUS_UNKNOWN,
+                      SYNC_ACTION_NONE,
+                      SYNC_DIRECTION_NONE);
+  VerifySizeOfRegisteredOrigins(0u, 0u, 0u);
+  EXPECT_TRUE(!remote_change_handler().HasChanges());
+}
+
+void DriveFileSyncServiceFakeTest::TestRemoteChange_Busy() {
+  const char kFileName[] = "File 1.txt";
+  const GURL origin = ExtensionNameToGURL(kExtensionName1);
+
+  const std::string origin_resource_id =
+      SetUpOriginRootDirectory(kExtensionName1);
+
+  EXPECT_CALL(*mock_remote_processor(),
+              PrepareForProcessRemoteChange(CreateURL(origin, kFileName), _))
+      .WillOnce(PrepareForRemoteChange_Busy());
+  EXPECT_CALL(*mock_remote_processor(),
+              ClearLocalChanges(CreateURL(origin, kFileName), _))
+      .WillOnce(InvokeCompletionCallback());
+
+  SetUpDriveSyncService(true);
+
+  std::string resource_id;
+  EXPECT_EQ(google_apis::HTTP_SUCCESS,
+            fake_drive_helper_->AddFile(
+                origin_resource_id, kFileName, "test data", &resource_id));
+  EXPECT_TRUE(AppendIncrementalRemoteChangeByResourceId(resource_id, origin));
+
+  ProcessRemoteChange(SYNC_STATUS_FILE_BUSY,
+                      CreateURL(origin, kFileName),
+                      SYNC_FILE_STATUS_UNKNOWN,
+                      SYNC_ACTION_NONE,
+                      SYNC_DIRECTION_NONE);
+}
+
+void DriveFileSyncServiceFakeTest::TestRemoteChange_NewFile() {
+  const char kFileName[] = "File 1.txt";
+  const GURL origin = ExtensionNameToGURL(kExtensionName1);
+
+  const std::string origin_resource_id =
+      SetUpOriginRootDirectory(kExtensionName1);
+
+  EXPECT_CALL(*mock_remote_processor(),
+              PrepareForProcessRemoteChange(CreateURL(origin, kFileName), _))
+      .WillOnce(PrepareForRemoteChange_NotFound());
+  EXPECT_CALL(*mock_remote_processor(),
+              ClearLocalChanges(CreateURL(origin, kFileName), _))
+      .WillOnce(InvokeCompletionCallback());
+
+  EXPECT_CALL(*mock_remote_processor(),
+              ApplyRemoteChange(_, _, CreateURL(origin, kFileName), _))
+      .WillOnce(InvokeDidApplyRemoteChange());
+
+  SetUpDriveSyncService(true);
+
+  std::string resource_id;
+  EXPECT_EQ(google_apis::HTTP_SUCCESS,
+            fake_drive_helper_->AddFile(
+                origin_resource_id, kFileName, "test data", &resource_id));
+  EXPECT_TRUE(AppendIncrementalRemoteChangeByResourceId(resource_id, origin));
+
+  ProcessRemoteChange(SYNC_STATUS_OK,
+                      CreateURL(origin, kFileName),
+                      SYNC_FILE_STATUS_SYNCED,
+                      SYNC_ACTION_ADDED,
+                      SYNC_DIRECTION_REMOTE_TO_LOCAL);
+}
+
+void DriveFileSyncServiceFakeTest::TestRemoteChange_UpdateFile() {
+  const char kFileName[] = "File 1.txt";
+  const GURL origin = ExtensionNameToGURL(kExtensionName1);
+
+  const std::string origin_resource_id =
+      SetUpOriginRootDirectory(kExtensionName1);
+
+  EXPECT_CALL(*mock_remote_processor(),
+              PrepareForProcessRemoteChange(CreateURL(origin, kFileName), _))
+      .WillOnce(PrepareForRemoteChange_NotModified());
+  EXPECT_CALL(*mock_remote_processor(),
+              ClearLocalChanges(CreateURL(origin, kFileName), _))
+      .WillOnce(InvokeCompletionCallback());
+
+  EXPECT_CALL(*mock_remote_processor(),
+              ApplyRemoteChange(_, _, CreateURL(origin, kFileName), _))
+      .WillOnce(InvokeDidApplyRemoteChange());
+
+  SetUpDriveSyncService(true);
+
+  std::string resource_id;
+  EXPECT_EQ(google_apis::HTTP_SUCCESS,
+            fake_drive_helper_->AddFile(
+                origin_resource_id, kFileName, "test data", &resource_id));
+  EXPECT_TRUE(AppendIncrementalRemoteChangeByResourceId(resource_id, origin));
+
+  ProcessRemoteChange(SYNC_STATUS_OK,
+                      CreateURL(origin, kFileName),
+                      SYNC_FILE_STATUS_SYNCED,
+                      SYNC_ACTION_UPDATED,
+                      SYNC_DIRECTION_REMOTE_TO_LOCAL);
+}
+
+void DriveFileSyncServiceFakeTest::TestRemoteChange_Override() {
+  const base::FilePath kFilePath(FPL("File 1.txt"));
+  const std::string kFileResourceId("file:2_file_resource_id");
+  const std::string kFileResourceId2("file:2_file_resource_id_2");
+  const GURL origin = ExtensionNameToGURL(kExtensionName1);
+
+  SetUpOriginRootDirectory(kExtensionName1);
+  SetUpDriveSyncService(true);
+
+  EXPECT_TRUE(AppendIncrementalRemoteChange(
+      origin, kFilePath, false /* is_deleted */,
+      kFileResourceId, 2, "remote_file_md5"));
+
+  // Expect to drop this change since there is another newer change on the
+  // queue.
+  EXPECT_FALSE(AppendIncrementalRemoteChange(
+      origin, kFilePath, false /* is_deleted */,
+      kFileResourceId, 1, "remote_file_md5_2"));
+
+  // Expect to drop this change since it has the same md5 with the previous one.
+  EXPECT_FALSE(AppendIncrementalRemoteChange(
+      origin, kFilePath, false /* is_deleted */,
+      kFileResourceId, 4, "remote_file_md5"));
+
+  // This should not cause browser crash.
+  EXPECT_FALSE(AppendIncrementalRemoteChange(
+      origin, kFilePath, false /* is_deleted */,
+      kFileResourceId, 4, "remote_file_md5"));
+
+  // Expect to drop these changes since they have different resource IDs with
+  // the previous ones.
+  EXPECT_FALSE(AppendIncrementalRemoteChange(
+      origin, kFilePath, false /* is_deleted */,
+      kFileResourceId2, 5, "updated_file_md5"));
+  EXPECT_FALSE(AppendIncrementalRemoteChange(
+      origin, kFilePath, true /* is_deleted */,
+      kFileResourceId2, 5, "deleted_file_md5"));
+
+  // Push delete change.
+  EXPECT_TRUE(AppendIncrementalRemoteChange(
+      origin, kFilePath, true /* is_deleted */,
+      kFileResourceId, 6, "deleted_file_md5"));
+
+  // Expect to drop this delete change since it has a different resource ID with
+  // the previous one.
+  EXPECT_FALSE(AppendIncrementalRemoteChange(
+      origin, kFilePath, true /* is_deleted */,
+      kFileResourceId2, 7, "deleted_file_md5"));
+
+  // Expect not to drop this change even if it has a different resource ID with
+  // the previous one.
+  EXPECT_TRUE(AppendIncrementalRemoteChange(
+      origin, kFilePath, false /* is_deleted */,
+      kFileResourceId2, 8, "updated_file_md5"));
+}
+
+void DriveFileSyncServiceFakeTest::TestRemoteChange_Folder() {
+  const std::string origin_resource_id =
+      SetUpOriginRootDirectory(kExtensionName1);
+  SetUpDriveSyncService(true);
+
+  std::string resource_id;
+  EXPECT_EQ(google_apis::HTTP_CREATED,
+            fake_drive_helper_->AddFolder(
+                origin_resource_id, "test_dir", &resource_id));
+
+  // Expect to drop this change for file.
+  EXPECT_FALSE(AppendIncrementalRemoteChangeByResourceId(
+      resource_id, ExtensionNameToGURL(kExtensionName1)));
+}
+
+TEST_F(DriveFileSyncServiceFakeTest, RegisterNewOrigin) {
+  ASSERT_FALSE(IsDriveAPIDisabled());
+  TestRegisterNewOrigin();
+}
+
+TEST_F(DriveFileSyncServiceFakeTest, RegisterNewOrigin_WAPI) {
+  ScopedDisableDriveAPI disable_drive_api;
+  TestRegisterNewOrigin();
+}
+
+TEST_F(DriveFileSyncServiceFakeTest, RegisterExistingOrigin) {
+  ASSERT_FALSE(IsDriveAPIDisabled());
+  TestRegisterExistingOrigin();
+}
+
+TEST_F(DriveFileSyncServiceFakeTest, RegisterExistingOrigin_WAPI) {
+  ScopedDisableDriveAPI disable_drive_api;
+  TestRegisterExistingOrigin();
+}
+
+TEST_F(DriveFileSyncServiceFakeTest, RegisterOriginWithSyncDisabled) {
+  ASSERT_FALSE(IsDriveAPIDisabled());
+  TestRegisterOriginWithSyncDisabled();
+}
+
+TEST_F(DriveFileSyncServiceFakeTest, RegisterOriginWithSyncDisabled_WAPI) {
+  ScopedDisableDriveAPI disable_drive_api;
+  TestRegisterOriginWithSyncDisabled();
+}
+
+TEST_F(DriveFileSyncServiceFakeTest, UnregisterOrigin) {
+  ASSERT_FALSE(IsDriveAPIDisabled());
+  TestUnregisterOrigin();
+}
+
+TEST_F(DriveFileSyncServiceFakeTest, UnregisterOrigin_WAPI) {
+  ScopedDisableDriveAPI disable_drive_api;
+  TestUnregisterOrigin();
+}
+
+TEST_F(DriveFileSyncServiceFakeTest, UpdateRegisteredOrigins) {
+  ASSERT_FALSE(IsDriveAPIDisabled());
+  TestUpdateRegisteredOrigins();
+}
+
+TEST_F(DriveFileSyncServiceFakeTest, UpdateRegisteredOrigins_WAPI) {
+  ScopedDisableDriveAPI disable_drive_api;
+  TestUpdateRegisteredOrigins();
+}
+
+TEST_F(DriveFileSyncServiceFakeTest, RemoteChange_NoChange) {
+  ASSERT_FALSE(IsDriveAPIDisabled());
+  TestRemoteChange_NoChange();
+}
+
+TEST_F(DriveFileSyncServiceFakeTest, RemoteChange_NoChange_WAPI) {
+  ScopedDisableDriveAPI disable_drive_api;
+  TestRemoteChange_NoChange();
+}
+
+TEST_F(DriveFileSyncServiceFakeTest, RemoteChange_Busy) {
+  ASSERT_FALSE(IsDriveAPIDisabled());
+  TestRemoteChange_Busy();
+}
+
+TEST_F(DriveFileSyncServiceFakeTest, RemoteChange_Busy_WAPI) {
+  ScopedDisableDriveAPI disable_drive_api;
+  TestRemoteChange_Busy();
+}
+
+TEST_F(DriveFileSyncServiceFakeTest, RemoteChange_NewFile) {
+  ASSERT_FALSE(IsDriveAPIDisabled());
+  TestRemoteChange_NewFile();
+}
+
+TEST_F(DriveFileSyncServiceFakeTest, RemoteChange_NewFile_WAPI) {
+  ScopedDisableDriveAPI disable_drive_api;
+  TestRemoteChange_NewFile();
+}
+
+TEST_F(DriveFileSyncServiceFakeTest, RemoteChange_UpdateFile) {
+  ASSERT_FALSE(IsDriveAPIDisabled());
+  TestRemoteChange_UpdateFile();
+}
+
+TEST_F(DriveFileSyncServiceFakeTest, RemoteChange_UpdateFile_WAPI) {
+  ScopedDisableDriveAPI disable_drive_api;
+  TestRemoteChange_UpdateFile();
+}
+
+TEST_F(DriveFileSyncServiceFakeTest, RemoteChange_Override) {
+  ASSERT_FALSE(IsDriveAPIDisabled());
+  TestRemoteChange_Override();
+}
+
+TEST_F(DriveFileSyncServiceFakeTest, RemoteChange_Override_WAPI) {
+  ScopedDisableDriveAPI disable_drive_api;
+  TestRemoteChange_Override();
+}
+
+TEST_F(DriveFileSyncServiceFakeTest, RemoteChange_Folder) {
+  ASSERT_FALSE(IsDriveAPIDisabled());
+  TestRemoteChange_Folder();
+}
+
+TEST_F(DriveFileSyncServiceFakeTest, RemoteChange_Folder_WAPI) {
+  ScopedDisableDriveAPI disable_drive_api;
+  TestRemoteChange_Folder();
+}
+
+#endif  // !defined(OS_ANDROID)
+
+}  // namespace sync_file_system
diff --git a/chrome/browser/sync_file_system/drive_file_sync_service_mock_unittest.cc b/chrome/browser/sync_file_system/drive_file_sync_service_mock_unittest.cc
deleted file mode 100644
index 94d7d10..0000000
--- a/chrome/browser/sync_file_system/drive_file_sync_service_mock_unittest.cc
+++ /dev/null
@@ -1,1023 +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/sync_file_system/drive_file_sync_service.h"
-
-#include <utility>
-
-#include "base/command_line.h"
-#include "base/message_loop.h"
-#include "base/message_loop/message_loop_proxy.h"
-#include "chrome/browser/drive/drive_uploader.h"
-#include "chrome/browser/drive/mock_drive_service.h"
-#include "chrome/browser/extensions/test_extension_service.h"
-#include "chrome/browser/extensions/test_extension_system.h"
-#include "chrome/browser/google_apis/drive_api_parser.h"
-#include "chrome/browser/google_apis/gdata_errorcode.h"
-#include "chrome/browser/google_apis/gdata_wapi_parser.h"
-#include "chrome/browser/google_apis/test_util.h"
-#include "chrome/browser/sync_file_system/drive/api_util.h"
-#include "chrome/browser/sync_file_system/drive_file_sync_util.h"
-#include "chrome/browser/sync_file_system/drive_metadata_store.h"
-#include "chrome/browser/sync_file_system/file_status_observer.h"
-#include "chrome/browser/sync_file_system/mock_remote_change_processor.h"
-#include "chrome/browser/sync_file_system/sync_file_system.pb.h"
-#include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/extension_builder.h"
-#include "chrome/test/base/testing_profile.h"
-#include "content/public/test/test_browser_thread.h"
-#include "extensions/common/id_util.h"
-#include "net/base/escape.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "webkit/browser/fileapi/syncable/sync_direction.h"
-#include "webkit/browser/fileapi/syncable/sync_file_metadata.h"
-#include "webkit/browser/fileapi/syncable/syncable_file_system_util.h"
-#include "webkit/common/fileapi/file_system_util.h"
-
-#if defined(OS_CHROMEOS)
-#include "chrome/browser/chromeos/login/user_manager.h"
-#include "chrome/browser/chromeos/settings/cros_settings.h"
-#include "chrome/browser/chromeos/settings/device_settings_service.h"
-#endif
-
-#define FPL(x) FILE_PATH_LITERAL(x)
-
-using ::testing::AnyNumber;
-using ::testing::AtLeast;
-using ::testing::AtMost;
-using ::testing::InSequence;
-using ::testing::Return;
-using ::testing::NiceMock;
-using ::testing::Sequence;
-using ::testing::StrictMock;
-using ::testing::_;
-
-using google_apis::ResourceEntry;
-using google_apis::DriveServiceInterface;
-using google_apis::DriveUploaderInterface;
-using google_apis::test_util::LoadJSONFile;
-
-using extensions::Extension;
-using extensions::DictionaryBuilder;
-using extensions::ListBuilder;
-
-namespace sync_file_system {
-
-namespace {
-
-const char kRootResourceId[] = "folder:root";
-
-base::FilePath::StringType ASCIIToFilePathString(const std::string& path) {
-  return base::FilePath().AppendASCII(path).value();
-}
-
-void DidInitialize(bool* done, SyncStatusCode status, bool created) {
-  EXPECT_FALSE(*done);
-  *done = true;
-  EXPECT_EQ(SYNC_STATUS_OK, status);
-  EXPECT_TRUE(created);
-}
-
-void DidGetSyncRoot(bool* done,
-                    SyncStatusCode status,
-                    const std::string& resource_id) {
-  EXPECT_FALSE(*done);
-  *done = true;
-}
-
-void ExpectEqStatus(bool* done,
-                    SyncStatusCode expected,
-                    SyncStatusCode actual) {
-  EXPECT_FALSE(*done);
-  *done = true;
-  EXPECT_EQ(expected, actual);
-}
-
-void ExpectOkStatus(SyncStatusCode status) {
-  EXPECT_EQ(SYNC_STATUS_OK, status);
-}
-
-// Mocks adding an installed extension to ExtensionService.
-scoped_refptr<const extensions::Extension> AddTestExtension(
-    ExtensionService* extension_service,
-    const base::FilePath::StringType& extension_name) {
-  std::string id = extensions::id_util::GenerateIdForPath(
-      base::FilePath(extension_name));
-
-  scoped_refptr<const Extension> extension =
-      extensions::ExtensionBuilder().SetManifest(
-          DictionaryBuilder()
-            .Set("name", extension_name)
-            .Set("version", "1.0"))
-          .SetID(id)
-      .Build();
-  extension_service->AddExtension(extension.get());
-  return extension;
-}
-
-// Converts extension_name to GURL version.
-GURL ExtensionNameToGURL(const base::FilePath::StringType& extension_name) {
-  std::string id = extensions::id_util::GenerateIdForPath(
-      base::FilePath(extension_name));
-  return extensions::Extension::GetBaseURLFromExtensionId(id);
-}
-
-ACTION(InvokeCompletionCallback) {
-  base::MessageLoopProxy::current()->PostTask(FROM_HERE, arg1);
-}
-
-// Invoke |arg2| as a EntryActionCallback.
-ACTION_P(InvokeEntryActionCallback, error) {
-  base::MessageLoopProxy::current()->PostTask(
-      FROM_HERE, base::Bind(arg2, error));
-  return google_apis::CancelCallback();
-}
-
-// Invokes |arg0| as a GetDataCallback.
-ACTION_P2(InvokeGetAboutResourceCallback0, error, result) {
-  scoped_ptr<google_apis::AboutResource> about_resource(result.Pass());
-  base::MessageLoopProxy::current()->PostTask(
-      FROM_HERE,
-      base::Bind(arg0, error, base::Passed(&about_resource)));
-  return google_apis::CancelCallback();
-}
-
-// Invokes |arg1| as a GetResourceEntryCallback.
-ACTION_P2(InvokeGetResourceEntryCallback1, error, result) {
-  scoped_ptr<google_apis::ResourceEntry> entry(result.Pass());
-  base::MessageLoopProxy::current()->PostTask(
-      FROM_HERE,
-      base::Bind(arg1, error, base::Passed(&entry)));
-  return google_apis::CancelCallback();
-}
-
-// Invokes |arg2| as a GetResourceEntryCallback.
-ACTION_P2(InvokeGetResourceEntryCallback2, error, result) {
-  scoped_ptr<google_apis::ResourceEntry> entry(result.Pass());
-  base::MessageLoopProxy::current()->PostTask(
-      FROM_HERE,
-      base::Bind(arg2, error, base::Passed(&entry)));
-  return google_apis::CancelCallback();
-}
-
-// Invokes |arg1| as a GetResourceListCallback.
-ACTION_P2(InvokeGetResourceListCallback1, error, result) {
-  scoped_ptr<google_apis::ResourceList> resource_list(result.Pass());
-  base::MessageLoopProxy::current()->PostTask(
-      FROM_HERE,
-      base::Bind(arg1, error, base::Passed(&resource_list)));
-  return google_apis::CancelCallback();
-}
-
-// Invokes |arg2| as a GetResourceListCallback.
-ACTION_P2(InvokeGetResourceListCallback2, error, result) {
-  scoped_ptr<google_apis::ResourceList> resource_list(result.Pass());
-  base::MessageLoopProxy::current()->PostTask(
-      FROM_HERE,
-      base::Bind(arg2, error, base::Passed(&resource_list)));
-  return google_apis::CancelCallback();
-}
-
-ACTION(PrepareForRemoteChange_Busy) {
-  base::MessageLoopProxy::current()->PostTask(
-      FROM_HERE,
-      base::Bind(arg1,
-                 SYNC_STATUS_FILE_BUSY,
-                 SyncFileMetadata(),
-                 FileChangeList()));
-}
-
-ACTION(PrepareForRemoteChange_NotFound) {
-  base::MessageLoopProxy::current()->PostTask(
-      FROM_HERE,
-      base::Bind(arg1,
-                 SYNC_STATUS_OK,
-                 SyncFileMetadata(SYNC_FILE_TYPE_UNKNOWN, 0, base::Time()),
-                 FileChangeList()));
-}
-
-ACTION(PrepareForRemoteChange_NotModified) {
-  base::MessageLoopProxy::current()->PostTask(
-      FROM_HERE,
-      base::Bind(arg1,
-                 SYNC_STATUS_OK,
-                 SyncFileMetadata(SYNC_FILE_TYPE_FILE, 0, base::Time()),
-                 FileChangeList()));
-}
-
-ACTION(InvokeDidDownloadFile) {
-  base::MessageLoopProxy::current()->PostTask(
-      FROM_HERE, base::Bind(arg3, google_apis::HTTP_SUCCESS, arg1));
-  return google_apis::CancelCallback();
-}
-
-ACTION(InvokeDidApplyRemoteChange) {
-  base::MessageLoopProxy::current()->PostTask(
-      FROM_HERE, base::Bind(arg3, SYNC_STATUS_OK));
-}
-
-}  // namespace
-
-class MockRemoteServiceObserver : public RemoteFileSyncService::Observer {
- public:
-  MockRemoteServiceObserver() {}
-  virtual ~MockRemoteServiceObserver() {}
-
-  // LocalChangeProcessor override.
-  MOCK_METHOD1(OnRemoteChangeQueueUpdated,
-               void(int64 pending_changes));
-  MOCK_METHOD2(OnRemoteServiceStateUpdated,
-               void(RemoteServiceState state,
-                    const std::string& description));
-};
-
-class MockFileStatusObserver: public FileStatusObserver {
- public:
-  MockFileStatusObserver() {}
-  virtual ~MockFileStatusObserver() {}
-
-  MOCK_METHOD4(OnFileStatusChanged,
-               void(const fileapi::FileSystemURL& url,
-                    SyncFileStatus sync_status,
-                    SyncAction action_taken,
-                    SyncDirection direction));
-};
-
-class DriveFileSyncServiceMockTest : public testing::Test {
- public:
-  DriveFileSyncServiceMockTest()
-      : ui_thread_(content::BrowserThread::UI, &message_loop_),
-        file_thread_(content::BrowserThread::FILE, &message_loop_),
-        mock_drive_service_(NULL) {
-  }
-
-  virtual void SetUp() OVERRIDE {
-    profile_.reset(new TestingProfile());
-
-    // Add TestExtensionSystem with registered ExtensionIds used in tests.
-    extensions::TestExtensionSystem* extension_system(
-        static_cast<extensions::TestExtensionSystem*>(
-            extensions::ExtensionSystem::Get(profile_.get())));
-    extension_system->CreateExtensionService(
-        CommandLine::ForCurrentProcess(), base::FilePath(), false);
-    extension_service_ = extension_system->Get(
-        profile_.get())->extension_service();
-
-    AddTestExtension(extension_service_, FPL("example1"));
-    AddTestExtension(extension_service_, FPL("example2"));
-
-    SetDisableDriveAPI(true);
-    RegisterSyncableFileSystem();
-
-    mock_drive_service_ = new NiceMock<google_apis::MockDriveService>;
-
-    EXPECT_CALL(*mock_drive_service(), Initialize(profile_.get()));
-    EXPECT_CALL(*mock_drive_service(), AddObserver(_));
-
-    // Expect to call GetRootResourceId and RemoveResourceFromDirectory to
-    // ensure the sync root directory is not in 'My Drive' directory.
-    EXPECT_CALL(*mock_drive_service(), GetRootResourceId())
-        .WillRepeatedly(Return(kRootResourceId));
-    EXPECT_CALL(*mock_drive_service(),
-                RemoveResourceFromDirectory(kRootResourceId, _, _))
-        .Times(AnyNumber());
-
-    api_util_ = drive::APIUtil::CreateForTesting(
-        profile_.get(),
-        scoped_ptr<DriveServiceInterface>(mock_drive_service_),
-        scoped_ptr<DriveUploaderInterface>()).Pass();
-    ASSERT_TRUE(base_dir_.CreateUniqueTempDir());
-    metadata_store_.reset(new DriveMetadataStore(
-        base_dir_.path(), base::MessageLoopProxy::current().get()));
-
-    bool done = false;
-    metadata_store_->Initialize(base::Bind(&DidInitialize, &done));
-    message_loop_.RunUntilIdle();
-    EXPECT_TRUE(done);
-  }
-
-  void SetUpDriveSyncService(bool enabled) {
-    sync_service_ = DriveFileSyncService::CreateForTesting(
-        profile_.get(),
-        base_dir_.path(),
-        api_util_.PassAs<drive::APIUtilInterface>(),
-        metadata_store_.Pass()).Pass();
-    sync_service_->AddServiceObserver(&mock_remote_observer_);
-    sync_service_->AddFileStatusObserver(&mock_file_status_observer_);
-    sync_service_->SetRemoteChangeProcessor(mock_remote_processor());
-    sync_service_->SetSyncEnabled(enabled);
-    message_loop_.RunUntilIdle();
-  }
-
-  virtual void TearDown() OVERRIDE {
-    EXPECT_CALL(*mock_drive_service(), RemoveObserver(_));
-
-    if (sync_service_) {
-      sync_service_.reset();
-    }
-
-    metadata_store_.reset();
-    api_util_.reset();
-    mock_drive_service_ = NULL;
-
-    RevokeSyncableFileSystem();
-    SetDisableDriveAPI(false);
-
-    extension_service_ = NULL;
-    profile_.reset();
-    message_loop_.RunUntilIdle();
-  }
-
-  void SetSyncEnabled(bool enabled) {
-    sync_service_->SetSyncEnabled(enabled);
-  }
-
- protected:
-  void EnableExtension(const std::string& extension_id) {
-    extension_service_->EnableExtension(extension_id);
-  }
-
-  void DisableExtension(const std::string& extension_id) {
-    extension_service_->DisableExtension(
-        extension_id, extensions::Extension::DISABLE_NONE);
-  }
-
-  void UninstallExtension(const std::string& extension_id) {
-    // Call UnloadExtension instead of UninstallExtension since it does
-    // unnecessary cleanup (e.g. deleting extension data) and emits warnings.
-    extension_service_->UnloadExtension(
-        extension_id, extension_misc::UNLOAD_REASON_UNINSTALL);
-  }
-
-  void UpdateRegisteredOrigins() {
-    sync_service_->UpdateRegisteredOrigins();
-    // Wait for completion of uninstalling origin.
-    message_loop()->RunUntilIdle();
-  }
-
-  void VerifySizeOfRegisteredOrigins(size_t b_size,
-                                     size_t i_size,
-                                     size_t d_size) {
-    EXPECT_EQ(b_size, pending_batch_sync_origins()->size());
-    EXPECT_EQ(i_size, metadata_store()->incremental_sync_origins().size());
-    EXPECT_EQ(d_size, metadata_store()->disabled_origins().size());
-  }
-
-  drive::APIUtilInterface* api_util() {
-    if (api_util_)
-      return api_util_.get();
-    return sync_service_->api_util_.get();
-  }
-
-  DriveMetadataStore* metadata_store() {
-    if (metadata_store_)
-      return metadata_store_.get();
-    return sync_service_->metadata_store_.get();
-  }
-
-  NiceMock<google_apis::MockDriveService>* mock_drive_service() {
-    return mock_drive_service_;
-  }
-
-  StrictMock<MockRemoteServiceObserver>* mock_remote_observer() {
-    return &mock_remote_observer_;
-  }
-
-  StrictMock<MockFileStatusObserver>* mock_file_status_observer() {
-    return &mock_file_status_observer_;
-  }
-
-  StrictMock<MockRemoteChangeProcessor>* mock_remote_processor() {
-    return &mock_remote_processor_;
-  }
-
-  base::MessageLoop* message_loop() { return &message_loop_; }
-  DriveFileSyncService* sync_service() { return sync_service_.get(); }
-  std::map<GURL, std::string>* pending_batch_sync_origins() {
-    return &(sync_service()->pending_batch_sync_origins_);
-  }
-
-  const RemoteChangeHandler& remote_change_handler() const {
-    return sync_service_->remote_change_handler_;
-  }
-
-  fileapi::FileSystemURL CreateURL(const GURL& origin,
-                                   const base::FilePath::StringType& path) {
-    return CreateSyncableFileSystemURL(origin, base::FilePath(path));
-  }
-
-  void ProcessRemoteChange(SyncStatusCode expected_status,
-                           const fileapi::FileSystemURL& expected_url,
-                           SyncFileStatus expected_sync_file_status,
-                           SyncAction expected_sync_action,
-                           SyncDirection expected_sync_direction) {
-    SyncStatusCode actual_status = SYNC_STATUS_UNKNOWN;
-    fileapi::FileSystemURL actual_url;
-
-    if (expected_sync_file_status != SYNC_FILE_STATUS_UNKNOWN) {
-      EXPECT_CALL(*mock_file_status_observer(),
-                  OnFileStatusChanged(expected_url,
-                                      expected_sync_file_status,
-                                      expected_sync_action,
-                                      expected_sync_direction))
-          .Times(1);
-    }
-
-    sync_service_->ProcessRemoteChange(
-        base::Bind(&DriveFileSyncServiceMockTest::DidProcessRemoteChange,
-                   base::Unretained(this),
-                   &actual_status, &actual_url));
-    message_loop_.RunUntilIdle();
-
-    EXPECT_EQ(expected_status, actual_status);
-    EXPECT_EQ(expected_url, actual_url);
-  }
-
-  void DidProcessRemoteChange(SyncStatusCode* status_out,
-                              fileapi::FileSystemURL* url_out,
-                              SyncStatusCode status,
-                              const fileapi::FileSystemURL& url) {
-    *status_out = status;
-    *url_out = url;
-  }
-
-  bool AppendIncrementalRemoteChangeByEntry(
-      const GURL& origin,
-      const google_apis::ResourceEntry& entry,
-      int64 changestamp) {
-    return sync_service_->AppendRemoteChange(origin, entry, changestamp);
-  }
-
-  bool AppendIncrementalRemoteChange(
-      const GURL& origin,
-      const base::FilePath& path,
-      bool is_deleted,
-      const std::string& resource_id,
-      int64 changestamp,
-      const std::string& remote_file_md5) {
-    return sync_service_->AppendRemoteChangeInternal(
-        origin, path, is_deleted, resource_id,
-        changestamp, remote_file_md5, base::Time(),
-        SYNC_FILE_TYPE_FILE);
-  }
-
-  // Mock setup helpers ------------------------------------------------------
-  void SetUpDriveServiceExpectCallsForSearchByTitle(
-      const std::string& result_mock_json_name,
-      const std::string& title,
-      const std::string& search_directory) {
-    scoped_ptr<Value> result_value(LoadJSONFile(
-        result_mock_json_name));
-    scoped_ptr<google_apis::ResourceList> result(
-        google_apis::ResourceList::ExtractAndParse(*result_value));
-    EXPECT_CALL(*mock_drive_service(),
-                SearchByTitle(title, search_directory, _))
-        .WillOnce(InvokeGetResourceListCallback2(
-            google_apis::HTTP_SUCCESS,
-            base::Passed(&result)))
-        .RetiresOnSaturation();
-  }
-
-  void SetUpDriveServiceExpectCallsForGetResourceListInDirectory(
-      const std::string& result_mock_json_name,
-      const std::string& search_directory) {
-    scoped_ptr<Value> result_value(LoadJSONFile(
-        result_mock_json_name));
-    scoped_ptr<google_apis::ResourceList> result(
-        google_apis::ResourceList::ExtractAndParse(*result_value));
-    EXPECT_CALL(*mock_drive_service(),
-                GetResourceListInDirectory(search_directory, _))
-        .WillOnce(InvokeGetResourceListCallback1(
-            google_apis::HTTP_SUCCESS,
-            base::Passed(&result)))
-        .RetiresOnSaturation();
-  }
-
-  void SetUpDriveServiceExpectCallsForIncrementalSync() {
-    scoped_ptr<Value> result_value(LoadJSONFile(
-        "chromeos/sync_file_system/origin_directory_not_found.json"));
-    scoped_ptr<google_apis::ResourceList> result(
-        google_apis::ResourceList::ExtractAndParse(*result_value));
-    EXPECT_CALL(*mock_drive_service(), GetChangeList(1, _))
-        .WillOnce(InvokeGetResourceListCallback1(
-            google_apis::HTTP_SUCCESS,
-            base::Passed(&result)))
-        .RetiresOnSaturation();
-  }
-
-  void SetUpDriveServiceExpectCallsForGetSyncRoot() {
-    scoped_ptr<Value> result_value(LoadJSONFile(
-        "chromeos/sync_file_system/sync_root_found.json"));
-    scoped_ptr<google_apis::ResourceList> result(
-        google_apis::ResourceList::ExtractAndParse(*result_value));
-    EXPECT_CALL(
-        *mock_drive_service(),
-        SearchByTitle(
-            drive::APIUtil::GetSyncRootDirectoryName(), std::string(), _))
-        .Times(AtMost(1)).WillOnce(InvokeGetResourceListCallback2(
-             google_apis::HTTP_SUCCESS, base::Passed(&result)))
-        .RetiresOnSaturation();
-  }
-
-  void SetUpDriveServiceExpectCallsForGetAboutResource() {
-    scoped_ptr<Value> account_metadata_value(LoadJSONFile(
-        "chromeos/gdata/account_metadata.json"));
-    scoped_ptr<google_apis::AboutResource> about_resource(
-        google_apis::AboutResource::CreateFromAccountMetadata(
-            *google_apis::AccountMetadata::CreateFrom(*account_metadata_value),
-            kRootResourceId));
-    EXPECT_CALL(*mock_drive_service(), GetAboutResource(_))
-        .WillOnce(InvokeGetAboutResourceCallback0(
-            google_apis::HTTP_SUCCESS,
-            base::Passed(&about_resource)))
-        .RetiresOnSaturation();
-  }
-
-  void SetUpDriveServiceExpectCallsForDownloadFile(
-      const std::string& file_resource_id) {
-    scoped_ptr<Value> file_entry_value(
-        LoadJSONFile("chromeos/gdata/file_entry.json").Pass());
-    scoped_ptr<google_apis::ResourceEntry> file_entry
-        = google_apis::ResourceEntry::ExtractAndParse(*file_entry_value);
-    EXPECT_CALL(*mock_drive_service(),
-                GetResourceEntry(file_resource_id, _))
-        .WillOnce(InvokeGetResourceEntryCallback1(
-            google_apis::HTTP_SUCCESS,
-            base::Passed(&file_entry)))
-        .RetiresOnSaturation();
-
-    EXPECT_CALL(*mock_drive_service(),
-                DownloadFile(_, _, GURL("https://file_content_url"), _, _, _))
-        .WillOnce(InvokeDidDownloadFile())
-        .RetiresOnSaturation();
-  }
-
-  // End of mock setup helpers -----------------------------------------------
-
- private:
-  base::MessageLoop message_loop_;
-  content::TestBrowserThread ui_thread_;
-  content::TestBrowserThread file_thread_;
-
-  base::ScopedTempDir base_dir_;
-  scoped_ptr<TestingProfile> profile_;
-
-#if defined OS_CHROMEOS
-  chromeos::ScopedTestDeviceSettingsService test_device_settings_service_;
-  chromeos::ScopedTestCrosSettings test_cros_settings_;
-  chromeos::ScopedTestUserManager test_user_manager_;
-#endif
-
-  scoped_ptr<DriveFileSyncService> sync_service_;
-
-  // Not owned.
-  ExtensionService* extension_service_;
-
-  // Owned by |api_util_|.
-  NiceMock<google_apis::MockDriveService>* mock_drive_service_;
-
-  StrictMock<MockRemoteServiceObserver> mock_remote_observer_;
-  StrictMock<MockFileStatusObserver> mock_file_status_observer_;
-  StrictMock<MockRemoteChangeProcessor> mock_remote_processor_;
-
-  scoped_ptr<drive::APIUtil> api_util_;
-  scoped_ptr<DriveMetadataStore> metadata_store_;
-
-  DISALLOW_COPY_AND_ASSIGN(DriveFileSyncServiceMockTest);
-};
-
-#if !defined(OS_ANDROID)
-
-TEST_F(DriveFileSyncServiceMockTest, RegisterNewOrigin) {
-  const GURL kOrigin("chrome-extension://example");
-  const std::string kDirectoryResourceId("folder:origin_directory_resource_id");
-  // The root id is in the "sync_root_entry.json" file.
-  const std::string kSyncRootResourceId("folder:sync_root_resource_id");
-
-  metadata_store()->SetSyncRootDirectory(kSyncRootResourceId);
-
-  EXPECT_CALL(*mock_remote_observer(), OnRemoteChangeQueueUpdated(0))
-      .Times(AnyNumber());
-
-  // Expect to call GetResourceList for the sync root from
-  // RegisterOriginForTrackingChanges.
-  SetUpDriveServiceExpectCallsForGetSyncRoot();
-
-  SetUpDriveServiceExpectCallsForSearchByTitle(
-      "chromeos/sync_file_system/origin_directory_found.json",
-      drive::APIUtil::OriginToDirectoryTitle(kOrigin),
-      kSyncRootResourceId);
-  SetUpDriveServiceExpectCallsForSearchByTitle(
-      "chromeos/sync_file_system/origin_directory_not_found.json",
-      drive::APIUtil::OriginToDirectoryTitle(kOrigin),
-      kSyncRootResourceId);
-
-  // Once the directory is created GetAboutResource should be called to get
-  // the largest changestamp for the origin as a prepariation of the batch sync.
-  SetUpDriveServiceExpectCallsForGetAboutResource();
-
-  SetUpDriveServiceExpectCallsForGetResourceListInDirectory(
-      "chromeos/sync_file_system/listing_files_in_empty_directory.json",
-      kDirectoryResourceId);
-
-  SetUpDriveSyncService(true);
-  bool done = false;
-  sync_service()->RegisterOriginForTrackingChanges(
-      kOrigin, base::Bind(&ExpectEqStatus, &done, SYNC_STATUS_OK));
-  message_loop()->RunUntilIdle();
-  EXPECT_TRUE(done);
-
-  VerifySizeOfRegisteredOrigins(0u, 1u, 0u);
-  EXPECT_TRUE(!remote_change_handler().HasChanges());
-}
-
-TEST_F(DriveFileSyncServiceMockTest, RegisterExistingOrigin) {
-  const GURL kOrigin("chrome-extension://example");
-  const std::string kDirectoryResourceId("folder:origin_directory_resource_id");
-  const std::string kSyncRootResourceId("folder:sync_root_resource_id");
-
-  metadata_store()->SetSyncRootDirectory(kSyncRootResourceId);
-
-  EXPECT_CALL(*mock_remote_observer(), OnRemoteChangeQueueUpdated(_))
-      .Times(AnyNumber());
-
-  InSequence sequence;
-
-  // Expect to call GetResourceList for the sync root from
-  // RegisterOriginForTrackingChanges.
-  SetUpDriveServiceExpectCallsForGetSyncRoot();
-
-  // We already have a directory for the origin.
-  SetUpDriveServiceExpectCallsForSearchByTitle(
-      "chromeos/sync_file_system/origin_directory_found.json",
-      drive::APIUtil::OriginToDirectoryTitle(kOrigin),
-      kSyncRootResourceId);
-
-  SetUpDriveServiceExpectCallsForGetAboutResource();
-
-  // DriveFileSyncService should fetch the list of the directory content
-  // to start the batch sync.
-  SetUpDriveServiceExpectCallsForGetResourceListInDirectory(
-      "chromeos/sync_file_system/listing_files_in_directory.json",
-      kDirectoryResourceId);
-
-  SetUpDriveSyncService(true);
-  bool done = false;
-  sync_service()->RegisterOriginForTrackingChanges(
-      kOrigin, base::Bind(&ExpectEqStatus, &done, SYNC_STATUS_OK));
-  message_loop()->RunUntilIdle();
-  EXPECT_TRUE(done);
-
-  // The origin should be registered as an incremental sync origin.
-  VerifySizeOfRegisteredOrigins(0u, 1u, 0u);
-
-  // |listing_files_in_directory| contains 4 items to sync.
-  EXPECT_EQ(1u, remote_change_handler().ChangesSize());
-}
-
-TEST_F(DriveFileSyncServiceMockTest, UnregisterOrigin) {
-  const GURL kOrigin1 = ExtensionNameToGURL(FPL("example1"));
-  const GURL kOrigin2 = ExtensionNameToGURL(FPL("example2"));
-  const std::string kDirectoryResourceId1(
-      "folder:origin_directory_resource_id");
-  const std::string kDirectoryResourceId2(
-      "folder:origin_directory_resource_id2");
-  const std::string kSyncRootResourceId("folder:sync_root_resource_id");
-
-  metadata_store()->SetSyncRootDirectory(kSyncRootResourceId);
-  metadata_store()->AddIncrementalSyncOrigin(kOrigin1, kDirectoryResourceId1);
-  metadata_store()->AddIncrementalSyncOrigin(kOrigin2, kDirectoryResourceId2);
-
-  EXPECT_CALL(*mock_remote_observer(), OnRemoteChangeQueueUpdated(_))
-      .Times(AnyNumber());
-
-  SetUpDriveSyncService(true);
-  message_loop()->RunUntilIdle();
-
-  VerifySizeOfRegisteredOrigins(0u, 2u, 0u);
-  EXPECT_EQ(0u, remote_change_handler().ChangesSize());
-
-  bool done = false;
-  sync_service()->UnregisterOriginForTrackingChanges(
-      kOrigin1, base::Bind(&ExpectEqStatus, &done, SYNC_STATUS_OK));
-  message_loop()->RunUntilIdle();
-  EXPECT_TRUE(done);
-
-  VerifySizeOfRegisteredOrigins(0u, 1u, 0u);
-  EXPECT_TRUE(!remote_change_handler().HasChanges());
-}
-
-TEST_F(DriveFileSyncServiceMockTest, UpdateRegisteredOrigins) {
-  const GURL kOrigin1 = ExtensionNameToGURL(FPL("example1"));
-  const GURL kOrigin2 = ExtensionNameToGURL(FPL("example2"));
-  const std::string kDirectoryResourceId1(
-      "folder:origin_directory_resource_id");
-  const std::string kDirectoryResourceId2(
-      "folder:origin_directory_resource_id2");
-  const std::string kSyncRootResourceId("folder:sync_root_resource_id");
-  const std::string extension_id1 =
-      extensions::id_util::GenerateIdForPath(base::FilePath(FPL("example1")));
-  const std::string extension_id2 =
-      extensions::id_util::GenerateIdForPath(base::FilePath(FPL("example2")));
-
-  metadata_store()->SetSyncRootDirectory(kSyncRootResourceId);
-  metadata_store()->AddIncrementalSyncOrigin(kOrigin1, kDirectoryResourceId1);
-  metadata_store()->AddIncrementalSyncOrigin(kOrigin2, kDirectoryResourceId2);
-
-  EXPECT_CALL(*mock_remote_observer(), OnRemoteChangeQueueUpdated(_))
-      .Times(AnyNumber());
-
-  SetUpDriveSyncService(true);
-  message_loop()->RunUntilIdle();
-
-  // [1] Both extensions and origins are enabled. Nothing to do.
-  VerifySizeOfRegisteredOrigins(0u, 2u, 0u);
-  UpdateRegisteredOrigins();
-  VerifySizeOfRegisteredOrigins(0u, 2u, 0u);
-
-  // [2] Extension 1 should move to disabled list.
-  DisableExtension(extension_id1);
-  UpdateRegisteredOrigins();
-  VerifySizeOfRegisteredOrigins(0u, 1u, 1u);
-
-  // [3] Make sure that state remains the same, nothing should change.
-  UpdateRegisteredOrigins();
-  VerifySizeOfRegisteredOrigins(0u, 1u, 1u);
-
-  // [4] Uninstall Extension 2.
-  UninstallExtension(extension_id2);
-  UpdateRegisteredOrigins();
-  VerifySizeOfRegisteredOrigins(0u, 0u, 1u);
-
-  // [5] Re-enable Extension 1. It moves back to batch and not to incremental.
-  EnableExtension(extension_id1);
-  UpdateRegisteredOrigins();
-  VerifySizeOfRegisteredOrigins(1u, 0u, 0u);
-}
-
-TEST_F(DriveFileSyncServiceMockTest, RemoteChange_NoChange) {
-  const std::string kSyncRootResourceId("folder:sync_root_resource_id");
-
-  metadata_store()->SetSyncRootDirectory(kSyncRootResourceId);
-
-  EXPECT_CALL(*mock_remote_observer(), OnRemoteChangeQueueUpdated(_))
-      .Times(AnyNumber());
-
-  SetUpDriveSyncService(true);
-
-  ProcessRemoteChange(SYNC_STATUS_NO_CHANGE_TO_SYNC,
-                      fileapi::FileSystemURL(),
-                      SYNC_FILE_STATUS_UNKNOWN,
-                      SYNC_ACTION_NONE,
-                      SYNC_DIRECTION_NONE);
-  VerifySizeOfRegisteredOrigins(0u, 0u, 0u);
-  EXPECT_TRUE(!remote_change_handler().HasChanges());
-}
-
-TEST_F(DriveFileSyncServiceMockTest, RemoteChange_Busy) {
-  const GURL kOrigin = ExtensionNameToGURL(FPL("example1"));
-  const std::string kDirectoryResourceId("folder:origin_directory_resource_id");
-  const std::string kSyncRootResourceId("folder:sync_root_resource_id");
-  const base::FilePath::StringType kFileName(FPL("File 1.mp3"));
-
-  metadata_store()->SetSyncRootDirectory(kSyncRootResourceId);
-  metadata_store()->AddIncrementalSyncOrigin(kOrigin, kDirectoryResourceId);
-
-  EXPECT_CALL(*mock_remote_observer(), OnRemoteChangeQueueUpdated(_))
-      .Times(AnyNumber());
-
-  EXPECT_CALL(*mock_remote_processor(),
-              PrepareForProcessRemoteChange(CreateURL(kOrigin, kFileName), _))
-      .WillOnce(PrepareForRemoteChange_Busy());
-  EXPECT_CALL(*mock_remote_processor(),
-              ClearLocalChanges(CreateURL(kOrigin, kFileName), _))
-      .WillOnce(InvokeCompletionCallback());
-
-  SetUpDriveServiceExpectCallsForIncrementalSync();
-
-  SetUpDriveSyncService(true);
-
-  scoped_ptr<ResourceEntry> entry(ResourceEntry::ExtractAndParse(
-      *LoadJSONFile("chromeos/gdata/file_entry.json")));
-  AppendIncrementalRemoteChangeByEntry(kOrigin, *entry, 12345);
-
-  ProcessRemoteChange(SYNC_STATUS_FILE_BUSY,
-                      CreateURL(kOrigin, kFileName),
-                      SYNC_FILE_STATUS_UNKNOWN,
-                      SYNC_ACTION_NONE,
-                      SYNC_DIRECTION_NONE);
-}
-
-TEST_F(DriveFileSyncServiceMockTest, RemoteChange_NewFile) {
-  const GURL kOrigin = ExtensionNameToGURL(FPL("example1"));
-  const std::string kDirectoryResourceId("folder:origin_directory_resource_id");
-  const std::string kSyncRootResourceId("folder:sync_root_resource_id");
-  const base::FilePath::StringType kFileName(FPL("File 1.mp3"));
-  const std::string kFileResourceId("file:2_file_resource_id");
-
-  metadata_store()->SetSyncRootDirectory(kSyncRootResourceId);
-  metadata_store()->AddIncrementalSyncOrigin(kOrigin, kDirectoryResourceId);
-
-  EXPECT_CALL(*mock_remote_observer(), OnRemoteChangeQueueUpdated(_))
-      .Times(AnyNumber());
-
-  EXPECT_CALL(*mock_remote_processor(),
-              PrepareForProcessRemoteChange(CreateURL(kOrigin, kFileName), _))
-      .WillOnce(PrepareForRemoteChange_NotFound());
-  EXPECT_CALL(*mock_remote_processor(),
-              ClearLocalChanges(CreateURL(kOrigin, kFileName), _))
-      .WillOnce(InvokeCompletionCallback());
-
-  SetUpDriveServiceExpectCallsForDownloadFile(kFileResourceId);
-
-  EXPECT_CALL(*mock_remote_processor(),
-              ApplyRemoteChange(_, _, CreateURL(kOrigin, kFileName), _))
-      .WillOnce(InvokeDidApplyRemoteChange());
-
-  SetUpDriveServiceExpectCallsForIncrementalSync();
-
-  SetUpDriveSyncService(true);
-
-  scoped_ptr<ResourceEntry> entry(ResourceEntry::ExtractAndParse(
-      *LoadJSONFile("chromeos/gdata/file_entry.json")));
-  AppendIncrementalRemoteChangeByEntry(kOrigin, *entry, 12345);
-
-  ProcessRemoteChange(SYNC_STATUS_OK,
-                      CreateURL(kOrigin, kFileName),
-                      SYNC_FILE_STATUS_SYNCED,
-                      SYNC_ACTION_ADDED,
-                      SYNC_DIRECTION_REMOTE_TO_LOCAL);
-}
-
-TEST_F(DriveFileSyncServiceMockTest, RemoteChange_UpdateFile) {
-  const GURL kOrigin = ExtensionNameToGURL(FPL("example1"));
-  const std::string kDirectoryResourceId("folder:origin_directory_resource_id");
-  const std::string kSyncRootResourceId("folder:sync_root_resource_id");
-  const base::FilePath::StringType kFileName(FPL("File 1.mp3"));
-  const std::string kFileResourceId("file:2_file_resource_id");
-
-  metadata_store()->SetSyncRootDirectory(kSyncRootResourceId);
-  metadata_store()->AddIncrementalSyncOrigin(kOrigin, kDirectoryResourceId);
-
-  EXPECT_CALL(*mock_remote_observer(), OnRemoteChangeQueueUpdated(_))
-      .Times(AnyNumber());
-
-  EXPECT_CALL(*mock_remote_processor(),
-              PrepareForProcessRemoteChange(CreateURL(kOrigin, kFileName), _))
-      .WillOnce(PrepareForRemoteChange_NotModified());
-  EXPECT_CALL(*mock_remote_processor(),
-              ClearLocalChanges(CreateURL(kOrigin, kFileName), _))
-      .WillOnce(InvokeCompletionCallback());
-
-  SetUpDriveServiceExpectCallsForDownloadFile(kFileResourceId);
-
-  EXPECT_CALL(*mock_remote_processor(),
-              ApplyRemoteChange(_, _, CreateURL(kOrigin, kFileName), _))
-      .WillOnce(InvokeDidApplyRemoteChange());
-
-  SetUpDriveServiceExpectCallsForIncrementalSync();
-
-  SetUpDriveSyncService(true);
-
-  scoped_ptr<ResourceEntry> entry(ResourceEntry::ExtractAndParse(
-      *LoadJSONFile("chromeos/gdata/file_entry.json")));
-  AppendIncrementalRemoteChangeByEntry(kOrigin, *entry, 12345);
-  ProcessRemoteChange(SYNC_STATUS_OK,
-                      CreateURL(kOrigin, kFileName),
-                      SYNC_FILE_STATUS_SYNCED,
-                      SYNC_ACTION_UPDATED,
-                      SYNC_DIRECTION_REMOTE_TO_LOCAL);
-}
-
-TEST_F(DriveFileSyncServiceMockTest, RegisterOriginWithSyncDisabled) {
-  const GURL kOrigin("chrome-extension://example");
-  const std::string kDirectoryResourceId("folder:origin_directory_resource_id");
-  const std::string kSyncRootResourceId("folder:sync_root_resource_id");
-
-  metadata_store()->SetSyncRootDirectory(kSyncRootResourceId);
-
-  EXPECT_CALL(*mock_remote_observer(),
-              OnRemoteServiceStateUpdated(REMOTE_SERVICE_DISABLED, _))
-      .Times(AtLeast(1));
-  EXPECT_CALL(*mock_remote_observer(), OnRemoteChangeQueueUpdated(0))
-      .Times(AnyNumber());
-
-  InSequence sequence;
-
-  // Expect to call GetResourceList for the sync root from
-  // RegisterOriginForTrackingChanges.
-  SetUpDriveServiceExpectCallsForGetSyncRoot();
-
-  SetUpDriveServiceExpectCallsForSearchByTitle(
-      "chromeos/sync_file_system/origin_directory_found.json",
-      drive::APIUtil::OriginToDirectoryTitle(kOrigin),
-      kSyncRootResourceId);
-
-  // Usually the sync service starts batch sync here, but since we're
-  // setting up a drive service with sync disabled batch sync doesn't
-  // start (while register origin should still return OK).
-
-  SetUpDriveSyncService(false);
-  bool done = false;
-  sync_service()->RegisterOriginForTrackingChanges(
-      kOrigin, base::Bind(&ExpectEqStatus, &done, SYNC_STATUS_OK));
-  message_loop()->RunUntilIdle();
-  EXPECT_TRUE(done);
-
-  // We must not have started batch sync for the newly registered origin,
-  // so it should still be in the batch_sync_origins.
-  VerifySizeOfRegisteredOrigins(1u, 0u, 0u);
-  EXPECT_TRUE(!remote_change_handler().HasChanges());
-}
-
-TEST_F(DriveFileSyncServiceMockTest, RemoteChange_Override) {
-  const GURL kOrigin = ExtensionNameToGURL(FPL("example1"));
-  const std::string kDirectoryResourceId("folder:origin_directory_resource_id");
-  const std::string kSyncRootResourceId("folder:sync_root_resource_id");
-  const base::FilePath kFilePath(FPL("File 1.mp3"));
-  const std::string kFileResourceId("file:2_file_resource_id");
-  const std::string kFileResourceId2("file:2_file_resource_id_2");
-  const fileapi::FileSystemURL kURL(CreateURL(kOrigin, kFilePath.value()));
-
-  metadata_store()->SetSyncRootDirectory(kSyncRootResourceId);
-  metadata_store()->AddIncrementalSyncOrigin(kOrigin, kDirectoryResourceId);
-
-  EXPECT_CALL(*mock_remote_observer(), OnRemoteChangeQueueUpdated(_))
-      .Times(AnyNumber());
-
-  SetUpDriveSyncService(true);
-
-  EXPECT_TRUE(AppendIncrementalRemoteChange(
-      kOrigin, kFilePath, false /* is_deleted */,
-      kFileResourceId, 2, "remote_file_md5"));
-
-  // Expect to drop this change since there is another newer change on the
-  // queue.
-  EXPECT_FALSE(AppendIncrementalRemoteChange(
-      kOrigin, kFilePath, false /* is_deleted */,
-      kFileResourceId, 1, "remote_file_md5_2"));
-
-  // Expect to drop this change since it has the same md5 with the previous one.
-  EXPECT_FALSE(AppendIncrementalRemoteChange(
-      kOrigin, kFilePath, false /* is_deleted */,
-      kFileResourceId, 4, "remote_file_md5"));
-
-  // This should not cause browser crash.
-  EXPECT_FALSE(AppendIncrementalRemoteChange(
-      kOrigin, kFilePath, false /* is_deleted */,
-      kFileResourceId, 4, "remote_file_md5"));
-
-  // Expect to drop these changes since they have different resource IDs with
-  // the previous ones.
-  EXPECT_FALSE(AppendIncrementalRemoteChange(
-      kOrigin, kFilePath, false /* is_deleted */,
-      kFileResourceId2, 5, "updated_file_md5"));
-  EXPECT_FALSE(AppendIncrementalRemoteChange(
-      kOrigin, kFilePath, true /* is_deleted */,
-      kFileResourceId2, 5, "deleted_file_md5"));
-
-  // Push delete change.
-  EXPECT_TRUE(AppendIncrementalRemoteChange(
-      kOrigin, kFilePath, true /* is_deleted */,
-      kFileResourceId, 6, "deleted_file_md5"));
-
-  // Expect to drop this delete change since it has a different resource ID with
-  // the previous one.
-  EXPECT_FALSE(AppendIncrementalRemoteChange(
-      kOrigin, kFilePath, true /* is_deleted */,
-      kFileResourceId2, 7, "deleted_file_md5"));
-
-  // Expect not to drop this change even if it has a different resource ID with
-  // the previous one.
-  EXPECT_TRUE(AppendIncrementalRemoteChange(
-      kOrigin, kFilePath, false /* is_deleted */,
-      kFileResourceId2, 8, "updated_file_md5"));
-}
-
-TEST_F(DriveFileSyncServiceMockTest, RemoteChange_Folder) {
-  const GURL kOrigin = ExtensionNameToGURL(FPL("example1"));
-  const std::string kDirectoryResourceId("folder:origin_directory_resource_id");
-  const std::string kSyncRootResourceId("folder:sync_root_resource_id");
-
-  metadata_store()->SetSyncRootDirectory(kSyncRootResourceId);
-  metadata_store()->AddIncrementalSyncOrigin(kOrigin, kDirectoryResourceId);
-
-  EXPECT_CALL(*mock_remote_observer(), OnRemoteChangeQueueUpdated(_))
-      .Times(AnyNumber());
-
-  SetUpDriveSyncService(true);
-
-  scoped_ptr<ResourceEntry> entry(ResourceEntry::ExtractAndParse(
-      *LoadJSONFile("chromeos/gdata/file_entry.json")));
-  entry->set_kind(google_apis::ENTRY_KIND_FOLDER);
-
-  // Expect to drop this change for file.
-  EXPECT_FALSE(AppendIncrementalRemoteChangeByEntry(
-      kOrigin, *entry, 1));
-}
-
-#endif  // !defined(OS_ANDROID)
-
-}  // namespace sync_file_system
diff --git a/chrome/browser/sync_file_system/drive_file_sync_service_sync_unittest.cc b/chrome/browser/sync_file_system/drive_file_sync_service_sync_unittest.cc
index d4ca730..60eb89f 100644
--- a/chrome/browser/sync_file_system/drive_file_sync_service_sync_unittest.cc
+++ b/chrome/browser/sync_file_system/drive_file_sync_service_sync_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2013 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.
 
@@ -6,541 +6,629 @@
 
 #include <algorithm>
 
-#include "base/format_macros.h"
+#include "base/file_util.h"
 #include "base/message_loop.h"
-#include "base/rand_util.h"
+#include "base/stl_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/sync_file_system/drive/fake_api_util.h"
-#include "chrome/browser/sync_file_system/drive/metadata_db_migration_util.h"
+#include "base/threading/sequenced_worker_pool.h"
+#include "chrome/browser/drive/drive_uploader.h"
+#include "chrome/browser/drive/fake_drive_service.h"
+#include "chrome/browser/sync_file_system/drive_backend/api_util.h"
+#include "chrome/browser/sync_file_system/drive_backend/fake_drive_service_helper.h"
 #include "chrome/browser/sync_file_system/drive_file_sync_util.h"
 #include "chrome/browser/sync_file_system/drive_metadata_store.h"
 #include "chrome/browser/sync_file_system/fake_remote_change_processor.h"
-#include "chrome/browser/sync_file_system/sync_file_system.pb.h"
+#include "chrome/browser/sync_file_system/local_file_sync_service.h"
 #include "chrome/test/base/testing_profile.h"
 #include "content/public/test/test_browser_thread.h"
+#include "content/public/test/test_browser_thread_bundle.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "webkit/browser/fileapi/file_system_context.h"
+#include "webkit/browser/fileapi/syncable/canned_syncable_file_system.h"
+#include "webkit/browser/fileapi/syncable/local_file_sync_context.h"
 #include "webkit/browser/fileapi/syncable/syncable_file_system_util.h"
 
+#define FPL(path) FILE_PATH_LITERAL(path)
+
+using content::BrowserThread;
+
+using google_apis::GDataErrorCode;
+using google_apis::ResourceEntry;
+
 namespace sync_file_system {
 
+using drive_backend::APIUtil;
+using drive_backend::APIUtilInterface;
+using drive_backend::FakeDriveServiceHelper;
+
 namespace {
 
-const char kAppId[] = "app-id";
-const char kAppOrigin[] = "chrome-extension://app-id";
-
-std::string GetSyncRootResourceId() {
-  const std::string kSyncRootResourceId("folder:sync_root_resource_id");
-  return IsDriveAPIDisabled() ? kSyncRootResourceId
-                              : drive::RemoveWapiIdPrefix(kSyncRootResourceId);
-}
-
-std::string GetParentResourceId() {
-  const std::string kParentResourceId("folder:parent_resource_id");
-  return IsDriveAPIDisabled() ? kParentResourceId
-                              : drive::RemoveWapiIdPrefix(kParentResourceId);
-}
-
-void DidInitialize(bool* done, SyncStatusCode status, bool created) {
-  EXPECT_EQ(SYNC_STATUS_OK, status);
+void SyncResultCallback(bool* done,
+                        SyncStatusCode* status_out,
+                        fileapi::FileSystemURL* url_out,
+                        SyncStatusCode status,
+                        const fileapi::FileSystemURL& url) {
+  EXPECT_FALSE(*done);
+  *status_out = status;
+  *url_out = url;
   *done = true;
 }
 
-void DidProcessRemoteChange(bool* done,
-                            SyncStatusCode* status_out,
-                            SyncStatusCode status,
-                            const fileapi::FileSystemURL& url) {
+void SyncStatusResultCallback(bool* done,
+                              SyncStatusCode* status_out,
+                              SyncStatusCode status) {
+  EXPECT_FALSE(*done);
   *status_out = status;
   *done = true;
 }
 
+void DatabaseInitResultCallback(bool* done,
+                                SyncStatusCode* status_out,
+                                bool* created_out,
+                                SyncStatusCode status,
+                                bool created) {
+  EXPECT_FALSE(*done);
+  *status_out = status;
+  *created_out = created;
+  *done = true;
+}
+
 }  // namespace
 
 class DriveFileSyncServiceSyncTest : public testing::Test {
  public:
   DriveFileSyncServiceSyncTest()
-      : ui_thread_(content::BrowserThread::UI, &message_loop_),
-        file_thread_(content::BrowserThread::FILE, &message_loop_),
-        fake_api_util_(NULL),
-        metadata_store_(NULL),
-        resource_count_(0) {}
+      : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP) {}
 
   virtual ~DriveFileSyncServiceSyncTest() {
   }
 
   virtual void SetUp() OVERRIDE {
-    SetEnableSyncFSDirectoryOperation(true);
+    // TODO(tzik): Set up TestExtensionSystem to support simulated relaunch.
+
     RegisterSyncableFileSystem();
+    local_sync_service_.reset(new LocalFileSyncService(&profile_));
+
+    fake_drive_service_ = new ::drive::FakeDriveService();
+    fake_drive_service_->Initialize(&profile_);
+    ASSERT_TRUE(fake_drive_service_->LoadAccountMetadataForWapi(
+        "sync_file_system/account_metadata.json"));
+    ASSERT_TRUE(fake_drive_service_->LoadResourceListForWapi(
+        "gdata/root_feed.json"));
+
+    drive_uploader_ = new ::drive::DriveUploader(
+        fake_drive_service_, base::MessageLoopProxy::current().get());
+
+    fake_drive_helper_.reset(new FakeDriveServiceHelper(
+        fake_drive_service_, drive_uploader_));
+
+    bool done = false;
+    SyncStatusCode status = SYNC_STATUS_UNKNOWN;
+    bool created = false;
+    scoped_ptr<DriveMetadataStore> metadata_store(
+        new DriveMetadataStore(fake_drive_helper_->base_dir_path(),
+                               base::MessageLoopProxy::current().get()));
+    metadata_store->Initialize(
+        base::Bind(&DatabaseInitResultCallback, &done, &status, &created));
+    FlushMessageLoop();
+    EXPECT_TRUE(done);
+    EXPECT_EQ(SYNC_STATUS_OK, status);
+    EXPECT_TRUE(created);
+
+    scoped_ptr<APIUtil> api_util(APIUtil::CreateForTesting(
+        &profile_,
+        scoped_ptr< ::drive::DriveServiceInterface>(fake_drive_service_),
+        scoped_ptr< ::drive::DriveUploaderInterface>(drive_uploader_)));
+
+    remote_sync_service_ = DriveFileSyncService::CreateForTesting(
+        &profile_,
+        fake_drive_helper_->base_dir_path(),
+        api_util.PassAs<APIUtilInterface>(),
+        metadata_store.Pass());
+
+    local_sync_service_->SetLocalChangeProcessor(remote_sync_service_.get());
+    remote_sync_service_->SetRemoteChangeProcessor(local_sync_service_.get());
   }
 
   virtual void TearDown() OVERRIDE {
-    SetDisableDriveAPI(false);
+    drive_uploader_ = NULL;
+    fake_drive_service_ = NULL;
+    remote_sync_service_.reset();
+    local_sync_service_.reset();
+    FlushMessageLoop();
+
+    typedef std::map<GURL, CannedSyncableFileSystem*>::iterator iterator;
+    for (iterator itr = file_systems_.begin();
+         itr != file_systems_.end(); ++itr) {
+      itr->second->TearDown();
+      delete itr->second;
+    }
+    file_systems_.clear();
+
+    FlushMessageLoop();
     RevokeSyncableFileSystem();
-    SetEnableSyncFSDirectoryOperation(false);
   }
 
  protected:
-  struct SyncEvent {
-    std::string description;
-    base::Closure callback;
+  void RegisterOrigin(const GURL& origin) {
+    if (!ContainsKey(file_systems_, origin)) {
+      CannedSyncableFileSystem* file_system = new CannedSyncableFileSystem(
+          origin,
+          BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO).get(),
+          BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE)
+              .get());
 
-    SyncEvent(const std::string& description,
-              base::Closure callback)
-        : description(description),
-          callback(callback) {
+      bool done = false;
+      SyncStatusCode status = SYNC_STATUS_UNKNOWN;
+      file_system->SetUp();
+      local_sync_service_->MaybeInitializeFileSystemContext(
+          origin, file_system->file_system_context(),
+          base::Bind(&SyncStatusResultCallback, &done, &status));
+      FlushMessageLoop();
+      EXPECT_TRUE(done);
+      EXPECT_EQ(SYNC_STATUS_OK, status);
+
+      file_system->file_system_context()->sync_context()->
+          set_mock_notify_changes_duration_in_sec(0);
+
+      EXPECT_EQ(base::PLATFORM_FILE_OK, file_system->OpenFileSystem());
+      file_systems_[origin] = file_system;
     }
-  };
 
-  SyncEvent CreateRemoteFileAddOrUpdateEvent(const std::string& title) {
-    return SyncEvent(
-        "SyncEvent: Add or Update remote file [" + title + "]",
-        base::Bind(&DriveFileSyncServiceSyncTest::AddOrUpdateResource,
-                   base::Unretained(this), title, SYNC_FILE_TYPE_FILE));
-  }
-
-  SyncEvent CreateRemoteDirectoryAddEvent(const std::string& title) {
-    return SyncEvent(
-        "SyncEvent: Add remote directory [" + title + "]",
-        base::Bind(&DriveFileSyncServiceSyncTest::AddOrUpdateResource,
-                   base::Unretained(this), title, SYNC_FILE_TYPE_DIRECTORY));
-  }
-
-  SyncEvent CreateRemoteFileDeleteEvent(const std::string& title) {
-    return SyncEvent(
-        "SyncEvent: Delete remote file [" + title + "]",
-        base::Bind(&DriveFileSyncServiceSyncTest::DeleteResource,
-                   base::Unretained(this), title));
-  }
-
-  SyncEvent CreateRelaunchEvent() {
-    return SyncEvent(
-        "SyncEvent: Relaunch service",
-        base::Bind(&DriveFileSyncServiceSyncTest::RelaunchService,
-                   base::Unretained(this)));
-  }
-
-  SyncEvent CreateFetchEvent() {
-    return SyncEvent(
-        "SyncEvent: Fetch remote changes",
-        base::Bind(&DriveFileSyncServiceSyncTest::FetchRemoteChange,
-                   base::Unretained(this)));
-  }
-
-  SyncEvent CreateProcessRemoteChangeEvent() {
-    return SyncEvent(
-        "SyncEvent: Process remote change",
-        base::Bind(
-            base::IgnoreResult(
-                &DriveFileSyncServiceSyncTest::ProcessRemoteChange),
-            base::Unretained(this)));
-  }
-
-  template <size_t array_size>
-  std::vector<SyncEvent> CreateTestCase(const SyncEvent (&events)[array_size]) {
-    return std::vector<SyncEvent>(events, events + array_size);
-  }
-
-  void ShuffleTestCase(std::vector<SyncEvent>* events) {
-    std::random_shuffle(events->begin(), events->end(), base::RandGenerator);
-  }
-
-  void RunTest(const std::vector<SyncEvent>& events) {
-    base::ScopedTempDir scoped_base_dir_;
-    ASSERT_TRUE(scoped_base_dir_.CreateUniqueTempDir());
-    base_dir_ = scoped_base_dir_.path();
-
-    SetUpForTestCase();
-
-    typedef std::vector<SyncEvent>::const_iterator iterator;
-    std::ostringstream out;
-    out << '\n';
-    for (iterator itr = events.begin(); itr != events.end(); ++itr)
-      out << itr->description << '\n';
-    SCOPED_TRACE(out.str());
-
-    for (iterator itr = events.begin(); itr != events.end(); ++itr)
-      itr->callback.Run();
-
-    FetchRemoteChange();
-    while (ProcessRemoteChange()) {}
-
-    VerifyResult();
-    TearDownForTestCase();
-
-    base_dir_ = base::FilePath();
-  }
-
-  void AddFileTest_Body();
-  void UpdateFileTest_Body();
-  void DeleteFileTest_Body();
-  void RelaunchTest_Body();
-  void SquashedFileAddTest_Body();
-  void RelaunchTestWithSquashedDeletion_Body();
-  void CreateDirectoryTest_Body();
-  void DeleteDirectoryTest_Body();
-
- private:
-  void SetUpForTestCase() {
-    fake_api_util_ = new drive::FakeAPIUtil;
-    fake_remote_processor_.reset(new FakeRemoteChangeProcessor);
-
-    metadata_store_ = new DriveMetadataStore(
-        base_dir_, base::MessageLoopProxy::current().get());
-
-    bool done = false;
-    metadata_store_->Initialize(base::Bind(&DidInitialize, &done));
-    message_loop_.RunUntilIdle();
-    EXPECT_TRUE(done);
-
-    metadata_store_->SetSyncRootDirectory(GetSyncRootResourceId());
-    metadata_store_->AddIncrementalSyncOrigin(GURL(kAppOrigin),
-                                              GetParentResourceId());
-
-    sync_service_ = DriveFileSyncService::CreateForTesting(
-        &profile_,
-        base_dir_,
-        scoped_ptr<drive::APIUtilInterface>(fake_api_util_),
-        scoped_ptr<DriveMetadataStore>(metadata_store_)).Pass();
-    sync_service_->SetRemoteChangeProcessor(fake_remote_processor_.get());
-  }
-
-  void TearDownForTestCase() {
-    metadata_store_ = NULL;
-    fake_api_util_ = NULL;
-    sync_service_.reset();
-    fake_remote_processor_.reset();
-    message_loop_.RunUntilIdle();
-  }
-
-  void AddOrUpdateResource(const std::string& title,
-                           SyncFileType type) {
-    typedef ResourceIdByTitle::iterator iterator;
-    std::pair<iterator, bool> inserted =
-        resources_.insert(std::make_pair(title, std::string()));
-    if (inserted.second) {
-      switch (type) {
-        case SYNC_FILE_TYPE_UNKNOWN:
-          NOTREACHED();
-          break;
-        case SYNC_FILE_TYPE_FILE:
-          inserted.first->second = IsDriveAPIDisabled()
-              ? base::StringPrintf("file:%" PRId64, ++resource_count_)
-              : base::StringPrintf("%" PRId64, ++resource_count_);
-          break;
-        case SYNC_FILE_TYPE_DIRECTORY:
-          inserted.first->second = IsDriveAPIDisabled()
-              ? base::StringPrintf("folder:%" PRId64, ++resource_count_)
-              : base::StringPrintf("%" PRId64, ++resource_count_);
-          break;
-      }
-    }
-    std::string resource_id = inserted.first->second;
-    std::string md5_checksum;
-    if (type == SYNC_FILE_TYPE_FILE)
-      md5_checksum = base::StringPrintf("%" PRIx64, base::RandUint64());
-
-    fake_api_util_->PushRemoteChange(GetParentResourceId(),
-                                     kAppId,
-                                     title,
-                                     resource_id,
-                                     md5_checksum,
-                                     type,
-                                     false /* deleted */);
-    message_loop_.RunUntilIdle();
-  }
-
-  void DeleteResource(const std::string& title) {
-    ResourceIdByTitle::iterator found = resources_.find(title);
-    if (found == resources_.end())
-      return;
-    std::string resource_id = found->second;
-    resources_.erase(found);
-    fake_api_util_->PushRemoteChange(GetParentResourceId(),
-                                     kAppId,
-                                     title,
-                                     resource_id,
-                                     std::string(),
-                                     SYNC_FILE_TYPE_UNKNOWN,
-                                     true /* deleted */);
-    message_loop_.RunUntilIdle();
-  }
-
-  void RelaunchService() {
-    metadata_store_ = NULL;
-    scoped_ptr<drive::APIUtilInterface> api_util =
-        DriveFileSyncService::DestroyAndPassAPIUtilForTesting(
-            sync_service_.Pass());
-    message_loop_.RunUntilIdle();
-
-    metadata_store_ = new DriveMetadataStore(
-        base_dir_, base::MessageLoopProxy::current().get());
-
-    bool done = false;
-    metadata_store_->Initialize(base::Bind(&DidInitialize, &done));
-    message_loop_.RunUntilIdle();
-    EXPECT_TRUE(done);
-
-    sync_service_ = DriveFileSyncService::CreateForTesting(
-        &profile_,
-        base_dir_,
-        api_util.Pass(),
-        scoped_ptr<DriveMetadataStore>(metadata_store_)).Pass();
-    sync_service_->SetRemoteChangeProcessor(fake_remote_processor_.get());
-  }
-
-  void FetchRemoteChange() {
-    sync_service_->may_have_unfetched_changes_ = true;
-    sync_service_->MaybeStartFetchChanges();
-    message_loop_.RunUntilIdle();
-  }
-
-  bool ProcessRemoteChange() {
     bool done = false;
     SyncStatusCode status = SYNC_STATUS_UNKNOWN;
-    sync_service_->ProcessRemoteChange(
-        base::Bind(&DidProcessRemoteChange, &done, &status));
-    message_loop_.RunUntilIdle();
+    remote_sync_service_->RegisterOriginForTrackingChanges(
+        origin, base::Bind(&SyncStatusResultCallback, &done, &status));
+    FlushMessageLoop();
     EXPECT_TRUE(done);
-    return status != SYNC_STATUS_NO_CHANGE_TO_SYNC;
+    EXPECT_EQ(SYNC_STATUS_OK, status);
   }
 
+  void AddLocalFolder(const GURL& origin,
+                      const base::FilePath& path) {
+    ASSERT_TRUE(ContainsKey(file_systems_, origin));
+    EXPECT_EQ(base::PLATFORM_FILE_OK,
+              file_systems_[origin]->CreateDirectory(
+                  CreateSyncableFileSystemURL(origin, path)));
+  }
 
-  void VerifyResult() {
-    typedef drive::FakeAPIUtil::RemoteResourceByResourceId RemoteResourceMap;
-    typedef drive::FakeAPIUtil::RemoteResource RemoteResource;
-    typedef FakeRemoteChangeProcessor::URLToFileChangesMap
-        AppliedRemoteChangeMap;
+  void AddOrUpdateLocalFile(const GURL& origin,
+                            const base::FilePath& path,
+                            const std::string& content) {
+    fileapi::FileSystemURL url(CreateSyncableFileSystemURL(origin, path));
+    ASSERT_TRUE(ContainsKey(file_systems_, origin));
+    EXPECT_EQ(base::PLATFORM_FILE_OK, file_systems_[origin]->CreateFile(url));
+    int64 bytes_written = file_systems_[origin]->WriteString(url, content);
+    EXPECT_EQ(static_cast<int64>(content.size()), bytes_written);
+    FlushMessageLoop();
+  }
 
-    const RemoteResourceMap& remote_resources =
-        fake_api_util_->remote_resources();
-    const AppliedRemoteChangeMap applied_changes =
-        fake_remote_processor_->GetAppliedRemoteChanges();
+  void UpdateLocalFile(const GURL& origin,
+                       const base::FilePath& path,
+                       const std::string& content) {
+    ASSERT_TRUE(ContainsKey(file_systems_, origin));
+    int64 bytes_written = file_systems_[origin]->WriteString(
+        CreateSyncableFileSystemURL(origin, path), content);
+    EXPECT_EQ(static_cast<int64>(content.size()), bytes_written);
+    FlushMessageLoop();
+  }
 
-    std::set<std::string> local_resources;
-    for (AppliedRemoteChangeMap::const_iterator itr = applied_changes.begin();
-         itr != applied_changes.end(); ++itr) {
-      const fileapi::FileSystemURL& url = itr->first;
-      const FileChange& applied_change = itr->second.back();
+  void RemoveLocal(const GURL& origin, const base::FilePath& path) {
+    ASSERT_TRUE(ContainsKey(file_systems_, origin));
+    EXPECT_EQ(base::PLATFORM_FILE_OK,
+              file_systems_[origin]->Remove(
+                  CreateSyncableFileSystemURL(origin, path),
+                  true /* recursive */));
+    FlushMessageLoop();
+  }
 
-      DriveMetadata metadata;
-      SyncStatusCode status = metadata_store_->ReadEntry(itr->first, &metadata);
-      if (applied_change.IsDelete()) {
-        EXPECT_EQ(SYNC_DATABASE_ERROR_NOT_FOUND, status);
-        continue;
+  SyncStatusCode ProcessLocalChange() {
+    bool done = false;
+    SyncStatusCode status = SYNC_STATUS_UNKNOWN;
+    fileapi::FileSystemURL url;
+    local_sync_service_->ProcessLocalChange(
+        base::Bind(&SyncResultCallback, &done, &status, &url));
+    FlushMessageLoop();
+    EXPECT_TRUE(done);
+    if (status != SYNC_STATUS_NO_CHANGE_TO_SYNC)
+      local_sync_service_->ClearSyncFlagForURL(url);
+    return status;
+  }
+
+  SyncStatusCode ProcessRemoteChange() {
+    bool done = false;
+    SyncStatusCode status = SYNC_STATUS_UNKNOWN;
+    fileapi::FileSystemURL url;
+    remote_sync_service_->ProcessRemoteChange(
+        base::Bind(&SyncResultCallback, &done, &status, &url));
+    FlushMessageLoop();
+    EXPECT_TRUE(done);
+    if (status != SYNC_STATUS_NO_CHANGE_TO_SYNC)
+      local_sync_service_->ClearSyncFlagForURL(url);
+    return status;
+  }
+
+  SyncStatusCode ProcessChangesUntilDone() {
+    remote_sync_service_->OnNotificationReceived();
+    FlushMessageLoop();
+
+    SyncStatusCode local_sync_status;
+    SyncStatusCode remote_sync_status;
+    do {
+      local_sync_status = ProcessLocalChange();
+      if (local_sync_status != SYNC_STATUS_OK &&
+          local_sync_status != SYNC_STATUS_NO_CHANGE_TO_SYNC)
+        return local_sync_status;
+
+      remote_sync_status = ProcessRemoteChange();
+      if (remote_sync_status != SYNC_STATUS_OK &&
+          remote_sync_status != SYNC_STATUS_NO_CHANGE_TO_SYNC)
+        return remote_sync_status;
+    } while (local_sync_status != SYNC_STATUS_NO_CHANGE_TO_SYNC &&
+             remote_sync_status != SYNC_STATUS_NO_CHANGE_TO_SYNC);
+    return SYNC_STATUS_OK;
+  }
+
+  // Verifies local and remote files/folders are consistent.
+  // This function checks:
+  //  - Each registered origin has corresponding remote folder.
+  //  - Each local file/folder has corresponding remote one.
+  //  - Each remote file/folder has corresponding local one.
+  // TODO(tzik): Handle conflict case. i.e. allow remote file has different
+  // file content if the corresponding local file conflicts to it.
+  void VerifyConsistency() {
+    std::string sync_root_folder_id;
+    GDataErrorCode error =
+        fake_drive_helper_->GetSyncRootFolderID(&sync_root_folder_id);
+    if (sync_root_folder_id.empty()) {
+      EXPECT_EQ(google_apis::HTTP_NOT_FOUND, error);
+      EXPECT_TRUE(file_systems_.empty());
+      return;
+    }
+    EXPECT_EQ(google_apis::HTTP_SUCCESS, error);
+
+    ScopedVector<ResourceEntry> remote_entries;
+    EXPECT_EQ(google_apis::HTTP_SUCCESS,
+              fake_drive_helper_->ListFilesInFolder(
+                  sync_root_folder_id, &remote_entries));
+    std::map<std::string, const ResourceEntry*> origin_root_by_title;
+    for (ScopedVector<ResourceEntry>::iterator itr = remote_entries.begin();
+         itr != remote_entries.end();
+         ++itr) {
+      const ResourceEntry& remote_entry = **itr;
+      EXPECT_FALSE(ContainsKey(origin_root_by_title, remote_entry.title()));
+      origin_root_by_title[remote_entry.title()] = *itr;
+    }
+
+    for (std::map<GURL, CannedSyncableFileSystem*>::const_iterator itr =
+             file_systems_.begin();
+         itr != file_systems_.end(); ++itr) {
+      const GURL& origin = itr->first;
+      SCOPED_TRACE(testing::Message() << "Verifying origin: " << origin);
+      CannedSyncableFileSystem* file_system = itr->second;
+      ASSERT_TRUE(ContainsKey(origin_root_by_title, origin.host()));
+      VerifyConsistencyForFolder(
+          origin, base::FilePath(),
+          origin_root_by_title[origin.host()]->resource_id(),
+          file_system);
+    }
+  }
+
+  void VerifyConsistencyForOrigin(const GURL& origin) {
+    std::string sync_root_folder_id;
+    ASSERT_EQ(google_apis::HTTP_SUCCESS,
+              fake_drive_helper_->GetSyncRootFolderID(&sync_root_folder_id));
+    ASSERT_FALSE(sync_root_folder_id.empty());
+
+    ScopedVector<ResourceEntry> origin_folder;
+    EXPECT_EQ(google_apis::HTTP_SUCCESS,
+              fake_drive_helper_->SearchByTitle(
+                  sync_root_folder_id, origin.host(), &origin_folder));
+    ASSERT_EQ(1u, origin_folder.size());
+
+    ASSERT_TRUE(ContainsKey(file_systems_, origin));
+    VerifyConsistencyForFolder(
+        origin, base::FilePath(),
+        origin_folder[0]->resource_id(),
+        file_systems_[origin]);
+  }
+
+  void VerifyConsistencyForFolder(const GURL& origin,
+                                  const base::FilePath& path,
+                                  const std::string& folder_id,
+                                  CannedSyncableFileSystem* file_system) {
+    SCOPED_TRACE(testing::Message() << "Verifying path: " << path.value());
+
+    ScopedVector<ResourceEntry> remote_entries;
+    EXPECT_EQ(google_apis::HTTP_SUCCESS,
+              fake_drive_helper_->ListFilesInFolder(
+                  folder_id, &remote_entries));
+    std::map<std::string, const ResourceEntry*> remote_entry_by_title;
+    for (ScopedVector<ResourceEntry>::iterator itr = remote_entries.begin();
+         itr != remote_entries.end();
+         ++itr) {
+      const ResourceEntry& remote_entry = **itr;
+      EXPECT_FALSE(ContainsKey(remote_entry_by_title, remote_entry.title()));
+      remote_entry_by_title[remote_entry.title()] = *itr;
+    }
+
+    fileapi::FileSystemURL url(CreateSyncableFileSystemURL(origin, path));
+    CannedSyncableFileSystem::FileEntryList local_entries;
+    EXPECT_EQ(base::PLATFORM_FILE_OK,
+              file_system->ReadDirectory(url, &local_entries));
+    for (CannedSyncableFileSystem::FileEntryList::iterator itr =
+             local_entries.begin();
+         itr != local_entries.end();
+         ++itr) {
+      const fileapi::DirectoryEntry& local_entry = *itr;
+      fileapi::FileSystemURL entry_url(
+          CreateSyncableFileSystemURL(origin, path.Append(local_entry.name)));
+      std::string title = DriveFileSyncService::PathToTitle(entry_url.path());
+      ASSERT_TRUE(ContainsKey(remote_entry_by_title, title));
+      const ResourceEntry& remote_entry = *remote_entry_by_title[title];
+      if (local_entry.is_directory) {
+        ASSERT_TRUE(remote_entry.is_folder());
+        VerifyConsistencyForFolder(origin, entry_url.path(),
+                                   remote_entry.resource_id(),
+                                   file_system);
+      } else {
+        ASSERT_TRUE(remote_entry.is_file());
+        VerifyConsistencyForFile(origin, entry_url.path(),
+                                 remote_entry.resource_id(),
+                                 file_system);
       }
-
-      EXPECT_EQ(SYNC_STATUS_OK, status);
-      EXPECT_FALSE(metadata.resource_id().empty());
-      EXPECT_FALSE(metadata.conflicted());
-      EXPECT_FALSE(metadata.to_be_fetched());
-      EXPECT_TRUE(metadata.type() == DriveMetadata::RESOURCE_TYPE_FOLDER ||
-                  !metadata.md5_checksum().empty());
-
-      RemoteResourceMap::const_iterator found =
-          remote_resources.find(metadata.resource_id());
-      ASSERT_TRUE(found != remote_resources.end());
-      const RemoteResource& remote_resource = found->second;
-
-      EXPECT_EQ(base::FilePath::FromUTF8Unsafe(remote_resource.title),
-                url.path());
-      EXPECT_EQ(remote_resource.md5_checksum, metadata.md5_checksum());
-      EXPECT_FALSE(remote_resource.deleted);
-
-      EXPECT_TRUE(local_resources.insert(metadata.resource_id()).second);
+      remote_entry_by_title.erase(title);
     }
 
-    for (RemoteResourceMap::const_iterator itr = remote_resources.begin();
-         itr != remote_resources.end(); ++itr) {
-      if (!itr->second.deleted)
-        EXPECT_TRUE(ContainsKey(local_resources, itr->first));
-      else
-        EXPECT_FALSE(ContainsKey(local_resources, itr->first));
-    }
+    EXPECT_TRUE(remote_entry_by_title.empty());
   }
 
-  base::MessageLoop message_loop_;
-  content::TestBrowserThread ui_thread_;
-  content::TestBrowserThread file_thread_;
+  void VerifyConsistencyForFile(const GURL& origin,
+                                const base::FilePath& path,
+                                const std::string& file_id,
+                                CannedSyncableFileSystem* file_system) {
+    fileapi::FileSystemURL url(CreateSyncableFileSystemURL(origin, path));
+    std::string file_content;
+    EXPECT_EQ(google_apis::HTTP_SUCCESS,
+              fake_drive_helper_->ReadFile(file_id, &file_content));
+    EXPECT_EQ(base::PLATFORM_FILE_OK,
+              file_system->VerifyFile(url, file_content));
+  }
+
+  void FlushMessageLoop() {
+    base::MessageLoop::current()->RunUntilIdle();
+    BrowserThread::GetBlockingPool()->FlushForTesting();
+    base::MessageLoop::current()->RunUntilIdle();
+  }
+
+  void TestInitialization();
+  void TestLocalToRemoteBasic();
+  void TestRemoteToLocalBasic();
+  void TestLocalFileUpdate();
+  void TestRemoteFileUpdate();
+  void TestLocalFileDeletion();
+  void TestRemoteFileDeletion();
+
+  content::TestBrowserThreadBundle thread_bundle_;
 
   TestingProfile profile_;
-  base::FilePath base_dir_;
 
-  drive::FakeAPIUtil* fake_api_util_;  // Owned by |sync_service_|.
-  scoped_ptr<FakeRemoteChangeProcessor> fake_remote_processor_;
-  DriveMetadataStore* metadata_store_;  // Owned by |sync_service_|.
+  ::drive::FakeDriveService* fake_drive_service_;
+  ::drive::DriveUploader* drive_uploader_;
+  scoped_ptr<FakeDriveServiceHelper> fake_drive_helper_;
+  std::map<GURL, CannedSyncableFileSystem*> file_systems_;
 
-  scoped_ptr<DriveFileSyncService> sync_service_;
-
-  typedef std::map<std::string, std::string> ResourceIdByTitle;
-  ResourceIdByTitle resources_;
-  int64 resource_count_;
+  scoped_ptr<DriveFileSyncService> remote_sync_service_;
+  scoped_ptr<LocalFileSyncService> local_sync_service_;
 
   DISALLOW_COPY_AND_ASSIGN(DriveFileSyncServiceSyncTest);
 };
 
-void DriveFileSyncServiceSyncTest::AddFileTest_Body() {
-  std::string kFile1 = "file title 1";
-  SyncEvent sync_event[] = {
-    CreateRemoteFileAddOrUpdateEvent(kFile1),
-  };
-
-  RunTest(CreateTestCase(sync_event));
+void DriveFileSyncServiceSyncTest::TestInitialization() {
+  EXPECT_EQ(SYNC_STATUS_OK, ProcessChangesUntilDone());
+  VerifyConsistency();
 }
 
-void DriveFileSyncServiceSyncTest::UpdateFileTest_Body() {
-  std::string kFile1 = "file title 1";
-  SyncEvent sync_event[] = {
-    CreateRemoteFileAddOrUpdateEvent(kFile1),
-    CreateRemoteFileAddOrUpdateEvent(kFile1),
-  };
+void DriveFileSyncServiceSyncTest::TestLocalToRemoteBasic() {
+  const GURL kOrigin("chrome-extension://example");
 
-  RunTest(CreateTestCase(sync_event));
+  RegisterOrigin(kOrigin);
+  AddOrUpdateLocalFile(kOrigin, base::FilePath(FPL("file")), "abcde");
+
+  EXPECT_EQ(SYNC_STATUS_OK, ProcessChangesUntilDone());
+  VerifyConsistency();
 }
 
-void DriveFileSyncServiceSyncTest::DeleteFileTest_Body() {
-  std::string kFile1 = "file title 1";
-  SyncEvent sync_event[] = {
-    CreateRemoteFileAddOrUpdateEvent(kFile1),
-    CreateFetchEvent(),
-    CreateProcessRemoteChangeEvent(),
-    CreateRemoteFileDeleteEvent(kFile1),
-  };
+void DriveFileSyncServiceSyncTest::TestRemoteToLocalBasic() {
+  const GURL kOrigin("chrome-extension://example");
 
-  RunTest(CreateTestCase(sync_event));
+  std::string sync_root_folder_id;
+  EXPECT_EQ(google_apis::HTTP_CREATED,
+            fake_drive_helper_->AddOrphanedFolder(
+                APIUtil::GetSyncRootDirectoryName(),
+                &sync_root_folder_id));
+
+  std::string origin_root_folder_id;
+  EXPECT_EQ(google_apis::HTTP_CREATED,
+            fake_drive_helper_->AddFolder(
+                sync_root_folder_id, kOrigin.host(), &origin_root_folder_id));
+
+  RegisterOrigin(kOrigin);
+
+  std::string file_id;
+  EXPECT_EQ(google_apis::HTTP_SUCCESS,
+            fake_drive_helper_->AddFile(
+                origin_root_folder_id, "file", "abcde", &file_id));
+
+  EXPECT_EQ(SYNC_STATUS_OK, ProcessChangesUntilDone());
+  VerifyConsistency();
 }
 
-void DriveFileSyncServiceSyncTest::RelaunchTest_Body() {
-  SyncEvent sync_event[] = {
-    CreateRelaunchEvent(),
-  };
+void DriveFileSyncServiceSyncTest::TestLocalFileUpdate() {
+  const GURL kOrigin("chrome-extension://example");
+  const base::FilePath kPath(FPL("file"));
 
-  RunTest(CreateTestCase(sync_event));
+  RegisterOrigin(kOrigin);
+  AddOrUpdateLocalFile(kOrigin, kPath, "abcde");
+
+  EXPECT_EQ(SYNC_STATUS_OK, ProcessChangesUntilDone());
+  VerifyConsistencyForOrigin(kOrigin);
+
+  UpdateLocalFile(kOrigin, kPath, "1234567890");
+
+  EXPECT_EQ(SYNC_STATUS_OK, ProcessChangesUntilDone());
+  VerifyConsistency();
 }
 
-void DriveFileSyncServiceSyncTest::SquashedFileAddTest_Body() {
-  std::string kFile1 = "file title 1";
-  SyncEvent sync_event[] = {
-    CreateRemoteFileAddOrUpdateEvent(kFile1),
-    CreateFetchEvent(),
-    CreateRemoteFileDeleteEvent(kFile1),
-  };
-  RunTest(CreateTestCase(sync_event));
+void DriveFileSyncServiceSyncTest::TestRemoteFileUpdate() {
+  const GURL kOrigin("chrome-extension://example");
+  const base::FilePath kPath(FPL("file"));
+  const std::string kTitle(DriveFileSyncService::PathToTitle(kPath));
+
+  std::string sync_root_folder_id;
+  EXPECT_EQ(google_apis::HTTP_CREATED,
+            fake_drive_helper_->AddOrphanedFolder(
+                APIUtil::GetSyncRootDirectoryName(),
+                &sync_root_folder_id));
+
+  std::string origin_root_folder_id;
+  EXPECT_EQ(google_apis::HTTP_CREATED,
+            fake_drive_helper_->AddFolder(
+                sync_root_folder_id, kOrigin.host(), &origin_root_folder_id));
+
+  std::string remote_file_id;
+  EXPECT_EQ(google_apis::HTTP_SUCCESS,
+            fake_drive_helper_->AddFile(
+                origin_root_folder_id, kTitle, "abcde", &remote_file_id));
+
+  RegisterOrigin(kOrigin);
+  EXPECT_EQ(SYNC_STATUS_OK, ProcessChangesUntilDone());
+  VerifyConsistencyForOrigin(kOrigin);
+
+  EXPECT_EQ(google_apis::HTTP_SUCCESS,
+            fake_drive_helper_->UpdateFile(remote_file_id, "1234567890"));
+
+  EXPECT_EQ(SYNC_STATUS_OK, ProcessChangesUntilDone());
+  VerifyConsistency();
 }
 
-void DriveFileSyncServiceSyncTest::RelaunchTestWithSquashedDeletion_Body() {
-  std::string kFile1 = "file title 1";
-  std::string kFile2 = "file title 2";
-  SyncEvent sync_event[] = {
-    CreateRemoteFileAddOrUpdateEvent(kFile1),
-    CreateFetchEvent(),
-    CreateProcessRemoteChangeEvent(),
+void DriveFileSyncServiceSyncTest::TestLocalFileDeletion() {
+  const GURL kOrigin("chrome-extension://example");
+  const base::FilePath kPath(FPL("file"));
 
-    CreateRemoteFileDeleteEvent(kFile1),
-    CreateRemoteFileAddOrUpdateEvent(kFile2),
-    CreateRemoteFileAddOrUpdateEvent(kFile1),
+  RegisterOrigin(kOrigin);
+  AddOrUpdateLocalFile(kOrigin, kPath, "abcde");
 
-    CreateFetchEvent(),
-    CreateProcessRemoteChangeEvent(),
-    CreateRelaunchEvent(),
-  };
-  RunTest(CreateTestCase(sync_event));
+  EXPECT_EQ(SYNC_STATUS_OK, ProcessChangesUntilDone());
+  VerifyConsistencyForOrigin(kOrigin);
+
+  RemoveLocal(kOrigin, kPath);
+
+  EXPECT_EQ(SYNC_STATUS_OK, ProcessChangesUntilDone());
+  VerifyConsistency();
 }
 
-void DriveFileSyncServiceSyncTest::CreateDirectoryTest_Body() {
-  std::string kDir = "dir title";
-  SyncEvent sync_event[] = {
-    CreateRemoteDirectoryAddEvent(kDir),
-  };
-  RunTest(CreateTestCase(sync_event));
+void DriveFileSyncServiceSyncTest::TestRemoteFileDeletion() {
+  const GURL kOrigin("chrome-extension://example");
+  const base::FilePath kPath(FPL("file"));
+  const std::string kTitle(DriveFileSyncService::PathToTitle(kPath));
+
+  std::string sync_root_folder_id;
+  EXPECT_EQ(google_apis::HTTP_CREATED,
+            fake_drive_helper_->AddOrphanedFolder(
+                APIUtil::GetSyncRootDirectoryName(),
+                &sync_root_folder_id));
+
+  std::string origin_root_folder_id;
+  EXPECT_EQ(google_apis::HTTP_CREATED,
+            fake_drive_helper_->AddFolder(
+                sync_root_folder_id, kOrigin.host(), &origin_root_folder_id));
+
+  std::string remote_file_id;
+  EXPECT_EQ(google_apis::HTTP_SUCCESS,
+            fake_drive_helper_->AddFile(
+                origin_root_folder_id, kTitle, "abcde", &remote_file_id));
+
+  RegisterOrigin(kOrigin);
+  EXPECT_EQ(SYNC_STATUS_OK, ProcessChangesUntilDone());
+  VerifyConsistencyForOrigin(kOrigin);
+
+  EXPECT_EQ(google_apis::HTTP_SUCCESS,
+            fake_drive_helper_->RemoveResource(remote_file_id));
+
+  EXPECT_EQ(SYNC_STATUS_OK, ProcessChangesUntilDone());
+  VerifyConsistency();
 }
 
-void DriveFileSyncServiceSyncTest::DeleteDirectoryTest_Body() {
-  std::string kDir = "dir title";
-  SyncEvent sync_event[] = {
-    CreateRemoteDirectoryAddEvent(kDir),
-    CreateRemoteFileDeleteEvent(kDir),
-  };
-  RunTest(CreateTestCase(sync_event));
-}
-
-TEST_F(DriveFileSyncServiceSyncTest, AddFileTest) {
+TEST_F(DriveFileSyncServiceSyncTest, InitializationTest) {
   ASSERT_FALSE(IsDriveAPIDisabled());
-  AddFileTest_Body();
+  TestInitialization();
 }
 
-TEST_F(DriveFileSyncServiceSyncTest, AddFileTest_WAPI) {
-  SetDisableDriveAPI(true);
-  AddFileTest_Body();
+TEST_F(DriveFileSyncServiceSyncTest, InitializationTest_WAPI) {
+  ScopedDisableDriveAPI disable_drive_api;
+  TestInitialization();
 }
 
-TEST_F(DriveFileSyncServiceSyncTest, UpdateFileTest) {
+TEST_F(DriveFileSyncServiceSyncTest, LocalToRemoteBasicTest) {
   ASSERT_FALSE(IsDriveAPIDisabled());
-  UpdateFileTest_Body();
+  TestLocalToRemoteBasic();
 }
 
-TEST_F(DriveFileSyncServiceSyncTest, UpdateFileTest_WAPI) {
-  SetDisableDriveAPI(true);
-  UpdateFileTest_Body();
+TEST_F(DriveFileSyncServiceSyncTest, LocalToRemoteBasicTest_WAPI) {
+  ScopedDisableDriveAPI disable_drive_api;
+  TestLocalToRemoteBasic();
 }
 
-TEST_F(DriveFileSyncServiceSyncTest, DeleteFileTest) {
+TEST_F(DriveFileSyncServiceSyncTest, RemoteToLocalBasicTest) {
   ASSERT_FALSE(IsDriveAPIDisabled());
-  DeleteFileTest_Body();
+  TestRemoteToLocalBasic();
 }
 
-TEST_F(DriveFileSyncServiceSyncTest, DeleteFileTest_WAPI) {
-  SetDisableDriveAPI(true);
-  DeleteFileTest_Body();
+TEST_F(DriveFileSyncServiceSyncTest, RemoteToLocalBasicTest_WAPI) {
+  ScopedDisableDriveAPI disable_drive_api;
+  TestRemoteToLocalBasic();
 }
 
-TEST_F(DriveFileSyncServiceSyncTest, RelaunchTest) {
+TEST_F(DriveFileSyncServiceSyncTest, LocalFileUpdateTest) {
   ASSERT_FALSE(IsDriveAPIDisabled());
-  RelaunchTest_Body();
+  TestLocalFileUpdate();
 }
 
-TEST_F(DriveFileSyncServiceSyncTest, RelaunchTest_WAPI) {
-  SetDisableDriveAPI(true);
-  RelaunchTest_Body();
+TEST_F(DriveFileSyncServiceSyncTest, LocalFileUpdateTest_WAPI) {
+  ScopedDisableDriveAPI disable_drive_api;
+  TestLocalFileUpdate();
 }
 
-TEST_F(DriveFileSyncServiceSyncTest, SquashedFileAddTest) {
+TEST_F(DriveFileSyncServiceSyncTest, RemoteFileUpdateTest) {
   ASSERT_FALSE(IsDriveAPIDisabled());
-  SquashedFileAddTest_Body();
+  TestRemoteFileUpdate();
 }
 
-TEST_F(DriveFileSyncServiceSyncTest, SquashedFileAddTest_WAPI) {
-  SetDisableDriveAPI(true);
-  SquashedFileAddTest_Body();
+TEST_F(DriveFileSyncServiceSyncTest, RemoteFileUpdateTest_WAPI) {
+  ScopedDisableDriveAPI disable_drive_api;
+  TestRemoteFileUpdate();
 }
 
-TEST_F(DriveFileSyncServiceSyncTest, RelaunchTestWithSquashedDeletion) {
+TEST_F(DriveFileSyncServiceSyncTest, LocalFileDeletionTest) {
   ASSERT_FALSE(IsDriveAPIDisabled());
-  RelaunchTestWithSquashedDeletion_Body();
+  TestLocalFileDeletion();
 }
 
-TEST_F(DriveFileSyncServiceSyncTest, RelaunchTestWithSquashedDeletion_WAPI) {
-  SetDisableDriveAPI(true);
-  RelaunchTestWithSquashedDeletion_Body();
+TEST_F(DriveFileSyncServiceSyncTest, LocalFileDeletionTest_WAPI) {
+  ScopedDisableDriveAPI disable_drive_api;
+  TestLocalFileDeletion();
 }
 
-TEST_F(DriveFileSyncServiceSyncTest, CreateDirectoryTest) {
+TEST_F(DriveFileSyncServiceSyncTest, RemoteFileDeletionTest) {
   ASSERT_FALSE(IsDriveAPIDisabled());
-  CreateDirectoryTest_Body();
+  TestRemoteFileDeletion();
 }
 
-TEST_F(DriveFileSyncServiceSyncTest, CreateDirectoryTest_WAPI) {
-  SetDisableDriveAPI(true);
-  CreateDirectoryTest_Body();
-}
-
-TEST_F(DriveFileSyncServiceSyncTest, DeleteDirectoryTest) {
-  ASSERT_FALSE(IsDriveAPIDisabled());
-  DeleteDirectoryTest_Body();
-}
-
-TEST_F(DriveFileSyncServiceSyncTest, DeleteDirectoryTest_WAPI) {
-  SetDisableDriveAPI(true);
-  DeleteDirectoryTest_Body();
+TEST_F(DriveFileSyncServiceSyncTest, RemoteFileDeletionTest_WAPI) {
+  ScopedDisableDriveAPI disable_drive_api;
+  TestRemoteFileDeletion();
 }
 
 }  // namespace sync_file_system
diff --git a/chrome/browser/sync_file_system/drive_file_sync_service_unittest.cc b/chrome/browser/sync_file_system/drive_file_sync_service_unittest.cc
index c063e41..a95685e 100644
--- a/chrome/browser/sync_file_system/drive_file_sync_service_unittest.cc
+++ b/chrome/browser/sync_file_system/drive_file_sync_service_unittest.cc
@@ -4,17 +4,22 @@
 
 #include "chrome/browser/sync_file_system/drive_file_sync_service.h"
 
-#include "base/message_loop.h"
-#include "chrome/browser/sync_file_system/drive/fake_api_util.h"
+#include "base/message_loop/message_loop.h"
+#include "base/message_loop/message_loop_proxy.h"
+#include "chrome/browser/sync_file_system/drive_backend/fake_api_util.h"
 #include "chrome/browser/sync_file_system/drive_metadata_store.h"
 #include "chrome/browser/sync_file_system/sync_file_system.pb.h"
 #include "chrome/test/base/testing_profile.h"
 #include "content/public/test/test_browser_thread.h"
+#include "content/public/test/test_browser_thread_bundle.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "webkit/browser/fileapi/syncable/syncable_file_system_util.h"
 
 namespace sync_file_system {
 
+using drive_backend::APIUtilInterface;
+using drive_backend::FakeAPIUtil;
+
 namespace {
 
 const char kSyncRootResourceId[] = "folder:sync_root_resource_id";
@@ -41,14 +46,13 @@
 class DriveFileSyncServiceTest : public testing::Test {
  public:
   DriveFileSyncServiceTest()
-      : ui_thread_(content::BrowserThread::UI, &message_loop_),
-        file_thread_(content::BrowserThread::FILE, &message_loop_),
+      : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP),
         fake_api_util_(NULL),
         metadata_store_(NULL) {}
 
   virtual void SetUp() OVERRIDE {
     RegisterSyncableFileSystem();
-    fake_api_util_ = new drive::FakeAPIUtil;
+    fake_api_util_ = new FakeAPIUtil;
 
     ASSERT_TRUE(scoped_base_dir_.CreateUniqueTempDir());
     base_dir_ = scoped_base_dir_.path();
@@ -56,23 +60,23 @@
         base_dir_, base::MessageLoopProxy::current().get());
     bool done = false;
     metadata_store_->Initialize(base::Bind(&DidInitialize, &done));
-    message_loop_.RunUntilIdle();
+    base::MessageLoop::current()->RunUntilIdle();
     metadata_store_->SetSyncRootDirectory(kSyncRootResourceId);
     EXPECT_TRUE(done);
 
     sync_service_ = DriveFileSyncService::CreateForTesting(
         &profile_,
         base_dir_,
-        scoped_ptr<drive::APIUtilInterface>(fake_api_util_),
+        scoped_ptr<APIUtilInterface>(fake_api_util_),
         scoped_ptr<DriveMetadataStore>(metadata_store_)).Pass();
-    message_loop_.RunUntilIdle();
+    base::MessageLoop::current()->RunUntilIdle();
   }
 
   virtual void TearDown() OVERRIDE {
     metadata_store_ = NULL;
     fake_api_util_ = NULL;
     sync_service_.reset();
-    message_loop_.RunUntilIdle();
+    base::MessageLoop::current()->RunUntilIdle();
 
     base_dir_ = base::FilePath();
     RevokeSyncableFileSystem();
@@ -82,8 +86,7 @@
   }
 
  protected:
-  base::MessageLoop* message_loop() { return &message_loop_; }
-  drive::FakeAPIUtil* fake_api_util() { return fake_api_util_; }
+  FakeAPIUtil* fake_api_util() { return fake_api_util_; }
   DriveMetadataStore* metadata_store() { return metadata_store_; }
   DriveFileSyncService* sync_service() { return sync_service_.get(); }
   std::map<GURL, std::string>* pending_batch_sync_origins() {
@@ -135,14 +138,12 @@
 
  private:
   base::ScopedTempDir scoped_base_dir_;
-  base::MessageLoop message_loop_;
-  content::TestBrowserThread ui_thread_;
-  content::TestBrowserThread file_thread_;
+  content::TestBrowserThreadBundle thread_bundle_;
 
   TestingProfile profile_;
   base::FilePath base_dir_;
 
-  drive::FakeAPIUtil* fake_api_util_;   // Owned by |sync_service_|.
+  FakeAPIUtil* fake_api_util_;          // Owned by |sync_service_|.
   DriveMetadataStore* metadata_store_;  // Owned by |sync_service_|.
 
   scoped_ptr<DriveFileSyncService> sync_service_;
@@ -171,7 +172,7 @@
   sync_service()->UninstallOrigin(
       origin_gurl,
       base::Bind(&ExpectEqStatus, &done, SYNC_STATUS_OK));
-  message_loop()->RunUntilIdle();
+  base::MessageLoop::current()->RunUntilIdle();
   EXPECT_TRUE(done);
 
   // Assert the App's origin folder was marked as deleted.
@@ -193,11 +194,11 @@
   sync_service()->UninstallOrigin(
       origin_gurl,
       base::Bind(&ExpectEqStatus, &done, SYNC_STATUS_OK));
-  message_loop()->RunUntilIdle();
+  base::MessageLoop::current()->RunUntilIdle();
   EXPECT_TRUE(done);
 
   // Assert the App's origin folder does not exist.
-  const drive::FakeAPIUtil::RemoteResourceByResourceId& remote_resources =
+  const FakeAPIUtil::RemoteResourceByResourceId& remote_resources =
       fake_api_util()->remote_resources();
   EXPECT_TRUE(remote_resources.find(origin_dir_resource_id) ==
               remote_resources.end());
@@ -214,7 +215,7 @@
   // Pending origins that are disabled are dropped and do not go to disabled.
   sync_service()->DisableOriginForTrackingChanges(origin,
                                                   base::Bind(&ExpectOkStatus));
-  message_loop()->RunUntilIdle();
+  base::MessageLoop::current()->RunUntilIdle();
   ASSERT_TRUE(VerifyOriginStatusCount(0u, 0u, 0u));
 }
 
@@ -228,7 +229,7 @@
 
   sync_service()->DisableOriginForTrackingChanges(origin,
                                                   base::Bind(&ExpectOkStatus));
-  message_loop()->RunUntilIdle();
+  base::MessageLoop::current()->RunUntilIdle();
   ASSERT_TRUE(VerifyOriginStatusCount(0u, 0u, 1u));
 }
 
@@ -245,7 +246,7 @@
   // origins > 0.
   sync_service()->EnableOriginForTrackingChanges(origin,
                                                  base::Bind(&ExpectOkStatus));
-  message_loop()->RunUntilIdle();
+  base::MessageLoop::current()->RunUntilIdle();
   ASSERT_TRUE(VerifyOriginStatusCount(0u, 1u, 0u));
 }
 
diff --git a/chrome/browser/sync_file_system/drive_file_sync_util.cc b/chrome/browser/sync_file_system/drive_file_sync_util.cc
index 25389e9..8999771 100644
--- a/chrome/browser/sync_file_system/drive_file_sync_util.cc
+++ b/chrome/browser/sync_file_system/drive_file_sync_util.cc
@@ -96,4 +96,14 @@
       CommandLine::ForCurrentProcess()->HasSwitch(kDisableDriveAPI);
 }
 
+ScopedDisableDriveAPI::ScopedDisableDriveAPI()
+    : was_disabled_(IsDriveAPIDisabled()) {
+  SetDisableDriveAPI(true);
+}
+
+ScopedDisableDriveAPI::~ScopedDisableDriveAPI() {
+  DCHECK(IsDriveAPIDisabled());
+  SetDisableDriveAPI(was_disabled_);
+}
+
 }  // namespace sync_file_system
diff --git a/chrome/browser/sync_file_system/drive_file_sync_util.h b/chrome/browser/sync_file_system/drive_file_sync_util.h
index 007122c..5df4ce5 100644
--- a/chrome/browser/sync_file_system/drive_file_sync_util.h
+++ b/chrome/browser/sync_file_system/drive_file_sync_util.h
@@ -26,6 +26,17 @@
 // DriveAPI. (http://crbug.com/234557)
 bool IsDriveAPIDisabled();
 
+class ScopedDisableDriveAPI {
+ public:
+  ScopedDisableDriveAPI();
+  ~ScopedDisableDriveAPI();
+
+ private:
+  bool was_disabled_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedDisableDriveAPI);
+};
+
 }  // namespace sync_file_system
 
 #endif  // CHROME_BROWSER_SYNC_FILE_SYSTEM_DRIVE_FILE_SYNC_UTIL_H_
diff --git a/chrome/browser/sync_file_system/drive_metadata_store.cc b/chrome/browser/sync_file_system/drive_metadata_store.cc
index da343e3..65f125b 100644
--- a/chrome/browser/sync_file_system/drive_metadata_store.cc
+++ b/chrome/browser/sync_file_system/drive_metadata_store.cc
@@ -14,20 +14,19 @@
 #include "base/message_loop/message_loop_proxy.h"
 #include "base/sequenced_task_runner.h"
 #include "base/stl_util.h"
-#include "base/string_util.h"
-#include "base/stringprintf.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
 #include "base/task_runner_util.h"
-#include "chrome/browser/sync_file_system/drive/metadata_db_migration_util.h"
+#include "chrome/browser/sync_file_system/drive_backend/metadata_db_migration_util.h"
 #include "chrome/browser/sync_file_system/drive_file_sync_service.h"
 #include "chrome/browser/sync_file_system/drive_file_sync_util.h"
 #include "chrome/browser/sync_file_system/file_metadata.h"
 #include "chrome/browser/sync_file_system/logger.h"
 #include "chrome/browser/sync_file_system/sync_file_system.pb.h"
-#include "googleurl/src/gurl.h"
 #include "third_party/leveldatabase/src/include/leveldb/db.h"
 #include "third_party/leveldatabase/src/include/leveldb/write_batch.h"
+#include "url/gurl.h"
 #include "webkit/browser/fileapi/file_system_url.h"
 #include "webkit/browser/fileapi/syncable/syncable_file_system_util.h"
 #include "webkit/common/fileapi/file_system_util.h"
@@ -174,10 +173,10 @@
 
   switch (version) {
     case 0:
-      drive::MigrateDatabaseFromV0ToV1(db);
+      drive_backend::MigrateDatabaseFromV0ToV1(db);
       // fall-through
     case 1:
-      drive::MigrateDatabaseFromV1ToV2(db);
+      drive_backend::MigrateDatabaseFromV1ToV2(db);
       // fall-through
     case 2:
       DCHECK_EQ(2, kCurrentDatabaseVersion);
@@ -209,7 +208,7 @@
     if (key == kSyncRootDirectoryKey) {
       std::string resource_id = itr->value().ToString();
       if (IsDriveAPIDisabled())
-        resource_id = drive::AddWapiFolderPrefix(resource_id);
+        resource_id = drive_backend::AddWapiFolderPrefix(resource_id);
       contents->sync_root_directory_resource_id = resource_id;
       continue;
     }
@@ -224,8 +223,8 @@
       DCHECK(success);
 
       if (IsDriveAPIDisabled()) {
-        metadata.set_resource_id(
-            drive::AddWapiIdPrefix(metadata.resource_id(), metadata.type()));
+        metadata.set_resource_id(drive_backend::AddWapiIdPrefix(
+            metadata.resource_id(), metadata.type()));
       }
 
       success = contents->metadata_map[origin].insert(
@@ -239,7 +238,7 @@
       DCHECK(origin.is_valid());
 
       std::string origin_resource_id = IsDriveAPIDisabled()
-          ? drive::AddWapiFolderPrefix(itr->value().ToString())
+          ? drive_backend::AddWapiFolderPrefix(itr->value().ToString())
           : itr->value().ToString();
 
       DCHECK(!ContainsKey(contents->incremental_sync_origins, origin));
@@ -252,7 +251,7 @@
       DCHECK(origin.is_valid());
 
       std::string origin_resource_id = IsDriveAPIDisabled()
-          ? drive::AddWapiFolderPrefix(itr->value().ToString())
+          ? drive_backend::AddWapiFolderPrefix(itr->value().ToString())
           : itr->value().ToString();
 
       DCHECK(!ContainsKey(contents->disabled_origins, origin));
@@ -444,7 +443,7 @@
   if (IsDriveAPIDisabled()) {
     DriveMetadata metadata_in_db(metadata);
     metadata_in_db.set_resource_id(
-        drive::RemoveWapiIdPrefix(metadata.resource_id()));
+        drive_backend::RemoveWapiIdPrefix(metadata.resource_id()));
     bool success = metadata_in_db.SerializeToString(&value);
     DCHECK(success);
   } else {
@@ -512,7 +511,7 @@
   scoped_ptr<leveldb::WriteBatch> batch(new leveldb::WriteBatch);
   batch->Delete(CreateKeyForOriginRoot(origin, DISABLED_ORIGIN));
   batch->Put(CreateKeyForOriginRoot(origin, INCREMENTAL_SYNC_ORIGIN),
-             drive::RemoveWapiIdPrefix(resource_id));
+             drive_backend::RemoveWapiIdPrefix(resource_id));
   WriteToDB(batch.Pass(),
             base::Bind(&DriveMetadataStore::UpdateDBStatus, AsWeakPtr()));
 }
@@ -523,7 +522,8 @@
   sync_root_directory_resource_id_ = resource_id;
 
   scoped_ptr<leveldb::WriteBatch> batch(new leveldb::WriteBatch);
-  batch->Put(kSyncRootDirectoryKey, drive::RemoveWapiIdPrefix(resource_id));
+  batch->Put(kSyncRootDirectoryKey,
+             drive_backend::RemoveWapiIdPrefix(resource_id));
   return WriteToDB(batch.Pass(),
                    base::Bind(&DriveMetadataStore::UpdateDBStatus,
                               AsWeakPtr()));
@@ -551,7 +551,7 @@
   DCHECK(!key.empty());
 
   scoped_ptr<leveldb::WriteBatch> batch(new leveldb::WriteBatch);
-  batch->Put(key, drive::RemoveWapiIdPrefix(resource_id));
+  batch->Put(key, drive_backend::RemoveWapiIdPrefix(resource_id));
   WriteToDB(batch.Pass(),
             base::Bind(&DriveMetadataStore::UpdateDBStatus, AsWeakPtr()));
 }
@@ -609,7 +609,7 @@
   scoped_ptr<leveldb::WriteBatch> batch(new leveldb::WriteBatch);
   batch->Delete(CreateKeyForOriginRoot(origin, INCREMENTAL_SYNC_ORIGIN));
   batch->Put(CreateKeyForOriginRoot(origin, DISABLED_ORIGIN),
-             drive::RemoveWapiIdPrefix(resource_id));
+             drive_backend::RemoveWapiIdPrefix(resource_id));
   AppendMetadataDeletionToBatch(metadata_map_, origin, batch.get());
   metadata_map_.erase(origin);
 
@@ -769,28 +769,29 @@
 }
 
 void DriveMetadataStore::GetFileMetadataMap(
-    OriginToFileMetadataMap* output_map) {
+    const GURL& origin,
+    FileMetadataMap* output_map) {
   DCHECK(CalledOnValidThread());
+  DCHECK(!origin.is_empty());
   DCHECK(output_map);
 
-  for (MetadataMap::const_iterator origin_itr = metadata_map_.begin();
-       origin_itr != metadata_map_.end();
-       ++origin_itr) {
-    for (PathToMetadata::const_iterator itr = origin_itr->second.begin();
-         itr != origin_itr->second.end();
-         ++itr) {
-      // Convert Drive specific metadata to Common File metadata object.
-      const GURL& origin = origin_itr->first;
-      const std::string title = itr->first.BaseName().AsUTF8Unsafe();
-      const DriveMetadata& metadata = itr->second;
-      const FileType type = DriveTypeToFileMetadataType(metadata.type());
-      std::ostringstream details;
-      details << "resource_id=" << metadata.resource_id() << ", "
-              << "md5_checksum=" << metadata.md5_checksum() << ", "
-              << "to_be_fetched=" << metadata.to_be_fetched();
-      FileMetadata file_metadata(title, type, details.str());
-      (*output_map)[origin][itr->first] = file_metadata;
-    }
+  MetadataMap::const_iterator origin_itr = metadata_map_.find(origin);
+  if (origin_itr == metadata_map_.end())
+    return;
+
+  for (PathToMetadata::const_iterator itr = origin_itr->second.begin();
+       itr != origin_itr->second.end();
+       ++itr) {
+    // Convert Drive specific metadata to Common File metadata object.
+    const std::string title = itr->first.BaseName().AsUTF8Unsafe();
+    const DriveMetadata& metadata = itr->second;
+    const FileType type = DriveTypeToFileMetadataType(metadata.type());
+    std::ostringstream details;
+    details << "resource_id=" << metadata.resource_id() << ", "
+            << "md5_checksum=" << metadata.md5_checksum() << ", "
+            << "to_be_fetched=" << metadata.to_be_fetched();
+    FileMetadata file_metadata(title, type, details.str());
+    (*output_map)[itr->first] = file_metadata;
   }
 }
 
diff --git a/chrome/browser/sync_file_system/drive_metadata_store.h b/chrome/browser/sync_file_system/drive_metadata_store.h
index da2a8c4..b243a5e 100644
--- a/chrome/browser/sync_file_system/drive_metadata_store.h
+++ b/chrome/browser/sync_file_system/drive_metadata_store.h
@@ -147,10 +147,9 @@
   bool GetOriginByOriginRootDirectoryId(const std::string& resource_id,
                                         GURL* origin);
 
-  // Returns all file metadata grouped by origin.
+  // Returns all file metadata for the given origin.
   typedef std::map<base::FilePath, FileMetadata> FileMetadataMap;
-  typedef std::map<GURL, FileMetadataMap> OriginToFileMetadataMap;
-  void GetFileMetadataMap(OriginToFileMetadataMap* output_map);
+  void GetFileMetadataMap(const GURL& origin, FileMetadataMap* output_map);
 
  private:
   friend class DriveMetadataStoreTest;
diff --git a/chrome/browser/sync_file_system/drive_metadata_store_unittest.cc b/chrome/browser/sync_file_system/drive_metadata_store_unittest.cc
index fddb38a..dc119bb 100644
--- a/chrome/browser/sync_file_system/drive_metadata_store_unittest.cc
+++ b/chrome/browser/sync_file_system/drive_metadata_store_unittest.cc
@@ -14,7 +14,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/threading/thread.h"
-#include "chrome/browser/sync_file_system/drive/metadata_db_migration_util.h"
+#include "chrome/browser/sync_file_system/drive_backend/metadata_db_migration_util.h"
 #include "chrome/browser/sync_file_system/drive_file_sync_service.h"
 #include "chrome/browser/sync_file_system/drive_file_sync_util.h"
 #include "chrome/browser/sync_file_system/file_metadata.h"
@@ -53,7 +53,7 @@
 
 std::string CreateResourceId(const std::string& resource_id) {
   return IsDriveAPIDisabled() ? resource_id
-                              : drive::RemoveWapiIdPrefix(resource_id);
+                              : drive_backend::RemoveWapiIdPrefix(resource_id);
 }
 
 DriveMetadata CreateMetadata(const std::string& resource_id,
@@ -588,60 +588,42 @@
 
 void DriveMetadataStoreTest::GetFileMetadataMap_Body() {
   InitializeDatabase();
-  DriveMetadataStore::OriginToFileMetadataMap metadata_map;
-  metadata_store()->GetFileMetadataMap(&metadata_map);
-  EXPECT_TRUE(metadata_map.empty());
 
-  // Add 2 files to one origin and 1 folder to another origin.
-  const GURL origin_a = GURL("chrome-extension://app_a");
-  const GURL origin_b = GURL("chrome-extension://app_b");
-  const base::FilePath origin_a_file_0 = base::FilePath(FPL("origin_a_file_0"));
-  const base::FilePath origin_a_file_1 = base::FilePath(FPL("origin_a_file_1"));
-  const base::FilePath origin_b_folder_0 = base::FilePath(FPL(
-      "origin_b_folder_0"));
+  // Save one file and folder to the origin.
+  const base::FilePath file_path = base::FilePath(FPL("file_0"));
+  const base::FilePath folder_path = base::FilePath(FPL("folder_0"));
 
-  const fileapi::FileSystemURL url_a_0 = CreateSyncableFileSystemURL(
-      origin_a, origin_a_file_0);
-  const fileapi::FileSystemURL url_a_1 = CreateSyncableFileSystemURL(
-      origin_a, origin_a_file_1);
-  const fileapi::FileSystemURL url_b_0 = CreateSyncableFileSystemURL(
-      origin_b, origin_b_folder_0);
+  const GURL origin = GURL("chrome-extension://app_a");
+  const fileapi::FileSystemURL url_0 = CreateSyncableFileSystemURL(
+      origin, file_path);
+  const fileapi::FileSystemURL url_1 = CreateSyncableFileSystemURL(
+      origin, folder_path);
 
   // Insert DrivaMetadata objects.
   EXPECT_EQ(SYNC_STATUS_OK, UpdateEntry(
-      url_a_0,
+      url_0,
       CreateMetadata("file:0", "1", false, false,
                      DriveMetadata_ResourceType_RESOURCE_TYPE_FILE)));
   EXPECT_EQ(SYNC_STATUS_OK, UpdateEntry(
-      url_a_1,
-      CreateMetadata("file:1", "2", false, true,
-                     DriveMetadata_ResourceType_RESOURCE_TYPE_FILE)));
-  EXPECT_EQ(SYNC_STATUS_OK, UpdateEntry(
-      url_b_0,
-      CreateMetadata("folder:0", "3", false, true,
+      url_1,
+      CreateMetadata("folder:0", "2", false, true,
                      DriveMetadata_ResourceType_RESOURCE_TYPE_FOLDER)));
 
   // Check that DriveMetadata objects get mapped back to generalized
   // FileMetadata objects.
-  metadata_store()->GetFileMetadataMap(&metadata_map);
+  DriveMetadataStore::FileMetadataMap metadata_map;
+  metadata_store()->GetFileMetadataMap(origin, &metadata_map);
   ASSERT_EQ(2U, metadata_map.size());
-  ASSERT_EQ(2U, metadata_map[origin_a].size());
-  ASSERT_EQ(1U, metadata_map[origin_b].size());
 
-  FileMetadata metadata_a_0 = metadata_map[origin_a][origin_a_file_0];
-  EXPECT_EQ("origin_a_file_0", metadata_a_0.title);
-  EXPECT_EQ(TYPE_FILE, metadata_a_0.type);
-  EXPECT_TRUE(!metadata_a_0.service_specific_metadata.empty());
+  FileMetadata metadata_0 = metadata_map[file_path];
+  EXPECT_EQ("file_0", metadata_0.title);
+  EXPECT_EQ(TYPE_FILE, metadata_0.type);
+  EXPECT_TRUE(!metadata_0.service_specific_metadata.empty());
 
-  FileMetadata metadata_a_1 = metadata_map[origin_a][origin_a_file_1];
-  EXPECT_EQ("origin_a_file_1", metadata_a_1.title);
-  EXPECT_EQ(TYPE_FILE, metadata_a_1.type);
-  EXPECT_TRUE(!metadata_a_1.service_specific_metadata.empty());
-
-  FileMetadata metadata_b_0 = metadata_map[origin_b][origin_b_folder_0];
-  EXPECT_EQ("origin_b_folder_0", metadata_b_0.title);
-  EXPECT_EQ(TYPE_FOLDER, metadata_b_0.type);
-  EXPECT_TRUE(!metadata_b_0.service_specific_metadata.empty());
+  FileMetadata metadata_1 = metadata_map[folder_path];
+  EXPECT_EQ("folder_0", metadata_1.title);
+  EXPECT_EQ(TYPE_FOLDER, metadata_1.type);
+  EXPECT_TRUE(!metadata_1.service_specific_metadata.empty());
 }
 
 TEST_F(DriveMetadataStoreTest, Initialization) {
diff --git a/chrome/browser/sync_file_system/file_status_observer.h b/chrome/browser/sync_file_system/file_status_observer.h
index 4c2af44..6fc667b 100644
--- a/chrome/browser/sync_file_system/file_status_observer.h
+++ b/chrome/browser/sync_file_system/file_status_observer.h
@@ -6,8 +6,8 @@
 #define CHROME_BROWSER_SYNC_FILE_SYSTEM_FILE_STATUS_OBSERVER_H_
 
 #include "base/basictypes.h"
-#include "webkit/browser/fileapi/syncable/sync_action.h"
-#include "webkit/browser/fileapi/syncable/sync_direction.h"
+#include "chrome/browser/sync_file_system/sync_action.h"
+#include "chrome/browser/sync_file_system/sync_direction.h"
 #include "webkit/browser/fileapi/syncable/sync_file_status.h"
 
 namespace fileapi {
diff --git a/chrome/browser/sync_file_system/local_file_sync_service.cc b/chrome/browser/sync_file_system/local_file_sync_service.cc
index ff8804c..13cbefb 100644
--- a/chrome/browser/sync_file_system/local_file_sync_service.cc
+++ b/chrome/browser/sync_file_system/local_file_sync_service.cc
@@ -14,7 +14,7 @@
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/site_instance.h"
 #include "content/public/browser/storage_partition.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 #include "webkit/browser/fileapi/file_system_context.h"
 #include "webkit/browser/fileapi/file_system_url.h"
 #include "webkit/browser/fileapi/syncable/file_change.h"
diff --git a/chrome/browser/sync_file_system/local_file_sync_service_unittest.cc b/chrome/browser/sync_file_system/local_file_sync_service_unittest.cc
index 09c500b..59722dc 100644
--- a/chrome/browser/sync_file_system/local_file_sync_service_unittest.cc
+++ b/chrome/browser/sync_file_system/local_file_sync_service_unittest.cc
@@ -173,6 +173,7 @@
     return file_system_->file_system_context()->change_tracker()->num_changes();
   }
 
+  ScopedEnableSyncFSDirectoryOperation enable_directory_operation_;
   TestingProfile profile_;
 
   MultiThreadTestHelper thread_helper_;
diff --git a/chrome/browser/sync_file_system/logger.cc b/chrome/browser/sync_file_system/logger.cc
index 2257c8d..9c825e8 100644
--- a/chrome/browser/sync_file_system/logger.cc
+++ b/chrome/browser/sync_file_system/logger.cc
@@ -8,13 +8,13 @@
 #include "base/lazy_instance.h"
 #include "base/location.h"
 #include "base/strings/stringprintf.h"
-#include "chrome/browser/google_apis/event_logger.h"
+#include "chrome/browser/drive/event_logger.h"
 
 namespace sync_file_system {
 namespace util {
 namespace {
 
-static base::LazyInstance<google_apis::EventLogger> g_logger =
+static base::LazyInstance<drive::EventLogger> g_logger =
     LAZY_INSTANCE_INITIALIZER;
 
 const char* LogSeverityToString(logging::LogSeverity level) {
@@ -36,7 +36,7 @@
 }  // namespace
 
 void ClearLog() {
-  g_logger.Pointer()->SetHistorySize(google_apis::kDefaultHistorySize);
+  g_logger.Pointer()->SetHistorySize(::drive::kDefaultHistorySize);
 }
 
 void Log(logging::LogSeverity severity,
@@ -50,20 +50,11 @@
   base::StringAppendV(&what, format, args);
   va_end(args);
 
-  // Use same output format as normal console logger.
-  base::FilePath path = base::FilePath::FromUTF8Unsafe(location.file_name());
-  std::string log_output = base::StringPrintf(
-      "[%s: %s(%d)] %s",
-      LogSeverityToString(severity),
-      path.BaseName().AsUTF8Unsafe().c_str(),
-      location.line_number(),
-      what.c_str());
-
   // Log to WebUI regardless of LogSeverity (e.g. ignores command line flags).
   // On thread-safety: LazyInstance guarantees thread-safety for the object
   // creation. EventLogger::Log() internally maintains the lock.
-  google_apis::EventLogger* ptr = g_logger.Pointer();
-  ptr->Log("%s", log_output.c_str());
+  drive::EventLogger* ptr = g_logger.Pointer();
+  ptr->Log("[%s] %s", LogSeverityToString(severity), what.c_str());
 
   // Log to console if the severity is at or above the min level.
   // LOG_VERBOSE logs are also output if the verbosity of this module
@@ -76,8 +67,8 @@
       .stream() << what;
 }
 
-std::vector<google_apis::EventLogger::Event> GetLogHistory() {
-  google_apis::EventLogger* ptr = g_logger.Pointer();
+std::vector<drive::EventLogger::Event> GetLogHistory() {
+  drive::EventLogger* ptr = g_logger.Pointer();
   return ptr->GetHistory();
 }
 
diff --git a/chrome/browser/sync_file_system/logger.h b/chrome/browser/sync_file_system/logger.h
index 9eac379..fbd3d4c 100644
--- a/chrome/browser/sync_file_system/logger.h
+++ b/chrome/browser/sync_file_system/logger.h
@@ -10,7 +10,7 @@
 
 #include "base/location.h"
 #include "base/logging.h"
-#include "chrome/browser/google_apis/event_logger.h"
+#include "chrome/browser/drive/event_logger.h"
 
 namespace sync_file_system {
 // Originally wanted to use 'logging' here, but it conflicts with
@@ -30,7 +30,7 @@
 
 // Returns the log history.
 // This function can be called from any thread.
-std::vector<google_apis::EventLogger::Event> GetLogHistory();
+std::vector< ::drive::EventLogger::Event> GetLogHistory();
 
 }  // namespace util
 }  // namespace sync_file_system
diff --git a/chrome/browser/sync_file_system/logger_unittest.cc b/chrome/browser/sync_file_system/logger_unittest.cc
index 8739183..157828c 100644
--- a/chrome/browser/sync_file_system/logger_unittest.cc
+++ b/chrome/browser/sync_file_system/logger_unittest.cc
@@ -5,7 +5,7 @@
 #include "chrome/browser/sync_file_system/logger.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-using google_apis::EventLogger;
+using drive::EventLogger;
 
 namespace sync_file_system {
 
diff --git a/chrome/browser/sync_file_system/mock_remote_file_sync_service.cc b/chrome/browser/sync_file_system/mock_remote_file_sync_service.cc
index f274dfe..0f41b15 100644
--- a/chrome/browser/sync_file_system/mock_remote_file_sync_service.cc
+++ b/chrome/browser/sync_file_system/mock_remote_file_sync_service.cc
@@ -9,7 +9,7 @@
 #include "base/bind.h"
 #include "base/location.h"
 #include "base/message_loop/message_loop_proxy.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 #include "webkit/browser/fileapi/file_system_url.h"
 
 using ::testing::_;
@@ -19,7 +19,7 @@
 namespace sync_file_system {
 
 MockRemoteFileSyncService::MockRemoteFileSyncService()
-    : conflict_resolution_policy_(CONFLICT_RESOLUTION_MANUAL) {
+    : conflict_resolution_policy_(CONFLICT_RESOLUTION_POLICY_MANUAL) {
   typedef MockRemoteFileSyncService self;
   ON_CALL(*this, AddServiceObserver(_))
       .WillByDefault(Invoke(this, &self::AddServiceObserverStub));
diff --git a/chrome/browser/sync_file_system/mock_remote_file_sync_service.h b/chrome/browser/sync_file_system/mock_remote_file_sync_service.h
index ae23d7c..e1df6a7 100644
--- a/chrome/browser/sync_file_system/mock_remote_file_sync_service.h
+++ b/chrome/browser/sync_file_system/mock_remote_file_sync_service.h
@@ -13,10 +13,10 @@
 #include "chrome/browser/sync_file_system/mock_local_change_processor.h"
 #include "chrome/browser/sync_file_system/remote_change_processor.h"
 #include "chrome/browser/sync_file_system/remote_file_sync_service.h"
-#include "googleurl/src/gurl.h"
+#include "chrome/browser/sync_file_system/sync_direction.h"
 #include "testing/gmock/include/gmock/gmock.h"
+#include "url/gurl.h"
 #include "webkit/browser/fileapi/syncable/sync_callbacks.h"
-#include "webkit/browser/fileapi/syncable/sync_direction.h"
 #include "webkit/browser/fileapi/syncable/sync_file_metadata.h"
 
 namespace sync_file_system {
@@ -51,9 +51,9 @@
                      RemoteServiceState());
   MOCK_METHOD1(GetOriginStatusMap,
                void(RemoteFileSyncService::OriginStatusMap* status_map));
-  MOCK_METHOD1(
-      GetFileMetadataMap,
-      void(RemoteFileSyncService::OriginFileMetadataMap* metadata_map));
+  MOCK_METHOD2(GetFileMetadataMap,
+               void(const GURL& origin,
+                    RemoteFileSyncService::FileMetadataMap* metadata_map));
   MOCK_METHOD1(SetSyncEnabled, void(bool));
   MOCK_METHOD1(SetConflictResolutionPolicy,
                SyncStatusCode(ConflictResolutionPolicy));
diff --git a/chrome/browser/sync_file_system/remote_change_handler.h b/chrome/browser/sync_file_system/remote_change_handler.h
index 4820833..96be8c3 100644
--- a/chrome/browser/sync_file_system/remote_change_handler.h
+++ b/chrome/browser/sync_file_system/remote_change_handler.h
@@ -12,7 +12,7 @@
 
 #include "base/files/file_path.h"
 #include "base/stl_util.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "webkit/browser/fileapi/file_system_url.h"
 #include "webkit/browser/fileapi/syncable/file_change.h"
 
diff --git a/chrome/browser/sync_file_system/remote_file_sync_service.h b/chrome/browser/sync_file_system/remote_file_sync_service.h
index 69d4bae..c4f32b7 100644
--- a/chrome/browser/sync_file_system/remote_file_sync_service.h
+++ b/chrome/browser/sync_file_system/remote_file_sync_service.h
@@ -145,10 +145,10 @@
   typedef std::map<GURL, std::string> OriginStatusMap;
   virtual void GetOriginStatusMap(OriginStatusMap* status_map) = 0;
 
-  // Returns all file metadata grouped by origin.
+  // Returns file metadata for one origin.
   typedef std::map<base::FilePath, FileMetadata> FileMetadataMap;
-  typedef std::map<GURL, FileMetadataMap> OriginFileMetadataMap;
-  virtual void GetFileMetadataMap(OriginFileMetadataMap* metadata_map) = 0;
+  virtual void GetFileMetadataMap(const GURL& origin,
+                                  FileMetadataMap* metadata_map) = 0;
 
   // Enables or disables the background sync.
   // Setting this to false should disable the synchronization (and make
diff --git a/chrome/browser/sync_file_system/sync_action.h b/chrome/browser/sync_file_system/sync_action.h
new file mode 100644
index 0000000..1941288
--- /dev/null
+++ b/chrome/browser/sync_file_system/sync_action.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 CHROME_BROWSER_SYNC_FILE_SYSTEM_SYNC_ACTION_H_
+#define CHROME_BROWSER_SYNC_FILE_SYSTEM_SYNC_ACTION_H_
+
+namespace sync_file_system {
+
+enum SyncAction {
+  // Indicates no action has been made.
+  SYNC_ACTION_NONE,
+
+  // Indicates a new file or directory has been added.
+  SYNC_ACTION_ADDED,
+
+  // Indicates an existing file or directory has been updated.
+  SYNC_ACTION_UPDATED,
+
+  // Indicates a file or directory has been deleted.
+  SYNC_ACTION_DELETED,
+};
+
+}  // namespace sync_file_system
+
+#endif  // CHROME_BROWSER_SYNC_FILE_SYSTEM_SYNC_ACTION_H_
diff --git a/chrome/browser/sync_file_system/sync_direction.h b/chrome/browser/sync_file_system/sync_direction.h
new file mode 100644
index 0000000..cffe640
--- /dev/null
+++ b/chrome/browser/sync_file_system/sync_direction.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 CHROME_BROWSER_SYNC_FILE_SYSTEM_SYNC_DIRECTION_H_
+#define CHROME_BROWSER_SYNC_FILE_SYSTEM_SYNC_DIRECTION_H_
+
+namespace sync_file_system {
+
+enum SyncDirection {
+  SYNC_DIRECTION_NONE,
+  SYNC_DIRECTION_LOCAL_TO_REMOTE,
+  SYNC_DIRECTION_REMOTE_TO_LOCAL,
+};
+
+}  // namespace sync_file_system
+
+#endif  // CHROME_BROWSER_SYNC_FILE_SYSTEM_SYNC_DIRECTION_H_
diff --git a/chrome/browser/sync_file_system/sync_file_system.proto b/chrome/browser/sync_file_system/sync_file_system.proto
index d9a6ed5..9b37584 100644
--- a/chrome/browser/sync_file_system/sync_file_system.proto
+++ b/chrome/browser/sync_file_system/sync_file_system.proto
@@ -28,59 +28,3 @@
 
   optional ResourceType type = 5 [default = RESOURCE_TYPE_FILE];
 }
-
-enum DriveResourceKind {
-  KIND_UNSUPPORTED = 0;
-  KIND_FILE = 1;
-  KIND_FOLDER = 2;
-}
-
-message DriveEntryMetadata {
-  // Resource ID of the remote resource which the DriveFileMetadata tracks.
-  required string resource_id = 1;
-
-  optional string app_id = 2;
-  optional bool is_app_root = 3;
-
-  // Holds details of file/folder metadata.
-  message Details {
-    optional string parent_resource_id = 1;
-    optional string title = 2;
-    optional DriveResourceKind kind = 3;
-    optional string md5 = 4;
-    optional string etag = 5;
-
-    // Creation time and modification time of the resource.
-    // Serialized by Time::ToInternalValue.
-    optional int64 creation_time = 6;
-    optional int64 modification_time = 7;
-
-    optional bool deleted = 8;
-    optional int64 change_id = 9;
-  }
-
-  // |synced_details| holds the file details snapshot when the file was
-  // fetched through remote-to-local update.
-  // This should contain same value if |dirty| is false.
-  optional Details synced_details = 4;
-
-  // |remote_details| holds the latest file details that may not yet be
-  // applied to local metadata.
-  // This should be updated by each listed ChangeResource.
-  optional Details remote_details = 5;
-
-  // True if the file is changed since last update for this file.
-  optional bool dirty = 6;
-
-  // True if the DriveFileMetadata is active.
-  // Remote file content update should only be applied for active
-  // DriveFileMetadata.
-  // Active DriveFileMetadata must have a unique title under its parent.
-  optional bool active = 7;
-
-  // Valid only for folders.
-  // True indicates the folder contents has not yet been fetched.
-  optional bool needs_folder_listing = 8;
-
-  optional bool conflicted = 9;
-}
diff --git a/chrome/browser/sync_file_system/sync_file_system_service.cc b/chrome/browser/sync_file_system/sync_file_system_service.cc
index 787c265..0278b36 100644
--- a/chrome/browser/sync_file_system/sync_file_system_service.cc
+++ b/chrome/browser/sync_file_system/sync_file_system_service.cc
@@ -18,6 +18,7 @@
 #include "chrome/browser/sync_file_system/drive_file_sync_service.h"
 #include "chrome/browser/sync_file_system/local_file_sync_service.h"
 #include "chrome/browser/sync_file_system/logger.h"
+#include "chrome/browser/sync_file_system/sync_direction.h"
 #include "chrome/browser/sync_file_system/sync_event_observer.h"
 #include "chrome/common/chrome_notification_types.h"
 #include "chrome/common/extensions/extension.h"
@@ -25,9 +26,8 @@
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/notification_details.h"
 #include "content/public/browser/notification_service.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 #include "webkit/browser/fileapi/file_system_context.h"
-#include "webkit/browser/fileapi/syncable/sync_direction.h"
 #include "webkit/browser/fileapi/syncable/sync_file_metadata.h"
 #include "webkit/browser/fileapi/syncable/sync_status_code.h"
 #include "webkit/browser/fileapi/syncable/syncable_file_system_util.h"
@@ -180,43 +180,31 @@
 }
 
 void SyncFileSystemService::GetFileMetadataMap(
-    RemoteFileSyncService::OriginFileMetadataMap* metadata_map,
+    const GURL& origin,
+    RemoteFileSyncService::FileMetadataMap* metadata_map,
     size_t* num_results,
     const SyncStatusCallback& callback) {
   DCHECK(metadata_map);
+  DCHECK(!origin.is_empty());
   DCHECK(num_results);
-  remote_file_service_->GetFileMetadataMap(metadata_map);
+  remote_file_service_->GetFileMetadataMap(origin, metadata_map);
 
   // Figure out how many results have to be waited on before callback.
-  size_t expected_results = 0;
-  RemoteFileSyncService::OriginFileMetadataMap::iterator origin_itr;
-  for (origin_itr = metadata_map->begin();
-       origin_itr != metadata_map->end();
-       ++origin_itr)
-    expected_results += origin_itr->second.size();
-  if (expected_results == 0) {
-    callback.Run(SYNC_STATUS_OK);
-    return;
-  }
+  size_t expected_results = metadata_map->size();
 
   // After all metadata loaded, sync status can be added to each entry.
-  for (origin_itr = metadata_map->begin();
-       origin_itr != metadata_map->end();
-       ++origin_itr) {
-    RemoteFileSyncService::FileMetadataMap::iterator file_path_itr;
-    for (file_path_itr = origin_itr->second.begin();
-         file_path_itr != origin_itr->second.end();
-         ++file_path_itr) {
-      const GURL& origin = origin_itr->first;
-      const base::FilePath& file_path = file_path_itr->first;
-      const FileSystemURL url = CreateSyncableFileSystemURL(origin, file_path);
-      FileMetadata& metadata = file_path_itr->second;
-      GetFileSyncStatus(url, base::Bind(&DidGetFileSyncStatus,
-                                        callback,
-                                        &metadata,
-                                        expected_results,
-                                        num_results));
-    }
+  RemoteFileSyncService::FileMetadataMap::iterator file_path_itr;
+  for (file_path_itr = metadata_map->begin();
+       file_path_itr != metadata_map->end();
+       ++file_path_itr) {
+    const base::FilePath& file_path = file_path_itr->first;
+    const FileSystemURL url = CreateSyncableFileSystemURL(origin, file_path);
+    FileMetadata& metadata = file_path_itr->second;
+    GetFileSyncStatus(url, base::Bind(&DidGetFileSyncStatus,
+                                      callback,
+                                      &metadata,
+                                      expected_results,
+                                      num_results));
   }
 }
 
diff --git a/chrome/browser/sync_file_system/sync_file_system_service.h b/chrome/browser/sync_file_system/sync_file_system_service.h
index cde4a6f..fbcadb9 100644
--- a/chrome/browser/sync_file_system/sync_file_system_service.h
+++ b/chrome/browser/sync_file_system/sync_file_system_service.h
@@ -13,7 +13,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
-#include "base/timer.h"
+#include "base/timer/timer.h"
 #include "chrome/browser/sync/profile_sync_service_observer.h"
 #include "chrome/browser/sync_file_system/conflict_resolution_policy.h"
 #include "chrome/browser/sync_file_system/file_status_observer.h"
@@ -23,7 +23,7 @@
 #include "components/browser_context_keyed_service/browser_context_keyed_service.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 #include "webkit/browser/fileapi/syncable/sync_callbacks.h"
 
 class ProfileSyncServiceBase;
@@ -56,7 +56,8 @@
   SyncServiceState GetSyncServiceState();
   void GetExtensionStatusMap(std::map<GURL, std::string>* status_map);
   void GetFileMetadataMap(
-      RemoteFileSyncService::OriginFileMetadataMap* metadata_map,
+      const GURL& origin,
+      RemoteFileSyncService::FileMetadataMap* metadata_map,
       size_t* num_results,
       const SyncStatusCallback& callback);
 
diff --git a/chrome/browser/sync_file_system/sync_file_system_service_factory.cc b/chrome/browser/sync_file_system/sync_file_system_service_factory.cc
index f8885ea..d01b5e4 100644
--- a/chrome/browser/sync_file_system/sync_file_system_service_factory.cc
+++ b/chrome/browser/sync_file_system/sync_file_system_service_factory.cc
@@ -40,7 +40,7 @@
     : BrowserContextKeyedServiceFactory(
         "SyncFileSystemService",
         BrowserContextDependencyManager::GetInstance()) {
-  DependsOn(google_apis::DriveNotificationManagerFactory::GetInstance());
+  DependsOn(::drive::DriveNotificationManagerFactory::GetInstance());
 }
 
 SyncFileSystemServiceFactory::~SyncFileSystemServiceFactory() {}
@@ -68,7 +68,7 @@
 
   if (CommandLine::ForCurrentProcess()->HasSwitch(kDisableLastWriteWin)) {
     remote_file_service->SetConflictResolutionPolicy(
-        CONFLICT_RESOLUTION_MANUAL);
+        CONFLICT_RESOLUTION_POLICY_MANUAL);
   }
 
   service->Initialize(local_file_service.Pass(),
diff --git a/chrome/browser/sync_file_system/sync_file_system_service_unittest.cc b/chrome/browser/sync_file_system/sync_file_system_service_unittest.cc
index 18222e2..6661bb1 100644
--- a/chrome/browser/sync_file_system/sync_file_system_service_unittest.cc
+++ b/chrome/browser/sync_file_system/sync_file_system_service_unittest.cc
@@ -235,6 +235,8 @@
     sync_service_->SetSyncEnabledForTesting(true);
   }
 
+  ScopedEnableSyncFSDirectoryOperation enable_directory_operation_;
+
   MultiThreadTestHelper thread_helper_;
   TestingProfile profile_;
   scoped_ptr<CannedSyncableFileSystem> file_system_;
diff --git a/chrome/browser/tab_contents/render_view_context_menu.cc b/chrome/browser/tab_contents/render_view_context_menu.cc
index e5a8f01..eb4b728 100644
--- a/chrome/browser/tab_contents/render_view_context_menu.cc
+++ b/chrome/browser/tab_contents/render_view_context_menu.cc
@@ -17,7 +17,7 @@
 #include "base/stl_util.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/app_mode/app_mode_utils.h"
 #include "chrome/browser/autocomplete/autocomplete_classifier.h"
@@ -40,7 +40,6 @@
 #include "chrome/browser/printing/print_view_manager.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_io_data.h"
-#include "chrome/browser/search/instant_extended_context_menu_observer.h"
 #include "chrome/browser/search/search.h"
 #include "chrome/browser/search_engines/template_url.h"
 #include "chrome/browser/search_engines/template_url_service.h"
@@ -596,7 +595,8 @@
     }
   }
 
-  if (has_link) {
+  // Do not show link related items for guest.
+  if (has_link && !is_guest_) {
     AppendLinkItems();
     if (params_.media_type != WebContextMenuData::MediaTypeNone)
       menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
@@ -644,13 +644,8 @@
       print_preview_menu_observer_.reset(
           new PrintPreviewContextMenuObserver(source_web_contents_));
     }
-    if (!instant_extended_observer_.get()) {
-      instant_extended_observer_.reset(
-          new InstantExtendedContextMenuObserver(source_web_contents_));
-    }
 
     observers_.AddObserver(print_preview_menu_observer_.get());
-    observers_.AddObserver(instant_extended_observer_.get());
   }
 }
 
@@ -732,12 +727,15 @@
 
   bool has_selection = !params_.selection_text.empty();
 
+  // Checking link should take precedence before checking selection since on Mac
+  // right-clicking a link will also make it selected.
+  if (params_.unfiltered_link_url.is_valid())
+    AppendLinkItems();
+
   if (params_.is_editable)
     AppendEditableItems();
   else if (has_selection)
     AppendCopyItem();
-  else if (params_.unfiltered_link_url.is_valid())
-    AppendLinkItems();
 
   // Only add extension items from this extension.
   int index = 0;
@@ -1777,7 +1775,7 @@
       // Since the user decided to translate for that language and site, clears
       // any preferences for not translating them.
       TranslatePrefs prefs(profile_->GetPrefs());
-      prefs.RemoveLanguageFromBlacklist(original_lang);
+      prefs.UnblockLanguage(original_lang);
       prefs.RemoveSiteFromBlacklist(params_.page_url.HostNoBrackets());
       TranslateManager::GetInstance()->TranslatePage(
           source_web_contents_, original_lang, target_lang);
diff --git a/chrome/browser/tab_contents/render_view_context_menu.h b/chrome/browser/tab_contents/render_view_context_menu.h
index a1179a2..6f2d0b4 100644
--- a/chrome/browser/tab_contents/render_view_context_menu.h
+++ b/chrome/browser/tab_contents/render_view_context_menu.h
@@ -22,7 +22,6 @@
 #include "ui/base/models/simple_menu_model.h"
 #include "ui/base/window_open_disposition.h"
 
-class InstantExtendedContextMenuObserver;
 class PrintPreviewContextMenuObserver;
 class Profile;
 class SpellingMenuObserver;
@@ -277,9 +276,6 @@
   // An observer that disables menu items when print preview is active.
   scoped_ptr<PrintPreviewContextMenuObserver> print_preview_menu_observer_;
 
-  // An observer that disables menu items for instant extended mode.
-  scoped_ptr<InstantExtendedContextMenuObserver> instant_extended_observer_;
-
   // Our observers.
   mutable ObserverList<RenderViewContextMenuObserver> observers_;
 
diff --git a/chrome/browser/tab_contents/render_view_context_menu_unittest.cc b/chrome/browser/tab_contents/render_view_context_menu_unittest.cc
index be937f2..1728e70 100644
--- a/chrome/browser/tab_contents/render_view_context_menu_unittest.cc
+++ b/chrome/browser/tab_contents/render_view_context_menu_unittest.cc
@@ -14,9 +14,9 @@
 #include "chrome/test/base/testing_profile.h"
 #include "content/public/browser/web_contents.h"
 #include "extensions/common/url_pattern.h"
-#include "googleurl/src/gurl.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/WebKit/public/web/WebContextMenuData.h"
+#include "url/gurl.h"
 
 using extensions::MenuItem;
 using extensions::URLPatternSet;
diff --git a/chrome/browser/tab_contents/retargeting_details.h b/chrome/browser/tab_contents/retargeting_details.h
index ffbd274..108b6a6 100644
--- a/chrome/browser/tab_contents/retargeting_details.h
+++ b/chrome/browser/tab_contents/retargeting_details.h
@@ -5,7 +5,7 @@
 #ifndef CHROME_BROWSER_TAB_CONTENTS_RETARGETING_DETAILS_H_
 #define CHROME_BROWSER_TAB_CONTENTS_RETARGETING_DETAILS_H_
 
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 namespace content {
 class WebContents;
diff --git a/chrome/browser/tab_contents/spelling_menu_observer.h b/chrome/browser/tab_contents/spelling_menu_observer.h
index 3f2194e..9490c30 100644
--- a/chrome/browser/tab_contents/spelling_menu_observer.h
+++ b/chrome/browser/tab_contents/spelling_menu_observer.h
@@ -11,7 +11,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/prefs/pref_member.h"
 #include "base/strings/string16.h"
-#include "base/timer.h"
+#include "base/timer/timer.h"
 #include "chrome/browser/spellchecker/spelling_service_client.h"
 #include "chrome/browser/tab_contents/render_view_context_menu_observer.h"
 
diff --git a/chrome/browser/tab_contents/tab_util.cc b/chrome/browser/tab_contents/tab_util.cc
index f855d6a..9d82f22 100644
--- a/chrome/browser/tab_contents/tab_util.cc
+++ b/chrome/browser/tab_contents/tab_util.cc
@@ -11,7 +11,7 @@
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/site_instance.h"
 #include "content/public/browser/web_contents.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 using content::RenderViewHost;
 using content::SiteInstance;
diff --git a/chrome/browser/tab_contents/view_source_browsertest.cc b/chrome/browser/tab_contents/view_source_browsertest.cc
index 9066db3..83f43b9 100644
--- a/chrome/browser/tab_contents/view_source_browsertest.cc
+++ b/chrome/browser/tab_contents/view_source_browsertest.cc
@@ -16,11 +16,11 @@
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/browser_test_utils.h"
-#include "googleurl/src/gurl.h"
-#include "net/test/spawned_test_server/spawned_test_server.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+#include "url/gurl.h"
 
 namespace {
-const char kTestHtml[] = "files/viewsource/test.html";
+const char kTestHtml[] = "/viewsource/test.html";
 const char kTestMedia[] = "files/media/pink_noise_140ms.wav";
 }
 
@@ -31,11 +31,11 @@
 // page in view source).
 // Flaky; see http://crbug.com/72201.
 IN_PROC_BROWSER_TEST_F(ViewSourceTest, DoesBrowserRenderInViewSource) {
-  ASSERT_TRUE(test_server()->Start());
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
 
   // First we navigate to our view-source test page.
   GURL url(content::kViewSourceScheme + std::string(":") +
-           test_server()->GetURL(kTestHtml).spec());
+           embedded_test_server()->GetURL(kTestHtml).spec());
   ui_test_utils::NavigateToURL(browser(), url);
 
   // Check that the title didn't get set.  It should not be there (because we
@@ -49,10 +49,10 @@
 // implementation of the view-source: prefix being consumed (removed from the
 // URL) if the URL was not changed (apart from adding the view-source prefix)
 IN_PROC_BROWSER_TEST_F(ViewSourceTest, DoesBrowserConsumeViewSourcePrefix) {
-  ASSERT_TRUE(test_server()->Start());
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
 
   // First we navigate to google.html.
-  GURL url(test_server()->GetURL(kTestHtml));
+  GURL url(embedded_test_server()->GetURL(kTestHtml));
   ui_test_utils::NavigateToURL(browser(), url);
 
   // Then we navigate to the same url but with the "view-source:" prefix.
@@ -69,9 +69,9 @@
 // Make sure that when looking at the actual page, we can select "View Source"
 // from the menu.
 IN_PROC_BROWSER_TEST_F(ViewSourceTest, ViewSourceInMenuEnabledOnANormalPage) {
-  ASSERT_TRUE(test_server()->Start());
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
 
-  GURL url(test_server()->GetURL(kTestHtml));
+  GURL url(embedded_test_server()->GetURL(kTestHtml));
   ui_test_utils::NavigateToURL(browser(), url);
 
   EXPECT_TRUE(chrome::CanViewSource(browser()));
@@ -96,10 +96,10 @@
 // from the menu.
 IN_PROC_BROWSER_TEST_F(ViewSourceTest,
                        ViewSourceInMenuDisabledWhileViewingSource) {
-  ASSERT_TRUE(test_server()->Start());
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
 
   GURL url_viewsource(content::kViewSourceScheme + std::string(":") +
-                      test_server()->GetURL(kTestHtml).spec());
+                      embedded_test_server()->GetURL(kTestHtml).spec());
   ui_test_utils::NavigateToURL(browser(), url_viewsource);
 
   EXPECT_FALSE(chrome::CanViewSource(browser()));
@@ -109,10 +109,10 @@
 // the page in view-source mode.
 // Times out on Mac, Windows, ChromeOS Linux: crbug.com/162080
 IN_PROC_BROWSER_TEST_F(ViewSourceTest, DISABLED_TestViewSourceReload) {
-  ASSERT_TRUE(test_server()->Start());
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
 
   GURL url_viewsource(content::kViewSourceScheme + std::string(":") +
-                      test_server()->GetURL(kTestHtml).spec());
+                      embedded_test_server()->GetURL(kTestHtml).spec());
 
   content::WindowedNotificationObserver observer(
       content::NOTIFICATION_LOAD_STOP,
diff --git a/chrome/browser/task_manager/child_process_resource_provider.cc b/chrome/browser/task_manager/child_process_resource_provider.cc
index 67b0918..03bea05 100644
--- a/chrome/browser/task_manager/child_process_resource_provider.cc
+++ b/chrome/browser/task_manager/child_process_resource_provider.cc
@@ -135,8 +135,6 @@
       return Resource::SANDBOX_HELPER;
     case content::PROCESS_TYPE_GPU:
       return Resource::GPU;
-    case PROCESS_TYPE_PROFILE_IMPORT:
-      return Resource::PROFILE_IMPORT;
     case PROCESS_TYPE_NACL_LOADER:
     case PROCESS_TYPE_NACL_BROKER:
       return Resource::NACL;
@@ -185,8 +183,6 @@
     case content::PROCESS_TYPE_PPAPI_BROKER:
       return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_PLUGIN_BROKER_PREFIX,
                                         title);
-    case PROCESS_TYPE_PROFILE_IMPORT:
-      return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_UTILITY_PREFIX);
     case PROCESS_TYPE_NACL_BROKER:
       return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NACL_BROKER_PREFIX);
     case PROCESS_TYPE_NACL_LOADER:
diff --git a/chrome/browser/task_manager/guest_resource_provider.cc b/chrome/browser/task_manager/guest_resource_provider.cc
index 1d7e016..5dcedf1 100644
--- a/chrome/browser/task_manager/guest_resource_provider.cc
+++ b/chrome/browser/task_manager/guest_resource_provider.cc
@@ -132,19 +132,12 @@
   updating_ = true;
 
   // Add all the existing guest WebContents.
-  for (RenderProcessHost::iterator i(
-           RenderProcessHost::AllHostsIterator());
-       !i.IsAtEnd(); i.Advance()) {
-    RenderProcessHost::RenderWidgetHostsIterator iter =
-        i.GetCurrentValue()->GetRenderWidgetHostsIterator();
-    for (; !iter.IsAtEnd(); iter.Advance()) {
-      const RenderWidgetHost* widget = iter.GetCurrentValue();
-      if (widget->IsRenderView()) {
-        RenderViewHost* rvh =
-            RenderViewHost::From(const_cast<RenderWidgetHost*>(widget));
-        if (rvh->IsSubframe())
-          Add(rvh);
-      }
+  RenderWidgetHost::List widgets = RenderWidgetHost::GetRenderWidgetHosts();
+  for (size_t i = 0; i < widgets.size(); ++i) {
+    if (widgets[i]->IsRenderView()) {
+      RenderViewHost* rvh = RenderViewHost::From(widgets[i]);
+      if (rvh->IsSubframe())
+        Add(rvh);
     }
   }
 
diff --git a/chrome/browser/task_manager/resource_provider.h b/chrome/browser/task_manager/resource_provider.h
index 8608f71..243730d 100644
--- a/chrome/browser/task_manager/resource_provider.h
+++ b/chrome/browser/task_manager/resource_provider.h
@@ -38,7 +38,6 @@
     def(WORKER)          /* A web worker process. */ \
     def(NACL)            /* A NativeClient loader or broker process. */ \
     def(UTILITY)         /* A browser utility process. */ \
-    def(PROFILE_IMPORT)  /* A profile import process. */ \
     def(ZYGOTE)          /* A Linux zygote process. */ \
     def(SANDBOX_HELPER)  /* A sandbox helper process. */ \
     def(GPU)             /* A graphics process. */
@@ -170,6 +169,6 @@
   virtual ~ResourceProvider() {}
 };
 
-}  // namepace task_manager
+}  // namespace task_manager
 
 #endif  // CHROME_BROWSER_TASK_MANAGER_RESOURCE_PROVIDER_H_
diff --git a/chrome/browser/task_manager/tab_contents_resource_provider.cc b/chrome/browser/task_manager/tab_contents_resource_provider.cc
index 6b185ff..de3a008 100644
--- a/chrome/browser/task_manager/tab_contents_resource_provider.cc
+++ b/chrome/browser/task_manager/tab_contents_resource_provider.cc
@@ -64,10 +64,6 @@
   explicit TabContentsResource(content::WebContents* web_contents);
   virtual ~TabContentsResource();
 
-  // Called when the underlying web_contents has been committed and is no
-  // longer an Instant overlay.
-  void InstantCommitted();
-
   // Resource methods:
   virtual Type GetType() const OVERRIDE;
   virtual string16 GetTitle() const OVERRIDE;
@@ -83,7 +79,7 @@
   static gfx::ImageSkia* prerender_icon_;
   content::WebContents* web_contents_;
   Profile* profile_;
-  bool is_instant_overlay_;
+  bool is_instant_ntp_;
 
   DISALLOW_COPY_AND_ASSIGN(TabContentsResource);
 };
@@ -96,8 +92,7 @@
                        web_contents->GetRenderViewHost()),
       web_contents_(web_contents),
       profile_(Profile::FromBrowserContext(web_contents->GetBrowserContext())),
-      is_instant_overlay_(chrome::IsInstantOverlay(web_contents) ||
-                          chrome::IsPreloadedInstantExtendedNTP(web_contents)) {
+      is_instant_ntp_(chrome::IsPreloadedInstantExtendedNTP(web_contents)) {
   if (!prerender_icon_) {
     ResourceBundle& rb = ResourceBundle::GetSharedInstance();
     prerender_icon_ = rb.GetImageSkiaNamed(IDR_PRERENDER);
@@ -107,11 +102,6 @@
 TabContentsResource::~TabContentsResource() {
 }
 
-void TabContentsResource::InstantCommitted() {
-  DCHECK(is_instant_overlay_);
-  is_instant_overlay_ = false;
-}
-
 bool TabContentsResource::HostsExtension() const {
   return web_contents_->GetURL().SchemeIs(extensions::kExtensionScheme);
 }
@@ -138,7 +128,7 @@
       HostsExtension(),
       profile_->IsOffTheRecord(),
       IsContentsPrerendering(web_contents_),
-      is_instant_overlay_,
+      is_instant_ntp_,
       false);  // is_background
   return l10n_util::GetStringFUTF16(message_id, tab_title);
 }
@@ -220,8 +210,6 @@
   // Add all the Instant pages.
   for (chrome::BrowserIterator it; !it.done(); it.Next()) {
     if (it->instant_controller()) {
-      if (it->instant_controller()->instant()->GetOverlayContents())
-        Add(it->instant_controller()->instant()->GetOverlayContents());
       if (it->instant_controller()->instant()->GetNTPContents())
         Add(it->instant_controller()->instant()->GetNTPContents());
     }
@@ -257,8 +245,6 @@
                  content::NotificationService::AllBrowserContextsAndSources());
   registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED,
                  content::NotificationService::AllBrowserContextsAndSources());
-  registrar_.Add(this, chrome::NOTIFICATION_INSTANT_COMMITTED,
-                 content::NotificationService::AllBrowserContextsAndSources());
 }
 
 void TabContentsResourceProvider::StopUpdating() {
@@ -272,8 +258,6 @@
       content::NotificationService::AllBrowserContextsAndSources());
   registrar_.Remove(this, content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED,
       content::NotificationService::AllBrowserContextsAndSources());
-  registrar_.Remove(this, chrome::NOTIFICATION_INSTANT_COMMITTED,
-      content::NotificationService::AllBrowserContextsAndSources());
 
   // Delete all the resources.
   STLDeleteContainerPairSecondPointers(resources_.begin(), resources_.end());
@@ -296,7 +280,6 @@
   // pages, prerender pages, and background printed pages.
   if (!chrome::FindBrowserWithWebContents(web_contents) &&
       !IsContentsPrerendering(web_contents) &&
-      !chrome::IsInstantOverlay(web_contents) &&
       !chrome::IsPreloadedInstantExtendedNTP(web_contents) &&
       !IsContentsBackgroundPrinted(web_contents)) {
     return;
@@ -340,16 +323,6 @@
   delete resource;
 }
 
-void TabContentsResourceProvider::InstantCommitted(WebContents* web_contents) {
-  if (!updating_)
-    return;
-  std::map<WebContents*, TabContentsResource*>::iterator
-      iter = resources_.find(web_contents);
-  DCHECK(iter != resources_.end());
-  if (iter != resources_.end())
-    iter->second->InstantCommitted();
-}
-
 void TabContentsResourceProvider::Observe(
     int type,
     const content::NotificationSource& source,
@@ -367,9 +340,6 @@
     case content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED:
       Remove(web_contents);
       break;
-    case chrome::NOTIFICATION_INSTANT_COMMITTED:
-      InstantCommitted(web_contents);
-      break;
     default:
       NOTREACHED() << "Unexpected notification.";
       return;
diff --git a/chrome/browser/task_manager/tab_contents_resource_provider.h b/chrome/browser/task_manager/tab_contents_resource_provider.h
index 66da6ad..3795e25 100644
--- a/chrome/browser/task_manager/tab_contents_resource_provider.h
+++ b/chrome/browser/task_manager/tab_contents_resource_provider.h
@@ -47,7 +47,6 @@
 
   void Add(content::WebContents* web_contents);
   void Remove(content::WebContents* web_contents);
-  void InstantCommitted(content::WebContents* web_contents);
 
   void AddToTaskManager(content::WebContents* web_contents);
 
diff --git a/chrome/browser/task_manager/task_manager.cc b/chrome/browser/task_manager/task_manager.cc
index f0e3408..be9a3b9 100644
--- a/chrome/browser/task_manager/task_manager.cc
+++ b/chrome/browser/task_manager/task_manager.cc
@@ -15,8 +15,6 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/background/background_contents_service.h"
-#include "chrome/browser/background/background_contents_service_factory.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/extensions/extension_process_manager.h"
 #include "chrome/browser/extensions/extension_system.h"
@@ -1545,36 +1543,6 @@
   chrome::Navigate(&params);
 }
 
-// static
-int TaskManager::GetBackgroundPageCount() {
-  int count = 0;
-  ProfileManager* profile_manager = g_browser_process->profile_manager();
-  if (!profile_manager)  // Null when running unit tests.
-    return count;
-  std::vector<Profile*> profiles(profile_manager->GetLoadedProfiles());
-  for (std::vector<Profile*>::const_iterator iter = profiles.begin();
-       iter != profiles.end();
-       ++iter) {
-    Profile* profile = *iter;
-    // Count the number of Background Contents (background pages for hosted
-    // apps). Incognito windows do not support hosted apps, so just check the
-    // main profile.
-    BackgroundContentsService* background_contents_service =
-        BackgroundContentsServiceFactory::GetForProfile(profile);
-    if (background_contents_service)
-      count += background_contents_service->GetBackgroundContents().size();
-
-    // Count the number of extensions with background pages (including
-    // incognito).
-    count += CountExtensionBackgroundPagesForProfile(profile);
-    if (profile->HasOffTheRecordProfile()) {
-      count += CountExtensionBackgroundPagesForProfile(
-          profile->GetOffTheRecordProfile());
-    }
-  }
-  return count;
-}
-
 TaskManager::TaskManager()
     : model_(new TaskManagerModel(this)) {
 }
diff --git a/chrome/browser/task_manager/task_manager.h b/chrome/browser/task_manager/task_manager.h
index 31ea9a8..7554747 100644
--- a/chrome/browser/task_manager/task_manager.h
+++ b/chrome/browser/task_manager/task_manager.h
@@ -15,7 +15,7 @@
 #include "base/observer_list.h"
 #include "base/process_util.h"
 #include "base/strings/string16.h"
-#include "base/timer.h"
+#include "base/timer/timer.h"
 #include "chrome/browser/renderer_host/web_cache_manager.h"
 #include "chrome/browser/task_manager/resource_provider.h"
 #include "chrome/browser/ui/host_desktop.h"
@@ -83,11 +83,6 @@
 
   void OpenAboutMemory(chrome::HostDesktopType desktop_type);
 
-  // Returns the number of background pages that will be displayed in the
-  // TaskManager. Used by the wrench menu code to display a count of background
-  // pages in the "View Background Pages" menu item.
-  static int GetBackgroundPageCount();
-
  private:
   FRIEND_TEST_ALL_PREFIXES(TaskManagerTest, Basic);
   FRIEND_TEST_ALL_PREFIXES(TaskManagerTest, Resources);
diff --git a/chrome/browser/task_manager/task_manager_browsertest.cc b/chrome/browser/task_manager/task_manager_browsertest.cc
index 73584ca..a4f2a93 100644
--- a/chrome/browser/task_manager/task_manager_browsertest.cc
+++ b/chrome/browser/task_manager/task_manager_browsertest.cc
@@ -7,8 +7,6 @@
 #include "base/files/file_path.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/background/background_contents_service.h"
-#include "chrome/browser/background/background_contents_service_factory.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/extensions/extension_browsertest.h"
 #include "chrome/browser/extensions/extension_service.h"
@@ -41,6 +39,7 @@
 #include "content/public/test/browser_test_utils.h"
 #include "grit/generated_resources.h"
 #include "net/dns/mock_host_resolver.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/l10n/l10n_util.h"
 
@@ -78,11 +77,9 @@
 
     EXPECT_EQ(0, model()->ResourceCount());
 
-    EXPECT_EQ(0, TaskManager::GetBackgroundPageCount());
-
     // Show the task manager. This populates the model, and helps with debugging
     // (you see the task manager).
-    chrome::ShowTaskManager(browser(), false);
+    chrome::ShowTaskManager(browser());
 
     // New Tab Page.
     TaskManagerBrowserTestUtil::WaitForWebResourceChange(1);
@@ -189,67 +186,6 @@
   TaskManagerBrowserTestUtil::WaitForWebResourceChange(1);
 }
 
-IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, NoticeBGContentsChanges) {
-  // Open a new background contents and make sure we notice that.
-  GURL url(ui_test_utils::GetTestUrl(base::FilePath(
-      base::FilePath::kCurrentDirectory), base::FilePath(kTitle1File)));
-
-  BackgroundContentsService* service =
-      BackgroundContentsServiceFactory::GetForProfile(browser()->profile());
-  string16 application_id(ASCIIToUTF16("test_app_id"));
-  service->LoadBackgroundContents(browser()->profile(),
-                                  url,
-                                  ASCIIToUTF16("background_page"),
-                                  application_id);
-  TaskManagerBrowserTestUtil::WaitForWebResourceChange(2);
-  EXPECT_EQ(1, TaskManager::GetBackgroundPageCount());
-
-  // Close the background contents and verify that we notice.
-  service->ShutdownAssociatedBackgroundContents(application_id);
-  TaskManagerBrowserTestUtil::WaitForWebResourceChange(1);
-  EXPECT_EQ(0, TaskManager::GetBackgroundPageCount());
-}
-
-IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, KillBGContents) {
-  int resource_count = TaskManager::GetInstance()->model()->ResourceCount();
-
-  // Open a new background contents and make sure we notice that.
-  GURL url(ui_test_utils::GetTestUrl(base::FilePath(
-      base::FilePath::kCurrentDirectory), base::FilePath(kTitle1File)));
-
-  content::WindowedNotificationObserver observer(
-      chrome::NOTIFICATION_BACKGROUND_CONTENTS_NAVIGATED,
-      content::Source<Profile>(browser()->profile()));
-
-  BackgroundContentsService* service =
-      BackgroundContentsServiceFactory::GetForProfile(browser()->profile());
-  string16 application_id(ASCIIToUTF16("test_app_id"));
-  service->LoadBackgroundContents(browser()->profile(),
-                                  url,
-                                  ASCIIToUTF16("background_page"),
-                                  application_id);
-
-  // Wait for the background contents process to finish loading.
-  observer.Wait();
-
-  EXPECT_EQ(resource_count + 1, model()->ResourceCount());
-  EXPECT_EQ(1, TaskManager::GetBackgroundPageCount());
-
-  // Kill the background contents process and verify that it disappears from the
-  // model.
-  bool found = false;
-  for (int i = 0; i < model()->ResourceCount(); ++i) {
-    if (model()->IsBackgroundResource(i)) {
-      TaskManager::GetInstance()->KillProcess(i);
-      found = true;
-      break;
-    }
-  }
-  ASSERT_TRUE(found);
-  TaskManagerBrowserTestUtil::WaitForWebResourceChange(1);
-  EXPECT_EQ(0, TaskManager::GetBackgroundPageCount());
-}
-
 #if defined(USE_ASH) || defined(OS_WIN)
 // This test fails on Ash because task manager treats view type
 // Panels differently for Ash.
@@ -288,20 +224,6 @@
   TaskManagerBrowserTestUtil::WaitForWebResourceChange(1);
 }
 
-IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, NoticeExtensionChanges) {
-  // Loading an extension with a background page should result in a new
-  // resource being created for it.
-  ASSERT_TRUE(LoadExtension(
-      test_data_dir_.AppendASCII("common").AppendASCII("background_page")));
-  TaskManagerBrowserTestUtil::WaitForWebResourceChange(2);
-  EXPECT_EQ(1, TaskManager::GetBackgroundPageCount());
-
-  // Unload extension to avoid crash on Windows (see http://crbug.com/31663).
-  UnloadExtension(last_loaded_extension_id_);
-  TaskManagerBrowserTestUtil::WaitForWebResourceChange(1);
-  EXPECT_EQ(0, TaskManager::GetBackgroundPageCount());
-}
-
 IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, NoticeExtensionTabs) {
   int resource_count = TaskManager::GetInstance()->model()->ResourceCount();
   ASSERT_TRUE(LoadExtension(
@@ -381,12 +303,12 @@
   // The app under test acts on URLs whose host is "localhost",
   // so the URLs we navigate to must have host "localhost".
   host_resolver()->AddRule("*", "127.0.0.1");
-  ASSERT_TRUE(test_server()->Start());
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
   GURL::Replacements replace_host;
   std::string host_str("localhost");  // must stay in scope with replace_host
   replace_host.SetHostStr(host_str);
-  GURL base_url = test_server()->GetURL(
-      "files/extensions/api_test/app_process/");
+  GURL base_url = embedded_test_server()->GetURL(
+      "/extensions/api_test/app_process/");
   base_url = base_url.ReplaceComponents(replace_host);
 
   // Open a new tab to an app URL before the app is loaded.
@@ -436,27 +358,6 @@
                          tab_prefix, true));
 }
 
-IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, MAYBE_KillExtension) {
-  int resource_count = TaskManager::GetInstance()->model()->ResourceCount();
-
-  ASSERT_TRUE(LoadExtension(
-      test_data_dir_.AppendASCII("common").AppendASCII("background_page")));
-
-  // Wait until we see the loaded extension in the task manager (the three
-  // resources are: the browser process, New Tab Page, and the extension).
-  TaskManagerBrowserTestUtil::WaitForWebResourceChange(2);
-  EXPECT_EQ(1, TaskManager::GetBackgroundPageCount());
-
-  EXPECT_TRUE(model()->GetResourceExtension(0) == NULL);
-  EXPECT_TRUE(model()->GetResourceExtension(1) == NULL);
-  ASSERT_TRUE(model()->GetResourceExtension(resource_count) != NULL);
-
-  // Kill the extension process and make sure we notice it.
-  TaskManager::GetInstance()->KillProcess(resource_count);
-  TaskManagerBrowserTestUtil::WaitForWebResourceChange(1);
-  EXPECT_EQ(0, TaskManager::GetBackgroundPageCount());
-}
-
 // Disabled, http://crbug.com/66957.
 IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest,
                        DISABLED_KillExtensionAndReload) {
diff --git a/chrome/browser/task_manager/task_manager_browsertest_util.cc b/chrome/browser/task_manager/task_manager_browsertest_util.cc
index f711d28..327b31a 100644
--- a/chrome/browser/task_manager/task_manager_browsertest_util.cc
+++ b/chrome/browser/task_manager/task_manager_browsertest_util.cc
@@ -29,7 +29,6 @@
         type == task_manager::Resource::NACL ||
         type == task_manager::Resource::GPU ||
         type == task_manager::Resource::UTILITY ||
-        type == task_manager::Resource::PROFILE_IMPORT ||
         type == task_manager::Resource::ZYGOTE ||
         type == task_manager::Resource::SANDBOX_HELPER) {
       continue;
diff --git a/chrome/browser/task_manager/task_manager_notification_browsertest.cc b/chrome/browser/task_manager/task_manager_notification_browsertest.cc
index 2dcacf3..76ad825 100644
--- a/chrome/browser/task_manager/task_manager_notification_browsertest.cc
+++ b/chrome/browser/task_manager/task_manager_notification_browsertest.cc
@@ -53,7 +53,7 @@
   EXPECT_EQ(0, model()->ResourceCount());
 
   // Show the task manager.
-  chrome::ShowTaskManager(browser(), false);
+  chrome::ShowTaskManager(browser());
   // Expect to see the browser and the New Tab Page renderer.
   TaskManagerBrowserTestUtil::WaitForWebResourceChange(1);
 
diff --git a/chrome/browser/task_profiler/task_profiler_data_serializer.cc b/chrome/browser/task_profiler/task_profiler_data_serializer.cc
index 4ad2fa0..8e93744 100644
--- a/chrome/browser/task_profiler/task_profiler_data_serializer.cc
+++ b/chrome/browser/task_profiler/task_profiler_data_serializer.cc
@@ -7,11 +7,11 @@
 #include "base/file_util.h"
 #include "base/files/file_path.h"
 #include "base/json/json_string_value_serializer.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "base/tracked_objects.h"
 #include "content/public/common/content_client.h"
 #include "content/public/common/process_type.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 using base::DictionaryValue;
 using base::ListValue;
diff --git a/chrome/browser/themes/browser_theme_pack.cc b/chrome/browser/themes/browser_theme_pack.cc
index 3a8fb68..d6340cb 100644
--- a/chrome/browser/themes/browser_theme_pack.cc
+++ b/chrome/browser/themes/browser_theme_pack.cc
@@ -444,6 +444,30 @@
       *src_image, hsl_shift));
 }
 
+// Computes a bitmap at one scale from a bitmap at a different scale.
+SkBitmap CreateLowQualityResizedBitmap(const SkBitmap& source_bitmap,
+                                       ui::ScaleFactor source_scale_factor,
+                                       ui::ScaleFactor desired_scale_factor) {
+  gfx::Size scaled_size = gfx::ToCeiledSize(
+      gfx::ScaleSize(gfx::Size(source_bitmap.width(),
+                               source_bitmap.height()),
+                     ui::GetScaleFactorScale(desired_scale_factor) /
+                     ui::GetScaleFactorScale(source_scale_factor)));
+  SkBitmap scaled_bitmap;
+  scaled_bitmap.setConfig(SkBitmap::kARGB_8888_Config,
+                          scaled_size.width(),
+                          scaled_size.height());
+  if (!scaled_bitmap.allocPixels())
+    SK_CRASH();
+  scaled_bitmap.eraseARGB(0, 0, 0, 0);
+  SkCanvas canvas(scaled_bitmap);
+  SkRect scaled_bounds = RectToSkRect(gfx::Rect(scaled_size));
+  // Note(oshima): The following scaling code doesn't work with
+  // a mask image.
+  canvas.drawBitmapRect(source_bitmap, NULL, scaled_bounds);
+  return scaled_bitmap;
+}
+
 // A ImageSkiaSource that scales 100P image to the target scale factor
 // if the ImageSkiaRep for the target scale factor isn't available.
 class ThemeImageSource: public gfx::ImageSkiaSource {
@@ -458,20 +482,11 @@
       return source_.GetRepresentation(scale_factor);
     const gfx::ImageSkiaRep& rep_100p =
         source_.GetRepresentation(ui::SCALE_FACTOR_100P);
-    float scale = ui::GetScaleFactorScale(scale_factor);
-    gfx::Size size(rep_100p.GetWidth() * scale, rep_100p.GetHeight() * scale);
-    SkBitmap resized_bitmap;
-    resized_bitmap.setConfig(SkBitmap::kARGB_8888_Config, size.width(),
-                             size.height());
-    if (!resized_bitmap.allocPixels())
-      SK_CRASH();
-    resized_bitmap.eraseARGB(0, 0, 0, 0);
-    SkCanvas canvas(resized_bitmap);
-    SkRect resized_bounds = RectToSkRect(gfx::Rect(size));
-    // Note(oshima): The following scaling code doesn't work with
-    // a mask image.
-    canvas.drawBitmapRect(rep_100p.sk_bitmap(), NULL, resized_bounds);
-    return gfx::ImageSkiaRep(resized_bitmap, scale_factor);
+    SkBitmap scaled_bitmap = CreateLowQualityResizedBitmap(
+        rep_100p.sk_bitmap(),
+        ui::SCALE_FACTOR_100P,
+        scale_factor);
+    return gfx::ImageSkiaRep(scaled_bitmap, scale_factor);
   }
 
  private:
@@ -480,6 +495,92 @@
   DISALLOW_COPY_AND_ASSIGN(ThemeImageSource);
 };
 
+// An ImageSkiaSource that delays decoding PNG data into bitmaps until
+// needed. Missing data for a scale factor is computed by scaling data for an
+// available scale factor. Computed bitmaps are stored for future look up.
+class ThemeImagePngSource : public gfx::ImageSkiaSource {
+ public:
+  typedef std::map<ui::ScaleFactor,
+                   scoped_refptr<base::RefCountedMemory> > PngMap;
+
+  explicit ThemeImagePngSource(const PngMap& png_map) : png_map_(png_map) {}
+
+  virtual ~ThemeImagePngSource() {}
+
+ private:
+  virtual gfx::ImageSkiaRep GetImageForScale(
+      ui::ScaleFactor scale_factor) OVERRIDE {
+    // Look up the bitmap for |scale factor| in the bitmap map. If found
+    // return it.
+    BitmapMap::const_iterator exact_bitmap_it = bitmap_map_.find(scale_factor);
+    if (exact_bitmap_it != bitmap_map_.end())
+      return gfx::ImageSkiaRep(exact_bitmap_it->second, scale_factor);
+
+    // Look up the raw PNG data for |scale_factor| in the png map. If found,
+    // decode it, store the result in the bitmap map and return it.
+    PngMap::const_iterator exact_png_it = png_map_.find(scale_factor);
+    if (exact_png_it != png_map_.end()) {
+      SkBitmap bitmap;
+      if (!gfx::PNGCodec::Decode(exact_png_it->second->front(),
+                                 exact_png_it->second->size(),
+                                 &bitmap)) {
+        NOTREACHED();
+        return gfx::ImageSkiaRep();
+      }
+      bitmap_map_[scale_factor] = bitmap;
+      return gfx::ImageSkiaRep(bitmap, scale_factor);
+    }
+
+    // Find an available PNG for another scale factor. We want to use the
+    // highest available scale factor.
+    PngMap::const_iterator available_png_it = png_map_.end();
+    for (PngMap::const_iterator png_it = png_map_.begin();
+         png_it != png_map_.end(); ++png_it) {
+      if (available_png_it == png_map_.end() ||
+          ui::GetScaleFactorScale(png_it->first) >
+          ui::GetScaleFactorScale(available_png_it->first)) {
+        available_png_it = png_it;
+      }
+    }
+    if (available_png_it == png_map_.end())
+      return gfx::ImageSkiaRep();
+    ui::ScaleFactor available_scale_factor = available_png_it->first;
+
+    // Look up the bitmap for |available_scale_factor| in the bitmap map.
+    // If not found, decode the corresponging png data, store the result
+    // in the bitmap map.
+    BitmapMap::const_iterator available_bitmap_it =
+        bitmap_map_.find(available_scale_factor);
+    if (available_bitmap_it == bitmap_map_.end()) {
+      SkBitmap available_bitmap;
+      if (!gfx::PNGCodec::Decode(available_png_it->second->front(),
+                                 available_png_it->second->size(),
+                                 &available_bitmap)) {
+        NOTREACHED();
+        return gfx::ImageSkiaRep();
+      }
+      bitmap_map_[available_scale_factor] = available_bitmap;
+      available_bitmap_it = bitmap_map_.find(available_scale_factor);
+    }
+
+    // Scale the available bitmap to the desired scale factor, store the result
+    // in the bitmap map and return it.
+    SkBitmap scaled_bitmap = CreateLowQualityResizedBitmap(
+        available_bitmap_it->second,
+        available_scale_factor,
+        scale_factor);
+    bitmap_map_[scale_factor] = scaled_bitmap;
+    return gfx::ImageSkiaRep(scaled_bitmap, scale_factor);
+  }
+
+  PngMap png_map_;
+
+  typedef std::map<ui::ScaleFactor, SkBitmap> BitmapMap;
+  BitmapMap bitmap_map_;
+
+  DISALLOW_COPY_AND_ASSIGN(ThemeImagePngSource);
+};
+
 class TabBackgroundImageSource: public gfx::CanvasImageSource {
  public:
   TabBackgroundImageSource(const gfx::ImageSkia& image_to_tint,
@@ -749,34 +850,22 @@
   if (image_iter != images_on_ui_thread_.end())
     return image_iter->second;
 
-  // TODO(pkotwicz): Do something better than loading the bitmaps
-  // for all the scale factors associated with |idr_id|.
-  // See crbug.com/243831.
-  gfx::ImageSkia source_image_skia;
+  ThemeImagePngSource::PngMap png_map;
   for (size_t i = 0; i < scale_factors_.size(); ++i) {
     scoped_refptr<base::RefCountedMemory> memory =
         GetRawData(idr_id, scale_factors_[i]);
-    if (memory.get()) {
-      // Decode the PNG.
-      SkBitmap bitmap;
-      if (!gfx::PNGCodec::Decode(memory->front(), memory->size(),
-                                 &bitmap)) {
-        NOTREACHED() << "Unable to decode theme image resource " << idr_id
-                     << " from saved DataPack.";
-        continue;
-      }
-      source_image_skia.AddRepresentation(
-          gfx::ImageSkiaRep(bitmap, scale_factors_[i]));
-    }
+    if (memory.get())
+      png_map[scale_factors_[i]] = memory;
   }
-
-  if (!source_image_skia.isNull()) {
-    ThemeImageSource* source = new ThemeImageSource(source_image_skia);
-    gfx::ImageSkia image_skia(source, source_image_skia.size());
+  if (!png_map.empty()) {
+    gfx::ImageSkia image_skia(new ThemeImagePngSource(png_map),
+                              ui::SCALE_FACTOR_100P);
+    // |image_skia| takes ownership of ThemeImagePngSource.
     gfx::Image ret = gfx::Image(image_skia);
     images_on_ui_thread_[prs_id] = ret;
     return ret;
   }
+
   return gfx::Image();
 }
 
@@ -1475,29 +1564,29 @@
     return;
 
   // Find available scale factor with highest scale.
-  ui::ScaleFactor available = ui::SCALE_FACTOR_NONE;
+  ui::ScaleFactor available_scale_factor = ui::SCALE_FACTOR_NONE;
   for (size_t i = 0; i < scale_factors_.size(); ++i) {
     int raw_id = GetRawIDByPersistentID(prs_id, scale_factors_[i]);
-    if ((available == ui::SCALE_FACTOR_NONE ||
+    if ((available_scale_factor == ui::SCALE_FACTOR_NONE ||
          (ui::GetScaleFactorScale(scale_factors_[i]) >
-          ui::GetScaleFactorScale(available))) &&
+          ui::GetScaleFactorScale(available_scale_factor))) &&
         image_memory_.find(raw_id) != image_memory_.end()) {
-      available = scale_factors_[i];
+      available_scale_factor = scale_factors_[i];
     }
   }
   // If no scale factor is available, we're done.
-  if (available == ui::SCALE_FACTOR_NONE)
+  if (available_scale_factor == ui::SCALE_FACTOR_NONE)
     return;
 
   // Get bitmap for the available scale factor.
-  int available_raw_id = GetRawIDByPersistentID(prs_id, available);
+  int available_raw_id = GetRawIDByPersistentID(prs_id, available_scale_factor);
   RawImages::const_iterator it = image_memory_.find(available_raw_id);
   SkBitmap available_bitmap;
   if (!gfx::PNGCodec::Decode(it->second->front(),
                              it->second->size(),
                              &available_bitmap)) {
     NOTREACHED() << "Unable to decode theme image for prs_id="
-                 << prs_id << " for scale_factor=" << available;
+                 << prs_id << " for scale_factor=" << available_scale_factor;
     return;
   }
 
@@ -1506,21 +1595,10 @@
     int scaled_raw_id = GetRawIDByPersistentID(prs_id, scale_factors_[i]);
     if (image_memory_.find(scaled_raw_id) != image_memory_.end())
       continue;
-    gfx::Size scaled_size = gfx::ToCeiledSize(
-        gfx::ScaleSize(gfx::Size(available_bitmap.width(),
-                                 available_bitmap.height()),
-                       ui::GetScaleFactorScale(scale_factors_[i]) /
-                       ui::GetScaleFactorScale(available)));
-    SkBitmap scaled_bitmap;
-    scaled_bitmap.setConfig(SkBitmap::kARGB_8888_Config,
-                            scaled_size.width(),
-                            scaled_size.height());
-    if (!scaled_bitmap.allocPixels())
-      SK_CRASH();
-    scaled_bitmap.eraseARGB(0, 0, 0, 0);
-    SkCanvas canvas(scaled_bitmap);
-    SkRect scaled_bounds = RectToSkRect(gfx::Rect(scaled_size));
-    canvas.drawBitmapRect(available_bitmap, NULL, scaled_bounds);
+    SkBitmap scaled_bitmap =
+        CreateLowQualityResizedBitmap(available_bitmap,
+                                      available_scale_factor,
+                                      scale_factors_[i]);
     std::vector<unsigned char> bitmap_data;
     if (!gfx::PNGCodec::EncodeBGRASkBitmap(scaled_bitmap,
                                            false,
diff --git a/chrome/browser/themes/theme_properties.cc b/chrome/browser/themes/theme_properties.cc
index ec777b6..0390af4 100644
--- a/chrome/browser/themes/theme_properties.cc
+++ b/chrome/browser/themes/theme_properties.cc
@@ -30,6 +30,9 @@
 const SkColor kDefaultColorFrameIncognito = SkColorSetRGB(83, 106, 139);
 const SkColor kDefaultColorFrameIncognitoInactive =
     SkColorSetRGB(126, 139, 156);
+const SkColor kDefaultColorFrameManagedUser = SkColorSetRGB(165, 197, 225);
+const SkColor kDefaultColorFrameManagedUserInactive =
+    SkColorSetRGB(180, 225, 247);
 #if defined(OS_MACOSX)
 const SkColor kDefaultColorToolbar = SkColorSetRGB(230, 230, 230);
 #else
@@ -249,6 +252,10 @@
       return kDefaultColorFrameIncognito;
     case COLOR_FRAME_INCOGNITO_INACTIVE:
       return kDefaultColorFrameIncognitoInactive;
+    case COLOR_FRAME_MANAGED_USER:
+      return kDefaultColorFrameManagedUser;
+    case COLOR_FRAME_MANAGED_USER_INACTIVE:
+      return kDefaultColorFrameManagedUserInactive;
     case COLOR_TOOLBAR:
       return kDefaultColorToolbar;
     case COLOR_TAB_TEXT:
diff --git a/chrome/browser/themes/theme_properties.h b/chrome/browser/themes/theme_properties.h
index 2eaa1ed..0f503c9 100644
--- a/chrome/browser/themes/theme_properties.h
+++ b/chrome/browser/themes/theme_properties.h
@@ -80,6 +80,8 @@
   enum NotOverwritableByUserThemeProperty {
     COLOR_CONTROL_BACKGROUND = 1000,
     COLOR_TOOLBAR_SEPARATOR,
+    COLOR_FRAME_MANAGED_USER,
+    COLOR_FRAME_MANAGED_USER_INACTIVE,
 
     // These colors don't have constant default values. They are derived from
     // the runtime value of other colors.
diff --git a/chrome/browser/themes/theme_service.cc b/chrome/browser/themes/theme_service.cc
index 6a90368..fb594d8 100644
--- a/chrome/browser/themes/theme_service.cc
+++ b/chrome/browser/themes/theme_service.cc
@@ -32,8 +32,8 @@
 #include "ui/base/win/shell.h"
 #endif
 
-#if defined(USE_AURA) && !defined(USE_ASH) && defined(OS_LINUX)
-#include "ui/linux_ui/linux_ui.h"
+#if defined(ENABLE_MANAGED_USERS)
+#include "chrome/browser/managed_mode/managed_user_service.h"
 #endif
 
 using content::BrowserThread;
@@ -104,16 +104,21 @@
 gfx::Image ThemeService::GetImageNamed(int id) const {
   DCHECK(CalledOnValidThread());
 
+  // For a managed user, use the special frame instead of the default one.
+  // TODO(akuegel): Remove this once we have the default managed user theme.
+  if (IsManagedUser()) {
+    if (id == IDR_THEME_FRAME)
+      id = IDR_MANAGED_USER_THEME_FRAME;
+    else if (id == IDR_THEME_FRAME_INACTIVE)
+      id = IDR_MANAGED_USER_THEME_FRAME_INACTIVE;
+    else if (id == IDR_THEME_TAB_BACKGROUND || id == IDR_THEME_TAB_BACKGROUND_V)
+      id = IDR_MANAGED_USER_THEME_TAB_BACKGROUND;
+  }
+
   gfx::Image image;
   if (theme_pack_.get())
     image = theme_pack_->GetImageNamed(id);
 
-#if defined(USE_AURA) && !defined(USE_ASH) && defined(OS_LINUX)
-  const ui::LinuxUI* linux_ui = ui::LinuxUI::instance();
-  if (image.IsEmpty() && linux_ui)
-    image = linux_ui->GetThemeImageNamed(id);
-#endif
-
   if (image.IsEmpty())
     image = rb_.GetNativeImageNamed(id);
 
@@ -132,16 +137,18 @@
 SkColor ThemeService::GetColor(int id) const {
   DCHECK(CalledOnValidThread());
 
+  // TODO(akuegel): Remove this once we have the default managed user theme.
+  if (IsManagedUser()) {
+    if (id == Properties::COLOR_FRAME)
+      id = Properties::COLOR_FRAME_MANAGED_USER;
+    else if (id == Properties::COLOR_FRAME_INACTIVE)
+      id = Properties::COLOR_FRAME_MANAGED_USER_INACTIVE;
+  }
+
   SkColor color;
   if (theme_pack_.get() && theme_pack_->GetColor(id, &color))
     return color;
 
-#if defined(USE_AURA) && !defined(USE_ASH) && defined(OS_LINUX)
-  const ui::LinuxUI* linux_ui = ui::LinuxUI::instance();
-  if (linux_ui && linux_ui->GetColor(id, &color))
-    return color;
-#endif
-
   // For backward compat with older themes, some newer colors are generated from
   // older ones if they are missing.
   switch (id) {
@@ -156,12 +163,14 @@
     case Properties::COLOR_NTP_TEXT_LIGHT:
       return IncreaseLightness(GetColor(Properties::COLOR_NTP_TEXT), 0.40);
     case Properties::COLOR_MANAGED_USER_LABEL:
-      return color_utils::GetReadableColor(
-          SK_ColorWHITE,
-          GetColor(Properties::COLOR_MANAGED_USER_LABEL_BACKGROUND));
+      // TODO(akuegel): Use GetReadableColor() once we want to support other
+      // themes as well.
+      return SkColorSetRGB(231, 245, 255);
     case Properties::COLOR_MANAGED_USER_LABEL_BACKGROUND:
-      return color_utils::BlendTowardOppositeLuminance(
-          GetColor(Properties::COLOR_FRAME), 0x80);
+      // TODO(akuegel): Replace this constant by a color calculated from the
+      // frame color once the default managed user theme is finished and we
+      // allow managed users to install other themes.
+      return SkColorSetRGB(108, 167, 210);
   }
 
   return Properties::GetDefaultColor(id);
@@ -419,6 +428,13 @@
   theme_pack_ = pack;
 }
 
+bool ThemeService::IsManagedUser() const {
+#if defined(ENABLE_MANAGED_USERS)
+  return ManagedUserService::ProfileIsManaged(profile_);
+#endif
+  return false;
+}
+
 void ThemeService::OnInfobarDisplayed() {
   number_of_infobars_++;
 }
diff --git a/chrome/browser/themes/theme_service.h b/chrome/browser/themes/theme_service.h
index 48f320d..b6d8869 100644
--- a/chrome/browser/themes/theme_service.h
+++ b/chrome/browser/themes/theme_service.h
@@ -163,7 +163,7 @@
   // from ClearCaches().
   virtual void FreePlatformCaches();
 
-  Profile* profile() { return profile_; }
+  Profile* profile() const { return profile_; }
 
   void set_ready() { ready_ = true; }
 
@@ -184,6 +184,9 @@
   // case we don't have a theme pack).
   void BuildFromExtension(const extensions::Extension* extension);
 
+  // Returns true if the profile belongs to a managed user.
+  bool IsManagedUser() const;
+
 #if defined(TOOLKIT_GTK)
   // Loads an image and flips it horizontally if |rtl_enabled| is true.
   GdkPixbuf* GetPixbufImpl(int id, bool rtl_enabled) const;
diff --git a/chrome/browser/themes/theme_service_aurax11.cc b/chrome/browser/themes/theme_service_aurax11.cc
new file mode 100644
index 0000000..fe1c3de
--- /dev/null
+++ b/chrome/browser/themes/theme_service_aurax11.cc
@@ -0,0 +1,85 @@
+// 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/themes/theme_service_aurax11.h"
+
+#include "base/bind.h"
+#include "base/prefs/pref_service.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/common/pref_names.h"
+#include "ui/gfx/image/image.h"
+#include "ui/linux_ui/linux_ui.h"
+
+ThemeServiceAuraX11::ThemeServiceAuraX11()
+    : use_system_theme_(false) {
+}
+
+ThemeServiceAuraX11::~ThemeServiceAuraX11() {}
+
+void ThemeServiceAuraX11::Init(Profile* profile) {
+  registrar_.Init(profile->GetPrefs());
+  registrar_.Add(prefs::kUsesSystemTheme,
+                 base::Bind(&ThemeServiceAuraX11::OnUsesSystemThemeChanged,
+                            base::Unretained(this)));
+  use_system_theme_ = profile->GetPrefs()->GetBoolean(prefs::kUsesSystemTheme);
+
+  ThemeService::Init(profile);
+}
+
+gfx::Image ThemeServiceAuraX11::GetImageNamed(int id) const {
+  const ui::LinuxUI* linux_ui = ui::LinuxUI::instance();
+  if (use_system_theme_ && linux_ui) {
+    gfx::Image image = linux_ui->GetThemeImageNamed(id);
+    if (!image.IsEmpty())
+      return image;
+  }
+
+  return ThemeService::GetImageNamed(id);
+}
+
+SkColor ThemeServiceAuraX11::GetColor(int id) const {
+  const ui::LinuxUI* linux_ui = ui::LinuxUI::instance();
+  SkColor color;
+  if (use_system_theme_ && linux_ui && linux_ui->GetColor(id, &color))
+    return color;
+
+  return ThemeService::GetColor(id);
+}
+
+bool ThemeServiceAuraX11::HasCustomImage(int id) const {
+  const ui::LinuxUI* linux_ui = ui::LinuxUI::instance();
+  if (use_system_theme_ && linux_ui)
+    return linux_ui->HasCustomImage(id);
+
+  return ThemeService::HasCustomImage(id);
+}
+
+void ThemeServiceAuraX11::SetTheme(const extensions::Extension* extension) {
+  profile()->GetPrefs()->SetBoolean(prefs::kUsesSystemTheme, false);
+  ThemeService::SetTheme(extension);
+}
+
+void ThemeServiceAuraX11::UseDefaultTheme() {
+  profile()->GetPrefs()->SetBoolean(prefs::kUsesSystemTheme, false);
+  ThemeService::UseDefaultTheme();
+}
+
+void ThemeServiceAuraX11::SetNativeTheme() {
+  profile()->GetPrefs()->SetBoolean(prefs::kUsesSystemTheme, true);
+  ClearAllThemeData();
+  NotifyThemeChanged();
+}
+
+bool ThemeServiceAuraX11::UsingDefaultTheme() const {
+  return !use_system_theme_ && ThemeService::UsingDefaultTheme();
+}
+
+bool ThemeServiceAuraX11::UsingNativeTheme() const {
+  return use_system_theme_;
+}
+
+void ThemeServiceAuraX11::OnUsesSystemThemeChanged() {
+  use_system_theme_ =
+      profile()->GetPrefs()->GetBoolean(prefs::kUsesSystemTheme);
+}
diff --git a/chrome/browser/themes/theme_service_aurax11.h b/chrome/browser/themes/theme_service_aurax11.h
new file mode 100644
index 0000000..96dce92
--- /dev/null
+++ b/chrome/browser/themes/theme_service_aurax11.h
@@ -0,0 +1,43 @@
+// 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_THEMES_THEME_SERVICE_AURAX11_H_
+#define CHROME_BROWSER_THEMES_THEME_SERVICE_AURAX11_H_
+
+#include "base/prefs/pref_change_registrar.h"
+#include "chrome/browser/themes/theme_service.h"
+
+// A subclass of ThemeService that queries the current ui::LinuxUI instance for
+// theme data.
+class ThemeServiceAuraX11 : public ThemeService {
+ public:
+  ThemeServiceAuraX11();
+  virtual ~ThemeServiceAuraX11();
+
+  // Overridden from ui::ThemeProvider:
+  virtual SkColor GetColor(int id) const OVERRIDE;
+  virtual bool HasCustomImage(int id) const OVERRIDE;
+
+  // Overridden from ThemeService:
+  virtual void Init(Profile* profile) OVERRIDE;
+  virtual gfx::Image GetImageNamed(int id) const OVERRIDE;
+  virtual void SetTheme(const extensions::Extension* extension) OVERRIDE;
+  virtual void UseDefaultTheme() OVERRIDE;
+  virtual void SetNativeTheme() OVERRIDE;
+  virtual bool UsingDefaultTheme() const OVERRIDE;
+  virtual bool UsingNativeTheme() const OVERRIDE;
+
+ private:
+  void OnUsesSystemThemeChanged();
+
+  // Whether we'll give the ui::LinuxUI object first shot at providing theme
+  // resources.
+  bool use_system_theme_;
+
+  PrefChangeRegistrar registrar_;
+
+  DISALLOW_COPY_AND_ASSIGN(ThemeServiceAuraX11);
+};
+
+#endif  // CHROME_BROWSER_THEMES_THEME_SERVICE_AURAX11_H_
diff --git a/chrome/browser/themes/theme_service_factory.cc b/chrome/browser/themes/theme_service_factory.cc
index 054d56c..adc424b 100644
--- a/chrome/browser/themes/theme_service_factory.cc
+++ b/chrome/browser/themes/theme_service_factory.cc
@@ -18,6 +18,11 @@
 #include "chrome/browser/ui/gtk/gtk_theme_service.h"
 #endif
 
+#if defined(USE_AURA) && defined(OS_LINUX) && !defined(OS_CHROMEOS)
+#include "chrome/browser/themes/theme_service_aurax11.h"
+#include "ui/linux_ui/linux_ui.h"
+#endif
+
 // static
 ThemeService* ThemeServiceFactory::GetForProfile(Profile* profile) {
   return static_cast<ThemeService*>(
@@ -51,6 +56,8 @@
   ThemeService* provider = NULL;
 #if defined(TOOLKIT_GTK)
   provider = new GtkThemeService;
+#elif defined(USE_AURA) && defined(OS_LINUX) && !defined(OS_CHROMEOS)
+  provider = new ThemeServiceAuraX11;
 #else
   provider = new ThemeService;
 #endif
@@ -61,10 +68,20 @@
 
 void ThemeServiceFactory::RegisterUserPrefs(
     user_prefs::PrefRegistrySyncable* registry) {
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+  bool default_uses_system_theme = false;
+
 #if defined(TOOLKIT_GTK)
+  default_uses_system_theme = GtkThemeService::DefaultUsesSystemTheme();
+#elif defined(USE_AURA) && defined(OS_LINUX) && !defined(OS_CHROMEOS)
+  const ui::LinuxUI* linux_ui = ui::LinuxUI::instance();
+  if (linux_ui)
+    default_uses_system_theme = linux_ui->GetDefaultUsesSystemTheme();
+#endif
+
   registry->RegisterBooleanPref(
       prefs::kUsesSystemTheme,
-      GtkThemeService::DefaultUsesSystemTheme(),
+      default_uses_system_theme,
       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
 #endif
   registry->RegisterFilePathPref(
diff --git a/chrome/browser/themes/theme_syncable_service.cc b/chrome/browser/themes/theme_syncable_service.cc
index bf414d6..3389443 100644
--- a/chrome/browser/themes/theme_syncable_service.cc
+++ b/chrome/browser/themes/theme_syncable_service.cc
@@ -135,6 +135,7 @@
 
   if (!sync_processor_.get()) {
     return syncer::SyncError(FROM_HERE,
+                             syncer::SyncError::DATATYPE_ERROR,
                              "Theme syncable service is not started.",
                              syncer::THEMES);
   }
@@ -180,8 +181,8 @@
   }
 
   return syncer::SyncError(FROM_HERE,
-                           base::StringPrintf(
-                               "Didn't find valid theme specifics."),
+                           syncer::SyncError::DATATYPE_ERROR,
+                           "Didn't find valid theme specifics",
                            syncer::THEMES);
 }
 
diff --git a/chrome/browser/themes/theme_syncable_service_unittest.cc b/chrome/browser/themes/theme_syncable_service_unittest.cc
index 4099223..5931a17 100644
--- a/chrome/browser/themes/theme_syncable_service_unittest.cc
+++ b/chrome/browser/themes/theme_syncable_service_unittest.cc
@@ -505,8 +505,9 @@
   // ProcessSyncChanges() should return error when sync has stopped.
   error = theme_sync_service_->ProcessSyncChanges(FROM_HERE, change_list);
   EXPECT_TRUE(error.IsSet());
-  EXPECT_EQ(syncer::THEMES, error.type());
-  EXPECT_EQ("Theme syncable service is not started.",
+  EXPECT_EQ(syncer::THEMES, error.model_type());
+  EXPECT_EQ("datatype error was encountered: Theme syncable service is not "
+                "started.",
             error.message());
 }
 
diff --git a/chrome/browser/three_d_api_observer.cc b/chrome/browser/three_d_api_observer.cc
index 02e52e9..61b39cf 100644
--- a/chrome/browser/three_d_api_observer.cc
+++ b/chrome/browser/three_d_api_observer.cc
@@ -11,9 +11,9 @@
 #include "content/public/browser/gpu_data_manager.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/three_d_api_types.h"
-#include "googleurl/src/gurl.h"
 #include "grit/generated_resources.h"
 #include "ui/base/l10n/l10n_util.h"
+#include "url/gurl.h"
 
 
 // ThreeDAPIInfoBarDelegate ---------------------------------------------
diff --git a/chrome/browser/thumbnails/thumbnail_service.h b/chrome/browser/thumbnails/thumbnail_service.h
index 9c7e395..11da713 100644
--- a/chrome/browser/thumbnails/thumbnail_service.h
+++ b/chrome/browser/thumbnails/thumbnail_service.h
@@ -7,8 +7,8 @@
 
 #include "chrome/common/thumbnail_score.h"
 #include "components/browser_context_keyed_service/refcounted_browser_context_keyed_service.h"
-#include "googleurl/src/gurl.h"
 #include "ui/gfx/image/image.h"
+#include "url/gurl.h"
 
 namespace base {
 class RefCountedMemory;
diff --git a/chrome/browser/translate/translate_accept_languages.cc b/chrome/browser/translate/translate_accept_languages.cc
index 6de5225..df2f4cc 100644
--- a/chrome/browser/translate/translate_accept_languages.cc
+++ b/chrome/browser/translate/translate_accept_languages.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/translate/translate_accept_languages.h"
 
 #include "base/bind.h"
+#include "base/command_line.h"
 #include "base/prefs/pref_change_registrar.h"
 #include "base/prefs/pref_service.h"
 #include "base/strings/string_split.h"
@@ -13,6 +14,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/translate/translate_manager.h"
 #include "chrome/common/chrome_notification_types.h"
+#include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/translate/translate_util.h"
 #include "content/public/browser/notification_source.h"
@@ -89,6 +91,11 @@
   std::string app_locale = g_browser_process->GetApplicationLocale();
   std::string ui_lang = TranslateManager::GetLanguageCode(app_locale);
   bool is_ui_english = StartsWithASCII(ui_lang, "en-", false);
+
+  CommandLine* command_line = CommandLine::ForCurrentProcess();
+  bool enable_translate_settings =
+      command_line->HasSwitch(switches::kEnableTranslateSettings);
+
   for (iter = accept_langs_list.begin();
        iter != accept_langs_list.end(); ++iter) {
     // Get rid of the locale extension if any (ex: en-US -> en), but for Chinese
@@ -97,6 +104,7 @@
     size_t index = iter->find("-");
     if (index != std::string::npos && *iter != "zh-CN" && *iter != "zh-TW")
       accept_lang = iter->substr(0, index);
+
     // Special-case English until we resolve bug 36182 properly.
     // Add English only if the UI language is not English. This will annoy
     // users of non-English Chrome who can comprehend English until English is
@@ -104,8 +112,12 @@
     // TODO(jungshik): Once we determine that it's safe to remove English from
     // the default Accept-Language values for most locales, remove this
     // special-casing.
-    if (accept_lang != "en" || is_ui_english)
-      accept_langs_set.insert(accept_lang);
+    // TODO(hajimehoshi): We can remove this special-casing if the Translate
+    // settings UI is enabled by default.
+    if (!enable_translate_settings && accept_lang == "en" && !is_ui_english)
+      continue;
+
+    accept_langs_set.insert(accept_lang);
   }
   accept_languages_[prefs] = accept_langs_set;
 }
diff --git a/chrome/browser/translate/translate_browsertest.cc b/chrome/browser/translate/translate_browsertest.cc
index bb6ec05..f65093f 100644
--- a/chrome/browser/translate/translate_browsertest.cc
+++ b/chrome/browser/translate/translate_browsertest.cc
@@ -19,6 +19,7 @@
 #include "content/public/browser/notification_service.h"
 #include "content/public/test/browser_test_utils.h"
 #include "net/http/http_status_code.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
 #include "net/test/spawned_test_server/spawned_test_server.h"
 #include "net/url_request/test_url_fetcher_factory.h"
 #include "net/url_request/url_fetcher_delegate.h"
@@ -27,7 +28,7 @@
 
 const base::FilePath::CharType kTranslateRoot[] =
     FILE_PATH_LITERAL("chrome/test/data/translate");
-const char kNonSecurePrefix[] = "files/translate/";
+const char kNonSecurePrefix[] = "/translate/";
 const char kSecurePrefix[] = "files/";
 const char kFrenchTestPath[] = "fr_test.html";
 const char kRefreshMetaTagTestPath[] = "refresh_meta_tag.html";
@@ -56,7 +57,7 @@
  protected:
   GURL GetNonSecureURL(const std::string& path) const {
     std::string prefix(kNonSecurePrefix);
-    return test_server()->GetURL(prefix + path);
+    return embedded_test_server()->GetURL(prefix + path);
   }
 
   GURL GetSecureURL(const std::string& path) const {
@@ -73,7 +74,7 @@
 };
 
 IN_PROC_BROWSER_TEST_F(TranslateBrowserTest, Translate) {
-  ASSERT_TRUE(test_server()->Start());
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
 
   content::WebContents* web_contents =
       browser()->tab_strip_model()->GetActiveWebContents();
@@ -141,7 +142,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(TranslateBrowserTest, IgnoreRefreshMetaTag) {
-  ASSERT_TRUE(test_server()->Start());
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
 
   content::WebContents* web_contents =
       browser()->tab_strip_model()->GetActiveWebContents();
@@ -172,7 +173,7 @@
 
 IN_PROC_BROWSER_TEST_F(TranslateBrowserTest,
                        IgnoreRefreshMetaTagInCaseInsensitive) {
-  ASSERT_TRUE(test_server()->Start());
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
 
   content::WebContents* web_contents =
       browser()->tab_strip_model()->GetActiveWebContents();
@@ -202,7 +203,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(TranslateBrowserTest, IgnoreRefreshMetaTagAtOnload) {
-  ASSERT_TRUE(test_server()->Start());
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
 
   content::WebContents* web_contents =
       browser()->tab_strip_model()->GetActiveWebContents();
@@ -232,7 +233,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(TranslateBrowserTest, UpdateLocation) {
-  ASSERT_TRUE(test_server()->Start());
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
 
   content::WebContents* web_contents =
       browser()->tab_strip_model()->GetActiveWebContents();
@@ -262,7 +263,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(TranslateBrowserTest, UpdateLocationAtOnload) {
-  ASSERT_TRUE(test_server()->Start());
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
 
   content::WebContents* web_contents =
       browser()->tab_strip_model()->GetActiveWebContents();
diff --git a/chrome/browser/translate/translate_error_details.h b/chrome/browser/translate/translate_error_details.h
index bb2b0b6..b2b5506 100644
--- a/chrome/browser/translate/translate_error_details.h
+++ b/chrome/browser/translate/translate_error_details.h
@@ -5,9 +5,9 @@
 #ifndef CHROME_BROWSER_TRANSLATE_TRANSLATE_ERROR_DETAILS_H_
 #define CHROME_BROWSER_TRANSLATE_TRANSLATE_ERROR_DETAILS_H_
 
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/common/translate/translate_errors.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 struct TranslateErrorDetails {
   // The time when this was created
diff --git a/chrome/browser/translate/translate_event_details.h b/chrome/browser/translate/translate_event_details.h
index a788f41..0b98b6d 100644
--- a/chrome/browser/translate/translate_event_details.h
+++ b/chrome/browser/translate/translate_event_details.h
@@ -7,7 +7,7 @@
 
 #include <string>
 
-#include "base/time.h"
+#include "base/time/time.h"
 
 struct TranslateEventDetails {
   TranslateEventDetails(const std::string& in_filename,
diff --git a/chrome/browser/translate/translate_infobar_delegate.cc b/chrome/browser/translate/translate_infobar_delegate.cc
index ca9df4c..b1f1345 100644
--- a/chrome/browser/translate/translate_infobar_delegate.cc
+++ b/chrome/browser/translate/translate_infobar_delegate.cc
@@ -74,6 +74,16 @@
                                    original_language, target_language));
   infobar->UpdateBackgroundAnimation(old_delegate);
 
+  // Do not create the after translate infobar if we are auto translating.
+  if (infobar_type == TranslateInfoBarDelegate::AFTER_TRANSLATE ||
+      infobar_type == TranslateInfoBarDelegate::TRANSLATING) {
+    TranslateTabHelper* translate_tab_helper =
+      TranslateTabHelper::FromWebContents(infobar_service->web_contents());
+    if (!translate_tab_helper ||
+         translate_tab_helper->language_state().InTranslateNavigation())
+      return;
+  }
+
   // Add the new delegate if necessary.
   if (!old_delegate) {
     infobar_service->AddInfoBar(infobar.PassAs<InfoBarDelegate>());
@@ -126,14 +136,6 @@
   UMA_HISTOGRAM_BOOLEAN(kDeclineTranslate, true);
 }
 
-bool TranslateInfoBarDelegate::InTranslateNavigation() {
-  TranslateTabHelper* translate_tab_helper =
-      TranslateTabHelper::FromWebContents(web_contents());
-  if (!translate_tab_helper)
-    return false;
-  return translate_tab_helper->language_state().InTranslateNavigation();
-}
-
 bool TranslateInfoBarDelegate::IsTranslatableLanguageByPrefs() {
   Profile* profile =
       Profile::FromBrowserContext(web_contents()->GetBrowserContext());
@@ -144,10 +146,10 @@
 
 void TranslateInfoBarDelegate::ToggleTranslatableLanguageByPrefs() {
   const std::string& original_lang = original_language_code();
-  if (prefs_.IsLanguageBlacklisted(original_lang)) {
-    prefs_.RemoveLanguageFromBlacklist(original_lang);
+  if (prefs_.IsBlockedLanguage(original_lang)) {
+    prefs_.UnblockLanguage(original_lang);
   } else {
-    prefs_.BlacklistLanguage(original_lang);
+    prefs_.BlockLanguage(original_lang);
     RemoveSelf();
   }
 }
@@ -194,8 +196,8 @@
 
 void TranslateInfoBarDelegate::NeverTranslatePageLanguage() {
   std::string original_lang = original_language_code();
-  DCHECK(!prefs_.IsLanguageBlacklisted(original_lang));
-  prefs_.BlacklistLanguage(original_lang);
+  DCHECK(!prefs_.IsBlockedLanguage(original_lang));
+  prefs_.BlockLanguage(original_lang);
   RemoveSelf();
 }
 
diff --git a/chrome/browser/translate/translate_infobar_delegate.h b/chrome/browser/translate/translate_infobar_delegate.h
index 257a32d..066df9b 100644
--- a/chrome/browser/translate/translate_infobar_delegate.h
+++ b/chrome/browser/translate/translate_infobar_delegate.h
@@ -148,7 +148,6 @@
   string16 GetMessageInfoBarButtonText();
   void MessageInfoBarButtonPressed();
   bool ShouldShowMessageInfoBarButton();
-  bool InTranslateNavigation();
 
   // Called by the before translate infobar to figure-out if it should show
   // an extra shortcut to let the user black-list/white-list that language
diff --git a/chrome/browser/translate/translate_language_list.cc b/chrome/browser/translate/translate_language_list.cc
index af0f77f..88f0701 100644
--- a/chrome/browser/translate/translate_language_list.cc
+++ b/chrome/browser/translate/translate_language_list.cc
@@ -17,14 +17,11 @@
 #include "chrome/browser/translate/translate_browser_metrics.h"
 #include "chrome/browser/translate/translate_event_details.h"
 #include "chrome/browser/translate/translate_manager.h"
+#include "chrome/browser/translate/translate_url_fetcher.h"
 #include "chrome/browser/translate/translate_url_util.h"
-#include "googleurl/src/gurl.h"
-#include "net/base/load_flags.h"
 #include "net/base/url_util.h"
-#include "net/http/http_status_code.h"
-#include "net/url_request/url_fetcher.h"
-#include "net/url_request/url_request_status.h"
 #include "ui/base/l10n/l10n_util.h"
+#include "url/gurl.h"
 
 namespace {
 
@@ -106,14 +103,17 @@
 const char kAlphaLanguageQueryName[] = "alpha";
 const char kAlphaLanguageQueryValue[] = "1";
 
-// Retry parameter for fetching supporting language list.
-const int kMaxRetryLanguageListFetch = 5;
-
 // Assign following IDs to URLFetchers so that tests can distinguish each
 // request in order to simiulate respectively.
 const int kFetcherIdForLanguageList = 1;
 const int kFetcherIdForAlphaLanguageList = 2;
 
+// Represent if the language list updater is disabled.
+bool update_is_disabled = false;
+
+// Retry parameter for fetching.
+const int kMaxRetryOn5xx = 5;
+
 // Show a message in chrome:://translate-internals Event Logs.
 void NotifyEvent(int line, const std::string& message) {
   TranslateManager* manager = TranslateManager::GetInstance();
@@ -187,83 +187,22 @@
   NotifyEvent(__LINE__, message);
 }
 
-}  // namespace
-
-TranslateLanguageList::LanguageListFetcher::LanguageListFetcher(
-    bool include_alpha_languages)
-  : include_alpha_languages_(include_alpha_languages),
-    state_(IDLE) {
-}
-
-TranslateLanguageList::LanguageListFetcher::~LanguageListFetcher() {
-}
-
-bool TranslateLanguageList::LanguageListFetcher::Request(
-    const TranslateLanguageList::LanguageListFetcher::Callback& callback) {
-  // This function is not supporsed to be called before previous operaion is not
-  // finished.
-  if (state_ == REQUESTING) {
-    NOTREACHED();
-    return false;
-  }
-
-  state_ = REQUESTING;
-  callback_ = callback;
-
+// Returns URL to fetch the language list.
+GURL GetLanguageListFetchURL(bool include_alpha_languages) {
   GURL url = GURL(kLanguageListFetchURL);
   url = TranslateURLUtil::AddHostLocaleToUrl(url);
   url = TranslateURLUtil::AddApiKeyToUrl(url);
-  if (include_alpha_languages_) {
+
+  if (include_alpha_languages) {
     url = net::AppendQueryParameter(url,
                                     kAlphaLanguageQueryName,
                                     kAlphaLanguageQueryValue);
   }
 
-  std::string message = base::StringPrintf(
-      "%s list fetch starts (URL: %s)",
-      include_alpha_languages_ ? "Language" : "Alpha language",
-      url.spec().c_str());
-  NotifyEvent(__LINE__, message);
-
-  fetcher_.reset(net::URLFetcher::Create(
-      include_alpha_languages_ ? kFetcherIdForAlphaLanguageList :
-                                 kFetcherIdForLanguageList,
-      url,
-      net::URLFetcher::GET,
-      this));
-  fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES |
-                         net::LOAD_DO_NOT_SAVE_COOKIES);
-  fetcher_->SetRequestContext(g_browser_process->system_request_context());
-  fetcher_->SetMaxRetriesOn5xx(kMaxRetryLanguageListFetch);
-  fetcher_->Start();
-
-  return true;
+  return url;
 }
 
-void TranslateLanguageList::LanguageListFetcher::OnURLFetchComplete(
-    const net::URLFetcher* source) {
-  DCHECK(fetcher_.get() == source);
-
-  std::string data;
-  if (source->GetStatus().status() == net::URLRequestStatus::SUCCESS &&
-      source->GetResponseCode() == net::HTTP_OK) {
-    state_ = COMPLETED;
-    source->GetResponseAsString(&data);
-    std::string message = base::StringPrintf(
-        "%s list is updated",
-        include_alpha_languages_ ? "Alpha language" : "Language");
-    NotifyEvent(__LINE__, message);
-  } else {
-    state_ = FAILED;
-    std::string message = base::StringPrintf(
-        "Failed to Fetch languages from: %s",
-        source->GetURL().spec().c_str());
-    NotifyEvent(__LINE__, message);
-  }
-
-  scoped_ptr<const net::URLFetcher> delete_ptr(fetcher_.release());
-  callback_.Run(include_alpha_languages_, state_ == COMPLETED, data);
-}
+}  // namespace
 
 // This must be kept in sync with the &cb= value in the kLanguageListFetchURL.
 const char TranslateLanguageList::kLanguageListCallbackName[] = "sl(";
@@ -277,8 +216,16 @@
     supported_languages_.insert(kDefaultSupportedLanguages[i]);
   UpdateSupportedLanguages();
 
-  language_list_fetcher_.reset(new LanguageListFetcher(false));
-  alpha_language_list_fetcher_.reset(new LanguageListFetcher(true));
+  if (update_is_disabled)
+    return;
+
+  language_list_fetcher_.reset(
+      new TranslateURLFetcher(kFetcherIdForLanguageList));
+  language_list_fetcher_->set_max_retry_on_5xx(kMaxRetryOn5xx);
+
+  alpha_language_list_fetcher_.reset(
+      new TranslateURLFetcher(kFetcherIdForAlphaLanguageList));
+  alpha_language_list_fetcher_->set_max_retry_on_5xx(kMaxRetryOn5xx);
 }
 
 TranslateLanguageList::~TranslateLanguageList() {
@@ -290,6 +237,11 @@
   std::set<std::string>::const_iterator iter = all_supported_languages_.begin();
   for (; iter != all_supported_languages_.end(); ++iter)
     languages->push_back(*iter);
+
+  // Update language lists if they are not updated after Chrome was launched
+  // for later requests.
+  if (language_list_fetcher_.get() || alpha_language_list_fetcher_.get())
+    RequestLanguageList();
 }
 
 std::string TranslateLanguageList::GetLanguageCode(
@@ -316,36 +268,89 @@
 }
 
 void TranslateLanguageList::RequestLanguageList() {
+  // If resource requests are not allowed, we'll get a callback when they are.
+  if (resource_request_allowed_notifier_.ResourceRequestsAllowed())
+    OnResourceRequestsAllowed();
+}
+
+void TranslateLanguageList::OnResourceRequestsAllowed() {
   if (language_list_fetcher_.get() &&
-      (language_list_fetcher_->state() == LanguageListFetcher::IDLE ||
-       language_list_fetcher_->state() == LanguageListFetcher::FAILED)) {
-    language_list_fetcher_->Request(
+      (language_list_fetcher_->state() == TranslateURLFetcher::IDLE ||
+       language_list_fetcher_->state() == TranslateURLFetcher::FAILED)) {
+    GURL url = GetLanguageListFetchURL(false);
+
+    std::string message = base::StringPrintf(
+        "Language list fetch starts (URL: %s)",
+        url.spec().c_str());
+    NotifyEvent(__LINE__, message);
+
+    bool result = language_list_fetcher_->Request(
+        url,
         base::Bind(&TranslateLanguageList::OnLanguageListFetchComplete,
                    base::Unretained(this)));
+    if (!result)
+      NotifyEvent(__LINE__, "Request is omitted due to retry limit");
   }
 
   if (alpha_language_list_fetcher_.get() &&
-      (alpha_language_list_fetcher_->state() == LanguageListFetcher::IDLE ||
-       alpha_language_list_fetcher_->state() == LanguageListFetcher::FAILED)) {
-    alpha_language_list_fetcher_->Request(
+      (alpha_language_list_fetcher_->state() == TranslateURLFetcher::IDLE ||
+       alpha_language_list_fetcher_->state() == TranslateURLFetcher::FAILED)) {
+    GURL url = GetLanguageListFetchURL(true);
+
+    std::string message = base::StringPrintf(
+        "Alpha language list fetch starts (URL: %s)",
+        url.spec().c_str());
+    NotifyEvent(__LINE__, message);
+
+    bool result = alpha_language_list_fetcher_->Request(
+        url,
         base::Bind(&TranslateLanguageList::OnLanguageListFetchComplete,
                    base::Unretained(this)));
+    if (!result)
+      NotifyEvent(__LINE__, "Request is omitted due to retry limit");
   }
 }
 
+// static
+void TranslateLanguageList::DisableUpdate() {
+  update_is_disabled = true;
+}
+
 void TranslateLanguageList::OnLanguageListFetchComplete(
-    bool include_alpha_languages,
+    int id,
     bool success,
     const std::string& data) {
-  if (!success)
+  if (!success) {
+    // Since it fails just now, omit to schedule resource requests if
+    // ResourceRequestAllowedNotifier think it's ready. Otherwise, a callback
+    // will be invoked later to request resources again.
+    // The TranslateURLFetcher has a limit for retried requests and aborts
+    // re-try not to invoke OnLanguageListFetchComplete anymore if it's asked to
+    // re-try too many times.
+    GURL url = GetLanguageListFetchURL(id == kFetcherIdForAlphaLanguageList);
+    std::string message = base::StringPrintf(
+        "Failed to Fetch languages from: %s", url.spec().c_str());
+    NotifyEvent(__LINE__, message);
     return;
+  }
 
-  if (!include_alpha_languages) {
-    SetSupportedLanguages(data, &supported_languages_);
-    language_list_fetcher_.reset();
-  } else {
-    SetSupportedLanguages(data, &supported_alpha_languages_);
-    alpha_language_list_fetcher_.reset();
+  std::string message = base::StringPrintf(
+      "%s list is updated",
+      id == kFetcherIdForLanguageList ? "Language" : "Alpha language");
+  NotifyEvent(__LINE__, message);
+
+  switch (id) {
+    case kFetcherIdForLanguageList:
+      SetSupportedLanguages(data, &supported_languages_);
+      language_list_fetcher_.reset();
+      break;
+    case kFetcherIdForAlphaLanguageList:
+      SetSupportedLanguages(data, &supported_alpha_languages_);
+      alpha_language_list_fetcher_.reset();
+      break;
+    default:
+      NOTREACHED();
+      break;
   }
   UpdateSupportedLanguages();
 
diff --git a/chrome/browser/translate/translate_language_list.h b/chrome/browser/translate/translate_language_list.h
index 4518eaf..a443817 100644
--- a/chrome/browser/translate/translate_language_list.h
+++ b/chrome/browser/translate/translate_language_list.h
@@ -9,20 +9,16 @@
 #include <string>
 #include <vector>
 
-#include "base/callback.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/time.h"
-#include "googleurl/src/gurl.h"
-#include "net/url_request/url_fetcher_delegate.h"
+#include "base/time/time.h"
+#include "chrome/browser/web_resource/resource_request_allowed_notifier.h"
 
-namespace net {
-class URLFetcher;
-}
+class TranslateURLFetcher;
 
 // The TranslateLanguageList class is responsible for maintaining the latest
 // supporting language list.
 // This class is defined to be owned only by TranslateManager.
-class TranslateLanguageList {
+class TranslateLanguageList : public ResourceRequestAllowedNotifier::Observer {
  public:
   TranslateLanguageList();
   virtual ~TranslateLanguageList();
@@ -47,68 +43,24 @@
   // alpha language.
   bool IsAlphaLanguage(const std::string& language);
 
-  // Fetches the language list from the translate server. It will not retry
-  // more than kMaxRetryLanguageListFetch times. Do nothing if the list is
-  // already updated.
+  // Fetches the language list from the translate server. It will retry
+  // automatically when a server return 5xx errors and retry count doesn't
+  // reach to limits.
   void RequestLanguageList();
 
+  // ResourceRequestAllowedNotifier::Observer implementation:
+  virtual void OnResourceRequestsAllowed() OVERRIDE;
+
+  // Disables the language list updater. This is used only for testing now.
+  static void DisableUpdate();
+
   // static const values shared with our browser tests.
   static const char kLanguageListCallbackName[];
   static const char kTargetLanguagesKey[];
 
  private:
-  // The LanguageListFetcher class implements a client to fetch a server
-  // supported language list. It also maintains the state to represent if the
-  // fetch is completed successfully to try again later.
-  class LanguageListFetcher : public net::URLFetcherDelegate {
-   public:
-    // Callback type for Request().
-    typedef base::Callback<void(bool, bool, const std::string&)> Callback;
-
-    // Represents internal state if the fetch is completed successfully.
-    enum State {
-      IDLE,        // No fetch request was issued.
-      REQUESTING,  // A fetch request was issued, but not finished yet.
-      COMPLETED,   // The last fetch request was finished successfully.
-      FAILED,      // The last fetch request was finished with a failure.
-    };
-
-    explicit LanguageListFetcher(bool include_alpha_languages);
-    virtual ~LanguageListFetcher();
-
-    // Requests to fetch a server supported language list. |callback| will be
-    // invoked when the function returns true, and the request is finished
-    // asynchronously.
-    // Returns false if the previous request is not finished, or the request
-    // is omitted due to retry limitation.
-    bool Request(const Callback& callback);
-
-    // Gets internal state.
-    State state() { return state_; }
-
-    // net::URLFetcherDelegate implementation:
-    virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE;
-
-   private:
-    // Represents if this instance should fetch a supported language list
-    // including alpha languages.
-    bool include_alpha_languages_;
-
-    // Internal state.
-    enum State state_;
-
-    // URLFetcher instance.
-    scoped_ptr<net::URLFetcher> fetcher_;
-
-    // Callback passed at Request(). It will be invoked when an asynchronous
-    // fetch operation is finished.
-    Callback callback_;
-
-    DISALLOW_COPY_AND_ASSIGN(LanguageListFetcher);
-  };
-
-  // Callback function called when LanguageListFetcher::Request() is finished.
-  void OnLanguageListFetchComplete(bool include_alpha_languages,
+  // Callback function called when TranslateURLFetcher::Request() is finished.
+  void OnLanguageListFetchComplete(int id,
                                    bool success,
                                    const std::string& data);
 
@@ -128,15 +80,18 @@
 
   // A LanguageListFetcher instance to fetch a server providing supported
   // language list.
-  scoped_ptr<LanguageListFetcher> language_list_fetcher_;
+  scoped_ptr<TranslateURLFetcher> language_list_fetcher_;
 
   // A LanguageListFetcher instance to fetch a server providing supported alpha
   // language list.
-  scoped_ptr<LanguageListFetcher> alpha_language_list_fetcher_;
+  scoped_ptr<TranslateURLFetcher> alpha_language_list_fetcher_;
 
   // The last-updated time when the language list is sent.
   base::Time last_updated_;
 
+  // Helper class to know if it's allowed to make network resource requests.
+  ResourceRequestAllowedNotifier resource_request_allowed_notifier_;
+
   DISALLOW_COPY_AND_ASSIGN(TranslateLanguageList);
 };
 
diff --git a/chrome/browser/translate/translate_manager.cc b/chrome/browser/translate/translate_manager.cc
index 8a2d93a..f071e4c 100644
--- a/chrome/browser/translate/translate_manager.cc
+++ b/chrome/browser/translate/translate_manager.cc
@@ -8,13 +8,12 @@
 #include "base/command_line.h"
 #include "base/compiler_specific.h"
 #include "base/memory/singleton.h"
-#include "base/message_loop.h"
 #include "base/metrics/histogram.h"
 #include "base/prefs/pref_service.h"
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/infobars/infobar_service.h"
@@ -29,6 +28,7 @@
 #include "chrome/browser/translate/translate_infobar_delegate.h"
 #include "chrome/browser/translate/translate_language_list.h"
 #include "chrome/browser/translate/translate_prefs.h"
+#include "chrome/browser/translate/translate_script.h"
 #include "chrome/browser/translate/translate_tab_helper.h"
 #include "chrome/browser/translate/translate_url_util.h"
 #include "chrome/browser/ui/browser.h"
@@ -52,16 +52,10 @@
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/web_contents.h"
-#include "google_apis/google_api_keys.h"
-#include "grit/browser_resources.h"
-#include "net/base/escape.h"
 #include "net/base/load_flags.h"
 #include "net/base/url_util.h"
 #include "net/http/http_status_code.h"
-#include "net/url_request/url_fetcher.h"
-#include "net/url_request/url_request_status.h"
 #include "ui/base/l10n/l10n_util.h"
-#include "ui/base/resource/resource_bundle.h"
 
 #ifdef FILE_MANAGER_EXTENSION
 #include "chrome/browser/chromeos/extensions/file_manager/file_manager_util.h"
@@ -74,17 +68,9 @@
 
 namespace {
 
-const char kTranslateScriptURL[] =
-    "https://translate.google.com/translate_a/element.js";
-const char kTranslateScriptHeader[] = "Google-Translate-Element-Mode: library";
 const char kReportLanguageDetectionErrorURL[] =
     "https://translate.google.com/translate_error?client=cr&action=langidc";
 
-// Used in kTranslateScriptURL to specify a callback function name.
-const char kCallbackQueryName[] = "cb";
-const char kCallbackQueryValue[] =
-    "cr.googleTranslate.onTranslateElementLoad";
-
 // Used in kReportLanguageDetectionErrorURL to specify the original page
 // language.
 const char kSourceLanguageQueryName[] = "sl";
@@ -100,8 +86,6 @@
 // loading before giving up the translation
 const int kMaxTranslateLoadCheckAttempts = 20;
 
-const int kTranslateScriptExpirationDelayDays = 1;
-
 }  // namespace
 
 TranslateManager::~TranslateManager() {
@@ -187,6 +171,14 @@
   return false;
 }
 
+void TranslateManager::SetTranslateScriptExpirationDelay(int delay_ms) {
+  if (script_.get() == NULL) {
+    NOTREACHED();
+    return;
+  }
+  script_->set_expiration_delay(delay_ms);
+}
+
 void TranslateManager::Observe(int type,
                                const content::NotificationSource& source,
                                const content::NotificationDetails& details) {
@@ -284,89 +276,6 @@
   }
 }
 
-void TranslateManager::OnURLFetchComplete(const net::URLFetcher* source) {
-  if (translate_script_request_pending_.get() != source) {
-    // Looks like crash on Mac is possibly caused with callback entering here
-    // with unknown fetcher when network is refreshed.
-    scoped_ptr<const net::URLFetcher> delete_ptr(source);
-    return;
-  }
-
-  bool error =
-      source->GetStatus().status() != net::URLRequestStatus::SUCCESS ||
-      source->GetResponseCode() != net::HTTP_OK;
-  if (translate_script_request_pending_.get() == source) {
-    scoped_ptr<const net::URLFetcher> delete_ptr(
-        translate_script_request_pending_.release());
-    if (!error) {
-      base::StringPiece str = ResourceBundle::GetSharedInstance().
-          GetRawDataResource(IDR_TRANSLATE_JS);
-      DCHECK(translate_script_.empty());
-      str.CopyToString(&translate_script_);
-      std::string argument = "('";
-      std::string api_key = google_apis::GetAPIKey();
-      argument += net::EscapeQueryParamValue(api_key, true);
-      argument += "');\n";
-      std::string data;
-      source->GetResponseAsString(&data);
-      translate_script_ += argument + data;
-
-      // We'll expire the cached script after some time, to make sure long
-      // running browsers still get fixes that might get pushed with newer
-      // scripts.
-      base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
-          base::Bind(&TranslateManager::ClearTranslateScript,
-                     weak_method_factory_.GetWeakPtr()),
-          translate_script_expiration_delay_);
-    }
-    // Process any pending requests.
-    std::vector<PendingRequest>::const_iterator iter;
-    for (iter = pending_requests_.begin(); iter != pending_requests_.end();
-         ++iter) {
-      const PendingRequest& request = *iter;
-      WebContents* web_contents =
-          tab_util::GetWebContentsByID(request.render_process_id,
-                                       request.render_view_id);
-      if (!web_contents) {
-        // The tab went away while we were retrieving the script.
-        continue;
-      }
-      NavigationEntry* entry = web_contents->GetController().GetActiveEntry();
-      if (!entry || entry->GetPageID() != request.page_id) {
-        // We navigated away from the page the translation was triggered on.
-        continue;
-      }
-
-      if (error) {
-        Profile* profile =
-            Profile::FromBrowserContext(web_contents->GetBrowserContext());
-        TranslateInfoBarDelegate::Create(
-            InfoBarService::FromWebContents(web_contents),
-            true,
-            TranslateInfoBarDelegate::TRANSLATION_ERROR,
-            TranslateErrors::NETWORK,
-            profile->GetPrefs(),
-            ShortcutConfig(),
-            request.source_lang,
-            request.target_lang);
-
-        if (!web_contents->GetBrowserContext()->IsOffTheRecord()) {
-          TranslateErrorDetails error_details;
-          error_details.time = base::Time::Now();
-          error_details.url = entry->GetURL();
-          error_details.error = TranslateErrors::NETWORK;
-          NotifyTranslateError(error_details);
-        }
-      } else {
-        // Translate the page.
-        DoTranslatePage(web_contents, translate_script_,
-                        request.source_lang, request.target_lang);
-      }
-    }
-    pending_requests_.clear();
-  }
-}
-
 void TranslateManager::AddObserver(Observer* obs) {
   observer_list_.AddObserver(obs);
 }
@@ -392,8 +301,6 @@
 
 TranslateManager::TranslateManager()
   : weak_method_factory_(this),
-    translate_script_expiration_delay_(base::TimeDelta::FromDays(
-        kTranslateScriptExpirationDelayDays)),
     max_reload_check_attempts_(kMaxTranslateLoadCheckAttempts) {
   notification_registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED,
                               content::NotificationService::AllSources());
@@ -404,6 +311,7 @@
                               content::NotificationService::AllSources());
   language_list_.reset(new TranslateLanguageList);
   accept_languages_.reset(new TranslateAcceptLanguages);
+  script_.reset(new TranslateScript);
 }
 
 void TranslateManager::InitiateTranslation(WebContents* web_contents,
@@ -438,17 +346,18 @@
     return;
   }
 
-  // Don't translate similar languages (ex: en-US to en).
   std::string target_lang = GetTargetLanguage(prefs);
   std::string language_code = GetLanguageCode(page_lang);
+
+  CommandLine* command_line = CommandLine::ForCurrentProcess();
+
+  // Don't translate similar languages (ex: en-US to en).
   if (language_code == target_lang) {
     TranslateBrowserMetrics::ReportInitiationStatus(
         TranslateBrowserMetrics::INITIATION_STATUS_SIMILAR_LANGUAGES);
     return;
   }
 
-  CommandLine* command_line = CommandLine::ForCurrentProcess();
-
   // Don't translate any language the user configured as accepted languages.
   // When the flag --enable-translate-settings is on, the condition is
   // different. In this case, even though a language is an Accept language,
@@ -586,8 +495,11 @@
       TranslateInfoBarDelegate::TRANSLATING, TranslateErrors::NONE,
       profile->GetPrefs(), ShortcutConfig(), source_lang, target_lang);
 
-  if (!translate_script_.empty()) {
-    DoTranslatePage(web_contents, translate_script_, source_lang, target_lang);
+  DCHECK(script_.get() != NULL);
+
+  const std::string& translate_script = script_->data();
+  if (!translate_script.empty()) {
+    DoTranslatePage(web_contents, translate_script, source_lang, target_lang);
     return;
   }
 
@@ -601,7 +513,13 @@
   request.source_lang = source_lang;
   request.target_lang = target_lang;
   pending_requests_.push_back(request);
-  RequestTranslateScript();
+
+  if (script_->HasPendingRequest())
+    return;
+
+  script_->Request(
+      base::Bind(&TranslateManager::OnTranslateScriptFetchComplete,
+                 base::Unretained(this)));
 }
 
 void TranslateManager::RevertTranslation(WebContents* web_contents) {
@@ -650,6 +568,14 @@
                                 content::PAGE_TRANSITION_AUTO_BOOKMARK);
 }
 
+void TranslateManager::ClearTranslateScript() {
+  if (script_.get() == NULL) {
+    NOTREACHED();
+    return;
+  }
+  script_->Clear();
+}
+
 void TranslateManager::DoTranslatePage(WebContents* web_contents,
                                        const std::string& translate_script,
                                        const std::string& source_lang,
@@ -718,51 +644,56 @@
 
 void TranslateManager::CleanupPendingUlrFetcher() {
   language_list_.reset();
-  translate_script_request_pending_.reset();
+  script_.reset();
 }
 
-void TranslateManager::RequestTranslateScript() {
-  if (translate_script_request_pending_.get() != NULL)
-    return;
+void TranslateManager::OnTranslateScriptFetchComplete(
+    bool success, const std::string& data) {
+  std::vector<PendingRequest>::const_iterator iter;
+  for (iter = pending_requests_.begin(); iter != pending_requests_.end();
+       ++iter) {
+    const PendingRequest& request = *iter;
+    WebContents* web_contents =
+        tab_util::GetWebContentsByID(request.render_process_id,
+                                     request.render_view_id);
+    if (!web_contents) {
+      // The tab went away while we were retrieving the script.
+      continue;
+    }
+    NavigationEntry* entry = web_contents->GetController().GetActiveEntry();
+    if (!entry || entry->GetPageID() != request.page_id) {
+      // We navigated away from the page the translation was triggered on.
+      continue;
+    }
 
-  GURL translate_script_url;
-  // Check if command-line contains an alternative URL for translate service.
-  const CommandLine& command_line = *CommandLine::ForCurrentProcess();
-  if (command_line.HasSwitch(switches::kTranslateScriptURL)) {
-    translate_script_url = GURL(
-        command_line.GetSwitchValueASCII(switches::kTranslateScriptURL));
-    if (!translate_script_url.is_valid() ||
-        !translate_script_url.query().empty()) {
-      LOG(WARNING) << "The following translate URL specified at the "
-                   << "command-line is invalid: "
-                   << translate_script_url.spec();
-      translate_script_url = GURL();
+    if (success) {
+      // Translate the page.
+      const std::string& translate_script = script_->data();
+      DoTranslatePage(web_contents, translate_script,
+                      request.source_lang, request.target_lang);
+    } else {
+      Profile* profile =
+          Profile::FromBrowserContext(web_contents->GetBrowserContext());
+      TranslateInfoBarDelegate::Create(
+          InfoBarService::FromWebContents(web_contents),
+          true,
+          TranslateInfoBarDelegate::TRANSLATION_ERROR,
+          TranslateErrors::NETWORK,
+          profile->GetPrefs(),
+          ShortcutConfig(),
+          request.source_lang,
+          request.target_lang);
+
+      if (!web_contents->GetBrowserContext()->IsOffTheRecord()) {
+        TranslateErrorDetails error_details;
+        error_details.time = base::Time::Now();
+        error_details.url = entry->GetURL();
+        error_details.error = TranslateErrors::NETWORK;
+        NotifyTranslateError(error_details);
+      }
     }
   }
-  // Use default URL when command-line argument is not specified, or specified
-  // URL is invalid.
-  if (translate_script_url.is_empty())
-    translate_script_url = GURL(kTranslateScriptURL);
-
-  translate_script_url = net::AppendQueryParameter(
-      translate_script_url,
-      kCallbackQueryName,
-      kCallbackQueryValue);
-
-  translate_script_url =
-      TranslateURLUtil::AddHostLocaleToUrl(translate_script_url);
-  translate_script_url =
-      TranslateURLUtil::AddApiKeyToUrl(translate_script_url);
-
-  translate_script_request_pending_.reset(net::URLFetcher::Create(
-      0, translate_script_url, net::URLFetcher::GET, this));
-  translate_script_request_pending_->SetLoadFlags(
-      net::LOAD_DO_NOT_SEND_COOKIES | net::LOAD_DO_NOT_SAVE_COOKIES);
-  translate_script_request_pending_->SetRequestContext(
-      g_browser_process->system_request_context());
-  translate_script_request_pending_->SetExtraRequestHeaders(
-      kTranslateScriptHeader);
-  translate_script_request_pending_->Start();
+  pending_requests_.clear();
 }
 
 // static
diff --git a/chrome/browser/translate/translate_manager.h b/chrome/browser/translate/translate_manager.h
index b00f444..8355ab1 100644
--- a/chrome/browser/translate/translate_manager.h
+++ b/chrome/browser/translate/translate_manager.h
@@ -13,11 +13,10 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/common/translate/translate_errors.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
-#include "net/url_request/url_fetcher_delegate.h"
 
 template <typename T> struct DefaultSingletonTraits;
 class GURL;
@@ -31,6 +30,7 @@
 struct TranslateEventDetails;
 class TranslateInfoBarDelegate;
 class TranslateLanguageList;
+class TranslateScript;
 
 namespace content {
 class WebContents;
@@ -45,8 +45,7 @@
 // page translation the user requests.
 // It is a singleton.
 
-class TranslateManager : public content::NotificationObserver,
-                         public net::URLFetcherDelegate {
+class TranslateManager : public content::NotificationObserver {
  public:
   // Returns the singleton instance.
   static TranslateManager* GetInstance();
@@ -78,6 +77,14 @@
   // Returns true if |language| is an Accept language for the user profile.
   static bool IsAcceptLanguage(Profile* profile, const std::string& language);
 
+  // Returns the language to translate to. The language returned is the
+  // first language found in the following list that is supported by the
+  // translation service:
+  //     the UI language
+  //     the accept-language list
+  // If no language is found then an empty string is returned.
+  static std::string GetTargetLanguage(PrefService* prefs);
+
   // Let the caller decide if and when we should fetch the language list from
   // the translate server. This is a NOOP if switches::kDisableTranslate is set
   // or if prefs::kEnableTranslate is set to false.
@@ -104,23 +111,17 @@
   void ReportLanguageDetectionError(content::WebContents* web_contents);
 
   // Clears the translate script, so it will be fetched next time we translate.
-  void ClearTranslateScript() { translate_script_.clear(); }
+  void ClearTranslateScript();
 
   // content::NotificationObserver implementation:
   virtual void Observe(int type,
                        const content::NotificationSource& source,
                        const content::NotificationDetails& details) OVERRIDE;
 
-  // net::URLFetcherDelegate implementation:
-  virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE;
-
   // Used by unit-tests to override some defaults:
   // Delay after which the translate script is fetched again from the
   // translation server.
-  void set_translate_script_expiration_delay(int delay_ms) {
-    translate_script_expiration_delay_ =
-        base::TimeDelta::FromMilliseconds(delay_ms);
-  }
+  void SetTranslateScriptExpirationDelay(int delay_ms);
 
   // Number of attempts before waiting for a page to be fully reloaded.
   void set_translate_max_reload_attemps(int attempts) {
@@ -182,9 +183,7 @@
   void PageTranslated(content::WebContents* web_contents,
                       PageTranslatedDetails* details);
 
-  // Fetches the JS translate script (the script that is injected in the page
-  // to translate it).
-  void RequestTranslateScript();
+  void OnTranslateScriptFetchComplete(bool success, const std::string& data);
 
   // Notifies to the observers when a language is detected.
   void NotifyLanguageDetection(const LanguageDetectionDetails& details);
@@ -192,14 +191,6 @@
   // Notifies to the observers when translate failed.
   void NotifyTranslateError(const TranslateErrorDetails& details);
 
-  // Returns the language to translate to. The language returned is the
-  // first language found in the following list that is supported by the
-  // translation service:
-  //     the UI language
-  //     the accept-language list
-  // If no language is found then an empty string is returned.
-  static std::string GetTargetLanguage(PrefService* prefs);
-
   // Returns the different parameters used to decide whether extra shortcuts
   // are needed.
   static ShortcutConfiguration ShortcutConfig();
@@ -208,19 +199,9 @@
 
   base::WeakPtrFactory<TranslateManager> weak_method_factory_;
 
-  // The JS injected in the page to do the translation.
-  std::string translate_script_;
-
-  // Delay after which the translate script is fetched again
-  // from the translate server.
-  base::TimeDelta translate_script_expiration_delay_;
-
   // Max number of attempts before checking if a page has been reloaded.
   int max_reload_check_attempts_;
 
-  // Set when the translate JS is currently being retrieved. NULL otherwise.
-  scoped_ptr<net::URLFetcher> translate_script_request_pending_;
-
   // The list of pending translate requests.  Translate requests are queued when
   // the translate script is not ready and has to be fetched from the translate
   // server.
@@ -232,6 +213,10 @@
   // An instance of TranslateLanguageList which manages supported language list.
   scoped_ptr<TranslateLanguageList> language_list_;
 
+  // An instance of TranslateScript which manages JavaScript source for
+  // Translate.
+  scoped_ptr<TranslateScript> script_;
+
   // An instance of TranslateAcceptLanguages which manages Accept languages of
   // each profiles.
   scoped_ptr<TranslateAcceptLanguages> accept_languages_;
diff --git a/chrome/browser/translate/translate_manager_browsertest.cc b/chrome/browser/translate/translate_manager_browsertest.cc
index 5de2bb8..d38b409 100644
--- a/chrome/browser/translate/translate_manager_browsertest.cc
+++ b/chrome/browser/translate/translate_manager_browsertest.cc
@@ -49,6 +49,7 @@
 #include "grit/generated_resources.h"
 #include "ipc/ipc_test_sink.h"
 #include "net/url_request/test_url_fetcher_factory.h"
+#include "net/url_request/url_fetcher_delegate.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "third_party/WebKit/public/web/WebContextMenuData.h"
 #include "third_party/WebKit/public/web/WebKit.h"
@@ -180,7 +181,7 @@
   }
 
   void ExpireTranslateScriptImmediately() {
-    TranslateManager::GetInstance()->set_translate_script_expiration_delay(0);
+    TranslateManager::GetInstance()->SetTranslateScriptExpirationDelay(0);
   }
 
   // If there is 1 infobar and it is a translate infobar, deny translation and
@@ -235,7 +236,7 @@
     // case it was zeroed in a previous test).
     TranslateManager::GetInstance()->ClearTranslateScript();
     TranslateManager::GetInstance()->
-        set_translate_script_expiration_delay(60 * 60 * 1000);
+        SetTranslateScriptExpirationDelay(60 * 60 * 1000);
     TranslateManager::GetInstance()->set_translate_max_reload_attemps(0);
 
     ChromeRenderViewHostTestHarness::SetUp();
@@ -632,17 +633,13 @@
   server_languages.push_back("fr-FR");
   server_languages.push_back("xx");
 
-  // First, get the default languages list:
+  // First, get the default languages list. Note that calling
+  // GetSupportedLanguages() invokes RequestLanguageList() internally.
   std::vector<std::string> default_supported_languages;
   TranslateManager::GetSupportedLanguages(&default_supported_languages);
   // To make sure we got the defaults and don't confuse them with the mocks.
   ASSERT_NE(default_supported_languages.size(), server_languages.size());
 
-  Profile* profile =
-      Profile::FromBrowserContext(web_contents()->GetBrowserContext());
-  PrefService* prefs = profile->GetPrefs();
-  TranslateManager::GetInstance()->FetchLanguageListFromTranslateServer(prefs);
-
   // Check that we still get the defaults until the URLFetch has completed.
   std::vector<std::string> current_supported_languages;
   TranslateManager::GetSupportedLanguages(&current_supported_languages);
@@ -655,7 +652,6 @@
   EXPECT_EQ(default_supported_languages, current_supported_languages);
 
   // Now check that we got the appropriate set of languages from the server.
-  TranslateManager::GetInstance()->FetchLanguageListFromTranslateServer(prefs);
   SimulateSupportedLanguagesURLFetch(true, server_languages);
   current_supported_languages.clear();
   TranslateManager::GetSupportedLanguages(&current_supported_languages);
@@ -1089,11 +1085,11 @@
   registrar.Add(TranslatePrefs::kPrefTranslateLanguageBlacklist,
                 pref_callback_);
   TranslatePrefs translate_prefs(prefs);
-  EXPECT_FALSE(translate_prefs.IsLanguageBlacklisted("fr"));
+  EXPECT_FALSE(translate_prefs.IsBlockedLanguage("fr"));
   EXPECT_TRUE(translate_prefs.CanTranslateLanguage(profile, "fr"));
   SetPrefObserverExpectation(TranslatePrefs::kPrefTranslateLanguageBlacklist);
-  translate_prefs.BlacklistLanguage("fr");
-  EXPECT_TRUE(translate_prefs.IsLanguageBlacklisted("fr"));
+  translate_prefs.BlockLanguage("fr");
+  EXPECT_TRUE(translate_prefs.IsBlockedLanguage("fr"));
   EXPECT_FALSE(translate_prefs.IsSiteBlacklisted(url.host()));
   EXPECT_FALSE(translate_prefs.CanTranslateLanguage(profile, "fr"));
 
@@ -1108,8 +1104,8 @@
 
   // Remove the language from the blacklist.
   SetPrefObserverExpectation(TranslatePrefs::kPrefTranslateLanguageBlacklist);
-  translate_prefs.RemoveLanguageFromBlacklist("fr");
-  EXPECT_FALSE(translate_prefs.IsLanguageBlacklisted("fr"));
+  translate_prefs.UnblockLanguage("fr");
+  EXPECT_FALSE(translate_prefs.IsBlockedLanguage("fr"));
   EXPECT_FALSE(translate_prefs.IsSiteBlacklisted(url.host()));
   EXPECT_TRUE(translate_prefs.CanTranslateLanguage(profile, "fr"));
 
@@ -1234,9 +1230,9 @@
   Profile* profile =
       Profile::FromBrowserContext(web_contents()->GetBrowserContext());
   TranslatePrefs translate_prefs(profile->GetPrefs());
-  translate_prefs.BlacklistLanguage("fr");
+  translate_prefs.BlockLanguage("fr");
   translate_prefs.BlacklistSite(url.host());
-  EXPECT_TRUE(translate_prefs.IsLanguageBlacklisted("fr"));
+  EXPECT_TRUE(translate_prefs.IsBlockedLanguage("fr"));
   EXPECT_TRUE(translate_prefs.IsSiteBlacklisted(url.host()));
 
   // Simulate navigating to a page in French. The translate menu should show but
@@ -1273,7 +1269,7 @@
   process()->sink().ClearMessages();
 
   // This should also have reverted the blacklisting of this site and language.
-  EXPECT_FALSE(translate_prefs.IsLanguageBlacklisted("fr"));
+  EXPECT_FALSE(translate_prefs.IsBlockedLanguage("fr"));
   EXPECT_FALSE(translate_prefs.IsSiteBlacklisted(url.host()));
 
   // Let's simulate the page being translated.
@@ -1413,7 +1409,7 @@
   }
   // Simulate the user pressing "Never translate French".
   infobar->NeverTranslatePageLanguage();
-  EXPECT_TRUE(translate_prefs.IsLanguageBlacklisted("de"));
+  EXPECT_TRUE(translate_prefs.IsBlockedLanguage("de"));
   // No translation should have occured and the infobar should be gone.
   EXPECT_FALSE(GetTranslateMessage(&page_id, &original_lang, &target_lang));
   process()->sink().ClearMessages();
diff --git a/chrome/browser/translate/translate_manager_unittest.cc b/chrome/browser/translate/translate_manager_unittest.cc
index 6b176a1..9073b3a 100644
--- a/chrome/browser/translate/translate_manager_unittest.cc
+++ b/chrome/browser/translate/translate_manager_unittest.cc
@@ -5,8 +5,8 @@
 #include "chrome/browser/translate/translate_manager.h"
 
 #include "content/public/common/url_constants.h"
-#include "googleurl/src/gurl.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
 
 #ifdef FILE_MANAGER_EXTENSION
 #include "chrome/browser/chromeos/extensions/file_manager/file_manager_util.h"
diff --git a/chrome/browser/translate/translate_prefs.cc b/chrome/browser/translate/translate_prefs.cc
index ccb2790..8ec9736 100644
--- a/chrome/browser/translate/translate_prefs.cc
+++ b/chrome/browser/translate/translate_prefs.cc
@@ -27,6 +27,25 @@
     "translate_denied_count";
 const char TranslatePrefs::kPrefTranslateAcceptedCount[] =
     "translate_accepted_count";
+const char TranslatePrefs::kPrefTranslateBlockedLanguages[] =
+    "translate_blocked_languages";
+
+namespace {
+
+void GetBlacklistedLanguages(const PrefService* prefs,
+                             std::vector<std::string>* languages) {
+  DCHECK(languages->empty());
+
+  const char* key = TranslatePrefs::kPrefTranslateLanguageBlacklist;
+  const ListValue* list = prefs->GetList(key);
+  for (ListValue::const_iterator it = list->begin(); it != list->end(); ++it) {
+    std::string lang;
+    (*it)->GetAsString(&lang);
+    languages->push_back(lang);
+  }
+}
+
+}  // namespace
 
 namespace {
 
@@ -58,21 +77,45 @@
     : prefs_(user_prefs) {
 }
 
-bool TranslatePrefs::IsLanguageBlacklisted(
+bool TranslatePrefs::IsBlockedLanguage(
     const std::string& original_language) const {
-  return IsValueBlacklisted(kPrefTranslateLanguageBlacklist, original_language);
-}
-
-void TranslatePrefs::BlacklistLanguage(const std::string& original_language) {
-  BlacklistValue(kPrefTranslateLanguageBlacklist, original_language);
   CommandLine* command_line = CommandLine::ForCurrentProcess();
-  if (command_line->HasSwitch(switches::kEnableTranslateSettings))
-    AppendLanguageToAcceptLanguages(prefs_, original_language);
+  if (command_line->HasSwitch(switches::kEnableTranslateSettings)) {
+    return IsValueBlacklisted(kPrefTranslateBlockedLanguages,
+                              original_language);
+  } else {
+    return IsValueBlacklisted(kPrefTranslateLanguageBlacklist,
+                              original_language);
+  }
 }
 
-void TranslatePrefs::RemoveLanguageFromBlacklist(
+void TranslatePrefs::BlockLanguage(
     const std::string& original_language) {
-  RemoveValueFromBlacklist(kPrefTranslateLanguageBlacklist, original_language);
+  CommandLine* command_line = CommandLine::ForCurrentProcess();
+  if (command_line->HasSwitch(switches::kEnableTranslateSettings)) {
+    BlacklistValue(kPrefTranslateBlockedLanguages, original_language);
+    AppendLanguageToAcceptLanguages(prefs_, original_language);
+  } else {
+    BlacklistValue(kPrefTranslateLanguageBlacklist, original_language);
+  }
+}
+
+void TranslatePrefs::UnblockLanguage(
+    const std::string& original_language) {
+  CommandLine* command_line = CommandLine::ForCurrentProcess();
+  if (command_line->HasSwitch(switches::kEnableTranslateSettings)) {
+    RemoveValueFromBlacklist(kPrefTranslateBlockedLanguages,
+                             original_language);
+  } else {
+    RemoveValueFromBlacklist(kPrefTranslateLanguageBlacklist,
+                             original_language);
+  }
+}
+
+void TranslatePrefs::RemoveLanguageFromLegacyBlacklist(
+    const std::string& original_language) {
+  RemoveValueFromBlacklist(kPrefTranslateLanguageBlacklist,
+                           original_language);
 }
 
 bool TranslatePrefs::IsSiteBlacklisted(const std::string& site) const {
@@ -125,11 +168,19 @@
 }
 
 bool TranslatePrefs::HasBlacklistedLanguages() const {
-  return !IsListEmpty(kPrefTranslateLanguageBlacklist);
+  CommandLine* command_line = CommandLine::ForCurrentProcess();
+  if (command_line->HasSwitch(switches::kEnableTranslateSettings))
+    return !IsListEmpty(kPrefTranslateBlockedLanguages);
+  else
+    return !IsListEmpty(kPrefTranslateLanguageBlacklist);
 }
 
 void TranslatePrefs::ClearBlacklistedLanguages() {
-  prefs_->ClearPref(kPrefTranslateLanguageBlacklist);
+  CommandLine* command_line = CommandLine::ForCurrentProcess();
+  if (command_line->HasSwitch(switches::kEnableTranslateSettings))
+    prefs_->ClearPref(kPrefTranslateBlockedLanguages);
+  else
+    prefs_->ClearPref(kPrefTranslateLanguageBlacklist);
 }
 
 bool TranslatePrefs::HasBlacklistedSites() const {
@@ -199,7 +250,7 @@
 bool TranslatePrefs::CanTranslateLanguage(Profile* profile,
                                           const std::string& language) {
   TranslatePrefs translate_prefs(profile->GetPrefs());
-  bool blacklisted = translate_prefs.IsLanguageBlacklisted(language);
+  bool blocked = translate_prefs.IsBlockedLanguage(language);
 
   CommandLine* command_line = CommandLine::ForCurrentProcess();
   if (command_line->HasSwitch(switches::kEnableTranslateSettings)) {
@@ -215,11 +266,11 @@
     // is also necessary because some minor languages can't be selected in the
     // language preference even though the language is available in Translate
     // server.
-    if (blacklisted && (is_accept_language || !can_be_accept_language))
+    if (blocked && (is_accept_language || !can_be_accept_language))
       return false;
   } else {
     // Don't translate any user user selected language.
-    if (blacklisted)
+    if (blocked)
       return false;
   }
 
@@ -249,6 +300,8 @@
   registry->RegisterDictionaryPref(
       kPrefTranslateAcceptedCount,
       user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
+  registry->RegisterListPref(kPrefTranslateBlockedLanguages,
+                             user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
 }
 
 // static
@@ -271,28 +324,113 @@
   //   keep auto-translated.
   DictionaryPrefUpdate update(user_prefs, kPrefTranslateWhitelists);
   DictionaryValue* dict = update.Get();
-  if (!dict || dict->empty())
-    return;
-  DictionaryValue::Iterator iter(*dict);
-  while (!iter.IsAtEnd()) {
-    const ListValue* list = NULL;
-    if (!iter.value().GetAsList(&list) || !list)
-      break;  // Dictionary has either been migrated or new format.
-    std::string key = iter.key();
-    // Advance the iterator before removing the current element.
-    iter.Advance();
-    std::string target_lang;
-    if (list->empty() || !list->GetString(list->GetSize() - 1, &target_lang) ||
-        target_lang.empty()) {
-      dict->Remove(key, NULL);
-    } else {
-      dict->SetString(key, target_lang);
+  if (dict && !dict->empty()) {
+    DictionaryValue::Iterator iter(*dict);
+    while (!iter.IsAtEnd()) {
+      const ListValue* list = NULL;
+      if (!iter.value().GetAsList(&list) || !list)
+        break;  // Dictionary has either been migrated or new format.
+      std::string key = iter.key();
+      // Advance the iterator before removing the current element.
+      iter.Advance();
+      std::string target_lang;
+      if (list->empty() ||
+          !list->GetString(list->GetSize() - 1, &target_lang) ||
+          target_lang.empty()) {
+        dict->Remove(key, NULL);
+      } else {
+        dict->SetString(key, target_lang);
+      }
     }
   }
+
+  // Get the union of the blacklist and the Accept languages, and set this to
+  // the new language set 'translate_blocked_languages'. This is used for the
+  // settings UI for Translate and configration to determine which langauage
+  // should be translated instead of the blacklist. The blacklist is no longer
+  // used after launching the settings UI.
+  // After that, Set 'translate_languages_not_translate' to Accept languages to
+  // enable settings for users.
+  bool merged = user_prefs->HasPrefPath(kPrefTranslateBlockedLanguages);
+
+  const CommandLine& command_line = *CommandLine::ForCurrentProcess();
+  bool enabled_translate_settings =
+      command_line.HasSwitch(switches::kEnableTranslateSettings);
+
+  if (!merged && enabled_translate_settings) {
+    std::vector<std::string> blacklisted_languages;
+    GetBlacklistedLanguages(user_prefs, &blacklisted_languages);
+
+    std::string accept_languages_str =
+        user_prefs->GetString(prefs::kAcceptLanguages);
+    std::vector<std::string> accept_languages;
+    base::SplitString(accept_languages_str, ',', &accept_languages);
+
+    std::vector<std::string> blocked_languages;
+    CreateBlockedLanguages(&blocked_languages,
+                           blacklisted_languages,
+                           accept_languages);
+
+    // Create the new preference kPrefTranslateBlockedLanguages.
+    {
+      ListValue* blocked_languages_list = new ListValue();
+      for (std::vector<std::string>::const_iterator it =
+               blocked_languages.begin();
+           it != blocked_languages.end(); ++it) {
+        blocked_languages_list->Append(new StringValue(*it));
+      }
+      ListPrefUpdate update(user_prefs, kPrefTranslateBlockedLanguages);
+      ListValue* list = update.Get();
+      DCHECK(list != NULL);
+      list->Swap(blocked_languages_list);
+    }
+
+    // Update kAcceptLanguages
+    for (std::vector<std::string>::const_iterator it =
+             blocked_languages.begin();
+         it != blocked_languages.end(); ++it) {
+      std::string lang = *it;
+      TranslateUtil::ToChromeLanguageSynonym(&lang);
+      bool not_found =
+          std::find(accept_languages.begin(), accept_languages.end(), lang) ==
+          accept_languages.end();
+      if (not_found)
+        accept_languages.push_back(lang);
+    }
+
+    std::string new_accept_languages_str = JoinString(accept_languages, ",");
+    user_prefs->SetString(prefs::kAcceptLanguages, new_accept_languages_str);
+  }
 }
 
 // TranslatePrefs: private: ----------------------------------------------------
 
+// static
+void TranslatePrefs::CreateBlockedLanguages(
+    std::vector<std::string>* blocked_languages,
+    const std::vector<std::string>& blacklisted_languages,
+    const std::vector<std::string>& accept_languages) {
+  DCHECK(blocked_languages->empty());
+
+  std::set<std::string> result;
+
+  for (std::vector<std::string>::const_iterator it =
+           blacklisted_languages.begin();
+       it != blacklisted_languages.end(); ++it) {
+    result.insert(*it);
+  }
+
+  for (std::vector<std::string>::const_iterator it = accept_languages.begin();
+       it != accept_languages.end(); ++it) {
+    std::string lang = *it;
+    TranslateUtil::ToTranslateLanguageSynonym(&lang);
+    result.insert(lang);
+  }
+
+  blocked_languages->insert(blocked_languages->begin(),
+                            result.begin(), result.end());
+}
+
 bool TranslatePrefs::IsValueInList(const ListValue* list,
     const std::string& in_value) const {
   for (size_t i = 0; i < list->GetSize(); ++i) {
diff --git a/chrome/browser/translate/translate_prefs.h b/chrome/browser/translate/translate_prefs.h
index d049b05..f1ce6d4 100644
--- a/chrome/browser/translate/translate_prefs.h
+++ b/chrome/browser/translate/translate_prefs.h
@@ -6,8 +6,10 @@
 #define CHROME_BROWSER_TRANSLATE_TRANSLATE_PREFS_H_
 
 #include <string>
+#include <vector>
 
-#include "googleurl/src/gurl.h"
+#include "base/gtest_prod_util.h"
+#include "url/gurl.h"
 
 class PrefService;
 class Profile;
@@ -28,12 +30,18 @@
   static const char kPrefTranslateWhitelists[];
   static const char kPrefTranslateDeniedCount[];
   static const char kPrefTranslateAcceptedCount[];
+  static const char kPrefTranslateBlockedLanguages[];
 
   explicit TranslatePrefs(PrefService* user_prefs);
 
-  bool IsLanguageBlacklisted(const std::string& original_language) const;
-  void BlacklistLanguage(const std::string& original_language);
-  void RemoveLanguageFromBlacklist(const std::string& original_language);
+  bool IsBlockedLanguage(const std::string& original_language) const;
+  void BlockLanguage(const std::string& original_language);
+  void UnblockLanguage(const std::string& original_language);
+
+  // Removes a language from the old blacklist. This method is for
+  // chrome://translate-internals/.  Don't use this if there is no special
+  // reason.
+  void RemoveLanguageFromLegacyBlacklist(const std::string& original_language);
 
   bool IsSiteBlacklisted(const std::string& site) const;
   void BlacklistSite(const std::string& site);
@@ -79,6 +87,15 @@
   static void MigrateUserPrefs(PrefService* user_prefs);
 
  private:
+  friend class TranslatePrefsTest;
+  FRIEND_TEST_ALL_PREFIXES(TranslatePrefsTest, CreateBlockedLanguages);
+
+  // Merges two language sets to migrate to the language setting UI.
+  static void CreateBlockedLanguages(
+      std::vector<std::string>* blocked_languages,
+      const std::vector<std::string>& blacklisted_languages,
+      const std::vector<std::string>& accept_languages);
+
   bool IsValueBlacklisted(const char* pref_id, const std::string& value) const;
   void BlacklistValue(const char* pref_id, const std::string& value);
   void RemoveValueFromBlacklist(const char* pref_id, const std::string& value);
diff --git a/chrome/browser/translate/translate_prefs_unittest.cc b/chrome/browser/translate/translate_prefs_unittest.cc
new file mode 100644
index 0000000..a09aa61
--- /dev/null
+++ b/chrome/browser/translate/translate_prefs_unittest.cc
@@ -0,0 +1,61 @@
+// 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/translate/translate_prefs.h"
+
+#include <algorithm>
+#include <string>
+#include <vector>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+class TranslatePrefsTest : public testing::Test {
+ public:
+  TranslatePrefsTest() {}
+  virtual ~TranslatePrefsTest() {}
+};
+
+TEST_F(TranslatePrefsTest, CreateBlockedLanguages) {
+  std::vector<std::string> blacklisted_languages;
+  blacklisted_languages.push_back("en");
+  blacklisted_languages.push_back("fr");
+  // Hebrew: synonym to 'he'
+  blacklisted_languages.push_back("iw");
+  // Haitian is not used as Accept-Language
+  blacklisted_languages.push_back("ht");
+
+  std::vector<std::string> accept_languages;
+  accept_languages.push_back("en");
+  accept_languages.push_back("ja");
+  // Filippino: synonym to 'tl'
+  accept_languages.push_back("fil");
+  // General Chinese is not used as Translate language, but not filtered
+  // when merging.
+  accept_languages.push_back("zh");
+
+  std::vector<std::string> blocked_languages;
+
+  TranslatePrefs::CreateBlockedLanguages(&blocked_languages,
+                                         blacklisted_languages,
+                                         accept_languages);
+
+  // The order of the elements cannot be determined.
+  std::vector<std::string> expected;
+  expected.push_back("en");
+  expected.push_back("fr");
+  expected.push_back("iw");
+  expected.push_back("ht");
+  expected.push_back("ja");
+  expected.push_back("tl");
+  expected.push_back("zh");
+
+  EXPECT_EQ(expected.size(), blocked_languages.size());
+  for (std::vector<std::string>::const_iterator it = expected.begin();
+       it != expected.end(); ++it) {
+    EXPECT_NE(blocked_languages.end(),
+              std::find(blocked_languages.begin(),
+                        blocked_languages.end(),
+                        *it));
+  }
+}
diff --git a/chrome/browser/translate/translate_script.cc b/chrome/browser/translate/translate_script.cc
new file mode 100644
index 0000000..41ebdd6
--- /dev/null
+++ b/chrome/browser/translate/translate_script.cc
@@ -0,0 +1,121 @@
+// 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/translate/translate_script.h"
+
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/logging.h"
+#include "base/message_loop.h"
+#include "base/strings/string_util.h"
+#include "chrome/browser/translate/translate_url_fetcher.h"
+#include "chrome/browser/translate/translate_url_util.h"
+#include "chrome/common/chrome_switches.h"
+#include "google_apis/google_api_keys.h"
+#include "grit/browser_resources.h"
+#include "net/base/escape.h"
+#include "net/base/url_util.h"
+#include "ui/base/resource/resource_bundle.h"
+
+namespace {
+
+const int kExpirationDelayDays = 1;
+
+const char kScriptURL[] =
+    "https://translate.google.com/translate_a/element.js";
+const char kRequestHeader[] = "Google-Translate-Element-Mode: library";
+const int kFetcherId = 0;
+
+// Used in kTranslateScriptURL to specify a callback function name.
+const char kCallbackQueryName[] = "cb";
+const char kCallbackQueryValue[] =
+    "cr.googleTranslate.onTranslateElementLoad";
+
+}  // namespace
+
+TranslateScript::TranslateScript()
+    : weak_method_factory_(this),
+      expiration_delay_(base::TimeDelta::FromDays(kExpirationDelayDays)) {
+}
+
+TranslateScript::~TranslateScript() {
+  weak_method_factory_.InvalidateWeakPtrs();
+}
+
+void TranslateScript::Request(const Callback& callback) {
+  if (fetcher_.get() != NULL) {
+    NOTREACHED();
+    return;
+  }
+
+  callback_ = callback;
+
+  GURL translate_script_url;
+  // Check if command-line contains an alternative URL for translate service.
+  const CommandLine& command_line = *CommandLine::ForCurrentProcess();
+  if (command_line.HasSwitch(switches::kTranslateScriptURL)) {
+    translate_script_url = GURL(
+        command_line.GetSwitchValueASCII(switches::kTranslateScriptURL));
+    if (!translate_script_url.is_valid() ||
+        !translate_script_url.query().empty()) {
+      LOG(WARNING) << "The following translate URL specified at the "
+                   << "command-line is invalid: "
+                   << translate_script_url.spec();
+      translate_script_url = GURL();
+    }
+  }
+
+  // Use default URL when command-line argument is not specified, or specified
+  // URL is invalid.
+  if (translate_script_url.is_empty())
+    translate_script_url = GURL(kScriptURL);
+
+  translate_script_url = net::AppendQueryParameter(
+      translate_script_url,
+      kCallbackQueryName,
+      kCallbackQueryValue);
+
+  translate_script_url =
+      TranslateURLUtil::AddHostLocaleToUrl(translate_script_url);
+  translate_script_url =
+      TranslateURLUtil::AddApiKeyToUrl(translate_script_url);
+
+  fetcher_.reset(new TranslateURLFetcher(kFetcherId));
+  fetcher_->set_extra_request_header(kRequestHeader);
+  fetcher_->Request(
+      translate_script_url,
+      base::Bind(&TranslateScript::OnScriptFetchComplete,
+                 base::Unretained(this)));
+}
+
+
+void TranslateScript::OnScriptFetchComplete(
+    int id, bool success, const std::string& data) {
+  DCHECK_EQ(kFetcherId, id);
+
+  scoped_ptr<const TranslateURLFetcher> delete_ptr(fetcher_.release());
+
+  if (success) {
+    base::StringPiece str = ResourceBundle::GetSharedInstance().
+        GetRawDataResource(IDR_TRANSLATE_JS);
+    DCHECK(data_.empty());
+    str.CopyToString(&data_);
+    std::string argument = "('";
+    std::string api_key = google_apis::GetAPIKey();
+    argument += net::EscapeQueryParamValue(api_key, true);
+    argument += "');\n";
+    data_ += argument + data;
+
+    // We'll expire the cached script after some time, to make sure long
+    // running browsers still get fixes that might get pushed with newer
+    // scripts.
+    base::MessageLoop::current()->PostDelayedTask(
+        FROM_HERE,
+        base::Bind(&TranslateScript::Clear,
+                   weak_method_factory_.GetWeakPtr()),
+        expiration_delay_);
+  }
+
+  callback_.Run(success, data);
+}
diff --git a/chrome/browser/translate/translate_script.h b/chrome/browser/translate/translate_script.h
new file mode 100644
index 0000000..5fe0f61
--- /dev/null
+++ b/chrome/browser/translate/translate_script.h
@@ -0,0 +1,66 @@
+// 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_TRANSLATE_TRANSLATE_SCRIPT_H_
+#define CHROME_BROWSER_TRANSLATE_TRANSLATE_SCRIPT_H_
+
+#include <string>
+
+#include "base/callback.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "base/time/time.h"
+
+class TranslateURLFetcher;
+
+class TranslateScript {
+ public:
+  typedef base::Callback<void(bool, const std::string&)> Callback;
+
+  TranslateScript();
+  virtual ~TranslateScript();
+
+  // Returns the feched the translate script.
+  const std::string& data() { return data_; }
+
+  // Used by unit-tests to override some defaults:
+  // Delay after which the translate script is fetched again from the
+  // translation server.
+  void set_expiration_delay(int delay_ms) {
+    expiration_delay_ = base::TimeDelta::FromMilliseconds(delay_ms);
+  }
+
+  // Clears the translate script, so it will be fetched next time we translate.
+  void Clear() { data_.clear(); }
+
+  // Fetches the JS translate script (the script that is injected in the page
+  // to translate it).
+  void Request(const Callback& callback);
+
+  // Returns true if this has a pending request.
+  bool HasPendingRequest() const { return fetcher_.get() != NULL; }
+
+ private:
+  // The callback when the script is fetched or a server error occured.
+  void OnScriptFetchComplete(int id, bool success, const std::string& data);
+
+  base::WeakPtrFactory<TranslateScript> weak_method_factory_;
+
+  // URL fetcher to fetch the translate script.
+  scoped_ptr<TranslateURLFetcher> fetcher_;
+
+  // The JS injected in the page to do the translation.
+  std::string data_;
+
+  // Delay after which the translate script is fetched again from the translate
+  // server.
+  base::TimeDelta expiration_delay_;
+
+  // The callback called when the server sends a response.
+  Callback callback_;
+
+  DISALLOW_COPY_AND_ASSIGN(TranslateScript);
+};
+
+#endif  // CHROME_BROWSER_TRANSLATE_TRANSLATE_SCRIPT_H_
diff --git a/chrome/browser/translate/translate_url_fetcher.cc b/chrome/browser/translate/translate_url_fetcher.cc
new file mode 100644
index 0000000..ba32046
--- /dev/null
+++ b/chrome/browser/translate/translate_url_fetcher.cc
@@ -0,0 +1,82 @@
+// 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/translate/translate_url_fetcher.h"
+
+#include "chrome/browser/browser_process.h"
+#include "net/base/load_flags.h"
+#include "net/http/http_status_code.h"
+#include "net/url_request/url_fetcher.h"
+#include "net/url_request/url_request_status.h"
+
+namespace {
+
+// Retry parameter for fetching.
+const int kMaxRetry = 16;
+
+}  // namespace
+
+TranslateURLFetcher::TranslateURLFetcher(int id)
+    : id_(id),
+      state_(IDLE),
+      retry_count_(0) {
+}
+
+TranslateURLFetcher::~TranslateURLFetcher() {
+}
+
+bool TranslateURLFetcher::Request(
+    const GURL& url,
+    const TranslateURLFetcher::Callback& callback) {
+  // This function is not supposed to be called before previous operaion is not
+  // finished.
+  if (state_ == REQUESTING) {
+    NOTREACHED();
+    return false;
+  }
+
+  if (retry_count_ >= kMaxRetry)
+    return false;
+  retry_count_++;
+
+  state_ = REQUESTING;
+  url_ = url;
+  callback_ = callback;
+
+  fetcher_.reset(net::URLFetcher::Create(
+      id_,
+      url_,
+      net::URLFetcher::GET,
+      this));
+  fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES |
+                         net::LOAD_DO_NOT_SAVE_COOKIES);
+  fetcher_->SetRequestContext(g_browser_process->system_request_context());
+  // Set retry parameter for HTTP status code 5xx. This doesn't work against
+  // 106 (net::ERR_INTERNET_DISCONNECTED) and so on.
+  // TranslateLanguageList handles network status, and implements retry.
+  fetcher_->SetMaxRetriesOn5xx(max_retry_on_5xx_);
+  if (!extra_request_header_.empty())
+    fetcher_->SetExtraRequestHeaders(extra_request_header_);
+
+  fetcher_->Start();
+
+  return true;
+}
+
+void TranslateURLFetcher::OnURLFetchComplete(const net::URLFetcher* source) {
+  DCHECK(fetcher_.get() == source);
+
+  std::string data;
+  if (source->GetStatus().status() == net::URLRequestStatus::SUCCESS &&
+      source->GetResponseCode() == net::HTTP_OK) {
+    state_ = COMPLETED;
+    source->GetResponseAsString(&data);
+  } else {
+    state_ = FAILED;
+  }
+
+  // Transfer URLFetcher's ownership before invoking a callback.
+  scoped_ptr<const net::URLFetcher> delete_ptr(fetcher_.release());
+  callback_.Run(id_, state_ == COMPLETED, data);
+}
diff --git a/chrome/browser/translate/translate_url_fetcher.h b/chrome/browser/translate/translate_url_fetcher.h
new file mode 100644
index 0000000..b7d8903
--- /dev/null
+++ b/chrome/browser/translate/translate_url_fetcher.h
@@ -0,0 +1,84 @@
+// 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_TRANSLATE_TRANSLATE_URL_FETCHER_H_
+#define CHROME_BROWSER_TRANSLATE_TRANSLATE_URL_FETCHER_H_
+
+#include "base/callback.h"
+#include "base/memory/scoped_ptr.h"
+#include "net/url_request/url_fetcher_delegate.h"
+#include "url/gurl.h"
+
+class TranslateURLFetcher : public net::URLFetcherDelegate {
+ public:
+  // Callback type for Request().
+  typedef base::Callback<void(int, bool, const std::string&)> Callback;
+
+  // Represents internal state if the fetch is completed successfully.
+  enum State {
+    IDLE,        // No fetch request was issued.
+    REQUESTING,  // A fetch request was issued, but not finished yet.
+    COMPLETED,   // The last fetch request was finished successfully.
+    FAILED,      // The last fetch request was finished with a failure.
+  };
+
+  explicit TranslateURLFetcher(int id);
+  virtual ~TranslateURLFetcher();
+
+  int max_retry_on_5xx() {
+    return max_retry_on_5xx_;
+  }
+  void set_max_retry_on_5xx(int count) {
+    max_retry_on_5xx_ = count;
+  }
+
+  const std::string& extra_request_header() {
+    return extra_request_header_;
+  }
+  void set_extra_request_header(const std::string& header) {
+    extra_request_header_ = header;
+  }
+
+  // Requests to |url|. |callback| will be invoked when the function returns
+  // true, and the request is finished asynchronously.
+  // Returns false if the previous request is not finished, or the request
+  // is omitted due to retry limitation.
+  bool Request(const GURL& url, const Callback& callback);
+
+  // Gets internal state.
+  State state() { return state_; }
+
+  // net::URLFetcherDelegate implementation:
+  virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE;
+
+ private:
+  // URL to send the request.
+  GURL url_;
+
+  // ID which is assigned to the URLFetcher.
+  const int id_;
+
+  // Internal state.
+  enum State state_;
+
+  // URLFetcher instance.
+  scoped_ptr<net::URLFetcher> fetcher_;
+
+  // Callback passed at Request(). It will be invoked when an asynchronous
+  // fetch operation is finished.
+  Callback callback_;
+
+  // Counts how many times did it try to fetch the language list.
+  int retry_count_;
+
+  // Max number how many times to retry on the server error
+  int max_retry_on_5xx_;
+
+  // An extra HTTP request header
+  std::string extra_request_header_;
+
+  DISALLOW_COPY_AND_ASSIGN(TranslateURLFetcher);
+};
+
+#endif  // CHROME_BROWSER_TRANSLATE_TRANSLATE_URL_FETCHER_H_
diff --git a/chrome/browser/translate/translate_url_util.h b/chrome/browser/translate/translate_url_util.h
index 716903e..9709c0c 100644
--- a/chrome/browser/translate/translate_url_util.h
+++ b/chrome/browser/translate/translate_url_util.h
@@ -5,7 +5,7 @@
 #ifndef CHROME_BROWSER_TRANSLATE_TRANSLATE_URL_UTIL_H_
 #define CHROME_BROWSER_TRANSLATE_TRANSLATE_URL_UTIL_H_
 
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 namespace TranslateURLUtil {
 
diff --git a/chrome/browser/ui/active_tab_tracker.h b/chrome/browser/ui/active_tab_tracker.h
index 9f69092..f58528c 100644
--- a/chrome/browser/ui/active_tab_tracker.h
+++ b/chrome/browser/ui/active_tab_tracker.h
@@ -7,8 +7,8 @@
 
 #include "base/logging.h"
 #include "base/memory/weak_ptr.h"
-#include "base/time.h"
-#include "base/timer.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
 #include "chrome/browser/idle.h"
 #include "chrome/browser/ui/browser_list_observer.h"
 #include "chrome/browser/ui/native_focus_tracker.h"
diff --git a/chrome/browser/ui/android/OWNERS b/chrome/browser/ui/android/OWNERS
index 3906ecc..04d1515 100644
--- a/chrome/browser/ui/android/OWNERS
+++ b/chrome/browser/ui/android/OWNERS
@@ -1,5 +1,4 @@
 aruslan@chromium.org
 bulach@chromium.org
-jcivelli@chromium.org
 tedchoc@chromium.org
 yfriedman@chromium.org
diff --git a/chrome/browser/ui/android/autofill/autofill_dialog_view_android.cc b/chrome/browser/ui/android/autofill/autofill_dialog_view_android.cc
index b5bd7f0..4b06e11 100644
--- a/chrome/browser/ui/android/autofill/autofill_dialog_view_android.cc
+++ b/chrome/browser/ui/android/autofill/autofill_dialog_view_android.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "chrome/browser/ui/android/autofill/autofill_dialog_view_android.h"
+
 #include "base/android/jni_android.h"
 #include "base/android/jni_array.h"
 #include "base/android/jni_string.h"
@@ -11,9 +12,9 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/ui/android/window_android_helper.h"
 #include "chrome/browser/ui/autofill/data_model_wrapper.h"
-#include "components/autofill/browser/autofill_profile.h"
-#include "components/autofill/browser/autofill_type.h"
-#include "components/autofill/browser/credit_card.h"
+#include "components/autofill/core/browser/autofill_profile.h"
+#include "components/autofill/core/browser/autofill_type.h"
+#include "components/autofill/core/browser/credit_card.h"
 #include "content/public/browser/web_contents.h"
 #include "grit/generated_resources.h"
 #include "jni/AutofillDialogGlue_jni.h"
@@ -134,6 +135,10 @@
   NOTIMPLEMENTED();
 }
 
+void AutofillDialogViewAndroid::UpdateAutocheckoutStepsArea() {
+  NOTIMPLEMENTED();
+}
+
 void AutofillDialogViewAndroid::UpdateSection(DialogSection section) {
   UpdateOrFillSectionToJava(section, true, UNKNOWN_TYPE);
 }
@@ -297,14 +302,6 @@
       controller_->LegalDocumentsText());
 }
 
-ScopedJavaLocalRef<jstring> AutofillDialogViewAndroid::GetProgressBarText(
-    JNIEnv* env,
-    jobject obj) {
-  return base::android::ConvertUTF16ToJavaString(
-      env,
-      controller_->ProgressBarText());
-}
-
 jboolean AutofillDialogViewAndroid::IsTheAddItem(
     JNIEnv* env,
     jobject obj,
diff --git a/chrome/browser/ui/android/autofill/autofill_dialog_view_android.h b/chrome/browser/ui/android/autofill/autofill_dialog_view_android.h
index 4b5b0d2..5a68739 100644
--- a/chrome/browser/ui/android/autofill/autofill_dialog_view_android.h
+++ b/chrome/browser/ui/android/autofill/autofill_dialog_view_android.h
@@ -29,6 +29,7 @@
   virtual void UpdateButtonStrip() OVERRIDE;
   virtual void UpdateDetailArea() OVERRIDE;
   virtual void UpdateForErrors() OVERRIDE;
+  virtual void UpdateAutocheckoutStepsArea() OVERRIDE;
   virtual void UpdateSection(DialogSection section) OVERRIDE;
   virtual void FillSection(DialogSection section,
                            const DetailInput& originating_input) OVERRIDE;
@@ -96,8 +97,6 @@
                                                                 jobject obj);
   base::android::ScopedJavaLocalRef<jstring> GetLegalDocumentsText(JNIEnv* env,
                                                                    jobject obj);
-  base::android::ScopedJavaLocalRef<jstring> GetProgressBarText(JNIEnv* env,
-                                                                jobject obj);
   jboolean IsTheAddItem(JNIEnv* env, jobject obj, jint section, jint index);
 
   static bool RegisterAutofillDialogViewAndroid(JNIEnv* env);
diff --git a/chrome/browser/ui/android/autofill/autofill_popup_view_android.cc b/chrome/browser/ui/android/autofill/autofill_popup_view_android.cc
index 6acc0c8..755947b 100644
--- a/chrome/browser/ui/android/autofill/autofill_popup_view_android.cc
+++ b/chrome/browser/ui/android/autofill/autofill_popup_view_android.cc
@@ -38,8 +38,6 @@
 }
 
 void AutofillPopupViewAndroid::Hide() {
-  AutofillPopupView::Hide();
-
   JNIEnv* env = base::android::AttachCurrentThread();
   Java_AutofillPopupGlue_hide(env, java_object_.obj());
   delete this;
diff --git a/chrome/browser/ui/app_list/app_context_menu.cc b/chrome/browser/ui/app_list/app_context_menu.cc
index 560117e..064516c 100644
--- a/chrome/browser/ui/app_list/app_context_menu.cc
+++ b/chrome/browser/ui/app_list/app_context_menu.cc
@@ -185,7 +185,7 @@
               IDS_APP_LIST_CONTEXT_MENU_PIN);
     }
 
-    if (controller_->CanShowCreateShortcutsDialog()) {
+    if (controller_->CanDoCreateShortcutsFlow(is_platform_app_)) {
       menu_model_->AddItemWithStringId(CREATE_SHORTCUTS,
                                        IDS_NEW_TAB_APP_CREATE_SHORTCUT);
     }
@@ -202,6 +202,12 @@
       if (!ash::Shell::IsForcedMaximizeMode())
 #endif
       {
+#if defined(OS_MACOSX)
+        // Mac does not support standalone web app browser windows or maximize.
+        menu_model_->AddCheckItemWithStringId(
+            LAUNCH_TYPE_FULLSCREEN,
+            IDS_APP_CONTEXT_MENU_OPEN_FULLSCREEN);
+#else
         menu_model_->AddCheckItemWithStringId(
             LAUNCH_TYPE_WINDOW,
             IDS_APP_CONTEXT_MENU_OPEN_WINDOW);
@@ -210,6 +216,7 @@
         menu_model_->AddCheckItemWithStringId(
             LAUNCH_TYPE_FULLSCREEN,
             IDS_APP_CONTEXT_MENU_OPEN_MAXIMIZED);
+#endif
       }
       menu_model_->AddSeparator(ui::NORMAL_SEPARATOR);
       menu_model_->AddItemWithStringId(OPTIONS, IDS_NEW_TAB_APP_OPTIONS);
@@ -346,7 +353,7 @@
     else
       controller_->PinApp(app_id_);
   } else if (command_id == CREATE_SHORTCUTS) {
-    controller_->ShowCreateShortcutsDialog(profile_, app_id_);
+    controller_->DoCreateShortcutsFlow(profile_, app_id_);
   } else if (command_id >= LAUNCH_TYPE_START &&
              command_id < LAUNCH_TYPE_LAST) {
     SetExtensionLaunchType(profile_,
diff --git a/chrome/browser/ui/app_list/app_list_controller_delegate.cc b/chrome/browser/ui/app_list/app_list_controller_delegate.cc
index dd747c6..23bff8d 100644
--- a/chrome/browser/ui/app_list/app_list_controller_delegate.cc
+++ b/chrome/browser/ui/app_list/app_list_controller_delegate.cc
@@ -27,7 +27,7 @@
 
 void AppListControllerDelegate::UnpinApp(const std::string& extension_id) {}
 
-void AppListControllerDelegate::ShowCreateShortcutsDialog(
+void AppListControllerDelegate::DoCreateShortcutsFlow(
     Profile* profile,
     const std::string& extension_id) {}
 
diff --git a/chrome/browser/ui/app_list/app_list_controller_delegate.h b/chrome/browser/ui/app_list/app_list_controller_delegate.h
index 0eb17cf..150d7c0 100644
--- a/chrome/browser/ui/app_list/app_list_controller_delegate.h
+++ b/chrome/browser/ui/app_list/app_list_controller_delegate.h
@@ -51,10 +51,10 @@
   virtual void OnShowExtensionPrompt() {}
   virtual void OnCloseExtensionPrompt() {}
 
-  // Whether the controller supports showing the Create Shortcuts dialog.
-  virtual bool CanShowCreateShortcutsDialog() = 0;
-  virtual void ShowCreateShortcutsDialog(Profile* profile,
-                                         const std::string& extension_id);
+  // Whether the controller supports a Create Shortcuts flow.
+  virtual bool CanDoCreateShortcutsFlow(bool is_platform_app) = 0;
+  virtual void DoCreateShortcutsFlow(Profile* profile,
+                                     const std::string& extension_id);
 
   // Handle the "create window" context menu items of Chrome App.
   // |incognito| is true to create an incognito window.
diff --git a/chrome/browser/ui/app_list/app_list_service.cc b/chrome/browser/ui/app_list/app_list_service.cc
index f02f45b..8ae72eb 100644
--- a/chrome/browser/ui/app_list/app_list_service.cc
+++ b/chrome/browser/ui/app_list/app_list_service.cc
@@ -9,7 +9,7 @@
 #include "base/prefs/pref_registry_simple.h"
 #include "base/process_info.h"
 #include "base/strings/string_number_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
 
@@ -24,7 +24,7 @@
   return base::Time::Now() - base::Time::FromInternalValue(remote_start_time);
 }
 
-}
+}  // namespace
 
 // static
 void AppListService::RegisterPrefs(PrefRegistrySimple* registry) {
@@ -41,8 +41,11 @@
   // The presence of kOriginalProcessStartTime implies that another process
   // has sent us its command line to handle, ie: we are already running.
   if (command_line.HasSwitch(switches::kOriginalProcessStartTime)) {
-     UMA_HISTOGRAM_LONG_TIMES("Startup.ShowAppListWarmStart",
-                              GetTimeFromOriginalProcessStart(command_line));
+    base::TimeDelta elapsed = GetTimeFromOriginalProcessStart(command_line);
+    if (command_line.HasSwitch(switches::kFastStart))
+      UMA_HISTOGRAM_LONG_TIMES("Startup.ShowAppListWarmStartFast", elapsed);
+    else
+      UMA_HISTOGRAM_LONG_TIMES("Startup.ShowAppListWarmStart", elapsed);
   } else {
     // base::CurrentProcessInfo::CreationTime() is only defined on win/mac.
 #if defined(OS_WIN) || defined(OS_MACOSX)
diff --git a/chrome/browser/ui/app_list/app_list_service_impl.cc b/chrome/browser/ui/app_list/app_list_service_impl.cc
index f04b303..c763cdd 100644
--- a/chrome/browser/ui/app_list/app_list_service_impl.cc
+++ b/chrome/browser/ui/app_list/app_list_service_impl.cc
@@ -6,7 +6,7 @@
 
 #include "base/metrics/histogram.h"
 #include "base/prefs/pref_service.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/common/chrome_constants.h"
diff --git a/chrome/browser/ui/app_list/app_list_service_impl.h b/chrome/browser/ui/app_list/app_list_service_impl.h
index 91909cc..01cace7 100644
--- a/chrome/browser/ui/app_list/app_list_service_impl.h
+++ b/chrome/browser/ui/app_list/app_list_service_impl.h
@@ -13,8 +13,8 @@
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_info_cache_observer.h"
+#include "chrome/browser/profiles/profile_loader.h"
 #include "chrome/browser/ui/app_list/app_list_service.h"
-#include "chrome/browser/ui/app_list/profile_loader.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
 
diff --git a/chrome/browser/ui/app_list/app_list_service_mac.mm b/chrome/browser/ui/app_list/app_list_service_mac.mm
index a22452b..2637424 100644
--- a/chrome/browser/ui/app_list/app_list_service_mac.mm
+++ b/chrome/browser/ui/app_list/app_list_service_mac.mm
@@ -2,20 +2,26 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <ApplicationServices/ApplicationServices.h>
+#import <Cocoa/Cocoa.h>
+
 #include "apps/app_shim/app_shim_handler_mac.h"
 #include "base/bind.h"
 #include "base/command_line.h"
 #include "base/file_util.h"
 #include "base/lazy_instance.h"
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "base/memory/singleton.h"
 #include "base/message_loop.h"
 #include "base/observer_list.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/extensions/extension_system.h"
 #include "chrome/browser/ui/app_list/app_list_controller_delegate.h"
 #include "chrome/browser/ui/app_list/app_list_service.h"
 #include "chrome/browser/ui/app_list/app_list_service_impl.h"
 #include "chrome/browser/ui/app_list/app_list_view_delegate.h"
 #include "chrome/browser/ui/extensions/application_launch.h"
+#include "chrome/browser/ui/web_applications/web_app_ui.h"
 #include "chrome/browser/web_applications/web_app.h"
 #include "chrome/browser/web_applications/web_app_mac.h"
 #include "chrome/common/chrome_switches.h"
@@ -64,7 +70,10 @@
   virtual bool OnShimLaunch(apps::AppShimHandler::Host* host,
                             apps::AppShimLaunchType launch_type) OVERRIDE;
   virtual void OnShimClose(apps::AppShimHandler::Host* host) OVERRIDE;
-  virtual void OnShimFocus(apps::AppShimHandler::Host* host) OVERRIDE;
+  virtual void OnShimFocus(apps::AppShimHandler::Host* host,
+                           apps::AppShimFocusType focus_type) OVERRIDE;
+  virtual void OnShimSetHidden(apps::AppShimHandler::Host* host,
+                               bool hidden) OVERRIDE;
   virtual void OnShimQuit(apps::AppShimHandler::Host* host) OVERRIDE;
 
  private:
@@ -72,7 +81,7 @@
 
   AppListServiceMac() {}
 
-  scoped_nsobject<AppListWindowController> window_controller_;
+  base::scoped_nsobject<AppListWindowController> window_controller_;
 
   // App shim hosts observing when the app list is dismissed. In normal user
   // usage there should only be one. However, it can't be guaranteed, so use
@@ -92,7 +101,9 @@
   virtual void DismissView() OVERRIDE;
   virtual gfx::NativeWindow GetAppListWindow() OVERRIDE;
   virtual bool CanPin() OVERRIDE;
-  virtual bool CanShowCreateShortcutsDialog() OVERRIDE;
+  virtual bool CanDoCreateShortcutsFlow(bool is_platform_app) OVERRIDE;
+  virtual void DoCreateShortcutsFlow(Profile* profile,
+                                     const std::string& extension_id) OVERRIDE;
   virtual void ActivateApp(Profile* profile,
                            const extensions::Extension* extension,
                            int event_flags) OVERRIDE;
@@ -155,7 +166,8 @@
 
   // TODO(tapted): Create a dock icon using chrome/browser/mac/dock.h .
   web_app::CreateShortcuts(shortcut_info,
-                           ShellIntegration::ShortcutLocations());
+                           ShellIntegration::ShortcutLocations(),
+                           web_app::ALLOW_DUPLICATE_SHORTCUTS);
 }
 
 // Check that there is an app list shim. If enabling and there is not, make one.
@@ -178,7 +190,14 @@
 
   // Sanity check because deleting things recursively is scary.
   CHECK(install_path.MatchesExtension(".app"));
-  file_util::Delete(install_path, true /* recursive */);
+  base::Delete(install_path, true /* recursive */);
+}
+
+void CreateShortcutsInDefaultLocation(
+    const ShellIntegration::ShortcutInfo& shortcut_info) {
+  web_app::CreateShortcuts(shortcut_info,
+                           ShellIntegration::ShortcutLocations(),
+                           web_app::ALLOW_DUPLICATE_SHORTCUTS);
 }
 
 AppListControllerDelegateCocoa::AppListControllerDelegateCocoa() {}
@@ -197,9 +216,23 @@
   return false;
 }
 
-bool AppListControllerDelegateCocoa::CanShowCreateShortcutsDialog() {
-  // TODO(tapted): Return true when create shortcuts menu is tested on mac.
-  return false;
+bool AppListControllerDelegateCocoa::CanDoCreateShortcutsFlow(
+    bool is_platform_app) {
+  return is_platform_app &&
+      CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableAppShims);
+}
+
+void AppListControllerDelegateCocoa::DoCreateShortcutsFlow(
+    Profile* profile, const std::string& extension_id) {
+  ExtensionService* service =
+      extensions::ExtensionSystem::Get(profile)->extension_service();
+  DCHECK(service);
+  const extensions::Extension* extension =
+      service->GetInstalledExtension(extension_id);
+  DCHECK(extension);
+
+  web_app::UpdateShortcutInfoAndIconForApp(
+      *extension, profile, base::Bind(&CreateShortcutsInDefaultLocation));
 }
 
 void AppListControllerDelegateCocoa::ActivateApp(
@@ -220,7 +253,7 @@
   // The Objective C objects might be released at some unknown point in the
   // future, so explicitly clear references to C++ objects.
   [[window_controller_ appListViewController]
-      setDelegate:scoped_ptr<app_list::AppListViewDelegate>(NULL)];
+      setDelegate:scoped_ptr<app_list::AppListViewDelegate>()];
 
   SetProfile(requested_profile);
   scoped_ptr<app_list::AppListViewDelegate> delegate(
@@ -304,10 +337,14 @@
   DismissAppList();
 }
 
-void AppListServiceMac::OnShimFocus(apps::AppShimHandler::Host* host) {
+void AppListServiceMac::OnShimFocus(apps::AppShimHandler::Host* host,
+                                    apps::AppShimFocusType focus_type) {
   DismissAppList();
 }
 
+void AppListServiceMac::OnShimSetHidden(apps::AppShimHandler::Host* host,
+                                        bool hidden) {}
+
 void AppListServiceMac::OnShimQuit(apps::AppShimHandler::Host* host) {
   DismissAppList();
 }
@@ -336,25 +373,52 @@
   return DockLocationOtherDisplay;
 }
 
+// If |work_area_edge| is too close to the |screen_edge| (e.g. autohide dock),
+// adjust |anchor| away from the edge by a constant amount to reduce overlap and
+// ensure the dock icon can still be clicked to dismiss the app list.
+int AdjustPointForDynamicDock(int anchor, int screen_edge, int work_area_edge) {
+  const int kAutohideDockThreshold = 10;
+  const int kExtraDistance = 50;  // A dock with 40 items is about this size.
+  if (abs(work_area_edge - screen_edge) > kAutohideDockThreshold)
+    return anchor;
+
+  return anchor +
+      (screen_edge < work_area_edge ? kExtraDistance : -kExtraDistance);
+}
+
 NSPoint GetAppListWindowOrigin(NSWindow* window) {
   gfx::Screen* const screen = gfx::Screen::GetScreenFor([window contentView]);
+  // Ensure y coordinates are flipped back into AppKit's coordinate system.
+  const CGFloat max_y = NSMaxY([[[NSScreen screens] objectAtIndex:0] frame]);
+  if (!CGCursorIsVisible()) {
+    // If Chrome is the active application, display on the same display as
+    // Chrome's keyWindow since this will catch activations triggered, e.g, via
+    // WebStore install. If another application is active, OSX doesn't provide a
+    // reliable way to get the display in use. Fall back to the primary display
+    // since it has the menu bar and is likely to be correct, e.g., for
+    // activations from Spotlight.
+    const gfx::NativeView key_view = [[NSApp keyWindow] contentView];
+    const gfx::Rect work_area = key_view && [NSApp isActive] ?
+        screen->GetDisplayNearestWindow(key_view).work_area() :
+        screen->GetPrimaryDisplay().work_area();
+    return NSMakePoint(work_area.x(), max_y - work_area.bottom());
+  }
+
   gfx::Point anchor = screen->GetCursorScreenPoint();
   const gfx::Display display = screen->GetDisplayNearestPoint(anchor);
   const DockLocation dock_location = DockLocationInDisplay(display);
   const gfx::Rect display_bounds = display.bounds();
 
-  // Ensure y coordinates are flipped back into AppKit's coordinate system.
-  const CGFloat max_y = NSMaxY([[[NSScreen screens] objectAtIndex:0] frame]);
   if (dock_location == DockLocationOtherDisplay) {
     // Just display at the bottom-left of the display the cursor is on.
-    return NSMakePoint(display_bounds.x(),
-                       max_y - display_bounds.bottom());
+    return NSMakePoint(display_bounds.x(), max_y - display_bounds.bottom());
   }
 
   // Anchor the center of the window in a region that prevents the window
   // showing outside of the work area.
   const NSSize window_size = [window frame].size;
-  gfx::Rect anchor_area = display.work_area();
+  const gfx::Rect work_area = display.work_area();
+  gfx::Rect anchor_area = work_area;
   anchor_area.Inset(window_size.width / 2, window_size.height / 2);
   anchor.SetToMax(anchor_area.origin());
   anchor.SetToMin(anchor_area.bottom_right());
@@ -362,13 +426,16 @@
   // Move anchor to the dock, keeping the other axis aligned with the cursor.
   switch (dock_location) {
     case DockLocationBottom:
-      anchor.set_y(anchor_area.bottom());
+      anchor.set_y(AdjustPointForDynamicDock(
+          anchor_area.bottom(), display_bounds.bottom(), work_area.bottom()));
       break;
     case DockLocationLeft:
-      anchor.set_x(anchor_area.x());
+      anchor.set_x(AdjustPointForDynamicDock(
+          anchor_area.x(), display_bounds.x(), work_area.x()));
       break;
     case DockLocationRight:
-      anchor.set_x(anchor_area.right());
+      anchor.set_x(AdjustPointForDynamicDock(
+          anchor_area.right(), display_bounds.right(), work_area.right()));
       break;
     default:
       NOTREACHED();
diff --git a/chrome/browser/ui/app_list/app_list_service_mac_browsertest.mm b/chrome/browser/ui/app_list/app_list_service_mac_browsertest.mm
index 8566af4..f198d2b 100644
--- a/chrome/browser/ui/app_list/app_list_service_mac_browsertest.mm
+++ b/chrome/browser/ui/app_list/app_list_service_mac_browsertest.mm
@@ -32,7 +32,8 @@
 
   void FocusShim() {
     DCHECK(running_);
-    AppShimHandler::GetForAppMode(app_mode::kAppListModeId)->OnShimFocus(this);
+    AppShimHandler::GetForAppMode(app_mode::kAppListModeId)->
+        OnShimFocus(this, apps::APP_SHIM_FOCUS_REOPEN);
   }
 
   void QuitShim() {
@@ -46,8 +47,9 @@
     ++close_count_;
     QuitShim();
   }
-  virtual Profile* GetProfile() const OVERRIDE {
-    return NULL;  // Currently unused in this test.
+  virtual base::FilePath GetProfilePath() const OVERRIDE {
+    NOTREACHED();  // Currently unused in this test.
+    return base::FilePath();
   }
   virtual std::string GetAppId() const OVERRIDE {
     return app_mode::kAppListModeId;
diff --git a/chrome/browser/ui/app_list/app_list_view_delegate.cc b/chrome/browser/ui/app_list/app_list_view_delegate.cc
index 4c24cb2..ee4769f 100644
--- a/chrome/browser/ui/app_list/app_list_view_delegate.cc
+++ b/chrome/browser/ui/app_list/app_list_view_delegate.cc
@@ -4,6 +4,8 @@
 
 #include "chrome/browser/ui/app_list/app_list_view_delegate.h"
 
+#include "base/callback.h"
+#include "base/files/file_path.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/feedback/feedback_util.h"
@@ -16,8 +18,11 @@
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/chrome_pages.h"
 #include "chrome/browser/ui/host_desktop.h"
+#include "chrome/browser/ui/web_applications/web_app_ui.h"
+#include "chrome/browser/web_applications/web_app.h"
 #include "chrome/common/extensions/extension_constants.h"
 #include "chrome/common/url_constants.h"
+#include "content/public/browser/browser_thread.h"
 #include "content/public/browser/page_navigator.h"
 #include "content/public/browser/user_metrics.h"
 
@@ -25,6 +30,27 @@
 #include "chrome/browser/ui/ash/app_list/app_sync_ui_state_watcher.h"
 #endif
 
+#if defined(OS_WIN)
+#include "chrome/browser/web_applications/web_app_win.h"
+#endif
+
+namespace {
+
+#if defined(OS_WIN)
+void CreateShortcutInWebAppDir(
+    const base::FilePath& app_data_dir,
+    base::Callback<void(const base::FilePath&)> callback,
+    const ShellIntegration::ShortcutInfo& info) {
+  content::BrowserThread::PostTaskAndReplyWithResult(
+      content::BrowserThread::FILE,
+      FROM_HERE,
+      base::Bind(web_app::CreateShortcutInWebAppDir, app_data_dir, info),
+      callback);
+}
+#endif
+
+}  // namespace
+
 AppListViewDelegate::AppListViewDelegate(AppListControllerDelegate* controller,
                                          Profile* profile)
     : controller_(controller),
@@ -68,6 +94,33 @@
   static_cast<ChromeAppListItem*>(item)->Activate(event_flags);
 }
 
+void AppListViewDelegate::GetShortcutPathForApp(
+    const std::string& app_id,
+    const base::Callback<void(const base::FilePath&)>& callback) {
+#if defined(OS_WIN)
+  ExtensionService* service = profile_->GetExtensionService();
+  DCHECK(service);
+  const extensions::Extension* extension =
+      service->GetInstalledExtension(app_id);
+  if (!extension) {
+    callback.Run(base::FilePath());
+    return;
+  }
+
+  base::FilePath app_data_dir(
+      web_app::GetWebAppDataDirectory(profile_->GetPath(),
+                                      extension->id(),
+                                      GURL()));
+
+  web_app::UpdateShortcutInfoAndIconForApp(
+      *extension,
+      profile_,
+      base::Bind(CreateShortcutInWebAppDir, app_data_dir, callback));
+#else
+  callback.Run(base::FilePath());
+#endif
+}
+
 void AppListViewDelegate::StartSearch() {
   if (search_controller_.get())
     search_controller_->Start();
diff --git a/chrome/browser/ui/app_list/app_list_view_delegate.h b/chrome/browser/ui/app_list/app_list_view_delegate.h
index d2803c0..0b5d121 100644
--- a/chrome/browser/ui/app_list/app_list_view_delegate.h
+++ b/chrome/browser/ui/app_list/app_list_view_delegate.h
@@ -8,6 +8,7 @@
 #include <string>
 
 #include "base/basictypes.h"
+#include "base/callback_forward.h"
 #include "base/compiler_specific.h"
 #include "base/memory/scoped_ptr.h"
 #include "ui/app_list/app_list_view_delegate.h"
@@ -20,6 +21,10 @@
 class SearchController;
 }
 
+namespace base {
+class FilePath;
+}
+
 namespace gfx {
 class ImageSkia;
 }
@@ -38,6 +43,9 @@
   // Overridden from app_list::AppListViewDelegate:
   virtual void SetModel(app_list::AppListModel* model) OVERRIDE;
   virtual app_list::SigninDelegate* GetSigninDelegate() OVERRIDE;
+  virtual void GetShortcutPathForApp(
+      const std::string& app_id,
+      const base::Callback<void(const base::FilePath&)>& callback) OVERRIDE;
   virtual void ActivateAppListItem(app_list::AppListItemModel* item,
                                    int event_flags) OVERRIDE;
   virtual void StartSearch() OVERRIDE;
diff --git a/chrome/browser/ui/app_list/chrome_signin_delegate.cc b/chrome/browser/ui/app_list/chrome_signin_delegate.cc
index a68db45..ed9639d 100644
--- a/chrome/browser/ui/app_list/chrome_signin_delegate.cc
+++ b/chrome/browser/ui/app_list/chrome_signin_delegate.cc
@@ -13,7 +13,7 @@
 #include "chrome/browser/ui/chrome_pages.h"
 #include "chrome/browser/ui/extensions/application_launch.h"
 #include "chrome/browser/ui/host_desktop.h"
-#include "chrome/browser/ui/webui/sync_promo/sync_promo_ui.h"
+#include "chrome/browser/ui/sync/sync_promo_ui.h"
 #include "chrome/common/extensions/extension_constants.h"
 #include "content/public/common/page_transition_types.h"
 #include "grit/chromium_strings.h"
diff --git a/chrome/browser/ui/app_list/profile_loader.cc b/chrome/browser/ui/app_list/profile_loader.cc
deleted file mode 100644
index 4654cf2..0000000
--- a/chrome/browser/ui/app_list/profile_loader.cc
+++ /dev/null
@@ -1,83 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ui/app_list/profile_loader.h"
-
-#include "base/bind.h"
-#include "base/files/file_path.h"
-#include "base/memory/weak_ptr.h"
-#include "chrome/browser/lifetime/application_lifetime.h"
-#include "chrome/browser/profiles/profile_manager.h"
-
-ProfileLoader::ProfileLoader(ProfileManager* profile_manager)
-  : profile_manager_(profile_manager),
-    profile_load_sequence_id_(0),
-    pending_profile_loads_(0),
-    weak_factory_(this) {
-}
-
-ProfileLoader::~ProfileLoader() {
-}
-
-bool ProfileLoader::AnyProfilesLoading() const {
-  return pending_profile_loads_ > 0;
-}
-
-void ProfileLoader::InvalidatePendingProfileLoads() {
-  profile_load_sequence_id_++;
-}
-
-void ProfileLoader::LoadProfileInvalidatingOtherLoads(
-    const base::FilePath& profile_file_path,
-    base::Callback<void(Profile*)> callback) {
-  Profile* profile = profile_manager_->GetProfileByPath(profile_file_path);
-  if (profile) {
-    callback.Run(profile);
-    return;
-  }
-
-  IncrementPendingProfileLoads();
-  profile_manager_->CreateProfileAsync(
-      profile_file_path,
-      base::Bind(&ProfileLoader::OnProfileLoaded,
-                 weak_factory_.GetWeakPtr(),
-                 profile_load_sequence_id_,
-                 callback),
-      string16(), string16(), false);
-}
-
-void ProfileLoader::OnProfileLoaded(int profile_load_sequence_id,
-                                    base::Callback<void(Profile*)> callback,
-                                    Profile* profile,
-                                    Profile::CreateStatus status) {
-  switch (status) {
-    case Profile::CREATE_STATUS_CREATED:
-      break;
-    case Profile::CREATE_STATUS_INITIALIZED:
-      if (profile_load_sequence_id == profile_load_sequence_id_)
-        callback.Run(profile);
-      DecrementPendingProfileLoads();
-      break;
-    case Profile::CREATE_STATUS_LOCAL_FAIL:
-    case Profile::CREATE_STATUS_REMOTE_FAIL:
-    case Profile::CREATE_STATUS_CANCELED:
-      DecrementPendingProfileLoads();
-      break;
-    case Profile::MAX_CREATE_STATUS:
-      NOTREACHED();
-      break;
-  }
-}
-
-void ProfileLoader::IncrementPendingProfileLoads() {
-  pending_profile_loads_++;
-  if (pending_profile_loads_ == 1)
-    chrome::StartKeepAlive();
-}
-
-void ProfileLoader::DecrementPendingProfileLoads() {
-  pending_profile_loads_--;
-  if (pending_profile_loads_ == 0)
-    chrome::EndKeepAlive();
-}
diff --git a/chrome/browser/ui/app_list/profile_loader.h b/chrome/browser/ui/app_list/profile_loader.h
deleted file mode 100644
index f2b12fd..0000000
--- a/chrome/browser/ui/app_list/profile_loader.h
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_APP_LIST_PROFILE_LOADER_H_
-#define CHROME_BROWSER_UI_APP_LIST_PROFILE_LOADER_H_
-
-#include "base/callback.h"
-#include "base/memory/weak_ptr.h"
-#include "chrome/browser/profiles/profile.h"
-
-namespace base {
-class FilePath;
-}
-
-class ProfileManager;
-
-class ProfileLoader {
- public:
-  explicit ProfileLoader(ProfileManager* profile_manager);
-  ~ProfileLoader();
-
-  bool AnyProfilesLoading() const;
-  void InvalidatePendingProfileLoads();
-  void LoadProfileInvalidatingOtherLoads(
-      const base::FilePath& profile_file_path,
-      base::Callback<void(Profile*)> callback);
-
- private:
-  void OnProfileLoaded(int profile_load_sequence_id,
-                       base::Callback<void(Profile*)> callback,
-                       Profile* profile,
-                       Profile::CreateStatus status);
-
-  void IncrementPendingProfileLoads();
-  void DecrementPendingProfileLoads();
-
- private:
-  ProfileManager* profile_manager_;
-  int profile_load_sequence_id_;
-  int pending_profile_loads_;
-
-  base::WeakPtrFactory<ProfileLoader> weak_factory_;
-
-  DISALLOW_COPY_AND_ASSIGN(ProfileLoader);
-};
-
-#endif  // CHROME_BROWSER_UI_APP_LIST_PROFILE_LOADER_H_
diff --git a/chrome/browser/ui/app_list/search/app_result.cc b/chrome/browser/ui/app_list/search/app_result.cc
index c7d3f58..9301f5d 100644
--- a/chrome/browser/ui/app_list/search/app_result.cc
+++ b/chrome/browser/ui/app_list/search/app_result.cc
@@ -84,6 +84,10 @@
   return copy.Pass();
 }
 
+ChromeSearchResultType AppResult::GetType() {
+  return APP_SEARCH_RESULT;
+}
+
 ui::MenuModel* AppResult::GetContextMenuModel() {
   if (!context_menu_) {
     context_menu_.reset(new AppContextMenu(
diff --git a/chrome/browser/ui/app_list/search/app_result.h b/chrome/browser/ui/app_list/search/app_result.h
index 5165b21..f270058 100644
--- a/chrome/browser/ui/app_list/search/app_result.h
+++ b/chrome/browser/ui/app_list/search/app_result.h
@@ -38,6 +38,7 @@
   virtual void InvokeAction(int action_index, int event_flags) OVERRIDE;
   virtual scoped_ptr<ChromeSearchResult> Duplicate() OVERRIDE;
   virtual ui::MenuModel* GetContextMenuModel() OVERRIDE;
+  virtual ChromeSearchResultType GetType() OVERRIDE;
 
  private:
   // extensions::IconImage::Observer overrides:
diff --git a/chrome/browser/ui/app_list/search/chrome_search_result.h b/chrome/browser/ui/app_list/search/chrome_search_result.h
index 26e2264..2c00607 100644
--- a/chrome/browser/ui/app_list/search/chrome_search_result.h
+++ b/chrome/browser/ui/app_list/search/chrome_search_result.h
@@ -12,6 +12,20 @@
 
 namespace app_list {
 
+// The type of the search result. This is used for logging so do not change the
+// order of this enum.
+enum ChromeSearchResultType {
+  // A result that forwards an omnibox search result.
+  OMNIBOX_SEARCH_RESULT,
+  // An app result.
+  APP_SEARCH_RESULT,
+  // A search result from the webstore.
+  WEBSTORE_SEARCH_RESULT,
+  // A result that opens a webstore search.
+  SEARCH_WEBSTORE_SEARCH_RESULT,
+  SEARCH_RESULT_TYPE_BOUNDARY
+};
+
 // Base class of all search results. It provides an additional interface
 // for SearchController to mix the results, duplicate a result from a
 // SearchProvider and pass it to UI and invoke actions on the results when
@@ -30,6 +44,8 @@
   // Creates a copy of the result.
   virtual scoped_ptr<ChromeSearchResult> Duplicate() = 0;
 
+  virtual ChromeSearchResultType GetType() = 0;
+
   const std::string& id() const { return id_; }
   double relevance() { return relevance_; }
 
diff --git a/chrome/browser/ui/app_list/search/history_data.h b/chrome/browser/ui/app_list/search/history_data.h
index 806da4f..f9d5bc5 100644
--- a/chrome/browser/ui/app_list/search/history_data.h
+++ b/chrome/browser/ui/app_list/search/history_data.h
@@ -13,7 +13,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/ui/app_list/search/history_types.h"
 
 namespace app_list {
diff --git a/chrome/browser/ui/app_list/search/history_unittest.cc b/chrome/browser/ui/app_list/search/history_unittest.cc
index c498118..e7e34a3 100644
--- a/chrome/browser/ui/app_list/search/history_unittest.cc
+++ b/chrome/browser/ui/app_list/search/history_unittest.cc
@@ -9,7 +9,7 @@
 #include "base/run_loop.h"
 #include "base/strings/stringprintf.h"
 #include "base/threading/platform_thread.h"
-#include "base/timer.h"
+#include "base/timer/timer.h"
 #include "chrome/browser/ui/app_list/search/history.h"
 #include "chrome/browser/ui/app_list/search/history_data.h"
 #include "chrome/browser/ui/app_list/search/history_data_observer.h"
diff --git a/chrome/browser/ui/app_list/search/mixer_unittest.cc b/chrome/browser/ui/app_list/search/mixer_unittest.cc
index 2a242e3..592d7c8 100644
--- a/chrome/browser/ui/app_list/search/mixer_unittest.cc
+++ b/chrome/browser/ui/app_list/search/mixer_unittest.cc
@@ -35,6 +35,9 @@
     return scoped_ptr<ChromeSearchResult>(
         new TestSearchResult(id(), relevance())).Pass();
   }
+  virtual ChromeSearchResultType GetType() OVERRIDE {
+    return SEARCH_RESULT_TYPE_BOUNDARY;
+  }
 
   DISALLOW_COPY_AND_ASSIGN(TestSearchResult);
 };
diff --git a/chrome/browser/ui/app_list/search/omnibox_provider.cc b/chrome/browser/ui/app_list/search/omnibox_provider.cc
index 50c470f..0869c20 100644
--- a/chrome/browser/ui/app_list/search/omnibox_provider.cc
+++ b/chrome/browser/ui/app_list/search/omnibox_provider.cc
@@ -92,6 +92,10 @@
         new OmniboxResult(profile_, match_)).Pass();
   }
 
+  virtual ChromeSearchResultType GetType() OVERRIDE {
+    return OMNIBOX_SEARCH_RESULT;
+  }
+
  private:
   void UpdateIcon() {
     int resource_id = match_.starred ?
diff --git a/chrome/browser/ui/app_list/search/search_controller.cc b/chrome/browser/ui/app_list/search/search_controller.cc
index f105398..b2cd7fb 100644
--- a/chrome/browser/ui/app_list/search/search_controller.cc
+++ b/chrome/browser/ui/app_list/search/search_controller.cc
@@ -10,6 +10,7 @@
 #include "base/bind.h"
 #include "base/command_line.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/metrics/histogram.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/profiles/profile.h"
@@ -27,6 +28,11 @@
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/resource/resource_bundle.h"
 
+namespace {
+  const char kAppListSearchResultOpenTypeHistogram[] =
+      "Apps.AppListSearchResultOpenType";
+}
+
 namespace app_list {
 
 SearchController::SearchController(Profile* profile,
@@ -57,7 +63,7 @@
   AddProvider(Mixer::OMNIBOX_GROUP, scoped_ptr<SearchProvider>(
       new OmniboxProvider(profile_)).Pass());
   AddProvider(Mixer::WEBSTORE_GROUP, scoped_ptr<SearchProvider>(
-      new WebstoreProvider(profile_)).Pass());
+      new WebstoreProvider(profile_, list_controller_)).Pass());
 }
 
 void SearchController::Start() {
@@ -100,6 +106,9 @@
 
   ChromeSearchResult* chrome_result =
       static_cast<app_list::ChromeSearchResult*>(result);
+  UMA_HISTOGRAM_ENUMERATION(kAppListSearchResultOpenTypeHistogram,
+                            chrome_result->GetType(),
+                            SEARCH_RESULT_TYPE_BOUNDARY);
   chrome_result->Open(event_flags);
 
   if (history_ && history_->IsReady()) {
diff --git a/chrome/browser/ui/app_list/search/search_controller.h b/chrome/browser/ui/app_list/search/search_controller.h
index fca4b61..cb4b922 100644
--- a/chrome/browser/ui/app_list/search/search_controller.h
+++ b/chrome/browser/ui/app_list/search/search_controller.h
@@ -8,7 +8,7 @@
 #include "base/basictypes.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/scoped_vector.h"
-#include "base/timer.h"
+#include "base/timer/timer.h"
 #include "chrome/browser/ui/app_list/search/mixer.h"
 #include "ui/app_list/app_list_model.h"
 
diff --git a/chrome/browser/ui/app_list/search/search_webstore_result.cc b/chrome/browser/ui/app_list/search/search_webstore_result.cc
index b38df4c..3c0a7c8 100644
--- a/chrome/browser/ui/app_list/search/search_webstore_result.cc
+++ b/chrome/browser/ui/app_list/search/search_webstore_result.cc
@@ -55,4 +55,8 @@
       new SearchWebstoreResult(profile_, query_)).Pass();
 }
 
+ChromeSearchResultType SearchWebstoreResult::GetType() {
+  return WEBSTORE_SEARCH_RESULT;
+}
+
 }  // namespace app_list
diff --git a/chrome/browser/ui/app_list/search/search_webstore_result.h b/chrome/browser/ui/app_list/search/search_webstore_result.h
index d577c75..4a0052e 100644
--- a/chrome/browser/ui/app_list/search/search_webstore_result.h
+++ b/chrome/browser/ui/app_list/search/search_webstore_result.h
@@ -25,6 +25,7 @@
   virtual void Open(int event_flags) OVERRIDE;
   virtual void InvokeAction(int action_index, int event_flags) OVERRIDE;
   virtual scoped_ptr<ChromeSearchResult> Duplicate() OVERRIDE;
+  virtual ChromeSearchResultType GetType() OVERRIDE;
 
  private:
   Profile* profile_;
diff --git a/chrome/browser/ui/app_list/search/webstore_installer.cc b/chrome/browser/ui/app_list/search/webstore_installer.cc
new file mode 100644
index 0000000..58c1ebb
--- /dev/null
+++ b/chrome/browser/ui/app_list/search/webstore_installer.cc
@@ -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.
+
+#include "chrome/browser/ui/app_list/search/webstore_installer.h"
+
+#include "chrome/browser/extensions/extension_install_prompt.h"
+#include "chrome/browser/ui/browser_finder.h"
+
+namespace app_list {
+
+WebstoreInstaller::WebstoreInstaller(const std::string& webstore_item_id,
+                                     Profile* profile,
+                                     gfx::NativeWindow parent_window,
+                                     const Callback& callback)
+    : WebstoreStartupInstaller(webstore_item_id, profile, true, callback),
+      profile_(profile),
+      parent_window_(parent_window) {}
+
+WebstoreInstaller::~WebstoreInstaller() {}
+
+scoped_ptr<ExtensionInstallPrompt> WebstoreInstaller::CreateInstallUI() {
+  return make_scoped_ptr(
+      new ExtensionInstallPrompt(profile_, parent_window_, this));
+}
+
+content::WebContents* WebstoreInstaller::OpenURL(
+    const content::OpenURLParams& params) {
+  Browser* browser = chrome::FindOrCreateTabbedBrowser(
+      profile_, chrome::GetActiveDesktop());
+  return browser->OpenURL(params);
+}
+
+}  // namespace app_list
diff --git a/chrome/browser/ui/app_list/search/webstore_installer.h b/chrome/browser/ui/app_list/search/webstore_installer.h
new file mode 100644
index 0000000..16363c6
--- /dev/null
+++ b/chrome/browser/ui/app_list/search/webstore_installer.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_UI_APP_LIST_SEARCH_WEBSTORE_INSTALLER_H_
+#define CHROME_BROWSER_UI_APP_LIST_SEARCH_WEBSTORE_INSTALLER_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "chrome/browser/extensions/webstore_startup_installer.h"
+#include "content/public/browser/page_navigator.h"
+
+class Profile;
+
+namespace app_list {
+
+// WebstoreInstaller handles install for web store search results.
+class WebstoreInstaller : public extensions::WebstoreStartupInstaller,
+                          public content::PageNavigator {
+ public:
+  typedef WebstoreStandaloneInstaller::Callback Callback;
+
+  WebstoreInstaller(const std::string& webstore_item_id,
+                    Profile* profile,
+                    gfx::NativeWindow parent_window,
+                    const Callback& callback);
+
+ private:
+  friend class base::RefCountedThreadSafe<WebstoreInstaller>;
+
+  virtual ~WebstoreInstaller();
+
+  // extensions::WebstoreStartupInstaller overrides:
+  virtual scoped_ptr<ExtensionInstallPrompt> CreateInstallUI() OVERRIDE;
+
+  // content::PageNavigator overrides:
+  virtual content::WebContents* OpenURL(
+      const content::OpenURLParams& params) OVERRIDE;
+
+  Profile* profile_;
+  gfx::NativeWindow parent_window_;
+
+  DISALLOW_COPY_AND_ASSIGN(WebstoreInstaller);
+};
+
+}  // namespace app_list
+
+#endif  // CHROME_BROWSER_UI_APP_LIST_SEARCH_WEBSTORE_INSTALLER_H_
diff --git a/chrome/browser/ui/app_list/search/webstore_provider.cc b/chrome/browser/ui/app_list/search/webstore_provider.cc
index 7f0cad1..16c2d30 100644
--- a/chrome/browser/ui/app_list/search/webstore_provider.cc
+++ b/chrome/browser/ui/app_list/search/webstore_provider.cc
@@ -28,7 +28,10 @@
 
 }  // namespace
 
-WebstoreProvider::WebstoreProvider(Profile* profile) : profile_(profile) {}
+WebstoreProvider::WebstoreProvider(Profile* profile,
+                                   AppListControllerDelegate* controller)
+  : profile_(profile),
+    controller_(controller) {}
 
 WebstoreProvider::~WebstoreProvider() {}
 
@@ -113,7 +116,8 @@
   if (!icon_url.is_valid())
     return result.Pass();
 
-  result.reset(new WebstoreResult(profile_, app_id, localized_name, icon_url));
+  result.reset(new WebstoreResult(
+      profile_, app_id, localized_name, icon_url, controller_));
   return result.Pass();
 }
 
diff --git a/chrome/browser/ui/app_list/search/webstore_provider.h b/chrome/browser/ui/app_list/search/webstore_provider.h
index cb0fba6..253111d 100644
--- a/chrome/browser/ui/app_list/search/webstore_provider.h
+++ b/chrome/browser/ui/app_list/search/webstore_provider.h
@@ -10,6 +10,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "chrome/browser/ui/app_list/search/search_provider.h"
 
+class AppListControllerDelegate;
 class Profile;
 
 namespace base {
@@ -30,7 +31,7 @@
 // return any results.
 class WebstoreProvider : public SearchProvider {
  public:
-  explicit WebstoreProvider(Profile* profile);
+  WebstoreProvider(Profile* profile, AppListControllerDelegate* controller);
   virtual ~WebstoreProvider();
 
   // SearchProvider overrides:
@@ -50,6 +51,7 @@
   }
 
   Profile* profile_;
+  AppListControllerDelegate* controller_;
   scoped_ptr<WebstoreSearchFetcher> webstore_search_;
   base::Closure webstore_search_fetched_callback_;
 
diff --git a/chrome/browser/ui/app_list/search/webstore_provider_browsertest.cc b/chrome/browser/ui/app_list/search/webstore_provider_browsertest.cc
index 9caf949..2399091 100644
--- a/chrome/browser/ui/app_list/search/webstore_provider_browsertest.cc
+++ b/chrome/browser/ui/app_list/search/webstore_provider_browsertest.cc
@@ -47,7 +47,7 @@
         switches::kAppsGalleryURL, test_server_->base_url().spec());
 
     webstore_provider_.reset(new WebstoreProvider(
-        ProfileManager::GetDefaultProfile()));
+        ProfileManager::GetDefaultProfile(), NULL));
     webstore_provider_->set_webstore_search_fetched_callback(
         base::Bind(&WebstoreProviderTest::OnSearchResultsFetched,
                    base::Unretained(this)));
@@ -98,11 +98,11 @@
 
     if (request.relative_url.find("/jsonsearch?") != std::string::npos) {
       if (mock_server_response_ == "404") {
-        response->set_code(net::test_server::NOT_FOUND);
+        response->set_code(net::HTTP_NOT_FOUND);
       } else if (mock_server_response_ == "500") {
-        response->set_code(net::test_server::ACCESS_DENIED);
+        response->set_code(net::HTTP_INTERNAL_SERVER_ERROR);
       } else {
-        response->set_code(net::test_server::SUCCESS);
+        response->set_code(net::HTTP_OK);
         response->set_content(mock_server_response_);
       }
     }
diff --git a/chrome/browser/ui/app_list/search/webstore_result.cc b/chrome/browser/ui/app_list/search/webstore_result.cc
index b7f55fc..1ceb310 100644
--- a/chrome/browser/ui/app_list/search/webstore_result.cc
+++ b/chrome/browser/ui/app_list/search/webstore_result.cc
@@ -7,11 +7,19 @@
 #include <vector>
 
 #include "base/bind.h"
+#include "base/memory/ref_counted.h"
 #include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/extensions/extension_system.h"
+#include "chrome/browser/extensions/install_tracker.h"
+#include "chrome/browser/extensions/install_tracker_factory.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/app_list/app_list_controller_delegate.h"
+#include "chrome/browser/ui/app_list/search/webstore_installer.h"
 #include "chrome/browser/ui/app_list/search/webstore_result_icon_source.h"
-#include "chrome/browser/ui/browser_navigator.h"
+#include "chrome/browser/ui/extensions/application_launch.h"
 #include "chrome/common/extensions/extension.h"
+#include "grit/chromium_strings.h"
 #include "grit/generated_resources.h"
 #include "ui/base/l10n/l10n_util.h"
 
@@ -20,18 +28,23 @@
 WebstoreResult::WebstoreResult(Profile* profile,
                                const std::string& app_id,
                                const std::string& localized_name,
-                               const GURL& icon_url)
+                               const GURL& icon_url,
+                               AppListControllerDelegate* controller)
     : profile_(profile),
       app_id_(app_id),
       localized_name_(localized_name),
       icon_url_(icon_url),
-      weak_factory_(this) {
+      weak_factory_(this),
+      controller_(controller),
+      install_tracker_(NULL) {
   set_id(extensions::Extension::GetBaseURLFromExtensionId(app_id_).spec());
   set_relevance(0.0);  // What is the right value to use?
 
   set_title(UTF8ToUTF16(localized_name_));
   SetDefaultDetails();
 
+  UpdateActions();
+
   const int kIconSize = 32;
   icon_ = gfx::ImageSkia(
       new WebstoreResultIconSource(
@@ -42,25 +55,50 @@
           kIconSize),
       gfx::Size(kIconSize, kIconSize));
   SetIcon(icon_);
+
+  StartObservingInstall();
 }
 
-WebstoreResult::~WebstoreResult() {}
+WebstoreResult::~WebstoreResult() {
+  StopObservingInstall();
+}
 
 void WebstoreResult::Open(int event_flags) {
-  const GURL store_url(extension_urls::GetWebstoreItemDetailURLPrefix() +
-                       app_id_);
-  chrome::NavigateParams params(profile_,
-                                store_url,
-                                content::PAGE_TRANSITION_LINK);
-  params.disposition = ui::DispositionFromEventFlags(event_flags);
-  chrome::Navigate(&params);
+  const extensions::Extension* extension =
+      extensions::ExtensionSystem::Get(profile_)->extension_service()
+          ->GetInstalledExtension(app_id_);
+  if (extension) {
+    controller_->ActivateApp(profile_, extension, event_flags);
+    return;
+  }
+
+  StartInstall();
 }
 
-void WebstoreResult::InvokeAction(int action_index, int event_flags) {}
+void WebstoreResult::InvokeAction(int action_index, int event_flags) {
+  DCHECK_EQ(0, action_index);
+  StartInstall();
+}
 
 scoped_ptr<ChromeSearchResult> WebstoreResult::Duplicate() {
-  return scoped_ptr<ChromeSearchResult>(
-      new WebstoreResult(profile_, app_id_, localized_name_, icon_url_)).Pass();
+  return scoped_ptr<ChromeSearchResult>(new WebstoreResult(
+      profile_, app_id_, localized_name_, icon_url_, controller_)).Pass();
+}
+
+void WebstoreResult::UpdateActions() {
+  Actions actions;
+
+  const bool is_otr = profile_->IsOffTheRecord();
+  const bool is_installed = !!extensions::ExtensionSystem::Get(profile_)->
+      extension_service()->GetInstalledExtension(app_id_);
+
+  if (!is_otr && !is_installed && !is_installing()) {
+    actions.push_back(Action(
+        l10n_util::GetStringUTF16(IDS_EXTENSION_INLINE_INSTALL_PROMPT_TITLE),
+        base::string16()));
+  }
+
+  SetActions(actions);
 }
 
 void WebstoreResult::SetDefaultDetails() {
@@ -83,4 +121,87 @@
   SetIcon(icon_);
 }
 
+void WebstoreResult::StartInstall() {
+  SetPercentDownloaded(0);
+  SetIsInstalling(true);
+
+  scoped_refptr<WebstoreInstaller> installer =
+      new WebstoreInstaller(
+          app_id_,
+          profile_,
+          controller_->GetAppListWindow(),
+          base::Bind(&WebstoreResult::InstallCallback,
+                     weak_factory_.GetWeakPtr()));
+  installer->BeginInstall();
+}
+
+void WebstoreResult::InstallCallback(bool success, const std::string& error) {
+  if (!success) {
+    LOG(ERROR) << "Failed to install app, error=" << error;
+    SetIsInstalling(false);
+    return;
+  }
+
+  // Success handling is continued in OnExtensionInstalled.
+  SetPercentDownloaded(100);
+}
+
+void WebstoreResult::StartObservingInstall() {
+  DCHECK(!install_tracker_);
+
+  install_tracker_ = extensions::InstallTrackerFactory::GetForProfile(profile_);
+  install_tracker_->AddObserver(this);
+}
+
+void WebstoreResult::StopObservingInstall() {
+  if (install_tracker_)
+    install_tracker_->RemoveObserver(this);
+
+  install_tracker_ = NULL;
+}
+
+void WebstoreResult::OnBeginExtensionInstall(
+    const std::string& extension_id,
+    const std::string& extension_name,
+    const gfx::ImageSkia& installing_icon,
+    bool is_app,
+    bool is_platform_app) {}
+
+void WebstoreResult::OnDownloadProgress(const std::string& extension_id,
+                                        int percent_downloaded) {
+  if (extension_id != app_id_ || percent_downloaded < 0)
+    return;
+
+  SetPercentDownloaded(percent_downloaded);
+}
+
+void WebstoreResult::OnInstallFailure(const std::string& extension_id) {}
+
+void WebstoreResult::OnExtensionInstalled(
+    const extensions::Extension* extension) {
+  if (extension->id() != app_id_)
+    return;
+
+  SetIsInstalling(false);
+  UpdateActions();
+}
+
+void WebstoreResult::OnExtensionUninstalled(
+    const extensions::Extension* extension) {}
+
+void WebstoreResult::OnExtensionDisabled(
+    const extensions::Extension* extension) {}
+
+void WebstoreResult::OnAppsReordered() {}
+
+void WebstoreResult::OnAppInstalledToAppList(const std::string& extension_id) {}
+
+void WebstoreResult::OnShutdown() {
+  StopObservingInstall();
+}
+
+ChromeSearchResultType WebstoreResult::GetType() {
+  return SEARCH_WEBSTORE_SEARCH_RESULT;
+}
+
 }  // namespace app_list
diff --git a/chrome/browser/ui/app_list/search/webstore_result.h b/chrome/browser/ui/app_list/search/webstore_result.h
index 9704a13..8743cd5 100644
--- a/chrome/browser/ui/app_list/search/webstore_result.h
+++ b/chrome/browser/ui/app_list/search/webstore_result.h
@@ -9,30 +9,66 @@
 
 #include "base/basictypes.h"
 #include "base/memory/weak_ptr.h"
+#include "chrome/browser/extensions/install_observer.h"
 #include "chrome/browser/ui/app_list/search/chrome_search_result.h"
 #include "googleurl/src/gurl.h"
 
+class AppListControllerDelegate;
 class Profile;
 
+namespace extensions {
+class InstallTracker;
+}
+
 namespace app_list {
 
-class WebstoreResult : public ChromeSearchResult {
+class WebstoreResult : public ChromeSearchResult,
+                       public extensions::InstallObserver {
  public:
   WebstoreResult(Profile* profile,
                  const std::string& app_id,
                  const std::string& localized_name,
-                 const GURL& icon_url);
+                 const GURL& icon_url,
+                 AppListControllerDelegate* controller);
   virtual ~WebstoreResult();
 
   // ChromeSearchResult overides:
   virtual void Open(int event_flags) OVERRIDE;
   virtual void InvokeAction(int action_index, int event_flags) OVERRIDE;
   virtual scoped_ptr<ChromeSearchResult> Duplicate() OVERRIDE;
+  virtual ChromeSearchResultType GetType() OVERRIDE;
 
  private:
+  void UpdateActions();
   void SetDefaultDetails();
   void OnIconLoaded();
 
+  void StartInstall();
+  void InstallCallback(bool success, const std::string& error);
+
+  void StartObservingInstall();
+  void StopObservingInstall();
+
+  // extensions::InstallObserver overrides:
+  virtual void OnBeginExtensionInstall(const std::string& extension_id,
+                                       const std::string& extension_name,
+                                       const gfx::ImageSkia& installing_icon,
+                                       bool is_app,
+                                       bool is_platform_app) OVERRIDE;
+  virtual void OnDownloadProgress(const std::string& extension_id,
+                                  int percent_downloaded) OVERRIDE;
+  virtual void OnInstallFailure(const std::string& extension_id) OVERRIDE;
+  virtual void OnExtensionInstalled(
+      const extensions::Extension* extension) OVERRIDE;
+  virtual void OnExtensionUninstalled(
+      const extensions::Extension* extension) OVERRIDE;
+  virtual void OnExtensionDisabled(
+      const extensions::Extension* extension) OVERRIDE;
+  virtual void OnAppsReordered() OVERRIDE;
+  virtual void OnAppInstalledToAppList(
+      const std::string& extension_id) OVERRIDE;
+  virtual void OnShutdown() OVERRIDE;
+
   Profile* profile_;
   const std::string app_id_;
   const std::string localized_name_;
@@ -41,6 +77,9 @@
   gfx::ImageSkia icon_;
   base::WeakPtrFactory<WebstoreResult> weak_factory_;
 
+  AppListControllerDelegate* controller_;
+  extensions::InstallTracker* install_tracker_;  // Not owned.
+
   DISALLOW_COPY_AND_ASSIGN(WebstoreResult);
 };
 
diff --git a/chrome/browser/ui/app_modal_dialogs/javascript_app_modal_dialog.h b/chrome/browser/ui/app_modal_dialogs/javascript_app_modal_dialog.h
index 7ce8ac1..38153fc 100644
--- a/chrome/browser/ui/app_modal_dialogs/javascript_app_modal_dialog.h
+++ b/chrome/browser/ui/app_modal_dialogs/javascript_app_modal_dialog.h
@@ -9,7 +9,7 @@
 
 #include "base/basictypes.h"
 #include "base/compiler_specific.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/ui/app_modal_dialogs/app_modal_dialog.h"
 #include "content/public/browser/javascript_dialog_manager.h"
 
diff --git a/chrome/browser/ui/apps/chrome_shell_window_delegate.cc b/chrome/browser/ui/apps/chrome_shell_window_delegate.cc
new file mode 100644
index 0000000..255c416
--- /dev/null
+++ b/chrome/browser/ui/apps/chrome_shell_window_delegate.cc
@@ -0,0 +1,153 @@
+// 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/ui/apps/chrome_shell_window_delegate.h"
+
+#include "base/strings/stringprintf.h"
+#include "chrome/browser/favicon/favicon_tab_helper.h"
+#include "chrome/browser/file_select_helper.h"
+#include "chrome/browser/media/media_capture_devices_dispatcher.h"
+#include "chrome/browser/platform_util.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_dialogs.h"
+#include "chrome/browser/ui/browser_finder.h"
+#include "chrome/browser/ui/browser_tabstrip.h"
+#include "chrome/browser/ui/browser_window.h"
+#include "chrome/common/render_messages.h"
+#include "content/public/browser/render_view_host.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_view.h"
+
+#if defined(USE_ASH)
+#include "ash/launcher/launcher_types.h"
+#endif
+
+namespace chrome {
+
+namespace {
+
+bool disable_external_open_for_testing_ = false;
+
+class ShellWindowLinkDelegate : public content::WebContentsDelegate {
+ public:
+  ShellWindowLinkDelegate();
+
+ private:
+  virtual content::WebContents* OpenURLFromTab(
+      content::WebContents* source,
+      const content::OpenURLParams& params) OVERRIDE;
+
+  DISALLOW_COPY_AND_ASSIGN(ShellWindowLinkDelegate);
+};
+
+ShellWindowLinkDelegate::ShellWindowLinkDelegate() {}
+
+// TODO(rockot): Add a test that exercises this code. See
+// http://crbug.com/254260.
+content::WebContents* ShellWindowLinkDelegate::OpenURLFromTab(
+    content::WebContents* source,
+    const content::OpenURLParams& params) {
+  platform_util::OpenExternal(params.url);
+  delete source;
+  return NULL;
+}
+
+}  // namespace
+
+ChromeShellWindowDelegate::ChromeShellWindowDelegate() {}
+
+ChromeShellWindowDelegate::~ChromeShellWindowDelegate() {}
+
+void ChromeShellWindowDelegate::DisableExternalOpenForTesting() {
+  disable_external_open_for_testing_ = true;
+}
+
+void ChromeShellWindowDelegate::InitWebContents(
+    content::WebContents* web_contents) {
+  FaviconTabHelper::CreateForWebContents(web_contents);
+}
+
+content::WebContents* ChromeShellWindowDelegate::OpenURLFromTab(
+    Profile* profile,
+    content::WebContents* source,
+    const content::OpenURLParams& params) {
+  // Force all links to open in a new tab, even if they were trying to open a
+  // window.
+  chrome::NavigateParams new_tab_params(
+      static_cast<Browser*>(NULL), params.url, params.transition);
+  new_tab_params.disposition = params.disposition == NEW_BACKGROUND_TAB ?
+      params.disposition : NEW_FOREGROUND_TAB;
+  new_tab_params.initiating_profile = profile;
+  chrome::Navigate(&new_tab_params);
+
+  return new_tab_params.target_contents;
+}
+
+void ChromeShellWindowDelegate::AddNewContents(
+    Profile* profile,
+    content::WebContents* new_contents,
+    WindowOpenDisposition disposition,
+    const gfx::Rect& initial_pos,
+    bool user_gesture,
+    bool* was_blocked) {
+  if (!disable_external_open_for_testing_) {
+    new_contents->SetDelegate(new ShellWindowLinkDelegate());
+    return;
+  }
+  Browser* browser =
+      chrome::FindOrCreateTabbedBrowser(profile, chrome::GetActiveDesktop());
+  // Force all links to open in a new tab, even if they were trying to open a
+  // new window.
+  disposition =
+      disposition == NEW_BACKGROUND_TAB ? disposition : NEW_FOREGROUND_TAB;
+  chrome::AddWebContents(browser, NULL, new_contents, disposition, initial_pos,
+                         user_gesture, was_blocked);
+}
+
+content::ColorChooser* ChromeShellWindowDelegate::ShowColorChooser(
+    content::WebContents* web_contents,
+    SkColor initial_color) {
+  return chrome::ShowColorChooser(web_contents, initial_color);
+}
+
+void ChromeShellWindowDelegate::RunFileChooser(
+    content::WebContents* tab,
+    const content::FileChooserParams& params) {
+  FileSelectHelper::RunFileChooser(tab, params);
+}
+
+void ChromeShellWindowDelegate::RequestMediaAccessPermission(
+      content::WebContents* web_contents,
+      const content::MediaStreamRequest& request,
+      const content::MediaResponseCallback& callback,
+      const extensions::Extension* extension) {
+  MediaCaptureDevicesDispatcher::GetInstance()->ProcessMediaAccessRequest(
+      web_contents, request, callback, extension);
+}
+
+int ChromeShellWindowDelegate::PreferredIconSize() {
+#if defined(USE_ASH)
+  return ash::kLauncherPreferredSize;
+#else
+  return extension_misc::EXTENSION_ICON_SMALL;
+#endif
+}
+
+void ChromeShellWindowDelegate::SetWebContentsBlocked(
+    content::WebContents* web_contents,
+    bool blocked) {
+  // RenderViewHost may be NULL during shutdown.
+  content::RenderViewHost* host = web_contents->GetRenderViewHost();
+  if (host) {
+    host->Send(new ChromeViewMsg_SetVisuallyDeemphasized(
+        host->GetRoutingID(), blocked));
+  }
+}
+
+bool ChromeShellWindowDelegate::IsWebContentsVisible(
+    content::WebContents* web_contents) {
+  return platform_util::IsVisible(web_contents->GetView()->GetNativeView());
+}
+
+}  // namespace chrome
diff --git a/chrome/browser/ui/apps/chrome_shell_window_delegate.h b/chrome/browser/ui/apps/chrome_shell_window_delegate.h
new file mode 100644
index 0000000..4bad8b2
--- /dev/null
+++ b/chrome/browser/ui/apps/chrome_shell_window_delegate.h
@@ -0,0 +1,59 @@
+// 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_UI_APPS_CHROME_SHELL_WINDOW_DELEGATE_H_
+#define CHROME_BROWSER_UI_APPS_CHROME_SHELL_WINDOW_DELEGATE_H_
+
+#include "apps/shell_window.h"
+#include "chrome/browser/profiles/profile.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_delegate.h"
+#include "ui/base/window_open_disposition.h"
+#include "ui/gfx/rect.h"
+
+namespace chrome {
+
+class ChromeShellWindowDelegate : public apps::ShellWindow::Delegate {
+ public:
+  ChromeShellWindowDelegate();
+  virtual ~ChromeShellWindowDelegate();
+
+  static void DisableExternalOpenForTesting();
+
+ private:
+  // apps::ShellWindow::Delegate:
+  virtual void InitWebContents(content::WebContents* web_contents) OVERRIDE;
+  virtual content::WebContents* OpenURLFromTab(
+      Profile* profile,
+      content::WebContents* source,
+      const content::OpenURLParams& params) OVERRIDE;
+  virtual void AddNewContents(Profile* profile,
+                              content::WebContents* new_contents,
+                              WindowOpenDisposition disposition,
+                              const gfx::Rect& initial_pos,
+                              bool user_gesture,
+                              bool* was_blocked) OVERRIDE;
+  virtual content::ColorChooser* ShowColorChooser(
+      content::WebContents* web_contents,
+      SkColor initial_color) OVERRIDE;
+  virtual void RunFileChooser(
+      content::WebContents* tab,
+      const content::FileChooserParams& params) OVERRIDE;
+  virtual void RequestMediaAccessPermission(
+      content::WebContents* web_contents,
+      const content::MediaStreamRequest& request,
+      const content::MediaResponseCallback& callback,
+      const extensions::Extension* extension) OVERRIDE;
+  virtual int PreferredIconSize() OVERRIDE;
+  virtual void SetWebContentsBlocked(content::WebContents* web_contents,
+                                     bool blocked) OVERRIDE;
+  virtual bool IsWebContentsVisible(
+      content::WebContents* web_contents) OVERRIDE;
+
+  DISALLOW_COPY_AND_ASSIGN(ChromeShellWindowDelegate);
+};
+
+}  // namespace chrome
+
+#endif  // CHROME_BROWSER_UI_APPS_CHROME_SHELL_WINDOW_DELEGATE_H_
diff --git a/chrome/browser/ui/ash/app_list/app_list_controller_ash.cc b/chrome/browser/ui/ash/app_list/app_list_controller_ash.cc
index a51a71a..7bf0587 100644
--- a/chrome/browser/ui/ash/app_list/app_list_controller_ash.cc
+++ b/chrome/browser/ui/ash/app_list/app_list_controller_ash.cc
@@ -39,7 +39,8 @@
   return ChromeLauncherController::instance()->CanPin();
 }
 
-bool AppListControllerDelegateAsh::CanShowCreateShortcutsDialog() {
+bool AppListControllerDelegateAsh::CanDoCreateShortcutsFlow(
+    bool is_platform_app) {
   return false;
 }
 
diff --git a/chrome/browser/ui/ash/app_list/app_list_controller_ash.h b/chrome/browser/ui/ash/app_list/app_list_controller_ash.h
index ad865f9..8df10a0 100644
--- a/chrome/browser/ui/ash/app_list/app_list_controller_ash.h
+++ b/chrome/browser/ui/ash/app_list/app_list_controller_ash.h
@@ -22,7 +22,7 @@
   virtual void PinApp(const std::string& extension_id) OVERRIDE;
   virtual void UnpinApp(const std::string& extension_id) OVERRIDE;
   virtual bool CanPin() OVERRIDE;
-  virtual bool CanShowCreateShortcutsDialog() OVERRIDE;
+  virtual bool CanDoCreateShortcutsFlow(bool is_platform_app) OVERRIDE;
   virtual void CreateNewWindow(Profile* profile, bool incognito) OVERRIDE;
   virtual void ActivateApp(Profile* profile,
                            const extensions::Extension* extension,
diff --git a/chrome/browser/ui/ash/app_sync_ui_state.h b/chrome/browser/ui/ash/app_sync_ui_state.h
index adad96a..55dc6c2 100644
--- a/chrome/browser/ui/ash/app_sync_ui_state.h
+++ b/chrome/browser/ui/ash/app_sync_ui_state.h
@@ -8,7 +8,7 @@
 #include "base/basictypes.h"
 #include "base/compiler_specific.h"
 #include "base/observer_list.h"
-#include "base/timer.h"
+#include "base/timer/timer.h"
 #include "chrome/browser/sync/profile_sync_service_observer.h"
 #include "components/browser_context_keyed_service/browser_context_keyed_service.h"
 #include "content/public/browser/notification_observer.h"
diff --git a/chrome/browser/ui/ash/chrome_shell_delegate.cc b/chrome/browser/ui/ash/chrome_shell_delegate.cc
index 5b7cecc..c285804 100644
--- a/chrome/browser/ui/ash/chrome_shell_delegate.cc
+++ b/chrome/browser/ui/ash/chrome_shell_delegate.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/ui/ash/chrome_shell_delegate.h"
 
+#include "apps/shell_window.h"
 #include "ash/ash_switches.h"
 #include "ash/host/root_window_host_factory.h"
 #include "ash/launcher/launcher_types.h"
@@ -36,7 +37,6 @@
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/extensions/native_app_window.h"
-#include "chrome/browser/ui/extensions/shell_window.h"
 #include "chrome/browser/ui/host_desktop.h"
 #include "chrome/browser/ui/immersive_fullscreen_configuration.h"
 #include "chrome/common/chrome_notification_types.h"
@@ -159,17 +159,36 @@
   bool is_fullscreen = ash::wm::IsWindowFullscreen(window);
 
   // Windows which cannot be maximized should not be fullscreened.
-  if (is_fullscreen && !ash::wm::CanMaximizeWindow(window))
+  if (!is_fullscreen && !ash::wm::CanMaximizeWindow(window))
     return;
 
   Browser* browser = chrome::FindBrowserWithWindow(window);
   if (browser) {
-    chrome::ToggleFullscreenMode(browser);
+    // If a window is fullscreen, exit fullscreen.
+    if (is_fullscreen) {
+      chrome::ToggleFullscreenMode(browser);
+      return;
+    }
+
+    // AppNonClientFrameViewAsh shows only the window controls and no other
+    // window decorations which is pretty close to fullscreen. Put v1 apps
+    // into maximized mode instead of fullscreen to avoid showing the ugly
+    // fullscreen exit bubble.
+#if defined(OS_WIN)
+    if (browser->host_desktop_type() == chrome::HOST_DESKTOP_TYPE_NATIVE) {
+      chrome::ToggleFullscreenMode(browser);
+      return;
+    }
+#endif  // OS_WIN
+    if (browser->is_app() && browser->app_type() != Browser::APP_TYPE_CHILD)
+      ash::wm::ToggleMaximizedWindow(window);
+    else
+      chrome::ToggleFullscreenMode(browser);
     return;
   }
 
   // |window| may belong to a shell window.
-  ShellWindow* shell_window = extensions::ShellWindowRegistry::
+  apps::ShellWindow* shell_window = extensions::ShellWindowRegistry::
       GetShellWindowForNativeWindowAnyProfile(window);
   if (shell_window) {
     if (is_fullscreen)
@@ -185,13 +204,6 @@
   if (!window)
     return;
 
-  // TODO(pkotwicz): If immersive mode replaces fullscreen, bind fullscreen to
-  // F4 and find a different key binding for maximize.
-  if (ImmersiveFullscreenConfiguration::UseImmersiveFullscreen()) {
-    ToggleFullscreen();
-    return;
-  }
-
   // Get out of fullscreen when in fullscreen mode.
   if (ash::wm::IsWindowFullscreen(window)) {
     ToggleFullscreen();
@@ -226,7 +238,7 @@
 }
 
 void ChromeShellDelegate::ShowTaskManager() {
-  chrome::OpenTaskManager(NULL, false);
+  chrome::OpenTaskManager(NULL);
 }
 
 content::BrowserContext* ChromeShellDelegate::GetCurrentBrowserContext() {
@@ -244,10 +256,7 @@
 
 ash::LauncherDelegate* ChromeShellDelegate::CreateLauncherDelegate(
     ash::LauncherModel* model) {
-  // Defer Launcher creation until DefaultProfile is created.
-  if (!ProfileManager::IsGetDefaultProfileAllowed())
-    return NULL;
-
+  DCHECK(ProfileManager::IsGetDefaultProfileAllowed());
   // TODO(oshima): This is currently broken with multiple launchers.
   // Refactor so that there is just one launcher delegate in the
   // shell.
diff --git a/chrome/browser/ui/ash/chrome_shell_delegate_browsertest.cc b/chrome/browser/ui/ash/chrome_shell_delegate_browsertest.cc
index 938d3f5..66a8927 100644
--- a/chrome/browser/ui/ash/chrome_shell_delegate_browsertest.cc
+++ b/chrome/browser/ui/ash/chrome_shell_delegate_browsertest.cc
@@ -4,16 +4,38 @@
 
 #include "chrome/browser/ui/ash/chrome_shell_delegate.h"
 
+#include "apps/shell_window.h"
 #include "ash/ash_switches.h"
 #include "ash/shell.h"
 #include "ash/shell_delegate.h"
+#include "ash/wm/window_properties.h"
 #include "ash/wm/window_util.h"
 #include "base/command_line.h"
+#include "chrome/browser/extensions/platform_app_browsertest_util.h"
 #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_window.h"
+#include "chrome/browser/ui/extensions/native_app_window.h"
 #include "chrome/browser/ui/immersive_fullscreen_configuration.h"
 #include "chrome/test/base/in_process_browser_test.h"
+#include "ui/aura/client/aura_constants.h"
+
+namespace {
+
+// Returns true if |window| is in immersive fullscreen. Infer whether |window|
+// is in immersive fullscreen based on whether kFullscreenUsesMinimalChromeKey
+// is set for |window| because DEPS does not allow the test to use BrowserView.
+// (This is not quite right because if a window is in both immersive browser
+// fullscreen and in tab fullscreen, kFullScreenUsesMinimalChromeKey will
+// not be set).
+bool IsInImmersiveFullscreen(BrowserWindow* browser_window) {
+  return browser_window->IsFullscreen() &&
+      browser_window->GetNativeWindow()->GetProperty(
+          ash::internal::kFullscreenUsesMinimalChromeKey);
+}
+
+}  // namespace
 
 typedef InProcessBrowserTest ChromeShellDelegateBrowserTest;
 
@@ -24,17 +46,6 @@
   aura::Window* window = ash::wm::GetActiveWindow();
   ASSERT_TRUE(window);
 
-  if (ImmersiveFullscreenConfiguration::UseImmersiveFullscreen()) {
-    // "ToggleMaximized" toggles immersive fullscreen.
-    EXPECT_FALSE(ash::wm::IsWindowMaximized(window));
-    EXPECT_FALSE(ash::wm::IsWindowFullscreen(window));
-    shell_delegate->ToggleMaximized();
-    EXPECT_TRUE(ash::wm::IsWindowFullscreen(window));
-    shell_delegate->ToggleMaximized();
-    EXPECT_FALSE(ash::wm::IsWindowFullscreen(window));
-    return;
-  }
-
   // When not in fullscreen, ShellDelegate::ToggleMaximized toggles Maximized.
   EXPECT_FALSE(ash::wm::IsWindowMaximized(window));
   shell_delegate->ToggleMaximized();
@@ -55,3 +66,126 @@
   EXPECT_FALSE(ash::wm::IsWindowFullscreen(window));
   EXPECT_TRUE(ash::wm::IsWindowMaximized(window));
 }
+
+// Confirm that toggling window fullscren works properly.
+IN_PROC_BROWSER_TEST_F(ChromeShellDelegateBrowserTest, ToggleFullscreen) {
+  ash::ShellDelegate* shell_delegate = ash::Shell::GetInstance()->delegate();
+  ASSERT_TRUE(shell_delegate);
+
+  // 1) ToggleFullscreen() should toggle whether a tabbed browser window is in
+  // immersive fullscreen.
+  ASSERT_TRUE(browser()->is_type_tabbed());
+  BrowserWindow* browser_window = browser()->window();
+  ASSERT_TRUE(browser_window->IsActive());
+  EXPECT_FALSE(browser_window->IsMaximized());
+  EXPECT_FALSE(browser_window->IsFullscreen());
+
+  shell_delegate->ToggleFullscreen();
+  EXPECT_TRUE(browser_window->IsFullscreen());
+  EXPECT_EQ(IsInImmersiveFullscreen(browser_window),
+      ImmersiveFullscreenConfiguration::UseImmersiveFullscreen());
+
+  shell_delegate->ToggleFullscreen();
+  EXPECT_FALSE(browser_window->IsMaximized());
+  EXPECT_FALSE(browser_window->IsFullscreen());
+
+  // 2) ToggleFullscreen() should have no effect on windows which cannot be
+  // maximized.
+  browser_window->GetNativeWindow()->SetProperty(aura::client::kCanMaximizeKey,
+                                                 false);
+  shell_delegate->ToggleFullscreen();
+  EXPECT_FALSE(browser_window->IsMaximized());
+  EXPECT_FALSE(browser_window->IsFullscreen());
+
+  // 3) ToggleFullscreen() should maximize v1 app browser windows which use
+  // AppNonClientFrameViewAsh.
+  // TODO(pkotwicz): Figure out if we actually want this behavior.
+  Browser::CreateParams browser_create_params(Browser::TYPE_POPUP,
+      browser()->profile(), chrome::HOST_DESKTOP_TYPE_NATIVE);
+#if defined(OS_WIN)
+  browser_create_params.host_desktop_type = chrome::HOST_DESKTOP_TYPE_ASH;
+#endif  // OS_WIN
+  browser_create_params.app_name = "Test";
+  browser_create_params.app_type = Browser::APP_TYPE_HOST;
+
+  Browser* app_host_browser = new Browser(browser_create_params);
+  ASSERT_TRUE(app_host_browser->is_app());
+  AddBlankTabAndShow(app_host_browser);
+  browser_window = app_host_browser->window();
+  ASSERT_TRUE(browser_window->IsActive());
+  EXPECT_FALSE(browser_window->IsMaximized());
+  EXPECT_FALSE(browser_window->IsFullscreen());
+
+  shell_delegate->ToggleFullscreen();
+  EXPECT_TRUE(browser_window->IsMaximized());
+
+  shell_delegate->ToggleFullscreen();
+  EXPECT_FALSE(browser_window->IsMaximized());
+  EXPECT_FALSE(browser_window->IsFullscreen());
+
+  // 4) ToggleFullscreen() should put child windows of v1 apps into
+  // non-immersive fullscreen.
+  browser_create_params.host_desktop_type = chrome::HOST_DESKTOP_TYPE_NATIVE;
+  browser_create_params.app_type = Browser::APP_TYPE_CHILD;
+  Browser* app_child_browser = new Browser(browser_create_params);
+  ASSERT_TRUE(app_child_browser->is_app());
+  AddBlankTabAndShow(app_child_browser);
+  browser_window = app_child_browser->window();
+  ASSERT_TRUE(browser_window->IsActive());
+  EXPECT_FALSE(browser_window->IsMaximized());
+  EXPECT_FALSE(browser_window->IsFullscreen());
+
+  shell_delegate->ToggleFullscreen();
+  EXPECT_TRUE(browser_window->IsFullscreen());
+  EXPECT_FALSE(IsInImmersiveFullscreen(browser_window));
+
+  shell_delegate->ToggleFullscreen();
+  EXPECT_FALSE(browser_window->IsMaximized());
+  EXPECT_FALSE(browser_window->IsFullscreen());
+
+  // 5) ToggleFullscreen() should put popup browser windows into non-immersive
+  // fullscreen.
+  browser_create_params.app_name = "";
+  Browser* popup_browser = new Browser(browser_create_params);
+  ASSERT_TRUE(popup_browser->is_type_popup());
+  ASSERT_FALSE(popup_browser->is_app());
+  AddBlankTabAndShow(popup_browser);
+  browser_window = popup_browser->window();
+  ASSERT_TRUE(browser_window->IsActive());
+  EXPECT_FALSE(browser_window->IsMaximized());
+  EXPECT_FALSE(browser_window->IsFullscreen());
+
+  shell_delegate->ToggleFullscreen();
+  EXPECT_TRUE(browser_window->IsFullscreen());
+  EXPECT_FALSE(IsInImmersiveFullscreen(browser_window));
+
+  shell_delegate->ToggleFullscreen();
+  EXPECT_FALSE(browser_window->IsMaximized());
+  EXPECT_FALSE(browser_window->IsFullscreen());
+}
+
+typedef extensions::PlatformAppBrowserTest
+    ChromeShellDelegatePlatformAppBrowserTest;
+
+// Test that ToggleFullscreen() toggles the platform app's fullscreen state.
+IN_PROC_BROWSER_TEST_F(ChromeShellDelegatePlatformAppBrowserTest,
+                       ToggleFullscreenPlatformApp) {
+  ash::ShellDelegate* shell_delegate = ash::Shell::GetInstance()->delegate();
+  ASSERT_TRUE(shell_delegate);
+
+  const extensions::Extension* extension = LoadAndLaunchPlatformApp("minimal");
+  apps::ShellWindow* shell_window = CreateShellWindow(extension);
+  NativeAppWindow* app_window = shell_window->GetBaseWindow();
+  ASSERT_TRUE(shell_window->GetBaseWindow()->IsActive());
+  EXPECT_FALSE(app_window->IsMaximized());
+  EXPECT_FALSE(app_window->IsFullscreen());
+
+  shell_delegate->ToggleFullscreen();
+  EXPECT_TRUE(app_window->IsFullscreen());
+
+  shell_delegate->ToggleFullscreen();
+  EXPECT_FALSE(app_window->IsMaximized());
+  EXPECT_FALSE(app_window->IsFullscreen());
+
+  CloseShellWindow(shell_window);
+}
diff --git a/chrome/browser/ui/ash/chrome_shell_delegate_chromeos.cc b/chrome/browser/ui/ash/chrome_shell_delegate_chromeos.cc
index f13d629..09becbb 100644
--- a/chrome/browser/ui/ash/chrome_shell_delegate_chromeos.cc
+++ b/chrome/browser/ui/ash/chrome_shell_delegate_chromeos.cc
@@ -29,7 +29,6 @@
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/extensions/application_launch.h"
 #include "chrome/browser/ui/extensions/native_app_window.h"
-#include "chrome/browser/ui/extensions/shell_window.h"
 #include "chrome/browser/ui/webui/chrome_web_contents_handler.h"
 #include "chrome/common/chrome_notification_types.h"
 #include "chrome/common/chrome_switches.h"
diff --git a/chrome/browser/ui/ash/event_rewriter.cc b/chrome/browser/ui/ash/event_rewriter.cc
index 76eea61..7f54cdf 100644
--- a/chrome/browser/ui/ash/event_rewriter.cc
+++ b/chrome/browser/ui/ash/event_rewriter.cc
@@ -27,6 +27,7 @@
 
 #include "base/chromeos/chromeos_version.h"
 #include "base/command_line.h"
+#include "chrome/browser/chromeos/keyboard_driven_event_rewriter.h"
 #include "chrome/browser/chromeos/login/login_display_host_impl.h"
 #include "chrome/browser/chromeos/login/user_manager.h"
 #include "chrome/browser/chromeos/xinput_hierarchy_changed_event_listener.h"
@@ -129,7 +130,6 @@
       chromeos::input_method::InputMethodManager::Get();
   return manager->GetCurrentInputMethod().id() == kNeo2LayoutId ||
       manager->GetCurrentInputMethod().id() == kCaMultixLayoutId;
-
 }
 #endif
 
@@ -146,6 +146,8 @@
     : last_device_id_(kBadDeviceId),
 #if defined(OS_CHROMEOS)
       xkeyboard_(NULL),
+      keyboard_driven_event_rewritter_(
+          new chromeos::KeyboardDrivenEventRewriter),
 #endif
       pref_service_(NULL) {
   // The ash shell isn't instantiated for our unit tests.
@@ -352,6 +354,11 @@
   // crbug.com/136465.
   if (event->native_event()->xkey.send_event)
     return;
+
+  // Keyboard driven rewriting needs to happen before RewriteExtendedKeys
+  // to handle Ctrl+Alt+Shift+(Up | Down) so that they are not translated
+  // to Home/End.
+  keyboard_driven_event_rewritter_->RewriteIfKeyboardDrivenOnLoginScreen(event);
 #endif
   RewriteModifiers(event);
   RewriteNumPadKeys(event);
@@ -449,11 +456,11 @@
   // restart chrome process. In future this is to be changed.
   // TODO(glotov): remove the following condition when we do not restart chrome
   // when user logs in as guest.
- #if defined(OS_CHROMEOS)
-   if (chromeos::UserManager::Get()->IsLoggedInAsGuest() &&
-       chromeos::LoginDisplayHostImpl::default_host())
-     return false;
- #endif  // defined(OS_CHROMEOS)
+#if defined(OS_CHROMEOS)
+  if (chromeos::UserManager::Get()->IsLoggedInAsGuest() &&
+      chromeos::LoginDisplayHostImpl::default_host())
+    return false;
+#endif  // defined(OS_CHROMEOS)
   const PrefService* pref_service =
       pref_service_ ? pref_service_ : GetPrefService();
   if (!pref_service)
diff --git a/chrome/browser/ui/ash/event_rewriter.h b/chrome/browser/ui/ash/event_rewriter.h
index f6add25..b819a00 100644
--- a/chrome/browser/ui/ash/event_rewriter.h
+++ b/chrome/browser/ui/ash/event_rewriter.h
@@ -12,6 +12,7 @@
 #include "base/basictypes.h"
 #include "base/compiler_specific.h"
 #include "base/containers/hash_tables.h"
+#include "base/memory/scoped_ptr.h"
 #include "ui/aura/root_window_observer.h"
 #include "ui/base/keycodes/keyboard_codes.h"
 
@@ -27,6 +28,9 @@
 
 #if defined(OS_CHROMEOS)
 namespace chromeos {
+
+class KeyboardDrivenEventRewriter;
+
 namespace input_method {
 class XKeyboard;
 }
@@ -209,6 +213,9 @@
   base::hash_map<unsigned long, unsigned long> keysym_to_keycode_map_;
 
   chromeos::input_method::XKeyboard* xkeyboard_;  // for testing.
+
+  scoped_ptr<chromeos::KeyboardDrivenEventRewriter>
+      keyboard_driven_event_rewritter_;
 #endif
 
   const PrefService* pref_service_;  // for testing.
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 46cf429..fc743d6 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
@@ -28,6 +28,13 @@
 
 using extensions::Extension;
 
+namespace {
+
+// The time delta between clicks in which clicks to launch V2 apps are ignored.
+const int kClickSuppressionInMS = 1000;
+
+}  // namespace
+
 // Item controller for an app shortcut. Shortcuts track app and launcher ids,
 // but do not have any associated windows (opening a shortcut will replace the
 // item with the appropriate LauncherItemController type).
@@ -88,12 +95,17 @@
 void AppShortcutLauncherItemController::Activate() {
   content::WebContents* content = GetLRUApplication();
   if (!content) {
-    // The initial launch of a V2 app will be done by this controller. Starting
-    // a hosted application takes time and if the user clicks fast, he can come
-    // here multiple times before the ShellLauncherItemController takes control.
-    // To avoid that situation we check for running applications.
-    if (!IsV2AppAndRunning())
-      Launch(ui::EF_NONE);
+    if (IsV2App()) {
+      // Ideally we come here only once. After that ShellLauncherItemController
+      // will take over when the shell window gets opened. However there are
+      // apps which take a lot of time for pre-processing (like the files app)
+      // before they open a window. Since there is currently no other way to
+      // detect if an app was started we suppress any further clicks within a
+      // special time out.
+      if (!AllowNextLaunchAttempt())
+        return;
+    }
+    Launch(ui::EF_NONE);
     return;
   }
   ActivateContent(content);
@@ -282,12 +294,17 @@
   return false;
 }
 
-bool AppShortcutLauncherItemController::IsV2AppAndRunning() {
-  const Extension* extension =
-      app_controller_->GetExtensionForAppID(app_id());
-  extensions::ExtensionSystem* extension_system =
-      extensions::ExtensionSystem::Get(app_controller_->profile());
-  return extension && extension->is_platform_app() && extension_system &&
-         extension_system->process_manager()->GetBackgroundHostForExtension(
-             app_id());
+bool AppShortcutLauncherItemController::IsV2App() {
+  const Extension* extension = app_controller_->GetExtensionForAppID(app_id());
+  return extension && extension->is_platform_app();
+}
+
+bool AppShortcutLauncherItemController::AllowNextLaunchAttempt() {
+  if (last_launch_attempt_.is_null() ||
+      last_launch_attempt_ + base::TimeDelta::FromMilliseconds(
+          kClickSuppressionInMS) < base::Time::Now()) {
+    last_launch_attempt_ = base::Time::Now();
+    return true;
+  }
+  return false;
 }
diff --git a/chrome/browser/ui/ash/launcher/app_shortcut_launcher_item_controller.h b/chrome/browser/ui/ash/launcher/app_shortcut_launcher_item_controller.h
index be7a5ed..49a2e7b 100644
--- a/chrome/browser/ui/ash/launcher/app_shortcut_launcher_item_controller.h
+++ b/chrome/browser/ui/ash/launcher/app_shortcut_launcher_item_controller.h
@@ -7,6 +7,7 @@
 
 #include <string>
 
+#include "base/time/time.h"
 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_app.h"
 #include "chrome/browser/ui/ash/launcher/launcher_item_controller.h"
 
@@ -71,12 +72,19 @@
   // will return true if it has sucessfully advanced.
   bool AdvanceToNextApp();
 
-  // Returns true if the application is a V2 app and it is running.
-  bool IsV2AppAndRunning();
+  // Returns true if the application is a V2 app.
+  bool IsV2App();
+
+  // Returns true if it is allowed to try starting a V2 app again.
+  bool AllowNextLaunchAttempt();
 
   GURL refocus_url_;
   ChromeLauncherControllerPerApp* app_controller_;
 
+  // Since V2 applications can be undetectable after launching, this timer is
+  // keeping track of the last launch attempt.
+  base::Time last_launch_attempt_;
+
   DISALLOW_COPY_AND_ASSIGN(AppShortcutLauncherItemController);
 };
 
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_browsertest.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_browsertest.cc
index e584338..8bcd379 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_browsertest.cc
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_browsertest.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
 
+#include "apps/shell_window.h"
 #include "ash/ash_switches.h"
 #include "ash/launcher/launcher.h"
 #include "ash/launcher/launcher_model.h"
@@ -29,7 +30,6 @@
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/extensions/application_launch.h"
 #include "chrome/browser/ui/extensions/native_app_window.h"
-#include "chrome/browser/ui/extensions/shell_window.h"
 #include "chrome/browser/ui/host_desktop.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/common/chrome_notification_types.h"
@@ -43,6 +43,7 @@
 #include "ui/aura/client/aura_constants.h"
 #include "ui/aura/window.h"
 
+using apps::ShellWindow;
 using extensions::Extension;
 using content::WebContents;
 
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_app.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_app.cc
index 3425019..8c1220d 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_app.cc
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_app.cc
@@ -326,10 +326,18 @@
     const std::string& app_id,
     ash::LauncherItemStatus status) {
   CHECK(controller);
+  int index = 0;
+  // Panels are inserted on the left so as not to push all existing panels over.
+  if (controller->GetLauncherItemType() != ash::TYPE_APP_PANEL) {
+    index = model_->item_count();
+    // For the alternate shelf layout increment the index (after the app icon)
+    if (ash::switches::UseAlternateShelfLayout())
+      ++index;
+  }
   return InsertAppLauncherItem(controller,
                                app_id,
                                status,
-                               model_->item_count(),
+                               index,
                                controller->GetLauncherItemType());
 }
 
@@ -1390,13 +1398,19 @@
   // of iterators because of model mutations as part of the loop.
   std::vector<std::string>::const_iterator pref_app_id(pinned_apps.begin());
   int index = 0;
-  for (; index < model_->item_count() && pref_app_id != pinned_apps.end();
-       ++index) {
+  int max_index = model_->item_count();
+  // Using the alternate shelf layout the App Icon should be the first item in
+  // the list thus start adding items at slot 1 (instead of slot 0).
+  if(ash::switches::UseAlternateShelfLayout()) {
+    ++index;
+    ++max_index;
+  }
+  for (; index < max_index && pref_app_id != pinned_apps.end(); ++index) {
     // If the next app launcher according to the pref is present in the model,
     // delete all app launcher entries in between.
     if (*pref_app_id == extension_misc::kChromeAppId ||
         IsAppPinned(*pref_app_id)) {
-      for (; index < model_->item_count(); ++index) {
+      for (; index < max_index; ++index) {
         const ash::LauncherItem& item(model_->items()[index]);
         if (item.type != ash::TYPE_APP_SHORTCUT &&
             item.type != ash::TYPE_BROWSER_SHORTCUT)
@@ -1418,13 +1432,14 @@
             MoveItemWithoutPinnedStateChangeNotification(index, index + 1);
           } else {
             LauncherItemClosed(item.id);
+            --max_index;
           }
           --index;
         }
       }
       // If the item wasn't found, that means id_to_item_controller_map_
       // is out of sync.
-      DCHECK(index < model_->item_count());
+      DCHECK(index < max_index);
     } else {
       // This app wasn't pinned before, insert a new entry.
       ash::LauncherID id = CreateAppShortcutLauncherItem(*pref_app_id, index);
@@ -1631,6 +1646,9 @@
   size_t index = profile_->GetPrefs()->GetInteger(prefs::kShelfChromeIconIndex);
   const base::ListValue* pinned_apps_pref =
       profile_->GetPrefs()->GetList(prefs::kPinnedLauncherApps);
+  if (ash::switches::UseAlternateShelfLayout())
+    return std::max(static_cast<size_t>(1),
+                    std::min(pinned_apps_pref->GetSize(), index));
   return std::max(static_cast<size_t>(0),
                   std::min(pinned_apps_pref->GetSize(), index));
 }
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 b31c8a7..621d225 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
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
 
+#include "apps/shell_window.h"
 #include "ash/ash_switches.h"
 #include "ash/display/display_controller.h"
 #include "ash/launcher/launcher.h"
@@ -35,7 +36,6 @@
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/extensions/application_launch.h"
 #include "chrome/browser/ui/extensions/native_app_window.h"
-#include "chrome/browser/ui/extensions/shell_window.h"
 #include "chrome/browser/ui/host_desktop.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/common/chrome_notification_types.h"
@@ -51,6 +51,7 @@
 #include "ui/aura/window.h"
 #include "ui/base/events/event.h"
 
+using apps::ShellWindow;
 using extensions::Extension;
 using content::WebContents;
 
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_app_unittest.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_app_unittest.cc
index 7163777..c5516c8 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_app_unittest.cc
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_app_unittest.cc
@@ -64,18 +64,22 @@
   // LauncherModelObserver
   virtual void LauncherItemAdded(int index) OVERRIDE {
     ++added_;
+    last_index_ = index;
   }
 
   virtual void LauncherItemRemoved(int index, ash::LauncherID id) OVERRIDE {
     ++removed_;
+    last_index_ = index;
   }
 
   virtual void LauncherItemChanged(int index,
                                    const ash::LauncherItem& old_item) OVERRIDE {
     ++changed_;
+    last_index_ = index;
   }
 
   virtual void LauncherItemMoved(int start_index, int target_index) OVERRIDE {
+    last_index_ = target_index;
   }
 
   virtual void LauncherStatusChanged() OVERRIDE {
@@ -85,16 +89,19 @@
     added_ = 0;
     removed_ = 0;
     changed_ = 0;
+    last_index_ = 0;
   }
 
   int added() const { return added_; }
   int removed() const { return removed_; }
   int changed() const { return changed_; }
+  int last_index() const { return last_index_; }
 
  private:
   int added_;
   int removed_;
   int changed_;
+  int last_index_;
 
   DISALLOW_COPY_AND_ASSIGN(TestLauncherModelObserver);
 };
@@ -1061,6 +1068,7 @@
       launcher_controller_.get());
   ash::LauncherID launcher_id1 = launcher_controller_->CreateAppLauncherItem(
       &app_panel_controller, app_id, ash::STATUS_RUNNING);
+  int panel_index = model_observer_->last_index();
   EXPECT_EQ(2, model_observer_->added());
   EXPECT_EQ(0, model_observer_->changed());
   EXPECT_EQ(1, app_icon_loader->fetch_count());
@@ -1074,9 +1082,19 @@
   gfx::ImageSkia image;
   launcher_controller_->SetAppImage(app_id, image);
   EXPECT_EQ(0, model_observer_->changed());
+  model_observer_->clear_counts();
 
+  // Add a second app panel and verify that it get the same index as the first
+  // one had, being added to the left of the existing panel.
+  ash::LauncherID launcher_id2 = launcher_controller_->CreateAppLauncherItem(
+      &app_panel_controller, app_id, ash::STATUS_RUNNING);
+  EXPECT_EQ(panel_index, model_observer_->last_index());
+  EXPECT_EQ(1, model_observer_->added());
+  model_observer_->clear_counts();
+
+  launcher_controller_->CloseLauncherItem(launcher_id2);
   launcher_controller_->CloseLauncherItem(launcher_id1);
-  EXPECT_EQ(1, model_observer_->removed());
+  EXPECT_EQ(2, model_observer_->removed());
 }
 
 // Tests that the Gmail extension matches more then the app itself claims with
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_browser.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_browser.cc
index 1bc7d35..447ab1d 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_browser.cc
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_browser.cc
@@ -6,6 +6,7 @@
 
 #include <vector>
 
+#include "ash/ash_switches.h"
 #include "ash/launcher/launcher_model.h"
 #include "ash/root_window_controller.h"
 #include "ash/shelf/shelf_layout_manager.h"
@@ -383,8 +384,15 @@
     const std::string& app_id,
     ash::LauncherItemStatus status) {
   DCHECK(controller);
-  return InsertAppLauncherItem(controller, app_id, status,
-                               model_->item_count());
+  int index = 0;
+  // Panels are inserted on the left so as not to push all existing panels over.
+  if (controller->GetLauncherItemType() != ash::TYPE_APP_PANEL) {
+    index = model_->item_count();
+    // For the alternate shelf layout increment index (insert after app icon).
+    if (ash::switches::UseAlternateShelfLayout())
+      ++index;
+  }
+  return InsertAppLauncherItem(controller, app_id, status, index);
 }
 
 void ChromeLauncherControllerPerBrowser::SetItemStatus(
@@ -1227,6 +1235,11 @@
   // of iterators because of model mutations as part of the loop.
   std::vector<std::string>::const_iterator pref_app_id(pinned_apps.begin());
   int index = 0;
+  int max_index = model_->item_count();
+  if (ash::switches::UseAlternateShelfLayout()) {
+    ++index;
+    ++max_index;
+  }
   for (; index < model_->item_count() && pref_app_id != pinned_apps.end();
        ++index) {
     // If the next app launcher according to the pref is present in the model,
@@ -1255,6 +1268,7 @@
             MoveItemWithoutPinnedStateChangeNotification(index, index + 1);
           } else {
             LauncherItemClosed(item.id);
+            --max_index;
           }
           --index;
         }
@@ -1427,6 +1441,9 @@
   size_t index = profile_->GetPrefs()->GetInteger(prefs::kShelfChromeIconIndex);
   const base::ListValue* pinned_apps_pref =
   profile_->GetPrefs()->GetList(prefs::kPinnedLauncherApps);
+  if (ash::switches::UseAlternateShelfLayout())
+    return std::max(static_cast<size_t>(1),
+                    std::min(pinned_apps_pref->GetSize(), index));
   return std::max(static_cast<size_t>(0),
                   std::min(pinned_apps_pref->GetSize(), index));
 }
diff --git a/chrome/browser/ui/ash/launcher/launcher_favicon_loader.cc b/chrome/browser/ui/ash/launcher/launcher_favicon_loader.cc
index 051e468..ce196e4 100644
--- a/chrome/browser/ui/ash/launcher/launcher_favicon_loader.cc
+++ b/chrome/browser/ui/ash/launcher/launcher_favicon_loader.cc
@@ -110,7 +110,11 @@
     if (pending_requests_.find(*iter) != pending_requests_.end())
       continue;  // Skip already pending downloads.
     pending_requests_.insert(*iter);
-    web_contents_->DownloadImage(*iter, true, 0,
+    web_contents_->DownloadImage(
+        *iter,
+        true,  // is a favicon
+        0,     // no preferred size
+        0,     // no maximum size
         base::Bind(&FaviconBitmapHandler::DidDownloadFavicon,
                    weak_ptr_factory_.GetWeakPtr()));
   }
diff --git a/chrome/browser/ui/ash/launcher/shell_window_launcher_controller.cc b/chrome/browser/ui/ash/launcher/shell_window_launcher_controller.cc
index ffad984..779a8f9 100644
--- a/chrome/browser/ui/ash/launcher/shell_window_launcher_controller.cc
+++ b/chrome/browser/ui/ash/launcher/shell_window_launcher_controller.cc
@@ -4,15 +4,17 @@
 
 #include "chrome/browser/ui/ash/launcher/shell_window_launcher_controller.h"
 
+#include "apps/shell_window.h"
 #include "ash/shell.h"
 #include "ash/wm/window_util.h"
 #include "base/stl_util.h"
 #include "base/strings/stringprintf.h"
 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
 #include "chrome/browser/ui/ash/launcher/shell_window_launcher_item_controller.h"
-#include "chrome/browser/ui/extensions/shell_window.h"
 #include "ui/aura/client/activation_client.h"
 
+using apps::ShellWindow;
+
 namespace {
 
 std::string GetAppLauncherId(ShellWindow* shell_window) {
diff --git a/chrome/browser/ui/ash/launcher/shell_window_launcher_controller.h b/chrome/browser/ui/ash/launcher/shell_window_launcher_controller.h
index 9c279f6..c47c357 100644
--- a/chrome/browser/ui/ash/launcher/shell_window_launcher_controller.h
+++ b/chrome/browser/ui/ash/launcher/shell_window_launcher_controller.h
@@ -13,6 +13,10 @@
 #include "ui/aura/client/activation_change_observer.h"
 #include "ui/aura/window_observer.h"
 
+namespace apps {
+class ShellWindow;
+}
+
 namespace aura {
 
 class Window;
@@ -24,7 +28,6 @@
 }
 
 class ChromeLauncherController;
-class ShellWindow;
 class ShellWindowLauncherItemController;
 
 // ShellWindowLauncherController observes the Shell Window registry and the
@@ -39,9 +42,10 @@
   virtual ~ShellWindowLauncherController();
 
   // Overridden from ShellWindowRegistry::Observer:
-  virtual void OnShellWindowAdded(ShellWindow* shell_window) OVERRIDE;
-  virtual void OnShellWindowIconChanged(ShellWindow* shell_window) OVERRIDE;
-  virtual void OnShellWindowRemoved(ShellWindow* shell_window) OVERRIDE;
+  virtual void OnShellWindowAdded(apps::ShellWindow* shell_window) OVERRIDE;
+  virtual void OnShellWindowIconChanged(
+      apps::ShellWindow* shell_window) OVERRIDE;
+  virtual void OnShellWindowRemoved(apps::ShellWindow* shell_window) OVERRIDE;
 
   // Overriden from aura::WindowObserver:
   virtual void OnWindowDestroying(aura::Window* window) OVERRIDE;
diff --git a/chrome/browser/ui/ash/launcher/shell_window_launcher_item_controller.cc b/chrome/browser/ui/ash/launcher/shell_window_launcher_item_controller.cc
index 276f899..703a8e5 100644
--- a/chrome/browser/ui/ash/launcher/shell_window_launcher_item_controller.cc
+++ b/chrome/browser/ui/ash/launcher/shell_window_launcher_item_controller.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/ui/ash/launcher/shell_window_launcher_item_controller.h"
 
+#include "apps/shell_window.h"
 #include "ash/wm/window_properties.h"
 #include "ash/wm/window_util.h"
 #include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item.h"
@@ -12,13 +13,14 @@
 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_app.h"
 #include "chrome/browser/ui/ash/launcher/launcher_item_controller.h"
 #include "chrome/browser/ui/extensions/native_app_window.h"
-#include "chrome/browser/ui/extensions/shell_window.h"
 #include "content/public/browser/web_contents.h"
 #include "ui/aura/client/aura_constants.h"
 #include "ui/aura/window.h"
 #include "ui/base/events/event.h"
 #include "ui/views/corewm/window_animations.h"
 
+using apps::ShellWindow;
+
 namespace {
 
 // Functor for std::find_if used in AppLauncherItemController.
diff --git a/chrome/browser/ui/ash/launcher/shell_window_launcher_item_controller.h b/chrome/browser/ui/ash/launcher/shell_window_launcher_item_controller.h
index 182ca98..acf4308 100644
--- a/chrome/browser/ui/ash/launcher/shell_window_launcher_item_controller.h
+++ b/chrome/browser/ui/ash/launcher/shell_window_launcher_item_controller.h
@@ -13,6 +13,10 @@
 #include "chrome/browser/ui/ash/launcher/launcher_item_controller.h"
 #include "ui/aura/window_observer.h"
 
+namespace apps {
+class ShellWindow;
+}
+
 namespace aura {
 class Window;
 }
@@ -22,7 +26,6 @@
 }
 
 class ChromeLauncherController;
-class ShellWindow;
 
 // This is a ShellWindowItemLauncherController for shell windows. There is one
 // instance per app, per launcher id.
@@ -42,7 +45,7 @@
 
   virtual ~ShellWindowLauncherItemController();
 
-  void AddShellWindow(ShellWindow* shell_window,
+  void AddShellWindow(apps::ShellWindow* shell_window,
                       ash::LauncherItemStatus status);
 
   void RemoveShellWindowForWindow(aura::Window* window);
@@ -79,19 +82,19 @@
   void ActivateIndexedApp(size_t index);
 
  private:
-  typedef std::list<ShellWindow*> ShellWindowList;
+  typedef std::list<apps::ShellWindow*> ShellWindowList;
 
-  void ShowAndActivateOrMinimize(ShellWindow* shell_window);
+  void ShowAndActivateOrMinimize(apps::ShellWindow* shell_window);
 
   // Activate the given |window_to_show|, or - if already selected - advance to
   // the next window of similar type.
-  void ActivateOrAdvanceToNextShellWindow(ShellWindow* window_to_show);
+  void ActivateOrAdvanceToNextShellWindow(apps::ShellWindow* window_to_show);
 
   // List of associated shell windows
   ShellWindowList shell_windows_;
 
   // Pointer to the most recently active shell window
-  ShellWindow* last_active_shell_window_;
+  apps::ShellWindow* last_active_shell_window_;
 
   // The launcher id associated with this set of windows. There is one
   // AppLauncherItemController for each |app_launcher_id_|.
diff --git a/chrome/browser/ui/ash/screenshot_taker.cc b/chrome/browser/ui/ash/screenshot_taker.cc
index 5d2f7e2..a73c4b5 100644
--- a/chrome/browser/ui/ash/screenshot_taker.cc
+++ b/chrome/browser/ui/ash/screenshot_taker.cc
@@ -15,7 +15,7 @@
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/sequenced_worker_pool.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/download/download_prefs.h"
 #include "chrome/browser/notifications/notification_ui_manager.h"
@@ -355,7 +355,8 @@
   // TODO(sschmitz): make this work for Windows.
   DesktopNotificationService* const service =
       DesktopNotificationServiceFactory::GetForProfile(GetProfile());
-  if (service->IsSystemComponentEnabled(message_center::Notifier::SCREENSHOT)) {
+  if (service->IsNotifierEnabled(
+          message_center::NotifierId(message_center::NotifierId::SCREENSHOT))) {
     scoped_ptr<Notification> notification(
         CreateNotification(screenshot_result, screenshot_path));
     g_browser_process->notification_ui_manager()->Add(*notification,
diff --git a/chrome/browser/ui/ash/screenshot_taker.h b/chrome/browser/ui/ash/screenshot_taker.h
index ecab08d..5411719 100644
--- a/chrome/browser/ui/ash/screenshot_taker.h
+++ b/chrome/browser/ui/ash/screenshot_taker.h
@@ -12,7 +12,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/notifications/notification.h"
 
 class Profile;
diff --git a/chrome/browser/ui/ash/session_state_delegate_chromeos.cc b/chrome/browser/ui/ash/session_state_delegate_chromeos.cc
index a44c892..faba973 100644
--- a/chrome/browser/ui/ash/session_state_delegate_chromeos.cc
+++ b/chrome/browser/ui/ash/session_state_delegate_chromeos.cc
@@ -44,8 +44,7 @@
   if (!CanLockScreen())
     return;
 
-  // TODO(antrim): Additional logging for http://crbug.com/173178.
-  LOG(WARNING) << "Requesting screen lock from SessionStateDelegate";
+  VLOG(1) << "Requesting screen lock from SessionStateDelegate";
   chromeos::DBusThreadManager::Get()->GetSessionManagerClient()->
       RequestLockScreen();
 }
diff --git a/chrome/browser/ui/aura/active_desktop_monitor.cc b/chrome/browser/ui/aura/active_desktop_monitor.cc
index c30cb2d..411aa3e 100644
--- a/chrome/browser/ui/aura/active_desktop_monitor.cc
+++ b/chrome/browser/ui/aura/active_desktop_monitor.cc
@@ -16,8 +16,9 @@
 // static
 ActiveDesktopMonitor* ActiveDesktopMonitor::g_instance_ = NULL;
 
-ActiveDesktopMonitor::ActiveDesktopMonitor()
-    : last_activated_desktop_(chrome::HOST_DESKTOP_TYPE_NATIVE) {
+ActiveDesktopMonitor::ActiveDesktopMonitor(
+    chrome::HostDesktopType initial_desktop)
+    : last_activated_desktop_(initial_desktop) {
   DCHECK(!g_instance_);
   g_instance_ = this;
   aura::Env::GetInstance()->AddObserver(this);
diff --git a/chrome/browser/ui/aura/active_desktop_monitor.h b/chrome/browser/ui/aura/active_desktop_monitor.h
index ff63984..1ae149b 100644
--- a/chrome/browser/ui/aura/active_desktop_monitor.h
+++ b/chrome/browser/ui/aura/active_desktop_monitor.h
@@ -14,7 +14,9 @@
 // RootWindowHost activations.
 class ActiveDesktopMonitor : public aura::EnvObserver {
  public:
-  ActiveDesktopMonitor();
+  // Constructs an ActiveDesktopMonitor which initially uses |initial_desktop|
+  // as the |last_activated_desktop_| until a root window is activated.
+  explicit ActiveDesktopMonitor(chrome::HostDesktopType initial_desktop);
   virtual ~ActiveDesktopMonitor();
 
   // Returns the host desktop type of the most-recently activated
diff --git a/chrome/browser/ui/aura/chrome_browser_main_extra_parts_aura.cc b/chrome/browser/ui/aura/chrome_browser_main_extra_parts_aura.cc
index 7a65e25..eb922f9 100644
--- a/chrome/browser/ui/aura/chrome_browser_main_extra_parts_aura.cc
+++ b/chrome/browser/ui/aura/chrome_browser_main_extra_parts_aura.cc
@@ -7,6 +7,7 @@
 #include "chrome/browser/chrome_browser_main.h"
 #include "chrome/browser/toolkit_extra_parts.h"
 #include "chrome/browser/ui/aura/active_desktop_monitor.h"
+#include "chrome/browser/ui/host_desktop.h"
 #include "ui/aura/env.h"
 #include "ui/gfx/screen.h"
 #include "ui/views/widget/desktop_aura/desktop_screen.h"
@@ -20,7 +21,27 @@
 
 #if defined(USE_ASH)
 #include "chrome/browser/ui/ash/ash_init.h"
+#if defined(OS_WIN)
+#include "base/command_line.h"
+#include "chrome/common/chrome_switches.h"
+#endif  // defined(OS_WIN)
+#endif  // defined(USE_ASH)
+
+namespace {
+
+// Returns the desktop this process was initially launched in.
+chrome::HostDesktopType GetInitialDesktop() {
+#if defined(OS_WIN) && defined(USE_ASH)
+  const CommandLine* command_line = CommandLine::ForCurrentProcess();
+  if (command_line->HasSwitch(switches::kViewerConnect) ||
+      command_line->HasSwitch(switches::kViewerLaunchViaAppId)) {
+    return chrome::HOST_DESKTOP_TYPE_ASH;
+  }
 #endif
+  return chrome::HOST_DESKTOP_TYPE_NATIVE;
+}
+
+}  // namespace
 
 ChromeBrowserMainExtraPartsAura::ChromeBrowserMainExtraPartsAura() {
 }
@@ -31,7 +52,7 @@
 void ChromeBrowserMainExtraPartsAura::ToolkitInitialized() {
 #if !defined(OS_CHROMEOS)
 #if defined(USE_ASH)
-  active_desktop_monitor_.reset(new ActiveDesktopMonitor);
+  active_desktop_monitor_.reset(new ActiveDesktopMonitor(GetInitialDesktop()));
   if (!chrome::ShouldOpenAshOnStartup())
 #endif
   {
diff --git a/chrome/browser/ui/aura/tab_contents/web_drag_bookmark_handler_aura.cc b/chrome/browser/ui/aura/tab_contents/web_drag_bookmark_handler_aura.cc
index b43eab5..7ea3102 100644
--- a/chrome/browser/ui/aura/tab_contents/web_drag_bookmark_handler_aura.cc
+++ b/chrome/browser/ui/aura/tab_contents/web_drag_bookmark_handler_aura.cc
@@ -11,7 +11,6 @@
 #include "chrome/browser/ui/bookmarks/bookmark_tab_helper.h"
 #include "content/public/browser/web_contents.h"
 #include "ui/base/dragdrop/os_exchange_data.h"
-#include "webkit/common/webdropdata.h"
 
 using content::WebContents;
 
diff --git a/chrome/browser/ui/auto_login_infobar_delegate.cc b/chrome/browser/ui/auto_login_infobar_delegate.cc
index e075c7a..2cb853a 100644
--- a/chrome/browser/ui/auto_login_infobar_delegate.cc
+++ b/chrome/browser/ui/auto_login_infobar_delegate.cc
@@ -16,7 +16,7 @@
 #include "chrome/browser/infobars/infobar_service.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/signin/ubertoken_fetcher.h"
-#include "chrome/browser/ui/webui/sync_promo/sync_promo_ui.h"
+#include "chrome/browser/ui/sync/sync_promo_ui.h"
 #include "chrome/common/chrome_notification_types.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
@@ -39,6 +39,10 @@
 #include "net/url_request/url_request.h"
 #include "ui/base/l10n/l10n_util.h"
 
+#if defined(OS_ANDROID)
+#include "chrome/browser/ui/auto_login_infobar_delegate_android.h"
+#endif
+
 using content::NavigationController;
 using content::NotificationSource;
 using content::NotificationDetails;
@@ -131,7 +135,7 @@
       std::string());
 }
 
-}  // namepsace
+}  // namespace
 
 
 // AutoLoginInfoBarDelegate::Params -------------------------------------------
@@ -146,13 +150,12 @@
 void AutoLoginInfoBarDelegate::Create(InfoBarService* infobar_service,
                                       const Params& params) {
   infobar_service->AddInfoBar(scoped_ptr<InfoBarDelegate>(
-      new AutoLoginInfoBarDelegate(infobar_service, params)));
-}
-
-string16 AutoLoginInfoBarDelegate::GetMessageText(
-    const std::string& username) const {
-  return l10n_util::GetStringFUTF16(IDS_AUTOLOGIN_INFOBAR_MESSAGE,
-                                    UTF8ToUTF16(username));
+#if defined(OS_ANDROID)
+      new AutoLoginInfoBarDelegateAndroid(infobar_service, params)
+#else
+      new AutoLoginInfoBarDelegate(infobar_service, params)
+#endif
+      ));
 }
 
 AutoLoginInfoBarDelegate::AutoLoginInfoBarDelegate(
@@ -192,7 +195,8 @@
 }
 
 string16 AutoLoginInfoBarDelegate::GetMessageText() const {
-  return GetMessageText(params_.username);
+  return l10n_util::GetStringFUTF16(IDS_AUTOLOGIN_INFOBAR_MESSAGE,
+                                    UTF8ToUTF16(params_.username));
 }
 
 string16 AutoLoginInfoBarDelegate::GetButtonLabel(
diff --git a/chrome/browser/ui/auto_login_infobar_delegate.h b/chrome/browser/ui/auto_login_infobar_delegate.h
index 540b26d..823fb6b 100644
--- a/chrome/browser/ui/auto_login_infobar_delegate.h
+++ b/chrome/browser/ui/auto_login_infobar_delegate.h
@@ -37,13 +37,12 @@
   // Creates an autologin delegate and adds it to |infobar_service|.
   static void Create(InfoBarService* infobar_service, const Params& params);
 
-  // All the methods below are used by the Android implementation of the
-  // AutoLogin bar on the app side.
-  string16 GetMessageText(const std::string& username) const;
+ protected:
+  AutoLoginInfoBarDelegate(InfoBarService* owner, const Params& params);
+  virtual ~AutoLoginInfoBarDelegate();
 
-  const std::string& realm() const { return params_.header.realm; }
-  const std::string& account() const { return params_.header.account; }
-  const std::string& args() const { return params_.header.args; }
+  // ConfirmInfoBarDelegate:
+  virtual string16 GetMessageText() const OVERRIDE;
 
  private:
   // Enum values used for UMA histograms.
@@ -57,15 +56,11 @@
     HISTOGRAM_MAX
   };
 
-  AutoLoginInfoBarDelegate(InfoBarService* owner, const Params& params);
-  virtual ~AutoLoginInfoBarDelegate();
-
   // ConfirmInfoBarDelegate:
   virtual void InfoBarDismissed() OVERRIDE;
   virtual int GetIconID() const OVERRIDE;
   virtual Type GetInfoBarType() const OVERRIDE;
   virtual AutoLoginInfoBarDelegate* AsAutoLoginInfoBarDelegate() OVERRIDE;
-  virtual string16 GetMessageText() const OVERRIDE;
   virtual string16 GetButtonLabel(InfoBarButton button) const OVERRIDE;
   virtual bool Accept() OVERRIDE;
   virtual bool Cancel() OVERRIDE;
diff --git a/chrome/browser/ui/auto_login_infobar_delegate_android.h b/chrome/browser/ui/auto_login_infobar_delegate_android.h
new file mode 100644
index 0000000..3f69e0f
--- /dev/null
+++ b/chrome/browser/ui/auto_login_infobar_delegate_android.h
@@ -0,0 +1,44 @@
+// 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_UI_AUTO_LOGIN_INFOBAR_DELEGATE_ANDROID_H_
+#define CHROME_BROWSER_UI_AUTO_LOGIN_INFOBAR_DELEGATE_ANDROID_H_
+
+#include "base/android/jni_helper.h"
+#include "base/android/scoped_java_ref.h"
+#include "chrome/browser/ui/auto_login_infobar_delegate.h"
+
+class AutoLoginInfoBarDelegateAndroid : public AutoLoginInfoBarDelegate {
+ public:
+  AutoLoginInfoBarDelegateAndroid(InfoBarService* owner, const Params& params);
+  virtual ~AutoLoginInfoBarDelegateAndroid();
+
+  // ConfirmInfoBarDelegate:
+  virtual bool Accept() OVERRIDE;
+  virtual bool Cancel() OVERRIDE;
+  virtual string16 GetMessageText() const OVERRIDE;
+
+  // These methods are defined in downstream code.
+  bool AttachAccount(JavaObjectWeakGlobalRef weak_java_translate_helper);
+  void LoginSuccess(JNIEnv* env, jobject obj, jstring result);
+  void LoginFailed(JNIEnv* env, jobject obj);
+  void LoginDismiss(JNIEnv* env, jobject obj);
+
+  // Register Android JNI bindings.
+  static bool Register(JNIEnv* env);
+
+ private:
+  const std::string& realm() const { return params_.header.realm; }
+  const std::string& account() const { return params_.header.account; }
+  const std::string& args() const { return params_.header.args; }
+
+  JavaObjectWeakGlobalRef weak_java_auto_login_delegate_;
+  std::string user_;
+  const Params params_;
+
+  DISALLOW_COPY_AND_ASSIGN(AutoLoginInfoBarDelegateAndroid);
+};
+
+
+#endif  // CHROME_BROWSER_UI_AUTO_LOGIN_INFOBAR_DELEGATE_ANDROID_H_
+
diff --git a/chrome/browser/ui/autofill/account_chooser_model.cc b/chrome/browser/ui/autofill/account_chooser_model.cc
index be5f630..3c3bcb0 100644
--- a/chrome/browser/ui/autofill/account_chooser_model.cc
+++ b/chrome/browser/ui/autofill/account_chooser_model.cc
@@ -9,9 +9,9 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/common/pref_names.h"
-#include "components/autofill/browser/autofill_metrics.h"
+#include "components/autofill/core/browser/autofill_metrics.h"
 #include "grit/generated_resources.h"
 #include "grit/theme_resources.h"
 #include "ui/base/l10n/l10n_util.h"
diff --git a/chrome/browser/ui/autofill/account_chooser_model.h b/chrome/browser/ui/autofill/account_chooser_model.h
index 940dccd..fd3f001 100644
--- a/chrome/browser/ui/autofill/account_chooser_model.h
+++ b/chrome/browser/ui/autofill/account_chooser_model.h
@@ -10,7 +10,7 @@
 #include "base/basictypes.h"
 #include "base/compiler_specific.h"
 #include "base/strings/string16.h"
-#include "components/autofill/browser/autofill_manager_delegate.h"
+#include "components/autofill/core/browser/autofill_manager_delegate.h"
 #include "ui/base/models/simple_menu_model.h"
 
 class AutofillMetrics;
diff --git a/chrome/browser/ui/autofill/account_chooser_model_unittest.cc b/chrome/browser/ui/autofill/account_chooser_model_unittest.cc
index 16f4010..f27c1be 100644
--- a/chrome/browser/ui/autofill/account_chooser_model_unittest.cc
+++ b/chrome/browser/ui/autofill/account_chooser_model_unittest.cc
@@ -7,7 +7,7 @@
 #include "chrome/browser/ui/autofill/account_chooser_model.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/testing_profile.h"
-#include "components/autofill/browser/autofill_metrics.h"
+#include "components/autofill/core/browser/autofill_metrics.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/chrome/browser/ui/autofill/autocheckout_bubble_controller.cc b/chrome/browser/ui/autofill/autocheckout_bubble_controller.cc
index d3cab37..da502a7 100644
--- a/chrome/browser/ui/autofill/autocheckout_bubble_controller.cc
+++ b/chrome/browser/ui/autofill/autocheckout_bubble_controller.cc
@@ -4,7 +4,7 @@
 
 #include "chrome/browser/ui/autofill/autocheckout_bubble_controller.h"
 
-#include "components/autofill/browser/autofill_metrics.h"
+#include "components/autofill/core/browser/autofill_metrics.h"
 #include "grit/generated_resources.h"
 #include "grit/ui_resources.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -44,26 +44,20 @@
                         IDS_AUTOCHECKOUT_BUBBLE_PROMPT_NOT_SIGNED_IN);
 }
 
+// TODO(ahutter): Change these functions back to not returning a "Buy With
+// Google" button after UX has finalized the non-Google user experience. See
+// http://crbug.com/253681.
 gfx::Image AutocheckoutBubbleController::NormalImage() {
-  if (!is_google_user_)
-    return gfx::Image();
-
   ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
   return rb.GetImageNamed(IDR_BUY_WITH_GOOGLE_BUTTON);
 }
 
 gfx::Image AutocheckoutBubbleController::HoverImage() {
-  if (!is_google_user_)
-    return gfx::Image();
-
   ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
   return rb.GetImageNamed(IDR_BUY_WITH_GOOGLE_BUTTON_H);
 }
 
 gfx::Image AutocheckoutBubbleController::PressedImage() {
-  if (!is_google_user_)
-    return gfx::Image();
-
   ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
   return rb.GetImageNamed(IDR_BUY_WITH_GOOGLE_BUTTON_P);
 }
diff --git a/chrome/browser/ui/autofill/autocheckout_bubble_controller_unittest.cc b/chrome/browser/ui/autofill/autocheckout_bubble_controller_unittest.cc
index d7ed4e0..ca353ad 100644
--- a/chrome/browser/ui/autofill/autocheckout_bubble_controller_unittest.cc
+++ b/chrome/browser/ui/autofill/autocheckout_bubble_controller_unittest.cc
@@ -6,7 +6,7 @@
 #include "base/callback.h"
 #include "base/memory/scoped_ptr.h"
 #include "chrome/browser/ui/autofill/autocheckout_bubble_controller.h"
-#include "components/autofill/browser/autofill_metrics.h"
+#include "components/autofill/core/browser/autofill_metrics.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/gfx/rect.h"
 
diff --git a/chrome/browser/ui/autofill/autofill_dialog_controller.h b/chrome/browser/ui/autofill/autofill_dialog_controller.h
index f7c5ddb..6bc0508 100644
--- a/chrome/browser/ui/autofill/autofill_dialog_controller.h
+++ b/chrome/browser/ui/autofill/autofill_dialog_controller.h
@@ -9,8 +9,8 @@
 
 #include "base/strings/string16.h"
 #include "chrome/browser/ui/autofill/autofill_dialog_types.h"
-#include "components/autofill/browser/field_types.h"
 #include "components/autofill/content/browser/wallet/required_action.h"
+#include "components/autofill/core/browser/field_types.h"
 #include "ui/base/range/range.h"
 #include "ui/base/ui_base_types.h"
 #include "ui/gfx/image/image.h"
@@ -46,7 +46,6 @@
   virtual string16 CancelButtonText() const = 0;
   virtual string16 ConfirmButtonText() const = 0;
   virtual string16 SaveLocallyText() const = 0;
-  virtual string16 ProgressBarText() const = 0;
   virtual string16 LegalDocumentsText() = 0;
 
   // State ---------------------------------------------------------------------
@@ -173,6 +172,11 @@
   // order from top to bottom.
   virtual std::vector<DialogNotification> CurrentNotifications() = 0;
 
+  // Returns Autocheckout steps that the view should currently be showing in
+  // order from first to last.
+  virtual std::vector<DialogAutocheckoutStep> CurrentAutocheckoutSteps()
+      const = 0;
+
   // Begins or aborts the flow to sign into Wallet.
   virtual void SignInLinkClicked() = 0;
 
diff --git a/chrome/browser/ui/autofill/autofill_dialog_controller_browsertest.cc b/chrome/browser/ui/autofill/autofill_dialog_controller_browsertest.cc
index 7a33c36..469655f 100644
--- a/chrome/browser/ui/autofill/autofill_dialog_controller_browsertest.cc
+++ b/chrome/browser/ui/autofill/autofill_dialog_controller_browsertest.cc
@@ -7,24 +7,32 @@
 #include "base/memory/ref_counted.h"
 #include "base/message_loop.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
+#include "chrome/browser/autofill/personal_data_manager_factory.h"
 #include "chrome/browser/ui/autofill/autofill_dialog_controller_impl.h"
 #include "chrome/browser/ui/autofill/autofill_dialog_view.h"
 #include "chrome/browser/ui/autofill/data_model_wrapper.h"
+#include "chrome/browser/ui/autofill/tab_autofill_manager_delegate.h"
 #include "chrome/browser/ui/autofill/testable_autofill_dialog_view.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/test/base/in_process_browser_test.h"
-#include "components/autofill/browser/autofill_common_test.h"
-#include "components/autofill/browser/autofill_metrics.h"
-#include "components/autofill/browser/test_personal_data_manager.h"
-#include "components/autofill/browser/validation.h"
+#include "chrome/test/base/ui_test_utils.h"
 #include "components/autofill/content/browser/wallet/wallet_test_util.h"
+#include "components/autofill/core/browser/autofill_common_test.h"
+#include "components/autofill/core/browser/autofill_metrics.h"
+#include "components/autofill/core/browser/test_personal_data_manager.h"
+#include "components/autofill/core/browser/validation.h"
 #include "components/autofill/core/common/autofill_switches.h"
 #include "components/autofill/core/common/form_data.h"
 #include "components/autofill/core/common/form_field_data.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_delegate.h"
+#include "content/public/test/browser_test_utils.h"
 #include "content/public/test/test_utils.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/WebKit/public/web/WebInputEvent.h"
 
 namespace autofill {
 
@@ -91,7 +99,8 @@
                                      dialog_type,
                                      base::Bind(&MockCallback)),
         metric_logger_(metric_logger),
-        message_loop_runner_(runner) {}
+        message_loop_runner_(runner),
+        use_validation_(false) {}
 
   virtual ~TestAutofillDialogController() {}
 
@@ -104,14 +113,20 @@
       DialogSection section,
       AutofillFieldType type,
       const string16& value) OVERRIDE {
-    return string16();
+    if (!use_validation_)
+      return string16();
+    return AutofillDialogControllerImpl::InputValidityMessage(
+        section, type, value);
   }
 
   virtual ValidityData InputsAreValid(
       DialogSection section,
       const DetailOutputMap& inputs,
       ValidationType validation_type) OVERRIDE {
-    return ValidityData();
+    if (!use_validation_)
+      return ValidityData();
+    return AutofillDialogControllerImpl::InputsAreValid(
+        section, inputs, validation_type);
   }
 
   // Saving to Chrome is tested in AutofillDialogController unit tests.
@@ -138,6 +153,11 @@
 
   using AutofillDialogControllerImpl::DisableWallet;
   using AutofillDialogControllerImpl::IsEditingExistingData;
+  using AutofillDialogControllerImpl::IsManuallyEditingSection;
+
+  void set_use_validation(bool use_validation) {
+    use_validation_ = use_validation;
+  }
 
  protected:
   virtual PersonalDataManager* GetManager() OVERRIDE {
@@ -153,6 +173,7 @@
   const AutofillMetrics& metric_logger_;
   TestPersonalDataManager test_manager_;
   scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
+  bool use_validation_;
 
   // A list of notifications to show in the notification area of the dialog.
   // This is used to control what |CurrentNotifications()| returns for testing.
@@ -177,7 +198,7 @@
     form.user_submitted = true;
 
     FormFieldData field;
-    field.autocomplete_attribute = "email";
+    field.autocomplete_attribute = "shipping tel";
     form.fields.push_back(field);
 
     message_loop_runner_ = new content::MessageLoopRunner;
@@ -201,10 +222,85 @@
     message_loop_runner_->Run();
   }
 
+  // Loads an HTML page in |GetActiveWebContents()| with markup as follows:
+  // <form>|form_inner_html|</form>. After loading, emulates a click event on
+  // the page as requestAutocomplete() must be in response to a user gesture.
+  // Returns the |AutofillDialogControllerImpl| created by this invocation.
+  AutofillDialogControllerImpl* SetUpHtmlAndInvoke(
+      const std::string& form_inner_html) {
+    content::WebContents* contents = GetActiveWebContents();
+    TabAutofillManagerDelegate* delegate =
+        TabAutofillManagerDelegate::FromWebContents(contents);
+    DCHECK(!delegate->GetDialogControllerForTesting());
+
+    ui_test_utils::NavigateToURL(
+        browser(), GURL(std::string("data:text/html,") +
+        "<!doctype html>"
+        "<html>"
+          "<body>"
+            "<form>" + form_inner_html + "</form>"
+            "<script>"
+              "function send(msg) {"
+                "domAutomationController.setAutomationId(0);"
+                "domAutomationController.send(msg);"
+              "}"
+              "document.forms[0].onautocompleteerror = function(e) {"
+                "send('error: ' + e.reason);"
+              "};"
+              "document.forms[0].onautocomplete = function() {"
+                "send('success');"
+              "};"
+              "window.onclick = function() {"
+                "document.forms[0].requestAutocomplete();"
+                "send('clicked');"
+              "};"
+            "</script>"
+          "</body>"
+        "</html>"));
+    content::WaitForLoadStop(contents);
+
+    dom_message_queue_.reset(new content::DOMMessageQueue);
+
+    // Triggers the onclick handler which invokes requestAutocomplete().
+    content::SimulateMouseClick(contents, 0, WebKit::WebMouseEvent::ButtonLeft);
+    ExpectDomMessage("clicked");
+
+    AutofillDialogControllerImpl* controller =
+        delegate->GetDialogControllerForTesting();
+    DCHECK(controller);
+    return controller;
+  }
+
+  // Wait for a message from the DOM automation controller (from JS in the
+  // page). Requires |SetUpHtmlAndInvoke()| be called first.
+  void ExpectDomMessage(const std::string& expected) {
+    std::string message;
+    ASSERT_TRUE(dom_message_queue_->WaitForMessage(&message));
+    dom_message_queue_->ClearQueue();
+    EXPECT_EQ("\"" + expected + "\"", message);
+  }
+
+  void AddCreditcardToProfile(Profile* profile, const CreditCard& card) {
+    PersonalDataManagerFactory::GetForProfile(profile)->AddCreditCard(card);
+    WaitForWebDB();
+  }
+
+  void AddAutofillProfileToProfile(Profile* profile,
+                                   const AutofillProfile& autofill_profile) {
+    PersonalDataManagerFactory::GetForProfile(profile)->AddProfile(
+        autofill_profile);
+    WaitForWebDB();
+  }
+
  private:
+  void WaitForWebDB() {
+    content::RunAllPendingInMessageLoop(content::BrowserThread::DB);
+  }
+
   MockAutofillMetrics metric_logger_;
   TestAutofillDialogController* controller_;  // Weak reference.
   scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
+  scoped_ptr<content::DOMMessageQueue> dom_message_queue_;
   DISALLOW_COPY_AND_ASSIGN(AutofillDialogControllerTest);
 };
 
@@ -214,7 +310,7 @@
 // Submit the form data.
 IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, Submit) {
   InitializeControllerOfType(DIALOG_TYPE_REQUEST_AUTOCOMPLETE);
-  controller()->view()->GetTestableView()->SubmitForTesting();
+  controller()->GetTestableView()->SubmitForTesting();
 
   RunMessageLoop();
 
@@ -226,7 +322,7 @@
 // Cancel out of the dialog.
 IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, Cancel) {
   InitializeControllerOfType(DIALOG_TYPE_REQUEST_AUTOCOMPLETE);
-  controller()->view()->GetTestableView()->CancelForTesting();
+  controller()->GetTestableView()->CancelForTesting();
 
   RunMessageLoop();
 
@@ -250,14 +346,14 @@
 // Test Autocheckout success metrics.
 IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, AutocheckoutSuccess) {
   InitializeControllerOfType(DIALOG_TYPE_AUTOCHECKOUT);
-  controller()->view()->GetTestableView()->SubmitForTesting();
+  controller()->GetTestableView()->SubmitForTesting();
 
   EXPECT_EQ(AutofillMetrics::DIALOG_ACCEPTED,
             metric_logger().dialog_dismissal_action());
   EXPECT_EQ(DIALOG_TYPE_AUTOCHECKOUT, metric_logger().dialog_type());
 
   controller()->OnAutocheckoutSuccess();
-  controller()->view()->GetTestableView()->CancelForTesting();
+  controller()->GetTestableView()->CancelForTesting();
   RunMessageLoop();
 
   EXPECT_EQ(AutofillMetrics::AUTOCHECKOUT_SUCCEEDED,
@@ -272,14 +368,14 @@
 // Test Autocheckout failure metric.
 IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, AutocheckoutError) {
   InitializeControllerOfType(DIALOG_TYPE_AUTOCHECKOUT);
-  controller()->view()->GetTestableView()->SubmitForTesting();
+  controller()->GetTestableView()->SubmitForTesting();
 
   EXPECT_EQ(AutofillMetrics::DIALOG_ACCEPTED,
             metric_logger().dialog_dismissal_action());
   EXPECT_EQ(DIALOG_TYPE_AUTOCHECKOUT, metric_logger().dialog_type());
 
   controller()->OnAutocheckoutError();
-  controller()->view()->GetTestableView()->CancelForTesting();
+  controller()->GetTestableView()->CancelForTesting();
   RunMessageLoop();
 
   EXPECT_EQ(AutofillMetrics::AUTOCHECKOUT_FAILED,
@@ -293,13 +389,13 @@
 
 IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, AutocheckoutCancelled) {
   InitializeControllerOfType(DIALOG_TYPE_AUTOCHECKOUT);
-  controller()->view()->GetTestableView()->SubmitForTesting();
+  controller()->GetTestableView()->SubmitForTesting();
 
   EXPECT_EQ(AutofillMetrics::DIALOG_ACCEPTED,
             metric_logger().dialog_dismissal_action());
   EXPECT_EQ(DIALOG_TYPE_AUTOCHECKOUT, metric_logger().dialog_type());
 
-  controller()->view()->GetTestableView()->CancelForTesting();
+  controller()->GetTestableView()->CancelForTesting();
   RunMessageLoop();
 
   EXPECT_EQ(AutofillMetrics::AUTOCHECKOUT_CANCELLED,
@@ -322,7 +418,7 @@
       controller()->RequestedFieldsForSection(SECTION_SHIPPING);
   const DetailInput& triggering_input = inputs[0];
   string16 value = full_profile.GetRawInfo(triggering_input.type);
-  TestableAutofillDialogView* view = controller()->view()->GetTestableView();
+  TestableAutofillDialogView* view = controller()->GetTestableView();
   view->SetTextContentsOfInput(triggering_input,
                                value.substr(0, value.size() / 2));
   view->ActivateInput(triggering_input);
@@ -361,29 +457,37 @@
   }
 }
 
-// Test that the Autocheckout progress bar is showing after submitting the
+// Test that Autocheckout steps are shown after submitting the
 // dialog for controller with type DIALOG_TYPE_AUTOCHECKOUT.
 IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest,
-                       AutocheckoutShowsProgressBar) {
+                       AutocheckoutShowsSteps) {
   InitializeControllerOfType(DIALOG_TYPE_AUTOCHECKOUT);
+  controller()->AddAutocheckoutStep(AUTOCHECKOUT_STEP_PROXY_CARD);
+
   EXPECT_TRUE(controller()->ShouldShowDetailArea());
+  EXPECT_TRUE(controller()->CurrentAutocheckoutSteps().empty());
   EXPECT_FALSE(controller()->ShouldShowProgressBar());
 
-  controller()->view()->GetTestableView()->SubmitForTesting();
+  controller()->GetTestableView()->SubmitForTesting();
   EXPECT_FALSE(controller()->ShouldShowDetailArea());
+  EXPECT_FALSE(controller()->CurrentAutocheckoutSteps().empty());
   EXPECT_TRUE(controller()->ShouldShowProgressBar());
 }
 
-// Test that the Autocheckout progress bar is not showing after submitting the
+// Test that Autocheckout steps are not showing after submitting the
 // dialog for controller with type DIALOG_TYPE_REQUEST_AUTOCOMPLETE.
 IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest,
-                       RequestAutocompleteDoesntShowProgressBar) {
+                       RequestAutocompleteDoesntShowSteps) {
   InitializeControllerOfType(DIALOG_TYPE_REQUEST_AUTOCOMPLETE);
+  controller()->AddAutocheckoutStep(AUTOCHECKOUT_STEP_PROXY_CARD);
+
   EXPECT_TRUE(controller()->ShouldShowDetailArea());
+  EXPECT_TRUE(controller()->CurrentAutocheckoutSteps().empty());
   EXPECT_FALSE(controller()->ShouldShowProgressBar());
 
-  controller()->view()->GetTestableView()->SubmitForTesting();
+  controller()->GetTestableView()->SubmitForTesting();
   EXPECT_TRUE(controller()->ShouldShowDetailArea());
+  EXPECT_TRUE(controller()->CurrentAutocheckoutSteps().empty());
   EXPECT_FALSE(controller()->ShouldShowProgressBar());
 }
 
@@ -406,7 +510,7 @@
       controller()->RequestedFieldsForSection(SECTION_CC);
   const DetailInput& triggering_input = inputs[0];
   string16 value = card1.GetRawInfo(triggering_input.type);
-  TestableAutofillDialogView* view = controller()->view()->GetTestableView();
+  TestableAutofillDialogView* view = controller()->GetTestableView();
   view->SetTextContentsOfInput(triggering_input,
                                value.substr(0, value.size() / 2));
   view->ActivateInput(triggering_input);
@@ -549,7 +653,7 @@
   InitializeControllerOfType(DIALOG_TYPE_REQUEST_AUTOCOMPLETE);
 
   const gfx::Size no_notification_size =
-      controller()->view()->GetTestableView()->GetSize();
+      controller()->GetTestableView()->GetSize();
   ASSERT_GT(no_notification_size.width(), 0);
 
   std::vector<DialogNotification> notifications;
@@ -566,7 +670,140 @@
   controller()->view()->UpdateNotificationArea();
 
   EXPECT_EQ(no_notification_size.width(),
-            controller()->view()->GetTestableView()->GetSize().width());
+            controller()->GetTestableView()->GetSize().width());
+}
+
+IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, AutocompleteEvent) {
+  AutofillDialogControllerImpl* controller =
+      SetUpHtmlAndInvoke("<input autocomplete='cc-name'>");
+
+  AddCreditcardToProfile(controller->profile(), test::GetVerifiedCreditCard());
+  AddAutofillProfileToProfile(controller->profile(),
+                              test::GetVerifiedProfile());
+
+  TestableAutofillDialogView* view = controller->GetTestableView();
+  view->SetTextContentsOfSuggestionInput(SECTION_CC, ASCIIToUTF16("123"));
+  view->SubmitForTesting();
+  ExpectDomMessage("success");
+}
+
+IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest,
+                       AutocompleteErrorEventReasonInvalid) {
+  AutofillDialogControllerImpl* controller =
+      SetUpHtmlAndInvoke("<input autocomplete='cc-name' pattern='.*zebra.*'>");
+
+  const CreditCard& credit_card = test::GetVerifiedCreditCard();
+  ASSERT_TRUE(
+    credit_card.GetRawInfo(CREDIT_CARD_NAME).find(ASCIIToUTF16("zebra")) ==
+        base::string16::npos);
+  AddCreditcardToProfile(controller->profile(), credit_card);
+  AddAutofillProfileToProfile(controller->profile(),
+                              test::GetVerifiedProfile());
+
+  TestableAutofillDialogView* view = controller->GetTestableView();
+  view->SetTextContentsOfSuggestionInput(SECTION_CC, ASCIIToUTF16("123"));
+  view->SubmitForTesting();
+  ExpectDomMessage("error: invalid");
+}
+
+IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest,
+                       AutocompleteErrorEventReasonCancel) {
+  SetUpHtmlAndInvoke("<input autocomplete='cc-name'>")->GetTestableView()->
+      CancelForTesting();
+  ExpectDomMessage("error: cancel");
+}
+
+IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, NoCvcSegfault) {
+  InitializeControllerOfType(DIALOG_TYPE_REQUEST_AUTOCOMPLETE);
+  controller()->DisableWallet(wallet::WalletClient::UNKNOWN_ERROR);
+  controller()->set_use_validation(true);
+
+  CreditCard credit_card(test::GetVerifiedCreditCard());
+  controller()->GetTestingManager()->AddTestingCreditCard(&credit_card);
+  EXPECT_FALSE(controller()->IsEditingExistingData(SECTION_CC));
+
+  ASSERT_NO_FATAL_FAILURE(
+      controller()->GetTestableView()->SubmitForTesting());
+}
+
+IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, PreservedSections) {
+  InitializeControllerOfType(DIALOG_TYPE_REQUEST_AUTOCOMPLETE);
+  controller()->set_use_validation(true);
+
+  // Set up some Autofill state.
+  CreditCard credit_card(test::GetVerifiedCreditCard());
+  controller()->GetTestingManager()->AddTestingCreditCard(&credit_card);
+
+  AutofillProfile profile(test::GetVerifiedProfile());
+  controller()->GetTestingManager()->AddTestingProfile(&profile);
+
+  EXPECT_TRUE(controller()->SectionIsActive(SECTION_CC));
+  EXPECT_TRUE(controller()->SectionIsActive(SECTION_BILLING));
+  EXPECT_FALSE(controller()->SectionIsActive(SECTION_CC_BILLING));
+  EXPECT_TRUE(controller()->SectionIsActive(SECTION_SHIPPING));
+
+  EXPECT_FALSE(controller()->IsManuallyEditingSection(SECTION_CC));
+  EXPECT_FALSE(controller()->IsManuallyEditingSection(SECTION_BILLING));
+  EXPECT_FALSE(controller()->IsManuallyEditingSection(SECTION_SHIPPING));
+
+  // Set up some Wallet state.
+  controller()->OnUserNameFetchSuccess("user@example.com");
+  controller()->OnDidGetWalletItems(wallet::GetTestWalletItems());
+
+  ui::MenuModel* account_chooser = controller()->MenuModelForAccountChooser();
+  ASSERT_TRUE(account_chooser->IsItemCheckedAt(0));
+
+  // Check that the view's in the state we expect before starting to simulate
+  // user input.
+  EXPECT_FALSE(controller()->SectionIsActive(SECTION_CC));
+  EXPECT_FALSE(controller()->SectionIsActive(SECTION_BILLING));
+  EXPECT_TRUE(controller()->SectionIsActive(SECTION_CC_BILLING));
+  EXPECT_TRUE(controller()->SectionIsActive(SECTION_SHIPPING));
+
+  EXPECT_TRUE(controller()->IsManuallyEditingSection(SECTION_CC_BILLING));
+
+  // Create some valid inputted billing data.
+  const DetailInput& cc_name =
+      controller()->RequestedFieldsForSection(SECTION_CC_BILLING)[4];
+  ASSERT_EQ(CREDIT_CARD_NAME, cc_name.type);
+  TestableAutofillDialogView* view = controller()->GetTestableView();
+  view->SetTextContentsOfInput(cc_name, ASCIIToUTF16("credit card name"));
+
+  // Select "Add new shipping info..." from suggestions menu.
+  ui::MenuModel* shipping_model =
+      controller()->MenuModelForSection(SECTION_SHIPPING);
+  shipping_model->ActivatedAt(shipping_model->GetItemCount() - 2);
+
+  EXPECT_TRUE(controller()->IsManuallyEditingSection(SECTION_SHIPPING));
+
+  // Create some invalid, manually inputted shipping data.
+  const DetailInput& shipping_zip =
+      controller()->RequestedFieldsForSection(SECTION_SHIPPING)[5];
+  ASSERT_EQ(ADDRESS_HOME_ZIP, shipping_zip.type);
+  view->SetTextContentsOfInput(shipping_zip, ASCIIToUTF16("shipping zip"));
+
+  // Switch to using Autofill.
+  account_chooser->ActivatedAt(1);
+
+  // Check that appropriate sections are preserved and in manually editing mode
+  // (or disabled, in the case of the combined cc + billing section).
+  EXPECT_TRUE(controller()->SectionIsActive(SECTION_CC));
+  EXPECT_TRUE(controller()->SectionIsActive(SECTION_BILLING));
+  EXPECT_FALSE(controller()->SectionIsActive(SECTION_CC_BILLING));
+  EXPECT_TRUE(controller()->SectionIsActive(SECTION_SHIPPING));
+
+  EXPECT_TRUE(controller()->IsManuallyEditingSection(SECTION_CC));
+  EXPECT_FALSE(controller()->IsManuallyEditingSection(SECTION_BILLING));
+  EXPECT_FALSE(controller()->IsManuallyEditingSection(SECTION_SHIPPING));
+
+  const DetailInput& new_cc_name =
+      controller()->RequestedFieldsForSection(SECTION_CC).back();
+  ASSERT_EQ(cc_name.type, new_cc_name.type);
+  EXPECT_EQ(ASCIIToUTF16("credit card name"),
+            view->GetTextContentsOfInput(new_cc_name));
+
+  EXPECT_NE(ASCIIToUTF16("shipping name"),
+            view->GetTextContentsOfInput(shipping_zip));
 }
 #endif  // defined(TOOLKIT_VIEWS)
 
diff --git a/chrome/browser/ui/autofill/autofill_dialog_controller_impl.cc b/chrome/browser/ui/autofill/autofill_dialog_controller_impl.cc
index 1b1c4b0..5e661c9 100644
--- a/chrome/browser/ui/autofill/autofill_dialog_controller_impl.cc
+++ b/chrome/browser/ui/autofill/autofill_dialog_controller_impl.cc
@@ -8,6 +8,7 @@
 #include <map>
 #include <string>
 
+#include "apps/shell_window.h"
 #include "base/base64.h"
 #include "base/bind.h"
 #include "base/i18n/rtl.h"
@@ -17,7 +18,7 @@
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/autofill/personal_data_manager_factory.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/extensions/shell_window_registry.h"
@@ -30,17 +31,9 @@
 #include "chrome/browser/ui/browser_navigator.h"
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/extensions/native_app_window.h"
-#include "chrome/browser/ui/extensions/shell_window.h"
 #include "chrome/common/chrome_version_info.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/url_constants.h"
-#include "components/autofill/browser/autofill_country.h"
-#include "components/autofill/browser/autofill_data_model.h"
-#include "components/autofill/browser/autofill_manager.h"
-#include "components/autofill/browser/autofill_type.h"
-#include "components/autofill/browser/personal_data_manager.h"
-#include "components/autofill/browser/phone_number_i18n.h"
-#include "components/autofill/browser/validation.h"
 #include "components/autofill/content/browser/risk/fingerprint.h"
 #include "components/autofill/content/browser/risk/proto/fingerprint.pb.h"
 #include "components/autofill/content/browser/wallet/form_field_error.h"
@@ -50,6 +43,13 @@
 #include "components/autofill/content/browser/wallet/wallet_items.h"
 #include "components/autofill/content/browser/wallet/wallet_service_url.h"
 #include "components/autofill/content/browser/wallet/wallet_signin_helper.h"
+#include "components/autofill/core/browser/autofill_country.h"
+#include "components/autofill/core/browser/autofill_data_model.h"
+#include "components/autofill/core/browser/autofill_manager.h"
+#include "components/autofill/core/browser/autofill_type.h"
+#include "components/autofill/core/browser/personal_data_manager.h"
+#include "components/autofill/core/browser/phone_number_i18n.h"
+#include "components/autofill/core/browser/validation.h"
 #include "components/autofill/core/common/form_data.h"
 #include "components/user_prefs/pref_registry_syncable.h"
 #include "content/public/browser/browser_thread.h"
@@ -70,6 +70,7 @@
 #include "net/cert/cert_status_flags.h"
 #include "ui/base/base_window.h"
 #include "ui/base/l10n/l10n_util.h"
+#include "ui/base/models/combobox_model.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/gfx/canvas.h"
 #include "ui/gfx/color_utils.h"
@@ -225,7 +226,7 @@
 
   gfx::NativeWindow native_window =
       web_contents->GetView()->GetTopLevelNativeWindow();
-  ShellWindow* shell_window =
+  apps::ShellWindow* shell_window =
       extensions::ShellWindowRegistry::
           GetShellWindowForNativeWindowAnyProfile(native_window);
   return shell_window->GetBaseWindow();
@@ -313,6 +314,16 @@
   return true;
 }
 
+// Returns true if |profile| has an invalid address, i.e. an invalid state, zip
+// code, or phone number. Otherwise returns false. Profiles with invalid
+// addresses are not suggested in the dropdown menu for billing and shipping
+// addresses.
+bool HasInvalidAddress(const AutofillProfile& profile) {
+  return profile.IsPresentButInvalid(ADDRESS_HOME_STATE) ||
+         profile.IsPresentButInvalid(ADDRESS_HOME_ZIP) ||
+         profile.IsPresentButInvalid(PHONE_HOME_WHOLE_NUMBER);
+}
+
 // Loops through |addresses_| comparing to |address| ignoring ID. If a match
 // is not found, NULL is returned.
 const wallet::Address* FindDuplicateAddress(
@@ -566,10 +577,6 @@
     view_->Hide();
 }
 
-void AutofillDialogControllerImpl::UpdateProgressBar(double value) {
-  view_->UpdateProgressBar(value);
-}
-
 bool AutofillDialogControllerImpl::AutocheckoutIsRunning() const {
   return autocheckout_state_ == AUTOCHECKOUT_IN_PROGRESS;
 }
@@ -579,11 +586,8 @@
   GetMetricLogger().LogAutocheckoutDuration(
       base::Time::Now() - autocheckout_started_timestamp_,
       AutofillMetrics::AUTOCHECKOUT_FAILED);
-  autocheckout_state_ = AUTOCHECKOUT_ERROR;
+  SetAutocheckoutState(AUTOCHECKOUT_ERROR);
   autocheckout_started_timestamp_ = base::Time();
-  view_->UpdateNotificationArea();
-  view_->UpdateButtonStrip();
-  view_->UpdateDetailArea();
 }
 
 void AutofillDialogControllerImpl::OnAutocheckoutSuccess() {
@@ -591,10 +595,50 @@
   GetMetricLogger().LogAutocheckoutDuration(
       base::Time::Now() - autocheckout_started_timestamp_,
       AutofillMetrics::AUTOCHECKOUT_SUCCEEDED);
-  autocheckout_state_ = AUTOCHECKOUT_SUCCESS;
+  SetAutocheckoutState(AUTOCHECKOUT_SUCCESS);
   autocheckout_started_timestamp_ = base::Time();
-  view_->UpdateNotificationArea();
-  view_->UpdateButtonStrip();
+}
+
+
+TestableAutofillDialogView* AutofillDialogControllerImpl::GetTestableView() {
+  return view_ ? view_->GetTestableView() : NULL;
+}
+
+void AutofillDialogControllerImpl::AddAutocheckoutStep(
+    AutocheckoutStepType step_type) {
+  for (size_t i = 0; i < steps_.size(); ++i) {
+    if (steps_[i].type() == step_type)
+      return;
+  }
+  steps_.push_back(
+      DialogAutocheckoutStep(step_type, AUTOCHECKOUT_STEP_UNSTARTED));
+}
+
+void AutofillDialogControllerImpl::UpdateAutocheckoutStep(
+    AutocheckoutStepType step_type,
+    AutocheckoutStepStatus step_status) {
+  int total_steps = 0;
+  int completed_steps = 0;
+  for (size_t i = 0; i < steps_.size(); ++i) {
+    ++total_steps;
+    if (steps_[i].status() == AUTOCHECKOUT_STEP_COMPLETED)
+      ++completed_steps;
+    if (steps_[i].type() == step_type && steps_[i].status() != step_status)
+      steps_[i] = DialogAutocheckoutStep(step_type, step_status);
+  }
+  if (view_) {
+    view_->UpdateAutocheckoutStepsArea();
+    view_->UpdateProgressBar(1.0 * completed_steps / total_steps);
+  }
+}
+
+std::vector<DialogAutocheckoutStep>
+    AutofillDialogControllerImpl::CurrentAutocheckoutSteps() const {
+  if (autocheckout_state_ != AUTOCHECKOUT_NOT_STARTED)
+    return steps_;
+
+  std::vector<DialogAutocheckoutStep> empty_steps;
+  return empty_steps;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -625,13 +669,8 @@
   return l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_SAVE_LOCALLY_CHECKBOX);
 }
 
-string16 AutofillDialogControllerImpl::ProgressBarText() const {
-  return l10n_util::GetStringUTF16(
-      IDS_AUTOFILL_DIALOG_AUTOCHECKOUT_PROGRESS_BAR);
-}
-
 string16 AutofillDialogControllerImpl::LegalDocumentsText() {
-  if (!IsPayingWithWallet())
+  if (!IsPayingWithWallet() || autocheckout_state_ != AUTOCHECKOUT_NOT_STARTED)
     return string16();
 
   EnsureLegalDocumentsText();
@@ -678,14 +717,10 @@
 }
 
 bool AutofillDialogControllerImpl::ShouldOfferToSaveInChrome() const {
-  // If Autocheckout is running, hide this checkbox so the progress bar has some
-  // room. If Autocheckout had an error, neither the [X] Save details in chrome
-  // nor the progress bar should show.
   return !IsPayingWithWallet() &&
       !profile_->IsOffTheRecord() &&
       IsManuallyEditingAnySection() &&
-      !ShouldShowProgressBar() &&
-      autocheckout_state_ != AUTOCHECKOUT_ERROR;
+      ShouldShowDetailArea();
 }
 
 int AutofillDialogControllerImpl::GetDialogButtons() const {
@@ -741,6 +776,10 @@
 }
 
 void AutofillDialogControllerImpl::GetWalletItems() {
+  wallet_items_.reset();
+  // The "Loading..." page should be showing now, which should cause the
+  // account chooser to hide.
+  view_->UpdateAccountChooser();
   GetWalletClient()->GetWalletItems(source_url_);
 }
 
@@ -821,8 +860,7 @@
   if (!wallet_server_validation_recoverable_)
     DisableWallet(wallet::WalletClient::UNKNOWN_ERROR);
 
-  if (view_)
-    view_->UpdateForErrors();
+  UpdateForErrors();
 }
 
 void AutofillDialogControllerImpl::EnsureLegalDocumentsText() {
@@ -866,33 +904,125 @@
   legal_documents_text_ = text;
 }
 
-void AutofillDialogControllerImpl::PrepareDetailInputsForSection(
-    DialogSection section) {
+void AutofillDialogControllerImpl::ResetSectionInput(DialogSection section) {
   SetEditingExistingData(section, false);
+
+  DetailInputs* inputs = MutableRequestedFieldsForSection(section);
+  for (DetailInputs::iterator it = inputs->begin(); it != inputs->end(); ++it) {
+    it->initial_value.clear();
+  }
+}
+
+void AutofillDialogControllerImpl::ShowEditUiIfBadSuggestion(
+    DialogSection section) {
+  // |CreateWrapper()| returns an empty wrapper if |IsEditingExistingData()|, so
+  // get the wrapper before this potentially happens below.
   scoped_ptr<DataModelWrapper> wrapper = CreateWrapper(section);
 
   // If the chosen item in |model| yields an empty suggestion text, it is
-  // invalid. In this case, show the editing UI with invalid fields highlighted.
+  // invalid. In this case, show the edit UI and highlight invalid fields.
   SuggestionsMenuModel* model = SuggestionsMenuModelForSection(section);
   if (IsASuggestionItemKey(model->GetItemKeyForCheckedItem()) &&
       SuggestionTextForSection(section).empty()) {
     SetEditingExistingData(section, true);
   }
 
-  // Reset all previously entered data and stop editing |section|.
   DetailInputs* inputs = MutableRequestedFieldsForSection(section);
-  for (DetailInputs::iterator it = inputs->begin(); it != inputs->end(); ++it) {
-    it->initial_value.clear();
-    it->editable = InputIsEditable(*it, section);
-  }
-
   if (wrapper && IsEditingExistingData(section))
     wrapper->FillInputs(inputs);
 
+  for (DetailInputs::iterator it = inputs->begin(); it != inputs->end(); ++it) {
+    it->editable = InputIsEditable(*it, section);
+  }
+}
+
+bool AutofillDialogControllerImpl::InputWasEdited(const DetailInput& input,
+                                                  const base::string16& value) {
+  if (value.empty())
+    return false;
+
+  // If this is a combobox at the default value, don't preserve.
+  ui::ComboboxModel* model = ComboboxModelForAutofillType(input.type);
+  if (model && model->GetItemAt(model->GetDefaultIndex()) == value)
+    return false;
+
+  return true;
+}
+
+DetailOutputMap AutofillDialogControllerImpl::TakeUserInputSnapshot() {
+  DetailOutputMap snapshot;
+  if (!view_)
+    return snapshot;
+
+  for (size_t i = SECTION_MIN; i <= SECTION_MAX; ++i) {
+    DialogSection section = static_cast<DialogSection>(i);
+    SuggestionsMenuModel* model = SuggestionsMenuModelForSection(section);
+    if (model->GetItemKeyForCheckedItem() != kAddNewItemKey)
+      continue;
+
+    DetailOutputMap outputs;
+    view_->GetUserInput(section, &outputs);
+    // Remove fields that are empty, at their default values, or invalid.
+    for (DetailOutputMap::iterator it = outputs.begin(); it != outputs.end();
+         ++it) {
+      if (InputWasEdited(*it->first, it->second) &&
+          InputValidityMessage(section, it->first->type, it->second).empty()) {
+        snapshot.insert(std::make_pair(it->first, it->second));
+      }
+    }
+  }
+
+  return snapshot;
+}
+
+void AutofillDialogControllerImpl::RestoreUserInputFromSnapshot(
+    const DetailOutputMap& snapshot) {
+  if (snapshot.empty())
+    return;
+
+  DetailOutputWrapper wrapper(snapshot);
+  for (size_t i = SECTION_MIN; i <= SECTION_MAX; ++i) {
+    DialogSection section = static_cast<DialogSection>(i);
+    if (!SectionIsActive(section))
+      continue;
+
+    DetailInputs* inputs = MutableRequestedFieldsForSection(section);
+    wrapper.FillInputs(inputs);
+
+    for (size_t i = 0; i < inputs->size(); ++i) {
+      if (InputWasEdited((*inputs)[i], (*inputs)[i].initial_value)) {
+        SuggestionsMenuModelForSection(section)->SetCheckedItem(kAddNewItemKey);
+        break;
+      }
+    }
+  }
+}
+
+void AutofillDialogControllerImpl::UpdateSection(DialogSection section) {
   if (view_)
     view_->UpdateSection(section);
 }
 
+void AutofillDialogControllerImpl::UpdateForErrors() {
+  if (!view_)
+    return;
+
+  // Currently, the view should only need to be updated if there are
+  // |wallet_errors_| or validating a suggestion that's based on existing data.
+  bool should_update = !wallet_errors_.empty();
+  if (!should_update) {
+    for (size_t i = SECTION_MIN; i <= SECTION_MAX; ++i) {
+      if (IsEditingExistingData(static_cast<DialogSection>(i))) {
+        should_update = true;
+        break;
+      }
+    }
+  }
+
+  if (should_update)
+    view_->UpdateForErrors();
+}
+
 const DetailInputs& AutofillDialogControllerImpl::RequestedFieldsForSection(
     DialogSection section) const {
   switch (section) {
@@ -1045,10 +1175,8 @@
   if (!IsASuggestionItemKey(item_key))
     return string16();
 
-  if (section == SECTION_EMAIL) {
-    string16 email_address = model->GetLabelAt(model->checked_item());
-    return IsValidEmailAddress(email_address) ? email_address : string16();
-  }
+  if (section == SECTION_EMAIL)
+    return model->GetLabelAt(model->checked_item());
 
   scoped_ptr<DataModelWrapper> wrapper = CreateWrapper(section);
   return wrapper->GetDisplayText();
@@ -1208,7 +1336,7 @@
   }
   model->FillInputs(inputs);
 
-  view_->UpdateSection(section);
+  UpdateSection(section);
 
   GetMetricLogger().LogDialogUiEvent(
       GetDialogType(), DialogSectionToUiEditEvent(section));
@@ -1216,7 +1344,8 @@
 
 void AutofillDialogControllerImpl::EditCancelledForSection(
     DialogSection section) {
-  PrepareDetailInputsForSection(section);
+  ResetSectionInput(section);
+  UpdateSection(section);
 }
 
 gfx::Image AutofillDialogControllerImpl::IconForField(
@@ -1295,8 +1424,14 @@
       }
       break;
 
-    case CREDIT_CARD_NUMBER:
-      return CreditCardNumberValidityMessage(value);
+    case CREDIT_CARD_NUMBER: {
+      if (!value.empty()) {
+        base::string16 message = CreditCardNumberValidityMessage(value);
+        if (!message.empty())
+          return message;
+      }
+      break;
+    }
 
     case CREDIT_CARD_NAME:
       // Wallet requires a first and last name.
@@ -1517,9 +1652,8 @@
   int show_count =
       profile_->GetPrefs()->GetInteger(::prefs::kAutofillDialogShowCount);
   if (show_count <= 4) {
-    // TODO(estade): this logo is not the right size.
     return ui::ResourceBundle::GetSharedInstance().GetImageNamed(
-        IDR_PRODUCT_LOGO);
+        IDR_PRODUCT_LOGO_NAME_48);
   }
 
   return gfx::Image();
@@ -1538,30 +1672,10 @@
     CurrentNotifications() {
   std::vector<DialogNotification> notifications;
 
-  if (account_chooser_model_.HadWalletError()) {
-    // TODO(dbeam): figure out a way to dismiss this error after a while.
+  if (IsPayingWithWallet() && !wallet::IsUsingProd()) {
     notifications.push_back(DialogNotification(
-        DialogNotification::WALLET_ERROR,
-        l10n_util::GetStringFUTF16(
-            IDS_AUTOFILL_DIALOG_COMPLETE_WITHOUT_WALLET,
-            account_chooser_model_.wallet_error_message())));
-  } else if (should_show_wallet_promo_) {
-    if (IsPayingWithWallet() && HasCompleteWallet()) {
-      notifications.push_back(DialogNotification(
-          DialogNotification::EXPLANATORY_MESSAGE,
-          l10n_util::GetStringUTF16(
-              IDS_AUTOFILL_DIALOG_DETAILS_FROM_WALLET)));
-    } else if ((IsPayingWithWallet() && !HasCompleteWallet()) ||
-               has_shown_wallet_usage_confirmation_) {
-      DialogNotification notification(
-          DialogNotification::WALLET_USAGE_CONFIRMATION,
-          l10n_util::GetStringUTF16(
-              IDS_AUTOFILL_DIALOG_SAVE_DETAILS_IN_WALLET));
-      notification.set_checked(account_chooser_model_.WalletIsSelected());
-      notification.set_interactive(!is_submitting_);
-      notifications.push_back(notification);
-      has_shown_wallet_usage_confirmation_ = true;
-    }
+        DialogNotification::DEVELOPER_WARNING,
+        l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_NOT_PROD_WARNING)));
   }
 
   if (RequestingCreditCardInfo() && !TransmissionWillBeSecure()) {
@@ -1577,6 +1691,15 @@
                                    UTF8ToUTF16(source_url_.host()))));
   }
 
+  if (account_chooser_model_.HadWalletError()) {
+    // TODO(dbeam): figure out a way to dismiss this error after a while.
+    notifications.push_back(DialogNotification(
+        DialogNotification::WALLET_ERROR,
+        l10n_util::GetStringFUTF16(
+            IDS_AUTOFILL_DIALOG_COMPLETE_WITHOUT_WALLET,
+            account_chooser_model_.wallet_error_message())));
+  }
+
   if (IsSubmitPausedOn(wallet::VERIFY_CVV)) {
     notifications.push_back(DialogNotification(
         DialogNotification::REQUIRED_ACTION,
@@ -1602,18 +1725,32 @@
         ASCIIToUTF16("Could not save Wallet data")));
   }
 
-  if (IsPayingWithWallet() && !wallet::IsUsingProd()) {
-    notifications.push_back(DialogNotification(
-        DialogNotification::DEVELOPER_WARNING,
-        l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_NOT_PROD_WARNING)));
-  }
-
   if (choose_another_instrument_or_address_) {
     notifications.push_back(DialogNotification(
         DialogNotification::REQUIRED_ACTION,
         ASCIIToUTF16("We need more information to complete your purchase.")));
   }
 
+  if (should_show_wallet_promo_ && ShouldShowDetailArea() &&
+      notifications.empty()) {
+    if (IsPayingWithWallet() && HasCompleteWallet()) {
+      notifications.push_back(DialogNotification(
+          DialogNotification::EXPLANATORY_MESSAGE,
+          l10n_util::GetStringUTF16(
+              IDS_AUTOFILL_DIALOG_DETAILS_FROM_WALLET)));
+    } else if ((IsPayingWithWallet() && !HasCompleteWallet()) ||
+               has_shown_wallet_usage_confirmation_) {
+      DialogNotification notification(
+          DialogNotification::WALLET_USAGE_CONFIRMATION,
+          l10n_util::GetStringUTF16(
+              IDS_AUTOFILL_DIALOG_SAVE_DETAILS_IN_WALLET));
+      notification.set_checked(account_chooser_model_.WalletIsSelected());
+      notification.set_interactive(!is_submitting_);
+      notifications.push_back(notification);
+      has_shown_wallet_usage_confirmation_ = true;
+    }
+  }
+
   return notifications;
 }
 
@@ -1672,6 +1809,21 @@
   choose_another_instrument_or_address_ = false;
   wallet_server_validation_recoverable_ = true;
   HidePopup();
+  if (IsPayingWithWallet()) {
+    bool has_proxy_card_step = false;
+    for (size_t i = 0; i < steps_.size(); ++i) {
+      if (steps_[i].type() == AUTOCHECKOUT_STEP_PROXY_CARD) {
+        has_proxy_card_step = true;
+        break;
+      }
+    }
+    if (!has_proxy_card_step) {
+      steps_.insert(steps_.begin(),
+                    DialogAutocheckoutStep(AUTOCHECKOUT_STEP_PROXY_CARD,
+                                           AUTOCHECKOUT_STEP_UNSTARTED));
+    }
+  }
+
   SetIsSubmitting(true);
   if (IsSubmitPausedOn(wallet::VERIFY_CVV)) {
     DCHECK(!active_instrument_id_.empty());
@@ -1680,7 +1832,9 @@
         UTF16ToUTF8(view_->GetCvc()),
         wallet_items_->obfuscated_gaia_id());
   } else if (IsPayingWithWallet()) {
-    SubmitWithWallet();
+    // TODO(dbeam): disallow interacting with the dialog while submitting.
+    // http://crbug.com/230932
+    AcceptLegalDocuments();
   } else {
     FinishSubmit();
   }
@@ -1757,9 +1911,9 @@
       content::Details<content::LoadCommittedDetails>(details).ptr();
   if (wallet::IsSignInContinueUrl(load_details->entry->GetVirtualURL())) {
     should_show_wallet_promo_ = false;
-    HideSignIn();
     account_chooser_model_.SelectActiveWalletAccount();
     GetWalletItems();
+    HideSignIn();
   }
 }
 
@@ -1784,7 +1938,11 @@
   }
 
   model->SetCheckedIndex(index);
-  PrepareDetailInputsForSection(SectionForSuggestionsMenuModel(*model));
+  DialogSection section = SectionForSuggestionsMenuModel(*model);
+  ResetSectionInput(section);
+  ShowEditUiIfBadSuggestion(section);
+  UpdateSection(section);
+  UpdateForErrors();
 
   LogSuggestionItemSelectedMetric(*model);
 }
@@ -1801,12 +1959,12 @@
 }
 
 std::string AutofillDialogControllerImpl::GetRiskData() const {
-  return risk_data_.empty() ? "no pagers" : risk_data_;
+  DCHECK(!risk_data_.empty());
+  return risk_data_;
 }
 
 void AutofillDialogControllerImpl::OnDidAcceptLegalDocuments() {
   DCHECK(is_submitting_ && IsPayingWithWallet());
-
   has_accepted_legal_documents_ = true;
   LoadRiskFingerprintData();
 }
@@ -1815,10 +1973,12 @@
   DCHECK(is_submitting_ && IsPayingWithWallet());
 
   // TODO(dbeam): use the returned full wallet. b/8332329
-  if (success)
+  if (success) {
     GetFullWallet();
-  else
+  } else {
     DisableWallet(wallet::WalletClient::UNKNOWN_ERROR);
+    SuggestionsUpdated();
+  }
 }
 
 void AutofillDialogControllerImpl::OnDidGetFullWallet(
@@ -1828,23 +1988,25 @@
   full_wallet_ = full_wallet.Pass();
 
   if (full_wallet_->required_actions().empty()) {
+    UpdateAutocheckoutStep(AUTOCHECKOUT_STEP_PROXY_CARD,
+                           AUTOCHECKOUT_STEP_COMPLETED);
     FinishSubmit();
     return;
   }
 
+  SetAutocheckoutState(AUTOCHECKOUT_NOT_STARTED);
+
   switch (full_wallet_->required_actions()[0]) {
     case wallet::CHOOSE_ANOTHER_INSTRUMENT_OR_ADDRESS:
       choose_another_instrument_or_address_ = true;
       SetIsSubmitting(false);
+      GetWalletItems();
       view_->UpdateNotificationArea();
       view_->UpdateButtonStrip();
-      GetWalletItems();
       break;
 
     case wallet::VERIFY_CVV:
       SuggestionsUpdated();
-      view_->UpdateNotificationArea();
-      view_->UpdateButtonStrip();
       break;
 
     default:
@@ -2080,10 +2242,6 @@
 }
 
 void AutofillDialogControllerImpl::LoadRiskFingerprintData() {
-  DCHECK(AreLegalDocumentsCurrent());
-
-  // Clear potential stale data to ensure |GetFullWalletIfReady()| triggers only
-  // when a new fingerprint is loaded.
   risk_data_.clear();
 
   uint64 obfuscated_gaia_id = 0;
@@ -2123,7 +2281,7 @@
   bool success = base::Base64Encode(proto_data, &risk_data_);
   DCHECK(success);
 
-  GetFullWalletIfReady();
+  SubmitWithWallet();
 }
 
 void AutofillDialogControllerImpl::OpenTabWithUrl(const GURL& url) {
@@ -2139,6 +2297,18 @@
 #endif
 }
 
+bool AutofillDialogControllerImpl::IsEditingExistingData(
+    DialogSection section) const {
+  return section_editing_state_.count(section) > 0;
+}
+
+bool AutofillDialogControllerImpl::IsManuallyEditingSection(
+    DialogSection section) const {
+  return IsEditingExistingData(section) ||
+         SuggestionsMenuModelForSection(section)->
+             GetItemKeyForCheckedItem() == kAddNewItemKey;
+}
+
 void AutofillDialogControllerImpl::OnWalletSigninError() {
   signin_helper_.reset();
   account_chooser_model_.SetHadWalletSigninError();
@@ -2152,11 +2322,21 @@
   wallet_items_.reset();
   wallet_errors_.clear();
   GetWalletClient()->CancelRequests();
+  SetAutocheckoutState(AUTOCHECKOUT_NOT_STARTED);
+  for (std::vector<DialogAutocheckoutStep>::iterator it = steps_.begin();
+      it != steps_.end(); ++it) {
+    if (it->type() == AUTOCHECKOUT_STEP_PROXY_CARD) {
+      steps_.erase(it);
+      break;
+    }
+  }
   SetIsSubmitting(false);
   account_chooser_model_.SetHadWalletError(WalletErrorMessage(error_type));
 }
 
 void AutofillDialogControllerImpl::SuggestionsUpdated() {
+  const DetailOutputMap snapshot = TakeUserInputSnapshot();
+
   suggested_email_.Reset();
   suggested_cc_.Reset();
   suggested_billing_.Reset();
@@ -2257,14 +2437,17 @@
     const std::vector<AutofillProfile*>& profiles = manager->GetProfiles();
     const std::string app_locale = g_browser_process->GetApplicationLocale();
     for (size_t i = 0; i < profiles.size(); ++i) {
-      if (!HasCompleteAndVerifiedData(*profiles[i], requested_shipping_fields_))
+      if (!HasCompleteAndVerifiedData(*profiles[i],
+                                      requested_shipping_fields_) ||
+          HasInvalidAddress(*profiles[i])) {
         continue;
+      }
 
       // Add all email addresses.
       std::vector<string16> values;
       profiles[i]->GetMultiInfo(EMAIL_ADDRESS, app_locale, &values);
       for (size_t j = 0; j < values.size(); ++j) {
-        if (!values[j].empty())
+        if (IsValidEmailAddress(values[j]))
           suggested_email_.AddKeyedItem(profiles[i]->guid(), values[j]);
       }
 
@@ -2331,9 +2514,19 @@
   if (view_)
     view_->ModelChanged();
 
-  for (size_t section = SECTION_MIN; section <= SECTION_MAX; ++section) {
-    PrepareDetailInputsForSection(static_cast<DialogSection>(section));
+  for (size_t i = SECTION_MIN; i <= SECTION_MAX; ++i) {
+    ResetSectionInput(static_cast<DialogSection>(i));
   }
+
+  RestoreUserInputFromSnapshot(snapshot);
+
+  for (size_t i = SECTION_MIN; i <= SECTION_MAX; ++i) {
+    DialogSection section = static_cast<DialogSection>(i);
+    ShowEditUiIfBadSuggestion(section);
+    UpdateSection(section);
+  }
+
+  UpdateForErrors();
 }
 
 void AutofillDialogControllerImpl::FillOutputForSectionWithComparator(
@@ -2529,11 +2722,6 @@
   input_showing_popup_ = NULL;
 }
 
-bool AutofillDialogControllerImpl::IsEditingExistingData(
-    DialogSection section) const {
-  return section_editing_state_.count(section) > 0;
-}
-
 void AutofillDialogControllerImpl::SetEditingExistingData(
     DialogSection section, bool editing) {
   if (editing)
@@ -2542,13 +2730,6 @@
     section_editing_state_.erase(section);
 }
 
-bool AutofillDialogControllerImpl::IsManuallyEditingSection(
-    DialogSection section) const {
-  return IsEditingExistingData(section) ||
-         SuggestionsMenuModelForSection(section)->
-             GetItemKeyForCheckedItem() == kAddNewItemKey;
-}
-
 bool AutofillDialogControllerImpl::IsASuggestionItemKey(
     const std::string& key) const {
   return !key.empty() &&
@@ -2671,17 +2852,10 @@
       (wallet_items_ && wallet_items_->legal_documents().empty());
 }
 
-void AutofillDialogControllerImpl::SubmitWithWallet() {
-  // TODO(dbeam): disallow interacting with the dialog while submitting.
-  // http://crbug.com/230932
-
-  active_instrument_id_.clear();
-  active_address_id_.clear();
-  full_wallet_.reset();
-
+void AutofillDialogControllerImpl::AcceptLegalDocuments() {
   content::BrowserThread::PostTask(
-     content::BrowserThread::IO, FROM_HERE,
-     base::Bind(&UserDidOptIntoLocationServices));
+      content::BrowserThread::IO, FROM_HERE,
+      base::Bind(&UserDidOptIntoLocationServices));
 
   GetWalletClient()->AcceptLegalDocuments(
       wallet_items_->legal_documents(),
@@ -2690,6 +2864,12 @@
 
   if (AreLegalDocumentsCurrent())
     LoadRiskFingerprintData();
+}
+
+void AutofillDialogControllerImpl::SubmitWithWallet() {
+  active_instrument_id_.clear();
+  active_address_id_.clear();
+  full_wallet_.reset();
 
   const wallet::WalletItems::MaskedInstrument* active_instrument =
       ActiveInstrument();
@@ -2705,6 +2885,11 @@
     DCHECK(!active_address_id_.empty());
   }
 
+  if (GetDialogType() == DIALOG_TYPE_AUTOCHECKOUT) {
+    DCHECK_EQ(AUTOCHECKOUT_NOT_STARTED, autocheckout_state_);
+    SetAutocheckoutState(AUTOCHECKOUT_IN_PROGRESS);
+  }
+
   scoped_ptr<wallet::Instrument> inputted_instrument =
       CreateTransientInstrument();
   scoped_ptr<wallet::WalletClient::UpdateInstrumentRequest> update_request =
@@ -2740,8 +2925,10 @@
 
   // If there's neither an address nor instrument to save, |GetFullWallet()|
   // is called when the risk fingerprint is loaded.
-  if (!active_instrument_id_.empty() && !active_address_id_.empty())
+  if (!active_instrument_id_.empty() && !active_address_id_.empty()) {
+    GetFullWallet();
     return;
+  }
 
   // If instrument and address aren't based off of any existing data, save both.
   if (inputted_instrument && inputted_address && !update_request &&
@@ -2832,6 +3019,9 @@
   std::vector<wallet::WalletClient::RiskCapability> capabilities;
   capabilities.push_back(wallet::WalletClient::VERIFY_CVC);
 
+  UpdateAutocheckoutStep(AUTOCHECKOUT_STEP_PROXY_CARD,
+                         AUTOCHECKOUT_STEP_STARTED);
+
   GetWalletClient()->GetFullWallet(wallet::WalletClient::FullWalletRequest(
       active_instrument_id_,
       active_address_id_,
@@ -2844,10 +3034,8 @@
   DCHECK(is_submitting_);
   DCHECK(IsPayingWithWallet());
 
-  if (!active_instrument_id_.empty() && !active_address_id_.empty() &&
-      !risk_data_.empty()) {
+  if (!active_instrument_id_.empty() && !active_address_id_.empty())
     GetFullWallet();
-  }
 }
 
 void AutofillDialogControllerImpl::HandleSaveOrUpdateRequiredActions(
@@ -2864,7 +3052,7 @@
       DisableWallet(wallet::WalletClient::UNKNOWN_ERROR);
     }
   }
-
+  SetAutocheckoutState(AUTOCHECKOUT_NOT_STARTED);
   SetIsSubmitting(false);
 }
 
@@ -2922,11 +3110,7 @@
     // in an Autocheckout flow.
     GetManager()->RemoveObserver(this);
     autocheckout_started_timestamp_ = base::Time::Now();
-    DCHECK_EQ(AUTOCHECKOUT_NOT_STARTED, autocheckout_state_);
-    autocheckout_state_ = AUTOCHECKOUT_IN_PROGRESS;
-    view_->UpdateButtonStrip();
-    view_->UpdateDetailArea();
-    view_->UpdateNotificationArea();
+    SetAutocheckoutState(AUTOCHECKOUT_IN_PROGRESS);
   }
 
   LogOnFinishSubmitMetrics();
@@ -3076,6 +3260,20 @@
   was_ui_latency_logged_ = true;
 }
 
+void AutofillDialogControllerImpl::SetAutocheckoutState(
+    AutocheckoutState autocheckout_state) {
+  if (autocheckout_state_ == autocheckout_state)
+    return;
+
+  autocheckout_state_ = autocheckout_state;
+  if (view_) {
+    view_->UpdateDetailArea();
+    view_->UpdateButtonStrip();
+    view_->UpdateAutocheckoutStepsArea();
+    view_->UpdateNotificationArea();
+  }
+}
+
 AutofillMetrics::DialogInitialUserStateMetric
     AutofillDialogControllerImpl::GetInitialUserState() const {
   // Consider a user to be an Autofill user if the user has any credit cards
diff --git a/chrome/browser/ui/autofill/autofill_dialog_controller_impl.h b/chrome/browser/ui/autofill/autofill_dialog_controller_impl.h
index cf4587a..598c6e5 100644
--- a/chrome/browser/ui/autofill/autofill_dialog_controller_impl.h
+++ b/chrome/browser/ui/autofill/autofill_dialog_controller_impl.h
@@ -12,24 +12,25 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/strings/string16.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/ui/autofill/account_chooser_model.h"
 #include "chrome/browser/ui/autofill/autofill_dialog_controller.h"
 #include "chrome/browser/ui/autofill/autofill_dialog_models.h"
 #include "chrome/browser/ui/autofill/autofill_dialog_types.h"
 #include "chrome/browser/ui/autofill/autofill_popup_controller_impl.h"
 #include "chrome/browser/ui/autofill/country_combobox_model.h"
-#include "components/autofill/browser/autofill_manager_delegate.h"
-#include "components/autofill/browser/autofill_metrics.h"
-#include "components/autofill/browser/autofill_popup_delegate.h"
-#include "components/autofill/browser/field_types.h"
-#include "components/autofill/browser/form_structure.h"
-#include "components/autofill/browser/personal_data_manager.h"
-#include "components/autofill/browser/personal_data_manager_observer.h"
+#include "components/autofill/content/browser/autocheckout_steps.h"
 #include "components/autofill/content/browser/wallet/wallet_client.h"
 #include "components/autofill/content/browser/wallet/wallet_client_delegate.h"
 #include "components/autofill/content/browser/wallet/wallet_items.h"
 #include "components/autofill/content/browser/wallet/wallet_signin_helper_delegate.h"
+#include "components/autofill/core/browser/autofill_manager_delegate.h"
+#include "components/autofill/core/browser/autofill_metrics.h"
+#include "components/autofill/core/browser/autofill_popup_delegate.h"
+#include "components/autofill/core/browser/field_types.h"
+#include "components/autofill/core/browser/form_structure.h"
+#include "components/autofill/core/browser/personal_data_manager.h"
+#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/common/ssl_status.h"
@@ -53,6 +54,7 @@
 class AutofillDialogView;
 class AutofillPopupControllerImpl;
 class DataModelWrapper;
+class TestableAutofillDialogView;
 
 namespace risk {
 class Fingerprint;
@@ -88,19 +90,26 @@
   void Show();
   void Hide();
 
-  // Updates the progress bar based on the Autocheckout progress. |value| should
-  // be in [0.0, 1.0].
-  void UpdateProgressBar(double value);
-
   // Whether Autocheckout is currently running.
   bool AutocheckoutIsRunning() const;
 
+  // Adds a step in the flow to the Autocheckout UI.
+  void AddAutocheckoutStep(AutocheckoutStepType step_type);
+
+  // Updates the status of a step in the Autocheckout UI.
+  void UpdateAutocheckoutStep(AutocheckoutStepType step_type,
+                              AutocheckoutStepStatus step_status);
+
   // Called when there is an error in an active Autocheckout flow.
   void OnAutocheckoutError();
 
   // Called when an Autocheckout flow completes successfully.
   void OnAutocheckoutSuccess();
 
+  // Returns |view_| as a testable version of itself (if |view_| exists and
+  // actually implements |AutofillDialogView::GetTestableView()|).
+  TestableAutofillDialogView* GetTestableView();
+
   // AutofillDialogController implementation.
   virtual string16 DialogTitle() const OVERRIDE;
   virtual string16 AccountChooserText() const OVERRIDE;
@@ -109,7 +118,6 @@
   virtual string16 CancelButtonText() const OVERRIDE;
   virtual string16 ConfirmButtonText() const OVERRIDE;
   virtual string16 SaveLocallyText() const OVERRIDE;
-  virtual string16 ProgressBarText() const OVERRIDE;
   virtual string16 LegalDocumentsText() OVERRIDE;
   virtual DialogSignedInState SignedInState() const OVERRIDE;
   virtual bool ShouldShowSpinner() const OVERRIDE;
@@ -157,6 +165,8 @@
   virtual gfx::Image SplashPageImage() const OVERRIDE;
   virtual void ViewClosed() OVERRIDE;
   virtual std::vector<DialogNotification> CurrentNotifications() OVERRIDE;
+  virtual std::vector<DialogAutocheckoutStep> CurrentAutocheckoutSteps()
+      const OVERRIDE;
   virtual void SignInLinkClicked() OVERRIDE;
   virtual void NotificationCheckboxStateChanged(DialogNotification::Type type,
                                                 bool checked) OVERRIDE;
@@ -283,18 +293,22 @@
   // happens when a user clicks "Edit" or a suggestion is invalid.
   virtual bool IsEditingExistingData(DialogSection section) const;
 
+  // Whether the user has chosen to enter all new data in |section|. This
+  // happens via choosing "Add a new X..." from a section's suggestion menu.
+  bool IsManuallyEditingSection(DialogSection section) const;
+
   // Should be called on the Wallet sign-in error.
   virtual void OnWalletSigninError();
 
+  // Whether the information input in this dialog will be securely transmitted
+  // to the requesting site.
+  virtual bool TransmissionWillBeSecure() const;
+
  private:
   // Whether or not the current request wants credit info back.
   bool RequestingCreditCardInfo() const;
 
-  // Whether the information input in this dialog will be securely transmitted
-  // to the requesting site.
-  bool TransmissionWillBeSecure() const;
-
-  // Initializes |suggested_email_| et al.
+  // Initializes or updates |suggested_email_| et al.
   void SuggestionsUpdated();
 
   // Whether the user's wallet items have at least one address and instrument.
@@ -321,9 +335,32 @@
   // they have not already been calculated.
   void EnsureLegalDocumentsText();
 
-  // Clears previously entered manual input, shows editing UI if the current
-  // suggestion is invalid, and updates the |view_| (if it exists).
-  void PrepareDetailInputsForSection(DialogSection section);
+  // Clears previously entered manual input and removes |section| from
+  // |section_editing_state_|. Does not update the view.
+  void ResetSectionInput(DialogSection section);
+
+  // Force |section| into edit mode if the current suggestion is invalid.
+  void ShowEditUiIfBadSuggestion(DialogSection section);
+
+  // Whether the |value| of |input| should be preserved on account change.
+  bool InputWasEdited(const DetailInput& input,
+                      const base::string16& value);
+
+  // Takes a snapshot of the newly inputted user data in |view_| (if it exists).
+  DetailOutputMap TakeUserInputSnapshot();
+
+  // Fills the detail inputs from a previously taken user input snapshot. Does
+  // not update the view.
+  void RestoreUserInputFromSnapshot(const DetailOutputMap& snapshot);
+
+  // Tells the view to update |section|.
+  void UpdateSection(DialogSection section);
+
+  // Tells |view_| to update the validity status of its detail inputs (if
+  // |view_| is non-null). Currently this is used solely for highlighting
+  // invalid suggestions, so if no sections are based on existing data,
+  // |view_->UpdateForErrors()| is not called.
+  void UpdateForErrors();
 
   // Creates a DataModelWrapper item for the item that's checked in the
   // suggestion model for |section|. This may represent Autofill
@@ -403,10 +440,6 @@
   // existing Wallet or Autofill data.
   void SetEditingExistingData(DialogSection section, bool editing);
 
-  // Whether the user has chosen to enter all new data in |section|. This
-  // happens via choosing "Add a new X..." from a section's suggestion menu.
-  bool IsManuallyEditingSection(DialogSection section) const;
-
   // Whether the user has chosen to enter all new data in at least one section.
   bool IsManuallyEditingAnySection() const;
 
@@ -446,6 +479,9 @@
   // Whether the user has accepted all the current legal documents' terms.
   bool AreLegalDocumentsCurrent() const;
 
+  // Accepts any pending legal documents now that the user has pressed Submit.
+  void AcceptLegalDocuments();
+
   // Start the submit proccess to interact with Online Wallet (might do various
   // things like accept documents, save details, update details, respond to
   // required actions, etc.).
@@ -518,6 +554,9 @@
   // interact with it.
   void LogDialogLatencyToShow();
 
+  // Sets the state of the autocheckout flow.
+  void SetAutocheckoutState(AutocheckoutState autocheckout_state);
+
   // Returns the metric corresponding to the user's initial state when
   // interacting with this dialog.
   AutofillMetrics::DialogInitialUserStateMetric GetInitialUserState() const;
@@ -666,6 +705,10 @@
   // Whether the latency to display to the UI was logged to UMA yet.
   bool was_ui_latency_logged_;
 
+  // State of steps in the current Autocheckout flow, or empty if not an
+  // Autocheckout use case.
+  std::vector<DialogAutocheckoutStep> steps_;
+
   DISALLOW_COPY_AND_ASSIGN(AutofillDialogControllerImpl);
 };
 
diff --git a/chrome/browser/ui/autofill/autofill_dialog_controller_unittest.cc b/chrome/browser/ui/autofill/autofill_dialog_controller_unittest.cc
index ab4557d..6249f5d 100644
--- a/chrome/browser/ui/autofill/autofill_dialog_controller_unittest.cc
+++ b/chrome/browser/ui/autofill/autofill_dialog_controller_unittest.cc
@@ -16,9 +16,6 @@
 #include "chrome/browser/ui/autofill/autofill_dialog_view.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/testing_profile.h"
-#include "components/autofill/browser/autofill_common_test.h"
-#include "components/autofill/browser/autofill_metrics.h"
-#include "components/autofill/browser/test_personal_data_manager.h"
 #include "components/autofill/content/browser/risk/proto/fingerprint.pb.h"
 #include "components/autofill/content/browser/wallet/full_wallet.h"
 #include "components/autofill/content/browser/wallet/instrument.h"
@@ -26,6 +23,9 @@
 #include "components/autofill/content/browser/wallet/wallet_client.h"
 #include "components/autofill/content/browser/wallet/wallet_service_url.h"
 #include "components/autofill/content/browser/wallet/wallet_test_util.h"
+#include "components/autofill/core/browser/autofill_common_test.h"
+#include "components/autofill/core/browser/autofill_metrics.h"
+#include "components/autofill/core/browser/test_personal_data_manager.h"
 #include "components/autofill/core/common/autofill_switches.h"
 #include "components/autofill/core/common/form_data.h"
 #include "content/public/browser/web_contents.h"
@@ -91,6 +91,13 @@
   }
 }
 
+scoped_ptr<wallet::WalletItems> CompleteAndValidWalletItems() {
+  scoped_ptr<wallet::WalletItems> items = wallet::GetTestWalletItems();
+  items->AddInstrument(wallet::GetTestMaskedInstrument());
+  items->AddAddress(wallet::GetTestShippingAddress());
+  return items.Pass();
+}
+
 scoped_ptr<wallet::FullWallet> CreateFullWallet(const char* required_action) {
   base::DictionaryValue dict;
   scoped_ptr<base::ListValue> list(new base::ListValue());
@@ -118,6 +125,7 @@
   virtual void UpdateAccountChooser() OVERRIDE {}
   virtual void UpdateButtonStrip() OVERRIDE {}
   virtual void UpdateDetailArea() OVERRIDE {}
+  virtual void UpdateAutocheckoutStepsArea() OVERRIDE {}
   virtual void UpdateSection(DialogSection section) OVERRIDE {}
   virtual void FillSection(DialogSection section,
                            const DetailInput& originating_input) OVERRIDE {};
@@ -294,6 +302,12 @@
     open_tab_url_ = url;
   }
 
+  // Whether the information input in this dialog will be securely transmitted
+  // to the requesting site.
+  virtual bool TransmissionWillBeSecure() const OVERRIDE {
+    return true;
+  }
+
  private:
   // To specify our own metric logger.
   virtual const AutofillMetrics& GetMetricLogger() const OVERRIDE {
@@ -412,6 +426,16 @@
     EXPECT_EQ(should_pass ? 0U : 1U, validity_data.count(CREDIT_CARD_NUMBER));
   }
 
+  void SubmitWithWalletItems(scoped_ptr<wallet::WalletItems> wallet_items) {
+    controller()->OnDidGetWalletItems(wallet_items.Pass());
+    AcceptAndLoadFakeFingerprint();
+  }
+
+  void AcceptAndLoadFakeFingerprint() {
+    controller()->OnAccept();
+    controller()->OnDidLoadRiskFingerprintData(GetFakeFingerprint().Pass());
+  }
+
   TestAutofillDialogController* controller() { return controller_.get(); }
 
   TestingProfile* profile() { return &profile_; }
@@ -796,7 +820,7 @@
   EXPECT_EQ(1, email_suggestions->checked_item());
 }
 
-TEST_F(AutofillDialogControllerTest, ValidSavedEmail) {
+TEST_F(AutofillDialogControllerTest, SuggestValidEmail) {
   AutofillProfile profile(test::GetVerifiedProfile());
   const string16 kValidEmail = ASCIIToUTF16(kFakeEmail);
   profile.SetRawInfo(EMAIL_ADDRESS, kValidEmail);
@@ -807,14 +831,47 @@
             controller()->SuggestionStateForSection(SECTION_EMAIL).text);
 }
 
-TEST_F(AutofillDialogControllerTest, InvalidSavedEmail) {
+TEST_F(AutofillDialogControllerTest, DoNotSuggestInvalidEmail) {
   AutofillProfile profile(test::GetVerifiedProfile());
   profile.SetRawInfo(EMAIL_ADDRESS, ASCIIToUTF16(".!#$%&'*+/=?^_`-@-.."));
   controller()->GetTestingManager()->AddTestingProfile(&profile);
+  EXPECT_EQ(static_cast<ui::MenuModel*>(NULL),
+            controller()->MenuModelForSection(SECTION_EMAIL));
+}
 
-  controller()->MenuModelForSection(SECTION_EMAIL)->ActivatedAt(0);
-  EXPECT_TRUE(
-      controller()->SuggestionStateForSection(SECTION_EMAIL).text.empty());
+TEST_F(AutofillDialogControllerTest, DoNotSuggestEmailFromIncompleteProfile) {
+  AutofillProfile profile(test::GetVerifiedProfile());
+  profile.SetRawInfo(EMAIL_ADDRESS, ASCIIToUTF16(kFakeEmail));
+  profile.SetRawInfo(ADDRESS_HOME_STATE, base::string16());
+  controller()->GetTestingManager()->AddTestingProfile(&profile);
+  EXPECT_EQ(static_cast<ui::MenuModel*>(NULL),
+            controller()->MenuModelForSection(SECTION_EMAIL));
+}
+
+TEST_F(AutofillDialogControllerTest, DoNotSuggestEmailFromInvalidProfile) {
+  AutofillProfile profile(test::GetVerifiedProfile());
+  profile.SetRawInfo(EMAIL_ADDRESS, ASCIIToUTF16(kFakeEmail));
+  profile.SetRawInfo(ADDRESS_HOME_STATE, ASCIIToUTF16("C"));
+  controller()->GetTestingManager()->AddTestingProfile(&profile);
+  EXPECT_EQ(static_cast<ui::MenuModel*>(NULL),
+            controller()->MenuModelForSection(SECTION_EMAIL));
+}
+
+TEST_F(AutofillDialogControllerTest, SuggestValidAddress) {
+  AutofillProfile full_profile(test::GetVerifiedProfile());
+  full_profile.set_origin(kSettingsOrigin);
+  controller()->GetTestingManager()->AddTestingProfile(&full_profile);
+  EXPECT_EQ(
+      4, controller()->MenuModelForSection(SECTION_SHIPPING)->GetItemCount());
+}
+
+TEST_F(AutofillDialogControllerTest, DoNotSuggestInvalidAddress) {
+  AutofillProfile full_profile(test::GetVerifiedProfile());
+  full_profile.set_origin(kSettingsOrigin);
+  full_profile.SetRawInfo(ADDRESS_HOME_STATE, ASCIIToUTF16("C"));
+  controller()->GetTestingManager()->AddTestingProfile(&full_profile);
+  EXPECT_EQ(
+      3, controller()->MenuModelForSection(SECTION_SHIPPING)->GetItemCount());
 }
 
 TEST_F(AutofillDialogControllerTest, AutofillCreditCards) {
@@ -964,10 +1021,8 @@
               GetFullWallet(_)).Times(1);
   EXPECT_CALL(*controller(), LoadRiskFingerprintData()).Times(1);
 
-  scoped_ptr<wallet::WalletItems> wallet_items = wallet::GetTestWalletItems();
+  scoped_ptr<wallet::WalletItems> wallet_items = CompleteAndValidWalletItems();
   wallet_items->AddLegalDocument(wallet::GetTestLegalDocument());
-  wallet_items->AddInstrument(wallet::GetTestMaskedInstrument());
-  wallet_items->AddAddress(wallet::GetTestShippingAddress());
   controller()->OnDidGetWalletItems(wallet_items.Pass());
   controller()->OnAccept();
   controller()->OnDidAcceptLegalDocuments();
@@ -1063,7 +1118,7 @@
   ui::MenuModel* shipping_model =
       controller()->MenuModelForSection(SECTION_SHIPPING);
   shipping_model->ActivatedAt(shipping_model->GetItemCount() - 1);
-  controller()->OnAccept();
+  AcceptAndLoadFakeFingerprint();
 }
 
 TEST_F(AutofillDialogControllerTest, SaveInstrument) {
@@ -1073,8 +1128,7 @@
 
   scoped_ptr<wallet::WalletItems> wallet_items = wallet::GetTestWalletItems();
   wallet_items->AddAddress(wallet::GetTestShippingAddress());
-  controller()->OnDidGetWalletItems(wallet_items.Pass());
-  controller()->OnAccept();
+  SubmitWithWalletItems(wallet_items.Pass());
 }
 
 TEST_F(AutofillDialogControllerTest, SaveInstrumentWithInvalidInstruments) {
@@ -1085,8 +1139,7 @@
   scoped_ptr<wallet::WalletItems> wallet_items = wallet::GetTestWalletItems();
   wallet_items->AddAddress(wallet::GetTestShippingAddress());
   wallet_items->AddInstrument(wallet::GetTestMaskedInstrumentInvalid());
-  controller()->OnDidGetWalletItems(wallet_items.Pass());
-  controller()->OnAccept();
+  SubmitWithWalletItems(wallet_items.Pass());
 }
 
 TEST_F(AutofillDialogControllerTest, SaveInstrumentAndAddress) {
@@ -1094,7 +1147,7 @@
               SaveInstrumentAndAddress(_, _, _, _)).Times(1);
 
   controller()->OnDidGetWalletItems(wallet::GetTestWalletItems());
-  controller()->OnAccept();
+  AcceptAndLoadFakeFingerprint();
 }
 
 // Tests that editing an address (in wallet mode0 and submitting the dialog
@@ -1103,25 +1156,19 @@
   EXPECT_CALL(*controller()->GetTestingWalletClient(),
               UpdateAddress(_, _)).Times(1);
 
-  scoped_ptr<wallet::WalletItems> wallet_items = wallet::GetTestWalletItems();
-  wallet_items->AddInstrument(wallet::GetTestMaskedInstrument());
-  wallet_items->AddAddress(wallet::GetTestShippingAddress());
-  controller()->OnDidGetWalletItems(wallet_items.Pass());
+  controller()->OnDidGetWalletItems(CompleteAndValidWalletItems());
 
   controller()->EditClickedForSection(SECTION_SHIPPING);
-  controller()->OnAccept();
+  AcceptAndLoadFakeFingerprint();
 }
 
 // Tests that editing an instrument (CC + address) in wallet mode updates an
 // existing instrument on the server via WalletClient.
 TEST_F(AutofillDialogControllerTest, UpdateInstrument) {
-  scoped_ptr<wallet::WalletItems> wallet_items = wallet::GetTestWalletItems();
-  wallet_items->AddInstrument(wallet::GetTestMaskedInstrument());
-  wallet_items->AddAddress(wallet::GetTestShippingAddress());
-  controller()->OnDidGetWalletItems(wallet_items.Pass());
+  controller()->OnDidGetWalletItems(CompleteAndValidWalletItems());
 
   controller()->EditClickedForSection(SECTION_CC_BILLING);
-  controller()->OnAccept();
+  AcceptAndLoadFakeFingerprint();
 
   EXPECT_TRUE(
       controller()->GetTestingWalletClient()->updated_billing_address());
@@ -1138,7 +1185,7 @@
   controller()->OnDidGetWalletItems(wallet_items.Pass());
 
   controller()->EditClickedForSection(SECTION_CC_BILLING);
-  controller()->OnAccept();
+  AcceptAndLoadFakeFingerprint();
 
   EXPECT_TRUE(
       controller()->GetTestingWalletClient()->updated_billing_address());
@@ -1157,7 +1204,7 @@
   controller()->OnDidGetWalletItems(wallet_items.Pass());
 
   controller()->EditClickedForSection(SECTION_SHIPPING);
-  controller()->OnAccept();
+  AcceptAndLoadFakeFingerprint();
 }
 
 MATCHER(UsesLocalBillingAddress, "uses the local billing address") {
@@ -1170,15 +1217,11 @@
   EXPECT_CALL(*controller()->GetTestingWalletClient(),
               SaveAddress(_, _)).Times(1);
 
-  scoped_ptr<wallet::WalletItems> wallet_items = wallet::GetTestWalletItems();
-  wallet_items->AddInstrument(wallet::GetTestMaskedInstrument());
-  wallet_items->AddAddress(wallet::GetTestShippingAddress());
-
-  controller()->OnDidGetWalletItems(wallet_items.Pass());
+  controller()->OnDidGetWalletItems(CompleteAndValidWalletItems());
   // Select "Same as billing" in the address menu.
   UseBillingForShipping();
 
-  controller()->OnAccept();
+  AcceptAndLoadFakeFingerprint();
 }
 
 // Tests that when using billing address for shipping, and there is an exact
@@ -1202,7 +1245,7 @@
   // Select "Same as billing" in the address menu.
   UseBillingForShipping();
 
-  controller()->OnAccept();
+  AcceptAndLoadFakeFingerprint();
 }
 
 // Tests that adding new instrument and also using billing address for shipping,
@@ -1218,7 +1261,7 @@
   // Select "Same as billing" in the address menu.
   UseBillingForShipping();
 
-  controller()->OnAccept();
+  AcceptAndLoadFakeFingerprint();
 }
 
 // Test that the local view contents is used when saving a new instrument and
@@ -1243,7 +1286,7 @@
 
   EXPECT_CALL(*controller()->GetTestingWalletClient(),
               SaveAddress(UsesLocalBillingAddress(), _)).Times(1);
-  controller()->OnAccept();
+  AcceptAndLoadFakeFingerprint();
 
   EXPECT_TRUE(
       controller()->GetTestingWalletClient()->updated_billing_address());
@@ -1456,12 +1499,7 @@
   EXPECT_CALL(*controller()->GetTestingWalletClient(),
               AuthenticateInstrument(_, _, _)).Times(1);
 
-  scoped_ptr<wallet::WalletItems> wallet_items = wallet::GetTestWalletItems();
-  wallet_items->AddInstrument(wallet::GetTestMaskedInstrument());
-  wallet_items->AddAddress(wallet::GetTestShippingAddress());
-  controller()->OnDidGetWalletItems(wallet_items.Pass());
-  controller()->OnAccept();
-  controller()->OnDidLoadRiskFingerprintData(GetFakeFingerprint().Pass());
+  SubmitWithWalletItems(CompleteAndValidWalletItems());
 
   EXPECT_TRUE(NotificationsOfType(DialogNotification::REQUIRED_ACTION).empty());
   EXPECT_TRUE(controller()->SectionIsActive(SECTION_SHIPPING));
@@ -1495,12 +1533,7 @@
   EXPECT_CALL(*controller()->GetTestingWalletClient(),
               GetFullWallet(_)).Times(1);
 
-  scoped_ptr<wallet::WalletItems> wallet_items = wallet::GetTestWalletItems();
-  wallet_items->AddInstrument(wallet::GetTestMaskedInstrument());
-  wallet_items->AddAddress(wallet::GetTestShippingAddress());
-  controller()->OnDidGetWalletItems(wallet_items.Pass());
-  controller()->OnAccept();
-  controller()->OnDidLoadRiskFingerprintData(GetFakeFingerprint().Pass());
+  SubmitWithWalletItems(CompleteAndValidWalletItems());
 
   EXPECT_FALSE(controller()->IsDialogButtonEnabled(ui::DIALOG_BUTTON_OK));
   EXPECT_FALSE(controller()->IsDialogButtonEnabled(ui::DIALOG_BUTTON_CANCEL));
@@ -1516,12 +1549,7 @@
   EXPECT_CALL(*controller()->GetTestingWalletClient(),
               GetFullWallet(_)).Times(1);
 
-  scoped_ptr<wallet::WalletItems> wallet_items = wallet::GetTestWalletItems();
-  wallet_items->AddInstrument(wallet::GetTestMaskedInstrument());
-  wallet_items->AddAddress(wallet::GetTestShippingAddress());
-  controller()->OnDidGetWalletItems(wallet_items.Pass());
-  controller()->OnAccept();
-  controller()->OnDidLoadRiskFingerprintData(GetFakeFingerprint().Pass());
+  SubmitWithWalletItems(CompleteAndValidWalletItems());
 
   EXPECT_FALSE(controller()->IsDialogButtonEnabled(ui::DIALOG_BUTTON_OK));
   EXPECT_FALSE(controller()->IsDialogButtonEnabled(ui::DIALOG_BUTTON_CANCEL));
@@ -1537,12 +1565,7 @@
   EXPECT_CALL(*controller()->GetTestingWalletClient(),
               GetFullWallet(_)).Times(1);
 
-  scoped_ptr<wallet::WalletItems> wallet_items = wallet::GetTestWalletItems();
-  wallet_items->AddInstrument(wallet::GetTestMaskedInstrument());
-  wallet_items->AddAddress(wallet::GetTestShippingAddress());
-  controller()->OnDidGetWalletItems(wallet_items.Pass());
-  controller()->OnAccept();
-  controller()->OnDidLoadRiskFingerprintData(GetFakeFingerprint().Pass());
+  SubmitWithWalletItems(CompleteAndValidWalletItems());
   controller()->OnDidGetFullWallet(CreateFullWallet("verify_cvv"));
 
   ASSERT_TRUE(controller()->IsDialogButtonEnabled(ui::DIALOG_BUTTON_OK));
@@ -1559,12 +1582,7 @@
   EXPECT_CALL(*controller()->GetTestingWalletClient(),
               GetFullWallet(_)).Times(1);
 
-  scoped_ptr<wallet::WalletItems> wallet_items = wallet::GetTestWalletItems();
-  wallet_items->AddInstrument(wallet::GetTestMaskedInstrument());
-  wallet_items->AddAddress(wallet::GetTestShippingAddress());
-  controller()->OnDidGetWalletItems(wallet_items.Pass());
-  controller()->OnAccept();
-  controller()->OnDidLoadRiskFingerprintData(GetFakeFingerprint().Pass());
+  SubmitWithWalletItems(CompleteAndValidWalletItems());
   controller()->OnDidGetFullWallet(CreateFullWallet("verify_cvv"));
 
   ASSERT_TRUE(controller()->IsDialogButtonEnabled(ui::DIALOG_BUTTON_OK));
@@ -1613,7 +1631,6 @@
       wallet::FormFieldError(wallet::FormFieldError::UNKNOWN_ERROR,
                              wallet::FormFieldError::UNKNOWN_LOCATION));
 
-  EXPECT_CALL(*controller()->GetView(), UpdateForErrors()).Times(1);
   controller()->OnDidSaveAddress(std::string(), required_actions, form_errors);
 
   EXPECT_EQ(1U, NotificationsOfType(
@@ -1624,6 +1641,8 @@
 // where Chrome got the user's data (i.e. "Got details from Wallet") or promote
 // saving details into Wallet (i.e. "[x] Save details to Wallet").
 TEST_F(AutofillDialogControllerTest, WalletBanners) {
+  CommandLine* command_line = CommandLine::ForCurrentProcess();
+  command_line->AppendSwitch(switches::kWalletServiceUseProd);
   PrefService* prefs = controller()->profile()->GetPrefs();
   ASSERT_FALSE(prefs->GetBoolean(::prefs::kAutofillDialogHasPaidWithWallet));
 
@@ -1633,10 +1652,7 @@
       DialogNotification::WALLET_USAGE_CONFIRMATION).size());
 
   // Sign in a user with a completed account.
-  scoped_ptr<wallet::WalletItems> wallet_items = wallet::GetTestWalletItems();
-  wallet_items->AddInstrument(wallet::GetTestMaskedInstrument());
-  wallet_items->AddAddress(wallet::GetTestShippingAddress());
-  controller()->OnDidGetWalletItems(wallet_items.Pass());
+  controller()->OnDidGetWalletItems(CompleteAndValidWalletItems());
 
   // Full account; should show "Details from Wallet" message.
   EXPECT_EQ(1U, NotificationsOfType(
@@ -1657,7 +1673,7 @@
   prefs->SetBoolean(::prefs::kAutofillDialogHasPaidWithWallet, true);
 
   // Sign in a user with a incomplete account.
-  wallet_items = wallet::GetTestWalletItems();
+  scoped_ptr<wallet::WalletItems> wallet_items = wallet::GetTestWalletItems();
   wallet_items->AddInstrument(wallet::GetTestMaskedInstrument());
   controller()->OnDidGetWalletItems(wallet_items.Pass());
 
@@ -1695,10 +1711,7 @@
   EXPECT_EQ(0U, NotificationsOfType(
       DialogNotification::WALLET_USAGE_CONFIRMATION).size());
 
-  wallet_items = wallet::GetTestWalletItems();
-  wallet_items->AddInstrument(wallet::GetTestMaskedInstrument());
-  wallet_items->AddAddress(wallet::GetTestShippingAddress());
-  controller()->OnDidGetWalletItems(wallet_items.Pass());
+  controller()->OnDidGetWalletItems(CompleteAndValidWalletItems());
 
   EXPECT_EQ(0U, NotificationsOfType(
       DialogNotification::EXPLANATORY_MESSAGE).size());
@@ -1735,13 +1748,25 @@
 }
 
 TEST_F(AutofillDialogControllerTest, OnAutocheckoutSuccess) {
-  SwitchToAutofill();
+  CommandLine* command_line = CommandLine::ForCurrentProcess();
+  command_line->AppendSwitch(switches::kWalletServiceUseProd);
   controller()->set_dialog_type(DIALOG_TYPE_AUTOCHECKOUT);
 
-  // We also have to simulate CC inputs to keep the controller happy.
-  FillCreditCardInputs();
+  // Sign in a user with a completed account.
+  controller()->OnDidGetWalletItems(CompleteAndValidWalletItems());
 
-  controller()->OnAccept();
+  // Full account; should show "Details from Wallet" message.
+  EXPECT_EQ(1U, NotificationsOfType(
+      DialogNotification::EXPLANATORY_MESSAGE).size());
+  EXPECT_EQ(0U, NotificationsOfType(
+      DialogNotification::WALLET_USAGE_CONFIRMATION).size());
+
+  AcceptAndLoadFakeFingerprint();
+  controller()->OnDidGetFullWallet(wallet::GetTestFullWallet());
+
+  EXPECT_EQ(0U, NotificationsOfType(
+      DialogNotification::EXPLANATORY_MESSAGE).size());
+
   controller()->OnAutocheckoutSuccess();
 
   EXPECT_TRUE(controller()->IsDialogButtonEnabled(ui::DIALOG_BUTTON_CANCEL));
@@ -1750,6 +1775,8 @@
       DialogNotification::AUTOCHECKOUT_SUCCESS).size());
   EXPECT_EQ(0U, NotificationsOfType(
       DialogNotification::AUTOCHECKOUT_ERROR).size());
+  EXPECT_EQ(0U, NotificationsOfType(
+      DialogNotification::EXPLANATORY_MESSAGE).size());
 }
 
 TEST_F(AutofillDialogControllerTest, ViewCancelDoesntSetPref) {
@@ -1832,9 +1859,7 @@
   SwitchToWallet();
 
   // Setup some wallet state, submit, and get a full wallet to end the flow.
-  scoped_ptr<wallet::WalletItems> wallet_items = wallet::GetTestWalletItems();
-  wallet_items->AddInstrument(wallet::GetTestMaskedInstrument());
-  wallet_items->AddAddress(wallet::GetTestShippingAddress());
+  scoped_ptr<wallet::WalletItems> wallet_items = CompleteAndValidWalletItems();
 
   // Filling |form_structure()| depends on the current username and wallet items
   // being fetched. Until both of these have occurred, the user should not be
@@ -1897,6 +1922,10 @@
 
 // Tests that user is prompted when using instrument with minimal address.
 TEST_F(AutofillDialogControllerTest, UpgradeMinimalAddress) {
+  // A minimal address being selected should trigger error validation in the
+  // view. Called once for each incomplete suggestion.
+  EXPECT_CALL(*controller()->GetView(), UpdateForErrors()).Times(1);
+
   scoped_ptr<wallet::WalletItems> wallet_items = wallet::GetTestWalletItems();
   wallet_items->AddInstrument(wallet::GetTestMaskedInstrumentWithIdAndAddress(
       "id", wallet::GetTestMinimalAddress()));
@@ -1919,23 +1948,6 @@
   wallet_items->AddLegalDocument(wallet::GetTestLegalDocument());
   controller()->OnDidGetWalletItems(wallet_items.Pass());
   controller()->OnAccept();
-
-  EXPECT_EQ("no pagers", controller()->GetRiskData());
-}
-
-TEST_F(AutofillDialogControllerTest, RiskLoadsWithoutPendingLegalDocuments) {
-  EXPECT_CALL(*controller(), LoadRiskFingerprintData()).Times(1);
-
-  scoped_ptr<wallet::WalletItems> wallet_items = wallet::GetTestWalletItems();
-  wallet_items->AddInstrument(wallet::GetTestMaskedInstrument());
-  wallet_items->AddAddress(wallet::GetTestShippingAddress());
-  controller()->OnDidGetWalletItems(wallet_items.Pass());
-  controller()->OnAccept();
-
-  EXPECT_EQ("no pagers", controller()->GetRiskData());
-
-  controller()->OnDidLoadRiskFingerprintData(GetFakeFingerprint().Pass());
-  EXPECT_EQ(kFakeFingerprintEncoded, controller()->GetRiskData());
 }
 
 TEST_F(AutofillDialogControllerTest, RiskLoadsAfterAcceptingLegalDocuments) {
@@ -1949,7 +1961,6 @@
   EXPECT_CALL(*controller(), LoadRiskFingerprintData()).Times(1);
 
   controller()->OnAccept();
-  EXPECT_EQ("no pagers", controller()->GetRiskData());
 
   // Simulate a risk load and verify |GetRiskData()| matches the encoded value.
   controller()->OnDidAcceptLegalDocuments();
@@ -2059,26 +2070,112 @@
 }
 
 TEST_F(AutofillDialogControllerTest, ChooseAnotherInstrumentOrAddress) {
-  scoped_ptr<wallet::WalletItems> wallet_items = wallet::GetTestWalletItems();
-  wallet_items->AddInstrument(wallet::GetTestMaskedInstrument());
-  wallet_items->AddAddress(wallet::GetTestShippingAddress());
-  controller()->OnDidGetWalletItems(wallet_items.Pass());
-  controller()->OnAccept();
-  controller()->OnDidLoadRiskFingerprintData(GetFakeFingerprint().Pass());
+  SubmitWithWalletItems(CompleteAndValidWalletItems());
 
   EXPECT_EQ(0U, NotificationsOfType(
       DialogNotification::REQUIRED_ACTION).size());
-
   EXPECT_CALL(*controller()->GetTestingWalletClient(),
               GetWalletItems(_)).Times(1);
   controller()->OnDidGetFullWallet(
       CreateFullWallet("choose_another_instrument_or_address"));
   EXPECT_EQ(1U, NotificationsOfType(
       DialogNotification::REQUIRED_ACTION).size());
+  controller()->OnDidGetWalletItems(CompleteAndValidWalletItems());
 
   controller()->OnAccept();
   EXPECT_EQ(0U, NotificationsOfType(
       DialogNotification::REQUIRED_ACTION).size());
 }
 
+// Make sure detailed steps for Autocheckout are added
+// and updated correctly.
+TEST_F(AutofillDialogControllerTest, DetailedSteps) {
+  EXPECT_CALL(*controller()->GetTestingWalletClient(),
+            GetFullWallet(_)).Times(1);
+
+  controller()->set_dialog_type(DIALOG_TYPE_AUTOCHECKOUT);
+
+  // Add steps as would normally be done by the AutocheckoutManager.
+  controller()->AddAutocheckoutStep(AUTOCHECKOUT_STEP_SHIPPING);
+  controller()->AddAutocheckoutStep(AUTOCHECKOUT_STEP_DELIVERY);
+  controller()->AddAutocheckoutStep(AUTOCHECKOUT_STEP_BILLING);
+
+  scoped_ptr<wallet::WalletItems> wallet_items = wallet::GetTestWalletItems();
+  wallet_items->AddInstrument(wallet::GetTestMaskedInstrument());
+  wallet_items->AddAddress(wallet::GetTestShippingAddress());
+  controller()->OnDidGetWalletItems(wallet_items.Pass());
+  // Initiate flow - should add proxy card step since the user is using wallet
+  // data.
+  controller()->OnAccept();
+  controller()->OnDidLoadRiskFingerprintData(GetFakeFingerprint().Pass());
+
+  SuggestionState suggestion_state =
+      controller()->SuggestionStateForSection(SECTION_CC_BILLING);
+  EXPECT_TRUE(suggestion_state.extra_text.empty());
+
+  // There should be four steps total, with the first being the card generation
+  // step added by the dialog controller.
+  EXPECT_EQ(4U, controller()->CurrentAutocheckoutSteps().size());
+  EXPECT_EQ(AUTOCHECKOUT_STEP_PROXY_CARD,
+            controller()->CurrentAutocheckoutSteps()[0].type());
+  EXPECT_EQ(AUTOCHECKOUT_STEP_STARTED,
+            controller()->CurrentAutocheckoutSteps()[0].status());
+
+  // Simulate a wallet error. This should remove the card generation step from
+  // the flow, as we will have to proceed with local data.
+  controller()->OnWalletError(wallet::WalletClient::UNKNOWN_ERROR);
+
+  AutofillProfile shipping_profile(test::GetVerifiedProfile());
+  AutofillProfile billing_profile(test::GetVerifiedProfile2());
+  CreditCard credit_card(test::GetVerifiedCreditCard());
+  controller()->GetTestingManager()->AddTestingProfile(&shipping_profile);
+  controller()->GetTestingManager()->AddTestingProfile(&billing_profile);
+  controller()->GetTestingManager()->AddTestingCreditCard(&credit_card);
+  ui::MenuModel* billing_model =
+      controller()->MenuModelForSection(SECTION_BILLING);
+  billing_model->ActivatedAt(1);
+
+  // Re-initiate flow.
+  controller()->OnAccept();
+
+  // All steps should be initially unstarted.
+  EXPECT_EQ(3U, controller()->CurrentAutocheckoutSteps().size());
+  EXPECT_EQ(AUTOCHECKOUT_STEP_SHIPPING,
+            controller()->CurrentAutocheckoutSteps()[0].type());
+  EXPECT_EQ(AUTOCHECKOUT_STEP_UNSTARTED,
+            controller()->CurrentAutocheckoutSteps()[0].status());
+  EXPECT_EQ(AUTOCHECKOUT_STEP_DELIVERY,
+            controller()->CurrentAutocheckoutSteps()[1].type());
+  EXPECT_EQ(AUTOCHECKOUT_STEP_UNSTARTED,
+            controller()->CurrentAutocheckoutSteps()[1].status());
+  EXPECT_EQ(AUTOCHECKOUT_STEP_BILLING,
+            controller()->CurrentAutocheckoutSteps()[2].type());
+  EXPECT_EQ(AUTOCHECKOUT_STEP_UNSTARTED,
+            controller()->CurrentAutocheckoutSteps()[2].status());
+
+  // Update steps in the same manner that we would expect to see from the
+  // AutocheckoutManager while progressing through a flow.
+  controller()->UpdateAutocheckoutStep(AUTOCHECKOUT_STEP_SHIPPING,
+                                       AUTOCHECKOUT_STEP_STARTED);
+  controller()->UpdateAutocheckoutStep(AUTOCHECKOUT_STEP_SHIPPING,
+                                       AUTOCHECKOUT_STEP_COMPLETED);
+  controller()->UpdateAutocheckoutStep(AUTOCHECKOUT_STEP_DELIVERY,
+                                       AUTOCHECKOUT_STEP_STARTED);
+
+  // Verify that the steps were appropriately updated.
+  EXPECT_EQ(3U, controller()->CurrentAutocheckoutSteps().size());
+  EXPECT_EQ(AUTOCHECKOUT_STEP_SHIPPING,
+            controller()->CurrentAutocheckoutSteps()[0].type());
+  EXPECT_EQ(AUTOCHECKOUT_STEP_COMPLETED,
+            controller()->CurrentAutocheckoutSteps()[0].status());
+  EXPECT_EQ(AUTOCHECKOUT_STEP_DELIVERY,
+            controller()->CurrentAutocheckoutSteps()[1].type());
+  EXPECT_EQ(AUTOCHECKOUT_STEP_STARTED,
+            controller()->CurrentAutocheckoutSteps()[1].status());
+  EXPECT_EQ(AUTOCHECKOUT_STEP_BILLING,
+            controller()->CurrentAutocheckoutSteps()[2].type());
+  EXPECT_EQ(AUTOCHECKOUT_STEP_UNSTARTED,
+            controller()->CurrentAutocheckoutSteps()[2].status());
+}
+
 }  // namespace autofill
diff --git a/chrome/browser/ui/autofill/autofill_dialog_models.cc b/chrome/browser/ui/autofill/autofill_dialog_models.cc
index 89b76b0..f5c7849 100644
--- a/chrome/browser/ui/autofill/autofill_dialog_models.cc
+++ b/chrome/browser/ui/autofill/autofill_dialog_models.cc
@@ -9,9 +9,9 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/common/pref_names.h"
-#include "components/autofill/browser/autofill_country.h"
+#include "components/autofill/core/browser/autofill_country.h"
 #include "grit/generated_resources.h"
 #include "grit/theme_resources.h"
 #include "ui/base/l10n/l10n_util.h"
diff --git a/chrome/browser/ui/autofill/autofill_dialog_sign_in_delegate.cc b/chrome/browser/ui/autofill/autofill_dialog_sign_in_delegate.cc
index fab3ffd..ec3651c 100644
--- a/chrome/browser/ui/autofill/autofill_dialog_sign_in_delegate.cc
+++ b/chrome/browser/ui/autofill/autofill_dialog_sign_in_delegate.cc
@@ -14,7 +14,8 @@
     AutofillDialogView* dialog_view,
     content::WebContents* web_contents)
     : WebContentsObserver(web_contents),
-      dialog_view_(dialog_view) {
+      dialog_view_(dialog_view),
+      min_width_(400) {
   web_contents->SetDelegate(this);
 }
 
@@ -25,15 +26,26 @@
 
 void AutofillDialogSignInDelegate::RenderViewCreated(
     content::RenderViewHost* render_view_host) {
-  // Sizes to be used for the sign-in Window.
-  const gfx::Size kSignInWindowMinSize(400, 331);
-  const gfx::Size kSignInWindowMaxSize(800, 600);
+  SetMinWidth(min_width_);
 
-  render_view_host->EnableAutoResize(kSignInWindowMinSize,
-                                     kSignInWindowMaxSize);
   // Set the initial size as soon as we have an RVH to avoid
   // bad size jumping.
-  dialog_view_->OnSignInResize(kSignInWindowMinSize);
+  dialog_view_->OnSignInResize(GetMinSize());
+}
+
+void AutofillDialogSignInDelegate::SetMinWidth(int width) {
+  min_width_ = width;
+  content::RenderViewHost* host = web_contents()->GetRenderViewHost();
+  if (host)
+    host->EnableAutoResize(GetMinSize(), GetMaxSize());
+}
+
+gfx::Size AutofillDialogSignInDelegate::GetMinSize() const {
+  return gfx::Size(min_width_, 331);
+}
+
+gfx::Size AutofillDialogSignInDelegate::GetMaxSize() const {
+  return gfx::Size(std::max(min_width_, 800), 600);
 }
 
 }  // namespace autofill
diff --git a/chrome/browser/ui/autofill/autofill_dialog_sign_in_delegate.h b/chrome/browser/ui/autofill/autofill_dialog_sign_in_delegate.h
index 82df831..12a876b 100644
--- a/chrome/browser/ui/autofill/autofill_dialog_sign_in_delegate.h
+++ b/chrome/browser/ui/autofill/autofill_dialog_sign_in_delegate.h
@@ -32,8 +32,17 @@
   virtual void RenderViewCreated(
       content::RenderViewHost* render_view_host) OVERRIDE;
 
+  // Sets the minimum width for the render view. This should be set to the
+  // width of the host AutofillDialogView.
+  void SetMinWidth(int width);
+
  private:
+  // Gets the minimum and maximum size for the dialog.
+  gfx::Size GetMinSize() const;
+  gfx::Size GetMaxSize() const;
+
   AutofillDialogView* dialog_view_;
+  int min_width_;
 };
 
 }  // namespace autofill
diff --git a/chrome/browser/ui/autofill/autofill_dialog_types.cc b/chrome/browser/ui/autofill/autofill_dialog_types.cc
index 5052c3c..eb62c15 100644
--- a/chrome/browser/ui/autofill/autofill_dialog_types.cc
+++ b/chrome/browser/ui/autofill/autofill_dialog_types.cc
@@ -5,6 +5,9 @@
 #include "chrome/browser/ui/autofill/autofill_dialog_types.h"
 
 #include "base/logging.h"
+#include "grit/generated_resources.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/resource/resource_bundle.h"
 
 namespace autofill {
 
@@ -73,6 +76,137 @@
   return type_ == DialogNotification::WALLET_USAGE_CONFIRMATION;
 }
 
+DialogAutocheckoutStep::DialogAutocheckoutStep(AutocheckoutStepType type,
+                                               AutocheckoutStepStatus status)
+    : type_(type),
+      status_(status) {}
+
+SkColor DialogAutocheckoutStep::GetTextColor() const {
+  switch (status_) {
+    case AUTOCHECKOUT_STEP_UNSTARTED:
+      return SK_ColorGRAY;
+
+    case AUTOCHECKOUT_STEP_STARTED:
+    case AUTOCHECKOUT_STEP_COMPLETED:
+      return SK_ColorBLACK;
+
+    case AUTOCHECKOUT_STEP_FAILED:
+      return SK_ColorRED;
+  }
+
+  NOTREACHED();
+  return SK_ColorTRANSPARENT;
+}
+
+gfx::Font DialogAutocheckoutStep::GetTextFont() const {
+  gfx::Font::FontStyle font_style = gfx::Font::NORMAL;
+  switch (status_) {
+    case AUTOCHECKOUT_STEP_UNSTARTED:
+    case AUTOCHECKOUT_STEP_STARTED:
+      font_style = gfx::Font::NORMAL;
+      break;
+
+    case AUTOCHECKOUT_STEP_COMPLETED:
+    case AUTOCHECKOUT_STEP_FAILED:
+      font_style = gfx::Font::BOLD;
+      break;
+  }
+
+  return ui::ResourceBundle::GetSharedInstance().GetFont(
+      ui::ResourceBundle::BaseFont).DeriveFont(0, font_style);
+}
+
+bool DialogAutocheckoutStep::IsIconVisible() const {
+  return status_ == AUTOCHECKOUT_STEP_COMPLETED;
+}
+
+string16 DialogAutocheckoutStep::GetDisplayText() const {
+  int description_id = -1;
+  switch (status_) {
+    case AUTOCHECKOUT_STEP_UNSTARTED:
+      switch (type_) {
+        case AUTOCHECKOUT_STEP_SHIPPING:
+          description_id = IDS_AUTOFILL_STEP_SHIPPING_DETAILS_UNSTARTED;
+          break;
+
+        case AUTOCHECKOUT_STEP_DELIVERY:
+          description_id = IDS_AUTOFILL_STEP_DELIVERY_DETAILS_UNSTARTED;
+          break;
+
+        case AUTOCHECKOUT_STEP_BILLING:
+          description_id = IDS_AUTOFILL_STEP_BILLING_DETAILS_UNSTARTED;
+          break;
+
+        case AUTOCHECKOUT_STEP_PROXY_CARD:
+          description_id = IDS_AUTOFILL_STEP_PROXY_CARD_UNSTARTED;
+          break;
+      }
+      break;
+
+    case AUTOCHECKOUT_STEP_STARTED:
+      switch (type_) {
+        case AUTOCHECKOUT_STEP_SHIPPING:
+          description_id = IDS_AUTOFILL_STEP_SHIPPING_DETAILS_STARTED;
+          break;
+
+        case AUTOCHECKOUT_STEP_DELIVERY:
+          description_id = IDS_AUTOFILL_STEP_DELIVERY_DETAILS_STARTED;
+          break;
+
+        case AUTOCHECKOUT_STEP_BILLING:
+          description_id = IDS_AUTOFILL_STEP_BILLING_DETAILS_STARTED;
+          break;
+
+        case AUTOCHECKOUT_STEP_PROXY_CARD:
+          description_id = IDS_AUTOFILL_STEP_PROXY_CARD_STARTED;
+          break;
+      }
+      break;
+
+    case AUTOCHECKOUT_STEP_COMPLETED:
+      switch (type_) {
+        case AUTOCHECKOUT_STEP_SHIPPING:
+          description_id = IDS_AUTOFILL_STEP_SHIPPING_DETAILS_COMPLETE;
+          break;
+
+        case AUTOCHECKOUT_STEP_DELIVERY:
+          description_id = IDS_AUTOFILL_STEP_DELIVERY_DETAILS_COMPLETE;
+          break;
+
+        case AUTOCHECKOUT_STEP_BILLING:
+          description_id = IDS_AUTOFILL_STEP_BILLING_DETAILS_COMPLETE;
+          break;
+
+        case AUTOCHECKOUT_STEP_PROXY_CARD:
+          description_id = IDS_AUTOFILL_STEP_PROXY_CARD_COMPLETE;
+          break;
+      }
+      break;
+
+    case AUTOCHECKOUT_STEP_FAILED:
+      switch (type_) {
+        case AUTOCHECKOUT_STEP_SHIPPING:
+          description_id = IDS_AUTOFILL_STEP_SHIPPING_DETAILS_FAILED;
+          break;
+
+        case AUTOCHECKOUT_STEP_DELIVERY:
+          description_id = IDS_AUTOFILL_STEP_DELIVERY_DETAILS_FAILED;
+          break;
+
+        case AUTOCHECKOUT_STEP_BILLING:
+          description_id = IDS_AUTOFILL_STEP_BILLING_DETAILS_FAILED;
+          break;
+
+        case AUTOCHECKOUT_STEP_PROXY_CARD:
+          description_id = IDS_AUTOFILL_STEP_PROXY_CARD_FAILED;
+          break;
+      }
+      break;
+  }
+
+  return l10n_util::GetStringUTF16(description_id);
+}
+
 SkColor const kWarningColor = SkColorSetRGB(0xde, 0x49, 0x32);
 
 SuggestionState::SuggestionState(const string16& text,
diff --git a/chrome/browser/ui/autofill/autofill_dialog_types.h b/chrome/browser/ui/autofill/autofill_dialog_types.h
index d18eca1..a65820b 100644
--- a/chrome/browser/ui/autofill/autofill_dialog_types.h
+++ b/chrome/browser/ui/autofill/autofill_dialog_types.h
@@ -10,8 +10,8 @@
 
 #include "base/callback_forward.h"
 #include "base/strings/string16.h"
-#include "components/autofill/browser/autofill_metrics.h"
-#include "components/autofill/browser/field_types.h"
+#include "components/autofill/core/browser/autofill_metrics.h"
+#include "components/autofill/core/browser/field_types.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "ui/gfx/font.h"
 #include "ui/gfx/image/image.h"
@@ -128,6 +128,35 @@
   bool interactive_;
 };
 
+// A notification to show in the autofill dialog. Ranges from information to
+// seriously scary security messages, and will give you the color it should be
+// displayed (if you ask it).
+class DialogAutocheckoutStep {
+ public:
+  DialogAutocheckoutStep(AutocheckoutStepType type,
+                         AutocheckoutStepStatus status);
+
+  // Returns the appropriate color for the display text based on |status_|.
+  SkColor GetTextColor() const;
+
+  // Returns the appropriate font for the display text based on |status_|.
+  gfx::Font GetTextFont() const;
+
+  // Returns whether the icon for the view should be visable based on |status_|.
+  bool IsIconVisible() const;
+
+  // Returns the display text based on |type_| and |status_|.
+  string16 GetDisplayText() const;
+
+  AutocheckoutStepStatus status() { return status_; }
+
+  AutocheckoutStepType type() { return type_; }
+
+ private:
+  AutocheckoutStepType type_;
+  AutocheckoutStepStatus status_;
+};
+
 extern SkColor const kWarningColor;
 
 enum DialogSignedInState {
diff --git a/chrome/browser/ui/autofill/autofill_dialog_view.h b/chrome/browser/ui/autofill/autofill_dialog_view.h
index b7548b8..12a7ddb 100644
--- a/chrome/browser/ui/autofill/autofill_dialog_view.h
+++ b/chrome/browser/ui/autofill/autofill_dialog_view.h
@@ -5,7 +5,7 @@
 #ifndef CHROME_BROWSER_UI_AUTOFILL_AUTOFILL_DIALOG_VIEW_H_
 #define CHROME_BROWSER_UI_AUTOFILL_AUTOFILL_DIALOG_VIEW_H_
 
-#include "chrome/browser/ui/autofill/autofill_dialog_types.h"
+#include "chrome/browser/ui/autofill/autofill_dialog_controller.h"
 
 namespace content {
 class NavigationController;
@@ -39,6 +39,10 @@
   // a new account, etc.).
   virtual void UpdateAccountChooser() = 0;
 
+  // Updates the container displaying detailed steps for Autocheckout. Called
+  // as progress is made through the buyflow.
+  virtual void UpdateAutocheckoutStepsArea() = 0;
+
   // Updates the button strip based on the current controller state.
   virtual void UpdateButtonStrip() = 0;
 
diff --git a/chrome/browser/ui/autofill/autofill_popup_controller_browsertest.cc b/chrome/browser/ui/autofill/autofill_popup_controller_browsertest.cc
index f9bd96b..35f6ecb 100644
--- a/chrome/browser/ui/autofill/autofill_popup_controller_browsertest.cc
+++ b/chrome/browser/ui/autofill/autofill_popup_controller_browsertest.cc
@@ -9,9 +9,9 @@
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/test/base/in_process_browser_test.h"
-#include "components/autofill/browser/autofill_manager.h"
-#include "components/autofill/browser/test_autofill_external_delegate.h"
 #include "components/autofill/content/browser/autofill_driver_impl.h"
+#include "components/autofill/core/browser/autofill_manager.h"
+#include "components/autofill/core/browser/test_autofill_external_delegate.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/test/test_utils.h"
@@ -97,11 +97,16 @@
   scoped_ptr<TestAutofillExternalDelegate> autofill_external_delegate_;
 };
 
+#if defined(OS_LINUX)
+#define MAYBE_HidePopupOnWindowConfiguration DISABLED_HidePopupOnWindowConfiguration
+#else
+#define MAYBE_HidePopupOnWindowConfiguration HidePopupOnWindowConfiguration
+#endif
 // Autofill UI isn't currently hidden on window move on Mac.
 // http://crbug.com/180566
 #if !defined(OS_MACOSX)
 IN_PROC_BROWSER_TEST_F(AutofillPopupControllerBrowserTest,
-                       HidePopupOnWindowConfiguration) {
+                       MAYBE_HidePopupOnWindowConfiguration) {
   GenerateTestAutofillPopup(autofill_external_delegate_.get());
 
   EXPECT_FALSE(autofill_external_delegate_->popup_hidden());
diff --git a/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc b/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc
index 7ba2d93..681c2d8 100644
--- a/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc
+++ b/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc
@@ -10,7 +10,7 @@
 #include "base/logging.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/ui/autofill/autofill_popup_view.h"
-#include "components/autofill/browser/autofill_popup_delegate.h"
+#include "components/autofill/core/browser/autofill_popup_delegate.h"
 #include "content/public/browser/native_web_keyboard_event.h"
 #include "grit/webkit_resources.h"
 #include "third_party/WebKit/public/web/WebAutofillClient.h"
@@ -61,7 +61,6 @@
   { "genericCC", IDR_AUTOFILL_CC_GENERIC },
   { "jcbCC", IDR_AUTOFILL_CC_JCB },
   { "masterCardCC", IDR_AUTOFILL_CC_MASTERCARD },
-  { "soloCC", IDR_AUTOFILL_CC_SOLO },
   { "visaCC", IDR_AUTOFILL_CC_VISA },
 };
 
@@ -608,10 +607,9 @@
     const gfx::Display& left_display,
     const gfx::Display& right_display,
     int popup_required_width) const {
-  int leftmost_display_x = left_display.bounds().x() *
-      left_display.device_scale_factor();
-  int rightmost_display_x = right_display.GetSizeInPixel().width() +
-      right_display.bounds().x() * right_display.device_scale_factor();
+  int leftmost_display_x = left_display.bounds().x();
+  int rightmost_display_x =
+      right_display.GetSizeInPixel().width() + right_display.bounds().x();
 
   // Calculate the start coordinates for the popup if it is growing right or
   // the end position if it is growing to the left, capped to screen space.
@@ -640,11 +638,9 @@
     const gfx::Display& top_display,
     const gfx::Display& bottom_display,
     int popup_required_height) const {
-  int topmost_display_y = top_display.bounds().y() *
-      top_display.device_scale_factor();
-  int bottommost_display_y = bottom_display.GetSizeInPixel().height() +
-      (bottom_display.bounds().y() *
-       bottom_display.device_scale_factor());
+  int topmost_display_y = top_display.bounds().y();
+  int bottommost_display_y =
+      bottom_display.GetSizeInPixel().height() + bottom_display.bounds().y();
 
   // Calculate the start coordinates for the popup if it is growing down or
   // the end position if it is growing up, capped to screen space.
diff --git a/chrome/browser/ui/autofill/autofill_popup_controller_unittest.cc b/chrome/browser/ui/autofill/autofill_popup_controller_unittest.cc
index f64cfb4..a645863 100644
--- a/chrome/browser/ui/autofill/autofill_popup_controller_unittest.cc
+++ b/chrome/browser/ui/autofill/autofill_popup_controller_unittest.cc
@@ -10,11 +10,11 @@
 #include "chrome/browser/ui/autofill/autofill_popup_view.h"
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
 #include "chrome/test/base/testing_profile.h"
-#include "components/autofill/browser/autofill_external_delegate.h"
-#include "components/autofill/browser/autofill_manager.h"
-#include "components/autofill/browser/test_autofill_external_delegate.h"
-#include "components/autofill/browser/test_autofill_manager_delegate.h"
 #include "components/autofill/content/browser/autofill_driver_impl.h"
+#include "components/autofill/core/browser/autofill_external_delegate.h"
+#include "components/autofill/core/browser/autofill_manager.h"
+#include "components/autofill/core/browser/test_autofill_external_delegate.h"
+#include "components/autofill/core/browser/test_autofill_manager_delegate.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/WebKit/public/web/WebAutofillClient.h"
@@ -161,8 +161,7 @@
         web_contents(),
         manager_delegate_.get(),
         "en-US",
-        AutofillManager::ENABLE_AUTOFILL_DOWNLOAD_MANAGER,
-        false);
+        AutofillManager::ENABLE_AUTOFILL_DOWNLOAD_MANAGER);
     AutofillDriverImpl* driver =
         AutofillDriverImpl::FromWebContents(web_contents());
     external_delegate_.reset(
diff --git a/chrome/browser/ui/autofill/autofill_popup_view.cc b/chrome/browser/ui/autofill/autofill_popup_view.cc
deleted file mode 100644
index c2dc065..0000000
--- a/chrome/browser/ui/autofill/autofill_popup_view.cc
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ui/autofill/autofill_popup_view.h"
-
-namespace autofill {
-
-void AutofillPopupView::Hide() {
-  hide_called_ = true;
-}
-
-AutofillPopupView::AutofillPopupView() : hide_called_(false) {}
-
-AutofillPopupView::~AutofillPopupView() {
-  CHECK(hide_called_);
-}
-
-}  // namespace autofill
diff --git a/chrome/browser/ui/autofill/autofill_popup_view.h b/chrome/browser/ui/autofill/autofill_popup_view.h
index 1085095..1ef1869 100644
--- a/chrome/browser/ui/autofill/autofill_popup_view.h
+++ b/chrome/browser/ui/autofill/autofill_popup_view.h
@@ -52,9 +52,7 @@
   virtual void Show() = 0;
 
   // Hides the popup from view. This will cause the popup to be deleted.
-  // TODO(csharp): Make Hide a pure virtual function again, once hide_call_ is
-  // removed.
-  virtual void Hide();
+  virtual void Hide() = 0;
 
   // Invalidates the given row and redraw it.
   virtual void InvalidateRow(size_t row) = 0;
@@ -66,14 +64,7 @@
   static AutofillPopupView* Create(AutofillPopupController* controller);
 
  protected:
-  AutofillPopupView();
-  virtual ~AutofillPopupView();
-
- private:
-  // Used to check that the hide function was called, to check that the class
-  // is only destroyed through the Hide function. Remove after Dev channel
-  // release.
-  bool hide_called_;
+  virtual ~AutofillPopupView() {}
 };
 
 }  // namespace autofill
diff --git a/chrome/browser/ui/autofill/country_combobox_model.cc b/chrome/browser/ui/autofill/country_combobox_model.cc
index fe2eab2..6079e02 100644
--- a/chrome/browser/ui/autofill/country_combobox_model.cc
+++ b/chrome/browser/ui/autofill/country_combobox_model.cc
@@ -6,7 +6,7 @@
 
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/browser_process.h"
-#include "components/autofill/browser/autofill_country.h"
+#include "components/autofill/core/browser/autofill_country.h"
 #include "ui/base/l10n/l10n_util_collator.h"
 
 namespace autofill {
diff --git a/chrome/browser/ui/autofill/data_model_wrapper.cc b/chrome/browser/ui/autofill/data_model_wrapper.cc
index 4487650..40a0072 100644
--- a/chrome/browser/ui/autofill/data_model_wrapper.cc
+++ b/chrome/browser/ui/autofill/data_model_wrapper.cc
@@ -8,15 +8,15 @@
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/ui/autofill/autofill_dialog_models.h"
-#include "components/autofill/browser/autofill_data_model.h"
-#include "components/autofill/browser/autofill_profile.h"
-#include "components/autofill/browser/autofill_type.h"
-#include "components/autofill/browser/credit_card.h"
-#include "components/autofill/browser/form_structure.h"
-#include "components/autofill/browser/validation.h"
 #include "components/autofill/content/browser/wallet/full_wallet.h"
 #include "components/autofill/content/browser/wallet/wallet_address.h"
 #include "components/autofill/content/browser/wallet/wallet_items.h"
+#include "components/autofill/core/browser/autofill_data_model.h"
+#include "components/autofill/core/browser/autofill_profile.h"
+#include "components/autofill/core/browser/autofill_type.h"
+#include "components/autofill/core/browser/credit_card.h"
+#include "components/autofill/core/browser/form_structure.h"
+#include "components/autofill/core/browser/validation.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/gfx/image/image.h"
 
@@ -140,12 +140,8 @@
 }
 
 string16 AutofillCreditCardWrapper::GetDisplayText() {
-  if (!autofill::IsValidCreditCardExpirationDate(
-           card_->GetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR),
-           card_->GetRawInfo(CREDIT_CARD_EXP_MONTH),
-           base::Time::Now())) {
+  if (!card_->IsValid())
     return string16();
-  }
 
   return card_->TypeAndLastFourDigits();
 }
@@ -259,4 +255,18 @@
       type, g_browser_process->GetApplicationLocale());
 }
 
+DetailOutputWrapper::DetailOutputWrapper(const DetailOutputMap& outputs)
+    : outputs_(outputs) {}
+
+DetailOutputWrapper::~DetailOutputWrapper() {}
+
+base::string16 DetailOutputWrapper::GetInfo(AutofillFieldType type) const {
+  for (DetailOutputMap::const_iterator it = outputs_.begin();
+       it != outputs_.end(); ++it) {
+    if (type == it->first->type)
+      return it->second;
+  }
+  return base::string16();
+}
+
 }  // namespace autofill
diff --git a/chrome/browser/ui/autofill/data_model_wrapper.h b/chrome/browser/ui/autofill/data_model_wrapper.h
index a9302de..0e54ff8 100644
--- a/chrome/browser/ui/autofill/data_model_wrapper.h
+++ b/chrome/browser/ui/autofill/data_model_wrapper.h
@@ -8,8 +8,8 @@
 #include "base/compiler_specific.h"
 #include "base/strings/string16.h"
 #include "chrome/browser/ui/autofill/autofill_dialog_types.h"
-#include "components/autofill/browser/field_types.h"
 #include "components/autofill/content/browser/wallet/wallet_items.h"
+#include "components/autofill/core/browser/field_types.h"
 
 namespace gfx {
 class Image;
@@ -196,6 +196,20 @@
   DISALLOW_COPY_AND_ASSIGN(FullWalletShippingWrapper);
 };
 
+// A DataModelWrapper to copy the output of one section to the input of another.
+class DetailOutputWrapper : public DataModelWrapper {
+ public:
+  explicit DetailOutputWrapper(const DetailOutputMap& outputs);
+  virtual ~DetailOutputWrapper();
+
+  virtual base::string16 GetInfo(AutofillFieldType type) const OVERRIDE;
+
+ private:
+  const DetailOutputMap& outputs_;
+
+  DISALLOW_COPY_AND_ASSIGN(DetailOutputWrapper);
+};
+
 }  // namespace autofill
 
 #endif  // CHROME_BROWSER_UI_AUTOFILL_DATA_MODEL_WRAPPER_H_
diff --git a/chrome/browser/ui/autofill/data_model_wrapper_unittest.cc b/chrome/browser/ui/autofill/data_model_wrapper_unittest.cc
index 144a6c9..a1f27ce 100644
--- a/chrome/browser/ui/autofill/data_model_wrapper_unittest.cc
+++ b/chrome/browser/ui/autofill/data_model_wrapper_unittest.cc
@@ -4,14 +4,15 @@
 
 #include "base/memory/scoped_ptr.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/ui/autofill/autofill_dialog_models.h"
 #include "chrome/browser/ui/autofill/data_model_wrapper.h"
-#include "components/autofill/browser/autofill_common_test.h"
-#include "components/autofill/browser/autofill_profile.h"
-#include "components/autofill/browser/credit_card.h"
-#include "components/autofill/browser/field_types.h"
 #include "components/autofill/content/browser/wallet/wallet_items.h"
 #include "components/autofill/content/browser/wallet/wallet_test_util.h"
+#include "components/autofill/core/browser/autofill_common_test.h"
+#include "components/autofill/core/browser/autofill_profile.h"
+#include "components/autofill/core/browser/credit_card.h"
+#include "components/autofill/core/browser/field_types.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace autofill {
@@ -28,10 +29,31 @@
 
 TEST(AutofillCreditCardWrapperTest, GetDisplayTextEmptyWhenExpired) {
   CreditCard card;
+  card.SetRawInfo(CREDIT_CARD_EXP_MONTH, ASCIIToUTF16("1"));
+  card.SetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR, ASCIIToUTF16("2010"));
+  card.SetRawInfo(CREDIT_CARD_NUMBER, ASCIIToUTF16("4111111111111111"));
   AutofillCreditCardWrapper wrapper(&card);
   EXPECT_TRUE(wrapper.GetDisplayText().empty());
 }
 
+TEST(AutofillCreditCardWrapperTest, GetDisplayTextEmptyWhenInvalid) {
+  CreditCard card;
+  card.SetRawInfo(CREDIT_CARD_EXP_MONTH, ASCIIToUTF16("12"));
+  card.SetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR, ASCIIToUTF16("9999"));
+  card.SetRawInfo(CREDIT_CARD_NUMBER, ASCIIToUTF16("41111"));
+  AutofillCreditCardWrapper wrapper(&card);
+  EXPECT_TRUE(wrapper.GetDisplayText().empty());
+}
+
+TEST(AutofillCreditCardWrapperTest, GetDisplayTextNotEmptyWhenValid) {
+  CreditCard card;
+  card.SetRawInfo(CREDIT_CARD_EXP_MONTH, ASCIIToUTF16("12"));
+  card.SetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR, ASCIIToUTF16("9999"));
+  card.SetRawInfo(CREDIT_CARD_NUMBER, ASCIIToUTF16("4111111111111111"));
+  AutofillCreditCardWrapper wrapper(&card);
+  EXPECT_FALSE(wrapper.GetDisplayText().empty());
+}
+
 TEST(WalletInstrumentWrapperTest, GetInfoCreditCardExpMonth) {
   scoped_ptr<wallet::WalletItems::MaskedInstrument> instrument(
       wallet::GetTestMaskedInstrument());
@@ -71,4 +93,4 @@
   EXPECT_TRUE(address_wrapper.GetDisplayText().empty());
 }
 
-}  // autofill
+}  // namespace autofill
diff --git a/chrome/browser/ui/autofill/mock_autofill_dialog_controller.cc b/chrome/browser/ui/autofill/mock_autofill_dialog_controller.cc
index 2388028..006fa2b 100644
--- a/chrome/browser/ui/autofill/mock_autofill_dialog_controller.cc
+++ b/chrome/browser/ui/autofill/mock_autofill_dialog_controller.cc
@@ -45,10 +45,6 @@
   return string16();
 }
 
-string16 MockAutofillDialogController::ProgressBarText() const {
-  return string16();
-}
-
 string16 MockAutofillDialogController::LegalDocumentsText() {
   return string16();
 }
@@ -161,6 +157,11 @@
   return std::vector<DialogNotification>();
 }
 
+std::vector<DialogAutocheckoutStep> MockAutofillDialogController::
+    CurrentAutocheckoutSteps() const {
+  return std::vector<DialogAutocheckoutStep>();
+}
+
 void MockAutofillDialogController::SignInLinkClicked() {}
 
 void MockAutofillDialogController::NotificationCheckboxStateChanged(
diff --git a/chrome/browser/ui/autofill/mock_autofill_dialog_controller.h b/chrome/browser/ui/autofill/mock_autofill_dialog_controller.h
index 0d016f6..6da9ce8 100644
--- a/chrome/browser/ui/autofill/mock_autofill_dialog_controller.h
+++ b/chrome/browser/ui/autofill/mock_autofill_dialog_controller.h
@@ -22,7 +22,6 @@
   virtual string16 CancelButtonText() const OVERRIDE;
   virtual string16 ConfirmButtonText() const OVERRIDE;
   virtual string16 SaveLocallyText() const OVERRIDE;
-  virtual string16 ProgressBarText() const OVERRIDE;
   virtual string16 LegalDocumentsText() OVERRIDE;
   virtual DialogSignedInState SignedInState() const OVERRIDE;
   virtual bool ShouldShowSpinner() const OVERRIDE;
@@ -72,6 +71,9 @@
 
   virtual std::vector<DialogNotification> CurrentNotifications() OVERRIDE;
 
+  virtual std::vector<DialogAutocheckoutStep> CurrentAutocheckoutSteps()
+      const OVERRIDE;
+
   virtual void SignInLinkClicked() OVERRIDE;
   virtual void NotificationCheckboxStateChanged(DialogNotification::Type type,
                                                 bool checked) OVERRIDE;
diff --git a/chrome/browser/ui/autofill/tab_autofill_manager_delegate.cc b/chrome/browser/ui/autofill/tab_autofill_manager_delegate.cc
index 9d38578..c66528c 100644
--- a/chrome/browser/ui/autofill/tab_autofill_manager_delegate.cc
+++ b/chrome/browser/ui/autofill/tab_autofill_manager_delegate.cc
@@ -20,6 +20,7 @@
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/chrome_pages.h"
 #include "chrome/common/url_constants.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/web_contents_view.h"
@@ -167,10 +168,20 @@
     popup_controller_->Hide();
 }
 
-void TabAutofillManagerDelegate::UpdateProgressBar(double value) {
-  // |dialog_controller_| is a WeakPtr, but we require it to be present when
-  // |UpdateProgressBar| is called, so we intentionally do not do NULL check.
-  dialog_controller_->UpdateProgressBar(value);
+void TabAutofillManagerDelegate::AddAutocheckoutStep(
+    AutocheckoutStepType step_type) {
+  dialog_controller_->AddAutocheckoutStep(step_type);
+}
+
+void TabAutofillManagerDelegate::UpdateAutocheckoutStep(
+    AutocheckoutStepType step_type,
+    AutocheckoutStepStatus step_status) {
+  dialog_controller_->UpdateAutocheckoutStep(step_type, step_status);
+}
+
+bool TabAutofillManagerDelegate::IsAutocompleteEnabled() {
+  // For browser, Autocomplete is always enabled as part of Autofill.
+  return GetPrefs()->GetBoolean(prefs::kAutofillEnabled);
 }
 
 void TabAutofillManagerDelegate::HideRequestAutocompleteDialog() {
diff --git a/chrome/browser/ui/autofill/tab_autofill_manager_delegate.h b/chrome/browser/ui/autofill/tab_autofill_manager_delegate.h
index 9864f1d..bb118bc 100644
--- a/chrome/browser/ui/autofill/tab_autofill_manager_delegate.h
+++ b/chrome/browser/ui/autofill/tab_autofill_manager_delegate.h
@@ -10,7 +10,8 @@
 #include "base/i18n/rtl.h"
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/ui/autofill/autofill_dialog_types.h"
-#include "components/autofill/browser/autofill_manager_delegate.h"
+#include "components/autofill/content/browser/autocheckout_steps.h"
+#include "components/autofill/core/browser/autofill_manager_delegate.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/browser/web_contents_user_data.h"
 
@@ -68,13 +69,23 @@
       const std::vector<int>& identifiers,
       base::WeakPtr<AutofillPopupDelegate> delegate) OVERRIDE;
   virtual void HideAutofillPopup() OVERRIDE;
-  virtual void UpdateProgressBar(double value) OVERRIDE;
+  virtual bool IsAutocompleteEnabled() OVERRIDE;
+
+  virtual void AddAutocheckoutStep(AutocheckoutStepType step_type) OVERRIDE;
+  virtual void UpdateAutocheckoutStep(
+      AutocheckoutStepType step_type,
+      AutocheckoutStepStatus step_status) OVERRIDE;
 
   // content::WebContentsObserver implementation.
   virtual void DidNavigateMainFrame(
       const content::LoadCommittedDetails& details,
       const content::FrameNavigateParams& params) OVERRIDE;
 
+  // Exposed for testing.
+  AutofillDialogControllerImpl* GetDialogControllerForTesting() {
+    return dialog_controller_.get();
+  }
+
  private:
   explicit TabAutofillManagerDelegate(content::WebContents* web_contents);
   friend class content::WebContentsUserData<TabAutofillManagerDelegate>;
diff --git a/chrome/browser/ui/autofill/testable_autofill_dialog_view.h b/chrome/browser/ui/autofill/testable_autofill_dialog_view.h
index 984426e..7020e81 100644
--- a/chrome/browser/ui/autofill/testable_autofill_dialog_view.h
+++ b/chrome/browser/ui/autofill/testable_autofill_dialog_view.h
@@ -26,6 +26,10 @@
   virtual void SetTextContentsOfInput(const DetailInput& input,
                                       const string16& contents) = 0;
 
+  // Sets the content of the extra field for a section.
+  virtual void SetTextContentsOfSuggestionInput(DialogSection section,
+                                                const base::string16& text) = 0;
+
   // Simulates a user activatino of the input which is modelled by |input|.
   virtual void ActivateInput(const DetailInput& input) = 0;
 
diff --git a/chrome/browser/ui/bookmarks/bookmark_bar_constants.h b/chrome/browser/ui/bookmarks/bookmark_bar_constants.h
index 5f7ff84..7708e58 100644
--- a/chrome/browser/ui/bookmarks/bookmark_bar_constants.h
+++ b/chrome/browser/ui/bookmarks/bookmark_bar_constants.h
@@ -10,9 +10,9 @@
 namespace chrome {
 
 // The Bookmark bar height, when visible in "new tab page" mode.
-#if defined(OS_WIN) || defined(TOOLKIT_VIEWS) || defined(TOOLKIT_GTK)
+#if defined(TOOLKIT_GTK)
 const int kNTPBookmarkBarHeight = 57;
-#elif defined(OS_MACOSX)
+#elif defined(TOOLKIT_VIEWS) || defined(OS_MACOSX)
 const int kNTPBookmarkBarHeight = 40;
 #endif
 
diff --git a/chrome/browser/ui/bookmarks/bookmark_browsertest.cc b/chrome/browser/ui/bookmarks/bookmark_browsertest.cc
index 7fc4004..71217ed 100644
--- a/chrome/browser/ui/bookmarks/bookmark_browsertest.cc
+++ b/chrome/browser/ui/bookmarks/bookmark_browsertest.cc
@@ -4,7 +4,7 @@
 
 #include "base/bind.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/timer.h"
+#include "base/timer/timer.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/bookmarks/bookmark_model.h"
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
diff --git a/chrome/browser/ui/bookmarks/bookmark_context_menu_controller.cc b/chrome/browser/ui/bookmarks/bookmark_context_menu_controller.cc
index d2703c3..660050d 100644
--- a/chrome/browser/ui/bookmarks/bookmark_context_menu_controller.cc
+++ b/chrome/browser/ui/bookmarks/bookmark_context_menu_controller.cc
@@ -7,18 +7,17 @@
 #include "base/compiler_specific.h"
 #include "base/prefs/pref_service.h"
 #include "chrome/app/chrome_command_ids.h"
-#include "chrome/browser/bookmarks/bookmark_editor.h"
 #include "chrome/browser/bookmarks/bookmark_model.h"
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
 #include "chrome/browser/bookmarks/bookmark_utils.h"
 #include "chrome/browser/prefs/incognito_mode_prefs.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/bookmarks/bookmark_editor.h"
 #include "chrome/browser/ui/bookmarks/bookmark_utils.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/chrome_pages.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/common/pref_names.h"
-#include "components/user_prefs/user_prefs.h"
 #include "content/public/browser/page_navigator.h"
 #include "content/public/browser/user_metrics.h"
 #include "grit/generated_resources.h"
@@ -265,7 +264,7 @@
 }
 
 bool BookmarkContextMenuController::IsCommandIdChecked(int command_id) const {
-  PrefService* prefs = user_prefs::UserPrefs::Get(profile_);
+  PrefService* prefs = profile_->GetPrefs();
   if (command_id == IDC_BOOKMARK_BAR_ALWAYS_SHOW)
     return prefs->GetBoolean(prefs::kShowBookmarkBar);
 
@@ -274,17 +273,17 @@
 }
 
 bool BookmarkContextMenuController::IsCommandIdEnabled(int command_id) const {
-  bool enabled;
+  bool enabled = false;
   if (IsPlatformCommandIdEnabled(command_id, &enabled))
     return enabled;
 
-  PrefService* prefs = user_prefs::UserPrefs::Get(profile_);
+  PrefService* prefs = profile_->GetPrefs();
 
   bool is_root_node = selection_.size() == 1 &&
                       selection_[0]->parent() == model_->root_node();
   bool can_edit = prefs->GetBoolean(prefs::kEditBookmarksEnabled);
   IncognitoModePrefs::Availability incognito_avail =
-      IncognitoModePrefs::GetAvailability(profile_->GetPrefs());
+      IncognitoModePrefs::GetAvailability(prefs);
   switch (command_id) {
     case IDC_BOOKMARK_BAR_OPEN_INCOGNITO:
       return !profile_->IsOffTheRecord() &&
diff --git a/chrome/browser/ui/bookmarks/bookmark_editor.cc b/chrome/browser/ui/bookmarks/bookmark_editor.cc
new file mode 100644
index 0000000..7338c91
--- /dev/null
+++ b/chrome/browser/ui/bookmarks/bookmark_editor.cc
@@ -0,0 +1,166 @@
+// 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/ui/bookmarks/bookmark_editor.h"
+
+#include "base/logging.h"
+#include "grit/generated_resources.h"
+
+namespace {
+
+const BookmarkNode* CreateNewNode(BookmarkModel* model,
+                                  const BookmarkNode* parent,
+                                  const BookmarkEditor::EditDetails& details,
+                                  const base::string16& new_title,
+                                  const GURL& new_url) {
+  const BookmarkNode* node;
+  // When create the new one to right-clicked folder, add it to the next to the
+  // folder's position. Because |details.index| has a index of the folder when
+  // it was right-clicked, it might cause out of range exception when another
+  // bookmark manager edits contents of the folder.
+  // So we must check the range.
+  int child_count = parent->child_count();
+  int insert_index = (parent == details.parent_node && details.index >= 0 &&
+                      details.index <= child_count) ?
+                      details.index : child_count;
+  if (details.type == BookmarkEditor::EditDetails::NEW_URL) {
+    node = model->AddURL(parent, insert_index, new_title, new_url);
+  } else if (details.type == BookmarkEditor::EditDetails::NEW_FOLDER) {
+    node = model->AddFolder(parent, insert_index, new_title);
+    for (size_t i = 0; i < details.urls.size(); ++i) {
+      model->AddURL(node, node->child_count(), details.urls[i].second,
+                    details.urls[i].first);
+    }
+    model->SetDateFolderModified(parent, base::Time::Now());
+  } else {
+    NOTREACHED();
+    return NULL;
+  }
+
+  return node;
+}
+
+}  // namespace
+
+BookmarkEditor::EditDetails::EditDetails(Type node_type)
+    : type(node_type), existing_node(NULL), parent_node(NULL), index(-1) {
+}
+
+BookmarkNode::Type BookmarkEditor::EditDetails::GetNodeType() const {
+  BookmarkNode::Type node_type = BookmarkNode::URL;
+  switch (type) {
+    case EXISTING_NODE:
+      node_type = existing_node->type();
+      break;
+    case NEW_URL:
+      node_type = BookmarkNode::URL;
+      break;
+    case NEW_FOLDER:
+      node_type = BookmarkNode::FOLDER;
+      break;
+    default:
+      NOTREACHED();
+  }
+  return node_type;
+}
+
+int BookmarkEditor::EditDetails::GetWindowTitleId() const {
+  int dialog_title = IDS_BOOKMARK_EDITOR_TITLE;
+  switch (type) {
+    case EditDetails::EXISTING_NODE:
+    case EditDetails::NEW_URL:
+      dialog_title = (type == EditDetails::EXISTING_NODE &&
+                      existing_node->type() == BookmarkNode::FOLDER) ?
+          IDS_BOOKMARK_FOLDER_EDITOR_WINDOW_TITLE :
+          IDS_BOOKMARK_EDITOR_TITLE;
+      break;
+    case EditDetails::NEW_FOLDER:
+      dialog_title = urls.empty() ?
+          IDS_BOOKMARK_FOLDER_EDITOR_WINDOW_TITLE_NEW :
+          IDS_BOOKMARK_ALL_TABS_DIALOG_TITLE;
+      break;
+    default:
+      NOTREACHED();
+  }
+  return dialog_title;
+}
+
+BookmarkEditor::EditDetails BookmarkEditor::EditDetails::EditNode(
+    const BookmarkNode* node) {
+  EditDetails details(EXISTING_NODE);
+  details.existing_node = node;
+  if (node)
+    details.parent_node = node->parent();
+  return details;
+}
+
+BookmarkEditor::EditDetails BookmarkEditor::EditDetails::AddNodeInFolder(
+    const BookmarkNode* parent_node,
+    int index,
+    const GURL& url,
+    const string16& title) {
+  EditDetails details(NEW_URL);
+  details.parent_node = parent_node;
+  details.index = index;
+  details.url = url;
+  details.title = title;
+  return details;
+}
+
+BookmarkEditor::EditDetails BookmarkEditor::EditDetails::AddFolder(
+    const BookmarkNode* parent_node,
+    int index) {
+  EditDetails details(NEW_FOLDER);
+  details.parent_node = parent_node;
+  details.index = index;
+  return details;
+}
+
+BookmarkEditor::EditDetails::~EditDetails() {}
+
+// static
+const BookmarkNode* BookmarkEditor::ApplyEditsWithNoFolderChange(
+    BookmarkModel* model,
+    const BookmarkNode* parent,
+    const EditDetails& details,
+    const base::string16& new_title,
+    const GURL& new_url) {
+  if (details.type == EditDetails::NEW_URL ||
+      details.type == EditDetails::NEW_FOLDER) {
+    return CreateNewNode(model, parent, details, new_title, new_url);
+  }
+
+  const BookmarkNode* node = details.existing_node;
+  DCHECK(node);
+
+  if (node->is_url())
+    model->SetURL(node, new_url);
+  model->SetTitle(node, new_title);
+
+  return node;
+}
+
+// static
+const BookmarkNode* BookmarkEditor::ApplyEditsWithPossibleFolderChange(
+    BookmarkModel* model,
+    const BookmarkNode* new_parent,
+    const EditDetails& details,
+    const base::string16& new_title,
+    const GURL& new_url) {
+  if (details.type == EditDetails::NEW_URL ||
+      details.type == EditDetails::NEW_FOLDER) {
+    return CreateNewNode(model, new_parent, details, new_title, new_url);
+  }
+
+  const BookmarkNode* node = details.existing_node;
+  DCHECK(node);
+
+  if (new_parent != node->parent())
+    model->Move(node, new_parent, new_parent->child_count());
+  if (node->is_url())
+    model->SetURL(node, new_url);
+  model->SetTitle(node, new_title);
+
+  return node;
+}
diff --git a/chrome/browser/ui/bookmarks/bookmark_editor.h b/chrome/browser/ui/bookmarks/bookmark_editor.h
new file mode 100644
index 0000000..75f0f9b
--- /dev/null
+++ b/chrome/browser/ui/bookmarks/bookmark_editor.h
@@ -0,0 +1,129 @@
+// 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_UI_BOOKMARKS_BOOKMARK_EDITOR_H_
+#define CHROME_BROWSER_UI_BOOKMARKS_BOOKMARK_EDITOR_H_
+
+#include <utility>
+#include <vector>
+
+#include "base/strings/string16.h"
+#include "chrome/browser/bookmarks/bookmark_model.h"
+#include "ui/gfx/native_widget_types.h"
+
+class GURL;
+class Profile;
+
+// Small, cross platform interface that shows the correct platform specific
+// bookmark editor dialog.
+class BookmarkEditor {
+ public:
+  // An enumeration of the possible configurations offered.
+  enum Configuration {
+    // If Configuration is SHOW_TREE, a tree is shown allowing the user to
+    // choose the parent of the node.
+    SHOW_TREE,
+    NO_TREE
+  };
+
+  // Describes what the user is editing.
+  class EditDetails {
+   public:
+    // Returns the type of the existing or new node.
+    BookmarkNode::Type GetNodeType() const;
+
+    // Returns the resource id for the string resource to use on the window
+    // title for this edit operation.
+    int GetWindowTitleId() const;
+
+    // Returns an EditDetails instance for the user editing the given bookmark.
+    static EditDetails EditNode(const BookmarkNode* node);
+
+    // Returns an EditDetails instance for the user adding a bookmark within
+    // a given parent node with a specified index.
+    static EditDetails AddNodeInFolder(const BookmarkNode* parent_node,
+                                       int index,
+                                       const GURL& url,
+                                       const string16& title);
+
+    // Returns an EditDetails instance for the user adding a folder within a
+    // given parent node with a specified index.
+    static EditDetails AddFolder(const BookmarkNode* parent_node,
+                                 int index);
+
+    enum Type {
+      // The user is editing an existing node in the model. The node the user
+      // is editing is set in |existing_node|.
+      EXISTING_NODE,
+
+      // A new bookmark should be created if the user accepts the edit.
+      // |existing_node| is null in this case.
+      NEW_URL,
+
+      // A new folder bookmark should be created if the user accepts the edit.
+      // The contents of the folder should be that of |urls|.
+      // |existing_node| is null in this case.
+      NEW_FOLDER
+    };
+
+    ~EditDetails();
+
+    // See description of enum value for details.
+    const Type type;
+
+    // If type == EXISTING_NODE this gives the existing node.
+    const BookmarkNode* existing_node;
+
+    // If type == NEW_URL or type == NEW_FOLDER this gives the initial parent
+    // node to place the new node in.
+    const BookmarkNode* parent_node;
+
+    // If type == NEW_URL or type == NEW_FOLDER this gives the index to insert
+    // the new node at.
+    int index;
+
+    // If type == NEW_URL this gives the URL/title.
+    GURL url;
+    string16 title;
+
+    // If type == NEW_FOLDER, this is the urls/title pairs to add to the
+    // folder.
+    std::vector<std::pair<GURL, string16> > urls;
+
+   private:
+    explicit EditDetails(Type node_type);
+  };
+
+  // Shows the bookmark editor. The bookmark editor allows editing an existing
+  // node or creating a new bookmark node (as determined by |details.type|).
+  // |details.parent_node| is only used if |details.existing_node| is null.
+  static void Show(gfx::NativeWindow parent_window,
+                   Profile* profile,
+                   const EditDetails& details,
+                   Configuration configuration);
+
+  // Modifies a bookmark node (assuming that there's no magic that needs to be
+  // done regarding moving from one folder to another).  If a new node is
+  // explicitly being added, returns a pointer to the new node that was created.
+  // Otherwise the return value is identically |node|.
+  static const BookmarkNode* ApplyEditsWithNoFolderChange(
+      BookmarkModel* model,
+      const BookmarkNode* parent,
+      const EditDetails& details,
+      const base::string16& new_title,
+      const GURL& new_url);
+
+  // Modifies a bookmark node assuming that the parent of the node may have
+  // changed and the node will need to be removed and reinserted.  If a new node
+  // is explicitly being added, returns a pointer to the new node that was
+  // created.  Otherwise the return value is identically |node|.
+  static const BookmarkNode* ApplyEditsWithPossibleFolderChange(
+      BookmarkModel* model,
+      const BookmarkNode* new_parent,
+      const EditDetails& details,
+      const base::string16& new_title,
+      const GURL& new_url);
+};
+
+#endif  // CHROME_BROWSER_UI_BOOKMARKS_BOOKMARK_EDITOR_H_
diff --git a/chrome/browser/ui/bookmarks/bookmark_editor_unittest.cc b/chrome/browser/ui/bookmarks/bookmark_editor_unittest.cc
new file mode 100644
index 0000000..83d16e6
--- /dev/null
+++ b/chrome/browser/ui/bookmarks/bookmark_editor_unittest.cc
@@ -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.
+
+#include "chrome/browser/ui/bookmarks/bookmark_editor.h"
+
+#include "base/strings/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+TEST(BookmarkEditorTest, ApplyEditsWithNoFolderChange) {
+  BookmarkModel model(NULL);
+  const BookmarkNode* bookmarkbar = model.bookmark_bar_node();
+  model.AddURL(bookmarkbar, 0, ASCIIToUTF16("url0"), GURL("chrome://newtab"));
+  model.AddURL(bookmarkbar, 1, ASCIIToUTF16("url1"), GURL("chrome://newtab"));
+
+  {
+    BookmarkEditor::EditDetails detail(
+        BookmarkEditor::EditDetails::AddFolder(bookmarkbar, 1));
+    BookmarkEditor::ApplyEditsWithNoFolderChange(&model,
+                                                 bookmarkbar,
+                                                 detail,
+                                                 ASCIIToUTF16("folder0"),
+                                                 GURL(std::string()));
+    EXPECT_EQ(ASCIIToUTF16("folder0"), bookmarkbar->GetChild(1)->GetTitle());
+  }
+  {
+    BookmarkEditor::EditDetails detail(
+        BookmarkEditor::EditDetails::AddFolder(bookmarkbar, -1));
+    BookmarkEditor::ApplyEditsWithNoFolderChange(&model,
+                                                 bookmarkbar,
+                                                 detail,
+                                                 ASCIIToUTF16("folder1"),
+                                                 GURL(std::string()));
+    EXPECT_EQ(ASCIIToUTF16("folder1"), bookmarkbar->GetChild(3)->GetTitle());
+  }
+  {
+    BookmarkEditor::EditDetails detail(
+        BookmarkEditor::EditDetails::AddFolder(bookmarkbar, 10));
+    BookmarkEditor::ApplyEditsWithNoFolderChange(&model,
+                                                 bookmarkbar,
+                                                 detail,
+                                                 ASCIIToUTF16("folder2"),
+                                                 GURL(std::string()));
+    EXPECT_EQ(ASCIIToUTF16("folder2"), bookmarkbar->GetChild(4)->GetTitle());
+  }
+}
+
+}  // namespace
diff --git a/chrome/browser/ui/bookmarks/bookmark_prompt_controller.h b/chrome/browser/ui/bookmarks/bookmark_prompt_controller.h
index 290f2fe..7b0d2a4 100644
--- a/chrome/browser/ui/bookmarks/bookmark_prompt_controller.h
+++ b/chrome/browser/ui/bookmarks/bookmark_prompt_controller.h
@@ -6,7 +6,7 @@
 #define CHROME_BROWSER_UI_BOOKMARKS_BOOKMARK_PROMPT_CONTROLLER_H_
 
 #include "base/basictypes.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/common/cancelable_request.h"
 #include "chrome/browser/history/history_types.h"
 #include "chrome/browser/ui/browser_list_observer.h"
diff --git a/chrome/browser/ui/bookmarks/bookmark_utils.cc b/chrome/browser/ui/bookmarks/bookmark_utils.cc
index dc63d7b..71c8ad0 100644
--- a/chrome/browser/ui/bookmarks/bookmark_utils.cc
+++ b/chrome/browser/ui/bookmarks/bookmark_utils.cc
@@ -9,11 +9,11 @@
 #include "base/logging.h"
 #include "base/prefs/pref_service.h"
 #include "base/strings/string_number_conversions.h"
-#include "chrome/browser/bookmarks/bookmark_editor.h"
 #include "chrome/browser/bookmarks/bookmark_model.h"
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/search/search.h"
+#include "chrome/browser/ui/bookmarks/bookmark_editor.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_navigator.h"
 #include "chrome/browser/ui/browser_window.h"
diff --git a/chrome/browser/ui/bookmarks/recently_used_folders_combo_model.cc b/chrome/browser/ui/bookmarks/recently_used_folders_combo_model.cc
index 879bb0d..a1775c4 100644
--- a/chrome/browser/ui/bookmarks/recently_used_folders_combo_model.cc
+++ b/chrome/browser/ui/bookmarks/recently_used_folders_combo_model.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/ui/bookmarks/recently_used_folders_combo_model.h"
 
+#include "chrome/browser/bookmarks/bookmark_model.h"
 #include "chrome/browser/bookmarks/bookmark_utils.h"
 #include "content/public/browser/user_metrics.h"
 #include "grit/generated_resources.h"
diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc
index ceab9ef..5513be6 100644
--- a/chrome/browser/ui/browser.cc
+++ b/chrome/browser/ui/browser.cc
@@ -26,7 +26,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/thread.h"
 #include "base/threading/thread_restrictions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/app_mode/app_mode_utils.h"
 #include "chrome/browser/autofill/personal_data_manager_factory.h"
@@ -66,7 +66,6 @@
 #include "chrome/browser/notifications/notification_ui_manager.h"
 #include "chrome/browser/pepper_broker_infobar_delegate.h"
 #include "chrome/browser/prefs/incognito_mode_prefs.h"
-#include "chrome/browser/printing/cloud_print/cloud_print_setup_flow.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_destroyer.h"
 #include "chrome/browser/profiles/profile_manager.h"
@@ -108,7 +107,7 @@
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/chrome_pages.h"
 #include "chrome/browser/ui/chrome_select_file_policy.h"
-#include "chrome/browser/ui/extensions/shell_window.h"
+#include "chrome/browser/ui/fast_unload_controller.h"
 #include "chrome/browser/ui/find_bar/find_bar.h"
 #include "chrome/browser/ui/find_bar/find_bar_controller.h"
 #include "chrome/browser/ui/find_bar/find_tab_helper.h"
@@ -191,7 +190,7 @@
 #include "chrome/browser/ssl/ssl_error_info.h"
 #include "chrome/browser/task_manager/task_manager.h"
 #include "chrome/browser/ui/view_ids.h"
-#include "components/autofill/browser/autofill_ie_toolbar_import_win.h"
+#include "components/autofill/core/browser/autofill_ie_toolbar_import_win.h"
 #include "ui/base/win/shell.h"
 #include "ui/views/win/hwnd_util.h"
 #endif  // OS_WIN
@@ -234,6 +233,12 @@
   return BrowserWindow::CreateBrowserWindow(browser);
 }
 
+// Is the fast tab unload experiment enabled?
+bool IsFastTabUnloadEnabled() {
+  return CommandLine::ForCurrentProcess()->HasSwitch(
+        switches::kEnableFastUnload);
+}
+
 }  // namespace
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -333,7 +338,6 @@
       initial_show_state_(params.initial_show_state),
       is_session_restore_(params.is_session_restore),
       host_desktop_type_(params.host_desktop_type),
-      unload_controller_(new chrome::UnloadController(this)),
       weak_factory_(this),
       content_setting_bubble_model_delegate_(
           new BrowserContentSettingBubbleModelDelegate(this)),
@@ -349,6 +353,12 @@
   // from opening at all, but the path that triggered it should be fixed.
   CHECK(IncognitoModePrefs::CanOpenBrowser(profile_));
 
+  // TODO(jeremy): Move to initializer list once flag is removed.
+  if (IsFastTabUnloadEnabled())
+    fast_unload_controller_.reset(new chrome::FastUnloadController(this));
+  else
+    unload_controller_.reset(new chrome::UnloadController(this));
+
   if (!app_name_.empty())
     chrome::RegisterAppPrefs(app_name_, profile_);
   tab_strip_model_->AddObserver(this);
@@ -483,6 +493,10 @@
   // is destroyed to make sure the chrome.windows.onRemoved event is sent.
   extension_window_controller_.reset();
 
+  // Destroy BrowserInstantController before the incongnito profile is destroyed
+  // because the InstantController destructor depends on this profile.
+  instant_controller_.reset();
+
   if (profile_->IsOffTheRecord() &&
       !BrowserList::IsOffTheRecordSessionActiveForProfile(profile_)) {
     // An incognito profile is no longer needed, this indirectly frees
@@ -582,18 +596,19 @@
   if (!CanCloseWithInProgressDownloads())
     return false;
 
+  if (IsFastTabUnloadEnabled())
+    return fast_unload_controller_->ShouldCloseWindow();
   return unload_controller_->ShouldCloseWindow();
 }
 
-bool Browser::TabsNeedBeforeUnloadFired() {
-  return unload_controller_->TabsNeedBeforeUnloadFired();
-}
-
 bool Browser::HasCompletedUnloadProcessing() const {
-  return unload_controller_->HasCompletedUnloadProcessing();
+  DCHECK(IsFastTabUnloadEnabled());
+  return fast_unload_controller_->HasCompletedUnloadProcessing();
 }
 
 bool Browser::IsAttemptingToCloseBrowser() const {
+  if (IsFastTabUnloadEnabled())
+    return fast_unload_controller_->is_attempting_to_close_browser();
   return unload_controller_->is_attempting_to_close_browser();
 }
 
@@ -636,6 +651,9 @@
       chrome::NOTIFICATION_BROWSER_CLOSING,
       content::Source<Browser>(this),
       content::NotificationService::NoDetails());
+
+  if (!IsFastTabUnloadEnabled())
+    tab_strip_model_->CloseAllTabs();
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -1083,6 +1101,7 @@
                             WebContents* new_contents,
                             int index) {
   TabDetachedAtImpl(old_contents, index, DETACH_TYPE_REPLACE);
+  fullscreen_controller_->OnTabClosing(old_contents);
   SessionService* session_service =
       SessionServiceFactory::GetForProfile(profile_);
   if (session_service)
@@ -1172,6 +1191,12 @@
   window()->HandleKeyboardEvent(event);
 }
 
+bool Browser::TabsNeedBeforeUnloadFired() {
+  if (IsFastTabUnloadEnabled())
+    return fast_unload_controller_->TabsNeedBeforeUnloadFired();
+  return unload_controller_->TabsNeedBeforeUnloadFired();
+}
+
 bool Browser::IsMouseLocked() const {
   return fullscreen_controller_->IsMouseLocked();
 }
@@ -1305,7 +1330,13 @@
 }
 
 void Browser::CloseContents(WebContents* source) {
-  if (unload_controller_->CanCloseContents(source))
+  bool can_close_contents;
+  if (IsFastTabUnloadEnabled())
+    can_close_contents = fast_unload_controller_->CanCloseContents(source);
+  else
+    can_close_contents = unload_controller_->CanCloseContents(source);
+
+  if (can_close_contents)
     chrome::CloseWebContents(this, source, true);
 }
 
@@ -1368,8 +1399,13 @@
 void Browser::BeforeUnloadFired(WebContents* web_contents,
                                 bool proceed,
                                 bool* proceed_to_fire_unload) {
-  *proceed_to_fire_unload =
-      unload_controller_->BeforeUnloadFired(web_contents, proceed);
+  if (IsFastTabUnloadEnabled()) {
+    *proceed_to_fire_unload =
+        fast_unload_controller_->BeforeUnloadFired(web_contents, proceed);
+  } else {
+    *proceed_to_fire_unload =
+        unload_controller_->BeforeUnloadFired(web_contents, proceed);
+  }
 }
 
 bool Browser::ShouldFocusLocationBarByDefault(WebContents* source) {
diff --git a/chrome/browser/ui/browser.h b/chrome/browser/ui/browser.h
index 60ac1ea..62f6ba6 100644
--- a/chrome/browser/ui/browser.h
+++ b/chrome/browser/ui/browser.h
@@ -66,6 +66,7 @@
 
 namespace chrome {
 class BrowserCommandController;
+class FastUnloadController;
 class UnloadController;
 }
 
@@ -869,6 +870,7 @@
   const chrome::HostDesktopType host_desktop_type_;
 
   scoped_ptr<chrome::UnloadController> unload_controller_;
+  scoped_ptr<chrome::FastUnloadController> fast_unload_controller_;
 
   // The following factory is used to close the frame at a later time.
   base::WeakPtrFactory<Browser> weak_factory_;
diff --git a/chrome/browser/ui/browser_browsertest.cc b/chrome/browser/ui/browser_browsertest.cc
index 74c466e..e8c2787 100644
--- a/chrome/browser/ui/browser_browsertest.cc
+++ b/chrome/browser/ui/browser_browsertest.cc
@@ -609,8 +609,7 @@
 
   // Open a second browser window at about:blank.
   ui_test_utils::BrowserAddedObserver browser_added_observer;
-  chrome::NewEmptyWindow(browser()->profile(),
-                         chrome::HOST_DESKTOP_TYPE_NATIVE);
+  chrome::NewEmptyWindow(browser()->profile(), chrome::GetActiveDesktop());
   Browser* second_window = browser_added_observer.WaitForSingleNewBrowser();
   ui_test_utils::NavigateToURL(second_window, GURL("about:blank"));
 
@@ -1888,7 +1887,7 @@
   EXPECT_EQ(0u, chrome::GetTotalBrowserCount());
 
   ui_test_utils::BrowserAddedObserver browser_added_observer;
-  chrome::NewEmptyWindow(profile, chrome::HOST_DESKTOP_TYPE_NATIVE);
+  chrome::NewEmptyWindow(profile, chrome::GetActiveDesktop());
   browser_added_observer.WaitForSingleNewBrowser();
 
   EXPECT_EQ(1u, chrome::GetTotalBrowserCount());
diff --git a/chrome/browser/ui/browser_command_controller.cc b/chrome/browser/ui/browser_command_controller.cc
index c5d34be..b38cf57 100644
--- a/chrome/browser/ui/browser_command_controller.cc
+++ b/chrome/browser/ui/browser_command_controller.cc
@@ -23,9 +23,9 @@
 #include "chrome/browser/ui/browser_commands.h"
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/chrome_pages.h"
+#include "chrome/browser/ui/sync/sync_promo_ui.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/tabs/tab_strip_model_utils.h"
-#include "chrome/browser/ui/webui/sync_promo/sync_promo_ui.h"
 #include "chrome/common/chrome_notification_types.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/profiling.h"
@@ -627,10 +627,7 @@
       ToggleDevToolsWindow(browser_, DEVTOOLS_TOGGLE_ACTION_TOGGLE);
       break;
     case IDC_TASK_MANAGER:
-      OpenTaskManager(browser_, false);
-      break;
-    case IDC_VIEW_BACKGROUND_PAGES:
-      OpenTaskManager(browser_, true);
+      OpenTaskManager(browser_);
       break;
     case IDC_FEEDBACK:
       OpenFeedbackDialog(browser_);
@@ -941,10 +938,6 @@
   command_updater_.UpdateCommandEnabled(IDC_UPGRADE_DIALOG, true);
   command_updater_.UpdateCommandEnabled(IDC_VIEW_INCOMPATIBILITIES, true);
 
-  // View Background Pages entry is always enabled, but is hidden if there are
-  // no background pages.
-  command_updater_.UpdateCommandEnabled(IDC_VIEW_BACKGROUND_PAGES, true);
-
   // Toggle speech input
   command_updater_.UpdateCommandEnabled(IDC_TOGGLE_SPEECH_INPUT, true);
 
diff --git a/chrome/browser/ui/browser_command_controller_unittest.cc b/chrome/browser/ui/browser_command_controller_unittest.cc
index 87e9be5..6d50522 100644
--- a/chrome/browser/ui/browser_command_controller_unittest.cc
+++ b/chrome/browser/ui/browser_command_controller_unittest.cc
@@ -301,8 +301,7 @@
   profile1->SetOffTheRecordProfile(profile2);
 
   // Create a new browser based on the off the record profile.
-  Browser::CreateParams profile_params(profile2,
-                                       chrome::HOST_DESKTOP_TYPE_NATIVE);
+  Browser::CreateParams profile_params(profile2, chrome::GetActiveDesktop());
   scoped_ptr<Browser> browser2(
       chrome::CreateBrowserWithTestWindowForParams(&profile_params));
 
diff --git a/chrome/browser/ui/browser_commands.cc b/chrome/browser/ui/browser_commands.cc
index 51c6169..d233e28 100644
--- a/chrome/browser/ui/browser_commands.cc
+++ b/chrome/browser/ui/browser_commands.cc
@@ -53,9 +53,9 @@
 #include "chrome/browser/ui/webui/ntp/app_launcher_handler.h"
 #include "chrome/browser/upgrade_detector.h"
 #include "chrome/browser/web_applications/web_app.h"
-#include "chrome/common/chrome_content_client.h"
 #include "chrome/common/chrome_notification_types.h"
 #include "chrome/common/chrome_switches.h"
+#include "chrome/common/chrome_version_info.h"
 #include "chrome/common/pref_names.h"
 #include "components/web_modal/web_contents_modal_dialog_manager.h"
 #include "content/public/browser/devtools_agent_host.h"
@@ -375,8 +375,8 @@
   // If the home page is a Google home page, add the RLZ header to the request.
   PrefService* pref_service = browser->profile()->GetPrefs();
   if (pref_service) {
-    std::string home_page = pref_service->GetString(prefs::kHomePage);
-    if (google_util::IsGoogleHomePageUrl(home_page)) {
+    if (google_util::IsGoogleHomePageUrl(
+        GURL(pref_service->GetString(prefs::kHomePage)))) {
       extra_headers = RLZTracker::GetAccessPointHttpHeader(
           RLZTracker::CHROME_HOME_PAGE);
     }
@@ -892,9 +892,9 @@
 #endif
 }
 
-void OpenTaskManager(Browser* browser, bool highlight_background_resources) {
+void OpenTaskManager(Browser* browser) {
   content::RecordAction(UserMetricsAction("TaskManager"));
-  chrome::ShowTaskManager(browser, highlight_background_resources);
+  chrome::ShowTaskManager(browser);
 }
 
 void OpenFeedbackDialog(Browser* browser) {
@@ -964,10 +964,13 @@
     entry->SetIsOverridingUserAgent(false);
   } else {
     entry->SetIsOverridingUserAgent(true);
+    chrome::VersionInfo version_info;
+    std::string product;
+    if (version_info.is_valid())
+      product = version_info.ProductNameAndVersionForUserAgent();
     current_tab->SetUserAgentOverride(
         webkit_glue::BuildUserAgentFromOSAndProduct(
-            kOsOverrideForTabletSite,
-            ChromeContentClient::GetProductImpl()));
+            kOsOverrideForTabletSite, product));
   }
   controller.ReloadOriginalRequestURL(true);
 }
diff --git a/chrome/browser/ui/browser_commands.h b/chrome/browser/ui/browser_commands.h
index f144d8c..b64b212 100644
--- a/chrome/browser/ui/browser_commands.h
+++ b/chrome/browser/ui/browser_commands.h
@@ -132,7 +132,7 @@
 void FocusPreviousPane(Browser* browser);
 void ToggleDevToolsWindow(Browser* browser, DevToolsToggleAction action);
 bool CanOpenTaskManager();
-void OpenTaskManager(Browser* browser, bool highlight_background_resources);
+void OpenTaskManager(Browser* browser);
 void OpenFeedbackDialog(Browser* browser);
 void ToggleBookmarkBar(Browser* browser);
 void ShowAppMenu(Browser* browser);
diff --git a/chrome/browser/ui/browser_dialogs.h b/chrome/browser/ui/browser_dialogs.h
index 8ee472e..c3ad400 100644
--- a/chrome/browser/ui/browser_dialogs.h
+++ b/chrome/browser/ui/browser_dialogs.h
@@ -68,9 +68,8 @@
 void ShowHungRendererDialog(content::WebContents* contents);
 void HideHungRendererDialog(content::WebContents* contents);
 
-// Shows the Task Manager. If |highlight_background_resources| is set, the
-// backgroundpages will be shown. |browser| can be NULL when called from ASH.
-void ShowTaskManager(Browser* browser, bool highlight_background_resources);
+// Shows the Task Manager. |browser| can be NULL when called from Ash.
+void ShowTaskManager(Browser* browser);
 
 #if !defined(OS_MACOSX)
 // Shows the create web app shortcut dialog box.
diff --git a/chrome/browser/ui/browser_focus_uitest.cc b/chrome/browser/ui/browser_focus_uitest.cc
index e83c347..303d4c2 100644
--- a/chrome/browser/ui/browser_focus_uitest.cc
+++ b/chrome/browser/ui/browser_focus_uitest.cc
@@ -37,7 +37,7 @@
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_view.h"
 #include "content/public/test/browser_test_utils.h"
-#include "net/test/spawned_test_server/spawned_test_server.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
 
 #if defined(TOOLKIT_VIEWS)
 #include "chrome/browser/ui/views/frame/browser_view.h"
@@ -87,9 +87,9 @@
 // Maxiumum time to wait until the focus is moved to expected view.
 const int kFocusChangeTimeoutMs = 500;
 
-const char kSimplePage[] = "files/focus/page_with_focus.html";
-const char kStealFocusPage[] = "files/focus/page_steals_focus.html";
-const char kTypicalPage[] = "files/focus/typical_page.html";
+const char kSimplePage[] = "/focus/page_with_focus.html";
+const char kStealFocusPage[] = "/focus/page_steals_focus.html";
+const char kTypicalPage[] = "/focus/typical_page.html";
 const char kTypicalPageName[] = "typical_page.html";
 
 // Test to make sure Chrome is in the foreground as we start testing. This is
@@ -238,10 +238,10 @@
 // Flaky, http://crbug.com/69034.
 IN_PROC_BROWSER_TEST_F(BrowserFocusTest, DISABLED_BrowsersRememberFocus) {
   ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
-  ASSERT_TRUE(test_server()->Start());
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
 
   // First we navigate to our test page.
-  GURL url = test_server()->GetURL(kSimplePage);
+  GURL url = embedded_test_server()->GetURL(kSimplePage);
   ui_test_utils::NavigateToURL(browser(), url);
 
   gfx::NativeWindow window = browser()->window()->GetNativeWindow();
@@ -307,10 +307,10 @@
 // Disabled, http://crbug.com/62542.
 IN_PROC_BROWSER_TEST_F(BrowserFocusTest, DISABLED_TabsRememberFocus) {
   ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
-  ASSERT_TRUE(test_server()->Start());
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
 
   // First we navigate to our test page.
-  GURL url = test_server()->GetURL(kSimplePage);
+  GURL url = embedded_test_server()->GetURL(kSimplePage);
   ui_test_utils::NavigateToURL(browser(), url);
 
   // Create several tabs.
@@ -376,10 +376,10 @@
 // Tabs remember focus with find-in-page box.
 IN_PROC_BROWSER_TEST_F(BrowserFocusTest, MAYBE_TabsRememberFocusFindInPage) {
   ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
-  ASSERT_TRUE(test_server()->Start());
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
 
   // First we navigate to our test page.
-  GURL url = test_server()->GetURL(kSimplePage);
+  GURL url = embedded_test_server()->GetURL(kSimplePage);
   ui_test_utils::NavigateToURL(browser(), url);
 
   chrome::Find(browser());
@@ -417,7 +417,7 @@
 IN_PROC_BROWSER_TEST_F(BrowserFocusTest,
                        DISABLED_BackgroundBrowserDontStealFocus) {
   ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
-  ASSERT_TRUE(test_server()->Start());
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
 
   // Open a new browser window.
   Browser* browser2 =
@@ -450,7 +450,7 @@
   unfocused_browser = browser();
 #endif
 
-  GURL steal_focus_url = test_server()->GetURL(kStealFocusPage);
+  GURL steal_focus_url = embedded_test_server()->GetURL(kStealFocusPage);
   ui_test_utils::NavigateToURL(unfocused_browser, steal_focus_url);
 
   // Activate the first browser.
@@ -467,10 +467,10 @@
 // Page cannot steal focus when focus is on location bar.
 IN_PROC_BROWSER_TEST_F(BrowserFocusTest, LocationBarLockFocus) {
   ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
-  ASSERT_TRUE(test_server()->Start());
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
 
   // Open the page that steals focus.
-  GURL url = test_server()->GetURL(kStealFocusPage);
+  GURL url = embedded_test_server()->GetURL(kStealFocusPage);
   ui_test_utils::NavigateToURL(browser(), url);
 
   chrome::FocusLocationBar(browser());
@@ -490,10 +490,10 @@
 // RenderWidget::didFocus()).
 IN_PROC_BROWSER_TEST_F(BrowserFocusTest, MAYBE_FocusTraversal) {
   ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
-  ASSERT_TRUE(test_server()->Start());
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
 
   // First we navigate to our test page.
-  GURL url = test_server()->GetURL(kTypicalPage);
+  GURL url = embedded_test_server()->GetURL(kTypicalPage);
   ui_test_utils::NavigateToURL(browser(), url);
 
   chrome::FocusLocationBar(browser());
@@ -612,10 +612,10 @@
 // Focus traversal while an interstitial is showing.
 IN_PROC_BROWSER_TEST_F(BrowserFocusTest, MAYBE_FocusTraversalOnInterstitial) {
   ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
-  ASSERT_TRUE(test_server()->Start());
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
 
   // First we navigate to our test page.
-  GURL url = test_server()->GetURL(kSimplePage);
+  GURL url = embedded_test_server()->GetURL(kSimplePage);
   ui_test_utils::NavigateToURL(browser(), url);
 
   // Focus should be on the page.
@@ -732,10 +732,10 @@
 // http://crbug.com/81451
 IN_PROC_BROWSER_TEST_F(BrowserFocusTest, DISABLED_InterstitialFocus) {
   ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
-  ASSERT_TRUE(test_server()->Start());
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
 
   // First we navigate to our test page.
-  GURL url = test_server()->GetURL(kSimplePage);
+  GURL url = embedded_test_server()->GetURL(kSimplePage);
   ui_test_utils::NavigateToURL(browser(), url);
 
   // Page should have focus.
@@ -769,10 +769,10 @@
 // Disabled due to flakiness. http://crbug.com/67301.
 IN_PROC_BROWSER_TEST_F(BrowserFocusTest, DISABLED_FindFocusTest) {
   ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
-  ASSERT_TRUE(test_server()->Start());
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
 
   // Open some page (any page that doesn't steal focus).
-  GURL url = test_server()->GetURL(kTypicalPage);
+  GURL url = embedded_test_server()->GetURL(kTypicalPage);
   ui_test_utils::NavigateToURL(browser(), url);
 
   EXPECT_TRUE(ChromeInForeground());
@@ -853,7 +853,7 @@
 // Tests that focus goes where expected when using reload.
 IN_PROC_BROWSER_TEST_F(BrowserFocusTest, FocusOnReload) {
   ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
-  ASSERT_TRUE(test_server()->Start());
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
 
   // Open the new tab, reload.
   {
@@ -878,7 +878,8 @@
   ASSERT_TRUE(IsViewFocused(VIEW_ID_OMNIBOX));
 
   // Open a regular page, focus the location bar, reload.
-  ui_test_utils::NavigateToURL(browser(), test_server()->GetURL(kSimplePage));
+  ui_test_utils::NavigateToURL(browser(),
+                               embedded_test_server()->GetURL(kSimplePage));
   chrome::FocusLocationBar(browser());
   ASSERT_TRUE(IsViewFocused(VIEW_ID_OMNIBOX));
   {
@@ -899,10 +900,11 @@
 // Tests that focus goes where expected when using reload on a crashed tab.
 IN_PROC_BROWSER_TEST_F(BrowserFocusTest, DISABLED_FocusOnReloadCrashedTab) {
   ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
-  ASSERT_TRUE(test_server()->Start());
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
 
   // Open a regular page, crash, reload.
-  ui_test_utils::NavigateToURL(browser(), test_server()->GetURL(kSimplePage));
+  ui_test_utils::NavigateToURL(browser(),
+                               embedded_test_server()->GetURL(kSimplePage));
   content::CrashTab(browser()->tab_strip_model()->GetActiveWebContents());
   {
     content::WindowedNotificationObserver observer(
diff --git a/chrome/browser/ui/browser_instant_controller.cc b/chrome/browser/ui/browser_instant_controller.cc
index 008753e..6203f51 100644
--- a/chrome/browser/ui/browser_instant_controller.cc
+++ b/chrome/browser/ui/browser_instant_controller.cc
@@ -15,27 +15,20 @@
 #include "chrome/browser/search_engines/template_url.h"
 #include "chrome/browser/search_engines/template_url_service.h"
 #include "chrome/browser/search_engines/template_url_service_factory.h"
-#include "chrome/browser/themes/theme_properties.h"
-#include "chrome/browser/themes/theme_service.h"
-#include "chrome/browser/themes/theme_service_factory.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/omnibox/location_bar.h"
 #include "chrome/browser/ui/omnibox/omnibox_view.h"
+#include "chrome/browser/ui/search/search_model.h"
 #include "chrome/browser/ui/search/search_tab_helper.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/webui/ntp/app_launcher_handler.h"
-#include "chrome/common/chrome_notification_types.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/url_constants.h"
 #include "components/user_prefs/pref_registry_syncable.h"
-#include "content/public/browser/notification_service.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/user_metrics.h"
 #include "content/public/browser/web_contents.h"
-#include "grit/theme_resources.h"
-#include "ui/gfx/color_utils.h"
-#include "ui/gfx/sys_color_change_listener.h"
 
 using content::UserMetricsAction;
 
@@ -44,10 +37,8 @@
 
 BrowserInstantController::BrowserInstantController(Browser* browser)
     : browser_(browser),
-      instant_(this,
-               chrome::IsInstantExtendedAPIEnabled()),
-      instant_unload_handler_(browser),
-      initialized_theme_info_(false) {
+      instant_(this, chrome::IsInstantExtendedAPIEnabled()),
+      instant_unload_handler_(browser) {
 
   // TODO(sreeram): Perhaps this can be removed, if field trial info is
   // available before we need to register the pref.
@@ -68,17 +59,12 @@
                  base::Unretained(this)));
   ResetInstant(std::string());
   browser_->search_model()->AddObserver(this);
-
-#if defined(ENABLE_THEMES)
-  // Listen for theme installation.
-  registrar_.Add(this, chrome::NOTIFICATION_BROWSER_THEME_CHANGED,
-                 content::Source<ThemeService>(
-                     ThemeServiceFactory::GetForProfile(profile())));
-#endif  // defined(ENABLE_THEMES)
+  net::NetworkChangeNotifier::AddNetworkChangeObserver(this);
 }
 
 BrowserInstantController::~BrowserInstantController() {
   browser_->search_model()->RemoveObserver(this);
+  net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this);
 }
 
 bool BrowserInstantController::MaybeSwapInInstantNTPContents(
@@ -159,29 +145,6 @@
   return browser_->profile();
 }
 
-void BrowserInstantController::CommitInstant(
-    scoped_ptr<content::WebContents> overlay,
-    bool in_new_tab) {
-  const extensions::Extension* extension =
-      profile()->GetExtensionService()->GetInstalledApp(overlay->GetURL());
-  if (extension) {
-    AppLauncherHandler::RecordAppLaunchType(
-        extension_misc::APP_LAUNCH_OMNIBOX_INSTANT,
-        extension->GetType());
-  }
-  if (in_new_tab) {
-    // TabStripModel takes ownership of |overlay|.
-    browser_->tab_strip_model()->AddWebContents(overlay.release(), -1,
-        instant_.last_transition_type(), TabStripModel::ADD_ACTIVE);
-  } else {
-    content::WebContents* contents = overlay.get();
-    ReplaceWebContentsAt(
-        browser_->tab_strip_model()->active_index(),
-        overlay.Pass());
-    browser_->window()->GetLocationBar()->SaveStateToContents(contents);
-  }
-}
-
 void BrowserInstantController::ReplaceWebContentsAt(
     int index,
     scoped_ptr<content::WebContents> new_contents) {
@@ -192,20 +155,6 @@
                                                       index);
 }
 
-void BrowserInstantController::SetInstantSuggestion(
-    const InstantSuggestion& suggestion) {
-  browser_->window()->GetLocationBar()->SetInstantSuggestion(suggestion);
-}
-
-gfx::Rect BrowserInstantController::GetInstantBounds() {
-  return browser_->window()->GetInstantBounds();
-}
-
-void BrowserInstantController::InstantOverlayFocused() {
-  // NOTE: This is only invoked on aura.
-  browser_->window()->WebContentsFocused(instant_.GetOverlayContents());
-}
-
 void BrowserInstantController::FocusOmnibox(bool caret_visibility) {
   OmniboxView* omnibox_view = browser_->window()->GetLocationBar()->
       GetLocationEntry();
@@ -233,15 +182,6 @@
   instant_.TabDeactivated(contents);
 }
 
-void BrowserInstantController::UpdateThemeInfo() {
-  // Update theme background info.
-  // Initialize |theme_info| if necessary.
-  if (!initialized_theme_info_)
-    OnThemeChanged(ThemeServiceFactory::GetForProfile(profile()));
-  else
-    OnThemeChanged(NULL);
-}
-
 void BrowserInstantController::OpenURL(
     const GURL& url,
     content::PageTransition transition,
@@ -257,16 +197,16 @@
   instant_.SetOmniboxBounds(bounds);
 }
 
+void BrowserInstantController::UpdateLocationBar() {
+  browser_->window()->UpdateToolbar(GetActiveWebContents(), false);
+}
+
 void BrowserInstantController::ToggleVoiceSearch() {
   instant_.ToggleVoiceSearch();
 }
 
 void BrowserInstantController::ResetInstant(const std::string& pref_name) {
-  bool instant_checkbox_checked = chrome::IsInstantCheckboxChecked(profile());
-  bool use_local_overlay_only =
-      chrome::IsLocalOnlyInstantExtendedAPIEnabled() ||
-      !chrome::IsInstantCheckboxEnabled(profile());
-  instant_.SetInstantEnabled(instant_checkbox_checked, use_local_overlay_only);
+  instant_.ReloadStaleNTP();
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -275,116 +215,33 @@
 void BrowserInstantController::ModelChanged(
     const SearchModel::State& old_state,
     const SearchModel::State& new_state) {
-  if (old_state.mode == new_state.mode)
-    return;
+  if (old_state.mode != new_state.mode) {
+    const SearchMode& new_mode = new_state.mode;
 
-  const SearchMode& new_mode = new_state.mode;
+    if (chrome::IsInstantExtendedAPIEnabled()) {
+      // Record some actions corresponding to the mode change. Note that to get
+      // the full story, it's necessary to look at other UMA actions as well,
+      // such as tab switches.
+      if (new_mode.is_search_results())
+        content::RecordAction(UserMetricsAction("InstantExtended.ShowSRP"));
+      else if (new_mode.is_ntp())
+        content::RecordAction(UserMetricsAction("InstantExtended.ShowNTP"));
+    }
 
-  if (chrome::IsInstantExtendedAPIEnabled()) {
-    // Record some actions corresponding to the mode change. Note that to get
-    // the full story, it's necessary to look at other UMA actions as well,
-    // such as tab switches.
-    if (new_mode.is_search_results())
-      content::RecordAction(UserMetricsAction("InstantExtended.ShowSRP"));
-    else if (new_mode.is_ntp())
-      content::RecordAction(UserMetricsAction("InstantExtended.ShowNTP"));
+    instant_.SearchModeChanged(old_state.mode, new_mode);
   }
 
-  // If mode is now |NTP|, send theme-related information to Instant.
-  if (new_mode.is_ntp())
-    UpdateThemeInfo();
-
-  instant_.SearchModeChanged(old_state.mode, new_mode);
+  if (old_state.instant_support != new_state.instant_support)
+    instant_.InstantSupportChanged(new_state.instant_support);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
-// BrowserInstantController, content::NotificationObserver implementation:
+// BrowserInstantController, net::NetworkChangeNotifier::NetworkChangeObserver
+// implementation:
 
-void BrowserInstantController::Observe(
-    int type,
-    const content::NotificationSource& source,
-    const content::NotificationDetails& details) {
-#if defined(ENABLE_THEMES)
-  DCHECK_EQ(chrome::NOTIFICATION_BROWSER_THEME_CHANGED, type);
-  OnThemeChanged(content::Source<ThemeService>(source).ptr());
-#endif  // defined(ENABLE_THEMES)
-}
-
-void BrowserInstantController::OnThemeChanged(ThemeService* theme_service) {
-  if (theme_service) {  // Get theme information from theme service.
-    theme_info_ = ThemeBackgroundInfo();
-
-    // Set theme background color.
-    SkColor background_color =
-        theme_service->GetColor(ThemeProperties::COLOR_NTP_BACKGROUND);
-    if (gfx::IsInvertedColorScheme())
-      background_color = color_utils::InvertColor(background_color);
-    theme_info_.color_r = SkColorGetR(background_color);
-    theme_info_.color_g = SkColorGetG(background_color);
-    theme_info_.color_b = SkColorGetB(background_color);
-    theme_info_.color_a = SkColorGetA(background_color);
-
-    if (theme_service->HasCustomImage(IDR_THEME_NTP_BACKGROUND)) {
-      // Set theme id for theme background image url.
-      theme_info_.theme_id = theme_service->GetThemeID();
-
-      // Set theme background image horizontal alignment.
-      int alignment = 0;
-      theme_service->GetDisplayProperty(
-          ThemeProperties::NTP_BACKGROUND_ALIGNMENT, &alignment);
-      if (alignment & ThemeProperties::ALIGN_LEFT) {
-        theme_info_.image_horizontal_alignment = THEME_BKGRND_IMAGE_ALIGN_LEFT;
-      } else if (alignment & ThemeProperties::ALIGN_RIGHT) {
-        theme_info_.image_horizontal_alignment = THEME_BKGRND_IMAGE_ALIGN_RIGHT;
-      } else {  // ALIGN_CENTER
-        theme_info_.image_horizontal_alignment =
-            THEME_BKGRND_IMAGE_ALIGN_CENTER;
-      }
-
-      // Set theme background image vertical alignment.
-      if (alignment & ThemeProperties::ALIGN_TOP)
-        theme_info_.image_vertical_alignment = THEME_BKGRND_IMAGE_ALIGN_TOP;
-      else if (alignment & ThemeProperties::ALIGN_BOTTOM)
-        theme_info_.image_vertical_alignment = THEME_BKGRND_IMAGE_ALIGN_BOTTOM;
-      else  // ALIGN_CENTER
-        theme_info_.image_vertical_alignment = THEME_BKGRND_IMAGE_ALIGN_CENTER;
-
-      // Set theme background image tiling.
-      int tiling = 0;
-      theme_service->GetDisplayProperty(ThemeProperties::NTP_BACKGROUND_TILING,
-                                        &tiling);
-      switch (tiling) {
-        case ThemeProperties::NO_REPEAT:
-            theme_info_.image_tiling = THEME_BKGRND_IMAGE_NO_REPEAT;
-            break;
-        case ThemeProperties::REPEAT_X:
-            theme_info_.image_tiling = THEME_BKGRND_IMAGE_REPEAT_X;
-            break;
-        case ThemeProperties::REPEAT_Y:
-            theme_info_.image_tiling = THEME_BKGRND_IMAGE_REPEAT_Y;
-            break;
-        case ThemeProperties::REPEAT:
-            theme_info_.image_tiling = THEME_BKGRND_IMAGE_REPEAT;
-            break;
-      }
-
-      // Set theme background image height.
-      gfx::ImageSkia* image = theme_service->GetImageSkiaNamed(
-          IDR_THEME_NTP_BACKGROUND);
-      DCHECK(image);
-      theme_info_.image_height = image->height();
-
-      theme_info_.has_attribution =
-          theme_service->HasCustomImage(IDR_THEME_NTP_ATTRIBUTION);
-    }
-
-    initialized_theme_info_ = true;
-  }
-
-  DCHECK(initialized_theme_info_);
-
-  if (browser_->search_model()->mode().is_ntp())
-    instant_.ThemeChanged(theme_info_);
+void BrowserInstantController::OnNetworkChanged(
+    net::NetworkChangeNotifier::ConnectionType type) {
+  instant_.OnNetworkChanged(type);
 }
 
 void BrowserInstantController::OnDefaultSearchProviderChanged(
diff --git a/chrome/browser/ui/browser_instant_controller.h b/chrome/browser/ui/browser_instant_controller.h
index defc8b6..0f9414f 100644
--- a/chrome/browser/ui/browser_instant_controller.h
+++ b/chrome/browser/ui/browser_instant_controller.h
@@ -13,14 +13,12 @@
 #include "chrome/browser/ui/search/instant_controller.h"
 #include "chrome/browser/ui/search/instant_unload_handler.h"
 #include "chrome/browser/ui/search/search_model_observer.h"
-#include "content/public/browser/notification_observer.h"
-#include "content/public/browser/notification_registrar.h"
+#include "net/base/network_change_notifier.h"
 #include "ui/base/window_open_disposition.h"
 
 class Browser;
 struct InstantSuggestion;
 class Profile;
-class ThemeService;
 
 namespace content {
 class WebContents;
@@ -30,8 +28,9 @@
 class Rect;
 }
 
-class BrowserInstantController : public content::NotificationObserver,
-                                 public SearchModelObserver {
+class BrowserInstantController
+    : public SearchModelObserver,
+      public net::NetworkChangeNotifier::NetworkChangeObserver {
  public:
   explicit BrowserInstantController(Browser* browser);
   virtual ~BrowserInstantController();
@@ -59,27 +58,11 @@
   // this BrowserInstantController.
   InstantController* instant() { return &instant_; }
 
-  // Invoked by |instant_| to commit the |overlay| by merging it into the active
-  // tab or adding it as a new tab.
-  void CommitInstant(scoped_ptr<content::WebContents> overlay, bool in_new_tab);
-
-  // Invoked by |instant_| to autocomplete the |suggestion| into the omnibox.
-  void SetInstantSuggestion(const InstantSuggestion& suggestion);
-
-  // Invoked by |instant_| to get the bounds that the overlay is placed at,
-  // in screen coordinates.
-  gfx::Rect GetInstantBounds();
-
-  // Invoked by |instant_| to notify that the overlay gained focus, usually due
-  // to the user clicking on it.
-  void InstantOverlayFocused();
-
   // Invoked by |instant_| to give the omnibox focus, with the option of making
   // the caret invisible.
   void FocusOmnibox(bool caret_visibility);
 
-  // Invoked by |instant_| to get the currently active tab, over which the
-  // overlay would be shown.
+  // Invoked by |instant_| to get the currently active tab.
   content::WebContents* GetActiveWebContents() const;
 
   // Invoked by |browser_| when the active tab changes.
@@ -88,9 +71,6 @@
   // Invoked by |browser_| when the active tab is about to be deactivated.
   void TabDeactivated(content::WebContents* contents);
 
-  // Invoked by |instant_| to update theme information for NTP.
-  void UpdateThemeInfo();
-
   // Invoked by the InstantController when it wants to open a URL.
   void OpenURL(const GURL& url,
                content::PageTransition transition,
@@ -99,6 +79,10 @@
   // Sets the stored omnibox bounds.
   void SetOmniboxBounds(const gfx::Rect& bounds);
 
+  // Updates the location bar to reflect the active page contents Instant
+  // support state.
+  void UpdateLocationBar();
+
   // Notifies |instant_| to toggle voice search.
   void ToggleVoiceSearch();
 
@@ -111,20 +95,16 @@
   virtual void ModelChanged(const SearchModel::State& old_state,
                             const SearchModel::State& new_state) OVERRIDE;
 
-  // content::NotificationObserver implementation.
-  virtual void Observe(int type,
-                       const content::NotificationSource& source,
-                       const content::NotificationDetails& details) OVERRIDE;
-
-  // Helper for handling theme change.
-  void OnThemeChanged(ThemeService* theme_service);
-
   // Called when the default search provider changes. Revokes the searchbox API
   // privileges for any existing WebContents (that belong to the erstwhile
   // default search provider) by simply reloading all such WebContents. This
   // ensures that they are reloaded in a non-privileged renderer process.
   void OnDefaultSearchProviderChanged(const std::string& pref_name);
 
+  // Overridden from net::NetworkChangeNotifier::NetworkChangeObserver:
+  virtual void OnNetworkChanged(net::NetworkChangeNotifier::ConnectionType type)
+      OVERRIDE;
+
   // Replaces the contents at tab |index| with |new_contents| and deletes the
   // existing contents.
   void ReplaceWebContentsAt(int index,
@@ -135,14 +115,8 @@
   InstantController instant_;
   InstantUnloadHandler instant_unload_handler_;
 
-  // Theme-related data for NTP overlay to adopt themes.
-  bool initialized_theme_info_;  // True if theme_info_ has been initialized.
-  ThemeBackgroundInfo theme_info_;
-
   PrefChangeRegistrar profile_pref_registrar_;
 
-  content::NotificationRegistrar registrar_;
-
   DISALLOW_COPY_AND_ASSIGN(BrowserInstantController);
 };
 
diff --git a/chrome/browser/ui/browser_mac.h b/chrome/browser/ui/browser_mac.h
index 2019b69..5031ac5 100644
--- a/chrome/browser/ui/browser_mac.h
+++ b/chrome/browser/ui/browser_mac.h
@@ -6,7 +6,7 @@
 #define CHROME_BROWSER_UI_BROWSER_MAC_H_
 
 #include "chrome/browser/ui/chrome_pages.h"
-#include "chrome/browser/ui/webui/sync_promo/sync_promo_ui.h"
+#include "chrome/browser/ui/sync/sync_promo_ui.h"
 
 class Profile;
 
diff --git a/chrome/browser/ui/browser_navigator.cc b/chrome/browser/ui/browser_navigator.cc
index 0b73f95..3942de5 100644
--- a/chrome/browser/ui/browser_navigator.cc
+++ b/chrome/browser/ui/browser_navigator.cc
@@ -364,6 +364,12 @@
       url, source_contents, &params->target_contents);
 }
 
+chrome::HostDesktopType GetHostDesktop(Browser* browser) {
+  if (browser)
+    return browser->host_desktop_type();
+  return chrome::GetActiveDesktop();
+}
+
 }  // namespace
 
 namespace chrome {
@@ -385,12 +391,9 @@
       ref_behavior(IGNORE_REF),
       browser(a_browser),
       initiating_profile(NULL),
+      host_desktop_type(GetHostDesktop(a_browser)),
       is_cross_site_redirect(false) {
-        if (a_browser)
-          host_desktop_type = a_browser->host_desktop_type();
-        else
-          host_desktop_type = chrome::HOST_DESKTOP_TYPE_NATIVE;
-      }
+}
 
 NavigateParams::NavigateParams(Browser* a_browser,
                                WebContents* a_target_contents)
@@ -407,12 +410,9 @@
       ref_behavior(IGNORE_REF),
       browser(a_browser),
       initiating_profile(NULL),
+      host_desktop_type(GetHostDesktop(a_browser)),
       is_cross_site_redirect(false) {
-        if (a_browser)
-          host_desktop_type = a_browser->host_desktop_type();
-        else
-          host_desktop_type = chrome::HOST_DESKTOP_TYPE_NATIVE;
-      }
+}
 
 NavigateParams::NavigateParams(Profile* a_profile,
                                const GURL& a_url,
@@ -431,8 +431,9 @@
       ref_behavior(IGNORE_REF),
       browser(NULL),
       initiating_profile(a_profile),
-      host_desktop_type(chrome::HOST_DESKTOP_TYPE_NATIVE),
-      is_cross_site_redirect(false) {}
+      host_desktop_type(chrome::GetActiveDesktop()),
+      is_cross_site_redirect(false) {
+}
 
 NavigateParams::~NavigateParams() {}
 
diff --git a/chrome/browser/ui/browser_navigator_browsertest.cc b/chrome/browser/ui/browser_navigator_browsertest.cc
index 5baf285..8cd9080 100644
--- a/chrome/browser/ui/browser_navigator_browsertest.cc
+++ b/chrome/browser/ui/browser_navigator_browsertest.cc
@@ -79,7 +79,7 @@
 Browser* BrowserNavigatorTest::CreateEmptyBrowserForType(Browser::Type type,
                                                          Profile* profile) {
   Browser* browser = new Browser(
-      Browser::CreateParams(type, profile, chrome::HOST_DESKTOP_TYPE_NATIVE));
+      Browser::CreateParams(type, profile, chrome::GetActiveDesktop()));
   chrome::AddBlankTabAt(browser, -1, true);
   return browser;
 }
@@ -89,7 +89,7 @@
   Browser* browser = new Browser(
       Browser::CreateParams::CreateForApp(
           Browser::TYPE_POPUP, "Test", gfx::Rect(), profile,
-          chrome::HOST_DESKTOP_TYPE_NATIVE));
+          chrome::GetActiveDesktop()));
   chrome::AddBlankTabAt(browser, -1, true);
   return browser;
 }
diff --git a/chrome/browser/ui/browser_tab_contents.cc b/chrome/browser/ui/browser_tab_contents.cc
index 56d3204..e10a5f2 100644
--- a/chrome/browser/ui/browser_tab_contents.cc
+++ b/chrome/browser/ui/browser_tab_contents.cc
@@ -42,8 +42,8 @@
 #include "chrome/browser/ui/tab_contents/core_tab_helper.h"
 #include "chrome/browser/ui/zoom/zoom_controller.h"
 #include "chrome/common/chrome_switches.h"
-#include "components/autofill/browser/autofill_manager.h"
 #include "components/autofill/content/browser/autofill_driver_impl.h"
+#include "components/autofill/core/browser/autofill_manager.h"
 #include "components/web_modal/web_contents_modal_dialog_manager.h"
 #include "content/public/browser/web_contents.h"
 #include "extensions/browser/view_type_utils.h"
@@ -109,15 +109,11 @@
 
   AlternateErrorPageTabObserver::CreateForWebContents(web_contents);
   TabAutofillManagerDelegate::CreateForWebContents(web_contents);
-  bool native_autofill_ui_enabled =
-      !CommandLine::ForCurrentProcess()->HasSwitch(
-           switches::kDisableNativeAutofillUi);
   AutofillDriverImpl::CreateForWebContentsAndDelegate(
       web_contents,
       TabAutofillManagerDelegate::FromWebContents(web_contents),
       g_browser_process->GetApplicationLocale(),
-      AutofillManager::ENABLE_AUTOFILL_DOWNLOAD_MANAGER,
-      native_autofill_ui_enabled);
+      AutofillManager::ENABLE_AUTOFILL_DOWNLOAD_MANAGER);
   BlockedContentTabHelper::CreateForWebContents(web_contents);
   BookmarkTabHelper::CreateForWebContents(web_contents);
   chrome_browser_net::LoadTimeStatsTabHelper::CreateForWebContents(
diff --git a/chrome/browser/ui/chrome_pages.h b/chrome/browser/ui/chrome_pages.h
index 9d943f7..3420c5d 100644
--- a/chrome/browser/ui/chrome_pages.h
+++ b/chrome/browser/ui/chrome_pages.h
@@ -7,7 +7,7 @@
 
 #include <string>
 
-#include "chrome/browser/ui/webui/sync_promo/sync_promo_ui.h"
+#include "chrome/browser/ui/sync/sync_promo_ui.h"
 #include "chrome/common/content_settings_types.h"
 
 class Browser;
diff --git a/chrome/browser/ui/chrome_web_modal_dialog_manager_delegate.cc b/chrome/browser/ui/chrome_web_modal_dialog_manager_delegate.cc
index 7155008..da6396e 100644
--- a/chrome/browser/ui/chrome_web_modal_dialog_manager_delegate.cc
+++ b/chrome/browser/ui/chrome_web_modal_dialog_manager_delegate.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2013 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.
 
diff --git a/chrome/browser/ui/chrome_web_modal_dialog_manager_delegate.h b/chrome/browser/ui/chrome_web_modal_dialog_manager_delegate.h
index 2263d75..749debc 100644
--- a/chrome/browser/ui/chrome_web_modal_dialog_manager_delegate.h
+++ b/chrome/browser/ui/chrome_web_modal_dialog_manager_delegate.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2013 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.
 
diff --git a/chrome/browser/ui/cocoa/about_ipc_controller.mm b/chrome/browser/ui/cocoa/about_ipc_controller.mm
index 33667ab..1aebf06 100644
--- a/chrome/browser/ui/cocoa/about_ipc_controller.mm
+++ b/chrome/browser/ui/cocoa/about_ipc_controller.mm
@@ -7,7 +7,7 @@
 #include "base/mac/mac_util.h"
 #include "base/strings/string_util.h"
 #include "base/strings/sys_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #import "chrome/browser/ui/cocoa/about_ipc_controller.h"
 #include "content/public/browser/browser_ipc_logging.h"
 
diff --git a/chrome/browser/ui/cocoa/about_ipc_controller_unittest.mm b/chrome/browser/ui/cocoa/about_ipc_controller_unittest.mm
index 3f4eee7..e4c7bc1 100644
--- a/chrome/browser/ui/cocoa/about_ipc_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/about_ipc_controller_unittest.mm
@@ -4,7 +4,7 @@
 
 #import <Cocoa/Cocoa.h>
 
-#import "base/memory/scoped_nsobject.h"
+#import "base/mac/scoped_nsobject.h"
 #include "base/message_loop.h"
 #import "chrome/browser/ui/cocoa/about_ipc_controller.h"
 #include "chrome/browser/ui/cocoa/cocoa_test_helper.h"
@@ -46,15 +46,15 @@
                           "NPObjectHell" };
   for (size_t i = 0; i < arraysize(names); i++) {
     data.message_name = names[i];
-    scoped_nsobject<CocoaLogData> cdata([[CocoaLogData alloc]
-                                          initWithLogData:data]);
+    base::scoped_nsobject<CocoaLogData> cdata(
+        [[CocoaLogData alloc] initWithLogData:data]);
     EXPECT_FALSE([controller filterOut:cdata.get()]);
   }
 
   // Flip a checkbox, see it filtered, flip back, all is fine.
   data.message_name = "ViewMsgFoo";
-  scoped_nsobject<CocoaLogData> cdata([[CocoaLogData alloc]
-                                        initWithLogData:data]);
+  base::scoped_nsobject<CocoaLogData> cdata(
+      [[CocoaLogData alloc] initWithLogData:data]);
   [controller setDisplayViewMessages:NO];
   EXPECT_TRUE([controller filterOut:cdata.get()]);
   [controller setDisplayViewMessages:YES];
diff --git a/chrome/browser/ui/cocoa/animatable_image.h b/chrome/browser/ui/cocoa/animatable_image.h
index da1f297..102f337 100644
--- a/chrome/browser/ui/cocoa/animatable_image.h
+++ b/chrome/browser/ui/cocoa/animatable_image.h
@@ -8,7 +8,7 @@
 #import <Cocoa/Cocoa.h>
 #import <QuartzCore/QuartzCore.h>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 
 // This class helps animate an NSImage's frame and opacity. It works by creating
 // a blank NSWindow in the size specified and giving it a layer on which the
@@ -20,7 +20,7 @@
 @interface AnimatableImage : NSWindow {
  @private
   // The image to animate.
-  scoped_nsobject<NSImage> image_;
+  base::scoped_nsobject<NSImage> image_;
 
   // The frame of the image before and after the animation. This is in this
   // window's coordinate system.
diff --git a/chrome/browser/ui/cocoa/animatable_image.mm b/chrome/browser/ui/cocoa/animatable_image.mm
index 2d09bf0..d2fd2da 100644
--- a/chrome/browser/ui/cocoa/animatable_image.mm
+++ b/chrome/browser/ui/cocoa/animatable_image.mm
@@ -130,7 +130,7 @@
 // Sets the layer contents by converting the NSImage to a CGImageRef.  This will
 // rasterize PDF resources.
 - (void)setLayerContents:(CALayer*)layer {
-  base::mac::ScopedCFTypeRef<CGImageRef> image(
+  base::ScopedCFTypeRef<CGImageRef> image(
       base::mac::CopyNSImageToCGImage(image_.get()));
   // Create the layer that will be animated.
   [layer setContents:(id)image.get()];
diff --git a/chrome/browser/ui/cocoa/animatable_view.h b/chrome/browser/ui/cocoa/animatable_view.h
index 91cae44..f84c2a5 100644
--- a/chrome/browser/ui/cocoa/animatable_view.h
+++ b/chrome/browser/ui/cocoa/animatable_view.h
@@ -7,7 +7,7 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #import "chrome/browser/ui/cocoa/background_gradient_view.h"
 #import "chrome/browser/ui/cocoa/view_resizer.h"
 
@@ -24,7 +24,7 @@
   IBOutlet id delegate_;  // weak, used to send animation ended messages.
 
  @private
-  scoped_nsobject<NSAnimation> currentAnimation_;
+  base::scoped_nsobject<NSAnimation> currentAnimation_;
   id<ViewResizer> resizeDelegate_;  // weak, usually owns us
 }
 
diff --git a/chrome/browser/ui/cocoa/animatable_view_unittest.mm b/chrome/browser/ui/cocoa/animatable_view_unittest.mm
index e59eae9..1554ff5 100644
--- a/chrome/browser/ui/cocoa/animatable_view_unittest.mm
+++ b/chrome/browser/ui/cocoa/animatable_view_unittest.mm
@@ -4,7 +4,7 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #import "chrome/browser/ui/cocoa/animatable_view.h"
 #import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #import "chrome/browser/ui/cocoa/view_resizer_pong.h"
@@ -24,8 +24,8 @@
     [view_ setResizeDelegate:resizeDelegate_.get()];
   }
 
-  scoped_nsobject<ViewResizerPong> resizeDelegate_;
-  scoped_nsobject<AnimatableView> view_;
+  base::scoped_nsobject<ViewResizerPong> resizeDelegate_;
+  base::scoped_nsobject<AnimatableView> view_;
 };
 
 // Basic view tests (AddRemove, Display).
diff --git a/chrome/browser/ui/cocoa/applescript/bookmark_applescript_utils_unittest.h b/chrome/browser/ui/cocoa/applescript/bookmark_applescript_utils_unittest.h
index 2de6a78..b1f6b07 100644
--- a/chrome/browser/ui/cocoa/applescript/bookmark_applescript_utils_unittest.h
+++ b/chrome/browser/ui/cocoa/applescript/bookmark_applescript_utils_unittest.h
@@ -5,10 +5,10 @@
 #ifndef CHROME_BROWSER_UI_COCOA_APPLESCRIPT_BOOKMARK_APPLESCRIPT_UTILS_UNITTEST_H_
 #define CHROME_BROWSER_UI_COCOA_APPLESCRIPT_BOOKMARK_APPLESCRIPT_UTILS_UNITTEST_H_
 
-#import <objc/objc-runtime.h>
 #import <Cocoa/Cocoa.h>
+#import <objc/objc-runtime.h>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #import "chrome/browser/app_controller_mac.h"
 #import "chrome/browser/ui/cocoa/applescript/bookmark_folder_applescript.h"
 #include "chrome/browser/ui/cocoa/cocoa_profile_test.h"
@@ -42,9 +42,10 @@
   virtual ~BookmarkAppleScriptTest();
   virtual void SetUp() OVERRIDE;
  private:
-  scoped_nsobject<FakeAppDelegate> appDelegate_;
+  base::scoped_nsobject<FakeAppDelegate> appDelegate_;
+
  protected:
-  scoped_nsobject<BookmarkFolderAppleScript> bookmarkBar_;
+  base::scoped_nsobject<BookmarkFolderAppleScript> bookmarkBar_;
 };
 
 #endif  // CHROME_BROWSER_UI_COCOA_APPLESCRIPT_BOOKMARK_APPLESCRIPT_UTILS_UNITTEST_H_
diff --git a/chrome/browser/ui/cocoa/applescript/bookmark_applescript_utils_unittest.mm b/chrome/browser/ui/cocoa/applescript/bookmark_applescript_utils_unittest.mm
index 79c1233..fee143a 100644
--- a/chrome/browser/ui/cocoa/applescript/bookmark_applescript_utils_unittest.mm
+++ b/chrome/browser/ui/cocoa/applescript/bookmark_applescript_utils_unittest.mm
@@ -6,7 +6,7 @@
 
 #include "chrome/browser/bookmarks/bookmark_model.h"
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
-#include "chrome/test/base/model_test_utils.h"
+#include "chrome/browser/bookmarks/bookmark_model_test_utils.h"
 
 @implementation FakeAppDelegate
 
@@ -66,7 +66,7 @@
   BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
   const BookmarkNode* root = model->bookmark_bar_node();
   const std::string modelString("a f1:[ b d c ] d f2:[ e f g ] h ");
-  model_test_utils::AddNodesFromModelString(model, root, modelString);
+  BookmarkModelTestUtils::AddNodesFromModelString(model, root, modelString);
   bookmarkBar_.reset([[BookmarkFolderAppleScript alloc]
       initWithBookmarkNode:model->bookmark_bar_node()]);
 }
diff --git a/chrome/browser/ui/cocoa/applescript/bookmark_folder_applescript.mm b/chrome/browser/ui/cocoa/applescript/bookmark_folder_applescript.mm
index cb978bf..a9ca820 100644
--- a/chrome/browser/ui/cocoa/applescript/bookmark_folder_applescript.mm
+++ b/chrome/browser/ui/cocoa/applescript/bookmark_folder_applescript.mm
@@ -4,7 +4,7 @@
 
 #import "chrome/browser/ui/cocoa/applescript/bookmark_folder_applescript.h"
 
-#import "base/memory/scoped_nsobject.h"
+#import "base/mac/scoped_nsobject.h"
 #import "base/strings/string16.h"
 #include "base/strings/sys_string_conversions.h"
 #include "chrome/browser/bookmarks/bookmark_model.h"
@@ -24,7 +24,7 @@
 
     if (!node->is_folder())
       continue;
-    scoped_nsobject<BookmarkFolderAppleScript> bookmarkFolder(
+    base::scoped_nsobject<BookmarkFolderAppleScript> bookmarkFolder(
         [[BookmarkFolderAppleScript alloc] initWithBookmarkNode:node]);
     [bookmarkFolder setContainer:self
                         property:AppleScript::kBookmarkFoldersProperty];
@@ -95,7 +95,7 @@
 
     if (!node->is_url())
       continue;
-    scoped_nsobject<BookmarkItemAppleScript> bookmarkItem(
+    base::scoped_nsobject<BookmarkItemAppleScript> bookmarkItem(
         [[BookmarkItemAppleScript alloc] initWithBookmarkNode:node]);
     [bookmarkItem setContainer:self
                       property:AppleScript::kBookmarkItemsProperty];
diff --git a/chrome/browser/ui/cocoa/applescript/bookmark_folder_applescript_unittest.mm b/chrome/browser/ui/cocoa/applescript/bookmark_folder_applescript_unittest.mm
index 0bbd0b4..04bac0e 100644
--- a/chrome/browser/ui/cocoa/applescript/bookmark_folder_applescript_unittest.mm
+++ b/chrome/browser/ui/cocoa/applescript/bookmark_folder_applescript_unittest.mm
@@ -4,7 +4,7 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "base/strings/sys_string_conversions.h"
 #import "chrome/browser/ui/cocoa/applescript/bookmark_applescript_utils_unittest.h"
 #import "chrome/browser/ui/cocoa/applescript/bookmark_folder_applescript.h"
@@ -45,9 +45,9 @@
   // Emulate what applescript would do when inserting a new bookmark folder.
   // Emulates a script like |set var to make new bookmark folder with
   // properties {title:"foo"}|.
-  scoped_nsobject<BookmarkFolderAppleScript> bookmarkFolder(
+  base::scoped_nsobject<BookmarkFolderAppleScript> bookmarkFolder(
       [[BookmarkFolderAppleScript alloc] init]);
-  scoped_nsobject<NSNumber> var([[bookmarkFolder.get() uniqueID] copy]);
+  base::scoped_nsobject<NSNumber> var([[bookmarkFolder.get() uniqueID] copy]);
   [bookmarkFolder.get() setTitle:@"foo"];
   [bookmarkBar_.get() insertInBookmarkFolders:bookmarkFolder.get()];
 
@@ -66,9 +66,9 @@
   // Emulate what applescript would do when inserting a new bookmark folder.
   // Emulates a script like |set var to make new bookmark folder with
   // properties {title:"foo"} at after bookmark folder 1|.
-  scoped_nsobject<BookmarkFolderAppleScript> bookmarkFolder(
+  base::scoped_nsobject<BookmarkFolderAppleScript> bookmarkFolder(
       [[BookmarkFolderAppleScript alloc] init]);
-  scoped_nsobject<NSNumber> var([[bookmarkFolder.get() uniqueID] copy]);
+  base::scoped_nsobject<NSNumber> var([[bookmarkFolder.get() uniqueID] copy]);
   [bookmarkFolder.get() setTitle:@"foo"];
   [bookmarkBar_.get() insertInBookmarkFolders:bookmarkFolder.get() atIndex:1];
 
@@ -119,9 +119,9 @@
   // Emulate what applescript would do when inserting a new bookmark folder.
   // Emulates a script like |set var to make new bookmark item with
   // properties {title:"Google", URL:"http://google.com"}|.
-  scoped_nsobject<BookmarkItemAppleScript> bookmarkItem(
+  base::scoped_nsobject<BookmarkItemAppleScript> bookmarkItem(
       [[BookmarkItemAppleScript alloc] init]);
-  scoped_nsobject<NSNumber> var([[bookmarkItem.get() uniqueID] copy]);
+  base::scoped_nsobject<NSNumber> var([[bookmarkItem.get() uniqueID] copy]);
   [bookmarkItem.get() setTitle:@"Google"];
   [bookmarkItem.get() setURL:@"http://google.com"];
   [bookmarkBar_.get() insertInBookmarkItems:bookmarkItem.get()];
@@ -137,7 +137,7 @@
   EXPECT_NSEQ(var.get(), [bi uniqueID]);
 
   // Test to see no bookmark item is created when no/invlid URL is entered.
-  scoped_nsobject<FakeScriptCommand> fakeScriptCommand(
+  base::scoped_nsobject<FakeScriptCommand> fakeScriptCommand(
       [[FakeScriptCommand alloc] init]);
   bookmarkItem.reset([[BookmarkItemAppleScript alloc] init]);
   [bookmarkBar_.get() insertInBookmarkItems:bookmarkItem.get()];
@@ -151,9 +151,9 @@
   // Emulates a script like |set var to make new bookmark item with
   // properties {title:"XKCD", URL:"http://xkcd.org}
   // at after bookmark item 1|.
-  scoped_nsobject<BookmarkItemAppleScript> bookmarkItem(
+  base::scoped_nsobject<BookmarkItemAppleScript> bookmarkItem(
       [[BookmarkItemAppleScript alloc] init]);
-  scoped_nsobject<NSNumber> var([[bookmarkItem.get() uniqueID] copy]);
+  base::scoped_nsobject<NSNumber> var([[bookmarkItem.get() uniqueID] copy]);
   [bookmarkItem.get() setTitle:@"XKCD"];
   [bookmarkItem.get() setURL:@"http://xkcd.org"];
 
@@ -171,7 +171,7 @@
   EXPECT_NSEQ(var.get(), [bi uniqueID]);
 
   // Test to see no bookmark item is created when no/invlid URL is entered.
-  scoped_nsobject<FakeScriptCommand> fakeScriptCommand(
+  base::scoped_nsobject<FakeScriptCommand> fakeScriptCommand(
       [[FakeScriptCommand alloc] init]);
   bookmarkItem.reset([[BookmarkItemAppleScript alloc] init]);
   [bookmarkBar_.get() insertInBookmarkItems:bookmarkItem.get() atIndex:1];
diff --git a/chrome/browser/ui/cocoa/applescript/bookmark_item_applescript_unittest.mm b/chrome/browser/ui/cocoa/applescript/bookmark_item_applescript_unittest.mm
index 44a309f..8e581f2 100644
--- a/chrome/browser/ui/cocoa/applescript/bookmark_item_applescript_unittest.mm
+++ b/chrome/browser/ui/cocoa/applescript/bookmark_item_applescript_unittest.mm
@@ -4,7 +4,7 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "base/strings/sys_string_conversions.h"
 #import "chrome/browser/ui/cocoa/applescript/bookmark_applescript_utils_unittest.h"
 #import "chrome/browser/ui/cocoa/applescript/bookmark_item_applescript.h"
@@ -35,7 +35,7 @@
             GURL(base::SysNSStringToUTF8([item1 URL])));
 
   // If scripter enters invalid URL.
-  scoped_nsobject<FakeScriptCommand> fakeScriptCommand(
+  base::scoped_nsobject<FakeScriptCommand> fakeScriptCommand(
       [[FakeScriptCommand alloc] init]);
   [item1 setURL:@"invalid-url.org"];
   EXPECT_EQ((int)AppleScript::errInvalidURL,
diff --git a/chrome/browser/ui/cocoa/applescript/bookmark_node_applescript.mm b/chrome/browser/ui/cocoa/applescript/bookmark_node_applescript.mm
index 49fcc06..5255cd6 100644
--- a/chrome/browser/ui/cocoa/applescript/bookmark_node_applescript.mm
+++ b/chrome/browser/ui/cocoa/applescript/bookmark_node_applescript.mm
@@ -5,7 +5,7 @@
 #import "chrome/browser/ui/cocoa/applescript/bookmark_node_applescript.h"
 
 #include "base/logging.h"
-#import "base/memory/scoped_nsobject.h"
+#import "base/mac/scoped_nsobject.h"
 #include "base/strings/sys_string_conversions.h"
 #import "chrome/browser/app_controller_mac.h"
 #include "chrome/browser/bookmarks/bookmark_model.h"
@@ -31,7 +31,7 @@
       return nil;
     }
 
-    scoped_nsobject<NSNumber> numID(
+    base::scoped_nsobject<NSNumber> numID(
         [[NSNumber alloc] initWithLongLong:model->next_node_id()]);
     [self setUniqueID:numID];
     [self setTempTitle:@""];
@@ -58,7 +58,7 @@
     // and this particular bookmark item/folder is never returned.
     bookmarkNode_ = aBookmarkNode;
 
-    scoped_nsobject<NSNumber>  numID(
+    base::scoped_nsobject<NSNumber> numID(
         [[NSNumber alloc] initWithLongLong:aBookmarkNode->id()]);
     [self setUniqueID:numID];
   }
@@ -73,7 +73,7 @@
   // and this particular bookmark item/folder is never returned.
   bookmarkNode_ = aBookmarkNode;
 
-  scoped_nsobject<NSNumber> numID(
+  base::scoped_nsobject<NSNumber> numID(
       [[NSNumber alloc] initWithLongLong:aBookmarkNode->id()]);
   [self setUniqueID:numID];
 
diff --git a/chrome/browser/ui/cocoa/applescript/browsercrapplication+applescript.mm b/chrome/browser/ui/cocoa/applescript/browsercrapplication+applescript.mm
index d6e3326..6cdd204 100644
--- a/chrome/browser/ui/cocoa/applescript/browsercrapplication+applescript.mm
+++ b/chrome/browser/ui/cocoa/applescript/browsercrapplication+applescript.mm
@@ -5,7 +5,7 @@
 #import "chrome/browser/ui/cocoa/applescript/browsercrapplication+applescript.h"
 
 #include "base/logging.h"
-#import "base/memory/scoped_nsobject.h"
+#import "base/mac/scoped_nsobject.h"
 #import "chrome/browser/app_controller_mac.h"
 #include "chrome/browser/bookmarks/bookmark_model.h"
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
@@ -30,7 +30,7 @@
     if ((*browserIterator)->IsAttemptingToCloseBrowser())
       continue;
 
-    scoped_nsobject<WindowAppleScript> window(
+    base::scoped_nsobject<WindowAppleScript> window(
         [[WindowAppleScript alloc] initWithBrowser:*browserIterator]);
     [window setContainer:NSApp
                 property:AppleScript::kWindowsProperty];
diff --git a/chrome/browser/ui/cocoa/applescript/browsercrapplication+applescript_test.mm b/chrome/browser/ui/cocoa/applescript/browsercrapplication+applescript_test.mm
index 0ac3eaa..12bdcb9 100644
--- a/chrome/browser/ui/cocoa/applescript/browsercrapplication+applescript_test.mm
+++ b/chrome/browser/ui/cocoa/applescript/browsercrapplication+applescript_test.mm
@@ -4,6 +4,7 @@
 
 #import <Cocoa/Cocoa.h>
 
+#include "base/mac/scoped_nsobject.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_tabstrip.h"
@@ -47,8 +48,9 @@
   // Emulate what applescript would do when creating a new window.
   // Emulate a script like |set var to make new window with properties
   // {visible:false}|.
-  scoped_nsobject<WindowAppleScript> aWindow([[WindowAppleScript alloc] init]);
-  scoped_nsobject<NSNumber> var([[aWindow.get() uniqueID] copy]);
+  base::scoped_nsobject<WindowAppleScript> aWindow(
+      [[WindowAppleScript alloc] init]);
+  base::scoped_nsobject<NSNumber> var([[aWindow.get() uniqueID] copy]);
   [aWindow.get() setValue:[NSNumber numberWithBool:YES] forKey:@"isVisible"];
 
   [NSApp insertInAppleScriptWindows:aWindow.get()];
@@ -66,7 +68,7 @@
 // Inserting and deleting windows.
 IN_PROC_BROWSER_TEST_F(BrowserCrApplicationAppleScriptTest,
                        InsertAndDeleteWindows) {
-  scoped_nsobject<WindowAppleScript> aWindow;
+  base::scoped_nsobject<WindowAppleScript> aWindow;
   int count;
   // Create a bunch of windows.
   for (int i = 0; i < 5; ++i) {
diff --git a/chrome/browser/ui/cocoa/applescript/tab_applescript.mm b/chrome/browser/ui/cocoa/applescript/tab_applescript.mm
index 7fc426f..e2a3539 100644
--- a/chrome/browser/ui/cocoa/applescript/tab_applescript.mm
+++ b/chrome/browser/ui/cocoa/applescript/tab_applescript.mm
@@ -7,7 +7,7 @@
 #include "base/bind.h"
 #include "base/files/file_path.h"
 #include "base/logging.h"
-#import "base/memory/scoped_nsobject.h"
+#import "base/mac/scoped_nsobject.h"
 #include "base/strings/sys_string_conversions.h"
 #include "chrome/browser/printing/print_view_manager.h"
 #include "chrome/browser/sessions/session_id.h"
@@ -60,7 +60,7 @@
     SessionID session;
     SessionID::id_type futureSessionIDOfTab = session.id() + 1;
     // Holds the SessionID that the new tab is going to get.
-    scoped_nsobject<NSNumber> numID(
+    base::scoped_nsobject<NSNumber> numID(
         [[NSNumber alloc] initWithInt:futureSessionIDOfTab]);
     [self setUniqueID:numID];
   }
@@ -85,7 +85,7 @@
     webContents_ = webContents;
     SessionTabHelper* session_tab_helper =
         SessionTabHelper::FromWebContents(webContents);
-    scoped_nsobject<NSNumber> numID(
+    base::scoped_nsobject<NSNumber> numID(
         [[NSNumber alloc] initWithInt:session_tab_helper->session_id().id()]);
     [self setUniqueID:numID];
   }
@@ -100,7 +100,7 @@
   webContents_ = webContents;
   SessionTabHelper* session_tab_helper =
       SessionTabHelper::FromWebContents(webContents);
-  scoped_nsobject<NSNumber> numID(
+  base::scoped_nsobject<NSNumber> numID(
       [[NSNumber alloc] initWithInt:session_tab_helper->session_id().id()]);
   [self setUniqueID:numID];
 
diff --git a/chrome/browser/ui/cocoa/applescript/window_applescript.mm b/chrome/browser/ui/cocoa/applescript/window_applescript.mm
index fe6677f..ba93252 100644
--- a/chrome/browser/ui/cocoa/applescript/window_applescript.mm
+++ b/chrome/browser/ui/cocoa/applescript/window_applescript.mm
@@ -5,9 +5,9 @@
 #import "chrome/browser/ui/cocoa/applescript/window_applescript.h"
 
 #include "base/logging.h"
-#import "base/memory/scoped_nsobject.h"
+#import "base/mac/scoped_nsobject.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #import "chrome/browser/app_controller_mac.h"
 #import "chrome/browser/chrome_browser_application_mac.h"
 #include "chrome/browser/profiles/profile.h"
@@ -75,7 +75,7 @@
         Browser::CreateParams(aProfile, chrome::HOST_DESKTOP_TYPE_NATIVE));
     chrome::NewTab(browser_);
     browser_->window()->Show();
-    scoped_nsobject<NSNumber> numID(
+    base::scoped_nsobject<NSNumber> numID(
         [[NSNumber alloc] initWithInt:browser_->session_id().id()]);
     [self setUniqueID:numID];
   }
@@ -93,7 +93,7 @@
     // the applescript runtime calls appleScriptWindows in
     // BrowserCrApplication and this particular window is never returned.
     browser_ = aBrowser;
-    scoped_nsobject<NSNumber> numID(
+    base::scoped_nsobject<NSNumber> numID(
         [[NSNumber alloc] initWithInt:browser_->session_id().id()]);
     [self setUniqueID:numID];
   }
@@ -159,7 +159,7 @@
       continue;
     }
 
-    scoped_nsobject<TabAppleScript> tab(
+    base::scoped_nsobject<TabAppleScript> tab(
         [[TabAppleScript alloc] initWithWebContents:webContents]);
     [tab setContainer:self
              property:AppleScript::kTabsProperty];
diff --git a/chrome/browser/ui/cocoa/applescript/window_applescript_test.mm b/chrome/browser/ui/cocoa/applescript/window_applescript_test.mm
index f13b03b..f627622 100644
--- a/chrome/browser/ui/cocoa/applescript/window_applescript_test.mm
+++ b/chrome/browser/ui/cocoa/applescript/window_applescript_test.mm
@@ -4,7 +4,7 @@
 
 #import <Cocoa/Cocoa.h>
 
-#import "base/memory/scoped_nsobject.h"
+#import "base/mac/scoped_nsobject.h"
 #include "base/strings/sys_string_conversions.h"
 #import "chrome/browser/app_controller_mac.h"
 #import "chrome/browser/chrome_browser_application_mac.h"
@@ -22,7 +22,7 @@
 
 // Create a window in default/normal mode.
 IN_PROC_BROWSER_TEST_F(WindowAppleScriptTest, DefaultCreation) {
-  scoped_nsobject<WindowAppleScript> aWindow(
+  base::scoped_nsobject<WindowAppleScript> aWindow(
       [[WindowAppleScript alloc] init]);
   EXPECT_TRUE(aWindow.get());
   NSString* mode = [aWindow.get() mode];
@@ -32,7 +32,7 @@
 
 // Create a window with a |NULL profile|.
 IN_PROC_BROWSER_TEST_F(WindowAppleScriptTest, CreationWithNoProfile) {
-  scoped_nsobject<WindowAppleScript> aWindow(
+  base::scoped_nsobject<WindowAppleScript> aWindow(
       [[WindowAppleScript alloc] initWithProfile:NULL]);
   EXPECT_FALSE(aWindow.get());
 }
@@ -40,7 +40,7 @@
 // Create a window with a particular profile.
 IN_PROC_BROWSER_TEST_F(WindowAppleScriptTest, CreationWithProfile) {
   Profile* lastProfile = [[NSApp delegate] lastProfile];
-  scoped_nsobject<WindowAppleScript> aWindow(
+  base::scoped_nsobject<WindowAppleScript> aWindow(
       [[WindowAppleScript alloc] initWithProfile:lastProfile]);
   EXPECT_TRUE(aWindow.get());
   EXPECT_TRUE([aWindow.get() uniqueID]);
@@ -48,14 +48,14 @@
 
 // Create a window with no |Browser*|.
 IN_PROC_BROWSER_TEST_F(WindowAppleScriptTest, CreationWithNoBrowser) {
-  scoped_nsobject<WindowAppleScript> aWindow(
+  base::scoped_nsobject<WindowAppleScript> aWindow(
       [[WindowAppleScript alloc] initWithBrowser:NULL]);
   EXPECT_FALSE(aWindow.get());
 }
 
 // Create a window with |Browser*| already present.
 IN_PROC_BROWSER_TEST_F(WindowAppleScriptTest, CreationWithBrowser) {
-  scoped_nsobject<WindowAppleScript> aWindow(
+  base::scoped_nsobject<WindowAppleScript> aWindow(
       [[WindowAppleScript alloc] initWithBrowser:browser()]);
   EXPECT_TRUE(aWindow.get());
   EXPECT_TRUE([aWindow.get() uniqueID]);
@@ -63,7 +63,7 @@
 
 // Tabs within the window.
 IN_PROC_BROWSER_TEST_F(WindowAppleScriptTest, Tabs) {
-  scoped_nsobject<WindowAppleScript> aWindow(
+  base::scoped_nsobject<WindowAppleScript> aWindow(
       [[WindowAppleScript alloc] initWithBrowser:browser()]);
   NSArray* tabs = [aWindow.get() tabs];
   EXPECT_EQ(1U, [tabs count]);
@@ -78,10 +78,10 @@
   // Emulate what applescript would do when creating a new tab.
   // Emulates a script like |set var to make new tab with
   // properties URL:"http://google.com"}|.
-  scoped_nsobject<TabAppleScript> aTab([[TabAppleScript alloc] init]);
-  scoped_nsobject<NSNumber> var([[aTab.get() uniqueID] copy]);
+  base::scoped_nsobject<TabAppleScript> aTab([[TabAppleScript alloc] init]);
+  base::scoped_nsobject<NSNumber> var([[aTab.get() uniqueID] copy]);
   [aTab.get() setURL:@"http://google.com"];
-  scoped_nsobject<WindowAppleScript> aWindow(
+  base::scoped_nsobject<WindowAppleScript> aWindow(
       [[WindowAppleScript alloc] initWithBrowser:browser()]);
   [aWindow.get() insertInTabs:aTab.get()];
 
@@ -100,10 +100,10 @@
   // Emulate what applescript would do when creating a new tab.
   // Emulates a script like |set var to make new tab with
   // properties URL:"http://google.com"} at before tab 1|.
-  scoped_nsobject<TabAppleScript> aTab([[TabAppleScript alloc] init]);
-  scoped_nsobject<NSNumber> var([[aTab.get() uniqueID] copy]);
+  base::scoped_nsobject<TabAppleScript> aTab([[TabAppleScript alloc] init]);
+  base::scoped_nsobject<NSNumber> var([[aTab.get() uniqueID] copy]);
   [aTab.get() setURL:@"http://google.com"];
-  scoped_nsobject<WindowAppleScript> aWindow(
+  base::scoped_nsobject<WindowAppleScript> aWindow(
       [[WindowAppleScript alloc] initWithBrowser:browser()]);
   [aWindow.get() insertInTabs:aTab.get() atIndex:0];
 
@@ -118,9 +118,9 @@
 
 // Inserting and deleting tabs.
 IN_PROC_BROWSER_TEST_F(WindowAppleScriptTest, InsertAndDeleteTabs) {
-  scoped_nsobject<WindowAppleScript> aWindow(
+  base::scoped_nsobject<WindowAppleScript> aWindow(
       [[WindowAppleScript alloc] initWithBrowser:browser()]);
-  scoped_nsobject<TabAppleScript> aTab;
+  base::scoped_nsobject<TabAppleScript> aTab;
   int count;
   for (int i = 0; i < 5; ++i) {
     for (int j = 0; j < 3; ++j) {
@@ -143,7 +143,7 @@
 
 // Getting and setting values from the NSWindow.
 IN_PROC_BROWSER_TEST_F(WindowAppleScriptTest, NSWindowTest) {
-  scoped_nsobject<WindowAppleScript> aWindow(
+  base::scoped_nsobject<WindowAppleScript> aWindow(
       [[WindowAppleScript alloc] initWithBrowser:browser()]);
   [aWindow.get() setValue:[NSNumber numberWithBool:YES]
                    forKey:@"isMiniaturized"];
@@ -155,9 +155,9 @@
 
 // Getting and setting the active tab.
 IN_PROC_BROWSER_TEST_F(WindowAppleScriptTest, ActiveTab) {
-  scoped_nsobject<WindowAppleScript> aWindow(
+  base::scoped_nsobject<WindowAppleScript> aWindow(
       [[WindowAppleScript alloc] initWithBrowser:browser()]);
-  scoped_nsobject<TabAppleScript> aTab([[TabAppleScript alloc] init]);
+  base::scoped_nsobject<TabAppleScript> aTab([[TabAppleScript alloc] init]);
   [aWindow.get() insertInTabs:aTab.get()];
   [aWindow.get() setActiveTabIndex:[NSNumber numberWithInt:2]];
   EXPECT_EQ(2, [[aWindow.get() activeTabIndex] intValue]);
@@ -168,9 +168,9 @@
 
 // Order of windows.
 IN_PROC_BROWSER_TEST_F(WindowAppleScriptTest, WindowOrder) {
-  scoped_nsobject<WindowAppleScript> window2(
+  base::scoped_nsobject<WindowAppleScript> window2(
       [[WindowAppleScript alloc] initWithBrowser:browser()]);
-  scoped_nsobject<WindowAppleScript> window1(
+  base::scoped_nsobject<WindowAppleScript> window1(
       [[WindowAppleScript alloc] init]);
   EXPECT_EQ([window1.get() windowComparator:window2.get()], NSOrderedAscending);
   EXPECT_EQ([window2.get() windowComparator:window1.get()],
diff --git a/chrome/browser/ui/cocoa/autofill/autofill_account_chooser.h b/chrome/browser/ui/cocoa/autofill/autofill_account_chooser.h
index c1b1116..67d2bff 100644
--- a/chrome/browser/ui/cocoa/autofill/autofill_account_chooser.h
+++ b/chrome/browser/ui/cocoa/autofill/autofill_account_chooser.h
@@ -7,7 +7,7 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 
 namespace autofill {
   class AutofillDialogController;
@@ -17,9 +17,9 @@
 
 @interface AutofillAccountChooser : NSView {
  @private
-  scoped_nsobject<NSButton> link_;
-  scoped_nsobject<MenuButton> popup_;
-  scoped_nsobject<NSImageView> icon_;
+  base::scoped_nsobject<NSButton> link_;
+  base::scoped_nsobject<MenuButton> popup_;
+  base::scoped_nsobject<NSImageView> icon_;
   autofill::AutofillDialogController* controller_;  // weak.
 }
 
diff --git a/chrome/browser/ui/cocoa/autofill/autofill_account_chooser.mm b/chrome/browser/ui/cocoa/autofill/autofill_account_chooser.mm
index c3904ae..35111d2 100644
--- a/chrome/browser/ui/cocoa/autofill/autofill_account_chooser.mm
+++ b/chrome/browser/ui/cocoa/autofill/autofill_account_chooser.mm
@@ -26,10 +26,10 @@
     return;
   }
 
-  scoped_nsobject<NSMenuItem> item([[NSMenuItem alloc]
-    initWithTitle:title
-           action:selector
-    keyEquivalent:@""]);
+  base::scoped_nsobject<NSMenuItem> item(
+      [[NSMenuItem alloc] initWithTitle:title
+                                 action:selector
+                          keyEquivalent:@""]);
   [item setTag:tag];
   [menu addItem:item];
   [item setTarget:target];
@@ -63,7 +63,7 @@
         gfx::SkColorToCalibratedNSColor(chrome_style::GetLinkColor())];
 
     popup_.reset([[MenuButton alloc] initWithFrame:NSZeroRect]);
-    scoped_nsobject<DownArrowPopupMenuCell> popupCell(
+    base::scoped_nsobject<DownArrowPopupMenuCell> popupCell(
         [[DownArrowPopupMenuCell alloc] initTextCell:@""]);
     [popup_ setCell:popupCell];
 
@@ -75,7 +75,7 @@
     [popupCell setImage:popupImage
         forButtonState:image_button_cell::kDefaultState];
 
-    scoped_nsobject<NSMenu> menu([[NSMenu alloc] initWithTitle:@""]);
+    base::scoped_nsobject<NSMenu> menu([[NSMenu alloc] initWithTitle:@""]);
     [menu setAutoenablesItems:NO];
     [popup_ setAttachedMenu:menu];
 
diff --git a/chrome/browser/ui/cocoa/autofill/autofill_account_chooser_unittest.mm b/chrome/browser/ui/cocoa/autofill/autofill_account_chooser_unittest.mm
index e6ce376..d4717cb 100644
--- a/chrome/browser/ui/cocoa/autofill/autofill_account_chooser_unittest.mm
+++ b/chrome/browser/ui/cocoa/autofill/autofill_account_chooser_unittest.mm
@@ -27,7 +27,7 @@
  }
 
  protected:
-  scoped_nsobject<AutofillAccountChooser> view_;
+  base::scoped_nsobject<AutofillAccountChooser> view_;
   testing::NiceMock<autofill::MockAutofillDialogController> controller_;
 
  private:
diff --git a/chrome/browser/ui/cocoa/autofill/autofill_details_container.h b/chrome/browser/ui/cocoa/autofill/autofill_details_container.h
index 79c5804..aa99561 100644
--- a/chrome/browser/ui/cocoa/autofill/autofill_details_container.h
+++ b/chrome/browser/ui/cocoa/autofill/autofill_details_container.h
@@ -7,7 +7,7 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "chrome/browser/ui/autofill/autofill_dialog_types.h"
 #import "chrome/browser/ui/cocoa/autofill/autofill_layout.h"
 
@@ -20,7 +20,8 @@
 // UI controller for details for current payment instrument.
 @interface AutofillDetailsContainer : NSViewController<AutofillLayout> {
  @private
-  scoped_nsobject<NSMutableArray> details_;  // The individual detail sections.
+  base::scoped_nsobject<NSMutableArray> details_;   // The individual detail
+                                                    // sections.
   autofill::AutofillDialogController* controller_;  // Not owned.
 }
 
diff --git a/chrome/browser/ui/cocoa/autofill/autofill_details_container.mm b/chrome/browser/ui/cocoa/autofill/autofill_details_container.mm
index 5a88597..0defb1f 100644
--- a/chrome/browser/ui/cocoa/autofill/autofill_details_container.mm
+++ b/chrome/browser/ui/cocoa/autofill/autofill_details_container.mm
@@ -19,7 +19,7 @@
 }
 
 - (void)addSection:(autofill::DialogSection)section {
-  scoped_nsobject<AutofillSectionContainer> sectionContainer(
+  base::scoped_nsobject<AutofillSectionContainer> sectionContainer(
       [[AutofillSectionContainer alloc] initWithController:controller_
                                                 forSection:section]);
   [details_ addObject:sectionContainer];
@@ -31,7 +31,7 @@
   [self addSection:autofill::SECTION_EMAIL];
   [self addSection:autofill::SECTION_CC];
   [self addSection:autofill::SECTION_BILLING];
-  // TODO(groby): Add SECTION_CC_BILLING once toggling is enabled.
+  [self addSection:autofill::SECTION_CC_BILLING];
   [self addSection:autofill::SECTION_SHIPPING];
 
   [self setView:[[NSView alloc] init]];
@@ -43,7 +43,6 @@
 
 - (NSSize)preferredSize {
   NSSize size = NSMakeSize(0, 0);
-
   for (AutofillSectionContainer* container in details_.get()) {
     NSSize containerSize = [container preferredSize];
     size.height += containerSize.height;
@@ -56,9 +55,11 @@
   NSRect rect = NSZeroRect;
   for (AutofillSectionContainer* container in
       [details_ reverseObjectEnumerator]) {
-    [container performLayout];
-    [[container view] setFrameOrigin:NSMakePoint(0, NSMaxY(rect))];
-    rect = NSUnionRect(rect, [[container view] frame]);
+    if (![[container view] isHidden]) {
+      [container performLayout];
+      [[container view] setFrameOrigin:NSMakePoint(0, NSMaxY(rect))];
+      rect = NSUnionRect(rect, [[container view] frame]);
+    }
   }
 
   [[self view] setFrameSize:[self preferredSize]];
diff --git a/chrome/browser/ui/cocoa/autofill/autofill_details_container_unittest.mm b/chrome/browser/ui/cocoa/autofill/autofill_details_container_unittest.mm
index 4841710..7cbc178 100644
--- a/chrome/browser/ui/cocoa/autofill/autofill_details_container_unittest.mm
+++ b/chrome/browser/ui/cocoa/autofill/autofill_details_container_unittest.mm
@@ -4,7 +4,7 @@
 
 #import "chrome/browser/ui/cocoa/autofill/autofill_details_container.h"
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "chrome/browser/ui/autofill/mock_autofill_dialog_controller.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/platform_test.h"
@@ -21,7 +21,7 @@
   }
 
  protected:
-  scoped_nsobject<AutofillDetailsContainer> container_;
+  base::scoped_nsobject<AutofillDetailsContainer> container_;
   testing::NiceMock<autofill::MockAutofillDialogController> controller_;
 };
 
diff --git a/chrome/browser/ui/cocoa/autofill/autofill_dialog_cocoa.h b/chrome/browser/ui/cocoa/autofill/autofill_dialog_cocoa.h
index d86d6ca..73fc8bf 100644
--- a/chrome/browser/ui/cocoa/autofill/autofill_dialog_cocoa.h
+++ b/chrome/browser/ui/cocoa/autofill/autofill_dialog_cocoa.h
@@ -5,7 +5,7 @@
 #ifndef CHROME_BROWSER_UI_COCOA_AUTOFILL_AUTOFILL_DIALOG_COCOA_H_
 #define CHROME_BROWSER_UI_COCOA_AUTOFILL_AUTOFILL_DIALOG_COCOA_H_
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "base/memory/scoped_ptr.h"
 #include "chrome/browser/ui/autofill/autofill_dialog_types.h"
 #include "chrome/browser/ui/autofill/autofill_dialog_view.h"
@@ -41,6 +41,7 @@
   virtual void UpdateDetailArea() OVERRIDE;
   virtual void UpdateForErrors() OVERRIDE;
   virtual void UpdateNotificationArea() OVERRIDE;
+  virtual void UpdateAutocheckoutStepsArea() OVERRIDE;
   virtual void UpdateSection(DialogSection section) OVERRIDE;
   virtual void FillSection(DialogSection section,
                            const DetailInput& originating_input) OVERRIDE;
@@ -65,7 +66,7 @@
  private:
 
   scoped_ptr<ConstrainedWindowMac> constrained_window_;
-  scoped_nsobject<AutofillDialogWindowController> sheet_controller_;
+  base::scoped_nsobject<AutofillDialogWindowController> sheet_controller_;
 
   // The controller |this| queries for logic and state.
   AutofillDialogController* controller_;
@@ -79,9 +80,9 @@
   content::WebContents* webContents_;  // weak.
   autofill::AutofillDialogCocoa* autofillDialog_;  // weak.
 
-  scoped_nsobject<AutofillMainContainer> mainContainer_;
-  scoped_nsobject<AutofillSignInContainer> signInContainer_;
-  scoped_nsobject<AutofillAccountChooser> accountChooser_;
+  base::scoped_nsobject<AutofillMainContainer> mainContainer_;
+  base::scoped_nsobject<AutofillSignInContainer> signInContainer_;
+  base::scoped_nsobject<AutofillAccountChooser> accountChooser_;
 }
 
 // Designated initializer. The WebContents cannot be NULL.
@@ -100,6 +101,7 @@
 
 // Forwarding AutofillDialogView calls.
 - (void)updateAccountChooser;
+- (void)updateNotificationArea;
 - (void)updateSection:(autofill::DialogSection)section;
 - (void)getInputs:(autofill::DetailOutputMap*)outputs
        forSection:(autofill::DialogSection)section;
diff --git a/chrome/browser/ui/cocoa/autofill/autofill_dialog_cocoa.mm b/chrome/browser/ui/cocoa/autofill/autofill_dialog_cocoa.mm
index 30ecf35..7d8e3e2 100644
--- a/chrome/browser/ui/cocoa/autofill/autofill_dialog_cocoa.mm
+++ b/chrome/browser/ui/cocoa/autofill/autofill_dialog_cocoa.mm
@@ -5,10 +5,9 @@
 #include "chrome/browser/ui/cocoa/autofill/autofill_dialog_cocoa.h"
 
 #include "base/mac/bundle_locations.h"
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "chrome/browser/ui/autofill/autofill_dialog_controller.h"
 #include "chrome/browser/ui/chrome_style.h"
-#import "chrome/browser/ui/cocoa/constrained_window/constrained_window_button.h"
 #include "chrome/browser/ui/chrome_style.h"
 #include "chrome/browser/ui/chrome_style.h"
 #import "chrome/browser/ui/cocoa/autofill/autofill_account_chooser.h"
@@ -16,6 +15,7 @@
 #import "chrome/browser/ui/cocoa/autofill/autofill_main_container.h"
 #import "chrome/browser/ui/cocoa/autofill/autofill_section_container.h"
 #import "chrome/browser/ui/cocoa/autofill/autofill_sign_in_container.h"
+#import "chrome/browser/ui/cocoa/constrained_window/constrained_window_button.h"
 #import "chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_sheet.h"
 #import "chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_window.h"
 #import "ui/base/cocoa/flipped_view.h"
@@ -49,7 +49,7 @@
   sheet_controller_.reset([[AutofillDialogWindowController alloc]
        initWithWebContents:controller_->web_contents()
             autofillDialog:this]);
-  scoped_nsobject<CustomConstrainedWindowSheet> sheet(
+  base::scoped_nsobject<CustomConstrainedWindowSheet> sheet(
       [[CustomConstrainedWindowSheet alloc]
           initWithCustomWindow:[sheet_controller_ window]]);
   constrained_window_.reset(
@@ -75,6 +75,10 @@
 }
 
 void AutofillDialogCocoa::UpdateNotificationArea() {
+  [sheet_controller_ updateNotificationArea];
+}
+
+void AutofillDialogCocoa::UpdateAutocheckoutStepsArea() {
 }
 
 void AutofillDialogCocoa::UpdateSection(DialogSection section) {
@@ -133,7 +137,7 @@
       autofillDialog:(autofill::AutofillDialogCocoa*)autofillDialog {
   DCHECK(webContents);
 
-  scoped_nsobject<ConstrainedWindowCustomWindow> window(
+  base::scoped_nsobject<ConstrainedWindowCustomWindow> window(
       [[ConstrainedWindowCustomWindow alloc]
           initWithContentRect:ui::kWindowSizeDeterminedLater]);
 
@@ -166,13 +170,14 @@
     // This needs a flipped content view because otherwise the size
     // animation looks odd. However, replacing the contentView for constrained
     // windows does not work - it does custom rendering.
-    scoped_nsobject<NSView> flippedContentView(
+    base::scoped_nsobject<NSView> flippedContentView(
         [[FlippedView alloc] initWithFrame:NSZeroRect]);
     [flippedContentView setSubviews:
         @[accountChooser_, [mainContainer_ view], [signInContainer_ view]]];
     [flippedContentView setAutoresizingMask:
         (NSViewWidthSizable | NSViewHeightSizable)];
     [[[self window] contentView] addSubview:flippedContentView];
+    [mainContainer_ setAnchorView:[[accountChooser_ subviews] objectAtIndex:1]];
 
     NSRect contentRect = clientRect;
     contentRect.origin = NSMakePoint(0, 0);
@@ -206,10 +211,6 @@
 }
 
 - (void)performLayout {
-  // Don't animate when we first show the window.
-  BOOL shouldAnimate =
-      !NSEqualRects(ui::kWindowSizeDeterminedLater, [[self window] frame]);
-
   NSRect contentRect = NSZeroRect;
   contentRect.size = [self preferredSize];
   NSRect clientRect = NSInsetRect(
@@ -231,7 +232,7 @@
   }
 
   NSRect frameRect = [[self window] frameRectForContentRect:contentRect];
-  [[self window] setFrame:frameRect display:YES animate:shouldAnimate];
+  [[self window] setFrame:frameRect display:YES];
 }
 
 - (IBAction)accept:(id)sender {
@@ -247,6 +248,11 @@
 
 - (void)updateAccountChooser {
   [accountChooser_ update];
+  [mainContainer_ updateLegalDocuments];
+}
+
+- (void)updateNotificationArea {
+  [mainContainer_ updateNotificationArea];
 }
 
 - (void)updateSection:(autofill::DialogSection)section {
diff --git a/chrome/browser/ui/cocoa/autofill/autofill_dialog_cocoa_browsertest.mm b/chrome/browser/ui/cocoa/autofill/autofill_dialog_cocoa_browsertest.mm
index f2394f1..c8c5429 100644
--- a/chrome/browser/ui/cocoa/autofill/autofill_dialog_cocoa_browsertest.mm
+++ b/chrome/browser/ui/cocoa/autofill/autofill_dialog_cocoa_browsertest.mm
@@ -10,7 +10,7 @@
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/test/base/in_process_browser_test.h"
-#include "components/autofill/browser/autofill_common_test.h"
+#include "components/autofill/core/browser/autofill_common_test.h"
 #include "components/autofill/core/common/form_data.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_view.h"
@@ -44,7 +44,7 @@
   virtual ~TestAutofillDialogController() {}
 
   virtual void ViewClosed() OVERRIDE {
-    DCHECK(runner_);
+    DCHECK(runner_.get());
     runner_->Quit();
     AutofillDialogControllerImpl::ViewClosed();
   }
@@ -92,7 +92,7 @@
   TestAutofillDialogController* controller() { return controller_; }
 
   void RunMessageLoop() {
-    DCHECK(runner_);
+    DCHECK(runner_.get());
     runner_->Run();
   }
 
diff --git a/chrome/browser/ui/cocoa/autofill/autofill_dialog_constants.h b/chrome/browser/ui/cocoa/autofill/autofill_dialog_constants.h
index d4e57ab..b5d1ba3 100644
--- a/chrome/browser/ui/cocoa/autofill/autofill_dialog_constants.h
+++ b/chrome/browser/ui/cocoa/autofill/autofill_dialog_constants.h
@@ -11,9 +11,20 @@
 // Horizontal padding between text and other elements (in pixels).
 const CGFloat kAroundTextPadding = 4;
 
+// Sizing of notification arrow.
+const int kArrowHeight = 7;
+const int kArrowWidth = 2 * kArrowHeight;
+
 // Spacing between buttons.
 const CGFloat kButtonGap = 6;
 
+// The space between the edges of a notification bar and the text within (in
+// pixels).
+const int kNotificationPadding = 14;
+
+// Vertical spacing between legal text and details section.
+const int kVerticalSpacing = 8;
+
 }  // namespace
 
 #endif  // CHROME_BROWSER_UI_COCOA_AUTOFILL_AUTOFILL_DIALOG_CONSTANTS__H_
diff --git a/chrome/browser/ui/cocoa/autofill/autofill_input_field.h b/chrome/browser/ui/cocoa/autofill/autofill_input_field.h
new file mode 100644
index 0000000..ea1e43d
--- /dev/null
+++ b/chrome/browser/ui/cocoa/autofill/autofill_input_field.h
@@ -0,0 +1,17 @@
+// 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_UI_COCOA_AUTOFILL_AUTOFILL_INPUT_FIELD_H_
+#define CHROME_BROWSER_UI_COCOA_AUTOFILL_AUTOFILL_INPUT_FIELD_H_
+
+// Protocol to allow access to any given input field in an Autofill dialog, no
+// matter what the underlying control is.
+@protocol AutofillInputField
+
+@property(nonatomic, assign) BOOL invalid;
+@property(nonatomic, copy) NSString* fieldValue;
+
+@end
+
+#endif  // CHROME_BROWSER_UI_COCOA_AUTOFILL_AUTOFILL_INPUT_FIELD_H_
diff --git a/chrome/browser/ui/cocoa/autofill/autofill_main_container.h b/chrome/browser/ui/cocoa/autofill/autofill_main_container.h
index b05a713..7f6a92e 100644
--- a/chrome/browser/ui/cocoa/autofill/autofill_main_container.h
+++ b/chrome/browser/ui/cocoa/autofill/autofill_main_container.h
@@ -7,14 +7,16 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "chrome/browser/ui/autofill/autofill_dialog_types.h"
 #import "chrome/browser/ui/cocoa/autofill/autofill_layout.h"
 
 @class AutofillDetailsContainer;
 @class AutofillDialogWindowController;
+@class AutofillNotificationContainer;
 @class AutofillSectionContainer;
 @class GTMWidthBasedTweaker;
+@class HyperlinkTextView;
 
 namespace autofill {
   class AutofillDialogController;
@@ -23,12 +25,23 @@
 // NSViewController for the main portion of the autofill dialog. Contains
 // account chooser, details for current payment instruments, OK/Cancel.
 // Might dynamically add and remove other elements.
-@interface AutofillMainContainer : NSViewController<AutofillLayout> {
+@interface AutofillMainContainer : NSViewController<AutofillLayout,
+                                                    NSTextViewDelegate> {
  @private
-  scoped_nsobject<GTMWidthBasedTweaker> buttonContainer_;
-  scoped_nsobject<AutofillDetailsContainer> detailsContainer_;
+  base::scoped_nsobject<GTMWidthBasedTweaker> buttonContainer_;
+  base::scoped_nsobject<AutofillDetailsContainer> detailsContainer_;
+  base::scoped_nsobject<HyperlinkTextView> legalDocumentsView_;
+  base::scoped_nsobject<AutofillNotificationContainer> notificationContainer_;
   AutofillDialogWindowController* target_;
-  autofill::AutofillDialogController* controller_;  // Not owned.
+
+  // Weak. Owns the dialog.
+  autofill::AutofillDialogController* controller_;
+
+  // Preferred size for legal documents.
+  NSSize legalDocumentsSize_;
+
+  // Dirty marker for preferred size.
+  BOOL legalDocumentsSizeDirty_;
 }
 
 @property(assign, nonatomic) AutofillDialogWindowController* target;
@@ -36,12 +49,21 @@
 // Designated initializer.
 - (id)initWithController:(autofill::AutofillDialogController*)controller;
 
+// Sets the anchor point for the notificationView_.
+- (void)setAnchorView:(NSView*)anchorView;
+
 // Returns the view controller responsible for |section|.
 - (AutofillSectionContainer*)sectionForId:(autofill::DialogSection)section;
 
 // Called when the controller-maintained suggestions model has changed.
 - (void)modelChanged;
 
+// Called when the legal documents text might need to be refreshed.
+- (void)updateLegalDocuments;
+
+// Called when there are changes to the notification area.
+- (void)updateNotificationArea;
+
 @end
 
 #endif  // CHROME_BROWSER_UI_COCOA_AUTOFILL_AUTOFILL_MAIN_CONTAINER_H_
diff --git a/chrome/browser/ui/cocoa/autofill/autofill_main_container.mm b/chrome/browser/ui/cocoa/autofill/autofill_main_container.mm
index 80b050c..9d9449c 100644
--- a/chrome/browser/ui/cocoa/autofill/autofill_main_container.mm
+++ b/chrome/browser/ui/cocoa/autofill/autofill_main_container.mm
@@ -7,20 +7,28 @@
 #include <algorithm>
 #include <cmath>
 
+#include "base/mac/foundation_util.h"
+#include "base/strings/sys_string_conversions.h"
+#include "chrome/browser/ui/autofill/autofill_dialog_controller.h"
 #include "chrome/browser/ui/cocoa/autofill/autofill_dialog_constants.h"
 #import "chrome/browser/ui/cocoa/constrained_window/constrained_window_button.h"
 #import "chrome/browser/ui/cocoa/autofill/autofill_details_container.h"
+#import "chrome/browser/ui/cocoa/autofill/autofill_notification_container.h"
+#import "chrome/browser/ui/cocoa/hyperlink_text_view.h"
 #import "chrome/browser/ui/cocoa/key_equivalent_constants.h"
 #include "grit/generated_resources.h"
 #import "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h"
 #include "ui/base/cocoa/window_size_constants.h"
 #include "ui/base/l10n/l10n_util.h"
+#include "ui/base/range/range.h"
 
 @interface AutofillMainContainer (Private)
 - (void)buildWindowButtonsForFrame:(NSRect)frame;
 - (void)layoutButtons;
+- (NSSize)preferredLegalDocumentSizeForWidth:(CGFloat)width;
 @end
 
+
 @implementation AutofillMainContainer
 
 @synthesize target = target_;
@@ -35,7 +43,7 @@
 - (void)loadView {
   [self buildWindowButtonsForFrame:NSZeroRect];
 
-  scoped_nsobject<NSView> view([[NSView alloc] initWithFrame:NSZeroRect]);
+  base::scoped_nsobject<NSView> view([[NSView alloc] initWithFrame:NSZeroRect]);
   [view setAutoresizesSubviews:YES];
   [view setSubviews:@[buttonContainer_]];
   [self setView:view];
@@ -50,22 +58,81 @@
   frameSize.height += NSHeight([buttonContainer_ frame]);
   [[self view] setFrameSize:frameSize];
   [[self view] addSubview:[detailsContainer_ view]];
+
+  legalDocumentsView_.reset(
+      [[HyperlinkTextView alloc] initWithFrame:NSZeroRect]);
+  [legalDocumentsView_ setEditable:NO];
+  [legalDocumentsView_ setBackgroundColor:
+      [NSColor colorWithCalibratedRed:0.96
+                                green:0.96
+                                 blue:0.96
+                                alpha:1.0]];
+  [legalDocumentsView_ setDrawsBackground:YES];
+  [legalDocumentsView_ setHidden:YES];
+  [legalDocumentsView_ setDelegate:self];
+  legalDocumentsSizeDirty_ = YES;
+  [[self view] addSubview:legalDocumentsView_];
+
+  notificationContainer_.reset(
+      [[AutofillNotificationContainer alloc] initWithController:controller_]);
+  [[self view] addSubview:[notificationContainer_ view]];
+}
+
+// Called when embedded links are clicked.
+- (BOOL)textView:(NSTextView*)textView
+    clickedOnLink:(id)link
+          atIndex:(NSUInteger)charIndex {
+  int index = [base::mac::ObjCCastStrict<NSNumber>(link) intValue];
+  controller_->LegalDocumentLinkClicked(
+      controller_->LegalDocumentLinks()[index]);
+  return YES;
 }
 
 - (NSSize)preferredSize {
-  // The buttons never change size, so rely on container.
+  // Overall width is determined by |detailsContainer_|.
   NSSize buttonSize = [buttonContainer_ frame].size;
   NSSize detailsSize = [detailsContainer_ preferredSize];
 
   NSSize size = NSMakeSize(std::max(buttonSize.width, detailsSize.width),
                            buttonSize.height + detailsSize.height);
 
+  if (![legalDocumentsView_ isHidden]) {
+    NSSize legalDocumentSize =
+        [self preferredLegalDocumentSizeForWidth:detailsSize.width];
+    size.height += legalDocumentSize.height + kVerticalSpacing;
+  }
+
+  NSSize notificationSize =
+      [notificationContainer_ preferredSizeForWidth:detailsSize.width];
+  size.height += notificationSize.height;
   return size;
 }
 
 - (void)performLayout {
-  // Assume that the frame for the container is set already.
+  NSSize preferredContainerSize = [self preferredSize];
+
+  CGFloat currentY = 0.0;
+  if (![legalDocumentsView_ isHidden]) {
+    [legalDocumentsView_ setFrameSize:
+        [self preferredLegalDocumentSizeForWidth:preferredContainerSize.width]];
+    currentY = NSMaxY([legalDocumentsView_ frame]) + kVerticalSpacing;
+  }
+
+  NSRect buttonFrame = [buttonContainer_ frame];
+  buttonFrame.origin.y = currentY;
+  [buttonContainer_ setFrameOrigin:buttonFrame.origin];
+
   [detailsContainer_ performLayout];
+  NSRect containerFrame = [[detailsContainer_ view] frame];
+  containerFrame.origin.y = NSMaxY(buttonFrame);
+  [[detailsContainer_ view] setFrameOrigin:containerFrame.origin];
+
+  NSRect notificationFrame;
+  notificationFrame.origin = NSMakePoint(0, NSMaxY(containerFrame));
+  notificationFrame.size = [notificationContainer_ preferredSizeForWidth:
+      preferredContainerSize.width];
+  [[notificationContainer_ view] setFrame:notificationFrame];
+  [notificationContainer_ performLayout];
 }
 
 - (void)buildWindowButtonsForFrame:(NSRect)frame {
@@ -77,7 +144,7 @@
   [buttonContainer_
       setAutoresizingMask:(NSViewMinXMargin | NSViewMaxYMargin)];
 
-  scoped_nsobject<NSButton> button(
+  base::scoped_nsobject<NSButton> button(
       [[ConstrainedWindowButton alloc] initWithFrame:NSZeroRect]);
   [button setTitle:l10n_util::GetNSStringWithFixup(IDS_CANCEL)];
   [button setKeyEquivalent:kKeyEquivalentEscape];
@@ -105,11 +172,37 @@
 }
 
 - (void)layoutButtons {
-  scoped_nsobject<GTMUILocalizerAndLayoutTweaker> layoutTweaker(
+  base::scoped_nsobject<GTMUILocalizerAndLayoutTweaker> layoutTweaker(
       [[GTMUILocalizerAndLayoutTweaker alloc] init]);
   [layoutTweaker tweakUI:buttonContainer_];
 }
 
+// Compute the preferred size for the legal documents text, given a width.
+- (NSSize)preferredLegalDocumentSizeForWidth:(CGFloat)width {
+  // Only recompute if necessary (On text or frame width change).
+  if (!legalDocumentsSizeDirty_ && abs(legalDocumentsSize_.width-width) < 1.0)
+    return legalDocumentsSize_;
+
+  // There's no direct API to compute desired sizes - use layouting instead.
+  // Layout in a rect with fixed width and "infinite" height.
+  NSRect currentFrame = [legalDocumentsView_ frame];
+  [legalDocumentsView_ setFrame:NSMakeRect(0, 0, width, CGFLOAT_MAX)];
+
+  // Now use the layout manager to compute layout.
+  NSLayoutManager* layoutManager = [legalDocumentsView_ layoutManager];
+  NSTextContainer* textContainer = [legalDocumentsView_ textContainer];
+  [layoutManager ensureLayoutForTextContainer:textContainer];
+  NSRect newFrame = [layoutManager usedRectForTextContainer:textContainer];
+
+  // And finally, restore old frame.
+  [legalDocumentsView_ setFrame:currentFrame];
+  newFrame.size.width = width;
+
+  legalDocumentsSizeDirty_ = NO;
+  legalDocumentsSize_ = newFrame.size;
+  return legalDocumentsSize_;
+}
+
 - (AutofillSectionContainer*)sectionForId:(autofill::DialogSection)section {
   return [detailsContainer_ sectionForId:section];
 }
@@ -118,4 +211,42 @@
   [detailsContainer_ modelChanged];
 }
 
+- (void)updateLegalDocuments {
+  NSString* text = base::SysUTF16ToNSString(controller_->LegalDocumentsText());
+
+  if ([text length]) {
+    NSFont* font = [NSFont systemFontOfSize:[NSFont smallSystemFontSize]];
+    [legalDocumentsView_ setMessage:text
+                           withFont:font
+                       messageColor:[NSColor blackColor]];
+
+    const std::vector<ui::Range>& link_ranges =
+        controller_->LegalDocumentLinks();
+    for (size_t i = 0; i < link_ranges.size(); ++i) {
+      NSRange range = link_ranges[i].ToNSRange();
+      [legalDocumentsView_ addLinkRange:range
+                               withName:@(i)
+                              linkColor:[NSColor blueColor]];
+    }
+    legalDocumentsSizeDirty_ = YES;
+  }
+  [legalDocumentsView_ setHidden:[text length] == 0];
+
+  // Always request re-layout on state change.
+  id controller = [[[self view] window] windowController];
+  if ([controller respondsToSelector:@selector(requestRelayout)])
+    [controller performSelector:@selector(requestRelayout)];
+}
+
+- (void)updateNotificationArea {
+  [notificationContainer_ setNotifications:controller_->CurrentNotifications()];
+  id controller = [[[self view] window] windowController];
+  if ([controller respondsToSelector:@selector(requestRelayout)])
+    [controller performSelector:@selector(requestRelayout)];
+}
+
+- (void)setAnchorView:(NSView*)anchorView {
+  [notificationContainer_ setAnchorView:anchorView];
+}
+
 @end
diff --git a/chrome/browser/ui/cocoa/autofill/autofill_main_container_unittest.mm b/chrome/browser/ui/cocoa/autofill/autofill_main_container_unittest.mm
index a52103d..5eeaf1d 100644
--- a/chrome/browser/ui/cocoa/autofill/autofill_main_container_unittest.mm
+++ b/chrome/browser/ui/cocoa/autofill/autofill_main_container_unittest.mm
@@ -4,9 +4,9 @@
 
 #import "chrome/browser/ui/cocoa/autofill/autofill_main_container.h"
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "chrome/browser/ui/autofill/mock_autofill_dialog_controller.h"
-#import "chrome/browser/ui/cocoa/autofill/autofill_account_chooser.h"
+#import "chrome/browser/ui/cocoa/autofill/autofill_section_view.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/platform_test.h"
 #import "ui/base/test/ui_cocoa_test_helper.h"
@@ -23,7 +23,7 @@
   }
 
  protected:
-  scoped_nsobject<AutofillMainContainer> container_;
+  base::scoped_nsobject<AutofillMainContainer> container_;
   testing::NiceMock<autofill::MockAutofillDialogController> controller_;
 };
 
@@ -33,9 +33,12 @@
 
 TEST_F(AutofillMainContainerTest, SubViews) {
   bool hasButtons = false;
+  bool hasTextView = false;
+  bool hasDetailsContainer = false;
+  int hasNotificationContainer = false;
 
   // Should have account chooser, button strip, and details section.
-  EXPECT_EQ(2U, [[[container_ view] subviews] count]);
+  EXPECT_EQ(4U, [[[container_ view] subviews] count]);
   for (NSView* view in [[container_ view] subviews]) {
     NSArray* subviews = [view subviews];
     if ([subviews count] == 2) {
@@ -44,8 +47,21 @@
       EXPECT_TRUE(
           [[subviews objectAtIndex:1] isKindOfClass:[NSButton class]]);
       hasButtons = true;
+    } else if ([view isKindOfClass:[NSTextView class]]) {
+      hasTextView = true;
+    } else if ([subviews count] > 0 &&
+        [[subviews objectAtIndex:0] isKindOfClass:
+            [AutofillSectionView class]]) {
+      hasDetailsContainer = true;
+    } else {
+      // Assume by default this is the notification area view.
+      // There is no way to easily verify that with more detail.
+      hasNotificationContainer = true;
     }
   }
 
   EXPECT_TRUE(hasButtons);
-}
\ No newline at end of file
+  EXPECT_TRUE(hasTextView);
+  EXPECT_TRUE(hasDetailsContainer);
+  EXPECT_TRUE(hasNotificationContainer);
+}
diff --git a/chrome/browser/ui/cocoa/autofill/autofill_notification_container.h b/chrome/browser/ui/cocoa/autofill/autofill_notification_container.h
new file mode 100644
index 0000000..7271f16
--- /dev/null
+++ b/chrome/browser/ui/cocoa/autofill/autofill_notification_container.h
@@ -0,0 +1,57 @@
+// 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_UI_COCOA_AUTOFILL_AUTOFILL_NOTIFICATION_CONTAINER_H_
+#define CHROME_BROWSER_UI_COCOA_AUTOFILL_AUTOFILL_NOTIFICATION_CONTAINER_H_
+
+#import <Cocoa/Cocoa.h>
+
+#include <vector>
+
+#include "base/mac/scoped_nsobject.h"
+#include "base/memory/scoped_ptr.h"
+#import "chrome/browser/ui/cocoa/autofill/autofill_layout.h"
+
+@class AutofillArrowView;
+
+namespace autofill {
+  class DialogNotification;
+  typedef std::vector<DialogNotification> DialogNotifications;
+  class AutofillDialogController;
+}
+
+// Container for all notifications shown in requestAutocomplete dialog.
+@interface AutofillNotificationContainer : NSViewController<AutofillLayout> {
+ @private
+  // Array of all AutofillNotificationControllers.
+  base::scoped_nsobject<NSMutableArray> notificationControllers_;
+
+  // View that the arrow is anchored to. Weak.
+  NSView* anchorView_;
+
+  // The notification that the checkbox is associated with.
+  scoped_ptr<autofill::DialogNotification> checkboxNotification_;
+
+  // Main controller for the dialog. Weak, owns dialog.
+  autofill::AutofillDialogController* controller_;
+}
+
+// Designated initializer.
+- (id)initWithController:(autofill::AutofillDialogController*)controller;
+
+// Computes the views preferred size given a fixed width.
+- (NSSize)preferredSizeForWidth:(CGFloat)width;
+
+// Sets the notification contents.
+- (void)setNotifications:(const autofill::DialogNotifications&) notifications;
+
+// Sets a view that the arrow is anchored to - center of arrow will be aligned
+// with center of anchorView. (horizontally only).
+- (void)setAnchorView:(NSView*)anchorView;
+
+- (IBAction)checkboxClicked:(id)sender;
+
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_AUTOFILL_AUTOFILL_NOTIFICATION_CONTAINER_H_
\ No newline at end of file
diff --git a/chrome/browser/ui/cocoa/autofill/autofill_notification_container.mm b/chrome/browser/ui/cocoa/autofill/autofill_notification_container.mm
new file mode 100644
index 0000000..7671ca7
--- /dev/null
+++ b/chrome/browser/ui/cocoa/autofill/autofill_notification_container.mm
@@ -0,0 +1,121 @@
+// 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 "chrome/browser/ui/cocoa/autofill/autofill_notification_container.h"
+
+#include "base/logging.h"
+#include "base/mac/scoped_nsobject.h"
+#include "base/strings/sys_string_conversions.h"
+#include "chrome/browser/ui/autofill/autofill_dialog_controller.h"
+#include "chrome/browser/ui/autofill/autofill_dialog_types.h"
+#include "chrome/browser/ui/cocoa/autofill/autofill_dialog_constants.h"
+#import "chrome/browser/ui/cocoa/autofill/autofill_notification_controller.h"
+#include "skia/ext/skia_utils_mac.h"
+
+@implementation AutofillNotificationContainer
+
+- (id)initWithController:(autofill::AutofillDialogController*)controller {
+  if (self = [super init]) {
+    controller_ = controller;
+    [self setView:[[[NSView alloc] initWithFrame:NSZeroRect] autorelease]];
+  }
+  return self;
+}
+
+// Just here to satisfy the protocol - not actually invoked.
+- (NSSize)preferredSize {
+  NOTREACHED();
+  return NSZeroSize;
+}
+
+- (NSSize)preferredSizeForWidth:(CGFloat)width {
+  NSSize preferredSize = NSMakeSize(width, 0);
+
+  if ([notificationControllers_ count] == 0)
+    return preferredSize;
+
+  // If the first notification doesn't have an arrow, reserve empty space.
+  if (![[notificationControllers_ objectAtIndex:0] hasArrow])
+    preferredSize.height += kArrowHeight;
+
+  for (AutofillNotificationController* controller in
+       notificationControllers_.get())
+    preferredSize.height += [controller preferredSizeForWidth:width].height;
+
+  return preferredSize;
+}
+
+- (void)performLayout {
+  if ([notificationControllers_ count] == 0)
+    return;
+
+  NSRect remaining = [[self view] bounds];
+
+  if (![[notificationControllers_ objectAtIndex:0] hasArrow])
+    remaining.size.height -= kArrowHeight;
+
+  for (AutofillNotificationController* controller in
+       notificationControllers_.get()) {
+    NSRect viewRect;
+    NSSize size = [controller preferredSizeForWidth:NSWidth(remaining)];
+    NSDivideRect(remaining, &viewRect, &remaining, size.height, NSMaxYEdge);
+    [[controller view ] setFrame:viewRect];
+    [controller performLayout];
+  }
+  DCHECK_EQ(0, NSHeight(remaining));
+}
+
+- (void)setNotifications:(const autofill::DialogNotifications&)notifications {
+  notificationControllers_.reset([[NSMutableArray alloc] init]);
+  checkboxNotification_.reset();
+  [[self view] setSubviews:@[]];
+
+  for (size_t i = 0; i < notifications.size(); ++i) {
+    // Create basic notification view.
+    const autofill::DialogNotification& notification = notifications[i];
+    base::scoped_nsobject<AutofillNotificationController>
+        notificationController([[AutofillNotificationController alloc] init]);
+    [notificationController setText:
+        base::SysUTF16ToNSString(notification.display_text())];
+    [notificationController setTextColor:
+        gfx::SkColorToCalibratedNSColor(notification.GetTextColor())];
+    [notificationController setBackgroundColor:
+        gfx::SkColorToCalibratedNSColor(notification.GetBackgroundColor())];
+
+    // Add optional checkbox.
+    if (notification.HasCheckbox()) {
+      DCHECK(checkboxNotification_);
+      checkboxNotification_.reset(
+          new autofill::DialogNotification(notification));
+      [notificationController setHasCheckbox:YES];
+      if (!notification.interactive())
+          [[notificationController checkbox] setEnabled:FALSE];
+      [[notificationController checkbox] setState:
+          (notification.checked() ? NSOnState : NSOffState)];
+      [[notificationController checkbox] setTarget:self];
+      [[notificationController checkbox] setAction:@selector(checkboxClicked:)];
+    }
+
+    if (i == 0) {
+      [notificationController setHasArrow:notification.HasArrow()
+                           withAnchorView:anchorView_];
+    }
+
+    [notificationControllers_ addObject:notificationController];
+    [[self view] addSubview:[notificationController view]];
+  }
+}
+
+- (void)setAnchorView:(NSView*)anchorView {
+  anchorView_ = anchorView;
+}
+
+- (IBAction)checkboxClicked:(id)sender {
+  DCHECK(checkboxNotification_);
+  BOOL isChecked = ([sender state] == NSOnState);
+  controller_->NotificationCheckboxStateChanged(checkboxNotification_->type(),
+                                                isChecked);
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/autofill/autofill_notification_container_unittest.mm b/chrome/browser/ui/cocoa/autofill/autofill_notification_container_unittest.mm
new file mode 100644
index 0000000..3d16429
--- /dev/null
+++ b/chrome/browser/ui/cocoa/autofill/autofill_notification_container_unittest.mm
@@ -0,0 +1,61 @@
+// 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 "chrome/browser/ui/cocoa/autofill/autofill_notification_container.h"
+
+#include "base/mac/scoped_nsobject.h"
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/ui/autofill/autofill_dialog_types.h"
+#include "chrome/browser/ui/autofill/mock_autofill_dialog_controller.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#import "ui/base/test/ui_cocoa_test_helper.h"
+
+namespace {
+
+class AutofillNotificationContainerTest : public ui::CocoaTest {
+ public:
+  virtual void SetUp() {
+    CocoaTest::SetUp();
+    container_.reset([[AutofillNotificationContainer alloc] initWithController:
+                         &controller_]);
+    [[test_window() contentView] addSubview:[container_ view]];
+  }
+
+ protected:
+  base::scoped_nsobject<AutofillNotificationContainer> container_;
+  testing::NiceMock<autofill::MockAutofillDialogController> controller_;
+};
+
+}  // namespace
+
+TEST_VIEW(AutofillNotificationContainerTest, [container_ view])
+
+TEST_F(AutofillNotificationContainerTest, Subviews) {
+  // No subviews if there are no notifications.
+  EXPECT_EQ(0U, [[[container_ view] subviews] count]);
+
+  // Single notification adds one subview.
+  std::vector<autofill::DialogNotification> notifications;
+  notifications.push_back(
+      autofill::DialogNotification(
+          autofill::DialogNotification::REQUIRED_ACTION,
+          ASCIIToUTF16("test")));
+  ASSERT_FALSE(notifications[0].HasArrow());
+  [container_ setNotifications:notifications];
+
+  EXPECT_EQ(1U, [[[container_ view] subviews] count]);
+
+  // 2 notifications, one with arrow - 2 views.
+  notifications.push_back(
+      autofill::DialogNotification(
+          autofill::DialogNotification::REQUIRED_ACTION,
+          ASCIIToUTF16("test")));
+  ASSERT_FALSE(notifications[1].HasArrow());
+  [container_ setNotifications:notifications];
+
+  EXPECT_EQ(2U, [[[container_ view] subviews] count]);
+
+  // Just to exercise code path.
+  [container_ performLayout];
+}
\ No newline at end of file
diff --git a/chrome/browser/ui/cocoa/autofill/autofill_notification_controller.h b/chrome/browser/ui/cocoa/autofill/autofill_notification_controller.h
new file mode 100644
index 0000000..deaff2a
--- /dev/null
+++ b/chrome/browser/ui/cocoa/autofill/autofill_notification_controller.h
@@ -0,0 +1,53 @@
+// 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_UI_COCOA_AUTOFILL_AUTOFILL_NOTIFICATION_CONTROLLER_H_
+#define CHROME_BROWSER_UI_COCOA_AUTOFILL_AUTOFILL_NOTIFICATION_CONTROLLER_H_
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/mac/scoped_nsobject.h"
+#import "chrome/browser/ui/cocoa/autofill/autofill_layout.h"
+
+@class AutofillNotificationView;
+
+// Contains a single notification for requestAutocomplete dialog.
+@interface AutofillNotificationController : NSViewController<AutofillLayout> {
+ @private
+  // NSTextField for label.
+  base::scoped_nsobject<NSTextField> textfield_;
+
+  // Optional checkbox.
+  base::scoped_nsobject<NSButton> checkbox_;
+
+  // Size of a checkbox without title.
+  NSSize checkboxSizeWithoutTitle_;
+}
+
+@property(nonatomic, readonly) NSTextField* textfield;
+@property(nonatomic, readonly) NSButton* checkbox;
+@property(nonatomic, retain) NSColor* backgroundColor;
+@property(nonatomic, retain) NSColor* textColor;
+@property(nonatomic, copy) NSString* text;  // Label text.
+
+// Designated initializer.
+- (id)init;
+
+// Displays arrow on top of notification if set to YES. |anchorView| determines
+// the arrow position - the tip of the arrow is centered on the horizontal
+// midpoint of the anchorView.
+- (void)setHasArrow:(BOOL)hasArrow withAnchorView:(NSView*)anchorView;
+
+// Indicates if the controller draws an arrow.
+- (BOOL)hasArrow;
+
+// Enables the optional checkbox.
+- (void)setHasCheckbox:(BOOL)hasCheckbox;
+
+// Compute preferred size for given width.
+- (NSSize)preferredSizeForWidth:(CGFloat)width;
+
+@end
+
+#endif  // CHROME_BROWSER_UI_COCOA_AUTOFILL_AUTOFILL_NOTIFICATION_CONTROLLER_H_
diff --git a/chrome/browser/ui/cocoa/autofill/autofill_notification_controller.mm b/chrome/browser/ui/cocoa/autofill/autofill_notification_controller.mm
new file mode 100644
index 0000000..12606a2
--- /dev/null
+++ b/chrome/browser/ui/cocoa/autofill/autofill_notification_controller.mm
@@ -0,0 +1,183 @@
+// 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 "chrome/browser/ui/cocoa/autofill/autofill_notification_controller.h"
+
+#include <algorithm>
+
+#include "base/logging.h"
+#include "base/mac/foundation_util.h"
+#include "base/mac/scoped_nsobject.h"
+#include "chrome/browser/ui/cocoa/autofill/autofill_dialog_constants.h"
+
+@interface AutofillNotificationView : NSView {
+ @private
+  // Weak, determines anchor point for arrow.
+  NSView* arrowAnchorView_;
+  BOOL hasArrow_;
+  base::scoped_nsobject<NSColor> backgroundColor_;
+}
+
+@property (nonatomic, assign) NSView* anchorView;
+@property (nonatomic, assign) BOOL hasArrow;
+@property (nonatomic, retain) NSColor* backgroundColor;
+
+@end
+
+@implementation AutofillNotificationView
+
+@synthesize hasArrow = hasArrow_;
+@synthesize anchorView = arrowAnchorView_;
+
+- (void)drawRect:(NSRect)dirtyRect {
+  [super drawRect:dirtyRect];
+
+  NSRect backgroundRect = [self bounds];
+  if (hasArrow_) {
+    NSPoint anchorPoint = NSMakePoint(NSMidX([arrowAnchorView_ bounds]), 0);
+    anchorPoint = [self convertPoint:anchorPoint fromView:arrowAnchorView_];
+    anchorPoint.y = NSMaxY([self bounds]);
+
+    NSBezierPath* arrow = [NSBezierPath bezierPath];
+    [arrow moveToPoint:anchorPoint];
+    [arrow relativeLineToPoint:NSMakePoint(-kArrowWidth / 2.0, -kArrowHeight)];
+    [arrow relativeLineToPoint:NSMakePoint(kArrowWidth, 0)];
+    [arrow closePath];
+    [backgroundColor_ setFill];
+    [arrow fill];
+    backgroundRect.size.height -= kArrowHeight;
+  }
+
+  dirtyRect = NSIntersectionRect(backgroundRect, dirtyRect);
+  [backgroundColor_ setFill];
+  NSRectFill(dirtyRect);
+}
+
+- (NSColor*)backgroundColor {
+  return backgroundColor_;
+}
+
+- (void)setBackgroundColor:(NSColor*)backgroundColor {
+  backgroundColor_.reset([backgroundColor retain]);
+}
+
+@end
+
+@implementation AutofillNotificationController
+
+- (id)init {
+  if (self = [super init]) {
+    base::scoped_nsobject<AutofillNotificationView> view(
+        [[AutofillNotificationView alloc] initWithFrame:NSZeroRect]);
+    [self setView:view];
+
+    textfield_.reset([[NSTextField alloc] initWithFrame:NSZeroRect]);
+    [textfield_ setEditable:NO];
+    [textfield_ setBordered:NO];
+    [textfield_ setDrawsBackground:NO];
+
+    checkbox_.reset([[NSButton alloc] initWithFrame:NSZeroRect]);
+    [checkbox_ setButtonType:NSSwitchButton];
+    [checkbox_ setTitle:@""];
+    [checkbox_ sizeToFit];
+    checkboxSizeWithoutTitle_ = [checkbox_ frame].size;
+    [checkbox_ setHidden:YES];
+    [view setSubviews:@[textfield_, checkbox_]];
+  }
+  return self;
+}
+
+- (AutofillNotificationView*)notificationView {
+  return base::mac::ObjCCastStrict<AutofillNotificationView>([self view]);
+}
+
+- (void)setHasArrow:(BOOL)hasArrow withAnchorView:(NSView*)anchorView {
+  [[self notificationView] setAnchorView:anchorView];
+  [[self notificationView] setHasArrow:hasArrow];
+}
+
+- (BOOL)hasArrow {
+  return [[self notificationView] hasArrow];
+}
+
+- (void)setHasCheckbox:(BOOL)hasCheckbox {
+  [checkbox_ setHidden:!hasCheckbox];
+}
+
+- (NSString*)text {
+  return [textfield_ stringValue];
+}
+
+- (void)setText:(NSString*)string {
+  [textfield_ setStringValue:string];
+}
+
+- (NSTextField*)textfield {
+  return textfield_;
+}
+
+- (NSButton*)checkbox {
+  return checkbox_;
+}
+
+- (NSColor*)backgroundColor {
+  return [[self notificationView] backgroundColor];
+}
+
+- (void)setBackgroundColor:(NSColor*)backgroundColor {
+  [[self notificationView] setBackgroundColor:backgroundColor];
+}
+
+- (NSColor*)textColor {
+  return [textfield_ textColor];
+}
+
+- (void)setTextColor:(NSColor*)textColor {
+  [textfield_ setTextColor:textColor];
+}
+
+- (NSSize)preferredSizeForWidth:(CGFloat)width {
+  NSRect textRect = NSMakeRect(0, 0, width, CGFLOAT_MAX);
+  if (![checkbox_ isHidden])
+    textRect.size.width -= checkboxSizeWithoutTitle_.width;
+
+  NSSize preferredSize = [[textfield_ cell] cellSizeForBounds:textRect];
+  if (![checkbox_ isHidden]) {
+    preferredSize.height = std::max(preferredSize.height,
+                                    checkboxSizeWithoutTitle_.height);
+  }
+
+  if ([[self notificationView] hasArrow])
+      preferredSize.height += kArrowHeight;
+
+  preferredSize.height += 2 * kNotificationPadding;
+  return preferredSize;
+}
+
+- (NSSize)preferredSize {
+  NOTREACHED();
+  return NSZeroSize;
+}
+
+- (void)performLayout {
+  NSRect bounds = [[self view] bounds];
+  if ([[self notificationView] hasArrow])
+    bounds.size.height -= kArrowHeight;
+
+  NSRect textFrame = NSInsetRect(bounds, 0, kNotificationPadding);
+  if (![checkbox_ isHidden]) {
+    // Temporarily resize checkbox to just the box, no extra clickable area.
+    textFrame.origin.x += checkboxSizeWithoutTitle_.width;
+    textFrame.size.width -= checkboxSizeWithoutTitle_.width;
+    textFrame.size = [[textfield_ cell] cellSizeForBounds:textFrame];
+
+    NSRect checkboxFrame =
+        NSMakeRect(0, 0, NSMaxX(textFrame), NSHeight(textFrame));
+    [checkbox_ setFrame:checkboxFrame];
+  }
+  [textfield_ setFrame:textFrame];
+}
+
+@end
+
diff --git a/chrome/browser/ui/cocoa/autofill/autofill_notification_controller_unittest.mm b/chrome/browser/ui/cocoa/autofill/autofill_notification_controller_unittest.mm
new file mode 100644
index 0000000..f353b03
--- /dev/null
+++ b/chrome/browser/ui/cocoa/autofill/autofill_notification_controller_unittest.mm
@@ -0,0 +1,43 @@
+// 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 "chrome/browser/ui/cocoa/autofill/autofill_notification_controller.h"
+
+#include "base/mac/scoped_nsobject.h"
+#include "testing/gtest_mac.h"
+#import "ui/base/test/ui_cocoa_test_helper.h"
+
+namespace {
+
+class AutofillNotificationControllerTest : public ui::CocoaTest {
+ public:
+  virtual void SetUp() {
+    CocoaTest::SetUp();
+    controller_.reset([[AutofillNotificationController alloc] init]);
+    [[test_window() contentView] addSubview:[controller_ view]];
+  }
+
+ protected:
+  base::scoped_nsobject<AutofillNotificationController> controller_;
+};
+
+}  // namespace
+
+TEST_VIEW(AutofillNotificationControllerTest, [controller_ view])
+
+TEST_F(AutofillNotificationControllerTest, Subviews) {
+  NSView* view = [controller_ view];
+  ASSERT_EQ(2U, [[view subviews] count]);
+  EXPECT_TRUE([[[view subviews] objectAtIndex:0] isKindOfClass:
+      [NSTextField class]]);
+  EXPECT_TRUE([[[view subviews] objectAtIndex:1] isKindOfClass:
+      [NSButton class]]);
+  EXPECT_NSEQ([controller_ textfield],
+              [[view subviews] objectAtIndex:0]);
+  EXPECT_NSEQ([controller_ checkbox],
+              [[view subviews] objectAtIndex:1]);
+
+  // Just to exercise the code path.
+  [controller_ performLayout];
+}
diff --git a/chrome/browser/ui/cocoa/autofill/autofill_pop_up_button.h b/chrome/browser/ui/cocoa/autofill/autofill_pop_up_button.h
new file mode 100644
index 0000000..8068169
--- /dev/null
+++ b/chrome/browser/ui/cocoa/autofill/autofill_pop_up_button.h
@@ -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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_AUTOFILL_AUTOFILL_POP_UP_BUTTON_H_
+#define CHROME_BROWSER_UI_COCOA_AUTOFILL_AUTOFILL_POP_UP_BUTTON_H_
+
+#import <Cocoa/Cocoa.h>
+
+#include "chrome/browser/ui/cocoa/autofill/autofill_input_field.h"
+
+@interface AutofillPopUpButton : NSPopUpButton<AutofillInputField>
+@end
+
+@interface AutofillPopUpCell : NSPopUpButtonCell<AutofillInputField> {
+ @private
+  BOOL invalid_;
+}
+
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_AUTOFILL_AUTOFILL_POP_UP_BUTTON_H_
diff --git a/chrome/browser/ui/cocoa/autofill/autofill_pop_up_button.mm b/chrome/browser/ui/cocoa/autofill/autofill_pop_up_button.mm
new file mode 100644
index 0000000..b7d81a5
--- /dev/null
+++ b/chrome/browser/ui/cocoa/autofill/autofill_pop_up_button.mm
@@ -0,0 +1,73 @@
+// 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 "chrome/browser/ui/cocoa/autofill/autofill_pop_up_button.h"
+
+#include <ApplicationServices/ApplicationServices.h>
+
+#include "base/mac/scoped_nsobject.h"
+#include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h"
+
+@implementation AutofillPopUpButton
+
++ (Class)cellClass {
+  return [AutofillPopUpCell class];
+}
+
+- (BOOL)invalid {
+  return [[self cell] invalid];
+}
+
+- (void)setInvalid:(BOOL)invalid {
+  [[self cell] setInvalid:invalid];
+}
+
+- (NSString*)fieldValue {
+  return [[self cell] fieldValue];
+}
+
+- (void)setFieldValue:(NSString*)fieldValue {
+  [[self cell] setFieldValue:fieldValue];
+}
+
+@end
+
+
+@implementation AutofillPopUpCell
+
+@synthesize invalid = invalid_;
+
+// Draw a bezel that's highlighted.
+- (void)drawBezelWithFrame:(NSRect)frame inView:(NSView*)controlView {
+  if (invalid_) {
+    CGContextRef context = static_cast<CGContextRef>(
+        [[NSGraphicsContext currentContext] graphicsPort]);
+
+    // Create a highlight-shaded bezel in a transparency layer.
+    CGContextBeginTransparencyLayerWithRect(context, NSRectToCGRect(frame), 0);
+    // 1. Draw bezel.
+    [super drawBezelWithFrame:frame inView:controlView];
+
+    // 2. Use that as stencil against solid color rect.
+    [[NSColor redColor] set];
+    NSRectFillUsingOperation(frame, NSCompositeSourceAtop);
+
+    // 3. Composite the solid color bezel and the actual bezel.
+    CGContextSetBlendMode(context, kCGBlendModePlusDarker);
+    [super drawBezelWithFrame:frame inView:controlView];
+    CGContextEndTransparencyLayer(context);
+  } else {
+    [super drawBezelWithFrame:frame inView:controlView];
+  }
+}
+
+- (NSString*)fieldValue {
+  return [self titleOfSelectedItem];
+}
+
+- (void)setFieldValue:(NSString*)fieldValue {
+  [self selectItemWithTitle:fieldValue];
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/autofill/autofill_pop_up_button_unittest.mm b/chrome/browser/ui/cocoa/autofill/autofill_pop_up_button_unittest.mm
new file mode 100644
index 0000000..9310992
--- /dev/null
+++ b/chrome/browser/ui/cocoa/autofill/autofill_pop_up_button_unittest.mm
@@ -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.
+
+#import "chrome/browser/ui/cocoa/autofill/autofill_pop_up_button.h"
+
+#import "base/mac/scoped_nsobject.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+class AutofillPopUpButtonTest : public CocoaTest {
+ public:
+  AutofillPopUpButtonTest() {
+    NSRect frame = NSMakeRect(0, 0, 50, 30);
+    button_.reset([[AutofillPopUpButton alloc] initWithFrame:frame]);
+    [button_ sizeToFit];
+    [[test_window() contentView] addSubview:button_];
+  }
+
+ protected:
+  base::scoped_nsobject<AutofillPopUpButton> button_;
+
+  DISALLOW_COPY_AND_ASSIGN(AutofillPopUpButtonTest);
+};
+
+TEST_VIEW(AutofillPopUpButtonTest, button_)
+
+// Test invalid, mostly to ensure nothing leaks or crashes.
+TEST_F(AutofillPopUpButtonTest, DisplayWithInvalid) {
+  [button_ setInvalid:YES];
+  [button_ display];
+  [button_ setInvalid:NO];
+  [button_ display];
+}
diff --git a/chrome/browser/ui/cocoa/autofill/autofill_popup_view_bridge.h b/chrome/browser/ui/cocoa/autofill/autofill_popup_view_bridge.h
index 99a4095..09119f4 100644
--- a/chrome/browser/ui/cocoa/autofill/autofill_popup_view_bridge.h
+++ b/chrome/browser/ui/cocoa/autofill/autofill_popup_view_bridge.h
@@ -8,7 +8,7 @@
 #include <vector>
 
 #include "base/basictypes.h"
-#include "base/memory/scoped_nsobject.h"
+#include "base/compiler_specific.h"
 #include "chrome/browser/ui/autofill/autofill_popup_view.h"
 
 @class AutofillPopupViewCocoa;
diff --git a/chrome/browser/ui/cocoa/autofill/autofill_popup_view_bridge.mm b/chrome/browser/ui/cocoa/autofill/autofill_popup_view_bridge.mm
index 18a4196..ee4313f 100644
--- a/chrome/browser/ui/cocoa/autofill/autofill_popup_view_bridge.mm
+++ b/chrome/browser/ui/cocoa/autofill/autofill_popup_view_bridge.mm
@@ -72,8 +72,6 @@
 }
 
 void AutofillPopupViewBridge::Hide() {
-  AutofillPopupView::Hide();
-
   delete this;
 }
 
@@ -92,11 +90,12 @@
 void AutofillPopupViewBridge::UpdateBoundsAndRedrawPopup() {
   NSRect frame = NSRectFromCGRect(controller_->popup_bounds().ToCGRect());
 
-  // Flip coordinates back into Cocoa-land.
-  // TODO(isherman): Does this agree with the controller's idea of handling
-  // multi-monitor setups correctly?
-  NSScreen* screen = [[controller_->container_view() window] screen];
-  frame.origin.y = NSHeight([screen frame]) - NSMaxY(frame);
+  // Flip coordinates back into Cocoa-land.  The controller's platform-neutral
+  // coordinate space places the origin at the top-left of the first screen,
+  // whereas Cocoa's coordinate space expects the origin to be at the
+  // bottom-left of this same screen.
+  NSScreen* screen = [[NSScreen screens] objectAtIndex:0];
+  frame.origin.y = NSMaxY([screen frame]) - NSMaxY(frame);
 
   // Leave room for the border.
   frame = NSInsetRect(frame, -kBorderWidth, -kBorderWidth);
diff --git a/chrome/browser/ui/cocoa/autofill/autofill_section_container.h b/chrome/browser/ui/cocoa/autofill/autofill_section_container.h
index 1abaab0..62ff41b 100644
--- a/chrome/browser/ui/cocoa/autofill/autofill_section_container.h
+++ b/chrome/browser/ui/cocoa/autofill/autofill_section_container.h
@@ -7,7 +7,7 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "chrome/browser/ui/autofill/autofill_dialog_types.h"
 #import "chrome/browser/ui/cocoa/autofill/autofill_layout.h"
 
@@ -27,13 +27,14 @@
 @interface AutofillSectionContainer :
     NSViewController<AutofillLayout> {
  @private
-  scoped_nsobject<LayoutView> inputs_;
-  scoped_nsobject<MenuButton> suggestButton_;
-  scoped_nsobject<AutofillSuggestionContainer> suggestContainer_;
-  scoped_nsobject<NSTextField> label_;
-  scoped_nsobject<AutofillSectionView> view_;  // The view for the container.
+  base::scoped_nsobject<LayoutView> inputs_;
+  base::scoped_nsobject<MenuButton> suggestButton_;
+  base::scoped_nsobject<AutofillSuggestionContainer> suggestContainer_;
+  base::scoped_nsobject<NSTextField> label_;
+  base::scoped_nsobject<AutofillSectionView> view_;  // The view for the
+                                                     // container.
 
-  scoped_nsobject<MenuController> menuController_;
+  base::scoped_nsobject<MenuController> menuController_;
   autofill::DialogSection section_;
   autofill::AutofillDialogController* controller_;  // Not owned.
 }
diff --git a/chrome/browser/ui/cocoa/autofill/autofill_section_container.mm b/chrome/browser/ui/cocoa/autofill/autofill_section_container.mm
index 73ef309..7c48db9 100644
--- a/chrome/browser/ui/cocoa/autofill/autofill_section_container.mm
+++ b/chrome/browser/ui/cocoa/autofill/autofill_section_container.mm
@@ -7,6 +7,7 @@
 #include "base/strings/sys_string_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/ui/autofill/autofill_dialog_controller.h"
+#import "chrome/browser/ui/cocoa/autofill/autofill_pop_up_button.h"
 #import "chrome/browser/ui/cocoa/autofill/autofill_section_view.h"
 #import "chrome/browser/ui/cocoa/autofill/autofill_suggestion_container.h"
 #import "chrome/browser/ui/cocoa/autofill/autofill_textfield.h"
@@ -91,12 +92,11 @@
 }
 
 - (void)getInputs:(autofill::DetailOutputMap*)output {
-  for (id input in [inputs_ subviews]) {
+  for (NSControl<AutofillInputField>* input in [inputs_ subviews]) {
     const autofill::DetailInput* detailInput =
         reinterpret_cast<autofill::DetailInput*>([input tag]);
     DCHECK(detailInput);
-    NSString* value = [input isKindOfClass:[NSPopUpButton class]] ?
-        [input titleOfSelectedItem] : [input stringValue];
+    NSString* value = [input fieldValue];
     output->insert(
         std::make_pair(detailInput,base::SysNSStringToUTF16(value)));
   }
@@ -126,7 +126,6 @@
 - (void)loadView {
   inputs_.reset([[self makeInputControls] retain]);
   string16 labelText = controller_->LabelForSection(section_);
-
   label_.reset([[self makeDetailSectionLabel:
                    base::SysUTF16ToNSString(labelText)] retain]);
 
@@ -141,6 +140,9 @@
 }
 
 - (NSSize)preferredSize {
+  if ([view_ isHidden])
+    return NSMakeSize(0, 0);
+
   NSSize labelSize = [label_ frame].size;  // Assumes sizeToFit was called.
   CGFloat controlHeight = [inputs_ preferredHeightForWidth:kDetailsWidth];
   if ([inputs_ isHidden])
@@ -154,6 +156,9 @@
 }
 
 - (void)performLayout {
+  if ([view_ isHidden])
+    return;
+
   NSSize buttonSize = [suggestButton_ frame].size;  // Assume sizeToFit.
   NSSize labelSize = [label_ frame].size;  // Assumes sizeToFit was called.
   CGFloat controlHeight = [inputs_ preferredHeightForWidth:kDetailsWidth];
@@ -198,12 +203,11 @@
 }
 
 - (NSTextField*)makeDetailSectionLabel:(NSString*)labelText {
-  scoped_nsobject<NSTextField> label([[NSTextField alloc] init]);
+  base::scoped_nsobject<NSTextField> label([[NSTextField alloc] init]);
   [label setFont:
       [[NSFontManager sharedFontManager] convertFont:[label font]
                                          toHaveTrait:NSBoldFontMask]];
   [label setStringValue:labelText];
-  [label sizeToFit];
   [label setEditable:NO];
   [label setBordered:NO];
   [label sizeToFit];
@@ -211,7 +215,7 @@
 }
 
 - (MenuButton*)makeSuggestionButton {
-  scoped_nsobject<MenuButton> button([[MenuButton alloc] init]);
+  base::scoped_nsobject<MenuButton> button([[MenuButton alloc] init]);
 
   [button setOpenMenuOnClick:YES];
   [button setBordered:NO];
@@ -245,7 +249,7 @@
   const autofill::DetailInputs& inputs =
       controller_->RequestedFieldsForSection(section_);
 
-  scoped_nsobject<LayoutView> view([[LayoutView alloc] init]);
+  base::scoped_nsobject<LayoutView> view([[LayoutView alloc] init]);
   [view setLayoutManager:
       scoped_ptr<SimpleGridLayout>(new SimpleGridLayout(view))];
   SimpleGridLayout* layout = [view layoutManager];
@@ -273,30 +277,30 @@
 
     ui::ComboboxModel* input_model =
         controller_->ComboboxModelForAutofillType(input.type);
+    base::scoped_nsprotocol<NSControl<AutofillInputField>*> control;
     if (input_model) {
-      scoped_nsobject<NSPopUpButton> popup(
-          [[NSPopUpButton alloc] initWithFrame:NSZeroRect pullsDown:YES]);
+      base::scoped_nsobject<AutofillPopUpButton> popup(
+          [[AutofillPopUpButton alloc] initWithFrame:NSZeroRect pullsDown:NO]);
       for (int i = 0; i < input_model->GetItemCount(); ++i) {
         [popup addItemWithTitle:
             base::SysUTF16ToNSString(input_model->GetItemAt(i))];
       }
-      [popup selectItemWithTitle:base::SysUTF16ToNSString(input.initial_value)];
-      [popup sizeToFit];
-      [popup setTag:reinterpret_cast<NSInteger>(&input)];
-      layout->AddView(popup);
+      control.reset(popup.release());
     } else {
-      scoped_nsobject<AutofillTextField> field(
+      base::scoped_nsobject<AutofillTextField> field(
           [[AutofillTextField alloc] init]);
       [[field cell] setPlaceholderString:
           l10n_util::GetNSStringWithFixup(input.placeholder_text_rid)];
       [[field cell] setIcon:
           controller_->IconForField(
               input.type, input.initial_value).AsNSImage()];
-      [[field cell] setInvalid:YES];
-      [field sizeToFit];
-      [field setTag:reinterpret_cast<NSInteger>(&input)];
-      layout->AddView(field);
+      control.reset(field.release());
     }
+    [control setFieldValue:base::SysUTF16ToNSString(input.initial_value)];
+    [control setInvalid:YES];
+    [control sizeToFit];
+    [control setTag:reinterpret_cast<NSInteger>(&input)];
+    layout->AddView(control);
   }
 
   return view.autorelease();
@@ -326,6 +330,7 @@
     [suggestContainer_ showTextfield:extraText withIcon:extraIcon];
   }
   [view_ setShouldHighlightOnHover:showSuggestions];
+  [view_ setHidden:!controller_->SectionIsActive(section_)];
 }
 
 - (void)update {
diff --git a/chrome/browser/ui/cocoa/autofill/autofill_section_container_unittest.mm b/chrome/browser/ui/cocoa/autofill/autofill_section_container_unittest.mm
index 651d0c0..12c8199 100644
--- a/chrome/browser/ui/cocoa/autofill/autofill_section_container_unittest.mm
+++ b/chrome/browser/ui/cocoa/autofill/autofill_section_container_unittest.mm
@@ -5,15 +5,15 @@
 #import "chrome/browser/ui/cocoa/autofill/autofill_section_container.h"
 
 #include "base/mac/foundation_util.h"
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/ui/autofill/autofill_dialog_models.h"
 #include "chrome/browser/ui/autofill/mock_autofill_dialog_controller.h"
 #import "chrome/browser/ui/cocoa/autofill/layout_view.h"
 #import "chrome/browser/ui/cocoa/menu_button.h"
 #include "grit/generated_resources.h"
-#include "testing/gtest_mac.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "testing/gtest_mac.h"
 #include "testing/platform_test.h"
 #include "ui/base/models/combobox_model.h"
 #include "ui/base/models/simple_menu_model.h"
@@ -41,7 +41,7 @@
   }
 
  protected:
-  scoped_nsobject<AutofillSectionContainer> container_;
+  base::scoped_nsobject<AutofillSectionContainer> container_;
   testing::NiceMock<autofill::MockAutofillDialogController> controller_;
 };
 
@@ -163,4 +163,4 @@
 
   EXPECT_NSEQ(@"a", [[menu itemAtIndex:1] title]);
   EXPECT_NSEQ(@"b", [[menu itemAtIndex:2] title]);
-}
\ No newline at end of file
+}
diff --git a/chrome/browser/ui/cocoa/autofill/autofill_section_view_unittest.mm b/chrome/browser/ui/cocoa/autofill/autofill_section_view_unittest.mm
index 2515c71..8cad9d7 100644
--- a/chrome/browser/ui/cocoa/autofill/autofill_section_view_unittest.mm
+++ b/chrome/browser/ui/cocoa/autofill/autofill_section_view_unittest.mm
@@ -4,7 +4,7 @@
 
 #import "chrome/browser/ui/cocoa/autofill/autofill_section_view.h"
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "base/memory/scoped_ptr.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/gtest_mac.h"
@@ -74,8 +74,8 @@
   }
 
  protected:
-  scoped_nsobject<AutofillSectionView> view_;
-  scoped_nsobject<NSBitmapImageRep> bitmap_;
+  base::scoped_nsobject<AutofillSectionView> view_;
+  base::scoped_nsobject<NSBitmapImageRep> bitmap_;
   scoped_ptr<gfx::ScopedNSGraphicsContextSaveGState> saved_context_;
   NSGraphicsContext* context_;
 };
diff --git a/chrome/browser/ui/cocoa/autofill/autofill_sign_in_container_unittest.mm b/chrome/browser/ui/cocoa/autofill/autofill_sign_in_container_unittest.mm
index 83220df..77f8a4b 100644
--- a/chrome/browser/ui/cocoa/autofill/autofill_sign_in_container_unittest.mm
+++ b/chrome/browser/ui/cocoa/autofill/autofill_sign_in_container_unittest.mm
@@ -4,7 +4,7 @@
 
 #import "chrome/browser/ui/cocoa/autofill/autofill_sign_in_container.h"
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "chrome/browser/ui/autofill/mock_autofill_dialog_controller.h"
 #import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
@@ -60,7 +60,7 @@
   }
 
  protected:
-  scoped_nsobject<AutofillSignInContainer> container_;
+  base::scoped_nsobject<AutofillSignInContainer> container_;
   testing::NiceMock<autofill::MockAutofillDialogController> controller_;
   CocoaTestHelperWindow* test_window_;
 };
diff --git a/chrome/browser/ui/cocoa/autofill/autofill_suggestion_container.h b/chrome/browser/ui/cocoa/autofill/autofill_suggestion_container.h
index 6253a20..6fe11d7 100644
--- a/chrome/browser/ui/cocoa/autofill/autofill_suggestion_container.h
+++ b/chrome/browser/ui/cocoa/autofill/autofill_suggestion_container.h
@@ -7,7 +7,7 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #import "chrome/browser/ui/cocoa/autofill/autofill_layout.h"
 
 namespace autofill {
@@ -20,16 +20,16 @@
 @interface AutofillSuggestionContainer : NSViewController<AutofillLayout> {
  @private
   // The label that holds the suggestion description text.
-  scoped_nsobject<NSTextField> label_;
+  base::scoped_nsobject<NSTextField> label_;
 
   // The second (and longer) line of text that describes the suggestion.
-  scoped_nsobject<NSTextField> label2_;
+  base::scoped_nsobject<NSTextField> label2_;
 
   // The icon that comes just before |label_|.
-  scoped_nsobject<NSImageView> iconImageView_;
+  base::scoped_nsobject<NSImageView> iconImageView_;
 
   // The input set by ShowTextfield.
-  scoped_nsobject<AutofillTextField> inputField_;
+  base::scoped_nsobject<AutofillTextField> inputField_;
 
   autofill::AutofillDialogController* controller_;  // Not owned.
 }
diff --git a/chrome/browser/ui/cocoa/autofill/autofill_suggestion_container.mm b/chrome/browser/ui/cocoa/autofill/autofill_suggestion_container.mm
index 6522e69..9989f83 100644
--- a/chrome/browser/ui/cocoa/autofill/autofill_suggestion_container.mm
+++ b/chrome/browser/ui/cocoa/autofill/autofill_suggestion_container.mm
@@ -8,7 +8,7 @@
 #include <cmath>
 
 #include "base/logging.h"
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "base/strings/sys_string_conversions.h"
 #include "chrome/browser/ui/autofill/autofill_dialog_controller.h"
 #include "chrome/browser/ui/chrome_style.h"
@@ -38,7 +38,7 @@
 @implementation AutofillSuggestionContainer
 
 - (NSTextField*)makeDetailSectionLabel:(NSString*)labelText {
-  scoped_nsobject<NSTextField> label([[NSTextField alloc] init]);
+  base::scoped_nsobject<NSTextField> label([[NSTextField alloc] init]);
   [label setFont:
       [[NSFontManager sharedFontManager] convertFont:[label font]
                                          toHaveTrait:NSBoldFontMask]];
@@ -60,14 +60,14 @@
   inputField_.reset([[AutofillTextField alloc] initWithFrame:NSZeroRect]);
   [inputField_ setHidden:YES];
 
-  scoped_nsobject<NSView> view([[NSView alloc] initWithFrame:NSZeroRect]);
+  base::scoped_nsobject<NSView> view([[NSView alloc] initWithFrame:NSZeroRect]);
   [view setSubviews:
       @[iconImageView_, label_, inputField_, label2_ ]];
   [self setView:view];
 }
 
 - (NSTextField*)createLabelWithFrame:(NSRect)frame {
-  scoped_nsobject<NSTextField> label(
+  base::scoped_nsobject<NSTextField> label(
       [[NSTextField alloc] initWithFrame:frame]);
   [label setEditable:NO];
   [label setDrawsBackground:NO];
@@ -174,4 +174,4 @@
   [[self view] setFrameSize:preferredContainerSize];
 }
 
-@end
\ No newline at end of file
+@end
diff --git a/chrome/browser/ui/cocoa/autofill/autofill_suggestion_container_unittest.mm b/chrome/browser/ui/cocoa/autofill/autofill_suggestion_container_unittest.mm
index 08b3848..e535d41 100644
--- a/chrome/browser/ui/cocoa/autofill/autofill_suggestion_container_unittest.mm
+++ b/chrome/browser/ui/cocoa/autofill/autofill_suggestion_container_unittest.mm
@@ -20,7 +20,7 @@
   }
 
  protected:
-  scoped_nsobject<AutofillSuggestionContainer> container_;
+  base::scoped_nsobject<AutofillSuggestionContainer> container_;
 };
 
 }  // namespace
@@ -47,4 +47,4 @@
   EXPECT_EQ(2, num_text_fields);
   EXPECT_TRUE(has_edit_field);
   EXPECT_TRUE(has_icon);
-}
\ No newline at end of file
+}
diff --git a/chrome/browser/ui/cocoa/autofill/autofill_textfield.h b/chrome/browser/ui/cocoa/autofill/autofill_textfield.h
index 57fcea7..4a2d4d9 100644
--- a/chrome/browser/ui/cocoa/autofill/autofill_textfield.h
+++ b/chrome/browser/ui/cocoa/autofill/autofill_textfield.h
@@ -7,21 +7,21 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include <base/memory/scoped_nsobject.h>
+#include "base/mac/scoped_nsobject.h"
+#include "chrome/browser/ui/cocoa/autofill/autofill_input_field.h"
 
 // Text field used for text inputs inside Autofill.
 // Provide both dog ear and red outline when the contents are marked invalid.
-@interface AutofillTextField : NSTextField
+@interface AutofillTextField : NSTextField<AutofillInputField>
 @end
 
-@interface AutofillTextFieldCell : NSTextFieldCell {
+@interface AutofillTextFieldCell : NSTextFieldCell<AutofillInputField> {
  @private
   BOOL invalid_;
-  scoped_nsobject<NSImage> icon_;
+  base::scoped_nsobject<NSImage> icon_;
 }
 
-@property(assign, nonatomic) BOOL invalid;
-@property(nonatomic, retain, getter=icon, setter=setIcon:) NSImage* icon;
+@property(nonatomic, retain) NSImage* icon;
 
 @end
 
diff --git a/chrome/browser/ui/cocoa/autofill/autofill_textfield.mm b/chrome/browser/ui/cocoa/autofill/autofill_textfield.mm
index 6be76c0..3daad77 100644
--- a/chrome/browser/ui/cocoa/autofill/autofill_textfield.mm
+++ b/chrome/browser/ui/cocoa/autofill/autofill_textfield.mm
@@ -27,6 +27,22 @@
   return [AutofillTextFieldCell class];
 }
 
+- (BOOL)invalid {
+  return [[self cell] invalid];
+}
+
+- (void)setInvalid:(BOOL)invalid {
+  [[self cell] setInvalid:invalid];
+}
+
+- (NSString*)fieldValue {
+  return [[self cell] fieldValue];
+}
+
+- (void)setFieldValue:(NSString*)fieldValue {
+  [[self cell] setFieldValue:fieldValue];
+}
+
 @end
 
 @implementation AutofillTextFieldCell
@@ -41,6 +57,14 @@
   icon_.reset([icon retain]);
 }
 
+- (NSString*)fieldValue {
+  return [self stringValue];
+}
+
+- (void)setFieldValue:(NSString*)fieldValue {
+  [self setStringValue:fieldValue];
+}
+
 - (NSRect)textFrameForFrame:(NSRect)frame {
   if (icon_) {
     NSRect textFrame, iconFrame;
diff --git a/chrome/browser/ui/cocoa/autofill/autofill_textfield_unittest.mm b/chrome/browser/ui/cocoa/autofill/autofill_textfield_unittest.mm
index ed6fa79..f32e636 100644
--- a/chrome/browser/ui/cocoa/autofill/autofill_textfield_unittest.mm
+++ b/chrome/browser/ui/cocoa/autofill/autofill_textfield_unittest.mm
@@ -4,7 +4,7 @@
 
 #import "chrome/browser/ui/cocoa/autofill/autofill_textfield.h"
 
-#import "base/memory/scoped_nsobject.h"
+#import "base/mac/scoped_nsobject.h"
 #import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/platform_test.h"
@@ -20,7 +20,7 @@
   }
 
  protected:
-  scoped_nsobject<AutofillTextField> textfield_;
+  base::scoped_nsobject<AutofillTextField> textfield_;
 
   DISALLOW_COPY_AND_ASSIGN(AutofillTextFieldTest);
 };
diff --git a/chrome/browser/ui/cocoa/autofill/down_arrow_popup_menu_cell_unittest.mm b/chrome/browser/ui/cocoa/autofill/down_arrow_popup_menu_cell_unittest.mm
index d41b496..4d878d6 100644
--- a/chrome/browser/ui/cocoa/autofill/down_arrow_popup_menu_cell_unittest.mm
+++ b/chrome/browser/ui/cocoa/autofill/down_arrow_popup_menu_cell_unittest.mm
@@ -6,7 +6,7 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "chrome/browser/ui/cocoa/autofill/autofill_dialog_constants.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/platform_test.h"
@@ -19,13 +19,13 @@
   DownArrowPopupMenuCellTest() {
     NSRect frame = NSMakeRect(0, 0, 50, 30);
     view_.reset([[NSButton alloc] initWithFrame:frame]);
-    scoped_nsobject<DownArrowPopupMenuCell> cell(
+    base::scoped_nsobject<DownArrowPopupMenuCell> cell(
         [[DownArrowPopupMenuCell alloc] initTextCell:@"Testing"]);
     [view_ setCell:cell.get()];
     [[test_window() contentView] addSubview:view_];  }
 
  protected:
-  scoped_nsobject<NSButton> view_;
+  base::scoped_nsobject<NSButton> view_;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(DownArrowPopupMenuCellTest);
@@ -50,7 +50,8 @@
   ASSERT_TRUE([cell isKindOfClass:[DownArrowPopupMenuCell class]]);
 
   NSRect rect = NSMakeRect(0, 0, 11, 17);
-  scoped_nsobject<NSImage> image([[NSImage alloc] initWithSize:rect.size]);
+  base::scoped_nsobject<NSImage> image(
+      [[NSImage alloc] initWithSize:rect.size]);
   [cell setImage:image forButtonState:image_button_cell::kDefaultState];
   [view_ setTitle:@"Testing"];
 
diff --git a/chrome/browser/ui/cocoa/autofill/layout_view_unittest.mm b/chrome/browser/ui/cocoa/autofill/layout_view_unittest.mm
index abfcd22..c56c9f8 100644
--- a/chrome/browser/ui/cocoa/autofill/layout_view_unittest.mm
+++ b/chrome/browser/ui/cocoa/autofill/layout_view_unittest.mm
@@ -4,7 +4,7 @@
 
 #import "chrome/browser/ui/cocoa/autofill/layout_view.h"
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "chrome/browser/ui/cocoa/autofill/simple_grid_layout.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/platform_test.h"
@@ -24,7 +24,7 @@
   }
 
  protected:
-  scoped_nsobject<LayoutView> view_;
+  base::scoped_nsobject<LayoutView> view_;
   SimpleGridLayout* layout_;  // weak, owned by view_.
 };
 
@@ -40,9 +40,9 @@
   cs->AddColumn(0.4);
   cs->AddColumn(0.6);
   layout_->StartRow(0, 0);
-  scoped_nsobject<NSView> childView1(
+  base::scoped_nsobject<NSView> childView1(
       [[NSView alloc] initWithFrame:NSMakeRect(0, 0, 0, 45)]);
-  scoped_nsobject<NSView> childView2(
+  base::scoped_nsobject<NSView> childView2(
       [[NSView alloc] initWithFrame:NSMakeRect(0, 0, 20, 55)]);
   layout_->AddView(childView1);
   layout_->AddView(childView2);
@@ -62,4 +62,4 @@
   subview = [[view_ subviews] objectAtIndex:1];
   EXPECT_FLOAT_EQ(24, NSWidth([subview frame]));
   EXPECT_FLOAT_EQ(55, NSHeight([subview frame]));
-}
\ No newline at end of file
+}
diff --git a/chrome/browser/ui/cocoa/autofill/simple_grid_layout_unittest.mm b/chrome/browser/ui/cocoa/autofill/simple_grid_layout_unittest.mm
index d529211..da517c7 100644
--- a/chrome/browser/ui/cocoa/autofill/simple_grid_layout_unittest.mm
+++ b/chrome/browser/ui/cocoa/autofill/simple_grid_layout_unittest.mm
@@ -5,7 +5,7 @@
 #include "chrome/browser/ui/cocoa/autofill/simple_grid_layout.h"
 
 #include "base/logging.h"
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace {
@@ -19,15 +19,15 @@
 
 class LayoutTest : public testing::Test {
  public:
-  scoped_nsobject<NSView> CreateViewWithWidth(float width) {
+  base::scoped_nsobject<NSView> CreateViewWithWidth(float width) {
     NSRect frame = NSMakeRect(0, 0, width, 0);
-    scoped_nsobject<NSView> view([[NSView alloc] initWithFrame:frame]);
+    base::scoped_nsobject<NSView> view([[NSView alloc] initWithFrame:frame]);
     return view;
   }
 
-  scoped_nsobject<NSView> CreateViewWithHeight(float height) {
+  base::scoped_nsobject<NSView> CreateViewWithHeight(float height) {
     NSRect frame = NSMakeRect(0, 0, 0, height);
-    scoped_nsobject<NSView> view([[NSView alloc] initWithFrame:frame]);
+    base::scoped_nsobject<NSView> view([[NSView alloc] initWithFrame:frame]);
     return view;
   }
 };
@@ -107,7 +107,7 @@
   ColumnSet* cs;
   cs = layout.AddRow();
   cs->AddColumn(1.0f);
-  scoped_nsobject<NSView> view1 = CreateViewWithHeight(30.0f);
+  base::scoped_nsobject<NSView> view1 = CreateViewWithHeight(30.0f);
   layout.AddView(view1);
 
   layout.AddPaddingRow(20);
@@ -115,7 +115,7 @@
   cs = layout.AddRow();
   cs->AddColumn(1.0f);
   EXPECT_EQ(3, layout.num_rows());
-  scoped_nsobject<NSView> view2 = CreateViewWithHeight(10.0f);
+  base::scoped_nsobject<NSView> view2 = CreateViewWithHeight(10.0f);
   layout.AddView(view2);
 
   layout.SizeRowsAndColumns(0.0f);
@@ -132,17 +132,17 @@
   layout.GetLastValidColumnSet()->AddColumn(0.6f);
   layout.GetLastValidColumnSet()->AddColumn(0.6f);
 
-  scoped_nsobject<NSView> view1 = CreateViewWithHeight(37.0f);
+  base::scoped_nsobject<NSView> view1 = CreateViewWithHeight(37.0f);
   layout.AddView(view1);
   layout.SizeRowsAndColumns(0.0f);
   EXPECT_FLOAT_EQ(37.0f, layout.GetRowHeight(0));
 
-  scoped_nsobject<NSView> view2 = CreateViewWithHeight(26.0f);
+  base::scoped_nsobject<NSView> view2 = CreateViewWithHeight(26.0f);
   layout.AddView(view2);
   layout.SizeRowsAndColumns(0.0f);
   EXPECT_FLOAT_EQ(37.0f, layout.GetRowHeight(0));
 
-  scoped_nsobject<NSView> view3 = CreateViewWithHeight(42.0f);
+  base::scoped_nsobject<NSView> view3 = CreateViewWithHeight(42.0f);
   layout.AddView(view3);
   layout.SizeRowsAndColumns(0.0f);
   EXPECT_FLOAT_EQ(42.0f, layout.GetRowHeight(0));
@@ -153,12 +153,12 @@
 
   layout.AddRow();
   layout.GetLastValidColumnSet()->AddColumn(0.6f);
-  scoped_nsobject<NSView> view1 = CreateViewWithHeight(30.0f);
+  base::scoped_nsobject<NSView> view1 = CreateViewWithHeight(30.0f);
   layout.AddView(view1);
 
   layout.AddRow();
   layout.GetLastValidColumnSet()->AddColumn(0.6f);
-  scoped_nsobject<NSView> view2 = CreateViewWithHeight(40.0f);
+  base::scoped_nsobject<NSView> view2 = CreateViewWithHeight(40.0f);
   layout.AddView(view2);
 
   layout.SizeRowsAndColumns(0.0f);
@@ -174,17 +174,17 @@
   layout.GetLastValidColumnSet()->AddPaddingColumn(30);
   layout.GetLastValidColumnSet()->AddColumn(0.4f);
 
-  scoped_nsobject<NSView> view1 = CreateViewWithHeight(22.0f);
-  scoped_nsobject<NSView> view2 = CreateViewWithHeight(20.0f);
+  base::scoped_nsobject<NSView> view1 = CreateViewWithHeight(22.0f);
+  base::scoped_nsobject<NSView> view2 = CreateViewWithHeight(20.0f);
   layout.AddView(view1);
   layout.AddView(view2);
 
   layout.AddRow();
   layout.GetLastValidColumnSet()->AddColumn(0.6f);
-  scoped_nsobject<NSView> view3 = CreateViewWithHeight(18.0f);
+  base::scoped_nsobject<NSView> view3 = CreateViewWithHeight(18.0f);
   layout.AddView(view3);
 
-  scoped_nsobject<NSView> host_view = CreateViewWithWidth(150.0f);
+  base::scoped_nsobject<NSView> host_view = CreateViewWithWidth(150.0f);
   layout.Layout(host_view);
 
   EXPECT_FLOAT_EQ(72.0f, NSWidth([view1 frame]));
@@ -214,7 +214,7 @@
   layout.AddRow();
   layout.GetLastValidColumnSet()->AddColumn(0.6f);
 
-  scoped_nsobject<NSView> view1 = CreateViewWithHeight(22.0f);
+  base::scoped_nsobject<NSView> view1 = CreateViewWithHeight(22.0f);
   layout.AddView(view1);
   EXPECT_FLOAT_EQ(22.0f, layout.GetPreferredHeightForWidth(100.0));
 
@@ -223,7 +223,7 @@
 
   layout.AddRow();
   layout.GetLastValidColumnSet()->AddColumn(0.6f);
-  scoped_nsobject<NSView> view2 = CreateViewWithHeight(13.0f);
+  base::scoped_nsobject<NSView> view2 = CreateViewWithHeight(13.0f);
   layout.AddView(view2);
   EXPECT_FLOAT_EQ(47.0f, layout.GetPreferredHeightForWidth(100.0));
 }
@@ -308,7 +308,7 @@
   layout.GetLastValidColumnSet()->AddColumn(0.4f);
 
   EXPECT_EQ(0, layout.next_column());
-  scoped_nsobject<NSView> view1 = CreateViewWithWidth(37.0f);
+  base::scoped_nsobject<NSView> view1 = CreateViewWithWidth(37.0f);
   layout.AddView(view1);
   EXPECT_EQ(2, layout.next_column());
 }
@@ -321,12 +321,12 @@
   layout.GetLastValidColumnSet()->AddPaddingColumn(30);
   layout.GetLastValidColumnSet()->AddColumn(0.4f);
 
-  scoped_nsobject<NSView> view1 = CreateViewWithWidth(37.0f);
-  scoped_nsobject<NSView> view2 = CreateViewWithWidth(42.0f);
+  base::scoped_nsobject<NSView> view1 = CreateViewWithWidth(37.0f);
+  base::scoped_nsobject<NSView> view2 = CreateViewWithWidth(42.0f);
   layout.AddView(view1);
   layout.AddView(view2);
 
-  scoped_nsobject<NSView> host_view = CreateViewWithWidth(150.0f);
+  base::scoped_nsobject<NSView> host_view = CreateViewWithWidth(150.0f);
   layout.Layout(host_view);
 
   EXPECT_FLOAT_EQ(72.0f, NSWidth([view1 frame]));
diff --git a/chrome/browser/ui/cocoa/background_gradient_view.h b/chrome/browser/ui/cocoa/background_gradient_view.h
index a156980..e8b6c2d 100644
--- a/chrome/browser/ui/cocoa/background_gradient_view.h
+++ b/chrome/browser/ui/cocoa/background_gradient_view.h
@@ -14,6 +14,9 @@
   BOOL showsDivider_;
 }
 
+// Controls whether the bar draws a dividing line at the bottom.
+@property(nonatomic, assign) BOOL showsDivider;
+
 // The color used for the bottom stroke. Public so subclasses can use.
 - (NSColor*)strokeColor;
 
@@ -26,8 +29,6 @@
 // example of this.
 - (void)drawBackgroundWithOpaque:(BOOL)opaque;
 
-// Controls whether the bar draws a dividing line at the bottom.
-@property(nonatomic, assign) BOOL showsDivider;
 @end
 
 #endif  // CHROME_BROWSER_UI_COCOA_BACKGROUND_GRADIENT_VIEW_H_
diff --git a/chrome/browser/ui/cocoa/background_gradient_view.mm b/chrome/browser/ui/cocoa/background_gradient_view.mm
index f16fd34..26a904f 100644
--- a/chrome/browser/ui/cocoa/background_gradient_view.mm
+++ b/chrome/browser/ui/cocoa/background_gradient_view.mm
@@ -16,6 +16,7 @@
 @end
 
 @implementation BackgroundGradientView
+
 @synthesize showsDivider = showsDivider_;
 
 - (id)initWithFrame:(NSRect)frameRect {
@@ -82,8 +83,12 @@
 }
 
 - (NSColor*)strokeColor {
-  BOOL isActive = [[self window] isMainWindow];
-  ui::ThemeProvider* themeProvider = [[self window] themeProvider];
+  NSWindow* window = [self window];
+  if ([window parentWindow])
+    window = [window parentWindow];
+
+  BOOL isActive = [window isMainWindow];
+  ui::ThemeProvider* themeProvider = [window themeProvider];
   if (!themeProvider)
     return [NSColor blackColor];
   return themeProvider->GetNSColor(
@@ -111,7 +116,7 @@
 
 - (void)windowFocusDidChange:(NSNotification*)notification {
   // The background color depends on the window's focus state.
-  [self setNeedsDisplay:YES];
+  [self cr_recursivelySetNeedsDisplay:YES];
 }
 
 - (void)viewWillMoveToWindow:(NSWindow*)window {
diff --git a/chrome/browser/ui/cocoa/background_gradient_view_unittest.mm b/chrome/browser/ui/cocoa/background_gradient_view_unittest.mm
index d1cda6c..b7e9697 100644
--- a/chrome/browser/ui/cocoa/background_gradient_view_unittest.mm
+++ b/chrome/browser/ui/cocoa/background_gradient_view_unittest.mm
@@ -4,7 +4,7 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #import "chrome/browser/ui/cocoa/background_gradient_view.h"
 #import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -36,7 +36,7 @@
  public:
   BackgroundGradientViewTest() {
     NSRect frame = NSMakeRect(0, 0, 100, 30);
-    scoped_nsobject<BackgroundGradientSubClassTest> view;
+    base::scoped_nsobject<BackgroundGradientSubClassTest> view;
     view.reset([[BackgroundGradientSubClassTest alloc] initWithFrame:frame]);
     view_ = view.get();
     [[test_window() contentView] addSubview:view_];
diff --git a/chrome/browser/ui/cocoa/base_bubble_controller.mm b/chrome/browser/ui/cocoa/base_bubble_controller.mm
index 91eaa98..c7ef5b6 100644
--- a/chrome/browser/ui/cocoa/base_bubble_controller.mm
+++ b/chrome/browser/ui/cocoa/base_bubble_controller.mm
@@ -7,7 +7,7 @@
 #include "base/logging.h"
 #include "base/mac/bundle_locations.h"
 #include "base/mac/mac_util.h"
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "base/strings/string_util.h"
 #import "chrome/browser/ui/cocoa/browser_window_controller.h"
 #import "chrome/browser/ui/cocoa/info_bubble_view.h"
@@ -76,7 +76,7 @@
     DCHECK(![[self window] delegate]);
     [theWindow setDelegate:self];
 
-    scoped_nsobject<InfoBubbleView> contentView(
+    base::scoped_nsobject<InfoBubbleView> contentView(
         [[InfoBubbleView alloc] initWithFrame:NSMakeRect(0, 0, 0, 0)]);
     [theWindow setContentView:contentView.get()];
     bubble_ = contentView.get();
@@ -123,7 +123,7 @@
 
 - (NSBox*)separatorWithFrame:(NSRect)frame {
   frame.size.height = 1.0;
-  scoped_nsobject<NSBox> spacer([[NSBox alloc] initWithFrame:frame]);
+  base::scoped_nsobject<NSBox> spacer([[NSBox alloc] initWithFrame:frame]);
   [spacer setBoxType:NSBoxSeparator];
   [spacer setBorderType:NSLineBorder];
   [spacer setAlphaValue:0.2];
diff --git a/chrome/browser/ui/cocoa/base_bubble_controller_unittest.mm b/chrome/browser/ui/cocoa/base_bubble_controller_unittest.mm
index 307034c..feccd6f 100644
--- a/chrome/browser/ui/cocoa/base_bubble_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/base_bubble_controller_unittest.mm
@@ -5,7 +5,7 @@
 #import "chrome/browser/ui/cocoa/base_bubble_controller.h"
 
 #include "base/mac/mac_util.h"
-#import "base/memory/scoped_nsobject.h"
+#import "base/mac/scoped_nsobject.h"
 #import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #import "chrome/browser/ui/cocoa/info_bubble_view.h"
 #import "chrome/browser/ui/cocoa/run_loop_testing.h"
@@ -44,7 +44,7 @@
   }
 
  public:
-  scoped_nsobject<NSWindow> bubbleWindow_;
+  base::scoped_nsobject<NSWindow> bubbleWindow_;
   BaseBubbleController* controller_;
 };
 
@@ -118,12 +118,12 @@
 // the key window changes.
 TEST_F(BaseBubbleControllerTest, ResignKeyCloses) {
   // Closing the bubble will autorelease the controller.
-  scoped_nsobject<BaseBubbleController> keep_alive([controller_ retain]);
+  base::scoped_nsobject<BaseBubbleController> keep_alive([controller_ retain]);
 
   NSWindow* bubble_window = [controller_ window];
   EXPECT_FALSE([bubble_window isVisible]);
 
-  scoped_nsobject<NSWindow> other_window(
+  base::scoped_nsobject<NSWindow> other_window(
       [[NSWindow alloc] initWithContentRect:NSMakeRect(500, 500, 500, 500)
                                   styleMask:NSTitledWindowMask
                                     backing:NSBackingStoreBuffered
@@ -163,7 +163,7 @@
     return;
 
   // Closing the bubble will autorelease the controller.
-  scoped_nsobject<BaseBubbleController> keep_alive([controller_ retain]);
+  base::scoped_nsobject<BaseBubbleController> keep_alive([controller_ retain]);
   NSWindow* window = [controller_ window];
 
   EXPECT_FALSE([window isVisible]);
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_all_tabs_controller_unittest.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_all_tabs_controller_unittest.mm
index 1e0a3ab..6e21dc2 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_all_tabs_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_all_tabs_controller_unittest.mm
@@ -4,7 +4,6 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
 #include "base/strings/sys_string_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/bookmarks/bookmark_model.h"
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_bridge_unittest.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_bridge_unittest.mm
index a0f2ef9..0a9650d 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_bridge_unittest.mm
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_bridge_unittest.mm
@@ -26,7 +26,7 @@
 // Oddly, we are our own delegate.
 @interface FakeBookmarkBarController : BookmarkBarController {
  @public
-  scoped_nsobject<NSMutableArray> callbacks_;
+  base::scoped_nsobject<NSMutableArray> callbacks_;
   std::vector<OpenInfo> opens_;
 }
 @end
@@ -98,15 +98,15 @@
 TEST_F(BookmarkBarBridgeTest, TestRedirect) {
   BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
 
-  scoped_nsobject<NSView> parentView([[NSView alloc]
-                                       initWithFrame:NSMakeRect(0,0,100,100)]);
-  scoped_nsobject<NSView> webView([[NSView alloc]
-                                       initWithFrame:NSMakeRect(0,0,100,100)]);
-  scoped_nsobject<NSView> infoBarsView(
-      [[NSView alloc] initWithFrame:NSMakeRect(0,0,100,100)]);
+  base::scoped_nsobject<NSView> parentView(
+      [[NSView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100)]);
+  base::scoped_nsobject<NSView> webView(
+      [[NSView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100)]);
+  base::scoped_nsobject<NSView> infoBarsView(
+      [[NSView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100)]);
 
-  scoped_nsobject<FakeBookmarkBarController>
-      controller([[FakeBookmarkBarController alloc] initWithBrowser:browser()]);
+  base::scoped_nsobject<FakeBookmarkBarController> controller(
+      [[FakeBookmarkBarController alloc] initWithBrowser:browser()]);
   EXPECT_TRUE(controller.get());
   scoped_ptr<BookmarkBarBridge> bridge(new BookmarkBarBridge(profile(),
                                                              controller.get(),
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_constants.h b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_constants.h
index 87fe929..9a2031b 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_constants.h
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_constants.h
@@ -23,21 +23,11 @@
 // |kVisualHeightOffset|.
 const int kBookmarkBarHeight = 26;
 
-// Height of the bookmark bar on the new tab page when instant extended is
-// enabled. TODO(sail): Remove this and update chrome::kNTPBookmarkBarHeight
-// instead.
-static const int kSearchNewTabBookmarkBarHeight = 40;
-
 // The amount of space between the inner bookmark bar and the outer toolbar on
 // new tab pages.
-const int kNTPBookmarkBarPadding = (chrome::kNTPBookmarkBarHeight -
-    (kBookmarkBarHeight + kVisualHeightOffset)) / 2;
-
-// Same as |kNTPBookmarkBarPadding| except for the instant extended UI.
-// TODO(sail): Remove this this and update |kNTPBookmarkBarPadding| instead.
-const int kSearchNTPBookmarkBarPadding =
-    (kSearchNewTabBookmarkBarHeight -
-     (kBookmarkBarHeight + kVisualHeightOffset)) / 2;
+const int kNTPBookmarkBarPadding =
+    (chrome::kNTPBookmarkBarHeight -
+        (kBookmarkBarHeight + kVisualHeightOffset)) / 2;
 
 // The height of buttons in the bookmark bar.
 const int kBookmarkButtonHeight = kBookmarkBarHeight + kVisualHeightOffset;
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.h b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.h
index 234f663..baf11cd 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.h
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.h
@@ -9,7 +9,7 @@
 #include <map>
 
 #import "base/mac/cocoa_protocols.h"
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "base/memory/scoped_ptr.h"
 #include "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_bridge.h"
 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_constants.h"
@@ -183,13 +183,13 @@
   std::map<int32,int64> menuTagMap_;
 
   // Our bookmark buttons, ordered from L-->R.
-  scoped_nsobject<NSMutableArray> buttons_;
+  base::scoped_nsobject<NSMutableArray> buttons_;
 
   // The folder image so we can use one copy for all buttons
-  scoped_nsobject<NSImage> folderImage_;
+  base::scoped_nsobject<NSImage> folderImage_;
 
   // The default image, so we can use one copy for all buttons.
-  scoped_nsobject<NSImage> defaultImage_;
+  base::scoped_nsobject<NSImage> defaultImage_;
 
   // If the bar is disabled, we hide it and ignore show/hide commands.
   // Set when using fullscreen mode.
@@ -206,7 +206,7 @@
   id<ViewResizer> resizeDelegate_;  // weak
 
   // Logic for dealing with a click on a bookmark folder button.
-  scoped_nsobject<BookmarkFolderTarget> folderTarget_;
+  base::scoped_nsobject<BookmarkFolderTarget> folderTarget_;
 
   // A controller for a pop-up bookmark folder window (custom menu).
   // This is not a scoped_nsobject because it owns itself (when its
@@ -224,17 +224,17 @@
   NSRect originalImportBookmarksRect_;  // Original, pre-resized field rect.
 
   // "Other bookmarks" button on the right side.
-  scoped_nsobject<BookmarkButton> otherBookmarksButton_;
+  base::scoped_nsobject<BookmarkButton> otherBookmarksButton_;
 
   // "Apps" button to the right of "Other bookmarks".
-  scoped_nsobject<BookmarkButton> appsPageShortcutButton_;
+  base::scoped_nsobject<BookmarkButton> appsPageShortcutButton_;
 
   // When doing a drag, this is folder button "hovered over" which we
   // may want to open after a short delay.  There are cases where a
   // mouse-enter can open a folder (e.g. if the menus are "active")
   // but that doesn't use this variable or need a delay so "hover" is
   // the wrong term.
-  scoped_nsobject<BookmarkButton> hoverButton_;
+  base::scoped_nsobject<BookmarkButton> hoverButton_;
 
   // We save the view width when we add bookmark buttons.  This lets
   // us avoid a rebuild until we've grown the window bigger than our
@@ -258,7 +258,7 @@
   BOOL showFolderMenus_;
 
   // If YES then state changes (for example, from hidden to shown) are animated.
-  // This is turned off for instant extended and for unit tests.
+  // This is turned off for unit tests.
   BOOL stateAnimationsEnabled_;
 
   // If YES then changes inside the bookmark bar (for example, removing a
@@ -273,7 +273,8 @@
   CGFloat insertionPos_;
 
   // Controller responsible for all bookmark context menus.
-  scoped_nsobject<BookmarkContextMenuCocoaController> contextMenuController_;
+  base::scoped_nsobject<BookmarkContextMenuCocoaController>
+      contextMenuController_;
 }
 
 @property(readonly, nonatomic) BookmarkBar::State currentState;
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.mm
index 3c43a37..baaf33a 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.mm
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.mm
@@ -9,17 +9,16 @@
 #include "base/metrics/histogram.h"
 #include "base/prefs/pref_service.h"
 #include "base/strings/sys_string_conversions.h"
-#include "chrome/browser/bookmarks/bookmark_editor.h"
 #include "chrome/browser/bookmarks/bookmark_model.h"
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
 #include "chrome/browser/bookmarks/bookmark_utils.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/prefs/incognito_mode_prefs.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/search/search.h"
 #include "chrome/browser/themes/theme_properties.h"
 #include "chrome/browser/themes/theme_service.h"
 #import "chrome/browser/themes/theme_service_factory.h"
+#include "chrome/browser/ui/bookmarks/bookmark_editor.h"
 #include "chrome/browser/ui/bookmarks/bookmark_utils.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_list.h"
@@ -44,7 +43,6 @@
 #import "chrome/browser/ui/cocoa/toolbar/toolbar_controller.h"
 #import "chrome/browser/ui/cocoa/view_id_util.h"
 #import "chrome/browser/ui/cocoa/view_resizer.h"
-#include "chrome/browser/ui/search/search_ui.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/webui/ntp/app_launcher_handler.h"
 #include "chrome/common/extensions/extension_constants.h"
@@ -472,13 +470,17 @@
   // Add padding to the detached bookmark bar.
   // The state of our morph (if any); 1 is total bubble, 0 is the regular bar.
   CGFloat morph = [self detachedMorphProgress];
-  CGFloat padding = chrome::IsInstantExtendedAPIEnabled()
-                    ? bookmarks::kSearchNTPBookmarkBarPadding
-                    : bookmarks::kNTPBookmarkBarPadding;
+  CGFloat padding = bookmarks::kNTPBookmarkBarPadding;
   buttonViewFrame =
       NSInsetRect(buttonViewFrame, morph * padding, morph * padding);
 
   [buttonView_ setFrame:buttonViewFrame];
+
+  // Update bookmark button backgrounds.
+  if ([self isAnimationRunning]) {
+    for (NSButton* button in buttons_.get())
+      [button setNeedsDisplay:YES];
+  }
 }
 
 // We don't change a preference; we only change visibility. Preference changing
@@ -899,10 +901,7 @@
     [[self backgroundGradientView] setShowsDivider:YES];
     [[self view] setHidden:NO];
     AnimatableView* view = [self animatableView];
-    CGFloat newHeight = chrome::IsInstantExtendedAPIEnabled()
-                        ? bookmarks::kSearchNewTabBookmarkBarHeight
-                        : chrome::kNTPBookmarkBarHeight;
-    [view animateToNewHeight:newHeight
+    [view animateToNewHeight:chrome::kNTPBookmarkBarHeight
                     duration:kBookmarkBarAnimationDuration];
   } else if ([self isAnimatingFromState:BookmarkBar::DETACHED
                                 toState:BookmarkBar::SHOW]) {
@@ -946,8 +945,6 @@
     case BookmarkBar::SHOW:
       return bookmarks::kBookmarkBarHeight;
     case BookmarkBar::DETACHED:
-      if (chrome::IsInstantExtendedAPIEnabled())
-        return bookmarks::kSearchNewTabBookmarkBarHeight;
       return chrome::kNTPBookmarkBarHeight;
     case BookmarkBar::HIDDEN:
       return 0;
@@ -1073,8 +1070,8 @@
   BookmarkButtonCell* cell = [self cellForBookmarkNode:node];
   NSRect frame = [self frameForBookmarkButtonFromCell:cell xOffset:xOffset];
 
-  scoped_nsobject<BookmarkButton>
-      button([[BookmarkButton alloc] initWithFrame:frame]);
+  base::scoped_nsobject<BookmarkButton> button(
+      [[BookmarkButton alloc] initWithFrame:frame]);
   DCHECK(button.get());
 
   // [NSButton setCell:] warns to NOT use setCell: other than in the
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 7769928..b654f44 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller_unittest.mm
@@ -6,13 +6,14 @@
 
 #include "base/basictypes.h"
 #include "base/command_line.h"
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "base/strings/string16.h"
 #include "base/strings/string_util.h"
 #include "base/strings/sys_string_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/bookmarks/bookmark_model.h"
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
+#include "chrome/browser/bookmarks/bookmark_model_test_utils.h"
 #include "chrome/browser/bookmarks/bookmark_utils.h"
 #include "chrome/browser/extensions/test_extension_system.h"
 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_constants.h"
@@ -26,12 +27,11 @@
 #import "chrome/browser/ui/cocoa/view_resizer_pong.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
-#include "chrome/test/base/model_test_utils.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #import "testing/gtest_mac.h"
 #include "testing/platform_test.h"
-#include "third_party/ocmock/gtest_support.h"
 #import "third_party/ocmock/OCMock/OCMock.h"
+#include "third_party/ocmock/gtest_support.h"
 #include "ui/base/cocoa/animation_utils.h"
 #include "ui/base/test/cocoa_test_event_utils.h"
 #include "ui/base/theme_provider.h"
@@ -204,7 +204,7 @@
 class FakeTheme : public ui::ThemeProvider {
  public:
   FakeTheme(NSColor* color) : color_(color) {}
-  scoped_nsobject<NSColor> color_;
+  base::scoped_nsobject<NSColor> color_;
 
   virtual gfx::ImageSkia* GetImageSkiaNamed(int id) const OVERRIDE {
     return NULL;
@@ -292,8 +292,8 @@
 
 class BookmarkBarControllerTestBase : public CocoaProfileTest {
  public:
-  scoped_nsobject<NSView> parent_view_;
-  scoped_nsobject<ViewResizerPong> resizeDelegate_;
+  base::scoped_nsobject<NSView> parent_view_;
+  base::scoped_nsobject<ViewResizerPong> resizeDelegate_;
 
   virtual void SetUp() {
     CocoaProfileTest::SetUp();
@@ -335,8 +335,8 @@
 
 class BookmarkBarControllerTest : public BookmarkBarControllerTestBase {
  public:
-  scoped_nsobject<NSButtonCell> cell_;
-  scoped_nsobject<BookmarkBarControllerNoOpen> bar_;
+  base::scoped_nsobject<NSButtonCell> cell_;
+  base::scoped_nsobject<BookmarkBarControllerNoOpen> bar_;
 
   virtual void SetUp() {
     BookmarkBarControllerTestBase::SetUp();
@@ -496,7 +496,7 @@
 
 // Make sure we're watching for frame change notifications.
 TEST_F(BookmarkBarControllerTest, FrameChangeNotification) {
-  scoped_nsobject<BookmarkBarControllerTogglePong> bar;
+  base::scoped_nsobject<BookmarkBarControllerTogglePong> bar;
   bar.reset(
     [[BookmarkBarControllerTogglePong alloc]
           initWithBrowser:browser()
@@ -731,9 +731,10 @@
   GURL gurl("http://walla.walla.ding.dong.com");
   scoped_ptr<BookmarkNode> node(new BookmarkNode(gurl));
 
-  scoped_nsobject<BookmarkButtonCell> cell([[BookmarkButtonCell alloc] init]);
+  base::scoped_nsobject<BookmarkButtonCell> cell(
+      [[BookmarkButtonCell alloc] init]);
   [cell setBookmarkNode:node.get()];
-  scoped_nsobject<BookmarkButton> button([[BookmarkButton alloc] init]);
+  base::scoped_nsobject<BookmarkButton> button([[BookmarkButton alloc] init]);
   [button setCell:cell.get()];
   [cell setRepresentedObject:[NSValue valueWithPointer:node.get()]];
 
@@ -830,7 +831,7 @@
 // Make sure that each button we add marches to the right and does not
 // overlap with the previous one.
 TEST_F(BookmarkBarControllerTest, TestButtonMarch) {
-  scoped_nsobject<NSMutableArray> cells([[NSMutableArray alloc] init]);
+  base::scoped_nsobject<NSMutableArray> cells([[NSMutableArray alloc] init]);
 
   CGFloat widths[] = { 10, 10, 100, 10, 500, 500, 80000, 60000, 1, 345 };
   for (unsigned int i = 0; i < arraysize(widths); i++) {
@@ -1168,7 +1169,7 @@
     bookmark_utils::AddIfNotBookmarked(model, gurls[i], titles[i]);
 
   // Get and retain the buttons so we can examine them after dealloc.
-  scoped_nsobject<NSArray> buttons([[bar_ buttons] retain]);
+  base::scoped_nsobject<NSArray> buttons([[bar_ buttons] retain]);
   EXPECT_EQ([buttons count], arraysize(titles));
 
   // Make sure that everything is set.
@@ -1238,10 +1239,11 @@
   BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
   const BookmarkNode* root = model->bookmark_bar_node();
   const std::string model_string("1b 2f:[ 2f1b 2f2b ] 3b 4f:[ 4f1b 4f2b ] ");
-  model_test_utils::AddNodesFromModelString(model, root, model_string);
+  BookmarkModelTestUtils::AddNodesFromModelString(model, root, model_string);
 
   // Validate initial model and that we do not have a folder controller.
-  std::string actualModelString = model_test_utils::ModelStringFromNode(root);
+  std::string actualModelString =
+      BookmarkModelTestUtils::ModelStringFromNode(root);
   EXPECT_EQ(model_string, actualModelString);
   EXPECT_FALSE([bar_ folderController]);
 
@@ -1452,10 +1454,11 @@
   BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
   const BookmarkNode* root = model->bookmark_bar_node();
   const std::string model_string("1b 2f:[ 2f1b 2f2b ] 3b ");
-  model_test_utils::AddNodesFromModelString(model, root, model_string);
+  BookmarkModelTestUtils::AddNodesFromModelString(model, root, model_string);
 
   // Validate initial model.
-  std::string actualModelString = model_test_utils::ModelStringFromNode(root);
+  std::string actualModelString =
+      BookmarkModelTestUtils::ModelStringFromNode(root);
   EXPECT_EQ(model_string, actualModelString);
 
   // Remember how many buttons are showing.
@@ -1525,7 +1528,7 @@
   BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
   const BookmarkNode* root = model->bookmark_bar_node();
   const std::string model_string("1b 2f:[ 2f1b 2f2b ] 3b ");
-  model_test_utils::AddNodesFromModelString(model, root, model_string);
+  BookmarkModelTestUtils::AddNodesFromModelString(model, root, model_string);
   [bar_ frameDidChange];
 
   CGFloat viewWidths[] = { 123.0, 124.0, 151.0, 152.0, 153.0, 154.0, 155.0,
@@ -1561,7 +1564,7 @@
   BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
   const BookmarkNode* root = model->bookmark_bar_node();
   const std::string model_string("1b 2f:[ 2f1b 2f2b ] 3b ");
-  model_test_utils::AddNodesFromModelString(model, root, model_string);
+  BookmarkModelTestUtils::AddNodesFromModelString(model, root, model_string);
   [bar_ frameDidChange];
 
   // Apps page shortcut button should be visible.
@@ -1702,9 +1705,9 @@
     // Do not add the bar to a window, yet.
   }
 
-  scoped_nsobject<NSView> parent_view_;
-  scoped_nsobject<ViewResizerPong> resizeDelegate_;
-  scoped_nsobject<BookmarkBarControllerNotificationPong> bar_;
+  base::scoped_nsobject<NSView> parent_view_;
+  base::scoped_nsobject<ViewResizerPong> resizeDelegate_;
+  base::scoped_nsobject<BookmarkBarControllerNotificationPong> bar_;
 };
 
 TEST_F(BookmarkBarControllerNotificationTest, DeregistersForNotifications) {
@@ -1740,7 +1743,7 @@
 
 class BookmarkBarControllerDragDropTest : public BookmarkBarControllerTestBase {
  public:
-  scoped_nsobject<BookmarkBarControllerDragData> bar_;
+  base::scoped_nsobject<BookmarkBarControllerDragData> bar_;
 
   virtual void SetUp() {
     BookmarkBarControllerTestBase::SetUp();
@@ -1765,10 +1768,11 @@
       "3bWithLongName 4bWithLongName 5bWithLongName 6bWithLongName "
       "7bWithLongName 8bWithLongName 9bWithLongName 10bWithLongName "
       "11bWithLongName 12bWithLongName 13b ");
-  model_test_utils::AddNodesFromModelString(model, root, model_string);
+  BookmarkModelTestUtils::AddNodesFromModelString(model, root, model_string);
 
   // Validate initial model.
-  std::string actualModelString = model_test_utils::ModelStringFromNode(root);
+  std::string actualModelString =
+      BookmarkModelTestUtils::ModelStringFromNode(root);
   EXPECT_EQ(model_string, actualModelString);
 
   // Insure that the off-the-side is not showing.
@@ -1817,16 +1821,18 @@
       "11bWithLongName 12bWithLongName 13bWithLongName 14bWithLongName "
       "15bWithLongName 16bWithLongName 17bWithLongName 18bWithLongName "
       "19bWithLongName 20bWithLongName ");
-  model_test_utils::AddNodesFromModelString(model, root, model_string);
+  BookmarkModelTestUtils::AddNodesFromModelString(model, root, model_string);
 
   const BookmarkNode* other = model->other_node();
   const std::string other_string("1other 2other 3other ");
-  model_test_utils::AddNodesFromModelString(model, other, other_string);
+  BookmarkModelTestUtils::AddNodesFromModelString(model, other, other_string);
 
   // Validate initial model.
-  std::string actualModelString = model_test_utils::ModelStringFromNode(root);
+  std::string actualModelString =
+      BookmarkModelTestUtils::ModelStringFromNode(root);
   EXPECT_EQ(model_string, actualModelString);
-  std::string actualOtherString = model_test_utils::ModelStringFromNode(other);
+  std::string actualOtherString =
+      BookmarkModelTestUtils::ModelStringFromNode(other);
   EXPECT_EQ(other_string, actualOtherString);
 
   // Insure that the off-the-side is showing.
@@ -1870,16 +1876,16 @@
   const BookmarkNode* root = model->bookmark_bar_node();
   const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b 2f2f3b ] "
                                   "2f3b ] 3b 4b ");
-  model_test_utils::AddNodesFromModelString(model, root, model_string);
+  BookmarkModelTestUtils::AddNodesFromModelString(model, root, model_string);
   const BookmarkNode* other = model->other_node();
   const std::string other_string("O1b O2b O3f:[ O3f1b O3f2f ] "
                                  "O4f:[ O4f1b O4f2f ] 05b ");
-  model_test_utils::AddNodesFromModelString(model, other, other_string);
+  BookmarkModelTestUtils::AddNodesFromModelString(model, other, other_string);
 
   // Validate initial model.
-  std::string actual = model_test_utils::ModelStringFromNode(root);
+  std::string actual = BookmarkModelTestUtils::ModelStringFromNode(root);
   EXPECT_EQ(model_string, actual);
-  actual = model_test_utils::ModelStringFromNode(other);
+  actual = BookmarkModelTestUtils::ModelStringFromNode(other);
   EXPECT_EQ(other_string, actual);
 
   // Remember the little ones.
@@ -1891,7 +1897,7 @@
   // Gen up some dragging data.
   const BookmarkNode* newNode = other->GetChild(2);
   [bar_ setDragDataNode:newNode];
-  scoped_nsobject<FakeDragInfo> dragInfo([[FakeDragInfo alloc] init]);
+  base::scoped_nsobject<FakeDragInfo> dragInfo([[FakeDragInfo alloc] init]);
   [dragInfo setDropLocation:[targetButton center]];
   [bar_ dragBookmarkData:(id<NSDraggingInfo>)dragInfo.get()];
 
@@ -1901,7 +1907,7 @@
   // Verify the model.
   const std::string expected("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b 2f2f3b ] "
                              "2f3b ] O3f:[ O3f1b O3f2f ] 3b 4b ");
-  actual = model_test_utils::ModelStringFromNode(root);
+  actual = BookmarkModelTestUtils::ModelStringFromNode(root);
   EXPECT_EQ(expected, actual);
   oldChildCount = newChildCount;
 
@@ -1921,7 +1927,7 @@
   const std::string expected1("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b 2f2f3b ] "
                               "2f3b O4f:[ O4f1b O4f2f ] ] O3f:[ O3f1b O3f2f ] "
                               "3b 4b ");
-  actual = model_test_utils::ModelStringFromNode(root);
+  actual = BookmarkModelTestUtils::ModelStringFromNode(root);
   EXPECT_EQ(expected1, actual);
 }
 
@@ -1930,10 +1936,10 @@
   const BookmarkNode* root = model->bookmark_bar_node();
   const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b 2f2f3b ] "
                                  "2f3b ] 3b 4b ");
-  model_test_utils::AddNodesFromModelString(model, root, model_string);
+  BookmarkModelTestUtils::AddNodesFromModelString(model, root, model_string);
 
   // Validate initial model.
-  std::string actual = model_test_utils::ModelStringFromNode(root);
+  std::string actual = BookmarkModelTestUtils::ModelStringFromNode(root);
   EXPECT_EQ(model_string, actual);
 
   // Remember the children.
@@ -1953,7 +1959,7 @@
   // Verify the model.
   const std::string expected("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b 2f2f3b ] "
                              "2f3b ] SiteA SiteB 3b 4b ");
-  actual = model_test_utils::ModelStringFromNode(root);
+  actual = BookmarkModelTestUtils::ModelStringFromNode(root);
   EXPECT_EQ(expected, actual);
 }
 
@@ -1961,10 +1967,11 @@
   BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
   const BookmarkNode* root = model->bookmark_bar_node();
   const std::string model_string("1b 2f:[ 2f1b 2f2b ] 3b ");
-  model_test_utils::AddNodesFromModelString(model, root, model_string);
+  BookmarkModelTestUtils::AddNodesFromModelString(model, root, model_string);
 
   // Validate initial model.
-  std::string actualModelString = model_test_utils::ModelStringFromNode(root);
+  std::string actualModelString =
+      BookmarkModelTestUtils::ModelStringFromNode(root);
   EXPECT_EQ(model_string, actualModelString);
 
   // Find the main bar controller.
@@ -1977,10 +1984,10 @@
   BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
   const BookmarkNode* root = model->bookmark_bar_node();
   const std::string model_string("1b 2f:[ 2f1b 2f2b 2f3b ] 3b 4b ");
-  model_test_utils::AddNodesFromModelString(model, root, model_string);
+  BookmarkModelTestUtils::AddNodesFromModelString(model, root, model_string);
 
   // Validate initial model.
-  std::string actualModel = model_test_utils::ModelStringFromNode(root);
+  std::string actualModel = BookmarkModelTestUtils::ModelStringFromNode(root);
   EXPECT_EQ(model_string, actualModel);
 
   // Test a series of points starting at the right edge of the bar.
@@ -2047,10 +2054,10 @@
   const BookmarkNode* root = model->bookmark_bar_node();
   const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b 2f2f3b ] "
                                   "2f3b ] 3b 4b ");
-  model_test_utils::AddNodesFromModelString(model, root, model_string);
+  BookmarkModelTestUtils::AddNodesFromModelString(model, root, model_string);
 
   // Validate initial model.
-  std::string actual = model_test_utils::ModelStringFromNode(root);
+  std::string actual = BookmarkModelTestUtils::ModelStringFromNode(root);
   EXPECT_EQ(model_string, actual);
 
   int oldChildCount = root->child_count();
@@ -2067,7 +2074,7 @@
   // Verify the model.
   const std::string expected("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b 2f2f3b ] "
                              "2f3b ] 4b ");
-  actual = model_test_utils::ModelStringFromNode(root);
+  actual = BookmarkModelTestUtils::ModelStringFromNode(root);
   EXPECT_EQ(expected, actual);
 
   // Verify that the other bookmark folder can't be deleted.
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_button_cell_unittest.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_button_cell_unittest.mm
index 3b1eb0a..7418039 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_button_cell_unittest.mm
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_button_cell_unittest.mm
@@ -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 "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_button_cell.h"
 #import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #include "grit/ui_resources.h"
@@ -15,7 +15,7 @@
 
 // Basic creation.
 TEST_F(BookmarkBarFolderButtonCellTest, Create) {
-  scoped_nsobject<BookmarkBarFolderButtonCell> cell;
+  base::scoped_nsobject<BookmarkBarFolderButtonCell> cell;
   cell.reset([[BookmarkBarFolderButtonCell buttonCellForNode:nil
                                                         text:nil
                                                        image:nil
@@ -25,21 +25,21 @@
 
 TEST_F(BookmarkBarFolderButtonCellTest, FaviconPositioning) {
   NSRect frame = NSMakeRect(0, 0, 50, 30);
-  scoped_nsobject<NSButton> view([[NSButton alloc] initWithFrame:frame]);
-  scoped_nsobject<NSButton> folder_view(
+  base::scoped_nsobject<NSButton> view([[NSButton alloc] initWithFrame:frame]);
+  base::scoped_nsobject<NSButton> folder_view(
       [[NSButton alloc] initWithFrame:frame]);
 
   ASSERT_TRUE(view.get());
   ASSERT_TRUE(folder_view.get());
 
   ResourceBundle& rb = ResourceBundle::GetSharedInstance();
-  scoped_nsobject<NSImage> image(
+  base::scoped_nsobject<NSImage> image(
       rb.GetNativeImageNamed(IDR_DEFAULT_FAVICON).CopyNSImage());
   ASSERT_TRUE(image.get());
 
-  scoped_nsobject<BookmarkButtonCell> cell(
+  base::scoped_nsobject<BookmarkButtonCell> cell(
       [[BookmarkButtonCell alloc] initTextCell:@"Testing"]);
-  scoped_nsobject<BookmarkBarFolderButtonCell> folder_cell(
+  base::scoped_nsobject<BookmarkBarFolderButtonCell> folder_cell(
       [[BookmarkBarFolderButtonCell buttonCellForNode:nil
                                                  text:@"Testing"
                                                 image:image
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_controller.h b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_controller.h
index 746552c..ec27fea 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_controller.h
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_controller.h
@@ -7,7 +7,7 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_button.h"
 #import "ui/base/cocoa/tracking_area.h"
 
@@ -27,7 +27,7 @@
                        BookmarkButtonControllerProtocol> {
  @private
   // The button whose click opened us.
-  scoped_nsobject<BookmarkButton> parentButton_;
+  base::scoped_nsobject<BookmarkButton> parentButton_;
 
   // Bookmark bar folder controller chains are torn down in two ways:
   // 1. Clicking "outside" the folder (see use of the NSEvent local event
@@ -57,13 +57,13 @@
 
   // Our parent controller, if we are a nested folder, otherwise nil.
   // Strong to insure the object lives as long as we need it.
-  scoped_nsobject<BookmarkBarFolderController> parentController_;
+  base::scoped_nsobject<BookmarkBarFolderController> parentController_;
 
   // The main bar controller from whence we or a parent sprang.
   BookmarkBarController* barController_;  // WEAK: It owns us.
 
   // Our buttons.  We do not have buttons for nested folders.
-  scoped_nsobject<NSMutableArray> buttons_;
+  base::scoped_nsobject<NSMutableArray> buttons_;
 
   // The scroll view that contains our main button view (below).
   IBOutlet NSScrollView* scrollView_;
@@ -102,10 +102,10 @@
   // We model hover state as a state machine with specific allowable
   // transitions.  |hoverState_| is the state of this machine at any
   // given time.
-  scoped_nsobject<BookmarkBarFolderHoverState> hoverState_;
+  base::scoped_nsobject<BookmarkBarFolderHoverState> hoverState_;
 
   // Logic for dealing with a click on a bookmark folder button.
-  scoped_nsobject<BookmarkFolderTarget> folderTarget_;
+  base::scoped_nsobject<BookmarkFolderTarget> folderTarget_;
 
   // A controller for a pop-up bookmark folder window (custom menu).
   // We (self) are the parentController_ for our folderController_.
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_controller_unittest.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_controller_unittest.mm
index 3999e7a..4ed276c 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_controller_unittest.mm
@@ -3,10 +3,11 @@
 // found in the LICENSE file.
 
 #include "base/basictypes.h"
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/bookmarks/bookmark_model.h"
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
+#include "chrome/browser/bookmarks/bookmark_model_test_utils.h"
 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_constants.h"
 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.h"
 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_button_cell.h"
@@ -15,7 +16,6 @@
 #include "chrome/browser/ui/cocoa/cocoa_profile_test.h"
 #import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #import "chrome/browser/ui/cocoa/view_resizer_pong.h"
-#include "chrome/test/base/model_test_utils.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #import "testing/gtest_mac.h"
 #include "testing/platform_test.h"
@@ -129,7 +129,7 @@
 
 class BookmarkBarFolderControllerTest : public CocoaProfileTest {
  public:
-  scoped_nsobject<BookmarkBarControllerChildFolderRedirect> bar_;
+  base::scoped_nsobject<BookmarkBarControllerChildFolderRedirect> bar_;
   const BookmarkNode* folderA_;  // Owned by model.
   const BookmarkNode* longTitleNode_;  // Owned by model.
 
@@ -217,7 +217,7 @@
 };
 
 TEST_F(BookmarkBarFolderControllerTest, InitCreateAndDelete) {
-  scoped_nsobject<BookmarkBarFolderController> bbfc;
+  base::scoped_nsobject<BookmarkBarFolderController> bbfc;
   bbfc.reset(SimpleBookmarkBarFolderController());
 
   // Make sure none of the buttons overlap, that all are inside
@@ -251,7 +251,7 @@
 // Make sure closing of the window releases the controller.
 // (e.g. valgrind shouldn't complain if we do this).
 TEST_F(BookmarkBarFolderControllerTest, ReleaseOnClose) {
-  scoped_nsobject<BookmarkBarFolderController> bbfc;
+  base::scoped_nsobject<BookmarkBarFolderController> bbfc;
   bbfc.reset(SimpleBookmarkBarFolderController());
   EXPECT_TRUE(bbfc.get());
 
@@ -264,7 +264,7 @@
   EXPECT_TRUE(parentButton);
 
   // If parent is a BookmarkBarController, grow down.
-  scoped_nsobject<BookmarkBarFolderController> bbfc;
+  base::scoped_nsobject<BookmarkBarFolderController> bbfc;
   bbfc.reset([[BookmarkBarFolderController alloc]
                initWithParentButton:parentButton
                    parentController:nil
@@ -289,7 +289,7 @@
   EXPECT_LT(shifted.x, pt.x);
 
   // If parent is a BookmarkBarFolderController, grow right.
-  scoped_nsobject<BookmarkBarFolderController> bbfc2;
+  base::scoped_nsobject<BookmarkBarFolderController> bbfc2;
   bbfc2.reset([[BookmarkBarFolderController alloc]
                 initWithParentButton:[[bbfc buttons] objectAtIndex:0]
                     parentController:bbfc.get()
@@ -323,7 +323,7 @@
   EXPECT_TRUE(parentButton);
 
   // Open them all.
-  scoped_nsobject<NSMutableArray> folder_controller_array;
+  base::scoped_nsobject<NSMutableArray> folder_controller_array;
   folder_controller_array.reset([[NSMutableArray array] retain]);
   for (i=0; i<count; i++) {
     BookmarkBarFolderControllerNoLevel* bbfcl =
@@ -368,7 +368,7 @@
 }
 
 TEST_F(BookmarkBarFolderControllerTest, DropDestination) {
-  scoped_nsobject<BookmarkBarFolderController> bbfc;
+  base::scoped_nsobject<BookmarkBarFolderController> bbfc;
   bbfc.reset(SimpleBookmarkBarFolderController());
   EXPECT_TRUE(bbfc.get());
 
@@ -404,7 +404,7 @@
 }
 
 TEST_F(BookmarkBarFolderControllerTest, OpenFolder) {
-  scoped_nsobject<BookmarkBarFolderController> bbfc;
+  base::scoped_nsobject<BookmarkBarFolderController> bbfc;
   bbfc.reset(SimpleBookmarkBarFolderController());
   EXPECT_TRUE(bbfc.get());
 
@@ -430,7 +430,7 @@
 }
 
 TEST_F(BookmarkBarFolderControllerTest, DeleteOpenFolder) {
-  scoped_nsobject<BookmarkBarFolderController> parent_controller(
+  base::scoped_nsobject<BookmarkBarFolderController> parent_controller(
       SimpleBookmarkBarFolderController());
 
   // Open a folder.
@@ -445,7 +445,7 @@
 }
 
 TEST_F(BookmarkBarFolderControllerTest, ChildFolderCallbacks) {
-  scoped_nsobject<BookmarkBarFolderControllerPong> bbfc;
+  base::scoped_nsobject<BookmarkBarFolderControllerPong> bbfc;
   bbfc.reset(SimpleBookmarkBarFolderController());
   EXPECT_TRUE(bbfc.get());
   [bar_ setChildFolderDelegate:bbfc.get()];
@@ -463,7 +463,7 @@
 
 // Make sure bookmark folders have variable widths.
 TEST_F(BookmarkBarFolderControllerTest, ChildFolderWidth) {
-  scoped_nsobject<BookmarkBarFolderController> bbfc;
+  base::scoped_nsobject<BookmarkBarFolderController> bbfc;
 
   bbfc.reset(SimpleBookmarkBarFolderController());
   EXPECT_TRUE(bbfc.get());
@@ -482,7 +482,7 @@
 // Simple scrolling tests.
 // Currently flaky due to a changed definition of the correct menu boundaries.
 TEST_F(BookmarkBarFolderControllerTest, DISABLED_SimpleScroll) {
-  scoped_nsobject<BookmarkBarFolderController> bbfc;
+  base::scoped_nsobject<BookmarkBarFolderController> bbfc;
   NSRect screenFrame = [[NSScreen mainScreen] visibleFrame];
   CGFloat screenHeight = NSHeight(screenFrame);
   int nodecount = AddLotsOfNodes();
@@ -572,7 +572,7 @@
 // Folder menu sizing and placement while deleting bookmarks
 // and scrolling tests.
 TEST_F(BookmarkBarFolderControllerTest, MenuPlacementWhileScrollingDeleting) {
-  scoped_nsobject<BookmarkBarFolderController> bbfc;
+  base::scoped_nsobject<BookmarkBarFolderController> bbfc;
   AddLotsOfNodes();
   bbfc.reset(SimpleBookmarkBarFolderController());
   [bbfc showWindow:bbfc.get()];
@@ -625,7 +625,7 @@
 
 // Make sure that we return the correct browser window.
 TEST_F(BookmarkBarFolderControllerTest, BrowserWindow) {
-  scoped_nsobject<BookmarkBarFolderController> controller(
+  base::scoped_nsobject<BookmarkBarFolderController> controller(
       SimpleBookmarkBarFolderController());
   EXPECT_EQ([bar_ browserWindow], [controller browserWindow]);
 }
@@ -680,9 +680,9 @@
 
 class BookmarkBarFolderControllerMenuTest : public CocoaProfileTest {
  public:
-  scoped_nsobject<NSView> parent_view_;
-  scoped_nsobject<ViewResizerPong> resizeDelegate_;
-  scoped_nsobject<BookmarkBarController> bar_;
+  base::scoped_nsobject<NSView> parent_view_;
+  base::scoped_nsobject<ViewResizerPong> resizeDelegate_;
+  base::scoped_nsobject<BookmarkBarController> bar_;
 
   virtual void SetUp() {
     CocoaProfileTest::SetUp();
@@ -725,10 +725,11 @@
   const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b "
       "2f2f3b ] 2f3b ] 3b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f:[ 4f2f1b "
       "4f2f2b 4f2f3b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b ");
-  model_test_utils::AddNodesFromModelString(model, root, model_string);
+  BookmarkModelTestUtils::AddNodesFromModelString(model, root, model_string);
 
   // Validate initial model.
-  std::string actualModelString = model_test_utils::ModelStringFromNode(root);
+  std::string actualModelString =
+      BookmarkModelTestUtils::ModelStringFromNode(root);
   EXPECT_EQ(model_string, actualModelString);
 
   // Pop up a folder menu and drag in a button from the bar.
@@ -757,7 +758,7 @@
   const std::string expected_string("2f:[ 2f1b 1b 2f2f:[ 2f2f1b "
       "2f2f2b 2f2f3b ] 2f3b ] 3b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f:[ "
       "4f2f1b 4f2f2b 4f2f3b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b ");
-  EXPECT_EQ(expected_string, model_test_utils::ModelStringFromNode(root));
+  EXPECT_EQ(expected_string, BookmarkModelTestUtils::ModelStringFromNode(root));
 
   // Verify the window still appears by looking for its controller.
   EXPECT_TRUE([bar_ folderController]);
@@ -788,7 +789,7 @@
   [bar_ dragButton:draggedButton
                 to:[targetButton left]
               copy:NO];
-  EXPECT_EQ(model_string, model_test_utils::ModelStringFromNode(root));
+  EXPECT_EQ(model_string, BookmarkModelTestUtils::ModelStringFromNode(root));
   // Don't check the folder window since it's not supposed to be showing.
 }
 
@@ -798,10 +799,11 @@
   const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b "
       "2f2f3b ] 2f3b ] 3b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f:[ 4f2f1b "
       "4f2f2b 4f2f3b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b ");
-  model_test_utils::AddNodesFromModelString(model, root, model_string);
+  BookmarkModelTestUtils::AddNodesFromModelString(model, root, model_string);
 
   // Validate initial model.
-  std::string actualModelString = model_test_utils::ModelStringFromNode(root);
+  std::string actualModelString =
+      BookmarkModelTestUtils::ModelStringFromNode(root);
   EXPECT_EQ(model_string, actualModelString);
 
   // Pop up a folder menu and copy in a button from the bar.
@@ -829,7 +831,7 @@
   const std::string expected_1("1b 2f:[ 2f1b 1b 2f2f:[ 2f2f1b "
     "2f2f2b 2f2f3b ] 2f3b ] 3b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f:[ "
     "4f2f1b 4f2f2b 4f2f3b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b ");
-  EXPECT_EQ(expected_1, model_test_utils::ModelStringFromNode(root));
+  EXPECT_EQ(expected_1, BookmarkModelTestUtils::ModelStringFromNode(root));
 
   // Gather the new frames.
   NSRect newToFolderFrame = [toFolder frame];
@@ -853,7 +855,7 @@
   const std::string expected_2("1b 2f:[ 2f1b 1b 2f2f:[ 2f2f1b "
       "2f2f2b 2f2f3b ] 2f3b ] 3b 1b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f:[ "
       "4f2f1b 4f2f2b 4f2f3b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b ");
-  EXPECT_EQ(expected_2, model_test_utils::ModelStringFromNode(root));
+  EXPECT_EQ(expected_2, BookmarkModelTestUtils::ModelStringFromNode(root));
 }
 
 TEST_F(BookmarkBarFolderControllerMenuTest, DragMoveBarBookmarkToSubfolder) {
@@ -862,10 +864,11 @@
   const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b "
       "2f2f3b ] 2f3b ] 3b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f:[ 4f2f1b "
       "4f2f2b 4f2f3b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b ");
-  model_test_utils::AddNodesFromModelString(model, root, model_string);
+  BookmarkModelTestUtils::AddNodesFromModelString(model, root, model_string);
 
   // Validate initial model.
-  std::string actualModelString = model_test_utils::ModelStringFromNode(root);
+  std::string actualModelString =
+      BookmarkModelTestUtils::ModelStringFromNode(root);
   EXPECT_EQ(model_string, actualModelString);
 
   // Pop up a folder menu and a subfolder menu.
@@ -903,7 +906,7 @@
   const std::string expected_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b "
       "2f2f2b 2f2f3b ] 2f3b ] 3b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f:[ "
       "4f2f1b 4f2f2b 4f2f3b 5b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] ");
-  EXPECT_EQ(expected_string, model_test_utils::ModelStringFromNode(root));
+  EXPECT_EQ(expected_string, BookmarkModelTestUtils::ModelStringFromNode(root));
 
   // Check button spacing.
   [folderController validateMenuSpacing];
@@ -927,10 +930,11 @@
   const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b "
       "2f2f3b ] 2f3b ] 3b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f:[ 4f2f1b "
       "4f2f2b 4f2f3b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b ");
-  model_test_utils::AddNodesFromModelString(model, root, model_string);
+  BookmarkModelTestUtils::AddNodesFromModelString(model, root, model_string);
 
   // Validate initial model.
-  std::string actualModelString = model_test_utils::ModelStringFromNode(root);
+  std::string actualModelString =
+      BookmarkModelTestUtils::ModelStringFromNode(root);
   EXPECT_EQ(model_string, actualModelString);
 
   // Pop up a folder menu.
@@ -957,7 +961,7 @@
   const std::string expected_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b "
       "2f2f2b 2f2f3b ] 2f3b ] 3b 4f:[ 4f2f:[ 4f2f1b 4f2f2b 4f2f3b ] "
       "4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b ");
-  EXPECT_EQ(expected_string, model_test_utils::ModelStringFromNode(root));
+  EXPECT_EQ(expected_string, BookmarkModelTestUtils::ModelStringFromNode(root));
 
   // The window should not have gone away.
   EXPECT_TRUE([bar_ folderController]);
@@ -976,10 +980,11 @@
   const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b "
       "2f2f3b ] 2f3b ] 3b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f:[ 4f2f1b "
       "4f2f2b 4f2f3b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b ");
-  model_test_utils::AddNodesFromModelString(model, root, model_string);
+  BookmarkModelTestUtils::AddNodesFromModelString(model, root, model_string);
 
   // Validate initial model.
-  std::string actualModelString = model_test_utils::ModelStringFromNode(root);
+  std::string actualModelString =
+      BookmarkModelTestUtils::ModelStringFromNode(root);
   EXPECT_EQ(model_string, actualModelString);
 
   // Pop up a folder menu.
@@ -1001,7 +1006,7 @@
                             to:[targetButton top]
                           copy:NO];
   // The model should not have changed.
-  EXPECT_EQ(model_string, model_test_utils::ModelStringFromNode(root));
+  EXPECT_EQ(model_string, BookmarkModelTestUtils::ModelStringFromNode(root));
 
   // Check button spacing.
   [folderController validateMenuSpacing];
@@ -1013,10 +1018,11 @@
   const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b "
       "2f2f3b ] 2f3b ] 3b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f:[ 4f2f1b "
       "4f2f2b 4f2f3b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b ");
-  model_test_utils::AddNodesFromModelString(model, root, model_string);
+  BookmarkModelTestUtils::AddNodesFromModelString(model, root, model_string);
 
   // Validate initial model.
-  std::string actualModelString = model_test_utils::ModelStringFromNode(root);
+  std::string actualModelString =
+      BookmarkModelTestUtils::ModelStringFromNode(root);
   EXPECT_EQ(model_string, actualModelString);
 
   // Pop up a folder menu and a subfolder menu.
@@ -1049,7 +1055,7 @@
   const std::string expected_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b "
       "2f2f3b ] 2f3b ] 3b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f3b 4f2f:[ "
       "4f2f1b 4f2f2b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b ");
-  EXPECT_EQ(expected_string, model_test_utils::ModelStringFromNode(root));
+  EXPECT_EQ(expected_string, BookmarkModelTestUtils::ModelStringFromNode(root));
 
   // Check button spacing.
   [folderController validateMenuSpacing];
@@ -1064,10 +1070,11 @@
   const BookmarkNode* root = model->bookmark_bar_node();
   const std::string
       model_string("a b:[ b1 b2 b3 ] reallyReallyLongBookmarkName c ");
-  model_test_utils::AddNodesFromModelString(model, root, model_string);
+  BookmarkModelTestUtils::AddNodesFromModelString(model, root, model_string);
 
   // Validate initial model.
-  std::string actualModelString = model_test_utils::ModelStringFromNode(root);
+  std::string actualModelString =
+      BookmarkModelTestUtils::ModelStringFromNode(root);
   EXPECT_EQ(model_string, actualModelString);
 
   // Pop up a folder menu.
@@ -1093,7 +1100,7 @@
   // Verify the model change.
   const std::string
       expected_string("a b:[ b1 reallyReallyLongBookmarkName b2 b3 ] c ");
-  EXPECT_EQ(expected_string, model_test_utils::ModelStringFromNode(root));
+  EXPECT_EQ(expected_string, BookmarkModelTestUtils::ModelStringFromNode(root));
   // Verify the window grew. Just test a reasonable width gain.
   CGFloat newWidth = NSWidth([toWindow frame]);
   EXPECT_LT(oldWidth + 30.0, newWidth);
@@ -1103,10 +1110,11 @@
   BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
   const BookmarkNode* root = model->bookmark_bar_node();
   const std::string model_string("1b 2f:[ 2f1b 2f2b 2f3b ] 3b 4b ");
-  model_test_utils::AddNodesFromModelString(model, root, model_string);
+  BookmarkModelTestUtils::AddNodesFromModelString(model, root, model_string);
 
   // Validate initial model.
-  std::string actualModelString = model_test_utils::ModelStringFromNode(root);
+  std::string actualModelString =
+      BookmarkModelTestUtils::ModelStringFromNode(root);
   EXPECT_EQ(model_string, actualModelString);
 
   // Pop up a folder menu.
@@ -1166,10 +1174,11 @@
   BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
   const BookmarkNode* root = model->bookmark_bar_node();
   const std::string model_string("1b 2f:[ 2f1b 2f2b ] 3b ");
-  model_test_utils::AddNodesFromModelString(model, root, model_string);
+  BookmarkModelTestUtils::AddNodesFromModelString(model, root, model_string);
 
   // Validate initial model.
-  std::string actualModelString = model_test_utils::ModelStringFromNode(root);
+  std::string actualModelString =
+      BookmarkModelTestUtils::ModelStringFromNode(root);
   EXPECT_EQ(model_string, actualModelString);
 
   // Find the main bar controller.
@@ -1201,10 +1210,11 @@
   BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
   const BookmarkNode* root = model->bookmark_bar_node();
   const std::string model_string("1b 2b 3b ");
-  model_test_utils::AddNodesFromModelString(model, root, model_string);
+  BookmarkModelTestUtils::AddNodesFromModelString(model, root, model_string);
 
   // Validate initial model.
-  std::string actualModelString = model_test_utils::ModelStringFromNode(root);
+  std::string actualModelString =
+      BookmarkModelTestUtils::ModelStringFromNode(root);
   EXPECT_EQ(model_string, actualModelString);
 
   const BookmarkNode* parent = model->bookmark_bar_node();
@@ -1365,21 +1375,21 @@
   const BookmarkNode* root = model->bookmark_bar_node();
   const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b 2f2f3b ] "
                                  "2f3b ] 3b 4b ");
-  model_test_utils::AddNodesFromModelString(model, root, model_string);
+  BookmarkModelTestUtils::AddNodesFromModelString(model, root, model_string);
   const BookmarkNode* other = model->other_node();
   const std::string other_string("O1b O2b O3f:[ O3f1b O3f2f ] "
                                  "O4f:[ O4f1b O4f2f ] 05b ");
-  model_test_utils::AddNodesFromModelString(model, other, other_string);
+  BookmarkModelTestUtils::AddNodesFromModelString(model, other, other_string);
 
   // Validate initial model.
-  std::string actual = model_test_utils::ModelStringFromNode(root);
+  std::string actual = BookmarkModelTestUtils::ModelStringFromNode(root);
   EXPECT_EQ(model_string, actual);
-  actual = model_test_utils::ModelStringFromNode(other);
+  actual = BookmarkModelTestUtils::ModelStringFromNode(other);
   EXPECT_EQ(other_string, actual);
 
   // Pop open a folder.
   BookmarkButton* button = [bar_ buttonWithTitleEqualTo:@"2f"];
-  scoped_nsobject<BookmarkBarFolderControllerDragData> folderController;
+  base::scoped_nsobject<BookmarkBarFolderControllerDragData> folderController;
   folderController.reset([[BookmarkBarFolderControllerDragData alloc]
                           initWithParentButton:button
                               parentController:nil
@@ -1392,14 +1402,14 @@
   // Gen up some dragging data.
   const BookmarkNode* newNode = other->GetChild(2);
   [folderController setDragDataNode:newNode];
-  scoped_nsobject<FakedDragInfo> dragInfo([[FakedDragInfo alloc] init]);
+  base::scoped_nsobject<FakedDragInfo> dragInfo([[FakedDragInfo alloc] init]);
   [dragInfo setDropLocation:[targetButton top]];
   [folderController dragBookmarkData:(id<NSDraggingInfo>)dragInfo.get()];
 
   // Verify the model.
   const std::string expected("1b 2f:[ O3f:[ O3f1b O3f2f ] 2f1b 2f2f:[ 2f2f1b "
                              "2f2f2b 2f2f3b ] 2f3b ] 3b 4b ");
-  actual = model_test_utils::ModelStringFromNode(root);
+  actual = BookmarkModelTestUtils::ModelStringFromNode(root);
   EXPECT_EQ(expected, actual);
 
   // Now drag over a folder button.
@@ -1415,7 +1425,7 @@
   const std::string expectedA("1b 2f:[ O3f:[ O3f1b O3f2f ] 2f1b 2f2f:[ "
                               "2f2f1b 2f2f2b 2f2f3b O4f:[ O4f1b O4f2f ] ] "
                               "2f3b ] 3b 4b ");
-  actual = model_test_utils::ModelStringFromNode(root);
+  actual = BookmarkModelTestUtils::ModelStringFromNode(root);
   EXPECT_EQ(expectedA, actual);
 
   // Check button spacing.
@@ -1427,10 +1437,10 @@
   const BookmarkNode* root = model->bookmark_bar_node();
   const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b 2f2f3b ] "
                                  "2f3b ] 3b 4b ");
-  model_test_utils::AddNodesFromModelString(model, root, model_string);
+  BookmarkModelTestUtils::AddNodesFromModelString(model, root, model_string);
 
   // Validate initial model.
-  std::string actual = model_test_utils::ModelStringFromNode(root);
+  std::string actual = BookmarkModelTestUtils::ModelStringFromNode(root);
   EXPECT_EQ(model_string, actual);
 
   const BookmarkNode* folderNode = root->GetChild(1);
@@ -1438,7 +1448,7 @@
 
   // Pop open a folder.
   BookmarkButton* button = [bar_ buttonWithTitleEqualTo:@"2f"];
-  scoped_nsobject<BookmarkBarFolderControllerDragData> folderController;
+  base::scoped_nsobject<BookmarkBarFolderControllerDragData> folderController;
   folderController.reset([[BookmarkBarFolderControllerDragData alloc]
                           initWithParentButton:button
                               parentController:nil
@@ -1458,7 +1468,7 @@
   // Verify the model.
   const std::string expected("1b 2f:[ 2f2f:[ 2f2f1b 2f2f2b 2f2f3b ] "
                              "2f3b ] 3b 4b ");
-  actual = model_test_utils::ModelStringFromNode(root);
+  actual = BookmarkModelTestUtils::ModelStringFromNode(root);
   EXPECT_EQ(expected, actual);
 
   // Check button spacing.
@@ -1470,10 +1480,10 @@
   const BookmarkNode* root = model->bookmark_bar_node();
   const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b 2f2f3b ] "
                                  "2f3b ] 3b 4b ");
-  model_test_utils::AddNodesFromModelString(model, root, model_string);
+  BookmarkModelTestUtils::AddNodesFromModelString(model, root, model_string);
 
   // Validate initial model.
-  std::string actual = model_test_utils::ModelStringFromNode(root);
+  std::string actual = BookmarkModelTestUtils::ModelStringFromNode(root);
   EXPECT_EQ(model_string, actual);
 
   // Pop open a folder.
@@ -1503,7 +1513,7 @@
   // Verify the model.
   const std::string expected("1b 2f:[ SiteA SiteB 2f1b 2f2f:[ 2f2f1b 2f2f2b "
                              "2f2f3b ] 2f3b ] 3b 4b ");
-  actual = model_test_utils::ModelStringFromNode(root);
+  actual = BookmarkModelTestUtils::ModelStringFromNode(root);
   EXPECT_EQ(expected, actual);
 
   // Check button spacing.
@@ -1515,10 +1525,10 @@
   const BookmarkNode* root = model->bookmark_bar_node();
   const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b 2f2f3b ] "
                                  "2f3b ] 3b 4b ");
-  model_test_utils::AddNodesFromModelString(model, root, model_string);
+  BookmarkModelTestUtils::AddNodesFromModelString(model, root, model_string);
 
   // Validate initial model.
-  std::string actual = model_test_utils::ModelStringFromNode(root);
+  std::string actual = BookmarkModelTestUtils::ModelStringFromNode(root);
   EXPECT_EQ(model_string, actual);
 
   // Pop open the folder.
@@ -1574,10 +1584,11 @@
   const BookmarkNode* root = model->bookmark_bar_node();
   const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b ] "
                                  "2f3b ] 3b ");
-  model_test_utils::AddNodesFromModelString(model, root, model_string);
+  BookmarkModelTestUtils::AddNodesFromModelString(model, root, model_string);
 
   // Validate initial model.
-  std::string actualModelString = model_test_utils::ModelStringFromNode(root);
+  std::string actualModelString =
+      BookmarkModelTestUtils::ModelStringFromNode(root);
   EXPECT_EQ(model_string, actualModelString);
 
   // Open the folder menu and submenu.
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_hover_state.h b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_hover_state.h
index 20ea39e..8d8dea7 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_hover_state.h
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_hover_state.h
@@ -4,7 +4,7 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_button.h"
 
 // Hover state machine.  Encapsulates the hover state for
@@ -39,7 +39,7 @@
   // Like normal menus, hovering over a folder button causes it to
   // open.  This variable is set when a hover is initiated (but has
   // not necessarily fired yet).
-  scoped_nsobject<BookmarkButton> hoverButton_;
+  base::scoped_nsobject<BookmarkButton> hoverButton_;
 
   // We model hover state as a state machine with specific allowable
   // transitions.  |hoverState_| is the state of this machine at any
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_hover_state_unittest.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_hover_state_unittest.mm
index bb39d7d..7c441be 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_hover_state_unittest.mm
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_hover_state_unittest.mm
@@ -19,14 +19,14 @@
 // these specific state transitions.
 TEST_F(BookmarkBarFolderHoverStateTest, HoverState) {
   base::MessageLoopForUI message_loop;
-  scoped_nsobject<BookmarkBarFolderHoverState> bbfhs;
+  base::scoped_nsobject<BookmarkBarFolderHoverState> bbfhs;
   bbfhs.reset([[BookmarkBarFolderHoverState alloc] init]);
 
   // Initial state.
   EXPECT_FALSE([bbfhs hoverButton]);
   ASSERT_EQ(kHoverStateClosed, [bbfhs hoverState]);
 
-  scoped_nsobject<BookmarkButton> button;
+  base::scoped_nsobject<BookmarkButton> button;
   button.reset([[BookmarkButton alloc] initWithFrame:NSMakeRect(0, 0, 20, 20)]);
 
   // Test transition from closed to opening.
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_view_unittest.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_view_unittest.mm
index 0550eab..b48b86a 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_view_unittest.mm
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_view_unittest.mm
@@ -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 "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "base/strings/string16.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/bookmarks/bookmark_model.h"
@@ -133,9 +133,9 @@
     return [mock_button retain];
   }
 
-  scoped_nsobject<id> mock_controller_;
-  scoped_nsobject<BookmarkBarFolderView> view_;
-  scoped_nsobject<id> mock_button_;
+  base::scoped_nsobject<id> mock_controller_;
+  base::scoped_nsobject<BookmarkBarFolderView> view_;
+  base::scoped_nsobject<id> mock_button_;
 };
 
 TEST_F(BookmarkBarFolderViewTest, BookmarkButtonDragAndDrop) {
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_window.h b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_window.h
index 21115db..513512f 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_window.h
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_window.h
@@ -6,8 +6,6 @@
 #define CHROME_BROWSER_UI_COCOA_BOOKMARKS_BOOKMARK_BAR_FOLDER_WINDOW_H_
 
 #import <Cocoa/Cocoa.h>
-#include "base/memory/scoped_nsobject.h"
-
 
 // Window for a bookmark folder "menu".  This menu pops up when you
 // click on a bookmark button that represents a folder of bookmarks.
@@ -27,5 +25,4 @@
 @interface BookmarkBarFolderWindowScrollView : NSScrollView
 @end
 
-
 #endif  // CHROME_BROWSER_UI_COCOA_BOOKMARKS_BOOKMARK_BAR_FOLDER_WINDOW_H_
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_window.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_window.mm
index 06a6112..3d6a25b 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_window.mm
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_window.mm
@@ -5,11 +5,11 @@
 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_window.h"
 
 #import "base/logging.h"
-#import "base/memory/scoped_nsobject.h"
+#import "base/mac/scoped_nsobject.h"
 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_constants.h"
 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_controller.h"
-#import "third_party/GTM/AppKit/GTMNSColor+Luminance.h"
 #import "third_party/GTM/AppKit/GTMNSBezierPath+RoundRect.h"
+#import "third_party/GTM/AppKit/GTMNSColor+Luminance.h"
 
 using bookmarks::kBookmarkBarMenuCornerRadius;
 
@@ -60,13 +60,13 @@
   NSColor* endColor =
       [startColor gtm_colorAdjustedFor:GTMColorationLightPenumbra faded:YES];
 
-  scoped_nsobject<NSGradient> gradient(
-    [[NSGradient alloc] initWithColorsAndLocations:startColor, 0.0,
-                        midColor, 0.25,
-                        endColor, 0.5,
-                        midColor, 0.75,
-                        startColor, 1.0,
-                        nil]);
+  base::scoped_nsobject<NSGradient> gradient(
+      [[NSGradient alloc] initWithColorsAndLocations:startColor, 0.0,
+                                                     midColor, 0.25,
+                                                     endColor, 0.5,
+                                                     midColor, 0.75,
+                                                     startColor, 1.0,
+                                                     nil]);
   [gradient drawInBezierPath:bezier angle:0.0];
 }
 
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_window_unittest.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_window_unittest.mm
index d1d1005..2701dd6 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_window_unittest.mm
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_window_unittest.mm
@@ -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 "base/memory/scoped_ptr.h"
+#include "base/mac/scoped_nsobject.h"
 #include "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_window.h"
 #include "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -12,7 +12,7 @@
 };
 
 TEST_F(BookmarkBarFolderWindowTest, Borderless) {
-  scoped_nsobject<BookmarkBarFolderWindow> window_;
+  base::scoped_nsobject<BookmarkBarFolderWindow> window_;
   window_.reset([[BookmarkBarFolderWindow alloc]
                   initWithContentRect:NSMakeRect(0,0,20,20)
                             styleMask:0
@@ -29,8 +29,8 @@
                   initWithFrame:NSMakeRect(0, 0, 100, 100)]);
     [[test_window() contentView] addSubview:view_.get()];
   }
-  scoped_nsobject<BookmarkBarFolderWindowContentView> view_;
-  scoped_nsobject<BookmarkBarFolderWindowScrollView> scroll_view_;
+  base::scoped_nsobject<BookmarkBarFolderWindowContentView> view_;
+  base::scoped_nsobject<BookmarkBarFolderWindowScrollView> scroll_view_;
 };
 
 TEST_VIEW(BookmarkBarFolderWindowContentViewTest, view_);
@@ -43,7 +43,7 @@
                   initWithFrame:NSMakeRect(0, 0, 100, 100)]);
     [[test_window() contentView] addSubview:scroll_view_.get()];
   }
-  scoped_nsobject<BookmarkBarFolderWindowScrollView> scroll_view_;
+  base::scoped_nsobject<BookmarkBarFolderWindowScrollView> scroll_view_;
 };
 
 TEST_VIEW(BookmarkBarFolderWindowScrollViewTest, scroll_view_);
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_toolbar_view.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_toolbar_view.mm
index 7c58eaa..096e376 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_toolbar_view.mm
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_toolbar_view.mm
@@ -26,7 +26,6 @@
 
 @interface BookmarkBarToolbarView (Private)
 - (void)drawAsDetachedBubble;
-- (void)drawAsDetachedInstantExtendedUI;
 @end
 
 @implementation BookmarkBarToolbarView
@@ -45,10 +44,7 @@
   if ([controller_ isInState:BookmarkBar::DETACHED] ||
       [controller_ isAnimatingToState:BookmarkBar::DETACHED] ||
       [controller_ isAnimatingFromState:BookmarkBar::DETACHED]) {
-    if (chrome::IsInstantExtendedAPIEnabled())
-      [self drawAsDetachedInstantExtendedUI];
-    else
-      [self drawAsDetachedBubble];
+    [self drawAsDetachedBubble];
   } else {
     NSPoint phase = [[self window] themePatternPhase];
     [[NSGraphicsContext currentContext] cr_setPatternPhase:phase forView:self];
@@ -57,98 +53,6 @@
 }
 
 - (void)drawAsDetachedBubble {
-  // The state of our morph; 1 is total bubble, 0 is the regular bar. We use it
-  // to morph the bubble to a regular bar (shape and colour).
-  CGFloat morph = [controller_ detachedMorphProgress];
-
-  NSRect bounds = [self bounds];
-
-  ThemeService* themeService = [controller_ themeService];
-  if (!themeService)
-    return;
-
-  gfx::ScopedNSGraphicsContextSaveGState scopedGState;
-
-  // Draw the background.
-  {
-    // CanvasSkiaPaint draws to the NSGraphicsContext during its destructor, so
-    // explicitly scope this.
-    //
-    // Paint the entire bookmark bar, even if the damage rect is much smaller
-    // because PaintBackgroundDetachedMode() assumes that area's origin is
-    // (0, 0) and that its size is the size of the bookmark bar.
-    //
-    // In practice, this sounds worse than it is because redraw time is still
-    // minimal compared to the pause between frames of animations. We were
-    // already repainting the rest of the bookmark bar below without setting a
-    // clip area, anyway. Also, the only time we weren't asked to redraw the
-    // whole bookmark bar is when the find bar is drawn over it.
-    gfx::CanvasSkiaPaint canvas(bounds, true);
-    gfx::Rect area(0, 0, NSWidth(bounds), NSHeight(bounds));
-
-    NtpBackgroundUtil::PaintBackgroundDetachedMode(themeService, &canvas,
-        area, [controller_ currentTabContentsHeight]);
-  }
-
-  // Draw our bookmark bar border on top of the background.
-  NSRect frameRect =
-      NSMakeRect(
-          morph * bookmarks::kNTPBookmarkBarPadding,
-          morph * bookmarks::kNTPBookmarkBarPadding,
-          NSWidth(bounds) - 2 * morph * bookmarks::kNTPBookmarkBarPadding,
-          NSHeight(bounds) - 2 * morph * bookmarks::kNTPBookmarkBarPadding);
-  // Now draw a bezier path with rounded rectangles around the area.
-  frameRect = NSInsetRect(frameRect, morph * 0.5, morph * 0.5);
-  NSBezierPath* border =
-      [NSBezierPath bezierPathWithRoundedRect:frameRect
-                                      xRadius:(morph * kBorderRadius)
-                                      yRadius:(morph * kBorderRadius)];
-
-  // Draw the rounded rectangle.
-  NSColor* toolbarColor =
-      themeService->GetNSColor(ThemeProperties::COLOR_TOOLBAR, true);
-  CGFloat alpha = morph * [toolbarColor alphaComponent];
-  [[toolbarColor colorWithAlphaComponent:alpha] set];  // Set with opacity.
-  [border fill];
-
-  // Fade in/out the background.
-  {
-    gfx::ScopedNSGraphicsContextSaveGState bgScopedState;
-    [border setClip];
-    NSGraphicsContext* context = [NSGraphicsContext currentContext];
-    CGContextRef cgContext = static_cast<CGContextRef>([context graphicsPort]);
-    CGContextSetAlpha(cgContext, 1 - morph);
-    CGContextBeginTransparencyLayer(cgContext, NULL);
-    [context cr_setPatternPhase:[[self window] themePatternPhase] forView:self];
-    [self drawBackgroundWithOpaque:YES];
-    CGContextEndTransparencyLayer(cgContext);
-  }
-
-  // Draw the border of the rounded rectangle.
-  NSColor* borderColor = themeService->GetNSColor(
-      ThemeProperties::COLOR_TOOLBAR_BUTTON_STROKE, true);
-  alpha = morph * [borderColor alphaComponent];
-  [[borderColor colorWithAlphaComponent:alpha] set];  // Set with opacity.
-  [border stroke];
-
-  // Fade in/out the divider.
-  // TODO(viettrungluu): It's not obvious that this divider lines up exactly
-  // with |BackgroundGradientView|'s (in fact, it probably doesn't).
-  NSColor* strokeColor = [self strokeColor];
-  alpha = (1 - morph) * [strokeColor alphaComponent];
-  [[strokeColor colorWithAlphaComponent:alpha] set];
-  NSBezierPath* divider = [NSBezierPath bezierPath];
-  NSPoint dividerStart =
-      NSMakePoint(morph * bookmarks::kNTPBookmarkBarPadding + morph * 0.5,
-                  morph * bookmarks::kNTPBookmarkBarPadding + morph * 0.5);
-  CGFloat dividerWidth =
-      NSWidth(bounds) - 2 * morph * bookmarks::kNTPBookmarkBarPadding - 2 * 0.5;
-  [divider moveToPoint:dividerStart];
-  [divider relativeLineToPoint:NSMakePoint(dividerWidth, 0)];
-  [divider stroke];
-}
-
-- (void)drawAsDetachedInstantExtendedUI {
   CGFloat morph = [controller_ detachedMorphProgress];
   NSRect bounds = [self bounds];
   ThemeService* themeService = [controller_ themeService];
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_toolbar_view_unittest.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_toolbar_view_unittest.mm
index e820897..f7a984b 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_toolbar_view_unittest.mm
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_toolbar_view_unittest.mm
@@ -4,7 +4,7 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "chrome/browser/themes/theme_properties.h"
 #include "chrome/browser/themes/theme_service.h"
 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.h"
@@ -94,14 +94,14 @@
   BookmarkBarToolbarViewTest() {
     controller_.reset([[DrawDetachedBarFakeController alloc] init]);
     NSRect frame = NSMakeRect(0, 0, 400, 40);
-    scoped_nsobject<BookmarkBarToolbarView> view(
+    base::scoped_nsobject<BookmarkBarToolbarView> view(
         [[BookmarkBarToolbarView alloc] initWithFrame:frame]);
     view_ = view.get();
     [[test_window() contentView] addSubview:view_];
     [view_ setController:controller_.get()];
   }
 
-  scoped_nsobject<DrawDetachedBarFakeController> controller_;
+  base::scoped_nsobject<DrawDetachedBarFakeController> controller_;
   BookmarkBarToolbarView* view_;
 };
 
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_view.h b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_view.h
index ef05ec6..f5083d0 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_view.h
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_view.h
@@ -10,14 +10,13 @@
 
 #import <Cocoa/Cocoa.h>
 
-#import "chrome/browser/ui/cocoa/background_gradient_view.h"
 #import "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h"
 
 @class BookmarkBarController;
 @class BookmarkBarItemContainer;
 @class BookmarkBarTextField;
 
-@interface BookmarkBarView : BackgroundGradientView {
+@interface BookmarkBarView : NSView {
  @private
   BOOL dropIndicatorShown_;
   CGFloat dropIndicatorPosition_;  // x position
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_view.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_view.mm
index 1a50f7c..b468c6f 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_view.mm
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_view.mm
@@ -121,10 +121,6 @@
     [controller_ clearDropInsertionPos];
 }
 
-- (void)drawRect:(NSRect)dirtyRect {
-  [super drawRect:dirtyRect];
-}
-
 // Shim function to assist in unit testing.
 - (BOOL)dragClipboardContainsBookmarks {
   return bookmark_pasteboard_helper_mac::PasteboardContainsBookmarks(
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_view_unittest.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_view_unittest.mm
index 902bb7f..8456dfa 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_view_unittest.mm
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_view_unittest.mm
@@ -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 "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "base/strings/string16.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/bookmarks/bookmark_model.h"
@@ -201,7 +201,7 @@
     view_.reset([[BookmarkBarView alloc] init]);
   }
 
-  scoped_nsobject<BookmarkBarView> view_;
+  base::scoped_nsobject<BookmarkBarView> view_;
 };
 
 TEST_F(BookmarkBarViewTest, CanDragWindow) {
@@ -209,8 +209,8 @@
 }
 
 TEST_F(BookmarkBarViewTest, BookmarkButtonDragAndDrop) {
-  scoped_nsobject<FakeBookmarkDraggingInfo>
-      info([[FakeBookmarkDraggingInfo alloc] init]);
+  base::scoped_nsobject<FakeBookmarkDraggingInfo> info(
+      [[FakeBookmarkDraggingInfo alloc] init]);
   [view_ setController:info.get()];
   [info reset];
 
@@ -222,12 +222,13 @@
                              ASCIIToUTF16("Test Bookmark"),
                              GURL("http://www.exmaple.com"));
 
-  scoped_nsobject<BookmarkButtonCell> button_cell(
+  base::scoped_nsobject<BookmarkButtonCell> button_cell(
       [[BookmarkButtonCell buttonCellForNode:node
                                         text:nil
                                        image:nil
                               menuController:nil] retain]);
-  scoped_nsobject<BookmarkButton> dragged_button([[BookmarkButton alloc] init]);
+  base::scoped_nsobject<BookmarkButton> dragged_button(
+      [[BookmarkButton alloc] init]);
   [dragged_button setCell:button_cell];
   [info setDraggingSource:dragged_button.get()];
   [info setDragDataType:kBookmarkButtonDragType];
@@ -243,8 +244,8 @@
 
 // When dragging bookmarks across profiles, we should always copy, never move.
 TEST_F(BookmarkBarViewTest, BookmarkButtonDragAndDropAcrossProfiles) {
-  scoped_nsobject<FakeBookmarkDraggingInfo>
-  info([[FakeBookmarkDraggingInfo alloc] init]);
+  base::scoped_nsobject<FakeBookmarkDraggingInfo> info(
+      [[FakeBookmarkDraggingInfo alloc] init]);
   [view_ setController:info.get()];
   [info reset];
 
@@ -263,12 +264,13 @@
                              ASCIIToUTF16("Test Bookmark"),
                              GURL("http://www.exmaple.com"));
 
-  scoped_nsobject<BookmarkButtonCell> button_cell(
+  base::scoped_nsobject<BookmarkButtonCell> button_cell(
       [[BookmarkButtonCell buttonCellForNode:node
                                         text:nil
                                        image:nil
                               menuController:nil] retain]);
-  scoped_nsobject<BookmarkButton> dragged_button([[BookmarkButton alloc] init]);
+  base::scoped_nsobject<BookmarkButton> dragged_button(
+      [[BookmarkButton alloc] init]);
   [dragged_button setCell:button_cell];
   [info setDraggingSource:dragged_button.get()];
   [info setDragDataType:kBookmarkButtonDragType];
@@ -283,8 +285,8 @@
 }
 
 TEST_F(BookmarkBarViewTest, URLDragAndDrop) {
-  scoped_nsobject<FakeBookmarkDraggingInfo>
-      info([[FakeBookmarkDraggingInfo alloc] init]);
+  base::scoped_nsobject<FakeBookmarkDraggingInfo> info(
+      [[FakeBookmarkDraggingInfo alloc] init]);
   [view_ setController:info.get()];
   [info reset];
 
@@ -301,12 +303,13 @@
 }
 
 TEST_F(BookmarkBarViewTest, BookmarkButtonDropIndicator) {
-  scoped_nsobject<FakeBookmarkDraggingInfo>
-      info([[FakeBookmarkDraggingInfo alloc] init]);
+  base::scoped_nsobject<FakeBookmarkDraggingInfo> info(
+      [[FakeBookmarkDraggingInfo alloc] init]);
   [view_ setController:info.get()];
   [info reset];
 
-  scoped_nsobject<BookmarkButton> dragged_button([[BookmarkButton alloc] init]);
+  base::scoped_nsobject<BookmarkButton> dragged_button(
+      [[BookmarkButton alloc] init]);
   [info setDraggingSource:dragged_button.get()];
   [info setDragDataType:kBookmarkButtonDragType];
   EXPECT_FALSE([info draggingEnteredCalled]);
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bubble_controller_unittest.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_bubble_controller_unittest.mm
index 5cad07e..1405f7c 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_bubble_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bubble_controller_unittest.mm
@@ -5,7 +5,7 @@
 #import <Cocoa/Cocoa.h>
 
 #include "base/basictypes.h"
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "base/strings/string16.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
@@ -252,8 +252,8 @@
         GURL("http://www.google.com"));
   EXPECT_EQ(edits_, 0);
 
-  scoped_nsobject<BookmarkPulseObserver> observer([[BookmarkPulseObserver alloc]
-                                                    init]);
+  base::scoped_nsobject<BookmarkPulseObserver> observer(
+      [[BookmarkPulseObserver alloc] init]);
   EXPECT_EQ([observer notifications], 0);
   BookmarkBubbleController* controller = ControllerForNode(node);
   EXPECT_TRUE(controller);
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_button.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_button.mm
index 876ac6d..43aff5d 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_button.mm
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_button.mm
@@ -7,13 +7,15 @@
 #include <cmath>
 
 #include "base/logging.h"
-#import "base/memory/scoped_nsobject.h"
+#include "base/mac/foundation_util.h"
+#import "base/mac/scoped_nsobject.h"
 #include "chrome/browser/bookmarks/bookmark_model.h"
 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_window.h"
 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_button_cell.h"
 #import "chrome/browser/ui/cocoa/browser_window_controller.h"
 #import "chrome/browser/ui/cocoa/view_id_util.h"
 #include "content/public/browser/user_metrics.h"
+#include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h"
 
 using content::UserMetricsAction;
 
@@ -383,6 +385,29 @@
   return kDraggableButtonMixinDidWork;
 }
 
+- (BOOL)isOpaque {
+  // Make this control opaque so that sub pixel anti aliasing works when core
+  // animation is enabled.
+  return YES;
+}
+
+- (void)drawRect:(NSRect)rect {
+  // Draw the toolbar background.
+  {
+    gfx::ScopedNSGraphicsContextSaveGState scopedGSState;
+    NSView* toolbarView = [[self superview] superview];
+    NSRect frame = [self convertRect:[self bounds] toView:toolbarView];
+
+    NSAffineTransform* transform = [NSAffineTransform transform];
+    [transform translateXBy:-NSMinX(frame) yBy:-NSMinY(frame)];
+    [transform concat];
+
+    [toolbarView drawRect:[toolbarView bounds]];
+  }
+
+  [super drawRect:rect];
+}
+
 @end
 
 @implementation BookmarkButton(Private)
@@ -409,35 +434,24 @@
 
 - (NSImage*)dragImage {
   NSRect bounds = [self bounds];
+  base::scoped_nsobject<NSImage> image(
+      [[NSImage alloc] initWithSize:bounds.size]);
+  [image lockFocusFlipped:[self isFlipped]];
 
-  // Grab the image from the screen and put it in an |NSImage|. We can't use
-  // this directly since we need to clip it and set its opacity. This won't work
-  // if the source view is clipped. Fortunately, we don't display clipped
-  // bookmark buttons.
-  [self lockFocus];
-  scoped_nsobject<NSBitmapImageRep>
-      bitmap([[NSBitmapImageRep alloc] initWithFocusedViewRect:bounds]);
-  [self unlockFocus];
-  scoped_nsobject<NSImage> image([[NSImage alloc] initWithSize:[bitmap size]]);
-  [image addRepresentation:bitmap];
+  NSGraphicsContext* context = [NSGraphicsContext currentContext];
+  CGContextRef cgContext = static_cast<CGContextRef>([context graphicsPort]);
+  CGContextBeginTransparencyLayer(cgContext, 0);
+  CGContextSetAlpha(cgContext, kDragImageOpacity);
 
-  // Make an autoreleased |NSImage|, which will be returned, and draw into it.
-  // By default, the |NSImage| will be completely transparent.
-  NSImage* dragImage =
-      [[[NSImage alloc] initWithSize:[bitmap size]] autorelease];
-  [dragImage lockFocus];
-
-  // Draw the image with the appropriate opacity, clipping it tightly.
-  GradientButtonCell* cell = static_cast<GradientButtonCell*>([self cell]);
-  DCHECK([cell isKindOfClass:[GradientButtonCell class]]);
+  GradientButtonCell* cell =
+      base::mac::ObjCCastStrict<GradientButtonCell>([self cell]);
   [[cell clipPathForFrame:bounds inView:self] setClip];
-  [image drawAtPoint:NSMakePoint(0, 0)
-            fromRect:NSMakeRect(0, 0, NSWidth(bounds), NSHeight(bounds))
-           operation:NSCompositeSourceOver
-            fraction:kDragImageOpacity];
+  [cell drawWithFrame:bounds inView:self];
 
-  [dragImage unlockFocus];
-  return dragImage;
+  CGContextEndTransparencyLayer(cgContext);
+  [image unlockFocus];
+
+  return image.autorelease();
 }
 
 @end  // @implementation BookmarkButton(Private)
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_button_cell.h b/chrome/browser/ui/cocoa/bookmarks/bookmark_button_cell.h
index 32b13f4..0a4b7da 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_button_cell.h
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_button_cell.h
@@ -30,10 +30,10 @@
   BOOL drawFolderArrow_;
 
   // Arrow for folders
-  scoped_nsobject<NSImage> arrowImage_;
+  base::scoped_nsobject<NSImage> arrowImage_;
 
   // Text color for title.
-  scoped_nsobject<NSColor> textColor_;
+  base::scoped_nsobject<NSColor> textColor_;
 }
 
 @property(nonatomic, readwrite, assign) const BookmarkNode* bookmarkNode;
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_button_cell.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_button_cell.mm
index 6aaab33..a377295 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_button_cell.mm
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_button_cell.mm
@@ -215,7 +215,8 @@
 
 // We must reapply the text color after any setTitle: call
 - (void)applyTextColor {
-  scoped_nsobject<NSMutableParagraphStyle> style([NSMutableParagraphStyle new]);
+  base::scoped_nsobject<NSMutableParagraphStyle> style(
+      [NSMutableParagraphStyle new]);
   [style setAlignment:NSLeftTextAlignment];
   NSDictionary* dict = [NSDictionary
                          dictionaryWithObjectsAndKeys:textColor_,
@@ -224,9 +225,8 @@
                          style.get(), NSParagraphStyleAttributeName,
                          [NSNumber numberWithFloat:0.2], NSKernAttributeName,
                          nil];
-  scoped_nsobject<NSAttributedString> ats([[NSAttributedString alloc]
-                                            initWithString:[self title]
-                                                attributes:dict]);
+  base::scoped_nsobject<NSAttributedString> ats(
+      [[NSAttributedString alloc] initWithString:[self title] attributes:dict]);
   [self setAttributedTitle:ats.get()];
 }
 
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_button_cell_unittest.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_button_cell_unittest.mm
index baeccef..db26ae7 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_button_cell_unittest.mm
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_button_cell_unittest.mm
@@ -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 "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/bookmarks/bookmark_model.h"
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
@@ -43,8 +43,8 @@
 // Make sure it's not totally bogus
 TEST_F(BookmarkButtonCellTest, SizeForBounds) {
   NSRect frame = NSMakeRect(0, 0, 50, 30);
-  scoped_nsobject<NSButton> view([[NSButton alloc] initWithFrame:frame]);
-  scoped_nsobject<BookmarkButtonCell> cell(
+  base::scoped_nsobject<NSButton> view([[NSButton alloc] initWithFrame:frame]);
+  base::scoped_nsobject<BookmarkButtonCell> cell(
       [[BookmarkButtonCell alloc] initTextCell:@"Testing"]);
   [view setCell:cell.get()];
   [[test_window() contentView] addSubview:view];
@@ -58,14 +58,14 @@
 // Make sure icon-only buttons are squeezed tightly.
 TEST_F(BookmarkButtonCellTest, IconOnlySqueeze) {
   NSRect frame = NSMakeRect(0, 0, 50, 30);
-  scoped_nsobject<NSButton> view([[NSButton alloc] initWithFrame:frame]);
-  scoped_nsobject<BookmarkButtonCell> cell(
+  base::scoped_nsobject<NSButton> view([[NSButton alloc] initWithFrame:frame]);
+  base::scoped_nsobject<BookmarkButtonCell> cell(
       [[BookmarkButtonCell alloc] initTextCell:@"Testing"]);
   [view setCell:cell.get()];
   [[test_window() contentView] addSubview:view];
 
   ResourceBundle& rb = ResourceBundle::GetSharedInstance();
-  scoped_nsobject<NSImage> image(
+  base::scoped_nsobject<NSImage> image(
       rb.GetNativeImageNamed(IDR_DEFAULT_FAVICON).CopyNSImage());
   EXPECT_TRUE(image.get());
 
@@ -87,7 +87,7 @@
 
 // Make sure the default from the base class is overridden.
 TEST_F(BookmarkButtonCellTest, MouseEnterStuff) {
-  scoped_nsobject<BookmarkButtonCell> cell(
+  base::scoped_nsobject<BookmarkButtonCell> cell(
       [[BookmarkButtonCell alloc] initTextCell:@"Testing"]);
   // Setting the menu should have no affect since we either share or
   // dynamically compose the menu given a node.
@@ -106,7 +106,7 @@
 
 TEST_F(BookmarkButtonCellTest, BookmarkNode) {
   BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
-  scoped_nsobject<BookmarkButtonCell> cell(
+  base::scoped_nsobject<BookmarkButtonCell> cell(
       [[BookmarkButtonCell alloc] initTextCell:@"Testing"]);
 
   const BookmarkNode* node = model->bookmark_bar_node();
@@ -119,11 +119,11 @@
 }
 
 TEST_F(BookmarkButtonCellTest, BookmarkMouseForwarding) {
-  scoped_nsobject<BookmarkButtonCell> cell(
+  base::scoped_nsobject<BookmarkButtonCell> cell(
       [[BookmarkButtonCell alloc] initTextCell:@"Testing"]);
-  scoped_nsobject<ButtonRemembersMouseEnterExit>
-    button([[ButtonRemembersMouseEnterExit alloc]
-             initWithFrame:NSMakeRect(0,0,50,50)]);
+  base::scoped_nsobject<ButtonRemembersMouseEnterExit> button(
+      [[ButtonRemembersMouseEnterExit alloc]
+          initWithFrame:NSMakeRect(0, 0, 50, 50)]);
   [button setCell:cell.get()];
   EXPECT_EQ(0, button.get()->enters_);
   EXPECT_EQ(0, button.get()->exits_);
@@ -147,7 +147,8 @@
 
 // Confirms a cell created in a nib is initialized properly
 TEST_F(BookmarkButtonCellTest, Awake) {
-  scoped_nsobject<BookmarkButtonCell> cell([[BookmarkButtonCell alloc] init]);
+  base::scoped_nsobject<BookmarkButtonCell> cell(
+      [[BookmarkButtonCell alloc] init]);
   [cell awakeFromNib];
   EXPECT_EQ(NSLeftTextAlignment, [cell alignment]);
 }
@@ -159,11 +160,11 @@
   const BookmarkNode* node = model->AddURL(bar, bar->child_count(),
                                            ASCIIToUTF16("title"),
                                            GURL("http://www.google.com"));
-  scoped_nsobject<BookmarkButtonCell> cell(
-    [[BookmarkButtonCell alloc] initForNode:node
-                                       text:@"small"
-                                      image:nil
-                             menuController:nil]);
+  base::scoped_nsobject<BookmarkButtonCell> cell(
+      [[BookmarkButtonCell alloc] initForNode:node
+                                         text:@"small"
+                                        image:nil
+                               menuController:nil]);
   EXPECT_TRUE(cell.get());
 
   NSSize size = [cell cellSize];
@@ -184,9 +185,9 @@
                                            ASCIIToUTF16("title"),
                                            GURL("http://www.google.com"));
 
-  scoped_nsobject<GradientButtonCell> gradient_cell(
+  base::scoped_nsobject<GradientButtonCell> gradient_cell(
       [[GradientButtonCell alloc] initTextCell:@"Testing"]);
-  scoped_nsobject<BookmarkButtonCell> bookmark_cell(
+  base::scoped_nsobject<BookmarkButtonCell> bookmark_cell(
       [[BookmarkButtonCell alloc] initForNode:node
                                          text:@"small"
                                         image:nil
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_button_unittest.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_button_unittest.mm
index 6e0b5d3..a6cb9d2 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_button_unittest.mm
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_button_unittest.mm
@@ -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 "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/bookmarks/bookmark_model.h"
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
@@ -65,14 +65,14 @@
 
 // Make sure nothing leaks
 TEST_F(BookmarkButtonTest, Create) {
-  scoped_nsobject<BookmarkButton> button;
+  base::scoped_nsobject<BookmarkButton> button;
   button.reset([[BookmarkButton alloc] initWithFrame:NSMakeRect(0,0,500,500)]);
 }
 
 // Test folder and empty node queries.
 TEST_F(BookmarkButtonTest, FolderAndEmptyOrNot) {
-  scoped_nsobject<BookmarkButton> button;
-  scoped_nsobject<BookmarkButtonCell> cell;
+  base::scoped_nsobject<BookmarkButton> button;
+  base::scoped_nsobject<BookmarkButtonCell> cell;
 
   button.reset([[BookmarkButton alloc] initWithFrame:NSMakeRect(0,0,500,500)]);
   cell.reset([[BookmarkButtonCell alloc] initTextCell:@"hi mom"]);
@@ -107,10 +107,10 @@
       cocoa_test_event_utils::MouseEventAtPoint(NSMakePoint(10,10),
                                                 NSMouseMoved,
                                                 0);
-  scoped_nsobject<BookmarkButton> button;
-  scoped_nsobject<BookmarkButtonCell> cell;
-  scoped_nsobject<FakeButtonDelegate>
-      delegate([[FakeButtonDelegate alloc] init]);
+  base::scoped_nsobject<BookmarkButton> button;
+  base::scoped_nsobject<BookmarkButtonCell> cell;
+  base::scoped_nsobject<FakeButtonDelegate> delegate(
+      [[FakeButtonDelegate alloc] init]);
   button.reset([[BookmarkButton alloc] initWithFrame:NSMakeRect(0,0,500,500)]);
   cell.reset([[BookmarkButtonCell alloc] initTextCell:@"hi mom"]);
   [button setCell:cell];
@@ -130,10 +130,10 @@
 }
 
 TEST_F(BookmarkButtonTest, DragToTrash) {
-  scoped_nsobject<BookmarkButton> button;
-  scoped_nsobject<BookmarkButtonCell> cell;
-  scoped_nsobject<FakeButtonDelegate>
-      delegate([[FakeButtonDelegate alloc] init]);
+  base::scoped_nsobject<BookmarkButton> button;
+  base::scoped_nsobject<BookmarkButtonCell> cell;
+  base::scoped_nsobject<FakeButtonDelegate> delegate(
+      [[FakeButtonDelegate alloc] init]);
   button.reset([[BookmarkButton alloc] initWithFrame:NSMakeRect(0,0,500,500)]);
   cell.reset([[BookmarkButtonCell alloc] initTextCell:@"hi mom"]);
   [button setCell:cell];
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_context_menu_cocoa_controller.h b/chrome/browser/ui/cocoa/bookmarks/bookmark_context_menu_cocoa_controller.h
index 7f4828c..61a49f0 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_context_menu_cocoa_controller.h
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_context_menu_cocoa_controller.h
@@ -8,7 +8,7 @@
 #import <Cocoa/Cocoa.h>
 
 #include "base/basictypes.h"
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "base/memory/scoped_ptr.h"
 
 @class BookmarkBarController;
@@ -41,7 +41,7 @@
 
   // Controller responsible for creating a Cocoa NSMenu from the cross-platform
   // SimpleMenuModel owned by the |bookmarkContextMenuController_|.
-  scoped_nsobject<MenuController> menuController_;
+  base::scoped_nsobject<MenuController> menuController_;
 }
 
 // Initializes the BookmarkContextMenuCocoaController for the given bookmark
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_drag_drop_cocoa.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_drag_drop_cocoa.mm
index 3c1889d..c69a17d 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_drag_drop_cocoa.mm
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_drag_drop_cocoa.mm
@@ -9,7 +9,7 @@
 #include <cmath>
 
 #include "base/logging.h"
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "base/message_loop.h"
 #include "base/strings/string16.h"
 #include "base/strings/sys_string_conversions.h"
@@ -69,9 +69,8 @@
 
   NSColor* color = [NSColor blackColor];
   NSColor* alpha_color = [color colorWithAlphaComponent:0.0];
-  scoped_nsobject<NSGradient> mask(
-      [[NSGradient alloc] initWithStartingColor:color
-                                    endingColor:alpha_color]);
+  base::scoped_nsobject<NSGradient> mask(
+      [[NSGradient alloc] initWithStartingColor:color endingColor:alpha_color]);
   // Draw the gradient mask.
   CGContextSetBlendMode(context, kCGBlendModeDestinationIn);
   [mask drawFromPoint:NSMakePoint(NSMaxX(frame) - gradient_width,
@@ -101,9 +100,8 @@
       [NSDictionary dictionaryWithObject:[NSFont systemFontOfSize:
                                            [NSFont smallSystemFontSize]]
                                   forKey:NSFontAttributeName];
-  scoped_nsobject<NSAttributedString> rich_title(
-      [[NSAttributedString alloc] initWithString:ns_title
-                                      attributes:attrs]);
+  base::scoped_nsobject<NSAttributedString> rich_title(
+      [[NSAttributedString alloc] initWithString:ns_title attributes:attrs]);
 
   // Set up sizes and locations for rendering.
   const CGFloat kIconMargin = 2.0;  // Gap between icon and text.
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_editor_base_controller.h b/chrome/browser/ui/cocoa/bookmarks/bookmark_editor_base_controller.h
index e8107ea..6e1162a 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_editor_base_controller.h
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_editor_base_controller.h
@@ -7,10 +7,10 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "base/memory/scoped_ptr.h"
-#include "chrome/browser/bookmarks/bookmark_editor.h"
 #include "chrome/browser/bookmarks/bookmark_expanded_state_tracker.h"
+#include "chrome/browser/ui/bookmarks/bookmark_editor.h"
 
 class BookmarkEditorBaseControllerBridge;
 class BookmarkModel;
@@ -41,10 +41,10 @@
   BOOL creatingNewFolders_;  // True while in createNewFolders.
   // An array of BookmarkFolderInfo where each item describes a folder in the
   // BookmarkNode structure.
-  scoped_nsobject<NSArray> folderTreeArray_;
+  base::scoped_nsobject<NSArray> folderTreeArray_;
   // Bound to the table view giving a path to the current selections, of which
   // there should only ever be one.
-  scoped_nsobject<NSArray> tableSelectionPaths_;
+  base::scoped_nsobject<NSArray> tableSelectionPaths_;
   // C++ bridge object that observes the BookmarkModel for me.
   scoped_ptr<BookmarkEditorBaseControllerBridge> observer_;
 }
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_editor_base_controller_unittest.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_editor_base_controller_unittest.mm
index c66f651..1efc1e7 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_editor_base_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_editor_base_controller_unittest.mm
@@ -4,7 +4,6 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
 #include "base/strings/sys_string_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/bookmarks/bookmark_model.h"
@@ -95,8 +94,7 @@
   }
 
   virtual Browser* CreateBrowser() OVERRIDE {
-    Browser::CreateParams native_params(profile(),
-                                        chrome::HOST_DESKTOP_TYPE_NATIVE);
+    Browser::CreateParams native_params(profile(), chrome::GetActiveDesktop());
     return chrome::CreateBrowserWithTestWindowForParams(&native_params);
   }
 };
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_editor_controller.h b/chrome/browser/ui/cocoa/bookmarks/bookmark_editor_controller.h
index da3ed89..abf67cb 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_editor_controller.h
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_editor_controller.h
@@ -13,7 +13,7 @@
 @interface BookmarkEditorController : BookmarkEditorBaseController {
  @private
   const BookmarkNode* node_;  // weak; owned by the model
-  scoped_nsobject<NSString> initialUrl_;
+  base::scoped_nsobject<NSString> initialUrl_;
   NSString* displayURL_;  // Bound to a text field in the dialog.
   IBOutlet NSTextField* urlField_;
   IBOutlet NSTextField* nameTextField_;
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_folder_target_unittest.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_folder_target_unittest.mm
index 2ca188d..c6019a9 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_folder_target_unittest.mm
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_folder_target_unittest.mm
@@ -57,8 +57,8 @@
   // Make sure we get an addNew
   [[controller expect] addNewFolderControllerWithParentButton:sender];
 
-  scoped_nsobject<BookmarkFolderTarget> target(
-    [[BookmarkFolderTarget alloc] initWithController:controller]);
+  base::scoped_nsobject<BookmarkFolderTarget> target(
+      [[BookmarkFolderTarget alloc] initWithController:controller]);
 
   [target openBookmarkFolderFromButton:sender];
   EXPECT_OCMOCK_VERIFY(controller);
@@ -82,7 +82,7 @@
   // any subfolders).
   [[controller expect] closeBookmarkFolder:controller];
 
-  scoped_nsobject<BookmarkFolderTarget> target(
+  base::scoped_nsobject<BookmarkFolderTarget> target(
       [[BookmarkFolderTarget alloc] initWithController:controller]);
 
   [target openBookmarkFolderFromButton:sender];
@@ -111,8 +111,8 @@
   // close and open.
   [[controller expect] addNewFolderControllerWithParentButton:sender];
 
-  scoped_nsobject<BookmarkFolderTarget> target(
-    [[BookmarkFolderTarget alloc] initWithController:controller]);
+  base::scoped_nsobject<BookmarkFolderTarget> target(
+      [[BookmarkFolderTarget alloc] initWithController:controller]);
 
   [target openBookmarkFolderFromButton:sender];
   EXPECT_OCMOCK_VERIFY(controller);
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_menu_bridge.h b/chrome/browser/ui/cocoa/bookmarks/bookmark_menu_bridge.h
index 747a480..1d8fc04 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_menu_bridge.h
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_menu_bridge.h
@@ -22,7 +22,7 @@
 
 #include <map>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "chrome/browser/bookmarks/bookmark_model_observer.h"
 #import "chrome/browser/ui/cocoa/main_menu_item.h"
 
@@ -139,7 +139,7 @@
   BookmarkMenuCocoaController* controller_;  // strong
 
   // The folder image so we can use one copy for all.
-  scoped_nsobject<NSImage> folder_image_;
+  base::scoped_nsobject<NSImage> folder_image_;
 
   // In order to appropriately update items in the bookmark menu, without
   // forcing a rebuild, map the model's nodes to menu items.
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_menu_bridge.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_menu_bridge.mm
index 1c2f80b..566f88a 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_menu_bridge.mm
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_menu_bridge.mm
@@ -9,6 +9,7 @@
 #import "chrome/browser/app_controller_mac.h"
 #include "chrome/browser/bookmarks/bookmark_model.h"
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
+#include "chrome/browser/prefs/incognito_mode_prefs.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/browser_list.h"
@@ -256,6 +257,12 @@
     // Add menus for 'Open All Bookmarks'.
     [menu addItem:[NSMenuItem separatorItem]];
     bool enabled = child_count != 0;
+
+    IncognitoModePrefs::Availability incognito_availability =
+        IncognitoModePrefs::GetAvailability(profile_->GetPrefs());
+    bool incognito_enabled =
+        enabled && incognito_availability != IncognitoModePrefs::DISABLED;
+
     AddItemToMenu(IDC_BOOKMARK_BAR_OPEN_ALL,
                   IDS_BOOKMARK_BAR_OPEN_ALL,
                   node, menu, enabled);
@@ -264,7 +271,7 @@
                   node, menu, enabled);
     AddItemToMenu(IDC_BOOKMARK_BAR_OPEN_ALL_INCOGNITO,
                   IDS_BOOKMARK_BAR_OPEN_ALL_INCOGNITO,
-                  node, menu, enabled);
+                  node, menu, incognito_enabled);
   }
 }
 
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_menu_bridge_unittest.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_menu_bridge_unittest.mm
index 73bc86d..e5eedd5 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_menu_bridge_unittest.mm
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_menu_bridge_unittest.mm
@@ -4,7 +4,6 @@
 
 #import <AppKit/AppKit.h>
 
-#import "base/memory/scoped_nsobject.h"
 #include "base/strings/string16.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_menu_cocoa_controller.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_menu_cocoa_controller.mm
index 36b9705..93e7c64 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_menu_cocoa_controller.mm
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_menu_cocoa_controller.mm
@@ -13,6 +13,7 @@
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_finder.h"
 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_menu_bridge.h"
+#import "chrome/browser/ui/cocoa/l10n_util.h"
 #include "chrome/browser/ui/host_desktop.h"
 #include "content/public/browser/user_metrics.h"
 #import "ui/base/cocoa/cocoa_event_utils.h"
@@ -40,14 +41,9 @@
 
 + (NSString*)tooltipForNode:(const BookmarkNode*)node {
   NSString* title = base::SysUTF16ToNSString(node->GetTitle());
-  std::string url_string = node->url().possibly_invalid_spec();
-  NSString* url = [NSString stringWithUTF8String:url_string.c_str()];
-  if ([title length] == 0)
-    return url;
-  else if ([url length] == 0 || [url isEqualToString:title])
-    return title;
-  else
-    return [NSString stringWithFormat:@"%@\n%@", title, url];
+  std::string urlString = node->url().possibly_invalid_spec();
+  NSString* url = base::SysUTF8ToNSString(urlString);
+  return cocoa_l10n_util::TooltipForURLAndTitle(url, title);
 }
 
 - (id)initWithBridge:(BookmarkMenuBridge*)bridge
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_menu_cocoa_controller_unittest.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_menu_cocoa_controller_unittest.mm
index fddc7fb..e4b7b4e 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_menu_cocoa_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_menu_cocoa_controller_unittest.mm
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#import "base/memory/scoped_nsobject.h"
+#import "base/mac/scoped_nsobject.h"
 #include "base/strings/string16.h"
 #include "chrome/browser/bookmarks/bookmark_model.h"
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
@@ -76,7 +76,7 @@
   FakeBookmarkMenuController* controller() { return controller_.get(); }
 
  private:
-  scoped_nsobject<FakeBookmarkMenuController> controller_;
+  base::scoped_nsobject<FakeBookmarkMenuController> controller_;
 };
 
 TEST_F(BookmarkMenuCocoaControllerTest, TestOpenItem) {
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_model_observer_for_cocoa.h b/chrome/browser/ui/cocoa/bookmarks/bookmark_model_observer_for_cocoa.h
index e6bc619..f5246b6 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_model_observer_for_cocoa.h
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_model_observer_for_cocoa.h
@@ -25,7 +25,6 @@
 
 #include "base/basictypes.h"
 #include "base/mac/scoped_block.h"
-#include "base/memory/scoped_nsobject.h"
 #include "chrome/browser/bookmarks/bookmark_model.h"
 #include "chrome/browser/bookmarks/bookmark_model_observer.h"
 
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_model_observer_for_cocoa_unittest.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_model_observer_for_cocoa_unittest.mm
index c781af2..83e8dae 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_model_observer_for_cocoa_unittest.mm
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_model_observer_for_cocoa_unittest.mm
@@ -4,7 +4,6 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_name_folder_controller.h b/chrome/browser/ui/cocoa/bookmarks/bookmark_name_folder_controller.h
index d7009dd..e5a603e 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_name_folder_controller.h
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_name_folder_controller.h
@@ -7,7 +7,7 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "base/memory/scoped_ptr.h"
 #include "chrome/browser/bookmarks/bookmark_model.h"
 
@@ -31,7 +31,7 @@
   const BookmarkNode* parent_;
   int newIndex_;
 
-  scoped_nsobject<NSString> initialName_;
+  base::scoped_nsobject<NSString> initialName_;
 
   // Ping me when things change out from under us.
   scoped_ptr<BookmarkModelObserverForCocoa> observer_;
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_name_folder_controller_unittest.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_name_folder_controller_unittest.mm
index eb78e7a..d8a023d 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_name_folder_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_name_folder_controller_unittest.mm
@@ -4,7 +4,7 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_name_folder_controller.h"
@@ -23,12 +23,11 @@
   const BookmarkNode* parent = model->bookmark_bar_node();
   EXPECT_EQ(0, parent->child_count());
 
-  scoped_nsobject<BookmarkNameFolderController>
-    controller([[BookmarkNameFolderController alloc]
-                 initWithParentWindow:test_window()
-                              profile:profile()
-                               parent:parent
-                             newIndex:0]);
+  base::scoped_nsobject<BookmarkNameFolderController> controller(
+      [[BookmarkNameFolderController alloc] initWithParentWindow:test_window()
+                                                         profile:profile()
+                                                          parent:parent
+                                                        newIndex:0]);
   [controller window];  // force nib load
 
   // Do nothing.
@@ -59,12 +58,11 @@
                 GURL("http://www.google.com"));
   EXPECT_EQ(2, parent->child_count());
 
-  scoped_nsobject<BookmarkNameFolderController>
-    controller([[BookmarkNameFolderController alloc]
-                 initWithParentWindow:test_window()
-                              profile:profile()
-                               parent:parent
-                             newIndex:1]);
+  base::scoped_nsobject<BookmarkNameFolderController> controller(
+      [[BookmarkNameFolderController alloc] initWithParentWindow:test_window()
+                                                         profile:profile()
+                                                          parent:parent
+                                                        newIndex:1]);
   [controller window];  // force nib load
 
   // Add a new folder.
@@ -83,12 +81,11 @@
   const BookmarkNode* parent = model->bookmark_bar_node();
   EXPECT_EQ(0, parent->child_count());
 
-  scoped_nsobject<BookmarkNameFolderController>
-    controller([[BookmarkNameFolderController alloc]
-                 initWithParentWindow:test_window()
-                              profile:profile()
-                               parent:parent
-                             newIndex:0]);
+  base::scoped_nsobject<BookmarkNameFolderController> controller(
+      [[BookmarkNameFolderController alloc] initWithParentWindow:test_window()
+                                                         profile:profile()
+                                                          parent:parent
+                                                        newIndex:0]);
 
   [controller window];  // force nib load
 
@@ -104,12 +101,11 @@
   const BookmarkNode* parent = model->bookmark_bar_node();
   EXPECT_EQ(0, parent->child_count());
 
-  scoped_nsobject<BookmarkNameFolderController>
-  controller([[BookmarkNameFolderController alloc]
-              initWithParentWindow:test_window()
-                           profile:profile()
-                            parent:parent
-                          newIndex:0]);
+  base::scoped_nsobject<BookmarkNameFolderController> controller(
+      [[BookmarkNameFolderController alloc] initWithParentWindow:test_window()
+                                                         profile:profile()
+                                                          parent:parent
+                                                        newIndex:0]);
   [controller window];  // force nib load
 
   // Change the name to blank, click OK.
@@ -128,11 +124,10 @@
 
   // Rename the folder by creating a controller that originates from
   // the node.
-  scoped_nsobject<BookmarkNameFolderController>
-    controller([[BookmarkNameFolderController alloc]
-                 initWithParentWindow:test_window()
-                              profile:profile()
-                                 node:folder]);
+  base::scoped_nsobject<BookmarkNameFolderController> controller(
+      [[BookmarkNameFolderController alloc] initWithParentWindow:test_window()
+                                                         profile:profile()
+                                                            node:folder]);
   [controller window];  // force nib load
 
   EXPECT_NSEQ(@"folder", [controller folderName]);
@@ -148,12 +143,11 @@
   const BookmarkNode* parent = model->bookmark_bar_node();
   EXPECT_EQ(0, parent->child_count());
 
-  scoped_nsobject<BookmarkNameFolderController>
-    controller([[BookmarkNameFolderController alloc]
-                 initWithParentWindow:test_window()
-                              profile:profile()
-                               parent:parent
-                             newIndex:0]);
+  base::scoped_nsobject<BookmarkNameFolderController> controller(
+      [[BookmarkNameFolderController alloc] initWithParentWindow:test_window()
+                                                         profile:profile()
+                                                          parent:parent
+                                                        newIndex:0]);
   [controller window];  // force nib load
 
   // We start enabled since the default "New Folder" is added for us.
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_tree_browser_cell_unittest.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_tree_browser_cell_unittest.mm
index 60f6deb..7450904 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_tree_browser_cell_unittest.mm
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_tree_browser_cell_unittest.mm
@@ -4,7 +4,7 @@
 
 #import <Cocoa/Cocoa.h>
 
-#import "base/memory/scoped_nsobject.h"
+#import "base/mac/scoped_nsobject.h"
 #include "chrome/browser/bookmarks/bookmark_model.h"
 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_tree_browser_cell.h"
 #include "testing/platform_test.h"
@@ -20,8 +20,8 @@
   }
 
   scoped_ptr<BookmarkNode> bookmarkNodeMock_;
-  scoped_nsobject<NSMatrix> matrixMock_;
-  scoped_nsobject<NSObject> targetMock_;
+  base::scoped_nsobject<NSMatrix> matrixMock_;
+  base::scoped_nsobject<NSObject> targetMock_;
 };
 
 TEST_F(BookmarkTreeBrowserCellTest, BasicAllocDealloc) {
diff --git a/chrome/browser/ui/cocoa/browser/avatar_button_controller.h b/chrome/browser/ui/cocoa/browser/avatar_button_controller.h
index a72d6ee..f61ccad 100644
--- a/chrome/browser/ui/cocoa/browser/avatar_button_controller.h
+++ b/chrome/browser/ui/cocoa/browser/avatar_button_controller.h
@@ -7,7 +7,7 @@
 
 #import <AppKit/AppKit.h>
 
-#import "base/memory/scoped_nsobject.h"
+#import "base/mac/scoped_nsobject.h"
 #include "base/memory/scoped_ptr.h"
 
 @class AvatarMenuBubbleController;
@@ -36,10 +36,10 @@
   __weak AvatarMenuBubbleController* menuController_;
 
   // The avatar button.
-  scoped_nsobject<NSButton> button_;
+  base::scoped_nsobject<NSButton> button_;
 
   // The managed user avatar label. Only used for managed user profiles.
-  scoped_nsobject<NSButton> labelButton_;
+  base::scoped_nsobject<NSButton> labelButton_;
 }
 
 // The avatar button view.
diff --git a/chrome/browser/ui/cocoa/browser/avatar_button_controller.mm b/chrome/browser/ui/cocoa/browser/avatar_button_controller.mm
index 52049b0..ab62229 100644
--- a/chrome/browser/ui/cocoa/browser/avatar_button_controller.mm
+++ b/chrome/browser/ui/cocoa/browser/avatar_button_controller.mm
@@ -98,8 +98,9 @@
   if ((self = [super init])) {
     browser_ = browser;
 
-    scoped_nsobject<NSView> container([[NSView alloc] initWithFrame:NSMakeRect(
-        0, 0, profiles::kAvatarIconWidth, profiles::kAvatarIconHeight)]);
+    base::scoped_nsobject<NSView> container(
+        [[NSView alloc] initWithFrame:NSMakeRect(
+            0, 0, profiles::kAvatarIconWidth, profiles::kAvatarIconHeight)]);
     [self setView:container];
     button_.reset([[NSButton alloc] initWithFrame:NSMakeRect(
         0, 0, profiles::kAvatarIconWidth, profiles::kAvatarIconHeight)]);
@@ -258,7 +259,7 @@
 - (NSImage*)compositeImageWithShadow:(NSImage*)image {
   gfx::ScopedNSGraphicsContextSaveGState scopedGState;
 
-  scoped_nsobject<NSImage> destination(
+  base::scoped_nsobject<NSImage> destination(
       [[NSImage alloc] initWithSize:[image size]]);
 
   NSRect destRect = NSZeroRect;
@@ -266,7 +267,7 @@
 
   [destination lockFocus];
 
-  scoped_nsobject<NSShadow> shadow([[NSShadow alloc] init]);
+  base::scoped_nsobject<NSShadow> shadow([[NSShadow alloc] init]);
   [shadow.get() setShadowColor:[NSColor colorWithCalibratedWhite:0.0
                                                            alpha:0.75]];
   [shadow.get() setShadowOffset:NSMakeSize(0, 0)];
diff --git a/chrome/browser/ui/cocoa/browser/avatar_button_controller_unittest.mm b/chrome/browser/ui/cocoa/browser/avatar_button_controller_unittest.mm
index 83001ee..43b7c3b 100644
--- a/chrome/browser/ui/cocoa/browser/avatar_button_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/browser/avatar_button_controller_unittest.mm
@@ -4,7 +4,7 @@
 
 #import "chrome/browser/ui/cocoa/browser/avatar_button_controller.h"
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_window.h"
 #import "chrome/browser/ui/cocoa/browser/avatar_menu_bubble_controller.h"
@@ -35,7 +35,7 @@
   AvatarButtonController* controller() { return controller_.get(); }
 
  private:
-  scoped_nsobject<AvatarButtonController> controller_;
+  base::scoped_nsobject<AvatarButtonController> controller_;
 };
 
 TEST_F(AvatarButtonControllerTest, AddRemoveProfiles) {
@@ -89,7 +89,7 @@
 
   // Build a new controller to check if it is initialized correctly for a
   // managed user profile.
-  scoped_nsobject<AvatarButtonController> controller(
+  base::scoped_nsobject<AvatarButtonController> controller(
       [[AvatarButtonController alloc] initWithBrowser:browser()]);
 
   EXPECT_TRUE([controller labelButtonView]);
diff --git a/chrome/browser/ui/cocoa/browser/avatar_menu_bubble_controller.h b/chrome/browser/ui/cocoa/browser/avatar_menu_bubble_controller.h
index f3f77f4..b0eb8f0 100644
--- a/chrome/browser/ui/cocoa/browser/avatar_menu_bubble_controller.h
+++ b/chrome/browser/ui/cocoa/browser/avatar_menu_bubble_controller.h
@@ -7,7 +7,7 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "base/memory/scoped_ptr.h"
 #import "chrome/browser/ui/cocoa/base_bubble_controller.h"
 #import "ui/base/cocoa/tracking_area.h"
@@ -23,7 +23,7 @@
   scoped_ptr<AvatarMenuModel> model_;
 
   // Array of the below view controllers.
-  scoped_nsobject<NSMutableArray> items_;
+  base::scoped_nsobject<NSMutableArray> items_;
 
   // Is set to true if the managed user has clicked on Switch Users.
   BOOL expanded_;
@@ -65,7 +65,7 @@
 
   // The animation showing the edit link, which is run after the user has
   // dwelled over the item for a short delay.
-  scoped_nsobject<NSAnimation> linkAnimation_;
+  base::scoped_nsobject<NSAnimation> linkAnimation_;
 
   // Instance variables that back the outlets.
   __weak NSImageView* iconView_;
diff --git a/chrome/browser/ui/cocoa/browser/avatar_menu_bubble_controller.mm b/chrome/browser/ui/cocoa/browser/avatar_menu_bubble_controller.mm
index 65cff17..26e5ec9 100644
--- a/chrome/browser/ui/cocoa/browser/avatar_menu_bubble_controller.mm
+++ b/chrome/browser/ui/cocoa/browser/avatar_menu_bubble_controller.mm
@@ -110,7 +110,7 @@
   // Use an arbitrary height because it will reflect the size of the content.
   NSRect contentRect = NSMakeRect(0, 0, kBubbleMinWidth, 150);
   // Create an empty window into which content is placed.
-  scoped_nsobject<InfoBubbleWindow> window(
+  base::scoped_nsobject<InfoBubbleWindow> window(
       [[InfoBubbleWindow alloc] initWithContentRect:contentRect
                                           styleMask:NSBorderlessWindowMask
                                             backing:NSBackingStoreBuffered
@@ -183,11 +183,13 @@
   NSRect frame = [[self window] frame];
   // Adjust the origin after we have switched from the managed user menu to the
   // regular menu.
-  if (expanded_)
+  CGFloat newWidth = std::min(kBubbleMinWidth + width, kBubbleMaxWidth);
+  if (expanded_) {
+    frame.origin.x += frame.size.width - newWidth;
     frame.origin.y += frame.size.height - yOffset;
+  }
   frame.size.height = yOffset;
-  frame.size.width = kBubbleMinWidth + width;
-  frame.size.width = std::min(NSWidth(frame), kBubbleMaxWidth);
+  frame.size.width = newWidth;
   [[self window] setFrame:frame display:YES];
 }
 
@@ -302,10 +304,11 @@
 }
 
 - (NSView*)configureManagedUserInformation:(CGFloat)width {
-  scoped_nsobject<NSView> container([[NSView alloc] initWithFrame:NSZeroRect]);
+  base::scoped_nsobject<NSView> container(
+      [[NSView alloc] initWithFrame:NSZeroRect]);
 
   // Add the limited user icon on the left side of the information TextView.
-  scoped_nsobject<NSImageView> iconView(
+  base::scoped_nsobject<NSImageView> iconView(
       [[NSImageView alloc] initWithFrame:NSMakeRect(5, 0, 16, 16)]);
   [iconView setImage:model_->GetManagedUserIcon().ToNSImage()];
   [container addSubview:iconView];
@@ -314,9 +317,9 @@
       base::SysUTF16ToNSString(model_->GetManagedUserInformation());
   NSDictionary* attributes =
       @{ NSFontAttributeName : [NSFont labelFontOfSize:12] };
-  scoped_nsobject<NSAttributedString> attrString(
+  base::scoped_nsobject<NSAttributedString> attrString(
       [[NSAttributedString alloc] initWithString:info attributes:attributes]);
-  scoped_nsobject<NSTextView> label(
+  base::scoped_nsobject<NSTextView> label(
       [[NSTextView alloc] initWithFrame:NSMakeRect(
           kManagedUserSpacing, 0, width - kManagedUserSpacing - 5, 0)]);
   [[label textStorage] setAttributedString:attrString];
@@ -333,12 +336,11 @@
 
 - (NSButton*)configureNewUserButton:(CGFloat)yOffset
                   updateWidthAdjust:(CGFloat*)widthAdjust {
-  scoped_nsobject<NSButton> newButton(
-      [[NSButton alloc] initWithFrame:NSMakeRect(
-          kLabelInset, yOffset, kBubbleMinWidth - kLabelInset, 16)]);
-  scoped_nsobject<HyperlinkButtonCell> buttonCell(
+  base::scoped_nsobject<NSButton> newButton([[NSButton alloc] initWithFrame:
+          NSMakeRect(kLabelInset, yOffset, kBubbleMinWidth - kLabelInset, 16)]);
+  base::scoped_nsobject<HyperlinkButtonCell> buttonCell(
       [[HyperlinkButtonCell alloc] initTextCell:
-          l10n_util::GetNSString(IDS_PROFILES_CREATE_NEW_PROFILE_LINK)]);
+              l10n_util::GetNSString(IDS_PROFILES_CREATE_NEW_PROFILE_LINK)]);
   [newButton setCell:buttonCell.get()];
   [newButton setFont:[NSFont labelFontOfSize:12.0]];
   [newButton setBezelStyle:NSRegularSquareBezelStyle];
@@ -352,12 +354,12 @@
 
 - (NSButton*)configureSwitchUserButton:(CGFloat)yOffset
                      updateWidthAdjust:(CGFloat*)widthAdjust {
-  scoped_nsobject<NSButton> newButton(
+  base::scoped_nsobject<NSButton> newButton(
       [[NSButton alloc] initWithFrame:NSMakeRect(
           kManagedUserSpacing, yOffset, kBubbleMinWidth - kLabelInset, 16)]);
-  scoped_nsobject<HyperlinkButtonCell> buttonCell(
+  base::scoped_nsobject<HyperlinkButtonCell> buttonCell(
       [[HyperlinkButtonCell alloc] initTextCell:
-          l10n_util::GetNSString(IDS_PROFILES_SWITCH_PROFILE_LINK)]);
+              l10n_util::GetNSString(IDS_PROFILES_SWITCH_PROFILE_LINK)]);
   [newButton setCell:buttonCell.get()];
   [newButton setFont:[NSFont labelFontOfSize:12.0]];
   [newButton setBezelStyle:NSRegularSquareBezelStyle];
diff --git a/chrome/browser/ui/cocoa/browser/avatar_menu_bubble_controller_unittest.mm b/chrome/browser/ui/cocoa/browser/avatar_menu_bubble_controller_unittest.mm
index 2f5b3be..153efc4 100644
--- a/chrome/browser/ui/cocoa/browser/avatar_menu_bubble_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/browser/avatar_menu_bubble_controller_unittest.mm
@@ -4,9 +4,10 @@
 
 #import "chrome/browser/ui/cocoa/browser/avatar_menu_bubble_controller.h"
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "base/message_loop/message_pump_mac.h"
 #include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/prefs/pref_service_syncable.h"
 #include "chrome/browser/profiles/avatar_menu_model.h"
 #include "chrome/browser/profiles/avatar_menu_model_observer.h"
 #include "chrome/browser/profiles/profile_info_cache.h"
@@ -27,8 +28,10 @@
     CocoaTest::SetUp();
     ASSERT_TRUE(manager_.SetUp());
 
-    manager_.CreateTestingProfile("test1", ASCIIToUTF16("Test 1"), 1);
-    manager_.CreateTestingProfile("test2", ASCIIToUTF16("Test 2"), 0);
+    manager_.CreateTestingProfile("test1", scoped_ptr<PrefServiceSyncable>(),
+                                  ASCIIToUTF16("Test 1"), 1);
+    manager_.CreateTestingProfile("test2", scoped_ptr<PrefServiceSyncable>(),
+                                  ASCIIToUTF16("Test 2"), 0);
 
     model_ = new AvatarMenuModel(manager_.profile_info_cache(), NULL, NULL);
 
@@ -113,10 +116,11 @@
   NSView* contents = [[controller() window] contentView];
   EXPECT_EQ(4U, [[contents subviews] count]);
 
-  scoped_nsobject<NSMutableArray> oldItems([[controller() items] copy]);
+  base::scoped_nsobject<NSMutableArray> oldItems([[controller() items] copy]);
 
   // Now create a new profile and notify the delegate.
-  manager()->CreateTestingProfile("test3", ASCIIToUTF16("Test 3"), 0);
+  manager()->CreateTestingProfile("test3", scoped_ptr<PrefServiceSyncable>(),
+                                  ASCIIToUTF16("Test 3"), 0);
 
   // Testing the bridge is not worth the effort...
   [controller() performLayout];
@@ -176,7 +180,7 @@
 @end
 
 TEST_F(AvatarMenuBubbleControllerTest, HighlightForEventType) {
-  scoped_nsobject<TestingAvatarMenuItemController> item(
+  base::scoped_nsobject<TestingAvatarMenuItemController> item(
       [[TestingAvatarMenuItemController alloc] initWithModelIndex:0
                                                    menuController:nil]);
   // Test non-active states first.
diff --git a/chrome/browser/ui/cocoa/browser/edit_search_engine_cocoa_controller_unittest.mm b/chrome/browser/ui/cocoa/browser/edit_search_engine_cocoa_controller_unittest.mm
index 2315cfc..32f365f 100644
--- a/chrome/browser/ui/cocoa/browser/edit_search_engine_cocoa_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/browser/edit_search_engine_cocoa_controller_unittest.mm
@@ -4,7 +4,6 @@
 
 #import "chrome/browser/ui/cocoa/browser/edit_search_engine_cocoa_controller.h"
 
-#include "base/memory/scoped_nsobject.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/search_engines/template_url.h"
 #include "chrome/browser/search_engines/template_url_service_factory.h"
diff --git a/chrome/browser/ui/cocoa/browser/password_generation_bubble_controller.mm b/chrome/browser/ui/cocoa/browser/password_generation_bubble_controller.mm
index 162b954..736ae92 100644
--- a/chrome/browser/ui/cocoa/browser/password_generation_bubble_controller.mm
+++ b/chrome/browser/ui/cocoa/browser/password_generation_bubble_controller.mm
@@ -13,7 +13,7 @@
 #import "chrome/browser/ui/cocoa/info_bubble_window.h"
 #include "chrome/browser/ui/cocoa/key_equivalent_constants.h"
 #import "chrome/browser/ui/cocoa/styled_text_field_cell.h"
-#include "components/autofill/browser/password_generator.h"
+#include "components/autofill/core/browser/password_generator.h"
 #include "components/autofill/core/common/autofill_messages.h"
 #include "components/autofill/core/common/password_generation_util.h"
 #include "content/public/browser/render_view_host.h"
@@ -69,8 +69,8 @@
  @private
   PasswordGenerationBubbleController* controller_;
   BOOL hovering_;
-  scoped_nsobject<NSImage> normalImage_;
-  scoped_nsobject<NSImage> hoverImage_;
+  base::scoped_nsobject<NSImage> normalImage_;
+  base::scoped_nsobject<NSImage> hoverImage_;
 }
 
 - (void)setUpWithController:(PasswordGenerationBubbleController*)controller
@@ -260,12 +260,10 @@
 - (void)setUpTrackingAreaInRect:(NSRect)frame
                          ofView:(PasswordGenerationTextField*)view {
   NSRect iconFrame = [self getIconFrame:frame];
-  scoped_nsobject<CrTrackingArea> area(
+  base::scoped_nsobject<CrTrackingArea> area(
       [[CrTrackingArea alloc] initWithRect:iconFrame
                                    options:NSTrackingMouseEnteredAndExited |
-                                           NSTrackingActiveAlways
-                                     owner:view
-                                  userInfo:nil]);
+          NSTrackingActiveAlways owner:view userInfo:nil]);
   [view addTrackingArea:area];
 }
 
@@ -308,7 +306,7 @@
                     kTopBorderOffset +
                     info_bubble::kBubbleArrowHeight);
   NSRect contentRect = NSMakeRect(0, 0, width, height);
-  scoped_nsobject<InfoBubbleWindow> window(
+  base::scoped_nsobject<InfoBubbleWindow> window(
       [[InfoBubbleWindow alloc] initWithContentRect:contentRect
                                           styleMask:NSBorderlessWindowMask
                                             backing:NSBackingStoreBuffered
@@ -364,12 +362,11 @@
   [button setAction:@selector(fillPassword:)];
   [contentView addSubview:button];
 
-  scoped_nsobject<NSTextField> title([[NSTextField alloc]
-                         initWithFrame:NSMakeRect(
-                             kBorderSize,
-                             kBorderSize + kTextFieldHeight + kVerticalSpacing,
-                             kTitleWidth,
-                             kTitleHeight)]);
+  base::scoped_nsobject<NSTextField> title([[NSTextField alloc] initWithFrame:
+          NSMakeRect(kBorderSize,
+                     kBorderSize + kTextFieldHeight + kVerticalSpacing,
+                     kTitleWidth,
+                     kTitleHeight)]);
   [title setEditable:NO];
   [title setBordered:NO];
   [title setStringValue:l10n_util::GetNSString(
diff --git a/chrome/browser/ui/cocoa/browser/password_generation_bubble_controller_unittest.mm b/chrome/browser/ui/cocoa/browser/password_generation_bubble_controller_unittest.mm
index 0e93aa6..f5c3db8 100644
--- a/chrome/browser/ui/cocoa/browser/password_generation_bubble_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/browser/password_generation_bubble_controller_unittest.mm
@@ -10,7 +10,7 @@
 #include "base/metrics/statistics_recorder.h"
 #include "base/strings/sys_string_conversions.h"
 #include "chrome/browser/ui/cocoa/cocoa_profile_test.h"
-#include "components/autofill/browser/password_generator.h"
+#include "components/autofill/core/browser/password_generator.h"
 #include "content/public/common/password_form.h"
 #include "testing/gtest_mac.h"
 
diff --git a/chrome/browser/ui/cocoa/browser/zoom_bubble_controller.h b/chrome/browser/ui/cocoa/browser/zoom_bubble_controller.h
index 8b909db..c92468e 100644
--- a/chrome/browser/ui/cocoa/browser/zoom_bubble_controller.h
+++ b/chrome/browser/ui/cocoa/browser/zoom_bubble_controller.h
@@ -6,7 +6,7 @@
 #define CHROME_BROWSER_UI_COCOA_BROWSER_ZOOM_BUBBLE_CONTROLLER_H_
 
 #include "base/mac/scoped_block.h"
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "chrome/browser/ui/cocoa/base_bubble_controller.h"
 #import "ui/base/cocoa/tracking_area.h"
 
@@ -31,7 +31,7 @@
   base::mac::ScopedBlock<void(^)(ZoomBubbleController*)> closeObserver_;
 
   // The text field that displays the current zoom percentage.
-  scoped_nsobject<NSTextField> zoomPercent_;
+  base::scoped_nsobject<NSTextField> zoomPercent_;
 
   // Whether or not the mouse is over the bubble.
   BOOL isMouseInside_;
diff --git a/chrome/browser/ui/cocoa/browser/zoom_bubble_controller.mm b/chrome/browser/ui/cocoa/browser/zoom_bubble_controller.mm
index a7c9b9e..0f2baa2 100644
--- a/chrome/browser/ui/cocoa/browser/zoom_bubble_controller.mm
+++ b/chrome/browser/ui/cocoa/browser/zoom_bubble_controller.mm
@@ -74,11 +74,11 @@
 
 - (id)initWithParentWindow:(NSWindow*)parentWindow
              closeObserver:(void(^)(ZoomBubbleController*))closeObserver {
-  scoped_nsobject<InfoBubbleWindow> window([[InfoBubbleWindow alloc]
-      initWithContentRect:NSMakeRect(0, 0, 200, 100)
-                styleMask:NSBorderlessWindowMask
-                  backing:NSBackingStoreBuffered
-                    defer:NO]);
+  base::scoped_nsobject<InfoBubbleWindow> window(
+      [[InfoBubbleWindow alloc] initWithContentRect:NSMakeRect(0, 0, 200, 100)
+                                          styleMask:NSBorderlessWindowMask
+                                            backing:NSBackingStoreBuffered
+                                              defer:NO]);
   if ((self = [super initWithWindow:window
                        parentWindow:parentWindow
                          anchoredAt:NSZeroPoint])) {
@@ -208,7 +208,8 @@
   // Separator view.
   rect.origin.x += NSWidth(rect);
   rect.size.width = 1;
-  scoped_nsobject<NSBox> separatorView([[NSBox alloc] initWithFrame:rect]);
+  base::scoped_nsobject<NSBox> separatorView(
+      [[NSBox alloc] initWithFrame:rect]);
   [separatorView setBoxType:NSBoxCustom];
   ui::NativeTheme* nativeTheme = ui::NativeTheme::instance();
   [separatorView setBorderColor:
@@ -241,7 +242,7 @@
 
 - (NSAttributedString*)attributedStringWithString:(NSString*)string
                                            fontSize:(CGFloat)fontSize {
-  scoped_nsobject<NSMutableParagraphStyle> paragraphStyle(
+  base::scoped_nsobject<NSMutableParagraphStyle> paragraphStyle(
       [[NSMutableParagraphStyle alloc] init]);
   [paragraphStyle setAlignment:NSCenterTextAlignment];
   NSDictionary* attributes = @{
@@ -260,7 +261,7 @@
 - (NSButton*)addButtonWithTitleID:(int)titleID
                          fontSize:(CGFloat)fontSize
                            action:(SEL)action {
-  scoped_nsobject<NSButton> button(
+  base::scoped_nsobject<NSButton> button(
       [[ZoomHoverButton alloc] initWithFrame:NSZeroRect]);
   NSString* title = l10n_util::GetNSStringWithFixup(titleID);
   [button setAttributedTitle:[self attributedStringWithString:title
@@ -273,7 +274,7 @@
 }
 
 - (NSTextField*)addZoomPercentTextField {
-  scoped_nsobject<NSTextField> textField(
+  base::scoped_nsobject<NSTextField> textField(
       [[NSTextField alloc] initWithFrame:NSZeroRect]);
   [textField setEditable:NO];
   [textField setBordered:NO];
diff --git a/chrome/browser/ui/cocoa/browser/zoom_bubble_controller_unittest.mm b/chrome/browser/ui/cocoa/browser/zoom_bubble_controller_unittest.mm
index 2d70b37..d5d4301 100644
--- a/chrome/browser/ui/cocoa/browser/zoom_bubble_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/browser/zoom_bubble_controller_unittest.mm
@@ -6,7 +6,7 @@
 
 #include "base/mac/bind_objc_block.h"
 #import "base/mac/mac_util.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #import "chrome/browser/ui/cocoa/info_bubble_window.h"
 #include "chrome/browser/ui/cocoa/run_loop_testing.h"
diff --git a/chrome/browser/ui/cocoa/browser_window_cocoa.h b/chrome/browser/ui/cocoa/browser_window_cocoa.h
index 199e421..ea17ec7 100644
--- a/chrome/browser/ui/cocoa/browser_window_cocoa.h
+++ b/chrome/browser/ui/cocoa/browser_window_cocoa.h
@@ -5,7 +5,7 @@
 #ifndef CHROME_BROWSER_UI_COCOA_BROWSER_WINDOW_COCOA_H_
 #define CHROME_BROWSER_UI_COCOA_BROWSER_WINDOW_COCOA_H_
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/bookmarks/bookmark_model.h"
 #include "chrome/browser/extensions/extension_keybinding_registry.h"
@@ -169,7 +169,7 @@
   Browser* browser_;  // weak, owned by controller
   BrowserWindowController* controller_;  // weak, owns us
   base::WeakPtrFactory<Browser> confirm_close_factory_;
-  scoped_nsobject<NSString> pending_window_title_;
+  base::scoped_nsobject<NSString> pending_window_title_;
   ui::WindowShowState initial_show_state_;
   NSInteger attention_request_id_;  // identifier from requestUserAttention
 };
diff --git a/chrome/browser/ui/cocoa/browser_window_cocoa.mm b/chrome/browser/ui/cocoa/browser_window_cocoa.mm
index 39813e2..5c7d583 100644
--- a/chrome/browser/ui/cocoa/browser_window_cocoa.mm
+++ b/chrome/browser/ui/cocoa/browser_window_cocoa.mm
@@ -6,10 +6,12 @@
 
 #include "base/bind.h"
 #include "base/command_line.h"
+#include "base/debug/crash_logging.h"
 #include "base/logging.h"
 #include "base/mac/mac_util.h"
 #include "base/message_loop.h"
 #include "base/prefs/pref_service.h"
+#include "base/strings/stringprintf.h"
 #include "base/strings/sys_string_conversions.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/download/download_shelf.h"
@@ -46,6 +48,7 @@
 #include "chrome/browser/ui/web_applications/web_app_ui.h"
 #include "chrome/browser/web_applications/web_app.h"
 #include "chrome/common/chrome_notification_types.h"
+#include "chrome/common/crash_keys.h"
 #include "chrome/common/pref_names.h"
 #include "content/public/browser/native_web_keyboard_event.h"
 #include "content/public/browser/notification_details.h"
@@ -106,7 +109,8 @@
 void CreateShortcuts(const ShellIntegration::ShortcutInfo& shortcut_info) {
   // creation_locations will be ignored by CreatePlatformShortcuts on Mac.
   ShellIntegration::ShortcutLocations creation_locations;
-  web_app::CreateShortcuts(shortcut_info, creation_locations);
+  web_app::CreateShortcuts(shortcut_info, creation_locations,
+                           web_app::ALLOW_DUPLICATE_SHORTCUTS);
 }
 
 }  // namespace
@@ -304,6 +308,16 @@
 }
 
 void BrowserWindowCocoa::ZoomChangedForActiveTab(bool can_show_bubble) {
+  // Debug data for <http://crbug.com/254977>.
+  base::debug::ScopedCrashKey window_type(
+      crash_keys::mac::kZoomBubbleWindowType,
+      base::StringPrintf("type=%d,app_type=%d,app_name=%s",
+          browser_->type(), browser_->app_type(),
+          browser_->app_name().c_str()));
+  base::debug::ScopedCrashKey url(crash_keys::mac::kZoomBubbleURL,
+      browser_->tab_strip_model()->GetActiveWebContents()->GetActiveURL().
+          possibly_invalid_spec());
+
   [controller_ zoomChangedForActiveTab:can_show_bubble ? YES : NO];
 }
 
@@ -497,13 +511,12 @@
   WebContents* web_contents =
         browser_->tab_strip_model()->GetActiveWebContents();
   if (type == ONE_CLICK_SIGNIN_BUBBLE_TYPE_BUBBLE) {
-    scoped_nsobject<OneClickSigninBubbleController> bubble_controller(
-        [[OneClickSigninBubbleController alloc]
-            initWithBrowserWindowController:cocoa_controller()
-                                webContents:web_contents
-                               errorMessage:base::SysUTF16ToNSString(
-                                                error_message)
-                                   callback:start_sync_callback]);
+    base::scoped_nsobject<OneClickSigninBubbleController> bubble_controller([
+            [OneClickSigninBubbleController alloc]
+        initWithBrowserWindowController:cocoa_controller()
+                            webContents:web_contents
+                           errorMessage:base::SysUTF16ToNSString(error_message)
+                               callback:start_sync_callback]);
     [bubble_controller showWindow:nil];
   } else {
     // Deletes itself when the dialog closes.
@@ -673,7 +686,6 @@
 
 void BrowserWindowCocoa::ModelChanged(const SearchModel::State& old_state,
                                       const SearchModel::State& new_state) {
-  [controller_ updateBookmarkBarStateForInstantOverlay];
 }
 
 void BrowserWindowCocoa::DestroyBrowser() {
diff --git a/chrome/browser/ui/cocoa/browser_window_cocoa_browsertest.mm b/chrome/browser/ui/cocoa/browser_window_cocoa_browsertest.mm
index 8577dfe..831f1d0 100644
--- a/chrome/browser/ui/cocoa/browser_window_cocoa_browsertest.mm
+++ b/chrome/browser/ui/cocoa/browser_window_cocoa_browsertest.mm
@@ -13,7 +13,7 @@
 #include "chrome/browser/ui/cocoa/browser_window_cocoa.h"
 #import "chrome/browser/ui/cocoa/info_bubble_window.h"
 #include "chrome/test/base/in_process_browser_test.h"
-#include "components/autofill/browser/password_generator.h"
+#include "components/autofill/core/browser/password_generator.h"
 #include "content/public/common/password_form.h"
 #include "ui/gfx/native_widget_types.h"
 #include "ui/gfx/rect.h"
diff --git a/chrome/browser/ui/cocoa/browser_window_cocoa_unittest.mm b/chrome/browser/ui/cocoa/browser_window_cocoa_unittest.mm
index 53835b3..8bb2f9e 100644
--- a/chrome/browser/ui/cocoa/browser_window_cocoa_unittest.mm
+++ b/chrome/browser/ui/cocoa/browser_window_cocoa_unittest.mm
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 #include "base/mac/mac_util.h"
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/strings/string_util.h"
 #include "chrome/browser/ui/bookmarks/bookmark_utils.h"
@@ -14,8 +14,8 @@
 #include "chrome/common/pref_names.h"
 #include "content/public/browser/notification_details.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#import "third_party/ocmock/gtest_support.h"
 #import "third_party/ocmock/OCMock/OCMock.h"
+#import "third_party/ocmock/gtest_support.h"
 
 // Main test class.
 class BrowserWindowCocoaTest : public CocoaProfileTest {
@@ -79,7 +79,7 @@
   // Wrap the FakeController in a scoped_nsobject instead of autoreleasing in
   // windowWillClose: because we never actually open a window in this test (so
   // windowWillClose: never gets called).
-  scoped_nsobject<FakeController> fake_controller(
+  base::scoped_nsobject<FakeController> fake_controller(
       [[FakeController alloc] init]);
   scoped_ptr<BrowserWindowCocoa> bwc(new BrowserWindowCocoa(
       browser(), static_cast<BrowserWindowController*>(fake_controller.get())));
@@ -99,7 +99,7 @@
   // Wrap the FakeController in a scoped_nsobject instead of autoreleasing in
   // windowWillClose: because we never actually open a window in this test (so
   // windowWillClose: never gets called).
-  scoped_nsobject<FakeController> fake_controller(
+  base::scoped_nsobject<FakeController> fake_controller(
       [[FakeController alloc] init]);
   scoped_ptr<BrowserWindowCocoa> bwc(new BrowserWindowCocoa(
       browser(), static_cast<BrowserWindowController*>(fake_controller.get())));
diff --git a/chrome/browser/ui/cocoa/browser_window_controller.h b/chrome/browser/ui/cocoa/browser_window_controller.h
index 8ce1492..f50723c 100644
--- a/chrome/browser/ui/cocoa/browser_window_controller.h
+++ b/chrome/browser/ui/cocoa/browser_window_controller.h
@@ -12,7 +12,7 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "base/memory/scoped_ptr.h"
 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.h"
 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bubble_controller.h"
@@ -62,16 +62,17 @@
   scoped_ptr<Browser> browser_;
   NSWindow* savedRegularWindow_;
   scoped_ptr<BrowserWindowCocoa> windowShim_;
-  scoped_nsobject<ToolbarController> toolbarController_;
-  scoped_nsobject<TabStripController> tabStripController_;
-  scoped_nsobject<FindBarCocoaController> findBarCocoaController_;
-  scoped_nsobject<InfoBarContainerController> infoBarContainerController_;
-  scoped_nsobject<DownloadShelfController> downloadShelfController_;
-  scoped_nsobject<BookmarkBarController> bookmarkBarController_;
-  scoped_nsobject<DevToolsController> devToolsController_;
-  scoped_nsobject<OverlayableContentsController> overlayableContentsController_;
-  scoped_nsobject<PresentationModeController> presentationModeController_;
-  scoped_nsobject<FullscreenExitBubbleController>
+  base::scoped_nsobject<ToolbarController> toolbarController_;
+  base::scoped_nsobject<TabStripController> tabStripController_;
+  base::scoped_nsobject<FindBarCocoaController> findBarCocoaController_;
+  base::scoped_nsobject<InfoBarContainerController> infoBarContainerController_;
+  base::scoped_nsobject<DownloadShelfController> downloadShelfController_;
+  base::scoped_nsobject<BookmarkBarController> bookmarkBarController_;
+  base::scoped_nsobject<DevToolsController> devToolsController_;
+  base::scoped_nsobject<OverlayableContentsController>
+      overlayableContentsController_;
+  base::scoped_nsobject<PresentationModeController> presentationModeController_;
+  base::scoped_nsobject<FullscreenExitBubbleController>
       fullscreenExitBubbleController_;
 
   // Strong. StatusBubble is a special case of a strong reference that
@@ -106,16 +107,16 @@
   // The view controller that manages the incognito badge or the multi-profile
   // avatar icon. The view is always in the view hierarchy, but will be hidden
   // unless it's appropriate to show it.
-  scoped_nsobject<AvatarButtonController> avatarButtonController_;
+  base::scoped_nsobject<AvatarButtonController> avatarButtonController_;
 
   // Lazily created view which draws the background for the floating set of bars
   // in presentation mode (for window types having a floating bar; it remains
   // nil for those which don't).
-  scoped_nsobject<NSView> floatingBarBackingView_;
+  base::scoped_nsobject<NSView> floatingBarBackingView_;
 
   // The borderless window used in fullscreen mode.  Lion reuses the original
   // window in fullscreen mode, so this is always nil on Lion.
-  scoped_nsobject<NSWindow> fullscreenWindow_;
+  base::scoped_nsobject<NSWindow> fullscreenWindow_;
 
   // Tracks whether presentation mode was entered from fullscreen mode or
   // directly from normal windowed mode.  Used to determine what to do when
@@ -143,7 +144,7 @@
   // where keyboard focus is. Whenever an object requires bar visibility, it has
   // itself added to |barVisibilityLocks_|. When it no longer requires bar
   // visibility, it has itself removed.
-  scoped_nsobject<NSMutableSet> barVisibilityLocks_;
+  base::scoped_nsobject<NSMutableSet> barVisibilityLocks_;
 
   // Bar visibility locks and releases only result (when appropriate) in changes
   // in visible state when the following is |YES|.
@@ -159,10 +160,6 @@
   // handle.
   scoped_ptr<ExtensionKeybindingRegistryCocoa> extension_keybinding_registry_;
 
-  // The offset between the bottom of the toolbar and web contents. This is used
-  // to push the web contents below the bookmark bar.
-  CGFloat toolbarToWebContentsOffset_;
-
   // The number of history overlay views being shown.
   NSUInteger historyOverlayCount_;
 }
@@ -331,9 +328,6 @@
 // coordinates.
 - (NSPoint)bookmarkBubblePoint;
 
-// Shows or hides the Instant overlay contents.
-- (void)commitInstant;
-
 // Returns the frame, in Cocoa (unflipped) screen coordinates, of the area where
 // Instant results are.  If Instant is not showing, returns the frame of where
 // it would be.
@@ -344,9 +338,6 @@
          returnCode:(NSInteger)code
             context:(void*)context;
 
-// Updates the bookmark bar visibility based on the instant overlay state.
-- (void)updateBookmarkBarStateForInstantOverlay;
-
 // Called when the find bar visibility changes. This is used to update the
 // allowOverlappingViews state.
 - (void)onFindBarVisibilityChanged;
diff --git a/chrome/browser/ui/cocoa/browser_window_controller.mm b/chrome/browser/ui/cocoa/browser_window_controller.mm
index d200899..f9fb551 100644
--- a/chrome/browser/ui/cocoa/browser_window_controller.mm
+++ b/chrome/browser/ui/cocoa/browser_window_controller.mm
@@ -10,11 +10,9 @@
 #include "base/command_line.h"
 #include "base/mac/bundle_locations.h"
 #include "base/mac/mac_util.h"
-#import "base/memory/scoped_nsobject.h"
 #include "base/strings/sys_string_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/app/chrome_command_ids.h"  // IDC_*
-#include "chrome/browser/bookmarks/bookmark_editor.h"
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/devtools/devtools_window.h"
@@ -25,6 +23,7 @@
 #include "chrome/browser/signin/signin_ui_util.h"
 #include "chrome/browser/themes/theme_service.h"
 #include "chrome/browser/themes/theme_service_factory.h"
+#include "chrome/browser/ui/bookmarks/bookmark_editor.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_command_controller.h"
 #include "chrome/browser/ui/browser_commands.h"
@@ -49,6 +48,7 @@
 #import "chrome/browser/ui/cocoa/fullscreen_window.h"
 #import "chrome/browser/ui/cocoa/infobars/infobar_container_controller.h"
 #import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor.h"
+#import "chrome/browser/ui/cocoa/nsview_additions.h"
 #import "chrome/browser/ui/cocoa/presentation_mode_controller.h"
 #import "chrome/browser/ui/cocoa/status_bubble_mac.h"
 #import "chrome/browser/ui/cocoa/tab_contents/overlayable_contents_controller.h"
@@ -268,11 +268,10 @@
     windowShim_.reset(new BrowserWindowCocoa(browser, self));
 
     // Eagerly enable core animation if requested.
-    if (CommandLine::ForCurrentProcess()->HasSwitch(
-            switches::kUseCoreAnimation) &&
-        CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
-            switches::kUseCoreAnimation) != "lazy") {
+    if ([self coreAnimationStatus] ==
+            browser_window_controller::kCoreAnimationEnabledAlways) {
       [[[self window] contentView] setWantsLayer:YES];
+      [[self tabStripView] setWantsLayer:YES];
     }
 
     // Set different minimum sizes on tabbed windows vs non-tabbed, e.g. popups.
@@ -345,8 +344,7 @@
     // Create the overlayable contents controller.  This provides the switch
     // view that TabStripController needs.
     overlayableContentsController_.reset(
-        [[OverlayableContentsController alloc] initWithBrowser:browser
-                                              windowController:self]);
+        [[OverlayableContentsController alloc] initWithBrowser:browser]);
     [[overlayableContentsController_ view]
         setFrame:[[devToolsController_ view] bounds]];
     [[devToolsController_ view]
@@ -598,15 +596,20 @@
   // have to save the window position before we call orderOut:.
   [self saveWindowPositionIfNeeded];
 
+  bool fast_tab_closing_enabled =
+      CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableFastUnload);
+
   if (!browser_->tab_strip_model()->empty()) {
-    // Tab strip isn't empty.  Hide the window (so it appears to have closed
+    // Tab strip isn't empty.  Hide the frame (so it appears to have closed
     // immediately) and close all the tabs, allowing the renderers to shut
     // down. When the tab strip is empty we'll be called back again.
     [[self window] orderOut:self];
     browser_->OnWindowClosing();
-    browser_->tab_strip_model()->CloseAllTabs();
+    if (fast_tab_closing_enabled)
+      browser_->tab_strip_model()->CloseAllTabs();
     return NO;
-  } else if (!browser_->HasCompletedUnloadProcessing()) {
+  } else if (fast_tab_closing_enabled &&
+        !browser_->HasCompletedUnloadProcessing()) {
     // The browser needs to finish running unload handlers.
     // Hide the window (so it appears to have closed immediately), and
     // the browser will call us back again when it is ready to close.
@@ -1636,9 +1639,8 @@
 }
 
 - (void)userChangedTheme {
-  // TODO(dmaclach): Instead of redrawing the whole window, views that care
-  // about the active window state should be registering for notifications.
-  [[self window] setViewsNeedDisplay:YES];
+  NSView* contentView = [[self window] contentView];
+  [[contentView superview] cr_recursivelySetNeedsDisplay:YES];
 }
 
 - (ui::ThemeProvider*)themeProvider {
@@ -1955,19 +1957,15 @@
   NSView* toolbarView = [toolbarController_ view];
   NSRect anchorRect = [toolbarView frame];
 
-  // Adjust to account for height and possible bookmark bar.
+  // Adjust to account for height and possible bookmark bar. Compress by 1
+  // to account for the separator.
   anchorRect.origin.y =
-      NSMaxY(anchorRect) - [toolbarController_ desiredHeightForCompression:0];
+      NSMaxY(anchorRect) - [toolbarController_ desiredHeightForCompression:1];
 
   // Shift to window base coordinates.
   return [[toolbarView superview] convertRect:anchorRect toView:nil];
 }
 
-- (void)commitInstant {
-  if (BrowserInstantController* controller = browser_->instant_controller())
-    controller->instant()->CommitIfPossible(INSTANT_COMMIT_FOCUS_LOST);
-}
-
 - (NSRect)instantFrame {
   // The view's bounds are in its own coordinate system.  Convert that to the
   // window base coordinate system, then translate it into the screen's
@@ -1995,13 +1993,6 @@
   [sheet orderOut:self];
 }
 
-- (void)updateBookmarkBarStateForInstantOverlay {
-  [toolbarController_ setDividerOpacity:[self toolbarDividerOpacity]];
-  [self updateContentOffsets];
-  [self updateSubviewZOrder:[self inPresentationMode]];
-  [self updateInfoBarTipVisibility];
-}
-
 - (void)onFindBarVisibilityChanged {
   [self updateAllowOverlappingViews:[self inPresentationMode]];
 }
diff --git a/chrome/browser/ui/cocoa/browser_window_controller_browsertest.mm b/chrome/browser/ui/cocoa/browser_window_controller_browsertest.mm
index adb1817..8ec94d1 100644
--- a/chrome/browser/ui/cocoa/browser_window_controller_browsertest.mm
+++ b/chrome/browser/ui/cocoa/browser_window_controller_browsertest.mm
@@ -12,7 +12,6 @@
 #include "chrome/browser/infobars/infobar_service.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
-#include "chrome/browser/search/search.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_commands.h"
 #include "chrome/browser/ui/browser_list.h"
@@ -29,7 +28,6 @@
 #include "chrome/browser/ui/extensions/application_launch.h"
 #include "chrome/browser/ui/find_bar/find_bar_controller.h"
 #include "chrome/browser/ui/find_bar/find_bar.h"
-#include "chrome/browser/ui/search/search_model.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/testing_profile.h"
@@ -106,27 +104,6 @@
         browser()->window()->GetNativeWindow()];
   }
 
-  void ShowInstantResults() {
-    chrome::EnableInstantExtendedAPIForTesting();
-    SearchMode mode(SearchMode::MODE_SEARCH_SUGGESTIONS,
-                    SearchMode::ORIGIN_SEARCH);
-    browser()->search_model()->SetMode(mode);
-    browser()->search_model()->SetTopBarsVisible(false);
-    EXPECT_TRUE(browser()->search_model()->mode().is_search_suggestions());
-    EXPECT_EQ(browser_window_controller::kInstantUIFullPageResults,
-              [controller() currentInstantUIState]);
-  }
-
-  void ShowInstantNTP() {
-    chrome::EnableInstantExtendedAPIForTesting();
-    SearchMode mode(SearchMode::MODE_NTP, SearchMode::ORIGIN_NTP);
-    browser()->search_model()->SetMode(mode);
-    browser()->search_model()->SetTopBarsVisible(true);
-    EXPECT_TRUE(browser()->search_model()->mode().is_ntp());
-    EXPECT_EQ(browser_window_controller::kInstantUINone,
-              [controller() currentInstantUIState]);
-  }
-
   void ShowInfoBar() {
     content::WebContents* web_contents =
         browser()->tab_strip_model()->GetActiveWebContents();
@@ -138,15 +115,6 @@
            animate:NO];
   }
 
-  void HideInstant() {
-    SearchMode mode;
-    browser()->search_model()->SetMode(mode);
-    browser()->search_model()->SetTopBarsVisible(true);
-    EXPECT_TRUE(browser()->search_model()->mode().is_default());
-    EXPECT_EQ(browser_window_controller::kInstantUINone,
-              [controller() currentInstantUIState]);
-  }
-
   NSView* GetViewWithID(ViewID view_id) const {
     switch (view_id) {
       case VIEW_ID_FULLSCREEN_FLOATING_BAR:
@@ -296,68 +264,6 @@
   VerifyZOrder(view_list);
 }
 
-// Normal mode with Instant results showing. Should be same z-order as normal
-// mode except find bar is below content area.
-IN_PROC_BROWSER_TEST_F(BrowserWindowControllerTest, ZOrderNormalInstant) {
-  ShowInstantResults();
-  browser()->GetFindBarController();  // add find bar
-
-  std::vector<ViewID> view_list;
-  view_list.push_back(VIEW_ID_BOOKMARK_BAR);
-  view_list.push_back(VIEW_ID_TOOLBAR);
-  view_list.push_back(VIEW_ID_INFO_BAR);
-  view_list.push_back(VIEW_ID_TAB_CONTENT_AREA);
-  view_list.push_back(VIEW_ID_FIND_BAR);
-  view_list.push_back(VIEW_ID_DOWNLOAD_SHELF);
-  VerifyZOrder(view_list);
-}
-
-// Presentation mode with Instant results showing. Should be exact same as
-// non-Instant presentation mode.
-IN_PROC_BROWSER_TEST_F(BrowserWindowControllerTest,
-                       DISABLED_ZOrderInstantPresentationMode) {
-  // TODO(kbr): re-enable: http://crbug.com/222296
-  if (base::mac::IsOSMountainLionOrLater())
-    return;
-
-  chrome::ToggleFullscreenMode(browser());
-  ShowInstantResults();
-  browser()->GetFindBarController();  // add find bar
-
-  std::vector<ViewID> view_list;
-  view_list.push_back(VIEW_ID_INFO_BAR);
-  view_list.push_back(VIEW_ID_TAB_CONTENT_AREA);
-  view_list.push_back(VIEW_ID_FULLSCREEN_FLOATING_BAR);
-  view_list.push_back(VIEW_ID_BOOKMARK_BAR);
-  view_list.push_back(VIEW_ID_TOOLBAR);
-  view_list.push_back(VIEW_ID_FIND_BAR);
-  view_list.push_back(VIEW_ID_DOWNLOAD_SHELF);
-  VerifyZOrder(view_list);
-}
-
-// Verify that in presentation mode, Instant search results are below the
-// floating toolbar.
-IN_PROC_BROWSER_TEST_F(BrowserWindowControllerTest,
-                       DISABLED_OverlayOffsetInstantPresentationMode) {
-  chrome::ToggleFullscreenMode(browser());
-  ShowInstantResults();
-  [controller() setFloatingBarShownFraction:0.0];
-  EXPECT_EQ(
-      0, [[controller() overlayableContentsController] overlayContentsOffset]);
-  EXPECT_EQ(
-      0, [[controller() overlayableContentsController] activeContainerOffset]);
-  [controller() setFloatingBarShownFraction:1.0];
-
-  NSView* floating_bar = GetViewWithID(VIEW_ID_FULLSCREEN_FLOATING_BAR);
-  CGFloat floating_bar_height = NSHeight([floating_bar frame]);
-  EXPECT_EQ(
-      floating_bar_height,
-      [[controller() overlayableContentsController] overlayContentsOffset]);
-  EXPECT_EQ(
-      floating_bar_height,
-      [[controller() overlayableContentsController] activeContainerOffset]);
-}
-
 // Verify that if the fullscreen floating bar view is below the tab content area
 // then calling |updateSubviewZOrder:| will correctly move back above.
 IN_PROC_BROWSER_TEST_F(BrowserWindowControllerTest,
@@ -386,161 +292,6 @@
   VerifyZOrder(view_list);
 }
 
-// Verify that in non-Instant presentation mode the content area is beneath
-// the bookmark bar and info bar.
-IN_PROC_BROWSER_TEST_F(BrowserWindowControllerTest, ContentOffset) {
-  OverlayableContentsController* overlay =
-      [controller() overlayableContentsController];
-  // Just toolbar.
-  EXPECT_EQ(1, [overlay activeContainerOffset]);
-
-  // Plus bookmark bar.
-  browser()->window()->ToggleBookmarkBar();
-  CGFloat bookmark_bar_offset =
-      GetViewHeight(VIEW_ID_BOOKMARK_BAR) - bookmarks::kBookmarkBarOverlap + 1;
-  EXPECT_EQ(bookmark_bar_offset, [overlay activeContainerOffset]);
-
-  // Plus info bar.
-  ShowInfoBar();
-  EXPECT_EQ(bookmark_bar_offset + GetViewHeight(VIEW_ID_INFO_BAR),
-            [overlay activeContainerOffset]);
-
-  // Minus bookmark bar.
-  browser()->window()->ToggleBookmarkBar();
-  EXPECT_EQ(GetViewHeight(VIEW_ID_INFO_BAR) + 1,
-            [overlay activeContainerOffset]);
-}
-
-// Verify that in non-Instant presentation mode the content area is beneath
-// the info bar.
-IN_PROC_BROWSER_TEST_F(BrowserWindowControllerTest,
-                       DISABLED_ContentOffsetPresentationMode) {
-  // TODO(kbr): re-enable: http://crbug.com/222296
-  if (base::mac::IsOSMountainLionOrLater())
-    return;
-
-  chrome::ToggleFullscreenMode(browser());
-  OverlayableContentsController* overlay =
-      [controller() overlayableContentsController];
-
-  // Just toolbar.
-  EXPECT_EQ(0, [overlay activeContainerOffset]);
-
-  // Plus bookmark bar.
-  browser()->window()->ToggleBookmarkBar();
-  EXPECT_EQ(0, [overlay activeContainerOffset]);
-
-  // Plus info bar.
-  ShowInfoBar();
-  EXPECT_EQ(0, [overlay activeContainerOffset]);
-
-  // Minus bookmark bar.
-  browser()->window()->ToggleBookmarkBar();
-  EXPECT_EQ(0, [overlay activeContainerOffset]);
-}
-
-// Verify that when showing Instant results the content area overlaps the
-// bookmark bar and info bar.
-IN_PROC_BROWSER_TEST_F(BrowserWindowControllerTest, ContentOffsetInstant) {
-  OverlayableContentsController* overlay =
-      [controller() overlayableContentsController];
-  ShowInstantResults();
-
-  // Just toolbar.
-  EXPECT_EQ(0, [overlay activeContainerOffset]);
-
-  // Plus bookmark bar.
-  browser()->window()->ToggleBookmarkBar();
-  EXPECT_EQ(0, [overlay activeContainerOffset]);
-
-  // Plus info bar.
-  ShowInfoBar();
-  EXPECT_EQ(0, [overlay activeContainerOffset]);
-
-  // Minus bookmark bar.
-  browser()->window()->ToggleBookmarkBar();
-  EXPECT_EQ(0, [overlay activeContainerOffset]);
-}
-
-// The Instant NTP case is same as normal case except that the overlay is
-// also shifted down.
-IN_PROC_BROWSER_TEST_F(BrowserWindowControllerTest, ContentOffsetInstantNTP) {
-  ShowInstantNTP();
-  OverlayableContentsController* overlay =
-      [controller() overlayableContentsController];
-
-  // Just toolbar.
-  EXPECT_EQ(1, [overlay activeContainerOffset]);
-
-  // Plus bookmark bar.
-  browser()->window()->ToggleBookmarkBar();
-  CGFloat bookmark_bar_offset =
-      GetViewHeight(VIEW_ID_BOOKMARK_BAR) - bookmarks::kBookmarkBarOverlap + 1;
-  EXPECT_EQ(bookmark_bar_offset, [overlay activeContainerOffset]);
-
-  // Plus info bar.
-  ShowInfoBar();
-  EXPECT_EQ(bookmark_bar_offset + GetViewHeight(VIEW_ID_INFO_BAR),
-            [overlay activeContainerOffset]);
-
-  // Minus bookmark bar.
-  browser()->window()->ToggleBookmarkBar();
-  EXPECT_EQ(GetViewHeight(VIEW_ID_INFO_BAR) + 1,
-            [overlay activeContainerOffset]);
-}
-
-// Verify that the find bar is positioned corerctly when a full page instant
-// search result is displayed.
-IN_PROC_BROWSER_TEST_F(BrowserWindowControllerTest, FindBarOffsetInstant) {
-  // Add bookmark bar and find bar.
-  browser()->window()->ToggleBookmarkBar();
-  browser()->GetFindBarController();
-
-  CGFloat line_width = [GetViewWithID(VIEW_ID_FIND_BAR) cr_lineWidth];
-  NSRect bookmark_bar_frame = [GetViewWithID(VIEW_ID_BOOKMARK_BAR) frame];
-  NSRect find_bar_frame = [GetViewWithID(VIEW_ID_FIND_BAR) frame];
-  EXPECT_EQ(NSMinY(bookmark_bar_frame), NSMaxY(find_bar_frame) - line_width);
-
-  // Show instant and add a find bar to it.
-  ShowInstantResults();
-  browser()->GetFindBarController()->find_bar()->Show(false);;
-
-  NSRect toolbar_bar_frame = [GetViewWithID(VIEW_ID_TOOLBAR) frame];
-  find_bar_frame = [GetViewWithID(VIEW_ID_FIND_BAR) frame];
-  EXPECT_EQ(NSMinY(toolbar_bar_frame) - bookmarks::kBookmarkBarOverlap + 1 -
-            line_width,
-            NSMaxY(find_bar_frame));
-}
-
-// Verify that if bookmark bar is underneath Instant search results then
-// clicking on Instant search results still works.
-IN_PROC_BROWSER_TEST_F(BrowserWindowControllerTest,
-                       InstantSearchResultsHitTest) {
-  browser()->window()->ToggleBookmarkBar();
-  ShowInstantResults();
-
-  NSView* bookmarkView = [[controller() bookmarkBarController] view];
-  NSView* contentView = [[controller() window] contentView];
-  NSPoint point = [bookmarkView convertPoint:NSMakePoint(1, 1)
-                                      toView:[contentView superview]];
-
-  EXPECT_FALSE([[contentView hitTest:point] isDescendantOf:bookmarkView]);
-  EXPECT_TRUE([[contentView hitTest:point]
-      isDescendantOf:[controller() tabContentArea]]);
-}
-
-// Verify that |currentInstantUIState| returns the correct value for search
-// results mode.
-IN_PROC_BROWSER_TEST_F(BrowserWindowControllerTest, InstantSearchResultsMode) {
-  chrome::EnableInstantExtendedAPIForTesting();
-  SearchMode mode(SearchMode::MODE_SEARCH_RESULTS, SearchMode::ORIGIN_SEARCH);
-  browser()->search_model()->SetMode(mode);
-  browser()->search_model()->SetTopBarsVisible(false);
-  EXPECT_TRUE(browser()->search_model()->mode().is_search_results());
-  EXPECT_EQ(browser_window_controller::kInstantUIFullPageResults,
-            [controller() currentInstantUIState]);
-}
-
 IN_PROC_BROWSER_TEST_F(BrowserWindowControllerTest, SheetPosition) {
   ASSERT_TRUE([controller() isKindOfClass:[BrowserWindowController class]]);
   EXPECT_TRUE([controller() isTabbedWindow]);
@@ -574,7 +325,7 @@
   chrome::OpenAppShortcutWindow(
       browser()->profile(), GURL("about:blank"), initial_bounds);
   Browser* popup_browser = BrowserList::GetInstance(
-      chrome::HOST_DESKTOP_TYPE_NATIVE)->GetLastActive();
+      chrome::GetActiveDesktop())->GetLastActive();
   NSWindow* popupWindow = popup_browser->window()->GetNativeWindow();
   BrowserWindowController* popupController =
       [BrowserWindowController browserWindowControllerForWindow:popupWindow];
@@ -599,22 +350,6 @@
   [popupController close];
 }
 
-// Verify that the info bar tip is hidden when the instant overlay is visible.
-IN_PROC_BROWSER_TEST_F(BrowserWindowControllerTest,
-                       InfoBarTipHiddenForInstant) {
-  ShowInfoBar();
-  EXPECT_FALSE(
-      [[controller() infoBarContainerController] shouldSuppressTopInfoBarTip]);
-
-  ShowInstantResults();
-  EXPECT_TRUE(
-      [[controller() infoBarContainerController] shouldSuppressTopInfoBarTip]);
-
-  HideInstant();
-  EXPECT_FALSE(
-      [[controller() infoBarContainerController] shouldSuppressTopInfoBarTip]);
-}
-
 // Verify that the info bar tip is hidden when the toolbar is not visible.
 IN_PROC_BROWSER_TEST_F(BrowserWindowControllerTest,
                        InfoBarTipHiddenForWindowWithoutToolbar) {
@@ -654,7 +389,7 @@
       browser()->tab_strip_model()->GetActiveWebContents()->GetView();
   EXPECT_FALSE(web_contents_view->GetAllowOverlappingViews());
 
-  scoped_nsobject<HistoryOverlayController> overlay(
+  base::scoped_nsobject<HistoryOverlayController> overlay(
       [[HistoryOverlayController alloc] initForMode:kHistoryOverlayModeBack]);
   [overlay showPanelForView:web_contents_view->GetNativeView()];
   EXPECT_TRUE(web_contents_view->GetAllowOverlappingViews());
diff --git a/chrome/browser/ui/cocoa/browser_window_controller_private.h b/chrome/browser/ui/cocoa/browser_window_controller_private.h
index 6a70dc0..f3ba8dc 100644
--- a/chrome/browser/ui/cocoa/browser_window_controller_private.h
+++ b/chrome/browser/ui/cocoa/browser_window_controller_private.h
@@ -9,13 +9,10 @@
 
 namespace browser_window_controller {
 
-enum InstantUIState {
-  kInstantUINone,
-  // Instant suggestions are displayed in a overlay overlapping the tab
-  // contents.
-  kInstantUIOverlay,
-  // Instant suggestions are displayed in the main tab contents.
-  kInstantUIFullPageResults,
+enum CoreAnimationStatus {
+  kCoreAnimationDisabled,
+  kCoreAnimationEnabledLazy,
+  kCoreAnimationEnabledAlways,
 };
 
 }  // namespace browser_window_controller
@@ -156,15 +153,6 @@
 // The opacity for the toolbar divider; 0 means that it shouldn't be shown.
 - (CGFloat)toolbarDividerOpacity;
 
-// This is used to check if either the instant overlay or full page instant
-// search results are currently being displayed.
-- (browser_window_controller::InstantUIState)currentInstantUIState;
-
-// Updates the content offets of the tab strip controller and the overlayable
-// contents controller. This is used to adjust the overlap between those views
-// and the bookmark bar.
-- (void)updateContentOffsets;
-
 // Ensures the z-order of subviews is correct.
 - (void)updateSubviewZOrder:(BOOL)inPresentationMode;
 
@@ -173,6 +161,9 @@
 // Update visibility of the infobar tip, depending on the state of the window.
 - (void)updateInfoBarTipVisibility;
 
+// Checks if core animation should be enabled or not.
+- (browser_window_controller::CoreAnimationStatus)coreAnimationStatus;
+
 @end  // @interface BrowserWindowController(Private)
 
 #endif  // CHROME_BROWSER_UI_COCOA_BROWSER_WINDOW_CONTROLLER_PRIVATE_H_
diff --git a/chrome/browser/ui/cocoa/browser_window_controller_private.mm b/chrome/browser/ui/cocoa/browser_window_controller_private.mm
index 39c04b0..43de7e5 100644
--- a/chrome/browser/ui/cocoa/browser_window_controller_private.mm
+++ b/chrome/browser/ui/cocoa/browser_window_controller_private.mm
@@ -7,13 +7,12 @@
 #include <cmath>
 
 #include "base/command_line.h"
-#import "base/memory/scoped_nsobject.h"
+#import "base/mac/scoped_nsobject.h"
 #include "base/prefs/pref_service.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_info_util.h"
-#include "chrome/browser/search/search.h"
 #include "chrome/browser/ui/bookmarks/bookmark_tab_helper.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_window_state.h"
@@ -34,8 +33,6 @@
 #import "chrome/browser/ui/cocoa/tabs/tab_strip_view.h"
 #import "chrome/browser/ui/cocoa/toolbar/toolbar_controller.h"
 #include "chrome/browser/ui/fullscreen/fullscreen_controller.h"
-#include "chrome/browser/ui/search/search_model.h"
-#include "chrome/browser/ui/search/search_ui.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
@@ -214,7 +211,6 @@
   DCHECK_LE(maxY, NSMaxY(contentBounds) + yOffset);
 
   // Place the toolbar at the top of the reserved area.
-  CGFloat toolbarTopY = maxY;
   maxY = [self layoutToolbarAtMinX:minX maxY:maxY width:width];
 
   // If we're not displaying the bookmark bar below the info bar, then it goes
@@ -222,7 +218,6 @@
   BOOL placeBookmarkBarBelowInfoBar = [self placeBookmarkBarBelowInfoBar];
   if (!placeBookmarkBarBelowInfoBar)
     maxY = [self layoutBookmarkBarAtMinX:minX maxY:maxY width:width];
-  CGFloat toolbarBottomY = maxY;
 
   // The floating bar backing view doesn't actually add any height.
   NSRect floatingBarBackingRect =
@@ -230,8 +225,11 @@
   [self layoutFloatingBarBackingView:floatingBarBackingRect
                     presentationMode:inPresentationMode];
 
-  [fullscreenExitBubbleController_ positionInWindowAtTop:toolbarBottomY
-                                                   width:width];
+  // Place the find bar immediately below the toolbar/attached bookmark bar. In
+  // presentation mode, it hangs off the top of the screen when the bar is
+  // hidden.
+  [findBarCocoaController_ positionFindBarViewAtMaxY:maxY maxWidth:width];
+  [fullscreenExitBubbleController_ positionInWindowAtTop:maxY width:width];
 
   // If in presentation mode, reset |maxY| to top of screen, so that the
   // floating bar slides over the things which appear to be in the content area.
@@ -242,55 +240,15 @@
   // presentation mode in which case it's at the top of the visual content area.
   maxY = [self layoutInfoBarAtMinX:minX maxY:maxY width:width];
 
-  // Place the download shelf, if any, at the bottom of the view.
-  minY = [self layoutDownloadShelfAtMinX:minX minY:minY width:width];
-
-  // Place the bookmark bar.
+  // If the bookmark bar is detached, place it next in the visual content area.
   if (placeBookmarkBarBelowInfoBar)
     maxY = [self layoutBookmarkBarAtMinX:minX maxY:maxY width:width];
 
-  // In presentation mode the content area takes up all the remaining space
-  // (from the bottom of the info bar down). In normal mode the content area
-  // takes up the space between the bottom of the toolbar down.
-  CGFloat contentAreaTop = 0;
-  if (inPresentationMode) {
-    // The tabContentaArea starts at the bottom of the info bar (or top of the
-    // screen if there's no info bar).
-    contentAreaTop = maxY;
-    CGFloat floatingBarHeight =
-        NSHeight(floatingBarBackingRect) * [self floatingBarShownFraction];
-    // When an instant overlay is shown this is the amount it needs to be pushed
-    // down so that it doesn't get covered by the floating toolbar.
-    toolbarToWebContentsOffset_ =
-        floatingBarHeight - (NSMaxY(contentBounds) - maxY);
-  } else {
-    // The tabContentArea view starts below the omnibox.
-    CGFloat minToolbarHeight = 0;
-    if ([self hasToolbar]) {
-      // 1 to account for the toolbar separator.
-      minToolbarHeight = [toolbarController_ desiredHeightForCompression:1];
-    }
-    contentAreaTop = toolbarTopY - minToolbarHeight;
-    // This is the space between the bottom of the omnibox and the bottom of the
-    // last bar (info bar or bookmark bar or toolbar). This is used to push the
-    // tab web content down when no instant overlay is shown.
-    toolbarToWebContentsOffset_ = contentAreaTop - maxY;
-  }
-  [self updateContentOffsets];
+  // Place the download shelf, if any, at the bottom of the view.
+  minY = [self layoutDownloadShelfAtMinX:minX minY:minY width:width];
 
-  // Place the find bar immediately below the toolbar/attached bookmark bar. In
-  // presentation mode, it hangs off the top of the screen when the bar is
-  // hidden.
-  if ([self currentInstantUIState] ==
-      browser_window_controller::kInstantUIFullPageResults) {
-    [findBarCocoaController_ positionFindBarViewAtMaxY:contentAreaTop - 1
-                                              maxWidth:width];
-  } else {
-    [findBarCocoaController_ positionFindBarViewAtMaxY:toolbarBottomY
-                                              maxWidth:width];
-  }
-
-  NSRect contentAreaRect = NSMakeRect(minX, minY, width, contentAreaTop - minY);
+  // Finally, the content area takes up all of the remaining space.
+  NSRect contentAreaRect = NSMakeRect(minX, minY, width, maxY - minY);
   [self layoutTabContentArea:contentAreaRect];
 
   // Normally, we don't need to tell the toolbar whether or not to show the
@@ -552,21 +510,22 @@
   [bookmarkBubbleController_ ok:self];
 
   // Save the current first responder so we can restore after views are moved.
-  scoped_nsobject<FocusTracker> focusTracker(
+  base::scoped_nsobject<FocusTracker> focusTracker(
       [[FocusTracker alloc] initWithWindow:sourceWindow]);
 
   // While we move views (and focus) around, disable any bar visibility changes.
   [self disableBarVisibilityUpdates];
 
   // Retain the tab strip view while we remove it from its superview.
-  scoped_nsobject<NSView> tabStripView;
+  base::scoped_nsobject<NSView> tabStripView;
   if ([self hasTabStrip]) {
     tabStripView.reset([[self tabStripView] retain]);
     [tabStripView removeFromSuperview];
   }
 
   // Ditto for the content view.
-  scoped_nsobject<NSView> contentView([[sourceWindow contentView] retain]);
+  base::scoped_nsobject<NSView> contentView(
+      [[sourceWindow contentView] retain]);
   // Disable autoresizing of subviews while we move views around. This prevents
   // spurious renderer resizes.
   [contentView setAutoresizesSubviews:NO];
@@ -883,71 +842,6 @@
   return [bookmarkBarController_ toolbarDividerOpacity];
 }
 
-- (browser_window_controller::InstantUIState)currentInstantUIState {
-  if (!browser_->search_model()->mode().is_search())
-    return browser_window_controller::kInstantUINone;
-
-  // If the search suggestions are already being displayed in the overlay
-  // contents then return kInstantUIOverlay.
-  if ([overlayableContentsController_ isShowingOverlay])
-    return browser_window_controller::kInstantUIOverlay;
-
-  if (browser_->search_model()->top_bars_visible())
-    return browser_window_controller::kInstantUINone;
-
-  return browser_window_controller::kInstantUIFullPageResults;
-}
-
-- (void)updateContentOffsets {
-  if ([self inPresentationMode]) {
-    // In presentation mode the tabContentArea starts at the bottom of the info
-    // bar (or top of the screen if there's no info bar).
-    if ([self currentInstantUIState] !=
-        browser_window_controller::kInstantUIFullPageResults) {
-      // Normal mode, keep the tab web contents at the top (below the info bar).
-      [overlayableContentsController_ setActiveContainerOffset:0];
-    } else {
-      // Instant suggestions are displayed in the main tab contents so push that
-      // down so that the floating toolbar doesn't obscure it.
-      [overlayableContentsController_
-          setActiveContainerOffset:toolbarToWebContentsOffset_];
-    }
-    // Floating overlay (if any) should also be below the floating toolbar.
-    [overlayableContentsController_
-        setOverlayContentsOffset:toolbarToWebContentsOffset_];
-
-    [[self tabContentArea] setContentOffset:0];
-    [devToolsController_ setTopContentOffset:0];
-  } else {
-    // In normal mode the tabContentArea starts just below the omnibox and the
-    // bookmark bar and info bar overlap it.
-    if ([self currentInstantUIState] !=
-        browser_window_controller::kInstantUIFullPageResults) {
-      // Normal mode, push the tab web contents down so that it doesn't obscure
-      // the bookmark bar and info bar.
-      [overlayableContentsController_
-          setActiveContainerOffset:toolbarToWebContentsOffset_];
-    } else {
-      // Instant suggestions are displayed in the main tab contents so don't
-      // push it down (keep it next to the omnibox).
-      [overlayableContentsController_ setActiveContainerOffset:0];
-    }
-    // Floating overlay (if any) should also be at the top (next to the
-    // omnibox).
-    [overlayableContentsController_ setOverlayContentsOffset:0];
-
-    // Prevent the fast resize view from drawing white over the bookmark bar.
-    [[self tabContentArea] setContentOffset:toolbarToWebContentsOffset_];
-    // Prevent the dev tools splitter from overlapping the bookmark bar.
-    if ([self currentInstantUIState] !=
-        browser_window_controller::kInstantUINone) {
-      [devToolsController_ setTopContentOffset:0];
-    } else {
-      [devToolsController_ setTopContentOffset:toolbarToWebContentsOffset_];
-    }
-  }
-}
-
 - (void)updateSubviewZOrder:(BOOL)inPresentationMode {
   NSView* contentView = [[self window] contentView];
   NSView* toolbarView = [toolbarController_ view];
@@ -959,17 +853,14 @@
                      isPositioned:NSWindowAbove
                        relativeTo:[self tabContentArea]];
   } else {
-    // Toolbar is below tab contents so that the infob ar arrow can appear above
-    // it.  Unlike other views the toolbar never overlaps the actual web
-    // content.
+    // Toolbar is below tab contents so that the info bar arrow can appear above
+    // it.
     [contentView cr_ensureSubview:toolbarView
                      isPositioned:NSWindowBelow
                        relativeTo:[self tabContentArea]];
   }
 
-  // The bookmark bar is always below the toolbar. In normal mode this means
-  // that it is below tab contents. This allows Instant results to be above
-  // the bookmark bar.
+  // The bookmark bar is always below the toolbar.
   [contentView cr_ensureSubview:[bookmarkBarController_ view]
                    isPositioned:NSWindowBelow
                      relativeTo:toolbarView];
@@ -987,17 +878,13 @@
                        relativeTo:toolbarView];
   }
 
-  // The find bar is above everything except Instant search results.
+  // The find bar is above everything.
   if (findBarCocoaController_) {
     NSView* relativeView = nil;
-    if (inPresentationMode) {
+    if (inPresentationMode)
       relativeView = toolbarView;
-    } else if ([self currentInstantUIState] ==
-               browser_window_controller::kInstantUIOverlay) {
-      relativeView = [infoBarContainerController_ view];
-    } else {
+    else
       relativeView = [self tabContentArea];
-    }
     [contentView cr_ensureSubview:[findBarCocoaController_ view]
                      isPositioned:NSWindowAbove
                        relativeTo:relativeView];
@@ -1040,6 +927,14 @@
 
   BOOL allowOverlappingViews =
       [self shouldAllowOverlappingViews:inPresentationMode];
+
+  if (allowOverlappingViews &&
+      [self coreAnimationStatus] ==
+          browser_window_controller::kCoreAnimationEnabledLazy) {
+    [[[self window] contentView] setWantsLayer:YES];
+    [[self tabStripView] setWantsLayer:YES];
+  }
+
   contents->GetView()->SetAllowOverlappingViews(allowOverlappingViews);
 
   DevToolsWindow* devToolsWindow =
@@ -1051,12 +946,26 @@
 }
 
 - (void)updateInfoBarTipVisibility {
-  // If the overlay is open or if there's no toolbar then hide the infobar tip.
-  BOOL suppressInfoBarTip =
-      [self currentInstantUIState] !=
-      browser_window_controller::kInstantUINone || ![self hasToolbar];
+  // If there's no toolbar then hide the infobar tip.
   [infoBarContainerController_
-      setShouldSuppressTopInfoBarTip:suppressInfoBarTip];
+      setShouldSuppressTopInfoBarTip:![self hasToolbar]];
+}
+
+- (browser_window_controller::CoreAnimationStatus)coreAnimationStatus {
+  // TODO(sail) Remove this.
+  if (!CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kUseCoreAnimation)) {
+    return browser_window_controller::kCoreAnimationDisabled;
+  }
+  if (CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+          switches::kUseCoreAnimation) == "lazy") {
+    return browser_window_controller::kCoreAnimationEnabledLazy;
+  }
+  if (CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+          switches::kUseCoreAnimation) == "disabled") {
+    return browser_window_controller::kCoreAnimationDisabled;
+  }
+  return browser_window_controller::kCoreAnimationEnabledAlways;
 }
 
 @end  // @implementation BrowserWindowController(Private)
diff --git a/chrome/browser/ui/cocoa/browser_window_controller_unittest.mm b/chrome/browser/ui/cocoa/browser_window_controller_unittest.mm
index ce77ea0..82032a1 100644
--- a/chrome/browser/ui/cocoa/browser_window_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/browser_window_controller_unittest.mm
@@ -5,7 +5,7 @@
 #import "chrome/browser/ui/cocoa/browser_window_controller.h"
 
 #include "base/mac/mac_util.h"
-#import "base/memory/scoped_nsobject.h"
+#import "base/mac/scoped_nsobject.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/prefs/pref_service.h"
 #include "base/strings/utf_string_conversions.h"
@@ -140,7 +140,7 @@
   // popup_browser will be owned by its window.
   Browser* popup_browser(new Browser(
       Browser::CreateParams(Browser::TYPE_POPUP, profile(),
-                            chrome::HOST_DESKTOP_TYPE_NATIVE)));
+                            chrome::GetActiveDesktop())));
   NSWindow *cocoaWindow = popup_browser->window()->GetNativeWindow();
   BrowserWindowController* controller =
       static_cast<BrowserWindowController*>([cocoaWindow windowController]);
@@ -155,7 +155,7 @@
 TEST_F(BrowserWindowControllerTest, TestSetBounds) {
   // Create a normal browser with bounds smaller than the minimum.
   Browser::CreateParams params(Browser::TYPE_TABBED, profile(),
-                               chrome::HOST_DESKTOP_TYPE_NATIVE);
+                               chrome::GetActiveDesktop());
   params.initial_bounds = gfx::Rect(0, 0, 50, 50);
   Browser* browser = new Browser(params);
   NSWindow *cocoaWindow = browser->window()->GetNativeWindow();
@@ -181,7 +181,7 @@
 TEST_F(BrowserWindowControllerTest, TestSetBoundsPopup) {
   // Create a popup with bounds smaller than the minimum.
   Browser::CreateParams params(Browser::TYPE_POPUP, profile(),
-                               chrome::HOST_DESKTOP_TYPE_NATIVE);
+                               chrome::GetActiveDesktop());
   params.initial_bounds = gfx::Rect(0, 0, 50, 50);
   Browser* browser = new Browser(params);
   NSWindow *cocoaWindow = browser->window()->GetNativeWindow();
@@ -228,7 +228,7 @@
   incognito_profile->set_off_the_record(true);
   scoped_ptr<Browser> browser(
       new Browser(Browser::CreateParams(incognito_profile.get(),
-                                        chrome::HOST_DESKTOP_TYPE_NATIVE));
+                                        chrome::GetActiveDesktop()));
   controller_.reset([[BrowserWindowController alloc]
                               initWithBrowser:browser.get()
                                 takeOwnership:NO]);
@@ -243,6 +243,7 @@
 #endif
 
 namespace {
+
 // Verifies that the toolbar, infobar, tab content area, and download shelf
 // completely fill the area under the tabstrip.
 void CheckViewPositions(BrowserWindowController* controller) {
@@ -255,10 +256,7 @@
 
   EXPECT_EQ(NSMinY(contentView), NSMinY(download));
   EXPECT_EQ(NSMaxY(download), NSMinY(contentArea));
-
-  CGFloat min_toolbar_height = [[controller toolbarController]
-      desiredHeightForCompression:1];
-  EXPECT_EQ(NSMaxY(contentArea), NSMaxY(toolbar) - min_toolbar_height);
+  EXPECT_EQ(NSMaxY(contentArea), NSMinY(infobar));
 
   // Bookmark bar frame is random memory when hidden.
   if ([controller bookmarkBarVisible]) {
@@ -275,6 +273,7 @@
   // not necessarily fixed with respect to the content view.
   EXPECT_EQ(NSMinY(tabstrip), NSMaxY(toolbar));
 }
+
 }  // end namespace
 
 TEST_F(BrowserWindowControllerTest, TestAdjustWindowHeight) {
@@ -641,7 +640,7 @@
   NSPoint bubbleOrigin = [controller_ statusBubbleBaseFrame].origin;
 
   // Add a fake subview to devToolsView to emulate docked devTools.
-  scoped_nsobject<NSView> view(
+  base::scoped_nsobject<NSView> view(
       [[NSView alloc] initWithFrame:NSMakeRect(0, 0, 10, 10)]);
   [[controller_ devToolsView] addSubview:view];
   [[controller_ devToolsView] adjustSubviews];
@@ -653,7 +652,7 @@
 }
 
 TEST_F(BrowserWindowControllerTest, TestSigninMenuItemNoErrors) {
-  scoped_nsobject<NSMenuItem> syncMenuItem(
+  base::scoped_nsobject<NSMenuItem> syncMenuItem(
       [[NSMenuItem alloc] initWithTitle:@""
                                  action:@selector(commandDispatch)
                           keyEquivalent:@""]);
@@ -697,7 +696,7 @@
 }
 
 TEST_F(BrowserWindowControllerTest, TestSigninMenuItemAuthError) {
-  scoped_nsobject<NSMenuItem> syncMenuItem(
+  base::scoped_nsobject<NSMenuItem> syncMenuItem(
       [[NSMenuItem alloc] initWithTitle:@""
                                  action:@selector(commandDispatch)
                           keyEquivalent:@""]);
@@ -728,7 +727,7 @@
 // If there's a separator after the signin menu item, make sure it is hidden/
 // shown when the signin menu item is.
 TEST_F(BrowserWindowControllerTest, TestSigninMenuItemWithSeparator) {
-  scoped_nsobject<NSMenu> menu([[NSMenu alloc] initWithTitle:@""]);
+  base::scoped_nsobject<NSMenu> menu([[NSMenu alloc] initWithTitle:@""]);
   NSMenuItem* signinMenuItem =
       [menu addItemWithTitle:@""
                       action:@selector(commandDispatch)
@@ -759,7 +758,7 @@
 // If there's a non-separator item after the signin menu item, it should not
 // change state when the signin menu item is hidden/shown.
 TEST_F(BrowserWindowControllerTest, TestSigninMenuItemWithNonSeparator) {
-  scoped_nsobject<NSMenu> menu([[NSMenu alloc] initWithTitle:@""]);
+  base::scoped_nsobject<NSMenu> menu([[NSMenu alloc] initWithTitle:@""]);
   NSMenuItem* signinMenuItem =
       [menu addItemWithTitle:@""
                       action:@selector(commandDispatch)
@@ -809,7 +808,7 @@
  @private
   // We release the window ourselves, so we don't have to rely on the unittest
   // doing it for us.
-  scoped_nsobject<NSWindow> testFullscreenWindow_;
+  base::scoped_nsobject<NSWindow> testFullscreenWindow_;
 }
 @end
 
diff --git a/chrome/browser/ui/cocoa/bubble_view.h b/chrome/browser/ui/cocoa/bubble_view.h
index 336f8cd..12c89f4 100644
--- a/chrome/browser/ui/cocoa/bubble_view.h
+++ b/chrome/browser/ui/cocoa/bubble_view.h
@@ -4,7 +4,7 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 
 // A view class that looks like a "bubble" with rounded corners and displays
 // text inside. Can be themed. To put flush against the sides of a window, the
@@ -33,7 +33,7 @@
 
 @interface BubbleView : NSView {
  @private
-  scoped_nsobject<NSString> content_;
+  base::scoped_nsobject<NSString> content_;
   unsigned long cornerFlags_;
   // The window from which we get the theme used to draw. In some cases,
   // it might not be the window we're in. As a result, this may or may not
diff --git a/chrome/browser/ui/cocoa/bubble_view.mm b/chrome/browser/ui/cocoa/bubble_view.mm
index 4c3d8e0..b9b8648 100644
--- a/chrome/browser/ui/cocoa/bubble_view.mm
+++ b/chrome/browser/ui/cocoa/bubble_view.mm
@@ -104,7 +104,7 @@
     textColor = themeProvider->GetNSColor(ThemeProperties::COLOR_TAB_TEXT,
                                           true);
   NSFont* textFont = [self font];
-  scoped_nsobject<NSShadow> textShadow([[NSShadow alloc] init]);
+  base::scoped_nsobject<NSShadow> textShadow([[NSShadow alloc] init]);
   [textShadow setShadowBlurRadius:0.0f];
   [textShadow.get() setShadowColor:[textColor gtm_legibleTextColor]];
   [textShadow.get() setShadowOffset:NSMakeSize(0.0f, -1.0f)];
diff --git a/chrome/browser/ui/cocoa/bubble_view_unittest.mm b/chrome/browser/ui/cocoa/bubble_view_unittest.mm
index 4b8850e..c1b5d9b 100644
--- a/chrome/browser/ui/cocoa/bubble_view_unittest.mm
+++ b/chrome/browser/ui/cocoa/bubble_view_unittest.mm
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #import "chrome/browser/ui/cocoa/bubble_view.h"
 #include "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #import "testing/gtest_mac.h"
@@ -12,7 +12,7 @@
  public:
   BubbleViewTest() {
     NSRect frame = NSMakeRect(0, 0, 50, 50);
-    scoped_nsobject<BubbleView> view(
+    base::scoped_nsobject<BubbleView> view(
         [[BubbleView alloc] initWithFrame:frame themeProvider:test_window()]);
     view_ = view.get();
     [[test_window() contentView] addSubview:view_];
@@ -27,7 +27,7 @@
 // Test a nil themeProvider in init.
 TEST_F(BubbleViewTest, NilThemeProvider) {
   NSRect frame = NSMakeRect(0, 0, 50, 50);
-  scoped_nsobject<BubbleView> view(
+  base::scoped_nsobject<BubbleView> view(
       [[BubbleView alloc] initWithFrame:frame themeProvider:nil]);
   [[test_window() contentView] addSubview:view.get()];
   [view display];
diff --git a/chrome/browser/ui/cocoa/certificate_viewer_mac.h b/chrome/browser/ui/cocoa/certificate_viewer_mac.h
index 737d40d..f33bef2 100644
--- a/chrome/browser/ui/cocoa/certificate_viewer_mac.h
+++ b/chrome/browser/ui/cocoa/certificate_viewer_mac.h
@@ -6,7 +6,7 @@
 
 #define CHROME_BROWSER_UI_COCOA_CERTIFICATE_VIEWER_MAC_H_
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "base/memory/scoped_ptr.h"
 #import "chrome/browser/ui/cocoa/constrained_window/constrained_window_mac.h"
 #import "chrome/browser/ui/cocoa/constrained_window/constrained_window_sheet.h"
@@ -21,11 +21,11 @@
 @interface SSLCertificateViewerCocoa : NSObject<ConstrainedWindowSheet> {
  @private
   // The corresponding list of certificates.
-  scoped_nsobject<NSArray> certificates_;
+  base::scoped_nsobject<NSArray> certificates_;
   scoped_ptr<SSLCertificateViewerCocoaBridge> observer_;
-  scoped_nsobject<SFCertificatePanel> panel_;
+  base::scoped_nsobject<SFCertificatePanel> panel_;
   scoped_ptr<ConstrainedWindowMac> constrainedWindow_;
-  scoped_nsobject<NSWindow> overlayWindow_;
+  base::scoped_nsobject<NSWindow> overlayWindow_;
   BOOL closePending_;
   // A copy of the sheet's frame used to restore on show.
   NSRect oldSheetFrame_;
diff --git a/chrome/browser/ui/cocoa/certificate_viewer_mac.mm b/chrome/browser/ui/cocoa/certificate_viewer_mac.mm
index 5fc37c5..8e8ab9c 100644
--- a/chrome/browser/ui/cocoa/certificate_viewer_mac.mm
+++ b/chrome/browser/ui/cocoa/certificate_viewer_mac.mm
@@ -10,8 +10,6 @@
 
 #include "base/mac/foundation_util.h"
 #include "base/mac/scoped_cftyperef.h"
-#include "base/memory/scoped_nsobject.h"
-#include "base/memory/scoped_ptr.h"
 #include "chrome/browser/certificate_viewer.h"
 #import "chrome/browser/ui/cocoa/constrained_window/constrained_window_mac.h"
 #import "chrome/browser/ui/cocoa/constrained_window/constrained_window_sheet.h"
@@ -80,7 +78,7 @@
 
 - (id)initWithCertificate:(net::X509Certificate*)certificate {
   if ((self = [super init])) {
-    base::mac::ScopedCFTypeRef<CFArrayRef> cert_chain(
+    base::ScopedCFTypeRef<CFArrayRef> cert_chain(
         certificate->CreateOSCertChainForCert());
     NSArray* certificates = base::mac::CFToNSCast(cert_chain.get());
     certificates_.reset([certificates retain]);
@@ -110,7 +108,7 @@
   // the certificate viewer UI from displaying which certificate is revoked.
   // This is acceptable, as certificate revocation will still be shown in
   // the page info bubble if a certificate in the chain is actually revoked.
-  base::mac::ScopedCFTypeRef<CFMutableArrayRef> policies(
+  base::ScopedCFTypeRef<CFMutableArrayRef> policies(
       CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks));
   if (!policies.get()) {
     NOTREACHED();
diff --git a/chrome/browser/ui/cocoa/certificate_viewer_mac_browsertest.mm b/chrome/browser/ui/cocoa/certificate_viewer_mac_browsertest.mm
index 1c665f5..0840e8a 100644
--- a/chrome/browser/ui/cocoa/certificate_viewer_mac_browsertest.mm
+++ b/chrome/browser/ui/cocoa/certificate_viewer_mac_browsertest.mm
@@ -39,7 +39,7 @@
       WebContentsModalDialogManager::FromWebContents(web_contents);
   EXPECT_FALSE(web_contents_modal_dialog_manager->IsShowingDialog());
 
-  ShowCertificateViewer(web_contents, window, cert);
+  ShowCertificateViewer(web_contents, window, cert.get());
 
   content::RunAllPendingInMessageLoop();
   EXPECT_TRUE(web_contents_modal_dialog_manager->IsShowingDialog());
@@ -59,7 +59,7 @@
       browser()->tab_strip_model()->GetActiveWebContents();
 
   SSLCertificateViewerCocoa* viewer =
-      [[SSLCertificateViewerCocoa alloc] initWithCertificate:cert];
+      [[SSLCertificateViewerCocoa alloc] initWithCertificate:cert.get()];
   [viewer displayForWebContents:web_contents];
 
   content::RunAllPendingInMessageLoop();
diff --git a/chrome/browser/ui/cocoa/chrome_event_processing_window.h b/chrome/browser/ui/cocoa/chrome_event_processing_window.h
index cb69c52..b9a20e9 100644
--- a/chrome/browser/ui/cocoa/chrome_event_processing_window.h
+++ b/chrome/browser/ui/cocoa/chrome_event_processing_window.h
@@ -7,7 +7,6 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
 #import "ui/base/cocoa/underlay_opengl_hosting_window.h"
 
 // Override NSWindow to access unhandled keyboard events (for command
diff --git a/chrome/browser/ui/cocoa/chrome_event_processing_window_unittest.mm b/chrome/browser/ui/cocoa/chrome_event_processing_window_unittest.mm
index 823e7bd..3865b24 100644
--- a/chrome/browser/ui/cocoa/chrome_event_processing_window_unittest.mm
+++ b/chrome/browser/ui/cocoa/chrome_event_processing_window_unittest.mm
@@ -5,13 +5,12 @@
 #include <Carbon/Carbon.h>
 
 #include "base/debug/debugger.h"
-#include "base/memory/scoped_nsobject.h"
 #include "chrome/app/chrome_command_ids.h"
-#import "chrome/browser/ui/cocoa/chrome_event_processing_window.h"
 #import "chrome/browser/ui/cocoa/browser_window_controller.h"
+#import "chrome/browser/ui/cocoa/chrome_event_processing_window.h"
 #import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
-#include "third_party/ocmock/gtest_support.h"
 #import "third_party/ocmock/OCMock/OCMock.h"
+#include "third_party/ocmock/gtest_support.h"
 #import "third_party/ocmock/ocmock_extensions.h"
 
 namespace {
diff --git a/chrome/browser/ui/cocoa/chrome_to_mobile_bubble_controller.h b/chrome/browser/ui/cocoa/chrome_to_mobile_bubble_controller.h
index a91db0d..74ca702 100644
--- a/chrome/browser/ui/cocoa/chrome_to_mobile_bubble_controller.h
+++ b/chrome/browser/ui/cocoa/chrome_to_mobile_bubble_controller.h
@@ -10,7 +10,7 @@
 #include <vector>
 
 #include "base/files/file_path.h"
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "base/memory/scoped_ptr.h"
 #include "chrome/browser/chrome_to_mobile_service.h"
 #import "chrome/browser/ui/cocoa/base_bubble_controller.h"
@@ -97,7 +97,7 @@
   base::FilePath snapshotPath_;
 
   // An animation used to cycle through the "Sending..." status messages.
-  scoped_nsobject<NSAnimation> progressAnimation_;
+  base::scoped_nsobject<NSAnimation> progressAnimation_;
 }
 
 // The owner of this object is responsible for showing the bubble. It is not
diff --git a/chrome/browser/ui/cocoa/clickhold_button_cell.h b/chrome/browser/ui/cocoa/clickhold_button_cell.h
index 554e1f6..187eef0 100644
--- a/chrome/browser/ui/cocoa/clickhold_button_cell.h
+++ b/chrome/browser/ui/cocoa/clickhold_button_cell.h
@@ -7,7 +7,6 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
 #import "chrome/browser/ui/cocoa/image_button_cell.h"
 
 // A button cell that implements "click hold" behavior after a specified delay
diff --git a/chrome/browser/ui/cocoa/clickhold_button_cell_unittest.mm b/chrome/browser/ui/cocoa/clickhold_button_cell_unittest.mm
index f76f805..0786271 100644
--- a/chrome/browser/ui/cocoa/clickhold_button_cell_unittest.mm
+++ b/chrome/browser/ui/cocoa/clickhold_button_cell_unittest.mm
@@ -4,7 +4,7 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #import "chrome/browser/ui/cocoa/clickhold_button_cell.h"
 #import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -16,9 +16,10 @@
  public:
   ClickHoldButtonCellTest() {
     NSRect frame = NSMakeRect(0, 0, 50, 30);
-    scoped_nsobject<NSButton> view([[NSButton alloc] initWithFrame:frame]);
+    base::scoped_nsobject<NSButton> view(
+        [[NSButton alloc] initWithFrame:frame]);
     view_ = view.get();
-    scoped_nsobject<ClickHoldButtonCell> cell(
+    base::scoped_nsobject<ClickHoldButtonCell> cell(
         [[ClickHoldButtonCell alloc] initTextCell:@"Testing"]);
     [view_ setCell:cell.get()];
     [[test_window() contentView] addSubview:view_];
diff --git a/chrome/browser/ui/cocoa/cocoa_profile_test.mm b/chrome/browser/ui/cocoa/cocoa_profile_test.mm
index 4d56be3..5c3529c 100644
--- a/chrome/browser/ui/cocoa/cocoa_profile_test.mm
+++ b/chrome/browser/ui/cocoa/cocoa_profile_test.mm
@@ -96,5 +96,5 @@
 
 Browser* CocoaProfileTest::CreateBrowser() {
   return new Browser(Browser::CreateParams(profile(),
-                                           chrome::HOST_DESKTOP_TYPE_NATIVE));
+                                           chrome::GetActiveDesktop()));
 }
diff --git a/chrome/browser/ui/cocoa/color_chooser_mac.mm b/chrome/browser/ui/cocoa/color_chooser_mac.mm
index f5e8dda..2241818 100644
--- a/chrome/browser/ui/cocoa/color_chooser_mac.mm
+++ b/chrome/browser/ui/cocoa/color_chooser_mac.mm
@@ -5,7 +5,7 @@
 #import <Cocoa/Cocoa.h>
 
 #include "base/logging.h"
-#import "base/memory/scoped_nsobject.h"
+#import "base/mac/scoped_nsobject.h"
 #include "chrome/browser/ui/browser_dialogs.h"
 #include "content/public/browser/color_chooser.h"
 #include "content/public/browser/web_contents.h"
@@ -54,7 +54,7 @@
   // The web contents invoking the color chooser.  No ownership because it will
   // outlive this class.
   content::WebContents* web_contents_;
-  scoped_nsobject<ColorPanelCocoa> panel_;
+  base::scoped_nsobject<ColorPanelCocoa> panel_;
 };
 
 ColorChooserMac* ColorChooserMac::current_color_chooser_ = NULL;
diff --git a/chrome/browser/ui/cocoa/command_observer_bridge_unittest.mm b/chrome/browser/ui/cocoa/command_observer_bridge_unittest.mm
index ed973b1..eb65c2e 100644
--- a/chrome/browser/ui/cocoa/command_observer_bridge_unittest.mm
+++ b/chrome/browser/ui/cocoa/command_observer_bridge_unittest.mm
@@ -4,7 +4,7 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "base/memory/scoped_ptr.h"
 #include "chrome/browser/command_updater.h"
 #import "chrome/browser/ui/cocoa/command_observer_bridge.h"
@@ -45,7 +45,7 @@
         observer_([[CommandTestObserver alloc] init]) {
   }
   scoped_ptr<CommandUpdater> updater_;
-  scoped_nsobject<CommandTestObserver> observer_;
+  base::scoped_nsobject<CommandTestObserver> observer_;
 };
 
 // Tests creation and deletion. NULL arguments aren't allowed.
diff --git a/chrome/browser/ui/cocoa/confirm_bubble_cocoa.h b/chrome/browser/ui/cocoa/confirm_bubble_cocoa.h
index 8d2a3f3..c1971b0 100644
--- a/chrome/browser/ui/cocoa/confirm_bubble_cocoa.h
+++ b/chrome/browser/ui/cocoa/confirm_bubble_cocoa.h
@@ -7,7 +7,7 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 
 @class ConfirmBubbleController;
 class ConfirmBubbleModel;
@@ -37,11 +37,11 @@
   ConfirmBubbleController* controller_;  // weak
 
   // Controls used in this bubble.
-  scoped_nsobject<NSImageView> icon_;
-  scoped_nsobject<NSTextView> titleLabel_;
-  scoped_nsobject<NSTextView> messageLabel_;
-  scoped_nsobject<NSButton> okButton_;
-  scoped_nsobject<NSButton> cancelButton_;
+  base::scoped_nsobject<NSImageView> icon_;
+  base::scoped_nsobject<NSTextView> titleLabel_;
+  base::scoped_nsobject<NSTextView> messageLabel_;
+  base::scoped_nsobject<NSButton> okButton_;
+  base::scoped_nsobject<NSButton> cancelButton_;
 }
 
 // Initializes a bubble view. Since this initializer programmatically creates a
diff --git a/chrome/browser/ui/cocoa/confirm_bubble_cocoa.mm b/chrome/browser/ui/cocoa/confirm_bubble_cocoa.mm
index b16acea..474bf21 100644
--- a/chrome/browser/ui/cocoa/confirm_bubble_cocoa.mm
+++ b/chrome/browser/ui/cocoa/confirm_bubble_cocoa.mm
@@ -215,17 +215,17 @@
       initWithFrame:NSMakeRect(left, bottom, kMaxMessageWidth, 0)]);
   NSString* messageText = [controller_ messageText];
   NSMutableDictionary* attributes = [NSMutableDictionary dictionary];
-  scoped_nsobject<NSMutableAttributedString> attributedMessage(
+  base::scoped_nsobject<NSMutableAttributedString> attributedMessage(
       [[NSMutableAttributedString alloc] initWithString:messageText
                                              attributes:attributes]);
   NSString* linkText = [controller_ linkText];
   if (linkText) {
-    scoped_nsobject<NSAttributedString> whiteSpace(
+    base::scoped_nsobject<NSAttributedString> whiteSpace(
         [[NSAttributedString alloc] initWithString:@" "]);
     [attributedMessage.get() appendAttributedString:whiteSpace.get()];
     [attributes setObject:[NSString string]
                    forKey:NSLinkAttributeName];
-    scoped_nsobject<NSAttributedString> attributedLink(
+    base::scoped_nsobject<NSAttributedString> attributedLink(
         [[NSAttributedString alloc] initWithString:linkText
                                         attributes:attributes]);
     [attributedMessage.get() appendAttributedString:attributedLink.get()];
diff --git a/chrome/browser/ui/cocoa/confirm_bubble_controller_unittest.mm b/chrome/browser/ui/cocoa/confirm_bubble_controller_unittest.mm
index 76d605b..f458e56 100644
--- a/chrome/browser/ui/cocoa/confirm_bubble_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/confirm_bubble_controller_unittest.mm
@@ -3,8 +3,6 @@
 // found in the LICENSE file.
 
 #include "base/compiler_specific.h"
-#include "base/memory/scoped_nsobject.h"
-#include "base/memory/scoped_ptr.h"
 #include "base/strings/string16.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/ui/cocoa/cocoa_test_helper.h"
diff --git a/chrome/browser/ui/cocoa/confirm_quit_panel_controller.mm b/chrome/browser/ui/cocoa/confirm_quit_panel_controller.mm
index 659fff8..27813eb 100644
--- a/chrome/browser/ui/cocoa/confirm_quit_panel_controller.mm
+++ b/chrome/browser/ui/cocoa/confirm_quit_panel_controller.mm
@@ -8,7 +8,7 @@
 #import "chrome/browser/ui/cocoa/confirm_quit_panel_controller.h"
 
 #include "base/logging.h"
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "base/metrics/histogram.h"
 #include "base/prefs/pref_registry_simple.h"
 #include "base/strings/sys_string_conversions.h"
@@ -65,7 +65,7 @@
 
 - (id)initWithFrame:(NSRect)frameRect {
   if ((self = [super initWithFrame:frameRect])) {
-    scoped_nsobject<NSTextField> message(
+    base::scoped_nsobject<NSTextField> message(
         // The frame will be fixed up when |-setMessageText:| is called.
         [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 0, 0)]);
     message_ = message.get();
@@ -95,9 +95,9 @@
   const CGFloat kHorizontalPadding = 30;  // In view coordinates.
 
   // Style the string.
-  scoped_nsobject<NSMutableAttributedString> attrString(
+  base::scoped_nsobject<NSMutableAttributedString> attrString(
       [[NSMutableAttributedString alloc] initWithString:text]);
-  scoped_nsobject<NSShadow> textShadow([[NSShadow alloc] init]);
+  base::scoped_nsobject<NSShadow> textShadow([[NSShadow alloc] init]);
   [textShadow.get() setShadowColor:[NSColor colorWithCalibratedWhite:0
                                                                alpha:0.6]];
   [textShadow.get() setShadowOffset:NSMakeSize(0, -1)];
@@ -192,7 +192,7 @@
 
 - (id)init {
   const NSRect kWindowFrame = NSMakeRect(0, 0, 350, 70);
-  scoped_nsobject<NSWindow> window(
+  base::scoped_nsobject<NSWindow> window(
       [[NSWindow alloc] initWithContentRect:kWindowFrame
                                   styleMask:NSBorderlessWindowMask
                                     backing:NSBackingStoreBuffered
@@ -205,7 +205,7 @@
 
     // Create the content view. Take the frame from the existing content view.
     NSRect frame = [[window contentView] frame];
-    scoped_nsobject<ConfirmQuitFrameView> frameView(
+    base::scoped_nsobject<ConfirmQuitFrameView> frameView(
         [[ConfirmQuitFrameView alloc] initWithFrame:frame]);
     contentView_ = frameView.get();
     [window setContentView:contentView_];
@@ -230,7 +230,7 @@
 }
 
 - (NSApplicationTerminateReply)runModalLoopForApplication:(NSApplication*)app {
-  scoped_nsobject<ConfirmQuitPanelController> keepAlive([self retain]);
+  base::scoped_nsobject<ConfirmQuitPanelController> keepAlive([self retain]);
 
   // If this is the second of two such attempts to quit within a certain time
   // interval, then just quit.
@@ -327,7 +327,7 @@
 - (void)showWindow:(id)sender {
   // If a panel that is fading out is going to be reused here, make sure it
   // does not get released when the animation finishes.
-  scoped_nsobject<ConfirmQuitPanelController> keepAlive([self retain]);
+  base::scoped_nsobject<ConfirmQuitPanelController> keepAlive([self retain]);
   [[self window] setAnimations:[NSDictionary dictionary]];
   [[self window] center];
   [[self window] setAlphaValue:1.0];
@@ -342,7 +342,7 @@
 
 - (void)animateFadeOut {
   NSWindow* window = [self window];
-  scoped_nsobject<CAAnimation> animation(
+  base::scoped_nsobject<CAAnimation> animation(
       [[window animationForKey:@"alphaValue"] copy]);
   [animation setDelegate:self];
   [animation setDuration:0.2];
diff --git a/chrome/browser/ui/cocoa/confirm_quit_panel_controller_unittest.mm b/chrome/browser/ui/cocoa/confirm_quit_panel_controller_unittest.mm
index 0348801..f191e0f 100644
--- a/chrome/browser/ui/cocoa/confirm_quit_panel_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/confirm_quit_panel_controller_unittest.mm
@@ -4,7 +4,6 @@
 
 #import "chrome/browser/ui/cocoa/confirm_quit_panel_controller.h"
 
-#include "base/memory/scoped_nsobject.h"
 #import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #include "chrome/browser/ui/cocoa/confirm_quit.h"
 #include "testing/gtest_mac.h"
diff --git a/chrome/browser/ui/cocoa/constrained_web_dialog_delegate_mac.mm b/chrome/browser/ui/cocoa/constrained_web_dialog_delegate_mac.mm
index 3a718a4..36529a9 100644
--- a/chrome/browser/ui/cocoa/constrained_web_dialog_delegate_mac.mm
+++ b/chrome/browser/ui/cocoa/constrained_web_dialog_delegate_mac.mm
@@ -6,7 +6,7 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #import "chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_sheet.h"
 #import "chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_window.h"
 #import "chrome/browser/ui/cocoa/constrained_window/constrained_window_mac.h"
@@ -95,7 +95,7 @@
  private:
   scoped_ptr<ConstrainedWebDialogDelegateMac> impl_;
   scoped_ptr<ConstrainedWindowMac> constrained_window_;
-  scoped_nsobject<NSWindow> window_;
+  base::scoped_nsobject<NSWindow> window_;
 
   DISALLOW_COPY_AND_ASSIGN(ConstrainedWebDialogDelegateViewMac);
 };
@@ -119,9 +119,8 @@
   [[window_ contentView]
       addSubview:GetWebContents()->GetView()->GetNativeView()];
 
-  scoped_nsobject<CustomConstrainedWindowSheet> sheet(
-      [[CustomConstrainedWindowSheet alloc]
-          initWithCustomWindow:window_]);
+  base::scoped_nsobject<CustomConstrainedWindowSheet> sheet(
+      [[CustomConstrainedWindowSheet alloc] initWithCustomWindow:window_]);
   constrained_window_.reset(new ConstrainedWindowMac(
       this, web_contents, sheet));
 
diff --git a/chrome/browser/ui/cocoa/constrained_window/constrained_window_alert.h b/chrome/browser/ui/cocoa/constrained_window/constrained_window_alert.h
index ac2f34c..389f6a8 100644
--- a/chrome/browser/ui/cocoa/constrained_window/constrained_window_alert.h
+++ b/chrome/browser/ui/cocoa/constrained_window/constrained_window_alert.h
@@ -7,7 +7,7 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 
 // This class implements an alert that has a constrained window look and feel
 // (close button on top right, WebUI style buttons, etc...).  The alert can be
@@ -15,12 +15,12 @@
 // this would be done by ConstrainedWindowSheetController.
 @interface ConstrainedWindowAlert : NSObject {
  @private
-  scoped_nsobject<NSTextField> informativeTextField_;
-  scoped_nsobject<NSTextField> messageTextField_;
-  scoped_nsobject<NSView> accessoryView_;
-  scoped_nsobject<NSMutableArray> buttons_;
-  scoped_nsobject<NSButton> closeButton_;
-  scoped_nsobject<NSWindow> window_;
+  base::scoped_nsobject<NSTextField> informativeTextField_;
+  base::scoped_nsobject<NSTextField> messageTextField_;
+  base::scoped_nsobject<NSView> accessoryView_;
+  base::scoped_nsobject<NSMutableArray> buttons_;
+  base::scoped_nsobject<NSButton> closeButton_;
+  base::scoped_nsobject<NSWindow> window_;
 }
 
 @property(nonatomic, copy) NSString* informativeText;
diff --git a/chrome/browser/ui/cocoa/constrained_window/constrained_window_alert.mm b/chrome/browser/ui/cocoa/constrained_window/constrained_window_alert.mm
index 7fda80b..036c42a 100644
--- a/chrome/browser/ui/cocoa/constrained_window/constrained_window_alert.mm
+++ b/chrome/browser/ui/cocoa/constrained_window/constrained_window_alert.mm
@@ -110,7 +110,7 @@
                     action:(SEL)action {
   if (!buttons_.get())
     buttons_.reset([[NSMutableArray alloc] init]);
-  scoped_nsobject<NSButton> button(
+  base::scoped_nsobject<NSButton> button(
       [[ConstrainedWindowButton alloc] initWithFrame:NSZeroRect]);
   [button setTitle:title];
   [button setKeyEquivalent:keyEquivalent];
diff --git a/chrome/browser/ui/cocoa/constrained_window/constrained_window_alert_unittest.mm b/chrome/browser/ui/cocoa/constrained_window/constrained_window_alert_unittest.mm
index 52f6ca1..868f81d 100644
--- a/chrome/browser/ui/cocoa/constrained_window/constrained_window_alert_unittest.mm
+++ b/chrome/browser/ui/cocoa/constrained_window/constrained_window_alert_unittest.mm
@@ -11,7 +11,7 @@
 
 // Test showing the alert.
 TEST_F(ConstrainedWindowAlertTest, Show) {
-  scoped_nsobject<ConstrainedWindowAlert> alert(
+  base::scoped_nsobject<ConstrainedWindowAlert> alert(
       [[ConstrainedWindowAlert alloc] init]);
   EXPECT_TRUE([alert window]);
   EXPECT_TRUE([alert closeButton]);
@@ -27,7 +27,7 @@
 
 // Test showing the alert with no buttons.
 TEST_F(ConstrainedWindowAlertTest, NoButtons) {
-  scoped_nsobject<ConstrainedWindowAlert> alert(
+  base::scoped_nsobject<ConstrainedWindowAlert> alert(
       [[ConstrainedWindowAlert alloc] init]);
   [alert layout];
   [[alert window] makeKeyAndOrderFront:nil];
@@ -35,13 +35,13 @@
 
 // Test adding an accessory view to an alert.
 TEST_F(ConstrainedWindowAlertTest, AccessoryView) {
-  scoped_nsobject<ConstrainedWindowAlert> alert(
+  base::scoped_nsobject<ConstrainedWindowAlert> alert(
       [[ConstrainedWindowAlert alloc] init]);
   [alert addButtonWithTitle:@"OK" keyEquivalent:@"" target:nil action:NULL];
   [alert addButtonWithTitle:@"Cancel" keyEquivalent:@"" target:nil action:NULL];
 
   NSRect view_rect = NSMakeRect(0, 0, 700, 300);
-  scoped_nsobject<NSView> view([[NSView alloc] initWithFrame:view_rect]);
+  base::scoped_nsobject<NSView> view([[NSView alloc] initWithFrame:view_rect]);
   EXPECT_FALSE([alert accessoryView]);
   [alert setAccessoryView:view];
   EXPECT_NSEQ([alert accessoryView], view);
diff --git a/chrome/browser/ui/cocoa/constrained_window/constrained_window_animation.h b/chrome/browser/ui/cocoa/constrained_window/constrained_window_animation.h
index 3248411..635a6e6 100644
--- a/chrome/browser/ui/cocoa/constrained_window/constrained_window_animation.h
+++ b/chrome/browser/ui/cocoa/constrained_window/constrained_window_animation.h
@@ -7,12 +7,12 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 
 // Base class for all constrained window animation classes.
 @interface ConstrainedWindowAnimationBase : NSAnimation {
  @protected
-  scoped_nsobject<NSWindow> window_;
+  base::scoped_nsobject<NSWindow> window_;
 }
 
 - (id)initWithWindow:(NSWindow*)window;
diff --git a/chrome/browser/ui/cocoa/constrained_window/constrained_window_animation_unittest.mm b/chrome/browser/ui/cocoa/constrained_window/constrained_window_animation_unittest.mm
index 9c7c2bd..5ec022f 100644
--- a/chrome/browser/ui/cocoa/constrained_window/constrained_window_animation_unittest.mm
+++ b/chrome/browser/ui/cocoa/constrained_window/constrained_window_animation_unittest.mm
@@ -2,10 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "base/message_loop/message_pump_mac.h"
-#import "chrome/browser/ui/cocoa/constrained_window/constrained_window_animation.h"
 #import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/constrained_window/constrained_window_animation.h"
 
 // This class runs an animation for exactly two frames then end it.
 @interface ConstrainedWindowAnimationTestDelegate : NSObject
@@ -57,26 +57,26 @@
     delegate_.reset([[ConstrainedWindowAnimationTestDelegate alloc] init]);
   }
 
-  scoped_nsobject<ConstrainedWindowAnimationTestDelegate> delegate_;
+  base::scoped_nsobject<ConstrainedWindowAnimationTestDelegate> delegate_;
 };
 
 // Test the show animation.
 TEST_F(ConstrainedWindowAnimationTest, Show) {
-  scoped_nsobject<NSAnimation> animation(
+  base::scoped_nsobject<NSAnimation> animation(
       [[ConstrainedWindowAnimationShow alloc] initWithWindow:test_window()]);
   [delegate_ runAnimation:animation];
 }
 
 // Test the hide animation.
 TEST_F(ConstrainedWindowAnimationTest, Hide) {
-  scoped_nsobject<NSAnimation> animation(
+  base::scoped_nsobject<NSAnimation> animation(
       [[ConstrainedWindowAnimationHide alloc] initWithWindow:test_window()]);
   [delegate_ runAnimation:animation];
 }
 
 // Test the pulse animation.
 TEST_F(ConstrainedWindowAnimationTest, Pulse) {
-  scoped_nsobject<NSAnimation> animation(
+  base::scoped_nsobject<NSAnimation> animation(
       [[ConstrainedWindowAnimationPulse alloc] initWithWindow:test_window()]);
   [delegate_ runAnimation:animation];
 }
diff --git a/chrome/browser/ui/cocoa/constrained_window/constrained_window_button.mm b/chrome/browser/ui/cocoa/constrained_window/constrained_window_button.mm
index fb07d84..39e4a3f 100644
--- a/chrome/browser/ui/cocoa/constrained_window/constrained_window_button.mm
+++ b/chrome/browser/ui/cocoa/constrained_window/constrained_window_button.mm
@@ -4,7 +4,7 @@
 
 #import "chrome/browser/ui/cocoa/constrained_window/constrained_window_button.h"
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #import "chrome/browser/ui/cocoa/key_equivalent_constants.h"
 #include "skia/ext/skia_utils_mac.h"
 #import "third_party/molokocacao/NSBezierPath+MCAdditions.h"
@@ -88,13 +88,13 @@
   const SkColor shadow_color[] =
       {0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF};
 
-  scoped_nsobject<NSShadow> shadow([[NSShadow alloc] init]);
+  base::scoped_nsobject<NSShadow> shadow([[NSShadow alloc] init]);
   [shadow setShadowColor:
       gfx::SkColorToCalibratedNSColor(shadow_color[button_state])];
   [shadow setShadowOffset:NSMakeSize(0, -1)];
   [shadow setShadowBlurRadius:0];
 
-  scoped_nsobject<NSMutableParagraphStyle> paragraphStyle(
+  base::scoped_nsobject<NSMutableParagraphStyle> paragraphStyle(
       [[NSMutableParagraphStyle alloc] init]);
   [paragraphStyle setAlignment:NSCenterTextAlignment];
 
diff --git a/chrome/browser/ui/cocoa/constrained_window/constrained_window_button_unittest.mm b/chrome/browser/ui/cocoa/constrained_window/constrained_window_button_unittest.mm
index 3f0628b..ed9b40c 100644
--- a/chrome/browser/ui/cocoa/constrained_window/constrained_window_button_unittest.mm
+++ b/chrome/browser/ui/cocoa/constrained_window/constrained_window_button_unittest.mm
@@ -2,9 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#import "base/memory/scoped_nsobject.h"
-#import "chrome/browser/ui/cocoa/constrained_window/constrained_window_button.h"
+#import "base/mac/scoped_nsobject.h"
 #import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/constrained_window/constrained_window_button.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/platform_test.h"
 
@@ -19,7 +19,7 @@
   }
 
  protected:
-  scoped_nsobject<ConstrainedWindowButton> button_;
+  base::scoped_nsobject<ConstrainedWindowButton> button_;
 };
 
 TEST_VIEW(ConstrainedWindowButtonTest, button_)
diff --git a/chrome/browser/ui/cocoa/constrained_window/constrained_window_control_utils.mm b/chrome/browser/ui/cocoa/constrained_window/constrained_window_control_utils.mm
index 5d73a8f..2be3ee7 100644
--- a/chrome/browser/ui/cocoa/constrained_window/constrained_window_control_utils.mm
+++ b/chrome/browser/ui/cocoa/constrained_window/constrained_window_control_utils.mm
@@ -4,7 +4,7 @@
 
 #import "chrome/browser/ui/cocoa/constrained_window/constrained_window_control_utils.h"
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "skia/ext/skia_utils_mac.h"
 
 namespace constrained_window {
@@ -29,7 +29,7 @@
 
   const gfx::Font& font =
       ui::ResourceBundle::GetSharedInstance().GetFont(fontStyle);
-  scoped_nsobject<NSMutableParagraphStyle> paragraphStyle(
+  base::scoped_nsobject<NSMutableParagraphStyle> paragraphStyle(
       [[NSMutableParagraphStyle alloc] init]);
   [paragraphStyle setAlignment:alignment];
   [paragraphStyle setLineBreakMode:lineBreakMode];
diff --git a/chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_sheet.h b/chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_sheet.h
index d1b6007..b36f07e 100644
--- a/chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_sheet.h
+++ b/chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_sheet.h
@@ -7,14 +7,14 @@
 
 #import <Cocoa/Cocoa.h>
 
+#import "base/mac/scoped_nsobject.h"
 #import "chrome/browser/ui/cocoa/constrained_window/constrained_window_sheet.h"
-#import "base/memory/scoped_nsobject.h"
 
 // Represents a custom sheet. The sheet's window is shown without using the
 // system |beginSheet:...| API.
 @interface CustomConstrainedWindowSheet : NSObject<ConstrainedWindowSheet> {
  @private
-  scoped_nsobject<NSWindow> customWindow_;
+  base::scoped_nsobject<NSWindow> customWindow_;
 }
 
 - (id)initWithCustomWindow:(NSWindow*)customWindow;
diff --git a/chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_sheet.mm b/chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_sheet.mm
index 28668aa..ab3d83e 100644
--- a/chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_sheet.mm
+++ b/chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_sheet.mm
@@ -17,7 +17,7 @@
 }
 
 - (void)showSheetForWindow:(NSWindow*)window {
-  scoped_nsobject<NSAnimation> animation(
+  base::scoped_nsobject<NSAnimation> animation(
       [[ConstrainedWindowAnimationShow alloc] initWithWindow:customWindow_]);
   [window addChildWindow:customWindow_
                  ordered:NSWindowAbove];
@@ -29,7 +29,7 @@
 
 - (void)closeSheetWithAnimation:(BOOL)withAnimation {
   if (withAnimation) {
-    scoped_nsobject<NSAnimation> animation(
+    base::scoped_nsobject<NSAnimation> animation(
         [[ConstrainedWindowAnimationHide alloc] initWithWindow:customWindow_]);
     [animation startAnimation];
   }
@@ -47,7 +47,7 @@
 }
 
 - (void)pulseSheet {
-  scoped_nsobject<NSAnimation> animation(
+  base::scoped_nsobject<NSAnimation> animation(
       [[ConstrainedWindowAnimationPulse alloc] initWithWindow:customWindow_]);
   [animation startAnimation];
 }
diff --git a/chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_window.mm b/chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_window.mm
index 984b176..cf972e0 100644
--- a/chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_window.mm
+++ b/chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_window.mm
@@ -4,7 +4,7 @@
 
 #import "chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_window.h"
 
-#import "base/memory/scoped_nsobject.h"
+#import "base/mac/scoped_nsobject.h"
 #import "chrome/browser/ui/chrome_style.h"
 #import "chrome/browser/ui/cocoa/constrained_window/constrained_window_sheet_controller.h"
 #include "skia/ext/skia_utils_mac.h"
@@ -17,7 +17,7 @@
                               styleMask:NSBorderlessWindowMask
                                 backing:NSBackingStoreBuffered
                                   defer:NO])) {
-    scoped_nsobject<NSView> contentView(
+    base::scoped_nsobject<NSView> contentView(
         [[ConstrainedWindowCustomWindowContentView alloc]
             initWithFrame:NSZeroRect]);
     [self setContentView:contentView];
diff --git a/chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_window_unittest.mm b/chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_window_unittest.mm
index f40ac1a..91dc464 100644
--- a/chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_window_unittest.mm
+++ b/chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_window_unittest.mm
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#import "base/memory/scoped_nsobject.h"
+#import "base/mac/scoped_nsobject.h"
 #import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #import "chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_window.h"
 
@@ -11,7 +11,7 @@
 
 // Simply test creating and drawing the window.
 TEST_F(ConstrainedWindowCustomWindowTest, Basic) {
-  scoped_nsobject<ConstrainedWindowCustomWindow> window(
+  base::scoped_nsobject<ConstrainedWindowCustomWindow> window(
       [[ConstrainedWindowCustomWindow alloc]
           initWithContentRect:NSMakeRect(0, 0, 10, 10)]);
   EXPECT_TRUE([window canBecomeKeyWindow]);
diff --git a/chrome/browser/ui/cocoa/constrained_window/constrained_window_mac.h b/chrome/browser/ui/cocoa/constrained_window/constrained_window_mac.h
index 3707539..73202e8 100644
--- a/chrome/browser/ui/cocoa/constrained_window/constrained_window_mac.h
+++ b/chrome/browser/ui/cocoa/constrained_window/constrained_window_mac.h
@@ -7,7 +7,7 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "components/web_modal/native_web_contents_modal_dialog.h"
 
 namespace content {
@@ -50,7 +50,7 @@
   // The WebContents that owns and constrains this ConstrainedWindowMac. Weak.
   content::WebContents* web_contents_;
 
-  scoped_nsprotocol<id<ConstrainedWindowSheet>> sheet_;
+  base::scoped_nsprotocol<id<ConstrainedWindowSheet>> sheet_;
 
   // This is true if the constrained window has been shown.
   bool shown_;
diff --git a/chrome/browser/ui/cocoa/constrained_window/constrained_window_mac_browsertest.mm b/chrome/browser/ui/cocoa/constrained_window/constrained_window_mac_browsertest.mm
index 6147583..04bc13a 100644
--- a/chrome/browser/ui/cocoa/constrained_window/constrained_window_mac_browsertest.mm
+++ b/chrome/browser/ui/cocoa/constrained_window/constrained_window_mac_browsertest.mm
@@ -66,8 +66,8 @@
   }
 
  protected:
-  scoped_nsobject<CustomConstrainedWindowSheet> sheet_;
-  scoped_nsobject<NSWindow> sheet_window_;
+  base::scoped_nsobject<CustomConstrainedWindowSheet> sheet_;
+  base::scoped_nsobject<NSWindow> sheet_window_;
   content::WebContents* tab0_;
   content::WebContents* tab1_;
   BrowserWindowController* controller_;
@@ -137,7 +137,7 @@
   EXPECT_EQ(1.0, [sheet_window_ alphaValue]);
 
   // Close the browser window.
-  scoped_nsobject<NSWindow> browser_window(
+  base::scoped_nsobject<NSWindow> browser_window(
       [browser()->window()->GetNativeWindow() retain]);
   EXPECT_TRUE([browser_window isVisible]);
   [browser()->window()->GetNativeWindow() performClose:nil];
diff --git a/chrome/browser/ui/cocoa/constrained_window/constrained_window_sheet_controller.h b/chrome/browser/ui/cocoa/constrained_window/constrained_window_sheet_controller.h
index 3223ac2..329594e 100644
--- a/chrome/browser/ui/cocoa/constrained_window/constrained_window_sheet_controller.h
+++ b/chrome/browser/ui/cocoa/constrained_window/constrained_window_sheet_controller.h
@@ -8,8 +8,8 @@
 #import <Cocoa/Cocoa.h>
 #include <vector>
 
+#include "base/mac/scoped_nsobject.h"
 #include "base/memory/scoped_vector.h"
-#include "base/memory/scoped_nsobject.h"
 
 @protocol ConstrainedWindowSheet;
 
@@ -18,9 +18,9 @@
 // A tab in this case is the |parentView| passed to |-showSheet:forParentView:|.
 @interface ConstrainedWindowSheetController : NSObject {
  @private
-  scoped_nsobject<NSMutableArray> sheets_;
-  scoped_nsobject<NSWindow> parentWindow_;
-  scoped_nsobject<NSView> activeView_;
+  base::scoped_nsobject<NSMutableArray> sheets_;
+  base::scoped_nsobject<NSWindow> parentWindow_;
+  base::scoped_nsobject<NSView> activeView_;
 }
 
 // Returns a sheet controller for |parentWindow|. If a sheet controller does not
diff --git a/chrome/browser/ui/cocoa/constrained_window/constrained_window_sheet_controller.mm b/chrome/browser/ui/cocoa/constrained_window/constrained_window_sheet_controller.mm
index c801d25..b4b4236 100644
--- a/chrome/browser/ui/cocoa/constrained_window/constrained_window_sheet_controller.mm
+++ b/chrome/browser/ui/cocoa/constrained_window/constrained_window_sheet_controller.mm
@@ -25,7 +25,7 @@
 // An invisible overlay window placed on top of the sheet's parent view.
 // This window blocks interaction with the underlying view.
 @interface CWSheetOverlayWindow : NSWindow {
-  scoped_nsobject<ConstrainedWindowSheetController> controller_;
+  base::scoped_nsobject<ConstrainedWindowSheetController> controller_;
 }
 @end
 
@@ -78,7 +78,7 @@
   if (controller)
     return controller;
 
-  scoped_nsobject<ConstrainedWindowSheetController> new_controller(
+  base::scoped_nsobject<ConstrainedWindowSheetController> new_controller(
       [[ConstrainedWindowSheetController alloc]
           initWithParentWindow:parentWindow]);
   if (!g_sheetControllers)
@@ -140,14 +140,13 @@
 
   // Create an invisible overlay window.
   NSRect rect = [self overlayWindowFrameForParentView:parentView];
-  scoped_nsobject<NSWindow> overlayWindow(
-      [[CWSheetOverlayWindow alloc] initWithContentRect:rect
-                                             controller:self]);
+  base::scoped_nsobject<NSWindow> overlayWindow(
+      [[CWSheetOverlayWindow alloc] initWithContentRect:rect controller:self]);
   [parentWindow_ addChildWindow:overlayWindow
                         ordered:NSWindowAbove];
 
   // Add an entry for the sheet.
-  scoped_nsobject<ConstrainedWindowSheetInfo> info(
+  base::scoped_nsobject<ConstrainedWindowSheetInfo> info(
       [[ConstrainedWindowSheetInfo alloc] initWithSheet:sheet
                                              parentView:parentView
                                           overlayWindow:overlayWindow]);
diff --git a/chrome/browser/ui/cocoa/constrained_window/constrained_window_sheet_controller_unittest.mm b/chrome/browser/ui/cocoa/constrained_window/constrained_window_sheet_controller_unittest.mm
index fdba717..562155a 100644
--- a/chrome/browser/ui/cocoa/constrained_window/constrained_window_sheet_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/constrained_window/constrained_window_sheet_controller_unittest.mm
@@ -79,7 +79,8 @@
     NSRect dummyRect = NSMakeRect(0, 0, 50, 50);
     tab_views_.reset([[NSMutableArray alloc] init]);
     for (int i = 0; i < 2; ++i) {
-      scoped_nsobject<NSView> view([[NSView alloc] initWithFrame:dummyRect]);
+      base::scoped_nsobject<NSView> view(
+          [[NSView alloc] initWithFrame:dummyRect]);
       [tab_views_ addObject:view];
     }
     tab0_.reset([[tab_views_ objectAtIndex:0] retain]);
@@ -135,13 +136,13 @@
     EXPECT_EQ(expected_x, NSMinX(sheet_frame));
   }
 
-  scoped_nsobject<NSWindow> sheet_window_;
-  scoped_nsobject<CustomConstrainedWindowSheet> sheet_;
-  scoped_nsobject<ConstrainedWindowSheetController> controller_;
-  scoped_nsobject<NSMutableArray> tab_views_;
-  scoped_nsobject<NSView> active_tab_view_;
-  scoped_nsobject<NSView> tab0_;
-  scoped_nsobject<NSView> tab1_;
+  base::scoped_nsobject<NSWindow> sheet_window_;
+  base::scoped_nsobject<CustomConstrainedWindowSheet> sheet_;
+  base::scoped_nsobject<ConstrainedWindowSheetController> controller_;
+  base::scoped_nsobject<NSMutableArray> tab_views_;
+  base::scoped_nsobject<NSView> active_tab_view_;
+  base::scoped_nsobject<NSView> tab0_;
+  base::scoped_nsobject<NSView> tab1_;
 };
 
 // Test showing then hiding the sheet.
@@ -183,11 +184,11 @@
 
 // Test that two parent windows with two sheet controllers don't conflict.
 TEST_F(ConstrainedWindowSheetControllerTest, TwoParentWindows) {
-  scoped_nsobject<NSWindow> parent_window2([[NSWindow alloc]
-      initWithContentRect:NSMakeRect(0, 0, 30, 30)
-                styleMask:NSTitledWindowMask
-                  backing:NSBackingStoreBuffered
-                    defer:NO]);
+  base::scoped_nsobject<NSWindow> parent_window2(
+      [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 30, 30)
+                                  styleMask:NSTitledWindowMask
+                                    backing:NSBackingStoreBuffered
+                                      defer:NO]);
   [parent_window2 setReleasedWhenClosed:NO];
 
   ConstrainedWindowSheetController* controller2 =
@@ -255,9 +256,9 @@
 
 // Test system sheets.
 TEST_F(ConstrainedWindowSheetControllerTest, SystemSheet) {
-  scoped_nsobject<ConstrainedWindowSystemSheetTest> system_sheet(
+  base::scoped_nsobject<ConstrainedWindowSystemSheetTest> system_sheet(
       [[ConstrainedWindowSystemSheetTest alloc] init]);
-  scoped_nsobject<NSAlert> alert([[NSAlert alloc] init]);
+  base::scoped_nsobject<NSAlert> alert([[NSAlert alloc] init]);
   [system_sheet setAlert:alert];
 
   EXPECT_FALSE([[alert window] isVisible]);
@@ -272,9 +273,9 @@
 
 // Test showing a system sheet on an inactive tab.
 TEST_F(ConstrainedWindowSheetControllerTest, SystemSheetAddToInactiveTab) {
-  scoped_nsobject<ConstrainedWindowSystemSheetTest> system_sheet(
+  base::scoped_nsobject<ConstrainedWindowSystemSheetTest> system_sheet(
       [[ConstrainedWindowSystemSheetTest alloc] init]);
-  scoped_nsobject<NSAlert> alert([[NSAlert alloc] init]);
+  base::scoped_nsobject<NSAlert> alert([[NSAlert alloc] init]);
   [system_sheet setAlert:alert];
 
   EXPECT_FALSE([[alert window] isVisible]);
diff --git a/chrome/browser/ui/cocoa/constrained_window/constrained_window_sheet_info.h b/chrome/browser/ui/cocoa/constrained_window/constrained_window_sheet_info.h
index 0c3c19b..b72e4f6 100644
--- a/chrome/browser/ui/cocoa/constrained_window/constrained_window_sheet_info.h
+++ b/chrome/browser/ui/cocoa/constrained_window/constrained_window_sheet_info.h
@@ -7,7 +7,7 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 
 @protocol ConstrainedWindowSheet;
 
@@ -16,9 +16,9 @@
 // public use.
 @interface ConstrainedWindowSheetInfo : NSObject {
  @private
-  scoped_nsprotocol<id<ConstrainedWindowSheet>> sheet_;
-  scoped_nsobject<NSView> parentView_;
-  scoped_nsobject<NSWindow> overlayWindow_;
+  base::scoped_nsprotocol<id<ConstrainedWindowSheet>> sheet_;
+  base::scoped_nsobject<NSView> parentView_;
+  base::scoped_nsobject<NSWindow> overlayWindow_;
   BOOL sheetDidShow_;
 }
 
diff --git a/chrome/browser/ui/cocoa/content_settings/collected_cookies_mac.h b/chrome/browser/ui/cocoa/content_settings/collected_cookies_mac.h
index 2d0c06b..71d193f 100644
--- a/chrome/browser/ui/cocoa/content_settings/collected_cookies_mac.h
+++ b/chrome/browser/ui/cocoa/content_settings/collected_cookies_mac.h
@@ -4,7 +4,7 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "base/memory/scoped_ptr.h"
 #include "chrome/browser/browsing_data/cookies_tree_model.h"
 #include "chrome/browser/ui/cocoa/constrained_window/constrained_window_mac.h"
@@ -48,7 +48,7 @@
 
   scoped_ptr<ConstrainedWindowMac> window_;
 
-  scoped_nsobject<CollectedCookiesWindowController> sheet_controller_;
+  base::scoped_nsobject<CollectedCookiesWindowController> sheet_controller_;
 
   DISALLOW_COPY_AND_ASSIGN(CollectedCookiesMac);
 };
@@ -68,11 +68,11 @@
   scoped_ptr<CookiesTreeModel> blockedTreeModel_;
 
   // Cached array of icons.
-  scoped_nsobject<NSMutableArray> icons_;
+  base::scoped_nsobject<NSMutableArray> icons_;
 
   // Our Cocoa copy of the model.
-  scoped_nsobject<CocoaCookieTreeNode> cocoaAllowedTreeModel_;
-  scoped_nsobject<CocoaCookieTreeNode> cocoaBlockedTreeModel_;
+  base::scoped_nsobject<CocoaCookieTreeNode> cocoaAllowedTreeModel_;
+  base::scoped_nsobject<CocoaCookieTreeNode> cocoaBlockedTreeModel_;
 
   BOOL allowedCookiesButtonsEnabled_;
   BOOL blockedCookiesButtonsEnabled_;
@@ -89,9 +89,9 @@
   IBOutlet NSTextField* blockedCookiesText_;
   IBOutlet NSView* cookieDetailsViewPlaceholder_;
 
-  scoped_nsobject<NSViewAnimation> animation_;
+  base::scoped_nsobject<NSViewAnimation> animation_;
 
-  scoped_nsobject<CookieDetailsViewController> detailsViewController_;
+  base::scoped_nsobject<CookieDetailsViewController> detailsViewController_;
 
   content::WebContents* webContents_;  // weak
 
diff --git a/chrome/browser/ui/cocoa/content_settings/collected_cookies_mac.mm b/chrome/browser/ui/cocoa/content_settings/collected_cookies_mac.mm
index f1e44d9..424c512 100644
--- a/chrome/browser/ui/cocoa/content_settings/collected_cookies_mac.mm
+++ b/chrome/browser/ui/cocoa/content_settings/collected_cookies_mac.mm
@@ -82,7 +82,7 @@
       initWithWebContents:web_contents
       collectedCookiesMac:this]);
 
-  scoped_nsobject<CustomConstrainedWindowSheet> sheet(
+  base::scoped_nsobject<CustomConstrainedWindowSheet> sheet(
       [[CustomConstrainedWindowSheet alloc]
           initWithCustomWindow:[sheet_controller_ window]]);
   window_.reset(new ConstrainedWindowMac(
@@ -170,7 +170,7 @@
                                 green:kBannerGradientColorBottom[1]
                                  blue:kBannerGradientColorBottom[2]
                                 alpha:1.0];
-  scoped_nsobject<NSGradient> bannerGradient(
+  base::scoped_nsobject<NSGradient> bannerGradient(
       [[NSGradient alloc] initWithStartingColor:bannerStartingColor
                                     endingColor:bannerEndingColor]);
   [infoBar_ setGradient:bannerGradient];
@@ -243,7 +243,7 @@
     CookieTreeHostNode* host_node =
         static_cast<CookieTreeHostNode*>(cookie);
     host_node->CreateContentException(
-        CookieSettings::Factory::GetForProfile(profile), setting);
+        CookieSettings::Factory::GetForProfile(profile).get(), setting);
     if (!lastDomain.empty())
       multipleDomainsChanged = YES;
     lastDomain = host_node->GetTitle();
@@ -382,7 +382,7 @@
   // Create the Cocoa model.
   CookieTreeNode* root =
       static_cast<CookieTreeNode*>(allowedTreeModel_->GetRoot());
-  scoped_nsobject<CocoaCookieTreeNode> model(
+  base::scoped_nsobject<CocoaCookieTreeNode> model(
       [[CocoaCookieTreeNode alloc] initWithNode:root]);
   [self setCocoaAllowedTreeModel:model.get()];  // Takes ownership.
   root = static_cast<CookieTreeNode*>(blockedTreeModel_->GetRoot());
diff --git a/chrome/browser/ui/cocoa/content_settings/content_setting_bubble_cocoa.h b/chrome/browser/ui/cocoa/content_settings/content_setting_bubble_cocoa.h
index d6097dd..6781fd3 100644
--- a/chrome/browser/ui/cocoa/content_settings/content_setting_bubble_cocoa.h
+++ b/chrome/browser/ui/cocoa/content_settings/content_setting_bubble_cocoa.h
@@ -6,7 +6,6 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
 #include "base/memory/scoped_ptr.h"
 #import "chrome/browser/ui/cocoa/base_bubble_controller.h"
 #include "content/public/common/media_stream_request.h"
@@ -91,4 +90,4 @@
 // Returns the weak reference to the |mediaMenus_|.
 - (content_setting_bubble::MediaMenuPartsMap*)mediaMenus;
 
-@end
\ No newline at end of file
+@end
diff --git a/chrome/browser/ui/cocoa/content_settings/content_setting_bubble_cocoa.mm b/chrome/browser/ui/cocoa/content_settings/content_setting_bubble_cocoa.mm
index 7d1c13c..5040e5b 100644
--- a/chrome/browser/ui/cocoa/content_settings/content_setting_bubble_cocoa.mm
+++ b/chrome/browser/ui/cocoa/content_settings/content_setting_bubble_cocoa.mm
@@ -90,7 +90,7 @@
 
 // Sets the title for the popup button.
 void SetTitleForPopUpButton(NSPopUpButton* button, NSString* title) {
-  scoped_nsobject<NSMenuItem> titleItem([[NSMenuItem alloc] init]);
+  base::scoped_nsobject<NSMenuItem> titleItem([[NSMenuItem alloc] init]);
   [titleItem setTitle:title];
   [[button cell] setUsesItemFromMenu:NO];
   [[button cell] setMenuItem:titleItem.get()];
@@ -293,8 +293,8 @@
                                 title:(NSString*)title
                                  icon:(NSImage*)icon
                        referenceFrame:(NSRect)referenceFrame {
-  scoped_nsobject<HyperlinkButtonCell> cell([[HyperlinkButtonCell alloc]
-      initTextCell:title]);
+  base::scoped_nsobject<HyperlinkButtonCell> cell(
+      [[HyperlinkButtonCell alloc] initTextCell:title]);
   [cell.get() setAlignment:NSNaturalTextAlignment];
   if (icon) {
     [cell.get() setImagePosition:NSImageLeft];
@@ -410,7 +410,7 @@
 
   // "Clear" button / text field.
   if (!content.custom_link.empty()) {
-    scoped_nsobject<NSControl> control;
+    base::scoped_nsobject<NSControl> control;
     if(content.custom_link_enabled) {
       NSRect buttonFrame = NSMakeRect(0, 0,
                                       NSWidth(containerFrame),
@@ -512,7 +512,7 @@
 
     // |buttonFrame| will be resized and repositioned later on.
     NSRect buttonFrame = NSMakeRect(NSMinX(radioFrame), 0, 0, 0);
-    scoped_nsobject<NSPopUpButton> button(
+    base::scoped_nsobject<NSPopUpButton> button(
         [[NSPopUpButton alloc] initWithFrame:buttonFrame]);
     [button setTarget:self];
 
diff --git a/chrome/browser/ui/cocoa/content_settings/content_setting_bubble_cocoa_unittest.mm b/chrome/browser/ui/cocoa/content_settings/content_setting_bubble_cocoa_unittest.mm
index f7f1a43..fee3a79 100644
--- a/chrome/browser/ui/cocoa/content_settings/content_setting_bubble_cocoa_unittest.mm
+++ b/chrome/browser/ui/cocoa/content_settings/content_setting_bubble_cocoa_unittest.mm
@@ -7,7 +7,7 @@
 #import <Cocoa/Cocoa.h>
 
 #include "base/mac/scoped_nsautorelease_pool.h"
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "chrome/browser/media/media_capture_devices_dispatcher.h"
 #import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #include "chrome/browser/ui/content_settings/content_setting_bubble_model.h"
@@ -48,7 +48,7 @@
   ContentSettingBubbleController* CreateBubbleController(
       ContentSettingsType settingsType);
 
-  scoped_nsobject<NSWindow> parent_;
+  base::scoped_nsobject<NSWindow> parent_;
 
  private:
   base::mac::ScopedNSAutoreleasePool pool_;
diff --git a/chrome/browser/ui/cocoa/content_settings/cookie_details.h b/chrome/browser/ui/cocoa/content_settings/cookie_details.h
index ca439d8..c0c9c84 100644
--- a/chrome/browser/ui/cocoa/content_settings/cookie_details.h
+++ b/chrome/browser/ui/cocoa/content_settings/cookie_details.h
@@ -4,7 +4,7 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "chrome/browser/browsing_data/browsing_data_database_helper.h"
 #include "chrome/browser/browsing_data/browsing_data_indexed_db_helper.h"
 #include "chrome/browser/browsing_data/browsing_data_local_storage_helper.h"
@@ -75,52 +75,52 @@
   BOOL hasExpiration_;
 
   // Only set for type kCocoaCookieDetailsTypeCookie.
-  scoped_nsobject<NSString> content_;
-  scoped_nsobject<NSString> path_;
-  scoped_nsobject<NSString> sendFor_;
+  base::scoped_nsobject<NSString> content_;
+  base::scoped_nsobject<NSString> path_;
+  base::scoped_nsobject<NSString> sendFor_;
   // Stringifed dates.
-  scoped_nsobject<NSString> expires_;
+  base::scoped_nsobject<NSString> expires_;
 
   // Only set for type kCocoaCookieDetailsTypeCookie and
   // kCocoaCookieDetailsTypeTreeAppCache nodes.
-  scoped_nsobject<NSString> created_;
+  base::scoped_nsobject<NSString> created_;
 
   // Only set for types kCocoaCookieDetailsTypeCookie, and
   // kCocoaCookieDetailsTypePromptDatabase nodes.
-  scoped_nsobject<NSString> name_;
+  base::scoped_nsobject<NSString> name_;
 
   // Only set for type kCocoaCookieDetailsTypeTreeLocalStorage,
   // kCocoaCookieDetailsTypeTreeDatabase,
   // kCocoaCookieDetailsTypePromptDatabase,
   // kCocoaCookieDetailsTypeTreeIndexedDB, and
   // kCocoaCookieDetailsTypeTreeAppCache nodes.
-  scoped_nsobject<NSString> fileSize_;
+  base::scoped_nsobject<NSString> fileSize_;
 
   // Only set for types kCocoaCookieDetailsTypeTreeLocalStorage,
   // kCocoaCookieDetailsTypeTreeDatabase, and
   // kCocoaCookieDetailsTypeTreeIndexedDB nodes.
-  scoped_nsobject<NSString> lastModified_;
+  base::scoped_nsobject<NSString> lastModified_;
 
   // Only set for type kCocoaCookieDetailsTypeTreeAppCache nodes.
-  scoped_nsobject<NSString> lastAccessed_;
+  base::scoped_nsobject<NSString> lastAccessed_;
 
   // Only set for type kCocoaCookieDetailsTypeCookie,
   // kCocoaCookieDetailsTypePromptDatabase,
   // kCocoaCookieDetailsTypePromptLocalStorage, and
   // kCocoaCookieDetailsTypeTreeIndexedDB nodes.
-  scoped_nsobject<NSString> domain_;
+  base::scoped_nsobject<NSString> domain_;
 
   // Only set for type kCocoaCookieTreeNodeTypeDatabaseStorage and
   // kCocoaCookieDetailsTypePromptDatabase nodes.
-  scoped_nsobject<NSString> databaseDescription_;
+  base::scoped_nsobject<NSString> databaseDescription_;
 
   // Only set for type kCocoaCookieDetailsTypePromptLocalStorage.
-  scoped_nsobject<NSString> localStorageKey_;
-  scoped_nsobject<NSString> localStorageValue_;
+  base::scoped_nsobject<NSString> localStorageKey_;
+  base::scoped_nsobject<NSString> localStorageValue_;
 
   // Only set for type kCocoaCookieDetailsTypeTreeAppCache and
   // kCocoaCookieDetailsTypePromptAppCache.
-  scoped_nsobject<NSString> manifestURL_;
+  base::scoped_nsobject<NSString> manifestURL_;
 }
 
 @property(nonatomic, readonly) BOOL canEditExpiration;
@@ -213,7 +213,7 @@
 // |CocoaCookieDetails| object for the cookie prompt.
 @interface CookiePromptContentDetailsAdapter : NSObject {
  @private
-  scoped_nsobject<CocoaCookieDetails> details_;
+  base::scoped_nsobject<CocoaCookieDetails> details_;
 }
 
 - (CocoaCookieDetails*)details;
diff --git a/chrome/browser/ui/cocoa/content_settings/cookie_details_unittest.mm b/chrome/browser/ui/cocoa/content_settings/cookie_details_unittest.mm
index 77cd6f7..fed777c 100644
--- a/chrome/browser/ui/cocoa/content_settings/cookie_details_unittest.mm
+++ b/chrome/browser/ui/cocoa/content_settings/cookie_details_unittest.mm
@@ -16,14 +16,14 @@
 };
 
 TEST_F(CookiesDetailsTest, CreateForFolder) {
-  scoped_nsobject<CocoaCookieDetails> details;
+  base::scoped_nsobject<CocoaCookieDetails> details;
   details.reset([[CocoaCookieDetails alloc] initAsFolder]);
 
   EXPECT_EQ([details.get() type], kCocoaCookieDetailsTypeFolder);
 }
 
 TEST_F(CookiesDetailsTest, CreateForCookie) {
-  scoped_nsobject<CocoaCookieDetails> details;
+  base::scoped_nsobject<CocoaCookieDetails> details;
   GURL url("http://chromium.org");
   std::string cookieLine(
       "PHPSESSID=0123456789abcdef0123456789abcdef; path=/");
@@ -53,15 +53,15 @@
 }
 
 TEST_F(CookiesDetailsTest, CreateForTreeDatabase) {
-  scoped_nsobject<CocoaCookieDetails> details;
-  std::string host("http://chromium.org");
+  base::scoped_nsobject<CocoaCookieDetails> details;
+  GURL origin("http://chromium.org");
   std::string database_name("sassolungo");
-  std::string origin_identifier("dolomites");
   std::string description("a great place to climb");
   int64 size = 1234;
   base::Time last_modified = base::Time::Now();
-  BrowsingDataDatabaseHelper::DatabaseInfo info(host, database_name,
-      origin_identifier, description, host, size, last_modified);
+  BrowsingDataDatabaseHelper::DatabaseInfo info(
+      webkit_database::DatabaseIdentifier::CreateFromOrigin(origin),
+      database_name, description, size, last_modified);
   details.reset([[CocoaCookieDetails alloc] initWithDatabase:&info]);
 
   EXPECT_EQ([details.get() type], kCocoaCookieDetailsTypeTreeDatabase);
@@ -80,7 +80,7 @@
 }
 
 TEST_F(CookiesDetailsTest, CreateForTreeLocalStorage) {
-  scoped_nsobject<CocoaCookieDetails> details;
+  base::scoped_nsobject<CocoaCookieDetails> details;
   const GURL kOrigin("http://chromium.org/");
   int64 size = 1234;
   base::Time last_modified = base::Time::Now();
@@ -104,7 +104,7 @@
 }
 
 TEST_F(CookiesDetailsTest, CreateForTreeAppCache) {
-  scoped_nsobject<CocoaCookieDetails> details;
+  base::scoped_nsobject<CocoaCookieDetails> details;
 
   GURL url("http://chromium.org/stuff.manifest");
   appcache::AppCacheInfo info;
@@ -133,7 +133,7 @@
 }
 
 TEST_F(CookiesDetailsTest, CreateForTreeIndexedDB) {
-  scoped_nsobject<CocoaCookieDetails> details;
+  base::scoped_nsobject<CocoaCookieDetails> details;
 
   GURL origin("http://moose.org/");
   int64 size = 1234;
@@ -162,7 +162,7 @@
 }
 
 TEST_F(CookiesDetailsTest, CreateForPromptDatabase) {
-  scoped_nsobject<CocoaCookieDetails> details;
+  base::scoped_nsobject<CocoaCookieDetails> details;
   std::string domain("chromium.org");
   string16 name(base::SysNSStringToUTF16(@"wicked_name"));
   string16 desc(base::SysNSStringToUTF16(@"desc"));
@@ -188,7 +188,7 @@
 }
 
 TEST_F(CookiesDetailsTest, CreateForPromptLocalStorage) {
-  scoped_nsobject<CocoaCookieDetails> details;
+  base::scoped_nsobject<CocoaCookieDetails> details;
   std::string domain("chromium.org");
   string16 key(base::SysNSStringToUTF16(@"testKey"));
   string16 value(base::SysNSStringToUTF16(@"testValue"));
@@ -212,7 +212,7 @@
 }
 
 TEST_F(CookiesDetailsTest, CreateForPromptAppCache) {
-  scoped_nsobject<CocoaCookieDetails> details;
+  base::scoped_nsobject<CocoaCookieDetails> details;
   std::string manifestURL("http://html5demos.com/html5demo.manifest");
   details.reset([[CocoaCookieDetails alloc]
       initWithAppCacheManifestURL:manifestURL.c_str()]);
diff --git a/chrome/browser/ui/cocoa/content_settings/cookie_details_view_controller_unittest.mm b/chrome/browser/ui/cocoa/content_settings/cookie_details_view_controller_unittest.mm
index 29a0806..c901c71 100644
--- a/chrome/browser/ui/cocoa/content_settings/cookie_details_view_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/content_settings/cookie_details_view_controller_unittest.mm
@@ -52,14 +52,14 @@
 }
 
 TEST_F(CookieDetailsViewControllerTest, Create) {
-  scoped_nsobject<CookieDetailsViewController> detailsViewController(
+  base::scoped_nsobject<CookieDetailsViewController> detailsViewController(
       [[CookieDetailsViewController alloc] init]);
 }
 
 TEST_F(CookieDetailsViewControllerTest, ShrinkToFit) {
-  scoped_nsobject<CookieDetailsViewController> detailsViewController(
+  base::scoped_nsobject<CookieDetailsViewController> detailsViewController(
       [[CookieDetailsViewController alloc] init]);
-  scoped_nsobject<CookiePromptContentDetailsAdapter> adapter(
+  base::scoped_nsobject<CookiePromptContentDetailsAdapter> adapter(
       [CreateDatabaseTestContent() retain]);
   [detailsViewController.get() setContentObject:adapter.get()];
   NSRect beforeFrame = [[detailsViewController.get() view] frame];
@@ -70,10 +70,10 @@
 }
 
 TEST_F(CookieDetailsViewControllerTest, ExpirationEditability) {
-  scoped_nsobject<CookieDetailsViewController> detailsViewController(
+  base::scoped_nsobject<CookieDetailsViewController> detailsViewController(
       [[CookieDetailsViewController alloc] init]);
   [detailsViewController view];
-  scoped_nsobject<CookiePromptContentDetailsAdapter> adapter(
+  base::scoped_nsobject<CookiePromptContentDetailsAdapter> adapter(
       [CreateCookieTestContent(YES) retain]);
   [detailsViewController.get() setContentObject:adapter.get()];
 
diff --git a/chrome/browser/ui/cocoa/content_settings/cookie_tree_node.h b/chrome/browser/ui/cocoa/content_settings/cookie_tree_node.h
index 2b95914..1af0a75 100644
--- a/chrome/browser/ui/cocoa/content_settings/cookie_tree_node.h
+++ b/chrome/browser/ui/cocoa/content_settings/cookie_tree_node.h
@@ -4,14 +4,14 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "chrome/browser/browsing_data/cookies_tree_model.h"
 #include "chrome/browser/ui/cocoa/content_settings/cookie_details.h"
 
 @interface CocoaCookieTreeNode : NSObject {
-  scoped_nsobject<NSString> title_;
-  scoped_nsobject<NSMutableArray> children_;
-  scoped_nsobject<CocoaCookieDetails> details_;
+  base::scoped_nsobject<NSString> title_;
+  base::scoped_nsobject<NSMutableArray> children_;
+  base::scoped_nsobject<CocoaCookieDetails> details_;
   CookieTreeNode* treeNode_;  // weak
 }
 
diff --git a/chrome/browser/ui/cocoa/content_settings/cookie_tree_node.mm b/chrome/browser/ui/cocoa/content_settings/cookie_tree_node.mm
index a459194..44b97d0 100644
--- a/chrome/browser/ui/cocoa/content_settings/cookie_tree_node.mm
+++ b/chrome/browser/ui/cocoa/content_settings/cookie_tree_node.mm
@@ -43,7 +43,7 @@
     children_.reset([[NSMutableArray alloc] initWithCapacity:childCount]);
     for (int i = 0; i < childCount; ++i) {
       CookieTreeNode* child = treeNode_->GetChild(i);
-      scoped_nsobject<CocoaCookieTreeNode> childNode(
+      base::scoped_nsobject<CocoaCookieTreeNode> childNode(
           [[CocoaCookieTreeNode alloc] initWithNode:child]);
       [children_ addObject:childNode.get()];
     }
diff --git a/chrome/browser/ui/cocoa/custom_frame_view_unittest.mm b/chrome/browser/ui/cocoa/custom_frame_view_unittest.mm
index ee4a5f8..4f061cd 100644
--- a/chrome/browser/ui/cocoa/custom_frame_view_unittest.mm
+++ b/chrome/browser/ui/cocoa/custom_frame_view_unittest.mm
@@ -6,7 +6,7 @@
 #include <objc/runtime.h>
 
 #include "base/mac/mac_util.h"
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #import "chrome/browser/ui/cocoa/custom_frame_view.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/platform_test.h"
@@ -24,7 +24,7 @@
     view_.reset([[customFrameClass alloc] initWithFrame:frame]);
   }
 
-  scoped_nsobject<NSView> view_;
+  base::scoped_nsobject<NSView> view_;
 };
 
 //  Test to make sure our class modifications were successful.
diff --git a/chrome/browser/ui/cocoa/dev_tools_controller.h b/chrome/browser/ui/cocoa/dev_tools_controller.h
index 554b8ab..cfb12c6 100644
--- a/chrome/browser/ui/cocoa/dev_tools_controller.h
+++ b/chrome/browser/ui/cocoa/dev_tools_controller.h
@@ -7,7 +7,7 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "chrome/browser/devtools/devtools_window.h"
 
 @class GraySplitView;
@@ -23,7 +23,7 @@
 @interface DevToolsController : NSObject<NSSplitViewDelegate> {
  @private
   // A view hosting docked devTools contents.
-  scoped_nsobject<GraySplitView> splitView_;
+  base::scoped_nsobject<GraySplitView> splitView_;
 
   DevToolsDockSide dockSide_;
 
@@ -47,9 +47,6 @@
 - (void)updateDevToolsForWebContents:(content::WebContents*)contents
                          withProfile:(Profile*)profile;
 
-- (CGFloat)topContentOffset;
-- (void)setTopContentOffset:(CGFloat)offset;
-
 @end
 
 #endif  // CHROME_BROWSER_UI_COCOA_DEV_TOOLS_CONTROLLER_H_
diff --git a/chrome/browser/ui/cocoa/dev_tools_controller.mm b/chrome/browser/ui/cocoa/dev_tools_controller.mm
index c495d1f..d9e5b77 100644
--- a/chrome/browser/ui/cocoa/dev_tools_controller.mm
+++ b/chrome/browser/ui/cocoa/dev_tools_controller.mm
@@ -8,7 +8,6 @@
 
 #include <Cocoa/Cocoa.h>
 
-#import "base/mac/foundation_util.h"
 #include "base/prefs/pref_service.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/profiles/profile.h"
@@ -20,11 +19,9 @@
 using content::WebContents;
 
 @interface GraySplitView : NSSplitView {
-  CGFloat topContentOffset_;
   BOOL dividerHidden_;
 }
 
-@property(assign, nonatomic) CGFloat topContentOffset;
 @property(assign, nonatomic) BOOL dividerHidden;
 
 - (NSColor*)dividerColor;
@@ -35,7 +32,6 @@
 
 @implementation GraySplitView
 
-@synthesize topContentOffset = topContentOffset_;
 @synthesize dividerHidden = dividerHidden_;
 
 - (NSColor*)dividerColor {
@@ -46,29 +42,12 @@
   return dividerHidden_ ? 0 : [super dividerThickness];
 }
 
-- (void)drawDividerInRect:(NSRect)aRect {
-  NSRect dividerRect = aRect;
-  if ([self isVertical]) {
-    dividerRect.size.height -= topContentOffset_;
-    dividerRect.origin.y += topContentOffset_;
-  }
-  [super drawDividerInRect:dividerRect];
-}
-
-- (NSView*)hitTest:(NSPoint)point {
-  NSPoint viewPoint = [self convertPoint:point fromView:[self superview]];
-  if (viewPoint.y < topContentOffset_)
-    return nil;
-  return [super hitTest:point];
-}
-
 @end
 
 @interface DevToolsController (Private)
 - (void)showDevToolsContainer;
 - (void)hideDevToolsContainer;
 - (void)updateDevToolsSplitPosition;
-- (void)updateDevToolsViewFrame;
 @end
 
 
@@ -136,16 +115,6 @@
   }
 }
 
-- (CGFloat)topContentOffset {
-  return [splitView_ topContentOffset];
-}
-
-- (void)setTopContentOffset:(CGFloat)offset {
-  [splitView_ setTopContentOffset:offset];
-  if ([[splitView_ subviews] count] > 1)
-    [self updateDevToolsViewFrame];
-}
-
 - (void)showDevToolsContainer {
   NSArray* subviews = [splitView_ subviews];
   DCHECK_EQ([subviews count], 1u);
@@ -156,18 +125,11 @@
   // VIEW_ID_DEV_TOOLS_DOCKED here.
   NSView* devToolsView = devToolsContents->GetView()->GetNativeView();
   view_id_util::SetID(devToolsView, VIEW_ID_DEV_TOOLS_DOCKED);
-  [devToolsView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
-
-  NSRect containerRect = NSMakeRect(0, 0, 100, 100);
-  scoped_nsobject<NSView> devToolsContainerView(
-      [[NSView alloc] initWithFrame:containerRect]);
-  [devToolsContainerView addSubview:devToolsView];
-  [splitView_ addSubview:devToolsContainerView];
+  [splitView_ addSubview:devToolsView];
 
   BOOL isVertical = devToolsWindow_->dock_side() == DEVTOOLS_DOCK_SIDE_RIGHT;
   [splitView_ setVertical:isVertical];
   [self updateDevToolsSplitPosition];
-  [self updateDevToolsViewFrame];
 }
 
 - (void)hideDevToolsContainer {
@@ -215,15 +177,6 @@
   [splitView_ adjustSubviews];
 }
 
-- (void)updateDevToolsViewFrame {
-  NSView* devToolsView =
-      devToolsWindow_->web_contents()->GetView()->GetNativeView();
-  NSRect devToolsRect = [[devToolsView superview] bounds];
-  if (devToolsWindow_->dock_side() == DEVTOOLS_DOCK_SIDE_RIGHT)
-    devToolsRect.size.height -= [splitView_ topContentOffset];
-  [devToolsView setFrame:devToolsRect];
-}
-
 // NSSplitViewDelegate protocol.
 - (BOOL)splitView:(NSSplitView *)splitView
     shouldAdjustSizeOfSubview:(NSView *)subview {
@@ -236,16 +189,6 @@
   return YES;
 }
 
-- (CGFloat)splitView:(NSSplitView*)splitView
-    constrainSplitPosition:(CGFloat)proposedPosition
-               ofSubviewAt:(NSInteger)dividerIndex {
-  if (![splitView_ isVertical] &&
-      proposedPosition < [splitView_ topContentOffset]) {
-    return [splitView_ topContentOffset];
-  }
-  return proposedPosition;
-}
-
 - (NSRect)splitView:(NSSplitView*)splitView
       effectiveRect:(NSRect)proposedEffectiveRect
        forDrawnRect:(NSRect)drawnRect
diff --git a/chrome/browser/ui/cocoa/dev_tools_controller_browsertest.mm b/chrome/browser/ui/cocoa/dev_tools_controller_browsertest.mm
index 2c61e80..cffd2a7 100644
--- a/chrome/browser/ui/cocoa/dev_tools_controller_browsertest.mm
+++ b/chrome/browser/ui/cocoa/dev_tools_controller_browsertest.mm
@@ -26,115 +26,10 @@
                                          DEVTOOLS_TOGGLE_ACTION_SHOW);
   }
 
-  DevToolsController* controller() {
-    NSWindow* window = browser()->window()->GetNativeWindow();
-    BrowserWindowController* window_controller =
-        [BrowserWindowController browserWindowControllerForWindow:window];
-    return [window_controller devToolsController];
-  }
-
-  void SetDockSide(DevToolsDockSide side) {
-    content::WebContents* web_contents =
-        browser()->tab_strip_model()->GetActiveWebContents();
-    DevToolsWindow* dev_tools =
-        DevToolsWindow::GetDockedInstanceForInspectedTab(web_contents);
-    dev_tools->SetDockSide(dev_tools->SideToString(side));
-  }
-
  private:
   DISALLOW_COPY_AND_ASSIGN(DevToolsControllerTest);
 };
 
-// Verify that in horizontal mode the splitter is not allowed to go past the
-// bookmark bar.
-IN_PROC_BROWSER_TEST_F(DevToolsControllerTest, ConstrainSplitter) {
-  [controller() setTopContentOffset:0];
-  EXPECT_EQ(0, [controller() splitView:[controller() splitView]
-                constrainSplitPosition:0
-                           ofSubviewAt:0]);
-
-  CGFloat offset = 50;
-  [controller() setTopContentOffset:offset];
-  EXPECT_EQ(offset, [controller() splitView:[controller() splitView]
-                     constrainSplitPosition:0
-                                ofSubviewAt:0]);
-
-  // Should not be constrained in vertical mode.
-  [[controller() splitView] setVertical:YES];
-  EXPECT_EQ(0, [controller() splitView:[controller() splitView]
-                constrainSplitPosition:0
-                           ofSubviewAt:0]);
-}
-
-// When docked to the right the dev tools view should be shrunk so that it
-// doesn't overlap the bookmark bar.
-IN_PROC_BROWSER_TEST_F(DevToolsControllerTest, ViewSize) {
-  EXPECT_EQ(2u, [[[controller() splitView] subviews] count]);
-  NSView* container_view = [[[controller() splitView] subviews] lastObject];
-  EXPECT_EQ(1u, [[container_view subviews] count]);
-  NSView* dev_tools_view = [[container_view subviews] lastObject];
-  CGFloat width = NSWidth([[controller() splitView] bounds]);
-  CGFloat height = NSHeight([[controller() splitView] bounds]);
-  CGFloat offset = [controller() topContentOffset];
-
-  SetDockSide(DEVTOOLS_DOCK_SIDE_BOTTOM);
-  EXPECT_EQ(width, NSWidth([dev_tools_view bounds]));
-
-  SetDockSide(DEVTOOLS_DOCK_SIDE_RIGHT);
-  EXPECT_EQ(height - offset, NSHeight([dev_tools_view bounds]));
-
-  CGFloat new_offset = 50;
-  [controller() setTopContentOffset:new_offset];
-
-  SetDockSide(DEVTOOLS_DOCK_SIDE_BOTTOM);
-  EXPECT_EQ(width, NSWidth([dev_tools_view bounds]));
-
-  SetDockSide(DEVTOOLS_DOCK_SIDE_RIGHT);
-  EXPECT_EQ(height - new_offset, NSHeight([dev_tools_view bounds]));
-}
-
-// Verify that the dev tool's web view is layed out correctly when docked to the
-// right.
-IN_PROC_BROWSER_TEST_F(DevToolsControllerTest, WebViewLayout) {
-  CGFloat offset = 50;
-  [controller() setTopContentOffset:offset];
-
-  SetDockSide(DEVTOOLS_DOCK_SIDE_RIGHT);
-  AddTabAtIndex(
-      0, GURL(content::kAboutBlankURL), content::PAGE_TRANSITION_TYPED);
-  DevToolsWindow::ToggleDevToolsWindow(browser(), DEVTOOLS_TOGGLE_ACTION_SHOW);
-
-  NSView* container_view = [[[controller() splitView] subviews] lastObject];
-  NSView* dev_tools_view = [[container_view subviews] lastObject];
-  NSView* web_view = [[dev_tools_view subviews] lastObject];
-
-  CGFloat height = NSHeight([[controller() splitView] bounds]);
-
-  EXPECT_EQ(height - offset, NSHeight([web_view bounds]));
-  EXPECT_EQ(0, NSMinY([web_view bounds]));
-
-  // Update the offset and verify that the view is resized.
-  CGFloat new_offset = 25;
-  [controller() setTopContentOffset:new_offset];
-  EXPECT_EQ(height - new_offset, NSHeight([web_view bounds]));
-  EXPECT_EQ(0, NSMinY([web_view bounds]));
-}
-
-// Verify that the dev tools undocked window is layed out correctly.
-IN_PROC_BROWSER_TEST_F(DevToolsControllerTest, UndockedOffset) {
-  BrowserList* browser_list =
-      BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_NATIVE);
-  EXPECT_EQ(1u, browser_list->size());
-  SetDockSide(DEVTOOLS_DOCK_SIDE_UNDOCKED);
-  EXPECT_EQ(2u, browser_list->size());
-
-  Browser* dev_tools_browser = browser_list->get(1);
-  BrowserWindowController* window_controller =
-      [BrowserWindowController browserWindowControllerForWindow:
-              dev_tools_browser->window()->GetNativeWindow()];
-  EXPECT_EQ(0.0, [[window_controller devToolsController] topContentOffset]);
-}
-
 // Verify that AllowOverlappingViews is set while the find bar is visible.
 IN_PROC_BROWSER_TEST_F(DevToolsControllerTest, AllowOverlappingViews) {
   content::WebContents* web_contents =
diff --git a/chrome/browser/ui/cocoa/dock_icon.h b/chrome/browser/ui/cocoa/dock_icon.h
index ee1cd8c..259171a 100644
--- a/chrome/browser/ui/cocoa/dock_icon.h
+++ b/chrome/browser/ui/cocoa/dock_icon.h
@@ -4,7 +4,7 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/time.h"
+#include "base/time/time.h"
 
 // A class representing the dock icon of the Chromium app. It's its own class
 // since several parts of the app want to manipulate the display of the dock
diff --git a/chrome/browser/ui/cocoa/dock_icon.mm b/chrome/browser/ui/cocoa/dock_icon.mm
index d70618d..f6bf5ae 100644
--- a/chrome/browser/ui/cocoa/dock_icon.mm
+++ b/chrome/browser/ui/cocoa/dock_icon.mm
@@ -6,7 +6,7 @@
 
 #include "base/logging.h"
 #include "base/mac/bundle_locations.h"
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "content/public/browser/browser_thread.h"
 #include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h"
 
@@ -85,7 +85,7 @@
   NSColor* backgroundHighlight =
       [backgroundColor blendedColorWithFraction:0.85
                                         ofColor:[NSColor whiteColor]];
-  scoped_nsobject<NSGradient> backgroundGradient(
+  base::scoped_nsobject<NSGradient> backgroundGradient(
       [[NSGradient alloc] initWithStartingColor:backgroundHighlight
                                     endingColor:backgroundColor]);
   NSBezierPath* badgeEdge = [NSBezierPath bezierPathWithOvalInRect:badgeRect];
@@ -108,7 +108,7 @@
     NSColor* sliceHighlight =
         [sliceColor blendedColorWithFraction:0.4
                                      ofColor:[NSColor whiteColor]];
-    scoped_nsobject<NSGradient> sliceGradient(
+    base::scoped_nsobject<NSGradient> sliceGradient(
         [[NSGradient alloc] initWithStartingColor:sliceHighlight
                                       endingColor:sliceColor]);
     NSBezierPath* progressSlice;
@@ -140,7 +140,7 @@
   {
     gfx::ScopedNSGraphicsContextSaveGState scopedGState;
     [[NSColor whiteColor] set];
-    scoped_nsobject<NSShadow> shadow([[NSShadow alloc] init]);
+    base::scoped_nsobject<NSShadow> shadow([[NSShadow alloc] init]);
     [shadow.get() setShadowOffset:NSMakeSize(0, -2)];
     [shadow setShadowBlurRadius:2];
     [shadow set];
@@ -149,12 +149,12 @@
   }
 
   // Download count
-  scoped_nsobject<NSNumberFormatter> formatter(
+  base::scoped_nsobject<NSNumberFormatter> formatter(
       [[NSNumberFormatter alloc] init]);
   NSString* countString =
       [formatter stringFromNumber:[NSNumber numberWithInt:downloads_]];
 
-  scoped_nsobject<NSShadow> countShadow([[NSShadow alloc] init]);
+  base::scoped_nsobject<NSShadow> countShadow([[NSShadow alloc] init]);
   [countShadow setShadowBlurRadius:3.0];
   [countShadow.get() setShadowColor:[NSColor whiteColor]];
   [countShadow.get() setShadowOffset:NSMakeSize(0.0, 0.0)];
@@ -165,7 +165,7 @@
           nil];
   CGFloat countFontSize = badgeRadius;
   NSSize countSize = NSZeroSize;
-  scoped_nsobject<NSAttributedString> countAttrString;
+  base::scoped_nsobject<NSAttributedString> countAttrString;
   while (1) {
     NSFont* countFont = [NSFont fontWithName:@"Helvetica-Bold"
                                         size:countFontSize];
@@ -207,7 +207,8 @@
   if (!icon) {
     NSDockTile* dockTile = [[NSApplication sharedApplication] dockTile];
 
-    scoped_nsobject<DockTileView> dockTileView([[DockTileView alloc] init]);
+    base::scoped_nsobject<DockTileView> dockTileView(
+        [[DockTileView alloc] init]);
     [dockTile setContentView:dockTileView];
 
     icon = [[DockIcon alloc] init];
diff --git a/chrome/browser/ui/cocoa/download/background_theme.h b/chrome/browser/ui/cocoa/download/background_theme.h
index 7751965..d044fe1 100644
--- a/chrome/browser/ui/cocoa/download/background_theme.h
+++ b/chrome/browser/ui/cocoa/download/background_theme.h
@@ -7,7 +7,7 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "ui/base/theme_provider.h"
 
 class BackgroundTheme : public ui::ThemeProvider {
@@ -33,9 +33,9 @@
 
  private:
   ui::ThemeProvider* provider_;
-  scoped_nsobject<NSGradient> buttonGradient_;
-  scoped_nsobject<NSGradient> buttonPressedGradient_;
-  scoped_nsobject<NSColor> borderColor_;
+  base::scoped_nsobject<NSGradient> buttonGradient_;
+  base::scoped_nsobject<NSGradient> buttonPressedGradient_;
+  base::scoped_nsobject<NSColor> borderColor_;
 };
 
 #endif  // CHROME_BROWSER_UI_COCOA_DOWNLOAD_BACKGROUND_THEME_H_
diff --git a/chrome/browser/ui/cocoa/download/download_item_button.mm b/chrome/browser/ui/cocoa/download/download_item_button.mm
index 67920fe..4bfd70f 100644
--- a/chrome/browser/ui/cocoa/download/download_item_button.mm
+++ b/chrome/browser/ui/cocoa/download/download_item_button.mm
@@ -34,7 +34,7 @@
   } else {
     // Hold a reference to our controller in case the download completes and we
     // represent a file that's auto-removed (e.g. a theme).
-    scoped_nsobject<DownloadItemController> ref([controller_ retain]);
+    base::scoped_nsobject<DownloadItemController> ref([controller_ retain]);
     [cell setHighlighted:YES];
     [[self menu] setDelegate:self];
     [NSMenu popUpContextMenu:[self menu]
@@ -46,7 +46,7 @@
 // Override to retain the controller, in case a closure is pumped that deletes
 // the DownloadItemController while the menu is open <http://crbug.com/129826>.
 - (void)rightMouseDown:(NSEvent*)event {
-  scoped_nsobject<DownloadItemController> ref([controller_ retain]);
+  base::scoped_nsobject<DownloadItemController> ref([controller_ retain]);
   [super rightMouseDown:event];
 }
 
diff --git a/chrome/browser/ui/cocoa/download/download_item_button_unittest.mm b/chrome/browser/ui/cocoa/download/download_item_button_unittest.mm
index 6fc6b43..e6f07e9 100644
--- a/chrome/browser/ui/cocoa/download/download_item_button_unittest.mm
+++ b/chrome/browser/ui/cocoa/download/download_item_button_unittest.mm
@@ -2,15 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "base/memory/scoped_nsobject.h"
-#import "chrome/browser/ui/cocoa/download/download_item_button.h"
+#include "base/mac/scoped_nsobject.h"
 #import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/download/download_item_button.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/platform_test.h"
 
 // Make sure nothing leaks.
 TEST(DownloadItemButtonTest, Create) {
-  scoped_nsobject<DownloadItemButton> button;
+  base::scoped_nsobject<DownloadItemButton> button;
   button.reset([[DownloadItemButton alloc]
       initWithFrame:NSMakeRect(0,0,500,500)]);
 
diff --git a/chrome/browser/ui/cocoa/download/download_item_cell.h b/chrome/browser/ui/cocoa/download/download_item_cell.h
index c73f9c8..9e01975 100644
--- a/chrome/browser/ui/cocoa/download/download_item_cell.h
+++ b/chrome/browser/ui/cocoa/download/download_item_cell.h
@@ -30,23 +30,23 @@
   // Track which part of the button the mouse is over
   DownloadItemMousePosition mousePosition_;
   int mouseInsideCount_;
-  scoped_nsobject<NSTrackingArea> trackingAreaButton_;
-  scoped_nsobject<NSTrackingArea> trackingAreaDropdown_;
+  base::scoped_nsobject<NSTrackingArea> trackingAreaButton_;
+  base::scoped_nsobject<NSTrackingArea> trackingAreaDropdown_;
 
   base::FilePath downloadPath_;  // stored unelided
   NSString* secondaryTitle_;
   NSFont* secondaryFont_;
   int percentDone_;
-  scoped_nsobject<NSAnimation> completionAnimation_;
+  base::scoped_nsobject<NSAnimation> completionAnimation_;
 
   // In degrees, for downloads with no known total size.
   int indeterminateProgressAngle_;
-  scoped_nsobject<IndeterminateProgressTimer> indeterminateProgressTimer_;
+  base::scoped_nsobject<IndeterminateProgressTimer> indeterminateProgressTimer_;
 
   BOOL isStatusTextVisible_;
   CGFloat titleY_;
   CGFloat statusAlpha_;
-  scoped_nsobject<NSAnimation> toggleStatusVisibilityAnimation_;
+  base::scoped_nsobject<NSAnimation> toggleStatusVisibilityAnimation_;
 
   scoped_ptr<ui::ThemeProvider> themeProvider_;
 }
diff --git a/chrome/browser/ui/cocoa/download/download_item_cell.mm b/chrome/browser/ui/cocoa/download/download_item_cell.mm
index 2a47782..f6af374 100644
--- a/chrome/browser/ui/cocoa/download/download_item_cell.mm
+++ b/chrome/browser/ui/cocoa/download/download_item_cell.mm
@@ -96,7 +96,7 @@
 @interface IndeterminateProgressTimer : NSObject {
  @private
   DownloadItemCell* cell_;
-  scoped_nsobject<NSTimer> timer_;
+  base::scoped_nsobject<NSTimer> timer_;
 }
 
 - (id)initWithDownloadItemCell:(DownloadItemCell*)cell;
@@ -621,7 +621,7 @@
 
   gfx::ScopedNSGraphicsContextSaveGState scopedGState;
 
-  scoped_nsobject<NSShadow> shadow([[NSShadow alloc] init]);
+  base::scoped_nsobject<NSShadow> shadow([[NSShadow alloc] init]);
   [shadow.get() setShadowColor:[NSColor whiteColor]];
   [shadow.get() setShadowOffset:NSMakeSize(0, -1)];
   [shadow setShadowBlurRadius:0.0];
diff --git a/chrome/browser/ui/cocoa/download/download_item_cell_unittest.mm b/chrome/browser/ui/cocoa/download/download_item_cell_unittest.mm
index b68f36f..ef4aa54 100644
--- a/chrome/browser/ui/cocoa/download/download_item_cell_unittest.mm
+++ b/chrome/browser/ui/cocoa/download/download_item_cell_unittest.mm
@@ -2,10 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "chrome/browser/download/download_item_model.h"
-#import "chrome/browser/ui/cocoa/download/download_item_cell.h"
 #import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/download/download_item_cell.h"
 #include "content/public/test/mock_download_item.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/platform_test.h"
@@ -32,8 +32,8 @@
   }
 
  protected:
-  scoped_nsobject<DownloadItemCell> cell_;
-  scoped_nsobject<NSButton> button_;
+  base::scoped_nsobject<DownloadItemCell> cell_;
+  base::scoped_nsobject<NSButton> button_;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(DownloadItemCellTest);
diff --git a/chrome/browser/ui/cocoa/download/download_item_controller.h b/chrome/browser/ui/cocoa/download/download_item_controller.h
index b7b25f5..b188a87 100644
--- a/chrome/browser/ui/cocoa/download/download_item_controller.h
+++ b/chrome/browser/ui/cocoa/download/download_item_controller.h
@@ -5,7 +5,7 @@
 #import <Cocoa/Cocoa.h>
 
 #include "base/memory/scoped_ptr.h"
-#include "base/time.h"
+#include "base/time/time.h"
 
 @class ChromeUILocalizer;
 @class DownloadItemCell;
diff --git a/chrome/browser/ui/cocoa/download/download_item_mac.h b/chrome/browser/ui/cocoa/download/download_item_mac.h
index 363dd33..6d77801 100644
--- a/chrome/browser/ui/cocoa/download/download_item_mac.h
+++ b/chrome/browser/ui/cocoa/download/download_item_mac.h
@@ -7,8 +7,6 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
-#include "base/memory/scoped_ptr.h"
 #include "chrome/browser/download/download_item_model.h"
 #include "chrome/browser/icon_manager.h"
 #include "chrome/common/cancelable_task_tracker.h"
diff --git a/chrome/browser/ui/cocoa/download/download_shelf_controller.h b/chrome/browser/ui/cocoa/download/download_shelf_controller.h
index a71cf8e..c264571 100644
--- a/chrome/browser/ui/cocoa/download/download_shelf_controller.h
+++ b/chrome/browser/ui/cocoa/download/download_shelf_controller.h
@@ -4,10 +4,10 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "base/memory/scoped_ptr.h"
-#include "ui/base/cocoa/tracking_area.h"
 #import "chrome/browser/ui/cocoa/view_resizer.h"
+#include "ui/base/cocoa/tracking_area.h"
 
 @class AnimatableView;
 class Browser;
@@ -71,7 +71,7 @@
   ui::ScopedCrTrackingArea trackingArea_;
 
   // The download items we have added to our shelf.
-  scoped_nsobject<NSMutableArray> downloadItemControllers_;
+  base::scoped_nsobject<NSMutableArray> downloadItemControllers_;
 
   // The container that contains (and clamps) all the download items.
   IBOutlet NSView* itemContainerView_;
diff --git a/chrome/browser/ui/cocoa/download/download_shelf_controller.mm b/chrome/browser/ui/cocoa/download/download_shelf_controller.mm
index e0b8eae..be8355b 100644
--- a/chrome/browser/ui/cocoa/download/download_shelf_controller.mm
+++ b/chrome/browser/ui/cocoa/download/download_shelf_controller.mm
@@ -300,7 +300,7 @@
 
 - (void)addDownloadItem:(DownloadItem*)downloadItem {
   DCHECK([NSThread isMainThread]);
-  scoped_nsobject<DownloadItemController> controller(
+  base::scoped_nsobject<DownloadItemController> controller(
       [[DownloadItemController alloc] initWithDownload:downloadItem
                                                  shelf:self
                                              navigator:navigator_]);
diff --git a/chrome/browser/ui/cocoa/download/download_shelf_controller_unittest.mm b/chrome/browser/ui/cocoa/download/download_shelf_controller_unittest.mm
index ed952c3..8ce96ca 100644
--- a/chrome/browser/ui/cocoa/download/download_shelf_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/download/download_shelf_controller_unittest.mm
@@ -4,7 +4,7 @@
 
 #import <Cocoa/Cocoa.h>
 
-#import "base/memory/scoped_nsobject.h"
+#import "base/mac/scoped_nsobject.h"
 #include "base/memory/scoped_ptr.h"
 #include "chrome/browser/download/download_shelf.h"
 #include "chrome/browser/ui/cocoa/cocoa_profile_test.h"
@@ -110,8 +110,8 @@
  protected:
   id CreateItemController();
 
-  scoped_nsobject<CountingDownloadShelfController> shelf_;
-  scoped_nsobject<ViewResizerPong> resize_delegate_;
+  base::scoped_nsobject<CountingDownloadShelfController> shelf_;
+  base::scoped_nsobject<ViewResizerPong> resize_delegate_;
 };
 
 id DownloadShelfControllerTest::CreateItemController() {
@@ -122,12 +122,12 @@
   ON_CALL(*download.get(), GetState())
       .WillByDefault(Return(content::DownloadItem::IN_PROGRESS));
 
-  scoped_nsobject<WrappedMockDownloadItem> wrappedMockDownload(
+  base::scoped_nsobject<WrappedMockDownloadItem> wrappedMockDownload(
       [[WrappedMockDownloadItem alloc] initWithMockDownload:download.Pass()]);
 
   id item_controller =
       [OCMockObject mockForClass:[DownloadItemController class]];
-  scoped_nsobject<NSView> view([[NSView alloc] initWithFrame:NSZeroRect]);
+  base::scoped_nsobject<NSView> view([[NSView alloc] initWithFrame:NSZeroRect]);
   [[[item_controller stub] andCall:@selector(download)
                           onObject:wrappedMockDownload.get()] download];
   [[item_controller stub] updateVisibility:[OCMArg any]];
@@ -144,7 +144,7 @@
 // Removing the last download from the shelf should cause it to close
 // immediately.
 TEST_F(DownloadShelfControllerTest, AddAndRemoveDownload) {
-  scoped_nsobject<DownloadItemController> item(CreateItemController());
+  base::scoped_nsobject<DownloadItemController> item(CreateItemController());
   [shelf_ showDownloadShelf:YES
                isUserAction:NO];
   EXPECT_TRUE([shelf_ isVisible]);
@@ -160,8 +160,8 @@
 // Test that the shelf doesn't close automatically after a removal if there are
 // active download items still on the shelf.
 TEST_F(DownloadShelfControllerTest, AddAndRemoveWithActiveItem) {
-  scoped_nsobject<DownloadItemController> item1(CreateItemController());
-  scoped_nsobject<DownloadItemController> item2(CreateItemController());
+  base::scoped_nsobject<DownloadItemController> item1(CreateItemController());
+  base::scoped_nsobject<DownloadItemController> item2(CreateItemController());
   [shelf_ showDownloadShelf:YES
                isUserAction:NO];
   EXPECT_TRUE([shelf_ isVisible]);
@@ -177,7 +177,7 @@
 // DownloadShelf::Unhide() should cause the shelf to be displayed if there are
 // active downloads on it.
 TEST_F(DownloadShelfControllerTest, HideAndUnhide) {
-  scoped_nsobject<DownloadItemController> item(CreateItemController());
+  base::scoped_nsobject<DownloadItemController> item(CreateItemController());
   [shelf_ showDownloadShelf:YES
                isUserAction:NO];
   EXPECT_TRUE([shelf_ isVisible]);
@@ -193,7 +193,7 @@
 // DownloadShelf::Unhide() shouldn't cause the shelf to be displayed if all
 // active downloads are removed from the shelf while the shelf was hidden.
 TEST_F(DownloadShelfControllerTest, HideAutocloseUnhide) {
-  scoped_nsobject<DownloadItemController> item(CreateItemController());
+  base::scoped_nsobject<DownloadItemController> item(CreateItemController());
   [shelf_ showDownloadShelf:YES
                isUserAction:NO];
   EXPECT_TRUE([shelf_ isVisible]);
@@ -209,7 +209,7 @@
 // Test of autoclosing behavior after opening a download item. The mouse is on
 // the download shelf at the time the autoclose is scheduled.
 TEST_F(DownloadShelfControllerTest, AutoCloseAfterOpenWithMouseInShelf) {
-  scoped_nsobject<DownloadItemController> item(CreateItemController());
+  base::scoped_nsobject<DownloadItemController> item(CreateItemController());
   [shelf_ showDownloadShelf:YES
                isUserAction:NO];
   EXPECT_TRUE([shelf_ isVisible]);
@@ -246,7 +246,7 @@
 
 // Test of autoclosing behavior after opening a download item.
 TEST_F(DownloadShelfControllerTest, AutoCloseAfterOpenWithMouseOffShelf) {
-  scoped_nsobject<DownloadItemController> item(CreateItemController());
+  base::scoped_nsobject<DownloadItemController> item(CreateItemController());
   [shelf_ showDownloadShelf:YES
                isUserAction:NO];
   EXPECT_TRUE([shelf_ isVisible]);
@@ -265,7 +265,7 @@
 // Test that if the shelf is closed while an autoClose is pending, the pending
 // autoClose is cancelled.
 TEST_F(DownloadShelfControllerTest, CloseWithPendingAutoClose) {
-  scoped_nsobject<DownloadItemController> item(CreateItemController());
+  base::scoped_nsobject<DownloadItemController> item(CreateItemController());
   [shelf_ showDownloadShelf:YES
                isUserAction:NO];
   EXPECT_TRUE([shelf_ isVisible]);
@@ -306,7 +306,7 @@
 // That that the shelf cancels a pending autoClose if a new download item is
 // added to it.
 TEST_F(DownloadShelfControllerTest, AddItemWithPendingAutoClose) {
-  scoped_nsobject<DownloadItemController> item(CreateItemController());
+  base::scoped_nsobject<DownloadItemController> item(CreateItemController());
   [shelf_ showDownloadShelf:YES
                isUserAction:NO];
   EXPECT_TRUE([shelf_ isVisible]);
@@ -337,7 +337,7 @@
   EXPECT_EQ(0, shelf_.get()->cancelAutoCloseCount_);
 
   // Add a new download item. The pending autoClose should be cancelled.
-  scoped_nsobject<DownloadItemController> item2(CreateItemController());
+  base::scoped_nsobject<DownloadItemController> item2(CreateItemController());
   [shelf_ add:item.get()];
   EXPECT_EQ(1, shelf_.get()->scheduleAutoCloseCount_);
   EXPECT_EQ(1, shelf_.get()->cancelAutoCloseCount_);
@@ -346,7 +346,7 @@
 
 // Test that pending autoClose calls are cancelled when exiting.
 TEST_F(DownloadShelfControllerTest, CancelAutoCloseOnExit) {
-  scoped_nsobject<DownloadItemController> item(CreateItemController());
+  base::scoped_nsobject<DownloadItemController> item(CreateItemController());
   [shelf_ showDownloadShelf:YES
                isUserAction:NO];
   EXPECT_TRUE([shelf_ isVisible]);
diff --git a/chrome/browser/ui/cocoa/download/download_shelf_mac_unittest.mm b/chrome/browser/ui/cocoa/download/download_shelf_mac_unittest.mm
index 32354e2..c38dedf 100644
--- a/chrome/browser/ui/cocoa/download/download_shelf_mac_unittest.mm
+++ b/chrome/browser/ui/cocoa/download/download_shelf_mac_unittest.mm
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#import "base/memory/scoped_nsobject.h"
+#import "base/mac/scoped_nsobject.h"
 #include "chrome/browser/ui/cocoa/cocoa_profile_test.h"
 #include "chrome/browser/ui/cocoa/download/download_shelf_mac.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -56,7 +56,7 @@
   }
 
  protected:
-  scoped_nsobject<FakeDownloadShelfController> shelf_controller_;
+  base::scoped_nsobject<FakeDownloadShelfController> shelf_controller_;
 };
 
 TEST_F(DownloadShelfMacTest, CreationDoesNotCallShow) {
diff --git a/chrome/browser/ui/cocoa/download/download_shelf_view.mm b/chrome/browser/ui/cocoa/download/download_shelf_view.mm
index d5a6743..a80420e 100644
--- a/chrome/browser/ui/cocoa/download/download_shelf_view.mm
+++ b/chrome/browser/ui/cocoa/download/download_shelf_view.mm
@@ -4,7 +4,6 @@
 
 #import "chrome/browser/ui/cocoa/download/download_shelf_view.h"
 
-#include "base/memory/scoped_nsobject.h"
 #include "chrome/browser/themes/theme_properties.h"
 #include "chrome/browser/themes/theme_service.h"
 #import "chrome/browser/ui/cocoa/nsview_additions.h"
diff --git a/chrome/browser/ui/cocoa/download/download_shelf_view_unittest.mm b/chrome/browser/ui/cocoa/download/download_shelf_view_unittest.mm
index b7263fc..cf22c69 100644
--- a/chrome/browser/ui/cocoa/download/download_shelf_view_unittest.mm
+++ b/chrome/browser/ui/cocoa/download/download_shelf_view_unittest.mm
@@ -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 "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #import "chrome/browser/ui/cocoa/download/download_shelf_view.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -16,7 +16,8 @@
 // This class only needs to do one thing: prevent mouse down events from moving
 // the parent window around.
 TEST_F(DownloadShelfViewTest, CanDragWindow) {
-  scoped_nsobject<DownloadShelfView> view([[DownloadShelfView alloc] init]);
+  base::scoped_nsobject<DownloadShelfView> view(
+      [[DownloadShelfView alloc] init]);
   EXPECT_FALSE([view mouseDownCanMoveWindow]);
 }
 
diff --git a/chrome/browser/ui/cocoa/draggable_button.h b/chrome/browser/ui/cocoa/draggable_button.h
index 5e126b2..0cd0d9b 100644
--- a/chrome/browser/ui/cocoa/draggable_button.h
+++ b/chrome/browser/ui/cocoa/draggable_button.h
@@ -7,7 +7,7 @@
 
 #import <Cocoa/Cocoa.h>
 
-#import "base/memory/scoped_nsobject.h"
+#import "base/mac/scoped_nsobject.h"
 #import "chrome/browser/ui/cocoa/draggable_button_mixin.h"
 
 // Class for buttons that can be drag sources. If the mouse is clicked and moved
@@ -15,7 +15,7 @@
 // |-performClick:|. Subclasses should override these two methods.
 @interface DraggableButton : NSButton<DraggableButtonMixin> {
  @private
-  scoped_nsobject<DraggableButtonImpl> draggableButtonImpl_;
+  base::scoped_nsobject<DraggableButtonImpl> draggableButtonImpl_;
 }
 
 @property(readonly, nonatomic) DraggableButtonImpl* draggableButton;
diff --git a/chrome/browser/ui/cocoa/draggable_button.mm b/chrome/browser/ui/cocoa/draggable_button.mm
index 1eb7d7d..0b3bcd8 100644
--- a/chrome/browser/ui/cocoa/draggable_button.mm
+++ b/chrome/browser/ui/cocoa/draggable_button.mm
@@ -39,7 +39,7 @@
   // The impl spins an event loop to distinguish clicks from drags,
   // which could result in our destruction.  Wire ourselves down for
   // the duration.
-  scoped_nsobject<DraggableButton> keepAlive([self retain]);
+  base::scoped_nsobject<DraggableButton> keepAlive([self retain]);
 
   if ([draggableButtonImpl_ mouseDownImpl:theEvent] ==
           kDraggableButtonMixinCallSuper) {
diff --git a/chrome/browser/ui/cocoa/draggable_button_mixin.mm b/chrome/browser/ui/cocoa/draggable_button_mixin.mm
index e28f674..986f5e9 100644
--- a/chrome/browser/ui/cocoa/draggable_button_mixin.mm
+++ b/chrome/browser/ui/cocoa/draggable_button_mixin.mm
@@ -7,9 +7,6 @@
 #include <cmath>
 
 #include "base/logging.h"
-#import "base/memory/scoped_nsobject.h"
-
-namespace {
 
 // Code taken from <http://codereview.chromium.org/180036/diff/3001/3004>.
 // TODO(viettrungluu): Do we want common, standard code for drag hysteresis?
@@ -17,8 +14,6 @@
 const CGFloat kWebDragStartHysteresisY = 5.0;
 const CGFloat kDragExpirationTimeout = 0.45;
 
-}
-
 // Private /////////////////////////////////////////////////////////////////////
 
 @interface DraggableButtonImpl (Private)
diff --git a/chrome/browser/ui/cocoa/draggable_button_unittest.mm b/chrome/browser/ui/cocoa/draggable_button_unittest.mm
index 6ee44a4..3cada7e 100644
--- a/chrome/browser/ui/cocoa/draggable_button_unittest.mm
+++ b/chrome/browser/ui/cocoa/draggable_button_unittest.mm
@@ -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 "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #import "chrome/browser/ui/cocoa/draggable_button.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -47,8 +47,9 @@
 
 // Make sure the basic case of "click" still works.
 TEST_F(DraggableButtonTest, DownUp) {
-  scoped_nsobject<TestableDraggableButton> button(
-      [[TestableDraggableButton alloc] initWithFrame:NSMakeRect(0,0,500,500)]);
+  base::scoped_nsobject<TestableDraggableButton> button(
+      [[TestableDraggableButton alloc]
+          initWithFrame:NSMakeRect(0, 0, 500, 500)]);
   [[test_window() contentView] addSubview:button.get()];
   [button setTarget:button];
   [button setAction:@selector(trigger:)];
@@ -67,8 +68,9 @@
 }
 
 TEST_F(DraggableButtonTest, DraggableHysteresis) {
-  scoped_nsobject<TestableDraggableButton> button(
-      [[TestableDraggableButton alloc] initWithFrame:NSMakeRect(0,0,500,500)]);
+  base::scoped_nsobject<TestableDraggableButton> button(
+      [[TestableDraggableButton alloc]
+          initWithFrame:NSMakeRect(0, 0, 500, 500)]);
   [[test_window() contentView] addSubview:button.get()];
   NSEvent* downEvent =
       cocoa_test_event_utils::MouseEventAtPoint(NSMakePoint(10,10),
@@ -106,8 +108,9 @@
 }
 
 TEST_F(DraggableButtonTest, ResetState) {
-  scoped_nsobject<TestableDraggableButton> button(
-      [[TestableDraggableButton alloc] initWithFrame:NSMakeRect(0,0,500,500)]);
+  base::scoped_nsobject<TestableDraggableButton> button(
+      [[TestableDraggableButton alloc]
+          initWithFrame:NSMakeRect(0, 0, 500, 500)]);
   [[test_window() contentView] addSubview:button.get()];
   NSEvent* downEvent =
       cocoa_test_event_utils::MouseEventAtPoint(NSMakePoint(10,10),
diff --git a/chrome/browser/ui/cocoa/extensions/browser_action_button.h b/chrome/browser/ui/cocoa/extensions/browser_action_button.h
index 7a083d3..fa5a46b 100644
--- a/chrome/browser/ui/cocoa/extensions/browser_action_button.h
+++ b/chrome/browser/ui/cocoa/extensions/browser_action_button.h
@@ -7,7 +7,7 @@
 
 #import <Cocoa/Cocoa.h>
 
-#import "base/memory/scoped_nsobject.h"
+#import "base/mac/scoped_nsobject.h"
 #include "base/memory/scoped_ptr.h"
 #import "chrome/browser/ui/cocoa/image_button_cell.h"
 
@@ -31,7 +31,7 @@
   scoped_ptr<ExtensionActionIconFactoryBridge> iconFactoryBridge_;
 
   // Used to move the button and query whether a button is currently animating.
-  scoped_nsobject<NSViewAnimation> moveAnimation_;
+  base::scoped_nsobject<NSViewAnimation> moveAnimation_;
 
   // The extension for this button. Weak.
   const extensions::Extension* extension_;
diff --git a/chrome/browser/ui/cocoa/extensions/browser_actions_container_view.mm b/chrome/browser/ui/cocoa/extensions/browser_actions_container_view.mm
index c6b1fa6..2a0a0d3 100644
--- a/chrome/browser/ui/cocoa/extensions/browser_actions_container_view.mm
+++ b/chrome/browser/ui/cocoa/extensions/browser_actions_container_view.mm
@@ -7,7 +7,6 @@
 #include <algorithm>
 
 #include "base/basictypes.h"
-#import "base/memory/scoped_nsobject.h"
 #import "chrome/browser/ui/cocoa/view_id_util.h"
 
 NSString* const kBrowserActionGrippyDragStartedNotification =
diff --git a/chrome/browser/ui/cocoa/extensions/browser_actions_container_view_unittest.mm b/chrome/browser/ui/cocoa/extensions/browser_actions_container_view_unittest.mm
index 14b5c1b..8e8d077 100644
--- a/chrome/browser/ui/cocoa/extensions/browser_actions_container_view_unittest.mm
+++ b/chrome/browser/ui/cocoa/extensions/browser_actions_container_view_unittest.mm
@@ -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 "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #import "chrome/browser/ui/cocoa/extensions/browser_actions_container_view.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -21,7 +21,7 @@
         initWithFrame:NSMakeRect(0, 0, 0, kContainerHeight)]);
   }
 
-  scoped_nsobject<BrowserActionsContainerView> view_;
+  base::scoped_nsobject<BrowserActionsContainerView> view_;
 };
 
 TEST_F(BrowserActionsContainerViewTest, BasicTests) {
diff --git a/chrome/browser/ui/cocoa/extensions/browser_actions_controller.h b/chrome/browser/ui/cocoa/extensions/browser_actions_controller.h
index f24a8d1..37cd3f0 100644
--- a/chrome/browser/ui/cocoa/extensions/browser_actions_controller.h
+++ b/chrome/browser/ui/cocoa/extensions/browser_actions_controller.h
@@ -7,7 +7,7 @@
 
 #import <Cocoa/Cocoa.h>
 
-#import "base/memory/scoped_nsobject.h"
+#import "base/mac/scoped_nsobject.h"
 #include "base/memory/scoped_ptr.h"
 
 class Browser;
@@ -52,19 +52,19 @@
   // A dictionary of Extension ID -> BrowserActionButton pairs representing the
   // buttons present in the container view. The ID is a string unique to each
   // extension.
-  scoped_nsobject<NSMutableDictionary> buttons_;
+  base::scoped_nsobject<NSMutableDictionary> buttons_;
 
   // Array of hidden buttons in the correct order in which the user specified.
-  scoped_nsobject<NSMutableArray> hiddenButtons_;
+  base::scoped_nsobject<NSMutableArray> hiddenButtons_;
 
   // The currently running chevron animation (fade in/out).
-  scoped_nsobject<NSViewAnimation> chevronAnimation_;
+  base::scoped_nsobject<NSViewAnimation> chevronAnimation_;
 
   // The chevron button used when Browser Actions are hidden.
-  scoped_nsobject<MenuButton> chevronMenuButton_;
+  base::scoped_nsobject<MenuButton> chevronMenuButton_;
 
   // The Browser Actions overflow menu.
-  scoped_nsobject<NSMenu> overflowMenu_;
+  base::scoped_nsobject<NSMenu> overflowMenu_;
 }
 
 @property(readonly, nonatomic) BrowserActionsContainerView* containerView;
diff --git a/chrome/browser/ui/cocoa/extensions/browser_actions_controller.mm b/chrome/browser/ui/cocoa/extensions/browser_actions_controller.mm
index 4f05f5a..e551c4b 100644
--- a/chrome/browser/ui/cocoa/extensions/browser_actions_controller.mm
+++ b/chrome/browser/ui/cocoa/extensions/browser_actions_controller.mm
@@ -487,10 +487,10 @@
   for (ExtensionList::const_iterator iter =
            toolbarModel_->toolbar_items().begin();
        iter != toolbarModel_->toolbar_items().end(); ++iter) {
-    if (![self shouldDisplayBrowserAction:*iter])
+    if (![self shouldDisplayBrowserAction:iter->get()])
       continue;
 
-    [self createActionButtonForExtension:*iter withIndex:i++];
+    [self createActionButtonForExtension:iter->get() withIndex:i++];
   }
 
   CGFloat width = [self savedWidth];
@@ -579,9 +579,9 @@
   for (ExtensionList::const_iterator iter =
            toolbarModel_->toolbar_items().begin();
        iter != toolbarModel_->toolbar_items().end(); ++iter) {
-    if (![self shouldDisplayBrowserAction:*iter])
+    if (![self shouldDisplayBrowserAction:iter->get()])
       continue;
-    BrowserActionButton* button = [self buttonForExtension:(*iter)];
+    BrowserActionButton* button = [self buttonForExtension:(iter->get())];
     if (!button)
       continue;
     if (![button isBeingDragged])
@@ -672,7 +672,7 @@
   for (ExtensionList::const_iterator iter =
            toolbarModel_->toolbar_items().begin();
        iter != toolbarModel_->toolbar_items().end(); ++iter) {
-    BrowserActionButton* button = [self buttonForExtension:(*iter)];
+    BrowserActionButton* button = [self buttonForExtension:(iter->get())];
     NSRect buttonFrame = [button frame];
     if (NSContainsRect([containerView_ bounds], buttonFrame))
       continue;
@@ -712,7 +712,7 @@
   for (ExtensionList::const_iterator iter =
            toolbarModel_->toolbar_items().begin();
        iter != toolbarModel_->toolbar_items().end(); ++iter) {
-    BrowserActionButton* button = [self buttonForExtension:(*iter)];
+    BrowserActionButton* button = [self buttonForExtension:(iter->get())];
     CGFloat intersectionWidth =
         NSWidth(NSIntersectionRect(draggedButtonFrame, [button frame]));
 
@@ -878,7 +878,7 @@
   const extensions::ExtensionList& toolbar_items =
       toolbarModel_->toolbar_items();
   if (index < toolbar_items.size()) {
-    const Extension* extension = toolbar_items[index];
+    const Extension* extension = toolbar_items[index].get();
     return [buttons_ objectForKey:base::SysUTF8ToNSString(extension->id())];
   }
   return nil;
diff --git a/chrome/browser/ui/cocoa/extensions/extension_action_context_menu.h b/chrome/browser/ui/cocoa/extensions/extension_action_context_menu.h
index b6b50f8..35d5ccf 100644
--- a/chrome/browser/ui/cocoa/extensions/extension_action_context_menu.h
+++ b/chrome/browser/ui/cocoa/extensions/extension_action_context_menu.h
@@ -7,7 +7,6 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
 #include "base/memory/scoped_ptr.h"
 
 class AsyncUninstaller;
diff --git a/chrome/browser/ui/cocoa/extensions/extension_action_context_menu_browsertest.mm b/chrome/browser/ui/cocoa/extensions/extension_action_context_menu_browsertest.mm
index a92c9cc..7aee38c 100644
--- a/chrome/browser/ui/cocoa/extensions/extension_action_context_menu_browsertest.mm
+++ b/chrome/browser/ui/cocoa/extensions/extension_action_context_menu_browsertest.mm
@@ -64,7 +64,7 @@
 
 IN_PROC_BROWSER_TEST_F(ExtensionActionContextMenuTest, BasicTest) {
   SetupPageAction();
-  scoped_nsobject<ExtensionActionContextMenu> menu;
+  base::scoped_nsobject<ExtensionActionContextMenu> menu;
   menu.reset([[ExtensionActionContextMenu alloc] initWithExtension:extension_
                                                            browser:browser()
                                                    extensionAction:action_]);
@@ -103,7 +103,7 @@
        new Browser(Browser::CreateParams(browser()->profile(),
                                          browser()->host_desktop_type())));
 
-  scoped_nsobject<ExtensionActionContextMenu> menu;
+  base::scoped_nsobject<ExtensionActionContextMenu> menu;
   menu.reset([[ExtensionActionContextMenu alloc]
       initWithExtension:extension_
                 browser:empty_browser
@@ -158,7 +158,7 @@
 IN_PROC_BROWSER_TEST_F(
     ExtensionActionContextMenuTest, DISABLED_RunInspectPopup) {
   SetupPageAction();
-  scoped_nsobject<ExtensionActionContextMenu> menu;
+  base::scoped_nsobject<ExtensionActionContextMenu> menu;
   menu.reset([[ExtensionActionContextMenu alloc] initWithExtension:extension_
                                                            browser:browser()
                                                    extensionAction:action_]);
diff --git a/chrome/browser/ui/cocoa/extensions/extension_install_dialog_controller.h b/chrome/browser/ui/cocoa/extensions/extension_install_dialog_controller.h
index c9ada3a..18478ab 100644
--- a/chrome/browser/ui/cocoa/extensions/extension_install_dialog_controller.h
+++ b/chrome/browser/ui/cocoa/extensions/extension_install_dialog_controller.h
@@ -7,7 +7,7 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "chrome/browser/extensions/extension_install_prompt.h"
 #import "chrome/browser/ui/cocoa/constrained_window/constrained_window_mac.h"
 
@@ -46,7 +46,7 @@
 
  private:
   ExtensionInstallPrompt::Delegate* delegate_;
-  scoped_nsobject<ExtensionInstallViewController> view_controller_;
+  base::scoped_nsobject<ExtensionInstallViewController> view_controller_;
   scoped_ptr<ConstrainedWindowMac> constrained_window_;
 };
 
diff --git a/chrome/browser/ui/cocoa/extensions/extension_install_dialog_controller.mm b/chrome/browser/ui/cocoa/extensions/extension_install_dialog_controller.mm
index eb08510..066f3f4 100644
--- a/chrome/browser/ui/cocoa/extensions/extension_install_dialog_controller.mm
+++ b/chrome/browser/ui/cocoa/extensions/extension_install_dialog_controller.mm
@@ -42,13 +42,12 @@
                delegate:this
                  prompt:prompt]);
 
-  scoped_nsobject<NSWindow> window([[ConstrainedWindowCustomWindow alloc]
+  base::scoped_nsobject<NSWindow> window([[ConstrainedWindowCustomWindow alloc]
       initWithContentRect:[[view_controller_ view] bounds]]);
   [[window contentView] addSubview:[view_controller_ view]];
 
-  scoped_nsobject<CustomConstrainedWindowSheet> sheet(
-      [[CustomConstrainedWindowSheet alloc]
-          initWithCustomWindow:window]);
+  base::scoped_nsobject<CustomConstrainedWindowSheet> sheet(
+      [[CustomConstrainedWindowSheet alloc] initWithCustomWindow:window]);
   constrained_window_.reset(new ConstrainedWindowMac(
       this, show_params.parent_web_contents, sheet));
 }
diff --git a/chrome/browser/ui/cocoa/extensions/extension_install_dialog_controller_browsertest.mm b/chrome/browser/ui/cocoa/extensions/extension_install_dialog_controller_browsertest.mm
index 402dcfb..e3dbf83 100644
--- a/chrome/browser/ui/cocoa/extensions/extension_install_dialog_controller_browsertest.mm
+++ b/chrome/browser/ui/cocoa/extensions/extension_install_dialog_controller_browsertest.mm
@@ -30,14 +30,14 @@
 
   chrome::MockExtensionInstallPromptDelegate delegate;
   ExtensionInstallPrompt::Prompt prompt =
-      chrome::BuildExtensionInstallPrompt(extension_);
+      chrome::BuildExtensionInstallPrompt(extension_.get());
 
   ExtensionInstallDialogController* controller =
       new ExtensionInstallDialogController(show_params,
                                            &delegate,
                                            prompt);
 
-  scoped_nsobject<NSWindow> window(
+  base::scoped_nsobject<NSWindow> window(
       [[[controller->view_controller() view] window] retain]);
   EXPECT_TRUE([window isVisible]);
 
@@ -54,14 +54,14 @@
 
   chrome::MockExtensionInstallPromptDelegate delegate;
   ExtensionInstallPrompt::Prompt prompt =
-      chrome::BuildExtensionPostInstallPermissionsPrompt(extension_);
+      chrome::BuildExtensionPostInstallPermissionsPrompt(extension_.get());
 
   ExtensionInstallDialogController* controller =
       new ExtensionInstallDialogController(show_params,
                                            &delegate,
                                            prompt);
 
-  scoped_nsobject<NSWindow> window(
+  base::scoped_nsobject<NSWindow> window(
       [[[controller->view_controller() view] window] retain]);
   EXPECT_TRUE([window isVisible]);
 
diff --git a/chrome/browser/ui/cocoa/extensions/extension_install_view_controller.h b/chrome/browser/ui/cocoa/extensions/extension_install_view_controller.h
index ba3f192..3ba7292 100644
--- a/chrome/browser/ui/cocoa/extensions/extension_install_view_controller.h
+++ b/chrome/browser/ui/cocoa/extensions/extension_install_view_controller.h
@@ -9,7 +9,7 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/strings/string16.h"
 #include "chrome/browser/extensions/extension_install_prompt.h"
@@ -45,7 +45,7 @@
   ExtensionInstallPrompt::Delegate* delegate_;  // weak
   scoped_ptr<ExtensionInstallPrompt::Prompt> prompt_;
 
-  scoped_nsobject<NSArray> warnings_;
+  base::scoped_nsobject<NSArray> warnings_;
   BOOL isComputingRowHeight_;
 }
 
diff --git a/chrome/browser/ui/cocoa/extensions/extension_install_view_controller.mm b/chrome/browser/ui/cocoa/extensions/extension_install_view_controller.mm
index 088f5ff..5e5af3c 100644
--- a/chrome/browser/ui/cocoa/extensions/extension_install_view_controller.mm
+++ b/chrome/browser/ui/cocoa/extensions/extension_install_view_controller.mm
@@ -149,7 +149,7 @@
     nibName = @"ExtensionInstallPromptBundle";
   } else if (prompt.type() == ExtensionInstallPrompt::INLINE_INSTALL_PROMPT) {
     nibName = @"ExtensionInstallPromptInline";
-  } else if (prompt.GetPermissionCount() == 0 &&
+  } else if (!prompt.ShouldShowPermissions() &&
              prompt.GetOAuthIssueCount() == 0 &&
              prompt.GetRetainedFileCount() == 0) {
     nibName = @"ExtensionInstallPromptNoWarnings";
@@ -270,7 +270,7 @@
 
   // If there are any warnings or OAuth issues, then we have to do some special
   // layout.
-  if (prompt_->GetPermissionCount() > 0 || prompt_->GetOAuthIssueCount() > 0 ||
+  if (prompt_->ShouldShowPermissions() || prompt_->GetOAuthIssueCount() > 0 ||
       prompt_->GetRetainedFileCount() > 0) {
     NSSize spacing = [outlineView_ intercellSpacing];
     spacing.width += 2;
@@ -314,7 +314,8 @@
   NSImage* image = gfx::NSImageFromImageSkiaWithColorSpace(
       *skiaImage, base::mac::GetSystemColorSpace());
   NSRect frame = NSMakeRect(0, 0, skiaImage->width(), skiaImage->height());
-  scoped_nsobject<NSImageView> view([[NSImageView alloc] initWithFrame:frame]);
+  base::scoped_nsobject<NSImageView> view(
+      [[NSImageView alloc] initWithFrame:frame]);
   [view setImage:image];
 
   // Add this star after all the other ones
@@ -489,17 +490,29 @@
 
 - (NSArray*)buildWarnings:(const ExtensionInstallPrompt::Prompt&)prompt {
   NSMutableArray* warnings = [NSMutableArray array];
+  NSString* heading = nil;
 
-  if (prompt.GetPermissionCount() > 0) {
+  if (prompt.ShouldShowPermissions()) {
     NSMutableArray* children = [NSMutableArray array];
-    for (size_t i = 0; i < prompt.GetPermissionCount(); ++i) {
+    if (prompt.GetPermissionCount() > 0) {
+      for (size_t i = 0; i < prompt.GetPermissionCount(); ++i) {
+        [children addObject:
+            [self buildItemWithTitle:SysUTF16ToNSString(prompt.GetPermission(i))
+                         isGroupItem:NO
+                            children:nil]];
+      }
+
+      heading = SysUTF16ToNSString(prompt.GetPermissionsHeading());
+    } else {
       [children addObject:
-          [self buildItemWithTitle:SysUTF16ToNSString(prompt.GetPermission(i))
+          [self buildItemWithTitle:
+              l10n_util::GetNSString(IDS_EXTENSION_NO_SPECIAL_PERMISSIONS)
                        isGroupItem:NO
                           children:nil]];
+      heading = @"";
     }
     [warnings addObject:[self
-        buildItemWithTitle:SysUTF16ToNSString(prompt.GetPermissionsHeading())
+        buildItemWithTitle:heading
                isGroupItem:YES
                   children:children]];
   }
diff --git a/chrome/browser/ui/cocoa/extensions/extension_install_view_controller_unittest.mm b/chrome/browser/ui/cocoa/extensions/extension_install_view_controller_unittest.mm
index ed72350..51e4bee 100644
--- a/chrome/browser/ui/cocoa/extensions/extension_install_view_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/extensions/extension_install_view_controller_unittest.mm
@@ -4,7 +4,7 @@
 
 #import <Cocoa/Cocoa.h>
 
-#import "base/memory/scoped_nsobject.h"
+#import "base/mac/scoped_nsobject.h"
 #include "base/strings/sys_string_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #import "chrome/browser/extensions/extension_install_prompt.h"
@@ -40,11 +40,10 @@
   permissions.push_back(UTF8ToUTF16("warning 1"));
   prompt.SetPermissions(permissions);
 
-  scoped_nsobject<ExtensionInstallViewController>
-    controller([[ExtensionInstallViewController alloc]
-                 initWithNavigator:browser()
-                          delegate:&delegate
-                            prompt:prompt]);
+  base::scoped_nsobject<ExtensionInstallViewController> controller(
+      [[ExtensionInstallViewController alloc] initWithNavigator:browser()
+                                                       delegate:&delegate
+                                                         prompt:prompt]);
 
   [controller view];  // Force nib load.
 
@@ -93,11 +92,10 @@
   permissions.push_back(UTF8ToUTF16("warning 1"));
   prompt.SetPermissions(permissions);
 
-  scoped_nsobject<ExtensionInstallViewController>
-  controller([[ExtensionInstallViewController alloc]
-               initWithNavigator:browser()
-                        delegate:&delegate
-                          prompt:prompt]);
+  base::scoped_nsobject<ExtensionInstallViewController> controller(
+      [[ExtensionInstallViewController alloc] initWithNavigator:browser()
+                                                       delegate:&delegate
+                                                         prompt:prompt]);
 
   [controller view];  // Force nib load.
   [controller ok:nil];
@@ -123,19 +121,19 @@
   permissions.push_back(UTF8ToUTF16("warning 2"));
   two_warnings_prompt.SetPermissions(permissions);
 
-  scoped_nsobject<ExtensionInstallViewController>
-  controller1([[ExtensionInstallViewController alloc]
-                initWithNavigator:browser()
-                         delegate:&delegate1
-                           prompt:one_warning_prompt]);
+  base::scoped_nsobject<ExtensionInstallViewController> controller1(
+      [[ExtensionInstallViewController alloc]
+          initWithNavigator:browser()
+                   delegate:&delegate1
+                     prompt:one_warning_prompt]);
 
   [controller1 view];  // Force nib load.
 
-  scoped_nsobject<ExtensionInstallViewController>
-  controller2([[ExtensionInstallViewController alloc]
-                initWithNavigator:browser()
-                         delegate:&delegate2
-                           prompt:two_warnings_prompt]);
+  base::scoped_nsobject<ExtensionInstallViewController> controller2(
+      [[ExtensionInstallViewController alloc]
+          initWithNavigator:browser()
+                   delegate:&delegate2
+                     prompt:two_warnings_prompt]);
 
   [controller2 view];  // Force nib load.
 
@@ -158,11 +156,11 @@
   ExtensionInstallPrompt::Prompt no_warnings_prompt =
       chrome::BuildExtensionInstallPrompt(extension_.get());
 
-  scoped_nsobject<ExtensionInstallViewController>
-  controller([[ExtensionInstallViewController alloc]
-               initWithNavigator:browser()
-                        delegate:&delegate
-                          prompt:no_warnings_prompt]);
+  base::scoped_nsobject<ExtensionInstallViewController> controller(
+      [[ExtensionInstallViewController alloc]
+          initWithNavigator:browser()
+                   delegate:&delegate
+                     prompt:no_warnings_prompt]);
 
   [controller view];  // Force nib load.
 
@@ -202,11 +200,10 @@
   inline_prompt.set_extension(extension_.get());
   inline_prompt.set_icon(chrome::LoadInstallPromptIcon());
 
-  scoped_nsobject<ExtensionInstallViewController>
-  controller([[ExtensionInstallViewController alloc]
-               initWithNavigator:browser()
-                        delegate:&delegate
-                          prompt:inline_prompt]);
+  base::scoped_nsobject<ExtensionInstallViewController> controller(
+      [[ExtensionInstallViewController alloc] initWithNavigator:browser()
+                                                       delegate:&delegate
+                                                         prompt:inline_prompt]);
 
   [controller view];  // Force nib load.
 
@@ -254,7 +251,7 @@
   chrome::MockExtensionInstallPromptDelegate delegate;
 
   ExtensionInstallPrompt::Prompt prompt =
-      chrome::BuildExtensionInstallPrompt(extension_);
+      chrome::BuildExtensionInstallPrompt(extension_.get());
   std::vector<string16> permissions;
   permissions.push_back(UTF8ToUTF16("warning 1"));
   prompt.SetPermissions(permissions);
@@ -265,11 +262,10 @@
   issues.push_back(issue);
   prompt.SetOAuthIssueAdvice(issues);
 
-  scoped_nsobject<ExtensionInstallViewController>
-  controller([[ExtensionInstallViewController alloc]
-               initWithNavigator:browser()
-                        delegate:&delegate
-                          prompt:prompt]);
+  base::scoped_nsobject<ExtensionInstallViewController> controller(
+      [[ExtensionInstallViewController alloc] initWithNavigator:browser()
+                                                       delegate:&delegate
+                                                         prompt:prompt]);
 
   [controller view];  // Force nib load.
   NSOutlineView* outlineView = [controller outlineView];
@@ -290,11 +286,10 @@
   permissions.push_back(UTF8ToUTF16("warning 1"));
   prompt.SetPermissions(permissions);
 
-  scoped_nsobject<ExtensionInstallViewController>
-  controller([[ExtensionInstallViewController alloc]
-               initWithNavigator:browser()
-                        delegate:&delegate
-                          prompt:prompt]);
+  base::scoped_nsobject<ExtensionInstallViewController> controller(
+      [[ExtensionInstallViewController alloc] initWithNavigator:browser()
+                                                       delegate:&delegate
+                                                         prompt:prompt]);
 
   [controller view];  // Force nib load.
 
diff --git a/chrome/browser/ui/cocoa/extensions/extension_installed_bubble_controller.h b/chrome/browser/ui/cocoa/extensions/extension_installed_bubble_controller.h
index 803a77d..aec6898 100644
--- a/chrome/browser/ui/cocoa/extensions/extension_installed_bubble_controller.h
+++ b/chrome/browser/ui/cocoa/extensions/extension_installed_bubble_controller.h
@@ -60,7 +60,7 @@
   const extensions::Extension* extension_;  // weak
   const extensions::BundleInstaller* bundle_;  // weak
   Browser* browser_;  // weak
-  scoped_nsobject<NSImage> icon_;
+  base::scoped_nsobject<NSImage> icon_;
 
   extension_installed_bubble::ExtensionType type_;
 
@@ -91,7 +91,7 @@
   // text views cannot conveniently be created in IB. The xib file contains
   // a text field |promoPlaceholder_| that's replaced by this text view |promo_|
   // in -awakeFromNib.
-  scoped_nsobject<HyperlinkTextView> promo_;
+  base::scoped_nsobject<HyperlinkTextView> promo_;
   // Only shown for bundle installs.
   IBOutlet NSTextField* installedHeadingMsg_;
   IBOutlet NSTextField* installedItemsMsg_;
diff --git a/chrome/browser/ui/cocoa/extensions/extension_installed_bubble_controller.mm b/chrome/browser/ui/cocoa/extensions/extension_installed_bubble_controller.mm
index 883ea76..4536b8d 100644
--- a/chrome/browser/ui/cocoa/extensions/extension_installed_bubble_controller.mm
+++ b/chrome/browser/ui/cocoa/extensions/extension_installed_bubble_controller.mm
@@ -29,7 +29,7 @@
 #include "chrome/browser/ui/cocoa/tabs/tab_strip_view.h"
 #include "chrome/browser/ui/cocoa/toolbar/toolbar_controller.h"
 #include "chrome/browser/ui/singleton_tabs.h"
-#include "chrome/browser/ui/webui/sync_promo/sync_promo_ui.h"
+#include "chrome/browser/ui/sync/sync_promo_ui.h"
 #include "chrome/common/chrome_notification_types.h"
 #include "chrome/common/extensions/api/commands/commands_handler.h"
 #include "chrome/common/extensions/api/extension_action/action_info.h"
diff --git a/chrome/browser/ui/cocoa/extensions/extension_installed_bubble_controller_unittest.mm b/chrome/browser/ui/cocoa/extensions/extension_installed_bubble_controller_unittest.mm
index 4781dd6..4016bbd 100644
--- a/chrome/browser/ui/cocoa/extensions/extension_installed_bubble_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/extensions/extension_installed_bubble_controller_unittest.mm
@@ -111,7 +111,7 @@
     scoped_refptr<Extension> extension =
         Extension::Create(path, extensions::Manifest::INVALID_LOCATION,
                           extension_input_value, Extension::NO_FLAGS, &error);
-    extension_service_->AddExtension(extension);
+    extension_service_->AddExtension(extension.get());
     return extension;
   }
 
diff --git a/chrome/browser/ui/cocoa/extensions/extension_popup_controller.h b/chrome/browser/ui/cocoa/extensions/extension_popup_controller.h
index 782505d..7bd1f23 100644
--- a/chrome/browser/ui/cocoa/extensions/extension_popup_controller.h
+++ b/chrome/browser/ui/cocoa/extensions/extension_popup_controller.h
@@ -7,7 +7,6 @@
 
 #import <Cocoa/Cocoa.h>
 
-#import "base/memory/scoped_nsobject.h"
 #include "base/memory/scoped_ptr.h"
 #import "chrome/browser/ui/cocoa/base_bubble_controller.h"
 #import "chrome/browser/ui/cocoa/info_bubble_view.h"
diff --git a/chrome/browser/ui/cocoa/extensions/extension_popup_controller.mm b/chrome/browser/ui/cocoa/extensions/extension_popup_controller.mm
index b2af054..d5dc47a 100644
--- a/chrome/browser/ui/cocoa/extensions/extension_popup_controller.mm
+++ b/chrome/browser/ui/cocoa/extensions/extension_popup_controller.mm
@@ -149,12 +149,11 @@
         anchoredAt:(NSPoint)anchoredAt
      arrowLocation:(info_bubble::BubbleArrowLocation)arrowLocation
            devMode:(BOOL)devMode {
-  scoped_nsobject<InfoBubbleWindow> window(
-      [[InfoBubbleWindow alloc]
-          initWithContentRect:ui::kWindowSizeDeterminedLater
-                    styleMask:NSBorderlessWindowMask
-                      backing:NSBackingStoreBuffered
-                        defer:YES]);
+  base::scoped_nsobject<InfoBubbleWindow> window([[InfoBubbleWindow alloc]
+      initWithContentRect:ui::kWindowSizeDeterminedLater
+                styleMask:NSBorderlessWindowMask
+                  backing:NSBackingStoreBuffered
+                    defer:YES]);
   if (!window.get())
     return nil;
 
diff --git a/chrome/browser/ui/cocoa/extensions/media_galleries_dialog_cocoa.h b/chrome/browser/ui/cocoa/extensions/media_galleries_dialog_cocoa.h
index 74e39cb..54559af 100644
--- a/chrome/browser/ui/cocoa/extensions/media_galleries_dialog_cocoa.h
+++ b/chrome/browser/ui/cocoa/extensions/media_galleries_dialog_cocoa.h
@@ -74,22 +74,22 @@
   scoped_ptr<ConstrainedWindowMac> window_;
 
   // The alert that the dialog is being displayed as.
-  scoped_nsobject<ConstrainedWindowAlert> alert_;
+  base::scoped_nsobject<ConstrainedWindowAlert> alert_;
 
   // True if the user has pressed accept.
   bool accepted_;
 
   // List of checkboxes ordered from bottom to top.
-  scoped_nsobject<NSMutableArray> checkboxes_;
+  base::scoped_nsobject<NSMutableArray> checkboxes_;
 
   // Container view for checkboxes.
-  scoped_nsobject<NSView> checkbox_container_;
+  base::scoped_nsobject<NSView> checkbox_container_;
 
   // Container view for the main dialog contents.
-  scoped_nsobject<NSBox> accessory_;
+  base::scoped_nsobject<NSBox> accessory_;
 
   // An Objective-C class to route callbacks from Cocoa code.
-  scoped_nsobject<MediaGalleriesCocoaController> cocoa_controller_;
+  base::scoped_nsobject<MediaGalleriesCocoaController> cocoa_controller_;
 
   DISALLOW_COPY_AND_ASSIGN(MediaGalleriesDialogCocoa);
 };
diff --git a/chrome/browser/ui/cocoa/extensions/media_galleries_dialog_cocoa.mm b/chrome/browser/ui/cocoa/extensions/media_galleries_dialog_cocoa.mm
index e9776ee..5e9940c 100644
--- a/chrome/browser/ui/cocoa/extensions/media_galleries_dialog_cocoa.mm
+++ b/chrome/browser/ui/cocoa/extensions/media_galleries_dialog_cocoa.mm
@@ -98,7 +98,7 @@
 
   // May be NULL during tests.
   if (controller->web_contents()) {
-    scoped_nsobject<CustomConstrainedWindowSheet> sheet(
+    base::scoped_nsobject<CustomConstrainedWindowSheet> sheet(
         [[CustomConstrainedWindowSheet alloc]
             initWithCustomWindow:[alert_ window]]);
     window_.reset(new ConstrainedWindowMac(
@@ -121,9 +121,8 @@
                                                         blue:0.625
                                                        alpha:1.0]];
 
-  scoped_nsobject<NSScrollView> scroll_view(
-      [[NSScrollView alloc] initWithFrame:NSMakeRect(
-          0, 0, kCheckboxMaxWidth, kScrollAreaHeight)]);
+  base::scoped_nsobject<NSScrollView> scroll_view([[NSScrollView alloc]
+      initWithFrame:NSMakeRect(0, 0, kCheckboxMaxWidth, kScrollAreaHeight)]);
   [scroll_view setHasVerticalScroller:YES];
   [scroll_view setHasHorizontalScroller:NO];
   [scroll_view setBorderType:NSNoBorder];
@@ -203,7 +202,8 @@
 }
 
 CGFloat MediaGalleriesDialogCocoa::CreateCheckboxSeparator(CGFloat y_pos) {
-  scoped_nsobject<NSBox> separator([[NSBox alloc] initWithFrame:NSMakeRect(
+  base::scoped_nsobject<NSBox> separator(
+      [[NSBox alloc] initWithFrame:NSMakeRect(
           0, y_pos + kCheckboxMargin * 0.5, kCheckboxMaxWidth, 1.0)]);
   [separator setBoxType:NSBoxSeparator];
   [separator setBorderType:NSLineBorder];
@@ -211,7 +211,7 @@
   [checkbox_container_ addSubview:separator];
   y_pos += kCheckboxMargin * 0.5 + 4;
 
-  scoped_nsobject<NSTextField> unattached_label(
+  base::scoped_nsobject<NSTextField> unattached_label(
       [[NSTextField alloc] initWithFrame:NSZeroRect]);
   [unattached_label setEditable:NO];
   [unattached_label setSelectable:NO];
@@ -288,7 +288,7 @@
     const MediaGalleryPrefInfo& gallery,
     bool permitted,
     CGFloat y_pos) {
-  scoped_nsobject<NSButton> checkbox(
+  base::scoped_nsobject<NSButton> checkbox(
       [[NSButton alloc] initWithFrame:NSZeroRect]);
   NSString* unique_id = GetUniqueIDForGallery(gallery);
   [[checkbox cell] setRepresentedObject:unique_id];
@@ -299,10 +299,8 @@
   [checkboxes_ addObject:checkbox];
 
   [checkbox setTitle:base::SysUTF16ToNSString(
-      MediaGalleriesDialogController::GetGalleryDisplayNameNoAttachment(
-          gallery))];
-  [checkbox setToolTip:base::SysUTF16ToNSString(
-      MediaGalleriesDialogController::GetGalleryTooltip(gallery))];
+      gallery.GetGalleryDisplayName())];
+  [checkbox setToolTip:base::SysUTF16ToNSString(gallery.GetGalleryTooltip())];
   [checkbox setState:permitted ? NSOnState : NSOffState];
 
   [checkbox sizeToFit];
@@ -313,16 +311,14 @@
   [checkbox setFrame:rect];
   [checkbox_container_ addSubview:checkbox];
 
-  scoped_nsobject<NSTextField> details(
-    [[NSTextField alloc] initWithFrame:NSZeroRect]);
+  base::scoped_nsobject<NSTextField> details(
+      [[NSTextField alloc] initWithFrame:NSZeroRect]);
   [details setEditable:NO];
   [details setSelectable:NO];
   [details setBezeled:NO];
   [details setAttributedStringValue:
       constrained_window::GetAttributedLabelString(
-          base::SysUTF16ToNSString(
-              MediaGalleriesDialogController::GetGalleryAdditionalDetails(
-                  gallery)),
+          base::SysUTF16ToNSString(gallery.GetGalleryAdditionalDetails()),
           chrome_style::kTextFontStyle,
           NSNaturalTextAlignment,
           NSLineBreakByClipping
@@ -359,7 +355,7 @@
 // static
 MediaGalleriesDialog* MediaGalleriesDialog::Create(
     MediaGalleriesDialogController* controller) {
-  scoped_nsobject<MediaGalleriesCocoaController> cocoa_controller(
+  base::scoped_nsobject<MediaGalleriesCocoaController> cocoa_controller(
       [[MediaGalleriesCocoaController alloc] init]);
   return new MediaGalleriesDialogCocoa(controller, cocoa_controller);
 }
diff --git a/chrome/browser/ui/cocoa/extensions/media_galleries_dialog_cocoa_browsertest.mm b/chrome/browser/ui/cocoa/extensions/media_galleries_dialog_cocoa_browsertest.mm
index 19b09ab..81dca35 100644
--- a/chrome/browser/ui/cocoa/extensions/media_galleries_dialog_cocoa_browsertest.mm
+++ b/chrome/browser/ui/cocoa/extensions/media_galleries_dialog_cocoa_browsertest.mm
@@ -44,7 +44,7 @@
   scoped_ptr<MediaGalleriesDialogCocoa> dialog(
       static_cast<MediaGalleriesDialogCocoa*>(
           MediaGalleriesDialog::Create(&controller)));
-  scoped_nsobject<NSWindow> window([[dialog->alert_ window] retain]);
+  base::scoped_nsobject<NSWindow> window([[dialog->alert_ window] retain]);
   EXPECT_TRUE([window isVisible]);
 
   WebContentsModalDialogManager* web_contents_modal_dialog_manager =
diff --git a/chrome/browser/ui/cocoa/extensions/native_app_window_cocoa.h b/chrome/browser/ui/cocoa/extensions/native_app_window_cocoa.h
index f92d833..795dd6b 100644
--- a/chrome/browser/ui/cocoa/extensions/native_app_window_cocoa.h
+++ b/chrome/browser/ui/cocoa/extensions/native_app_window_cocoa.h
@@ -8,11 +8,11 @@
 #import <Cocoa/Cocoa.h>
 #include <vector>
 
-#include "base/memory/scoped_nsobject.h"
+#include "apps/shell_window.h"
+#include "base/mac/scoped_nsobject.h"
 #include "base/memory/scoped_ptr.h"
 #import "chrome/browser/ui/cocoa/browser_command_executor.h"
 #include "chrome/browser/ui/extensions/native_app_window.h"
-#include "chrome/browser/ui/extensions/shell_window.h"
 #include "content/public/browser/notification_registrar.h"
 #include "extensions/common/draggable_region.h"
 #include "ui/gfx/rect.h"
@@ -43,8 +43,8 @@
 // Cocoa bridge to AppWindow.
 class NativeAppWindowCocoa : public NativeAppWindow {
  public:
-  NativeAppWindowCocoa(ShellWindow* shell_window,
-                       const ShellWindow::CreateParams& params);
+  NativeAppWindowCocoa(apps::ShellWindow* shell_window,
+                       const apps::ShellWindow::CreateParams& params);
 
   // ui::BaseWindow implementation.
   virtual bool IsActive() const OVERRIDE;
@@ -147,7 +147,7 @@
   void UpdateDraggableRegionsForCustomDrag(
       const std::vector<extensions::DraggableRegion>& regions);
 
-  ShellWindow* shell_window_; // weak - ShellWindow owns NativeAppWindow.
+  apps::ShellWindow* shell_window_; // weak - ShellWindow owns NativeAppWindow.
 
   bool has_frame_;
 
@@ -159,7 +159,7 @@
   gfx::Size max_size_;
   bool resizable_;
 
-  scoped_nsobject<NativeAppWindowController> window_controller_;
+  base::scoped_nsobject<NativeAppWindowController> window_controller_;
   NSInteger attention_request_id_;  // identifier from requestUserAttention
 
   // Indicates whether system drag or custom drag should be used, depending on
diff --git a/chrome/browser/ui/cocoa/extensions/native_app_window_cocoa.mm b/chrome/browser/ui/cocoa/extensions/native_app_window_cocoa.mm
index 460ac10..d6ee237 100644
--- a/chrome/browser/ui/cocoa/extensions/native_app_window_cocoa.mm
+++ b/chrome/browser/ui/cocoa/extensions/native_app_window_cocoa.mm
@@ -20,6 +20,8 @@
 #include "content/public/browser/web_contents_view.h"
 #include "third_party/skia/include/core/SkRegion.h"
 
+using apps::ShellWindow;
+
 @interface NSWindow (NSPrivateApis)
 - (void)setBottomCornerRounded:(BOOL)rounded;
 @end
@@ -226,7 +228,7 @@
                           NSTexturedBackgroundWindowMask;
   if (resizable_)
     style_mask |= NSResizableWindowMask;
-  scoped_nsobject<NSWindow> window;
+  base::scoped_nsobject<NSWindow> window;
   if (has_frame_) {
     window.reset([[ShellNSWindow alloc]
         initWithContentRect:cocoa_bounds
@@ -656,7 +658,7 @@
   // Note that [webView subviews] returns the view's mutable internal array and
   // it should be copied to avoid mutating the original array while enumerating
   // it.
-  scoped_nsobject<NSArray> subviews([[webView subviews] copy]);
+  base::scoped_nsobject<NSArray> subviews([[webView subviews] copy]);
   for (NSView* subview in subviews.get())
     if ([subview isKindOfClass:[ControlRegionView class]])
       [subview removeFromSuperview];
@@ -667,7 +669,7 @@
            system_drag_exclude_areas_.begin();
        iter != system_drag_exclude_areas_.end();
        ++iter) {
-    scoped_nsobject<NSView> controlRegion(
+    base::scoped_nsobject<NSView> controlRegion(
         [[ControlRegionView alloc] initWithAppWindow:this]);
     [controlRegion setFrame:NSMakeRect(iter->x(),
                                        webViewHeight - iter->bottom(),
diff --git a/chrome/browser/ui/cocoa/external_protocol_dialog.h b/chrome/browser/ui/cocoa/external_protocol_dialog.h
index 224c280..e677c3e 100644
--- a/chrome/browser/ui/cocoa/external_protocol_dialog.h
+++ b/chrome/browser/ui/cocoa/external_protocol_dialog.h
@@ -4,7 +4,7 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/time.h"
+#include "base/time/time.h"
 #include "googleurl/src/gurl.h"
 
 @interface ExternalProtocolDialogController : NSObject {
diff --git a/chrome/browser/ui/cocoa/fast_resize_view.h b/chrome/browser/ui/cocoa/fast_resize_view.h
index cdc9c7f..fb68d95 100644
--- a/chrome/browser/ui/cocoa/fast_resize_view.h
+++ b/chrome/browser/ui/cocoa/fast_resize_view.h
@@ -16,19 +16,14 @@
 @interface FastResizeView : NSView {
  @private
   BOOL fastResizeMode_;
-
-  // Offset from the top of the view where the view's content starts. This is
-  // used to prevent this view from drawing white on non-content area.
-  CGFloat contentOffset_;
 }
 
-@property(assign, nonatomic) CGFloat contentOffset;
-
 // Turns fast resizing mode on or off, which determines how this view resizes
 // its subviews.  Turning fast resizing mode off has the effect of immediately
 // resizing subviews to fit; callers do not need to explictly call |setFrame:|
 // to trigger a resize.
 - (void)setFastResizeMode:(BOOL)fastResizeMode;
+
 @end
 
 #endif  // CHROME_BROWSER_UI_COCOA_FAST_RESIZE_VIEW_H_
diff --git a/chrome/browser/ui/cocoa/fast_resize_view.mm b/chrome/browser/ui/cocoa/fast_resize_view.mm
index e87a343..87f7787 100644
--- a/chrome/browser/ui/cocoa/fast_resize_view.mm
+++ b/chrome/browser/ui/cocoa/fast_resize_view.mm
@@ -16,14 +16,17 @@
 
 @implementation FastResizeView
 
-@synthesize contentOffset = contentOffset_;
-
 - (void)setFastResizeMode:(BOOL)fastResizeMode {
+  if (fastResizeMode_ == fastResizeMode)
+    return;
+
   fastResizeMode_ = fastResizeMode;
 
   // Force a relayout when coming out of fast resize mode.
   if (!fastResizeMode_)
     [self layoutSubviews];
+
+  [self setNeedsDisplay:YES];
 }
 
 - (void)resizeSubviewsWithOldSize:(NSSize)oldSize {
@@ -37,27 +40,14 @@
   if (!fastResizeMode_)
     return;
 
-  // Don't draw on the non-content area.
-  NSRect clipRect = [self bounds];
-  clipRect.size.height -= contentOffset_;
-  NSRectClip(clipRect);
-
   [[NSColor whiteColor] set];
   NSRectFill(dirtyRect);
 }
 
-- (NSView*)hitTest:(NSPoint)point {
-  NSView* result = [super hitTest:point];
-  // Never return this view during hit testing. This allows overlapping views to
-  // get events even when they are not topmost.
-  if ([result isEqual:self])
-    return nil;
-  return result;
-}
-
 @end
 
 @implementation FastResizeView (PrivateMethods)
+
 - (void)layoutSubviews {
   // There should never be more than one subview.  There can be zero, if we are
   // in the process of switching tabs or closing the window.  In those cases, no
@@ -79,4 +69,5 @@
     [subview setFrame:bounds];
   }
 }
+
 @end
diff --git a/chrome/browser/ui/cocoa/fast_resize_view_unittest.mm b/chrome/browser/ui/cocoa/fast_resize_view_unittest.mm
index 02ac295..edfea60 100644
--- a/chrome/browser/ui/cocoa/fast_resize_view_unittest.mm
+++ b/chrome/browser/ui/cocoa/fast_resize_view_unittest.mm
@@ -2,9 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "base/memory/scoped_nsobject.h"
-#import "chrome/browser/ui/cocoa/fast_resize_view.h"
+#include "base/mac/scoped_nsobject.h"
 #import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/fast_resize_view.h"
 
 namespace {
 
@@ -12,12 +12,13 @@
  public:
   FastResizeViewTest() {
     NSRect frame = NSMakeRect(0, 0, 100, 30);
-    scoped_nsobject<FastResizeView> view(
+    base::scoped_nsobject<FastResizeView> view(
         [[FastResizeView alloc] initWithFrame:frame]);
     view_ = view.get();
     [[test_window() contentView] addSubview:view_];
 
-    scoped_nsobject<NSView> childView([[NSView alloc] initWithFrame:frame]);
+    base::scoped_nsobject<NSView> childView(
+        [[NSView alloc] initWithFrame:frame]);
     childView_ = childView.get();
     [view_ addSubview:childView_];
   }
diff --git a/chrome/browser/ui/cocoa/find_bar/find_bar_cocoa_controller.h b/chrome/browser/ui/cocoa/find_bar/find_bar_cocoa_controller.h
index e5c482b..4c5a018 100644
--- a/chrome/browser/ui/cocoa/find_bar/find_bar_cocoa_controller.h
+++ b/chrome/browser/ui/cocoa/find_bar/find_bar_cocoa_controller.h
@@ -4,7 +4,7 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "base/strings/string16.h"
 #include "ui/gfx/point.h"
 
@@ -33,19 +33,19 @@
 
   Browser* browser_;
 
-  scoped_nsobject<FocusTracker> focusTracker_;
+  base::scoped_nsobject<FocusTracker> focusTracker_;
 
   // The show/hide animation. This is defined to be non-nil if the
   // animation is running, and is always nil otherwise.  The
   // FindBarCocoaController should not be deallocated while an animation is
   // running (stopAnimation is currently called before the last tab in a
   // window is removed).
-  scoped_nsobject<NSViewAnimation> showHideAnimation_;
+  base::scoped_nsobject<NSViewAnimation> showHideAnimation_;
 
   // The horizontal-moving animation, to avoid occluding find results. This
   // is nil when the animation is not running, and is also stopped by
   // stopAnimation.
-  scoped_nsobject<NSViewAnimation> moveAnimation_;
+  base::scoped_nsobject<NSViewAnimation> moveAnimation_;
 
   // If YES, do nothing as a result of find pasteboard update notifications.
   BOOL suppressPboardUpdateActions_;
diff --git a/chrome/browser/ui/cocoa/find_bar/find_bar_cocoa_controller.mm b/chrome/browser/ui/cocoa/find_bar/find_bar_cocoa_controller.mm
index cc3e356..6fcb98f 100644
--- a/chrome/browser/ui/cocoa/find_bar/find_bar_cocoa_controller.mm
+++ b/chrome/browser/ui/cocoa/find_bar/find_bar_cocoa_controller.mm
@@ -123,6 +123,11 @@
     findBarBridge_->GetFindBarController()->EndFindSession(
         FindBarController::kKeepSelectionOnPage,
         FindBarController::kKeepResultsInFindBox);
+
+  // Turn off hover state on close button else the button will remain
+  // hovered when we bring the find bar back up.
+  // crbug.com/227424
+  [[closeButton_ cell] setIsMouseInside:NO];
 }
 
 - (IBAction)previousResult:(id)sender {
diff --git a/chrome/browser/ui/cocoa/find_bar/find_bar_cocoa_controller_unittest.mm b/chrome/browser/ui/cocoa/find_bar/find_bar_cocoa_controller_unittest.mm
index 20aae91..9cd4db5 100644
--- a/chrome/browser/ui/cocoa/find_bar/find_bar_cocoa_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/find_bar/find_bar_cocoa_controller_unittest.mm
@@ -53,7 +53,7 @@
   }
 
  protected:
-  scoped_nsobject<FindBarCocoaController> controller_;
+  base::scoped_nsobject<FindBarCocoaController> controller_;
 };
 
 TEST_VIEW(FindBarCocoaControllerTest, [controller_ view])
@@ -110,7 +110,7 @@
 }
 
 TEST_F(FindBarCocoaControllerTest, FindTextIsGlobal) {
-  scoped_nsobject<FindBarCocoaController> otherController(
+  base::scoped_nsobject<FindBarCocoaController> otherController(
       [[FindBarCocoaController alloc] initWithBrowser:nil]);
   [[test_window() contentView] addSubview:[otherController view]];
 
diff --git a/chrome/browser/ui/cocoa/find_bar/find_bar_text_field_cell.h b/chrome/browser/ui/cocoa/find_bar/find_bar_text_field_cell.h
index ec61dc5..130009f 100644
--- a/chrome/browser/ui/cocoa/find_bar/find_bar_text_field_cell.h
+++ b/chrome/browser/ui/cocoa/find_bar/find_bar_text_field_cell.h
@@ -6,14 +6,14 @@
 
 #import "chrome/browser/ui/cocoa/styled_text_field_cell.h"
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 
 // FindBarTextFieldCell extends StyledTextFieldCell to provide support for a
 // results label rooted at the right edge of the cell.
 @interface FindBarTextFieldCell : StyledTextFieldCell {
  @private
   // Set if there is a results label to display on the right side of the cell.
-  scoped_nsobject<NSAttributedString> resultsString_;
+  base::scoped_nsobject<NSAttributedString> resultsString_;
 }
 
 // Sets the results label to the localized equivalent of "X of Y".
diff --git a/chrome/browser/ui/cocoa/find_bar/find_bar_text_field_cell.mm b/chrome/browser/ui/cocoa/find_bar/find_bar_text_field_cell.mm
index 3d2095c..82b0bf0 100644
--- a/chrome/browser/ui/cocoa/find_bar/find_bar_text_field_cell.mm
+++ b/chrome/browser/ui/cocoa/find_bar/find_bar_text_field_cell.mm
@@ -57,7 +57,7 @@
 // Convenience for the attributes used in the right-justified info
 // cells.  Sets the background color to red if |foundMatches| is YES.
 - (NSDictionary*)resultsAttributes:(BOOL)foundMatches {
-  scoped_nsobject<NSMutableParagraphStyle> style(
+  base::scoped_nsobject<NSMutableParagraphStyle> style(
       [[NSMutableParagraphStyle alloc] init]);
   [style setAlignment:NSRightTextAlignment];
 
diff --git a/chrome/browser/ui/cocoa/find_bar/find_bar_text_field_cell_unittest.mm b/chrome/browser/ui/cocoa/find_bar/find_bar_text_field_cell_unittest.mm
index 8b33d2a..249ff56 100644
--- a/chrome/browser/ui/cocoa/find_bar/find_bar_text_field_cell_unittest.mm
+++ b/chrome/browser/ui/cocoa/find_bar/find_bar_text_field_cell_unittest.mm
@@ -4,9 +4,9 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
-#import "chrome/browser/ui/cocoa/find_bar/find_bar_text_field_cell.h"
+#include "base/mac/scoped_nsobject.h"
 #import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/find_bar/find_bar_text_field_cell.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/platform_test.h"
 
@@ -36,13 +36,13 @@
     // decorations.
     const NSRect frame = NSMakeRect(0, 0, kWidth, 30);
 
-    scoped_nsobject<FindBarTextFieldCell> cell(
+    base::scoped_nsobject<FindBarTextFieldCell> cell(
         [[FindBarTextFieldCell alloc] initTextCell:@"Testing"]);
     cell_ = cell;
     [cell_ setEditable:YES];
     [cell_ setBordered:YES];
 
-    scoped_nsobject<NSTextField> view(
+    base::scoped_nsobject<NSTextField> view(
         [[NSTextField alloc] initWithFrame:frame]);
     view_ = view;
     [view_ setCell:cell_];
@@ -81,12 +81,12 @@
 // appropriately.
 TEST_F(FindBarTextFieldCellTest, SetAndClearFindResults) {
   [cell_ setActiveMatch:10 of:30];
-  scoped_nsobject<NSAttributedString> tenString(
+  base::scoped_nsobject<NSAttributedString> tenString(
       [[cell_ resultsAttributedString] copy]);
   EXPECT_GT([tenString length], 0U);
 
   [cell_ setActiveMatch:0 of:0];
-  scoped_nsobject<NSAttributedString> zeroString(
+  base::scoped_nsobject<NSAttributedString> zeroString(
       [[cell_ resultsAttributedString] copy]);
   EXPECT_GT([zeroString length], 0U);
   EXPECT_FALSE([tenString isEqualToAttributedString:zeroString]);
diff --git a/chrome/browser/ui/cocoa/find_bar/find_bar_text_field_unittest.mm b/chrome/browser/ui/cocoa/find_bar/find_bar_text_field_unittest.mm
index d205efb..30bc8d6 100644
--- a/chrome/browser/ui/cocoa/find_bar/find_bar_text_field_unittest.mm
+++ b/chrome/browser/ui/cocoa/find_bar/find_bar_text_field_unittest.mm
@@ -4,10 +4,10 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #import "chrome/browser/ui/cocoa/find_bar/find_bar_text_field.h"
 #import "chrome/browser/ui/cocoa/find_bar/find_bar_text_field_cell.h"
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/platform_test.h"
 
@@ -23,7 +23,7 @@
     // Make sure this is wide enough to play games with the cell
     // decorations.
     NSRect frame = NSMakeRect(0, 0, kWidth, 30);
-    scoped_nsobject<FindBarTextField> field(
+    base::scoped_nsobject<FindBarTextField> field(
         [[FindBarTextField alloc] initWithFrame:frame]);
     field_ = field.get();
 
diff --git a/chrome/browser/ui/cocoa/find_bar/find_bar_view_unittest.mm b/chrome/browser/ui/cocoa/find_bar/find_bar_view_unittest.mm
index 3714aa5..6f6ea80 100644
--- a/chrome/browser/ui/cocoa/find_bar/find_bar_view_unittest.mm
+++ b/chrome/browser/ui/cocoa/find_bar/find_bar_view_unittest.mm
@@ -4,7 +4,7 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #import "chrome/browser/ui/cocoa/find_bar/find_bar_view.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -31,7 +31,7 @@
  public:
   FindBarViewTest() {
     NSRect frame = NSMakeRect(0, 0, 100, 30);
-    scoped_nsobject<FindBarView> view(
+    base::scoped_nsobject<FindBarView> view(
         [[FindBarView alloc] initWithFrame:frame]);
     view_ = view.get();
     [[test_window() contentView] addSubview:view_];
@@ -43,7 +43,7 @@
 TEST_VIEW(FindBarViewTest, view_)
 
 TEST_F(FindBarViewTest, FindBarEatsMouseClicksInBackgroundArea) {
-  scoped_nsobject<MouseDownViewPong> pongView(
+  base::scoped_nsobject<MouseDownViewPong> pongView(
       [[MouseDownViewPong alloc] initWithFrame:NSMakeRect(0, 0, 200, 200)]);
 
   // Remove all of the subviews of the findbar, to make sure we don't
@@ -68,7 +68,7 @@
 }
 
 TEST_F(FindBarViewTest, FindBarPassesThroughClicksInTransparentArea) {
-  scoped_nsobject<MouseDownViewPong> pongView(
+  base::scoped_nsobject<MouseDownViewPong> pongView(
       [[MouseDownViewPong alloc] initWithFrame:NSMakeRect(0, 0, 200, 200)]);
   [view_ setFrame:NSMakeRect(0, 0, 200, 200)];
 
diff --git a/chrome/browser/ui/cocoa/find_pasteboard_unittest.mm b/chrome/browser/ui/cocoa/find_pasteboard_unittest.mm
index 049e152..374abc6 100644
--- a/chrome/browser/ui/cocoa/find_pasteboard_unittest.mm
+++ b/chrome/browser/ui/cocoa/find_pasteboard_unittest.mm
@@ -4,7 +4,7 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/platform_test.h"
@@ -68,7 +68,7 @@
     pboard_.reset([[FindPasteboardTesting alloc] init]);
   }
  protected:
-  scoped_nsobject<FindPasteboardTesting> pboard_;
+  base::scoped_nsobject<FindPasteboardTesting> pboard_;
 };
 
 TEST_F(FindPasteboardTest, SettingTextUpdatesPboard) {
diff --git a/chrome/browser/ui/cocoa/first_run_bubble_controller_unittest.mm b/chrome/browser/ui/cocoa/first_run_bubble_controller_unittest.mm
index 1d502f4..aee4d06 100644
--- a/chrome/browser/ui/cocoa/first_run_bubble_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/first_run_bubble_controller_unittest.mm
@@ -7,7 +7,7 @@
 #import <Cocoa/Cocoa.h>
 
 #include "base/debug/debugger.h"
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "chrome/browser/ui/cocoa/cocoa_profile_test.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -18,11 +18,11 @@
 
 // Check that the bubble doesn't crash or leak.
 TEST_F(FirstRunBubbleControllerTest, Init) {
-  scoped_nsobject<NSWindow> parent([[NSWindow alloc]
-      initWithContentRect:NSMakeRect(0, 0, 800, 600)
-                styleMask:NSBorderlessWindowMask
-                  backing:NSBackingStoreBuffered
-         defer:NO]);
+  base::scoped_nsobject<NSWindow> parent(
+      [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 800, 600)
+                                  styleMask:NSBorderlessWindowMask
+                                    backing:NSBackingStoreBuffered
+                                      defer:NO]);
   [parent setReleasedWhenClosed:NO];
   if (base::debug::BeingDebugged())
     [parent.get() orderFront:nil];
diff --git a/chrome/browser/ui/cocoa/first_run_dialog.mm b/chrome/browser/ui/cocoa/first_run_dialog.mm
index 658495e..29486ff 100644
--- a/chrome/browser/ui/cocoa/first_run_dialog.mm
+++ b/chrome/browser/ui/cocoa/first_run_dialog.mm
@@ -7,8 +7,8 @@
 #include "base/bind.h"
 #include "base/mac/bundle_locations.h"
 #include "base/mac/mac_util.h"
+#import "base/mac/scoped_nsobject.h"
 #include "base/memory/ref_counted.h"
-#import "base/memory/scoped_nsobject.h"
 #include "base/message_loop.h"
 #include "base/strings/sys_string_conversions.h"
 #include "chrome/browser/first_run/first_run.h"
@@ -91,7 +91,7 @@
       g_browser_process->local_state()->FindPreference(
           prefs::kMetricsReportingEnabled);
   if (!metrics_reporting_pref || !metrics_reporting_pref->IsManaged()) {
-    scoped_nsobject<FirstRunDialogController> dialog(
+    base::scoped_nsobject<FirstRunDialogController> dialog(
         [[FirstRunDialogController alloc] init]);
 
     [dialog.get() showWindow:nil];
diff --git a/chrome/browser/ui/cocoa/floating_bar_backing_view_unittest.mm b/chrome/browser/ui/cocoa/floating_bar_backing_view_unittest.mm
index bf94628..f4a3a59 100644
--- a/chrome/browser/ui/cocoa/floating_bar_backing_view_unittest.mm
+++ b/chrome/browser/ui/cocoa/floating_bar_backing_view_unittest.mm
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#import "base/memory/scoped_nsobject.h"
+#import "base/mac/scoped_nsobject.h"
 #import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #import "chrome/browser/ui/cocoa/floating_bar_backing_view.h"
 
@@ -12,7 +12,7 @@
  public:
   FloatingBarBackingViewTest() {
     NSRect content_frame = [[test_window() contentView] frame];
-    scoped_nsobject<FloatingBarBackingView> view(
+    base::scoped_nsobject<FloatingBarBackingView> view(
         [[FloatingBarBackingView alloc] initWithFrame:content_frame]);
     view_ = view.get();
     [[test_window() contentView] addSubview:view_];
diff --git a/chrome/browser/ui/cocoa/framed_browser_window.h b/chrome/browser/ui/cocoa/framed_browser_window.h
index ee70280..a5750bf 100644
--- a/chrome/browser/ui/cocoa/framed_browser_window.h
+++ b/chrome/browser/ui/cocoa/framed_browser_window.h
@@ -7,7 +7,6 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
 #include "chrome/browser/ui/cocoa/chrome_browser_window.h"
 
 // Offsets from the top/left of the window frame to the top of the window
diff --git a/chrome/browser/ui/cocoa/framed_browser_window_unittest.mm b/chrome/browser/ui/cocoa/framed_browser_window_unittest.mm
index 066576e..32322ee 100644
--- a/chrome/browser/ui/cocoa/framed_browser_window_unittest.mm
+++ b/chrome/browser/ui/cocoa/framed_browser_window_unittest.mm
@@ -5,7 +5,7 @@
 #import <Cocoa/Cocoa.h>
 
 #include "base/debug/debugger.h"
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "chrome/app/chrome_command_ids.h"
 #import "chrome/browser/ui/cocoa/browser_window_controller.h"
 #import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
@@ -54,7 +54,7 @@
     bounds.origin.y += 40;
 
     [frameView lockFocus];
-    scoped_nsobject<NSBitmapImageRep> bitmap(
+    base::scoped_nsobject<NSBitmapImageRep> bitmap(
         [[NSBitmapImageRep alloc] initWithFocusedViewRect:bounds]);
     [frameView unlockFocus];
 
diff --git a/chrome/browser/ui/cocoa/fullscreen_exit_bubble_controller.h b/chrome/browser/ui/cocoa/fullscreen_exit_bubble_controller.h
index b48fc87..60b986d 100644
--- a/chrome/browser/ui/cocoa/fullscreen_exit_bubble_controller.h
+++ b/chrome/browser/ui/cocoa/fullscreen_exit_bubble_controller.h
@@ -4,7 +4,7 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "chrome/browser/ui/fullscreen/fullscreen_exit_bubble_type.h"
 #include "googleurl/src/gurl.h"
 
@@ -34,10 +34,10 @@
   // text views cannot conveniently be created in IB. The xib file contains
   // a text field |exitLabelPlaceholder_| that's replaced by this text view
   // |exitLabel_| in -awakeFromNib.
-  scoped_nsobject<NSTextView> exitLabel_;
+  base::scoped_nsobject<NSTextView> exitLabel_;
 
-  scoped_nsobject<NSTimer> hideTimer_;
-  scoped_nsobject<NSAnimation> hideAnimation_;
+  base::scoped_nsobject<NSTimer> hideTimer_;
+  base::scoped_nsobject<NSAnimation> hideAnimation_;
 };
 
 // Initializes a new InfoBarController.
diff --git a/chrome/browser/ui/cocoa/fullscreen_exit_bubble_controller_unittest.mm b/chrome/browser/ui/cocoa/fullscreen_exit_bubble_controller_unittest.mm
index 520755e..fc169c1 100644
--- a/chrome/browser/ui/cocoa/fullscreen_exit_bubble_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/fullscreen_exit_bubble_controller_unittest.mm
@@ -66,13 +66,13 @@
 
   void AppendTabToStrip() {
     WebContents* web_contents = WebContents::Create(
-        content::WebContents::CreateParams(profile(), site_instance_));
+        content::WebContents::CreateParams(profile(), site_instance_.get()));
     browser()->tab_strip_model()->AppendWebContents(
         web_contents, /*foreground=*/true);
   }
 
   scoped_refptr<SiteInstance> site_instance_;
-  scoped_nsobject<FullscreenExitBubbleController> controller_;
+  base::scoped_nsobject<FullscreenExitBubbleController> controller_;
 };
 
 // http://crbug.com/103912
diff --git a/chrome/browser/ui/cocoa/fullscreen_exit_bubble_view.mm b/chrome/browser/ui/cocoa/fullscreen_exit_bubble_view.mm
index 6c491d6..8d79127 100644
--- a/chrome/browser/ui/cocoa/fullscreen_exit_bubble_view.mm
+++ b/chrome/browser/ui/cocoa/fullscreen_exit_bubble_view.mm
@@ -5,7 +5,7 @@
 #import "chrome/browser/ui/cocoa/fullscreen_exit_bubble_view.h"
 
 #include "base/mac/mac_util.h"
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h"
 
 namespace {
@@ -43,7 +43,7 @@
   [bezier closePath];
   [[NSColor whiteColor] set];
   gfx::ScopedNSGraphicsContextSaveGState scoped_g_state;
-  scoped_nsobject<NSShadow> shadow([[NSShadow alloc] init]);
+  base::scoped_nsobject<NSShadow> shadow([[NSShadow alloc] init]);
   if (base::mac::IsOSLionOrLater()) {
     [shadow setShadowBlurRadius:kShadowBlurRadiusLion];
   } else {
diff --git a/chrome/browser/ui/cocoa/fullscreen_window_unittest.mm b/chrome/browser/ui/cocoa/fullscreen_window_unittest.mm
index 0ccf365..053a951 100644
--- a/chrome/browser/ui/cocoa/fullscreen_window_unittest.mm
+++ b/chrome/browser/ui/cocoa/fullscreen_window_unittest.mm
@@ -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 "base/memory/scoped_ptr.h"
+#include "base/mac/scoped_nsobject.h"
 #include "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #include "chrome/browser/ui/cocoa/fullscreen_window.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -25,7 +25,7 @@
 };
 
 TEST_F(FullscreenWindowTest, Basics) {
-  scoped_nsobject<FullscreenWindow> window;
+  base::scoped_nsobject<FullscreenWindow> window;
   window.reset([[FullscreenWindow alloc] init]);
 
   EXPECT_EQ([NSScreen mainScreen], [window screen]);
@@ -37,10 +37,10 @@
 }
 
 TEST_F(FullscreenWindowTest, CanPerformClose) {
-  scoped_nsobject<FullscreenWindow> window;
+  base::scoped_nsobject<FullscreenWindow> window;
   window.reset([[FullscreenWindow alloc] init]);
 
-  scoped_nsobject<PerformCloseUIItem> item;
+  base::scoped_nsobject<PerformCloseUIItem> item;
   item.reset([[PerformCloseUIItem alloc] init]);
 
   EXPECT_TRUE([window validateUserInterfaceItem:item.get()]);
diff --git a/chrome/browser/ui/cocoa/global_error_bubble_controller.mm b/chrome/browser/ui/cocoa/global_error_bubble_controller.mm
index bb3377a..4ccb41a 100644
--- a/chrome/browser/ui/cocoa/global_error_bubble_controller.mm
+++ b/chrome/browser/ui/cocoa/global_error_bubble_controller.mm
@@ -5,7 +5,7 @@
 #import "chrome/browser/ui/cocoa/global_error_bubble_controller.h"
 
 #include "base/logging.h"
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "base/strings/string_util.h"
 #include "base/strings/sys_string_conversions.h"
 #include "base/strings/utf_string_conversions.h"
@@ -90,10 +90,10 @@
   std::vector<string16> messages = error_->GetBubbleViewMessages();
   string16 message = JoinString(messages, '\n');
 
-  scoped_nsobject<NSMutableAttributedString> messageValue(
+  base::scoped_nsobject<NSMutableAttributedString> messageValue(
       [[NSMutableAttributedString alloc]
-        initWithString:SysUTF16ToNSString(message)]);
-  scoped_nsobject<NSMutableParagraphStyle> style(
+          initWithString:SysUTF16ToNSString(message)]);
+  base::scoped_nsobject<NSMutableParagraphStyle> style(
       [[NSMutableParagraphStyle alloc] init]);
   [style setParagraphSpacing:kParagraphSpacing];
   [messageValue addAttribute:NSParagraphStyleAttributeName
diff --git a/chrome/browser/ui/cocoa/gradient_button_cell.h b/chrome/browser/ui/cocoa/gradient_button_cell.h
index 515bc3a..7b03a28 100644
--- a/chrome/browser/ui/cocoa/gradient_button_cell.h
+++ b/chrome/browser/ui/cocoa/gradient_button_cell.h
@@ -7,7 +7,7 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 
 namespace ui {
 class ThemeProvider;
@@ -55,15 +55,15 @@
   // Custom drawing means we need to perform our own mouse tracking if
   // the cell is setShowsBorderOnlyWhileMouseInside:YES.
   BOOL isMouseInside_;
-  scoped_nsobject<NSTrackingArea> trackingArea_;
+  base::scoped_nsobject<NSTrackingArea> trackingArea_;
   BOOL shouldTheme_;
   CGFloat hoverAlpha_;  // 0-1. Controls the alpha during mouse hover
   NSTimeInterval lastHoverUpdate_;
-  scoped_nsobject<NSGradient> gradient_;
+  base::scoped_nsobject<NSGradient> gradient_;
   gradient_button_cell::PulseState pulseState_;
   CGFloat pulseMultiplier_;  // for selecting pulse direction when continuous.
   CGFloat outerStrokeAlphaMult_;  // For pulsing.
-  scoped_nsobject<NSImage> overlayImage_;
+  base::scoped_nsobject<NSImage> overlayImage_;
 }
 
 // Turn off theming.  Temporary work-around.
diff --git a/chrome/browser/ui/cocoa/gradient_button_cell.mm b/chrome/browser/ui/cocoa/gradient_button_cell.mm
index b5b0d51..959e0d3 100644
--- a/chrome/browser/ui/cocoa/gradient_button_cell.mm
+++ b/chrome/browser/ui/cocoa/gradient_button_cell.mm
@@ -7,12 +7,12 @@
 #include <cmath>
 
 #include "base/logging.h"
-#import "base/memory/scoped_nsobject.h"
+#import "base/mac/scoped_nsobject.h"
 #import "chrome/browser/themes/theme_properties.h"
 #import "chrome/browser/themes/theme_service.h"
 #import "chrome/browser/ui/cocoa/nsview_additions.h"
-#import "chrome/browser/ui/cocoa/themed_window.h"
 #import "chrome/browser/ui/cocoa/rect_path_utils.h"
+#import "chrome/browser/ui/cocoa/themed_window.h"
 #include "grit/theme_resources.h"
 #import "third_party/GTM/AppKit/GTMNSColor+Luminance.h"
 #import "ui/base/cocoa/nsgraphics_context_additions.h"
@@ -422,7 +422,7 @@
     // Draw the top inner highlight.
     NSAffineTransform* highlightTransform = [NSAffineTransform transform];
     [highlightTransform translateXBy:1 yBy:1];
-    scoped_nsobject<NSBezierPath> highlightPath([innerPath copy]);
+    base::scoped_nsobject<NSBezierPath> highlightPath([innerPath copy]);
     [highlightPath transformUsingAffineTransform:highlightTransform];
     [[NSColor colorWithCalibratedWhite:1.0 alpha:0.2] setStroke];
     [highlightPath stroke];
@@ -604,7 +604,7 @@
         [NSColor blackColor];
 
     if (isTemplate && themeProvider && themeProvider->UsingDefaultTheme()) {
-      scoped_nsobject<NSShadow> shadow([[NSShadow alloc] init]);
+      base::scoped_nsobject<NSShadow> shadow([[NSShadow alloc] init]);
       [shadow.get() setShadowColor:themeProvider->GetNSColor(
           ThemeProperties::COLOR_TOOLBAR_BEZEL, true)];
       [shadow.get() setShadowOffset:NSMakeSize(0.0, -lineWidth)];
diff --git a/chrome/browser/ui/cocoa/gradient_button_cell_unittest.mm b/chrome/browser/ui/cocoa/gradient_button_cell_unittest.mm
index c174ae6..b9ea960 100644
--- a/chrome/browser/ui/cocoa/gradient_button_cell_unittest.mm
+++ b/chrome/browser/ui/cocoa/gradient_button_cell_unittest.mm
@@ -4,9 +4,9 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
-#import "chrome/browser/ui/cocoa/gradient_button_cell.h"
+#include "base/mac/scoped_nsobject.h"
 #import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/gradient_button_cell.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/platform_test.h"
 
@@ -20,10 +20,11 @@
  public:
   GradientButtonCellTest() {
     NSRect frame = NSMakeRect(0, 0, 50, 30);
-    scoped_nsobject<NSButton>view([[NSButton alloc] initWithFrame:frame]);
+    base::scoped_nsobject<NSButton> view(
+        [[NSButton alloc] initWithFrame:frame]);
     view_ = view.get();
-    scoped_nsobject<GradientButtonCell> cell([[GradientButtonCell alloc]
-                                              initTextCell:@"Testing"]);
+    base::scoped_nsobject<GradientButtonCell> cell(
+        [[GradientButtonCell alloc] initTextCell:@"Testing"]);
     [view_ setCell:cell.get()];
     [[test_window() contentView] addSubview:view_];
   }
diff --git a/chrome/browser/ui/cocoa/history_menu_bridge.h b/chrome/browser/ui/cocoa/history_menu_bridge.h
index 8f4582e..2ab76ed 100644
--- a/chrome/browser/ui/cocoa/history_menu_bridge.h
+++ b/chrome/browser/ui/cocoa/history_menu_bridge.h
@@ -9,8 +9,8 @@
 #include <map>
 #include <vector>
 
+#include "base/mac/scoped_nsobject.h"
 #include "base/memory/ref_counted.h"
-#include "base/memory/scoped_nsobject.h"
 #include "chrome/browser/common/cancelable_request.h"
 #import "chrome/browser/favicon/favicon_service.h"
 #include "chrome/browser/history/history_service.h"
@@ -75,7 +75,7 @@
     // The URL that will be navigated to if the user selects this item.
     GURL url;
     // Favicon for the URL.
-    scoped_nsobject<NSImage> icon;
+    base::scoped_nsobject<NSImage> icon;
 
     // If the icon is being requested from the FaviconService, |icon_requested|
     // will be true and |icon_task_id| will be valid. If this is false, then
@@ -89,7 +89,7 @@
     // quickly), the NSMenu can release the item before the HistoryItem has
     // been fully deleted. If this were a weak pointer, it would result in a
     // zombie.
-    scoped_nsobject<NSMenuItem> menu_item;
+    base::scoped_nsobject<NSMenuItem> menu_item;
 
     // This ID is unique for a browser session and can be passed to the
     // TabRestoreService to re-open the closed window or tab that this
@@ -204,7 +204,7 @@
   friend class ::HistoryMenuBridgeTest;
   friend class HistoryMenuCocoaControllerTest;
 
-  scoped_nsobject<HistoryMenuCocoaController> controller_;  // strong
+  base::scoped_nsobject<HistoryMenuCocoaController> controller_;  // strong
 
   Profile* profile_;  // weak
   HistoryService* history_service_;  // weak
@@ -229,7 +229,7 @@
   bool need_recreate_;
 
   // The default favicon if a HistoryItem does not have one.
-  scoped_nsobject<NSImage> default_favicon_;
+  base::scoped_nsobject<NSImage> default_favicon_;
 
   DISALLOW_COPY_AND_ASSIGN(HistoryMenuBridge);
 };
diff --git a/chrome/browser/ui/cocoa/history_menu_bridge.mm b/chrome/browser/ui/cocoa/history_menu_bridge.mm
index dcf7b8b..0fc7438 100644
--- a/chrome/browser/ui/cocoa/history_menu_bridge.mm
+++ b/chrome/browser/ui/cocoa/history_menu_bridge.mm
@@ -207,12 +207,12 @@
       item->session_id = entry_win->id;
 
       // Create the submenu.
-      scoped_nsobject<NSMenu> submenu([[NSMenu alloc] init]);
+      base::scoped_nsobject<NSMenu> submenu([[NSMenu alloc] init]);
 
       // Create standard items within the window submenu.
       NSString* restore_title = l10n_util::GetNSString(
           IDS_HISTORY_CLOSED_RESTORE_WINDOW_MAC);
-      scoped_nsobject<NSMenuItem> restore_item(
+      base::scoped_nsobject<NSMenuItem> restore_item(
           [[NSMenuItem alloc] initWithTitle:restore_title
                                      action:@selector(openHistoryMenuItem:)
                               keyEquivalent:@""]);
diff --git a/chrome/browser/ui/cocoa/history_menu_bridge_unittest.mm b/chrome/browser/ui/cocoa/history_menu_bridge_unittest.mm
index cccecdb..8ff1cf8 100644
--- a/chrome/browser/ui/cocoa/history_menu_bridge_unittest.mm
+++ b/chrome/browser/ui/cocoa/history_menu_bridge_unittest.mm
@@ -42,7 +42,7 @@
   }
 
  private:
-  scoped_nsobject<NSMenu> menu_;
+  base::scoped_nsobject<NSMenu> menu_;
 };
 
 class HistoryMenuBridgeTest : public CocoaProfileTest {
diff --git a/chrome/browser/ui/cocoa/history_menu_cocoa_controller_unittest.mm b/chrome/browser/ui/cocoa/history_menu_cocoa_controller_unittest.mm
index ddcfa9c..3870efb 100644
--- a/chrome/browser/ui/cocoa/history_menu_cocoa_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/history_menu_cocoa_controller_unittest.mm
@@ -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 "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/strings/string_util.h"
 #include "base/strings/sys_string_conversions.h"
@@ -71,7 +71,7 @@
 };
 
 TEST_F(HistoryMenuCocoaControllerTest, OpenURLForItem) {
-  scoped_nsobject<NSMenu> menu([[NSMenu alloc] initWithTitle:@"History"]);
+  base::scoped_nsobject<NSMenu> menu([[NSMenu alloc] initWithTitle:@"History"]);
   CreateItems(menu.get());
 
   std::map<NSMenuItem*, HistoryMenuBridge::HistoryItem*>& items =
diff --git a/chrome/browser/ui/cocoa/history_overlay_controller.h b/chrome/browser/ui/cocoa/history_overlay_controller.h
index 3a83a26..541b2f2 100644
--- a/chrome/browser/ui/cocoa/history_overlay_controller.h
+++ b/chrome/browser/ui/cocoa/history_overlay_controller.h
@@ -7,7 +7,7 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 
 @class HistoryOverlayView;
 
@@ -23,9 +23,9 @@
  @private
   HistoryOverlayMode mode_;
   // Strongly typed reference of self.view.
-  scoped_nsobject<HistoryOverlayView> contentView_;
+  base::scoped_nsobject<HistoryOverlayView> contentView_;
   // The view above which self.view is inserted as a subview.
-  scoped_nsobject<NSView> parent_;
+  base::scoped_nsobject<NSView> parent_;
 }
 
 // Designated initializer.
diff --git a/chrome/browser/ui/cocoa/history_overlay_controller.mm b/chrome/browser/ui/cocoa/history_overlay_controller.mm
index f211afc..593a942 100644
--- a/chrome/browser/ui/cocoa/history_overlay_controller.mm
+++ b/chrome/browser/ui/cocoa/history_overlay_controller.mm
@@ -62,7 +62,7 @@
     NSRect arrowRect = NSMakeRect(offset, 0, kShieldRadius, kShieldHeight);
     arrowRect = NSInsetRect(arrowRect, 10, 0);  // Give a little padding.
 
-    scoped_nsobject<NSImageView> imageView(
+    base::scoped_nsobject<NSImageView> imageView(
         [[NSImageView alloc] initWithFrame:arrowRect]);
     [imageView setImage:image];
     [imageView setAutoresizingMask:NSViewMinYMargin | NSViewMaxYMargin];
@@ -162,7 +162,7 @@
 
   NSView* overlay = self.view;
 
-  scoped_nsobject<CAAnimation> animation(
+  base::scoped_nsobject<CAAnimation> animation(
       [[overlay animationForKey:@"alphaValue"] copy]);
   [animation setDelegate:self];
   [animation setDuration:kFadeOutDurationSeconds];
diff --git a/chrome/browser/ui/cocoa/history_overlay_controller_unittest.mm b/chrome/browser/ui/cocoa/history_overlay_controller_unittest.mm
index 491bf24..96ab915 100644
--- a/chrome/browser/ui/cocoa/history_overlay_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/history_overlay_controller_unittest.mm
@@ -28,7 +28,7 @@
   }
 
  private:
-  scoped_nsobject<NSView> test_view_;
+  base::scoped_nsobject<NSView> test_view_;
 };
 
 // Tests that the controller's view gets removed from the hierarchy when the
@@ -37,7 +37,7 @@
   NSView* content_view = [test_window() contentView];
   EXPECT_EQ(1u, [[content_view subviews] count]);
 
-  scoped_nsobject<HistoryOverlayController> controller(
+  base::scoped_nsobject<HistoryOverlayController> controller(
       [[HistoryOverlayController alloc] initForMode:kHistoryOverlayModeBack]);
   [controller showPanelForView:test_view()];
   EXPECT_EQ(2u, [[content_view subviews] count]);
@@ -49,7 +49,7 @@
 // Tests that when the controller is |-dismiss|ed, the animation runs and then
 // is removed when the animation completes.
 TEST_F(HistoryOverlayControllerTest, DismissClearsAnimations) {
-  scoped_nsobject<HistoryOverlayController> controller(
+  base::scoped_nsobject<HistoryOverlayController> controller(
       [[HistoryOverlayController alloc] initForMode:kHistoryOverlayModeBack]);
   [controller showPanelForView:test_view()];
 
diff --git a/chrome/browser/ui/cocoa/hover_close_button.mm b/chrome/browser/ui/cocoa/hover_close_button.mm
index f01a172..7825cf7 100644
--- a/chrome/browser/ui/cocoa/hover_close_button.mm
+++ b/chrome/browser/ui/cocoa/hover_close_button.mm
@@ -4,8 +4,6 @@
 
 #import "chrome/browser/ui/cocoa/hover_close_button.h"
 
-#include "base/memory/scoped_nsobject.h"
-#include "base/memory/scoped_ptr.h"
 #include "grit/generated_resources.h"
 #include "grit/theme_resources.h"
 #include "grit/ui_resources.h"
@@ -80,22 +78,6 @@
   [self animationDidStop:animation];
 }
 
-// Override to only accept clicks within the bounds of the defined path, not
-// the entire bounding box. |aPoint| is in the superview's coordinate system.
-- (NSView*)hitTest:(NSPoint)point {
-  NSPoint localPoint = [self convertPoint:point fromView:[self superview]];
-  NSRect pointRect = NSMakeRect(localPoint.x, localPoint.y, 1, 1);
-
-  NSImage* hoverImage = [self imageForHoverState:kHoverStateMouseOver];
-  if ([hoverImage hitTestRect:pointRect
-      withImageDestinationRect:[self bounds]
-                       context:nil
-                         hints:nil
-                       flipped:YES])
-    return [super hitTest:point];
-  return nil;
-}
-
 - (void)drawRect:(NSRect)dirtyRect {
   NSImage* image = [self imageForHoverState:[self hoverState]];
 
diff --git a/chrome/browser/ui/cocoa/hover_close_button_unittest.mm b/chrome/browser/ui/cocoa/hover_close_button_unittest.mm
index c978499..5d19c30 100644
--- a/chrome/browser/ui/cocoa/hover_close_button_unittest.mm
+++ b/chrome/browser/ui/cocoa/hover_close_button_unittest.mm
@@ -4,7 +4,7 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #import "chrome/browser/ui/cocoa/hover_close_button.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -18,7 +18,7 @@
   }
 
  protected:
-  scoped_nsobject<HoverCloseButton> button_;
+  base::scoped_nsobject<HoverCloseButton> button_;
 };
 
 class WebUIHoverCloseButtonTest : public CocoaTest {
@@ -30,7 +30,7 @@
   }
 
  protected:
-  scoped_nsobject<WebUIHoverCloseButton> button_;
+  base::scoped_nsobject<WebUIHoverCloseButton> button_;
 };
 
 TEST_VIEW(HoverCloseButtonTest, button_)
diff --git a/chrome/browser/ui/cocoa/hung_renderer_controller.h b/chrome/browser/ui/cocoa/hung_renderer_controller.h
index 1d55c8d..1725726 100644
--- a/chrome/browser/ui/cocoa/hung_renderer_controller.h
+++ b/chrome/browser/ui/cocoa/hung_renderer_controller.h
@@ -19,7 +19,7 @@
 
 #import <Cocoa/Cocoa.h>
 
-#import "base/memory/scoped_nsobject.h"
+#import "base/mac/scoped_nsobject.h"
 #import "base/memory/scoped_ptr.h"
 
 @class MultiKeyEquivalentButton;
@@ -46,11 +46,11 @@
 
   // Backing data for |tableView_|.  Titles of each WebContents that
   // shares a renderer process with |hungContents_|.
-  scoped_nsobject<NSArray> hungTitles_;
+  base::scoped_nsobject<NSArray> hungTitles_;
 
   // Favicons of each WebContents that shares a renderer process with
   // |hungContents_|.
-  scoped_nsobject<NSArray> hungFavicons_;
+  base::scoped_nsobject<NSArray> hungFavicons_;
 }
 
 // Kills the hung renderers.
diff --git a/chrome/browser/ui/cocoa/hung_renderer_controller.mm b/chrome/browser/ui/cocoa/hung_renderer_controller.mm
index 0837b8b..b75da41 100644
--- a/chrome/browser/ui/cocoa/hung_renderer_controller.mm
+++ b/chrome/browser/ui/cocoa/hung_renderer_controller.mm
@@ -176,8 +176,8 @@
   DCHECK(contents);
   hungContents_ = contents;
   hungContentsObserver_.reset(new WebContentsObserverBridge(contents, self));
-  scoped_nsobject<NSMutableArray> titles([[NSMutableArray alloc] init]);
-  scoped_nsobject<NSMutableArray> favicons([[NSMutableArray alloc] init]);
+  base::scoped_nsobject<NSMutableArray> titles([[NSMutableArray alloc] init]);
+  base::scoped_nsobject<NSMutableArray> favicons([[NSMutableArray alloc] init]);
   for (TabContentsIterator it; !it.done(); it.Next()) {
     if (it->GetRenderProcessHost() == hungContents_->GetRenderProcessHost()) {
       string16 title = it->GetTitle();
diff --git a/chrome/browser/ui/cocoa/hung_renderer_controller_unittest.mm b/chrome/browser/ui/cocoa/hung_renderer_controller_unittest.mm
index 4e71bd4..d7e1766 100644
--- a/chrome/browser/ui/cocoa/hung_renderer_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/hung_renderer_controller_unittest.mm
@@ -4,7 +4,6 @@
 
 #import <Cocoa/Cocoa.h>
 
-#import "base/memory/scoped_nsobject.h"
 #include "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #import "chrome/browser/ui/cocoa/hung_renderer_controller.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/chrome/browser/ui/cocoa/hyperlink_button_cell.h b/chrome/browser/ui/cocoa/hyperlink_button_cell.h
index 2857275..1cdc263 100644
--- a/chrome/browser/ui/cocoa/hyperlink_button_cell.h
+++ b/chrome/browser/ui/cocoa/hyperlink_button_cell.h
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 #import <Cocoa/Cocoa.h>
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 
 // A HyperlinkButtonCell is used to create an NSButton that looks and acts
 // like a hyperlink. The default styling is to look like blue, underlined text
@@ -16,7 +16,7 @@
 //  4. In the Attributes panel, change the Bezel to Square.
 //  5. In the Size panel, set the Height to 16.
 @interface HyperlinkButtonCell : NSButtonCell {
-  scoped_nsobject<NSColor> textColor_;
+  base::scoped_nsobject<NSColor> textColor_;
   BOOL shouldUnderline_;
   BOOL underlineOnHover_;
   BOOL mouseIsInside_;
diff --git a/chrome/browser/ui/cocoa/hyperlink_button_cell.mm b/chrome/browser/ui/cocoa/hyperlink_button_cell.mm
index 4047101..49f316c 100644
--- a/chrome/browser/ui/cocoa/hyperlink_button_cell.mm
+++ b/chrome/browser/ui/cocoa/hyperlink_button_cell.mm
@@ -20,7 +20,7 @@
 
 + (NSButton*)buttonWithString:(NSString*)string {
   NSButton* button = [[[NSButton alloc] initWithFrame:NSZeroRect] autorelease];
-  scoped_nsobject<HyperlinkButtonCell> cell(
+  base::scoped_nsobject<HyperlinkButtonCell> cell(
       [[HyperlinkButtonCell alloc] initTextCell:string]);
   [cell setAlignment:NSLeftTextAlignment];
   [button setCell:cell.get()];
@@ -83,8 +83,8 @@
       (!underlineOnHover_ || (mouseIsInside_ && [self isEnabled])))
     underlineMask = NSUnderlinePatternSolid | NSUnderlineStyleSingle;
 
-  scoped_nsobject<NSMutableParagraphStyle> paragraphStyle(
-    [[NSParagraphStyle defaultParagraphStyle] mutableCopy]);
+  base::scoped_nsobject<NSMutableParagraphStyle> paragraphStyle(
+      [[NSParagraphStyle defaultParagraphStyle] mutableCopy]);
   [paragraphStyle setAlignment:[self alignment]];
   [paragraphStyle setLineBreakMode:[self lineBreakMode]];
 
diff --git a/chrome/browser/ui/cocoa/hyperlink_button_cell_unittest.mm b/chrome/browser/ui/cocoa/hyperlink_button_cell_unittest.mm
index fb59046..18abc03 100644
--- a/chrome/browser/ui/cocoa/hyperlink_button_cell_unittest.mm
+++ b/chrome/browser/ui/cocoa/hyperlink_button_cell_unittest.mm
@@ -5,9 +5,9 @@
 #import <Cocoa/Cocoa.h>
 
 #include "base/mac/foundation_util.h"
-#include "base/memory/scoped_nsobject.h"
-#import "chrome/browser/ui/cocoa/hyperlink_button_cell.h"
+#include "base/mac/scoped_nsobject.h"
 #import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/hyperlink_button_cell.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/platform_test.h"
 
@@ -15,9 +15,10 @@
  public:
   HyperlinkButtonCellTest() {
     NSRect frame = NSMakeRect(0, 0, 50, 30);
-    scoped_nsobject<NSButton> view([[NSButton alloc] initWithFrame:frame]);
+    base::scoped_nsobject<NSButton> view(
+        [[NSButton alloc] initWithFrame:frame]);
     view_ = view.get();
-    scoped_nsobject<HyperlinkButtonCell> cell(
+    base::scoped_nsobject<HyperlinkButtonCell> cell(
         [[HyperlinkButtonCell alloc] initTextCell:@"Testing"]);
     cell_ = cell.get();
     [view_ setCell:cell_];
@@ -47,7 +48,8 @@
 // Tests the three designated intializers.
 TEST_F(HyperlinkButtonCellTest, Initializers) {
   TestCellCustomization(cell_);  // |-initTextFrame:|
-  scoped_nsobject<HyperlinkButtonCell> cell([[HyperlinkButtonCell alloc] init]);
+  base::scoped_nsobject<HyperlinkButtonCell> cell(
+      [[HyperlinkButtonCell alloc] init]);
   TestCellCustomization(cell.get());
 
   // Need to create a dummy archiver to test |-initWithCoder:|.
diff --git a/chrome/browser/ui/cocoa/hyperlink_text_view.h b/chrome/browser/ui/cocoa/hyperlink_text_view.h
index a9ba8d3..adcfa4f 100644
--- a/chrome/browser/ui/cocoa/hyperlink_text_view.h
+++ b/chrome/browser/ui/cocoa/hyperlink_text_view.h
@@ -4,10 +4,13 @@
 
 #import <Cocoa/Cocoa.h>
 
+@class NSColor;
+
 // HyperlinkTextView is an NSTextView subclass for unselectable, linkable text.
 // This subclass doesn't show the text caret or IBeamCursor, whereas the base
 // class NSTextView displays both with full keyboard accessibility enabled.
 @interface HyperlinkTextView : NSTextView
+
 // Convenience function that sets the |HyperlinkTextView| contents to the
 // specified |message| with a hypertext style |link| inserted at |linkOffset|.
 // Uses the supplied |font|, |messageColor|, and |linkColor|.
@@ -17,4 +20,16 @@
                      font:(NSFont*)font
              messageColor:(NSColor*)messageColor
                 linkColor:(NSColor*)linkColor;
+
+// Set the |message| displayed by the HyperlinkTextView, using |font| and
+// |messageColor|.
+- (void)setMessage:(NSString*)message
+          withFont:(NSFont*)font
+      messageColor:(NSColor*)messageColor;
+
+// Marks a |range| within the given message as link, associating it with
+// a |name| that is passed to the delegate's textView:clickedOnLink:atIndex:.
+- (void)addLinkRange:(NSRange)range
+            withName:(id)name
+           linkColor:(NSColor*)linkColor;
 @end
diff --git a/chrome/browser/ui/cocoa/hyperlink_text_view.mm b/chrome/browser/ui/cocoa/hyperlink_text_view.mm
index ea92f4c..178d6a2 100644
--- a/chrome/browser/ui/cocoa/hyperlink_text_view.mm
+++ b/chrome/browser/ui/cocoa/hyperlink_text_view.mm
@@ -4,7 +4,7 @@
 
 #import "chrome/browser/ui/cocoa/hyperlink_text_view.h"
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 
 // The baseline shift for text in the NSTextView.
 const float kTextBaselineShift = -1.0;
@@ -71,6 +71,11 @@
   [self setDrawsBackground:NO];
   [self setHorizontallyResizable:NO];
   [self setVerticallyResizable:NO];
+
+  // When text is rendered, linkTextAttributes override anything set via
+  // addAttributes for text that has NSLinkAttributeName. Set to nil to allow
+  // custom attributes to take precendence.
+  [self setLinkTextAttributes:nil];
 }
 
 - (void)fixupCursor {
@@ -84,48 +89,48 @@
                      font:(NSFont*)font
              messageColor:(NSColor*)messageColor
                 linkColor:(NSColor*)linkColor {
+  NSMutableString* finalMessage = [NSMutableString stringWithString:message];
+  [finalMessage insertString:link atIndex:linkOffset];
+  [self setMessage:finalMessage withFont:font messageColor:messageColor];
+  if ([link length] != 0) {
+    [self addLinkRange:NSMakeRange(linkOffset, [link length])
+              withName:@""
+             linkColor:linkColor];
+  }
+}
+
+- (void)setMessage:(NSString*)message
+          withFont:(NSFont*)font
+      messageColor:(NSColor*)messageColor {
   // Create an attributes dictionary for the message and link.
-  NSMutableDictionary* attributes = [NSMutableDictionary dictionary];
-  [attributes setObject:messageColor
-                 forKey:NSForegroundColorAttributeName];
-  [attributes setObject:[NSCursor arrowCursor]
-                 forKey:NSCursorAttributeName];
-  [attributes setObject:font
-                 forKey:NSFontAttributeName];
-  [attributes setObject:[NSNumber numberWithFloat:kTextBaselineShift]
-                 forKey:NSBaselineOffsetAttributeName];
+  NSDictionary* attributes = @{
+    NSForegroundColorAttributeName : messageColor,
+    NSCursorAttributeName : [NSCursor arrowCursor],
+    NSFontAttributeName : font,
+    NSBaselineOffsetAttributeName : @(kTextBaselineShift)
+  };
 
   // Create the attributed string for the message.
-  scoped_nsobject<NSMutableAttributedString> attributedMessage(
+  base::scoped_nsobject<NSAttributedString> attributedMessage(
       [[NSMutableAttributedString alloc] initWithString:message
                                              attributes:attributes]);
 
-  if ([link length] != 0) {
-    // Add additional attributes to style the link text appropriately as
-    // well as linkify it.
-    [attributes setObject:linkColor
-                   forKey:NSForegroundColorAttributeName];
-    [attributes setObject:[NSNumber numberWithBool:YES]
-                   forKey:NSUnderlineStyleAttributeName];
-    [attributes setObject:[NSCursor pointingHandCursor]
-                   forKey:NSCursorAttributeName];
-    [attributes setObject:[NSNumber numberWithInt:NSSingleUnderlineStyle]
-                   forKey:NSUnderlineStyleAttributeName];
-    [attributes setObject:[NSString string]  // dummy value
-                   forKey:NSLinkAttributeName];
-
-    // Insert the link into the message at the appropriate offset.
-    scoped_nsobject<NSAttributedString> attributedLink(
-        [[NSAttributedString alloc] initWithString:link
-                                        attributes:attributes]);
-    [attributedMessage.get() insertAttributedString:attributedLink.get()
-                                            atIndex:linkOffset];
-    // Ensure the TextView doesn't override the link style.
-    [self setLinkTextAttributes:attributes];
-  }
-
   // Update the text view with the new text.
   [[self textStorage] setAttributedString:attributedMessage];
 }
 
+- (void)addLinkRange:(NSRange)range
+            withName:(id)name
+           linkColor:(NSColor*)linkColor {
+  NSDictionary* attributes = @{
+    NSForegroundColorAttributeName : linkColor,
+    NSUnderlineStyleAttributeName : @(YES),
+    NSCursorAttributeName : [NSCursor pointingHandCursor],
+    NSLinkAttributeName : name,
+    NSUnderlineStyleAttributeName : @(NSSingleUnderlineStyle)
+  };
+
+  [[self textStorage] addAttributes:attributes range:range];
+}
+
 @end
diff --git a/chrome/browser/ui/cocoa/hyperlink_text_view_unittest.mm b/chrome/browser/ui/cocoa/hyperlink_text_view_unittest.mm
index b5903b2..7b02530 100644
--- a/chrome/browser/ui/cocoa/hyperlink_text_view_unittest.mm
+++ b/chrome/browser/ui/cocoa/hyperlink_text_view_unittest.mm
@@ -2,9 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #import "chrome/browser/ui/cocoa/hyperlink_text_view.h"
+#include "testing/gtest_mac.h"
 
 namespace {
 
@@ -12,13 +13,46 @@
  public:
   HyperlinkTextViewTest() {
     NSRect frame = NSMakeRect(0, 0, 50, 50);
-    scoped_nsobject<HyperlinkTextView> view(
+    base::scoped_nsobject<HyperlinkTextView> view(
         [[HyperlinkTextView alloc] initWithFrame:frame]);
     view_ = view.get();
     [[test_window() contentView] addSubview:view_];
   }
 
+  NSFont* GetDefaultFont() {
+    return [NSFont labelFontOfSize:
+         [NSFont systemFontSizeForControlSize:NSRegularControlSize]];
+  }
+
+  NSDictionary* GetDefaultTextAttributes() {
+    const float kTextBaselineShift = -1.0;
+    return @{
+      NSForegroundColorAttributeName : [NSColor blackColor],
+      NSCursorAttributeName : [NSCursor arrowCursor],
+      NSFontAttributeName : GetDefaultFont(),
+      NSBaselineOffsetAttributeName : @(kTextBaselineShift)
+    };
+  }
+
+  NSMutableDictionary* GetDefaultLinkAttributes() {
+    if (!linkAttributes_.get()) {
+      linkAttributes_.reset(
+          [[NSMutableDictionary dictionaryWithDictionary:
+              GetDefaultTextAttributes()] retain]);
+      [linkAttributes_ addEntriesFromDictionary:@{
+          NSForegroundColorAttributeName : [NSColor blueColor],
+          NSUnderlineStyleAttributeName : @(YES),
+          NSCursorAttributeName : [NSCursor pointingHandCursor],
+          NSUnderlineStyleAttributeName : @(NSSingleUnderlineStyle),
+          NSLinkAttributeName : @""}];
+    }
+    return [NSMutableDictionary dictionaryWithDictionary:linkAttributes_];
+  }
+
   HyperlinkTextView* view_;
+
+ private:
+  base::scoped_nsobject<NSMutableDictionary> linkAttributes_;
 };
 
 TEST_VIEW(HyperlinkTextViewTest, view_);
@@ -30,4 +64,126 @@
   EXPECT_FALSE([view_ isVerticallyResizable]);
 }
 
+TEST_F(HyperlinkTextViewTest, LinkInsertion) {
+  // Test that setMessage:withLink:... inserts the link text.
+  [view_ setMessageAndLink:@"This is a short text message"
+                  withLink:@"alarmingly "
+                  atOffset:10
+                      font:GetDefaultFont()
+              messageColor:[NSColor blackColor]
+                 linkColor:[NSColor blueColor]];
+  EXPECT_NSEQ(@"This is a alarmingly short text message",
+              [[view_ textStorage] string]);
+
+  // Test insertion at end - most common use case.
+  NSString* message=@"This is another test message ";
+  [view_ setMessageAndLink:message
+                  withLink:@"with link"
+                  atOffset:[message length]
+                      font:GetDefaultFont()
+              messageColor:[NSColor blackColor]
+                 linkColor:[NSColor blueColor]];
+  EXPECT_NSEQ(@"This is another test message with link",
+              [[view_ textStorage] string]);
+}
+
+TEST_F(HyperlinkTextViewTest, AttributesForMessageWithLink) {
+  // Verifies text attributes are set as expected for setMessageWithLink:...
+  [view_ setMessageAndLink:@"aaabbbbb"
+                  withLink:@"xxxx"
+                  atOffset:3
+                      font:GetDefaultFont()
+              messageColor:[NSColor blackColor]
+                 linkColor:[NSColor blueColor]];
+
+  NSDictionary* attributes;
+  NSRange rangeLimit = NSMakeRange(0, 12);
+  NSRange range;
+  attributes = [[view_ textStorage] attributesAtIndex:0
+                                longestEffectiveRange:&range
+                                              inRange:rangeLimit];
+  EXPECT_EQ(0U, range.location);
+  EXPECT_EQ(3U, range.length);
+  EXPECT_NSEQ(GetDefaultTextAttributes(), attributes);
+
+  attributes = [[view_ textStorage] attributesAtIndex:3
+                                longestEffectiveRange:&range
+                                              inRange:rangeLimit];
+  EXPECT_EQ(3U, range.location);
+  EXPECT_EQ(4U, range.length);
+  EXPECT_NSEQ(GetDefaultLinkAttributes(), attributes);
+
+  attributes = [[view_ textStorage] attributesAtIndex:7
+                                longestEffectiveRange:&range
+                                              inRange:rangeLimit];
+  EXPECT_EQ(7U, range.location);
+  EXPECT_EQ(5U, range.length);
+  EXPECT_NSEQ(GetDefaultTextAttributes(), attributes);
+
+}
+
+TEST_F(HyperlinkTextViewTest, TestSetMessage) {
+  // Verifies setMessage sets text and attributes properly.
+  NSString* message = @"Test message";
+  [view_ setMessage:message
+           withFont:GetDefaultFont()
+       messageColor:[NSColor blackColor]];
+  EXPECT_NSEQ(@"Test message", [[view_ textStorage] string]);
+
+  NSDictionary* attributes;
+  NSRange rangeLimit = NSMakeRange(0, [message length]);
+  NSRange range;
+  attributes = [[view_ textStorage] attributesAtIndex:0
+                                longestEffectiveRange:&range
+                                              inRange:rangeLimit];
+  EXPECT_EQ(0U, range.location);
+  EXPECT_EQ([message length], range.length);
+  EXPECT_NSEQ(GetDefaultTextAttributes(), attributes);
+}
+
+TEST_F(HyperlinkTextViewTest, TestAddLinkRange) {
+  NSString* message = @"One Two Three Four";
+  [view_ setMessage:message
+           withFont:GetDefaultFont()
+       messageColor:[NSColor blackColor]];
+
+  NSColor* blue = [NSColor blueColor];
+  [view_ addLinkRange:NSMakeRange(4,3) withName:@"Name:Two" linkColor:blue];
+  [view_ addLinkRange:NSMakeRange(14,4) withName:@"Name:Four" linkColor:blue];
+
+  NSDictionary* attributes;
+  NSRange rangeLimit = NSMakeRange(0, [message length]);
+  NSRange range;
+  attributes = [[view_ textStorage] attributesAtIndex:0
+                                longestEffectiveRange:&range
+                                              inRange:rangeLimit];
+  EXPECT_EQ(0U, range.location);
+  EXPECT_EQ(4U, range.length);
+  EXPECT_NSEQ(GetDefaultTextAttributes(), attributes);
+
+  NSMutableDictionary* linkAttributes = GetDefaultLinkAttributes();
+  [linkAttributes setObject:@"Name:Two" forKey:NSLinkAttributeName];
+  attributes = [[view_ textStorage] attributesAtIndex:4
+                                longestEffectiveRange:&range
+                                              inRange:rangeLimit];
+  EXPECT_EQ(4U, range.location);
+  EXPECT_EQ(3U, range.length);
+  EXPECT_NSEQ(linkAttributes, attributes);
+
+  attributes = [[view_ textStorage] attributesAtIndex:7
+                                longestEffectiveRange:&range
+                                              inRange:rangeLimit];
+  EXPECT_EQ(7U, range.location);
+  EXPECT_EQ(7U, range.length);
+  EXPECT_NSEQ(GetDefaultTextAttributes(), attributes);
+
+  [linkAttributes setObject:@"Name:Four" forKey:NSLinkAttributeName];
+  attributes = [[view_ textStorage] attributesAtIndex:14
+                                longestEffectiveRange:&range
+                                              inRange:rangeLimit];
+  EXPECT_EQ(14U, range.location);
+  EXPECT_EQ(4U, range.length);
+  EXPECT_NSEQ(linkAttributes, attributes);
+}
+
 }  // namespace
diff --git a/chrome/browser/ui/cocoa/image_button_cell.h b/chrome/browser/ui/cocoa/image_button_cell.h
index 7f90195..4f4dc60 100644
--- a/chrome/browser/ui/cocoa/image_button_cell.h
+++ b/chrome/browser/ui/cocoa/image_button_cell.h
@@ -7,7 +7,7 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 
 namespace image_button_cell {
 
@@ -39,7 +39,7 @@
   struct {
     // At most one of these two fields will be non-null.
     int imageId;
-    scoped_nsobject<NSImage> image;
+    base::scoped_nsobject<NSImage> image;
   } image_[image_button_cell::kButtonStateCount];
   BOOL isMouseInside_;
 }
diff --git a/chrome/browser/ui/cocoa/image_button_cell_unittest.mm b/chrome/browser/ui/cocoa/image_button_cell_unittest.mm
index bbe2921..84d1191 100644
--- a/chrome/browser/ui/cocoa/image_button_cell_unittest.mm
+++ b/chrome/browser/ui/cocoa/image_button_cell_unittest.mm
@@ -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 "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #import "chrome/browser/ui/cocoa/image_button_cell.h"
 #include "grit/theme_resources.h"
@@ -13,9 +13,10 @@
  public:
   ImageButtonCellTest() {
     NSRect frame = NSMakeRect(0, 0, 50, 30);
-    scoped_nsobject<NSButton>view([[NSButton alloc] initWithFrame:frame]);
+    base::scoped_nsobject<NSButton> view(
+        [[NSButton alloc] initWithFrame:frame]);
     view_ = view.get();
-    scoped_nsobject<ImageButtonCell> cell(
+    base::scoped_nsobject<ImageButtonCell> cell(
         [[ImageButtonCell alloc] initTextCell:@""]);
     [view_ setCell:cell.get()];
     [[test_window() contentView] addSubview:view_];
diff --git a/chrome/browser/ui/cocoa/importer/import_lock_dialog_cocoa.mm b/chrome/browser/ui/cocoa/importer/import_lock_dialog_cocoa.mm
index c3db086..e884072 100644
--- a/chrome/browser/ui/cocoa/importer/import_lock_dialog_cocoa.mm
+++ b/chrome/browser/ui/cocoa/importer/import_lock_dialog_cocoa.mm
@@ -6,7 +6,7 @@
 
 #include "base/bind.h"
 #include "base/callback.h"
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "base/message_loop.h"
 #include "chrome/browser/importer/importer_lock_dialog.h"
 #include "content/public/browser/user_metrics.h"
@@ -20,7 +20,7 @@
 
 void ShowImportLockDialog(gfx::NativeWindow parent,
                           const base::Callback<void(bool)>& callback) {
-  scoped_nsobject<NSAlert> lock_alert([[NSAlert alloc] init]);
+  base::scoped_nsobject<NSAlert> lock_alert([[NSAlert alloc] init]);
   [lock_alert addButtonWithTitle:l10n_util::GetNSStringWithFixup(
       IDS_IMPORTER_LOCK_OK)];
   [lock_alert addButtonWithTitle:l10n_util::GetNSStringWithFixup(
diff --git a/chrome/browser/ui/cocoa/info_bubble_view.h b/chrome/browser/ui/cocoa/info_bubble_view.h
index b7c9a76..6987eb7 100644
--- a/chrome/browser/ui/cocoa/info_bubble_view.h
+++ b/chrome/browser/ui/cocoa/info_bubble_view.h
@@ -7,7 +7,7 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 
 namespace info_bubble {
 
@@ -50,7 +50,7 @@
   info_bubble::BubbleArrowLocation arrowLocation_;
   info_bubble::BubbleAlignment alignment_;
   info_bubble::CornerFlags cornerFlags_;
-  scoped_nsobject<NSColor> backgroundColor_;
+  base::scoped_nsobject<NSColor> backgroundColor_;
 }
 
 @property(assign, nonatomic) info_bubble::BubbleArrowLocation arrowLocation;
diff --git a/chrome/browser/ui/cocoa/info_bubble_view.mm b/chrome/browser/ui/cocoa/info_bubble_view.mm
index e5be040..a25932a 100644
--- a/chrome/browser/ui/cocoa/info_bubble_view.mm
+++ b/chrome/browser/ui/cocoa/info_bubble_view.mm
@@ -5,7 +5,6 @@
 #import "chrome/browser/ui/cocoa/info_bubble_view.h"
 
 #include "base/logging.h"
-#include "base/memory/scoped_nsobject.h"
 #import "third_party/GTM/AppKit/GTMNSBezierPath+RoundRect.h"
 
 @implementation InfoBubbleView
diff --git a/chrome/browser/ui/cocoa/info_bubble_view_unittest.mm b/chrome/browser/ui/cocoa/info_bubble_view_unittest.mm
index ff60da5..82b135a 100644
--- a/chrome/browser/ui/cocoa/info_bubble_view_unittest.mm
+++ b/chrome/browser/ui/cocoa/info_bubble_view_unittest.mm
@@ -2,9 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "base/memory/scoped_nsobject.h"
-#import "chrome/browser/ui/cocoa/info_bubble_view.h"
+#include "base/mac/scoped_nsobject.h"
 #import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/info_bubble_view.h"
 
 namespace {
 
@@ -12,7 +12,7 @@
  public:
   InfoBubbleViewTest() {
     NSRect frame = NSMakeRect(0, 0, 100, 30);
-    scoped_nsobject<InfoBubbleView> view(
+    base::scoped_nsobject<InfoBubbleView> view(
         [[InfoBubbleView alloc] initWithFrame:frame]);
     view_ = view.get();
     [[test_window() contentView] addSubview:view_];
diff --git a/chrome/browser/ui/cocoa/info_bubble_window.mm b/chrome/browser/ui/cocoa/info_bubble_window.mm
index 4da277a..1cc17b8 100644
--- a/chrome/browser/ui/cocoa/info_bubble_window.mm
+++ b/chrome/browser/ui/cocoa/info_bubble_window.mm
@@ -6,7 +6,7 @@
 
 #include "base/basictypes.h"
 #include "base/logging.h"
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "chrome/common/chrome_notification_types.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
@@ -123,7 +123,7 @@
     // Notice that only the alphaValue Animation is replaced in case
     // superclasses set up animations.
     CAAnimation* alphaAnimation = [CABasicAnimation animation];
-    scoped_nsobject<InfoBubbleWindowCloser> delegate(
+    base::scoped_nsobject<InfoBubbleWindowCloser> delegate(
         [[InfoBubbleWindowCloser alloc] initWithWindow:self]);
     [alphaAnimation setDelegate:delegate];
     NSMutableDictionary* animations =
diff --git a/chrome/browser/ui/cocoa/infobars/before_translate_infobar_controller.h b/chrome/browser/ui/cocoa/infobars/before_translate_infobar_controller.h
index b2e10a0..df751e2 100644
--- a/chrome/browser/ui/cocoa/infobars/before_translate_infobar_controller.h
+++ b/chrome/browser/ui/cocoa/infobars/before_translate_infobar_controller.h
@@ -5,8 +5,8 @@
 #import "chrome/browser/ui/cocoa/infobars/translate_infobar_base.h"
 
 @interface BeforeTranslateInfobarController : TranslateInfoBarControllerBase {
-  scoped_nsobject<NSButton> alwaysTranslateButton_;
-  scoped_nsobject<NSButton> neverTranslateButton_;
+  base::scoped_nsobject<NSButton> alwaysTranslateButton_;
+  base::scoped_nsobject<NSButton> neverTranslateButton_;
 }
 
 // Creates and initializes the alwaysTranslate and neverTranslate buttons.
diff --git a/chrome/browser/ui/cocoa/infobars/confirm_infobar_controller_unittest.mm b/chrome/browser/ui/cocoa/infobars/confirm_infobar_controller_unittest.mm
index af29dee..2ef1404 100644
--- a/chrome/browser/ui/cocoa/infobars/confirm_infobar_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/infobars/confirm_infobar_controller_unittest.mm
@@ -4,7 +4,7 @@
 
 #import "chrome/browser/ui/cocoa/infobars/confirm_infobar_controller.h"
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "base/strings/string_util.h"
 #include "base/strings/sys_string_conversions.h"
 #include "chrome/browser/infobars/confirm_infobar_delegate.h"
@@ -110,8 +110,8 @@
   bool delegate_closed() const { return delegate_ == NULL; }
 
   MockConfirmInfoBarDelegate* delegate_;  // Owns itself.
-  scoped_nsobject<id> container_;
-  scoped_nsobject<ConfirmInfoBarController> controller_;
+  base::scoped_nsobject<id> container_;
+  base::scoped_nsobject<ConfirmInfoBarController> controller_;
   bool closed_delegate_ok_clicked_;
   bool closed_delegate_cancel_clicked_;
   bool closed_delegate_link_clicked_;
diff --git a/chrome/browser/ui/cocoa/infobars/extension_infobar_controller.h b/chrome/browser/ui/cocoa/infobars/extension_infobar_controller.h
index b028658..809aa31 100644
--- a/chrome/browser/ui/cocoa/infobars/extension_infobar_controller.h
+++ b/chrome/browser/ui/cocoa/infobars/extension_infobar_controller.h
@@ -9,7 +9,7 @@
 
 #import <Cocoa/Cocoa.h>
 
-#import "base/memory/scoped_nsobject.h"
+#import "base/mac/scoped_nsobject.h"
 #include "base/memory/scoped_ptr.h"
 
 @class ExtensionActionContextMenu;
@@ -25,10 +25,10 @@
 
   // The InfoBar's button with the Extension's icon that launches the context
   // menu.
-  scoped_nsobject<MenuButton> dropdownButton_;
+  base::scoped_nsobject<MenuButton> dropdownButton_;
 
   // The context menu that pops up when the left button is clicked.
-  scoped_nsobject<ExtensionActionContextMenu> contextMenu_;
+  base::scoped_nsobject<ExtensionActionContextMenu> contextMenu_;
 
   // Helper class to bridge C++ and ObjC functionality together for the infobar.
   scoped_ptr<InfobarBridge> bridge_;
diff --git a/chrome/browser/ui/cocoa/infobars/infobar_container_controller.h b/chrome/browser/ui/cocoa/infobars/infobar_container_controller.h
index c08ea19..f645b79 100644
--- a/chrome/browser/ui/cocoa/infobars/infobar_container_controller.h
+++ b/chrome/browser/ui/cocoa/infobars/infobar_container_controller.h
@@ -7,7 +7,7 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "base/memory/scoped_ptr.h"
 #import "chrome/browser/ui/cocoa/view_resizer.h"
 #include "content/public/browser/notification_registrar.h"
@@ -58,10 +58,10 @@
   content::WebContents* currentWebContents_;  // weak
 
   // Holds the InfoBarControllers currently owned by this container.
-  scoped_nsobject<NSMutableArray> infobarControllers_;
+  base::scoped_nsobject<NSMutableArray> infobarControllers_;
 
   // Holds InfoBarControllers when they are in the process of animating out.
-  scoped_nsobject<NSMutableSet> closingInfoBars_;
+  base::scoped_nsobject<NSMutableSet> closingInfoBars_;
 
   // Lets us registers for INFOBAR_ADDED/INFOBAR_REMOVED
   // notifications.  The actual notifications are sent to the
diff --git a/chrome/browser/ui/cocoa/infobars/infobar_container_controller_unittest.mm b/chrome/browser/ui/cocoa/infobars/infobar_container_controller_unittest.mm
index 5251de5..88d3152 100644
--- a/chrome/browser/ui/cocoa/infobars/infobar_container_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/infobars/infobar_container_controller_unittest.mm
@@ -4,7 +4,7 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #import "chrome/browser/ui/cocoa/infobars/infobar_container_controller.h"
 #include "chrome/browser/ui/cocoa/infobars/mock_confirm_infobar_delegate.h"
@@ -32,7 +32,7 @@
   }
 
  public:
-  scoped_nsobject<ViewResizerPong> resizeDelegate_;
+  base::scoped_nsobject<ViewResizerPong> resizeDelegate_;
   InfoBarContainerController* controller_;
 };
 
diff --git a/chrome/browser/ui/cocoa/infobars/infobar_controller.h b/chrome/browser/ui/cocoa/infobars/infobar_controller.h
index 2f8f26b..f96e7b1 100644
--- a/chrome/browser/ui/cocoa/infobars/infobar_controller.h
+++ b/chrome/browser/ui/cocoa/infobars/infobar_controller.h
@@ -4,7 +4,7 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 
 @class AnimatableView;
 @protocol InfoBarContainer;
@@ -39,7 +39,7 @@
   // text views cannot conveniently be created in IB. The xib file contains
   // a text field |labelPlaceholder_| that's replaced by this text view |label_|
   // in -awakeFromNib.
-  scoped_nsobject<NSTextView> label_;
+  base::scoped_nsobject<NSTextView> label_;
 };
 
 // Initializes a new InfoBarController.
diff --git a/chrome/browser/ui/cocoa/infobars/infobar_gradient_view.mm b/chrome/browser/ui/cocoa/infobars/infobar_gradient_view.mm
index 352d7ce..51fdb17 100644
--- a/chrome/browser/ui/cocoa/infobars/infobar_gradient_view.mm
+++ b/chrome/browser/ui/cocoa/infobars/infobar_gradient_view.mm
@@ -4,7 +4,7 @@
 
 #include "chrome/browser/ui/cocoa/infobars/infobar_gradient_view.h"
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "chrome/browser/infobars/infobar.h"
 #import "chrome/browser/themes/theme_properties.h"
 #import "chrome/browser/ui/cocoa/browser_window_controller.h"
@@ -42,7 +42,7 @@
 - (void)setInfobarType:(InfoBarDelegate::Type)infobarType {
   SkColor topColor = GetInfoBarTopColor(infobarType);
   SkColor bottomColor = GetInfoBarBottomColor(infobarType);
-  scoped_nsobject<NSGradient> gradient([[NSGradient alloc]
+  base::scoped_nsobject<NSGradient> gradient([[NSGradient alloc]
       initWithStartingColor:gfx::SkColorToCalibratedNSColor(topColor)
                 endingColor:gfx::SkColorToCalibratedNSColor(bottomColor)]);
   [self setGradient:gradient];
@@ -84,7 +84,7 @@
   [infoBarPath lineToPoint:NSMakePoint(NSMaxX(bounds), NSMaxY(bounds))];
 
   // Save off the top path of the infobar.
-  scoped_nsobject<NSBezierPath> topPath([infoBarPath copy]);
+  base::scoped_nsobject<NSBezierPath> topPath([infoBarPath copy]);
 
   [infoBarPath lineToPoint:NSMakePoint(NSMaxX(bounds), NSMinY(bounds))];
   [infoBarPath lineToPoint:NSMakePoint(NSMinX(bounds), NSMinY(bounds))];
diff --git a/chrome/browser/ui/cocoa/infobars/infobar_gradient_view_unittest.mm b/chrome/browser/ui/cocoa/infobars/infobar_gradient_view_unittest.mm
index da5b02b..5ef8e83 100644
--- a/chrome/browser/ui/cocoa/infobars/infobar_gradient_view_unittest.mm
+++ b/chrome/browser/ui/cocoa/infobars/infobar_gradient_view_unittest.mm
@@ -2,9 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "base/memory/scoped_nsobject.h"
-#import "chrome/browser/ui/cocoa/infobars/infobar_gradient_view.h"
+#include "base/mac/scoped_nsobject.h"
 #import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/infobars/infobar_gradient_view.h"
 
 namespace {
 
@@ -12,7 +12,7 @@
  public:
   InfoBarGradientViewTest() {
     NSRect frame = NSMakeRect(0, 0, 100, 30);
-    scoped_nsobject<InfoBarGradientView> view(
+    base::scoped_nsobject<InfoBarGradientView> view(
         [[InfoBarGradientView alloc] initWithFrame:frame]);
     view_ = view.get();
     [[test_window() contentView] addSubview:view_];
diff --git a/chrome/browser/ui/cocoa/infobars/infobar_utilities.mm b/chrome/browser/ui/cocoa/infobars/infobar_utilities.mm
index 13a09ff..c5e5e63 100644
--- a/chrome/browser/ui/cocoa/infobars/infobar_utilities.mm
+++ b/chrome/browser/ui/cocoa/infobars/infobar_utilities.mm
@@ -4,7 +4,7 @@
 
 #import "chrome/browser/ui/cocoa/infobars/infobar_utilities.h"
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #import "chrome/browser/ui/cocoa/infobars/infobar_container_controller.h"
 #import "chrome/browser/ui/cocoa/infobars/infobar_gradient_view.h"
 
@@ -69,10 +69,10 @@
   if (tag == -1) {
     [menu addItem:[NSMenuItem separatorItem]];
   } else {
-    scoped_nsobject<NSMenuItem> item([[NSMenuItem alloc]
-      initWithTitle:title
-             action:selector
-      keyEquivalent:@""]);
+    base::scoped_nsobject<NSMenuItem> item(
+        [[NSMenuItem alloc] initWithTitle:title
+                                   action:selector
+                            keyEquivalent:@""]);
     [item setTag:tag];
     [menu addItem:item];
     [item setTarget:target];
diff --git a/chrome/browser/ui/cocoa/infobars/translate_infobar_base.h b/chrome/browser/ui/cocoa/infobars/translate_infobar_base.h
index 31df784..d1d96ae 100644
--- a/chrome/browser/ui/cocoa/infobars/translate_infobar_base.h
+++ b/chrome/browser/ui/cocoa/infobars/translate_infobar_base.h
@@ -7,7 +7,7 @@
 
 #import <Cocoa/Cocoa.h>
 
-#import "base/memory/scoped_nsobject.h"
+#import "base/mac/scoped_nsobject.h"
 #include "base/memory/scoped_ptr.h"
 #include "chrome/browser/translate/options_menu_model.h"
 #include "chrome/browser/translate/translate_infobar_delegate.h"
@@ -23,17 +23,17 @@
 // - (bool)verifyLayout; // For testing.
 @interface TranslateInfoBarControllerBase : InfoBarController<NSMenuDelegate> {
  @protected
-  scoped_nsobject<NSTextField> label1_;
-  scoped_nsobject<NSTextField> label2_;
-  scoped_nsobject<NSTextField> label3_;
-  scoped_nsobject<NSPopUpButton> fromLanguagePopUp_;
-  scoped_nsobject<NSPopUpButton> toLanguagePopUp_;
-  scoped_nsobject<NSPopUpButton> optionsPopUp_;
-  scoped_nsobject<NSButton> showOriginalButton_;
+  base::scoped_nsobject<NSTextField> label1_;
+  base::scoped_nsobject<NSTextField> label2_;
+  base::scoped_nsobject<NSTextField> label3_;
+  base::scoped_nsobject<NSPopUpButton> fromLanguagePopUp_;
+  base::scoped_nsobject<NSPopUpButton> toLanguagePopUp_;
+  base::scoped_nsobject<NSPopUpButton> optionsPopUp_;
+  base::scoped_nsobject<NSButton> showOriginalButton_;
   // This is the button used in the translate message infobar.  It can either be
   // a "Try Again" button, or a "Show Original" button in the case that the
   // page was translated from an unknown language.
-  scoped_nsobject<NSButton> translateMessageButton_;
+  base::scoped_nsobject<NSButton> translateMessageButton_;
 
   // In the current locale, are the "from" and "to" language popup menu
   // flipped from what they'd appear in English.
diff --git a/chrome/browser/ui/cocoa/infobars/translate_infobar_unittest.mm b/chrome/browser/ui/cocoa/infobars/translate_infobar_unittest.mm
index fbbf9f3..e5ae2a0 100644
--- a/chrome/browser/ui/cocoa/infobars/translate_infobar_unittest.mm
+++ b/chrome/browser/ui/cocoa/infobars/translate_infobar_unittest.mm
@@ -4,12 +4,13 @@
 
 #import <Cocoa/Cocoa.h>
 
-#import "base/memory/scoped_nsobject.h"
+#import "base/mac/scoped_nsobject.h"
 #import "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #import "chrome/app/chrome_command_ids.h"  // For translate menu command ids.
 #include "chrome/browser/infobars/infobar_service.h"
 #import "chrome/browser/translate/translate_infobar_delegate.h"
+#include "chrome/browser/translate/translate_language_list.h"
 #include "chrome/browser/ui/cocoa/cocoa_profile_test.h"
 #import "chrome/browser/ui/cocoa/infobars/before_translate_infobar_controller.h"
 #import "chrome/browser/ui/cocoa/infobars/infobar.h"
@@ -61,6 +62,7 @@
   // Each test gets a single Mock translate delegate for the lifetime of
   // the test.
   virtual void SetUp() {
+    TranslateLanguageList::DisableUpdate();
     CocoaProfileTest::SetUp();
     web_contents_.reset(
         WebContents::Create(WebContents::CreateParams(profile())));
@@ -105,7 +107,7 @@
 
   scoped_ptr<WebContents> web_contents_;
   scoped_ptr<MockTranslateInfoBarDelegate> infobar_delegate_;
-  scoped_nsobject<TranslateInfoBarControllerBase> infobar_controller_;
+  base::scoped_nsobject<TranslateInfoBarControllerBase> infobar_controller_;
 };
 
 // Check that we can instantiate a Translate Infobar correctly.
diff --git a/chrome/browser/ui/cocoa/javascript_app_modal_dialog_cocoa.h b/chrome/browser/ui/cocoa/javascript_app_modal_dialog_cocoa.h
index 7aa97ff..aa7153c 100644
--- a/chrome/browser/ui/cocoa/javascript_app_modal_dialog_cocoa.h
+++ b/chrome/browser/ui/cocoa/javascript_app_modal_dialog_cocoa.h
@@ -8,7 +8,7 @@
 #include "chrome/browser/ui/app_modal_dialogs/native_app_modal_dialog.h"
 
 #include "base/logging.h"
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "base/memory/scoped_ptr.h"
 
 #if __OBJC__
@@ -37,7 +37,7 @@
  private:
   scoped_ptr<JavaScriptAppModalDialog> dialog_;
 
-  scoped_nsobject<JavaScriptAppModalDialogHelper> helper_;
+  base::scoped_nsobject<JavaScriptAppModalDialogHelper> helper_;
   NSAlert* alert_; // weak, owned by |helper_|.
 
   DISALLOW_COPY_AND_ASSIGN(JavaScriptAppModalDialogCocoa);
diff --git a/chrome/browser/ui/cocoa/javascript_app_modal_dialog_cocoa.mm b/chrome/browser/ui/cocoa/javascript_app_modal_dialog_cocoa.mm
index 5e8b6e3..a903723 100644
--- a/chrome/browser/ui/cocoa/javascript_app_modal_dialog_cocoa.mm
+++ b/chrome/browser/ui/cocoa/javascript_app_modal_dialog_cocoa.mm
@@ -21,7 +21,7 @@
 // going away. Is responsible for cleaning itself up.
 @interface JavaScriptAppModalDialogHelper : NSObject<NSAlertDelegate> {
  @private
-  scoped_nsobject<NSAlert> alert_;
+  base::scoped_nsobject<NSAlert> alert_;
   NSTextField* textField_;  // WEAK; owned by alert_
 }
 
@@ -208,13 +208,13 @@
   }
 
   if (message_has_rtl && message_text_field) {
-    scoped_nsobject<NSMutableParagraphStyle> alignment(
+    base::scoped_nsobject<NSMutableParagraphStyle> alignment(
         [[NSParagraphStyle defaultParagraphStyle] mutableCopy]);
     [alignment setAlignment:NSRightTextAlignment];
 
     NSDictionary* alignment_attributes =
         @{ NSParagraphStyleAttributeName : alignment };
-    scoped_nsobject<NSAttributedString> attr_string(
+    base::scoped_nsobject<NSAttributedString> attr_string(
         [[NSAttributedString alloc] initWithString:message_text
                                         attributes:alignment_attributes]);
 
@@ -225,7 +225,7 @@
   if (informative_has_rtl && informative_text_field) {
     base::i18n::TextDirection direction =
         base::i18n::GetFirstStrongCharacterDirection(dialog_->message_text());
-    scoped_nsobject<NSMutableParagraphStyle> alignment(
+    base::scoped_nsobject<NSMutableParagraphStyle> alignment(
         [[NSParagraphStyle defaultParagraphStyle] mutableCopy]);
     [alignment setAlignment:
         (direction == base::i18n::RIGHT_TO_LEFT) ? NSRightTextAlignment
@@ -233,7 +233,7 @@
 
     NSDictionary* alignment_attributes =
         @{ NSParagraphStyleAttributeName : alignment };
-    scoped_nsobject<NSAttributedString> attr_string(
+    base::scoped_nsobject<NSAttributedString> attr_string(
         [[NSAttributedString alloc] initWithString:informative_text
                                         attributes:alignment_attributes]);
 
diff --git a/chrome/browser/ui/cocoa/l10n_util.h b/chrome/browser/ui/cocoa/l10n_util.h
index 7f1be9e..17e8f22 100644
--- a/chrome/browser/ui/cocoa/l10n_util.h
+++ b/chrome/browser/ui/cocoa/l10n_util.h
@@ -29,4 +29,7 @@
                                       const string16& a,
                                       size_t* offset);
 
+// Generates a tooltip string for a given URL and title.
+NSString* TooltipForURLAndTitle(NSString* url, NSString* title);
+
 }  // namespace cocoa_l10n_util
diff --git a/chrome/browser/ui/cocoa/l10n_util.mm b/chrome/browser/ui/cocoa/l10n_util.mm
index 5b4dee4..61eb681 100644
--- a/chrome/browser/ui/cocoa/l10n_util.mm
+++ b/chrome/browser/ui/cocoa/l10n_util.mm
@@ -75,4 +75,13 @@
                                 offset));
 }
 
+NSString* TooltipForURLAndTitle(NSString* url, NSString* title) {
+  if ([title length] == 0)
+    return url;
+  else if ([url length] == 0 || [url isEqualToString:title])
+    return title;
+  else
+    return [NSString stringWithFormat:@"%@\n%@", title, url];
+}
+
 }  // namespace cocoa_l10n_util
diff --git a/chrome/browser/ui/cocoa/location_bar/action_box_menu_bubble_controller.h b/chrome/browser/ui/cocoa/location_bar/action_box_menu_bubble_controller.h
index c24c8de..f0a38ac 100644
--- a/chrome/browser/ui/cocoa/location_bar/action_box_menu_bubble_controller.h
+++ b/chrome/browser/ui/cocoa/location_bar/action_box_menu_bubble_controller.h
@@ -7,7 +7,7 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "base/memory/scoped_ptr.h"
 #import "chrome/browser/ui/cocoa/base_bubble_controller.h"
 #import "ui/base/cocoa/tracking_area.h"
@@ -25,7 +25,7 @@
   scoped_ptr<ActionBoxMenuModel> model_;
 
   // Array of the below view controllers.
-  scoped_nsobject<NSMutableArray> items_;
+  base::scoped_nsobject<NSMutableArray> items_;
 }
 
 // Designated initializer. |point| must be in screen coordinates.
diff --git a/chrome/browser/ui/cocoa/location_bar/action_box_menu_bubble_controller.mm b/chrome/browser/ui/cocoa/location_bar/action_box_menu_bubble_controller.mm
index 5c0862e..d65dc50 100644
--- a/chrome/browser/ui/cocoa/location_bar/action_box_menu_bubble_controller.mm
+++ b/chrome/browser/ui/cocoa/location_bar/action_box_menu_bubble_controller.mm
@@ -100,7 +100,7 @@
   // Use an arbitrary height because it will reflect the size of the content.
   NSRect contentRect = NSMakeRect(0, 0, kBubbleMinWidth, 150);
   // Create an empty window into which content is placed.
-  scoped_nsobject<InfoBubbleWindow> window(
+  base::scoped_nsobject<InfoBubbleWindow> window(
       [[InfoBubbleWindow alloc] initWithContentRect:contentRect
                                           styleMask:NSBorderlessWindowMask
                                             backing:NSBackingStoreBuffered
@@ -160,7 +160,7 @@
   CGFloat yOffset = kVerticalPadding;
 
   // Keep track of a potential separator to resize it when we know the width.
-  scoped_nsobject<NSBox> separatorView;
+  base::scoped_nsobject<NSBox> separatorView;
 
   // Loop over the items in reverse, constructing the menu items.
   CGFloat width = kBubbleMinWidth;
@@ -183,11 +183,10 @@
     } else {
       // Create the item controller. Autorelease it because it will be owned
       // by the |items_| array.
-      scoped_nsobject<ActionBoxMenuItemController> itemController(
-          [[ActionBoxMenuItemController alloc]
-              initWithModelIndex:i
-                  menuController:self
-                         profile:profile_]);
+      base::scoped_nsobject<ActionBoxMenuItemController> itemController(
+          [[ActionBoxMenuItemController alloc] initWithModelIndex:i
+                                                   menuController:self
+                                                          profile:profile_]);
 
       // Adjust the name field to fit the string.
       [GTMUILocalizerAndLayoutTweaker sizeToFitView:[itemController nameField]];
diff --git a/chrome/browser/ui/cocoa/location_bar/action_box_menu_bubble_controller_unittest.mm b/chrome/browser/ui/cocoa/location_bar/action_box_menu_bubble_controller_unittest.mm
index 7139ed6..7399ac5 100644
--- a/chrome/browser/ui/cocoa/location_bar/action_box_menu_bubble_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/location_bar/action_box_menu_bubble_controller_unittest.mm
@@ -87,8 +87,8 @@
                          .Set("background", extensions::DictionaryBuilder()
                              .Set("page", ""))))
         .Build();
-    service_->AddExtension(extension);
-    model->AddExtension(*extension, command_id);
+    service_->AddExtension(extension.get());
+    model->AddExtension(*extension.get(), command_id);
     return extension;
   }
 
diff --git a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.h b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.h
index a54e788..eadb217 100644
--- a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.h
+++ b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.h
@@ -7,7 +7,7 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #import "chrome/browser/ui/cocoa/styled_text_field.h"
 #import "chrome/browser/ui/cocoa/url_drop_target.h"
 
@@ -113,18 +113,18 @@
  @private
   // Undo manager for this text field.  We use a specific instance rather than
   // the standard undo manager in order to let us clear the undo stack at will.
-  scoped_nsobject<NSUndoManager> undoManager_;
+  base::scoped_nsobject<NSUndoManager> undoManager_;
 
   AutocompleteTextFieldObserver* observer_;  // weak, owned by location bar.
 
   // Handles being a drag-and-drop target.
-  scoped_nsobject<URLDropTargetHandler> dropHandler_;
+  base::scoped_nsobject<URLDropTargetHandler> dropHandler_;
 
   // Holds current tooltip strings, to keep them from being dealloced.
-  scoped_nsobject<NSMutableArray> currentToolTips_;
+  base::scoped_nsobject<NSMutableArray> currentToolTips_;
 
-  scoped_nsobject<NSString> suggestText_;
-  scoped_nsobject<NSColor> suggestColor_;
+  base::scoped_nsobject<NSString> suggestText_;
+  base::scoped_nsobject<NSColor> suggestColor_;
 }
 
 @property(nonatomic) AutocompleteTextFieldObserver* observer;
diff --git a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.mm b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.mm
index fcdd149..addda9c 100644
--- a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.mm
+++ b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.mm
@@ -449,13 +449,13 @@
   if (![suggestText length])
     return;
 
-  scoped_nsobject<NSTextFieldCell> cell(
+  base::scoped_nsobject<NSTextFieldCell> cell(
       [[NSTextFieldCell alloc] initTextCell:@""]);
   [cell setBordered:NO];
   [cell setDrawsBackground:NO];
   [cell setEditable:NO];
 
-  scoped_nsobject<NSMutableAttributedString> combinedText(
+  base::scoped_nsobject<NSMutableAttributedString> combinedText(
       [[NSMutableAttributedString alloc] initWithAttributedString:mainText]);
   NSRange range = NSMakeRange([combinedText length], 0);
   [combinedText replaceCharactersInRange:range withString:suggestText];
diff --git a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell.mm b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell.mm
index 6277c90..ac53430 100644
--- a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell.mm
+++ b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell.mm
@@ -185,8 +185,6 @@
 @implementation AutocompleteTextFieldCell
 
 - (CGFloat)topTextFrameOffset {
-  if (chrome::IsInstantExtendedAPIEnabled())
-    return 2.0;
   return 3.0;
 }
 
@@ -208,9 +206,7 @@
 }
 
 - (CGFloat)lineHeight {
-  if (chrome::IsInstantExtendedAPIEnabled())
-    return 19;
-  return 16;
+  return 17;
 }
 
 - (void)clearDecorations {
@@ -551,7 +547,7 @@
       }
 
       NSDictionary* info = [self getDictionaryForButtonDecoration:button];
-      scoped_nsobject<CrTrackingArea> area(
+      base::scoped_nsobject<CrTrackingArea> area(
           [[CrTrackingArea alloc] initWithRect:decorationFrames[i]
                                        options:NSTrackingMouseEnteredAndExited |
                                                NSTrackingActiveAlways
diff --git a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell_unittest.mm b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell_unittest.mm
index 3af9e75..def7ede 100644
--- a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell_unittest.mm
+++ b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell_unittest.mm
@@ -4,7 +4,7 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "base/strings/utf_string_conversions.h"
 #import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.h"
@@ -19,8 +19,8 @@
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/platform_test.h"
-#include "third_party/ocmock/gtest_support.h"
 #import "third_party/ocmock/OCMock/OCMock.h"
+#include "third_party/ocmock/gtest_support.h"
 #include "ui/base/resource/resource_bundle.h"
 
 using ::testing::Return;
@@ -51,11 +51,11 @@
     // decorations.
     const NSRect frame = NSMakeRect(0, 0, kWidth, 30);
 
-    scoped_nsobject<NSTextField> view(
+    base::scoped_nsobject<NSTextField> view(
         [[NSTextField alloc] initWithFrame:frame]);
     view_ = view.get();
 
-    scoped_nsobject<AutocompleteTextFieldCell> cell(
+    base::scoped_nsobject<AutocompleteTextFieldCell> cell(
         [[AutocompleteTextFieldCell alloc] initTextCell:@"Testing"]);
     [cell setEditable:YES];
     [cell setBordered:YES];
diff --git a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor.h b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor.h
index 1943ae8..cf2c5b3 100644
--- a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor.h
+++ b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor.h
@@ -4,7 +4,7 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #import "chrome/browser/ui/cocoa/url_drop_target.h"
 
 @class AutocompleteTextField;
@@ -23,9 +23,9 @@
   // allowing the |AutocompletTextField| to handle it (by making an empty
   // |-updateDragTypeRegistration|), since the latter results in a weird
   // start-up time regression.
-  scoped_nsobject<URLDropTargetHandler> dropHandler_;
+  base::scoped_nsobject<URLDropTargetHandler> dropHandler_;
 
-  scoped_nsobject<NSCharacterSet> forbiddenCharacters_;
+  base::scoped_nsobject<NSCharacterSet> forbiddenCharacters_;
 
   // Indicates if the field editor's interpretKeyEvents: method is being called.
   // If it's YES, then we should postpone the call to the observer's
diff --git a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor_unittest.mm b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor_unittest.mm
index 548f6e2..dac079a 100644
--- a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor_unittest.mm
+++ b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor_unittest.mm
@@ -4,7 +4,7 @@
 
 #import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor.h"
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/strings/string_util.h"
 #include "chrome/app/chrome_command_ids.h"  // IDC_*
@@ -15,8 +15,8 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #import "testing/gtest_mac.h"
 #include "testing/platform_test.h"
-#include "third_party/ocmock/gtest_support.h"
 #import "third_party/ocmock/OCMock/OCMock.h"
+#include "third_party/ocmock/gtest_support.h"
 #import "third_party/ocmock/ocmock_extensions.h"
 #import "ui/base/test/cocoa_test_event_utils.h"
 
@@ -35,7 +35,7 @@
   virtual void SetUp() {
     CocoaTest::SetUp();
     NSRect frame = NSMakeRect(0, 0, 50, 30);
-    scoped_nsobject<AutocompleteTextField> field(
+    base::scoped_nsobject<AutocompleteTextField> field(
         [[AutocompleteTextField alloc] initWithFrame:frame]);
     field_ = field.get();
     [field_ setStringValue:@"Testing"];
@@ -56,7 +56,8 @@
 
   AutocompleteTextFieldEditor* editor_;
   AutocompleteTextField* field_;
-  scoped_nsobject<AutocompleteTextFieldWindowTestDelegate> window_delegate_;
+  base::scoped_nsobject<AutocompleteTextFieldWindowTestDelegate>
+      window_delegate_;
 };
 
 // Disabled because it crashes sometimes. http://crbug.com/49522
@@ -107,7 +108,7 @@
 
   // Trivial menu which we can recognize and which doesn't look like
   // the default editor context menu.
-  scoped_nsobject<id> menu([[NSMenu alloc] initWithTitle:@"Menu"]);
+  base::scoped_nsobject<id> menu([[NSMenu alloc] initWithTitle:@"Menu"]);
   [menu addItemWithTitle:@"Go Fish"
                   action:@selector(goFish:)
            keyEquivalent:@""];
diff --git a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_unittest.mm b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_unittest.mm
index 63a4d85..72ffc7a 100644
--- a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_unittest.mm
+++ b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_unittest.mm
@@ -5,13 +5,13 @@
 #import <Cocoa/Cocoa.h>
 
 #include "base/mac/foundation_util.h"
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.h"
 #import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell.h"
 #import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor.h"
 #import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_unittest_helper.h"
 #import "chrome/browser/ui/cocoa/location_bar/location_bar_decoration.h"
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #include "grit/theme_resources.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -75,7 +75,7 @@
     // Make sure this is wide enough to play games with the cell
     // decorations.
     NSRect frame = NSMakeRect(0, 0, kWidth, 30);
-    scoped_nsobject<AutocompleteTextField> field(
+    base::scoped_nsobject<AutocompleteTextField> field(
         [[AutocompleteTextField alloc] initWithFrame:frame]);
     field_ = field.get();
     [field_ setStringValue:@"Test test"];
@@ -129,7 +129,8 @@
   AutocompleteTextField* field_;
   MockDecoration mock_left_decoration_;
   MockDecoration mock_right_decoration_;
-  scoped_nsobject<AutocompleteTextFieldWindowTestDelegate> window_delegate_;
+  base::scoped_nsobject<AutocompleteTextFieldWindowTestDelegate>
+      window_delegate_;
 };
 
 TEST_VIEW(AutocompleteTextFieldTest, field_);
@@ -622,9 +623,9 @@
 
   const CGFloat edge = NSHeight(bounds) - 4.0;
   const NSSize size = NSMakeSize(edge, edge);
-  scoped_nsobject<NSImage> image([[NSImage alloc] initWithSize:size]);
+  base::scoped_nsobject<NSImage> image([[NSImage alloc] initWithSize:size]);
 
-  scoped_nsobject<NSMenu> menu([[NSMenu alloc] initWithTitle:@"Menu"]);
+  base::scoped_nsobject<NSMenu> menu([[NSMenu alloc] initWithTitle:@"Menu"]);
 
   mock_left_decoration_.SetVisible(true);
   mock_right_decoration_.SetVisible(true);
@@ -674,7 +675,7 @@
       [NSDictionary dictionaryWithObject:font
                                   forKey:NSFontAttributeName];
   NSString* const kString = @"This is a test";
-  scoped_nsobject<NSAttributedString> attributedString(
+  base::scoped_nsobject<NSAttributedString> attributedString(
       [[NSAttributedString alloc] initWithString:kString
                                       attributes:attributes]);
 
@@ -707,7 +708,7 @@
       [NSDictionary dictionaryWithObject:redColor
                                   forKey:NSForegroundColorAttributeName];
   NSString* const kString = @"This is a test";
-  scoped_nsobject<NSAttributedString> attributedString(
+  base::scoped_nsobject<NSAttributedString> attributedString(
       [[NSAttributedString alloc] initWithString:kString
                                       attributes:attributes]);
   [test_window() makePretendKeyWindowAndSetFirstResponder:field_];
@@ -816,7 +817,7 @@
   EXPECT_CALL(field_observer_, ClosePopup());
   [test_window() resignKeyWindow];
 
-  scoped_nsobject<AutocompleteTextField> pin([field_ retain]);
+  base::scoped_nsobject<AutocompleteTextField> pin([field_ retain]);
   [field_ removeFromSuperview];
   [test_window() resignKeyWindow];
 
diff --git a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_unittest_helper.h b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_unittest_helper.h
index cd8116a..3ba6511 100644
--- a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_unittest_helper.h
+++ b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_unittest_helper.h
@@ -7,7 +7,7 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
@@ -17,7 +17,7 @@
 
 @interface AutocompleteTextFieldWindowTestDelegate :
     NSObject<NSWindowDelegate> {
-  scoped_nsobject<AutocompleteTextFieldEditor> editor_;
+  base::scoped_nsobject<AutocompleteTextFieldEditor> editor_;
 }
 - (id)windowWillReturnFieldEditor:(NSWindow *)sender toObject:(id)anObject;
 @end
diff --git a/chrome/browser/ui/cocoa/location_bar/bubble_decoration.h b/chrome/browser/ui/cocoa/location_bar/bubble_decoration.h
index a1e55f5..6a1d1cc 100644
--- a/chrome/browser/ui/cocoa/location_bar/bubble_decoration.h
+++ b/chrome/browser/ui/cocoa/location_bar/bubble_decoration.h
@@ -8,7 +8,7 @@
 #import <Cocoa/Cocoa.h>
 
 #include "base/gtest_prod_util.h"
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "chrome/browser/ui/cocoa/location_bar/location_bar_decoration.h"
 
 // Draws an outlined rounded rect, with an optional image to the left
@@ -46,18 +46,18 @@
                            UsesPartialKeywordIfNarrow);
 
   // Image drawn in the left side of the bubble.
-  scoped_nsobject<NSImage> image_;
+  base::scoped_nsobject<NSImage> image_;
 
   // Label to draw to right of image.  Can be |nil|.
-  scoped_nsobject<NSString> label_;
+  base::scoped_nsobject<NSString> label_;
 
   // Contains attribute for drawing |label_|.
-  scoped_nsobject<NSMutableDictionary> attributes_;
+  base::scoped_nsobject<NSMutableDictionary> attributes_;
 
   // Colors used to draw the bubble, should be set by the subclass
   // constructor.
-  scoped_nsobject<NSColor> background_color_;
-  scoped_nsobject<NSColor> border_color_;
+  base::scoped_nsobject<NSColor> background_color_;
+  base::scoped_nsobject<NSColor> border_color_;
 
   DISALLOW_COPY_AND_ASSIGN(BubbleDecoration);
 };
diff --git a/chrome/browser/ui/cocoa/location_bar/button_decoration.h b/chrome/browser/ui/cocoa/location_bar/button_decoration.h
index 70d4708..fde8f94 100644
--- a/chrome/browser/ui/cocoa/location_bar/button_decoration.h
+++ b/chrome/browser/ui/cocoa/location_bar/button_decoration.h
@@ -5,7 +5,7 @@
 #ifndef CHROME_BROWSER_UI_COCOA_LOCATION_BAR_BUTTON_DECORATION_H_
 #define CHROME_BROWSER_UI_COCOA_LOCATION_BAR_BUTTON_DECORATION_H_
 
-#import "base/memory/scoped_nsobject.h"
+#import "base/mac/scoped_nsobject.h"
 #include "chrome/browser/ui/cocoa/location_bar/location_bar_decoration.h"
 
 // |LocationBarDecoration| which looks and acts like a button.
@@ -42,9 +42,9 @@
   void SetPressedImage(NSImage* pressed_image);
 
  private:
-  scoped_nsobject<NSImage> normal_image_;
-  scoped_nsobject<NSImage> hover_image_;
-  scoped_nsobject<NSImage> pressed_image_;
+  base::scoped_nsobject<NSImage> normal_image_;
+  base::scoped_nsobject<NSImage> hover_image_;
+  base::scoped_nsobject<NSImage> pressed_image_;
   ButtonState state_;
 
   NSImage* GetImage();
diff --git a/chrome/browser/ui/cocoa/location_bar/content_setting_decoration.h b/chrome/browser/ui/cocoa/location_bar/content_setting_decoration.h
index 219992e..dafcd11 100644
--- a/chrome/browser/ui/cocoa/location_bar/content_setting_decoration.h
+++ b/chrome/browser/ui/cocoa/location_bar/content_setting_decoration.h
@@ -52,7 +52,7 @@
   void SetToolTip(NSString* tooltip);
 
   // Returns an attributed string with the animated text.
-  scoped_nsobject<NSAttributedString> CreateAnimatedText();
+  base::scoped_nsobject<NSAttributedString> CreateAnimatedText();
 
   // Measure the width of the animated text.
   CGFloat MeasureTextWidth();
@@ -62,13 +62,13 @@
   LocationBarViewMac* owner_;  // weak
   Profile* profile_;  // weak
 
-  scoped_nsobject<NSString> tooltip_;
+  base::scoped_nsobject<NSString> tooltip_;
 
   // Used when the decoration has animated text.
-  scoped_nsobject<ContentSettingAnimationState> animation_;
+  base::scoped_nsobject<ContentSettingAnimationState> animation_;
   CGFloat text_width_;
-  scoped_nsobject<NSAttributedString> animated_text_;
-  scoped_nsobject<NSGradient> gradient_;
+  base::scoped_nsobject<NSAttributedString> animated_text_;
+  base::scoped_nsobject<NSGradient> gradient_;
 
   DISALLOW_COPY_AND_ASSIGN(ContentSettingDecoration);
 };
diff --git a/chrome/browser/ui/cocoa/location_bar/content_setting_decoration.mm b/chrome/browser/ui/cocoa/location_bar/content_setting_decoration.mm
index 79c33f1..174f5bf 100644
--- a/chrome/browser/ui/cocoa/location_bar/content_setting_decoration.mm
+++ b/chrome/browser/ui/cocoa/location_bar/content_setting_decoration.mm
@@ -228,19 +228,19 @@
   return [animated_text_ size].width;
 }
 
-scoped_nsobject<NSAttributedString>
+base::scoped_nsobject<NSAttributedString>
 ContentSettingDecoration::CreateAnimatedText() {
   NSString* text =
       l10n_util::GetNSString(
           content_setting_image_model_->explanatory_string_id());
-  scoped_nsobject<NSMutableParagraphStyle> style(
+  base::scoped_nsobject<NSMutableParagraphStyle> style(
       [[NSMutableParagraphStyle alloc] init]);
   // Set line break mode to clip the text, otherwise drawInRect: won't draw a
   // word if it doesn't fit in the bounding box.
   [style setLineBreakMode:NSLineBreakByClipping];
   NSDictionary* attributes = @{ NSFontAttributeName : GetFont(),
                                 NSParagraphStyleAttributeName : style };
-  return scoped_nsobject<NSAttributedString>(
+  return base::scoped_nsobject<NSAttributedString>(
       [[NSAttributedString alloc] initWithString:text attributes:attributes]);
 }
 
diff --git a/chrome/browser/ui/cocoa/location_bar/ev_bubble_decoration.h b/chrome/browser/ui/cocoa/location_bar/ev_bubble_decoration.h
index ee7d99f..b17e7d8 100644
--- a/chrome/browser/ui/cocoa/location_bar/ev_bubble_decoration.h
+++ b/chrome/browser/ui/cocoa/location_bar/ev_bubble_decoration.h
@@ -44,7 +44,7 @@
 
  private:
   // The real label.  BubbleDecoration's label may be elided.
-  scoped_nsobject<NSString> full_label_;
+  base::scoped_nsobject<NSString> full_label_;
 
   LocationIconDecoration* location_icon_;  // weak, owned by location bar.
 
diff --git a/chrome/browser/ui/cocoa/location_bar/ev_bubble_decoration_unittest.mm b/chrome/browser/ui/cocoa/location_bar/ev_bubble_decoration_unittest.mm
index f07cfb2..e898e20 100644
--- a/chrome/browser/ui/cocoa/location_bar/ev_bubble_decoration_unittest.mm
+++ b/chrome/browser/ui/cocoa/location_bar/ev_bubble_decoration_unittest.mm
@@ -28,7 +28,8 @@
   const CGFloat kMinimumWidth = 100.0;  // Never should get this small.
 
   const NSSize kImageSize = NSMakeSize(20.0, 20.0);
-  scoped_nsobject<NSImage> image([[NSImage alloc] initWithSize:kImageSize]);
+  base::scoped_nsobject<NSImage> image(
+      [[NSImage alloc] initWithSize:kImageSize]);
 
   decoration_.SetImage(image);
   decoration_.SetFullLabel(kLongString);
diff --git a/chrome/browser/ui/cocoa/location_bar/image_decoration.h b/chrome/browser/ui/cocoa/location_bar/image_decoration.h
index 6b105ab..0bb4193 100644
--- a/chrome/browser/ui/cocoa/location_bar/image_decoration.h
+++ b/chrome/browser/ui/cocoa/location_bar/image_decoration.h
@@ -5,7 +5,7 @@
 #ifndef CHROME_BROWSER_UI_COCOA_LOCATION_BAR_IMAGE_DECORATION_H_
 #define CHROME_BROWSER_UI_COCOA_LOCATION_BAR_IMAGE_DECORATION_H_
 
-#import "base/memory/scoped_nsobject.h"
+#import "base/mac/scoped_nsobject.h"
 #include "chrome/browser/ui/cocoa/location_bar/location_bar_decoration.h"
 
 // |LocationBarDecoration| which sizes and draws itself according to
@@ -27,7 +27,7 @@
   virtual void DrawInFrame(NSRect frame, NSView* control_view) OVERRIDE;
 
  private:
-  scoped_nsobject<NSImage> image_;
+  base::scoped_nsobject<NSImage> image_;
 
   DISALLOW_COPY_AND_ASSIGN(ImageDecoration);
 };
diff --git a/chrome/browser/ui/cocoa/location_bar/image_decoration_unittest.mm b/chrome/browser/ui/cocoa/location_bar/image_decoration_unittest.mm
index db69b0d..2362f79 100644
--- a/chrome/browser/ui/cocoa/location_bar/image_decoration_unittest.mm
+++ b/chrome/browser/ui/cocoa/location_bar/image_decoration_unittest.mm
@@ -20,7 +20,8 @@
   EXPECT_FALSE(decoration_.GetImage());
 
   const NSSize kImageSize = NSMakeSize(20.0, 20.0);
-  scoped_nsobject<NSImage> image([[NSImage alloc] initWithSize:kImageSize]);
+  base::scoped_nsobject<NSImage> image(
+      [[NSImage alloc] initWithSize:kImageSize]);
 
   decoration_.SetImage(image);
   EXPECT_EQ(decoration_.GetImage(), image);
@@ -38,7 +39,8 @@
             LocationBarDecoration::kOmittedWidth);
 
   const NSSize kImageSize = NSMakeSize(20.0, 20.0);
-  scoped_nsobject<NSImage> image([[NSImage alloc] initWithSize:kImageSize]);
+  base::scoped_nsobject<NSImage> image(
+      [[NSImage alloc] initWithSize:kImageSize]);
 
   // Decoration takes up the space of the image.
   decoration_.SetImage(image);
diff --git a/chrome/browser/ui/cocoa/location_bar/keyword_hint_decoration.h b/chrome/browser/ui/cocoa/location_bar/keyword_hint_decoration.h
index 7a0e57e..cd218e8 100644
--- a/chrome/browser/ui/cocoa/location_bar/keyword_hint_decoration.h
+++ b/chrome/browser/ui/cocoa/location_bar/keyword_hint_decoration.h
@@ -9,7 +9,7 @@
 
 #import "chrome/browser/ui/cocoa/location_bar/location_bar_decoration.h"
 
-#import "base/memory/scoped_nsobject.h"
+#import "base/mac/scoped_nsobject.h"
 #include "base/strings/string16.h"
 
 // Draws the keyword hint, "Press [tab] to search <site>".
@@ -32,14 +32,14 @@
   NSImage* GetHintImage();
 
   // Attributes for drawing the hint string, such as font and color.
-  scoped_nsobject<NSDictionary> attributes_;
+  base::scoped_nsobject<NSDictionary> attributes_;
 
   // Cache for the [tab] image.
-  scoped_nsobject<NSImage> hint_image_;
+  base::scoped_nsobject<NSImage> hint_image_;
 
   // The text to display to the left and right of the hint image.
-  scoped_nsobject<NSString> hint_prefix_;
-  scoped_nsobject<NSString> hint_suffix_;
+  base::scoped_nsobject<NSString> hint_prefix_;
+  base::scoped_nsobject<NSString> hint_suffix_;
 
   DISALLOW_COPY_AND_ASSIGN(KeywordHintDecoration);
 };
diff --git a/chrome/browser/ui/cocoa/location_bar/location_bar_decoration.mm b/chrome/browser/ui/cocoa/location_bar/location_bar_decoration.mm
index a425bbb..13ff083 100644
--- a/chrome/browser/ui/cocoa/location_bar/location_bar_decoration.mm
+++ b/chrome/browser/ui/cocoa/location_bar/location_bar_decoration.mm
@@ -5,9 +5,8 @@
 #import "chrome/browser/ui/cocoa/location_bar/location_bar_decoration.h"
 
 #include "base/logging.h"
-#include "base/memory/scoped_nsobject.h"
-#include "chrome/browser/search/search.h"
-#include "ui/base/resource/resource_bundle.h"
+#include "base/mac/scoped_nsobject.h"
+#include "chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.h"
 
 const CGFloat LocationBarDecoration::kOmittedWidth = 0.0;
 
@@ -69,17 +68,14 @@
 }
 
 NSFont* LocationBarDecoration::GetFont() const {
-  if (chrome::IsInstantExtendedAPIEnabled())
-    return [NSFont fontWithName:@"Helvetica Neue" size:15];
-  ResourceBundle& rb = ResourceBundle::GetSharedInstance();
-  return rb.GetFont(ResourceBundle::BaseFont).GetNativeFont();
+  return OmniboxViewMac::GetFieldFont();
 }
 
 // static
 void LocationBarDecoration::DrawLabel(NSString* label,
                                       NSDictionary* attributes,
                                       const NSRect& frame) {
-  scoped_nsobject<NSAttributedString> str(
+  base::scoped_nsobject<NSAttributedString> str(
       [[NSAttributedString alloc] initWithString:label attributes:attributes]);
   DrawAttributedString(str, frame);
 }
diff --git a/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h b/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h
index 7b07555..3948654 100644
--- a/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h
+++ b/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h
@@ -9,7 +9,6 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/scoped_vector.h"
 #include "base/memory/weak_ptr.h"
diff --git a/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.mm b/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.mm
index 71b11ff..8e871d2 100644
--- a/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.mm
+++ b/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.mm
@@ -94,7 +94,6 @@
       selected_keyword_decoration_(new SelectedKeywordDecoration()),
       ev_bubble_decoration_(
           new EVBubbleDecoration(location_icon_decoration_.get())),
-      plus_decoration_(NULL),
       star_decoration_(new StarDecoration(command_updater)),
       zoom_decoration_(new ZoomDecoration(this)),
       keyword_hint_decoration_(new KeywordHintDecoration()),
diff --git a/chrome/browser/ui/cocoa/location_bar/page_action_decoration.h b/chrome/browser/ui/cocoa/location_bar/page_action_decoration.h
index 99dfba9..74f56cc 100644
--- a/chrome/browser/ui/cocoa/location_bar/page_action_decoration.h
+++ b/chrome/browser/ui/cocoa/location_bar/page_action_decoration.h
@@ -104,10 +104,10 @@
   GURL current_url_;
 
   // The string to show for a tooltip.
-  scoped_nsobject<NSString> tooltip_;
+  base::scoped_nsobject<NSString> tooltip_;
 
   // The context menu for the Page Action.
-  scoped_nsobject<ExtensionActionContextMenu> menu_;
+  base::scoped_nsobject<ExtensionActionContextMenu> menu_;
 
   // This is used for post-install visual feedback. The page_action
   // icon is briefly shown even if it hasn't been enabled by its
diff --git a/chrome/browser/ui/cocoa/location_bar/plus_decoration.h b/chrome/browser/ui/cocoa/location_bar/plus_decoration.h
index e318c70..64bcf70 100644
--- a/chrome/browser/ui/cocoa/location_bar/plus_decoration.h
+++ b/chrome/browser/ui/cocoa/location_bar/plus_decoration.h
@@ -7,7 +7,7 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "chrome/browser/ui/cocoa/location_bar/button_decoration.h"
 #include "chrome/browser/ui/toolbar/action_box_button_controller.h"
 
@@ -54,7 +54,7 @@
 
   void SetIcons(int normal_id, int hover_id, int pressed_id);
 
-  scoped_nsobject<ActionBoxMenuBubbleController> menu_controller_;
+  base::scoped_nsobject<ActionBoxMenuBubbleController> menu_controller_;
 
   DISALLOW_COPY_AND_ASSIGN(PlusDecoration);
 };
diff --git a/chrome/browser/ui/cocoa/location_bar/selected_keyword_decoration.h b/chrome/browser/ui/cocoa/location_bar/selected_keyword_decoration.h
index bdd9e6f..000245c 100644
--- a/chrome/browser/ui/cocoa/location_bar/selected_keyword_decoration.h
+++ b/chrome/browser/ui/cocoa/location_bar/selected_keyword_decoration.h
@@ -33,9 +33,9 @@
   FRIEND_TEST_ALL_PREFIXES(SelectedKeywordDecorationTest,
                            UsesPartialKeywordIfNarrow);
 
-  scoped_nsobject<NSImage> search_image_;
-  scoped_nsobject<NSString> full_string_;
-  scoped_nsobject<NSString> partial_string_;
+  base::scoped_nsobject<NSImage> search_image_;
+  base::scoped_nsobject<NSString> full_string_;
+  base::scoped_nsobject<NSString> partial_string_;
 
   DISALLOW_COPY_AND_ASSIGN(SelectedKeywordDecoration);
 };
diff --git a/chrome/browser/ui/cocoa/location_bar/star_decoration.h b/chrome/browser/ui/cocoa/location_bar/star_decoration.h
index 6ec7d0d..691f52e 100644
--- a/chrome/browser/ui/cocoa/location_bar/star_decoration.h
+++ b/chrome/browser/ui/cocoa/location_bar/star_decoration.h
@@ -38,7 +38,7 @@
   CommandUpdater* command_updater_;  // Weak, owned by Browser.
 
   // The string to show for a tooltip.
-  scoped_nsobject<NSString> tooltip_;
+  base::scoped_nsobject<NSString> tooltip_;
 
   // Whether the star icon is lit.
   bool starred_;
diff --git a/chrome/browser/ui/cocoa/location_bar/zoom_decoration.h b/chrome/browser/ui/cocoa/location_bar/zoom_decoration.h
index 7819a18..ffc1994 100644
--- a/chrome/browser/ui/cocoa/location_bar/zoom_decoration.h
+++ b/chrome/browser/ui/cocoa/location_bar/zoom_decoration.h
@@ -50,7 +50,7 @@
   ZoomBubbleController* bubble_;
 
   // The string to show for a tooltip.
-  scoped_nsobject<NSString> tooltip_;
+  base::scoped_nsobject<NSString> tooltip_;
 
   DISALLOW_COPY_AND_ASSIGN(ZoomDecoration);
 };
diff --git a/chrome/browser/ui/cocoa/login_prompt_cocoa.mm b/chrome/browser/ui/cocoa/login_prompt_cocoa.mm
index fba3c01..dc3b678 100644
--- a/chrome/browser/ui/cocoa/login_prompt_cocoa.mm
+++ b/chrome/browser/ui/cocoa/login_prompt_cocoa.mm
@@ -6,7 +6,7 @@
 
 #include "base/mac/bundle_locations.h"
 #include "base/mac/mac_util.h"
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "base/strings/string16.h"
 #include "base/strings/string_util.h"
 #include "base/strings/sys_string_conversions.h"
@@ -73,7 +73,7 @@
     WebContents* requesting_contents = GetWebContentsForLogin();
     DCHECK(requesting_contents);
 
-    scoped_nsobject<CustomConstrainedWindowSheet> sheet(
+    base::scoped_nsobject<CustomConstrainedWindowSheet> sheet(
         [[CustomConstrainedWindowSheet alloc]
             initWithCustomWindow:[sheet_controller_ window]]);
     constrained_window_.reset(new ConstrainedWindowMac(
@@ -121,7 +121,7 @@
   }
 
   // The Cocoa controller of the GUI.
-  scoped_nsobject<LoginHandlerSheet> sheet_controller_;
+  base::scoped_nsobject<LoginHandlerSheet> sheet_controller_;
 
   scoped_ptr<ConstrainedWindowMac> constrained_window_;
 
diff --git a/chrome/browser/ui/cocoa/menu_button.h b/chrome/browser/ui/cocoa/menu_button.h
index b2de8de..d0ffb58 100644
--- a/chrome/browser/ui/cocoa/menu_button.h
+++ b/chrome/browser/ui/cocoa/menu_button.h
@@ -7,7 +7,7 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #import "chrome/browser/ui/cocoa/toolbar/toolbar_button.h"
 
 // This a button which displays a user-provided menu "attached" below it upon
@@ -24,10 +24,10 @@
 // value is NO so that custom actions can be hooked up in Interface Builder.
 @interface MenuButton : ToolbarButton {
  @private
-  scoped_nsobject<NSMenu> attachedMenu_;
+  base::scoped_nsobject<NSMenu> attachedMenu_;
   BOOL openMenuOnClick_;
   BOOL openMenuOnRightClick_;
-  scoped_nsobject<NSPopUpButtonCell> popUpCell_;
+  base::scoped_nsobject<NSPopUpButtonCell> popUpCell_;
 }
 
 // The menu to display. Note that it should have no (i.e., a blank) title and
diff --git a/chrome/browser/ui/cocoa/menu_button.mm b/chrome/browser/ui/cocoa/menu_button.mm
index 8cc0812..4147a16 100644
--- a/chrome/browser/ui/cocoa/menu_button.mm
+++ b/chrome/browser/ui/cocoa/menu_button.mm
@@ -5,7 +5,6 @@
 #import "chrome/browser/ui/cocoa/menu_button.h"
 
 #include "base/logging.h"
-#include "base/memory/scoped_nsobject.h"
 #import "chrome/browser/ui/cocoa/clickhold_button_cell.h"
 #import "chrome/browser/ui/cocoa/nsview_additions.h"
 
diff --git a/chrome/browser/ui/cocoa/menu_button_unittest.mm b/chrome/browser/ui/cocoa/menu_button_unittest.mm
index 543208f..95b00dc 100644
--- a/chrome/browser/ui/cocoa/menu_button_unittest.mm
+++ b/chrome/browser/ui/cocoa/menu_button_unittest.mm
@@ -2,14 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #import "chrome/browser/ui/cocoa/clickhold_button_cell.h"
 #import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #import "chrome/browser/ui/cocoa/menu_button.h"
 
 @interface MenuButtonTestDelegate : NSObject<NSMenuDelegate> {
  @private
-  scoped_nsobject<NSMenu> menu_;
+  base::scoped_nsobject<NSMenu> menu_;
   BOOL open_;
   BOOL didOpen_;
 }
@@ -60,10 +60,10 @@
  public:
   MenuButtonTest() {
     NSRect frame = NSMakeRect(0, 0, 50, 30);
-    scoped_nsobject<MenuButton> button(
+    base::scoped_nsobject<MenuButton> button(
         [[MenuButton alloc] initWithFrame:frame]);
     button_ = button.get();
-    scoped_nsobject<ClickHoldButtonCell> cell(
+    base::scoped_nsobject<ClickHoldButtonCell> cell(
         [[ClickHoldButtonCell alloc] initTextCell:@"Testing"]);
     [button_ setCell:cell.get()];
     [[test_window() contentView] addSubview:button_];
@@ -102,7 +102,7 @@
 
 // Test assigning a menu, again mostly to ensure nothing leaks or crashes.
 TEST_F(MenuButtonTest, MenuAssign) {
-  scoped_nsobject<NSMenu> menu(CreateMenu());
+  base::scoped_nsobject<NSMenu> menu(CreateMenu());
   ASSERT_TRUE(menu.get());
 
   [button_ setAttachedMenu:menu];
@@ -110,10 +110,10 @@
 }
 
 TEST_F(MenuButtonTest, OpenOnClick) {
-  scoped_nsobject<NSMenu> menu(CreateMenu());
+  base::scoped_nsobject<NSMenu> menu(CreateMenu());
   ASSERT_TRUE(menu.get());
 
-  scoped_nsobject<MenuButtonTestDelegate> delegate(
+  base::scoped_nsobject<MenuButtonTestDelegate> delegate(
       [[MenuButtonTestDelegate alloc] initWithMenu:menu.get()]);
   ASSERT_TRUE(delegate.get());
 
@@ -132,10 +132,10 @@
 }
 
 TEST_F(MenuButtonTest, OpenOnRightClick) {
-  scoped_nsobject<NSMenu> menu(CreateMenu());
+  base::scoped_nsobject<NSMenu> menu(CreateMenu());
   ASSERT_TRUE(menu.get());
 
-  scoped_nsobject<MenuButtonTestDelegate> delegate(
+  base::scoped_nsobject<MenuButtonTestDelegate> delegate(
       [[MenuButtonTestDelegate alloc] initWithMenu:menu.get()]);
   ASSERT_TRUE(delegate.get());
 
@@ -157,10 +157,10 @@
 }
 
 TEST_F(MenuButtonTest, DontOpenOnRightClickWithoutSetRightClick) {
-  scoped_nsobject<NSMenu> menu(CreateMenu());
+  base::scoped_nsobject<NSMenu> menu(CreateMenu());
   ASSERT_TRUE(menu.get());
 
-  scoped_nsobject<MenuButtonTestDelegate> delegate(
+  base::scoped_nsobject<MenuButtonTestDelegate> delegate(
       [[MenuButtonTestDelegate alloc] initWithMenu:menu.get()]);
   ASSERT_TRUE(delegate.get());
 
diff --git a/chrome/browser/ui/cocoa/notifications/balloon_controller.h b/chrome/browser/ui/cocoa/notifications/balloon_controller.h
index c63caed..7c9c00a 100644
--- a/chrome/browser/ui/cocoa/notifications/balloon_controller.h
+++ b/chrome/browser/ui/cocoa/notifications/balloon_controller.h
@@ -7,7 +7,7 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "base/memory/scoped_ptr.h"
 
 class Balloon;
@@ -46,7 +46,7 @@
   // The options menu that appears when "options" is pressed.
   IBOutlet HoverImageButton* optionsButton_;
   scoped_ptr<NotificationOptionsMenuModel> menuModel_;
-  scoped_nsobject<MenuController> menuController_;
+  base::scoped_nsobject<MenuController> menuController_;
 
   // The host for the renderer of the HTML contents.
   scoped_ptr<BalloonViewHost> htmlContents_;
diff --git a/chrome/browser/ui/cocoa/notifications/balloon_controller.mm b/chrome/browser/ui/cocoa/notifications/balloon_controller.mm
index 4ee0669..fb481cd 100644
--- a/chrome/browser/ui/cocoa/notifications/balloon_controller.mm
+++ b/chrome/browser/ui/cocoa/notifications/balloon_controller.mm
@@ -6,7 +6,6 @@
 
 #include "base/mac/bundle_locations.h"
 #include "base/mac/mac_util.h"
-#import "base/memory/scoped_nsobject.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/notifications/balloon.h"
 #include "chrome/browser/notifications/desktop_notification_service.h"
diff --git a/chrome/browser/ui/cocoa/notifications/balloon_controller_unittest.mm b/chrome/browser/ui/cocoa/notifications/balloon_controller_unittest.mm
index 854e39a..8f4f659 100644
--- a/chrome/browser/ui/cocoa/notifications/balloon_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/notifications/balloon_controller_unittest.mm
@@ -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 "base/memory/scoped_nsobject.h"
+#include "base/memory/scoped_ptr.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/notifications/balloon.h"
 #include "chrome/browser/notifications/balloon_collection.h"
@@ -59,8 +59,7 @@
     ChromeRenderViewHostTestHarness::SetUp();
     CocoaTest::BootstrapCocoa();
     profile()->CreateRequestContext();
-    Browser::CreateParams native_params(profile(),
-                                        chrome::HOST_DESKTOP_TYPE_NATIVE);
+    Browser::CreateParams native_params(profile(), chrome::GetActiveDesktop());
     browser_.reset(
         chrome::CreateBrowserWithTestWindowForParams(&native_params));
     collection_.reset(new MockBalloonCollection());
diff --git a/chrome/browser/ui/cocoa/notifications/balloon_view.mm b/chrome/browser/ui/cocoa/notifications/balloon_view.mm
index eeac6fa..b507eab 100644
--- a/chrome/browser/ui/cocoa/notifications/balloon_view.mm
+++ b/chrome/browser/ui/cocoa/notifications/balloon_view.mm
@@ -7,7 +7,6 @@
 #import <Cocoa/Cocoa.h>
 
 #include "base/basictypes.h"
-#include "base/memory/scoped_nsobject.h"
 #import "chrome/browser/ui/cocoa/notifications/balloon_controller.h"
 #import "third_party/GTM/AppKit/GTMNSBezierPath+RoundRect.h"
 
diff --git a/chrome/browser/ui/cocoa/notifications/message_center_tray_bridge.h b/chrome/browser/ui/cocoa/notifications/message_center_tray_bridge.h
index 5a5fa79..d78a910 100644
--- a/chrome/browser/ui/cocoa/notifications/message_center_tray_bridge.h
+++ b/chrome/browser/ui/cocoa/notifications/message_center_tray_bridge.h
@@ -8,7 +8,7 @@
 #import <AppKit/AppKit.h>
 
 #include "base/basictypes.h"
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "ui/message_center/message_center_tray_delegate.h"
@@ -39,6 +39,7 @@
   virtual void UpdatePopups() OVERRIDE;
   virtual bool ShowMessageCenter() OVERRIDE;
   virtual void HideMessageCenter() OVERRIDE;
+  virtual bool ShowNotifierSettings() OVERRIDE;
 
   message_center::MessageCenter* message_center() { return message_center_; }
 
@@ -58,13 +59,13 @@
   scoped_ptr<message_center::MessageCenterTray> tray_;
 
   // Obj-C window controller for the notification tray.
-  scoped_nsobject<MCTrayController> tray_controller_;
+  base::scoped_nsobject<MCTrayController> tray_controller_;
 
   // View that is displayed on the system menu bar item.
-  scoped_nsobject<MCStatusItemView> status_item_view_;
+  base::scoped_nsobject<MCStatusItemView> status_item_view_;
 
   // Obj-C controller for the on-screen popup notifications.
-  scoped_nsobject<MCPopupCollection> popup_collection_;
+  base::scoped_nsobject<MCPopupCollection> popup_collection_;
 
   // Weak pointer factory to posts tasks to self.
   base::WeakPtrFactory<MessageCenterTrayBridge> weak_ptr_factory_;
diff --git a/chrome/browser/ui/cocoa/notifications/message_center_tray_bridge.mm b/chrome/browser/ui/cocoa/notifications/message_center_tray_bridge.mm
index aced76a..adca08e 100644
--- a/chrome/browser/ui/cocoa/notifications/message_center_tray_bridge.mm
+++ b/chrome/browser/ui/cocoa/notifications/message_center_tray_bridge.mm
@@ -83,6 +83,12 @@
   tray_controller_.autorelease();
 }
 
+bool MessageCenterTrayBridge::ShowNotifierSettings() {
+  // This method needs to be implemented when the context menu of each
+  // notification is ready and it contains 'settings' menu item.
+  return false;
+}
+
 void MessageCenterTrayBridge::UpdateStatusItem() {
   // Only show the status item if there are notifications.
   if (message_center_->NotificationCount() == 0) {
diff --git a/chrome/browser/ui/cocoa/notifications/message_center_tray_bridge_unittest.mm b/chrome/browser/ui/cocoa/notifications/message_center_tray_bridge_unittest.mm
index 7fadb8a..24b6cb7 100644
--- a/chrome/browser/ui/cocoa/notifications/message_center_tray_bridge_unittest.mm
+++ b/chrome/browser/ui/cocoa/notifications/message_center_tray_bridge_unittest.mm
@@ -4,14 +4,14 @@
 
 #import "chrome/browser/ui/cocoa/notifications/message_center_tray_bridge.h"
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/memory/scoped_ptr.h"
 #include "base/message_loop.h"
 #include "base/run_loop.h"
-#include "base/utf_string_conversions.h"
+#include "base/strings/utf_string_conversions.h"
+#import "ui/base/test/ui_cocoa_test_helper.h"
 #import "ui/message_center/cocoa/status_item_view.h"
 #include "ui/message_center/message_center.h"
 #include "ui/message_center/notification.h"
-#import "ui/base/test/ui_cocoa_test_helper.h"
 
 class MessageCenterTrayBridgeTest : public ui::CocoaTest {
  public:
diff --git a/chrome/browser/ui/cocoa/nsmenuitem_additions_unittest.mm b/chrome/browser/ui/cocoa/nsmenuitem_additions_unittest.mm
index 90185bb..33ed98c 100644
--- a/chrome/browser/ui/cocoa/nsmenuitem_additions_unittest.mm
+++ b/chrome/browser/ui/cocoa/nsmenuitem_additions_unittest.mm
@@ -8,7 +8,7 @@
 
 #include <ostream>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "base/strings/sys_string_conversions.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -56,7 +56,7 @@
   // key equivalent, even though the original event would) and isn't a good
   // oracle function.
   if (compareCocoa) {
-    scoped_nsobject<NSMenu> menu([[NSMenu alloc] initWithTitle:@"Menu!"]);
+    base::scoped_nsobject<NSMenu> menu([[NSMenu alloc] initWithTitle:@"Menu!"]);
     [menu setAutoenablesItems:NO];
     EXPECT_FALSE([menu performKeyEquivalent:key]);
     [menu addItem:item];
diff --git a/chrome/browser/ui/cocoa/nsview_additions.h b/chrome/browser/ui/cocoa/nsview_additions.h
index ac52646..0ef8854 100644
--- a/chrome/browser/ui/cocoa/nsview_additions.h
+++ b/chrome/browser/ui/cocoa/nsview_additions.h
@@ -29,6 +29,9 @@
 // Return best color for keyboard focus ring.
 - (NSColor*)cr_keyboardFocusIndicatorColor;
 
+// Set needsDisplay for this view and all descendants.
+- (void)cr_recursivelySetNeedsDisplay:(BOOL)flag;
+
 @end
 
 #endif  // CHROME_BROWSER_UI_COCOA_NSVIEW_ADDITIONS_H_
diff --git a/chrome/browser/ui/cocoa/nsview_additions.mm b/chrome/browser/ui/cocoa/nsview_additions.mm
index 507f77b..00f36ab 100644
--- a/chrome/browser/ui/cocoa/nsview_additions.mm
+++ b/chrome/browser/ui/cocoa/nsview_additions.mm
@@ -67,4 +67,10 @@
       colorWithAlphaComponent:0.5 / [self cr_lineWidth]];
 }
 
+- (void)cr_recursivelySetNeedsDisplay:(BOOL)flag {
+  [self setNeedsDisplay:YES];
+  for (NSView* child in [self subviews])
+    [child cr_recursivelySetNeedsDisplay:flag];
+}
+
 @end
diff --git a/chrome/browser/ui/cocoa/nsview_additions_unittest.mm b/chrome/browser/ui/cocoa/nsview_additions_unittest.mm
index ffb7e0f..a9b7468 100644
--- a/chrome/browser/ui/cocoa/nsview_additions_unittest.mm
+++ b/chrome/browser/ui/cocoa/nsview_additions_unittest.mm
@@ -4,7 +4,7 @@
 
 #import "chrome/browser/ui/cocoa/nsview_additions.h"
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #import "testing/gtest_mac.h"
@@ -38,9 +38,12 @@
 @end
 
 TEST_F(NSViewChromeAdditionsTest, BelowAboveView) {
-  scoped_nsobject<NSView> parent([[NSView alloc] initWithFrame:NSZeroRect]);
-  scoped_nsobject<NSView> child1([[NSView alloc] initWithFrame:NSZeroRect]);
-  scoped_nsobject<NSView> child2([[NSView alloc] initWithFrame:NSZeroRect]);
+  base::scoped_nsobject<NSView> parent(
+      [[NSView alloc] initWithFrame:NSZeroRect]);
+  base::scoped_nsobject<NSView> child1(
+      [[NSView alloc] initWithFrame:NSZeroRect]);
+  base::scoped_nsobject<NSView> child2(
+      [[NSView alloc] initWithFrame:NSZeroRect]);
 
   [parent addSubview:child1];
   [parent addSubview:child2];
@@ -60,9 +63,12 @@
 }
 
 TEST_F(NSViewChromeAdditionsTest, EnsurePosition) {
-  scoped_nsobject<NSView> parent([[NSView alloc] initWithFrame:NSZeroRect]);
-  scoped_nsobject<NSView> child1([[NSView alloc] initWithFrame:NSZeroRect]);
-  scoped_nsobject<NSView> child2([[NSView alloc] initWithFrame:NSZeroRect]);
+  base::scoped_nsobject<NSView> parent(
+      [[NSView alloc] initWithFrame:NSZeroRect]);
+  base::scoped_nsobject<NSView> child1(
+      [[NSView alloc] initWithFrame:NSZeroRect]);
+  base::scoped_nsobject<NSView> child2(
+      [[NSView alloc] initWithFrame:NSZeroRect]);
 
   [parent addSubview:child1];
   [parent cr_ensureSubview:child2
@@ -81,10 +87,12 @@
 
 // Verify that no view is removed or added when no change is needed.
 TEST_F(NSViewChromeAdditionsTest, EnsurePositionNoChange) {
-  scoped_nsobject<ParentView> parent(
+  base::scoped_nsobject<ParentView> parent(
       [[ParentView alloc] initWithFrame:NSZeroRect]);
-  scoped_nsobject<NSView> child1([[NSView alloc] initWithFrame:NSZeroRect]);
-  scoped_nsobject<NSView> child2([[NSView alloc] initWithFrame:NSZeroRect]);
+  base::scoped_nsobject<NSView> child1(
+      [[NSView alloc] initWithFrame:NSZeroRect]);
+  base::scoped_nsobject<NSView> child2(
+      [[NSView alloc] initWithFrame:NSZeroRect]);
   [parent addSubview:child1];
   [parent addSubview:child2];
 
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.h b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.h
new file mode 100644
index 0000000..829441b
--- /dev/null
+++ b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.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 CHROME_BROWSER_UI_COCOA_OMNIBOX_OMNIBOX_POPUP_CELL_H_
+#define CHROME_BROWSER_UI_COCOA_OMNIBOX_OMNIBOX_POPUP_CELL_H_
+
+#import <Cocoa/Cocoa.h>
+
+// OmniboxPopupCell overrides how backgrounds are displayed to
+// handle hover versus selected.  So long as we're in there, it also
+// provides some default initialization.
+@interface OmniboxPopupCell : NSButtonCell {
+}
+
+@end
+
+#endif  // CHROME_BROWSER_UI_COCOA_OMNIBOX_OMNIBOX_POPUP_CELL_H_
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.mm b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.mm
new file mode 100644
index 0000000..db647f8
--- /dev/null
+++ b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.mm
@@ -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.
+
+#import "chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.h"
+
+#include <cmath>
+
+namespace {
+
+// How far to offset image column from the left.
+const CGFloat kImageXOffset = 5.0;
+
+// How far to offset the text column from the left.
+const CGFloat kTextXOffset = 28.0;
+
+// Rounding radius of selection and hover background on popup items.
+const CGFloat kCellRoundingRadius = 2.0;
+
+NSColor* SelectedBackgroundColor() {
+  return [NSColor selectedControlColor];
+}
+NSColor* HoveredBackgroundColor() {
+  return [NSColor controlHighlightColor];
+}
+
+}  // namespace
+
+@implementation OmniboxPopupCell
+
+- (id)init {
+  self = [super init];
+  if (self) {
+    [self setImagePosition:NSImageLeft];
+    [self setBordered:NO];
+    [self setButtonType:NSRadioButton];
+
+    // Without this highlighting messes up white areas of images.
+    [self setHighlightsBy:NSNoCellMask];
+  }
+  return self;
+}
+
+// The default NSButtonCell drawing leaves the image flush left and
+// the title next to the image.  This spaces things out to line up
+// with the star button and autocomplete field.
+- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView *)controlView {
+  if ([self state] == NSOnState || [self isHighlighted]) {
+    if ([self state] == NSOnState)
+      [SelectedBackgroundColor() set];
+    else
+      [HoveredBackgroundColor() set];
+    NSBezierPath* path =
+        [NSBezierPath bezierPathWithRoundedRect:cellFrame
+                                        xRadius:kCellRoundingRadius
+                                        yRadius:kCellRoundingRadius];
+    [path fill];
+  }
+
+  // Put the image centered vertically but in a fixed column.
+  NSImage* image = [self image];
+  if (image) {
+    NSRect imageRect = cellFrame;
+    imageRect.size = [image size];
+    imageRect.origin.y +=
+        std::floor((NSHeight(cellFrame) - NSHeight(imageRect)) / 2.0);
+    imageRect.origin.x += kImageXOffset;
+    [image drawInRect:imageRect
+             fromRect:NSZeroRect  // Entire image
+            operation:NSCompositeSourceOver
+             fraction:1.0
+       respectFlipped:YES
+                hints:nil];
+  }
+
+  // Adjust the title position to be lined up under the field's text.
+  NSAttributedString* title = [self attributedTitle];
+  if (title && [title length]) {
+    NSRect titleRect = cellFrame;
+    titleRect.size.width -= kTextXOffset;
+    titleRect.origin.x += kTextXOffset;
+    [self drawTitle:title withFrame:titleRect inView:controlView];
+  }
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell_unittest.mm b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell_unittest.mm
new file mode 100644
index 0000000..9b08280
--- /dev/null
+++ b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell_unittest.mm
@@ -0,0 +1,47 @@
+// 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.
+
+#import "chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.h"
+
+#include "base/mac/scoped_nsobject.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+
+namespace {
+
+class OmniboxPopupCellTest : public CocoaTest {
+ public:
+  OmniboxPopupCellTest() {
+  }
+
+  virtual void SetUp() OVERRIDE {
+    CocoaTest::SetUp();
+    cell_.reset([[OmniboxPopupCell alloc] initTextCell:@""]);
+    button_.reset([[NSButton alloc] initWithFrame:NSMakeRect(0, 0, 200, 20)]);
+    [button_ setCell:cell_];
+    [[test_window() contentView] addSubview:button_];
+  };
+
+ protected:
+  base::scoped_nsobject<OmniboxPopupCell> cell_;
+  base::scoped_nsobject<NSButton> button_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(OmniboxPopupCellTest);
+};
+
+TEST_VIEW(OmniboxPopupCellTest, button_);
+
+TEST_F(OmniboxPopupCellTest, Image) {
+  [cell_ setImage:[NSImage imageNamed:NSImageNameInfo]];
+  [button_ display];
+}
+
+TEST_F(OmniboxPopupCellTest, Title) {
+  base::scoped_nsobject<NSAttributedString> text([[NSAttributedString alloc]
+      initWithString:@"The quick brown fox jumps over the lazy dog."]);
+  [cell_ setAttributedTitle:text];
+  [button_ display];
+}
+
+}  // namespace
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_matrix.h b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_matrix.h
new file mode 100644
index 0000000..2ce6167
--- /dev/null
+++ b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_matrix.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_UI_COCOA_OMNIBOX_OMNIBOX_POPUP_MATRIX_H_
+#define CHROME_BROWSER_UI_COCOA_OMNIBOX_OMNIBOX_POPUP_MATRIX_H_
+
+#import <Cocoa/Cocoa.h>
+
+#import "ui/base/cocoa/tracking_area.h"
+#include "ui/base/window_open_disposition.h"
+
+@class OmniboxPopupMatrix;
+
+class OmniboxPopupMatrixDelegate {
+ public:
+  // Called when the selection in the matrix changes.
+  virtual void OnMatrixRowSelected(OmniboxPopupMatrix* matrix, size_t row) = 0;
+
+  // Called when the user clicks on a row.
+  virtual void OnMatrixRowClicked(OmniboxPopupMatrix* matrix, size_t row) = 0;
+
+  // Called when the user middle clicks on a row.
+  virtual void OnMatrixRowMiddleClicked(OmniboxPopupMatrix* matrix,
+                                        size_t row) = 0;
+};
+
+// Sets up a tracking area to implement hover by highlighting the cell the mouse
+// is over.
+@interface OmniboxPopupMatrix : NSMatrix {
+  OmniboxPopupMatrixDelegate* delegate_;  // weak
+  ui::ScopedCrTrackingArea trackingArea_;
+}
+
+// Create a zero-size matrix.
+- (id)initWithDelegate:(OmniboxPopupMatrixDelegate*)delegate;
+
+// Sets the delegate.
+- (void)setDelegate:(OmniboxPopupMatrixDelegate*)delegate;
+
+// Return the currently highlighted row.  Returns -1 if no row is highlighted.
+- (NSInteger)highlightedRow;
+
+@end
+
+#endif  // CHROME_BROWSER_UI_COCOA_OMNIBOX_OMNIBOX_POPUP_MATRIX_H_
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_matrix.mm b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_matrix.mm
new file mode 100644
index 0000000..6bddf63
--- /dev/null
+++ b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_matrix.mm
@@ -0,0 +1,192 @@
+// 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 "chrome/browser/ui/cocoa/omnibox/omnibox_popup_matrix.h"
+
+#include "base/logging.h"
+#import "chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.h"
+
+namespace {
+
+// NSEvent -buttonNumber for middle mouse button.
+const NSInteger kMiddleButtonNumber = 2;
+
+}  // namespace
+
+@interface OmniboxPopupMatrix()
+- (void)resetTrackingArea;
+- (void)highlightRowAt:(NSInteger)rowIndex;
+- (void)highlightRowUnder:(NSEvent*)theEvent;
+- (BOOL)selectCellForEvent:(NSEvent*)theEvent;
+@end
+
+@implementation OmniboxPopupMatrix
+
+- (id)initWithDelegate:(OmniboxPopupMatrixDelegate*)delegate {
+  if ((self = [super initWithFrame:NSZeroRect])) {
+    delegate_ = delegate;
+    [self setCellClass:[OmniboxPopupCell class]];
+
+    // Cells pack with no spacing.
+    [self setIntercellSpacing:NSMakeSize(0.0, 0.0)];
+
+    [self setDrawsBackground:YES];
+    [self setBackgroundColor:[NSColor controlBackgroundColor]];
+    [self renewRows:0 columns:1];
+    [self setAllowsEmptySelection:YES];
+    [self setMode:NSRadioModeMatrix];
+    [self deselectAllCells];
+
+    [self resetTrackingArea];
+  }
+  return self;
+}
+
+- (void)setDelegate:(OmniboxPopupMatrixDelegate*)delegate {
+  delegate_ = delegate;
+}
+
+- (NSInteger)highlightedRow {
+  NSArray* cells = [self cells];
+  const NSUInteger count = [cells count];
+  for(NSUInteger i = 0; i < count; ++i) {
+    if ([[cells objectAtIndex:i] isHighlighted]) {
+      return i;
+    }
+  }
+  return -1;
+}
+
+- (void)updateTrackingAreas {
+  [self resetTrackingArea];
+  [super updateTrackingAreas];
+}
+
+// Callbacks from tracking area.
+- (void)mouseEntered:(NSEvent*)theEvent {
+  [self highlightRowUnder:theEvent];
+}
+
+- (void)mouseMoved:(NSEvent*)theEvent {
+  [self highlightRowUnder:theEvent];
+}
+
+- (void)mouseExited:(NSEvent*)theEvent {
+  [self highlightRowAt:-1];
+}
+
+// The tracking area events aren't forwarded during a drag, so handle
+// highlighting manually for middle-click and middle-drag.
+- (void)otherMouseDown:(NSEvent*)theEvent {
+  if ([theEvent buttonNumber] == kMiddleButtonNumber) {
+    [self highlightRowUnder:theEvent];
+  }
+  [super otherMouseDown:theEvent];
+}
+
+- (void)otherMouseDragged:(NSEvent*)theEvent {
+  if ([theEvent buttonNumber] == kMiddleButtonNumber) {
+    [self highlightRowUnder:theEvent];
+  }
+  [super otherMouseDragged:theEvent];
+}
+
+- (void)otherMouseUp:(NSEvent*)theEvent {
+  // Only intercept middle button.
+  if ([theEvent buttonNumber] != kMiddleButtonNumber) {
+    [super otherMouseUp:theEvent];
+    return;
+  }
+
+  // -otherMouseDragged: should always have been called at this location, but
+  // make sure the user is getting the right feedback.
+  [self highlightRowUnder:theEvent];
+
+  const NSInteger highlightedRow = [self highlightedRow];
+  if (highlightedRow != -1) {
+    DCHECK(delegate_);
+    delegate_->OnMatrixRowMiddleClicked(self, highlightedRow);
+  }
+}
+
+// Track the mouse until released, keeping the cell under the mouse selected.
+// If the mouse wanders off-view, revert to the originally-selected cell. If
+// the mouse is released over a cell, call the delegate to open the row's URL.
+- (void)mouseDown:(NSEvent*)theEvent {
+  NSCell* selectedCell = [self selectedCell];
+
+  // Clear any existing highlight.
+  [self highlightRowAt:-1];
+
+  do {
+    if (![self selectCellForEvent:theEvent]) {
+      [self selectCell:selectedCell];
+    }
+
+    const NSUInteger mask = NSLeftMouseUpMask | NSLeftMouseDraggedMask;
+    theEvent = [[self window] nextEventMatchingMask:mask];
+  } while ([theEvent type] == NSLeftMouseDragged);
+
+  // Do not message the delegate if released outside view.
+  if (![self selectCellForEvent:theEvent]) {
+    [self selectCell:selectedCell];
+  } else {
+    const NSInteger selectedRow = [self selectedRow];
+    DCHECK_GE(selectedRow, 0);
+
+    DCHECK(delegate_);
+    delegate_->OnMatrixRowClicked(self, selectedRow);
+  }
+}
+
+- (void)resetTrackingArea {
+  if (trackingArea_.get())
+    [self removeTrackingArea:trackingArea_.get()];
+
+  trackingArea_.reset([[CrTrackingArea alloc]
+      initWithRect:[self frame]
+           options:NSTrackingMouseEnteredAndExited |
+                   NSTrackingMouseMoved |
+                   NSTrackingActiveInActiveApp |
+                   NSTrackingInVisibleRect
+             owner:self
+          userInfo:nil]);
+  [self addTrackingArea:trackingArea_.get()];
+}
+
+- (void)highlightRowAt:(NSInteger)rowIndex {
+  // highlightCell will be nil if rowIndex is out of range, so no cell will be
+  // highlighted.
+  NSCell* highlightCell = [self cellAtRow:rowIndex column:0];
+
+  for (NSCell* cell in [self cells]) {
+    [cell setHighlighted:(cell == highlightCell)];
+  }
+}
+
+- (void)highlightRowUnder:(NSEvent*)theEvent {
+  NSPoint point = [self convertPoint:[theEvent locationInWindow] fromView:nil];
+  NSInteger row, column;
+  if ([self getRow:&row column:&column forPoint:point]) {
+    [self highlightRowAt:row];
+  } else {
+    [self highlightRowAt:-1];
+  }
+}
+
+// Select cell under |theEvent|, returning YES if a selection is made.
+- (BOOL)selectCellForEvent:(NSEvent*)theEvent {
+  NSPoint point = [self convertPoint:[theEvent locationInWindow] fromView:nil];
+
+  NSInteger row, column;
+  if ([self getRow:&row column:&column forPoint:point]) {
+    DCHECK_EQ(column, 0);
+    DCHECK(delegate_);
+    delegate_->OnMatrixRowSelected(self, row);
+    return YES;
+  }
+  return NO;
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_matrix_unittest.mm b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_matrix_unittest.mm
new file mode 100644
index 0000000..54d1e47
--- /dev/null
+++ b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_matrix_unittest.mm
@@ -0,0 +1,87 @@
+// 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.
+
+#import "chrome/browser/ui/cocoa/omnibox/omnibox_popup_matrix.h"
+
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "ui/base/test/cocoa_test_event_utils.h"
+
+namespace {
+
+NSEvent* MouseEventInRow(NSMatrix* matrix, NSEventType type, NSInteger row) {
+  NSRect cell_rect = [matrix cellFrameAtRow:row column:0];
+  NSPoint point_in_view = NSMakePoint(NSMidX(cell_rect), NSMidY(cell_rect));
+  NSPoint point_in_window = [matrix convertPoint:point_in_view toView:nil];
+  return cocoa_test_event_utils::MouseEventAtPoint(
+      point_in_window, type, 0);
+}
+
+class OmniboxPopupMatrixTest : public CocoaTest,
+                               public OmniboxPopupMatrixDelegate {
+ public:
+  OmniboxPopupMatrixTest()
+      : selected_row_(0),
+        clicked_row_(0),
+        middle_clicked_row_(0) {
+  }
+
+  virtual void SetUp() OVERRIDE {
+    CocoaTest::SetUp();
+    matrix_.reset([[OmniboxPopupMatrix alloc] initWithDelegate:this]);
+    [[test_window() contentView] addSubview:matrix_];
+  };
+
+  virtual void OnMatrixRowSelected(OmniboxPopupMatrix* matrix,
+                                   size_t row) OVERRIDE {
+    selected_row_ = row;
+    [matrix_ selectCellAtRow:row column:0];
+  }
+
+  virtual void OnMatrixRowClicked(OmniboxPopupMatrix* matrix,
+                                size_t row) OVERRIDE {
+    clicked_row_ = row;
+  }
+
+  virtual void OnMatrixRowMiddleClicked(OmniboxPopupMatrix* matrix,
+                                        size_t row) OVERRIDE {
+    middle_clicked_row_ = row;
+  }
+
+ protected:
+  base::scoped_nsobject<OmniboxPopupMatrix> matrix_;
+  size_t selected_row_;
+  size_t clicked_row_;
+  size_t middle_clicked_row_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(OmniboxPopupMatrixTest);
+};
+
+TEST_VIEW(OmniboxPopupMatrixTest, matrix_);
+
+TEST_F(OmniboxPopupMatrixTest, HighlightedRow) {
+  [matrix_ renewRows:3 columns:1];
+  EXPECT_EQ(-1, [matrix_ highlightedRow]);
+
+  [matrix_ mouseEntered:MouseEventInRow(matrix_, NSMouseMoved, 0)];
+  EXPECT_EQ(0, [matrix_ highlightedRow]);
+  [matrix_ mouseEntered:MouseEventInRow(matrix_, NSMouseMoved, 2)];
+  EXPECT_EQ(2, [matrix_ highlightedRow]);
+
+  [matrix_ mouseExited:MouseEventInRow(matrix_, NSMouseMoved, 2)];
+  EXPECT_EQ(-1, [matrix_ highlightedRow]);
+}
+
+TEST_F(OmniboxPopupMatrixTest, SelectedRow) {
+  [matrix_ renewRows:3 columns:1];
+
+  [NSApp postEvent:MouseEventInRow(matrix_, NSLeftMouseUp, 2) atStart:YES];
+  [matrix_ mouseDown:MouseEventInRow(matrix_, NSLeftMouseDown, 2)];
+
+  EXPECT_EQ(2u, selected_row_);
+  EXPECT_EQ(2u, clicked_row_);
+  EXPECT_EQ(0u, middle_clicked_row_);
+}
+
+}  // namespace
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_separator_view.h b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_separator_view.h
new file mode 100644
index 0000000..ae2355a
--- /dev/null
+++ b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_separator_view.h
@@ -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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_OMNIBOX_OMNIBOX_POPUP_SEPARATOR_VIEW_H_
+#define CHROME_BROWSER_UI_COCOA_OMNIBOX_OMNIBOX_POPUP_SEPARATOR_VIEW_H_
+
+#import <Cocoa/Cocoa.h>
+
+#include "chrome/browser/ui/cocoa/background_gradient_view.h"
+
+// A view used to draw a separator above omnibox popup.
+@interface OmniboxPopupTopSeparatorView : BackgroundGradientView {
+}
+
++ (CGFloat)preferredHeight;
+
+@end
+
+// A view used to draw a drop shadow beneath the omnibox popup.
+@interface OmniboxPopupBottomSeparatorView : NSView {
+}
+
++ (CGFloat)preferredHeight;
+
+@end
+
+#endif  // CHROME_BROWSER_UI_COCOA_OMNIBOX_OMNIBOX_POPUP_SEPARATOR_VIEW_H_
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_separator_view.mm b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_separator_view.mm
new file mode 100644
index 0000000..1e43cea
--- /dev/null
+++ b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_separator_view.mm
@@ -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.
+
+#import "chrome/browser/ui/cocoa/omnibox/omnibox_popup_separator_view.h"
+
+#import "chrome/browser/ui/cocoa/nsview_additions.h"
+#include "grit/theme_resources.h"
+#include "ui/base/resource/resource_bundle.h"
+
+@implementation OmniboxPopupTopSeparatorView
+
++ (CGFloat)preferredHeight {
+  return 1;
+}
+
+- (void)drawRect:(NSRect)rect {
+  NSRect separatorRect = [self bounds];
+  separatorRect.size.height = [self cr_lineWidth];
+  [[self strokeColor] set];
+  NSRectFillUsingOperation(separatorRect, NSCompositeSourceOver);
+}
+
+@end
+
+@implementation OmniboxPopupBottomSeparatorView
+
++ (CGFloat)preferredHeight {
+  ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+  NSImage* shadowImage =
+      rb.GetNativeImageNamed(IDR_OVERLAY_DROP_SHADOW).ToNSImage();
+  return [shadowImage size].height;
+}
+
+- (void)drawRect:(NSRect)rect {
+  ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+  NSRect bounds = [self bounds];
+
+  // Draw the shadow.
+  NSImage* shadowImage =
+      rb.GetNativeImageNamed(IDR_OVERLAY_DROP_SHADOW).ToNSImage();
+  [shadowImage drawInRect:bounds
+                 fromRect:NSZeroRect
+                operation:NSCompositeSourceOver
+                 fraction:1.0];
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_separator_view_unittest.mm b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_separator_view_unittest.mm
new file mode 100644
index 0000000..85149a3
--- /dev/null
+++ b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_separator_view_unittest.mm
@@ -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.
+
+#import "chrome/browser/ui/cocoa/omnibox/omnibox_popup_separator_view.h"
+
+#include "base/mac/scoped_nsobject.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+
+class OmniboxPopupBottomSeparatorViewTest : public CocoaTest {
+ public:
+  OmniboxPopupBottomSeparatorViewTest() {
+    NSView* contentView = [test_window() contentView];
+    bottom_view_.reset([[OmniboxPopupBottomSeparatorView alloc]
+        initWithFrame:[contentView bounds]]);
+    [contentView addSubview:bottom_view_];
+  }
+
+ protected:
+  base::scoped_nsobject<OmniboxPopupBottomSeparatorView> bottom_view_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(OmniboxPopupBottomSeparatorViewTest);
+};
+
+TEST_VIEW(OmniboxPopupBottomSeparatorViewTest, bottom_view_);
+
+TEST_F(OmniboxPopupBottomSeparatorViewTest, PreferredHeight) {
+  EXPECT_LT(0, [OmniboxPopupBottomSeparatorView preferredHeight]);
+}
+
+class OmniboxPopupTopSeparatorViewTest : public CocoaTest {
+ public:
+  OmniboxPopupTopSeparatorViewTest() {
+    NSView* contentView = [test_window() contentView];
+    top_view_.reset([[OmniboxPopupTopSeparatorView alloc]
+        initWithFrame:[contentView bounds]]);
+    [contentView addSubview:top_view_];
+  }
+
+ protected:
+  base::scoped_nsobject<OmniboxPopupTopSeparatorView> top_view_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(OmniboxPopupTopSeparatorViewTest);
+};
+
+TEST_VIEW(OmniboxPopupTopSeparatorViewTest, top_view_);
+
+TEST_F(OmniboxPopupTopSeparatorViewTest, PreferredHeight) {
+  EXPECT_LT(0, [OmniboxPopupTopSeparatorView preferredHeight]);
+}
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac.h b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac.h
index 629d572..da3b545 100644
--- a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac.h
+++ b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac.h
@@ -8,29 +8,23 @@
 #import <Cocoa/Cocoa.h>
 
 #include "base/basictypes.h"
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "base/memory/scoped_ptr.h"
 #include "chrome/browser/autocomplete/autocomplete_match.h"
+#import "chrome/browser/ui/cocoa/omnibox/omnibox_popup_matrix.h"
 #include "chrome/browser/ui/omnibox/omnibox_popup_view.h"
 #include "ui/gfx/font.h"
 
-@class AutocompleteMatrix;
+class AutocompleteResult;
 class OmniboxEditModel;
 class OmniboxPopupModel;
 class OmniboxView;
 
 // Implements OmniboxPopupView using a raw NSWindow containing an
 // NSTableView.
-//
-// TODO(rohitrao): This class is set up in a way that makes testing hard.
-// Refactor and write unittests.  http://crbug.com/9977
-
-class OmniboxPopupViewMac : public OmniboxPopupView {
+class OmniboxPopupViewMac : public OmniboxPopupView,
+                            public OmniboxPopupMatrixDelegate {
  public:
-  static OmniboxPopupView* Create(OmniboxView* omnibox_view,
-                                  OmniboxEditModel* edit_model,
-                                  NSTextField* field);
-
   OmniboxPopupViewMac(OmniboxView* omnibox_view,
                       OmniboxEditModel* edit_model,
                       NSTextField* field);
@@ -38,71 +32,56 @@
 
   // Overridden from OmniboxPopupView:
   virtual bool IsOpen() const OVERRIDE;
-  virtual void InvalidateLine(size_t line) OVERRIDE {
-    // TODO(shess): Verify that there is no need to implement this.
-    // This is currently used in two places in the model:
-    //
-    // When setting the selected line, the selected line is
-    // invalidated, then the selected line is changed, then the new
-    // selected line is invalidated, then PaintUpdatesNow() is called.
-    // For us PaintUpdatesNow() should be sufficient.
-    //
-    // Same thing happens when changing the hovered line, except with
-    // no call to PaintUpdatesNow().  Since this code does not
-    // currently support special display of the hovered line, there's
-    // nothing to do here.
-    //
-    // deanm indicates that this is an anti-flicker optimization,
-    // which we probably cannot utilize (and may not need) so long as
-    // we're using NSTableView to implement the popup contents.  We
-    // may need to move away from NSTableView to implement hover,
-    // though.
-  }
+  virtual void InvalidateLine(size_t line) OVERRIDE {}
   virtual void UpdatePopupAppearance() OVERRIDE;
-
   virtual gfx::Rect GetTargetBounds() OVERRIDE;
-
-  // Set |line| to be selected.
-  void SetSelectedLine(size_t line);
-
   // This is only called by model in SetSelectedLine() after updating
   // everything.  Popup should already be visible.
   virtual void PaintUpdatesNow() OVERRIDE;
-
   virtual void OnDragCanceled() OVERRIDE {}
 
-  // Opens the URL corresponding to the given |row|.  If |force_background| is
-  // true, forces the URL to open in a background tab.  Otherwise, determines
-  // the proper window open disposition from the modifier flags on |[NSApp
-  // currentEvent]|.
-  void OpenURLForRow(int row, bool force_background);
+  // Overridden from OmniboxPopupMatrixDelegate:
+  virtual void OnMatrixRowSelected(OmniboxPopupMatrix* matrix,
+                                   size_t row) OVERRIDE;
+  virtual void OnMatrixRowClicked(OmniboxPopupMatrix* matrix,
+                                  size_t row) OVERRIDE;
+  virtual void OnMatrixRowMiddleClicked(OmniboxPopupMatrix* matrix,
+                                        size_t row) OVERRIDE;
+
+  OmniboxPopupMatrix* matrix() { return matrix_; }
 
   // Return the text to show for the match, based on the match's
   // contents and description.  Result will be in |font|, with the
   // boldfaced version used for matches.
   static NSAttributedString* MatchText(const AutocompleteMatch& match,
                                        gfx::Font& font,
-                                       float cellWidth);
+                                       float cell_width);
 
-  // Helper for MatchText() to allow sharing code between the contents
-  // and description cases.  Returns NSMutableAttributedString as a
-  // convenience for MatchText().
+  // Applies the given font and colors to the match string based on
+  // classifications.
   static NSMutableAttributedString* DecorateMatchedString(
-      const string16 &matchString,
-      const AutocompleteMatch::ACMatchClassifications &classifications,
-      NSColor* textColor, NSColor* dimTextColor, gfx::Font& font);
+      const string16& match_string,
+      const AutocompleteMatch::ACMatchClassifications& classifications,
+      NSColor* text_color,
+      NSColor* dim_text_color,
+      gfx::Font& font);
 
   // Helper for MatchText() to elide a marked-up string using
-  // gfx::ElideText() as a model.  Modifies |aString| in place.
+  // gfx::ElideText() as a model.  Modifies |a_string| in place.
   // TODO(shess): Consider breaking AutocompleteButtonCell out of this
   // code, and modifying it to have something like -setMatch:, so that
   // these convolutions to expose internals for testing can be
   // cleaner.
   static NSMutableAttributedString* ElideString(
-      NSMutableAttributedString* aString,
-      const string16 originalString,
+      NSMutableAttributedString* a_string,
+      const string16& original_string,
       const gfx::Font& font,
-      const float cellWidth);
+      const float cell_width);
+
+ protected:
+  // Gets the autocomplete results. This is virtual so that it can be overriden
+  // by tests.
+  virtual const AutocompleteResult& GetResult() const;
 
  private:
   // Create the popup_ instance if needed.
@@ -119,17 +98,21 @@
   // Returns the NSImage that should be used as an icon for the given match.
   NSImage* ImageForMatch(const AutocompleteMatch& match);
 
-  // TODO(shess): |omnibox_view_| should already be accessible via
-  // |field_|, or perhaps via |model_|.  Consider refactoring.
+  // Opens the URL at the given row.
+  void OpenURLForRow(size_t row, WindowOpenDisposition disposition);
+
   OmniboxView* omnibox_view_;
   scoped_ptr<OmniboxPopupModel> model_;
   NSTextField* field_;  // owned by tab controller
 
   // Child window containing a matrix which implements the popup.
-  scoped_nsobject<NSWindow> popup_;
-  NSRect targetPopupFrame_;
+  base::scoped_nsobject<NSWindow> popup_;
+  NSRect target_popup_frame_;
 
-  scoped_nsobject<AutocompleteMatrix> autocomplete_matrix_;
+  base::scoped_nsobject<OmniboxPopupMatrix> matrix_;
+  base::scoped_nsobject<NSView> top_separator_view_;
+  base::scoped_nsobject<NSView> bottom_separator_view_;
+  base::scoped_nsobject<NSBox> background_view_;
 
   DISALLOW_COPY_AND_ASSIGN(OmniboxPopupViewMac);
 };
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac.mm b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac.mm
index 9ba9aad..4d11860 100644
--- a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac.mm
+++ b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac.mm
@@ -11,6 +11,8 @@
 #include "chrome/browser/autocomplete/autocomplete_match.h"
 #include "chrome/browser/search/search.h"
 #include "chrome/browser/ui/cocoa/browser_window_controller.h"
+#import "chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.h"
+#import "chrome/browser/ui/cocoa/omnibox/omnibox_popup_separator_view.h"
 #include "chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.h"
 #include "chrome/browser/ui/omnibox/omnibox_edit_model.h"
 #include "chrome/browser/ui/omnibox/omnibox_popup_model.h"
@@ -35,9 +37,6 @@
 // Padding between matrix and the top and bottom of the popup window.
 const CGFloat kPopupPaddingVertical = 5.0;
 
-// How far to offset image column from the left.
-const CGFloat kImageXOffset = 5.0;
-
 // How far to offset the text column from the left.
 const CGFloat kTextXOffset = 28.0;
 
@@ -48,22 +47,10 @@
 // contents.
 const CGFloat kMaxContentsFraction = 0.7;
 
-// NSEvent -buttonNumber for middle mouse button.
-const NSInteger kMiddleButtonNumber = 2;
-
-// Rounding radius of selection and hover background on popup items.
-const CGFloat kCellRoundingRadius = 2.0;
-
 // Background colors for different states of the popup elements.
 NSColor* BackgroundColor() {
   return [NSColor controlBackgroundColor];
 }
-NSColor* SelectedBackgroundColor() {
-  return [NSColor selectedControlColor];
-}
-NSColor* HoveredBackgroundColor() {
-  return [NSColor controlHighlightColor];
-}
 
 NSColor* ContentTextColor() {
   return [NSColor blackColor];
@@ -77,111 +64,127 @@
 
 }  // namespace
 
-// Helper for MatchText() to allow sharing code between the contents
-// and description cases.  Returns NSMutableAttributedString as a
-// convenience for MatchText().
-NSMutableAttributedString* OmniboxPopupViewMac::DecorateMatchedString(
-    const string16 &matchString,
-    const AutocompleteMatch::ACMatchClassifications &classifications,
-    NSColor* textColor, NSColor* dimTextColor, gfx::Font& font) {
-  // Cache for on-demand computation of the bold version of |font|.
-  NSFont* boldFont = nil;
-
-  // Start out with a string using the default style info.
-  NSString* s = base::SysUTF16ToNSString(matchString);
-  NSDictionary* attributes = [NSDictionary dictionaryWithObjectsAndKeys:
-                                  font.GetNativeFont(), NSFontAttributeName,
-                                  textColor, NSForegroundColorAttributeName,
-                                  nil];
-  NSMutableAttributedString* as =
-      [[[NSMutableAttributedString alloc] initWithString:s
-                                              attributes:attributes]
-        autorelease];
-
-  // As a protective measure, bail if the length of the match string is not
-  // the same as the length of the converted NSString. http://crbug.com/121703
-  if ([s length] != matchString.size())
-    return as;
-
-  // Mark up the runs which differ from the default.
-  for (ACMatchClassifications::const_iterator i = classifications.begin();
-       i != classifications.end(); ++i) {
-    const BOOL isLast = (i+1) == classifications.end();
-    const NSInteger nextOffset =
-        (isLast ? [s length] : static_cast<NSInteger>((i + 1)->offset));
-    const NSInteger location = static_cast<NSInteger>(i->offset);
-    const NSInteger length = nextOffset - static_cast<NSInteger>(i->offset);
-    // Guard against bad, off-the-end classification ranges.
-    if (i->offset >= [s length] || length <= 0)
-      break;
-    const NSRange range = NSMakeRange(location,
-        MIN(length, static_cast<NSInteger>([s length]) - location));
-
-    if (0 != (i->style & ACMatchClassification::URL)) {
-      [as addAttribute:NSForegroundColorAttributeName
-                 value:URLTextColor() range:range];
-    }
-
-    if (0 != (i->style & ACMatchClassification::MATCH)) {
-      if (!boldFont) {
-        NSFontManager* fontManager = [NSFontManager sharedFontManager];
-        boldFont = [fontManager convertFont:font.GetNativeFont()
-                                toHaveTrait:NSBoldFontMask];
-      }
-      [as addAttribute:NSFontAttributeName value:boldFont range:range];
-    }
-
-    if (0 != (i->style & ACMatchClassification::DIM)) {
-      [as addAttribute:NSForegroundColorAttributeName
-                 value:dimTextColor
-                 range:range];
-    }
-  }
-
-  return as;
+OmniboxPopupViewMac::OmniboxPopupViewMac(OmniboxView* omnibox_view,
+                                         OmniboxEditModel* edit_model,
+                                         NSTextField* field)
+    : omnibox_view_(omnibox_view),
+      model_(new OmniboxPopupModel(this, edit_model)),
+      field_(field),
+      popup_(nil),
+      target_popup_frame_(NSZeroRect) {
+  DCHECK(omnibox_view);
+  DCHECK(edit_model);
 }
 
-NSMutableAttributedString* OmniboxPopupViewMac::ElideString(
-    NSMutableAttributedString* aString,
-    const string16 originalString,
-    const gfx::Font& font,
-    const float width) {
-  // If it already fits, nothing to be done.
-  if ([aString size].width <= width) {
-    return aString;
+OmniboxPopupViewMac::~OmniboxPopupViewMac() {
+  // Destroy the popup model before this object is destroyed, because
+  // it can call back to us in the destructor.
+  model_.reset();
+
+  // Break references to |this| because the popup may not be
+  // deallocated immediately.
+  [matrix_ setDelegate:NULL];
+}
+
+bool OmniboxPopupViewMac::IsOpen() const {
+  return popup_ != nil;
+}
+
+void OmniboxPopupViewMac::UpdatePopupAppearance() {
+  DCHECK([NSThread isMainThread]);
+  const AutocompleteResult& result = GetResult();
+  if (result.empty()) {
+    [[popup_ parentWindow] removeChildWindow:popup_];
+    [popup_ orderOut:nil];
+
+    // Break references to |this| because the popup may not be
+    // deallocated immediately.
+    [matrix_ setDelegate:nil];
+    matrix_.reset();
+
+    popup_.reset(nil);
+
+    target_popup_frame_ = NSZeroRect;
+
+    return;
   }
 
-  // If ElideText() decides to do nothing, nothing to be done.
-  const string16 elided =
-      ui::ElideText(originalString, font, width, ui::ELIDE_AT_END);
-  if (0 == elided.compare(originalString)) {
-    return aString;
+  CreatePopupIfNeeded();
+
+  gfx::Font result_font(OmniboxViewMac::GetFieldFont());
+
+  // Calculate the width of the matrix based on backing out the popup's border
+  // from the width of the field.
+  const CGFloat matrix_width = NSWidth([field_ bounds]);
+  DCHECK_GT(matrix_width, 0.0);
+
+  // Load the results into the popup's matrix.
+  const size_t rows = GetResult().size();
+  DCHECK_GT(rows, 0U);
+  [matrix_ renewRows:rows columns:1];
+  for (size_t ii = 0; ii < rows; ++ii) {
+    OmniboxPopupCell* cell = [matrix_ cellAtRow:ii column:0];
+    const AutocompleteMatch& match = GetResult().match_at(ii);
+    [cell setImage:ImageForMatch(match)];
+    [cell setAttributedTitle:MatchText(match, result_font, matrix_width)];
   }
 
-  // If everything was elided away, clear the string.
-  if (elided.empty()) {
-    [aString deleteCharactersInRange:NSMakeRange(0, [aString length])];
-    return aString;
-  }
+  // Set the cell size to fit a line of text in the cell's font.  All
+  // cells should use the same font and each should layout in one
+  // line, so they should all be about the same height.
+  const NSSize cell_size = [[matrix_ cellAtRow:0 column:0] cellSize];
+  DCHECK_GT(cell_size.height, 0.0);
+  const CGFloat cell_height = cell_size.height + kCellHeightAdjust;
+  [matrix_ setCellSize:NSMakeSize(matrix_width, cell_height)];
 
-  // The ellipses should be the last character, and everything before
-  // that should match the original string.
-  const size_t i(elided.length() - 1);
-  DCHECK_NE(0, elided.compare(0, i, originalString));
+  // Update the selection before placing (and displaying) the window.
+  PaintUpdatesNow();
 
-  // Replace the end of |aString| with the ellipses from |elided|.
-  NSString* s = base::SysUTF16ToNSString(elided.substr(i));
-  [aString replaceCharactersInRange:NSMakeRange(i, [aString length] - i)
-                         withString:s];
+  // Calculate the matrix size manually rather than using -sizeToCells
+  // because actually resizing the matrix messed up the popup size
+  // animation.
+  DCHECK_EQ([matrix_ intercellSpacing].height, 0.0);
+  PositionPopup(rows * cell_height);
+}
 
-  return aString;
+gfx::Rect OmniboxPopupViewMac::GetTargetBounds() {
+  // Flip the coordinate system before returning.
+  NSScreen* screen = [[NSScreen screens] objectAtIndex:0];
+  NSRect monitor_frame = [screen frame];
+  gfx::Rect bounds(NSRectToCGRect(target_popup_frame_));
+  bounds.set_y(monitor_frame.size.height - bounds.y() - bounds.height());
+  return bounds;
+}
+
+// This is only called by model in SetSelectedLine() after updating
+// everything.  Popup should already be visible.
+void OmniboxPopupViewMac::PaintUpdatesNow() {
+  [matrix_ selectCellAtRow:model_->selected_line() column:0];
+}
+
+void OmniboxPopupViewMac::OnMatrixRowSelected(OmniboxPopupMatrix* matrix,
+                                              size_t row) {
+  model_->SetSelectedLine(row, false, false);
+}
+
+void OmniboxPopupViewMac::OnMatrixRowClicked(OmniboxPopupMatrix* matrix,
+                                             size_t row) {
+  OpenURLForRow(row,
+                ui::WindowOpenDispositionFromNSEvent([NSApp currentEvent]));
+}
+
+void OmniboxPopupViewMac::OnMatrixRowMiddleClicked(OmniboxPopupMatrix* matrix,
+                                                   size_t row) {
+  OpenURLForRow(row, NEW_BACKGROUND_TAB);
 }
 
 // Return the text to show for the match, based on the match's
 // contents and description.  Result will be in |font|, with the
 // boldfaced version used for matches.
 NSAttributedString* OmniboxPopupViewMac::MatchText(
-    const AutocompleteMatch& match, gfx::Font& font, float cellWidth) {
+    const AutocompleteMatch& match,
+    gfx::Font& font,
+    float cell_width) {
   NSMutableAttributedString *as =
       DecorateMatchedString(match.contents,
                             match.contents_class,
@@ -197,18 +200,17 @@
     // partially visible.
     // TODO(shess): Consider revising our NSCell subclass to have two
     // bits and just draw them right, rather than truncating here.
-    const float textWidth = cellWidth - kTextXOffset;
+    const float text_width = cell_width - kTextXOffset;
     as = ElideString(as, match.contents, font,
-                     textWidth * kMaxContentsFraction);
+                     text_width * kMaxContentsFraction);
 
-    NSDictionary* attributes =
-        [NSDictionary dictionaryWithObjectsAndKeys:
-             font.GetNativeFont(), NSFontAttributeName,
-             ContentTextColor(), NSForegroundColorAttributeName,
-             nil];
-    NSString* rawEnDash = @" \u2013 ";
-    NSAttributedString* enDash =
-        [[[NSAttributedString alloc] initWithString:rawEnDash
+    NSDictionary* attributes = @{
+        NSFontAttributeName :  font.GetNativeFont(),
+        NSForegroundColorAttributeName : ContentTextColor()
+    };
+    NSString* raw_en_dash = @" \u2013 ";
+    NSAttributedString* en_dash =
+        [[[NSAttributedString alloc] initWithString:raw_en_dash
                                          attributes:attributes] autorelease];
 
     // In Windows, a boolean force_dim is passed as true for the
@@ -220,7 +222,7 @@
                               DimContentTextColor(),
                               font);
 
-    [as appendAttributedString:enDash];
+    [as appendAttributedString:en_dash];
     [as appendAttributedString:description];
   }
 
@@ -234,71 +236,109 @@
   return as;
 }
 
-// AutocompleteButtonCell overrides how backgrounds are displayed to
-// handle hover versus selected.  So long as we're in there, it also
-// provides some default initialization.
-
-@interface AutocompleteButtonCell : NSButtonCell {
-}
-@end
-
-// AutocompleteMatrix sets up a tracking area to implement hover by
-// highlighting the cell the mouse is over.
-
-@interface AutocompleteMatrix : NSMatrix {
- @private
-  // Target for click and middle-click.
-  OmniboxPopupViewMac* popupView_;  // weak, owns us.
-}
-
-// Create a zero-size matrix initializing |popupView_|.
-- (id)initWithPopupView:(OmniboxPopupViewMac*)popupView;
-
-// Set |popupView_|.
-- (void)setPopupView:(OmniboxPopupViewMac*)popupView;
-
-// Return the currently highlighted row.  Returns -1 if no row is
-// highlighted.
-- (NSInteger)highlightedRow;
-
-@end
-
 // static
-OmniboxPopupView* OmniboxPopupViewMac::Create(OmniboxView* omnibox_view,
-                                              OmniboxEditModel* edit_model,
-                                              NSTextField* field) {
-#if defined(HTML_INSTANT_EXTENDED_POPUP)
-  if (chrome::IsInstantExtendedAPIEnabled())
-    return new OmniboxPopupNonView(edit_model);
-#endif
-  return new OmniboxPopupViewMac(omnibox_view, edit_model, field);
+NSMutableAttributedString* OmniboxPopupViewMac::DecorateMatchedString(
+    const string16& match_string,
+    const AutocompleteMatch::ACMatchClassifications& classifications,
+    NSColor* text_color,
+    NSColor* dim_text_color,
+    gfx::Font& font) {
+  // Cache for on-demand computation of the bold version of |font|.
+  NSFont* bold_font = nil;
+
+  // Start out with a string using the default style info.
+  NSString* s = base::SysUTF16ToNSString(match_string);
+  NSDictionary* attributes = @{
+      NSFontAttributeName : font.GetNativeFont(),
+      NSForegroundColorAttributeName : text_color
+  };
+  NSMutableAttributedString* as =
+      [[[NSMutableAttributedString alloc] initWithString:s
+                                              attributes:attributes]
+        autorelease];
+
+  // As a protective measure, bail if the length of the match string is not
+  // the same as the length of the converted NSString. http://crbug.com/121703
+  if ([s length] != match_string.size())
+    return as;
+
+  // Mark up the runs which differ from the default.
+  for (ACMatchClassifications::const_iterator i = classifications.begin();
+       i != classifications.end(); ++i) {
+    const BOOL is_last = (i+1) == classifications.end();
+    const NSInteger next_offset =
+        (is_last ? [s length] : static_cast<NSInteger>((i + 1)->offset));
+    const NSInteger location = static_cast<NSInteger>(i->offset);
+    const NSInteger length = next_offset - static_cast<NSInteger>(i->offset);
+    // Guard against bad, off-the-end classification ranges.
+    if (i->offset >= [s length] || length <= 0)
+      break;
+    const NSRange range = NSMakeRange(location,
+        MIN(length, static_cast<NSInteger>([s length]) - location));
+
+    if (0 != (i->style & ACMatchClassification::URL)) {
+      [as addAttribute:NSForegroundColorAttributeName
+                 value:URLTextColor()
+                 range:range];
+    }
+
+    if (0 != (i->style & ACMatchClassification::MATCH)) {
+      if (!bold_font) {
+        NSFontManager* font_manager = [NSFontManager sharedFontManager];
+        bold_font = [font_manager convertFont:font.GetNativeFont()
+                                  toHaveTrait:NSBoldFontMask];
+      }
+      [as addAttribute:NSFontAttributeName value:bold_font range:range];
+    }
+
+    if (0 != (i->style & ACMatchClassification::DIM)) {
+      [as addAttribute:NSForegroundColorAttributeName
+                 value:dim_text_color
+                 range:range];
+    }
+  }
+
+  return as;
 }
 
+NSMutableAttributedString* OmniboxPopupViewMac::ElideString(
+    NSMutableAttributedString* a_string,
+    const string16& original_string,
+    const gfx::Font& font,
+    const float width) {
+  // If it already fits, nothing to be done.
+  if ([a_string size].width <= width) {
+    return a_string;
+  }
 
-OmniboxPopupViewMac::OmniboxPopupViewMac(OmniboxView* omnibox_view,
-                                         OmniboxEditModel* edit_model,
-                                         NSTextField* field)
-    : omnibox_view_(omnibox_view),
-      model_(new OmniboxPopupModel(this, edit_model)),
-      field_(field),
-      popup_(nil),
-      targetPopupFrame_(NSZeroRect) {
-  DCHECK(omnibox_view);
-  DCHECK(edit_model);
+  // If ElideText() decides to do nothing, nothing to be done.
+  const string16 elided =
+      ui::ElideText(original_string, font, width, ui::ELIDE_AT_END);
+  if (0 == elided.compare(original_string)) {
+    return a_string;
+  }
+
+  // If everything was elided away, clear the string.
+  if (elided.empty()) {
+    [a_string deleteCharactersInRange:NSMakeRange(0, [a_string length])];
+    return a_string;
+  }
+
+  // The ellipses should be the last character, and everything before
+  // that should match the original string.
+  const size_t i(elided.length() - 1);
+  DCHECK_NE(0, elided.compare(0, i, original_string));
+
+  // Replace the end of |aString| with the ellipses from |elided|.
+  NSString* s = base::SysUTF16ToNSString(elided.substr(i));
+  [a_string replaceCharactersInRange:NSMakeRange(i, [a_string length] - i)
+                          withString:s];
+
+  return a_string;
 }
 
-OmniboxPopupViewMac::~OmniboxPopupViewMac() {
-  // Destroy the popup model before this object is destroyed, because
-  // it can call back to us in the destructor.
-  model_.reset();
-
-  // Break references to |this| because the popup may not be
-  // deallocated immediately.
-  [autocomplete_matrix_ setPopupView:NULL];
-}
-
-bool OmniboxPopupViewMac::IsOpen() const {
-  return popup_ != nil;
+const AutocompleteResult& OmniboxPopupViewMac::GetResult() const {
+  return model_->result();
 }
 
 void OmniboxPopupViewMac::CreatePopupIfNeeded() {
@@ -308,65 +348,103 @@
                                     styleMask:NSBorderlessWindowMask
                                       backing:NSBackingStoreBuffered
                                         defer:YES]);
-    [popup_ setMovableByWindowBackground:NO];
-    // The window shape is determined by the content view.
-    [popup_ setAlphaValue:1.0];
-    [popup_ setOpaque:YES];
-    [popup_ setBackgroundColor:BackgroundColor()];
-    [popup_ setHasShadow:YES];
-    [popup_ setLevel:NSNormalWindowLevel];
+    [popup_ setBackgroundColor:[NSColor clearColor]];
+    [popup_ setOpaque:NO];
+
     // Use a flipped view to pin the matrix top the top left. This is needed
     // for animated resize.
-    scoped_nsobject<FlippedView> contentView(
+    base::scoped_nsobject<FlippedView> contentView(
         [[FlippedView alloc] initWithFrame:NSZeroRect]);
     [popup_ setContentView:contentView];
 
-    autocomplete_matrix_.reset(
-        [[AutocompleteMatrix alloc] initWithPopupView:this]);
-    [contentView addSubview:autocomplete_matrix_];
+    // View to draw a background beneath the matrix.
+    background_view_.reset([[NSBox alloc] initWithFrame:NSZeroRect]);
+    [background_view_ setBoxType:NSBoxCustom];
+    [background_view_ setBorderType:NSNoBorder];
+    [background_view_ setFillColor:BackgroundColor()];
+    [background_view_ setContentViewMargins:NSZeroSize];
+    [contentView addSubview:background_view_];
+
+    matrix_.reset([[OmniboxPopupMatrix alloc] initWithDelegate:this]);
+    [background_view_ addSubview:matrix_];
+
+    top_separator_view_.reset(
+        [[OmniboxPopupTopSeparatorView alloc] initWithFrame:NSZeroRect]);
+    [contentView addSubview:top_separator_view_];
+
+    bottom_separator_view_.reset(
+        [[OmniboxPopupBottomSeparatorView alloc] initWithFrame:NSZeroRect]);
+    [contentView addSubview:bottom_separator_view_];
 
     // TODO(dtseng): Ignore until we provide NSAccessibility support.
     [popup_ accessibilitySetOverrideValue:NSAccessibilityUnknownRole
-        forAttribute:NSAccessibilityRoleAttribute];
+                             forAttribute:NSAccessibilityRoleAttribute];
   }
 }
 
 void OmniboxPopupViewMac::PositionPopup(const CGFloat matrixHeight) {
   BrowserWindowController* controller =
       [BrowserWindowController browserWindowControllerForView:field_];
-  NSRect anchorRectBase = [controller omniboxPopupAnchorRect];
+  NSRect anchor_rect_base = [controller omniboxPopupAnchorRect];
 
   // Calculate the popup's position on the screen.
-  NSRect popupFrame = anchorRectBase;
+  NSRect popup_frame = anchor_rect_base;
   // Size to fit the matrix and shift down by the size.
-  popupFrame.size.height = matrixHeight + kPopupPaddingVertical * 2.0;
-  popupFrame.origin.y -= NSHeight(popupFrame);
+  popup_frame.size.height = matrixHeight + kPopupPaddingVertical * 2.0;
+  popup_frame.size.height += [OmniboxPopupTopSeparatorView preferredHeight];
+  popup_frame.size.height += [OmniboxPopupBottomSeparatorView preferredHeight];
+  popup_frame.origin.y -= NSHeight(popup_frame);
   // Shift to screen coordinates.
-  popupFrame.origin =
-      [[controller window] convertBaseToScreen:popupFrame.origin];
+  popup_frame.origin =
+      [[controller window] convertBaseToScreen:popup_frame.origin];
 
   // Do nothing if the popup is already animating to the given |frame|.
-  if (NSEqualRects(popupFrame, targetPopupFrame_))
+  if (NSEqualRects(popup_frame, target_popup_frame_))
     return;
 
-  NSPoint fieldOriginBase =
-      [field_ convertPoint:[field_ bounds].origin toView:nil];
-  NSRect matrixFrame = NSZeroRect;
-  matrixFrame.origin.x = fieldOriginBase.x - NSMinX(anchorRectBase);
-  matrixFrame.origin.y = kPopupPaddingVertical;
-  matrixFrame.size.width = [autocomplete_matrix_ cellSize].width;
-  matrixFrame.size.height = matrixHeight;
-  [autocomplete_matrix_ setFrame:matrixFrame];
+  // Top separator.
+  NSRect top_separator_frame = NSZeroRect;
+  top_separator_frame.size.width = NSWidth(popup_frame);
+  top_separator_frame.size.height =
+      [OmniboxPopupTopSeparatorView preferredHeight];
+  [top_separator_view_ setFrame:top_separator_frame];
 
-  NSRect currentPopupFrame = [popup_ frame];
-  targetPopupFrame_ = popupFrame;
+  // Bottom separator.
+  NSRect bottom_separator_frame = NSZeroRect;
+  bottom_separator_frame.size.width = NSWidth(popup_frame);
+  bottom_separator_frame.size.height =
+      [OmniboxPopupBottomSeparatorView preferredHeight];
+  bottom_separator_frame.origin.y =
+      NSHeight(popup_frame) - NSHeight(bottom_separator_frame);
+  [bottom_separator_view_ setFrame:bottom_separator_frame];
+
+  // Background view.
+  NSRect background_rect = NSZeroRect;
+  background_rect.size.width = NSWidth(popup_frame);
+  background_rect.size.height = NSHeight(popup_frame) -
+      NSHeight(top_separator_frame) - NSHeight(bottom_separator_frame);
+  background_rect.origin.y = NSMaxY(top_separator_frame);
+  [background_view_ setFrame:background_rect];
+
+  // Matrix.
+  NSPoint field_origin_base =
+      [field_ convertPoint:[field_ bounds].origin toView:nil];
+  NSRect matrix_frame = NSZeroRect;
+  matrix_frame.origin.x = field_origin_base.x - NSMinX(anchor_rect_base);
+  matrix_frame.origin.y = kPopupPaddingVertical;
+  matrix_frame.size.width = [matrix_ cellSize].width;
+  matrix_frame.size.height = matrixHeight;
+  [matrix_ setFrame:matrix_frame];
+
+  NSRect current_poup_frame = [popup_ frame];
+  target_popup_frame_ = popup_frame;
 
   // Animate the frame change if the only change is that the height got smaller.
   // Otherwise, resize immediately.
-  bool animate = (NSHeight(popupFrame) < NSHeight(currentPopupFrame) &&
-                  NSWidth(popupFrame) == NSWidth(currentPopupFrame));
+  bool animate = (NSHeight(popup_frame) < NSHeight(current_poup_frame) &&
+                  NSWidth(popup_frame) == NSWidth(current_poup_frame));
 
-  scoped_nsobject<NSDictionary> savedAnimations;
+  base::scoped_nsobject<NSDictionary> savedAnimations;
   if (!animate) {
     // In an ideal world, running a zero-length animation would cancel any
     // running animations and set the new frame value immediately.  In practice,
@@ -376,16 +454,14 @@
     // convinces AppKit to do the right thing.  Save off the current animations
     // dictionary so it can be restored later.
     savedAnimations.reset([[popup_ animations] copy]);
-    [popup_ setAnimations:
-              [NSDictionary dictionaryWithObjectsAndKeys:[NSNull null],
-                                                         @"frame", nil]];
+    [popup_ setAnimations:@{@"frame" : [NSNull null]}];
   }
 
   [NSAnimationContext beginGrouping];
   // Don't use the GTM additon for the "Steve" slowdown because this can happen
   // async from user actions and the effects could be a surprise.
   [[NSAnimationContext currentContext] setDuration:kShrinkAnimationDuration];
-  [[popup_ animator] setFrame:popupFrame display:YES];
+  [[popup_ animator] setFrame:popup_frame display:YES];
   [NSAnimationContext endGrouping];
 
   if (!animate) {
@@ -408,338 +484,13 @@
   return OmniboxViewMac::ImageForResource(resource_id);
 }
 
-void OmniboxPopupViewMac::UpdatePopupAppearance() {
-  DCHECK([NSThread isMainThread]);
-  const AutocompleteResult& result = model_->result();
-  if (result.empty()) {
-    [[popup_ parentWindow] removeChildWindow:popup_];
-    [popup_ orderOut:nil];
+void OmniboxPopupViewMac::OpenURLForRow(size_t row,
+                                        WindowOpenDisposition disposition) {
+  DCHECK_GE(row, 0u);
 
-    // Break references to |this| because the popup may not be
-    // deallocated immediately.
-    [autocomplete_matrix_ setPopupView:NULL];
-    autocomplete_matrix_.reset();
-
-    popup_.reset(nil);
-
-    targetPopupFrame_ = NSZeroRect;
-
-    return;
-  }
-
-  CreatePopupIfNeeded();
-
-  // The popup's font is a slightly smaller version of the field's.
-  NSFont* fieldFont = OmniboxViewMac::GetFieldFont();
-  const CGFloat resultFontSize = [fieldFont pointSize];
-  gfx::Font resultFont(base::SysNSStringToUTF8([fieldFont fontName]),
-                       static_cast<int>(resultFontSize));
-
-  // Calculate the width of the matrix based on backing out the
-  // popup's border from the width of the field.
-  const CGFloat matrixWidth = NSWidth([field_ bounds]);
-  DCHECK_GT(matrixWidth, 0.0);
-
-  // Load the results into the popup's matrix.
-  const size_t rows = model_->result().size();
-  DCHECK_GT(rows, 0U);
-  [autocomplete_matrix_ renewRows:rows columns:1];
-  for (size_t ii = 0; ii < rows; ++ii) {
-    AutocompleteButtonCell* cell = [autocomplete_matrix_ cellAtRow:ii column:0];
-    const AutocompleteMatch& match = model_->result().match_at(ii);
-    [cell setImage:ImageForMatch(match)];
-    [cell setAttributedTitle:MatchText(match, resultFont, matrixWidth)];
-  }
-
-  // Set the cell size to fit a line of text in the cell's font.  All
-  // cells should use the same font and each should layout in one
-  // line, so they should all be about the same height.
-  const NSSize cellSize =
-      [[autocomplete_matrix_ cellAtRow:0 column:0] cellSize];
-  DCHECK_GT(cellSize.height, 0.0);
-  const CGFloat cellHeight = cellSize.height + kCellHeightAdjust;
-  [autocomplete_matrix_ setCellSize:NSMakeSize(matrixWidth, cellHeight)];
-
-  // Update the selection before placing (and displaying) the window.
-  PaintUpdatesNow();
-
-  // Calculate the matrix size manually rather than using -sizeToCells
-  // because actually resizing the matrix messed up the popup size
-  // animation.
-  DCHECK_EQ([autocomplete_matrix_ intercellSpacing].height, 0.0);
-  PositionPopup(rows * cellHeight);
-}
-
-gfx::Rect OmniboxPopupViewMac::GetTargetBounds() {
-  // Flip the coordinate system before returning.
-  NSScreen* screen = [[NSScreen screens] objectAtIndex:0];
-  NSRect monitorFrame = [screen frame];
-  gfx::Rect bounds(NSRectToCGRect(targetPopupFrame_));
-  bounds.set_y(monitorFrame.size.height - bounds.y() - bounds.height());
-  return bounds;
-}
-
-void OmniboxPopupViewMac::SetSelectedLine(size_t line) {
-  model_->SetSelectedLine(line, false, false);
-}
-
-// This is only called by model in SetSelectedLine() after updating
-// everything.  Popup should already be visible.
-void OmniboxPopupViewMac::PaintUpdatesNow() {
-  [autocomplete_matrix_ selectCellAtRow:model_->selected_line() column:0];
-}
-
-void OmniboxPopupViewMac::OpenURLForRow(int row, bool force_background) {
-  DCHECK_GE(row, 0);
-
-  WindowOpenDisposition disposition = NEW_BACKGROUND_TAB;
-  if (!force_background) {
-    disposition = ui::WindowOpenDispositionFromNSEvent([NSApp currentEvent]);
-  }
-
-  // OpenMatch() may close the popup, which will clear the result set
-  // and, by extension, |match| and its contents.  So copy the
-  // relevant match out to make sure it stays alive until the call
-  // completes.
-  AutocompleteMatch match = model_->result().match_at(row);
+  // OpenMatch() may close the popup, which will clear the result set and, by
+  // extension, |match| and its contents.  So copy the relevant match out to
+  // make sure it stays alive until the call completes.
+  AutocompleteMatch match = GetResult().match_at(row);
   omnibox_view_->OpenMatch(match, disposition, GURL(), row);
 }
-
-@implementation AutocompleteButtonCell
-
-- (id)init {
-  self = [super init];
-  if (self) {
-    [self setImagePosition:NSImageLeft];
-    [self setBordered:NO];
-    [self setButtonType:NSRadioButton];
-
-    // Without this highlighting messes up white areas of images.
-    [self setHighlightsBy:NSNoCellMask];
-  }
-  return self;
-}
-
-// The default NSButtonCell drawing leaves the image flush left and
-// the title next to the image.  This spaces things out to line up
-// with the star button and autocomplete field.
-- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView *)controlView {
-  [BackgroundColor() set];
-  NSRectFill(cellFrame);
-  if ([self state] == NSOnState || [self isHighlighted]) {
-    if ([self state] == NSOnState)
-      [SelectedBackgroundColor() set];
-    else
-      [HoveredBackgroundColor() set];
-    NSBezierPath* path =
-        [NSBezierPath bezierPathWithRoundedRect:cellFrame
-                                        xRadius:kCellRoundingRadius
-                                        yRadius:kCellRoundingRadius];
-    [path fill];
-  }
-
-  // Put the image centered vertically but in a fixed column.
-  NSImage* image = [self image];
-  if (image) {
-    NSRect imageRect = cellFrame;
-    imageRect.size = [image size];
-    imageRect.origin.y +=
-        std::floor((NSHeight(cellFrame) - NSHeight(imageRect)) / 2.0);
-    imageRect.origin.x += kImageXOffset;
-    [image drawInRect:imageRect
-             fromRect:NSZeroRect  // Entire image
-            operation:NSCompositeSourceOver
-             fraction:1.0
-       respectFlipped:YES
-                hints:nil];
-  }
-
-  // Adjust the title position to be lined up under the field's text.
-  NSAttributedString* title = [self attributedTitle];
-  if (title && [title length]) {
-    NSRect titleRect = cellFrame;
-    titleRect.size.width -= kTextXOffset;
-    titleRect.origin.x += kTextXOffset;
-    [self drawTitle:title withFrame:titleRect inView:controlView];
-  }
-}
-
-@end
-
-@implementation AutocompleteMatrix
-
-// Remove all tracking areas and initialize the one we want.  Removing
-// all might be overkill, but it's unclear why there would be others
-// for the popup window.
-- (void)resetTrackingArea {
-  for (NSTrackingArea* trackingArea in [self trackingAreas]) {
-    [self removeTrackingArea:trackingArea];
-  }
-
-  // TODO(shess): Consider overriding -acceptsFirstMouse: and changing
-  // NSTrackingActiveInActiveApp to NSTrackingActiveAlways.
-  NSTrackingAreaOptions options = NSTrackingMouseEnteredAndExited;
-  options |= NSTrackingMouseMoved;
-  options |= NSTrackingActiveInActiveApp;
-  options |= NSTrackingInVisibleRect;
-
-  scoped_nsobject<NSTrackingArea> trackingArea(
-      [[NSTrackingArea alloc] initWithRect:[self frame]
-                                   options:options
-                                     owner:self
-                                  userInfo:nil]);
-  [self addTrackingArea:trackingArea];
-}
-
-- (void)updateTrackingAreas {
-  [self resetTrackingArea];
-  [super updateTrackingAreas];
-}
-
-- (id)initWithPopupView:(OmniboxPopupViewMac*)popupView {
-  self = [super initWithFrame:NSZeroRect];
-  if (self) {
-    popupView_ = popupView;
-
-    [self setCellClass:[AutocompleteButtonCell class]];
-
-    // Cells pack with no spacing.
-    [self setIntercellSpacing:NSMakeSize(0.0, 0.0)];
-
-    [self setDrawsBackground:YES];
-    [self setBackgroundColor:BackgroundColor()];
-    [self renewRows:0 columns:1];
-    [self setAllowsEmptySelection:YES];
-    [self setMode:NSRadioModeMatrix];
-    [self deselectAllCells];
-
-    [self resetTrackingArea];
-  }
-  return self;
-}
-
-- (void)setPopupView:(OmniboxPopupViewMac*)popupView {
-  popupView_ = popupView;
-}
-
-- (void)highlightRowAt:(NSInteger)rowIndex {
-  // highlightCell will be nil if rowIndex is out of range, so no cell
-  // will be highlighted.
-  NSCell* highlightCell = [self cellAtRow:rowIndex column:0];
-
-  for (NSCell* cell in [self cells]) {
-    [cell setHighlighted:(cell == highlightCell)];
-  }
-}
-
-- (void)highlightRowUnder:(NSEvent*)theEvent {
-  NSPoint point = [self convertPoint:[theEvent locationInWindow] fromView:nil];
-  NSInteger row, column;
-  if ([self getRow:&row column:&column forPoint:point]) {
-    [self highlightRowAt:row];
-  } else {
-    [self highlightRowAt:-1];
-  }
-}
-
-// Callbacks from NSTrackingArea.
-- (void)mouseEntered:(NSEvent*)theEvent {
-  [self highlightRowUnder:theEvent];
-}
-- (void)mouseMoved:(NSEvent*)theEvent {
-  [self highlightRowUnder:theEvent];
-}
-- (void)mouseExited:(NSEvent*)theEvent {
-  [self highlightRowAt:-1];
-}
-
-// The tracking area events aren't forwarded during a drag, so handle
-// highlighting manually for middle-click and middle-drag.
-- (void)otherMouseDown:(NSEvent*)theEvent {
-  if ([theEvent buttonNumber] == kMiddleButtonNumber) {
-    [self highlightRowUnder:theEvent];
-  }
-  [super otherMouseDown:theEvent];
-}
-- (void)otherMouseDragged:(NSEvent*)theEvent {
-  if ([theEvent buttonNumber] == kMiddleButtonNumber) {
-    [self highlightRowUnder:theEvent];
-  }
-  [super otherMouseDragged:theEvent];
-}
-
-- (void)otherMouseUp:(NSEvent*)theEvent {
-  // Only intercept middle button.
-  if ([theEvent buttonNumber] != kMiddleButtonNumber) {
-    [super otherMouseUp:theEvent];
-    return;
-  }
-
-  // -otherMouseDragged: should always have been called at this
-  // location, but make sure the user is getting the right feedback.
-  [self highlightRowUnder:theEvent];
-
-  const NSInteger highlightedRow = [self highlightedRow];
-  if (highlightedRow != -1) {
-    DCHECK(popupView_);
-    popupView_->OpenURLForRow(highlightedRow, true);
-  }
-}
-
-// Select cell under |theEvent|, returning YES if a selection is made.
-- (BOOL)selectCellForEvent:(NSEvent*)theEvent {
-  NSPoint point = [self convertPoint:[theEvent locationInWindow] fromView:nil];
-
-  NSInteger row, column;
-  if ([self getRow:&row column:&column forPoint:point]) {
-    DCHECK_EQ(column, 0);
-    DCHECK(popupView_);
-    popupView_->SetSelectedLine(row);
-    return YES;
-  }
-  return NO;
-}
-
-// Track the mouse until released, keeping the cell under the mouse
-// selected.  If the mouse wanders off-view, revert to the
-// originally-selected cell.  If the mouse is released over a cell,
-// call |popupView_| to open the row's URL.
-- (void)mouseDown:(NSEvent*)theEvent {
-  NSCell* selectedCell = [self selectedCell];
-
-  // Clear any existing highlight.
-  [self highlightRowAt:-1];
-
-  do {
-    if (![self selectCellForEvent:theEvent]) {
-      [self selectCell:selectedCell];
-    }
-
-    const NSUInteger mask = NSLeftMouseUpMask | NSLeftMouseDraggedMask;
-    theEvent = [[self window] nextEventMatchingMask:mask];
-  } while ([theEvent type] == NSLeftMouseDragged);
-
-  // Do not message |popupView_| if released outside view.
-  if (![self selectCellForEvent:theEvent]) {
-    [self selectCell:selectedCell];
-  } else {
-    const NSInteger selectedRow = [self selectedRow];
-    DCHECK_GE(selectedRow, 0);
-
-    DCHECK(popupView_);
-    popupView_->OpenURLForRow(selectedRow, false);
-  }
-}
-
-- (NSInteger)highlightedRow {
-  NSArray* cells = [self cells];
-  const NSUInteger count = [cells count];
-  for(NSUInteger i = 0; i < count; ++i) {
-    if ([[cells objectAtIndex:i] isHighlighted]) {
-      return i;
-    }
-  }
-  return -1;
-}
-
-@end
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac_unittest.mm b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac_unittest.mm
index de68daf..75f973a 100644
--- a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac_unittest.mm
+++ b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac_unittest.mm
@@ -7,101 +7,126 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/strings/sys_string_conversions.h"
 #include "base/strings/utf_string_conversions.h"
-#include "testing/platform_test.h"
+#include "chrome/browser/ui/cocoa/cocoa_profile_test.h"
+#import "chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.h"
 #include "ui/base/text/text_elider.h"
 
 namespace {
 
 const float kLargeWidth = 10000;
 
-class OmniboxPopupViewMacTest : public PlatformTest {
+// Returns the length of the run starting at |location| for which
+// |attributeName| remains the same.
+NSUInteger RunLengthForAttribute(NSAttributedString* string,
+                                 NSUInteger location,
+                                 NSString* attributeName) {
+  const NSRange full_range = NSMakeRange(0, [string length]);
+  NSRange range;
+  [string attribute:attributeName
+            atIndex:location longestEffectiveRange:&range inRange:full_range];
+
+  // In order to signal when the run doesn't start exactly at location, return
+  // a weirdo length.  This causes the incorrect expectation to manifest at the
+  // calling location, which is more useful than an EXPECT_EQ() would be here.
+  if (range.location != location) {
+    return -1;
+  }
+
+  return range.length;
+}
+
+// Return true if the run starting at |location| has |color| for attribute
+// NSForegroundColorAttributeName.
+bool RunHasColor(NSAttributedString* string,
+                 NSUInteger location,
+                 NSColor* color) {
+  const NSRange full_range = NSMakeRange(0, [string length]);
+  NSRange range;
+  NSColor* run_color = [string attribute:NSForegroundColorAttributeName
+                                 atIndex:location
+                   longestEffectiveRange:&range
+                                 inRange:full_range];
+
+  // According to one "Ali Ozer", you can compare objects within the same color
+  // space using -isEqual:.  Converting color spaces seems too heavyweight for
+  // these tests.
+  // http://lists.apple.com/archives/cocoa-dev/2005/May/msg00186.html
+  return [run_color isEqual:color] ? true : false;
+}
+
+// Return true if the run starting at |location| has the font trait(s) in |mask|
+// font in NSFontAttributeName.
+bool RunHasFontTrait(NSAttributedString* string,
+                     NSUInteger location,
+                     NSFontTraitMask mask) {
+  const NSRange full_range = NSMakeRange(0, [string length]);
+  NSRange range;
+  NSFont* run_font = [string attribute:NSFontAttributeName
+                               atIndex:location
+                 longestEffectiveRange:&range
+                               inRange:full_range];
+  NSFontManager* fontManager = [NSFontManager sharedFontManager];
+  if (run_font && (mask == ([fontManager traitsOfFont:run_font] & mask))) {
+    return true;
+  }
+  return false;
+}
+
+// AutocompleteMatch doesn't really have the right constructor for our
+// needs.  Fake one for us to use.
+AutocompleteMatch MakeMatch(const string16& contents,
+                            const string16& description) {
+  AutocompleteMatch m(NULL, 1, true, AutocompleteMatchType::URL_WHAT_YOU_TYPED);
+  m.contents = contents;
+  m.description = description;
+  return m;
+}
+
+class MockOmniboxPopupViewMac : public OmniboxPopupViewMac {
  public:
-  OmniboxPopupViewMacTest() {}
+  MockOmniboxPopupViewMac(OmniboxView* omnibox_view,
+                          OmniboxEditModel* edit_model,
+                          NSTextField* field)
+      : OmniboxPopupViewMac(omnibox_view, edit_model, field) {
+  }
 
-  virtual void SetUp() {
-    PlatformTest::SetUp();
+  void SetResultCount(size_t count) {
+    ACMatches matches;
+    for (size_t i = 0; i < count; ++i)
+      matches.push_back(AutocompleteMatch());
+    result_.Reset();
+    result_.AppendMatches(matches);
+  }
 
-    // These are here because there is no autorelease pool for the
-    // constructor.
+ protected:
+  virtual const AutocompleteResult& GetResult() const OVERRIDE {
+    return result_;
+  }
+
+ private:
+  AutocompleteResult result_;
+};
+
+class OmniboxPopupViewMacTest : public CocoaProfileTest {
+ public:
+  OmniboxPopupViewMacTest() {
     color_ = [NSColor blackColor];
-    dimColor_ = [NSColor darkGrayColor];
+    dim_color_ = [NSColor darkGrayColor];
     font_ = gfx::Font(
         base::SysNSStringToUTF8([[NSFont userFontOfSize:12] fontName]), 12);
   }
 
-  // Returns the length of the run starting at |location| for which
-  // |attributeName| remains the same.
-  static NSUInteger RunLengthForAttribute(NSAttributedString* string,
-                                          NSUInteger location,
-                                          NSString* attributeName) {
-    const NSRange fullRange = NSMakeRange(0, [string length]);
-    NSRange range;
-    [string attribute:attributeName
-              atIndex:location longestEffectiveRange:&range inRange:fullRange];
-
-    // In order to signal when the run doesn't start exactly at
-    // location, return a weirdo length.  This causes the incorrect
-    // expectation to manifest at the calling location, which is more
-    // useful than an EXPECT_EQ() would be here.
-    if (range.location != location) {
-      return -1;
-    }
-
-    return range.length;
-  }
-
-  // Return true if the run starting at |location| has |color| for
-  // attribute NSForegroundColorAttributeName.
-  static bool RunHasColor(NSAttributedString* string,
-                          NSUInteger location, NSColor* color) {
-    const NSRange fullRange = NSMakeRange(0, [string length]);
-    NSRange range;
-    NSColor* runColor = [string attribute:NSForegroundColorAttributeName
-                                  atIndex:location
-                    longestEffectiveRange:&range inRange:fullRange];
-
-    // According to one "Ali Ozer", you can compare objects within the
-    // same color space using -isEqual:.  Converting color spaces
-    // seems too heavyweight for these tests.
-    // http://lists.apple.com/archives/cocoa-dev/2005/May/msg00186.html
-    return [runColor isEqual:color] ? true : false;
-  }
-
-  // Return true if the run starting at |location| has the font
-  // trait(s) in |mask| font in NSFontAttributeName.
-  static bool RunHasFontTrait(NSAttributedString* string, NSUInteger location,
-                              NSFontTraitMask mask) {
-    const NSRange fullRange = NSMakeRange(0, [string length]);
-    NSRange range;
-    NSFont* runFont = [string attribute:NSFontAttributeName
-                                atIndex:location
-                  longestEffectiveRange:&range inRange:fullRange];
-    NSFontManager* fontManager = [NSFontManager sharedFontManager];
-    if (runFont && (mask == ([fontManager traitsOfFont:runFont]&mask))) {
-      return true;
-    }
-    return false;
-  }
-
-  // AutocompleteMatch doesn't really have the right constructor for our
-  // needs.  Fake one for us to use.
-  static AutocompleteMatch MakeMatch(const string16 &contents,
-                                     const string16 &description) {
-    AutocompleteMatch m(NULL, 1, true,
-                        AutocompleteMatchType::URL_WHAT_YOU_TYPED);
-    m.contents = contents;
-    m.description = description;
-    return m;
-  }
-
+ protected:
   NSColor* color_;  // weak
-  NSColor* dimColor_;  // weak
+  NSColor* dim_color_;  // weak
   gfx::Font font_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(OmniboxPopupViewMacTest);
 };
 
-// Simple inputs with no matches should result in styled output who's
-// text matches the input string, with the passed-in color, and
-// nothing bolded.
+// Simple inputs with no matches should result in styled output who's text
+// matches the input string, with the passed-in color, and nothing bolded.
 TEST_F(OmniboxPopupViewMacTest, DecorateMatchedStringNoMatch) {
   NSString* const string = @"This is a test";
   AutocompleteMatch::ACMatchClassifications classifications;
@@ -109,7 +134,7 @@
   NSAttributedString* decorated =
       OmniboxPopupViewMac::DecorateMatchedString(
           base::SysNSStringToUTF16(string), classifications,
-          color_, dimColor_, font_);
+          color_, dim_color_, font_);
 
   // Result has same characters as the input.
   EXPECT_EQ([decorated length], [string length]);
@@ -122,13 +147,13 @@
   EXPECT_TRUE(RunHasColor(decorated, 0U, color_));
 
   // An unbolded font for the entire string.
-  EXPECT_EQ(RunLengthForAttribute(decorated, 0U,
-                                  NSFontAttributeName), [string length]);
+  EXPECT_EQ(RunLengthForAttribute(decorated, 0U, NSFontAttributeName),
+            [string length]);
   EXPECT_FALSE(RunHasFontTrait(decorated, 0U, NSBoldFontMask));
 }
 
-// Identical to DecorateMatchedStringNoMatch, except test that URL
-// style gets a different color than we passed in.
+// Identical to DecorateMatchedStringNoMatch, except test that URL style gets a
+// different color than we passed in.
 TEST_F(OmniboxPopupViewMacTest, DecorateMatchedStringURLNoMatch) {
   NSString* const string = @"This is a test";
   AutocompleteMatch::ACMatchClassifications classifications;
@@ -139,7 +164,7 @@
   NSAttributedString* decorated =
       OmniboxPopupViewMac::DecorateMatchedString(
           base::SysNSStringToUTF16(string), classifications,
-          color_, dimColor_, font_);
+          color_, dim_color_, font_);
 
   // Result has same characters as the input.
   EXPECT_EQ([decorated length], [string length]);
@@ -161,24 +186,24 @@
 TEST_F(OmniboxPopupViewMacTest, DecorateMatchedStringDimNoMatch) {
   NSString* const string = @"This is a test";
   // Dim "is".
-  const NSUInteger runLength1 = 5, runLength2 = 2, runLength3 = 7;
+  const NSUInteger run_length_1 = 5, run_length_2 = 2, run_length_3 = 7;
   // Make sure nobody messed up the inputs.
-  EXPECT_EQ(runLength1 + runLength2 + runLength3, [string length]);
+  EXPECT_EQ(run_length_1 + run_length_2 + run_length_3, [string length]);
 
   // Push each run onto classifications.
   AutocompleteMatch::ACMatchClassifications classifications;
   classifications.push_back(
       ACMatchClassification(0, ACMatchClassification::NONE));
   classifications.push_back(
-      ACMatchClassification(runLength1, ACMatchClassification::DIM));
+      ACMatchClassification(run_length_1, ACMatchClassification::DIM));
   classifications.push_back(
-      ACMatchClassification(runLength1 + runLength2,
+      ACMatchClassification(run_length_1 + run_length_2,
                             ACMatchClassification::NONE));
 
   NSAttributedString* decorated =
       OmniboxPopupViewMac::DecorateMatchedString(
           base::SysNSStringToUTF16(string), classifications,
-          color_, dimColor_, font_);
+          color_, dim_color_, font_);
 
   // Result has same characters as the input.
   EXPECT_EQ([decorated length], [string length]);
@@ -187,18 +212,18 @@
   // Should have three font runs, normal, dim, normal.
   EXPECT_EQ(RunLengthForAttribute(decorated, 0U,
                                   NSForegroundColorAttributeName),
-            runLength1);
+            run_length_1);
   EXPECT_TRUE(RunHasColor(decorated, 0U, color_));
 
-  EXPECT_EQ(RunLengthForAttribute(decorated, runLength1,
+  EXPECT_EQ(RunLengthForAttribute(decorated, run_length_1,
                                   NSForegroundColorAttributeName),
-            runLength2);
-  EXPECT_TRUE(RunHasColor(decorated, runLength1, dimColor_));
+            run_length_2);
+  EXPECT_TRUE(RunHasColor(decorated, run_length_1, dim_color_));
 
-  EXPECT_EQ(RunLengthForAttribute(decorated, runLength1 + runLength2,
+  EXPECT_EQ(RunLengthForAttribute(decorated, run_length_1 + run_length_2,
                                   NSForegroundColorAttributeName),
-            runLength3);
-  EXPECT_TRUE(RunHasColor(decorated, runLength1 + runLength2, color_));
+            run_length_3);
+  EXPECT_TRUE(RunHasColor(decorated, run_length_1 + run_length_2, color_));
 
   // An unbolded font for the entire string.
   EXPECT_EQ(RunLengthForAttribute(decorated, 0U,
@@ -206,29 +231,28 @@
   EXPECT_FALSE(RunHasFontTrait(decorated, 0U, NSBoldFontMask));
 }
 
-// Test that the matched run gets bold-faced, but keeps the same
-// color.
+// Test that the matched run gets bold-faced, but keeps the same color.
 TEST_F(OmniboxPopupViewMacTest, DecorateMatchedStringMatch) {
   NSString* const string = @"This is a test";
   // Match "is".
-  const NSUInteger runLength1 = 5, runLength2 = 2, runLength3 = 7;
+  const NSUInteger run_length_1 = 5, run_length_2 = 2, run_length_3 = 7;
   // Make sure nobody messed up the inputs.
-  EXPECT_EQ(runLength1 + runLength2 + runLength3, [string length]);
+  EXPECT_EQ(run_length_1 + run_length_2 + run_length_3, [string length]);
 
   // Push each run onto classifications.
   AutocompleteMatch::ACMatchClassifications classifications;
   classifications.push_back(
       ACMatchClassification(0, ACMatchClassification::NONE));
   classifications.push_back(
-      ACMatchClassification(runLength1, ACMatchClassification::MATCH));
+      ACMatchClassification(run_length_1, ACMatchClassification::MATCH));
   classifications.push_back(
-      ACMatchClassification(runLength1 + runLength2,
+      ACMatchClassification(run_length_1 + run_length_2,
                             ACMatchClassification::NONE));
 
   NSAttributedString* decorated =
       OmniboxPopupViewMac::DecorateMatchedString(
           base::SysNSStringToUTF16(string), classifications,
-          color_, dimColor_, font_);
+          color_, dim_color_, font_);
 
   // Result has same characters as the input.
   EXPECT_EQ([decorated length], [string length]);
@@ -242,16 +266,16 @@
 
   // Should have three font runs, not bold, bold, then not bold again.
   EXPECT_EQ(RunLengthForAttribute(decorated, 0U,
-                                  NSFontAttributeName), runLength1);
+                                  NSFontAttributeName), run_length_1);
   EXPECT_FALSE(RunHasFontTrait(decorated, 0U, NSBoldFontMask));
 
-  EXPECT_EQ(RunLengthForAttribute(decorated, runLength1,
-                                  NSFontAttributeName), runLength2);
-  EXPECT_TRUE(RunHasFontTrait(decorated, runLength1, NSBoldFontMask));
+  EXPECT_EQ(RunLengthForAttribute(decorated, run_length_1,
+                                  NSFontAttributeName), run_length_2);
+  EXPECT_TRUE(RunHasFontTrait(decorated, run_length_1, NSBoldFontMask));
 
-  EXPECT_EQ(RunLengthForAttribute(decorated, runLength1 + runLength2,
-                                  NSFontAttributeName), runLength3);
-  EXPECT_FALSE(RunHasFontTrait(decorated, runLength1 + runLength2,
+  EXPECT_EQ(RunLengthForAttribute(decorated, run_length_1 + run_length_2,
+                                  NSFontAttributeName), run_length_3);
+  EXPECT_FALSE(RunHasFontTrait(decorated, run_length_1 + run_length_2,
                                NSBoldFontMask));
 }
 
@@ -259,24 +283,24 @@
 TEST_F(OmniboxPopupViewMacTest, DecorateMatchedStringURLMatch) {
   NSString* const string = @"http://hello.world/";
   // Match "hello".
-  const NSUInteger runLength1 = 7, runLength2 = 5, runLength3 = 7;
+  const NSUInteger run_length_1 = 7, run_length_2 = 5, run_length_3 = 7;
   // Make sure nobody messed up the inputs.
-  EXPECT_EQ(runLength1 + runLength2 + runLength3, [string length]);
+  EXPECT_EQ(run_length_1 + run_length_2 + run_length_3, [string length]);
 
   // Push each run onto classifications.
   AutocompleteMatch::ACMatchClassifications classifications;
   classifications.push_back(
       ACMatchClassification(0, ACMatchClassification::URL));
   const int kURLMatch = ACMatchClassification::URL|ACMatchClassification::MATCH;
-  classifications.push_back(ACMatchClassification(runLength1, kURLMatch));
+  classifications.push_back(ACMatchClassification(run_length_1, kURLMatch));
   classifications.push_back(
-      ACMatchClassification(runLength1 + runLength2,
+      ACMatchClassification(run_length_1 + run_length_2,
                             ACMatchClassification::URL));
 
   NSAttributedString* decorated =
       OmniboxPopupViewMac::DecorateMatchedString(
           base::SysNSStringToUTF16(string), classifications,
-          color_, dimColor_, font_);
+          color_, dim_color_, font_);
 
   // Result has same characters as the input.
   EXPECT_EQ([decorated length], [string length]);
@@ -290,16 +314,16 @@
 
   // Should have three font runs, not bold, bold, then not bold again.
   EXPECT_EQ(RunLengthForAttribute(decorated, 0U,
-                                  NSFontAttributeName), runLength1);
+                                  NSFontAttributeName), run_length_1);
   EXPECT_FALSE(RunHasFontTrait(decorated, 0U, NSBoldFontMask));
 
-  EXPECT_EQ(RunLengthForAttribute(decorated, runLength1,
-                                  NSFontAttributeName), runLength2);
-  EXPECT_TRUE(RunHasFontTrait(decorated, runLength1, NSBoldFontMask));
+  EXPECT_EQ(RunLengthForAttribute(decorated, run_length_1,
+                                  NSFontAttributeName), run_length_2);
+  EXPECT_TRUE(RunHasFontTrait(decorated, run_length_1, NSBoldFontMask));
 
-  EXPECT_EQ(RunLengthForAttribute(decorated, runLength1 + runLength2,
-                                  NSFontAttributeName), runLength3);
-  EXPECT_FALSE(RunHasFontTrait(decorated, runLength1 + runLength2,
+  EXPECT_EQ(RunLengthForAttribute(decorated, run_length_1 + run_length_2,
+                                  NSFontAttributeName), run_length_3);
+  EXPECT_FALSE(RunHasFontTrait(decorated, run_length_1 + run_length_2,
                                NSBoldFontMask));
 }
 
@@ -342,9 +366,9 @@
 TEST_F(OmniboxPopupViewMacTest, MatchTextContentsMatch) {
   NSString* const contents = @"This is a test";
   // Match "is".
-  const NSUInteger runLength1 = 5, runLength2 = 2, runLength3 = 7;
+  const NSUInteger run_length_1 = 5, run_length_2 = 2, run_length_3 = 7;
   // Make sure nobody messed up the inputs.
-  EXPECT_EQ(runLength1 + runLength2 + runLength3, [contents length]);
+  EXPECT_EQ(run_length_1 + run_length_2 + run_length_3, [contents length]);
 
   AutocompleteMatch m = MakeMatch(base::SysNSStringToUTF16(contents),
                                   string16());
@@ -353,9 +377,9 @@
   m.contents_class.push_back(
       ACMatchClassification(0, ACMatchClassification::NONE));
   m.contents_class.push_back(
-      ACMatchClassification(runLength1, ACMatchClassification::MATCH));
+      ACMatchClassification(run_length_1, ACMatchClassification::MATCH));
   m.contents_class.push_back(
-      ACMatchClassification(runLength1 + runLength2,
+      ACMatchClassification(run_length_1 + run_length_2,
                             ACMatchClassification::NONE));
 
   NSAttributedString* decorated =
@@ -372,16 +396,16 @@
 
   // Should have three font runs, not bold, bold, then not bold again.
   EXPECT_EQ(RunLengthForAttribute(decorated, 0U,
-                                  NSFontAttributeName), runLength1);
+                                  NSFontAttributeName), run_length_1);
   EXPECT_FALSE(RunHasFontTrait(decorated, 0U, NSBoldFontMask));
 
-  EXPECT_EQ(RunLengthForAttribute(decorated, runLength1,
-                                  NSFontAttributeName), runLength2);
-  EXPECT_TRUE(RunHasFontTrait(decorated, runLength1, NSBoldFontMask));
+  EXPECT_EQ(RunLengthForAttribute(decorated, run_length_1,
+                                  NSFontAttributeName), run_length_2);
+  EXPECT_TRUE(RunHasFontTrait(decorated, run_length_1, NSBoldFontMask));
 
-  EXPECT_EQ(RunLengthForAttribute(decorated, runLength1 + runLength2,
-                                  NSFontAttributeName), runLength3);
-  EXPECT_FALSE(RunHasFontTrait(decorated, runLength1 + runLength2,
+  EXPECT_EQ(RunLengthForAttribute(decorated, run_length_1 + run_length_2,
+                                  NSFontAttributeName), run_length_3);
+  EXPECT_FALSE(RunHasFontTrait(decorated, run_length_1 + run_length_2,
                                NSBoldFontMask));
 }
 
@@ -390,9 +414,9 @@
   NSString* const contents = @"This is a test";
   NSString* const description = @"That was a test";
   // Match "That was".
-  const NSUInteger runLength1 = 8, runLength2 = 7;
+  const NSUInteger run_length_1 = 8, run_length_2 = 7;
   // Make sure nobody messed up the inputs.
-  EXPECT_EQ(runLength1 + runLength2, [description length]);
+  EXPECT_EQ(run_length_1 + run_length_2, [description length]);
 
   AutocompleteMatch m = MakeMatch(base::SysNSStringToUTF16(contents),
                                   base::SysNSStringToUTF16(description));
@@ -401,7 +425,7 @@
   m.description_class.push_back(
       ACMatchClassification(0, ACMatchClassification::MATCH));
   m.description_class.push_back(
-      ACMatchClassification(runLength1, ACMatchClassification::NONE));
+      ACMatchClassification(run_length_1, ACMatchClassification::NONE));
 
   NSAttributedString* decorated =
       OmniboxPopupViewMac::MatchText(m, font_, kLargeWidth);
@@ -430,12 +454,12 @@
   EXPECT_FALSE(RunHasFontTrait(decorated, 0U, NSBoldFontMask));
 
   EXPECT_EQ(RunLengthForAttribute(decorated, descriptionLocation,
-                                  NSFontAttributeName), runLength1);
+                                  NSFontAttributeName), run_length_1);
   EXPECT_TRUE(RunHasFontTrait(decorated, descriptionLocation, NSBoldFontMask));
 
-  EXPECT_EQ(RunLengthForAttribute(decorated, descriptionLocation + runLength1,
-                                  NSFontAttributeName), runLength2);
-  EXPECT_FALSE(RunHasFontTrait(decorated, descriptionLocation + runLength1,
+  EXPECT_EQ(RunLengthForAttribute(decorated, descriptionLocation + run_length_1,
+                                  NSFontAttributeName), run_length_2);
+  EXPECT_FALSE(RunHasFontTrait(decorated, descriptionLocation + run_length_1,
                                NSBoldFontMask));
 }
 
@@ -449,7 +473,7 @@
   NSDictionary* attributes =
       [NSDictionary dictionaryWithObject:font_.GetNativeFont()
                                   forKey:NSFontAttributeName];
-  scoped_nsobject<NSMutableAttributedString> as(
+  base::scoped_nsobject<NSMutableAttributedString> as(
       [[NSMutableAttributedString alloc] initWithString:contents
                                              attributes:attributes]);
 
@@ -478,9 +502,9 @@
   NSString* const contents = @"This is a test with long contents";
   NSString* const description = @"That was a test";
   // Match "long".
-  const NSUInteger runLength1 = 20, runLength2 = 4, runLength3 = 9;
+  const NSUInteger run_length_1 = 20, run_length_2 = 4, run_length_3 = 9;
   // Make sure nobody messed up the inputs.
-  EXPECT_EQ(runLength1 + runLength2 + runLength3, [contents length]);
+  EXPECT_EQ(run_length_1 + run_length_2 + run_length_3, [contents length]);
 
   AutocompleteMatch m = MakeMatch(base::SysNSStringToUTF16(contents),
                                   base::SysNSStringToUTF16(description));
@@ -489,9 +513,9 @@
   m.contents_class.push_back(
       ACMatchClassification(0, ACMatchClassification::NONE));
   m.contents_class.push_back(
-      ACMatchClassification(runLength1, ACMatchClassification::MATCH));
+      ACMatchClassification(run_length_1, ACMatchClassification::MATCH));
   m.contents_class.push_back(
-      ACMatchClassification(runLength1 + runLength2,
+      ACMatchClassification(run_length_1 + run_length_2,
                             ACMatchClassification::URL));
 
   // Figure out the width of the contents.
@@ -519,7 +543,7 @@
   // values being passed to NSAttributedString.  Push the ellipsis
   // through part of each run to verify that we don't continue to see
   // such things.
-  while([commonPrefix length] > runLength1 - 3) {
+  while([commonPrefix length] > run_length_1 - 3) {
     EXPECT_GT(cellWidth, 0.0);
     cellWidth -= 1.0;
     decorated = OmniboxPopupViewMac::MatchText(m, font_, cellWidth);
@@ -529,24 +553,33 @@
   }
 }
 
-// TODO(shess): Test that
-// OmniboxPopupViewMac::UpdatePopupAppearance() creates/destroys
-// the popup according to result contents.  Test that the matrix gets
-// the right number of results.  Test the contents of the cells for
-// the right strings.  Icons?  Maybe, that seems harder to test.
-// Styling seems almost impossible.
+TEST_F(OmniboxPopupViewMacTest, UpdatePopupAppearance) {
+  base::scoped_nsobject<NSTextField> field(
+      [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 100, 20)]);
+  [[test_window() contentView] addSubview:field];
 
-// TODO(shess): Test that OmniboxPopupViewMac::PaintUpdatesNow()
-// updates the matrix selection.
+  OmniboxViewMac view(NULL, NULL, profile(), NULL, NULL);
+  MockOmniboxPopupViewMac popup_view(&view, view.model(), field);
 
-// TODO(shess): Test that OmniboxPopupViewMac::AcceptInput()
-// updates the model's selection from the matrix before returning.
-// Could possibly test that via -select:.
+  popup_view.UpdatePopupAppearance();
+  EXPECT_FALSE(popup_view.IsOpen());
+  EXPECT_EQ(0, [popup_view.matrix() numberOfRows]);
 
-// TODO(shess): Test that AutocompleteButtonCell returns the right
-// background colors for on, highlighted, and neither.
+  popup_view.SetResultCount(3);
+  popup_view.UpdatePopupAppearance();
+  EXPECT_TRUE(popup_view.IsOpen());
+  EXPECT_EQ(3, [popup_view.matrix() numberOfRows]);
 
-// TODO(shess): Test that AutocompleteMatrixTarget can be initialized
-// and then sends -select: to the view.
+  int old_height = popup_view.GetTargetBounds().height();
+  popup_view.SetResultCount(5);
+  popup_view.UpdatePopupAppearance();
+  EXPECT_GT(popup_view.GetTargetBounds().height(), old_height);
+  EXPECT_EQ(5, [popup_view.matrix() numberOfRows]);
+
+  popup_view.SetResultCount(0);
+  popup_view.UpdatePopupAppearance();
+  EXPECT_FALSE(popup_view.IsOpen());
+  EXPECT_EQ(0, [popup_view.matrix() numberOfRows]);
+}
 
 }  // namespace
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.mm b/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.mm
index 03a7df3..7a2ce85 100644
--- a/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.mm
+++ b/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.mm
@@ -13,7 +13,6 @@
 #include "chrome/browser/autocomplete/autocomplete_input.h"
 #include "chrome/browser/autocomplete/autocomplete_match.h"
 #include "chrome/browser/browser_process.h"
-#include "chrome/browser/search/search.h"
 #include "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell.h"
 #import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor.h"
 #include "chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac.h"
@@ -139,8 +138,11 @@
                                CommandUpdater* command_updater,
                                AutocompleteTextField* field)
     : OmniboxView(profile, controller, toolbar_model, command_updater),
-      popup_view_(OmniboxPopupViewMac::Create(this, model(), field)),
+      popup_view_(new OmniboxPopupViewMac(this, model(), field)),
       field_(field),
+      saved_temporary_selection_(NSMakeRange(0, 0)),
+      selection_before_change_(NSMakeRange(0, 0)),
+      marked_range_before_change_(NSMakeRange(0, 0)),
       delete_was_pressed_(false),
       delete_at_end_pressed_(false) {
   [field_ setObserver:this];
@@ -149,8 +151,8 @@
   [field_ setAllowsEditingTextAttributes:YES];
 
   // Get the appropriate line height for the font that we use.
-  scoped_nsobject<NSLayoutManager>
-      layoutManager([[NSLayoutManager alloc] init]);
+  base::scoped_nsobject<NSLayoutManager> layoutManager(
+      [[NSLayoutManager alloc] init]);
   [layoutManager setUsesScreenFonts:YES];
 }
 
@@ -435,8 +437,8 @@
 
   // Make a paragraph style locking in the standard line height as the maximum,
   // otherwise the baseline may shift "downwards".
-  scoped_nsobject<NSMutableParagraphStyle>
-      paragraph_style([[NSMutableParagraphStyle alloc] init]);
+  base::scoped_nsobject<NSMutableParagraphStyle> paragraph_style(
+      [[NSMutableParagraphStyle alloc] init]);
   CGFloat line_height = [[field_ cell] lineHeight];
   [paragraph_style setMaximumLineHeight:line_height];
   [paragraph_style setMinimumLineHeight:line_height];
@@ -665,16 +667,12 @@
   }
 
   if (model()->popup_model()->IsOpen()) {
-    // If instant extended is enabled then allow users to press tab to select
-    // results from the omnibox popup.
-    BOOL enableTabAutocomplete = chrome::IsInstantExtendedAPIEnabled();
-
     if (cmd == @selector(insertBacktab:)) {
       if (model()->popup_model()->selected_line_state() ==
             OmniboxPopupModel::KEYWORD) {
         model()->ClearKeyword(GetText());
         return true;
-      } else if (enableTabAutocomplete) {
+      } else {
         model()->OnUpOrDownKeyPressed(-1);
         return true;
       }
@@ -682,7 +680,7 @@
 
     if ((cmd == @selector(insertTab:) ||
         cmd == @selector(insertTabIgnoringFieldEditor:)) &&
-        !model()->is_keyword_hint() && enableTabAutocomplete) {
+        !model()->is_keyword_hint()) {
       model()->OnUpOrDownKeyPressed(1);
       return true;
     }
@@ -902,7 +900,6 @@
   // things even cheaper by refactoring between the popup-placement
   // code and the matrix-population code.
   popup_view_->UpdatePopupAppearance();
-  model()->OnPopupBoundsChanged(popup_view_->GetTargetBounds());
 
   // Give controller a chance to rearrange decorations.
   model()->OnChanged();
@@ -953,11 +950,8 @@
 // static
 NSFont* OmniboxViewMac::GetFieldFont() {
   // This value should be kept in sync with InstantPage::InitializeFonts.
-  if (chrome::IsInstantExtendedAPIEnabled())
-    return [NSFont fontWithName:@"Helvetica Neue" size:16];
-
   ResourceBundle& rb = ResourceBundle::GetSharedInstance();
-  return rb.GetFont(ResourceBundle::BaseFont).GetNativeFont();
+  return rb.GetFont(ResourceBundle::BaseFont).DeriveFont(1).GetNativeFont();
 }
 
 int OmniboxViewMac::GetOmniboxTextLength() const {
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac_unittest.mm b/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac_unittest.mm
index 308d065..e9d77a3 100644
--- a/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac_unittest.mm
+++ b/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac_unittest.mm
@@ -146,7 +146,7 @@
 
 TEST_F(OmniboxViewMacTest, SetInstantSuggestion) {
   const NSRect frame = NSMakeRect(0, 0, 50, 30);
-  scoped_nsobject<AutocompleteTextField> field(
+  base::scoped_nsobject<AutocompleteTextField> field(
       [[AutocompleteTextField alloc] initWithFrame:frame]);
 
   TestingToolbarModelDelegate delegate;
diff --git a/chrome/browser/ui/cocoa/one_click_signin_bubble_controller.h b/chrome/browser/ui/cocoa/one_click_signin_bubble_controller.h
index 4676267..5298ef0 100644
--- a/chrome/browser/ui/cocoa/one_click_signin_bubble_controller.h
+++ b/chrome/browser/ui/cocoa/one_click_signin_bubble_controller.h
@@ -8,7 +8,7 @@
 #import <Cocoa/Cocoa.h>
 
 #include "base/callback.h"
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "chrome/browser/ui/browser_window.h"
 #import "chrome/browser/ui/cocoa/base_bubble_controller.h"
 
@@ -17,7 +17,7 @@
 
 // Displays the one-click signin confirmation bubble
 @interface OneClickSigninBubbleController : BaseBubbleController {
-  scoped_nsobject<OneClickSigninViewController> viewController_;
+  base::scoped_nsobject<OneClickSigninViewController> viewController_;
  @private
    IBOutlet NSTextField* messageTextField_;
 }
diff --git a/chrome/browser/ui/cocoa/one_click_signin_bubble_controller.mm b/chrome/browser/ui/cocoa/one_click_signin_bubble_controller.mm
index 6126103..a3d97fa 100644
--- a/chrome/browser/ui/cocoa/one_click_signin_bubble_controller.mm
+++ b/chrome/browser/ui/cocoa/one_click_signin_bubble_controller.mm
@@ -44,7 +44,7 @@
 
   // Create an empty window into which content is placed.
   NSRect viewBounds = [[viewController_ view] bounds];
-  scoped_nsobject<InfoBubbleWindow> window(
+  base::scoped_nsobject<InfoBubbleWindow> window(
       [[InfoBubbleWindow alloc] initWithContentRect:viewBounds
                                           styleMask:NSBorderlessWindowMask
                                             backing:NSBackingStoreBuffered
diff --git a/chrome/browser/ui/cocoa/one_click_signin_bubble_controller_browsertest.mm b/chrome/browser/ui/cocoa/one_click_signin_bubble_controller_browsertest.mm
index 1d4db26..0387770 100644
--- a/chrome/browser/ui/cocoa/one_click_signin_bubble_controller_browsertest.mm
+++ b/chrome/browser/ui/cocoa/one_click_signin_bubble_controller_browsertest.mm
@@ -39,7 +39,7 @@
                 [[controller_ viewController] nibName]);
   }
 
-  scoped_nsobject<OneClickSigninBubbleController> controller_;
+  base::scoped_nsobject<OneClickSigninBubbleController> controller_;
   int callback_count_;
 
  private:
diff --git a/chrome/browser/ui/cocoa/one_click_signin_bubble_controller_unittest.mm b/chrome/browser/ui/cocoa/one_click_signin_bubble_controller_unittest.mm
index 86ac826..a60e3a2 100644
--- a/chrome/browser/ui/cocoa/one_click_signin_bubble_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/one_click_signin_bubble_controller_unittest.mm
@@ -8,12 +8,12 @@
 
 #include "base/bind.h"
 #include "base/compiler_specific.h"
-#import "base/memory/scoped_nsobject.h"
+#import "base/mac/scoped_nsobject.h"
 #include "base/memory/weak_ptr.h"
 #import "chrome/browser/ui/cocoa/browser_window_cocoa.h"
 #include "chrome/browser/ui/cocoa/cocoa_profile_test.h"
-#include "chrome/browser/ui/sync/one_click_signin_sync_starter.h"
 #import "chrome/browser/ui/cocoa/one_click_signin_view_controller.h"
+#include "chrome/browser/ui/sync/one_click_signin_sync_starter.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #import "testing/gtest_mac.h"
@@ -54,7 +54,7 @@
  protected:
   base::WeakPtrFactory<OneClickSigninBubbleControllerTest> weak_ptr_factory_;
   BrowserWindow::StartSyncCallback start_sync_callback_;
-  scoped_nsobject<OneClickSigninBubbleController> controller_;
+  base::scoped_nsobject<OneClickSigninBubbleController> controller_;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(OneClickSigninBubbleControllerTest);
diff --git a/chrome/browser/ui/cocoa/one_click_signin_dialog_controller.h b/chrome/browser/ui/cocoa/one_click_signin_dialog_controller.h
index 2cfa36b..4a7f082 100644
--- a/chrome/browser/ui/cocoa/one_click_signin_dialog_controller.h
+++ b/chrome/browser/ui/cocoa/one_click_signin_dialog_controller.h
@@ -7,7 +7,7 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "base/memory/scoped_ptr.h"
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/cocoa/constrained_window/constrained_window_mac.h"
@@ -40,7 +40,7 @@
   void PerformClose();
 
   scoped_ptr<ConstrainedWindowMac> constrained_window_;
-  scoped_nsobject<OneClickSigninViewController> view_controller_;
+  base::scoped_nsobject<OneClickSigninViewController> view_controller_;
 };
 
 #endif  // CHROME_BROWSER_UI_COCOA_ONE_CLICK_SIGNIN_DIALOG_CONTROLLER_H_
diff --git a/chrome/browser/ui/cocoa/one_click_signin_dialog_controller.mm b/chrome/browser/ui/cocoa/one_click_signin_dialog_controller.mm
index 00b5a08..6078a50 100644
--- a/chrome/browser/ui/cocoa/one_click_signin_dialog_controller.mm
+++ b/chrome/browser/ui/cocoa/one_click_signin_dialog_controller.mm
@@ -22,13 +22,12 @@
         closeCallback:close_callback
          isSyncDialog:YES
          errorMessage:nil]);
-  scoped_nsobject<NSWindow> window([[ConstrainedWindowCustomWindow alloc]
+  base::scoped_nsobject<NSWindow> window([[ConstrainedWindowCustomWindow alloc]
       initWithContentRect:[[view_controller_ view] bounds]]);
   [[window contentView] addSubview:[view_controller_ view]];
 
-  scoped_nsobject<CustomConstrainedWindowSheet> sheet(
-      [[CustomConstrainedWindowSheet alloc]
-          initWithCustomWindow:window]);
+  base::scoped_nsobject<CustomConstrainedWindowSheet> sheet(
+      [[CustomConstrainedWindowSheet alloc] initWithCustomWindow:window]);
   constrained_window_.reset(new ConstrainedWindowMac(
       this, web_contents, sheet));
 }
diff --git a/chrome/browser/ui/cocoa/one_click_signin_view_controller.h b/chrome/browser/ui/cocoa/one_click_signin_view_controller.h
index 004ed34..02d71ae 100644
--- a/chrome/browser/ui/cocoa/one_click_signin_view_controller.h
+++ b/chrome/browser/ui/cocoa/one_click_signin_view_controller.h
@@ -8,7 +8,7 @@
 #import <Cocoa/Cocoa.h>
 
 #include "base/callback.h"
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "chrome/browser/ui/browser_window.h"
 
 @class BrowserWindowController;
@@ -31,13 +31,13 @@
   // This is YES if the user clicked the Learn More link before another action.
   BOOL clickedLearnMore_;
 
-  scoped_nsobject<NSString> errorMessage_;
+  base::scoped_nsobject<NSString> errorMessage_;
 
   // Text fields don't work as well with embedded links as text views, but
   // text views cannot conveniently be created in IB. The xib file contains
   // a text field |informativePlaceholderTextField_| that's replaced by this
   // text view |promo_| in -awakeFromNib.
-  scoped_nsobject<HyperlinkTextView> informativeTextView_;
+  base::scoped_nsobject<HyperlinkTextView> informativeTextView_;
   BrowserWindow::StartSyncCallback startSyncCallback_;
   base::Closure closeCallback_;
   content::WebContents* webContents_;
diff --git a/chrome/browser/ui/cocoa/panels/panel_cocoa_unittest.mm b/chrome/browser/ui/cocoa/panels/panel_cocoa_unittest.mm
index b0eda33..a817812 100644
--- a/chrome/browser/ui/cocoa/panels/panel_cocoa_unittest.mm
+++ b/chrome/browser/ui/cocoa/panels/panel_cocoa_unittest.mm
@@ -296,7 +296,7 @@
 TEST_F(PanelCocoaTest, MenuItems) {
   Panel* panel = CreateTestPanel("Test Panel");
 
-  scoped_nsobject<NSMenu> menu([[NSMenu alloc] initWithTitle:@""]);
+  base::scoped_nsobject<NSMenu> menu([[NSMenu alloc] initWithTitle:@""]);
   NSMenuItem* close_tab_menu_item = CreateMenuItem(menu, IDC_CLOSE_TAB);
   NSMenuItem* new_tab_menu_item = CreateMenuItem(menu, IDC_NEW_TAB);
   NSMenuItem* new_tab_window_item = CreateMenuItem(menu, IDC_NEW_WINDOW);
diff --git a/chrome/browser/ui/cocoa/panels/panel_stack_window_cocoa.h b/chrome/browser/ui/cocoa/panels/panel_stack_window_cocoa.h
index 35824de..442044c 100644
--- a/chrome/browser/ui/cocoa/panels/panel_stack_window_cocoa.h
+++ b/chrome/browser/ui/cocoa/panels/panel_stack_window_cocoa.h
@@ -11,7 +11,7 @@
 #include <map>
 
 #include "base/basictypes.h"
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "base/memory/scoped_ptr.h"
 #include "chrome/browser/ui/panels/native_panel_stack_window.h"
 #include "ui/gfx/rect.h"
@@ -70,7 +70,7 @@
   NativePanelStackWindowDelegate* delegate_;
 
   // The underlying window.
-  scoped_nsobject<NSWindow> window_;
+  base::scoped_nsobject<NSWindow> window_;
 
   Panels panels_;
 
@@ -85,7 +85,8 @@
   // Used to animate the bounds changes at a synchronized pace.
   // Lifetime controlled manually, needs more than just |release| to terminate.
   NSViewAnimation* bounds_animation_;
-  scoped_nsobject<BatchBoundsAnimationDelegate> bounds_animation_delegate_;
+  base::scoped_nsobject<BatchBoundsAnimationDelegate>
+      bounds_animation_delegate_;
 
   DISALLOW_COPY_AND_ASSIGN(PanelStackWindowCocoa);
 };
diff --git a/chrome/browser/ui/cocoa/panels/panel_stack_window_cocoa.mm b/chrome/browser/ui/cocoa/panels/panel_stack_window_cocoa.mm
index ee2045d..90ba6e0 100644
--- a/chrome/browser/ui/cocoa/panels/panel_stack_window_cocoa.mm
+++ b/chrome/browser/ui/cocoa/panels/panel_stack_window_cocoa.mm
@@ -226,7 +226,7 @@
   int num_of_animations = 1;
   if (need_to_animate_individual_panels)
     num_of_animations += bounds_updates_.size();
-  scoped_nsobject<NSMutableArray> animations(
+  base::scoped_nsobject<NSMutableArray> animations(
       [[NSMutableArray alloc] initWithCapacity:num_of_animations]);
 
   // Add the animation for each panel in the update list.
diff --git a/chrome/browser/ui/cocoa/panels/panel_titlebar_view_cocoa.h b/chrome/browser/ui/cocoa/panels/panel_titlebar_view_cocoa.h
index e353fb4..dc139e5 100644
--- a/chrome/browser/ui/cocoa/panels/panel_titlebar_view_cocoa.h
+++ b/chrome/browser/ui/cocoa/panels/panel_titlebar_view_cocoa.h
@@ -61,12 +61,12 @@
   BOOL isDrawingAttention_;
 
   // "Glint" animation is used in "Draw Attention" mode.
-  scoped_nsobject<RepaintAnimation> glintAnimation_;
-  scoped_nsobject<NSTimer> glintAnimationTimer_;
+  base::scoped_nsobject<RepaintAnimation> glintAnimation_;
+  base::scoped_nsobject<NSTimer> glintAnimationTimer_;
   int glintCounter_;
 
   // Drag support.
-  scoped_nsobject<MouseDragController> dragController_;
+  base::scoped_nsobject<MouseDragController> dragController_;
 }
 
 // Callbacks from Close, Minimize, and Restore buttons.
diff --git a/chrome/browser/ui/cocoa/panels/panel_titlebar_view_cocoa.mm b/chrome/browser/ui/cocoa/panels/panel_titlebar_view_cocoa.mm
index 673e628..3a9dde6 100644
--- a/chrome/browser/ui/cocoa/panels/panel_titlebar_view_cocoa.mm
+++ b/chrome/browser/ui/cocoa/panels/panel_titlebar_view_cocoa.mm
@@ -146,7 +146,7 @@
     NSRectFillUsingOperation([self bounds], NSCompositeSourceOver);
 
     if ([glintAnimation_ isAnimating]) {
-      scoped_nsobject<NSGradient> glint([NSGradient alloc]);
+      base::scoped_nsobject<NSGradient> glint([NSGradient alloc]);
       float currentAlpha = 0.8 * [glintAnimation_ currentValue];
       NSColor* startColor = [NSColor colorWithCalibratedWhite:1.0
                                                         alpha:currentAlpha];
@@ -406,6 +406,8 @@
 
   if ([event clickCount] == 1)
     [controller_ onTitlebarMouseClicked:[event modifierFlags]];
+  else if ([event clickCount] == 2)
+    [controller_ minimizeButtonClicked:[event modifierFlags]];
 }
 
 - (void)mouseDragged:(NSEvent*)event {
diff --git a/chrome/browser/ui/cocoa/panels/panel_window_controller_cocoa.h b/chrome/browser/ui/cocoa/panels/panel_window_controller_cocoa.h
index 3e8bc57..6627170 100644
--- a/chrome/browser/ui/cocoa/panels/panel_window_controller_cocoa.h
+++ b/chrome/browser/ui/cocoa/panels/panel_window_controller_cocoa.h
@@ -11,7 +11,7 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "base/memory/scoped_ptr.h"
 #import "chrome/browser/ui/cocoa/chrome_browser_window.h"
 #include "chrome/browser/ui/panels/panel.h"
@@ -29,7 +29,7 @@
  @private
   IBOutlet PanelTitlebarViewCocoa* titlebar_view_;
   scoped_ptr<PanelCocoa> windowShim_;
-  scoped_nsobject<NSString> pendingWindowTitle_;
+  base::scoped_nsobject<NSString> pendingWindowTitle_;
   NSViewAnimation* boundsAnimation_;  // Lifetime controlled manually, needs
                                       // more then just |release| to terminate.
   BOOL animateOnBoundsChange_;
@@ -42,7 +42,7 @@
   // window over other application windows due to panels having a higher
   // priority NSWindowLevel, so we distinguish between the two scenarios.
   BOOL activationRequestedByPanel_;
-  scoped_nsobject<NSView> overlayView_;
+  base::scoped_nsobject<NSView> overlayView_;
 }
 
 // Load the window nib and do any Cocoa-specific initialization.
diff --git a/chrome/browser/ui/cocoa/panels/panel_window_controller_cocoa.mm b/chrome/browser/ui/cocoa/panels/panel_window_controller_cocoa.mm
index c335faa..3d3dbe8 100644
--- a/chrome/browser/ui/cocoa/panels/panel_window_controller_cocoa.mm
+++ b/chrome/browser/ui/cocoa/panels/panel_window_controller_cocoa.mm
@@ -94,6 +94,10 @@
       [[app windows] count] == static_cast<NSUInteger>([controller numPanels]);
 }
 
+- (void)performMiniaturize:(id)sender {
+  [[self windowController] minimizeButtonClicked:0];
+}
+
 // Ignore key events if window cannot become key window to fix problem
 // where keyboard input is still going into a minimized panel even though
 // the app has been deactivated in -[PanelWindowControllerCocoa deactivate:].
@@ -112,12 +116,12 @@
 @interface PanelResizeByMouseOverlay : NSView <MouseDragControllerClient> {
  @private
    Panel* panel_;
-   scoped_nsobject<MouseDragController> dragController_;
-   scoped_nsobject<NSCursor> dragCursor_;
-   scoped_nsobject<NSCursor> eastWestCursor_;
-   scoped_nsobject<NSCursor> northSouthCursor_;
-   scoped_nsobject<NSCursor> northEastSouthWestCursor_;
-   scoped_nsobject<NSCursor> northWestSouthEastCursor_;
+   base::scoped_nsobject<MouseDragController> dragController_;
+   base::scoped_nsobject<NSCursor> dragCursor_;
+   base::scoped_nsobject<NSCursor> eastWestCursor_;
+   base::scoped_nsobject<NSCursor> northSouthCursor_;
+   base::scoped_nsobject<NSCursor> northEastSouthWestCursor_;
+   base::scoped_nsobject<NSCursor> northWestSouthEastCursor_;
    NSRect leftCursorRect_;
    NSRect rightCursorRect_;
    NSRect topCursorRect_;
diff --git a/chrome/browser/ui/cocoa/presentation_mode_controller.h b/chrome/browser/ui/cocoa/presentation_mode_controller.h
index 728c2da..8af03b4 100644
--- a/chrome/browser/ui/cocoa/presentation_mode_controller.h
+++ b/chrome/browser/ui/cocoa/presentation_mode_controller.h
@@ -45,16 +45,16 @@
   // hidden, we still need to keep a 1px tall tracking area visible.  Attaching
   // to the content view allows us to do this.  |trackingArea_| can be nil if
   // not in presentation mode or during animations.
-  scoped_nsobject<NSTrackingArea> trackingArea_;
+  base::scoped_nsobject<NSTrackingArea> trackingArea_;
 
   // Pointer to the currently running animation.  Is nil if no animation is
   // running.
-  scoped_nsobject<DropdownAnimation> currentAnimation_;
+  base::scoped_nsobject<DropdownAnimation> currentAnimation_;
 
   // Timers for scheduled showing/hiding of the bar (which are always done with
   // animation).
-  scoped_nsobject<NSTimer> showTimer_;
-  scoped_nsobject<NSTimer> hideTimer_;
+  base::scoped_nsobject<NSTimer> showTimer_;
+  base::scoped_nsobject<NSTimer> hideTimer_;
 
   // Holds the current bounds of |trackingArea_|, even if |trackingArea_| is
   // currently nil.  Used to restore the tracking area when an animation
diff --git a/chrome/browser/ui/cocoa/presentation_mode_controller.mm b/chrome/browser/ui/cocoa/presentation_mode_controller.mm
index 8b11839..ccba724 100644
--- a/chrome/browser/ui/cocoa/presentation_mode_controller.mm
+++ b/chrome/browser/ui/cocoa/presentation_mode_controller.mm
@@ -53,7 +53,7 @@
 // duration may be less than |fullDuration|.
 - (id)initWithFraction:(CGFloat)fromFraction
           fullDuration:(CGFloat)fullDuration
-        animationCurve:(NSInteger)animationCurve
+        animationCurve:(NSAnimationCurve)animationCurve
             controller:(PresentationModeController*)controller;
 
 @end
@@ -65,7 +65,7 @@
 
 - (id)initWithFraction:(CGFloat)toFraction
           fullDuration:(CGFloat)fullDuration
-        animationCurve:(NSInteger)animationCurve
+        animationCurve:(NSAnimationCurve)animationCurve
             controller:(PresentationModeController*)controller {
   // Calculate the effective duration, based on the current shown fraction.
   DCHECK(controller);
diff --git a/chrome/browser/ui/cocoa/profile_menu_controller.h b/chrome/browser/ui/cocoa/profile_menu_controller.h
index 1610fa6..d7e552b 100644
--- a/chrome/browser/ui/cocoa/profile_menu_controller.h
+++ b/chrome/browser/ui/cocoa/profile_menu_controller.h
@@ -7,7 +7,6 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
 #include "base/memory/scoped_ptr.h"
 
 class AvatarMenuModel;
diff --git a/chrome/browser/ui/cocoa/profile_menu_controller.mm b/chrome/browser/ui/cocoa/profile_menu_controller.mm
index 4f08ec4..f1ee54e 100644
--- a/chrome/browser/ui/cocoa/profile_menu_controller.mm
+++ b/chrome/browser/ui/cocoa/profile_menu_controller.mm
@@ -4,6 +4,7 @@
 
 #import "chrome/browser/ui/cocoa/profile_menu_controller.h"
 
+#include "base/mac/scoped_nsobject.h"
 #include "base/strings/sys_string_conversions.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/profiles/avatar_menu_model.h"
@@ -66,8 +67,7 @@
   if ((self = [super init])) {
     mainMenuItem_ = item;
 
-    scoped_nsobject<NSMenu> menu(
-        [[NSMenu alloc] initWithTitle:
+    base::scoped_nsobject<NSMenu> menu([[NSMenu alloc] initWithTitle:
             l10n_util::GetNSStringWithFixup(IDS_PROFILES_OPTIONS_GROUP_NAME)]);
     [mainMenuItem_ setSubmenu:menu];
 
@@ -110,7 +110,7 @@
   if (dock) {
     NSString* headerName =
         l10n_util::GetNSStringWithFixup(IDS_PROFILES_OPTIONS_GROUP_NAME);
-    scoped_nsobject<NSMenuItem> header(
+    base::scoped_nsobject<NSMenuItem> header(
         [[NSMenuItem alloc] initWithTitle:headerName
                                    action:NULL
                             keyEquivalent:@""]);
@@ -213,7 +213,7 @@
 }
 
 - (NSMenuItem*)createItemWithTitle:(NSString*)title action:(SEL)sel {
-  scoped_nsobject<NSMenuItem> item(
+  base::scoped_nsobject<NSMenuItem> item(
       [[NSMenuItem alloc] initWithTitle:title action:sel keyEquivalent:@""]);
   [item setTarget:self];
   return [item.release() autorelease];
diff --git a/chrome/browser/ui/cocoa/profile_menu_controller_unittest.mm b/chrome/browser/ui/cocoa/profile_menu_controller_unittest.mm
index 06f22b3..a0b001c 100644
--- a/chrome/browser/ui/cocoa/profile_menu_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/profile_menu_controller_unittest.mm
@@ -4,7 +4,7 @@
 
 #import "chrome/browser/ui/cocoa/profile_menu_controller.h"
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "base/threading/thread_restrictions.h"
 #include "chrome/browser/profiles/avatar_menu_model.h"
 #include "chrome/browser/profiles/profile_manager.h"
@@ -71,8 +71,8 @@
   NSMenuItem* menu_item() { return item_.get(); }
 
  private:
-  scoped_nsobject<NSMenuItem> item_;
-  scoped_nsobject<ProfileMenuController> controller_;
+  base::scoped_nsobject<NSMenuItem> item_;
+  base::scoped_nsobject<ProfileMenuController> controller_;
 };
 
 TEST_F(ProfileMenuControllerTest, InitializeMenu) {
@@ -124,7 +124,7 @@
 }
 
 TEST_F(ProfileMenuControllerTest, InsertItems) {
-  scoped_nsobject<NSMenu> menu([[NSMenu alloc] initWithTitle: @""]);
+  base::scoped_nsobject<NSMenu> menu([[NSMenu alloc] initWithTitle:@""]);
   ASSERT_EQ(0, [menu numberOfItems]);
 
   // With only one profile, insertItems should be a no-op.
@@ -197,8 +197,7 @@
   ASSERT_EQ(7, [menu numberOfItems]);
 
   // Create a browser and "show" it.
-  Browser::CreateParams profile2_params(profile2,
-                                        chrome::HOST_DESKTOP_TYPE_NATIVE);
+  Browser::CreateParams profile2_params(profile2, chrome::GetActiveDesktop());
   scoped_ptr<Browser> p2_browser(
       chrome::CreateBrowserWithTestWindowForParams(&profile2_params));
   BrowserList::SetLastActive(p2_browser.get());
@@ -209,8 +208,7 @@
   VerifyProfileNamedIsActive(@"Profile 2", __LINE__);
 
   // Open a new browser and make sure it takes effect.
-  Browser::CreateParams profile3_params(profile3,
-                                        chrome::HOST_DESKTOP_TYPE_NATIVE);
+  Browser::CreateParams profile3_params(profile3, chrome::GetActiveDesktop());
   scoped_ptr<Browser> p3_browser(
       chrome::CreateBrowserWithTestWindowForParams(&profile3_params));
   BrowserList::SetLastActive(p3_browser.get());
diff --git a/chrome/browser/ui/cocoa/profile_signin_confirmation_dialog_cocoa.h b/chrome/browser/ui/cocoa/profile_signin_confirmation_dialog_cocoa.h
index 561c0d6..227840e 100644
--- a/chrome/browser/ui/cocoa/profile_signin_confirmation_dialog_cocoa.h
+++ b/chrome/browser/ui/cocoa/profile_signin_confirmation_dialog_cocoa.h
@@ -11,7 +11,7 @@
 
 #include "base/callback.h"
 #include "base/compiler_specific.h"
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/ui/cocoa/constrained_window/constrained_window_mac.h"
@@ -49,7 +49,7 @@
   virtual void OnConstrainedWindowClosed(ConstrainedWindowMac* window) OVERRIDE;
 
   // Controller for the dialog view.
-  scoped_nsobject<ProfileSigninConfirmationViewController> controller_;
+  base::scoped_nsobject<ProfileSigninConfirmationViewController> controller_;
 
   // The constrained window that contains the dialog view.
   scoped_ptr<ConstrainedWindowMac> window_;
diff --git a/chrome/browser/ui/cocoa/profile_signin_confirmation_dialog_cocoa.mm b/chrome/browser/ui/cocoa/profile_signin_confirmation_dialog_cocoa.mm
index 44fb43f..c1c8a49 100644
--- a/chrome/browser/ui/cocoa/profile_signin_confirmation_dialog_cocoa.mm
+++ b/chrome/browser/ui/cocoa/profile_signin_confirmation_dialog_cocoa.mm
@@ -72,13 +72,11 @@
      offerProfileCreation:offer_profile_creation]);
 
   // Setup the constrained window that will show the view.
-  scoped_nsobject<NSWindow> window(
-      [[ConstrainedWindowCustomWindow alloc]
-          initWithContentRect:[[controller_ view] bounds]]);
+  base::scoped_nsobject<NSWindow> window([[ConstrainedWindowCustomWindow alloc]
+      initWithContentRect:[[controller_ view] bounds]]);
   [[window contentView] addSubview:[controller_ view]];
-  scoped_nsobject<CustomConstrainedWindowSheet> sheet(
-      [[CustomConstrainedWindowSheet alloc]
-          initWithCustomWindow:window]);
+  base::scoped_nsobject<CustomConstrainedWindowSheet> sheet(
+      [[CustomConstrainedWindowSheet alloc] initWithCustomWindow:window]);
   window_.reset(new ConstrainedWindowMac(this, web_contents, sheet));
 }
 
diff --git a/chrome/browser/ui/cocoa/profile_signin_confirmation_view_controller.h b/chrome/browser/ui/cocoa/profile_signin_confirmation_view_controller.h
index 2b9f2d1..ffde5c4 100644
--- a/chrome/browser/ui/cocoa/profile_signin_confirmation_view_controller.h
+++ b/chrome/browser/ui/cocoa/profile_signin_confirmation_view_controller.h
@@ -9,7 +9,7 @@
 #include <string>
 
 #include "base/callback.h"
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "chrome/browser/ui/cocoa/constrained_window/constrained_window_button.h"
 
 @class HyperlinkTextView;
@@ -38,14 +38,14 @@
   base::Closure closeDialogCallback_;
 
   // UI elements.
-  scoped_nsobject<NSBox> promptBox_;
-  scoped_nsobject<NSButton> closeButton_;
-  scoped_nsobject<NSTextField> titleField_;
-  scoped_nsobject<NSTextField> promptField_;
-  scoped_nsobject<NSTextView> explanationField_;
-  scoped_nsobject<NSButton> createProfileLinkField_;
-  scoped_nsobject<ConstrainedWindowButton> cancelButton_;
-  scoped_nsobject<ConstrainedWindowButton> okButton_;
+  base::scoped_nsobject<NSBox> promptBox_;
+  base::scoped_nsobject<NSButton> closeButton_;
+  base::scoped_nsobject<NSTextField> titleField_;
+  base::scoped_nsobject<NSTextField> promptField_;
+  base::scoped_nsobject<NSTextView> explanationField_;
+  base::scoped_nsobject<ConstrainedWindowButton> createProfileButton_;
+  base::scoped_nsobject<ConstrainedWindowButton> cancelButton_;
+  base::scoped_nsobject<ConstrainedWindowButton> okButton_;
 }
 
 - (id)initWithBrowser:(Browser*)browser
@@ -63,7 +63,7 @@
 @interface ProfileSigninConfirmationViewController (TestingAPI)
 
 @property(readonly, nonatomic) ui::ProfileSigninConfirmationDelegate* delegate;
-@property(readonly, nonatomic) NSButton* createProfileLinkField;
+@property(readonly, nonatomic) NSButton* createProfileButton;
 @property(readonly, nonatomic) NSTextView* explanationField;
 
 @end
diff --git a/chrome/browser/ui/cocoa/profile_signin_confirmation_view_controller.mm b/chrome/browser/ui/cocoa/profile_signin_confirmation_view_controller.mm
index e6d6d77..367556b 100644
--- a/chrome/browser/ui/cocoa/profile_signin_confirmation_view_controller.mm
+++ b/chrome/browser/ui/cocoa/profile_signin_confirmation_view_controller.mm
@@ -59,7 +59,7 @@
 
 // Make the indicated range of characters in a text view bold.
 void MakeTextBold(NSTextField* textField, int offset, int length) {
-  scoped_nsobject<NSMutableAttributedString> text(
+  base::scoped_nsobject<NSMutableAttributedString> text(
       [[textField attributedStringValue] mutableCopy]);
   NSFont* currentFont =
       [text attribute:NSFontAttributeName
@@ -96,7 +96,7 @@
     const string16& link,
     int offset,
     const ui::ResourceBundle::FontStyle& font_style) {
-  scoped_nsobject<HyperlinkTextView> textView(
+  base::scoped_nsobject<HyperlinkTextView> textView(
       [[HyperlinkTextView alloc] initWithFrame:NSZeroRect]);
   NSFont* font = ui::ResourceBundle::GetSharedInstance().GetFont(
       font_style).GetNativeFont();
@@ -182,6 +182,10 @@
       [[ConstrainedWindowButton alloc] initWithFrame:NSZeroRect]);
   okButton_.reset(
       [[ConstrainedWindowButton alloc] initWithFrame:NSZeroRect]);
+  if (offerProfileCreation_) {
+    createProfileButton_.reset(
+        [[ConstrainedWindowButton alloc] initWithFrame:NSZeroRect]);
+  }
   promptBox_.reset(
       [[NSBox alloc] initWithFrame:NSZeroRect]);
   closeButton_.reset(
@@ -229,13 +233,11 @@
 
   // Create Profile link.
   if (offerProfileCreation_) {
-    createProfileLinkField_.reset(
-        [AddLinkButton([self view],
-                       l10n_util::GetStringUTF16(
-                           IDS_ENTERPRISE_SIGNIN_CREATE_NEW_PROFILE_NEW_STYLE),
-                       self,
-                       @selector(createProfile:)) retain]);
-    [createProfileLinkField_ sizeToFit];
+    [self addButton:createProfileButton_
+          withTitle:IDS_ENTERPRISE_SIGNIN_CREATE_NEW_PROFILE_NEW_STYLE
+             target:self
+             action:@selector(createProfile:)
+     shouldAutoSize:YES];
   }
 
   // Add the title label.
@@ -249,7 +251,7 @@
 
   // Compute the dialog width using the title and buttons.
   const CGFloat buttonsWidth =
-      (offerProfileCreation_ ? NSWidth([createProfileLinkField_ frame]) : 0) +
+      (offerProfileCreation_ ? NSWidth([createProfileButton_ frame]) : 0) +
       kButtonGap + NSWidth([cancelButton_ frame]) +
       kButtonGap + NSWidth([okButton_ frame]);
   const CGFloat titleWidth =
@@ -276,17 +278,17 @@
   [[self view] addSubview:promptBox_];
 
   // Prompt text.
-  std::vector<size_t> offsets;
+  size_t offset;
   const string16 domain = ASCIIToUTF16(gaia::ExtractDomainName(username_));
   const string16 username = ASCIIToUTF16(username_);
   const string16 prompt_text =
       l10n_util::GetStringFUTF16(
           IDS_ENTERPRISE_SIGNIN_ALERT_NEW_STYLE,
-          username, domain, &offsets);
+          domain, &offset);
   promptField_.reset(
       [AddTextField(promptBox_, prompt_text, chrome_style::kTextFontStyle)
           retain]);
-  MakeTextBold(promptField_, offsets[1], domain.size());
+  MakeTextBold(promptField_, offset, domain.size());
   [promptField_ setFrame:ComputeFrame(
         [promptField_ attributedStringValue], width, 0.0)];
 
@@ -300,7 +302,7 @@
   [promptBox_ setFrame:NSMakeRect(0, 0, dialogWidth, boxHeight)];
 
   // Explanation text.
-  offsets.clear();
+  std::vector<size_t> offsets;
   const string16 learn_more_text =
       l10n_util::GetStringUTF16(
           IDS_ENTERPRISE_SIGNIN_PROFILE_LINK_LEARN_MORE);
@@ -326,24 +328,21 @@
 
   // Layout the elements, starting at the bottom and moving up.
 
-  CGFloat curX = chrome_style::kHorizontalPadding;
+  CGFloat curX = dialogWidth - chrome_style::kHorizontalPadding;
   CGFloat curY = chrome_style::kClientBottomPadding;
 
-  // CreateProfile link sticks to the bottom-left, vertically centered with
-  // the other buttons.
+  // Buttons should go |Cancel|Continue|CreateProfile|, unless
+  // |CreateProfile| isn't shown.
   if (offerProfileCreation_) {
-    CGFloat linkHeight = NSHeight([createProfileLinkField_ frame]);
-    CGFloat buttonHeight = NSHeight([okButton_ frame]);
-    CGFloat dy = roundf((buttonHeight - linkHeight) / 2.0 + 1.0);
-    [createProfileLinkField_ setFrameOrigin:NSMakePoint(curX, curY + dy)];
+    curX -= NSWidth([createProfileButton_ frame]);
+    [createProfileButton_ setFrameOrigin:NSMakePoint(curX, curY)];
+    curX -= kButtonGap;
   }
-
-  // OK and Cancel buttons stick to the bottom-right.
-  curX = dialogWidth - chrome_style::kHorizontalPadding;
   curX -= NSWidth([okButton_ frame]);
   [okButton_ setFrameOrigin:NSMakePoint(curX, curY)];
   curX -= (kButtonGap + NSWidth([cancelButton_ frame]));
   [cancelButton_ setFrameOrigin:NSMakePoint(curX, curY)];
+
   curY += NSHeight([cancelButton_ frame]);
 
   // Explanation text.
@@ -463,8 +462,8 @@
   return delegate_;
 }
 
-- (NSButton*)createProfileLinkField {
-  return createProfileLinkField_.get();
+- (NSButton*)createProfileButton {
+  return createProfileButton_.get();
 }
 
 - (NSTextView*)explanationField {
diff --git a/chrome/browser/ui/cocoa/profile_signin_confirmation_view_controller_browsertest.mm b/chrome/browser/ui/cocoa/profile_signin_confirmation_view_controller_browsertest.mm
index 939875d..0d5a5c4 100644
--- a/chrome/browser/ui/cocoa/profile_signin_confirmation_view_controller_browsertest.mm
+++ b/chrome/browser/ui/cocoa/profile_signin_confirmation_view_controller_browsertest.mm
@@ -6,7 +6,7 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "base/strings/sys_string_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/ui/browser.h"
@@ -69,10 +69,10 @@
   void OnClose() { closed_ = true; }
 
   // The window containing the dialog.
-  scoped_nsobject<NSWindow> window_;
+  base::scoped_nsobject<NSWindow> window_;
 
   // Dialog under test.
-  scoped_nsobject<ProfileSigninConfirmationViewController> controller_;
+  base::scoped_nsobject<ProfileSigninConfirmationViewController> controller_;
 
   // Visible for testing UI interactions.
   bool continued_;
@@ -160,7 +160,7 @@
                        DoNotOfferNewProfile) {
   SetupDialog(/*offerProfileCreation = */ false);
   // Create Profile button shouldn't exist.
-  EXPECT_NSEQ(nil, [controller_ createProfileLinkField]);
+  EXPECT_NSEQ(nil, [controller_ createProfileButton]);
   // Explanation shouldn't mention creating a new profile.
   NSString* explanationWithoutCreateProfile = base::SysUTF16ToNSString(
       l10n_util::GetStringFUTF16(
@@ -174,9 +174,9 @@
                        OfferNewProfile) {
   SetupDialog(/*offerProfileCreation = */ true);
   // Create Profile button should exist and be visible.
-  EXPECT_NSNE(nil, [controller_ createProfileLinkField]);
+  EXPECT_NSNE(nil, [controller_ createProfileButton]);
   EXPECT_TRUE([[[controller_ view] subviews]
-                containsObject:[controller_ createProfileLinkField]]);
+                containsObject:[controller_ createProfileButton]]);
   NSString* explanationWithCreateProfile = base::SysUTF16ToNSString(
       l10n_util::GetStringFUTF16(
           IDS_ENTERPRISE_SIGNIN_EXPLANATION_WITH_PROFILE_CREATION_NEW_STYLE,
diff --git a/chrome/browser/ui/cocoa/run_loop_testing.mm b/chrome/browser/ui/cocoa/run_loop_testing.mm
index b85722a..f79aa53 100644
--- a/chrome/browser/ui/cocoa/run_loop_testing.mm
+++ b/chrome/browser/ui/cocoa/run_loop_testing.mm
@@ -6,7 +6,7 @@
 
 #import <Foundation/Foundation.h>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "base/message_loop/message_pump_mac.h"
 
 // This class is scheduled with a delayed selector to quit the message pump.
@@ -42,8 +42,8 @@
 
   // Put a delayed selector on the queue. All other pending delayed selectors
   // will run before this, after which the internal loop can end.
-  scoped_nsobject<CocoaQuitTask> quit_task(
-      [[CocoaQuitTask alloc] initWithMessagePump:message_pump]);
+  base::scoped_nsobject<CocoaQuitTask> quit_task(
+      [[CocoaQuitTask alloc] initWithMessagePump:message_pump.get()]);
 
   [quit_task performSelector:@selector(doQuit)
                   withObject:nil
diff --git a/chrome/browser/ui/cocoa/run_loop_testing_unittest.mm b/chrome/browser/ui/cocoa/run_loop_testing_unittest.mm
index d281c46..760f985 100644
--- a/chrome/browser/ui/cocoa/run_loop_testing_unittest.mm
+++ b/chrome/browser/ui/cocoa/run_loop_testing_unittest.mm
@@ -6,7 +6,7 @@
 
 #import <Foundation/Foundation.h>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 @interface TestDelayed : NSObject {
@@ -36,7 +36,7 @@
 @end
 
 TEST(RunLoopTesting, RunAllPending) {
-  scoped_nsobject<TestDelayed> tester([[TestDelayed alloc] init]);
+  base::scoped_nsobject<TestDelayed> tester([[TestDelayed alloc] init]);
   EXPECT_FALSE([tester didWork]);
 
   chrome::testing::NSRunLoopRunAllPending();
@@ -45,8 +45,8 @@
 }
 
 TEST(RunLoopTesting, NestedWork) {
-  scoped_nsobject<TestDelayed> tester([[TestDelayed alloc] init]);
-  scoped_nsobject<TestDelayed> nested([[TestDelayed alloc] init]);
+  base::scoped_nsobject<TestDelayed> tester([[TestDelayed alloc] init]);
+  base::scoped_nsobject<TestDelayed> nested([[TestDelayed alloc] init]);
   [tester setNext:nested];
 
   EXPECT_FALSE([tester didWork]);
diff --git a/chrome/browser/ui/cocoa/speech_recognition_bubble_cocoa.mm b/chrome/browser/ui/cocoa/speech_recognition_bubble_cocoa.mm
index eb48acb..c308f5a 100644
--- a/chrome/browser/ui/cocoa/speech_recognition_bubble_cocoa.mm
+++ b/chrome/browser/ui/cocoa/speech_recognition_bubble_cocoa.mm
@@ -6,7 +6,7 @@
 
 #include "chrome/browser/speech/speech_recognition_bubble.h"
 
-#import "base/memory/scoped_nsobject.h"
+#import "base/mac/scoped_nsobject.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/cocoa/browser_window_cocoa.h"
 #include "chrome/browser/ui/cocoa/browser_window_controller.h"
@@ -35,7 +35,7 @@
   virtual void UpdateImage() OVERRIDE;
 
  private:
-  scoped_nsobject<SpeechRecognitionWindowController> window_;
+  base::scoped_nsobject<SpeechRecognitionWindowController> window_;
   Delegate* delegate_;
   gfx::Rect element_rect_;
 };
diff --git a/chrome/browser/ui/cocoa/ssl_client_certificate_selector_cocoa.h b/chrome/browser/ui/cocoa/ssl_client_certificate_selector_cocoa.h
index 88d9b79..ce94e3c 100644
--- a/chrome/browser/ui/cocoa/ssl_client_certificate_selector_cocoa.h
+++ b/chrome/browser/ui/cocoa/ssl_client_certificate_selector_cocoa.h
@@ -9,8 +9,8 @@
 #include <vector>
 
 #include "base/mac/scoped_cftyperef.h"
+#include "base/mac/scoped_nsobject.h"
 #include "base/memory/ref_counted.h"
-#include "base/memory/scoped_nsobject.h"
 #include "base/memory/scoped_ptr.h"
 #include "chrome/browser/ssl/ssl_client_certificate_selector.h"
 #import "chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_sheet.h"
@@ -24,14 +24,14 @@
     : NSObject<ConstrainedWindowSheet> {
  @private
   // The list of identities offered to the user.
-  base::mac::ScopedCFTypeRef<CFMutableArrayRef> identities_;
+  base::ScopedCFTypeRef<CFMutableArrayRef> identities_;
   // The corresponding list of certificates.
   std::vector<scoped_refptr<net::X509Certificate> > certificates_;
   // A C++ object to bridge SSLClientAuthObserver notifications to us.
   scoped_ptr<SSLClientAuthObserverCocoaBridge> observer_;
-  scoped_nsobject<SFChooseIdentityPanel> panel_;
+  base::scoped_nsobject<SFChooseIdentityPanel> panel_;
   scoped_ptr<ConstrainedWindowMac> constrainedWindow_;
-  scoped_nsobject<NSWindow> overlayWindow_;
+  base::scoped_nsobject<NSWindow> overlayWindow_;
   BOOL closePending_;
   // A copy of the sheet's frame used to restore on show.
   NSRect oldSheetFrame_;
diff --git a/chrome/browser/ui/cocoa/ssl_client_certificate_selector_cocoa.mm b/chrome/browser/ui/cocoa/ssl_client_certificate_selector_cocoa.mm
index 232d55b..b3c9c05 100644
--- a/chrome/browser/ui/cocoa/ssl_client_certificate_selector_cocoa.mm
+++ b/chrome/browser/ui/cocoa/ssl_client_certificate_selector_cocoa.mm
@@ -111,7 +111,7 @@
     CFIndex index =
         CFArrayGetFirstIndexOfValue(identities_, range, [panel_ identity]);
     if (index != -1)
-      cert = certificates_[index];
+      cert = certificates_[index].get();
     else
       NOTREACHED();
   }
diff --git a/chrome/browser/ui/cocoa/status_bubble_mac.mm b/chrome/browser/ui/cocoa/status_bubble_mac.mm
index 99f8d98..e5e46e0 100644
--- a/chrome/browser/ui/cocoa/status_bubble_mac.mm
+++ b/chrome/browser/ui/cocoa/status_bubble_mac.mm
@@ -374,7 +374,7 @@
   // teardown sequence in BWC guarantees that |parent_| outlives the status
   // bubble and that the StatusBubble is torn down completely prior to the
   // window going away.
-  scoped_nsobject<BubbleView> view(
+  base::scoped_nsobject<BubbleView> view(
       [[BubbleView alloc] initWithFrame:NSZeroRect themeProvider:parent_]);
   [window_ setContentView:view];
 
diff --git a/chrome/browser/ui/cocoa/status_bubble_mac_unittest.mm b/chrome/browser/ui/cocoa/status_bubble_mac_unittest.mm
index b25225f..ffd903b 100644
--- a/chrome/browser/ui/cocoa/status_bubble_mac_unittest.mm
+++ b/chrome/browser/ui/cocoa/status_bubble_mac_unittest.mm
@@ -4,7 +4,7 @@
 
 #include <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/message_loop.h"
 #include "base/strings/utf_string_conversions.h"
@@ -175,7 +175,7 @@
   }
 
   base::MessageLoop message_loop_;
-  scoped_nsobject<StatusBubbleMacTestDelegate> delegate_;
+  base::scoped_nsobject<StatusBubbleMacTestDelegate> delegate_;
   StatusBubbleMac* bubble_;  // Strong.
 };
 
diff --git a/chrome/browser/ui/cocoa/status_icons/status_icon_mac.h b/chrome/browser/ui/cocoa/status_icons/status_icon_mac.h
index 51fa138..8b380c4 100644
--- a/chrome/browser/ui/cocoa/status_icons/status_icon_mac.h
+++ b/chrome/browser/ui/cocoa/status_icons/status_icon_mac.h
@@ -9,7 +9,7 @@
 
 #include "base/compiler_specific.h"
 #include "base/gtest_prod_util.h"
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "base/strings/string16.h"
 #include "chrome/browser/status_icons/desktop_notification_balloon.h"
 #include "chrome/browser/status_icons/status_icon.h"
@@ -46,18 +46,18 @@
 
   // Getter for item_ that allows lazy initialization.
   NSStatusItem* item();
-  scoped_nsobject<NSStatusItem> item_;
+  base::scoped_nsobject<NSStatusItem> item_;
 
-  scoped_nsobject<StatusItemController> controller_;
+  base::scoped_nsobject<StatusItemController> controller_;
 
   // Notification balloon.
   DesktopNotificationBalloon notification_;
 
-  scoped_nsobject<NSString> toolTip_;
+  base::scoped_nsobject<NSString> toolTip_;
 
   // Status menu shown when right-clicking the system icon, if it has been
   // created by |UpdatePlatformContextMenu|.
-  scoped_nsobject<MenuController> menu_;
+  base::scoped_nsobject<MenuController> menu_;
 
   DISALLOW_COPY_AND_ASSIGN(StatusIconMac);
 };
diff --git a/chrome/browser/ui/cocoa/styled_text_field_cell_unittest.mm b/chrome/browser/ui/cocoa/styled_text_field_cell_unittest.mm
index 076583f..a01c2c4 100644
--- a/chrome/browser/ui/cocoa/styled_text_field_cell_unittest.mm
+++ b/chrome/browser/ui/cocoa/styled_text_field_cell_unittest.mm
@@ -4,10 +4,10 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #import "chrome/browser/ui/cocoa/styled_text_field_cell.h"
 #import "chrome/browser/ui/cocoa/styled_text_field_test_helper.h"
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/platform_test.h"
 
@@ -24,13 +24,13 @@
     // decorations.
     const NSRect frame = NSMakeRect(0, 0, kWidth, 30);
 
-    scoped_nsobject<StyledTextFieldTestCell> cell(
+    base::scoped_nsobject<StyledTextFieldTestCell> cell(
         [[StyledTextFieldTestCell alloc] initTextCell:@"Testing"]);
     cell_ = cell.get();
     [cell_ setEditable:YES];
     [cell_ setBordered:YES];
 
-    scoped_nsobject<NSTextField> view(
+    base::scoped_nsobject<NSTextField> view(
         [[NSTextField alloc] initWithFrame:frame]);
     view_ = view.get();
     [view_ setCell:cell_];
diff --git a/chrome/browser/ui/cocoa/styled_text_field_unittest.mm b/chrome/browser/ui/cocoa/styled_text_field_unittest.mm
index c4f066c..0a8ebe9 100644
--- a/chrome/browser/ui/cocoa/styled_text_field_unittest.mm
+++ b/chrome/browser/ui/cocoa/styled_text_field_unittest.mm
@@ -4,11 +4,11 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #import "chrome/browser/ui/cocoa/styled_text_field.h"
 #import "chrome/browser/ui/cocoa/styled_text_field_cell.h"
 #import "chrome/browser/ui/cocoa/styled_text_field_test_helper.h"
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace {
@@ -24,13 +24,13 @@
     // decorations.
     NSRect frame = NSMakeRect(0, 0, kWidth, 30);
 
-    scoped_nsobject<StyledTextFieldTestCell> cell(
+    base::scoped_nsobject<StyledTextFieldTestCell> cell(
         [[StyledTextFieldTestCell alloc] initTextCell:@"Testing"]);
     cell_ = cell.get();
     [cell_ setEditable:YES];
     [cell_ setBordered:YES];
 
-    scoped_nsobject<StyledTextField> field(
+    base::scoped_nsobject<StyledTextField> field(
         [[StyledTextField alloc] initWithFrame:frame]);
     field_ = field.get();
     [field_ setCell:cell_];
diff --git a/chrome/browser/ui/cocoa/tab_contents/instant_overlay_controller_mac.h b/chrome/browser/ui/cocoa/tab_contents/instant_overlay_controller_mac.h
index 2da31f7..836e225 100644
--- a/chrome/browser/ui/cocoa/tab_contents/instant_overlay_controller_mac.h
+++ b/chrome/browser/ui/cocoa/tab_contents/instant_overlay_controller_mac.h
@@ -10,13 +10,11 @@
 #include "chrome/browser/ui/search/instant_overlay_controller.h"
 
 class Browser;
-@class BrowserWindowController;
 @class OverlayableContentsController;
 
 class InstantOverlayControllerMac : public InstantOverlayController {
  public:
   InstantOverlayControllerMac(Browser* browser,
-                              BrowserWindowController* window,
                               OverlayableContentsController* overlay);
   virtual ~InstantOverlayControllerMac();
 
@@ -24,7 +22,6 @@
   // Overridden from InstantOverlayController:
   virtual void OverlayStateChanged(const InstantOverlayModel& model) OVERRIDE;
 
-  BrowserWindowController* const window_;
   OverlayableContentsController* const overlay_;
 
   DISALLOW_COPY_AND_ASSIGN(InstantOverlayControllerMac);
diff --git a/chrome/browser/ui/cocoa/tab_contents/instant_overlay_controller_mac.mm b/chrome/browser/ui/cocoa/tab_contents/instant_overlay_controller_mac.mm
index c5c819e..3510721 100644
--- a/chrome/browser/ui/cocoa/tab_contents/instant_overlay_controller_mac.mm
+++ b/chrome/browser/ui/cocoa/tab_contents/instant_overlay_controller_mac.mm
@@ -4,22 +4,13 @@
 
 #include "chrome/browser/ui/cocoa/tab_contents/instant_overlay_controller_mac.h"
 
-#include "chrome/browser/search/search.h"
-#include "chrome/browser/ui/browser.h"
-#import "chrome/browser/ui/cocoa/browser_window_controller.h"
-#include "chrome/browser/ui/cocoa/tab_contents/instant_overlay_controller_mac.h"
 #import "chrome/browser/ui/cocoa/tab_contents/overlayable_contents_controller.h"
 #include "chrome/browser/ui/search/instant_overlay_model.h"
-#include "chrome/browser/ui/search/search_model.h"
-#include "chrome/browser/ui/search/search_tab_helper.h"
-#include "chrome/browser/ui/tabs/tab_strip_model.h"
 
 InstantOverlayControllerMac::InstantOverlayControllerMac(
     Browser* browser,
-    BrowserWindowController* window,
     OverlayableContentsController* overlay)
     : InstantOverlayController(browser),
-      window_(window),
       overlay_(overlay) {
 }
 
@@ -28,8 +19,6 @@
 
 void InstantOverlayControllerMac::OverlayStateChanged(
     const InstantOverlayModel& model) {
-  bool set_top_bars_visibility = chrome::IsInstantExtendedAPIEnabled();
-
   if (model.mode().is_ntp() || model.mode().is_search_suggestions()) {
     // Drop shadow is only needed if search mode is not |NTP| and overlay does
     // not fill up the entire contents page.
@@ -45,25 +34,5 @@
                   height:0
              heightUnits:INSTANT_SIZE_PIXELS
           drawDropShadow:NO];
-  } else {
-    set_top_bars_visibility = false;
   }
-
-  if (set_top_bars_visibility) {
-    // Set top bars (bookmark and info bars) visibility for current tab via
-    // |SearchTabHelper| of current active web contents: top bars are hidden if
-    // there's overlay.
-    content::WebContents* active_web_contents =
-        browser_->tab_strip_model()->GetActiveWebContents();
-    if (active_web_contents) {
-      SearchTabHelper* search_tab_helper =
-          SearchTabHelper::FromWebContents(active_web_contents);
-      if (search_tab_helper) {
-        search_tab_helper->model()->SetTopBarsVisible(
-            ![overlay_ isShowingOverlay]);
-      }
-    }
-  }
-
-  [window_ updateBookmarkBarStateForInstantOverlay];
 }
diff --git a/chrome/browser/ui/cocoa/tab_contents/overlay_separator_view.h b/chrome/browser/ui/cocoa/tab_contents/overlay_separator_view.h
deleted file mode 100644
index 3ebd5da..0000000
--- a/chrome/browser/ui/cocoa/tab_contents/overlay_separator_view.h
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_COCOA_TAB_CONTENTS_OVERLAY_SEPARATOR_VIEW_H_
-#define CHROME_BROWSER_UI_COCOA_TAB_CONTENTS_OVERLAY_SEPARATOR_VIEW_H_
-
-#import <Cocoa/Cocoa.h>
-
-#include "chrome/browser/ui/cocoa/background_gradient_view.h"
-
-// A view used to draw a separator above Instant overlay view.
-@interface OverlayTopSeparatorView : BackgroundGradientView {
-}
-
-+ (CGFloat)preferredHeight;
-
-@end
-
-// A view used to draw a drop shadow beneath the Instant overlay view.
-@interface OverlayBottomSeparatorView : NSView {
-}
-
-+ (CGFloat)preferredHeight;
-
-@end
-
-#endif  // CHROME_BROWSER_UI_COCOA_TAB_CONTENTS_OVERLAY_SEPARATOR_VIEW_H_
diff --git a/chrome/browser/ui/cocoa/tab_contents/overlay_separator_view.mm b/chrome/browser/ui/cocoa/tab_contents/overlay_separator_view.mm
deleted file mode 100644
index 35509b2..0000000
--- a/chrome/browser/ui/cocoa/tab_contents/overlay_separator_view.mm
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "chrome/browser/ui/cocoa/tab_contents/overlay_separator_view.h"
-
-#import "chrome/browser/ui/cocoa/nsview_additions.h"
-#include "grit/theme_resources.h"
-#include "ui/base/resource/resource_bundle.h"
-
-@implementation OverlayTopSeparatorView
-
-+ (CGFloat)preferredHeight {
-  return 1;
-}
-
-- (void)drawRect:(NSRect)rect {
-  NSRect separatorRect = [self bounds];
-  separatorRect.size.height = [self cr_lineWidth];
-  [[self strokeColor] set];
-  NSRectFillUsingOperation(separatorRect, NSCompositeSourceOver);
-}
-
-@end
-
-@implementation OverlayBottomSeparatorView
-
-+ (CGFloat)preferredHeight {
-  ResourceBundle& rb = ResourceBundle::GetSharedInstance();
-  NSImage* shadowImage =
-      rb.GetNativeImageNamed(IDR_OVERLAY_DROP_SHADOW).ToNSImage();
-  return [shadowImage size].height;
-}
-
-- (void)drawRect:(NSRect)rect {
-  ResourceBundle& rb = ResourceBundle::GetSharedInstance();
-  NSRect bounds = [self bounds];
-
-  // Draw the shadow.
-  NSImage* shadowImage =
-      rb.GetNativeImageNamed(IDR_OVERLAY_DROP_SHADOW).ToNSImage();
-  [shadowImage drawInRect:bounds
-                 fromRect:NSZeroRect
-                operation:NSCompositeSourceOver
-                 fraction:1.0];
-}
-
-@end
diff --git a/chrome/browser/ui/cocoa/tab_contents/overlay_separator_view_unittest.mm b/chrome/browser/ui/cocoa/tab_contents/overlay_separator_view_unittest.mm
deleted file mode 100644
index 7254a31..0000000
--- a/chrome/browser/ui/cocoa/tab_contents/overlay_separator_view_unittest.mm
+++ /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.
-
-#import "chrome/browser/ui/cocoa/tab_contents/overlay_separator_view.h"
-
-#include "base/memory/scoped_nsobject.h"
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
-
-class OverlayBottomSeparatorViewTest : public CocoaTest {
- public:
-  OverlayBottomSeparatorViewTest() {
-    NSView* contentView = [test_window() contentView];
-    bottom_view_.reset([[OverlayBottomSeparatorView alloc]
-        initWithFrame:[contentView bounds]]);
-    [contentView addSubview:bottom_view_];
-  }
-
- protected:
-  scoped_nsobject<OverlayBottomSeparatorView> bottom_view_;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(OverlayBottomSeparatorViewTest);
-};
-
-TEST_VIEW(OverlayBottomSeparatorViewTest, bottom_view_);
-
-TEST_F(OverlayBottomSeparatorViewTest, PreferredHeight) {
-  EXPECT_LT(0, [OverlayBottomSeparatorView preferredHeight]);
-}
-
-class OverlayTopSeparatorViewTest : public CocoaTest {
- public:
-  OverlayTopSeparatorViewTest() {
-    NSView* contentView = [test_window() contentView];
-    top_view_.reset(
-        [[OverlayTopSeparatorView alloc] initWithFrame:[contentView bounds]]);
-    [contentView addSubview:top_view_];
-  }
-
- protected:
-  scoped_nsobject<OverlayTopSeparatorView> top_view_;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(OverlayTopSeparatorViewTest);
-};
-
-TEST_VIEW(OverlayTopSeparatorViewTest, top_view_);
-
-TEST_F(OverlayTopSeparatorViewTest, PreferredHeight) {
-  EXPECT_LT(0, [OverlayTopSeparatorView preferredHeight]);
-}
diff --git a/chrome/browser/ui/cocoa/tab_contents/overlayable_contents_controller.h b/chrome/browser/ui/cocoa/tab_contents/overlayable_contents_controller.h
index 15ef7a6..6033cba 100644
--- a/chrome/browser/ui/cocoa/tab_contents/overlayable_contents_controller.h
+++ b/chrome/browser/ui/cocoa/tab_contents/overlayable_contents_controller.h
@@ -7,12 +7,11 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "base/memory/scoped_ptr.h"
 #include "chrome/common/instant_types.h"
 
 class Browser;
-@class BrowserWindowController;
 class InstantOverlayControllerMac;
 
 namespace content {
@@ -33,7 +32,7 @@
 @interface OverlayableContentsController : NSViewController {
  @private
   // Container view for the "active" contents.
-  scoped_nsobject<NSView> activeContainer_;
+  base::scoped_nsobject<NSView> activeContainer_;
 
   // The overlay WebContents. Will be NULL if no overlay is currently showing.
   content::WebContents* overlayContents_;  // weak
@@ -44,41 +43,12 @@
   // The desired height of the overlay and units.
   CGFloat overlayHeight_;
   InstantSizeUnits overlayHeightUnits_;
-
-  // If true then a shadow is drawn below the overlay. This is used to make the
-  // overlay "float" over the tab's web contents.
-  BOOL drawDropShadow_;
-
-  // View responsible for drawing a drop shadow.
-  scoped_nsobject<NSView> dropShadowView_;
-
-  // View responsible for drawing a separator at the top. The separator is
-  // only visible when the overlay is positioned right next to the omnibox.
-  scoped_nsobject<NSView> topSeparatorView_;
-
-  BrowserWindowController* windowController_;
-
-  // The vertical offset between the top of the view and the active container.
-  // This is used to push the active container below the bookmark bar. Normally
-  // this is set to the height of the bookmark bar so that the bookmark bar is
-  // not obscured.
-  CGFloat activeContainerOffset_;
-
-  // The vertical offset between the top of the view and the overlay. This is
-  // used in presentation mode to push the overlay below the floating toolbar
-  // view.
-  CGFloat overlayContentsOffset_;
 }
 
 @property(readonly, nonatomic) NSView* activeContainer;
-@property(readonly, nonatomic) NSView* dropShadowView;
-@property(readonly, nonatomic) BOOL drawDropShadow;
-@property(assign, nonatomic) CGFloat activeContainerOffset;
-@property(assign, nonatomic) CGFloat overlayContentsOffset;
 
 // Initialization.
-- (id)initWithBrowser:(Browser*)browser
-     windowController:(BrowserWindowController*)windowController;
+- (id)initWithBrowser:(Browser*)browser;
 
 // Sets the current overlay and installs its WebContentsView into the view
 // hierarchy. Hides the active view. If |overlay| is NULL then closes the
@@ -92,12 +62,9 @@
 // if it's the overlay being activated (and adjust internal state accordingly).
 - (void)onActivateTabWithContents:(content::WebContents*)contents;
 
-// Returns YES if the overlay contents is currently showing.
-- (BOOL)isShowingOverlay;
-
 - (InstantOverlayControllerMac*)instantOverlayController;
 
-- (void)activeContentsCompositingIOSurfaceCreated;
+- (BOOL)isShowingOverlay;
 
 @end
 
diff --git a/chrome/browser/ui/cocoa/tab_contents/overlayable_contents_controller.mm b/chrome/browser/ui/cocoa/tab_contents/overlayable_contents_controller.mm
index a7ec256..0b19677 100644
--- a/chrome/browser/ui/cocoa/tab_contents/overlayable_contents_controller.mm
+++ b/chrome/browser/ui/cocoa/tab_contents/overlayable_contents_controller.mm
@@ -4,10 +4,7 @@
 
 #import "chrome/browser/ui/cocoa/tab_contents/overlayable_contents_controller.h"
 
-#include "base/mac/bundle_locations.h"
-#include "chrome/browser/ui/cocoa/browser_window_controller.h"
 #include "chrome/browser/ui/cocoa/tab_contents/instant_overlay_controller_mac.h"
-#include "chrome/browser/ui/cocoa/tab_contents/overlay_separator_view.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_view.h"
 
@@ -15,22 +12,15 @@
 - (void)viewDidResize:(NSNotification*)note;
 - (void)layoutViews;
 - (CGFloat)overlayHeightInPixels;
-- (BOOL)shouldShowTopSeparator;
 @end
 
 @implementation OverlayableContentsController
 
-@synthesize drawDropShadow = drawDropShadow_;
-@synthesize activeContainerOffset = activeContainerOffset_;
-@synthesize overlayContentsOffset = overlayContentsOffset_;
-
-- (id)initWithBrowser:(Browser*)browser
-     windowController:(BrowserWindowController*)windowController {
+- (id)initWithBrowser:(Browser*)browser {
   if ((self = [super init])) {
-    windowController_ = windowController;
-    scoped_nsobject<NSView> view([[NSView alloc] initWithFrame:NSZeroRect]);
+    base::scoped_nsobject<NSView> view(
+        [[NSView alloc] initWithFrame:NSZeroRect]);
     [view setAutoresizingMask:NSViewHeightSizable | NSViewWidthSizable];
-    [view setAutoresizesSubviews:NO];
     [[NSNotificationCenter defaultCenter]
         addObserver:self
            selector:@selector(viewDidResize:)
@@ -39,13 +29,12 @@
     [self setView:view];
 
     activeContainer_.reset([[NSView alloc] initWithFrame:NSZeroRect]);
+    [activeContainer_ setAutoresizingMask:NSViewHeightSizable |
+                                          NSViewWidthSizable];
     [view addSubview:activeContainer_];
 
     instantOverlayController_.reset(
-        new InstantOverlayControllerMac(browser, windowController, self));
-    topSeparatorView_.reset(
-        [[OverlayTopSeparatorView alloc] initWithFrame:NSZeroRect]);
-    [[self view] addSubview:topSeparatorView_];
+        new InstantOverlayControllerMac(browser, self));
   }
   return self;
 }
@@ -59,17 +48,9 @@
             height:(CGFloat)height
        heightUnits:(InstantSizeUnits)heightUnits
     drawDropShadow:(BOOL)drawDropShadow {
-  // If drawing drop shadow, clip the bottom 1-px-thick separator out of
-  // overlay.
-  // TODO(sail): remove this when GWS gives chrome the height without the
-  // separator.
-  if (drawDropShadow && heightUnits != INSTANT_SIZE_PERCENT)
-    --height;
-
   if (overlayContents_ == overlay &&
       overlayHeight_ == height &&
-      overlayHeightUnits_ == heightUnits &&
-      drawDropShadow_ == drawDropShadow) {
+      overlayHeightUnits_ == heightUnits) {
     return;
   }
 
@@ -83,7 +64,6 @@
   overlayContents_ = overlay;
   overlayHeight_ = height;
   overlayHeightUnits_ = heightUnits;
-  drawDropShadow_ = drawDropShadow;
 
   // Add the overlay contents.
   if (overlayContents_) {
@@ -91,17 +71,6 @@
     [[self view] addSubview:overlayContents_->GetView()->GetNativeView()];
   }
 
-  if (drawDropShadow_) {
-    if (!dropShadowView_) {
-      dropShadowView_.reset(
-          [[OverlayBottomSeparatorView alloc] initWithFrame:NSZeroRect]);
-      [[self view] addSubview:dropShadowView_];
-    }
-  } else {
-    [dropShadowView_ removeFromSuperview];
-    dropShadowView_.reset();
-  }
-
   [self layoutViews];
 
   if (overlayContents_)
@@ -121,98 +90,36 @@
   }
 }
 
-- (BOOL)isShowingOverlay {
-  return overlayContents_ != nil;
-}
-
 - (InstantOverlayControllerMac*)instantOverlayController {
   return instantOverlayController_.get();
 }
 
-- (void)activeContentsCompositingIOSurfaceCreated {
-  if (!overlayContents_)
-    return;
-
-  // If the active tab becomes composited the the overlay will no longer be
-  // visible. Workaround this by re-adding the overlay to the view hierarchy.
-  // See http://crbug.com/222122
-  [overlayContents_->GetView()->GetNativeView() removeFromSuperview];
-  [[self view] addSubview:overlayContents_->GetView()->GetNativeView()];
+- (BOOL)isShowingOverlay {
+  return overlayContents_ != nil;
 }
 
 - (NSView*)activeContainer {
   return activeContainer_.get();
 }
 
-- (NSView*)dropShadowView {
-  return dropShadowView_.get();
-}
-
-- (void)setActiveContainerOffset:(CGFloat)activeContainerOffset {
-  if (activeContainerOffset_ == activeContainerOffset)
-    return;
-
-  activeContainerOffset_ = activeContainerOffset;
-  [self layoutViews];
-}
-
-- (void)setOverlayContentsOffset:(CGFloat)overlayContentsOffset {
-  if (overlayContentsOffset_ == overlayContentsOffset)
-    return;
-
-  overlayContentsOffset_ = overlayContentsOffset;
-  [self layoutViews];
-}
-
 - (void)viewDidResize:(NSNotification*)note {
   [self layoutViews];
 }
 
 - (void)layoutViews {
-  NSRect bounds = [[self view] bounds];
-
-  // Layout the separator at the top of the view.
-  NSRect separatorRect = bounds;
-  if ([self shouldShowTopSeparator])
-    separatorRect.size.height = [OverlayTopSeparatorView preferredHeight];
-  else
-    separatorRect.size.height = 0;
-  separatorRect.origin.y = NSMaxY(bounds) - NSHeight(separatorRect);
-  [topSeparatorView_ setFrame:separatorRect];
+  if (!overlayContents_)
+    return;
 
   // Layout the overlay.
-  if (overlayContents_) {
-    NSRect overlayFrame = bounds;
-    overlayFrame.size.height = [self overlayHeightInPixels];
-    overlayFrame.origin.y = NSMinY([topSeparatorView_ frame]) -
-                            NSHeight(overlayFrame) - overlayContentsOffset_;
-    [overlayContents_->GetView()->GetNativeView() setFrame:overlayFrame];
-
-    if (dropShadowView_) {
-      NSRect dropShadowFrame = bounds;
-      dropShadowFrame.size.height =
-          [OverlayBottomSeparatorView preferredHeight];
-      dropShadowFrame.origin.y =
-          NSMinY(overlayFrame) - NSHeight(dropShadowFrame);
-      [dropShadowView_ setFrame:dropShadowFrame];
-    }
-  }
-
-  // Layout the active tab contents.
-  NSRect activeFrame = bounds;
-  if (activeContainerOffset_)
-    activeFrame.size.height -= activeContainerOffset_;
-  else
-    activeFrame.size.height -= NSHeight([topSeparatorView_ frame]);
-  if (!NSEqualRects(activeFrame, [activeContainer_ frame])) {
-    [[activeContainer_ window] disableScreenUpdatesUntilFlush];
-    [activeContainer_ setFrame:activeFrame];
-  }
+  NSRect bounds = [[self view] bounds];
+  NSRect overlayFrame = bounds;
+  overlayFrame.size.height = [self overlayHeightInPixels];
+  overlayFrame.origin.y = NSMaxY(bounds) - NSHeight(overlayFrame);
+  [overlayContents_->GetView()->GetNativeView() setFrame:overlayFrame];
 }
 
 - (CGFloat)overlayHeightInPixels {
-  CGFloat height = NSHeight([[self view] bounds]) -
-                   NSHeight([topSeparatorView_ frame]) - overlayContentsOffset_;
+  CGFloat height = NSHeight([[self view] bounds]);
   switch (overlayHeightUnits_) {
     case INSTANT_SIZE_PERCENT:
       return std::min(height, (height * overlayHeight_) / 100);
@@ -221,18 +128,4 @@
   }
 }
 
-- (BOOL)shouldShowTopSeparator {
-  // In presentation mode tab contents are flush with the top of the screen
-  // so there's no need for a separator.
-  if ([windowController_ inPresentationMode])
-    return NO;
-
-  if (![windowController_ hasToolbar])
-    return NO;
-
-  // Show a separator is the overlay or the tab contents will be shown right
-  // next to the omnibox.
-  return activeContainerOffset_ == 0 || overlayContents_;
-}
-
 @end
diff --git a/chrome/browser/ui/cocoa/tab_contents/overlayable_contents_controller_browsertest.mm b/chrome/browser/ui/cocoa/tab_contents/overlayable_contents_controller_browsertest.mm
index d2e115d..075b981 100644
--- a/chrome/browser/ui/cocoa/tab_contents/overlayable_contents_controller_browsertest.mm
+++ b/chrome/browser/ui/cocoa/tab_contents/overlayable_contents_controller_browsertest.mm
@@ -7,9 +7,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_window.h"
-#include "chrome/browser/ui/cocoa/browser_window_controller.h"
 #include "chrome/browser/ui/cocoa/tab_contents/instant_overlay_controller_mac.h"
-#include "chrome/browser/ui/cocoa/tab_contents/overlay_separator_view.h"
 #include "chrome/browser/ui/search/instant_overlay_model.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "content/public/browser/notification_source.h"
@@ -29,12 +27,8 @@
         content::WebContents::CreateParams(browser()->profile())));
     instant_overlay_model_.SetOverlayContents(web_contents_.get());
 
-    BrowserWindowController* window_controller =
-        [BrowserWindowController browserWindowControllerForWindow:
-                browser()->window()->GetNativeWindow()];
     controller_.reset([[OverlayableContentsController alloc]
-         initWithBrowser:browser()
-        windowController:window_controller]);
+         initWithBrowser:browser()]);
     [[controller_ view] setFrame:NSMakeRect(0, 0, 100, 200)];
     instant_overlay_model_.AddObserver([controller_ instantOverlayController]);
   }
@@ -50,7 +44,6 @@
   void VerifyOverlayFrame(CGFloat expected_height,
                           InstantSizeUnits units) {
     NSRect container_bounds = [[controller_ view] bounds];
-    container_bounds.size.height -= [OverlayTopSeparatorView preferredHeight];
     NSRect overlay_frame =
         [web_contents_->GetView()->GetNativeView() frame];
 
@@ -78,7 +71,7 @@
  protected:
   InstantOverlayModel instant_overlay_model_;
   scoped_ptr<content::WebContents> web_contents_;
-  scoped_nsobject<OverlayableContentsController> controller_;
+  base::scoped_nsobject<OverlayableContentsController> controller_;
   content::NotificationRegistrar registrar_;
   int visibility_changed_count_;
 };
@@ -117,48 +110,6 @@
   VerifyOverlayFrame(expected_height, units);
 }
 
-// Verify that a bottom border is not shown when the overlay covers the entire
-// page or when the overlay is in NTP mode.
-IN_PROC_BROWSER_TEST_F(OverlayableContentsControllerTest, NoShadowFullHeight) {
-  SearchMode mode;
-  mode.mode = SearchMode::MODE_SEARCH_SUGGESTIONS;
-  instant_overlay_model_.SetOverlayState(mode, 100, INSTANT_SIZE_PERCENT);
-  EXPECT_FALSE([controller_ dropShadowView]);
-  EXPECT_FALSE([controller_ drawDropShadow]);
-
-  mode.mode = SearchMode::MODE_NTP;
-  instant_overlay_model_.SetOverlayState(mode, 10, INSTANT_SIZE_PERCENT);
-  EXPECT_FALSE([controller_ dropShadowView]);
-  EXPECT_FALSE([controller_ drawDropShadow]);
-}
-
-// Verify that a shadow is shown when the overlay is in search mode.
-IN_PROC_BROWSER_TEST_F(OverlayableContentsControllerTest, NoShadowNTP) {
-  SearchMode mode;
-  mode.mode = SearchMode::MODE_SEARCH_SUGGESTIONS;
-  instant_overlay_model_.SetOverlayState(mode, 10, INSTANT_SIZE_PERCENT);
-  EXPECT_TRUE([controller_ dropShadowView]);
-  EXPECT_TRUE([controller_ drawDropShadow]);
-  EXPECT_NSEQ([controller_ view], [[controller_ dropShadowView] superview]);
-
-  NSRect dropShadowFrame = [[controller_ dropShadowView] frame];
-  NSRect controllerBounds = [[controller_ view] bounds];
-  EXPECT_EQ(NSWidth(controllerBounds), NSWidth(dropShadowFrame));
-  EXPECT_EQ([OverlayBottomSeparatorView preferredHeight],
-            NSHeight(dropShadowFrame));
-}
-
-// Verify that the shadow is hidden when hiding the overlay.
-IN_PROC_BROWSER_TEST_F(OverlayableContentsControllerTest, HideShadow) {
-  SearchMode mode;
-  mode.mode = SearchMode::MODE_SEARCH_SUGGESTIONS;
-  instant_overlay_model_.SetOverlayState(mode, 10, INSTANT_SIZE_PERCENT);
-  EXPECT_TRUE([controller_ dropShadowView]);
-
-  [controller_ onActivateTabWithContents:web_contents_.get()];
-  EXPECT_FALSE([controller_ dropShadowView]);
-}
-
 // Verify that the web contents is not hidden when just the height changes.
 IN_PROC_BROWSER_TEST_F(OverlayableContentsControllerTest, HeightChangeNoHide) {
   SearchMode mode;
@@ -172,23 +123,3 @@
   instant_overlay_model_.SetOverlayState(mode, 11, INSTANT_SIZE_PERCENT);
   EXPECT_EQ(1, visibility_changed_count_);
 }
-
-IN_PROC_BROWSER_TEST_F(OverlayableContentsControllerTest, OverlayOffset) {
-  SearchMode mode;
-  mode.mode = SearchMode::MODE_NTP;
-  CGFloat expected_height = 10;
-  InstantSizeUnits units = INSTANT_SIZE_PIXELS;
-  instant_overlay_model_.SetOverlayState(mode, expected_height, units);
-
-  CGFloat separator_height = [OverlayTopSeparatorView preferredHeight];
-  NSView* overlay_view = web_contents_->GetView()->GetNativeView();
-  EXPECT_EQ(separator_height,
-            NSMaxY([[overlay_view superview] frame]) -
-            NSMaxY([overlay_view frame]));
-
-  CGFloat offset = 30;
-  [controller_ setOverlayContentsOffset:offset];
-  EXPECT_EQ(separator_height + offset,
-            NSMaxY([[overlay_view superview] frame]) -
-            NSMaxY([overlay_view frame]));
-}
diff --git a/chrome/browser/ui/cocoa/tab_contents/render_view_context_menu_mac.h b/chrome/browser/ui/cocoa/tab_contents/render_view_context_menu_mac.h
index 35f8177..c43503a 100644
--- a/chrome/browser/ui/cocoa/tab_contents/render_view_context_menu_mac.h
+++ b/chrome/browser/ui/cocoa/tab_contents/render_view_context_menu_mac.h
@@ -7,7 +7,7 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "chrome/browser/tab_contents/render_view_context_menu.h"
 
 @class MenuController;
@@ -59,7 +59,7 @@
   void StopSpeaking();
 
   // The Cocoa menu controller for this menu.
-  scoped_nsobject<MenuController> menu_controller_;
+  base::scoped_nsobject<MenuController> menu_controller_;
 
   // Model for the "Speech" submenu.
   ui::SimpleMenuModel speech_submenu_model_;
diff --git a/chrome/browser/ui/cocoa/tab_contents/render_view_context_menu_mac.mm b/chrome/browser/ui/cocoa/tab_contents/render_view_context_menu_mac.mm
index 1581632..3ae3496 100644
--- a/chrome/browser/ui/cocoa/tab_contents/render_view_context_menu_mac.mm
+++ b/chrome/browser/ui/cocoa/tab_contents/render_view_context_menu_mac.mm
@@ -6,11 +6,9 @@
 
 #include "base/compiler_specific.h"
 #import "base/mac/scoped_sending_event.h"
-#include "base/memory/scoped_nsobject.h"
 #include "base/message_loop.h"
 #include "base/strings/sys_string_conversions.h"
 #include "chrome/app/chrome_command_ids.h"
-#import "chrome/browser/ui/cocoa/browser_window_controller.h"
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/render_widget_host_view.h"
 #include "grit/generated_resources.h"
@@ -110,13 +108,6 @@
 }
 
 void RenderViewContextMenuMac::ExecuteCommand(int command_id, int event_flags) {
-  // Auxiliary windows that do not have address bars (Panels for example)
-  // may not have Instant support.
-  NSWindow* parent_window = [parent_view_ window];
-  BrowserWindowController* controller =
-      [BrowserWindowController browserWindowControllerForWindow:parent_window];
-  [controller commitInstant];  // It's ok if controller is nil.
-
   switch (command_id) {
     case IDC_CONTENT_CONTEXT_LOOK_UP_IN_DICTIONARY:
       LookUpInDictionary();
diff --git a/chrome/browser/ui/cocoa/tab_contents/sad_tab_controller.h b/chrome/browser/ui/cocoa/tab_contents/sad_tab_controller.h
index 439e539..91fc745 100644
--- a/chrome/browser/ui/cocoa/tab_contents/sad_tab_controller.h
+++ b/chrome/browser/ui/cocoa/tab_contents/sad_tab_controller.h
@@ -7,7 +7,7 @@
 
 #include "base/basictypes.h"
 #include "base/compiler_specific.h"
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "chrome/browser/ui/sad_tab.h"
 
 #import <Cocoa/Cocoa.h>
@@ -27,7 +27,7 @@
   virtual void Show() OVERRIDE;
   virtual void Close() OVERRIDE;
 
-  scoped_nsobject<SadTabController> sad_tab_controller_;
+  base::scoped_nsobject<SadTabController> sad_tab_controller_;
 
   content::WebContents* web_contents_;
 
diff --git a/chrome/browser/ui/cocoa/tab_contents/sad_tab_controller_unittest.mm b/chrome/browser/ui/cocoa/tab_contents/sad_tab_controller_unittest.mm
index 5c2e925..0067968 100644
--- a/chrome/browser/ui/cocoa/tab_contents/sad_tab_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/tab_contents/sad_tab_controller_unittest.mm
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 #include "base/debug/debugger.h"
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #import "chrome/browser/ui/cocoa/hyperlink_text_view.h"
 #import "chrome/browser/ui/cocoa/tab_contents/sad_tab_controller.h"
@@ -75,7 +75,7 @@
 bool SadTabControllerTest::link_clicked_;
 
 TEST_F(SadTabControllerTest, WithTabContents) {
-  scoped_nsobject<SadTabController> controller(CreateController());
+  base::scoped_nsobject<SadTabController> controller(CreateController());
   EXPECT_TRUE(controller);
   HyperlinkTextView* help = GetHelpTextView(controller);
   EXPECT_TRUE(help);
@@ -83,14 +83,14 @@
 
 TEST_F(SadTabControllerTest, WithoutTabContents) {
   DeleteContents();
-  scoped_nsobject<SadTabController> controller(CreateController());
+  base::scoped_nsobject<SadTabController> controller(CreateController());
   EXPECT_TRUE(controller);
   HyperlinkTextView* help = GetHelpTextView(controller);
   EXPECT_FALSE(help);
 }
 
 TEST_F(SadTabControllerTest, ClickOnLink) {
-  scoped_nsobject<SadTabController> controller(CreateController());
+  base::scoped_nsobject<SadTabController> controller(CreateController());
   HyperlinkTextView* help = GetHelpTextView(controller);
   EXPECT_TRUE(help);
   EXPECT_FALSE(link_clicked_);
diff --git a/chrome/browser/ui/cocoa/tab_contents/sad_tab_view.h b/chrome/browser/ui/cocoa/tab_contents/sad_tab_view.h
index b203cb2..45fdf7e 100644
--- a/chrome/browser/ui/cocoa/tab_contents/sad_tab_view.h
+++ b/chrome/browser/ui/cocoa/tab_contents/sad_tab_view.h
@@ -5,7 +5,7 @@
 #ifndef CHROME_BROWSER_UI_COCOA_TAB_CONTENTS_SAD_TAB_VIEW_H_
 #define CHROME_BROWSER_UI_COCOA_TAB_CONTENTS_SAD_TAB_VIEW_H_
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "ui/base/cocoa/base_view.h"
 
 #import <Cocoa/Cocoa.h>
@@ -21,14 +21,14 @@
   IBOutlet NSTextField* message_;
   IBOutlet NSTextField* helpPlaceholder_;
 
-  scoped_nsobject<NSColor> backgroundColor_;
+  base::scoped_nsobject<NSColor> backgroundColor_;
   NSSize messageSize_;
 
   // Text fields don't work as well with embedded links as text views, but
   // text views cannot conveniently be created in IB. The xib file contains
   // a text field |helpPlaceholder_| that's replaced by this text view |help_|
   // in -awakeFromNib.
-  scoped_nsobject<HyperlinkTextView> help_;
+  base::scoped_nsobject<HyperlinkTextView> help_;
 
   // A weak reference to the parent controller.
   IBOutlet SadTabController* controller_;
diff --git a/chrome/browser/ui/cocoa/tab_contents/sad_tab_view_unittest.mm b/chrome/browser/ui/cocoa/tab_contents/sad_tab_view_unittest.mm
index 76808cf..82bf73a 100644
--- a/chrome/browser/ui/cocoa/tab_contents/sad_tab_view_unittest.mm
+++ b/chrome/browser/ui/cocoa/tab_contents/sad_tab_view_unittest.mm
@@ -11,8 +11,8 @@
  public:
   SadTabViewTest() {
     NSRect content_frame = [[test_window() contentView] frame];
-    scoped_nsobject<SadTabView> view([[SadTabView alloc]
-                                      initWithFrame:content_frame]);
+    base::scoped_nsobject<SadTabView> view(
+        [[SadTabView alloc] initWithFrame:content_frame]);
     view_ = view.get();
     [[test_window() contentView] addSubview:view_];
   }
diff --git a/chrome/browser/ui/cocoa/tab_contents/tab_contents_controller.mm b/chrome/browser/ui/cocoa/tab_contents/tab_contents_controller.mm
index 51d4c5b..5d54f76 100644
--- a/chrome/browser/ui/cocoa/tab_contents/tab_contents_controller.mm
+++ b/chrome/browser/ui/cocoa/tab_contents/tab_contents_controller.mm
@@ -6,7 +6,7 @@
 
 #include <utility>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "chrome/browser/devtools/devtools_window.h"
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/render_widget_host_view.h"
@@ -32,7 +32,7 @@
 }
 
 - (void)loadView {
-  scoped_nsobject<NSView> view([[NSView alloc] initWithFrame:NSZeroRect]);
+  base::scoped_nsobject<NSView> view([[NSView alloc] initWithFrame:NSZeroRect]);
   [view setAutoresizingMask:NSViewHeightSizable|NSViewWidthSizable];
   [self setView:view];
 }
diff --git a/chrome/browser/ui/cocoa/tab_modal_confirm_dialog_mac.h b/chrome/browser/ui/cocoa/tab_modal_confirm_dialog_mac.h
index 6a88203..0ead38a 100644
--- a/chrome/browser/ui/cocoa/tab_modal_confirm_dialog_mac.h
+++ b/chrome/browser/ui/cocoa/tab_modal_confirm_dialog_mac.h
@@ -47,8 +47,8 @@
 
   scoped_ptr<ConstrainedWindowMac> window_;
   scoped_ptr<TabModalConfirmDialogDelegate> delegate_;
-  scoped_nsobject<ConstrainedWindowAlert> alert_;
-  scoped_nsobject<TabModalConfirmDialogMacBridge> bridge_;
+  base::scoped_nsobject<ConstrainedWindowAlert> alert_;
+  base::scoped_nsobject<TabModalConfirmDialogMacBridge> bridge_;
 
   DISALLOW_COPY_AND_ASSIGN(TabModalConfirmDialogMac);
 };
diff --git a/chrome/browser/ui/cocoa/tab_modal_confirm_dialog_mac.mm b/chrome/browser/ui/cocoa/tab_modal_confirm_dialog_mac.mm
index ffc806f..e9b938e 100644
--- a/chrome/browser/ui/cocoa/tab_modal_confirm_dialog_mac.mm
+++ b/chrome/browser/ui/cocoa/tab_modal_confirm_dialog_mac.mm
@@ -4,7 +4,7 @@
 
 #include "chrome/browser/ui/cocoa/tab_modal_confirm_dialog_mac.h"
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "chrome/browser/ui/browser_dialogs.h"
 #import "chrome/browser/ui/cocoa/constrained_window/constrained_window_alert.h"
 #import "chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_sheet.h"
@@ -73,7 +73,7 @@
   [[alert_ closeButton] setAction:@selector(onCancelButton:)];
   [alert_ layout];
 
-  scoped_nsobject<CustomConstrainedWindowSheet> sheet(
+  base::scoped_nsobject<CustomConstrainedWindowSheet> sheet(
       [[CustomConstrainedWindowSheet alloc]
           initWithCustomWindow:[alert_ window]]);
   window_.reset(new ConstrainedWindowMac(this, web_contents, sheet));
diff --git a/chrome/browser/ui/cocoa/table_row_nsimage_cache.h b/chrome/browser/ui/cocoa/table_row_nsimage_cache.h
index d0829fe..4932aa2 100644
--- a/chrome/browser/ui/cocoa/table_row_nsimage_cache.h
+++ b/chrome/browser/ui/cocoa/table_row_nsimage_cache.h
@@ -7,7 +7,7 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 
 namespace gfx {
 class ImageSkia;
@@ -50,7 +50,7 @@
 
   // Stores strong NSImage refs for icons. If an entry is NULL, it will be
   // created in GetImageForRow().
-  scoped_nsobject<NSPointerArray> icon_images_;
+  base::scoped_nsobject<NSPointerArray> icon_images_;
 };
 
 #endif  // CHROME_BROWSER_UI_COCOA_TABLE_ROW_NSIMAGE_CACHE_H_
diff --git a/chrome/browser/ui/cocoa/tabpose_window.h b/chrome/browser/ui/cocoa/tabpose_window.h
index b2e0f28..7651812 100644
--- a/chrome/browser/ui/cocoa/tabpose_window.h
+++ b/chrome/browser/ui/cocoa/tabpose_window.h
@@ -9,7 +9,7 @@
 
 #include "base/mac/scoped_cftyperef.h"
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/scoped_vector.h"
 
@@ -54,17 +54,17 @@
   CALayer* selectionHighlight_;  // weak
 
   // Colors used by the layers.
-  base::mac::ScopedCFTypeRef<CGColorRef> gray_;
-  base::mac::ScopedCFTypeRef<CGColorRef> darkBlue_;
+  base::ScopedCFTypeRef<CGColorRef> gray_;
+  base::ScopedCFTypeRef<CGColorRef> darkBlue_;
 
   TabStripModel* tabStripModel_;  // weak
 
   // Stores all preview layers. The order in here matches the order in
   // the tabstrip model.
-  scoped_nsobject<NSMutableArray> allThumbnailLayers_;
+  base::scoped_nsobject<NSMutableArray> allThumbnailLayers_;
 
-  scoped_nsobject<NSMutableArray> allFaviconLayers_;
-  scoped_nsobject<NSMutableArray> allTitleLayers_;
+  base::scoped_nsobject<NSMutableArray> allFaviconLayers_;
+  base::scoped_nsobject<NSMutableArray> allTitleLayers_;
 
   // Manages the state of all layers.
   scoped_ptr<tabpose::TileSet> tileSet_;
@@ -77,7 +77,7 @@
   scoped_ptr<TabStripModelObserverBridge> tabStripModelObserverBridge_;
 
   // The icon used for the closebutton layers.
-  base::mac::ScopedCFTypeRef<CGImageRef> closeIcon_;
+  base::ScopedCFTypeRef<CGImageRef> closeIcon_;
 
   // True if all close layers should be shown (as opposed to just the close
   // layer of the currently selected thumbnail).
diff --git a/chrome/browser/ui/cocoa/tabpose_window.mm b/chrome/browser/ui/cocoa/tabpose_window.mm
index 339abd7..1921489 100644
--- a/chrome/browser/ui/cocoa/tabpose_window.mm
+++ b/chrome/browser/ui/cocoa/tabpose_window.mm
@@ -89,11 +89,11 @@
 }
 
 - (void)drawInContext:(CGContextRef)context {
-  base::mac::ScopedCFTypeRef<CGColorSpaceRef> grayColorSpace(
+  base::ScopedCFTypeRef<CGColorSpaceRef> grayColorSpace(
       CGColorSpaceCreateWithName(kCGColorSpaceGenericGray));
   CGFloat grays[] = { startGray_, 1.0, endGray_, 1.0 };
   CGFloat locations[] = { 0, 1 };
-  base::mac::ScopedCFTypeRef<CGGradientRef> gradient(
+  base::ScopedCFTypeRef<CGGradientRef> gradient(
       CGGradientCreateWithColorComponents(
           grayColorSpace.get(), grays, locations, arraysize(locations)));
   CGPoint topLeft = CGPointMake(0.0, self.bounds.size.height);
@@ -120,7 +120,7 @@
 
   // If the backing store couldn't be used and a thumbnail was returned from a
   // renderer process, it's stored in |thumbnail_|.
-  base::mac::ScopedCFTypeRef<CGImageRef> thumbnail_;
+  base::ScopedCFTypeRef<CGImageRef> thumbnail_;
 
   // True if the layer already sent a thumbnail request to a renderer.
   BOOL didSendLoad_;
@@ -976,10 +976,10 @@
                 showZoom:(BOOL)showZoom
                    slomo:(BOOL)slomo
        animationDelegate:(id)animationDelegate {
-  scoped_nsobject<CALayer> layer([[ThumbnailLayer alloc]
-      initWithWebContents:tile.web_contents()
-                 fullSize:tile.GetStartRectRelativeTo(
-                     tileSet_->selected_tile()).size]);
+  base::scoped_nsobject<CALayer> layer(
+      [[ThumbnailLayer alloc] initWithWebContents:tile.web_contents()
+                                         fullSize:tile.GetStartRectRelativeTo(
+                                             tileSet_->selected_tile()).size]);
   [layer setNeedsDisplay];
 
   NSTimeInterval interval =
@@ -1031,7 +1031,7 @@
   NSFont* font = [NSFont systemFontOfSize:tile.title_font_size()];
   tile.set_font_metrics([font ascender], -[font descender]);
 
-  base::mac::ScopedCFTypeRef<CGImageRef> favicon(
+  base::ScopedCFTypeRef<CGImageRef> favicon(
       base::mac::CopyNSImageToCGImage(tile.favicon()));
 
   CALayer* faviconLayer = [CALayer layer];
@@ -1611,15 +1611,15 @@
   tileSet_->MoveTileFromTo(from, to);
 
   // Move corresponding layers from |from| to |to|.
-  scoped_nsobject<CALayer> thumbLayer(
+  base::scoped_nsobject<CALayer> thumbLayer(
       [[allThumbnailLayers_ objectAtIndex:from] retain]);
   [allThumbnailLayers_ removeObjectAtIndex:from];
   [allThumbnailLayers_ insertObject:thumbLayer.get() atIndex:to];
-  scoped_nsobject<CALayer> faviconLayer(
+  base::scoped_nsobject<CALayer> faviconLayer(
       [[allFaviconLayers_ objectAtIndex:from] retain]);
   [allFaviconLayers_ removeObjectAtIndex:from];
   [allFaviconLayers_ insertObject:faviconLayer.get() atIndex:to];
-  scoped_nsobject<CALayer> titleLayer(
+  base::scoped_nsobject<CALayer> titleLayer(
       [[allTitleLayers_ objectAtIndex:from] retain]);
   [allTitleLayers_ removeObjectAtIndex:from];
   [allTitleLayers_ insertObject:titleLayer.get() atIndex:to];
diff --git a/chrome/browser/ui/cocoa/tabpose_window_unittest.mm b/chrome/browser/ui/cocoa/tabpose_window_unittest.mm
index bace43e..fdeba6c 100644
--- a/chrome/browser/ui/cocoa/tabpose_window_unittest.mm
+++ b/chrome/browser/ui/cocoa/tabpose_window_unittest.mm
@@ -25,7 +25,7 @@
 
   void AppendTabToStrip() {
     content::WebContents* web_contents = content::WebContents::Create(
-        content::WebContents::CreateParams(profile(), site_instance_));
+        content::WebContents::CreateParams(profile(), site_instance_.get()));
     browser()->tab_strip_model()->AppendWebContents(
         web_contents, /*foreground=*/true);
   }
diff --git a/chrome/browser/ui/cocoa/tabs/tab_audio_indicator_view_mac.h b/chrome/browser/ui/cocoa/tabs/tab_audio_indicator_view_mac.h
index 4150bef..4a21e7d 100644
--- a/chrome/browser/ui/cocoa/tabs/tab_audio_indicator_view_mac.h
+++ b/chrome/browser/ui/cocoa/tabs/tab_audio_indicator_view_mac.h
@@ -7,7 +7,6 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
 #include "base/memory/scoped_ptr.h"
 
 namespace content {
diff --git a/chrome/browser/ui/cocoa/tabs/tab_audio_indicator_view_mac_unittest.mm b/chrome/browser/ui/cocoa/tabs/tab_audio_indicator_view_mac_unittest.mm
index 478df04..b4b3620 100644
--- a/chrome/browser/ui/cocoa/tabs/tab_audio_indicator_view_mac_unittest.mm
+++ b/chrome/browser/ui/cocoa/tabs/tab_audio_indicator_view_mac_unittest.mm
@@ -5,18 +5,19 @@
 #import "chrome/browser/ui/cocoa/tabs/tab_audio_indicator_view_mac.h"
 
 #include "base/message_loop.h"
+#include "base/mac/scoped_nsobject.h"
 #import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 
 class TabAudioIndicatorViewMacTest : public CocoaTest {
  protected:
   TabAudioIndicatorViewMacTest() {
-    scoped_nsobject<TabAudioIndicatorViewMac> view(
+    base::scoped_nsobject<TabAudioIndicatorViewMac> view(
         [[TabAudioIndicatorViewMac alloc]
             initWithFrame:NSMakeRect(0, 0, 16, 16)]);
     view_ = view.get();
     [[test_window() contentView] addSubview:view_];
 
-    scoped_nsobject<NSImage> image(
+    base::scoped_nsobject<NSImage> image(
         [[NSImage alloc] initWithSize:NSMakeSize(16, 16)]);
     [image lockFocus];
     NSRectFill(NSMakeRect(0, 0, 16, 16));
diff --git a/chrome/browser/ui/cocoa/tabs/tab_controller.h b/chrome/browser/ui/cocoa/tabs/tab_controller.h
index d75d8d6..93cdbe4 100644
--- a/chrome/browser/ui/cocoa/tabs/tab_controller.h
+++ b/chrome/browser/ui/cocoa/tabs/tab_controller.h
@@ -40,9 +40,9 @@
 
 @interface TabController : NSViewController<TabDraggingEventTarget> {
  @private
-  scoped_nsobject<NSView> iconView_;
-  scoped_nsobject<NSTextField> titleView_;
-  scoped_nsobject<HoverCloseButton> closeButton_;
+  base::scoped_nsobject<NSView> iconView_;
+  base::scoped_nsobject<NSTextField> titleView_;
+  base::scoped_nsobject<HoverCloseButton> closeButton_;
 
   NSRect originalIconFrame_;  // frame of iconView_ as loaded from nib
   BOOL isIconShowing_;  // last state of iconView_ in updateVisibility
@@ -60,7 +60,7 @@
   SEL action_;  // selector sent when tab is selected by clicking
   scoped_ptr<ui::SimpleMenuModel> contextMenuModel_;
   scoped_ptr<TabControllerInternal::MenuDelegate> contextMenuDelegate_;
-  scoped_nsobject<MenuController> contextMenuController_;
+  base::scoped_nsobject<MenuController> contextMenuController_;
 }
 
 @property(assign, nonatomic) TabLoadingState loadingState;
diff --git a/chrome/browser/ui/cocoa/tabs/tab_controller.mm b/chrome/browser/ui/cocoa/tabs/tab_controller.mm
index 3e7924c..1006ef0 100644
--- a/chrome/browser/ui/cocoa/tabs/tab_controller.mm
+++ b/chrome/browser/ui/cocoa/tabs/tab_controller.mm
@@ -102,7 +102,7 @@
     // Label.
     titleView_.reset([[NSTextField alloc] initWithFrame:titleFrame]);
     [titleView_ setAutoresizingMask:NSViewWidthSizable];
-    scoped_nsobject<GTMFadeTruncatingTextFieldCell> labelCell(
+    base::scoped_nsobject<GTMFadeTruncatingTextFieldCell> labelCell(
         [[GTMFadeTruncatingTextFieldCell alloc] initTextCell:@"Label"]);
     [labelCell setControlSize:NSSmallControlSize];
     CGFloat fontSize = [NSFont systemFontSizeForControlSize:NSSmallControlSize];
@@ -118,8 +118,10 @@
     [closeButton_ setTarget:self];
     [closeButton_ setAction:@selector(closeTab:)];
 
-    scoped_nsobject<TabView> view([[TabView alloc] initWithFrame:
-        NSMakeRect(0, 0, 160, 25) controller:self closeButton:closeButton_]);
+    base::scoped_nsobject<TabView> view(
+        [[TabView alloc] initWithFrame:NSMakeRect(0, 0, 160, 25)
+                            controller:self
+                           closeButton:closeButton_]);
     [view setAutoresizingMask:NSViewMaxXMargin | NSViewMinYMargin];
     [view addSubview:iconView_];
     [view addSubview:titleView_];
diff --git a/chrome/browser/ui/cocoa/tabs/tab_controller_unittest.mm b/chrome/browser/ui/cocoa/tabs/tab_controller_unittest.mm
index f039c3b..ad24ca7 100644
--- a/chrome/browser/ui/cocoa/tabs/tab_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/tabs/tab_controller_unittest.mm
@@ -4,7 +4,7 @@
 
 #import <Cocoa/Cocoa.h>
 
-#import "base/memory/scoped_nsobject.h"
+#import "base/mac/scoped_nsobject.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #import "chrome/browser/ui/cocoa/tabs/tab_controller.h"
@@ -20,7 +20,7 @@
  @private
   bool selected_;
   bool closed_;
-  scoped_nsobject<TabStripDragController> dragController_;
+  base::scoped_nsobject<TabStripDragController> dragController_;
 }
 - (bool)selected;
 - (bool)closed;
@@ -101,7 +101,7 @@
 // Tests creating the controller, sticking it in a window, and removing it.
 TEST_F(TabControllerTest, Creation) {
   NSWindow* window = test_window();
-  scoped_nsobject<TabController> controller([[TabController alloc] init]);
+  base::scoped_nsobject<TabController> controller([[TabController alloc] init]);
   [[window contentView] addSubview:[controller view]];
   EXPECT_TRUE([controller tabView]);
   EXPECT_EQ([[controller view] window], window);
@@ -113,10 +113,10 @@
 // called. Mimics the user clicking on the close button in the tab.
 TEST_F(TabControllerTest, Close) {
   NSWindow* window = test_window();
-  scoped_nsobject<TabController> controller([[TabController alloc] init]);
+  base::scoped_nsobject<TabController> controller([[TabController alloc] init]);
   [[window contentView] addSubview:[controller view]];
 
-  scoped_nsobject<TabControllerTestTarget> target(
+  base::scoped_nsobject<TabControllerTestTarget> target(
       [[TabControllerTestTarget alloc] init]);
   EXPECT_FALSE([target closed]);
   [controller setTarget:target];
@@ -131,7 +131,7 @@
 // Tests setting the |selected| property via code.
 TEST_F(TabControllerTest, APISelection) {
   NSWindow* window = test_window();
-  scoped_nsobject<TabController> controller([[TabController alloc] init]);
+  base::scoped_nsobject<TabController> controller([[TabController alloc] init]);
   [[window contentView] addSubview:[controller view]];
 
   EXPECT_FALSE([controller selected]);
@@ -145,7 +145,7 @@
 TEST_F(TabControllerTest, ToolTip) {
   NSWindow* window = test_window();
 
-  scoped_nsobject<TabController> controller([[TabController alloc] init]);
+  base::scoped_nsobject<TabController> controller([[TabController alloc] init]);
   [[window contentView] addSubview:[controller view]];
 
   EXPECT_TRUE([[controller toolTip] length] == 0);
@@ -157,7 +157,7 @@
 // Tests setting the |loading| property via code.
 TEST_F(TabControllerTest, Loading) {
   NSWindow* window = test_window();
-  scoped_nsobject<TabController> controller([[TabController alloc] init]);
+  base::scoped_nsobject<TabController> controller([[TabController alloc] init]);
   [[window contentView] addSubview:[controller view]];
 
   EXPECT_EQ(kTabDone, [controller loadingState]);
@@ -178,7 +178,7 @@
 
   // Create a tab at a known location in the window that we can click on
   // to activate selection.
-  scoped_nsobject<TabController> controller([[TabController alloc] init]);
+  base::scoped_nsobject<TabController> controller([[TabController alloc] init]);
   [[window contentView] addSubview:[controller view]];
   NSRect frame = [[controller view] frame];
   frame.size.width = [TabController minTabWidth];
@@ -186,7 +186,7 @@
   [[controller view] setFrame:frame];
 
   // Set the target and action.
-  scoped_nsobject<TabControllerTestTarget> target(
+  base::scoped_nsobject<TabControllerTestTarget> target(
       [[TabControllerTestTarget alloc] init]);
   EXPECT_FALSE([target selected]);
   [controller setTarget:target];
@@ -224,7 +224,7 @@
 
 TEST_F(TabControllerTest, IconCapacity) {
   NSWindow* window = test_window();
-  scoped_nsobject<TabController> controller([[TabController alloc] init]);
+  base::scoped_nsobject<TabController> controller([[TabController alloc] init]);
   [[window contentView] addSubview:[controller view]];
   int cap = [controller iconCapacity];
   EXPECT_GE(cap, 1);
@@ -238,7 +238,7 @@
 
 TEST_F(TabControllerTest, ShouldShowIcon) {
   NSWindow* window = test_window();
-  scoped_nsobject<TabController> controller([[TabController alloc] init]);
+  base::scoped_nsobject<TabController> controller([[TabController alloc] init]);
   [[window contentView] addSubview:[controller view]];
   int cap = [controller iconCapacity];
   EXPECT_GT(cap, 0);
@@ -251,7 +251,7 @@
   EXPECT_FALSE([controller shouldShowCloseButton]);
 
   // Setting the icon when tab is at min width should not show icon (bug 18359).
-  scoped_nsobject<NSView> newIcon(
+  base::scoped_nsobject<NSView> newIcon(
       [[NSView alloc] initWithFrame:NSMakeRect(0, 0, 16, 16)]);
   [controller setIconView:newIcon.get()];
   EXPECT_TRUE([newIcon isHidden]);
@@ -283,8 +283,8 @@
 
 TEST_F(TabControllerTest, Menu) {
   NSWindow* window = test_window();
-  scoped_nsobject<TabController> controller([[TabController alloc] init]);
-  scoped_nsobject<TabControllerTestTarget> target(
+  base::scoped_nsobject<TabController> controller([[TabController alloc] init]);
+  base::scoped_nsobject<TabControllerTestTarget> target(
       [[TabControllerTestTarget alloc] init]);
   [controller setTarget:target];
 
@@ -303,7 +303,7 @@
 TEST_F(TabControllerTest, TitleViewLayout) {
   NSWindow* window = test_window();
 
-  scoped_nsobject<TabController> controller([[TabController alloc] init]);
+  base::scoped_nsobject<TabController> controller([[TabController alloc] init]);
   [[window contentView] addSubview:[controller view]];
   NSRect tabFrame = [[controller view] frame];
   tabFrame.size.width = [TabController maxTabWidth];
diff --git a/chrome/browser/ui/cocoa/tabs/tab_projecting_image_view.h b/chrome/browser/ui/cocoa/tabs/tab_projecting_image_view.h
index 9b07b5b..7f74b16 100644
--- a/chrome/browser/ui/cocoa/tabs/tab_projecting_image_view.h
+++ b/chrome/browser/ui/cocoa/tabs/tab_projecting_image_view.h
@@ -7,7 +7,7 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "base/memory/scoped_ptr.h"
 #include "chrome/browser/ui/cocoa/tabs/throbbing_image_view.h"
 
@@ -16,7 +16,7 @@
 // animated glow. This view paints outside the favicon bounds due to the glow.
 @interface TabProjectingImageView : ThrobbingImageView {
  @private
-  scoped_nsobject<NSImage> projectorImage_;
+  base::scoped_nsobject<NSImage> projectorImage_;
 }
 
 - (id)initWithFrame:(NSRect)rect
diff --git a/chrome/browser/ui/cocoa/tabs/tab_projecting_image_view_unittest.mm b/chrome/browser/ui/cocoa/tabs/tab_projecting_image_view_unittest.mm
index 25bc7dd..ab10080 100644
--- a/chrome/browser/ui/cocoa/tabs/tab_projecting_image_view_unittest.mm
+++ b/chrome/browser/ui/cocoa/tabs/tab_projecting_image_view_unittest.mm
@@ -14,31 +14,31 @@
 class TabProjectingImageViewTest : public CocoaTest {
  public:
   TabProjectingImageViewTest() {
-    scoped_nsobject<NSImage> backgroundImage(
+    base::scoped_nsobject<NSImage> backgroundImage(
         [[NSImage alloc] initWithSize:NSMakeSize(16, 16)]);
     [backgroundImage lockFocus];
     NSRectFill(NSMakeRect(0, 0, 16, 16));
     [backgroundImage unlockFocus];
 
-    scoped_nsobject<NSImage> projectorImage(
+    base::scoped_nsobject<NSImage> projectorImage(
         [[NSImage alloc] initWithSize:NSMakeSize(16, 16)]);
     [projectorImage lockFocus];
     NSRectFill(NSMakeRect(0, 0, 16, 16));
     [projectorImage unlockFocus];
 
-    scoped_nsobject<NSImage> throbImage(
+    base::scoped_nsobject<NSImage> throbImage(
         [[NSImage alloc] initWithSize:NSMakeSize(32, 32)]);
     [throbImage lockFocus];
     NSRectFill(NSMakeRect(0, 0, 32, 32));
     [throbImage unlockFocus];
 
-    scoped_nsobject<TabProjectingImageView> view([[TabProjectingImageView alloc]
-              initWithFrame:NSMakeRect(0, 0, 32, 32)
-            backgroundImage:backgroundImage
-             projectorImage:projectorImage
-                 throbImage:throbImage
-                 durationMS:20
-         animationContainer:NULL]);
+    base::scoped_nsobject<TabProjectingImageView> view(
+        [[TabProjectingImageView alloc] initWithFrame:NSMakeRect(0, 0, 32, 32)
+                                      backgroundImage:backgroundImage
+                                       projectorImage:projectorImage
+                                           throbImage:throbImage
+                                           durationMS:20
+                                   animationContainer:NULL]);
     view_ = view.get();
     [[test_window() contentView] addSubview:view_];
   }
diff --git a/chrome/browser/ui/cocoa/tabs/tab_strip_controller.h b/chrome/browser/ui/cocoa/tabs/tab_strip_controller.h
index dc5e357..216ff3b 100644
--- a/chrome/browser/ui/cocoa/tabs/tab_strip_controller.h
+++ b/chrome/browser/ui/cocoa/tabs/tab_strip_controller.h
@@ -7,7 +7,7 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "base/memory/scoped_ptr.h"
 #import "chrome/browser/ui/cocoa/tabs/tab_controller_target.h"
 #import "chrome/browser/ui/cocoa/url_drop_target.h"
@@ -61,16 +61,17 @@
   NSObject<TabControllerTarget,
            URLDropTargetController> {
  @private
-  scoped_nsobject<TabStripView> tabStripView_;
+  base::scoped_nsobject<TabStripView> tabStripView_;
   NSView* switchView_;  // weak
-  scoped_nsobject<NSView> dragBlockingView_;  // avoid bad window server drags
+  base::scoped_nsobject<NSView> dragBlockingView_;  // avoid bad window server
+                                                    // drags
   NewTabButton* newTabButton_;  // weak, obtained from the nib.
 
   // The controller that manages all the interactions of dragging tabs.
-  scoped_nsobject<TabStripDragController> dragController_;
+  base::scoped_nsobject<TabStripDragController> dragController_;
 
   // Tracks the newTabButton_ for rollovers.
-  scoped_nsobject<CrTrackingArea> newTabTrackingArea_;
+  base::scoped_nsobject<CrTrackingArea> newTabTrackingArea_;
   scoped_ptr<TabStripModelObserverBridge> bridge_;
   Browser* browser_;  // weak
   TabStripModel* tabStripModel_;  // weak
@@ -89,14 +90,14 @@
   // tabs are animating closed (closed tabs are removed from |tabStripModel_|
   // immediately, but from |tabContentsArray_| only after their close animation
   // has completed).
-  scoped_nsobject<NSMutableArray> tabContentsArray_;
+  base::scoped_nsobject<NSMutableArray> tabContentsArray_;
   // An array of TabControllers which manage the actual tab views. See note
   // above |tabContentsArray_|. |tabContentsArray_| and |tabArray_| always
   // contain objects belonging to the same tabs at the same indices.
-  scoped_nsobject<NSMutableArray> tabArray_;
+  base::scoped_nsobject<NSMutableArray> tabArray_;
 
   // Set of TabControllers that are currently animating closed.
-  scoped_nsobject<NSMutableSet> closingControllers_;
+  base::scoped_nsobject<NSMutableSet> closingControllers_;
 
   // These values are only used during a drag, and override tab positioning.
   TabView* placeholderTab_;  // weak. Tab being dragged
@@ -105,7 +106,7 @@
   // Frame targets for all the current views.
   // target frames are used because repeated requests to [NSView animator].
   // aren't coalesced, so we store frames to avoid redundant calls.
-  scoped_nsobject<NSMutableDictionary> targetFrames_;
+  base::scoped_nsobject<NSMutableDictionary> targetFrames_;
   NSRect newTabTargetFrame_;
   // If YES, do not show the new tab button during layout.
   BOOL forceNewTabButtonHidden_;
@@ -121,15 +122,15 @@
   float availableResizeWidth_;
   // A tracking area that's the size of the tab strip used to be notified
   // when the mouse moves in the tab strip
-  scoped_nsobject<CrTrackingArea> trackingArea_;
+  base::scoped_nsobject<CrTrackingArea> trackingArea_;
   TabView* hoveredTab_;  // weak. Tab that the mouse is hovering over
 
   // Array of subviews which are permanent (and which should never be removed),
   // such as the new-tab button, but *not* the tabs themselves.
-  scoped_nsobject<NSMutableArray> permanentSubviews_;
+  base::scoped_nsobject<NSMutableArray> permanentSubviews_;
 
   // The default favicon, so we can use one copy for all buttons.
-  scoped_nsobject<NSImage> defaultFavicon_;
+  base::scoped_nsobject<NSImage> defaultFavicon_;
 
   // The amount by which to indent the tabs on the sides (to make room for the
   // red/yellow/green and incognito/fullscreen buttons).
diff --git a/chrome/browser/ui/cocoa/tabs/tab_strip_controller.mm b/chrome/browser/ui/cocoa/tabs/tab_strip_controller.mm
index de91256..b7f1c9d 100644
--- a/chrome/browser/ui/cocoa/tabs/tab_strip_controller.mm
+++ b/chrome/browser/ui/cocoa/tabs/tab_strip_controller.mm
@@ -162,7 +162,7 @@
 // 10.6 and 10.7.
 NSImage* CreateImageWithSize(NSSize size,
                              void (^drawingHandler)(NSSize)) {
-  scoped_nsobject<NSImage> result([[NSImage alloc] initWithSize:size]);
+  base::scoped_nsobject<NSImage> result([[NSImage alloc] initWithSize:size]);
   [NSGraphicsContext saveGraphicsState];
   for (ui::ScaleFactor scale_factor : ui::GetSupportedScaleFactors()) {
     float scale = GetScaleFactorScale(scale_factor);
@@ -1296,7 +1296,7 @@
 
   // Make a new tab. Load the contents of this tab from the nib and associate
   // the new controller with |contents| so it can be looked up later.
-  scoped_nsobject<TabContentsController> contentsController(
+  base::scoped_nsobject<TabContentsController> contentsController(
       [[TabContentsController alloc] initWithContents:contents]);
   [tabContentsArray_ insertObject:contentsController atIndex:index];
 
@@ -1410,7 +1410,7 @@
   // Simply create a new TabContentsController for |newContents| and place it
   // into the array, replacing |oldContents|.  An ActiveTabChanged notification
   // will follow, at which point we will install the new view.
-  scoped_nsobject<TabContentsController> newController(
+  base::scoped_nsobject<TabContentsController> newController(
       [[TabContentsController alloc] initWithContents:newContents]);
 
   // Bye bye, |oldController|.
@@ -1491,9 +1491,9 @@
   NSView* tabView = [closingTab view];
   CAAnimation* animation = [[tabView animationForKey:@"frameOrigin"] copy];
   [animation autorelease];
-  scoped_nsobject<TabCloseAnimationDelegate> delegate(
-    [[TabCloseAnimationDelegate alloc] initWithTabStrip:self
-                                          tabController:closingTab]);
+  base::scoped_nsobject<TabCloseAnimationDelegate> delegate(
+      [[TabCloseAnimationDelegate alloc] initWithTabStrip:self
+                                            tabController:closingTab]);
   [animation setDelegate:delegate.get()];  // Retains delegate.
   NSMutableDictionary* animationDictionary =
       [NSMutableDictionary dictionaryWithDictionary:[tabView animations]];
@@ -1636,7 +1636,7 @@
                  projectorImage:projector
                      throbImage:projectorGlow
                      durationMS:kRecordingDurationMs
-             animationContainer:animationContainer_] autorelease];
+             animationContainer:animationContainer_.get()] autorelease];
 
           iconView = projectingView;
         } else if (theme && chrome::ShouldShowRecordingIndicator(contents)) {
@@ -1655,7 +1655,7 @@
                      throbImage:recording
                      durationMS:kRecordingDurationMs
                   throbPosition:kThrobPositionBottomRight
-             animationContainer:animationContainer_] autorelease];
+             animationContainer:animationContainer_.get()] autorelease];
 
           iconView = recordingView;
         } else if (chrome::IsPlayingAudio(contents) ||
@@ -1666,7 +1666,7 @@
             tabAudioIndicatorViewMac = [[[TabAudioIndicatorViewMac alloc]
                 initWithFrame:frame] autorelease];
             [tabAudioIndicatorViewMac
-                setAnimationContainer:animationContainer_];
+                setAnimationContainer:animationContainer_.get()];
           }
           [tabAudioIndicatorViewMac
               setIsPlayingAudio:chrome::IsPlayingAudio(contents)];
@@ -1746,12 +1746,12 @@
   // Cancel any pending tab transition.
   hoverTabSelector_->CancelTabTransition();
 
-  scoped_nsobject<TabContentsController> movedTabContentsController(
+  base::scoped_nsobject<TabContentsController> movedTabContentsController(
       [[tabContentsArray_ objectAtIndex:from] retain]);
   [tabContentsArray_ removeObjectAtIndex:from];
   [tabContentsArray_ insertObject:movedTabContentsController.get()
                           atIndex:to];
-  scoped_nsobject<TabController> movedTabController(
+  base::scoped_nsobject<TabController> movedTabController(
       [[tabArray_ objectAtIndex:from] retain]);
   DCHECK([movedTabController isKindOfClass:[TabController class]]);
   [tabArray_ removeObjectAtIndex:from];
@@ -2044,6 +2044,7 @@
   if (activeTabView) {
     [subviews addObject:activeTabView];
   }
+  WithNoAnimation noAnimation;
   [tabStripView_ setSubviews:subviews];
   [self setTabTrackingAreasEnabled:mouseInside_];
 }
diff --git a/chrome/browser/ui/cocoa/tabs/tab_strip_controller_unittest.mm b/chrome/browser/ui/cocoa/tabs/tab_strip_controller_unittest.mm
index 025caae..cf230d1 100644
--- a/chrome/browser/ui/cocoa/tabs/tab_strip_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/tabs/tab_strip_controller_unittest.mm
@@ -93,7 +93,7 @@
     // Create the "switch view" (view that gets changed out when a tab
     // switches).
     NSRect switch_frame = NSMakeRect(0, 0, content_frame.size.width, 500);
-    scoped_nsobject<NSView> switch_view(
+    base::scoped_nsobject<NSView> switch_view(
         [[NSView alloc] initWithFrame:switch_frame]);
     [parent addSubview:switch_view.get()];
 
@@ -105,7 +105,7 @@
         [[TabStripView alloc] initWithFrame:strip_frame]);
     [parent addSubview:tab_strip_.get()];
     NSRect button_frame = NSMakeRect(0, 0, 15, 15);
-    scoped_nsobject<NewTabButton> new_tab_button(
+    base::scoped_nsobject<NewTabButton> new_tab_button(
         [[NewTabButton alloc] initWithFrame:button_frame]);
     [tab_strip_ addSubview:new_tab_button.get()];
     [tab_strip_ setNewTabButton:new_tab_button.get()];
@@ -152,9 +152,9 @@
 
   scoped_ptr<TestTabStripModelDelegate> delegate_;
   TabStripModel* model_;
-  scoped_nsobject<TestTabStripControllerDelegate> controller_delegate_;
-  scoped_nsobject<TabStripController> controller_;
-  scoped_nsobject<TabStripView> tab_strip_;
+  base::scoped_nsobject<TestTabStripControllerDelegate> controller_delegate_;
+  base::scoped_nsobject<TabStripController> controller_;
+  base::scoped_nsobject<TabStripView> tab_strip_;
 };
 
 // Test adding and removing tabs and making sure that views get added to
@@ -240,10 +240,9 @@
   // Schedule a task to close all the tabs and stop the drag, before the call to
   // -maybeStartDrag:forTab:, which starts a nested event loop. This task will
   // run in that nested event loop, which shouldn't crash.
-  scoped_nsobject<TestClosureRunner> runner(
-      [[TestClosureRunner alloc] initWithClosure:
-          base::Bind(&TabStripControllerTest::CloseTabsAndEndDrag,
-                     base::Unretained(this))]);
+  base::scoped_nsobject<TestClosureRunner> runner([[TestClosureRunner alloc]
+      initWithClosure:base::Bind(&TabStripControllerTest::CloseTabsAndEndDrag,
+                                 base::Unretained(this))]);
   [runner scheduleDelayedRun];
 
   NSEvent* event =
diff --git a/chrome/browser/ui/cocoa/tabs/tab_strip_drag_controller.mm b/chrome/browser/ui/cocoa/tabs/tab_strip_drag_controller.mm
index 2a338bb..e24351a 100644
--- a/chrome/browser/ui/cocoa/tabs/tab_strip_drag_controller.mm
+++ b/chrome/browser/ui/cocoa/tabs/tab_strip_drag_controller.mm
@@ -108,8 +108,8 @@
   // When spinning the event loop, a tab can get detached, which could lead to
   // our own destruction. Keep ourselves around while spinning the loop as well
   // as the tab controller being dragged.
-  scoped_nsobject<TabStripDragController> keepAlive([self retain]);
-  scoped_nsobject<TabController> keepAliveTab([tab retain]);
+  base::scoped_nsobject<TabStripDragController> keepAlive([self retain]);
+  base::scoped_nsobject<TabController> keepAliveTab([tab retain]);
 
   // Because we move views between windows, we need to handle the event loop
   // ourselves. Ideally we should use the standard event loop.
diff --git a/chrome/browser/ui/cocoa/tabs/tab_strip_view.h b/chrome/browser/ui/cocoa/tabs/tab_strip_view.h
index 1cb4ba2..c919671 100644
--- a/chrome/browser/ui/cocoa/tabs/tab_strip_view.h
+++ b/chrome/browser/ui/cocoa/tabs/tab_strip_view.h
@@ -7,7 +7,8 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
+#import "chrome/browser/ui/cocoa/background_gradient_view.h"
 #import "chrome/browser/ui/cocoa/url_drop_target.h"
 
 @class NewTabButton;
@@ -16,16 +17,16 @@
 // A view class that handles rendering the tab strip and drops of URLS with
 // a positioning locator for drop feedback.
 
-@interface TabStripView : NSView<URLDropTarget> {
+@interface TabStripView : BackgroundGradientView<URLDropTarget> {
  @private
   TabStripController* controller_;  // Weak; owns us.
 
   NSTimeInterval lastMouseUp_;
 
   // Handles being a drag-and-drop target.
-  scoped_nsobject<URLDropTargetHandler> dropHandler_;
+  base::scoped_nsobject<URLDropTargetHandler> dropHandler_;
 
-  scoped_nsobject<NewTabButton> newTabButton_;
+  base::scoped_nsobject<NewTabButton> newTabButton_;
 
   // Whether the drop-indicator arrow is shown, and if it is, the coordinate of
   // its tip.
diff --git a/chrome/browser/ui/cocoa/tabs/tab_strip_view_unittest.mm b/chrome/browser/ui/cocoa/tabs/tab_strip_view_unittest.mm
index d7961aa..ed816bf 100644
--- a/chrome/browser/ui/cocoa/tabs/tab_strip_view_unittest.mm
+++ b/chrome/browser/ui/cocoa/tabs/tab_strip_view_unittest.mm
@@ -4,7 +4,7 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #import "chrome/browser/ui/cocoa/tabs/tab_strip_view.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -16,7 +16,7 @@
  public:
   TabStripViewTest() {
     NSRect frame = NSMakeRect(0, 0, 100, 30);
-    scoped_nsobject<TabStripView> view(
+    base::scoped_nsobject<TabStripView> view(
         [[TabStripView alloc] initWithFrame:frame]);
     view_ = view.get();
     [[test_window() contentView] addSubview:view_];
diff --git a/chrome/browser/ui/cocoa/tabs/tab_view.h b/chrome/browser/ui/cocoa/tabs/tab_view.h
index 7f640d0..f5c3177 100644
--- a/chrome/browser/ui/cocoa/tabs/tab_view.h
+++ b/chrome/browser/ui/cocoa/tabs/tab_view.h
@@ -5,11 +5,11 @@
 #ifndef CHROME_BROWSER_UI_COCOA_TABS_TAB_VIEW_H_
 #define CHROME_BROWSER_UI_COCOA_TABS_TAB_VIEW_H_
 
-#import <Cocoa/Cocoa.h>
 #include <ApplicationServices/ApplicationServices.h>
+#import <Cocoa/Cocoa.h>
 
 #include "base/mac/scoped_cftyperef.h"
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #import "chrome/browser/ui/cocoa/hover_close_button.h"
 
 namespace tabs {
@@ -70,11 +70,11 @@
   NSCellStateValue state_;
 
   // The tool tip text for this tab view.
-  scoped_nsobject<NSString> toolTipText_;
+  base::scoped_nsobject<NSString> toolTipText_;
 
   // A one-element mask image cache.  This cache makes drawing roughly 16%
   // faster.
-  base::mac::ScopedCFTypeRef<CGImageRef> maskCache_;
+  base::ScopedCFTypeRef<CGImageRef> maskCache_;
   CGFloat maskCacheWidth_;
   CGFloat maskCacheScale_;
 }
diff --git a/chrome/browser/ui/cocoa/tabs/tab_view.mm b/chrome/browser/ui/cocoa/tabs/tab_view.mm
index c312444..d7ff32f 100644
--- a/chrome/browser/ui/cocoa/tabs/tab_view.mm
+++ b/chrome/browser/ui/cocoa/tabs/tab_view.mm
@@ -142,12 +142,8 @@
 // view or our child close button.
 - (NSView*)hitTest:(NSPoint)aPoint {
   NSPoint viewPoint = [self convertPoint:aPoint fromView:[self superview]];
-  if (![closeButton_ isHidden]) {
-    if (NSPointInRect(viewPoint,[closeButton_ frame]) &&
-        [closeButton_ hitTest:viewPoint]) {
-      return closeButton_;
-    }
-  }
+  if (![closeButton_ isHidden])
+    if (NSPointInRect(viewPoint, [closeButton_ frame])) return closeButton_;
 
   NSRect pointRect = NSMakeRect(viewPoint.x, viewPoint.y, 1, 1);
 
@@ -215,7 +211,7 @@
   // strip and then deallocated. This will also result in *us* being
   // deallocated. Both these are bad, so we prevent this by retaining the
   // controller.
-  scoped_nsobject<TabController> controller([controller_ retain]);
+  base::scoped_nsobject<TabController> controller([controller_ retain]);
 
   // Try to initiate a drag. This will spin a custom event loop and may
   // dispatch other mouse events.
@@ -383,7 +379,7 @@
     // Draw a mouse hover gradient for the default themes.
     if (!selected && hoverAlpha > 0) {
       if (themeProvider && !hasCustomTheme) {
-        scoped_nsobject<NSGradient> glow([NSGradient alloc]);
+        base::scoped_nsobject<NSGradient> glow([NSGradient alloc]);
         [glow initWithStartingColor:[NSColor colorWithCalibratedWhite:1.0
                                         alpha:1.0 * hoverAlpha]
                         endingColor:[NSColor colorWithCalibratedWhite:1.0
@@ -438,6 +434,13 @@
   [self drawStroke:dirtyRect];
 }
 
+- (void)setFrameOrigin:(NSPoint)origin {
+  // The background color depends on the view's vertical position.
+  if (NSMinY([self frame]) != origin.y)
+    [self setNeedsDisplay:YES];
+  [super setFrameOrigin:origin];
+}
+
 // Override this to catch the text so that we can choose when to display it.
 - (void)setToolTip:(NSString*)string {
   toolTipText_.reset([string retain]);
@@ -457,6 +460,13 @@
   }
 }
 
+- (void)setState:(NSCellStateValue)state {
+  if (state_ == state)
+    return;
+  state_ = state;
+  [self setNeedsDisplay:YES];
+}
+
 - (void)setClosing:(BOOL)closing {
   closing_ = closing;  // Safe because the property is nonatomic.
   // When closing, ensure clicks to the close button go nowhere.
@@ -671,7 +681,7 @@
 
   // Image masks must be in the DeviceGray colorspace. Create a context and
   // draw the mask into it.
-  base::mac::ScopedCFTypeRef<CGColorSpaceRef> colorspace(
+  base::ScopedCFTypeRef<CGColorSpaceRef> colorspace(
       CGColorSpaceCreateDeviceGray());
   CGContextRef maskContext =
       CGBitmapContextCreate(NULL, tabWidth * scale, kMaskHeight * scale,
diff --git a/chrome/browser/ui/cocoa/tabs/tab_view_unittest.mm b/chrome/browser/ui/cocoa/tabs/tab_view_unittest.mm
index e5f6c12..ccc1216 100644
--- a/chrome/browser/ui/cocoa/tabs/tab_view_unittest.mm
+++ b/chrome/browser/ui/cocoa/tabs/tab_view_unittest.mm
@@ -4,7 +4,7 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #import "chrome/browser/ui/cocoa/tabs/tab_view.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -19,7 +19,7 @@
  public:
   TabViewTest() {
     NSRect frame = NSMakeRect(0, 0, kTabWidth, kTabHeight);
-    scoped_nsobject<TabView> view([[TabView alloc] initWithFrame:frame]);
+    base::scoped_nsobject<TabView> view([[TabView alloc] initWithFrame:frame]);
     view_ = view.get();
     [[test_window() contentView] addSubview:view_];
   }
diff --git a/chrome/browser/ui/cocoa/tabs/tab_window_controller.h b/chrome/browser/ui/cocoa/tabs/tab_window_controller.h
index 4242c2d..70693ff 100644
--- a/chrome/browser/ui/cocoa/tabs/tab_window_controller.h
+++ b/chrome/browser/ui/cocoa/tabs/tab_window_controller.h
@@ -14,7 +14,7 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 
 @class FastResizeView;
 @class FocusTracker;
@@ -23,8 +23,8 @@
 
 @interface TabWindowController : NSWindowController<NSWindowDelegate> {
  @private
-  scoped_nsobject<FastResizeView> tabContentArea_;
-  scoped_nsobject<TabStripView> tabStripView_;
+  base::scoped_nsobject<FastResizeView> tabContentArea_;
+  base::scoped_nsobject<TabStripView> tabStripView_;
 
   // The child window used during dragging to achieve the opacity tricks.
   NSWindow* overlayWindow_;
@@ -33,7 +33,7 @@
   // of the drag) to the |overlayWindow_|.
   NSView* originalContentView_;  // weak
 
-  scoped_nsobject<FocusTracker> focusBeforeOverlay_;
+  base::scoped_nsobject<FocusTracker> focusBeforeOverlay_;
   BOOL closeDeferred_;  // If YES, call performClose: in removeOverlay:.
 }
 @property(readonly, nonatomic) TabStripView* tabStripView;
diff --git a/chrome/browser/ui/cocoa/tabs/tab_window_controller.mm b/chrome/browser/ui/cocoa/tabs/tab_window_controller.mm
index fa7a5e7..e49c875 100644
--- a/chrome/browser/ui/cocoa/tabs/tab_window_controller.mm
+++ b/chrome/browser/ui/cocoa/tabs/tab_window_controller.mm
@@ -45,7 +45,7 @@
 
 - (id)initTabWindowControllerWithTabStrip:(BOOL)hasTabStrip {
   NSRect contentRect = NSMakeRect(60, 229, 750, 600);
-  scoped_nsobject<FramedBrowserWindow> window(
+  base::scoped_nsobject<FramedBrowserWindow> window(
       [[FramedBrowserWindow alloc] initWithContentRect:contentRect
                                            hasTabStrip:hasTabStrip]);
   [window setReleasedWhenClosed:YES];
diff --git a/chrome/browser/ui/cocoa/tabs/throbber_view.h b/chrome/browser/ui/cocoa/tabs/throbber_view.h
index 6e90ec0..ade4d7f 100644
--- a/chrome/browser/ui/cocoa/tabs/throbber_view.h
+++ b/chrome/browser/ui/cocoa/tabs/throbber_view.h
@@ -7,8 +7,6 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
-
 @protocol ThrobberDataDelegate;
 
 // A class that knows how to draw an animated state to indicate progress.
diff --git a/chrome/browser/ui/cocoa/tabs/throbber_view.mm b/chrome/browser/ui/cocoa/tabs/throbber_view.mm
index 29cc6df..0d838a3 100644
--- a/chrome/browser/ui/cocoa/tabs/throbber_view.mm
+++ b/chrome/browser/ui/cocoa/tabs/throbber_view.mm
@@ -7,6 +7,7 @@
 #include <set>
 
 #include "base/logging.h"
+#include "base/mac/scoped_nsobject.h"
 
 static const float kAnimationIntervalSeconds = 0.03;  // 30ms, same as windows
 
@@ -29,7 +30,7 @@
 
 @interface ThrobberFilmstripDelegate : NSObject
                                        <ThrobberDataDelegate> {
-  scoped_nsobject<NSImage> image_;
+  base::scoped_nsobject<NSImage> image_;
   unsigned int numFrames_;  // Number of frames in this animation.
   unsigned int animationFrame_;  // Current frame of the animation,
                                  // [0..numFrames_)
@@ -83,8 +84,8 @@
 
 @interface ThrobberToastDelegate : NSObject
                                    <ThrobberDataDelegate> {
-  scoped_nsobject<NSImage> image1_;
-  scoped_nsobject<NSImage> image2_;
+  base::scoped_nsobject<NSImage> image1_;
+  base::scoped_nsobject<NSImage> image2_;
   NSSize image1Size_;
   NSSize image2Size_;
   int animationFrame_;  // Current frame of the animation,
diff --git a/chrome/browser/ui/cocoa/tabs/throbber_view_unittest.mm b/chrome/browser/ui/cocoa/tabs/throbber_view_unittest.mm
index de7f295..22e72cc 100644
--- a/chrome/browser/ui/cocoa/tabs/throbber_view_unittest.mm
+++ b/chrome/browser/ui/cocoa/tabs/throbber_view_unittest.mm
@@ -4,7 +4,7 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #import "chrome/browser/ui/cocoa/tabs/throbber_view.h"
 #include "grit/ui_resources.h"
diff --git a/chrome/browser/ui/cocoa/tabs/throbbing_image_view.h b/chrome/browser/ui/cocoa/tabs/throbbing_image_view.h
index 1cd8d60..4cf9486 100644
--- a/chrome/browser/ui/cocoa/tabs/throbbing_image_view.h
+++ b/chrome/browser/ui/cocoa/tabs/throbbing_image_view.h
@@ -7,7 +7,7 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "base/memory/scoped_ptr.h"
 #include "ui/base/animation/throb_animation.h"
 
@@ -23,8 +23,8 @@
 
 @interface ThrobbingImageView : NSView {
  @protected
-  scoped_nsobject<NSImage> backgroundImage_;
-  scoped_nsobject<NSImage> throbImage_;
+  base::scoped_nsobject<NSImage> backgroundImage_;
+  base::scoped_nsobject<NSImage> throbImage_;
   scoped_ptr<ui::ThrobAnimation> throbAnimation_;
 
  @private
diff --git a/chrome/browser/ui/cocoa/tabs/throbbing_image_view_unittest.mm b/chrome/browser/ui/cocoa/tabs/throbbing_image_view_unittest.mm
index 33f7f41..703d97b 100644
--- a/chrome/browser/ui/cocoa/tabs/throbbing_image_view_unittest.mm
+++ b/chrome/browser/ui/cocoa/tabs/throbbing_image_view_unittest.mm
@@ -14,19 +14,19 @@
 class ThrobbingImageViewTest : public CocoaTest {
  public:
   ThrobbingImageViewTest() {
-    scoped_nsobject<NSImage> image(
+    base::scoped_nsobject<NSImage> image(
         [[NSImage alloc] initWithSize:NSMakeSize(16, 16)]);
     [image lockFocus];
     NSRectFill(NSMakeRect(0, 0, 16, 16));
     [image unlockFocus];
 
-    scoped_nsobject<ThrobbingImageView> view([[ThrobbingImageView alloc]
-            initWithFrame:NSMakeRect(0, 0, 16, 16)
-          backgroundImage:image
-               throbImage:image
-               durationMS:20
-            throbPosition:kThrobPositionOverlay
-       animationContainer:NULL]);
+    base::scoped_nsobject<ThrobbingImageView> view(
+        [[ThrobbingImageView alloc] initWithFrame:NSMakeRect(0, 0, 16, 16)
+                                  backgroundImage:image
+                                       throbImage:image
+                                       durationMS:20
+                                    throbPosition:kThrobPositionOverlay
+                               animationContainer:NULL]);
     view_ = view.get();
     [[test_window() contentView] addSubview:view_];
   }
diff --git a/chrome/browser/ui/cocoa/task_manager_mac.h b/chrome/browser/ui/cocoa/task_manager_mac.h
index 7651e0d..093f9f4 100644
--- a/chrome/browser/ui/cocoa/task_manager_mac.h
+++ b/chrome/browser/ui/cocoa/task_manager_mac.h
@@ -8,7 +8,7 @@
 #import <Cocoa/Cocoa.h>
 #include <vector>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "chrome/browser/task_manager/task_manager.h"
 #include "chrome/browser/ui/cocoa/table_row_nsimage_cache.h"
 
@@ -30,9 +30,8 @@
   TaskManagerMac* taskManagerObserver_;  // weak
   TaskManager* taskManager_;  // weak
   TaskManagerModel* model_;  // weak
-  bool highlightBackgroundResources_;
 
-  scoped_nsobject<WindowSizeAutosaver> size_saver_;
+  base::scoped_nsobject<WindowSizeAutosaver> size_saver_;
 
   // These contain a permutation of [0..|model_->ResourceCount() - 1|]. Used to
   // implement sorting.
@@ -40,15 +39,11 @@
   std::vector<int> modelToViewMap_;
 
   // Descriptor of the current sort column.
-  scoped_nsobject<NSSortDescriptor> currentSortDescriptor_;
-
-  // Color we use for background resources.
-  scoped_nsobject<NSColor> backgroundResourceColor_;
+  base::scoped_nsobject<NSSortDescriptor> currentSortDescriptor_;
 }
 
 // Creates and shows the task manager's window.
-- (id)initWithTaskManagerObserver:(TaskManagerMac*)taskManagerObserver
-     highlightBackgroundResources:(bool)highlightBackgroundResources;
+- (id)initWithTaskManagerObserver:(TaskManagerMac*)taskManagerObserver;
 
 // Refreshes all data in the task manager table.
 - (void)reloadData;
@@ -71,7 +66,7 @@
 class TaskManagerMac : public TaskManagerModelObserver,
                        public TableRowNSImageCache::Table {
  public:
-  TaskManagerMac(TaskManager* task_manager, bool highlight_background);
+  explicit TaskManagerMac(TaskManager* task_manager);
   virtual ~TaskManagerMac();
 
   // TaskManagerModelObserver
@@ -89,9 +84,8 @@
   virtual gfx::ImageSkia GetIcon(int r) const OVERRIDE;
 
   // Creates the task manager if it doesn't exist; otherwise, it activates the
-  // existing task manager window. Highlights background resources if
-  // |highlight_background_resources| is true.
-  static void Show(bool highlight_background_resources);
+  // existing task manager window.
+  static void Show();
 
   // Returns the TaskManager observed by |this|.
   TaskManager* task_manager() { return task_manager_; }
@@ -102,8 +96,6 @@
   // Returns the cocoa object. Used for testing.
   TaskManagerWindowController* cocoa_controller() { return window_controller_; }
 
-  // Returns true if the resource at this location is a background resource.
-  bool IsBackgroundRow(int row) const;
  private:
   // The task manager.
   TaskManager* const task_manager_;  // weak
@@ -118,9 +110,6 @@
   // Caches favicons for all rows. Needs to be initalized after |model_|.
   TableRowNSImageCache icon_cache_;
 
-  // If true, highlight background resources.
-  bool highlight_background_resources_;
-
   // An open task manager window. There can only be one open at a time. This
   // is reset to NULL when the window is closed.
   static TaskManagerMac* instance_;
diff --git a/chrome/browser/ui/cocoa/task_manager_mac.mm b/chrome/browser/ui/cocoa/task_manager_mac.mm
index bf8e04d..a75e706 100644
--- a/chrome/browser/ui/cocoa/task_manager_mac.mm
+++ b/chrome/browser/ui/cocoa/task_manager_mac.mm
@@ -113,8 +113,7 @@
 
 @implementation TaskManagerWindowController
 
-- (id)initWithTaskManagerObserver:(TaskManagerMac*)taskManagerObserver
-     highlightBackgroundResources:(bool)highlightBackgroundResources {
+- (id)initWithTaskManagerObserver:(TaskManagerMac*)taskManagerObserver {
   NSString* nibpath = [base::mac::FrameworkBundle()
                         pathForResource:@"TaskManager"
                                  ofType:@"nib"];
@@ -122,15 +121,6 @@
     taskManagerObserver_ = taskManagerObserver;
     taskManager_ = taskManagerObserver_->task_manager();
     model_ = taskManager_->model();
-    highlightBackgroundResources_ = highlightBackgroundResources;
-    if (highlightBackgroundResources_) {
-      // Highlight background resources with a yellow background.
-      backgroundResourceColor_.reset(
-          [[NSColor colorWithDeviceRed:0xff/255.0
-                                 green:0xfa/255.0
-                                  blue:0xcd/255.0
-                                 alpha:1.0] retain]);
-    }
 
     if (g_browser_process && g_browser_process->local_state()) {
       size_saver_.reset([[WindowSizeAutosaver alloc]
@@ -226,7 +216,7 @@
 // Adds a column which has the given string id as title. |isVisible| specifies
 // if the column is initially visible.
 - (NSTableColumn*)addColumnWithId:(int)columnId visible:(BOOL)isVisible {
-  scoped_nsobject<NSTableColumn> column([[NSTableColumn alloc]
+  base::scoped_nsobject<NSTableColumn> column([[NSTableColumn alloc]
       initWithIdentifier:[NSString stringWithFormat:@"%d", columnId]]);
 
   NSTextAlignment textAlignment =
@@ -248,9 +238,10 @@
   // The page column should by default be sorted ascending.
   BOOL ascending = columnId == IDS_TASK_MANAGER_TASK_COLUMN;
 
-  scoped_nsobject<NSSortDescriptor> sortDescriptor([[NSSortDescriptor alloc]
-      initWithKey:[NSString stringWithFormat:@"%d", columnId]
-        ascending:ascending]);
+  base::scoped_nsobject<NSSortDescriptor> sortDescriptor(
+      [[NSSortDescriptor alloc]
+          initWithKey:[NSString stringWithFormat:@"%d", columnId]
+            ascending:ascending]);
   [column.get() setSortDescriptorPrototype:sortDescriptor.get()];
 
   // Default values, only used in release builds if nobody notices the DCHECK
@@ -285,7 +276,7 @@
                                             visible:YES];
   // |nameColumn| displays an icon for every row -- this is done by an
   // NSButtonCell.
-  scoped_nsobject<NSButtonCell> nameCell(
+  base::scoped_nsobject<NSButtonCell> nameCell(
       [[NSButtonCell alloc] initTextCell:@""]);
   [nameCell.get() setImagePosition:NSImageLeft];
   [nameCell.get() setButtonType:NSSwitchButton];
@@ -320,7 +311,7 @@
 // which columns should be shown and which should be hidden (like e.g.
 // Task Manager.app's table header context menu).
 - (void)setUpTableHeaderContextMenu {
-  scoped_nsobject<NSMenu> contextMenu(
+  base::scoped_nsobject<NSMenu> contextMenu(
       [[NSMenu alloc] initWithTitle:@"Task Manager context menu"]);
   for (NSTableColumn* column in [tableView_ tableColumns]) {
     NSMenuItem* item = [contextMenu.get()
@@ -396,35 +387,6 @@
   [self autorelease];
 }
 
-// Delegate method invoked before each cell in the table is displayed. We
-// override this to provide highlighting of background resources.
-- (void)  tableView:(NSTableView*)tableView
-    willDisplayCell:(id)cell
-     forTableColumn:(NSTableColumn*)tableColumn
-                row:(NSInteger)row {
-  if (!highlightBackgroundResources_)
-    return;
-
-  DCHECK([cell respondsToSelector:@selector(setBackgroundColor:)]);
-  if ([cell respondsToSelector:@selector(setBackgroundColor:)]) {
-    NSColor* color = nil;
-    if (taskManagerObserver_->IsBackgroundRow(viewToModelMap_[row]) &&
-        ![tableView isRowSelected:row]) {
-      color = backgroundResourceColor_.get();
-      if ((row % 2) == 1 && [tableView usesAlternatingRowBackgroundColors]) {
-        color = [color blendedColorWithFraction:0.05
-                                        ofColor:[NSColor blackColor]];
-      }
-    }
-    [cell setBackgroundColor:color];
-
-    // The icon at the left is an |NSButtonCell|, which does not
-    // implement this method on 10.5.
-    if ([cell respondsToSelector:@selector(setDrawsBackground:)])
-      [cell setDrawsBackground:(color != nil)];
-  }
-}
-
 @end
 
 @implementation TaskManagerWindowController (NSTableDataSource)
@@ -489,16 +451,12 @@
 ////////////////////////////////////////////////////////////////////////////////
 // TaskManagerMac implementation:
 
-TaskManagerMac::TaskManagerMac(TaskManager* task_manager,
-                               bool highlight_background_resources)
+TaskManagerMac::TaskManagerMac(TaskManager* task_manager)
   : task_manager_(task_manager),
     model_(task_manager->model()),
-    icon_cache_(this),
-    highlight_background_resources_(highlight_background_resources) {
+    icon_cache_(this) {
   window_controller_ =
-      [[TaskManagerWindowController alloc]
-           initWithTaskManagerObserver:this
-          highlightBackgroundResources:highlight_background_resources];
+      [[TaskManagerWindowController alloc] initWithTaskManagerObserver:this];
   model_->AddObserver(this);
 }
 
@@ -560,37 +518,23 @@
   return model_->GetResourceIcon(r);
 }
 
-bool TaskManagerMac::IsBackgroundRow(int row) const {
-  return model_->IsBackgroundResource(row);
-}
-
 // static
-void TaskManagerMac::Show(bool highlight_background_resources) {
+void TaskManagerMac::Show() {
   if (instance_) {
-    if (instance_->highlight_background_resources_ ==
-        highlight_background_resources) {
-      // There's a Task manager window open already, so just activate it.
-      [[instance_->window_controller_ window]
-        makeKeyAndOrderFront:instance_->window_controller_];
-      return;
-    } else {
-      // The user is switching between "View Background Pages" and
-      // "Task Manager" so close the existing window and fall through to
-      // open a new one.
-      [[instance_->window_controller_ window] close];
-    }
+    [[instance_->window_controller_ window]
+      makeKeyAndOrderFront:instance_->window_controller_];
+    return;
   }
   // Create a new instance.
-  instance_ = new TaskManagerMac(TaskManager::GetInstance(),
-                                 highlight_background_resources);
+  instance_ = new TaskManagerMac(TaskManager::GetInstance());
   instance_->model_->StartUpdating();
 }
 
 namespace chrome {
 
 // Declared in browser_dialogs.h.
-void ShowTaskManager(Browser* browser, bool highlight_background_resources) {
-  TaskManagerMac::Show(highlight_background_resources);
+void ShowTaskManager(Browser* browser) {
+  TaskManagerMac::Show();
 }
 
 }  // namespace chrome
diff --git a/chrome/browser/ui/cocoa/task_manager_mac_unittest.mm b/chrome/browser/ui/cocoa/task_manager_mac_unittest.mm
index 6a548e4..9dff6b1 100644
--- a/chrome/browser/ui/cocoa/task_manager_mac_unittest.mm
+++ b/chrome/browser/ui/cocoa/task_manager_mac_unittest.mm
@@ -5,7 +5,6 @@
 #import <Cocoa/Cocoa.h>
 
 #include "base/compiler_specific.h"
-#include "base/memory/scoped_nsobject.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/task_manager/resource_provider.h"
 #import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
@@ -47,7 +46,7 @@
 // Test creation, to ensure nothing leaks or crashes.
 TEST_F(TaskManagerWindowControllerTest, Init) {
   TaskManager task_manager;
-  TaskManagerMac* bridge(new TaskManagerMac(&task_manager, false));
+  TaskManagerMac* bridge(new TaskManagerMac(&task_manager));
   TaskManagerWindowController* controller = bridge->cocoa_controller();
 
   // Releases the controller, which in turn deletes |bridge|.
@@ -65,7 +64,7 @@
   task_manager.AddResource(&resource2);
   task_manager.AddResource(&resource3);  // Will be in the same group as 2.
 
-  TaskManagerMac* bridge(new TaskManagerMac(&task_manager, false));
+  TaskManagerMac* bridge(new TaskManagerMac(&task_manager));
   TaskManagerWindowController* controller = bridge->cocoa_controller();
   NSTableView* table = [controller tableView];
   ASSERT_EQ(3, [controller numberOfRowsInTableView:table]);
@@ -98,7 +97,7 @@
   task_manager.AddResource(&resource1);
   task_manager.AddResource(&resource2);
 
-  TaskManagerMac* bridge(new TaskManagerMac(&task_manager, false));
+  TaskManagerMac* bridge(new TaskManagerMac(&task_manager));
   TaskManagerWindowController* controller = bridge->cocoa_controller();
   NSTableView* table = [controller tableView];
   ASSERT_EQ(2, [controller numberOfRowsInTableView:table]);
diff --git a/chrome/browser/ui/cocoa/toolbar/back_forward_menu_controller.h b/chrome/browser/ui/cocoa/toolbar/back_forward_menu_controller.h
index 282ff77..e186341 100644
--- a/chrome/browser/ui/cocoa/toolbar/back_forward_menu_controller.h
+++ b/chrome/browser/ui/cocoa/toolbar/back_forward_menu_controller.h
@@ -7,7 +7,7 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "base/memory/scoped_ptr.h"
 #include "chrome/browser/ui/toolbar/back_forward_menu_model.h"
 
@@ -27,7 +27,7 @@
   BackForwardMenuType type_;
   MenuButton* button_;  // Weak; comes from nib.
   scoped_ptr<BackForwardMenuModel> model_;
-  scoped_nsobject<NSMenu> backForwardMenu_;
+  base::scoped_nsobject<NSMenu> backForwardMenu_;
 }
 
 // Type (back or forwards); can only be set on initialization.
diff --git a/chrome/browser/ui/cocoa/toolbar/reload_button_unittest.mm b/chrome/browser/ui/cocoa/toolbar/reload_button_unittest.mm
index c7eccd9..b8079c9 100644
--- a/chrome/browser/ui/cocoa/toolbar/reload_button_unittest.mm
+++ b/chrome/browser/ui/cocoa/toolbar/reload_button_unittest.mm
@@ -6,7 +6,7 @@
 
 #import "chrome/browser/ui/cocoa/toolbar/reload_button.h"
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "chrome/app/chrome_command_ids.h"
 #import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #import "chrome/browser/ui/cocoa/image_button_cell.h"
@@ -29,7 +29,7 @@
  public:
   ReloadButtonTest() {
     NSRect frame = NSMakeRect(0, 0, 20, 20);
-    scoped_nsobject<ReloadButton> button(
+    base::scoped_nsobject<ReloadButton> button(
         [[ReloadButton alloc] initWithFrame:frame]);
     button_ = button.get();
 
diff --git a/chrome/browser/ui/cocoa/toolbar/toolbar_button_unittest.mm b/chrome/browser/ui/cocoa/toolbar/toolbar_button_unittest.mm
index 3ebbefc..48a7dd3 100644
--- a/chrome/browser/ui/cocoa/toolbar/toolbar_button_unittest.mm
+++ b/chrome/browser/ui/cocoa/toolbar/toolbar_button_unittest.mm
@@ -4,7 +4,7 @@
 
 #import <Cocoa/Cocoa.h>
 
-#import "base/memory/scoped_nsobject.h"
+#import "base/mac/scoped_nsobject.h"
 #include "chrome/app/chrome_command_ids.h"
 #import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #import "chrome/browser/ui/cocoa/toolbar/toolbar_button.h"
@@ -54,7 +54,7 @@
  public:
   ToolbarButtonTest() {
     NSRect frame = NSMakeRect(0, 0, 20, 20);
-    scoped_nsobject<TestableToolbarButton> button(
+    base::scoped_nsobject<TestableToolbarButton> button(
         [[TestableToolbarButton alloc] initWithFrame:frame]);
     button_ = button.get();
 
diff --git a/chrome/browser/ui/cocoa/toolbar/toolbar_controller.h b/chrome/browser/ui/cocoa/toolbar/toolbar_controller.h
index 6fdbd58..07a0bf5 100644
--- a/chrome/browser/ui/cocoa/toolbar/toolbar_controller.h
+++ b/chrome/browser/ui/cocoa/toolbar/toolbar_controller.h
@@ -7,7 +7,7 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/prefs/pref_member.h"
 #import "chrome/browser/ui/cocoa/command_observer_bridge.h"
@@ -64,14 +64,15 @@
   Browser* browser_;  // weak, one per window
   scoped_ptr<CommandObserverBridge> commandObserver_;
   scoped_ptr<LocationBarViewMac> locationBarView_;
-  scoped_nsobject<AutocompleteTextFieldEditor> autocompleteTextFieldEditor_;
+  base::scoped_nsobject<AutocompleteTextFieldEditor>
+      autocompleteTextFieldEditor_;
   id<ViewResizer> resizeDelegate_;  // weak
-  scoped_nsobject<BackForwardMenuController> backMenuController_;
-  scoped_nsobject<BackForwardMenuController> forwardMenuController_;
-  scoped_nsobject<BrowserActionsController> browserActionsController_;
+  base::scoped_nsobject<BackForwardMenuController> backMenuController_;
+  base::scoped_nsobject<BackForwardMenuController> forwardMenuController_;
+  base::scoped_nsobject<BrowserActionsController> browserActionsController_;
 
   // Lazily-instantiated menu controller.
-  scoped_nsobject<WrenchMenuController> wrenchMenuController_;
+  base::scoped_nsobject<WrenchMenuController> wrenchMenuController_;
 
   // Used for monitoring the optional toolbar button prefs.
   scoped_ptr<ToolbarControllerInternal::NotificationBridge> notificationBridge_;
@@ -82,7 +83,7 @@
 
   // We have an extra retain in the locationBar_.
   // See comments in awakeFromNib for more info.
-  scoped_nsobject<AutocompleteTextField> locationBarRetainer_;
+  base::scoped_nsobject<AutocompleteTextField> locationBarRetainer_;
 
   // Tracking area for mouse enter/exit/moved in the toolbar.
   ui::ScopedCrTrackingArea trackingArea_;
diff --git a/chrome/browser/ui/cocoa/toolbar/toolbar_controller.mm b/chrome/browser/ui/cocoa/toolbar/toolbar_controller.mm
index f037f1e..15cc8fb 100644
--- a/chrome/browser/ui/cocoa/toolbar/toolbar_controller.mm
+++ b/chrome/browser/ui/cocoa/toolbar/toolbar_controller.mm
@@ -72,11 +72,7 @@
 namespace {
 
 // Height of the toolbar in pixels when the bookmark bar is closed.
-const CGFloat kBaseToolbarHeightNormal = 34.0;
-
-// Height of the toolbar in pixels when the bookmark bar is if instant extended
-// is enabled.
-const CGFloat kBaseToolbarHeightInstantExtended = 35.0;
+const CGFloat kBaseToolbarHeightNormal = 35.0;
 
 // The minimum width of the location bar in pixels.
 const CGFloat kMinimumLocationBarWidth = 100.0;
@@ -221,16 +217,6 @@
 // Now we can hook up bridges that rely on UI objects such as the location
 // bar and button state.
 - (void)awakeFromNib {
-  // Make the location bar taller in instant extended mode. TODO(sail): Move
-  // this to the xib file once this switch is removed.
-  if (chrome::IsInstantExtendedAPIEnabled()) {
-    NSRect toolbarFrame = [[self view] frame];
-    toolbarFrame.size.height += 1;
-    [[self view] setFrame:toolbarFrame];
-    NSRect frame = NSInsetRect([locationBar_ frame], 0, -1);
-    [locationBar_ setFrame:frame];
-  }
-
   [[backButton_ cell] setImageID:IDR_BACK
                   forButtonState:image_button_cell::kDefaultState];
   [[backButton_ cell] setImageID:IDR_BACK_H
@@ -752,9 +738,6 @@
   if (!hasToolbar_)
     return NSHeight([locationBar_ frame]);
 
-  if (chrome::IsInstantExtendedAPIEnabled())
-    return kBaseToolbarHeightInstantExtended - compressByHeight;
-
   return kBaseToolbarHeightNormal - compressByHeight;
 }
 
@@ -768,6 +751,8 @@
     ToolbarView* toolbarView = (ToolbarView*)view;
     [toolbarView setDividerOpacity:opacity];
   }
+
+  [view setNeedsDisplay:YES];
 }
 
 - (BrowserActionsController*)browserActionsController {
diff --git a/chrome/browser/ui/cocoa/toolbar/toolbar_controller_unittest.mm b/chrome/browser/ui/cocoa/toolbar/toolbar_controller_unittest.mm
index 7491229..8fb005e 100644
--- a/chrome/browser/ui/cocoa/toolbar/toolbar_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/toolbar/toolbar_controller_unittest.mm
@@ -4,7 +4,7 @@
 
 #import <Cocoa/Cocoa.h>
 
-#import "base/memory/scoped_nsobject.h"
+#import "base/mac/scoped_nsobject.h"
 #include "base/prefs/pref_service.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/command_updater.h"
@@ -89,8 +89,8 @@
               [[views objectAtIndex:kHomeIndex] isEnabled] ? true : false);
   }
 
-  scoped_nsobject<ViewResizerPong> resizeDelegate_;
-  scoped_nsobject<ToolbarController> bar_;
+  base::scoped_nsobject<ViewResizerPong> resizeDelegate_;
+  base::scoped_nsobject<ToolbarController> bar_;
 };
 
 TEST_VIEW(ToolbarControllerTest, [bar_ view])
@@ -215,8 +215,8 @@
 }
 
 TEST_F(ToolbarControllerTest, HoverButtonForEvent) {
-  scoped_nsobject<HitView> view([[HitView alloc]
-                                  initWithFrame:NSMakeRect(0,0,100,100)]);
+  base::scoped_nsobject<HitView> view(
+      [[HitView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100)]);
   [bar_ setView:view];
   NSEvent* event = [NSEvent mouseEventWithType:NSMouseMoved
                                       location:NSMakePoint(10,10)
@@ -233,12 +233,13 @@
   EXPECT_FALSE([bar_ hoverButtonForEvent:event]);
 
   // Not yet...
-  scoped_nsobject<NSButton> button([[NSButton alloc] init]);
+  base::scoped_nsobject<NSButton> button([[NSButton alloc] init]);
   [view setHitTestReturn:button];
   EXPECT_FALSE([bar_ hoverButtonForEvent:event]);
 
   // Now!
-  scoped_nsobject<GradientButtonCell> cell([[GradientButtonCell alloc] init]);
+  base::scoped_nsobject<GradientButtonCell> cell(
+      [[GradientButtonCell alloc] init]);
   [button setCell:cell.get()];
   EXPECT_TRUE([bar_ hoverButtonForEvent:nil]);
 }
diff --git a/chrome/browser/ui/cocoa/toolbar/toolbar_view_unittest.mm b/chrome/browser/ui/cocoa/toolbar/toolbar_view_unittest.mm
index f6bb035..4bdeb56 100644
--- a/chrome/browser/ui/cocoa/toolbar/toolbar_view_unittest.mm
+++ b/chrome/browser/ui/cocoa/toolbar/toolbar_view_unittest.mm
@@ -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 "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #import "chrome/browser/ui/cocoa/toolbar/toolbar_view.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -16,7 +16,7 @@
 // This class only needs to do one thing: prevent mouse down events from moving
 // the parent window around.
 TEST_F(ToolbarViewTest, CanDragWindow) {
-  scoped_nsobject<ToolbarView> view([[ToolbarView alloc] init]);
+  base::scoped_nsobject<ToolbarView> view([[ToolbarView alloc] init]);
   EXPECT_FALSE([view mouseDownCanMoveWindow]);
 }
 
diff --git a/chrome/browser/ui/cocoa/toolbar/wrench_toolbar_button_cell_unittest.mm b/chrome/browser/ui/cocoa/toolbar/wrench_toolbar_button_cell_unittest.mm
index 79ee865..416a500 100644
--- a/chrome/browser/ui/cocoa/toolbar/wrench_toolbar_button_cell_unittest.mm
+++ b/chrome/browser/ui/cocoa/toolbar/wrench_toolbar_button_cell_unittest.mm
@@ -21,14 +21,14 @@
 class WrenchToolbarButtonCellTest : public CocoaTest {
  protected:
   WrenchToolbarButtonCellTest() {
-    scoped_nsobject<NSButton> button([[TestWrenchToolbarButton alloc]
+    base::scoped_nsobject<NSButton> button([[TestWrenchToolbarButton alloc]
         initWithFrame:NSMakeRect(0, 0, 29, 29)]);
     button_ = button;
     [[test_window() contentView] addSubview:button_];
   }
 
   NSButton* button_;
-  scoped_nsobject<WrenchToolbarButtonCell> cell_;
+  base::scoped_nsobject<WrenchToolbarButtonCell> cell_;
   base::MessageLoopForUI message_loop_;  // Needed for ui::Animation.
 
  private:
diff --git a/chrome/browser/ui/cocoa/validation_message_bubble_cocoa.mm b/chrome/browser/ui/cocoa/validation_message_bubble_cocoa.mm
index 54cffda..362fd18 100644
--- a/chrome/browser/ui/cocoa/validation_message_bubble_cocoa.mm
+++ b/chrome/browser/ui/cocoa/validation_message_bubble_cocoa.mm
@@ -32,12 +32,12 @@
   mainText:(const string16&)mainText
    subText:(const string16&)subText {
 
-  scoped_nsobject<InfoBubbleWindow> window([[InfoBubbleWindow alloc]
-      initWithContentRect:
-          NSMakeRect(0, 0, kWindowInitialWidth, kWindowInitialHeight)
-                styleMask:NSBorderlessWindowMask
-                  backing:NSBackingStoreBuffered
-                    defer:NO]);
+  base::scoped_nsobject<InfoBubbleWindow> window(
+      [[InfoBubbleWindow alloc] initWithContentRect:
+              NSMakeRect(0, 0, kWindowInitialWidth, kWindowInitialHeight)
+                                          styleMask:NSBorderlessWindowMask
+                                            backing:NSBackingStoreBuffered
+                                              defer:NO]);
   if ((self = [super initWithWindow:window.get()
                        parentWindow:parentWindow
                          anchoredAt:anchorPoint])) {
@@ -66,7 +66,7 @@
 
   NSImage* image = ResourceBundle::GetSharedInstance()
       .GetNativeImageNamed(IDR_INPUT_ALERT).ToNSImage();
-  scoped_nsobject<NSImageView> imageView([[NSImageView alloc]
+  base::scoped_nsobject<NSImageView> imageView([[NSImageView alloc]
       initWithFrame:NSMakeRect(0, 0, image.size.width, image.size.height)]);
   [imageView setImageFrameStyle:NSImageFrameNone];
   [imageView setImage:image];
@@ -75,7 +75,7 @@
 
   const CGFloat textX = NSWidth([imageView frame]) + kIconTextMargin;
   NSRect textFrame = NSMakeRect(textX, 0, NSWidth(contentFrame) - textX, 0);
-  scoped_nsobject<NSTextField> text(
+  base::scoped_nsobject<NSTextField> text(
       [[NSTextField alloc] initWithFrame:textFrame]);
   [text setStringValue:base::SysUTF16ToNSString(mainText)];
   [text setFont:[NSFont systemFontOfSize:[NSFont systemFontSize]]];
@@ -104,7 +104,7 @@
     NSRect subTextFrame = NSMakeRect(
         textX, NSMaxY(textFrame) + kTextVerticalMargin,
         NSWidth(textFrame), 0);
-    scoped_nsobject<NSTextField> text2(
+    base::scoped_nsobject<NSTextField> text2(
         [[NSTextField alloc] initWithFrame:subTextFrame]);
     [text2 setStringValue:base::SysUTF16ToNSString(subText)];
     [text2 setFont:[NSFont systemFontOfSize:[NSFont smallSystemFontSize]]];
@@ -174,7 +174,7 @@
   }
 
  private:
-  scoped_nsobject<ValidationMessageBubbleController> controller_;
+  base::scoped_nsobject<ValidationMessageBubbleController> controller_;
 };
 
 }
diff --git a/chrome/browser/ui/cocoa/validation_message_bubble_controller_unittest.mm b/chrome/browser/ui/cocoa/validation_message_bubble_controller_unittest.mm
index 207188b..c80c24d 100644
--- a/chrome/browser/ui/cocoa/validation_message_bubble_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/validation_message_bubble_controller_unittest.mm
@@ -4,7 +4,6 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
 #include "base/strings/utf_string_conversions.h"
 #import "chrome/browser/ui/cocoa/validation_message_bubble_controller.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/chrome/browser/ui/cocoa/vertical_gradient_view.h b/chrome/browser/ui/cocoa/vertical_gradient_view.h
index b42928d..c123017 100644
--- a/chrome/browser/ui/cocoa/vertical_gradient_view.h
+++ b/chrome/browser/ui/cocoa/vertical_gradient_view.h
@@ -5,7 +5,7 @@
 #ifndef CHROME_BROWSER_UI_COCOA_VERTICAL_GRADIENT_VIEW_H_
 #define CHROME_BROWSER_UI_COCOA_VERTICAL_GRADIENT_VIEW_H_
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 
 #import <Cocoa/Cocoa.h>
 
@@ -17,9 +17,9 @@
 @interface VerticalGradientView : NSView {
  @private
   // The gradient to draw.
-  scoped_nsobject<NSGradient> gradient_;
+  base::scoped_nsobject<NSGradient> gradient_;
   // Color for bottom stroke.
-  scoped_nsobject<NSColor> strokeColor_;
+  base::scoped_nsobject<NSColor> strokeColor_;
 }
 
 // Gets and sets the gradient to paint as background.
diff --git a/chrome/browser/ui/cocoa/vertical_gradient_view_unittest.mm b/chrome/browser/ui/cocoa/vertical_gradient_view_unittest.mm
index ac046b0..fa550b3 100644
--- a/chrome/browser/ui/cocoa/vertical_gradient_view_unittest.mm
+++ b/chrome/browser/ui/cocoa/vertical_gradient_view_unittest.mm
@@ -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 "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #import "chrome/browser/ui/cocoa/vertical_gradient_view.h"
 
@@ -12,7 +12,7 @@
  public:
   VerticalGradientViewTest() {
     NSRect frame = NSMakeRect(0, 0, 50, 27);
-    scoped_nsobject<VerticalGradientView> view(
+    base::scoped_nsobject<VerticalGradientView> view(
         [[VerticalGradientView alloc] initWithFrame:frame]);
     view_ = view.get();
     [[test_window() contentView] addSubview:view_];
diff --git a/chrome/browser/ui/cocoa/web_dialog_window_controller.mm b/chrome/browser/ui/cocoa/web_dialog_window_controller.mm
index 9797deb..4460de9 100644
--- a/chrome/browser/ui/cocoa/web_dialog_window_controller.mm
+++ b/chrome/browser/ui/cocoa/web_dialog_window_controller.mm
@@ -5,7 +5,7 @@
 #import "chrome/browser/ui/cocoa/web_dialog_window_controller.h"
 
 #include "base/logging.h"
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "base/strings/sys_string_conversions.h"
 #import "chrome/browser/ui/browser_dialogs.h"
 #import "chrome/browser/ui/cocoa/browser_command_executor.h"
@@ -317,12 +317,12 @@
   NSRect dialogRect = NSMakeRect(0, 0, dialogSize.width(), dialogSize.height());
   NSUInteger style = NSTitledWindowMask | NSClosableWindowMask |
       NSResizableWindowMask;
-  scoped_nsobject<ChromeEventProcessingWindow> window(
+  base::scoped_nsobject<ChromeEventProcessingWindow> window(
       [[ChromeEventProcessingWindow alloc]
-           initWithContentRect:dialogRect
-                     styleMask:style
-                       backing:NSBackingStoreBuffered
-                         defer:YES]);
+          initWithContentRect:dialogRect
+                    styleMask:style
+                      backing:NSBackingStoreBuffered
+                        defer:YES]);
   if (!window.get()) {
     return nil;
   }
diff --git a/chrome/browser/ui/cocoa/website_settings_bubble_controller.h b/chrome/browser/ui/cocoa/website_settings_bubble_controller.h
index 060496d..5f671e7 100644
--- a/chrome/browser/ui/cocoa/website_settings_bubble_controller.h
+++ b/chrome/browser/ui/cocoa/website_settings_bubble_controller.h
@@ -4,7 +4,7 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "base/memory/scoped_ptr.h"
 #import "chrome/browser/ui/cocoa/base_bubble_controller.h"
 #include "chrome/browser/ui/website_settings/website_settings_ui.h"
@@ -21,9 +21,9 @@
  @private
   content::WebContents* webContents_;
 
-  scoped_nsobject<NSView> contentView_;
-  scoped_nsobject<NSSegmentedControl> segmentedControl_;
-  scoped_nsobject<NSTabView> tabView_;
+  base::scoped_nsobject<NSView> contentView_;
+  base::scoped_nsobject<NSSegmentedControl> segmentedControl_;
+  base::scoped_nsobject<NSTabView> tabView_;
 
   // Displays the web site identity.
   NSTextField* identityField_;
diff --git a/chrome/browser/ui/cocoa/website_settings_bubble_controller.mm b/chrome/browser/ui/cocoa/website_settings_bubble_controller.mm
index 74e602c..b66584f 100644
--- a/chrome/browser/ui/cocoa/website_settings_bubble_controller.mm
+++ b/chrome/browser/ui/cocoa/website_settings_bubble_controller.mm
@@ -120,13 +120,13 @@
 
 @interface WebsiteSettingsTabSegmentedCell : NSSegmentedCell {
  @private
-  scoped_nsobject<NSImage> tabstripCenterImage_;
-  scoped_nsobject<NSImage> tabstripLeftImage_;
-  scoped_nsobject<NSImage> tabstripRightImage_;
+  base::scoped_nsobject<NSImage> tabstripCenterImage_;
+  base::scoped_nsobject<NSImage> tabstripLeftImage_;
+  base::scoped_nsobject<NSImage> tabstripRightImage_;
 
-  scoped_nsobject<NSImage> tabCenterImage_;
-  scoped_nsobject<NSImage> tabLeftImage_;
-  scoped_nsobject<NSImage> tabRightImage_;
+  base::scoped_nsobject<NSImage> tabCenterImage_;
+  base::scoped_nsobject<NSImage> tabLeftImage_;
+  base::scoped_nsobject<NSImage> tabRightImage_;
 
   // Key track of the index of segment which has keyboard focus. This is not
   // the same as the currently selected segment.
@@ -303,7 +303,7 @@
   // Use an arbitrary height; it will be changed in performLayout.
   NSRect contentRect = NSMakeRect(0, 0, [self defaultWindowWidth], 1);
   // Create an empty window into which content is placed.
-  scoped_nsobject<InfoBubbleWindow> window(
+  base::scoped_nsobject<InfoBubbleWindow> window(
       [[InfoBubbleWindow alloc] initWithContentRect:contentRect
                                           styleMask:NSBorderlessWindowMask
                                             backing:NSBackingStoreBuffered
@@ -403,7 +403,7 @@
 
   // Create the tab view and its two tabs.
 
-  scoped_nsobject<WebsiteSettingsTabSegmentedCell> cell(
+  base::scoped_nsobject<WebsiteSettingsTabSegmentedCell> cell(
       [[WebsiteSettingsTabSegmentedCell alloc] init]);
   CGFloat tabstripHeight = [cell cellSize].height;
   NSRect tabstripFrame = NSMakeRect(
@@ -470,11 +470,11 @@
 // Create the contents of the Permissions tab and add it to the given tab view.
 // Returns a weak reference to the tab view item's view.
 - (NSView*)addPermissionsTabToTabView:(NSTabView*)tabView {
-  scoped_nsobject<NSTabViewItem> item([[NSTabViewItem alloc] init]);
+  base::scoped_nsobject<NSTabViewItem> item([[NSTabViewItem alloc] init]);
   [tabView_ insertTabViewItem:item.get()
                       atIndex:WebsiteSettingsUI::TAB_ID_PERMISSIONS];
-  scoped_nsobject<NSView> contentView([[FlippedView alloc]
-      initWithFrame:[tabView_ contentRect]]);
+  base::scoped_nsobject<NSView> contentView(
+      [[FlippedView alloc] initWithFrame:[tabView_ contentRect]]);
   [contentView setAutoresizingMask:NSViewWidthSizable];
   [item setView:contentView.get()];
 
@@ -531,9 +531,9 @@
 // Create the contents of the Connection tab and add it to the given tab view.
 // Returns a weak reference to the tab view item's view.
 - (NSView*)addConnectionTabToTabView:(NSTabView*)tabView {
-  scoped_nsobject<NSTabViewItem> item([[NSTabViewItem alloc] init]);
-  scoped_nsobject<NSView> contentView([[FlippedView alloc]
-      initWithFrame:[tabView_ contentRect]]);
+  base::scoped_nsobject<NSTabViewItem> item([[NSTabViewItem alloc] init]);
+  base::scoped_nsobject<NSView> contentView(
+      [[FlippedView alloc] initWithFrame:[tabView_ contentRect]]);
   [contentView setAutoresizingMask:NSViewWidthSizable];
 
   // Place all the text and images at the same position. The positions will be
@@ -782,8 +782,8 @@
   // The height is arbitrary as it will be adjusted later.
   CGFloat width = NSWidth([view frame]) - point.x - kFramePadding;
   NSRect frame = NSMakeRect(point.x, point.y, width, 100);
-  scoped_nsobject<NSTextField> textField(
-     [[NSTextField alloc] initWithFrame:frame]);
+  base::scoped_nsobject<NSTextField> textField(
+      [[NSTextField alloc] initWithFrame:frame]);
   [self configureTextFieldAsLabel:textField.get()];
   [textField setStringValue:base::SysUTF16ToNSString(text)];
   NSFont* font = bold ? [NSFont boldSystemFontOfSize:fontSize]
@@ -801,7 +801,7 @@
                           toView:(NSView*)view
                          atPoint:(NSPoint)point {
   NSRect frame = NSMakeRect(point.x, point.y, size.width, size.height);
-  scoped_nsobject<NSImageView> imageView(
+  base::scoped_nsobject<NSImageView> imageView(
       [[NSImageView alloc] initWithFrame:frame]);
   [imageView setImageFrameStyle:NSImageFrameNone];
   [view addSubview:imageView.get()];
@@ -824,8 +824,9 @@
 - (NSButton*)addLinkButtonWithText:(NSString*)text toView:(NSView*)view {
   // Frame size is arbitrary; it will be adjusted by the layout tweaker.
   NSRect frame = NSMakeRect(kFramePadding, 0, 100, 10);
-  scoped_nsobject<NSButton> button([[NSButton alloc] initWithFrame:frame]);
-  scoped_nsobject<HyperlinkButtonCell> cell(
+  base::scoped_nsobject<NSButton> button(
+      [[NSButton alloc] initWithFrame:frame]);
+  base::scoped_nsobject<HyperlinkButtonCell> cell(
       [[HyperlinkButtonCell alloc] initTextCell:text]);
   [cell setControlSize:NSSmallControlSize];
   [button setCell:cell.get()];
@@ -860,7 +861,7 @@
                                       atPoint:(NSPoint)point {
   // Use an arbitrary width and height; it will be sized to fit.
   NSRect frame = NSMakeRect(point.x, point.y, 1, 1);
-  scoped_nsobject<NSPopUpButton> button(
+  base::scoped_nsobject<NSPopUpButton> button(
       [[NSPopUpButton alloc] initWithFrame:frame pullsDown:NO]);
   [button setFont:[NSFont systemFontOfSize:[NSFont smallSystemFontSize]]];
   [button setBordered:NO];
@@ -896,7 +897,7 @@
   [button selectItemWithTag:permissionInfo.setting];
 
   // Set the button title.
-  scoped_nsobject<NSMenuItem> titleItem([[NSMenuItem alloc] init]);
+  base::scoped_nsobject<NSMenuItem> titleItem([[NSMenuItem alloc] init]);
   string16 buttonTitle = WebsiteSettingsUI::PermissionActionToUIString(
       permissionInfo.setting,
       permissionInfo.default_setting,
diff --git a/chrome/browser/ui/cocoa/window_size_autosaver.h b/chrome/browser/ui/cocoa/window_size_autosaver.h
index 8d136e3..e167125 100644
--- a/chrome/browser/ui/cocoa/window_size_autosaver.h
+++ b/chrome/browser/ui/cocoa/window_size_autosaver.h
@@ -10,7 +10,8 @@
 
 // WindowSizeAutosaver is a helper class that makes it easy to let windows
 // autoremember their position or position and size in a PrefService object.
-// To use this, add a |scoped_nsobject<WindowSizeAutosaver>| to your window
+// To use this, add a |base::scoped_nsobject<WindowSizeAutosaver>| to your
+// window
 // controller and initialize it in the window controller's init method, passing
 // a window and an autosave name. The autosaver will register for "window moved"
 // and "window resized" notifications and write the current window state to the
diff --git a/chrome/browser/ui/cocoa/window_size_autosaver_unittest.mm b/chrome/browser/ui/cocoa/window_size_autosaver_unittest.mm
index 93e28f9..b8d553c 100644
--- a/chrome/browser/ui/cocoa/window_size_autosaver_unittest.mm
+++ b/chrome/browser/ui/cocoa/window_size_autosaver_unittest.mm
@@ -6,7 +6,7 @@
 
 #import "chrome/browser/ui/cocoa/window_size_autosaver.h"
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "base/prefs/pref_service.h"
 #include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/ui/cocoa/cocoa_profile_test.h"
@@ -69,10 +69,10 @@
   {
     NSRect frame = [window_ frame];
     // Empty state, shouldn't restore:
-    scoped_nsobject<WindowSizeAutosaver> sizeSaver([[WindowSizeAutosaver alloc]
-        initWithWindow:window_
-           prefService:pref
-                  path:path_]);
+    base::scoped_nsobject<WindowSizeAutosaver> sizeSaver(
+        [[WindowSizeAutosaver alloc] initWithWindow:window_
+                                        prefService:pref
+                                               path:path_]);
     EXPECT_EQ(NSMinX(frame), NSMinX([window_ frame]));
     EXPECT_EQ(NSMinY(frame), NSMinY([window_ frame]));
     EXPECT_EQ(NSWidth(frame), NSWidth([window_ frame]));
@@ -87,10 +87,10 @@
 
   {
     // Should restore last stored position, but not size.
-    scoped_nsobject<WindowSizeAutosaver> sizeSaver([[WindowSizeAutosaver alloc]
-        initWithWindow:window_
-           prefService:pref
-                  path:path_]);
+    base::scoped_nsobject<WindowSizeAutosaver> sizeSaver(
+        [[WindowSizeAutosaver alloc] initWithWindow:window_
+                                        prefService:pref
+                                               path:path_]);
     EXPECT_EQ(300, NSMinX([window_ frame]));
     EXPECT_EQ(310, NSMinY([window_ frame]));
     EXPECT_EQ(160, NSWidth([window_ frame]));
@@ -128,10 +128,10 @@
   {
     NSRect frame = [window_ frame];
     // Empty state, shouldn't restore:
-    scoped_nsobject<WindowSizeAutosaver> sizeSaver([[WindowSizeAutosaver alloc]
-        initWithWindow:window_
-           prefService:pref
-                  path:path_]);
+    base::scoped_nsobject<WindowSizeAutosaver> sizeSaver(
+        [[WindowSizeAutosaver alloc] initWithWindow:window_
+                                        prefService:pref
+                                               path:path_]);
     EXPECT_EQ(NSMinX(frame), NSMinX([window_ frame]));
     EXPECT_EQ(NSMinY(frame), NSMinY([window_ frame]));
     EXPECT_EQ(NSWidth(frame), NSWidth([window_ frame]));
@@ -146,10 +146,10 @@
 
   {
     // Should restore last stored size
-    scoped_nsobject<WindowSizeAutosaver> sizeSaver([[WindowSizeAutosaver alloc]
-        initWithWindow:window_
-           prefService:pref
-                  path:path_]);
+    base::scoped_nsobject<WindowSizeAutosaver> sizeSaver(
+        [[WindowSizeAutosaver alloc] initWithWindow:window_
+                                        prefService:pref
+                                               path:path_]);
     EXPECT_EQ(300, NSMinX([window_ frame]));
     EXPECT_EQ(310, NSMinY([window_ frame]));
     EXPECT_EQ(250, NSWidth([window_ frame]));
@@ -187,10 +187,10 @@
   {
     // Window rect shouldn't change...
     NSRect frame = [window_ frame];
-    scoped_nsobject<WindowSizeAutosaver> sizeSaver([[WindowSizeAutosaver alloc]
-        initWithWindow:window_
-           prefService:pref
-                  path:path_]);
+    base::scoped_nsobject<WindowSizeAutosaver> sizeSaver(
+        [[WindowSizeAutosaver alloc] initWithWindow:window_
+                                        prefService:pref
+                                               path:path_]);
     EXPECT_EQ(NSMinX(frame), NSMinX([window_ frame]));
     EXPECT_EQ(NSMinY(frame), NSMinY([window_ frame]));
     EXPECT_EQ(NSWidth(frame), NSWidth([window_ frame]));
diff --git a/chrome/browser/ui/cocoa/wrench_menu/menu_tracked_root_view_unittest.mm b/chrome/browser/ui/cocoa/wrench_menu/menu_tracked_root_view_unittest.mm
index 76da79c..14266b6 100644
--- a/chrome/browser/ui/cocoa/wrench_menu/menu_tracked_root_view_unittest.mm
+++ b/chrome/browser/ui/cocoa/wrench_menu/menu_tracked_root_view_unittest.mm
@@ -4,13 +4,13 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #import "chrome/browser/ui/cocoa/wrench_menu/menu_tracked_root_view.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/platform_test.h"
-#include "third_party/ocmock/gtest_support.h"
 #import "third_party/ocmock/OCMock/OCMock.h"
+#include "third_party/ocmock/gtest_support.h"
 
 class MenuTrackedRootViewTest : public CocoaTest {
  public:
@@ -19,7 +19,7 @@
     view_.reset([[MenuTrackedRootView alloc] init]);
   }
 
-  scoped_nsobject<MenuTrackedRootView> view_;
+  base::scoped_nsobject<MenuTrackedRootView> view_;
 };
 
 TEST_F(MenuTrackedRootViewTest, MouseUp) {
diff --git a/chrome/browser/ui/cocoa/wrench_menu/recent_tabs_menu_model_delegate.h b/chrome/browser/ui/cocoa/wrench_menu/recent_tabs_menu_model_delegate.h
index b1f2f42..d9cdd60 100644
--- a/chrome/browser/ui/cocoa/wrench_menu/recent_tabs_menu_model_delegate.h
+++ b/chrome/browser/ui/cocoa/wrench_menu/recent_tabs_menu_model_delegate.h
@@ -7,7 +7,7 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "ui/base/models/menu_model_delegate.h"
 
 namespace ui {
@@ -26,7 +26,7 @@
 
  private:
   ui::MenuModel* model_;  // weak
-  scoped_nsobject<NSMenu> menu_;
+  base::scoped_nsobject<NSMenu> menu_;
 
   DISALLOW_COPY_AND_ASSIGN(RecentTabsMenuModelDelegate);
 };
diff --git a/chrome/browser/ui/cocoa/wrench_menu/wrench_menu_button_cell.mm b/chrome/browser/ui/cocoa/wrench_menu/wrench_menu_button_cell.mm
index 2e14478..bd334c2 100644
--- a/chrome/browser/ui/cocoa/wrench_menu/wrench_menu_button_cell.mm
+++ b/chrome/browser/ui/cocoa/wrench_menu/wrench_menu_button_cell.mm
@@ -4,7 +4,7 @@
 
 #import "chrome/browser/ui/cocoa/wrench_menu/wrench_menu_button_cell.h"
 
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h"
 
 @implementation WrenchMenuButtonCell
@@ -26,7 +26,7 @@
   // The default state should be a subtle gray gradient.
   if (![self isHighlighted]) {
     NSColor* end = [NSColor colorWithDeviceWhite:0.922 alpha:1.0];
-    scoped_nsobject<NSGradient> gradient(
+    base::scoped_nsobject<NSGradient> gradient(
         [[NSGradient alloc] initWithStartingColor:[NSColor whiteColor]
                                       endingColor:end]);
     [gradient drawInRect:frame angle:90.0];
diff --git a/chrome/browser/ui/cocoa/wrench_menu/wrench_menu_button_cell_unittest.mm b/chrome/browser/ui/cocoa/wrench_menu/wrench_menu_button_cell_unittest.mm
index 52791e2..2336393 100644
--- a/chrome/browser/ui/cocoa/wrench_menu/wrench_menu_button_cell_unittest.mm
+++ b/chrome/browser/ui/cocoa/wrench_menu/wrench_menu_button_cell_unittest.mm
@@ -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 "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "chrome/app/chrome_command_ids.h"
 #import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #import "chrome/browser/ui/cocoa/wrench_menu/wrench_menu_button_cell.h"
@@ -32,7 +32,7 @@
     [button_ setButtonType:NSMomentaryPushInButton];
   }
 
-  scoped_nsobject<NSButton> button_;
+  base::scoped_nsobject<NSButton> button_;
 };
 
 TEST_F(WrenchMenuButtonCellTest, Draw) {
diff --git a/chrome/browser/ui/cocoa/wrench_menu/wrench_menu_controller.h b/chrome/browser/ui/cocoa/wrench_menu/wrench_menu_controller.h
index fd6a283..fdbc62f 100644
--- a/chrome/browser/ui/cocoa/wrench_menu/wrench_menu_controller.h
+++ b/chrome/browser/ui/cocoa/wrench_menu/wrench_menu_controller.h
@@ -46,7 +46,7 @@
 
   // A shim NSViewController that loads the buttons from the NIB because ObjC
   // doesn't have multiple inheritance as this class is a MenuController.
-  scoped_nsobject<WrenchMenuButtonViewController> buttonViewController_;
+  base::scoped_nsobject<WrenchMenuButtonViewController> buttonViewController_;
 
   // The browser for which this controller exists.
   Browser* browser_;  // weak
diff --git a/chrome/browser/ui/cocoa/wrench_menu/wrench_menu_controller.mm b/chrome/browser/ui/cocoa/wrench_menu/wrench_menu_controller.mm
index 79fe776..172056d 100644
--- a/chrome/browser/ui/cocoa/wrench_menu/wrench_menu_controller.mm
+++ b/chrome/browser/ui/cocoa/wrench_menu/wrench_menu_controller.mm
@@ -16,7 +16,9 @@
 #include "chrome/browser/ui/browser_window.h"
 #import "chrome/browser/ui/cocoa/accelerators_cocoa.h"
 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_menu_bridge.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_menu_cocoa_controller.h"
 #import "chrome/browser/ui/cocoa/encoding_menu_controller_delegate_mac.h"
+#import "chrome/browser/ui/cocoa/l10n_util.h"
 #import "chrome/browser/ui/cocoa/toolbar/toolbar_controller.h"
 #import "chrome/browser/ui/cocoa/wrench_menu/menu_tracked_root_view.h"
 #import "chrome/browser/ui/cocoa/wrench_menu/recent_tabs_menu_model_delegate.h"
@@ -38,7 +40,7 @@
 - (NSButton*)zoomDisplay;
 - (void)removeAllItems:(NSMenu*)menu;
 - (NSMenu*)recentTabsSubmenu;
-- (ui::MenuModel*)recentTabsMenuModel;
+- (RecentTabsSubMenuModel*)recentTabsMenuModel;
 - (int)maxWidthForMenuModel:(ui::MenuModel*)model
                  modelIndex:(int)modelIndex;
 @end
@@ -122,10 +124,8 @@
 
   // Handle the special-cased menu items.
   int command_id = model->GetCommandIdAt(index);
-  scoped_nsobject<NSMenuItem> customItem(
-      [[NSMenuItem alloc] initWithTitle:@""
-                                 action:nil
-                          keyEquivalent:@""]);
+  base::scoped_nsobject<NSMenuItem> customItem(
+      [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""]);
   MenuTrackedRootView* view;
   switch (command_id) {
     case IDC_EDIT_MENU:
@@ -148,6 +148,43 @@
   [menu insertItem:customItem.get() atIndex:index];
 }
 
+- (BOOL)validateUserInterfaceItem:(id<NSValidatedUserInterfaceItem>)item {
+  const BOOL enabled = [super validateUserInterfaceItem:item];
+
+  NSMenuItem* menuItem = (id)item;
+  ui::MenuModel* model =
+      static_cast<ui::MenuModel*>(
+          [[menuItem representedObject] pointerValue]);
+
+  // The section headers in the recent tabs submenu should be bold and black if
+  // a font is specified for the items (bold is already applied in the
+  // |MenuController| as the font returned by |GetLabelFontAt| is bold).
+  if (model && model == [self recentTabsMenuModel]) {
+    if (model->GetLabelFontAt([item tag])) {
+      DCHECK([menuItem attributedTitle]);
+      base::scoped_nsobject<NSMutableAttributedString> title(
+          [[NSMutableAttributedString alloc]
+              initWithAttributedString:[menuItem attributedTitle]]);
+      [title addAttribute:NSForegroundColorAttributeName
+                    value:[NSColor blackColor]
+                    range:NSMakeRange(0, [title length])];
+      [menuItem setAttributedTitle:title.get()];
+    } else {
+      // Not a section header. Add a tooltip with the title and the URL.
+      std::string url;
+      string16 title;
+      if ([self recentTabsMenuModel]->GetURLAndTitleForItemAtIndex(
+              [item tag], &url, &title)) {
+        [menuItem setToolTip:
+            cocoa_l10n_util::TooltipForURLAndTitle(
+                base::SysUTF8ToNSString(url), base::SysUTF16ToNSString(title))];
+       }
+    }
+  }
+
+  return enabled;
+}
+
 - (NSMenu*)bookmarkSubMenu {
   NSString* title = l10n_util::GetNSStringWithFixup(IDS_BOOKMARKS_MENU);
   return [[[self menu] itemWithTitle:title] submenu];
@@ -319,20 +356,20 @@
 
 // The recent tabs menu model is recognized by the existence of either the
 // kRecentlyClosedHeaderCommandId or the kDisabledRecentlyClosedHeaderCommandId.
-- (ui::MenuModel*)recentTabsMenuModel {
+- (RecentTabsSubMenuModel*)recentTabsMenuModel {
   int index = 0;
-  // Start searching at the wrnech menu model level, |model| will be updated
+  // Start searching at the wrench menu model level, |model| will be updated
   // only if the command we're looking for is found in one of the [sub]menus.
   ui::MenuModel* model = [self wrenchMenuModel];
   if (ui::MenuModel::GetModelAndIndexForCommandId(
           RecentTabsSubMenuModel::kRecentlyClosedHeaderCommandId, &model,
           &index)) {
-    return model;
+    return static_cast<RecentTabsSubMenuModel*>(model);
   }
   if (ui::MenuModel::GetModelAndIndexForCommandId(
           RecentTabsSubMenuModel::kDisabledRecentlyClosedHeaderCommandId,
           &model, &index)) {
-    return model;
+    return static_cast<RecentTabsSubMenuModel*>(model);
   }
   return NULL;
 }
@@ -341,10 +378,9 @@
 // menu.
 - (int)maxWidthForMenuModel:(ui::MenuModel*)model
                  modelIndex:(int)modelIndex {
-  ui::MenuModel* recentTabsMenuModel = [self recentTabsMenuModel];
+  RecentTabsSubMenuModel* recentTabsMenuModel = [self recentTabsMenuModel];
   if (recentTabsMenuModel && recentTabsMenuModel == model) {
-    return static_cast<RecentTabsSubMenuModel*>(
-        recentTabsMenuModel)->GetMaxWidthForItemAtIndex(modelIndex);
+    return recentTabsMenuModel->GetMaxWidthForItemAtIndex(modelIndex);
   }
   return -1;
 }
diff --git a/chrome/browser/ui/cocoa/wrench_menu/wrench_menu_controller_unittest.mm b/chrome/browser/ui/cocoa/wrench_menu/wrench_menu_controller_unittest.mm
index 0d08c3c..d681db0 100644
--- a/chrome/browser/ui/cocoa/wrench_menu/wrench_menu_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/wrench_menu/wrench_menu_controller_unittest.mm
@@ -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 "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "base/strings/sys_string_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/app/chrome_command_ids.h"
@@ -62,7 +62,7 @@
     return controller_.get();
   }
 
-  scoped_nsobject<WrenchMenuController> controller_;
+  base::scoped_nsobject<WrenchMenuController> controller_;
 
   scoped_ptr<MockWrenchMenuModel> fake_model_;
 };
@@ -73,7 +73,7 @@
 }
 
 TEST_F(WrenchMenuControllerTest, DispatchSimple) {
-  scoped_nsobject<NSButton> button([[NSButton alloc] init]);
+  base::scoped_nsobject<NSButton> button([[NSButton alloc] init]);
   [button setTag:IDC_ZOOM_PLUS];
 
   // Set fake model to test dispatching.
diff --git a/chrome/browser/ui/extensions/OWNERS b/chrome/browser/ui/extensions/OWNERS
index 6ff02c4..565b21c 100644
--- a/chrome/browser/ui/extensions/OWNERS
+++ b/chrome/browser/ui/extensions/OWNERS
@@ -1,3 +1,2 @@
 benwells@chromium.org
-jeremya@chromium.org
 miket@chromium.org
diff --git a/chrome/browser/ui/extensions/apps_metro_handler_win.cc b/chrome/browser/ui/extensions/apps_metro_handler_win.cc
index 125c8bf..0f253b2 100644
--- a/chrome/browser/ui/extensions/apps_metro_handler_win.cc
+++ b/chrome/browser/ui/extensions/apps_metro_handler_win.cc
@@ -4,8 +4,8 @@
 
 #include "chrome/browser/ui/extensions/apps_metro_handler_win.h"
 
+#include "apps/shell_window.h"
 #include "chrome/browser/extensions/shell_window_registry.h"
-#include "chrome/browser/ui/extensions/shell_window.h"
 #include "chrome/browser/ui/simple_message_box.h"
 #include "grit/chromium_strings.h"
 #include "grit/generated_resources.h"
@@ -15,7 +15,7 @@
 
 bool VerifySwitchToMetroForApps(gfx::NativeWindow parent_window) {
   if (!extensions::ShellWindowRegistry::IsShellWindowRegisteredInAnyProfile(
-          ShellWindow::WINDOW_TYPE_DEFAULT)) {
+          apps::ShellWindow::WINDOW_TYPE_DEFAULT)) {
     return true;
   }
 
diff --git a/chrome/browser/ui/extensions/native_app_window.h b/chrome/browser/ui/extensions/native_app_window.h
index 868b906..3e030f2 100644
--- a/chrome/browser/ui/extensions/native_app_window.h
+++ b/chrome/browser/ui/extensions/native_app_window.h
@@ -5,7 +5,7 @@
 #ifndef CHROME_BROWSER_UI_EXTENSIONS_NATIVE_APP_WINDOW_H_
 #define CHROME_BROWSER_UI_EXTENSIONS_NATIVE_APP_WINDOW_H_
 
-#include "chrome/browser/ui/extensions/shell_window.h"
+#include "apps/shell_window.h"
 #include "components/web_modal/web_contents_modal_dialog_host.h"
 #include "ui/base/base_window.h"
 #include "ui/gfx/insets.h"
@@ -16,9 +16,10 @@
 class NativeAppWindow : public ui::BaseWindow,
                         public web_modal::WebContentsModalDialogHost {
  public:
-  // Used by ShellWindow to instantiate the platform-specific ShellWindow code.
-  static NativeAppWindow* Create(ShellWindow* window,
-                                 const ShellWindow::CreateParams& params);
+  // Used by apps::ShellWindow to instantiate the platform-specific
+  // apps::ShellWindow code.
+  static NativeAppWindow* Create(apps::ShellWindow* window,
+                                 const apps::ShellWindow::CreateParams& params);
 
   // Called when the draggable regions are changed.
   virtual void UpdateDraggableRegions(
diff --git a/chrome/browser/ui/extensions/shell_window.cc b/chrome/browser/ui/extensions/shell_window.cc
deleted file mode 100644
index 5d3f4af..0000000
--- a/chrome/browser/ui/extensions/shell_window.cc
+++ /dev/null
@@ -1,646 +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/extensions/shell_window.h"
-
-#include "apps/shell_window_geometry_cache.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/values.h"
-#include "chrome/browser/extensions/app_window_contents.h"
-#include "chrome/browser/extensions/extension_process_manager.h"
-#include "chrome/browser/extensions/extension_system.h"
-#include "chrome/browser/extensions/image_loader.h"
-#include "chrome/browser/extensions/shell_window_registry.h"
-#include "chrome/browser/extensions/suggest_permission_util.h"
-#include "chrome/browser/favicon/favicon_tab_helper.h"
-#include "chrome/browser/file_select_helper.h"
-#include "chrome/browser/lifetime/application_lifetime.h"
-#include "chrome/browser/media/media_capture_devices_dispatcher.h"
-#include "chrome/browser/platform_util.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/sessions/session_id.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/browser_dialogs.h"
-#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/native_app_window.h"
-#include "chrome/common/chrome_notification_types.h"
-#include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/extension_constants.h"
-#include "chrome/common/extensions/extension_messages.h"
-#include "chrome/common/extensions/manifest_handlers/icons_handler.h"
-#include "components/web_modal/web_contents_modal_dialog_manager.h"
-#include "content/public/browser/invalidate_type.h"
-#include "content/public/browser/navigation_entry.h"
-#include "content/public/browser/notification_details.h"
-#include "content/public/browser/notification_service.h"
-#include "content/public/browser/notification_source.h"
-#include "content/public/browser/notification_types.h"
-#include "content/public/browser/render_view_host.h"
-#include "content/public/browser/resource_dispatcher_host.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/common/media_stream_request.h"
-#include "extensions/browser/view_type_utils.h"
-#include "skia/ext/image_operations.h"
-#include "third_party/skia/include/core/SkRegion.h"
-#include "ui/gfx/image/image_skia.h"
-
-#if defined(USE_ASH)
-#include "ash/launcher/launcher_types.h"
-#endif
-
-using content::ConsoleMessageLevel;
-using content::WebContents;
-using extensions::APIPermission;
-using web_modal::WebContentsModalDialogHost;
-using web_modal::WebContentsModalDialogManager;
-
-namespace {
-const int kDefaultWidth = 512;
-const int kDefaultHeight = 384;
-
-// The preferred icon size for displaying the app icon.
-#if defined(USE_ASH)
-const int kPreferredIconSize = ash::kLauncherPreferredSize;
-#else
-const int kPreferredIconSize = extension_misc::EXTENSION_ICON_SMALL;
-#endif
-
-static bool disable_external_open_for_testing_ = false;
-
-class ShellWindowLinkDelegate : public content::WebContentsDelegate {
- private:
-  virtual content::WebContents* OpenURLFromTab(
-      content::WebContents* source,
-      const content::OpenURLParams& params) OVERRIDE;
-};
-
-content::WebContents* ShellWindowLinkDelegate::OpenURLFromTab(
-    content::WebContents* source,
-    const content::OpenURLParams& params) {
-  platform_util::OpenExternal(params.url);
-  delete source;
-  return NULL;
-}
-
-}  // namespace
-
-ShellWindow::CreateParams::CreateParams()
-  : window_type(ShellWindow::WINDOW_TYPE_DEFAULT),
-    frame(ShellWindow::FRAME_CHROME),
-    transparent_background(false),
-    bounds(INT_MIN, INT_MIN, 0, 0),
-    creator_process_id(0),
-    state(ui::SHOW_STATE_DEFAULT),
-    hidden(false),
-    resizable(true),
-    focused(true) {
-}
-
-ShellWindow::CreateParams::~CreateParams() {
-}
-
-ShellWindow* ShellWindow::Create(Profile* profile,
-                                 const extensions::Extension* extension,
-                                 const GURL& url,
-                                 const CreateParams& params) {
-  // This object will delete itself when the window is closed.
-  ShellWindow* window = new ShellWindow(profile, extension);
-  window->Init(url, new AppWindowContents(window), params);
-  extensions::ShellWindowRegistry::Get(profile)->AddShellWindow(window);
-  return window;
-}
-
-ShellWindow::ShellWindow(Profile* profile,
-                         const extensions::Extension* extension)
-    : profile_(profile),
-      extension_(extension),
-      extension_id_(extension->id()),
-      window_type_(WINDOW_TYPE_DEFAULT),
-      image_loader_ptr_factory_(this),
-      fullscreen_for_window_api_(false),
-      fullscreen_for_tab_(false) {
-}
-
-void ShellWindow::Init(const GURL& url,
-                       ShellWindowContents* shell_window_contents,
-                       const CreateParams& params) {
-  // Initialize the render interface and web contents
-  shell_window_contents_.reset(shell_window_contents);
-  shell_window_contents_->Initialize(profile(), url);
-  WebContents* web_contents = shell_window_contents_->GetWebContents();
-  WebContentsModalDialogManager::CreateForWebContents(web_contents);
-  FaviconTabHelper::CreateForWebContents(web_contents);
-
-  web_contents->SetDelegate(this);
-  WebContentsModalDialogManager::FromWebContents(web_contents)->
-      set_delegate(this);
-  extensions::SetViewType(web_contents, extensions::VIEW_TYPE_APP_SHELL);
-
-  // Initialize the window
-  window_type_ = params.window_type;
-
-  gfx::Rect bounds = params.bounds;
-
-  if (bounds.width() == 0)
-    bounds.set_width(kDefaultWidth);
-  if (bounds.height() == 0)
-    bounds.set_height(kDefaultHeight);
-
-  // If left and top are left undefined, the native shell window will center
-  // the window on the main screen in a platform-defined manner.
-
-  ui::WindowShowState cached_state = ui::SHOW_STATE_DEFAULT;
-  if (!params.window_key.empty()) {
-    window_key_ = params.window_key;
-
-    apps::ShellWindowGeometryCache* cache =
-        apps::ShellWindowGeometryCache::Get(profile());
-
-    gfx::Rect cached_bounds;
-    if (cache->GetGeometry(extension()->id(), params.window_key,
-                           &cached_bounds, &cached_state)) {
-      bounds = cached_bounds;
-    }
-  }
-
-  CreateParams new_params = params;
-
-  gfx::Size& minimum_size = new_params.minimum_size;
-  gfx::Size& maximum_size = new_params.maximum_size;
-
-  // In the case that minimum size > maximum size, we consider the minimum
-  // size to be more important.
-  if (maximum_size.width() && maximum_size.width() < minimum_size.width())
-    maximum_size.set_width(minimum_size.width());
-  if (maximum_size.height() && maximum_size.height() < minimum_size.height())
-    maximum_size.set_height(minimum_size.height());
-
-  if (maximum_size.width() && bounds.width() > maximum_size.width())
-    bounds.set_width(maximum_size.width());
-  if (bounds.width() != INT_MIN && bounds.width() < minimum_size.width())
-    bounds.set_width(minimum_size.width());
-
-  if (maximum_size.height() && bounds.height() > maximum_size.height())
-    bounds.set_height(maximum_size.height());
-  if (bounds.height() != INT_MIN && bounds.height() < minimum_size.height())
-    bounds.set_height(minimum_size.height());
-
-  new_params.bounds = bounds;
-
-  if (cached_state != ui::SHOW_STATE_DEFAULT)
-    new_params.state = cached_state;
-
-  native_app_window_.reset(NativeAppWindow::Create(this, new_params));
-
-  if (!new_params.hidden) {
-    if (window_type_is_panel())
-      GetBaseWindow()->ShowInactive();  // Panels are not activated by default.
-    else
-      GetBaseWindow()->Show();
-  }
-
-  if (new_params.state == ui::SHOW_STATE_FULLSCREEN)
-    Fullscreen();
-  else if (new_params.state == ui::SHOW_STATE_MAXIMIZED)
-    Maximize();
-  else if (new_params.state == ui::SHOW_STATE_MINIMIZED)
-    Minimize();
-
-  OnNativeWindowChanged();
-
-  // When the render view host is changed, the native window needs to know
-  // about it in case it has any setup to do to make the renderer appear
-  // properly. In particular, on Windows, the view's clickthrough region needs
-  // to be set.
-  registrar_.Add(this, content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED,
-                 content::Source<content::NavigationController>(
-                    &web_contents->GetController()));
-  registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED,
-                 content::Source<Profile>(profile_));
-  // Close when the browser is exiting.
-  // TODO(mihaip): we probably don't want this in the long run (when platform
-  // apps are no longer tied to the browser process).
-  registrar_.Add(this, chrome::NOTIFICATION_APP_TERMINATING,
-                 content::NotificationService::AllSources());
-
-  shell_window_contents_->LoadContents(params.creator_process_id);
-
-  // Prevent the browser process from shutting down while this window is open.
-  chrome::StartKeepAlive();
-
-  UpdateExtensionAppIcon();
-}
-
-ShellWindow::~ShellWindow() {
-  // Unregister now to prevent getting NOTIFICATION_APP_TERMINATING if we're the
-  // last window open.
-  registrar_.RemoveAll();
-
-  // Remove shutdown prevention.
-  chrome::EndKeepAlive();
-}
-
-void ShellWindow::RequestMediaAccessPermission(
-    content::WebContents* web_contents,
-    const content::MediaStreamRequest& request,
-    const content::MediaResponseCallback& callback) {
-  MediaCaptureDevicesDispatcher::GetInstance()->ProcessMediaAccessRequest(
-      web_contents, request, callback, extension());
-}
-
-WebContents* ShellWindow::OpenURLFromTab(WebContents* source,
-                                         const content::OpenURLParams& params) {
-  // Don't allow the current tab to be navigated. It would be nice to map all
-  // anchor tags (even those without target="_blank") to new tabs, but right
-  // now we can't distinguish between those and <meta> refreshes or window.href
-  // navigations, which we don't want to allow.
-  // TOOD(mihaip): Can we check for user gestures instead?
-  WindowOpenDisposition disposition = params.disposition;
-  if (disposition == CURRENT_TAB) {
-    AddMessageToDevToolsConsole(
-        content::CONSOLE_MESSAGE_LEVEL_ERROR,
-        base::StringPrintf(
-            "Can't open same-window link to \"%s\"; try target=\"_blank\".",
-            params.url.spec().c_str()));
-    return NULL;
-  }
-
-  // These dispositions aren't really navigations.
-  if (disposition == SUPPRESS_OPEN || disposition == SAVE_TO_DISK ||
-      disposition == IGNORE_ACTION) {
-    return NULL;
-  }
-
-  // Force all links to open in a new tab, even if they were trying to open a
-  // window.
-  chrome::NavigateParams new_tab_params(
-      static_cast<Browser*>(NULL), params.url, params.transition);
-  new_tab_params.disposition =
-      disposition == NEW_BACKGROUND_TAB ? disposition : NEW_FOREGROUND_TAB;
-  new_tab_params.initiating_profile = profile_;
-  chrome::Navigate(&new_tab_params);
-
-  if (!new_tab_params.target_contents) {
-    AddMessageToDevToolsConsole(
-        content::CONSOLE_MESSAGE_LEVEL_ERROR,
-        base::StringPrintf(
-            "Can't navigate to \"%s\"; apps do not support navigation.",
-            params.url.spec().c_str()));
-  }
-
-  return new_tab_params.target_contents;
-}
-
-void ShellWindow::AddNewContents(WebContents* source,
-                                 WebContents* new_contents,
-                                 WindowOpenDisposition disposition,
-                                 const gfx::Rect& initial_pos,
-                                 bool user_gesture,
-                                 bool* was_blocked) {
-  DCHECK(Profile::FromBrowserContext(new_contents->GetBrowserContext()) ==
-      profile_);
-#if defined(OS_MACOSX) || defined(OS_WIN) || \
-    (defined(OS_LINUX) && !defined(OS_CHROMEOS))
-  if (disable_external_open_for_testing_) {
-    Browser* browser =
-        chrome::FindOrCreateTabbedBrowser(profile_, chrome::GetActiveDesktop());
-    // Force all links to open in a new tab, even if they were trying to open a
-    // new window.
-    disposition =
-        disposition == NEW_BACKGROUND_TAB ? disposition : NEW_FOREGROUND_TAB;
-    chrome::AddWebContents(browser, NULL, new_contents, disposition,
-                           initial_pos, user_gesture, was_blocked);
-  } else {
-    new_contents->SetDelegate(new ShellWindowLinkDelegate());
-  }
-#else
-  Browser* browser =
-      chrome::FindOrCreateTabbedBrowser(profile_, chrome::GetActiveDesktop());
-  // Force all links to open in a new tab, even if they were trying to open a
-  // new window.
-  disposition =
-      disposition == NEW_BACKGROUND_TAB ? disposition : NEW_FOREGROUND_TAB;
-  chrome::AddWebContents(browser, NULL, new_contents, disposition, initial_pos,
-                         user_gesture, was_blocked);
-#endif
-}
-
-void ShellWindow::HandleKeyboardEvent(
-    WebContents* source,
-    const content::NativeWebKeyboardEvent& event) {
-  native_app_window_->HandleKeyboardEvent(event);
-}
-
-void ShellWindow::RequestToLockMouse(WebContents* web_contents,
-                                     bool user_gesture,
-                                     bool last_unlocked_by_target) {
-  bool has_permission = IsExtensionWithPermissionOrSuggestInConsole(
-      APIPermission::kPointerLock,
-      extension_,
-      web_contents->GetRenderViewHost());
-
-  web_contents->GotResponseToLockMouseRequest(has_permission);
-}
-
-void ShellWindow::OnNativeClose() {
-  extensions::ShellWindowRegistry::Get(profile_)->RemoveShellWindow(this);
-  if (shell_window_contents_)
-    shell_window_contents_->NativeWindowClosed();
-  delete this;
-}
-
-void ShellWindow::OnNativeWindowChanged() {
-  SaveWindowPosition();
-  if (shell_window_contents_ && native_app_window_)
-    shell_window_contents_->NativeWindowChanged(native_app_window_.get());
-}
-
-void ShellWindow::OnNativeWindowActivated() {
-  extensions::ShellWindowRegistry::Get(profile_)->ShellWindowActivated(this);
-}
-
-scoped_ptr<gfx::Image> ShellWindow::GetAppListIcon() {
-  // TODO(skuhne): We might want to use LoadImages in UpdateExtensionAppIcon
-  // instead to let the extension give us pre-defined icons in the launcher
-  // and the launcher list sizes. Since there is no mock yet, doing this now
-  // seems a bit premature and we scale for the time being.
-  if (app_icon_.IsEmpty())
-    return make_scoped_ptr(new gfx::Image());
-
-  SkBitmap bmp = skia::ImageOperations::Resize(
-        *app_icon_.ToSkBitmap(), skia::ImageOperations::RESIZE_BEST,
-        extension_misc::EXTENSION_ICON_SMALLISH,
-        extension_misc::EXTENSION_ICON_SMALLISH);
-  return make_scoped_ptr(
-      new gfx::Image(gfx::ImageSkia::CreateFrom1xBitmap(bmp)));
-}
-
-content::WebContents* ShellWindow::web_contents() const {
-  return shell_window_contents_->GetWebContents();
-}
-
-NativeAppWindow* ShellWindow::GetBaseWindow() {
-  return native_app_window_.get();
-}
-
-gfx::NativeWindow ShellWindow::GetNativeWindow() {
-  return GetBaseWindow()->GetNativeWindow();
-}
-
-gfx::Rect ShellWindow::GetClientBounds() const {
-  gfx::Rect bounds = native_app_window_->GetBounds();
-  bounds.Inset(native_app_window_->GetFrameInsets());
-  return bounds;
-}
-
-string16 ShellWindow::GetTitle() const {
-  // WebContents::GetTitle() will return the page's URL if there's no <title>
-  // specified. However, we'd prefer to show the name of the extension in that
-  // case, so we directly inspect the NavigationEntry's title.
-  if (!web_contents() ||
-      !web_contents()->GetController().GetActiveEntry() ||
-      web_contents()->GetController().GetActiveEntry()->GetTitle().empty())
-    return UTF8ToUTF16(extension()->name());
-  string16 title = web_contents()->GetTitle();
-  Browser::FormatTitleForDisplay(&title);
-  return title;
-}
-
-void ShellWindow::SetAppIconUrl(const GURL& url) {
-  // Avoid using any previous app icons were are being downloaded.
-  image_loader_ptr_factory_.InvalidateWeakPtrs();
-
-  app_icon_url_ = url;
-  web_contents()->DownloadImage(
-      url, true, kPreferredIconSize,
-      base::Bind(&ShellWindow::DidDownloadFavicon,
-                 image_loader_ptr_factory_.GetWeakPtr()));
-}
-
-void ShellWindow::UpdateDraggableRegions(
-    const std::vector<extensions::DraggableRegion>& regions) {
-  native_app_window_->UpdateDraggableRegions(regions);
-}
-
-void ShellWindow::UpdateAppIcon(const gfx::Image& image) {
-  if (image.IsEmpty())
-    return;
-  app_icon_ = image;
-  native_app_window_->UpdateWindowIcon();
-  extensions::ShellWindowRegistry::Get(profile_)->ShellWindowIconChanged(this);
-}
-
-void ShellWindow::Fullscreen() {
-  fullscreen_for_window_api_ = true;
-  GetBaseWindow()->SetFullscreen(true);
-}
-
-void ShellWindow::Maximize() {
-  GetBaseWindow()->Maximize();
-}
-
-void ShellWindow::Minimize() {
-  GetBaseWindow()->Minimize();
-}
-
-void ShellWindow::Restore() {
-  fullscreen_for_window_api_ = false;
-  fullscreen_for_tab_ = false;
-  if (GetBaseWindow()->IsFullscreenOrPending()) {
-    GetBaseWindow()->SetFullscreen(false);
-  } else {
-    GetBaseWindow()->Restore();
-  }
-}
-
-//------------------------------------------------------------------------------
-// Private methods
-
-void ShellWindow::OnImageLoaded(const gfx::Image& image) {
-  UpdateAppIcon(image);
-}
-
-void ShellWindow::DidDownloadFavicon(int id,
-                                     int http_status_code,
-                                     const GURL& image_url,
-                                     int requested_size,
-                                     const std::vector<SkBitmap>& bitmaps) {
-  if (image_url != app_icon_url_ || bitmaps.empty())
-    return;
-
-  // Bitmaps are ordered largest to smallest. Choose the smallest bitmap
-  // whose height >= the preferred size.
-  int largest_index = 0;
-  for (size_t i = 1; i < bitmaps.size(); ++i) {
-    if (bitmaps[i].height() < kPreferredIconSize)
-      break;
-    largest_index = i;
-  }
-  const SkBitmap& largest = bitmaps[largest_index];
-  UpdateAppIcon(gfx::Image::CreateFrom1xBitmap(largest));
-}
-
-void ShellWindow::UpdateExtensionAppIcon() {
-  // Avoid using any previous app icons were are being downloaded.
-  image_loader_ptr_factory_.InvalidateWeakPtrs();
-
-  // Enqueue OnImageLoaded callback.
-  extensions::ImageLoader* loader = extensions::ImageLoader::Get(profile());
-  loader->LoadImageAsync(
-      extension(),
-      extensions::IconsInfo::GetIconResource(extension(),
-                                             kPreferredIconSize,
-                                             ExtensionIconSet::MATCH_BIGGER),
-      gfx::Size(kPreferredIconSize, kPreferredIconSize),
-      base::Bind(&ShellWindow::OnImageLoaded,
-                 image_loader_ptr_factory_.GetWeakPtr()));
-}
-
-void ShellWindow::CloseContents(WebContents* contents) {
-  native_app_window_->Close();
-}
-
-bool ShellWindow::ShouldSuppressDialogs() {
-  return true;
-}
-
-content::ColorChooser* ShellWindow::OpenColorChooser(WebContents* web_contents,
-                                                     SkColor initial_color) {
-  return chrome::ShowColorChooser(web_contents, initial_color);
-}
-
-void ShellWindow::RunFileChooser(WebContents* tab,
-                                 const content::FileChooserParams& params) {
-  if (window_type_is_panel()) {
-    // Panels can't host a file dialog, abort. TODO(stevenjb): allow file
-    // dialogs to be unhosted but still close with the owning web contents.
-    // crbug.com/172502.
-    LOG(WARNING) << "File dialog opened by panel.";
-    return;
-  }
-  FileSelectHelper::RunFileChooser(tab, params);
-}
-
-bool ShellWindow::IsPopupOrPanel(const WebContents* source) const {
-  return true;
-}
-
-void ShellWindow::MoveContents(WebContents* source, const gfx::Rect& pos) {
-  native_app_window_->SetBounds(pos);
-}
-
-void ShellWindow::NavigationStateChanged(
-    const content::WebContents* source, unsigned changed_flags) {
-  if (changed_flags & content::INVALIDATE_TYPE_TITLE)
-    native_app_window_->UpdateWindowTitle();
-  else if (changed_flags & content::INVALIDATE_TYPE_TAB)
-    native_app_window_->UpdateWindowIcon();
-}
-
-void ShellWindow::ToggleFullscreenModeForTab(content::WebContents* source,
-                                             bool enter_fullscreen) {
-  if (!IsExtensionWithPermissionOrSuggestInConsole(
-      APIPermission::kFullscreen,
-      extension_,
-      source->GetRenderViewHost())) {
-    return;
-  }
-
-  fullscreen_for_tab_ = enter_fullscreen;
-
-  if (enter_fullscreen) {
-    native_app_window_->SetFullscreen(true);
-  } else if (!fullscreen_for_window_api_) {
-    native_app_window_->SetFullscreen(false);
-  }
-}
-
-bool ShellWindow::IsFullscreenForTabOrPending(
-    const content::WebContents* source) const {
-  return fullscreen_for_tab_;
-}
-
-void ShellWindow::Observe(int type,
-                          const content::NotificationSource& source,
-                          const content::NotificationDetails& details) {
-  switch (type) {
-    case content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED: {
-      // TODO(jianli): once http://crbug.com/123007 is fixed, we'll no longer
-      // need to make the native window (ShellWindowViews specially) update
-      // the clickthrough region for the new RVH.
-      native_app_window_->RenderViewHostChanged();
-      break;
-    }
-    case chrome::NOTIFICATION_EXTENSION_UNLOADED: {
-      const extensions::Extension* unloaded_extension =
-          content::Details<extensions::UnloadedExtensionInfo>(
-              details)->extension;
-      if (extension_ == unloaded_extension)
-        native_app_window_->Close();
-      break;
-    }
-    case chrome::NOTIFICATION_APP_TERMINATING:
-      native_app_window_->Close();
-      break;
-    default:
-      NOTREACHED() << "Received unexpected notification";
-  }
-}
-
-extensions::ActiveTabPermissionGranter*
-    ShellWindow::GetActiveTabPermissionGranter() {
-  // Shell windows don't support the activeTab permission.
-  return NULL;
-}
-
-WebContentsModalDialogHost* ShellWindow::GetWebContentsModalDialogHost() {
-  return native_app_window_.get();
-}
-
-void ShellWindow::AddMessageToDevToolsConsole(ConsoleMessageLevel level,
-                                              const std::string& message) {
-  content::RenderViewHost* rvh = web_contents()->GetRenderViewHost();
-  rvh->Send(new ExtensionMsg_AddMessageToConsole(
-      rvh->GetRoutingID(), level, message));
-}
-
-void ShellWindow::SaveWindowPosition() {
-  if (window_key_.empty())
-    return;
-  if (!native_app_window_)
-    return;
-
-  apps::ShellWindowGeometryCache* cache =
-      apps::ShellWindowGeometryCache::Get(profile());
-
-  gfx::Rect bounds = native_app_window_->GetRestoredBounds();
-  bounds.Inset(native_app_window_->GetFrameInsets());
-  ui::WindowShowState window_state = native_app_window_->GetRestoredState();
-  cache->SaveGeometry(extension()->id(), window_key_, bounds, window_state);
-}
-
-// static
-SkRegion* ShellWindow::RawDraggableRegionsToSkRegion(
-      const std::vector<extensions::DraggableRegion>& regions) {
-  SkRegion* sk_region = new SkRegion;
-  for (std::vector<extensions::DraggableRegion>::const_iterator iter =
-           regions.begin();
-       iter != regions.end(); ++iter) {
-    const extensions::DraggableRegion& region = *iter;
-    sk_region->op(
-        region.bounds.x(),
-        region.bounds.y(),
-        region.bounds.right(),
-        region.bounds.bottom(),
-        region.draggable ? SkRegion::kUnion_Op : SkRegion::kDifference_Op);
-  }
-  return sk_region;
-}
-
-void ShellWindow::DisableExternalOpenForTesting() {
-  disable_external_open_for_testing_ = true;
-}
-
diff --git a/chrome/browser/ui/extensions/shell_window.h b/chrome/browser/ui/extensions/shell_window.h
deleted file mode 100644
index 64e66c7..0000000
--- a/chrome/browser/ui/extensions/shell_window.h
+++ /dev/null
@@ -1,319 +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_EXTENSIONS_SHELL_WINDOW_H_
-#define CHROME_BROWSER_UI_EXTENSIONS_SHELL_WINDOW_H_
-
-#include "base/memory/scoped_ptr.h"
-#include "base/memory/weak_ptr.h"
-#include "chrome/browser/extensions/extension_keybinding_registry.h"
-#include "chrome/browser/sessions/session_id.h"
-#include "chrome/browser/ui/chrome_web_modal_dialog_manager_delegate.h"
-#include "content/public/browser/notification_observer.h"
-#include "content/public/browser/notification_registrar.h"
-#include "content/public/browser/web_contents_delegate.h"
-#include "content/public/common/console_message_level.h"
-#include "ui/base/ui_base_types.h"  // WindowShowState
-#include "ui/gfx/image/image.h"
-#include "ui/gfx/rect.h"
-
-class GURL;
-class Profile;
-class NativeAppWindow;
-class SkRegion;
-
-namespace content {
-class WebContents;
-}
-
-namespace extensions {
-class Extension;
-class PlatformAppBrowserTest;
-class WindowController;
-
-struct DraggableRegion;
-}
-
-namespace ui {
-class BaseWindow;
-}
-
-// Manages the web contents for Shell Windows. The implementation for this
-// class should create and maintain the WebContents for the window, and handle
-// any message passing between the web contents and the extension system or
-// native window.
-class ShellWindowContents {
- public:
-  ShellWindowContents() {}
-  virtual ~ShellWindowContents() {}
-
-  // Called to initialize the WebContents, before the app window is created.
-  virtual void Initialize(Profile* profile, const GURL& url) = 0;
-
-  // Called to load the contents, after the app window is created.
-  virtual void LoadContents(int32 creator_process_id) = 0;
-
-  // Called when the native window changes.
-  virtual void NativeWindowChanged(NativeAppWindow* native_app_window) = 0;
-
-  // Called when the native window closes.
-  virtual void NativeWindowClosed() = 0;
-
-  virtual content::WebContents* GetWebContents() const = 0;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(ShellWindowContents);
-};
-
-// ShellWindow is the type of window used by platform apps. Shell windows
-// have a WebContents but none of the chrome of normal browser windows.
-class ShellWindow : public content::NotificationObserver,
-                    public content::WebContentsDelegate,
-                    public extensions::ExtensionKeybindingRegistry::Delegate,
-                    public ChromeWebModalDialogManagerDelegate {
- public:
-  enum WindowType {
-    WINDOW_TYPE_DEFAULT  = 1 << 0,  // Default shell window.
-    WINDOW_TYPE_PANEL    = 1 << 1,  // OS controlled panel window (Ash only).
-    WINDOW_TYPE_V1_PANEL = 1 << 2,  // For apps v1 support in Ash; deprecate
-                                    // with v1 apps.
-  };
-
-  enum Frame {
-    FRAME_CHROME,  // Chrome-style window frame.
-    FRAME_NONE,  // Frameless window.
-  };
-
-  struct CreateParams {
-    CreateParams();
-    ~CreateParams();
-
-    WindowType window_type;
-    Frame frame;
-    bool transparent_background;  // Only supported on ash.
-
-    // Specify the initial content bounds of the window (excluding any window
-    // decorations). INT_MIN designates 'unspecified' for the position
-    // components, and 0 for the size components. When unspecified, they should
-    // be replaced with a default value.
-    gfx::Rect bounds;
-
-    gfx::Size minimum_size;
-    gfx::Size maximum_size;
-
-    std::string window_key;
-
-    // The process ID of the process that requested the create.
-    int32 creator_process_id;
-
-    // Initial state of the window.
-    ui::WindowShowState state;
-
-    // If true, don't show the window after creation.
-    bool hidden;
-
-    // If true, the window will be resizable by the user. Defaults to true.
-    bool resizable;
-
-    // If true, the window will be focused on creation. Defaults to true.
-    bool focused;
-  };
-
-  // Helper function for creating and intiailizing a v2 app window.
-  static ShellWindow* Create(Profile* profile,
-                             const extensions::Extension* extension,
-                             const GURL& url,
-                             const CreateParams& params);
-
-  // Convert draggable regions in raw format to SkRegion format. Caller is
-  // responsible for deleting the returned SkRegion instance.
-  static SkRegion* RawDraggableRegionsToSkRegion(
-      const std::vector<extensions::DraggableRegion>& regions);
-
-  // The constructor and Init methods are public for constructing a ShellWindow
-  // with a non-standard render interface (e.g. v1 apps using Ash Panels).
-  // Normally ShellWindow::Create should be used.
-  ShellWindow(Profile* profile, const extensions::Extension* extension);
-
-  // Initializes the render interface, web contents, and native window.
-  // |shell_window_contents| will become owned by ShellWindow.
-  void Init(const GURL& url,
-            ShellWindowContents* shell_window_contents,
-            const CreateParams& params);
-
-
-  const std::string& window_key() const { return window_key_; }
-  const SessionID& session_id() const { return session_id_; }
-  const extensions::Extension* extension() const { return extension_; }
-  const std::string& extension_id() const { return extension_id_; }
-  content::WebContents* web_contents() const;
-  WindowType window_type() const { return window_type_; }
-  bool window_type_is_panel() const {
-    return (window_type_ == WINDOW_TYPE_PANEL ||
-            window_type_ == WINDOW_TYPE_V1_PANEL);
-  }
-  Profile* profile() const { return profile_; }
-  const gfx::Image& app_icon() const { return app_icon_; }
-  const GURL& app_icon_url() { return app_icon_url_; }
-
-  NativeAppWindow* GetBaseWindow();
-  gfx::NativeWindow GetNativeWindow();
-
-  // Returns the bounds that should be reported to the renderer.
-  gfx::Rect GetClientBounds() const;
-
-  // This will return a slightly smaller icon then the app_icon to be used in
-  // application lists.
-  scoped_ptr<gfx::Image> GetAppListIcon();
-
-  // NativeAppWindows should call this to determine what the window's title
-  // is on startup and from within UpdateWindowTitle().
-  string16 GetTitle() const;
-
-  // Call to notify ShellRegistry and delete the window. Subclasses should
-  // invoke this method instead of using "delete this".
-  void OnNativeClose();
-
-  // Should be called by native implementations when the window size, position,
-  // or minimized/maximized state has changed.
-  void OnNativeWindowChanged();
-
-  // Should be called by native implementations when the window is activated.
-  void OnNativeWindowActivated();
-
-  // Specifies a url for the launcher icon.
-  void SetAppIconUrl(const GURL& icon_url);
-
-  // Called from the render interface to modify the draggable regions.
-  void UpdateDraggableRegions(
-      const std::vector<extensions::DraggableRegion>& regions);
-
-  // Updates the app image to |image|. Called internally from the image loader
-  // callback. Also called externally for v1 apps using Ash Panels.
-  void UpdateAppIcon(const gfx::Image& image);
-
-  // Transitions window into fullscreen, maximized, minimized or restores based
-  // on chrome.app.window API.
-  void Fullscreen();
-  void Maximize();
-  void Minimize();
-  void Restore();
-
-  ShellWindowContents* shell_window_contents_for_test() {
-    return shell_window_contents_.get();
-  }
-
-  static void DisableExternalOpenForTesting();
-
- protected:
-  virtual ~ShellWindow();
-
- private:
-  // PlatformAppBrowserTest needs access to web_contents()
-  friend class extensions::PlatformAppBrowserTest;
-
-  // content::WebContentsDelegate implementation.
-  virtual void CloseContents(content::WebContents* contents) OVERRIDE;
-  virtual bool ShouldSuppressDialogs() OVERRIDE;
-  virtual content::ColorChooser* OpenColorChooser(
-      content::WebContents* web_contents, SkColor color) OVERRIDE;
-  virtual void RunFileChooser(
-      content::WebContents* tab,
-      const content::FileChooserParams& params) OVERRIDE;
-  virtual bool IsPopupOrPanel(
-      const content::WebContents* source) const OVERRIDE;
-  virtual void MoveContents(
-      content::WebContents* source, const gfx::Rect& pos) OVERRIDE;
-  virtual void NavigationStateChanged(const content::WebContents* source,
-                                      unsigned changed_flags) OVERRIDE;
-  virtual void ToggleFullscreenModeForTab(content::WebContents* source,
-                                          bool enter_fullscreen) OVERRIDE;
-  virtual bool IsFullscreenForTabOrPending(
-      const content::WebContents* source) const OVERRIDE;
-  virtual void RequestMediaAccessPermission(
-      content::WebContents* web_contents,
-      const content::MediaStreamRequest& request,
-      const content::MediaResponseCallback& callback) OVERRIDE;
-  virtual content::WebContents* OpenURLFromTab(
-      content::WebContents* source,
-      const content::OpenURLParams& params) OVERRIDE;
-  virtual void AddNewContents(content::WebContents* source,
-                              content::WebContents* new_contents,
-                              WindowOpenDisposition disposition,
-                              const gfx::Rect& initial_pos,
-                              bool user_gesture,
-                              bool* was_blocked) OVERRIDE;
-  virtual void HandleKeyboardEvent(
-      content::WebContents* source,
-      const content::NativeWebKeyboardEvent& event) OVERRIDE;
-  virtual void RequestToLockMouse(content::WebContents* web_contents,
-                                  bool user_gesture,
-                                  bool last_unlocked_by_target) OVERRIDE;
-
-  // content::NotificationObserver implementation.
-  virtual void Observe(int type,
-                       const content::NotificationSource& source,
-                       const content::NotificationDetails& details) OVERRIDE;
-
-  // Helper method to add a message to the renderer's DevTools console.
-  void AddMessageToDevToolsConsole(content::ConsoleMessageLevel level,
-                                   const std::string& message);
-
-  // Saves the window geometry/position.
-  void SaveWindowPosition();
-
-  // Load the app's image, firing a load state change when loaded.
-  void UpdateExtensionAppIcon();
-
-  void OnImageLoaded(const gfx::Image& image);
-
-  // extensions::ExtensionKeybindingRegistry::Delegate implementation.
-  virtual extensions::ActiveTabPermissionGranter*
-      GetActiveTabPermissionGranter() OVERRIDE;
-
-  // web_modal::WebContentsModalDialogManagerDelegate implementation.
-  virtual web_modal::WebContentsModalDialogHost*
-      GetWebContentsModalDialogHost() OVERRIDE;
-
-  // Callback from web_contents()->DownloadFavicon.
-  void DidDownloadFavicon(int id,
-                          int http_status_code,
-                          const GURL& image_url,
-                          int requested_size,
-                          const std::vector<SkBitmap>& bitmaps);
-
-  Profile* profile_;  // weak pointer - owned by ProfileManager.
-  // weak pointer - owned by ExtensionService.
-  const extensions::Extension* extension_;
-  const std::string extension_id_;
-
-  // Identifier that is used when saving and restoring geometry for this
-  // window.
-  std::string window_key_;
-
-  const SessionID session_id_;
-  WindowType window_type_;
-  content::NotificationRegistrar registrar_;
-
-  // Icon shown in the task bar.
-  gfx::Image app_icon_;
-
-  // Icon URL to be used for setting the app icon. If not empty, app_icon_ will
-  // be fetched and set using this URL.
-  GURL app_icon_url_;
-
-  scoped_ptr<NativeAppWindow> native_app_window_;
-  scoped_ptr<ShellWindowContents> shell_window_contents_;
-
-  base::WeakPtrFactory<ShellWindow> image_loader_ptr_factory_;
-
-  // Fullscreen entered by app.window api.
-  bool fullscreen_for_window_api_;
-  // Fullscreen entered by HTML requestFullscreen.
-  bool fullscreen_for_tab_;
-
-  DISALLOW_COPY_AND_ASSIGN(ShellWindow);
-};
-
-#endif  // CHROME_BROWSER_UI_EXTENSIONS_SHELL_WINDOW_H_
diff --git a/chrome/browser/ui/external_protocol_dialog_delegate.h b/chrome/browser/ui/external_protocol_dialog_delegate.h
index 27647ca..8862e7e 100644
--- a/chrome/browser/ui/external_protocol_dialog_delegate.h
+++ b/chrome/browser/ui/external_protocol_dialog_delegate.h
@@ -7,7 +7,7 @@
 
 #include "base/basictypes.h"
 #include "base/compiler_specific.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/ui/protocol_dialog_delegate.h"
 #include "googleurl/src/gurl.h"
 
diff --git a/chrome/browser/ui/fast_unload_controller.cc b/chrome/browser/ui/fast_unload_controller.cc
new file mode 100644
index 0000000..5a8373e
--- /dev/null
+++ b/chrome/browser/ui/fast_unload_controller.cc
@@ -0,0 +1,380 @@
+// 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/ui/fast_unload_controller.h"
+
+#include "base/logging.h"
+#include "base/message_loop.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_tabstrip.h"
+#include "chrome/browser/ui/tab_contents/core_tab_helper.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/browser/ui/tabs/tab_strip_model_delegate.h"
+#include "chrome/common/chrome_notification_types.h"
+#include "content/public/browser/notification_service.h"
+#include "content/public/browser/notification_source.h"
+#include "content/public/browser/notification_types.h"
+#include "content/public/browser/render_view_host.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_delegate.h"
+
+namespace chrome {
+
+
+////////////////////////////////////////////////////////////////////////////////
+// DetachedWebContentsDelegate will delete web contents when they close.
+class FastUnloadController::DetachedWebContentsDelegate
+    : public content::WebContentsDelegate {
+ public:
+  DetachedWebContentsDelegate() { }
+  virtual ~DetachedWebContentsDelegate() { }
+
+ private:
+  // WebContentsDelegate implementation.
+  virtual bool ShouldSuppressDialogs() OVERRIDE {
+    return true;  // Return true so dialogs are suppressed.
+  }
+
+  virtual void CloseContents(content::WebContents* source) OVERRIDE {
+    // Finished detached close.
+    // FastUnloadController will observe
+    // |NOTIFICATION_WEB_CONTENTS_DISCONNECTED|.
+    delete source;
+  }
+
+  DISALLOW_COPY_AND_ASSIGN(DetachedWebContentsDelegate);
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// FastUnloadController, public:
+
+FastUnloadController::FastUnloadController(Browser* browser)
+    : browser_(browser),
+      tab_needing_before_unload_ack_(NULL),
+      is_attempting_to_close_browser_(false),
+      detached_delegate_(new DetachedWebContentsDelegate()),
+      weak_factory_(this) {
+  browser_->tab_strip_model()->AddObserver(this);
+}
+
+FastUnloadController::~FastUnloadController() {
+  browser_->tab_strip_model()->RemoveObserver(this);
+}
+
+bool FastUnloadController::CanCloseContents(content::WebContents* contents) {
+  // Don't try to close the tab when the whole browser is being closed, since
+  // that avoids the fast shutdown path where we just kill all the renderers.
+  return !is_attempting_to_close_browser_;
+}
+
+bool FastUnloadController::BeforeUnloadFired(content::WebContents* contents,
+                                             bool proceed) {
+  if (!is_attempting_to_close_browser_) {
+    if (!proceed) {
+      contents->SetClosedByUserGesture(false);
+    } else {
+      // No more dialogs are possible, so remove the tab and finish
+      // running unload listeners asynchrounously.
+      browser_->tab_strip_model()->delegate()->CreateHistoricalTab(contents);
+      DetachWebContents(contents);
+    }
+    return proceed;
+  }
+
+  if (!proceed) {
+    CancelWindowClose();
+    contents->SetClosedByUserGesture(false);
+    return false;
+  }
+
+  if (tab_needing_before_unload_ack_ == contents) {
+    // Now that beforeunload has fired, queue the tab to fire unload.
+    tab_needing_before_unload_ack_ = NULL;
+    tabs_needing_unload_.insert(contents);
+    ProcessPendingTabs();
+    // We want to handle firing the unload event ourselves since we want to
+    // fire all the beforeunload events before attempting to fire the unload
+    // events should the user cancel closing the browser.
+    return false;
+  }
+
+  return true;
+}
+
+bool FastUnloadController::ShouldCloseWindow() {
+  if (HasCompletedUnloadProcessing())
+    return true;
+
+  is_attempting_to_close_browser_ = true;
+
+  if (!TabsNeedBeforeUnloadFired())
+    return true;
+
+  ProcessPendingTabs();
+  return false;
+}
+
+bool FastUnloadController::TabsNeedBeforeUnloadFired() {
+  if (!tabs_needing_before_unload_.empty() ||
+      tab_needing_before_unload_ack_ != NULL)
+    return true;
+
+  if (!tabs_needing_unload_.empty())
+    return false;
+
+  for (int i = 0; i < browser_->tab_strip_model()->count(); ++i) {
+    content::WebContents* contents =
+        browser_->tab_strip_model()->GetWebContentsAt(i);
+    if (contents->NeedToFireBeforeUnload())
+      tabs_needing_before_unload_.insert(contents);
+  }
+  return !tabs_needing_before_unload_.empty();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// FastUnloadController, content::NotificationObserver implementation:
+
+void FastUnloadController::Observe(
+      int type,
+      const content::NotificationSource& source,
+      const content::NotificationDetails& details) {
+  switch (type) {
+    case content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED: {
+      registrar_.Remove(this,
+                        content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED,
+                        source);
+      content::WebContents* contents =
+          content::Source<content::WebContents>(source).ptr();
+      ClearUnloadState(contents);
+      break;
+    }
+    default:
+      NOTREACHED() << "Got a notification we didn't register for.";
+  }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// FastUnloadController, TabStripModelObserver implementation:
+
+void FastUnloadController::TabInsertedAt(content::WebContents* contents,
+                                         int index,
+                                         bool foreground) {
+  TabAttachedImpl(contents);
+}
+
+void FastUnloadController::TabDetachedAt(content::WebContents* contents,
+                                         int index) {
+  TabDetachedImpl(contents);
+}
+
+void FastUnloadController::TabReplacedAt(TabStripModel* tab_strip_model,
+                                         content::WebContents* old_contents,
+                                         content::WebContents* new_contents,
+                                         int index) {
+  TabDetachedImpl(old_contents);
+  TabAttachedImpl(new_contents);
+}
+
+void FastUnloadController::TabStripEmpty() {
+  // Set is_attempting_to_close_browser_ here, so that extensions, etc, do not
+  // attempt to add tabs to the browser before it closes.
+  is_attempting_to_close_browser_ = true;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// FastUnloadController, private:
+
+void FastUnloadController::TabAttachedImpl(content::WebContents* contents) {
+  // If the tab crashes in the beforeunload or unload handler, it won't be
+  // able to ack. But we know we can close it.
+  registrar_.Add(
+      this,
+      content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED,
+      content::Source<content::WebContents>(contents));
+}
+
+void FastUnloadController::TabDetachedImpl(content::WebContents* contents) {
+  if (tabs_needing_unload_ack_.find(contents) !=
+      tabs_needing_unload_ack_.end()) {
+    // Tab needs unload to complete.
+    // It will send |NOTIFICATION_WEB_CONTENTS_DISCONNECTED| when done.
+    return;
+  }
+
+  // If WEB_CONTENTS_DISCONNECTED was received then the notification may have
+  // already been unregistered.
+  const content::NotificationSource& source =
+      content::Source<content::WebContents>(contents);
+  if (registrar_.IsRegistered(this,
+                              content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED,
+                              source)) {
+    registrar_.Remove(this,
+                      content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED,
+                      source);
+  }
+
+  if (is_attempting_to_close_browser_)
+    ClearUnloadState(contents);
+}
+
+bool FastUnloadController::DetachWebContents(content::WebContents* contents) {
+  int index = browser_->tab_strip_model()->GetIndexOfWebContents(contents);
+  if (index != TabStripModel::kNoTab &&
+      contents->NeedToFireBeforeUnload()) {
+    tabs_needing_unload_ack_.insert(contents);
+    browser_->tab_strip_model()->DetachWebContentsAt(index);
+    contents->SetDelegate(detached_delegate_.get());
+    CoreTabHelper* core_tab_helper = CoreTabHelper::FromWebContents(contents);
+    core_tab_helper->OnUnloadDetachedStarted();
+    return true;
+  }
+  return false;
+}
+
+void FastUnloadController::ProcessPendingTabs() {
+  if (!is_attempting_to_close_browser_) {
+    // Because we might invoke this after a delay it's possible for the value of
+    // is_attempting_to_close_browser_ to have changed since we scheduled the
+    // task.
+    return;
+  }
+
+  if (tab_needing_before_unload_ack_ != NULL) {
+    // Wait for |BeforeUnloadFired| before proceeding.
+    return;
+  }
+
+  // Process a beforeunload handler.
+  if (!tabs_needing_before_unload_.empty()) {
+    WebContentsSet::iterator it = tabs_needing_before_unload_.begin();
+    content::WebContents* contents = *it;
+    tabs_needing_before_unload_.erase(it);
+    // Null check render_view_host here as this gets called on a PostTask and
+    // the tab's render_view_host may have been nulled out.
+    if (contents->GetRenderViewHost()) {
+      tab_needing_before_unload_ack_ = contents;
+
+      CoreTabHelper* core_tab_helper = CoreTabHelper::FromWebContents(contents);
+      core_tab_helper->OnCloseStarted();
+
+      contents->GetRenderViewHost()->FirePageBeforeUnload(false);
+    } else {
+      ProcessPendingTabs();
+    }
+    return;
+  }
+
+  // Process all the unload handlers. (The beforeunload handlers have finished.)
+  if (!tabs_needing_unload_.empty()) {
+    browser_->OnWindowClosing();
+
+    // Run unload handlers detached since no more interaction is possible.
+    WebContentsSet::iterator it = tabs_needing_unload_.begin();
+    while (it != tabs_needing_unload_.end()) {
+      WebContentsSet::iterator current = it++;
+      content::WebContents* contents = *current;
+      tabs_needing_unload_.erase(current);
+      // Null check render_view_host here as this gets called on a PostTask
+      // and the tab's render_view_host may have been nulled out.
+      if (contents->GetRenderViewHost()) {
+        CoreTabHelper* core_tab_helper =
+            CoreTabHelper::FromWebContents(contents);
+        core_tab_helper->OnUnloadStarted();
+        DetachWebContents(contents);
+        contents->GetRenderViewHost()->ClosePage();
+      }
+    }
+
+    // Get the browser hidden.
+    if (browser_->tab_strip_model()->empty()) {
+      browser_->TabStripEmpty();
+    } else {
+      browser_->tab_strip_model()->CloseAllTabs();  // tabs not needing unload
+    }
+    return;
+  }
+
+  if (HasCompletedUnloadProcessing()) {
+    browser_->OnWindowClosing();
+
+    // Get the browser closed.
+    if (browser_->tab_strip_model()->empty()) {
+      browser_->TabStripEmpty();
+    } else {
+      // There may be tabs if the last tab needing beforeunload crashed.
+      browser_->tab_strip_model()->CloseAllTabs();
+    }
+    return;
+  }
+}
+
+bool FastUnloadController::HasCompletedUnloadProcessing() const {
+  return is_attempting_to_close_browser_ &&
+      tabs_needing_before_unload_.empty() &&
+      tab_needing_before_unload_ack_ == NULL &&
+      tabs_needing_unload_.empty() &&
+      tabs_needing_unload_ack_.empty();
+}
+
+void FastUnloadController::CancelWindowClose() {
+  // Closing of window can be canceled from a beforeunload handler.
+  DCHECK(is_attempting_to_close_browser_);
+  tabs_needing_before_unload_.clear();
+  if (tab_needing_before_unload_ack_ != NULL) {
+
+    CoreTabHelper* core_tab_helper =
+        CoreTabHelper::FromWebContents(tab_needing_before_unload_ack_);
+    core_tab_helper->OnCloseCanceled();
+    tab_needing_before_unload_ack_ = NULL;
+  }
+  for (WebContentsSet::iterator it = tabs_needing_unload_.begin();
+       it != tabs_needing_unload_.end(); it++) {
+    content::WebContents* contents = *it;
+
+    CoreTabHelper* core_tab_helper = CoreTabHelper::FromWebContents(contents);
+    core_tab_helper->OnCloseCanceled();
+  }
+  tabs_needing_unload_.clear();
+
+  // No need to clear tabs_needing_unload_ack_. Those tabs are already detached.
+
+  is_attempting_to_close_browser_ = false;
+
+  content::NotificationService::current()->Notify(
+      chrome::NOTIFICATION_BROWSER_CLOSE_CANCELLED,
+      content::Source<Browser>(browser_),
+      content::NotificationService::NoDetails());
+}
+
+void FastUnloadController::ClearUnloadState(content::WebContents* contents) {
+  if (tabs_needing_unload_ack_.erase(contents) > 0) {
+    if (HasCompletedUnloadProcessing())
+      PostTaskForProcessPendingTabs();
+    return;
+  }
+
+  if (!is_attempting_to_close_browser_)
+    return;
+
+  if (tab_needing_before_unload_ack_ == contents) {
+    tab_needing_before_unload_ack_ = NULL;
+    PostTaskForProcessPendingTabs();
+    return;
+  }
+
+  if (tabs_needing_before_unload_.erase(contents) > 0 ||
+      tabs_needing_unload_.erase(contents) > 0) {
+    if (tab_needing_before_unload_ack_ == NULL)
+      PostTaskForProcessPendingTabs();
+  }
+}
+
+void FastUnloadController::PostTaskForProcessPendingTabs() {
+  base::MessageLoop::current()->PostTask(
+      FROM_HERE,
+      base::Bind(&FastUnloadController::ProcessPendingTabs,
+                 weak_factory_.GetWeakPtr()));
+}
+
+}  // namespace chrome
diff --git a/chrome/browser/ui/fast_unload_controller.h b/chrome/browser/ui/fast_unload_controller.h
new file mode 100644
index 0000000..945197d
--- /dev/null
+++ b/chrome/browser/ui/fast_unload_controller.h
@@ -0,0 +1,180 @@
+// 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_UI_FAST_UNLOAD_CONTROLLER_H_
+#define CHROME_BROWSER_UI_FAST_UNLOAD_CONTROLLER_H_
+
+#include <set>
+
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "base/strings/string_piece.h"
+#include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
+#include "content/public/browser/notification_observer.h"
+#include "content/public/browser/notification_registrar.h"
+
+class Browser;
+class TabStripModel;
+
+namespace content {
+class NotificationSource;
+class NotifictaionDetails;
+class WebContents;
+}
+
+namespace chrome {
+// FastUnloadController manages closing tabs and windows -- especially in
+// regards to beforeunload handlers (have proceed/cancel dialogs) and
+// unload handlers (have no user interaction).
+//
+// Typical flow of closing a tab:
+//  1. Browser calls CanCloseContents().
+//     If true, browser calls contents::CloseWebContents().
+//  2. WebContents notifies us via its delegate and BeforeUnloadFired()
+//     that the beforeunload handler was run. If the user allowed the
+//     close to continue, we detached the tab and hold onto it while the
+//     close finishes.
+//
+// Typical flow of closing a window:
+//  1. BrowserView::CanClose() calls TabsNeedBeforeUnloadFired().
+//     If beforeunload/unload handlers need to run, FastUnloadController returns
+//     true and calls ProcessPendingTabs() (private method).
+//  2. For each tab with a beforeunload/unload handler, ProcessPendingTabs()
+//        calls |CoreTabHelper::OnCloseStarted()|
+//        and   |web_contents->GetRenderViewHost()->FirePageBeforeUnload()|.
+//  3. If the user allowed the close to continue, we detach all the tabs with
+//     unload handlers, remove them from the tab strip, and finish closing
+//     the tabs in the background.
+//  4. The browser gets notified that the tab strip is empty and calls
+//     CloseFrame where the empty tab strip causes the window to hide.
+//     Once the detached tabs finish, the browser calls CloseFrame again and
+//     the window is finally closed.
+//
+class FastUnloadController : public content::NotificationObserver,
+                             public TabStripModelObserver {
+ public:
+  explicit FastUnloadController(Browser* browser);
+  virtual ~FastUnloadController();
+
+  // Returns true if |contents| can be cleanly closed. When |browser_| is being
+  // closed, this function will return false to indicate |contents| should not
+  // be cleanly closed, since the fast shutdown path will just kill its
+  // renderer.
+  bool CanCloseContents(content::WebContents* contents);
+
+  // Called when a BeforeUnload handler is fired for |contents|. |proceed|
+  // indicates the user's response to the Y/N BeforeUnload handler dialog. If
+  // this parameter is false, any pending attempt to close the whole browser
+  // will be canceled. Returns true if Unload handlers should be fired. When the
+  // |browser_| is being closed, Unload handlers for any particular WebContents
+  // will not be run until every WebContents being closed has a chance to run
+  // its BeforeUnloadHandler.
+  bool BeforeUnloadFired(content::WebContents* contents, bool proceed);
+
+  bool is_attempting_to_close_browser() const {
+    return is_attempting_to_close_browser_;
+  }
+
+  // Called in response to a request to close |browser_|'s window. Returns true
+  // when there are no remaining beforeunload handlers to be run.
+  bool ShouldCloseWindow();
+
+  // Returns true if |browser_| has any tabs that have BeforeUnload handlers
+  // that have not been fired. This method is non-const because it builds a list
+  // of tabs that need their BeforeUnloadHandlers fired.
+  // TODO(beng): This seems like it could be private but it is used by
+  //             AreAllBrowsersCloseable() in application_lifetime.cc. It seems
+  //             very similar to ShouldCloseWindow() and some consolidation
+  //             could be pursued.
+  bool TabsNeedBeforeUnloadFired();
+
+  // Returns true if all tabs' beforeunload/unload events have fired.
+  bool HasCompletedUnloadProcessing() const;
+
+ private:
+  // Overridden from content::NotificationObserver:
+  virtual void Observe(int type,
+                       const content::NotificationSource& source,
+                       const content::NotificationDetails& details) OVERRIDE;
+
+  // Overridden from TabStripModelObserver:
+  virtual void TabInsertedAt(content::WebContents* contents,
+                             int index,
+                             bool foreground) OVERRIDE;
+  virtual void TabDetachedAt(content::WebContents* contents,
+                             int index) OVERRIDE;
+  virtual void TabReplacedAt(TabStripModel* tab_strip_model,
+                             content::WebContents* old_contents,
+                             content::WebContents* new_contents,
+                             int index) OVERRIDE;
+  virtual void TabStripEmpty() OVERRIDE;
+
+  void TabAttachedImpl(content::WebContents* contents);
+  void TabDetachedImpl(content::WebContents* contents);
+
+  // Detach |contents| and wait for it to finish closing.
+  // The close must be inititiated outside of this method.
+  // Returns true if it succeeds.
+  bool DetachWebContents(content::WebContents* contents);
+
+  // Processes the next tab that needs it's beforeunload/unload event fired.
+  void ProcessPendingTabs();
+
+  // Clears all the state associated with processing tabs' beforeunload/unload
+  // events since the user cancelled closing the window.
+  void CancelWindowClose();
+
+  // Cleans up state appropriately when we are trying to close the
+  // browser or close a tab in the background. We also use this in the
+  // cases where a tab crashes or hangs even if the
+  // beforeunload/unload haven't successfully fired.
+  void ClearUnloadState(content::WebContents* contents);
+
+  // Helper for |ClearUnloadState| to unwind stack before proceeding.
+  void PostTaskForProcessPendingTabs();
+
+  // Log a step of the unload processing.
+  void LogUnloadStep(const base::StringPiece& step_name,
+                     content::WebContents* contents) const;
+
+  Browser* browser_;
+
+  content::NotificationRegistrar registrar_;
+
+  typedef std::set<content::WebContents*> WebContentsSet;
+
+  // Tracks tabs that need their beforeunload event started.
+  // Only gets populated when we try to close the browser.
+  WebContentsSet tabs_needing_before_unload_;
+
+  // Tracks the tab that needs its beforeunload event result.
+  // Only gets populated when we try to close the browser.
+  content::WebContents* tab_needing_before_unload_ack_;
+
+  // Tracks tabs that need their unload event started.
+  // Only gets populated when we try to close the browser.
+  WebContentsSet tabs_needing_unload_;
+
+  // Tracks tabs that need to finish running their unload event.
+  // Populated both when closing individual tabs and when closing the browser.
+  WebContentsSet tabs_needing_unload_ack_;
+
+  // Whether we are processing the beforeunload and unload events of each tab
+  // in preparation for closing the browser. FastUnloadController owns this
+  // state rather than Browser because unload handlers are the only reason that
+  // a Browser window isn't just immediately closed.
+  bool is_attempting_to_close_browser_;
+
+  // Manage tabs with beforeunload/unload handlers that close detached.
+  class DetachedWebContentsDelegate;
+  scoped_ptr<DetachedWebContentsDelegate> detached_delegate_;
+
+  base::WeakPtrFactory<FastUnloadController> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(FastUnloadController);
+};
+
+}  // namespace chrome
+
+#endif  // CHROME_BROWSER_UI_FAST_UNLOAD_CONTROLLER_H_
diff --git a/chrome/browser/ui/fullscreen/fullscreen_controller.cc b/chrome/browser/ui/fullscreen/fullscreen_controller.cc
index 6c9c340..935703d 100644
--- a/chrome/browser/ui/fullscreen/fullscreen_controller.cc
+++ b/chrome/browser/ui/fullscreen/fullscreen_controller.cc
@@ -79,8 +79,13 @@
 
 void FullscreenController::ToggleFullscreenModeForTab(WebContents* web_contents,
                                                       bool enter_fullscreen) {
-  if (web_contents != browser_->tab_strip_model()->GetActiveWebContents())
+  if (fullscreened_tab_) {
+    if (web_contents != fullscreened_tab_)
+      return;
+  } else if (
+      web_contents != browser_->tab_strip_model()->GetActiveWebContents()) {
     return;
+  }
   if (IsFullscreenForTabOrPending() == enter_fullscreen)
     return;
 
diff --git a/chrome/browser/ui/fullscreen/fullscreen_controller_state_unittest.cc b/chrome/browser/ui/fullscreen/fullscreen_controller_state_unittest.cc
index 24984be..885bb76 100644
--- a/chrome/browser/ui/fullscreen/fullscreen_controller_state_unittest.cc
+++ b/chrome/browser/ui/fullscreen/fullscreen_controller_state_unittest.cc
@@ -7,6 +7,7 @@
 #include "chrome/browser/ui/browser_tabstrip.h"
 #include "chrome/browser/ui/fullscreen/fullscreen_controller.h"
 #include "chrome/browser/ui/fullscreen/fullscreen_controller_state_test.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/test/base/browser_with_test_window_test.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/url_constants.h"
@@ -597,3 +598,50 @@
   EXPECT_EQ(FEB_TYPE_NONE,
             browser()->fullscreen_controller()->GetFullscreenExitBubbleType());
 }
+
+// Test that switching tabs takes the browser out of tab fullscreen.
+TEST_F(FullscreenControllerStateUnitTest, ExitTabFullscreenViaSwitchingTab) {
+  AddTab(browser(), GURL(content::kAboutBlankURL));
+  AddTab(browser(), GURL(content::kAboutBlankURL));
+  ASSERT_TRUE(InvokeEvent(TAB_FULLSCREEN_TRUE));
+  ASSERT_TRUE(InvokeEvent(WINDOW_CHANGE));
+  ASSERT_TRUE(browser()->window()->IsFullscreen());
+
+  browser()->tab_strip_model()->SelectNextTab();
+  ChangeWindowFullscreenState();
+  EXPECT_FALSE(browser()->window()->IsFullscreen());
+}
+
+// Test that switching tabs via detaching the active tab (which is in tab
+// fullscreen) takes the browser out of tab fullscreen. This case can
+// occur if the user is in both tab fullscreen and immersive browser fullscreen.
+TEST_F(FullscreenControllerStateUnitTest, ExitTabFullscreenViaDetachingTab) {
+  AddTab(browser(), GURL(content::kAboutBlankURL));
+  AddTab(browser(), GURL(content::kAboutBlankURL));
+  ASSERT_TRUE(InvokeEvent(TAB_FULLSCREEN_TRUE));
+  ASSERT_TRUE(InvokeEvent(WINDOW_CHANGE));
+  ASSERT_TRUE(browser()->window()->IsFullscreen());
+
+  scoped_ptr<content::WebContents> web_contents(
+      browser()->tab_strip_model()->DetachWebContentsAt(0));
+  ChangeWindowFullscreenState();
+  EXPECT_FALSE(browser()->window()->IsFullscreen());
+}
+
+// Test that replacing the web contents for a tab which is in tab fullscreen
+// takes the browser out of tab fullscreen. This can occur if the user
+// navigates to a prerendered page from a page which is tab fullscreen.
+TEST_F(FullscreenControllerStateUnitTest, ExitTabFullscreenViaReplacingTab) {
+  AddTab(browser(), GURL(content::kAboutBlankURL));
+  ASSERT_TRUE(InvokeEvent(TAB_FULLSCREEN_TRUE));
+  ASSERT_TRUE(InvokeEvent(WINDOW_CHANGE));
+  ASSERT_TRUE(browser()->window()->IsFullscreen());
+
+  content::WebContents* new_web_contents = content::WebContents::Create(
+      content::WebContents::CreateParams(profile()));
+  scoped_ptr<content::WebContents> old_web_contents(
+      browser()->tab_strip_model()->ReplaceWebContentsAt(
+          0, new_web_contents));
+  ChangeWindowFullscreenState();
+  EXPECT_FALSE(browser()->window()->IsFullscreen());
+}
diff --git a/chrome/browser/ui/fullscreen/fullscreen_exit_bubble.h b/chrome/browser/ui/fullscreen/fullscreen_exit_bubble.h
index da20148..d8d464d 100644
--- a/chrome/browser/ui/fullscreen/fullscreen_exit_bubble.h
+++ b/chrome/browser/ui/fullscreen/fullscreen_exit_bubble.h
@@ -5,7 +5,7 @@
 #ifndef CHROME_BROWSER_UI_FULLSCREEN_FULLSCREEN_EXIT_BUBBLE_H_
 #define CHROME_BROWSER_UI_FULLSCREEN_FULLSCREEN_EXIT_BUBBLE_H_
 
-#include "base/timer.h"
+#include "base/timer/timer.h"
 #include "chrome/browser/ui/fullscreen/fullscreen_exit_bubble_type.h"
 #include "googleurl/src/gurl.h"
 #include "ui/base/animation/animation_delegate.h"
diff --git a/chrome/browser/ui/gesture_prefs_observer_factory_aura.cc b/chrome/browser/ui/gesture_prefs_observer_factory_aura.cc
index 288af95..c02c3e4 100644
--- a/chrome/browser/ui/gesture_prefs_observer_factory_aura.cc
+++ b/chrome/browser/ui/gesture_prefs_observer_factory_aura.cc
@@ -311,6 +311,8 @@
   GestureConfiguration::set_rail_start_proportion(
       prefs_->GetDouble(
           prefs::kRailStartProportion));
+  GestureConfiguration::set_scroll_prediction_seconds(
+      prefs_->GetDouble(prefs::kScrollPredictionSeconds));
 
   UpdateOverscrollPrefs();
   UpdateImmersiveModePrefs();
@@ -560,6 +562,10 @@
       prefs::kRailStartProportion,
       GestureConfiguration::rail_start_proportion(),
       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
+  registry->RegisterDoublePref(
+      prefs::kScrollPredictionSeconds,
+      GestureConfiguration::scroll_prediction_seconds(),
+      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
 
   // Register for migration.
   registry->RegisterDoublePref(
diff --git a/chrome/browser/ui/gtk/autofill/autofill_popup_view_gtk.cc b/chrome/browser/ui/gtk/autofill/autofill_popup_view_gtk.cc
index 47782e4..114e8fa 100644
--- a/chrome/browser/ui/gtk/autofill/autofill_popup_view_gtk.cc
+++ b/chrome/browser/ui/gtk/autofill/autofill_popup_view_gtk.cc
@@ -72,8 +72,6 @@
 }
 
 void AutofillPopupViewGtk::Hide() {
-  AutofillPopupView::Hide();
-
   delete this;
 }
 
diff --git a/chrome/browser/ui/gtk/avatar_menu_bubble_gtk.cc b/chrome/browser/ui/gtk/avatar_menu_bubble_gtk.cc
index 8d81513..5488cf8 100644
--- a/chrome/browser/ui/gtk/avatar_menu_bubble_gtk.cc
+++ b/chrome/browser/ui/gtk/avatar_menu_bubble_gtk.cc
@@ -124,17 +124,6 @@
   OnAvatarMenuModelChanged(avatar_menu_model_.get());
 }
 
-void AvatarMenuBubbleGtk::OnRealize(GtkWidget* parent_widget) {
-  if (!managed_user_info_ || !theme_service_->UsingNativeTheme())
-    return;
-
-  // Use the same background color for the GtkTextView as the background color
-  // of the enclosing widget.
-  GtkStyle* style = gtk_widget_get_style(parent_widget);
-  GdkColor bg_color = style->bg[GTK_STATE_NORMAL];
-  gtk_widget_modify_base(managed_user_info_, GTK_STATE_NORMAL, &bg_color);
-}
-
 void AvatarMenuBubbleGtk::InitMenuContents() {
   size_t profile_count = avatar_menu_model_->GetNumberOfItems();
   GtkWidget* items_vbox = gtk_vbox_new(FALSE, ui::kContentAreaSpacing);
@@ -183,40 +172,29 @@
   gtk_box_pack_start(GTK_BOX(inner_contents_),
                      gtk_hseparator_new(), TRUE, TRUE, 0);
 
-  // Add information about managed users.
-  managed_user_info_ = gtk_text_view_new();
-  gtk_text_view_set_editable(GTK_TEXT_VIEW(managed_user_info_), FALSE);
-  gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(managed_user_info_), FALSE);
-  GtkTextBuffer* text_buffer =
-      gtk_text_view_get_buffer(GTK_TEXT_VIEW(managed_user_info_));
-  std::string info =
-      UTF16ToUTF8(avatar_menu_model_->GetManagedUserInformation());
-  gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(managed_user_info_), GTK_WRAP_WORD);
-
-  // Insert the managed user icon. Insert it inside a hbox in order to be able
-  // to define a padding around it.
-  GtkTextIter start_iter;
-  gtk_text_buffer_get_start_iter(text_buffer, &start_iter);
-  GtkWidget* icon_box = gtk_hbox_new(FALSE, 0);
+  // Add information about managed users within a hbox.
+  GtkWidget* managed_user_info = gtk_hbox_new(FALSE, 5);
   GdkPixbuf* limited_user_pixbuf =
       avatar_menu_model_->GetManagedUserIcon().ToGdkPixbuf();
   GtkWidget* limited_user_img = gtk_image_new_from_pixbuf(limited_user_pixbuf);
-  gtk_box_pack_start(GTK_BOX(icon_box), limited_user_img, FALSE, FALSE, 5);
-  GtkTextChildAnchor* anchor =
-      gtk_text_buffer_create_child_anchor(text_buffer, &start_iter);
-  gtk_text_view_add_child_at_anchor(
-      GTK_TEXT_VIEW(managed_user_info_), icon_box, anchor);
-
-  // Insert the information text.
-  GtkTextIter end_iter;
-  gtk_text_buffer_get_end_iter(text_buffer, &end_iter);
-  GtkTextTag* text_tag = gtk_text_buffer_create_tag(
-      text_buffer, NULL, "size-set", TRUE, "size", 10 * PANGO_SCALE, NULL);
-  gtk_text_buffer_insert_with_tags(
-      text_buffer, &end_iter, info.c_str(), info.size(), text_tag, NULL);
-
+  GtkWidget* icon_align = gtk_alignment_new(0, 0, 0, 0);
+  gtk_container_add(GTK_CONTAINER(icon_align), limited_user_img);
+  gtk_box_pack_start(GTK_BOX(managed_user_info), icon_align, FALSE, FALSE, 0);
+  GtkWidget* status_label =
+      theme_service_->BuildLabel(std::string(), ui::kGdkBlack);
+  char* markup = g_markup_printf_escaped(
+      "<span size='small'>%s</span>",
+      UTF16ToUTF8(avatar_menu_model_->GetManagedUserInformation()).c_str());
+  const int kLabelWidth = 150;
+  gtk_widget_set_size_request(status_label, kLabelWidth, -1);
+  gtk_label_set_markup(GTK_LABEL(status_label), markup);
+  gtk_label_set_line_wrap(GTK_LABEL(status_label), TRUE);
+  gtk_misc_set_alignment(GTK_MISC(status_label), 0, 0);
+  g_free(markup);
+  gtk_box_pack_start(GTK_BOX(managed_user_info), status_label, FALSE, FALSE, 0);
   gtk_box_pack_start(
-      GTK_BOX(inner_contents_), managed_user_info_, FALSE, FALSE, 0);
+      GTK_BOX(inner_contents_), managed_user_info, FALSE, FALSE, 0);
+
   gtk_box_pack_start(
       GTK_BOX(inner_contents_), gtk_hseparator_new(), TRUE, TRUE, 0);
 
@@ -226,14 +204,10 @@
   g_signal_connect(switch_profile_link, "clicked",
                    G_CALLBACK(OnSwitchProfileLinkClickedThunk), this);
 
-  GtkWidget* link_align = gtk_alignment_new(0, 0, 0, 0);
-  gtk_alignment_set_padding(GTK_ALIGNMENT(link_align),
-                            0, 0, kNewProfileLinkLeftPadding, 0);
+  GtkWidget* link_align = gtk_alignment_new(0.5, 0, 0, 0);
   gtk_container_add(GTK_CONTAINER(link_align), switch_profile_link);
 
   gtk_box_pack_start(GTK_BOX(inner_contents_), link_align, FALSE, FALSE, 0);
-  g_signal_connect(
-      inner_contents_, "realize", G_CALLBACK(OnRealizeThunk), this);
 }
 
 void AvatarMenuBubbleGtk::InitContents() {
diff --git a/chrome/browser/ui/gtk/avatar_menu_bubble_gtk.h b/chrome/browser/ui/gtk/avatar_menu_bubble_gtk.h
index 3c2136b..f611f68 100644
--- a/chrome/browser/ui/gtk/avatar_menu_bubble_gtk.h
+++ b/chrome/browser/ui/gtk/avatar_menu_bubble_gtk.h
@@ -51,7 +51,6 @@
                        GtkRequisition*);
   CHROMEGTK_CALLBACK_0(AvatarMenuBubbleGtk, void, OnNewProfileLinkClicked);
   CHROMEGTK_CALLBACK_0(AvatarMenuBubbleGtk, void, OnSwitchProfileLinkClicked);
-  CHROMEGTK_CALLBACK_0(AvatarMenuBubbleGtk, void, OnRealize);
 
   // Create all widgets in this bubble.
   void InitContents();
@@ -75,10 +74,6 @@
   // widgets in the bubble.
   GtkWidget* inner_contents_;
 
-  // A weak pointer to the GtkTextView which holds general information about
-  // managed users.
-  GtkWidget* managed_user_info_;
-
   // A weak pointer to the bubble window.
   BubbleGtk* bubble_;
 
diff --git a/chrome/browser/ui/gtk/bookmarks/bookmark_bar_gtk_interactive_uitest.cc b/chrome/browser/ui/gtk/bookmarks/bookmark_bar_gtk_interactive_uitest.cc
index fe0922d..cca8aa3 100644
--- a/chrome/browser/ui/gtk/bookmarks/bookmark_bar_gtk_interactive_uitest.cc
+++ b/chrome/browser/ui/gtk/bookmarks/bookmark_bar_gtk_interactive_uitest.cc
@@ -13,11 +13,11 @@
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/interactive_test_utils.h"
 #include "chrome/test/base/ui_test_utils.h"
-#include "net/test/spawned_test_server/spawned_test_server.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
 
 namespace {
 
-const char kSimplePage[] = "404_is_enough_for_us.html";
+const char kSimplePage[] = "/404_is_enough_for_us.html";
 
 void OnClicked(GtkWidget* widget, bool* clicked_bit) {
   *clicked_bit = true;
@@ -31,14 +31,14 @@
 // Makes sure that when you switch back to an NTP with an active findbar,
 // the findbar is above the floating bookmark bar.
 IN_PROC_BROWSER_TEST_F(BookmarkBarGtkInteractiveUITest, FindBarTest) {
-  ASSERT_TRUE(test_server()->Start());
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
 
   // Create new tab; open findbar.
   chrome::NewTab(browser());
   chrome::Find(browser());
 
   // Create new tab with an arbitrary URL.
-  GURL url = test_server()->GetURL(kSimplePage);
+  GURL url = embedded_test_server()->GetURL(kSimplePage);
   chrome::AddSelectedTabWithURL(browser(), url, content::PAGE_TRANSITION_TYPED);
 
   // Switch back to the NTP with the active findbar.
@@ -58,7 +58,7 @@
 // Disabled due to http://crbug.com/88933.
 IN_PROC_BROWSER_TEST_F(
     BookmarkBarGtkInteractiveUITest, DISABLED_ClickOnFloatingTest) {
-  ASSERT_TRUE(test_server()->Start());
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
 
   GtkWidget* other_bookmarks =
       ViewIDUtil::GetWidget(GTK_WIDGET(browser()->window()->GetNativeWindow()),
diff --git a/chrome/browser/ui/gtk/bookmarks/bookmark_bar_gtk_unittest.cc b/chrome/browser/ui/gtk/bookmarks/bookmark_bar_gtk_unittest.cc
index debbce8..c8330ba 100644
--- a/chrome/browser/ui/gtk/bookmarks/bookmark_bar_gtk_unittest.cc
+++ b/chrome/browser/ui/gtk/bookmarks/bookmark_bar_gtk_unittest.cc
@@ -42,7 +42,7 @@
     ui_test_utils::WaitForBookmarkModelToLoad(model_);
 
     Browser::CreateParams native_params(profile_.get(),
-                                        chrome::HOST_DESKTOP_TYPE_NATIVE);
+                                        chrome::GetActiveDesktop());
     browser_.reset(
         chrome::CreateBrowserWithTestWindowForParams(&native_params));
     origin_provider_.reset(new EmptyTabstripOriginProvider);
diff --git a/chrome/browser/ui/gtk/bookmarks/bookmark_bubble_gtk.cc b/chrome/browser/ui/gtk/bookmarks/bookmark_bubble_gtk.cc
index a5592d4..7125577 100644
--- a/chrome/browser/ui/gtk/bookmarks/bookmark_bubble_gtk.cc
+++ b/chrome/browser/ui/gtk/bookmarks/bookmark_bubble_gtk.cc
@@ -13,11 +13,11 @@
 #include "base/message_loop.h"
 #include "base/strings/string16.h"
 #include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/bookmarks/bookmark_editor.h"
 #include "chrome/browser/bookmarks/bookmark_model.h"
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
 #include "chrome/browser/bookmarks/bookmark_utils.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/bookmarks/bookmark_editor.h"
 #include "chrome/browser/ui/bookmarks/recently_used_folders_combo_model.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_list.h"
diff --git a/chrome/browser/ui/gtk/bookmarks/bookmark_editor_gtk.cc b/chrome/browser/ui/gtk/bookmarks/bookmark_editor_gtk.cc
index a4e2f14..aa6030b 100644
--- a/chrome/browser/ui/gtk/bookmarks/bookmark_editor_gtk.cc
+++ b/chrome/browser/ui/gtk/bookmarks/bookmark_editor_gtk.cc
@@ -549,7 +549,7 @@
   if (!show_tree_ || !selected_parent) {
     // TODO: this is wrong. Just because there is no selection doesn't mean new
     // folders weren't added.
-    bookmark_utils::ApplyEditsWithNoFolderChange(
+    BookmarkEditor::ApplyEditsWithNoFolderChange(
         bb_model_, parent_, details_, new_title, new_url);
     return;
   }
@@ -572,7 +572,7 @@
     return;
   }
 
-  bookmark_utils::ApplyEditsWithPossibleFolderChange(
+  BookmarkEditor::ApplyEditsWithPossibleFolderChange(
       bb_model_, new_parent, details_, new_title, new_url);
 
   // Remove the folders that were removed. This has to be done after all the
diff --git a/chrome/browser/ui/gtk/bookmarks/bookmark_editor_gtk.h b/chrome/browser/ui/gtk/bookmarks/bookmark_editor_gtk.h
index 798d6ed..59e3889 100644
--- a/chrome/browser/ui/gtk/bookmarks/bookmark_editor_gtk.h
+++ b/chrome/browser/ui/gtk/bookmarks/bookmark_editor_gtk.h
@@ -10,8 +10,8 @@
 #include "base/gtest_prod_util.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/strings/string16.h"
-#include "chrome/browser/bookmarks/bookmark_editor.h"
 #include "chrome/browser/bookmarks/bookmark_model_observer.h"
+#include "chrome/browser/ui/bookmarks/bookmark_editor.h"
 #include "ui/base/glib/glib_integers.h"
 #include "ui/base/gtk/gtk_signal.h"
 
diff --git a/chrome/browser/ui/gtk/browser_titlebar.cc b/chrome/browser/ui/gtk/browser_titlebar.cc
index b81f6eb..0780f19 100644
--- a/chrome/browser/ui/gtk/browser_titlebar.cc
+++ b/chrome/browser/ui/gtk/browser_titlebar.cc
@@ -784,7 +784,7 @@
     gtk_widget_modify_bg(
         GTK_WIDGET(avatar_label_bg_), GTK_STATE_NORMAL, &label_background);
     char* markup = g_markup_printf_escaped(
-        "<span size='small' weight='bold'>%s</span>",
+        "<span size='small'>%s</span>",
         l10n_util::GetStringUTF8(IDS_MANAGED_USER_AVATAR_LABEL).c_str());
     gtk_label_set_markup(GTK_LABEL(avatar_label_), markup);
     g_free(markup);
@@ -820,7 +820,7 @@
   Profile* profile = browser_window_->browser()->profile();
   if (ManagedUserService::ProfileIsManaged(profile)) {
     avatar_label_ = gtk_label_new(NULL);
-    gtk_misc_set_padding(GTK_MISC(avatar_label_), 2, 2);
+    gtk_misc_set_padding(GTK_MISC(avatar_label_), 10, 2);
     avatar_label_bg_ = gtk_event_box_new();
     gtk_container_add(GTK_CONTAINER(avatar_label_bg_), avatar_label_);
     g_signal_connect(avatar_label_bg_, "button-press-event",
diff --git a/chrome/browser/ui/gtk/browser_window_gtk.cc b/chrome/browser/ui/gtk/browser_window_gtk.cc
index f343c44..d3ab2c8 100644
--- a/chrome/browser/ui/gtk/browser_window_gtk.cc
+++ b/chrome/browser/ui/gtk/browser_window_gtk.cc
@@ -24,7 +24,7 @@
 #include "base/prefs/pref_service.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/download/download_item_model.h"
@@ -1443,15 +1443,21 @@
   if (!browser_->ShouldCloseWindow())
     return false;
 
+  bool fast_tab_closing_enabled =
+      CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableFastUnload);
+
   if (!browser_->tab_strip_model()->empty()) {
     // Tab strip isn't empty.  Hide the window (so it appears to have closed
     // immediately) and close all the tabs, allowing the renderers to shut
     // down. When the tab strip is empty we'll be called back again.
     gtk_widget_hide(GTK_WIDGET(window_));
     browser_->OnWindowClosing();
-    browser_->tab_strip_model()->CloseAllTabs();
+
+    if (fast_tab_closing_enabled)
+      browser_->tab_strip_model()->CloseAllTabs();
     return false;
-  } else if (!browser_->HasCompletedUnloadProcessing()) {
+  } else if (fast_tab_closing_enabled &&
+      !browser_->HasCompletedUnloadProcessing()) {
     // The browser needs to finish running unload handlers.
     // Hide the window (so it appears to have closed immediately), and
     // the browser will call us back again when it is ready to close.
diff --git a/chrome/browser/ui/gtk/browser_window_gtk.h b/chrome/browser/ui/gtk/browser_window_gtk.h
index 4cd6ad6..40f763f 100644
--- a/chrome/browser/ui/gtk/browser_window_gtk.h
+++ b/chrome/browser/ui/gtk/browser_window_gtk.h
@@ -13,7 +13,7 @@
 #include "base/compiler_specific.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/prefs/pref_member.h"
-#include "base/timer.h"
+#include "base/timer/timer.h"
 #include "build/build_config.h"
 #include "chrome/browser/devtools/devtools_window.h"
 #include "chrome/browser/extensions/extension_keybinding_registry.h"
diff --git a/chrome/browser/ui/gtk/bubble/bubble_gtk.cc b/chrome/browser/ui/gtk/bubble/bubble_gtk.cc
index f8c2064..0b023b0 100644
--- a/chrome/browser/ui/gtk/bubble/bubble_gtk.cc
+++ b/chrome/browser/ui/gtk/bubble/bubble_gtk.cc
@@ -539,6 +539,7 @@
 }
 
 void BubbleGtk::StopGrabbingInput() {
+  UngrabPointerAndKeyboard();
   if (!grab_input_)
     return;
   grab_input_ = false;
@@ -598,6 +599,12 @@
   }
 }
 
+void BubbleGtk::UngrabPointerAndKeyboard() {
+  gdk_pointer_ungrab(GDK_CURRENT_TIME);
+  if (grab_input_)
+    gdk_keyboard_ungrab(GDK_CURRENT_TIME);
+}
+
 gboolean BubbleGtk::OnGtkAccelerator(GtkAccelGroup* group,
                                      GObject* acceleratable,
                                      guint keyval,
diff --git a/chrome/browser/ui/gtk/bubble/bubble_gtk.h b/chrome/browser/ui/gtk/bubble/bubble_gtk.h
index 111654d..f800278 100644
--- a/chrome/browser/ui/gtk/bubble/bubble_gtk.h
+++ b/chrome/browser/ui/gtk/bubble/bubble_gtk.h
@@ -172,6 +172,11 @@
   // sure that we have the input focus.
   void GrabPointerAndKeyboard();
 
+  // Ungrab (in the X sense) the pointer and keyboard.  This is needed to make
+  // sure that we release the input focus, e.g. when an extension popup
+  // is inspected by the DevTools.
+  void UngrabPointerAndKeyboard();
+
   CHROMEG_CALLBACK_3(BubbleGtk, gboolean, OnGtkAccelerator, GtkAccelGroup*,
                      GObject*, guint, GdkModifierType);
 
diff --git a/chrome/browser/ui/gtk/certificate_viewer_gtk.cc b/chrome/browser/ui/gtk/certificate_viewer_gtk.cc
index b76b660..f0b8672 100644
--- a/chrome/browser/ui/gtk/certificate_viewer_gtk.cc
+++ b/chrome/browser/ui/gtk/certificate_viewer_gtk.cc
@@ -12,7 +12,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/certificate_viewer.h"
 #include "chrome/browser/ui/certificate_dialogs.h"
 #include "chrome/browser/ui/gtk/gtk_util.h"
diff --git a/chrome/browser/ui/gtk/create_application_shortcuts_dialog_gtk.cc b/chrome/browser/ui/gtk/create_application_shortcuts_dialog_gtk.cc
index d8fdd0f..48eb200 100644
--- a/chrome/browser/ui/gtk/create_application_shortcuts_dialog_gtk.cc
+++ b/chrome/browser/ui/gtk/create_application_shortcuts_dialog_gtk.cc
@@ -347,7 +347,9 @@
     const ShellIntegration::ShortcutLocations& creation_locations) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
 
-  if (web_app::CreateShortcutsOnFileThread(shortcut_info, creation_locations)) {
+  if (web_app::CreateShortcutsOnFileThread(
+          shortcut_info, creation_locations,
+          web_app::ALLOW_DUPLICATE_SHORTCUTS)) {
     Release();
   } else {
     BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
diff --git a/chrome/browser/ui/gtk/download/download_item_gtk.cc b/chrome/browser/ui/gtk/download/download_item_gtk.cc
index 7577367..860f011 100644
--- a/chrome/browser/ui/gtk/download/download_item_gtk.cc
+++ b/chrome/browser/ui/gtk/download/download_item_gtk.cc
@@ -10,7 +10,7 @@
 #include "base/metrics/histogram.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/download/chrome_download_manager_delegate.h"
 #include "chrome/browser/download/download_item_model.h"
diff --git a/chrome/browser/ui/gtk/download/download_item_gtk.h b/chrome/browser/ui/gtk/download/download_item_gtk.h
index c71905d..e71d325 100644
--- a/chrome/browser/ui/gtk/download/download_item_gtk.h
+++ b/chrome/browser/ui/gtk/download/download_item_gtk.h
@@ -12,8 +12,8 @@
 #include "base/compiler_specific.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
-#include "base/time.h"
-#include "base/timer.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
 #include "chrome/browser/download/download_item_model.h"
 #include "chrome/browser/icon_manager.h"
 #include "chrome/common/cancelable_task_tracker.h"
diff --git a/chrome/browser/ui/gtk/extensions/media_galleries_dialog_gtk.cc b/chrome/browser/ui/gtk/extensions/media_galleries_dialog_gtk.cc
index ef81871..aaf3130 100644
--- a/chrome/browser/ui/gtk/extensions/media_galleries_dialog_gtk.cc
+++ b/chrome/browser/ui/gtk/extensions/media_galleries_dialog_gtk.cc
@@ -127,19 +127,15 @@
                              checkbox_container);
   }
 
-  // Holds the "add gallery" and cancel/confirm buttons.
-  GtkWidget* add_folder_area = gtk_hbox_new(FALSE, ui::kControlSpacing);
-  gtk_box_pack_start(GTK_BOX(contents_.get()), add_folder_area,
-                     FALSE, FALSE, 0);
+  GtkWidget* bottom_area = gtk_hbox_new(FALSE, ui::kControlSpacing);
 
   // Add gallery button.
   GtkWidget* add_folder = gtk_button_new_with_label(
       l10n_util::GetStringUTF8(IDS_MEDIA_GALLERIES_DIALOG_ADD_GALLERY).c_str());
   g_signal_connect(add_folder, "clicked", G_CALLBACK(OnAddFolderThunk), this);
-  gtk_box_pack_start(GTK_BOX(add_folder_area), add_folder, FALSE, FALSE, 0);
+  gtk_box_pack_start(GTK_BOX(bottom_area), add_folder, FALSE, FALSE, 0);
 
   // Confirm/cancel button.
-  GtkWidget* bottom_area = gtk_hbox_new(FALSE, ui::kControlSpacing);
   confirm_ = gtk_button_new_with_label(l10n_util::GetStringUTF8(
       IDS_MEDIA_GALLERIES_DIALOG_CONFIRM).c_str());
   gtk_button_set_image(
@@ -180,8 +176,7 @@
   g_signal_connect(widget, "toggled", G_CALLBACK(OnToggledThunk), this);
   gtk_box_pack_start(GTK_BOX(checkbox_container), hbox, FALSE, FALSE, 0);
   gtk_box_pack_start(GTK_BOX(hbox), widget, FALSE, FALSE, 0);
-  std::string details = UTF16ToUTF8(
-      MediaGalleriesDialogController::GetGalleryAdditionalDetails(gallery));
+  std::string details = UTF16ToUTF8(gallery.GetGalleryAdditionalDetails());
   GtkWidget* details_label = gtk_label_new(details.c_str());
   gtk_label_set_line_wrap(GTK_LABEL(details_label), FALSE);
   gtk_util::SetLabelColor(details_label, &kDeemphasizedTextColor);
@@ -190,14 +185,11 @@
   gtk_widget_show(hbox);
   checkbox_map_[gallery.pref_id] = widget;
 
-  std::string tooltip_text = UTF16ToUTF8(
-      MediaGalleriesDialogController::GetGalleryTooltip(gallery));
+  std::string tooltip_text = UTF16ToUTF8(gallery.GetGalleryTooltip());
   gtk_widget_set_tooltip_text(widget, tooltip_text.c_str());
 
   gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), permitted);
-  std::string label = UTF16ToUTF8(
-      MediaGalleriesDialogController::GetGalleryDisplayNameNoAttachment(
-          gallery));
+  std::string label = UTF16ToUTF8(gallery.GetGalleryDisplayName());
   gtk_button_set_label(GTK_BUTTON(widget), label.c_str());
 }
 
diff --git a/chrome/browser/ui/gtk/extensions/native_app_window_gtk.cc b/chrome/browser/ui/gtk/extensions/native_app_window_gtk.cc
index b715652..76e5b04 100644
--- a/chrome/browser/ui/gtk/extensions/native_app_window_gtk.cc
+++ b/chrome/browser/ui/gtk/extensions/native_app_window_gtk.cc
@@ -20,6 +20,8 @@
 #include "ui/gfx/image/image.h"
 #include "ui/gfx/rect.h"
 
+using apps::ShellWindow;
+
 namespace {
 
 // The timeout in milliseconds before we'll get the true window position with
diff --git a/chrome/browser/ui/gtk/extensions/native_app_window_gtk.h b/chrome/browser/ui/gtk/extensions/native_app_window_gtk.h
index e01f9bd..c1c018e 100644
--- a/chrome/browser/ui/gtk/extensions/native_app_window_gtk.h
+++ b/chrome/browser/ui/gtk/extensions/native_app_window_gtk.h
@@ -7,10 +7,10 @@
 
 #include <gtk/gtk.h>
 
+#include "apps/shell_window.h"
 #include "base/observer_list.h"
-#include "base/timer.h"
+#include "base/timer/timer.h"
 #include "chrome/browser/ui/extensions/native_app_window.h"
-#include "chrome/browser/ui/extensions/shell_window.h"
 #include "chrome/browser/ui/gtk/extensions/extension_view_gtk.h"
 #include "third_party/skia/include/core/SkRegion.h"
 #include "ui/base/gtk/gtk_signal.h"
@@ -28,8 +28,8 @@
                            public ExtensionViewGtk::Container,
                            public ui::ActiveWindowWatcherXObserver {
  public:
-  NativeAppWindowGtk(ShellWindow* shell_window,
-                     const ShellWindow::CreateParams& params);
+  NativeAppWindowGtk(apps::ShellWindow* shell_window,
+                     const apps::ShellWindow::CreateParams& params);
 
   // ui::BaseWindow implementation.
   virtual bool IsActive() const OVERRIDE;
@@ -105,7 +105,7 @@
 
   void OnDebouncedBoundsChanged();
 
-  ShellWindow* shell_window_;  // weak - ShellWindow owns NativeAppWindow.
+  apps::ShellWindow* shell_window_;  // weak - ShellWindow owns NativeAppWindow.
 
   GtkWindow* window_;
   GdkWindowState state_;
diff --git a/chrome/browser/ui/gtk/gtk_theme_service.cc b/chrome/browser/ui/gtk/gtk_theme_service.cc
index 5ab6203..143ddcb 100644
--- a/chrome/browser/ui/gtk/gtk_theme_service.cc
+++ b/chrome/browser/ui/gtk/gtk_theme_service.cc
@@ -15,6 +15,7 @@
 #include "base/nix/xdg_util.h"
 #include "base/prefs/pref_service.h"
 #include "base/stl_util.h"
+#include "chrome/browser/managed_mode/managed_user_service.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/themes/theme_properties.h"
 #include "chrome/browser/themes/theme_service_factory.h"
@@ -308,6 +309,14 @@
 }
 
 gfx::Image GtkThemeService::GetImageNamed(int id) const {
+  // TODO(akuegel): Remove this once we have the default managed user theme.
+  if (ManagedUserService::ProfileIsManaged(profile())) {
+    if (id == IDR_THEME_FRAME)
+      id = IDR_MANAGED_USER_THEME_FRAME;
+    else if (id == IDR_THEME_FRAME_INACTIVE)
+      id = IDR_MANAGED_USER_THEME_FRAME_INACTIVE;
+  }
+
   // Try to get our cached version:
   ImageCache::const_iterator it = gtk_images_.find(id);
   if (it != gtk_images_.end())
@@ -324,6 +333,14 @@
 }
 
 SkColor GtkThemeService::GetColor(int id) const {
+  // TODO(akuegel): Remove this once we have the default managed user theme.
+  if (ManagedUserService::ProfileIsManaged(profile())) {
+    if (id == ThemeProperties::COLOR_FRAME)
+      id = ThemeProperties::COLOR_FRAME_MANAGED_USER;
+    else if (id == ThemeProperties::COLOR_FRAME_INACTIVE)
+      id = ThemeProperties::COLOR_FRAME_MANAGED_USER_INACTIVE;
+  }
+
   if (use_gtk_) {
     ColorMap::const_iterator it = colors_.find(id);
     if (it != colors_.end())
diff --git a/chrome/browser/ui/gtk/gtk_util.cc b/chrome/browser/ui/gtk/gtk_util.cc
index 0e5a902..df8a277 100644
--- a/chrome/browser/ui/gtk/gtk_util.cc
+++ b/chrome/browser/ui/gtk/gtk_util.cc
@@ -804,18 +804,18 @@
     return false;
 
   GdkWindow* gdk_window = gtk_widget_get_window(widget);
-  if (!gdk_pointer_grab(gdk_window,
-                        TRUE,
-                        GdkEventMask(GDK_BUTTON_PRESS_MASK |
-                                     GDK_BUTTON_RELEASE_MASK |
-                                     GDK_ENTER_NOTIFY_MASK |
-                                     GDK_LEAVE_NOTIFY_MASK |
-                                     GDK_POINTER_MOTION_MASK),
-                        NULL, NULL, time) == 0) {
+  if (gdk_pointer_grab(gdk_window,
+                       TRUE,
+                       GdkEventMask(GDK_BUTTON_PRESS_MASK |
+                                    GDK_BUTTON_RELEASE_MASK |
+                                    GDK_ENTER_NOTIFY_MASK |
+                                    GDK_LEAVE_NOTIFY_MASK |
+                                    GDK_POINTER_MOTION_MASK),
+                       NULL, NULL, time) != 0) {
     return false;
   }
 
-  if (!gdk_keyboard_grab(gdk_window, TRUE, time) == 0) {
+  if (gdk_keyboard_grab(gdk_window, TRUE, time) != 0) {
     gdk_display_pointer_ungrab(gdk_drawable_get_display(gdk_window), time);
     return false;
   }
diff --git a/chrome/browser/ui/gtk/omnibox/omnibox_view_gtk.cc b/chrome/browser/ui/gtk/omnibox/omnibox_view_gtk.cc
index 9e99690..a824049 100644
--- a/chrome/browser/ui/gtk/omnibox/omnibox_view_gtk.cc
+++ b/chrome/browser/ui/gtk/omnibox/omnibox_view_gtk.cc
@@ -1238,7 +1238,7 @@
   g_free(text);
 
   // Copy URL menu item.
-  if (chrome::IsQueryExtractionEnabled(browser_->profile())) {
+  if (chrome::IsQueryExtractionEnabled()) {
     GtkWidget* copy_url_menuitem = gtk_menu_item_new_with_mnemonic(
         ui::ConvertAcceleratorsFromWindowsStyle(
             l10n_util::GetStringUTF8(IDS_COPY_URL)).c_str());
diff --git a/chrome/browser/ui/gtk/panels/panel_gtk.cc b/chrome/browser/ui/gtk/panels/panel_gtk.cc
index 4361cf9..26ae46d 100644
--- a/chrome/browser/ui/gtk/panels/panel_gtk.cc
+++ b/chrome/browser/ui/gtk/panels/panel_gtk.cc
@@ -195,7 +195,7 @@
   frame_size.SetSize(new_size.width(), new_size.height());
 }
 
-}
+}  // namespace
 
 // static
 NativePanel* Panel::CreateNativePanel(Panel* panel,
@@ -608,7 +608,30 @@
   if (event->type != GDK_BUTTON_PRESS)
     return TRUE;
 
-  gdk_window_raise(gtk_widget_get_window(GTK_WIDGET(window_)));
+  // If the panel is in a stack, bring all other panels in the stack to the
+  // top.
+  StackedPanelCollection* stack = panel_->stack();
+  if (stack) {
+    for (StackedPanelCollection::Panels::const_iterator iter =
+             stack->panels().begin();
+         iter != stack->panels().end(); ++iter) {
+      Panel* panel = *iter;
+      GtkWindow* gtk_window = panel->GetNativeWindow();
+      // If a panel is collapsed, we make it not to take focus. For such window,
+      // it cannot be brought to the top by calling gdk_window_raise. To work
+      // around this issue, we make it always-on-top first and then put it back
+      // to normal. Note that this trick has been done for all panels in the
+      // stack, regardless of whether it is collapsed or not.
+      // There is one side-effect to this approach: if the panel being pressed
+      // on is collapsed, clicking on the client area of the last active
+      // window will not raise it above these panels.
+      gtk_window_set_keep_above(gtk_window, true);
+      gtk_window_set_keep_above(gtk_window, false);
+    }
+  } else {
+    gdk_window_raise(gtk_widget_get_window(GTK_WIDGET(window_)));
+  }
+
   EnsureDragHelperCreated();
   drag_helper_->InitialTitlebarMousePress(event, titlebar_->widget());
   return TRUE;
diff --git a/chrome/browser/ui/gtk/panels/panel_gtk.h b/chrome/browser/ui/gtk/panels/panel_gtk.h
index 8b76023..e3b35e6 100644
--- a/chrome/browser/ui/gtk/panels/panel_gtk.h
+++ b/chrome/browser/ui/gtk/panels/panel_gtk.h
@@ -10,7 +10,7 @@
 
 #include "base/basictypes.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/timer.h"
+#include "base/timer/timer.h"
 #include "chrome/browser/ui/panels/native_panel.h"
 #include "chrome/browser/ui/panels/panel_constants.h"
 #include "ui/base/gtk/gtk_signal.h"
diff --git a/chrome/browser/ui/gtk/panels/panel_stack_window_gtk.cc b/chrome/browser/ui/gtk/panels/panel_stack_window_gtk.cc
index 395a9af..dfdde74 100644
--- a/chrome/browser/ui/gtk/panels/panel_stack_window_gtk.cc
+++ b/chrome/browser/ui/gtk/panels/panel_stack_window_gtk.cc
@@ -220,6 +220,7 @@
   window_ = GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL));
   gtk_window_set_decorated(window_, false);
   gtk_window_set_resizable(window_, false);
+  gtk_window_set_focus_on_map(window_, false);
   gtk_widget_show(GTK_WIDGET(window_));
   gdk_window_move_resize(gtk_widget_get_window(GTK_WIDGET(window_)),
       panel->GetBounds().x(), panel->GetBounds().y(), 1, 1);
diff --git a/chrome/browser/ui/gtk/password_generation_bubble_gtk.cc b/chrome/browser/ui/gtk/password_generation_bubble_gtk.cc
index 70be410..5086b87 100644
--- a/chrome/browser/ui/gtk/password_generation_bubble_gtk.cc
+++ b/chrome/browser/ui/gtk/password_generation_bubble_gtk.cc
@@ -14,7 +14,7 @@
 #include "chrome/browser/ui/gtk/gtk_theme_service.h"
 #include "chrome/browser/ui/gtk/gtk_util.h"
 #include "chrome/common/url_constants.h"
-#include "components/autofill/browser/password_generator.h"
+#include "components/autofill/core/browser/password_generator.h"
 #include "components/autofill/core/common/autofill_messages.h"
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/web_contents.h"
diff --git a/chrome/browser/ui/gtk/protocol_dialog_gtk.h b/chrome/browser/ui/gtk/protocol_dialog_gtk.h
index 9ee746f..0685b3e 100644
--- a/chrome/browser/ui/gtk/protocol_dialog_gtk.h
+++ b/chrome/browser/ui/gtk/protocol_dialog_gtk.h
@@ -7,7 +7,7 @@
 
 #include "base/basictypes.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/ui/protocol_dialog_delegate.h"
 #include "googleurl/src/gurl.h"
 #include "ui/base/gtk/gtk_signal.h"
diff --git a/chrome/browser/ui/gtk/reload_button_gtk.h b/chrome/browser/ui/gtk/reload_button_gtk.h
index 7527c37..8d30745 100644
--- a/chrome/browser/ui/gtk/reload_button_gtk.h
+++ b/chrome/browser/ui/gtk/reload_button_gtk.h
@@ -9,14 +9,14 @@
 
 #include "base/basictypes.h"
 #include "base/compiler_specific.h"
-#include "base/timer.h"
+#include "base/timer/timer.h"
 #include "chrome/browser/ui/gtk/custom_button.h"
 #include "chrome/browser/ui/gtk/menu_gtk.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
-#include "ui/base/models/simple_menu_model.h"
 #include "ui/base/gtk/gtk_signal.h"
 #include "ui/base/gtk/owned_widget_gtk.h"
+#include "ui/base/models/simple_menu_model.h"
 
 class Browser;
 class GtkThemeService;
diff --git a/chrome/browser/ui/gtk/status_bubble_gtk.h b/chrome/browser/ui/gtk/status_bubble_gtk.h
index 8cc71a6..dbc2b5b 100644
--- a/chrome/browser/ui/gtk/status_bubble_gtk.h
+++ b/chrome/browser/ui/gtk/status_bubble_gtk.h
@@ -11,7 +11,7 @@
 
 #include "base/compiler_specific.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/timer.h"
+#include "base/timer/timer.h"
 #include "chrome/browser/ui/status_bubble.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
diff --git a/chrome/browser/ui/gtk/tab_contents/chrome_web_contents_view_delegate_gtk.cc b/chrome/browser/ui/gtk/tab_contents/chrome_web_contents_view_delegate_gtk.cc
index 26d5f50..45a32e0 100644
--- a/chrome/browser/ui/gtk/tab_contents/chrome_web_contents_view_delegate_gtk.cc
+++ b/chrome/browser/ui/gtk/tab_contents/chrome_web_contents_view_delegate_gtk.cc
@@ -136,9 +136,9 @@
   content::RenderWidgetHostView* view = NULL;
   if (params.custom_context.render_widget_id !=
       content::CustomContextMenuContext::kCurrentRenderWidget) {
-    content::RenderWidgetHost* host =
-        web_contents_->GetRenderProcessHost()->GetRenderWidgetHostByID(
-            params.custom_context.render_widget_id);
+    content::RenderWidgetHost* host = content::RenderWidgetHost::FromID(
+        web_contents_->GetRenderProcessHost()->GetID(),
+        params.custom_context.render_widget_id);
     if (!host) {
       NOTREACHED();
       return;
diff --git a/chrome/browser/ui/gtk/tab_modal_confirm_dialog_gtk.cc b/chrome/browser/ui/gtk/tab_modal_confirm_dialog_gtk.cc
index ff4b261..f96d8a6 100644
--- a/chrome/browser/ui/gtk/tab_modal_confirm_dialog_gtk.cc
+++ b/chrome/browser/ui/gtk/tab_modal_confirm_dialog_gtk.cc
@@ -6,7 +6,12 @@
 
 #include "base/message_loop.h"
 #include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_dialogs.h"
+#include "chrome/browser/ui/browser_finder.h"
+#include "chrome/browser/ui/gtk/event_utils.h"
+#include "chrome/browser/ui/gtk/gtk_theme_service.h"
 #include "chrome/browser/ui/tab_modal_confirm_dialog_delegate.h"
 #include "components/web_modal/web_contents_modal_dialog_manager.h"
 #include "content/public/browser/notification_types.h"
@@ -37,6 +42,7 @@
                                                      GTK_ICON_SIZE_DIALOG);
   gtk_misc_set_alignment(GTK_MISC(image), 0.5, 0.0);
 
+  gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0);
   gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
   gtk_label_set_selectable(GTK_LABEL(label), TRUE);
 
@@ -44,8 +50,26 @@
 
   gtk_box_pack_start(GTK_BOX(hbox), image, FALSE, FALSE, 0);
 
-  gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);
+  GtkWidget* vbox = gtk_vbox_new(FALSE, ui::kContentAreaSpacing);
 
+  gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 0);
+
+  string16 link_text = delegate->GetLinkText();
+  if (!link_text.empty()) {
+    Browser* browser = chrome::FindBrowserWithWebContents(web_contents);
+    GtkThemeService* theme_service = GtkThemeService::GetFrom(
+        browser->profile());
+
+    GtkWidget* link = theme_service->BuildChromeLinkButton(UTF16ToUTF8(
+        link_text.c_str()));
+    g_signal_connect(link, "clicked", G_CALLBACK(OnLinkClickedThunk), this);
+    GtkWidget* link_align = gtk_alignment_new(0, 0, 0, 0);
+    gtk_container_add(GTK_CONTAINER(link_align), link);
+
+    gtk_box_pack_end(GTK_BOX(vbox), link_align, FALSE, FALSE, 0);
+  }
+
+  gtk_box_pack_start(GTK_BOX(hbox), vbox, TRUE, TRUE, 0);
   gtk_box_pack_start(GTK_BOX(dialog_), hbox, FALSE, FALSE, 0);
 
   GtkWidget* buttonBox = gtk_hbutton_box_new();
@@ -107,6 +131,10 @@
   delegate_->Cancel();
 }
 
+void TabModalConfirmDialogGtk::OnLinkClicked(GtkWidget* widget) {
+  delegate_->LinkClicked(event_utils::DispositionForCurrentButtonPressEvent());
+}
+
 void TabModalConfirmDialogGtk::OnDestroy(GtkWidget* widget) {
   delete this;
 }
diff --git a/chrome/browser/ui/gtk/tab_modal_confirm_dialog_gtk.h b/chrome/browser/ui/gtk/tab_modal_confirm_dialog_gtk.h
index 543d148..8c7104a 100644
--- a/chrome/browser/ui/gtk/tab_modal_confirm_dialog_gtk.h
+++ b/chrome/browser/ui/gtk/tab_modal_confirm_dialog_gtk.h
@@ -45,6 +45,7 @@
   CHROMEGTK_CALLBACK_0(TabModalConfirmDialogGtk, void, OnAccept);
   CHROMEGTK_CALLBACK_0(TabModalConfirmDialogGtk, void, OnCancel);
   CHROMEGTK_CALLBACK_0(TabModalConfirmDialogGtk, void, OnDestroy);
+  CHROMEGTK_CALLBACK_0(TabModalConfirmDialogGtk, void, OnLinkClicked);
 
   scoped_ptr<TabModalConfirmDialogDelegate> delegate_;
 
diff --git a/chrome/browser/ui/gtk/tabs/dragged_tab_controller_gtk.h b/chrome/browser/ui/gtk/tabs/dragged_tab_controller_gtk.h
index 4e757c6..ad780c3 100644
--- a/chrome/browser/ui/gtk/tabs/dragged_tab_controller_gtk.h
+++ b/chrome/browser/ui/gtk/tabs/dragged_tab_controller_gtk.h
@@ -13,7 +13,7 @@
 #include "base/basictypes.h"
 #include "base/compiler_specific.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/timer.h"
+#include "base/timer/timer.h"
 #include "chrome/browser/ui/gtk/tabs/drag_data.h"
 #include "chrome/browser/ui/tabs/dock_info.h"
 #include "content/public/browser/notification_observer.h"
diff --git a/chrome/browser/ui/gtk/task_manager_gtk.cc b/chrome/browser/ui/gtk/task_manager_gtk.cc
index c765e3e..32cb85c 100644
--- a/chrome/browser/ui/gtk/task_manager_gtk.cc
+++ b/chrome/browser/ui/gtk/task_manager_gtk.cc
@@ -71,16 +71,12 @@
   kTaskManagerFPS,
   kTaskManagerSqliteMemoryUsed,
   kTaskManagerGoatsTeleported,
-  // Columns below this point are not visible in the task manager.
-  kTaskManagerBackgroundColor,
   kTaskManagerColumnCount,
 };
 
 const TaskManagerColumn kTaskManagerLastVisibleColumn =
     kTaskManagerGoatsTeleported;
 
-static const GdkColor kHighlightColor = GDK_COLOR_RGB(0xff, 0xfa, 0xcd);
-
 TaskManagerColumn TaskManagerResourceIDToColumnID(int id) {
   switch (id) {
     case IDS_TASK_MANAGER_TASK_COLUMN:
@@ -194,15 +190,9 @@
   gtk_tree_view_column_pack_start(column, image_renderer, FALSE);
   gtk_tree_view_column_add_attribute(column, image_renderer,
                                      "pixbuf", kTaskManagerIcon);
-  gtk_tree_view_column_add_attribute(column, image_renderer,
-                                     "cell-background-gdk",
-                                     kTaskManagerBackgroundColor);
   GtkCellRenderer* text_renderer = gtk_cell_renderer_text_new();
   gtk_tree_view_column_pack_start(column, text_renderer, TRUE);
   gtk_tree_view_column_add_attribute(column, text_renderer, "markup", colid);
-  gtk_tree_view_column_add_attribute(column, text_renderer,
-                                     "cell-background-gdk",
-                                     kTaskManagerBackgroundColor);
   gtk_tree_view_column_set_resizable(column, TRUE);
   // This is temporary: we'll turn expanding off after getting the size.
   gtk_tree_view_column_set_expand(column, TRUE);
@@ -218,7 +208,6 @@
       GTK_TREE_VIEW(treeview), -1,
       name, renderer,
       "text", colid,
-      "cell-background-gdk", kTaskManagerBackgroundColor,
       NULL);
   GtkTreeViewColumn* column = gtk_tree_view_get_column(
       GTK_TREE_VIEW(treeview), TreeViewColumnIndexFromID(colid));
@@ -315,15 +304,14 @@
   DISALLOW_COPY_AND_ASSIGN(ContextMenuController);
 };
 
-TaskManagerGtk::TaskManagerGtk(bool highlight_background_resources)
+TaskManagerGtk::TaskManagerGtk()
   : task_manager_(TaskManager::GetInstance()),
     model_(TaskManager::GetInstance()->model()),
     dialog_(NULL),
     treeview_(NULL),
     process_list_(NULL),
     process_count_(0),
-    ignore_selection_changed_(false),
-    highlight_background_resources_(highlight_background_resources) {
+    ignore_selection_changed_(false) {
   Init();
 }
 
@@ -427,19 +415,12 @@
 }
 
 // static
-void TaskManagerGtk::Show(bool highlight_background_resources) {
-  if (instance_ &&
-      instance_->highlight_background_resources_ !=
-          highlight_background_resources) {
-    instance_->Close();
-    DCHECK(!instance_);
-  }
-
+void TaskManagerGtk::Show() {
   if (instance_) {
     // If there's a Task manager window open already, just activate it.
     gtk_util::PresentWindow(instance_->dialog_, 0);
   } else {
-    instance_ = new TaskManagerGtk(highlight_background_resources);
+    instance_ = new TaskManagerGtk();
     instance_->model_->StartUpdating();
   }
 }
@@ -584,7 +565,7 @@
       GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
       G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
       G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
-      G_TYPE_STRING, G_TYPE_STRING, GDK_TYPE_COLOR);
+      G_TYPE_STRING, G_TYPE_STRING);
 
   // Support sorting on all columns.
   process_list_sort_ = gtk_tree_model_sort_new_with_model(
@@ -736,8 +717,6 @@
   std::string goats =
       GetModelText(row, IDS_TASK_MANAGER_GOATS_TELEPORTED_COLUMN);
 
-  bool is_background = model_->IsBackgroundResource(row) &&
-      highlight_background_resources_;
   gtk_list_store_set(process_list_, iter,
                      kTaskManagerIcon, icon,
                      kTaskManagerTask, task_markup,
@@ -755,8 +734,6 @@
                      kTaskManagerFPS, fps.c_str(),
                      kTaskManagerSqliteMemoryUsed, sqlite_memory.c_str(),
                      kTaskManagerGoatsTeleported, goats.c_str(),
-                     kTaskManagerBackgroundColor,
-                     is_background ? &kHighlightColor : NULL,
                      -1);
   g_object_unref(icon);
   g_free(task_markup);
@@ -969,8 +946,8 @@
 namespace chrome {
 
 // Declared in browser_dialogs.h.
-void ShowTaskManager(Browser* browser, bool highlight_background_resources) {
-  TaskManagerGtk::Show(highlight_background_resources);
+void ShowTaskManager(Browser* browser) {
+  TaskManagerGtk::Show();
 }
 
 }  // namespace chrome
diff --git a/chrome/browser/ui/gtk/task_manager_gtk.h b/chrome/browser/ui/gtk/task_manager_gtk.h
index 7df063d..cce76f9 100644
--- a/chrome/browser/ui/gtk/task_manager_gtk.h
+++ b/chrome/browser/ui/gtk/task_manager_gtk.h
@@ -21,7 +21,7 @@
 
 class TaskManagerGtk : public TaskManagerModelObserver {
  public:
-  explicit TaskManagerGtk(bool highlight_background_resources);
+  TaskManagerGtk();
   virtual ~TaskManagerGtk();
 
   // TaskManagerModelObserver
@@ -34,10 +34,8 @@
   void Close();
 
   // Creates the task manager if it doesn't exist; otherwise, it activates the
-  // existing task manager window. If |highlight_background_resources| is true,
-  // background resources are rendered with a yellow highlight (for the
-  // "View Background Pages" menu item).
-  static void Show(bool highlight_background_resources);
+  // existing task manager window.
+  static void Show();
 
  private:
   class ContextMenuController;
@@ -249,9 +247,6 @@
   // ourselves caused.
   bool ignore_selection_changed_;
 
-  // If true, background resources are rendered with a yellow highlight.
-  bool highlight_background_resources_;
-
   DISALLOW_COPY_AND_ASSIGN(TaskManagerGtk);
 };
 
diff --git a/chrome/browser/ui/gtk/zoom_bubble_gtk.h b/chrome/browser/ui/gtk/zoom_bubble_gtk.h
index 4a6b470..355109f 100644
--- a/chrome/browser/ui/gtk/zoom_bubble_gtk.h
+++ b/chrome/browser/ui/gtk/zoom_bubble_gtk.h
@@ -8,7 +8,7 @@
 #include <gtk/gtk.h>
 
 #include "base/basictypes.h"
-#include "base/timer.h"
+#include "base/timer/timer.h"
 #include "chrome/browser/ui/gtk/bubble/bubble_gtk.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
diff --git a/chrome/browser/ui/host_desktop.h b/chrome/browser/ui/host_desktop.h
index 1349da5..9728454 100644
--- a/chrome/browser/ui/host_desktop.h
+++ b/chrome/browser/ui/host_desktop.h
@@ -12,8 +12,9 @@
 namespace chrome {
 
 // A value that specifies what desktop environment hosts a particular piece of
-// UI. Please take a look at the following document for details on choosing the
-// right HostDesktopType:
+// UI. You should almost never manually hardcode one of these enums manually,
+// please refer to the following document for details on getting the right
+// HostDesktopType:
 // http://sites.google.com/a/chromium.org/dev/developers/design-documents/aura/multi-desktop
 enum HostDesktopType {
   HOST_DESKTOP_TYPE_FIRST = 0,
@@ -37,6 +38,9 @@
 
 // Returns the type of host desktop most likely to be in use.  This is the one
 // most recently activated by the user.
+// You should almost never use this outside of tests, please refer to the
+// following document for details on getting the right HostDesktopType:
+// http://sites.google.com/a/chromium.org/dev/developers/design-documents/aura/multi-desktop
 HostDesktopType GetActiveDesktop();
 
 }  // namespace chrome
diff --git a/chrome/browser/ui/hung_plugin_tab_helper.h b/chrome/browser/ui/hung_plugin_tab_helper.h
index 52dbfc2..4457797 100644
--- a/chrome/browser/ui/hung_plugin_tab_helper.h
+++ b/chrome/browser/ui/hung_plugin_tab_helper.h
@@ -9,8 +9,8 @@
 
 #include "base/memory/linked_ptr.h"
 #include "base/strings/string16.h"
-#include "base/time.h"
-#include "base/timer.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
 #include "content/public/browser/web_contents_observer.h"
diff --git a/chrome/browser/ui/libgtk2ui/gtk2_ui.cc b/chrome/browser/ui/libgtk2ui/gtk2_ui.cc
index 195460a..c249cc6 100644
--- a/chrome/browser/ui/libgtk2ui/gtk2_ui.cc
+++ b/chrome/browser/ui/libgtk2ui/gtk2_ui.cc
@@ -7,6 +7,7 @@
 #include <set>
 
 #include "base/command_line.h"
+#include "base/environment.h"
 #include "base/i18n/rtl.h"
 #include "base/logging.h"
 #include "base/nix/mime_util_xdg.h"
@@ -17,6 +18,7 @@
 #include "chrome/browser/ui/libgtk2ui/native_theme_gtk2.h"
 #include "chrome/browser/ui/libgtk2ui/select_file_dialog_impl.h"
 #include "chrome/browser/ui/libgtk2ui/skia_utils_gtk2.h"
+#include "chrome/browser/ui/libgtk2ui/unity_service.h"
 #include "grit/theme_resources.h"
 #include "grit/ui_resources.h"
 #include "third_party/skia/include/core/SkBitmap.h"
@@ -342,10 +344,42 @@
   return false;
 }
 
+bool Gtk2UI::HasCustomImage(int id) const {
+  return IsOverridableImage(id);
+}
+
 ui::NativeTheme* Gtk2UI::GetNativeTheme() const {
   return NativeThemeGtk2::instance();
 }
 
+bool Gtk2UI::GetDefaultUsesSystemTheme() const {
+  scoped_ptr<base::Environment> env(base::Environment::Create());
+
+  switch (base::nix::GetDesktopEnvironment(env.get())) {
+    case base::nix::DESKTOP_ENVIRONMENT_GNOME:
+    case base::nix::DESKTOP_ENVIRONMENT_UNITY:
+    case base::nix::DESKTOP_ENVIRONMENT_XFCE:
+      return true;
+    case base::nix::DESKTOP_ENVIRONMENT_KDE3:
+    case base::nix::DESKTOP_ENVIRONMENT_KDE4:
+    case base::nix::DESKTOP_ENVIRONMENT_OTHER:
+      return false;
+  }
+  // Unless GetDesktopEnvironment() badly misbehaves, this should never happen.
+  NOTREACHED();
+  return false;
+}
+
+void Gtk2UI::SetDownloadCount(int count) const {
+  if (unity::IsRunning())
+    unity::SetDownloadCount(count);
+}
+
+void Gtk2UI::SetProgressFraction(float percentage) const {
+  if (unity::IsRunning())
+    unity::SetProgressFraction(percentage);
+}
+
 ui::SelectFileDialog* Gtk2UI::CreateSelectFileDialog(
     ui::SelectFileDialog::Listener* listener,
     ui::SelectFilePolicy* policy) const {
diff --git a/chrome/browser/ui/libgtk2ui/gtk2_ui.h b/chrome/browser/ui/libgtk2ui/gtk2_ui.h
index 5d1d681..e53ff6b 100644
--- a/chrome/browser/ui/libgtk2ui/gtk2_ui.h
+++ b/chrome/browser/ui/libgtk2ui/gtk2_ui.h
@@ -42,7 +42,11 @@
   virtual bool UseNativeTheme() const OVERRIDE;
   virtual gfx::Image GetThemeImageNamed(int id) const OVERRIDE;
   virtual bool GetColor(int id, SkColor* color) const OVERRIDE;
+  virtual bool HasCustomImage(int id) const OVERRIDE;
   virtual ui::NativeTheme* GetNativeTheme() const OVERRIDE;
+  virtual bool GetDefaultUsesSystemTheme() const OVERRIDE;
+  virtual void SetDownloadCount(int count) const OVERRIDE;
+  virtual void SetProgressFraction(float percentage) const OVERRIDE;
 
  private:
   typedef std::map<int, SkColor> ColorMap;
diff --git a/chrome/browser/ui/libgtk2ui/gtk2_util.cc b/chrome/browser/ui/libgtk2ui/gtk2_util.cc
index ce542f6..eec6b1a 100644
--- a/chrome/browser/ui/libgtk2ui/gtk2_util.cc
+++ b/chrome/browser/ui/libgtk2ui/gtk2_util.cc
@@ -7,6 +7,7 @@
 #include <gtk/gtk.h>
 
 #include "base/command_line.h"
+#include "base/environment.h"
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
 #include "skia/ext/platform_canvas.h"
@@ -43,6 +44,23 @@
   CommonInitFromCommandLine(command_line, gtk_init);
 }
 
+// TODO(erg): This method was copied out of shell_integration_linux.cc. Because
+// of how this library is structured as a stand alone .so, we can't call code
+// from browser and above.
+std::string GetDesktopName(base::Environment* env) {
+#if defined(GOOGLE_CHROME_BUILD)
+  return "google-chrome.desktop";
+#else  // CHROMIUM_BUILD
+  // Allow $CHROME_DESKTOP to override the built-in value, so that development
+  // versions can set themselves as the default without interfering with
+  // non-official, packaged versions using the built-in value.
+  std::string name;
+  if (env->GetVar("CHROME_DESKTOP", &name) && !name.empty())
+    return name;
+  return "chromium-browser.desktop";
+#endif
+}
+
 const SkBitmap GdkPixbufToImageSkia(GdkPixbuf* pixbuf) {
   // TODO(erg): What do we do in the case where the pixbuf fails these dchecks?
   // I would prefer to use our gtk based canvas, but that would require
diff --git a/chrome/browser/ui/libgtk2ui/gtk2_util.h b/chrome/browser/ui/libgtk2ui/gtk2_util.h
index b1673df..77a1cbf 100644
--- a/chrome/browser/ui/libgtk2ui/gtk2_util.h
+++ b/chrome/browser/ui/libgtk2ui/gtk2_util.h
@@ -5,15 +5,24 @@
 #ifndef CHROME_BROWSER_UI_LIBGTK2UI_GTK2_UTIL_H_
 #define CHROME_BROWSER_UI_LIBGTK2UI_GTK2_UTIL_H_
 
+#include <string>
+
 typedef struct _GdkPixbuf GdkPixbuf;
 
 class CommandLine;
 class SkBitmap;
 
+namespace base {
+class Environment;
+}
+
 namespace libgtk2ui {
 
 void GtkInitFromCommandLine(const CommandLine& command_line);
 
+// Returns the name of the ".desktop" file associated with our running process.
+std::string GetDesktopName(base::Environment* env);
+
 const SkBitmap GdkPixbufToImageSkia(GdkPixbuf* pixbuf);
 
 }  // namespace libgtk2ui
diff --git a/chrome/browser/ui/libgtk2ui/libgtk2ui.gyp b/chrome/browser/ui/libgtk2ui/libgtk2ui.gyp
index 3e91f6d..efa61e9 100644
--- a/chrome/browser/ui/libgtk2ui/libgtk2ui.gyp
+++ b/chrome/browser/ui/libgtk2ui/libgtk2ui.gyp
@@ -50,6 +50,8 @@
         'select_file_dialog_impl_kde.cc',
         'skia_utils_gtk2.cc',
         'skia_utils_gtk2.h',
+        'unity_service.cc',
+        'unity_service.h',
       ],
     },
   ],
diff --git a/chrome/browser/ui/libgtk2ui/native_theme_gtk2.cc b/chrome/browser/ui/libgtk2ui/native_theme_gtk2.cc
index 680e39c..18b0f4b 100644
--- a/chrome/browser/ui/libgtk2ui/native_theme_gtk2.cc
+++ b/chrome/browser/ui/libgtk2ui/native_theme_gtk2.cc
@@ -218,8 +218,6 @@
       return GetEntryStyle()->text[GTK_STATE_SELECTED];
     case kColorId_TextfieldSelectionBackgroundFocused:
       return GetEntryStyle()->base[GTK_STATE_SELECTED];
-    case kColorId_TextfieldSelectionBackgroundUnfocused:
-      return GetEntryStyle()->base[GTK_STATE_ACTIVE];
 
     // Tree
     // Table
diff --git a/chrome/browser/ui/libgtk2ui/unity_service.cc b/chrome/browser/ui/libgtk2ui/unity_service.cc
new file mode 100644
index 0000000..10085fc
--- /dev/null
+++ b/chrome/browser/ui/libgtk2ui/unity_service.cc
@@ -0,0 +1,141 @@
+// 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/ui/libgtk2ui/unity_service.h"
+
+#include <dlfcn.h>
+#include <string>
+
+#include <gtk/gtk.h>
+
+#include "base/environment.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/nix/xdg_util.h"
+#include "chrome/browser/shell_integration_linux.h"
+#include "chrome/browser/ui/libgtk2ui/gtk2_util.h"
+
+// Unity data typedefs.
+typedef struct _UnityInspector UnityInspector;
+typedef UnityInspector* (*unity_inspector_get_default_func)(void);
+typedef gboolean (*unity_inspector_get_unity_running_func)
+    (UnityInspector* self);
+
+typedef struct _UnityLauncherEntry UnityLauncherEntry;
+typedef UnityLauncherEntry* (*unity_launcher_entry_get_for_desktop_id_func)
+    (const gchar* desktop_id);
+typedef void (*unity_launcher_entry_set_count_func)(UnityLauncherEntry* self,
+                                               gint64 value);
+typedef void (*unity_launcher_entry_set_count_visible_func)
+    (UnityLauncherEntry* self, gboolean value);
+typedef void (*unity_launcher_entry_set_progress_func)(UnityLauncherEntry* self,
+                                                       gdouble value);
+typedef void (*unity_launcher_entry_set_progress_visible_func)
+    (UnityLauncherEntry* self, gboolean value);
+
+
+namespace {
+
+bool attempted_load = false;
+
+// Unity has a singleton object that we can ask whether the unity is running.
+UnityInspector* inspector = NULL;
+
+// A link to the desktop entry in the panel.
+UnityLauncherEntry* chrome_entry = NULL;
+
+// Retrieved functions from libunity.
+unity_inspector_get_unity_running_func get_unity_running = NULL;
+unity_launcher_entry_set_count_func entry_set_count = NULL;
+unity_launcher_entry_set_count_visible_func entry_set_count_visible = NULL;
+unity_launcher_entry_set_progress_func entry_set_progress = NULL;
+unity_launcher_entry_set_progress_visible_func entry_set_progress_visible =
+    NULL;
+
+void EnsureMethodsLoaded() {
+  using base::nix::GetDesktopEnvironment;
+
+  if (attempted_load)
+    return;
+  attempted_load = true;
+
+  scoped_ptr<base::Environment> env(base::Environment::Create());
+  if (GetDesktopEnvironment(env.get()) != base::nix::DESKTOP_ENVIRONMENT_UNITY)
+    return;
+
+  // Ubuntu still hasn't given us a nice libunity.so symlink.
+  void* unity_lib = dlopen("libunity.so.4", RTLD_LAZY);
+  if (!unity_lib)
+    unity_lib = dlopen("libunity.so.6", RTLD_LAZY);
+  if (!unity_lib)
+    unity_lib = dlopen("libunity.so.9", RTLD_LAZY);
+  if (!unity_lib)
+    return;
+
+  unity_inspector_get_default_func inspector_get_default =
+      reinterpret_cast<unity_inspector_get_default_func>(
+          dlsym(unity_lib, "unity_inspector_get_default"));
+  if (inspector_get_default) {
+    inspector = inspector_get_default();
+
+    get_unity_running =
+        reinterpret_cast<unity_inspector_get_unity_running_func>(
+            dlsym(unity_lib, "unity_inspector_get_unity_running"));
+  }
+
+  unity_launcher_entry_get_for_desktop_id_func entry_get_for_desktop_id =
+      reinterpret_cast<unity_launcher_entry_get_for_desktop_id_func>(
+          dlsym(unity_lib, "unity_launcher_entry_get_for_desktop_id"));
+  if (entry_get_for_desktop_id) {
+    std::string desktop_id = libgtk2ui::GetDesktopName(env.get());
+    chrome_entry = entry_get_for_desktop_id(desktop_id.c_str());
+
+    entry_set_count =
+        reinterpret_cast<unity_launcher_entry_set_count_func>(
+            dlsym(unity_lib, "unity_launcher_entry_set_count"));
+
+    entry_set_count_visible =
+        reinterpret_cast<unity_launcher_entry_set_count_visible_func>(
+            dlsym(unity_lib, "unity_launcher_entry_set_count_visible"));
+
+    entry_set_progress =
+        reinterpret_cast<unity_launcher_entry_set_progress_func>(
+            dlsym(unity_lib, "unity_launcher_entry_set_progress"));
+
+    entry_set_progress_visible =
+        reinterpret_cast<unity_launcher_entry_set_progress_visible_func>(
+            dlsym(unity_lib, "unity_launcher_entry_set_progress_visible"));
+  }
+}
+
+}  // namespace
+
+
+namespace unity {
+
+bool IsRunning() {
+  EnsureMethodsLoaded();
+  if (inspector && get_unity_running)
+    return get_unity_running(inspector);
+
+  return false;
+}
+
+void SetDownloadCount(int count) {
+  EnsureMethodsLoaded();
+  if (chrome_entry && entry_set_count && entry_set_count_visible) {
+    entry_set_count(chrome_entry, count);
+    entry_set_count_visible(chrome_entry, count != 0);
+  }
+}
+
+void SetProgressFraction(float percentage) {
+  EnsureMethodsLoaded();
+  if (chrome_entry && entry_set_progress && entry_set_progress_visible) {
+    entry_set_progress(chrome_entry, percentage);
+    entry_set_progress_visible(chrome_entry,
+                               percentage > 0.0 && percentage < 1.0);
+  }
+}
+
+}  // namespace unity
diff --git a/chrome/browser/ui/libgtk2ui/unity_service.h b/chrome/browser/ui/libgtk2ui/unity_service.h
new file mode 100644
index 0000000..53c9007
--- /dev/null
+++ b/chrome/browser/ui/libgtk2ui/unity_service.h
@@ -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.
+
+#ifndef CHROME_BROWSER_UI_LIBGTK2UI_UNITY_SERVICE_H_
+#define CHROME_BROWSER_UI_LIBGTK2UI_UNITY_SERVICE_H_
+
+namespace unity {
+
+// Returns whether unity is currently running.
+bool IsRunning();
+
+// If unity is running, sets the download counter in the dock icon. Any value
+// other than 0 displays the badge.
+void SetDownloadCount(int count);
+
+// If unity is running, sets the download progress bar in the dock icon. Any
+// value between 0.0 and 1.0 (exclusive) shows the progress bar.
+void SetProgressFraction(float percentage);
+
+}  // namespace unity
+
+#endif  // CHROME_BROWSER_UI_LIBGTK2UI_UNITY_SERVICE_H_
diff --git a/chrome/browser/ui/login/login_prompt_browsertest.cc b/chrome/browser/ui/login/login_prompt_browsertest.cc
index eca933d..5220c8b 100644
--- a/chrome/browser/ui/login/login_prompt_browsertest.cc
+++ b/chrome/browser/ui/login/login_prompt_browsertest.cc
@@ -753,10 +753,9 @@
   EXPECT_TRUE(test_server()->Stop());
 }
 
-// Block crossdomain subresource login prompting as a phishing defense.
-// Disabled per http://crbug.com/174179.
+// Block crossdomain image login prompting as a phishing defense.
 IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest,
-                       DISABLED_BlockCrossdomainPrompt) {
+                       BlockCrossdomainPrompt) {
   const char* kTestPage = "files/login/load_img_from_b.html";
 
   host_resolver()->AddRule("www.a.com", "127.0.0.1");
@@ -825,6 +824,54 @@
   EXPECT_TRUE(test_server()->Stop());
 }
 
+// Allow crossdomain iframe login prompting despite the above.
+IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest,
+                       AllowCrossdomainPrompt) {
+  const char* kTestPage = "files/login/load_iframe_from_b.html";
+
+  host_resolver()->AddRule("www.a.com", "127.0.0.1");
+  host_resolver()->AddRule("www.b.com", "127.0.0.1");
+  ASSERT_TRUE(test_server()->Start());
+
+  content::WebContents* contents =
+      browser()->tab_strip_model()->GetActiveWebContents();
+  NavigationController* controller = &contents->GetController();
+  LoginPromptBrowserTestObserver observer;
+  observer.Register(content::Source<NavigationController>(controller));
+
+  // Load a page that has a cross-domain iframe authentication.
+  {
+    GURL test_page = test_server()->GetURL(kTestPage);
+    ASSERT_EQ("127.0.0.1", test_page.host());
+
+    // Change the host from 127.0.0.1 to www.a.com so that when the
+    // page tries to load from b, it will be cross-origin.
+    std::string new_host("www.a.com");
+    GURL::Replacements replacements;
+    replacements.SetHostStr(new_host);
+    test_page = test_page.ReplaceComponents(replacements);
+
+    WindowedAuthNeededObserver auth_needed_waiter(controller);
+    browser()->OpenURL(OpenURLParams(
+        test_page, Referrer(), CURRENT_TAB, content::PAGE_TRANSITION_TYPED,
+        false));
+    auth_needed_waiter.Wait();
+    ASSERT_EQ(1u, observer.handlers_.size());
+
+    while (!observer.handlers_.empty()) {
+      WindowedAuthCancelledObserver auth_cancelled_waiter(controller);
+      LoginHandler* handler = *observer.handlers_.begin();
+
+      ASSERT_TRUE(handler);
+      handler->CancelAuth();
+      auth_cancelled_waiter.Wait();
+    }
+  }
+
+  EXPECT_EQ(1, observer.auth_needed_count_);
+  EXPECT_TRUE(test_server()->Stop());
+}
+
 IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest, SupplyRedundantAuths) {
   ASSERT_TRUE(test_server()->Start());
 
diff --git a/chrome/browser/ui/metro_pin_tab_helper_win.cc b/chrome/browser/ui/metro_pin_tab_helper_win.cc
index a05c564..a11664e 100644
--- a/chrome/browser/ui/metro_pin_tab_helper_win.cc
+++ b/chrome/browser/ui/metro_pin_tab_helper_win.cc
@@ -394,7 +394,8 @@
   }
 
   // Request all the candidates.
-  int image_size = 0; // Request the full sized image.
+  int preferred_image_size = 0;  // Request the first image.
+  int max_image_size = 0;  // Do not resize images.
   for (std::vector<content::FaviconURL>::const_iterator iter =
            favicon_url_candidates_.begin();
        iter != favicon_url_candidates_.end();
@@ -402,7 +403,8 @@
     favicon_chooser_->AddPendingRequest(
         web_contents()->DownloadImage(iter->icon_url,
             true,
-            image_size,
+            preferred_image_size,
+            max_image_size,
             base::Bind(&MetroPinTabHelper::DidDownloadFavicon,
                        base::Unretained(this))));
   }
diff --git a/chrome/browser/ui/network_profile_bubble.cc b/chrome/browser/ui/network_profile_bubble.cc
index fa8cfe8..9152e84 100644
--- a/chrome/browser/ui/network_profile_bubble.cc
+++ b/chrome/browser/ui/network_profile_bubble.cc
@@ -17,7 +17,7 @@
 #include "base/logging.h"
 #include "base/metrics/histogram.h"
 #include "base/prefs/pref_service.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser_finder.h"
@@ -135,7 +135,7 @@
       } else {
         RecordUmaEvent(METRIC_CHECK_IO_FAILED);
       }
-      file_util::Delete(temp_file, false);
+      base::Delete(temp_file, false);
     }
     if (profile_on_network) {
       RecordUmaEvent(METRIC_PROFILE_ON_NETWORK);
diff --git a/chrome/browser/ui/omnibox/alternate_nav_url_fetcher.cc b/chrome/browser/ui/omnibox/alternate_nav_url_fetcher.cc
index c6e6d63..2b302c0 100644
--- a/chrome/browser/ui/omnibox/alternate_nav_url_fetcher.cc
+++ b/chrome/browser/ui/omnibox/alternate_nav_url_fetcher.cc
@@ -29,8 +29,6 @@
       navigated_to_entry_(false) {
   registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_PENDING,
                  content::NotificationService::AllSources());
-  registrar_.Add(this, chrome::NOTIFICATION_INSTANT_COMMITTED,
-                 content::NotificationService::AllSources());
 }
 
 AlternateNavURLFetcher::~AlternateNavURLFetcher() {
@@ -60,19 +58,6 @@
       break;
     }
 
-    case chrome::NOTIFICATION_INSTANT_COMMITTED: {
-      // See above.
-      NavigationController* controller =
-          &content::Source<content::WebContents>(source)->GetController();
-      if (controller_ == controller) {
-        delete this;
-      } else if (!controller_) {
-        navigated_to_entry_ = true;
-        StartFetch(controller);
-      }
-      break;
-    }
-
     case content::NOTIFICATION_NAV_ENTRY_COMMITTED:
       // The page was navigated, we can show the infobar now if necessary.
       registrar_.Remove(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED,
diff --git a/chrome/browser/ui/omnibox/omnibox_controller.cc b/chrome/browser/ui/omnibox/omnibox_controller.cc
index c99baa2..cd75dda 100644
--- a/chrome/browser/ui/omnibox/omnibox_controller.cc
+++ b/chrome/browser/ui/omnibox/omnibox_controller.cc
@@ -25,23 +25,6 @@
 #include "extensions/common/constants.h"
 #include "ui/gfx/rect.h"
 
-using predictors::AutocompleteActionPredictor;
-
-namespace {
-
-string16 GetDefaultSearchProviderKeyword(Profile* profile) {
-  TemplateURLService* template_url_service =
-      TemplateURLServiceFactory::GetForProfile(profile);
-  if (template_url_service) {
-    TemplateURL* template_url =
-        template_url_service->GetDefaultSearchProvider();
-    if (template_url)
-      return template_url->keyword();
-  }
-  return string16();
-}
-
-}  // namespace
 
 OmniboxController::OmniboxController(OmniboxEditModel* omnibox_edit_model,
                                      Profile* profile)
@@ -59,6 +42,7 @@
 void OmniboxController::StartAutocomplete(
     string16 user_text,
     size_t cursor_position,
+    const GURL& current_url,
     bool prevent_inline_autocomplete,
     bool prefer_keyword,
     bool allow_exact_keyword_match,
@@ -66,20 +50,6 @@
   ClearPopupKeywordMode();
   popup_->SetHoveredLine(OmniboxPopupModel::kNoMatch);
 
-#if defined(HTML_INSTANT_EXTENDED_POPUP)
-  InstantController* instant_controller = GetInstantController();
-  if (instant_controller) {
-    instant_controller->OnAutocompleteStart();
-    // If the embedded page for InstantExtended is fetching its own suggestions,
-    // suppress search suggestions from SearchProvider. We still need
-    // SearchProvider to run for FinalizeInstantQuery.
-    // TODO(dcblack): Once we are done refactoring the omnibox so we don't need
-    // to use FinalizeInstantQuery anymore, we can take out this check and
-    // remove this provider from kInstantExtendedOmniboxProviders.
-    if (instant_controller->WillFetchCompletions())
-      autocomplete_controller_->search_provider()->SuppressSearchSuggestions();
-  }
-#endif
   if (chrome::IsInstantExtendedAPIEnabled()) {
     autocomplete_controller_->search_provider()->
         SetOmniboxStartMargin(omnibox_start_margin);
@@ -88,7 +58,7 @@
   // We don't explicitly clear OmniboxPopupModel::manually_selected_match, as
   // Start ends up invoking OmniboxPopupModel::OnResultChanged which clears it.
   autocomplete_controller_->Start(AutocompleteInput(
-      user_text, cursor_position, string16(), GURL(),
+      user_text, cursor_position, string16(), current_url,
       prevent_inline_autocomplete, prefer_keyword, allow_exact_keyword_match,
       AutocompleteInput::ALL_MATCHES));
 }
@@ -121,7 +91,7 @@
 
       if (!prerender::IsOmniboxEnabled(profile_))
         DoPreconnect(*match);
-      omnibox_edit_model_->OnCurrentMatchChanged(false);
+      omnibox_edit_model_->OnCurrentMatchChanged();
     } else {
       InvalidateCurrentMatch();
       popup_->OnResultChanged();
@@ -132,138 +102,22 @@
     popup_->OnResultChanged();
   }
 
-  // TODO(beaudoin): This may no longer be needed now that instant classic is
-  // gone.
-  if (popup_->IsOpen()) {
-    // The popup size may have changed, let instant know.
-    OnPopupBoundsChanged(popup_->view()->GetTargetBounds());
-
-#if defined(HTML_INSTANT_EXTENDED_POPUP)
-    InstantController* instant_controller = GetInstantController();
-    if (instant_controller && !omnibox_edit_model_->in_revert()) {
-      instant_controller->HandleAutocompleteResults(
-          *autocomplete_controller_->providers(),
-          autocomplete_controller_->result());
-    }
-#endif
-  } else if (was_open) {
+  if (!popup_->IsOpen() && was_open) {
     // Accept the temporary text as the user text, because it makes little sense
     // to have temporary text when the popup is closed.
     omnibox_edit_model_->AcceptTemporaryTextAsUserText();
-    // The popup has been closed, let instant know.
-    OnPopupBoundsChanged(gfx::Rect());
   }
 }
 
-bool OmniboxController::DoInstant(const AutocompleteMatch& match,
-                                  string16 user_text,
-                                  string16 full_text,
-                                  size_t selection_start,
-                                  size_t selection_end,
-                                  bool user_input_in_progress,
-                                  bool in_escape_handler,
-                                  bool just_deleted_text,
-                                  bool keyword_is_selected) {
-#if defined(HTML_INSTANT_EXTENDED_POPUP)
-  InstantController* instant_controller = GetInstantController();
-  if (!instant_controller)
-    return false;
-
-  // Remove "?" if we're in forced query mode.
-  AutocompleteInput::RemoveForcedQueryStringIfNecessary(
-      autocomplete_controller_->input().type(), &user_text);
-  AutocompleteInput::RemoveForcedQueryStringIfNecessary(
-      autocomplete_controller_->input().type(), &full_text);
-  return instant_controller->Update(
-      match, user_text, full_text, selection_start, selection_end,
-      UseVerbatimInstant(just_deleted_text), user_input_in_progress,
-      popup_->IsOpen(), in_escape_handler, keyword_is_selected);
-#else
-  return false;
-#endif
-}
-
-void OmniboxController::FinalizeInstantQuery(
-    const string16& input_text,
-    const InstantSuggestion& suggestion) {
-// Should only get called for the HTML popup.
-#if defined(HTML_INSTANT_EXTENDED_POPUP)
-  if (!popup_model()->result().empty()) {
-    // We need to finalize the instant query in all cases where the
-    // |popup_model| holds some result. It is not enough to check whether the
-    // popup is open, since when an IME is active the popup may be closed while
-    // |popup_model| contains a non-empty result.
-    SearchProvider* search_provider =
-        autocomplete_controller_->search_provider();
-    // There may be no providers during testing; guard against that.
-    if (search_provider)
-      search_provider->FinalizeInstantQuery(input_text, suggestion);
-  }
-#endif
-}
-
 void OmniboxController::SetInstantSuggestion(
     const InstantSuggestion& suggestion) {
-// Should only get called for the HTML popup.
-#if defined(HTML_INSTANT_EXTENDED_POPUP)
-  switch (suggestion.behavior) {
-    case INSTANT_COMPLETE_NOW:
-      // Set blue suggestion text.
-      // TODO(beaudoin): This currently goes to the SearchProvider. Instead we
-      // should just create a valid current_match_ and call
-      // omnibox_edit_model_->OnCurrentMatchChanged. This way we can get rid of
-      // FinalizeInstantQuery entirely.
-      if (!suggestion.text.empty())
-        FinalizeInstantQuery(omnibox_edit_model_->GetViewText(), suggestion);
-      return;
-
-    case INSTANT_COMPLETE_NEVER: {
-      DCHECK_EQ(INSTANT_SUGGESTION_SEARCH, suggestion.type);
-
-      // Set gray suggestion text.
-      // Remove "?" if we're in forced query mode.
-      gray_suggestion_ = suggestion.text;
-
-      // TODO(beaudoin): The following should no longer be needed once the
-      // instant suggestion no longer goes through the search provider.
-      SearchProvider* search_provider =
-          autocomplete_controller_->search_provider();
-      if (search_provider)
-        search_provider->ClearInstantSuggestion();
-
-      omnibox_edit_model_->OnGrayTextChanged();
-      return;
-    }
-
-    case INSTANT_COMPLETE_REPLACE:
-      // Replace the entire omnibox text by the suggestion the user just arrowed
-      // to.
-      CreateAndSetInstantMatch(suggestion.text, suggestion.text,
-                               suggestion.type == INSTANT_SUGGESTION_SEARCH ?
-                                   AutocompleteMatchType::SEARCH_SUGGEST :
-                                   AutocompleteMatchType::URL_WHAT_YOU_TYPED);
-
-      omnibox_edit_model_->OnCurrentMatchChanged(true);
-      return;
-  }
-#endif
+  // TODO(jered): Delete this.
 }
 
 void OmniboxController::InvalidateCurrentMatch() {
   current_match_ = AutocompleteMatch();
 }
 
-const AutocompleteMatch& OmniboxController::CurrentMatch(
-    GURL* alternate_nav_url) const {
-  if (alternate_nav_url && current_match_.destination_url.is_valid()) {
-    *alternate_nav_url = AutocompleteResult::ComputeAlternateNavUrl(
-        autocomplete_controller_->input(), current_match_);
-  }
-
-  return current_match_;
-}
-
-
 void OmniboxController::ClearPopupKeywordMode() const {
   if (popup_->IsOpen() &&
       popup_->selected_line_state() == OmniboxPopupModel::KEYWORD)
@@ -278,7 +132,7 @@
     if (profile_->GetNetworkPredictor()) {
       profile_->GetNetworkPredictor()->AnticipateOmniboxUrl(
           match.destination_url,
-          AutocompleteActionPredictor::IsPreconnectable(match));
+          predictors::AutocompleteActionPredictor::IsPreconnectable(match));
     }
     // We could prefetch the alternate nav URL, if any, but because there
     // can be many of these as a user types an initial series of characters,
@@ -286,12 +140,6 @@
   }
 }
 
-void OmniboxController::OnPopupBoundsChanged(const gfx::Rect& bounds) {
-  InstantController* instant_controller = GetInstantController();
-  if (instant_controller)
-    instant_controller->SetPopupBounds(bounds);
-}
-
 bool OmniboxController::UseVerbatimInstant(bool just_deleted_text) const {
 #if defined(OS_MACOSX)
   // TODO(suzhe): Fix Mac port to display Instant suggest in a separated NSView,
@@ -320,11 +168,17 @@
     string16 query_string,
     string16 input_text,
     AutocompleteMatchType::Type match_type) {
-  string16 keyword = GetDefaultSearchProviderKeyword(profile_);
-  if (keyword.empty())
-    return;  // CreateSearchSuggestion needs a keyword.
+  TemplateURLService* template_url_service =
+      TemplateURLServiceFactory::GetForProfile(profile_);
+  if (!template_url_service)
+    return;
+
+  TemplateURL* template_url =
+      template_url_service->GetDefaultSearchProvider();
+  if (!template_url)
+    return;
 
   current_match_ = SearchProvider::CreateSearchSuggestion(
-      profile_, NULL, AutocompleteInput(), query_string, input_text, 0,
-      match_type, 0, false, keyword, -1);
+      NULL, 0, match_type, template_url, query_string, input_text,
+      AutocompleteInput(), false, 0, -1, true);
 }
diff --git a/chrome/browser/ui/omnibox/omnibox_controller.h b/chrome/browser/ui/omnibox/omnibox_controller.h
index 75bc5a8..2259ae7 100644
--- a/chrome/browser/ui/omnibox/omnibox_controller.h
+++ b/chrome/browser/ui/omnibox/omnibox_controller.h
@@ -41,8 +41,10 @@
                     Profile* profile);
   virtual ~OmniboxController();
 
+  // |current_url| is only set for mobile ports.
   void StartAutocomplete(string16 user_text,
                          size_t cursor_position,
+                         const GURL& current_url,
                          bool prevent_inline_autocomplete,
                          bool prefer_keyword,
                          bool allow_exact_keyword_match,
@@ -55,20 +57,6 @@
     return autocomplete_controller_.get();
   }
 
-  bool DoInstant(const AutocompleteMatch& match,
-                 string16 user_text,
-                 string16 full_text,
-                 size_t selection_start,
-                 size_t selection_end,
-                 bool user_input_in_progress,
-                 bool in_escape_handler,
-                 bool just_deleted_text,
-                 bool keyword_is_selected);
-
-  // Calls through to SearchProvider::FinalizeInstantQuery.
-  void FinalizeInstantQuery(const string16& input_text,
-                            const InstantSuggestion& suggestion);
-
   // Sets the suggestion text.
   void SetInstantSuggestion(const InstantSuggestion& suggestion);
 
@@ -84,9 +72,7 @@
   // LocationBarView, making this accessor unnecessary.
   OmniboxPopupModel* popup_model() const { return popup_; }
 
-  const string16& gray_suggestion() const { return gray_suggestion_; }
-
-  const AutocompleteMatch& CurrentMatch(GURL* alternate_nav_url) const;
+  const AutocompleteMatch& current_match() const { return current_match_; }
 
   // Turns off keyword mode for the current match.
   void ClearPopupKeywordMode() const;
@@ -98,11 +84,6 @@
   // TODO(beaudoin): Make private once OmniboxEditModel no longer refers to it.
   void DoPreconnect(const AutocompleteMatch& match);
 
-  // TODO(beaudoin): Make private once OmniboxEditModel no longer refers to it.
-  // Invoked when the popup has changed its bounds to |bounds|. |bounds| here
-  // is in screen coordinates.
-  void OnPopupBoundsChanged(const gfx::Rect& bounds);
-
  private:
 
   // Returns true if a verbatim query should be used for Instant. A verbatim
@@ -138,10 +119,6 @@
   // some time to extract these fields and use a tighter structure here.
   AutocompleteMatch current_match_;
 
-  // The completion suggested by instant, displayed in gray text besides
-  // |fill_into_edit|.
-  string16 gray_suggestion_;
-
   DISALLOW_COPY_AND_ASSIGN(OmniboxController);
 };
 
diff --git a/chrome/browser/ui/omnibox/omnibox_controller_unittest.cc b/chrome/browser/ui/omnibox/omnibox_controller_unittest.cc
index ad9d9c6..4c855c3 100644
--- a/chrome/browser/ui/omnibox/omnibox_controller_unittest.cc
+++ b/chrome/browser/ui/omnibox/omnibox_controller_unittest.cc
@@ -69,11 +69,8 @@
   // Ensure we have at least one provider.
   ASSERT_NE(0, observed_providers);
 
-  // Ensure instant extended includes all the basic ones save for those that are
-  // not expected to run in instant extended.
-  int providers_with_instant_extended =
-      observed_providers &
-      ~AutocompleteProvider::TYPE_SHORTCUTS;
+  // Ensure instant extended includes all the provides in classic Chrome.
+  int providers_with_instant_extended = observed_providers;
   // TODO(beaudoin): remove TYPE_SEARCH once it's no longer needed to pass
   // the Instant suggestion through via FinalizeInstantQuery.
   chrome::EnableInstantExtendedAPIForTesting();
diff --git a/chrome/browser/ui/omnibox/omnibox_edit_model.cc b/chrome/browser/ui/omnibox/omnibox_edit_model.cc
index 99d6680..405e407 100644
--- a/chrome/browser/ui/omnibox/omnibox_edit_model.cc
+++ b/chrome/browser/ui/omnibox/omnibox_edit_model.cc
@@ -127,15 +127,11 @@
       user_input_in_progress_(false),
       just_deleted_text_(false),
       has_temporary_text_(false),
-      is_temporary_text_set_by_instant_(false),
-      selected_instant_autocomplete_match_index_(OmniboxPopupModel::kNoMatch),
-      is_instant_temporary_text_a_search_query_(false),
       paste_state_(NONE),
       control_key_state_(UP),
       is_keyword_hint_(false),
       profile_(profile),
       in_revert_(false),
-      in_escape_handler_(false),
       allow_exact_keyword_match_(false) {
   omnibox_controller_.reset(new OmniboxController(this, profile));
   delegate_.reset(new OmniboxCurrentPageDelegateImpl(controller, profile));
@@ -187,10 +183,14 @@
 AutocompleteMatch OmniboxEditModel::CurrentMatch(
     GURL* alternate_nav_url) const {
   // If we have a valid match use it. Otherwise get one for the current text.
-  AutocompleteMatch match =
-      omnibox_controller_->CurrentMatch(alternate_nav_url);
-  if (!match.destination_url.is_valid())
+  AutocompleteMatch match = omnibox_controller_->current_match();
+
+  if (!match.destination_url.is_valid()) {
     GetInfoForCurrentText(&match, alternate_nav_url);
+  } else if (alternate_nav_url) {
+    *alternate_nav_url = AutocompleteResult::ComputeAlternateNavUrl(
+        autocomplete_controller()->input(), match);
+  }
   return match;
 }
 
@@ -209,7 +209,8 @@
   string16 instant_suggestion = view_->GetInstantSuggestion();
   const bool visibly_changed_permanent_text =
       (permanent_text_ != new_permanent_text) &&
-      (!user_input_in_progress_ || !has_focus()) &&
+      (!has_focus() ||
+       (!user_input_in_progress_ && !popup_model()->IsOpen())) &&
       (instant_suggestion.empty() ||
        new_permanent_text != user_text_ + instant_suggestion);
 
@@ -227,17 +228,10 @@
   omnibox_controller_->InvalidateCurrentMatch();
   paste_state_ = NONE;
   has_temporary_text_ = false;
-  is_temporary_text_set_by_instant_ = false;
-  selected_instant_autocomplete_match_index_ = OmniboxPopupModel::kNoMatch;
-  is_instant_temporary_text_a_search_query_ = false;
 }
 
 void OmniboxEditModel::SetInstantSuggestion(
     const InstantSuggestion& suggestion) {
-// Should only get called for the HTML popup.
-#if defined(HTML_INSTANT_EXTENDED_POPUP)
-  omnibox_controller_->SetInstantSuggestion(suggestion);
-#endif
 }
 
 bool OmniboxEditModel::CommitSuggestedText() {
@@ -282,27 +276,8 @@
                             recommended_action,
                             AutocompleteActionPredictor::LAST_PREDICT_ACTION);
 
-  // Do not perform instant if we're currently reverting or the change is the
-  // result of an INSTANT_COMPLETE_REPLACE instant suggestion.
-  bool performed_instant = false;
-  if (!in_revert_ && !is_temporary_text_set_by_instant_) {
-    size_t start, end;
-    view_->GetSelectionBounds(&start, &end);
-    string16 user_text = DisplayTextFromUserText(user_text_);
-    performed_instant = omnibox_controller_->DoInstant(
-        current_match, user_text, view_->GetText(), start, end,
-        user_input_in_progress_, in_escape_handler_,
-        view_->DeleteAtEndPressed() || just_deleted_text_,
-        KeywordIsSelected());
-  }
-
-  if (!performed_instant) {
-    // Hide any suggestions we might be showing.
-    view_->SetInstantSuggestion(string16());
-
-    // No need to wait any longer for Instant.
-    omnibox_controller_->FinalizeInstantQuery(string16(), InstantSuggestion());
-  }
+  // Hide any suggestions we might be showing.
+  view_->SetInstantSuggestion(string16());
 
   switch (recommended_action) {
     case AutocompleteActionPredictor::ACTION_PRERENDER:
@@ -427,9 +402,6 @@
   keyword_.clear();
   is_keyword_hint_ = false;
   has_temporary_text_ = false;
-  is_temporary_text_set_by_instant_ = false;
-  selected_instant_autocomplete_match_index_ = OmniboxPopupModel::kNoMatch;
-  is_instant_temporary_text_a_search_query_ = false;
   view_->SetWindowTextAndCaretPos(permanent_text_,
                                   has_focus() ? permanent_text_.length() : 0,
                                   false, true);
@@ -467,10 +439,14 @@
     cursor_position = user_text_.length();
   }
 
+  GURL current_url =
+      (delegate_->CurrentPageExists() && view_->IsIndicatingQueryRefinement()) ?
+      delegate_->GetURL() : GURL();
   bool keyword_is_selected = KeywordIsSelected();
   omnibox_controller_->StartAutocomplete(
       user_text_,
       cursor_position,
+      current_url,
       prevent_inline_autocomplete || just_deleted_text_ ||
       (has_selected_text && inline_autocomplete_text_.empty()) ||
       (paste_state_ != NONE),
@@ -599,7 +575,6 @@
       elapsed_time_since_last_change_to_default_match =
           base::TimeDelta::FromMilliseconds(-1);
     }
-    // TODO(sreeram): Handle is_temporary_text_set_by_instant_ correctly.
     OmniboxLog log(
         autocomplete_controller()->input().text(),
         just_deleted_text_,
@@ -696,19 +671,14 @@
     const GURL destination_url = autocomplete_controller()->
         GetDestinationURL(match, query_formulation_time);
 
-#if defined(HTML_INSTANT_EXTENDED_POPUP)
-    // If running with instant, notify the instant controller that a navigation
-    // is about to take place if we are navigating to a URL. This can be
-    // determined by inspecting the transition type. To ensure that this is only
-    // done on Enter key press, check that the disposition is CURRENT_TAB. This
-    // is the same heuristic used by BrowserInstantController::OpenInstant
-    if (match.transition == content::PAGE_TRANSITION_TYPED &&
-        disposition == CURRENT_TAB) {
-      InstantController* instant = GetInstantController();
-      if (instant)
-        instant->OmniboxNavigateToURL();
-    }
-#endif
+    // Track whether the destination URL sends us to a search results page
+    // using the default search provider.
+    TemplateURL* default_provider =
+        TemplateURLServiceFactory::GetForProfile(profile_)->
+            GetDefaultSearchProvider();
+    if (default_provider && default_provider->IsSearchURL(destination_url))
+      content::RecordAction(UserMetricsAction(
+          "OmniboxDestinationURLMatchesDefaultSearchProvider"));
 
     // This calls RevertAll again.
     base::AutoReset<bool> tmp(&in_revert_, true);
@@ -736,9 +706,6 @@
   // the current state properly.
   bool save_original_selection = !has_temporary_text_;
   has_temporary_text_ = true;
-  is_temporary_text_set_by_instant_ = false;
-  selected_instant_autocomplete_match_index_ = OmniboxPopupModel::kNoMatch;
-  is_instant_temporary_text_a_search_query_ = false;
   view_->OnTemporaryTextMaybeChanged(
       DisplayTextFromUserText(CurrentMatch(NULL).fill_into_edit),
       save_original_selection, true);
@@ -753,10 +720,6 @@
 void OmniboxEditModel::AcceptTemporaryTextAsUserText() {
   InternalSetUserText(UserTextFromDisplayText(view_->GetText()));
   has_temporary_text_ = false;
-  is_temporary_text_set_by_instant_ = false;
-  selected_instant_autocomplete_match_index_ = OmniboxPopupModel::kNoMatch;
-  is_instant_temporary_text_a_search_query_ = false;
-  OnPopupBoundsChanged(gfx::Rect());
   delegate_->NotifySearchTabHelper(user_input_in_progress_, !in_revert_,
                                    popup_model()->IsOpen(), user_text_.empty());
 }
@@ -801,7 +764,6 @@
     // the actual underlying current URL, e.g. if we're on the NTP and the
     // |permanent_text_| is empty.
     autocomplete_controller()->StartZeroSuggest(delegate_->GetURL(),
-                                                user_text_,
                                                 permanent_text_);
   }
 
@@ -863,77 +825,47 @@
   if (!user_input_in_progress_ && view_->IsSelectAll())
     return false;
 
-  in_escape_handler_ = true;
   if (!user_text_.empty()) {
     UMA_HISTOGRAM_ENUMERATION(kOmniboxUserTextClearedHistogram,
                               OMNIBOX_USER_TEXT_CLEARED_WITH_ESCAPE,
                               OMNIBOX_USER_TEXT_CLEARED_NUM_OF_ITEMS);
   }
   view_->RevertAll();
-  in_escape_handler_ = false;
   view_->SelectAll(true);
   return true;
 }
 
 void OmniboxEditModel::OnControlKeyChanged(bool pressed) {
-  // Don't change anything unless the key state is actually toggling.
-  if (pressed == (control_key_state_ == UP)) {
-    ControlKeyState old_state = control_key_state_;
+  if (pressed == (control_key_state_ == UP))
     control_key_state_ = pressed ? DOWN_WITHOUT_CHANGE : UP;
-    if ((control_key_state_ == DOWN_WITHOUT_CHANGE) && has_temporary_text_) {
-      // Arrowing down and then hitting control accepts the temporary text as
-      // the input text.
-      InternalSetUserText(UserTextFromDisplayText(view_->GetText()));
-      has_temporary_text_ = false;
-      is_temporary_text_set_by_instant_ = false;
-      selected_instant_autocomplete_match_index_ = OmniboxPopupModel::kNoMatch;
-      is_instant_temporary_text_a_search_query_ = false;
-    }
-    if ((old_state != DOWN_WITH_CHANGE) && popup_model()->IsOpen()) {
-      // Autocomplete history provider results may change, so refresh the
-      // popup.  This will force user_input_in_progress_ to true, but if the
-      // popup is open, that should have already been the case.
-      view_->UpdatePopup();
-    }
-  }
 }
 
 void OmniboxEditModel::OnUpOrDownKeyPressed(int count) {
   // NOTE: This purposefully doesn't trigger any code that resets paste_state_.
-  if (!popup_model()->IsOpen()) {
-    if (!query_in_progress()) {
-      // The popup is neither open nor working on a query already.  So, start an
-      // autocomplete query for the current text.  This also sets
-      // user_input_in_progress_ to true, which we want: if the user has started
-      // to interact with the popup, changing the permanent_text_ shouldn't
-      // change the displayed text.
-      // Note: This does not force the popup to open immediately.
-      // TODO(pkasting): We should, in fact, force this particular query to open
-      // the popup immediately.
-      if (!user_input_in_progress_)
-        InternalSetUserText(permanent_text_);
-      view_->UpdatePopup();
-    } else {
-      // TODO(pkasting): The popup is working on a query but is not open.  We
-      // should force it to open immediately.
-    }
-  } else {
-#if defined(HTML_INSTANT_EXTENDED_POPUP)
-    InstantController* instant = GetInstantController();
-    if (instant && instant->OnUpOrDownKeyPressed(count)) {
-      // If Instant handles the key press, it's showing a list of suggestions
-      // that it's stepping through. In that case, our popup model is
-      // irrelevant, so don't process the key press ourselves. However, do stop
-      // the autocomplete system from changing the results.
-      autocomplete_controller()->Stop(false);
-    } else
-#endif
-    {
-      // The popup is open, so the user should be able to interact with it
-      // normally.
-      popup_model()->Move(count);
-    }
+  if (popup_model()->IsOpen()) {
+    // The popup is open, so the user should be able to interact with it
+    // normally.
+    popup_model()->Move(count);
+    return;
   }
+
+  if (!query_in_progress()) {
+    // The popup is neither open nor working on a query already.  So, start an
+    // autocomplete query for the current text.  This also sets
+    // user_input_in_progress_ to true, which we want: if the user has started
+    // to interact with the popup, changing the permanent_text_ shouldn't change
+    // the displayed text.
+    // Note: This does not force the popup to open immediately.
+    // TODO(pkasting): We should, in fact, force this particular query to open
+    // the popup immediately.
+    if (!user_input_in_progress_)
+      InternalSetUserText(permanent_text_);
+    view_->UpdatePopup();
+    return;
+  }
+
+  // TODO(pkasting): The popup is working on a query but is not open.  We should
+  // force it to open immediately.
 }
 
 void OmniboxEditModel::OnPopupDataChanged(
@@ -961,9 +893,6 @@
     if (save_original_selection) {
       // Save the original selection and URL so it can be reverted later.
       has_temporary_text_ = true;
-      is_temporary_text_set_by_instant_ = false;
-      selected_instant_autocomplete_match_index_ = OmniboxPopupModel::kNoMatch;
-      is_instant_temporary_text_a_search_query_ = false;
       original_url_ = *destination_for_temporary_text_change;
       inline_autocomplete_text_.clear();
     }
@@ -985,6 +914,7 @@
   bool call_controller_onchanged = true;
   inline_autocomplete_text_ = text;
 
+  string16 user_text = user_input_in_progress_ ? user_text_ : permanent_text_;
   if (keyword_state_changed && KeywordIsSelected()) {
     // If we reach here, the user most likely entered keyword mode by inserting
     // a space between a keyword name and a search string (as pressing space or
@@ -1001,11 +931,11 @@
     // temporary text back to a default match that's a keyword search, but in
     // that case the RevertTemporaryText() call below will reset the caret or
     // selection correctly so the caret positioning we do here won't matter.
-    view_->SetWindowTextAndCaretPos(DisplayTextFromUserText(user_text_), 0,
+    view_->SetWindowTextAndCaretPos(DisplayTextFromUserText(user_text), 0,
                                                             false, false);
   } else if (view_->OnInlineAutocompleteTextMaybeChanged(
-             DisplayTextFromUserText(user_text_ + inline_autocomplete_text_),
-             DisplayTextFromUserText(user_text_).length())) {
+             DisplayTextFromUserText(user_text + inline_autocomplete_text_),
+             DisplayTextFromUserText(user_text).length())) {
     call_controller_onchanged = false;
   }
 
@@ -1068,9 +998,6 @@
   if (user_text_changed) {
     InternalSetUserText(UserTextFromDisplayText(new_text));
     has_temporary_text_ = false;
-    is_temporary_text_set_by_instant_ = false;
-    selected_instant_autocomplete_match_index_ = OmniboxPopupModel::kNoMatch;
-    is_instant_temporary_text_a_search_query_ = false;
 
     // Track when the user has deleted text so we won't allow inline
     // autocomplete.
@@ -1122,38 +1049,27 @@
            MaybeAcceptKeywordBySpace(user_text_));
 }
 
-void OmniboxEditModel::OnCurrentMatchChanged(bool is_temporary_set_by_instant) {
-  has_temporary_text_ = is_temporary_set_by_instant;
-  is_temporary_text_set_by_instant_ = is_temporary_set_by_instant;
+void OmniboxEditModel::OnCurrentMatchChanged() {
+  has_temporary_text_ = false;
 
-  const AutocompleteMatch& match = omnibox_controller_->CurrentMatch(NULL);
+  const AutocompleteMatch& match = omnibox_controller_->current_match();
 
-  if (is_temporary_set_by_instant) {
-    view_->OnTemporaryTextMaybeChanged(
-        DisplayTextFromUserText(match.fill_into_edit), !has_temporary_text_,
-        false);
-  } else {
-    // We store |keyword| and |is_keyword_hint| in temporary variables since
-    // OnPopupDataChanged use their previous state to detect changes.
-    string16 keyword;
-    bool is_keyword_hint;
-    match.GetKeywordUIState(profile_, &keyword, &is_keyword_hint);
-    string16 inline_autocomplete_text;
-    if (match.inline_autocomplete_offset < match.fill_into_edit.length()) {
-      // We have blue text, go through OnPopupDataChanged.
-      // TODO(beaudoin): Merge OnPopupDataChanged with this method once the
-      // popup handling has completely migrated to omnibox_controller.
-      inline_autocomplete_text =
-          match.fill_into_edit.substr(match.inline_autocomplete_offset);
-    }
-    popup_model()->OnResultChanged();
-    OnPopupDataChanged(inline_autocomplete_text, NULL, keyword,
-                       is_keyword_hint);
+  // We store |keyword| and |is_keyword_hint| in temporary variables since
+  // OnPopupDataChanged use their previous state to detect changes.
+  string16 keyword;
+  bool is_keyword_hint;
+  match.GetKeywordUIState(profile_, &keyword, &is_keyword_hint);
+  string16 inline_autocomplete_text;
+  if (match.inline_autocomplete_offset < match.fill_into_edit.length()) {
+    // We have blue text, go through OnPopupDataChanged.
+    // TODO(beaudoin): Merge OnPopupDataChanged with this method once the
+    // popup handling has completely migrated to omnibox_controller.
+    inline_autocomplete_text =
+        match.fill_into_edit.substr(match.inline_autocomplete_offset);
   }
-}
-
-void OmniboxEditModel::OnGrayTextChanged() {
-  view_->SetInstantSuggestion(omnibox_controller_->gray_suggestion());
+  popup_model()->OnResultChanged();
+  OnPopupDataChanged(inline_autocomplete_text, NULL, keyword,
+                     is_keyword_hint);
 }
 
 string16 OmniboxEditModel::GetViewText() const {
@@ -1211,56 +1127,6 @@
     match->destination_url =
         delegate_->GetNavigationController().GetVisibleEntry()->GetURL();
     match->transition = content::PAGE_TRANSITION_RELOAD;
-#if defined(HTML_INSTANT_EXTENDED_POPUP)
-  } else if (is_temporary_text_set_by_instant_) {
-    // If there's temporary text and it has been set by Instant, we won't find
-    // it in the popup model, so create the match based on the type Instant told
-    // us (SWYT for queries and UWYT for URLs). We do this instead of
-    // classifying the text ourselves because the text may look like a URL, but
-    // Instant may expect it to be a search (e.g.: a query for "amazon.com").
-    if (selected_instant_autocomplete_match_index_ !=
-            OmniboxPopupModel::kNoMatch) {
-      // Great, we know the exact match struct. Just use that.
-      const AutocompleteResult& result = this->result();
-      *match = result.match_at(selected_instant_autocomplete_match_index_);
-    } else {
-      const string16& text = view_->GetText();
-      AutocompleteInput input(text, string16::npos, string16(), GURL(), false,
-                              false, false, AutocompleteInput::BEST_MATCH);
-      // Only the destination_url and the transition of the match will be be
-      // used (to either navigate to the URL or let Instant commit its preview).
-      // The match won't be used for logging, displaying in the dropdown, etc.
-      // So, it's okay to pass in mostly bogus params (such as relevance = 0).
-      // TODO(sreeram): Always using NO_SUGGESTIONS_AVAILABLE is wrong when
-      // Instant is using the local fallback overlay. Fix.
-      if (is_instant_temporary_text_a_search_query_) {
-        const TemplateURL* default_provider =
-            TemplateURLServiceFactory::GetForProfile(profile_)->
-                GetDefaultSearchProvider();
-        if (default_provider && default_provider->SupportsReplacement()) {
-          *match = SearchProvider::CreateSearchSuggestion(profile_,
-              autocomplete_controller()->search_provider(), input, text, text,
-              0, AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
-              TemplateURLRef::NO_SUGGESTIONS_AVAILABLE, false,
-              default_provider->keyword(),
-              controller_->GetOmniboxBounds().x());
-        } else {
-          // Can't create a new search match. Leave |match| as is, with an
-          // invalid destination_url. This shouldn't ever happen. For example,
-          // even if a group policy update in the midst of interacting with
-          // Instant leaves us without a valid search provider, Instant
-          // should've observed the update and reset
-          // |is_temporary_text_set_by_instant_|, so we still shouldn't get
-          // here. However, as protection against the unknowns and Instant
-          // regressions, we simply return an invalid match instead of crashing
-          // (hence no DCHECK).
-        }
-      } else {
-        *match = HistoryURLProvider::SuggestExactInput(
-            autocomplete_controller()->history_url_provider(), input, false);
-      }
-    }
-#endif
   } else if (popup_model()->IsOpen() || query_in_progress()) {
     if (query_in_progress()) {
       // It's technically possible for |result| to be empty if no provider
@@ -1291,36 +1157,9 @@
   // The user typed something, then selected a different item.  Restore the
   // text they typed and change back to the default item.
   // NOTE: This purposefully does not reset paste_state_.
-#if defined(HTML_INSTANT_EXTENDED_POPUP)
-  bool notify_instant = is_temporary_text_set_by_instant_;
-#endif
   just_deleted_text_ = false;
   has_temporary_text_ = false;
-  is_temporary_text_set_by_instant_ = false;
-  selected_instant_autocomplete_match_index_ = OmniboxPopupModel::kNoMatch;
-  is_instant_temporary_text_a_search_query_ = false;
 
-#if defined(HTML_INSTANT_EXTENDED_POPUP)
-  InstantController* instant = GetInstantController();
-  if (instant && notify_instant) {
-    // Normally, popup_model()->ResetToDefaultMatch() will cause the view text
-    // to be updated. In Instant Extended mode however, the popup_model() is
-    // not used, so it won't do anything. So, update the view ourselves. Even
-    // if Instant is not in extended mode (i.e., it's enabled in non-extended
-    // mode, or disabled altogether), this is okay to do, since the call to
-    // popup_model()->ResetToDefaultMatch() will just override whatever we do
-    // here.
-    //
-    // The two "false" arguments make sure that our shenanigans don't cause any
-    // previously saved selection to be erased nor OnChanged() to be called.
-    view_->OnTemporaryTextMaybeChanged(user_text_ + inline_autocomplete_text_,
-        false, false);
-    AutocompleteResult::const_iterator match(result().default_match());
-    instant->OnCancel(match != result().end() ? *match : AutocompleteMatch(),
-                      user_text_,
-                      user_text_ + inline_autocomplete_text_);
-  }
-#endif
   if (revert_popup)
     popup_model()->ResetToDefaultMatch();
   view_->OnRevertTemporaryText();
diff --git a/chrome/browser/ui/omnibox/omnibox_edit_model.h b/chrome/browser/ui/omnibox/omnibox_edit_model.h
index dcf6ccc..d9f40c8 100644
--- a/chrome/browser/ui/omnibox/omnibox_edit_model.h
+++ b/chrome/browser/ui/omnibox/omnibox_edit_model.h
@@ -9,7 +9,7 @@
 #include "base/compiler_specific.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/strings/string16.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/autocomplete/autocomplete_controller_delegate.h"
 #include "chrome/browser/autocomplete/autocomplete_match.h"
 #include "chrome/browser/ui/omnibox/omnibox_controller.h"
@@ -297,19 +297,8 @@
                              bool just_deleted_text,
                              bool allow_keyword_ui_change);
 
-  // TODO(beaudoin): Mac code still calls this here. We should try to untangle
-  // this.
-  // Invoked when the popup has changed its bounds to |bounds|. |bounds| here
-  // is in screen coordinates.
-  void OnPopupBoundsChanged(const gfx::Rect& bounds) {
-    omnibox_controller_->OnPopupBoundsChanged(bounds);
-  }
-
   // Called when the current match has changed in the OmniboxController.
-  void OnCurrentMatchChanged(bool is_temporary_set_by_instant);
-
-  // Callend when the gray text suggestion has changed in the OmniboxController.
-  void OnGrayTextChanged();
+  void OnCurrentMatchChanged();
 
   // Access the current view text.
   string16 GetViewText() const;
@@ -492,26 +481,6 @@
   bool has_temporary_text_;
   GURL original_url_;
 
-  // True if Instant set the current temporary text, as opposed to it being set
-  // due to the user arrowing up/down through the popup. This can only be true
-  // if |has_temporary_text_| is true.
-  // TODO(sreeram): This is a temporary hack. Remove it once the omnibox edit
-  // model/view code is decoupled from Instant (among other things).
-  bool is_temporary_text_set_by_instant_;
-
-  // The index of the selected AutocompleteMatch in AutocompleteResult. This is
-  // needed to get the metadata details of the temporary text set by instant on
-  // the Local NTP. If the Instant extended is disabled or an Instant NTP is
-  // used, this is set to OmniboxPopupModel::kNoMatch.
-  size_t selected_instant_autocomplete_match_index_;
-
-  // True if the current temporary text set by Instant is a search query; false
-  // if it is a URL that can be directly navigated to. This is only valid if
-  // |is_temporary_text_set_by_instant_| is true. This field is needed because
-  // Instant's temporary text doesn't come from the popup model, so we can't
-  // lookup its type from the current match.
-  bool is_instant_temporary_text_a_search_query_;
-
   // When the user's last action was to paste, we disallow inline autocomplete
   // (on the theory that the user is trying to paste in a new URL or part of
   // one, and in either case inline autocomplete would get in the way).
@@ -552,11 +521,6 @@
   // "foo", which is wrong.
   bool in_revert_;
 
-  // InstantController needs this in extended mode to distinguish the case in
-  // which it should instruct a committed search results page to revert to
-  // showing results for the original query.
-  bool in_escape_handler_;
-
   // Indicates if the upcoming autocomplete search is allowed to be treated as
   // an exact keyword match.  If this is true then keyword mode will be
   // triggered automatically if the input is "<keyword> <search string>".  We
diff --git a/chrome/browser/ui/omnibox/omnibox_view.cc b/chrome/browser/ui/omnibox/omnibox_view.cc
index 86b5bdd..50cc536 100644
--- a/chrome/browser/ui/omnibox/omnibox_view.cc
+++ b/chrome/browser/ui/omnibox/omnibox_view.cc
@@ -128,9 +128,16 @@
 }
 
 bool OmniboxView::IsImeShowingPopup() const {
-  // Since not all the IMEs/platforms support the detection of a IME's popup
-  // window, falls back to IsImeComposing().
-  return IsImeComposing();
+  // Default to claiming that the IME is not showing a popup, since hiding the
+  // omnibox dropdown is a bad user experience when we don't know for sure that
+  // we have to.
+  return false;
+}
+
+bool OmniboxView::IsIndicatingQueryRefinement() const {
+  // The default implementation always returns false.  Mobile ports can override
+  // this method and implement as needed.
+  return false;
 }
 
 OmniboxView::OmniboxView(Profile* profile,
diff --git a/chrome/browser/ui/omnibox/omnibox_view.h b/chrome/browser/ui/omnibox/omnibox_view.h
index 32e7810..972cac8 100644
--- a/chrome/browser/ui/omnibox/omnibox_view.h
+++ b/chrome/browser/ui/omnibox/omnibox_view.h
@@ -209,10 +209,17 @@
   // Returns true if the user is composing something in an IME.
   virtual bool IsImeComposing() const = 0;
 
-  // Returns true if an IME is showing a popup window, which may overlap
-  // the omnibox's popup window.
+  // Returns true if we know for sure that an IME is showing a popup window,
+  // which may overlap the omnibox's popup window.
   virtual bool IsImeShowingPopup() const;
 
+  // Returns true if the view is displaying UI that indicates that query
+  // refinement will take place when the user selects the current match.  For
+  // search matches, this will cause the omnibox to search over the existing
+  // corpus (e.g. Images) rather than start a new Web search.  This method will
+  // only ever return true on mobile ports.
+  virtual bool IsIndicatingQueryRefinement() const;
+
 #if defined(TOOLKIT_VIEWS)
   virtual int GetMaxEditWidth(int entry_width) const = 0;
 
diff --git a/chrome/browser/ui/omnibox/omnibox_view_browsertest.cc b/chrome/browser/ui/omnibox/omnibox_view_browsertest.cc
index 7e7ab10..0cda639 100644
--- a/chrome/browser/ui/omnibox/omnibox_view_browsertest.cc
+++ b/chrome/browser/ui/omnibox/omnibox_view_browsertest.cc
@@ -8,7 +8,7 @@
 #include "base/strings/string16.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/autocomplete/autocomplete_input.h"
 #include "chrome/browser/autocomplete/autocomplete_match.h"
@@ -580,7 +580,8 @@
                 GetController())));
 
     GURL url = browser()->tab_strip_model()->GetActiveWebContents()->GetURL();
-    EXPECT_STREQ(kDesiredTLDHostname, url.host().c_str());
+    EXPECT_EQ(kDesiredTLDHostname, url.host());
+    EXPECT_EQ("/", url.path());
   }
 
   void AltEnterTest() {
@@ -616,7 +617,7 @@
             &browser()->tab_strip_model()->GetActiveWebContents()->
                 GetController())));
     GURL url = browser()->tab_strip_model()->GetActiveWebContents()->GetURL();
-    EXPECT_STREQ(kSearchTextURL, url.spec().c_str());
+    EXPECT_EQ(kSearchTextURL, url.spec());
 
     // Test that entering a single character then Enter performs a search.
     chrome::FocusLocationBar(browser());
@@ -637,7 +638,7 @@
             &browser()->tab_strip_model()->GetActiveWebContents()->
                 GetController())));
     url = browser()->tab_strip_model()->GetActiveWebContents()->GetURL();
-    EXPECT_STREQ(kSearchSingleCharURL, url.spec().c_str());
+    EXPECT_EQ(kSearchSingleCharURL, url.spec());
   }
 
   void EscapeToDefaultMatchTest() {
@@ -1336,14 +1337,7 @@
 }
 #undef MAYBE_ESCAPE
 
-// http://crbug.com/131179
-#if defined(OS_LINUX)
-#define MAYBE_DesiredTLD DISABLED_DesiredTLD
-#else
-#define MAYBE_DesiredTLD DesiredTLD
-#endif
-
-IN_PROC_BROWSER_TEST_F(OmniboxViewTest, MAYBE_DesiredTLD) {
+IN_PROC_BROWSER_TEST_F(OmniboxViewTest, DesiredTLD) {
   DesiredTLDTest();
 }
 
diff --git a/chrome/browser/ui/panels/base_panel_browser_test.cc b/chrome/browser/ui/panels/base_panel_browser_test.cc
index 4cce306..8277ce2 100644
--- a/chrome/browser/ui/panels/base_panel_browser_test.cc
+++ b/chrome/browser/ui/panels/base_panel_browser_test.cc
@@ -14,6 +14,7 @@
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/panels/detached_panel_collection.h"
 #include "chrome/browser/ui/panels/native_panel.h"
 #include "chrome/browser/ui/panels/panel_collection.h"
@@ -447,6 +448,48 @@
   return panel;
 }
 
+Panel* BasePanelBrowserTest::CreateInactivePanel(const std::string& name) {
+  // Create an active panel first, instead of inactive panel. This is because
+  // certain window managers on Linux, like icewm, will always activate the
+  // new window.
+  Panel* panel = CreatePanel(name);
+
+  DeactivatePanel(panel);
+  WaitForPanelActiveState(panel, SHOW_AS_INACTIVE);
+
+  return panel;
+}
+
+Panel* BasePanelBrowserTest::CreateInactiveDetachedPanel(
+    const std::string& name, const gfx::Rect& bounds) {
+  // Create an active panel first, instead of inactive panel. This is because
+  // certain window managers on Linux, like icewm, will always activate the
+  // new window.
+  Panel* panel = CreateDetachedPanel(name, bounds);
+
+  DeactivatePanel(panel);
+  WaitForPanelActiveState(panel, SHOW_AS_INACTIVE);
+
+  return panel;
+}
+
+void BasePanelBrowserTest::DeactivatePanel(Panel* panel) {
+#if defined(OS_LINUX)
+  // For certain window managers on Linux, like icewm, panel activation and
+  // deactivation notification might not get tiggered when non-panel window is
+  // activated or deactivated. So we deactivate the panel directly.
+  panel->Deactivate();
+#else
+  // Make the panel lose focus by activating the browser window. This is
+  // because:
+  // 1) On Windows, deactivating the panel window might cause the application
+  //    to lose the foreground status. When this occurs, trying to activate
+  //    the panel window again will not be allowed by the system.
+  // 2) On MacOS, deactivating a window is not supported by Cocoa.
+  browser()->window()->Activate();
+#endif
+}
+
 // static
 NativePanelTesting* BasePanelBrowserTest::CreateNativePanelTesting(
     Panel* panel) {
diff --git a/chrome/browser/ui/panels/base_panel_browser_test.h b/chrome/browser/ui/panels/base_panel_browser_test.h
index 83b4820..c5e21b2 100644
--- a/chrome/browser/ui/panels/base_panel_browser_test.h
+++ b/chrome/browser/ui/panels/base_panel_browser_test.h
@@ -86,6 +86,12 @@
                             const gfx::Rect& bounds,
                             StackedPanelCollection* stack);
 
+  Panel* CreateInactivePanel(const std::string& name);
+  Panel* CreateInactiveDetachedPanel(const std::string& name,
+                                     const gfx::Rect& bounds);
+
+  void DeactivatePanel(Panel* panel);
+
   static NativePanelTesting* CreateNativePanelTesting(Panel* panel);
 
   void WaitForPanelActiveState(Panel* panel, ActiveState state);
diff --git a/chrome/browser/ui/panels/detached_panel_browsertest.cc b/chrome/browser/ui/panels/detached_panel_browsertest.cc
index e20501f..4b744dc 100644
--- a/chrome/browser/ui/panels/detached_panel_browsertest.cc
+++ b/chrome/browser/ui/panels/detached_panel_browsertest.cc
@@ -12,14 +12,7 @@
 class DetachedPanelBrowserTest : public BasePanelBrowserTest {
 };
 
-// http://crbug.com/143247
-#if !defined(OS_WIN)
-#define MAYBE_CheckDetachedPanelProperties DISABLED_CheckDetachedPanelProperties
-#else
-#define MAYBE_CheckDetachedPanelProperties CheckDetachedPanelProperties
-#endif
-IN_PROC_BROWSER_TEST_F(DetachedPanelBrowserTest,
-                       MAYBE_CheckDetachedPanelProperties) {
+IN_PROC_BROWSER_TEST_F(DetachedPanelBrowserTest, CheckDetachedPanelProperties) {
   PanelManager* panel_manager = PanelManager::GetInstance();
   DetachedPanelCollection* detached_collection =
       panel_manager->detached_collection();
@@ -46,7 +39,12 @@
   EXPECT_FALSE(panel->IsAlwaysOnTop());
 
   EXPECT_TRUE(panel_testing->IsButtonVisible(panel::CLOSE_BUTTON));
-  EXPECT_TRUE(panel_testing->IsButtonVisible(panel::MINIMIZE_BUTTON));
+  // The minimize button will not be shown on some Linux desktop environment
+  // that does not support system minimize.
+  if (PanelManager::CanUseSystemMinimize())
+    EXPECT_TRUE(panel_testing->IsButtonVisible(panel::MINIMIZE_BUTTON));
+  else
+    EXPECT_FALSE(panel_testing->IsButtonVisible(panel::MINIMIZE_BUTTON));
   EXPECT_FALSE(panel_testing->IsButtonVisible(panel::RESTORE_BUTTON));
 
   EXPECT_EQ(panel::RESIZABLE_ALL, panel->CanResizeByMouse());
@@ -61,13 +59,7 @@
   panel_manager->CloseAll();
 }
 
-// http://crbug.com/143247
-#if !defined(OS_WIN)
-#define MAYBE_DrawAttentionOnActive DISABLED_DrawAttentionOnActive
-#else
-#define MAYBE_DrawAttentionOnActive DrawAttentionOnActive
-#endif
-IN_PROC_BROWSER_TEST_F(DetachedPanelBrowserTest, MAYBE_DrawAttentionOnActive) {
+IN_PROC_BROWSER_TEST_F(DetachedPanelBrowserTest, DrawAttentionOnActive) {
   // Create a detached panel that is initially active.
   Panel* panel = CreateDetachedPanel("1", gfx::Rect(300, 200, 250, 200));
   scoped_ptr<NativePanelTesting> native_panel_testing(
@@ -75,7 +67,6 @@
 
   // Test that the attention should not be drawn if the detached panel is in
   // focus.
-  WaitForPanelActiveState(panel, SHOW_AS_ACTIVE);  // doublecheck active state
   EXPECT_FALSE(panel->IsDrawingAttention());
   panel->FlashFrame(true);
   EXPECT_FALSE(panel->IsDrawingAttention());
@@ -84,19 +75,10 @@
   panel->Close();
 }
 
-// http://crbug.com/143247
-#if !defined(OS_WIN)
-#define MAYBE_DrawAttentionOnInactive DISABLED_DrawAttentionOnInactive
-#else
-#define MAYBE_DrawAttentionOnInactive DrawAttentionOnInactive
-#endif
-IN_PROC_BROWSER_TEST_F(DetachedPanelBrowserTest,
-                       MAYBE_DrawAttentionOnInactive) {
-  // Create two panels so that first panel becomes inactive.
-  Panel* panel = CreateDetachedPanel("1", gfx::Rect(300, 200, 250, 200));
-  CreateDetachedPanel("2", gfx::Rect(100, 100, 250, 200));
-  WaitForPanelActiveState(panel, SHOW_AS_INACTIVE);
-
+IN_PROC_BROWSER_TEST_F(DetachedPanelBrowserTest, DrawAttentionOnInactive) {
+  // Create an inactive detached panel.
+  Panel* panel =
+      CreateInactiveDetachedPanel("1", gfx::Rect(300, 200, 250, 200));
   scoped_ptr<NativePanelTesting> native_panel_testing(
       CreateNativePanelTesting(panel));
 
@@ -115,55 +97,33 @@
   PanelManager::GetInstance()->CloseAll();
 }
 
-// http://crbug.com/143247
-#if !defined(OS_WIN)
-#define MAYBE_DrawAttentionResetOnActivate DISABLED_DrawAttentionResetOnActivate
-#else
-#define MAYBE_DrawAttentionResetOnActivate DrawAttentionResetOnActivate
-#endif
-IN_PROC_BROWSER_TEST_F(DetachedPanelBrowserTest,
-                       MAYBE_DrawAttentionResetOnActivate) {
-  // Create 2 panels so we end up with an inactive panel that can
-  // be made to draw attention.
-  Panel* panel1 = CreateDetachedPanel("test panel1",
-                                      gfx::Rect(300, 200, 250, 200));
-  Panel* panel2 = CreateDetachedPanel("test panel2",
-                                      gfx::Rect(100, 100, 250, 200));
-  WaitForPanelActiveState(panel1, SHOW_AS_INACTIVE);
-
+IN_PROC_BROWSER_TEST_F(DetachedPanelBrowserTest, DrawAttentionResetOnActivate) {
+  // Create an inactive detached panel.
+  Panel* panel =
+      CreateInactiveDetachedPanel("1", gfx::Rect(300, 200, 250, 200));
   scoped_ptr<NativePanelTesting> native_panel_testing(
-      CreateNativePanelTesting(panel1));
+      CreateNativePanelTesting(panel));
 
   // Test that the attention is drawn when the detached panel is not in focus.
-  panel1->FlashFrame(true);
-  EXPECT_TRUE(panel1->IsDrawingAttention());
+  panel->FlashFrame(true);
+  EXPECT_TRUE(panel->IsDrawingAttention());
   EXPECT_TRUE(native_panel_testing->VerifyDrawingAttention());
 
   // Test that the attention is cleared when panel gets focus.
-  panel1->Activate();
-  WaitForPanelActiveState(panel1, SHOW_AS_ACTIVE);
-  EXPECT_FALSE(panel1->IsDrawingAttention());
+  panel->Activate();
+  WaitForPanelActiveState(panel, SHOW_AS_ACTIVE);
+  EXPECT_FALSE(panel->IsDrawingAttention());
   EXPECT_FALSE(native_panel_testing->VerifyDrawingAttention());
 
-  panel1->Close();
-  panel2->Close();
+  PanelManager::GetInstance()->CloseAll();
 }
 
-// http://crbug.com/143247
-#if !defined(OS_WIN)
-#define MAYBE_ClickTitlebar DISABLED_ClickTitlebar
-#else
-#define MAYBE_ClickTitlebar ClickTitlebar
-#endif
-IN_PROC_BROWSER_TEST_F(DetachedPanelBrowserTest, MAYBE_ClickTitlebar) {
-  PanelManager* panel_manager = PanelManager::GetInstance();
-
+IN_PROC_BROWSER_TEST_F(DetachedPanelBrowserTest, ClickTitlebar) {
   Panel* panel = CreateDetachedPanel("1", gfx::Rect(300, 200, 250, 200));
   EXPECT_FALSE(panel->IsMinimized());
 
   // Clicking on an active detached panel's titlebar has no effect, regardless
   // of modifier.
-  WaitForPanelActiveState(panel, SHOW_AS_ACTIVE);  // doublecheck active state
   scoped_ptr<NativePanelTesting> test_panel(
       CreateNativePanelTesting(panel));
   test_panel->PressLeftMouseButtonTitlebar(panel->GetBounds().origin());
@@ -177,17 +137,14 @@
   EXPECT_TRUE(panel->IsActive());
   EXPECT_FALSE(panel->IsMinimized());
 
-  // Create a second panel to cause the first to become inactive.
-  CreateDetachedPanel("2", gfx::Rect(100, 200, 230, 345));
-  WaitForPanelActiveState(panel, SHOW_AS_INACTIVE);
-
   // Clicking on an inactive detached panel's titlebar activates it.
+  DeactivatePanel(panel);
   test_panel->PressLeftMouseButtonTitlebar(panel->GetBounds().origin());
   test_panel->ReleaseMouseButtonTitlebar();
   WaitForPanelActiveState(panel, SHOW_AS_ACTIVE);
   EXPECT_FALSE(panel->IsMinimized());
 
-  panel_manager->CloseAll();
+  PanelManager::GetInstance()->CloseAll();
 }
 
 IN_PROC_BROWSER_TEST_F(DetachedPanelBrowserTest,
diff --git a/chrome/browser/ui/panels/display_settings_provider.h b/chrome/browser/ui/panels/display_settings_provider.h
index 5dc527d..da3df1d 100644
--- a/chrome/browser/ui/panels/display_settings_provider.h
+++ b/chrome/browser/ui/panels/display_settings_provider.h
@@ -6,7 +6,7 @@
 #define CHROME_BROWSER_UI_PANELS_DISPLAY_SETTINGS_PROVIDER_H_
 
 #include "base/observer_list.h"
-#include "base/timer.h"
+#include "base/timer/timer.h"
 #include "ui/gfx/rect.h"
 
 // Encapsulates the logic to provide display settings support, including the
diff --git a/chrome/browser/ui/panels/display_settings_provider_win.h b/chrome/browser/ui/panels/display_settings_provider_win.h
index 50343ba..75b0674 100644
--- a/chrome/browser/ui/panels/display_settings_provider_win.h
+++ b/chrome/browser/ui/panels/display_settings_provider_win.h
@@ -9,7 +9,7 @@
 
 #include <windows.h>
 #include "base/compiler_specific.h"
-#include "base/timer.h"
+#include "base/timer/timer.h"
 
 class DisplaySettingsProviderWin : public DisplaySettingsProvider {
  public:
diff --git a/chrome/browser/ui/panels/panel_browsertest.cc b/chrome/browser/ui/panels/panel_browsertest.cc
index 7148c24..6b5dccf 100644
--- a/chrome/browser/ui/panels/panel_browsertest.cc
+++ b/chrome/browser/ui/panels/panel_browsertest.cc
@@ -503,16 +503,10 @@
   panel->Close();
 }
 
-#if defined(OS_LINUX) || defined(OS_WIN)
-// There is no animations on Linux, by design (http://crbug.com/144074).
-// And there are intermittent/flaky failures on windows try bots
-// (http://crbug.com/179069).
-#define MAYBE_AnimateBounds DISABLED_AnimateBounds
-#else
-#define MAYBE_AnimateBounds AnimateBounds
-#endif
-IN_PROC_BROWSER_TEST_F(PanelBrowserTest, MAYBE_AnimateBounds) {
-  Panel* panel = CreatePanelWithBounds("PanelTest", gfx::Rect(0, 0, 100, 100));
+IN_PROC_BROWSER_TEST_F(PanelBrowserTest, AnimateBounds) {
+  // Create a detached panel, instead of docked panel because it cannot be
+  // moved to any location.
+  Panel* panel = CreateDetachedPanel("1", gfx::Rect(200, 100, 100, 100));
   scoped_ptr<NativePanelTesting> panel_testing(
       CreateNativePanelTesting(panel));
 
@@ -527,8 +521,11 @@
   // Set bounds with animation.
   gfx::Rect bounds = gfx::Rect(10, 20, 150, 160);
   panel->SetPanelBounds(bounds);
+  // There is no animation on Linux, by design.
+#if !defined(OS_LINUX)
   EXPECT_TRUE(panel_testing->IsAnimatingBounds());
   WaitForBoundsAnimationFinished(panel);
+#endif
   EXPECT_FALSE(panel_testing->IsAnimatingBounds());
   EXPECT_EQ(bounds, panel->GetBounds());
 
@@ -1046,15 +1043,8 @@
   EXPECT_FALSE(tabbed_window->IsActive());
 }
 
-// http://crbug.com/143247
-#if !defined(OS_WIN)
-#define MAYBE_DrawAttentionBasic DISABLED_DrawAttentionBasic
-#else
-#define MAYBE_DrawAttentionBasic DrawAttentionBasic
-#endif
-IN_PROC_BROWSER_TEST_F(PanelBrowserTest, MAYBE_DrawAttentionBasic) {
-  CreatePanelParams params("Initially Inactive", gfx::Rect(), SHOW_AS_INACTIVE);
-  Panel* panel = CreatePanelWithParams(params);
+IN_PROC_BROWSER_TEST_F(PanelBrowserTest, DrawAttentionBasic) {
+  Panel* panel = CreateInactivePanel("P1");
   scoped_ptr<NativePanelTesting> native_panel_testing(
       CreateNativePanelTesting(panel));
 
@@ -1087,70 +1077,50 @@
   panel->Close();
 }
 
-// http://crbug.com/143247
-#if !defined(OS_WIN)
-#define MAYBE_DrawAttentionWhileMinimized DISABLED_DrawAttentionWhileMinimized
-#else
-#define MAYBE_DrawAttentionWhileMinimized DrawAttentionWhileMinimized
-#endif
-IN_PROC_BROWSER_TEST_F(PanelBrowserTest, MAYBE_DrawAttentionWhileMinimized) {
-  // Create 3 panels so we end up with an inactive panel that can
-  // be made to draw attention.
-  Panel* panel = CreatePanel("test panel1");
-  Panel* panel2 = CreatePanel("test panel2");
-  Panel* panel3 = CreatePanel("test panel3");
+IN_PROC_BROWSER_TEST_F(PanelBrowserTest, DrawAttentionWhileMinimized) {
+  Panel* panel1 = CreateInactivePanel("P1");
+  Panel* panel2 = CreateInactivePanel("P2");
 
-  scoped_ptr<NativePanelTesting> native_panel_testing(
-      CreateNativePanelTesting(panel));
+  scoped_ptr<NativePanelTesting> native_panel1_testing(
+      CreateNativePanelTesting(panel1));
 
   // Test that the attention is drawn and the title-bar is brought up when the
   // minimized panel is drawing attention.
-  panel->Minimize();
-  EXPECT_EQ(Panel::MINIMIZED, panel->expansion_state());
-  panel->FlashFrame(true);
-  EXPECT_TRUE(panel->IsDrawingAttention());
-  EXPECT_EQ(Panel::TITLE_ONLY, panel->expansion_state());
-  EXPECT_TRUE(native_panel_testing->VerifyDrawingAttention());
+  panel1->Minimize();
+  EXPECT_EQ(Panel::MINIMIZED, panel1->expansion_state());
+  panel1->FlashFrame(true);
+  EXPECT_TRUE(panel1->IsDrawingAttention());
+  EXPECT_EQ(Panel::TITLE_ONLY, panel1->expansion_state());
+  EXPECT_TRUE(native_panel1_testing->VerifyDrawingAttention());
 
   // Test that we cannot bring up other minimized panel if the mouse is over
   // the panel that draws attension.
   panel2->Minimize();
-  gfx::Point hover_point(panel->GetBounds().origin());
+  gfx::Point hover_point(panel1->GetBounds().origin());
   MoveMouse(hover_point);
-  EXPECT_EQ(Panel::TITLE_ONLY, panel->expansion_state());
+  EXPECT_EQ(Panel::TITLE_ONLY, panel1->expansion_state());
   EXPECT_EQ(Panel::MINIMIZED, panel2->expansion_state());
 
   // Test that we cannot bring down the panel that is drawing the attention.
   hover_point.set_y(hover_point.y() - 200);
   MoveMouse(hover_point);
-  EXPECT_EQ(Panel::TITLE_ONLY, panel->expansion_state());
+  EXPECT_EQ(Panel::TITLE_ONLY, panel1->expansion_state());
 
   // Test that the attention is cleared when activated.
-  panel->Activate();
-  WaitForPanelActiveState(panel, SHOW_AS_ACTIVE);
-  EXPECT_FALSE(panel->IsDrawingAttention());
-  EXPECT_EQ(Panel::EXPANDED, panel->expansion_state());
-  EXPECT_FALSE(native_panel_testing->VerifyDrawingAttention());
+  panel1->Activate();
+  WaitForPanelActiveState(panel1, SHOW_AS_ACTIVE);
+  EXPECT_FALSE(panel1->IsDrawingAttention());
+  EXPECT_EQ(Panel::EXPANDED, panel1->expansion_state());
+  EXPECT_FALSE(native_panel1_testing->VerifyDrawingAttention());
 
-  panel->Close();
-  panel2->Close();
-  panel3->Close();
+  PanelManager::GetInstance()->CloseAll();
 }
 
-// http://crbug.com/175760; several panel tests failing regularly on mac.
-#if defined(OS_MACOSX) || defined(OS_LINUX)
-#define MAYBE_StopDrawingAttentionWhileMinimized \
-  DISABLED_StopDrawingAttentionWhileMinimized
-#else
-#define MAYBE_StopDrawingAttentionWhileMinimized \
-  StopDrawingAttentionWhileMinimized
-#endif
 // Verify that minimized state of a panel is correct after draw attention
 // is stopped when there are other minimized panels.
-IN_PROC_BROWSER_TEST_F(PanelBrowserTest,
-                       MAYBE_StopDrawingAttentionWhileMinimized) {
-  Panel* panel1 = CreatePanel("panel1");
-  Panel* panel2 = CreatePanel("panel2");
+IN_PROC_BROWSER_TEST_F(PanelBrowserTest, StopDrawingAttentionWhileMinimized) {
+  Panel* panel1 = CreateInactivePanel("P1");
+  Panel* panel2 = CreateInactivePanel("P2");
 
   panel1->Minimize();
   EXPECT_EQ(Panel::MINIMIZED, panel1->expansion_state());
@@ -1214,21 +1184,17 @@
   EXPECT_EQ(Panel::MINIMIZED, panel1->expansion_state());
   EXPECT_EQ(Panel::MINIMIZED, panel2->expansion_state());
 
-  panel1->Close();
-  panel2->Close();
+  PanelManager::GetInstance()->CloseAll();
 }
 
 IN_PROC_BROWSER_TEST_F(PanelBrowserTest, DrawAttentionWhenActive) {
-  CreatePanelParams params("Initially Active", gfx::Rect(), SHOW_AS_ACTIVE);
-  Panel* panel = CreatePanelWithParams(params);
+  // Create an active panel.
+  Panel* panel = CreatePanel("P1");
   scoped_ptr<NativePanelTesting> native_panel_testing(
       CreateNativePanelTesting(panel));
 
   // Test that the attention should not be drawn if the expanded panel is in
   // focus.
-  EXPECT_EQ(Panel::EXPANDED, panel->expansion_state());
-  WaitForPanelActiveState(panel, SHOW_AS_ACTIVE);  // doublecheck active state
-  EXPECT_FALSE(panel->IsDrawingAttention());
   panel->FlashFrame(true);
   EXPECT_FALSE(panel->IsDrawingAttention());
   EXPECT_FALSE(native_panel_testing->VerifyDrawingAttention());
@@ -1236,19 +1202,8 @@
   panel->Close();
 }
 
-// http://crbug.com/143247
-#if !defined(OS_WIN)
-#define MAYBE_DrawAttentionResetOnActivate DISABLED_DrawAttentionResetOnActivate
-#else
-#define MAYBE_DrawAttentionResetOnActivate DrawAttentionResetOnActivate
-#endif
-IN_PROC_BROWSER_TEST_F(PanelBrowserTest, MAYBE_DrawAttentionResetOnActivate) {
-  // Create 2 panels so we end up with an inactive panel that can
-  // be made to draw attention.
-  Panel* panel = CreatePanel("test panel1");
-  Panel* panel2 = CreatePanel("test panel2");
-  WaitForPanelActiveState(panel, SHOW_AS_INACTIVE);
-
+IN_PROC_BROWSER_TEST_F(PanelBrowserTest, DrawAttentionResetOnActivate) {
+  Panel* panel = CreateInactivePanel("P1");
   scoped_ptr<NativePanelTesting> native_panel_testing(
       CreateNativePanelTesting(panel));
 
@@ -1263,59 +1218,36 @@
   EXPECT_FALSE(native_panel_testing->VerifyDrawingAttention());
 
   panel->Close();
-  panel2->Close();
 }
 
-// http://crbug.com/143247
-#if !defined(OS_WIN)
-#define MAYBE_DrawAttentionMinimizedNotResetOnActivate DISABLED_DrawAttentionMinimizedNotResetOnActivate
-#else
-#define MAYBE_DrawAttentionMinimizedNotResetOnActivate DrawAttentionMinimizedNotResetOnActivate
-#endif
 IN_PROC_BROWSER_TEST_F(PanelBrowserTest,
-                       MAYBE_DrawAttentionMinimizedNotResetOnActivate) {
-  // Create 2 panels so we end up with an inactive panel that can
-  // be made to draw attention.
-  Panel* panel1 = CreatePanel("test panel1");
-  Panel* panel2 = CreatePanel("test panel2");
-  WaitForPanelActiveState(panel1, SHOW_AS_INACTIVE);
+                       DrawAttentionMinimizedNotResetOnActivate) {
+  Panel* panel = CreateInactivePanel("P1");
 
-  panel1->Minimize();
-  EXPECT_TRUE(panel1->IsMinimized());
-  panel1->FlashFrame(true);
-  EXPECT_TRUE(panel1->IsDrawingAttention());
+  panel->Minimize();
+  EXPECT_TRUE(panel->IsMinimized());
+  panel->FlashFrame(true);
+  EXPECT_TRUE(panel->IsDrawingAttention());
 
   // Simulate panel being activated while minimized. Cannot call
   // Activate() as that expands the panel.
-  panel1->OnActiveStateChanged(true);
-  EXPECT_TRUE(panel1->IsDrawingAttention());  // Unchanged.
+  panel->OnActiveStateChanged(true);
+  EXPECT_TRUE(panel->IsDrawingAttention());  // Unchanged.
 
   // Unminimize panel to show that attention would have been cleared
   // if panel had not been minimized.
-  panel1->Restore();
-  EXPECT_FALSE(panel1->IsMinimized());
-  EXPECT_TRUE(panel1->IsDrawingAttention());  // Unchanged.
+  panel->Restore();
+  EXPECT_FALSE(panel->IsMinimized());
+  EXPECT_TRUE(panel->IsDrawingAttention());  // Unchanged.
 
-  panel1->OnActiveStateChanged(true);
-  EXPECT_FALSE(panel1->IsDrawingAttention());  // Attention cleared.
+  panel->OnActiveStateChanged(true);
+  EXPECT_FALSE(panel->IsDrawingAttention());  // Attention cleared.
 
-  panel1->Close();
-  panel2->Close();
+  panel->Close();
 }
 
-// http://crbug.com/143247
-#if !defined(OS_WIN)
-#define MAYBE_DrawAttentionResetOnClick DISABLED_DrawAttentionResetOnClick
-#else
-#define MAYBE_DrawAttentionResetOnClick DrawAttentionResetOnClick
-#endif
-IN_PROC_BROWSER_TEST_F(PanelBrowserTest, MAYBE_DrawAttentionResetOnClick) {
-  // Create 2 panels so we end up with an inactive panel that can
-  // be made to draw attention.
-  Panel* panel = CreatePanel("test panel1");
-  Panel* panel2 = CreatePanel("test panel2");
-  WaitForPanelActiveState(panel, SHOW_AS_INACTIVE);
-
+IN_PROC_BROWSER_TEST_F(PanelBrowserTest, DrawAttentionResetOnClick) {
+  Panel* panel = CreateInactivePanel("P1");
   scoped_ptr<NativePanelTesting> native_panel_testing(
       CreateNativePanelTesting(panel));
 
@@ -1333,7 +1265,6 @@
   EXPECT_FALSE(native_panel_testing->VerifyDrawingAttention());
 
   panel->Close();
-  panel2->Close();
 }
 
 // http://crbug.com/175760; several panel tests failing regularly on mac.
@@ -1448,14 +1379,8 @@
   panel2->Close();
 }
 
-// http://crbug.com/143247
-#if !defined(OS_WIN)
-#define MAYBE_NonExtensionDomainPanelsCloseOnUninstall DISABLED_NonExtensionDomainPanelsCloseOnUninstall
-#else
-#define MAYBE_NonExtensionDomainPanelsCloseOnUninstall NonExtensionDomainPanelsCloseOnUninstall
-#endif
 IN_PROC_BROWSER_TEST_F(PanelBrowserTest,
-                       MAYBE_NonExtensionDomainPanelsCloseOnUninstall) {
+                       NonExtensionDomainPanelsCloseOnUninstall) {
   // Create a test extension.
   DictionaryValue empty_value;
   scoped_refptr<extensions::Extension> extension =
@@ -1468,7 +1393,7 @@
   EXPECT_EQ(0, panel_manager->num_panels());
 
   // Create a panel with the extension as host.
-  CreatePanelParams params(extension_app_name, gfx::Rect(), SHOW_AS_INACTIVE);
+  CreatePanelParams params(extension_app_name, gfx::Rect(), SHOW_AS_ACTIVE);
   std::string extension_domain_url(extensions::kExtensionScheme);
   extension_domain_url += "://";
   extension_domain_url += extension->id();
@@ -1478,7 +1403,7 @@
   EXPECT_EQ(1, panel_manager->num_panels());
 
   // Create a panel with a non-extension host.
-  CreatePanelParams params1(extension_app_name, gfx::Rect(), SHOW_AS_INACTIVE);
+  CreatePanelParams params1(extension_app_name, gfx::Rect(), SHOW_AS_ACTIVE);
   params1.url = GURL(content::kAboutBlankURL);
   Panel* panel1 = CreatePanelWithParams(params1);
   EXPECT_EQ(2, panel_manager->num_panels());
@@ -1685,12 +1610,6 @@
   panel->Close();
 }
 
-// http://crbug.com/175760; several panel tests failing regularly on mac.
-#if defined(OS_MACOSX)
-#define MAYBE_DevTools DISABLED_DevTools
-#else
-#define MAYBE_DevTools DevTools
-#endif
 IN_PROC_BROWSER_TEST_F(PanelBrowserTest, DevTools) {
   // Create a test panel with web contents loaded.
   CreatePanelParams params("1", gfx::Rect(0, 0, 200, 220), SHOW_AS_ACTIVE);
@@ -1725,12 +1644,6 @@
   panel->Close();
 }
 
-// http://crbug.com/175760; several panel tests failing regularly on mac.
-#if defined(OS_MACOSX)
-#define MAYBE_DevToolsConsole DISABLED_DevToolsConsole
-#else
-#define MAYBE_DevToolsConsole DevToolsConsole
-#endif
 IN_PROC_BROWSER_TEST_F(PanelBrowserTest, DevToolsConsole) {
   // Create a test panel with web contents loaded.
   CreatePanelParams params("1", gfx::Rect(0, 0, 200, 220), SHOW_AS_ACTIVE);
diff --git a/chrome/browser/ui/panels/panel_drag_browsertest.cc b/chrome/browser/ui/panels/panel_drag_browsertest.cc
index 1cd2603..f88a649 100644
--- a/chrome/browser/ui/panels/panel_drag_browsertest.cc
+++ b/chrome/browser/ui/panels/panel_drag_browsertest.cc
@@ -820,47 +820,37 @@
   PanelManager::GetInstance()->CloseAll();
 }
 
-IN_PROC_BROWSER_TEST_F(PanelDragBrowserTest,
-                       DISABLED_CloseDetachedPanelOnDrag) {
+IN_PROC_BROWSER_TEST_F(PanelDragBrowserTest, CloseDetachedPanelOnDrag) {
   PanelManager* panel_manager = PanelManager::GetInstance();
   PanelDragController* drag_controller = panel_manager->drag_controller();
   DetachedPanelCollection* detached_collection =
       panel_manager->detached_collection();
 
-  // Create 4 detached panels.
+  // Create 1 detached panel.
   Panel* panel1 = CreateDetachedPanel("1", gfx::Rect(100, 200, 100, 100));
-  Panel* panel2 = CreateDetachedPanel("2", gfx::Rect(200, 210, 110, 110));
-  Panel* panel3 = CreateDetachedPanel("3", gfx::Rect(300, 220, 120, 120));
-  Panel* panel4 = CreateDetachedPanel("4", gfx::Rect(400, 230, 130, 130));
-  ASSERT_EQ(4, detached_collection->num_panels());
+  ASSERT_EQ(1, detached_collection->num_panels());
 
   scoped_ptr<NativePanelTesting> panel1_testing(
       CreateNativePanelTesting(panel1));
   gfx::Point panel1_old_position = panel1->GetBounds().origin();
-  gfx::Point panel2_position = panel2->GetBounds().origin();
-  gfx::Point panel3_position = panel3->GetBounds().origin();
-  gfx::Point panel4_position = panel4->GetBounds().origin();
 
   // Test the scenario: drag a panel, close another panel, cancel the drag.
   {
-    gfx::Point panel1_new_position = panel1_old_position;
-    panel1_new_position.Offset(-51, -102);
+    // Create a panel to be closed.
+    Panel* panel2 = CreateDetachedPanel("2", gfx::Rect(300, 210, 110, 110));
 
     // Start dragging a panel.
     panel1_testing->PressLeftMouseButtonTitlebar(panel1->GetBounds().origin());
+    gfx::Point panel1_new_position = panel1_old_position;
+    panel1_new_position.Offset(-51, -102);
     panel1_testing->DragTitlebar(panel1_new_position);
     EXPECT_TRUE(drag_controller->is_dragging());
     EXPECT_EQ(panel1, drag_controller->dragging_panel());
 
-    ASSERT_EQ(4, detached_collection->num_panels());
+    ASSERT_EQ(2, detached_collection->num_panels());
     EXPECT_TRUE(detached_collection->HasPanel(panel1));
     EXPECT_TRUE(detached_collection->HasPanel(panel2));
-    EXPECT_TRUE(detached_collection->HasPanel(panel3));
-    EXPECT_TRUE(detached_collection->HasPanel(panel4));
     EXPECT_EQ(panel1_new_position, panel1->GetBounds().origin());
-    EXPECT_EQ(panel2_position, panel2->GetBounds().origin());
-    EXPECT_EQ(panel3_position, panel3->GetBounds().origin());
-    EXPECT_EQ(panel4_position, panel4->GetBounds().origin());
 
     // Closing another panel while dragging in progress will keep the dragging
     // panel intact.
@@ -868,86 +858,64 @@
     EXPECT_TRUE(drag_controller->is_dragging());
     EXPECT_EQ(panel1, drag_controller->dragging_panel());
 
-    ASSERT_EQ(3, detached_collection->num_panels());
+    ASSERT_EQ(1, detached_collection->num_panels());
     EXPECT_TRUE(detached_collection->HasPanel(panel1));
-    EXPECT_TRUE(detached_collection->HasPanel(panel3));
-    EXPECT_TRUE(detached_collection->HasPanel(panel4));
     EXPECT_EQ(panel1_new_position, panel1->GetBounds().origin());
-    EXPECT_EQ(panel3_position, panel3->GetBounds().origin());
-    EXPECT_EQ(panel4_position, panel4->GetBounds().origin());
 
     // Cancel the drag.
     panel1_testing->CancelDragTitlebar();
     WaitForBoundsAnimationFinished(panel1);
     EXPECT_FALSE(drag_controller->is_dragging());
-
-    ASSERT_EQ(3, detached_collection->num_panels());
-    EXPECT_TRUE(detached_collection->HasPanel(panel1));
-    EXPECT_TRUE(detached_collection->HasPanel(panel3));
-    EXPECT_TRUE(detached_collection->HasPanel(panel4));
     EXPECT_EQ(panel1_old_position, panel1->GetBounds().origin());
-    EXPECT_EQ(panel3_position, panel3->GetBounds().origin());
-    EXPECT_EQ(panel4_position, panel4->GetBounds().origin());
   }
 
   // Test the scenario: drag a panel, close another panel, end the drag.
   {
-    gfx::Point panel1_new_position = panel1_old_position;
-    panel1_new_position.Offset(-51, -102);
+    // Create a panel to be closed.
+    Panel* panel2 = CreateDetachedPanel("2", gfx::Rect(300, 210, 110, 110));
 
     // Start dragging a panel.
     panel1_testing->PressLeftMouseButtonTitlebar(panel1->GetBounds().origin());
+    gfx::Point panel1_new_position = panel1_old_position;
+    panel1_new_position.Offset(-51, -102);
     panel1_testing->DragTitlebar(panel1_new_position);
     EXPECT_TRUE(drag_controller->is_dragging());
     EXPECT_EQ(panel1, drag_controller->dragging_panel());
 
-    ASSERT_EQ(3, detached_collection->num_panels());
-    EXPECT_TRUE(detached_collection->HasPanel(panel1));
-    EXPECT_TRUE(detached_collection->HasPanel(panel3));
-    EXPECT_TRUE(detached_collection->HasPanel(panel4));
-    EXPECT_EQ(panel1_new_position, panel1->GetBounds().origin());
-    EXPECT_EQ(panel3_position, panel3->GetBounds().origin());
-    EXPECT_EQ(panel4_position, panel4->GetBounds().origin());
-
-    // Closing another panel while dragging in progress will keep the dragging
-    // panel intact.
-    CloseWindowAndWait(panel3);
-    EXPECT_TRUE(drag_controller->is_dragging());
-    EXPECT_EQ(panel1, drag_controller->dragging_panel());
-
     ASSERT_EQ(2, detached_collection->num_panels());
     EXPECT_TRUE(detached_collection->HasPanel(panel1));
-    EXPECT_TRUE(detached_collection->HasPanel(panel4));
+    EXPECT_TRUE(detached_collection->HasPanel(panel2));
     EXPECT_EQ(panel1_new_position, panel1->GetBounds().origin());
-    EXPECT_EQ(panel4_position, panel4->GetBounds().origin());
+
+    // Closing another panel while dragging in progress will keep the dragging
+    // panel intact.
+    CloseWindowAndWait(panel2);
+    EXPECT_TRUE(drag_controller->is_dragging());
+    EXPECT_EQ(panel1, drag_controller->dragging_panel());
+
+    ASSERT_EQ(1, detached_collection->num_panels());
+    EXPECT_TRUE(detached_collection->HasPanel(panel1));
+    EXPECT_EQ(panel1_new_position, panel1->GetBounds().origin());
 
     // Finish the drag.
     panel1_testing->FinishDragTitlebar();
     EXPECT_FALSE(drag_controller->is_dragging());
-
-    ASSERT_EQ(2, detached_collection->num_panels());
-    EXPECT_TRUE(detached_collection->HasPanel(panel1));
-    EXPECT_TRUE(detached_collection->HasPanel(panel4));
     EXPECT_EQ(panel1_new_position, panel1->GetBounds().origin());
-    EXPECT_EQ(panel4_position, panel4->GetBounds().origin());
   }
 
   // Test the scenario: drag a panel and close the dragging panel.
   {
-    gfx::Point panel1_new_position = panel1->GetBounds().origin();
-    panel1_new_position.Offset(-51, -102);
-
     // Start dragging a panel again.
     panel1_testing->PressLeftMouseButtonTitlebar(panel1->GetBounds().origin());
+    gfx::Point panel1_new_position = panel1->GetBounds().origin();
+    panel1_new_position.Offset(45, 67);
     panel1_testing->DragTitlebar(panel1_new_position);
     EXPECT_TRUE(drag_controller->is_dragging());
     EXPECT_EQ(panel1, drag_controller->dragging_panel());
 
-    ASSERT_EQ(2, detached_collection->num_panels());
+    ASSERT_EQ(1, detached_collection->num_panels());
     EXPECT_TRUE(detached_collection->HasPanel(panel1));
-    EXPECT_TRUE(detached_collection->HasPanel(panel4));
     EXPECT_EQ(panel1_new_position, panel1->GetBounds().origin());
-    EXPECT_EQ(panel4_position, panel4->GetBounds().origin());
 
     // Closing the dragging panel should make the drag controller abort.
     content::WindowedNotificationObserver signal(
@@ -962,12 +930,8 @@
 
     // Wait till the panel is fully closed.
     signal.Wait();
-    ASSERT_EQ(1, detached_collection->num_panels());
-    EXPECT_TRUE(detached_collection->HasPanel(panel4));
-    EXPECT_EQ(panel4_position, panel4->GetBounds().origin());
+    ASSERT_EQ(0, detached_collection->num_panels());
   }
-
-  panel_manager->CloseAll();
 }
 
 IN_PROC_BROWSER_TEST_F(PanelDragBrowserTest, Detach) {
@@ -1278,21 +1242,12 @@
   panel_manager->CloseAll();
 }
 
-// http://crbug.com/175760; several panel tests failing regularly on mac.
-// http://crbug.com/240459 some panel tests are flaky on Linux/GTK.
-#if defined(OS_MACOSX) || defined(TOOLKIT_GTK)
-#define MAYBE_DetachWithSqueeze DISABLED_DetachWithSqueeze
-#else
-#define MAYBE_DetachWithSqueeze DetachWithSqueeze
-#endif
-IN_PROC_BROWSER_TEST_F(PanelDragBrowserTest, MAYBE_DetachWithSqueeze) {
+IN_PROC_BROWSER_TEST_F(PanelDragBrowserTest, DetachWithSqueeze) {
   PanelManager* panel_manager = PanelManager::GetInstance();
   DockedPanelCollection* docked_collection = panel_manager->docked_collection();
   DetachedPanelCollection* detached_collection =
       panel_manager->detached_collection();
 
-  gfx::Vector2d drag_delta_to_detach = GetDragDeltaToDetach();
-
   // Create some docked panels.
   //   docked:    P1  P2  P3  P4  P5
   Panel* panel1 = CreateDockedPanel("1", gfx::Rect(0, 0, 200, 100));
@@ -1308,7 +1263,8 @@
   //   detached:  P2
   //   docked:    P1  P3  P4 P5
   gfx::Point panel2_docked_position = panel2->GetBounds().origin();
-  DragPanelByDelta(panel2, drag_delta_to_detach);
+  gfx::Vector2d drag_delta_to_detach_panel2(-20, -100);
+  DragPanelByDelta(panel2, drag_delta_to_detach_panel2);
   ASSERT_EQ(1, detached_collection->num_panels());
   ASSERT_EQ(4, docked_collection->num_panels());
   EXPECT_EQ(PanelCollection::DOCKED, panel1->collection()->type());
@@ -1317,7 +1273,7 @@
   EXPECT_EQ(PanelCollection::DOCKED, panel4->collection()->type());
   EXPECT_EQ(PanelCollection::DOCKED, panel5->collection()->type());
   gfx::Point panel2_new_position =
-      panel2_docked_position + drag_delta_to_detach;
+      panel2_docked_position + drag_delta_to_detach_panel2;
   EXPECT_EQ(panel2_new_position, panel2->GetBounds().origin());
 
   // Drag to detach the left-most docked panel.
@@ -1325,7 +1281,8 @@
   //   detached:  P2  P4
   //   docked:    P1  P3  P5
   gfx::Point panel4_docked_position = panel4->GetBounds().origin();
-  DragPanelByDelta(panel4, drag_delta_to_detach);
+  gfx::Vector2d drag_delta_to_detach_panel4(-40, -250);
+  DragPanelByDelta(panel4, drag_delta_to_detach_panel4);
   ASSERT_EQ(2, detached_collection->num_panels());
   ASSERT_EQ(3, docked_collection->num_panels());
   EXPECT_EQ(PanelCollection::DOCKED, panel1->collection()->type());
@@ -1335,7 +1292,7 @@
   EXPECT_EQ(PanelCollection::DOCKED, panel5->collection()->type());
   EXPECT_EQ(panel2_new_position, panel2->GetBounds().origin());
   gfx::Point panel4_new_position =
-      panel4_docked_position + drag_delta_to_detach;
+      panel4_docked_position + drag_delta_to_detach_panel4;
   EXPECT_EQ(panel4_new_position, panel4->GetBounds().origin());
 
   // Drag to detach the right-most docked panel.
@@ -1344,8 +1301,8 @@
   //   docked:    P3  P5
   gfx::Point docked_position1 = panel1->GetBounds().origin();
   gfx::Point docked_position2 = panel3->GetBounds().origin();
-
-  DragPanelByDelta(panel1, drag_delta_to_detach);
+  gfx::Vector2d drag_delta_to_detach_panel1(-60, -400);
+  DragPanelByDelta(panel1, drag_delta_to_detach_panel1);
   ASSERT_EQ(3, detached_collection->num_panels());
   ASSERT_EQ(2, docked_collection->num_panels());
   EXPECT_EQ(PanelCollection::DETACHED, panel1->collection()->type());
@@ -1353,7 +1310,8 @@
   EXPECT_EQ(PanelCollection::DOCKED, panel3->collection()->type());
   EXPECT_EQ(PanelCollection::DETACHED, panel4->collection()->type());
   EXPECT_EQ(PanelCollection::DOCKED, panel5->collection()->type());
-  gfx::Point panel1_new_position = docked_position1 + drag_delta_to_detach;
+  gfx::Point panel1_new_position =
+      docked_position1 + drag_delta_to_detach_panel1;
   EXPECT_EQ(panel1_new_position, panel1->GetBounds().origin());
   EXPECT_EQ(panel2_new_position, panel2->GetBounds().origin());
   EXPECT_EQ(panel4_new_position, panel4->GetBounds().origin());
diff --git a/chrome/browser/ui/panels/panel_mouse_watcher_timer.cc b/chrome/browser/ui/panels/panel_mouse_watcher_timer.cc
index 029a835..0572eda 100644
--- a/chrome/browser/ui/panels/panel_mouse_watcher_timer.cc
+++ b/chrome/browser/ui/panels/panel_mouse_watcher_timer.cc
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "base/time.h"
-#include "base/timer.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
 #include "chrome/browser/ui/panels/panel_mouse_watcher.h"
 #include "ui/gfx/screen.h"
 
diff --git a/chrome/browser/ui/panels/stacked_panel_browsertest.cc b/chrome/browser/ui/panels/stacked_panel_browsertest.cc
index e019ee2..dbc55e4 100644
--- a/chrome/browser/ui/panels/stacked_panel_browsertest.cc
+++ b/chrome/browser/ui/panels/stacked_panel_browsertest.cc
@@ -907,22 +907,15 @@
   panel_manager->CloseAll();
 }
 
-// http://crbug.com/240459 some panel tests are flaky on Linux/GTK.
-#if defined(TOOLKIT_GTK)
-#define MAYBE_AddNewPanelToGroupWithDetachedPanelWithCollapseToFit \
-    DISABLED_AddNewPanelToGroupWithDetachedPanelWithCollapseToFit
-#else
-#define MAYBE_AddNewPanelToGroupWithDetachedPanelWithCollapseToFit \
-    AddNewPanelToGroupWithDetachedPanelWithCollapseToFit
-#endif
 IN_PROC_BROWSER_TEST_F(StackedPanelBrowserTest,
-    MAYBE_AddNewPanelToGroupWithDetachedPanelWithCollapseToFit) {
+                       AddNewPanelToGroupWithDetachedPanelWithCollapseToFit) {
   PanelManager* panel_manager = PanelManager::GetInstance();
 
   // Create 2 detached panels.
   // Since P2 is active, it will not get collapsed when the new panel to stack
   // with needs the space.
-  Panel* panel1 = CreateDetachedPanel("1", gfx::Rect(100, 310, 200, 200));
+  Panel* panel1 =
+      CreateInactiveDetachedPanel("1", gfx::Rect(100, 310, 200, 200));
   Panel* panel2 = CreateDetachedPanel("2", gfx::Rect(300, 300, 150, 200));
   ASSERT_EQ(2, panel_manager->num_panels());
   ASSERT_EQ(0, panel_manager->num_stacks());
diff --git a/chrome/browser/ui/pdf/pdf_browsertest.cc b/chrome/browser/ui/pdf/pdf_browsertest.cc
index 1917021..e7b0c14 100644
--- a/chrome/browser/ui/pdf/pdf_browsertest.cc
+++ b/chrome/browser/ui/pdf/pdf_browsertest.cc
@@ -21,7 +21,7 @@
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/browser_test_utils.h"
-#include "net/test/spawned_test_server/spawned_test_server.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/base/clipboard/clipboard.h"
 #include "ui/gfx/codec/png_codec.h"
@@ -44,16 +44,19 @@
   PDFBrowserTest()
       : snapshot_different_(true),
         next_dummy_search_value_(0),
-        load_stop_notification_count_(0) {
-    pdf_test_server_.reset(new net::SpawnedTestServer(
-        net::SpawnedTestServer::TYPE_HTTP,
-        net::SpawnedTestServer::kLocalhost,
-        base::FilePath(FILE_PATH_LITERAL("pdf/test"))));
+        load_stop_notification_count_(0),
+        pdf_test_server_(
+            content::BrowserThread::GetMessageLoopProxyForThread(
+                content::BrowserThread::IO)) {
+    pdf_test_server_.ServeFilesFromDirectory(
+        base::FilePath(FILE_PATH_LITERAL("pdf/test")));
   }
 
  protected:
   // Use our own TestServer so that we can serve files from the pdf directory.
-  net::SpawnedTestServer* pdf_test_server() { return pdf_test_server_.get(); }
+  net::test_server::EmbeddedTestServer* pdf_test_server() {
+    return &pdf_test_server_;
+  }
 
   int load_stop_notification_count() const {
     return load_stop_notification_count_;
@@ -207,7 +210,7 @@
   // How many times we've seen chrome::LOAD_STOP.
   int load_stop_notification_count_;
 
-  scoped_ptr<net::SpawnedTestServer> pdf_test_server_;
+  net::test_server::EmbeddedTestServer pdf_test_server_;
 };
 
 #if defined(OS_CHROMEOS)
@@ -303,7 +306,7 @@
 // regressions.
 // If it flakes, reopen http://crbug.com/74548.
 IN_PROC_BROWSER_TEST_P(PDFBrowserTest, Loading) {
-  ASSERT_TRUE(pdf_test_server()->Start());
+  ASSERT_TRUE(pdf_test_server()->InitializeAndWaitUntilReady());
 
   NavigationController* controller =
       &(browser()->tab_strip_model()->GetActiveWebContents()->GetController());
@@ -311,7 +314,7 @@
   registrar.Add(this,
                 content::NOTIFICATION_LOAD_STOP,
                 content::Source<NavigationController>(controller));
-  std::string base_url = std::string("files/");
+  std::string base_url = std::string("/");
 
   base::FileEnumerator file_enumerator(
       ui_test_utils::GetTestFilePath(GetPDFTestDir(), base::FilePath()),
@@ -396,9 +399,9 @@
 
 // Flaky as per http://crbug.com/74549.
 IN_PROC_BROWSER_TEST_F(PDFBrowserTest, DISABLED_OnLoadAndReload) {
-  ASSERT_TRUE(pdf_test_server()->Start());
+  ASSERT_TRUE(pdf_test_server()->InitializeAndWaitUntilReady());
 
-  GURL url = pdf_test_server()->GetURL("files/onload_reload.html");
+  GURL url = pdf_test_server()->GetURL("/onload_reload.html");
   ui_test_utils::NavigateToURL(browser(), url);
 
   content::WindowedNotificationObserver observer(
diff --git a/chrome/browser/ui/screen_capture_notification_ui_win.cc b/chrome/browser/ui/screen_capture_notification_ui_win.cc
deleted file mode 100644
index 3841601..0000000
--- a/chrome/browser/ui/screen_capture_notification_ui_win.cc
+++ /dev/null
@@ -1,366 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ui/screen_capture_notification_ui.h"
-
-#include <windows.h>
-
-#include "base/compiler_specific.h"
-#include "base/i18n/rtl.h"
-#include "base/logging.h"
-#include "base/process_util.h"
-#include "base/strings/string_util.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/win/scoped_gdi_object.h"
-#include "base/win/scoped_hdc.h"
-#include "base/win/scoped_select_object.h"
-#include "chrome/app/chrome_dll_resource.h"
-#include "grit/generated_resources.h"
-#include "ui/base/l10n/l10n_util.h"
-
-namespace {
-
-// Maximum length of "Your desktop is shared with ..." message in UTF-16
-// characters.
-const size_t kMaxSharingWithTextLength = 100;
-
-const wchar_t kShellTrayWindowName[] = L"Shell_TrayWnd";
-const int kWindowBorderRadius = 14;
-
-} // namespace anonymous
-
-class ScreenCaptureNotificationUIWin : public ScreenCaptureNotificationUI {
- public:
-  ScreenCaptureNotificationUIWin();
-  virtual ~ScreenCaptureNotificationUIWin();
-
-  // ScreenCaptureNotificationUI interface.
-  virtual bool Show(const base::Closure& stop_callback,
-                    const string16& title) OVERRIDE;
-
- private:
-  static INT_PTR CALLBACK DialogProc(HWND hwnd, UINT message, WPARAM wparam,
-                                     LPARAM lparam);
-
-  BOOL OnDialogMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
-
-  // Creates the dialog window.
-  bool BeginDialog(const string16& title);
-
-  // Closes the dialog and invokes the disconnect callback, if set.
-  void EndDialog();
-
-  // Trys to position the dialog window above the taskbar.
-  void SetDialogPosition();
-
-  // Applies localization string and resizes the dialog.
-  bool UpdateStrings(const string16& title);
-
-  base::Closure stop_callback_;
-  HWND hwnd_;
-  base::win::ScopedGDIObject<HPEN> border_pen_;
-
-  DISALLOW_COPY_AND_ASSIGN(ScreenCaptureNotificationUIWin);
-};
-
-static int GetControlTextWidth(HWND control) {
-  RECT rect = {0, 0, 0, 0};
-  WCHAR text[256];
-  int result = GetWindowText(control, text, arraysize(text));
-  if (result) {
-    base::win::ScopedGetDC dc(control);
-    base::win::ScopedSelectObject font(
-        dc, (HFONT)SendMessage(control, WM_GETFONT, 0, 0));
-    DrawText(dc, text, -1, &rect, DT_CALCRECT | DT_SINGLELINE);
-  }
-  return rect.right;
-}
-
-ScreenCaptureNotificationUIWin::ScreenCaptureNotificationUIWin()
-    : hwnd_(NULL),
-      border_pen_(CreatePen(PS_SOLID, 5,
-                            RGB(0.13 * 255, 0.69 * 255, 0.11 * 255))) {
-}
-
-ScreenCaptureNotificationUIWin::~ScreenCaptureNotificationUIWin() {
-  stop_callback_.Reset();
-  EndDialog();
-}
-
-bool ScreenCaptureNotificationUIWin::Show(
-    const base::Closure& stop_callback,
-    const string16& title) {
-  DCHECK(stop_callback_.is_null());
-  DCHECK(!stop_callback.is_null());
-
-  stop_callback_ = stop_callback;
-
-  if (BeginDialog(title)) {
-    return true;
-  } else {
-    stop_callback_ = stop_callback;
-    EndDialog();
-    return false;
-  }
-}
-
-INT_PTR CALLBACK ScreenCaptureNotificationUIWin::DialogProc(
-    HWND hwnd, UINT message,
-    WPARAM wparam, LPARAM lparam) {
-  LONG_PTR self = NULL;
-  if (message == WM_INITDIALOG) {
-    self = lparam;
-
-    // Store |this| to the window's user data.
-    SetLastError(ERROR_SUCCESS);
-    LONG_PTR result = SetWindowLongPtr(hwnd, DWLP_USER, self);
-    if (result == 0 && GetLastError() != ERROR_SUCCESS)
-      reinterpret_cast<ScreenCaptureNotificationUIWin*>(self)->EndDialog();
-  } else {
-    self = GetWindowLongPtr(hwnd, DWLP_USER);
-  }
-
-  if (self) {
-    return reinterpret_cast<ScreenCaptureNotificationUIWin*>(self)->
-        OnDialogMessage(hwnd, message, wparam, lparam);
-  }
-  return FALSE;
-}
-
-BOOL ScreenCaptureNotificationUIWin::OnDialogMessage(HWND hwnd, UINT message,
-                                          WPARAM wparam, LPARAM lparam) {
-  switch (message) {
-    // Ignore close messages.
-    case WM_CLOSE:
-      return TRUE;
-
-    // Handle the Stop button.
-    case WM_COMMAND:
-      switch (LOWORD(wparam)) {
-        case IDC_SCREEN_CAPTURE_STOP:
-          EndDialog();
-          return TRUE;
-      }
-      return FALSE;
-
-    // Ensure we don't try to use the HWND anymore.
-    case WM_DESTROY:
-      hwnd_ = NULL;
-
-      // Ensure that the stop callback is invoked even if somehow our window
-      // gets destroyed.
-      EndDialog();
-
-      return TRUE;
-
-    // Ensure the dialog stays visible if the work area dimensions change.
-    case WM_SETTINGCHANGE:
-      if (wparam == SPI_SETWORKAREA)
-        SetDialogPosition();
-      return TRUE;
-
-    // Ensure the dialog stays visible if the display dimensions change.
-    case WM_DISPLAYCHANGE:
-      SetDialogPosition();
-      return TRUE;
-
-    // Let the window be draggable by its client area by responding
-    // that the entire window is the title bar.
-    case WM_NCHITTEST:
-      SetWindowLongPtr(hwnd, DWLP_MSGRESULT, HTCAPTION);
-      return TRUE;
-
-    case WM_PAINT: {
-      PAINTSTRUCT ps;
-      HDC hdc = BeginPaint(hwnd_, &ps);
-      RECT rect;
-      GetClientRect(hwnd_, &rect);
-      {
-        base::win::ScopedSelectObject border(hdc, border_pen_);
-        base::win::ScopedSelectObject brush(hdc, GetStockObject(NULL_BRUSH));
-        RoundRect(hdc, rect.left, rect.top, rect.right - 1, rect.bottom - 1,
-                  kWindowBorderRadius, kWindowBorderRadius);
-      }
-      EndPaint(hwnd_, &ps);
-      return TRUE;
-    }
-  }
-  return FALSE;
-}
-
-bool ScreenCaptureNotificationUIWin::BeginDialog(const string16& title) {
-  DCHECK(!hwnd_);
-
-  // TODO(sergeyu): Currently this code relies on resources for the dialog. Fix
-  // it to work without resources.
-
-  // Load the dialog resource so that we can modify the RTL flags if necessary.
-  HMODULE module = base::GetModuleFromAddress(&DialogProc);
-  HRSRC dialog_resource = FindResource(
-      module, MAKEINTRESOURCE(IDD_SCREEN_CAPTURE_NOTIFICATION), RT_DIALOG);
-  if (!dialog_resource)
-    return false;
-
-  HGLOBAL dialog_template = LoadResource(module, dialog_resource);
-  if (!dialog_template)
-    return false;
-
-  DLGTEMPLATE* dialog_pointer =
-      reinterpret_cast<DLGTEMPLATE*>(LockResource(dialog_template));
-  if (!dialog_pointer)
-    return false;
-
-  // The actual resource type is DLGTEMPLATEEX, but this is not defined in any
-  // standard headers, so we treat it as a generic pointer and manipulate the
-  // correct offsets explicitly.
-  scoped_ptr<unsigned char[]> rtl_dialog_template;
-  if (base::i18n::IsRTL()) {
-    unsigned long dialog_template_size =
-        SizeofResource(module, dialog_resource);
-    rtl_dialog_template.reset(new unsigned char[dialog_template_size]);
-    memcpy(rtl_dialog_template.get(), dialog_pointer, dialog_template_size);
-    DWORD* rtl_dwords = reinterpret_cast<DWORD*>(rtl_dialog_template.get());
-    rtl_dwords[2] |= (WS_EX_LAYOUTRTL | WS_EX_RTLREADING);
-    dialog_pointer = reinterpret_cast<DLGTEMPLATE*>(rtl_dwords);
-  }
-
-  hwnd_ = CreateDialogIndirectParam(module, dialog_pointer, NULL,
-                                    DialogProc, reinterpret_cast<LPARAM>(this));
-  if (!hwnd_)
-    return false;
-
-  if (!UpdateStrings(title))
-    return false;
-
-  SetDialogPosition();
-  ShowWindow(hwnd_, SW_SHOW);
-  return IsWindowVisible(hwnd_) != FALSE;
-}
-
-void ScreenCaptureNotificationUIWin::EndDialog() {
-  if (hwnd_) {
-    DestroyWindow(hwnd_);
-    hwnd_ = NULL;
-  }
-
-  if (!stop_callback_.is_null()) {
-    stop_callback_.Run();
-    stop_callback_.Reset();
-  }
-}
-
-void ScreenCaptureNotificationUIWin::SetDialogPosition() {
-  // Try to center the window above the task-bar. If that fails, use the
-  // primary monitor. If that fails (very unlikely), use the default position.
-  HWND taskbar = FindWindow(kShellTrayWindowName, NULL);
-  HMONITOR monitor = MonitorFromWindow(taskbar, MONITOR_DEFAULTTOPRIMARY);
-  MONITORINFO monitor_info = {sizeof(monitor_info)};
-  RECT window_rect;
-  if (GetMonitorInfo(monitor, &monitor_info) &&
-      GetWindowRect(hwnd_, &window_rect)) {
-    int window_width = window_rect.right - window_rect.left;
-    int window_height = window_rect.bottom - window_rect.top;
-    int top = monitor_info.rcWork.bottom - window_height;
-    int left = (monitor_info.rcWork.right + monitor_info.rcWork.left -
-        window_width) / 2;
-    SetWindowPos(hwnd_, NULL, left, top, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
-  }
-}
-
-bool ScreenCaptureNotificationUIWin::UpdateStrings(const string16& title) {
-  string16 window_title =
-      l10n_util::GetStringFUTF16(IDS_MEDIA_SCREEN_CAPTURE_NOTIFICATION_TITLE,
-                                 title);
-  if (!SetWindowText(hwnd_, window_title.c_str()))
-    return false;
-
-  // Localize the disconnect button text and measure length of the old and new
-  // labels.
-  HWND stop_button = GetDlgItem(hwnd_, IDC_SCREEN_CAPTURE_STOP);
-  if (!stop_button)
-    return false;
-  int button_old_required_width = GetControlTextWidth(stop_button);
-  string16 button_label =
-      l10n_util::GetStringUTF16(IDS_MEDIA_SCREEN_CAPTURE_NOTIFICATION_STOP);
-  if (!SetWindowText(stop_button, button_label.c_str()))
-    return false;
-  int button_new_required_width = GetControlTextWidth(stop_button);
-  int button_width_delta =
-      button_new_required_width - button_old_required_width;
-
-  // Format and truncate "Your desktop is shared with ..." message.
-
-  string16 text = l10n_util::GetStringFUTF16(
-      IDS_MEDIA_SCREEN_CAPTURE_NOTIFICATION_TEXT, title);
-  if (text.length() > kMaxSharingWithTextLength)
-    text.erase(kMaxSharingWithTextLength);
-
-  // Set localized and truncated "Your desktop is shared with ..." message and
-  // measure length of the old and new text.
-  HWND sharing_with_label = GetDlgItem(hwnd_, IDC_SCREEN_CAPTURE_TEXT);
-  if (!sharing_with_label)
-    return false;
-  int label_old_required_width = GetControlTextWidth(sharing_with_label);
-  if (!SetWindowText(sharing_with_label, text.c_str()))
-    return false;
-  int label_new_required_width = GetControlTextWidth(sharing_with_label);
-  int label_width_delta = label_new_required_width - label_old_required_width;
-
-  // Reposition the controls such that the label lies to the left of the
-  // disconnect button (assuming LTR layout). The dialog template determines
-  // the controls' spacing; update their size to fit the localized content.
-  RECT label_rect;
-  if (!GetClientRect(sharing_with_label, &label_rect))
-    return false;
-  if (!SetWindowPos(sharing_with_label, NULL, 0, 0,
-                    label_rect.right + label_width_delta, label_rect.bottom,
-                    SWP_NOMOVE | SWP_NOZORDER)) {
-    return false;
-  }
-
-  // Reposition the disconnect button as well.
-  RECT button_rect;
-  if (!GetWindowRect(stop_button, &button_rect))
-    return false;
-  int button_width = button_rect.right - button_rect.left;
-  int button_height = button_rect.bottom - button_rect.top;
-  SetLastError(ERROR_SUCCESS);
-  int result = MapWindowPoints(HWND_DESKTOP, hwnd_,
-                               reinterpret_cast<LPPOINT>(&button_rect), 2);
-  if (!result && GetLastError() != ERROR_SUCCESS)
-    return false;
-  if (!SetWindowPos(stop_button, NULL,
-                    button_rect.left + label_width_delta, button_rect.top,
-                    button_width + button_width_delta, button_height,
-                    SWP_NOZORDER)) {
-    return false;
-  }
-
-  // Resize the whole window to fit the resized controls.
-  RECT window_rect;
-  if (!GetWindowRect(hwnd_, &window_rect))
-    return false;
-  int width = (window_rect.right - window_rect.left) +
-      button_width_delta + label_width_delta;
-  int height = window_rect.bottom - window_rect.top;
-  if (!SetWindowPos(hwnd_, NULL, 0, 0, width, height,
-                    SWP_NOMOVE | SWP_NOZORDER)) {
-    return false;
-  }
-
-  // Make the corners of the disconnect window rounded.
-  HRGN rgn = CreateRoundRectRgn(0, 0, width, height, kWindowBorderRadius,
-                                kWindowBorderRadius);
-  if (!rgn)
-    return false;
-  if (!SetWindowRgn(hwnd_, rgn, TRUE))
-    return false;
-
-  return true;
-}
-
-scoped_ptr<ScreenCaptureNotificationUI> ScreenCaptureNotificationUI::Create() {
-  return scoped_ptr<ScreenCaptureNotificationUI>(
-      new ScreenCaptureNotificationUIWin());
-}
diff --git a/chrome/browser/ui/search/instant_commit_type.h b/chrome/browser/ui/search/instant_commit_type.h
deleted file mode 100644
index 3ead857..0000000
--- a/chrome/browser/ui/search/instant_commit_type.h
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 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_SEARCH_INSTANT_COMMIT_TYPE_H_
-#define CHROME_BROWSER_UI_SEARCH_INSTANT_COMMIT_TYPE_H_
-
-// Reason why the Instant overlay is committed (merged into a tab).
-enum InstantCommitType {
-  // The commit is due to the user pressing Enter from the omnibox.
-  INSTANT_COMMIT_PRESSED_ENTER,
-
-  // The commit is due to the user pressing Alt-Enter from the omnibox (which
-  // causes the overlay to be committed onto a new tab).
-  INSTANT_COMMIT_PRESSED_ALT_ENTER,
-
-  // The commit is due to the omnibox losing focus, usually due to the user
-  // clicking on the overlay.
-  INSTANT_COMMIT_FOCUS_LOST,
-
-  // The commit is due to the Instant overlay navigating to a non-Instant URL.
-  INSTANT_COMMIT_NAVIGATED,
-};
-
-#endif  // CHROME_BROWSER_UI_SEARCH_INSTANT_COMMIT_TYPE_H_
diff --git a/chrome/browser/ui/search/instant_controller.cc b/chrome/browser/ui/search/instant_controller.cc
index c861a1c..a3f465b 100644
--- a/chrome/browser/ui/search/instant_controller.cc
+++ b/chrome/browser/ui/search/instant_controller.cc
@@ -4,22 +4,13 @@
 
 #include "chrome/browser/ui/search/instant_controller.h"
 
-#include <iterator>
-
 #include "base/metrics/histogram.h"
 #include "base/prefs/pref_service.h"
-#include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
-#include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/autocomplete/autocomplete_provider.h"
-#include "chrome/browser/autocomplete/autocomplete_result.h"
-#include "chrome/browser/autocomplete/search_provider.h"
 #include "chrome/browser/content_settings/content_settings_provider.h"
 #include "chrome/browser/content_settings/host_content_settings_map.h"
-#include "chrome/browser/history/history_service.h"
-#include "chrome/browser/history/history_service_factory.h"
-#include "chrome/browser/history/history_tab_helper.h"
 #include "chrome/browser/platform_util.h"
+#include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/search/instant_service.h"
 #include "chrome/browser/search/instant_service_factory.h"
 #include "chrome/browser/search/search.h"
@@ -28,7 +19,6 @@
 #include "chrome/browser/search_engines/template_url_service_factory.h"
 #include "chrome/browser/ui/browser_instant_controller.h"
 #include "chrome/browser/ui/search/instant_ntp.h"
-#include "chrome/browser/ui/search/instant_overlay.h"
 #include "chrome/browser/ui/search/instant_tab.h"
 #include "chrome/browser/ui/search/search_tab_helper.h"
 #include "chrome/common/chrome_notification_types.h"
@@ -46,7 +36,6 @@
 #include "content/public/browser/web_contents_view.h"
 #include "net/base/escape.h"
 #include "net/base/network_change_notifier.h"
-#include "third_party/icu/public/common/unicode/normalizer2.h"
 
 #if defined(TOOLKIT_VIEWS)
 #include "ui/views/widget/widget.h"
@@ -54,11 +43,6 @@
 
 namespace {
 
-// An artificial delay (in milliseconds) we introduce before telling the Instant
-// page about the new omnibox bounds, in cases where the bounds shrink. This is
-// to avoid the page jumping up/down very fast in response to bounds changes.
-const int kUpdateBoundsDelayMS = 1000;
-
 // For reporting Instant navigations.
 enum InstantNavigation {
   INSTANT_NAVIGATION_LOCAL_CLICK = 0,
@@ -85,128 +69,6 @@
                             INSTANT_NAVIGATION_MAX);
 }
 
-void RecordFallbackReasonHistogram(
-    const InstantController::InstantFallbackReason fallback_reason) {
-  UMA_HISTOGRAM_ENUMERATION("InstantExtended.FallbackToLocalOverlay",
-                            fallback_reason,
-                            InstantController::INSTANT_FALLBACK_MAX);
-}
-
-InstantController::InstantFallbackReason DetermineFallbackReason(
-    const InstantPage* page, std::string instant_url) {
-  InstantController::InstantFallbackReason fallback_reason;
-  if (!page) {
-    fallback_reason = InstantController::INSTANT_FALLBACK_NO_OVERLAY;
-  } else if (instant_url.empty()) {
-    fallback_reason = InstantController::INSTANT_FALLBACK_INSTANT_URL_EMPTY;
-  } else if (!chrome::MatchesOriginAndPath(GURL(page->instant_url()),
-                                           GURL(instant_url))) {
-    fallback_reason = InstantController::INSTANT_FALLBACK_ORIGIN_PATH_MISMATCH;
-  } else if (!page->supports_instant()) {
-    fallback_reason = InstantController::INSTANT_FALLBACK_INSTANT_NOT_SUPPORTED;
-  } else {
-    fallback_reason = InstantController::INSTANT_FALLBACK_UNKNOWN;
-  }
-  return fallback_reason;
-}
-
-void AddSessionStorageHistogram(bool extended_enabled,
-                                const content::WebContents* tab1,
-                                const content::WebContents* tab2) {
-  base::HistogramBase* histogram = base::BooleanHistogram::FactoryGet(
-      std::string("Instant.SessionStorageNamespace") +
-          (extended_enabled ? "_Extended" : "_Instant"),
-      base::HistogramBase::kUmaTargetedHistogramFlag);
-  const content::SessionStorageNamespaceMap& session_storage_map1 =
-      tab1->GetController().GetSessionStorageNamespaceMap();
-  const content::SessionStorageNamespaceMap& session_storage_map2 =
-      tab2->GetController().GetSessionStorageNamespaceMap();
-  bool is_session_storage_the_same =
-      session_storage_map1.size() == session_storage_map2.size();
-  if (is_session_storage_the_same) {
-    // The size is the same, so let's check that all entries match.
-    for (content::SessionStorageNamespaceMap::const_iterator
-             it1 = session_storage_map1.begin(),
-             it2 = session_storage_map2.begin();
-         it1 != session_storage_map1.end() && it2 != session_storage_map2.end();
-         ++it1, ++it2) {
-      if (it1->first != it2->first || it1->second.get() != it2->second.get()) {
-        is_session_storage_the_same = false;
-        break;
-      }
-    }
-  }
-  histogram->AddBoolean(is_session_storage_the_same);
-}
-
-string16 Normalize(const string16& str) {
-  UErrorCode status = U_ZERO_ERROR;
-  const icu::Normalizer2* normalizer =
-      icu::Normalizer2::getInstance(NULL, "nfkc_cf", UNORM2_COMPOSE, status);
-  if (normalizer == NULL || U_FAILURE(status))
-    return str;
-  icu::UnicodeString norm_str(normalizer->normalize(
-      icu::UnicodeString(FALSE, str.c_str(), str.size()), status));
-  if (U_FAILURE(status))
-    return str;
-  return string16(norm_str.getBuffer(), norm_str.length());
-}
-
-bool NormalizeAndStripPrefix(string16* text, const string16& prefix) {
-  string16 norm_prefix = Normalize(prefix);
-  string16 norm_text = Normalize(*text);
-  if (norm_prefix.size() <= norm_text.size() &&
-      norm_text.compare(0, norm_prefix.size(), norm_prefix) == 0) {
-    *text = norm_text.erase(0, norm_prefix.size());
-    return true;
-  }
-  return false;
-}
-
-// For TOOLKIT_VIEWS, the top level widget is always focused. If the focus
-// change originated in views determine the child Widget from the view that is
-// being focused.
-gfx::NativeView GetViewGainingFocus(gfx::NativeView view_gaining_focus) {
-#if defined(TOOLKIT_VIEWS)
-  views::Widget* widget = view_gaining_focus ?
-      views::Widget::GetWidgetForNativeView(view_gaining_focus) : NULL;
-  if (widget) {
-    views::FocusManager* focus_manager = widget->GetFocusManager();
-    if (focus_manager && focus_manager->is_changing_focus() &&
-        focus_manager->GetFocusedView() &&
-        focus_manager->GetFocusedView()->GetWidget())
-      return focus_manager->GetFocusedView()->GetWidget()->GetNativeView();
-  }
-#endif
-  return view_gaining_focus;
-}
-
-// Returns true if |view| is the top-level contents view or a child view in the
-// view hierarchy of |contents|.
-bool IsViewInContents(gfx::NativeView view, content::WebContents* contents) {
-  content::RenderWidgetHostView* rwhv = contents->GetRenderWidgetHostView();
-  if (!view || !rwhv)
-    return false;
-
-  gfx::NativeView tab_view = contents->GetView()->GetNativeView();
-  if (view == rwhv->GetNativeView() || view == tab_view)
-    return true;
-
-  // Walk up the view hierarchy to determine if the view is a subview of the
-  // WebContents view (such as a windowed plugin or http auth dialog).
-  while (view) {
-    view = platform_util::GetParent(view);
-    if (view == tab_view)
-      return true;
-  }
-
-  return false;
-}
-
-bool IsFullHeight(const InstantOverlayModel& model) {
-  return model.height() == 100 && model.height_units() == INSTANT_SIZE_PERCENT;
-}
-
 bool IsContentsFrom(const InstantPage* page,
                     const content::WebContents* contents) {
   return page && (page->contents() == contents);
@@ -256,300 +118,31 @@
                                      bool extended_enabled)
     : browser_(browser),
       extended_enabled_(extended_enabled),
-      instant_enabled_(false),
-      use_local_page_only_(true),
-      preload_ntp_(true),
-      model_(this),
-      use_tab_for_suggestions_(false),
-      last_omnibox_text_has_inline_autocompletion_(false),
-      last_verbatim_(false),
-      last_transition_type_(content::PAGE_TRANSITION_LINK),
-      last_match_was_search_(false),
       omnibox_focus_state_(OMNIBOX_FOCUS_NONE),
       omnibox_focus_change_reason_(OMNIBOX_FOCUS_CHANGE_EXPLICIT),
-      omnibox_bounds_(-1, -1, 0, 0),
-      allow_overlay_to_show_search_suggestions_(false) {
+      omnibox_bounds_(-1, -1, 0, 0) {
 
   // When the InstantController lives, the InstantService should live.
   // InstantService sets up profile-level facilities such as the ThemeSource for
   // the NTP.
   // However, in some tests, browser_ may be null.
-  if (browser_)
-    InstantServiceFactory::GetForProfile(browser_->profile());
+  if (browser_) {
+    InstantService* instant_service = GetInstantService();
+    instant_service->AddObserver(this);
+  }
 }
 
 InstantController::~InstantController() {
-}
-
-void InstantController::OnAutocompleteStart() {
-  if (UseTabForSuggestions() && instant_tab_->supports_instant()) {
-    LOG_INSTANT_DEBUG_EVENT(
-        this, "OnAutocompleteStart: using InstantTab");
-    return;
+  if (browser_) {
+    InstantService* instant_service = GetInstantService();
+    instant_service->RemoveObserver(this);
   }
-
-  // Not using |instant_tab_|. Check if overlay is OK to use.
-  InstantFallbackReason fallback_reason = ShouldSwitchToLocalOverlay();
-  if (fallback_reason != INSTANT_FALLBACK_NONE) {
-    ResetOverlay(GetLocalInstantURL());
-    RecordFallbackReasonHistogram(fallback_reason);
-    LOG_INSTANT_DEBUG_EVENT(
-        this, "OnAutocompleteStart: switching to local overlay");
-  } else {
-    LOG_INSTANT_DEBUG_EVENT(
-        this, "OnAutocompleteStart: using existing overlay");
-  }
-  use_tab_for_suggestions_ = false;
-}
-
-bool InstantController::Update(const AutocompleteMatch& match,
-                               const string16& user_text,
-                               const string16& full_text,
-                               size_t selection_start,
-                               size_t selection_end,
-                               bool verbatim,
-                               bool user_input_in_progress,
-                               bool omnibox_popup_is_open,
-                               bool escape_pressed,
-                               bool is_keyword_search) {
-  if (!extended_enabled() && !instant_enabled_)
-    return false;
-
-  LOG_INSTANT_DEBUG_EVENT(this, base::StringPrintf(
-      "Update: %s user_text='%s' full_text='%s' selection_start=%d "
-      "selection_end=%d verbatim=%d typing=%d popup=%d escape_pressed=%d "
-      "is_keyword_search=%d",
-      AutocompleteMatchType::ToString(match.type).c_str(),
-      UTF16ToUTF8(user_text).c_str(), UTF16ToUTF8(full_text).c_str(),
-      static_cast<int>(selection_start), static_cast<int>(selection_end),
-      verbatim, user_input_in_progress, omnibox_popup_is_open, escape_pressed,
-      is_keyword_search));
-
-  // Store the current |last_omnibox_text_| and update |last_omnibox_text_|
-  // upfront with the contents of |full_text|. Even if we do an early return,
-  // |last_omnibox_text_| will be updated.
-  string16 previous_omnibox_text = last_omnibox_text_;
-  last_omnibox_text_ = full_text;
-  last_match_was_search_ = AutocompleteMatch::IsSearchType(match.type) &&
-                           !user_text.empty();
-
-  // TODO(dhollowa): Complete keyword match UI.  For now just hide suggestions.
-  // http://crbug.com/153932.  Note, this early escape is happens prior to the
-  // DCHECKs below because |user_text| and |full_text| have different semantics
-  // when keyword search is in effect.
-  if (is_keyword_search) {
-    if (UseTabForSuggestions())
-      instant_tab_->Update(string16(), 0, 0, true);
-    else
-      HideOverlay();
-    last_match_was_search_ = false;
-    last_suggestion_ = InstantSuggestion();
-    return false;
-  }
-
-  // Ignore spurious updates when the omnibox is blurred; otherwise click
-  // targets on the page may vanish before a click event arrives.
-  if (omnibox_focus_state_ == OMNIBOX_FOCUS_NONE)
-    return false;
-
-  // If the popup is open, the user has to be typing.
-  DCHECK(!omnibox_popup_is_open || user_input_in_progress);
-
-  // If the popup is closed, there should be no inline autocompletion.
-  DCHECK(omnibox_popup_is_open || user_text.empty() || user_text == full_text)
-      << user_text << "|" << full_text;
-
-  // If there's no text in the omnibox, the user can't have typed any.
-  DCHECK(!full_text.empty() || user_text.empty()) << user_text;
-
-  // If the user isn't typing, and the popup is closed, there can't be any
-  // user-typed text.
-  DCHECK(user_input_in_progress || omnibox_popup_is_open || user_text.empty())
-      << user_text;
-
-  // The overlay is being clicked and will commit soon. Don't change anything.
-  // TODO(sreeram): Add a browser test for this.
-  if (overlay_ && overlay_->is_pointer_down_from_activate())
-    return false;
-
-  // In non-extended mode, SearchModeChanged() is never called, so fake it. The
-  // mode is set to "disallow suggestions" here, so that if one of the early
-  // "return false" conditions is hit, suggestions will be disallowed. If the
-  // query is sent to the overlay, the mode is set to "allow" further below.
-  if (!extended_enabled())
-    search_mode_.mode = SearchMode::MODE_DEFAULT;
-
-  // In non extended mode, Instant is disabled for URLs and keyword mode.
-  if (!extended_enabled() &&
-      (!last_match_was_search_ ||
-       match.type == AutocompleteMatchType::SEARCH_OTHER_ENGINE)) {
-    HideOverlay();
-    return false;
-  }
-
-  if (!UseTabForSuggestions() && !overlay_) {
-    HideOverlay();
-    return false;
-  }
-
-  if (extended_enabled()) {
-    if (!omnibox_popup_is_open) {
-      if (!user_input_in_progress) {
-        // If the user isn't typing and the omnibox popup is closed, it means a
-        // regular navigation, tab-switch or the user hitting Escape.
-        if (UseTabForSuggestions()) {
-          // The user is on a search results page. It may be showing results for
-          // a partial query the user typed before they hit Escape. Send the
-          // omnibox text to the page to restore the original results.
-          //
-          // In a tab switch, |instant_tab_| won't have updated yet, so it may
-          // be pointing to the previous tab (which was a search results page).
-          // Ensure we don't send the omnibox text to a random webpage (the new
-          // tab), by comparing the old and new WebContents.
-          if (escape_pressed &&
-              instant_tab_->contents() == browser_->GetActiveWebContents()) {
-            // TODO(kmadhusu): If the |full_text| is not empty, send an
-            // onkeypress(esc) to the Instant page. Do not call
-            // onsubmit(full_text). Fix.
-            if (full_text.empty()) {
-              // Call onchange("") to clear the query for the page.
-              instant_tab_->Update(string16(), 0, 0, true);
-              instant_tab_->EscKeyPressed();
-             } else {
-              instant_tab_->Submit(full_text);
-            }
-          }
-        } else if (!full_text.empty()) {
-          // If |full_text| is empty, the user is on the NTP. The overlay may
-          // be showing custom NTP content; hide only if that's not the case.
-          HideOverlay();
-        }
-      } else if (full_text.empty()) {
-        // The user is typing, and backspaced away all omnibox text. Clear
-        // |last_omnibox_text_| so that we don't attempt to set suggestions.
-        last_omnibox_text_.clear();
-        last_user_text_.clear();
-        last_suggestion_ = InstantSuggestion();
-        if (UseTabForSuggestions()) {
-          // On a search results page, tell it to clear old results.
-          instant_tab_->Update(string16(), 0, 0, true);
-        } else if (search_mode_.is_origin_ntp()) {
-          // On the NTP, tell the overlay to clear old results. Don't hide the
-          // overlay so it can show a blank page or logo if it wants.
-          overlay_->Update(string16(), 0, 0, true);
-        } else {
-          HideOverlay();
-        }
-      } else {
-        // The user switched to a tab with partial text already in the omnibox.
-        HideOverlay();
-
-        // The new tab may or may not be a search results page; we don't know
-        // since SearchModeChanged() hasn't been called yet. If it later turns
-        // out to be, we should store |full_text| now, so that if the user hits
-        // Enter, we'll send the correct query to instant_tab_->Submit(). If the
-        // partial text is not a query (|last_match_was_search_| is false), we
-        // won't Submit(), so no need to worry about that.
-        last_user_text_ = user_text;
-        last_suggestion_ = InstantSuggestion();
-      }
-      return false;
-    } else if (full_text.empty()) {
-      // The user typed a solitary "?". Same as the backspace case above.
-      last_omnibox_text_.clear();
-      last_user_text_.clear();
-      last_suggestion_ = InstantSuggestion();
-      if (UseTabForSuggestions())
-        instant_tab_->Update(string16(), 0, 0, true);
-      else if (search_mode_.is_origin_ntp())
-        overlay_->Update(string16(), 0, 0, true);
-      else
-        HideOverlay();
-      return false;
-    }
-  } else if (!omnibox_popup_is_open || full_text.empty()) {
-    // In the non-extended case, hide the overlay as long as the user isn't
-    // actively typing a non-empty query.
-    HideOverlay();
-    return false;
-  }
-
-  last_omnibox_text_has_inline_autocompletion_ = user_text != full_text;
-
-  // If the user continues typing the same query as the suggested text is
-  // showing, reuse the suggestion (but only for INSTANT_COMPLETE_NEVER).
-  bool reused_suggestion = false;
-  if (last_suggestion_.behavior == INSTANT_COMPLETE_NEVER &&
-      !last_omnibox_text_has_inline_autocompletion_) {
-    if (StartsWith(previous_omnibox_text, full_text, false))  {
-      // The user is backspacing away characters.
-      last_suggestion_.text.insert(0, previous_omnibox_text, full_text.size(),
-          previous_omnibox_text.size() - full_text.size());
-      reused_suggestion = true;
-    } else if (StartsWith(full_text, previous_omnibox_text, false)) {
-      // The user is typing forward. Normalize any added characters.
-      reused_suggestion = NormalizeAndStripPrefix(&last_suggestion_.text,
-          string16(full_text, previous_omnibox_text.size()));
-    }
-  }
-  if (!reused_suggestion)
-    last_suggestion_ = InstantSuggestion();
-
-  // TODO(kmadhusu): Investigate whether it's possible to update
-  // |last_user_text_| at the beginning of this function.
-  last_user_text_ = user_text;
-
-  if (!extended_enabled()) {
-    // In non-extended mode, the query is verbatim if there's any selection
-    // (including inline autocompletion) or if the cursor is not at the end.
-    verbatim = verbatim || selection_start != selection_end ||
-                           selection_start != full_text.size();
-  }
-  last_verbatim_ = verbatim;
-
-  last_transition_type_ = match.transition;
-  url_for_history_ = match.destination_url;
-
-  // Allow search suggestions. In extended mode, SearchModeChanged() will set
-  // this, but it's not called in non-extended mode, so fake it.
-  if (!extended_enabled())
-    search_mode_.mode = SearchMode::MODE_SEARCH_SUGGESTIONS;
-
-  if (UseTabForSuggestions()) {
-    instant_tab_->Update(user_text, selection_start, selection_end, verbatim);
-  } else {
-    allow_overlay_to_show_search_suggestions_ = true;
-
-    overlay_->Update(extended_enabled() ? user_text : full_text,
-                     selection_start, selection_end, verbatim);
-  }
-
-  content::NotificationService::current()->Notify(
-      chrome::NOTIFICATION_INSTANT_CONTROLLER_UPDATED,
-      content::Source<InstantController>(this),
-      content::NotificationService::NoDetails());
-
-  // We don't have new suggestions yet, but we can either reuse the existing
-  // suggestion or reset the existing "gray text".
-  browser_->SetInstantSuggestion(last_suggestion_);
-
-  // Record the time of the first keypress for logging histograms.
-  if (!first_interaction_time_recorded_ && first_interaction_time_.is_null())
-    first_interaction_time_ = base::Time::Now();
-
-  return true;
-}
-
-bool InstantController::WillFetchCompletions() const {
-  if (!extended_enabled())
-    return false;
-
-  return !UsingLocalPage();
 }
 
 scoped_ptr<content::WebContents> InstantController::ReleaseNTPContents() {
   if (!extended_enabled() || !browser_->profile() ||
-      browser_->profile()->IsOffTheRecord())
+      browser_->profile()->IsOffTheRecord() ||
+      !chrome::ShouldShowInstantNTP())
     return scoped_ptr<content::WebContents>();
 
   LOG_INSTANT_DEBUG_EVENT(this, "ReleaseNTPContents");
@@ -560,199 +153,32 @@
   scoped_ptr<content::WebContents> ntp_contents = ntp_->ReleaseContents();
 
   // Preload a new Instant NTP.
-  if (preload_ntp_)
-    ResetNTP(GetInstantURL());
-  else
-    ntp_.reset();
+  ResetNTP(GetInstantURL());
 
   return ntp_contents.Pass();
 }
 
-// TODO(tonyg): This method only fires when the omnibox bounds change. It also
-// needs to fire when the overlay bounds change (e.g.: open/close info bar).
-void InstantController::SetPopupBounds(const gfx::Rect& bounds) {
-  if (!extended_enabled() && !instant_enabled_)
-    return;
-
-  if (popup_bounds_ == bounds)
-    return;
-
-  popup_bounds_ = bounds;
-  if (popup_bounds_.height() > last_popup_bounds_.height()) {
-    update_bounds_timer_.Stop();
-    SendPopupBoundsToPage();
-  } else if (!update_bounds_timer_.IsRunning()) {
-    update_bounds_timer_.Start(FROM_HERE,
-        base::TimeDelta::FromMilliseconds(kUpdateBoundsDelayMS), this,
-        &InstantController::SendPopupBoundsToPage);
-  }
-}
-
 void InstantController::SetOmniboxBounds(const gfx::Rect& bounds) {
   if (!extended_enabled() || omnibox_bounds_ == bounds)
     return;
 
   omnibox_bounds_ = bounds;
-  if (overlay_)
-    overlay_->SetOmniboxBounds(omnibox_bounds_);
   if (ntp_)
-    ntp_->SetOmniboxBounds(omnibox_bounds_);
+    ntp_->sender()->SetOmniboxBounds(omnibox_bounds_);
   if (instant_tab_)
-    instant_tab_->SetOmniboxBounds(omnibox_bounds_);
-}
-
-void InstantController::HandleAutocompleteResults(
-    const std::vector<AutocompleteProvider*>& providers,
-    const AutocompleteResult& autocomplete_result) {
-  if (!extended_enabled())
-    return;
-
-  if (!UseTabForSuggestions() && !overlay_)
-    return;
-
-  // The omnibox sends suggestions when its possibly imaginary popup closes
-  // as it stops autocomplete. Ignore these.
-  if (omnibox_focus_state_ == OMNIBOX_FOCUS_NONE)
-    return;
-
-  for (ACProviders::const_iterator provider = providers.begin();
-       provider != providers.end(); ++provider) {
-    const bool from_search_provider =
-        (*provider)->type() == AutocompleteProvider::TYPE_SEARCH;
-
-    // TODO(jeremycho): Pass search_provider() as a parameter to this function
-    // and remove the static cast.
-    const bool provider_done = from_search_provider ?
-        static_cast<SearchProvider*>(*provider)->IsNonInstantSearchDone() :
-        (*provider)->done();
-    if (!provider_done) {
-      DVLOG(1) << "Waiting for " << (*provider)->GetName();
-      return;
-    }
-  }
-
-  DVLOG(1) << "AutocompleteResults:";
-  std::vector<InstantAutocompleteResult> results;
-  if (UsingLocalPage()) {
-    for (AutocompleteResult::const_iterator match(autocomplete_result.begin());
-         match != autocomplete_result.end(); ++match) {
-      InstantAutocompleteResult result;
-      PopulateInstantAutocompleteResultFromMatch(
-          *match, std::distance(autocomplete_result.begin(), match), &result);
-      results.push_back(result);
-    }
-  } else {
-    for (ACProviders::const_iterator provider = providers.begin();
-         provider != providers.end(); ++provider) {
-      for (ACMatches::const_iterator match = (*provider)->matches().begin();
-           match != (*provider)->matches().end(); ++match) {
-        // When the top match is an inline history URL, the page calls
-        // SetSuggestions(url) which calls FinalizeInstantQuery() in
-        // SearchProvider creating a NAVSUGGEST match for the URL. If we sent
-        // this NAVSUGGEST match back to the page, it would be deduped against
-        // the original history match and replace it. But since the page ignores
-        // SearchProvider suggestions, the match would then disappear. Yuck.
-        // TODO(jered): Remove this when FinalizeInstantQuery() is ripped out.
-        if ((*provider)->type() == AutocompleteProvider::TYPE_SEARCH &&
-            match->type == AutocompleteMatchType::NAVSUGGEST) {
-          continue;
-        }
-        InstantAutocompleteResult result;
-        PopulateInstantAutocompleteResultFromMatch(*match, kNoMatchIndex,
-                                                   &result);
-        results.push_back(result);
-      }
-    }
-  }
-  LOG_INSTANT_DEBUG_EVENT(this, base::StringPrintf(
-      "HandleAutocompleteResults: total_results=%d",
-      static_cast<int>(results.size())));
-
-  if (UseTabForSuggestions())
-    instant_tab_->SendAutocompleteResults(results);
-  else
-    overlay_->SendAutocompleteResults(results);
-
-  content::NotificationService::current()->Notify(
-      chrome::NOTIFICATION_INSTANT_SENT_AUTOCOMPLETE_RESULTS,
-      content::Source<InstantController>(this),
-      content::NotificationService::NoDetails());
+    instant_tab_->sender()->SetOmniboxBounds(omnibox_bounds_);
 }
 
 void InstantController::OnDefaultSearchProviderChanged() {
   if (ntp_ && extended_enabled()) {
     ntp_.reset();
-    if (preload_ntp_)
-      ResetNTP(GetInstantURL());
+    ResetNTP(GetInstantURL());
   }
-
-  // Do not reload the overlay if it's actually the local overlay.
-  if (overlay_ && !overlay_->IsLocal()) {
-    overlay_.reset();
-    if (extended_enabled() || instant_enabled_) {
-      // Try to create another overlay immediately so that it is ready for the
-      // next user interaction.
-      ResetOverlay(GetInstantURL());
-    }
-  }
-}
-
-bool InstantController::OnUpOrDownKeyPressed(int count) {
-  if (!extended_enabled())
-    return false;
-
-  if (!UseTabForSuggestions() && !overlay_)
-    return false;
-
-  if (UseTabForSuggestions())
-    instant_tab_->UpOrDownKeyPressed(count);
-  else
-    overlay_->UpOrDownKeyPressed(count);
-
-  return true;
-}
-
-void InstantController::OnCancel(const AutocompleteMatch& match,
-                                 const string16& user_text,
-                                 const string16& full_text) {
-  if (!extended_enabled())
-    return;
-
-  if (!UseTabForSuggestions() && !overlay_)
-    return;
-
-  // We manually reset the state here since the JS is not expected to do it.
-  // TODO(sreeram): Handle the case where user_text is now a URL
-  last_match_was_search_ = AutocompleteMatch::IsSearchType(match.type) &&
-                           !full_text.empty();
-  last_omnibox_text_ = full_text;
-  last_user_text_ = user_text;
-  last_suggestion_ = InstantSuggestion();
-
-  // Say |full_text| is "amazon.com" and |user_text| is "ama". This means the
-  // inline autocompletion is "zon.com"; so the selection should span from
-  // user_text.size() to full_text.size(). The selection bounds are inverted
-  // because the caret is at the end of |user_text|, not |full_text|.
-  if (UseTabForSuggestions()) {
-    instant_tab_->CancelSelection(user_text, full_text.size(), user_text.size(),
-                                  last_verbatim_);
-  } else {
-    overlay_->CancelSelection(user_text, full_text.size(), user_text.size(),
-                              last_verbatim_);
-  }
-}
-
-void InstantController::OmniboxNavigateToURL() {
-  RecordNavigationHistogram(UsingLocalPage(), false, extended_enabled());
-  if (!extended_enabled())
-    return;
-  if (UseTabForSuggestions())
-    instant_tab_->Submit(string16());
 }
 
 void InstantController::ToggleVoiceSearch() {
   if (instant_tab_)
-    instant_tab_->ToggleVoiceSearch();
+    instant_tab_->sender()->ToggleVoiceSearch();
 }
 
 void InstantController::InstantPageLoadFailed(content::WebContents* contents) {
@@ -787,35 +213,21 @@
     DeletePageSoon(ntp_.Pass());
     if (!is_local)
       ResetNTP(GetLocalInstantURL());
-  } else if (IsContentsFrom(overlay(), contents)) {
-    LOG_INSTANT_DEBUG_EVENT(this, "InstantPageLoadFailed: overlay");
-    bool is_local = overlay_->IsLocal();
-    DeletePageSoon(overlay_.Pass());
-    if (!is_local)
-      ResetOverlay(GetLocalInstantURL());
+  } else {
+    NOTREACHED();
   }
 }
 
-content::WebContents* InstantController::GetOverlayContents() const {
-  return overlay_ ? overlay_->contents() : NULL;
-}
-
 content::WebContents* InstantController::GetNTPContents() const {
   return ntp_ ? ntp_->contents() : NULL;
 }
 
-bool InstantController::IsOverlayingSearchResults() const {
-  return model_.mode().is_search_suggestions() && IsFullHeight(model_) &&
-         (last_match_was_search_ ||
-          last_suggestion_.behavior == INSTANT_COMPLETE_NEVER);
-}
-
 bool InstantController::SubmitQuery(const string16& search_terms) {
   if (extended_enabled() && instant_tab_ && instant_tab_->supports_instant() &&
       search_mode_.is_origin_search()) {
     // Use |instant_tab_| to run the query if we're already on a search results
     // page. (NOTE: in particular, we do not send the query to NTPs.)
-    instant_tab_->Submit(search_terms);
+    instant_tab_->sender()->Submit(search_terms);
     instant_tab_->contents()->GetView()->Focus();
     EnsureSearchTermsAreSet(instant_tab_->contents(), search_terms);
     return true;
@@ -823,153 +235,6 @@
   return false;
 }
 
-bool InstantController::CommitIfPossible(InstantCommitType type) {
-  if (!extended_enabled() && !instant_enabled_)
-    return false;
-
-  LOG_INSTANT_DEBUG_EVENT(this, base::StringPrintf(
-      "CommitIfPossible: type=%d last_omnibox_text_='%s' "
-      "last_match_was_search_=%d use_tab_for_suggestions=%d", type,
-      UTF16ToUTF8(last_omnibox_text_).c_str(), last_match_was_search_,
-      UseTabForSuggestions()));
-
-  // If we are on an already committed search results page, send a submit event
-  // to the page, but otherwise, nothing else to do.
-  if (UseTabForSuggestions()) {
-    if (type == INSTANT_COMMIT_PRESSED_ENTER &&
-        !instant_tab_->IsLocal() &&
-        (last_match_was_search_ ||
-         last_suggestion_.behavior == INSTANT_COMPLETE_NEVER)) {
-      last_suggestion_.text.clear();
-      instant_tab_->Submit(last_omnibox_text_);
-      instant_tab_->contents()->GetView()->Focus();
-      EnsureSearchTermsAreSet(instant_tab_->contents(), last_omnibox_text_);
-      return true;
-    }
-    return false;
-  }
-
-  // If the overlay is not showing at all, don't commit it.
-  if (!model_.mode().is_search_suggestions())
-    return false;
-
-  // If the overlay is showing at full height (with results), commit it.
-  // If it's showing at parial height, commit if it's navigating.
-  if (!IsOverlayingSearchResults() && type != INSTANT_COMMIT_NAVIGATED)
-    return false;
-
-  // There may re-entrance here, from the call to browser_->CommitInstant below,
-  // which can cause a TabDeactivated notification which gets back here.
-  // In this case, overlay_->ReleaseContents() was called already.
-  if (!GetOverlayContents())
-    return false;
-
-  // Never commit the local overlay.
-  if (overlay_->IsLocal())
-    return false;
-
-  if (type == INSTANT_COMMIT_FOCUS_LOST) {
-    // Extended mode doesn't need or use the Cancel message.
-    if (!extended_enabled())
-      overlay_->Cancel(last_omnibox_text_);
-  } else if (type != INSTANT_COMMIT_NAVIGATED) {
-    overlay_->Submit(last_omnibox_text_);
-  }
-
-  // We expect the WebContents to be in a valid state (i.e., has a last
-  // committed entry, no transient entry, and no existing pending entry).
-  scoped_ptr<content::WebContents> overlay = overlay_->ReleaseContents();
-  CHECK(overlay->GetController().CanPruneAllButVisible());
-
-  // If the overlay page has navigated since the last Update(), we need to add
-  // the navigation to history ourselves. Else, the page will navigate after
-  // commit, and it will be added to history in the usual manner.
-  const history::HistoryAddPageArgs& last_navigation =
-      overlay_->last_navigation();
-  if (!last_navigation.url.is_empty()) {
-    content::NavigationEntry* entry = overlay->GetController().GetActiveEntry();
-
-    // The last navigation should be the same as the active entry if the overlay
-    // is in search mode. During navigation, the active entry could have
-    // changed since DidCommitProvisionalLoadForFrame is called after the entry
-    // is changed.
-    // TODO(shishir): Should we commit the last navigation for
-    // INSTANT_COMMIT_NAVIGATED.
-    DCHECK(type == INSTANT_COMMIT_NAVIGATED ||
-           last_navigation.url == entry->GetURL());
-
-    // Add the page to history.
-    HistoryTabHelper* history_tab_helper =
-        HistoryTabHelper::FromWebContents(overlay.get());
-    history_tab_helper->UpdateHistoryForNavigation(last_navigation);
-
-    // Update the page title.
-    history_tab_helper->UpdateHistoryPageTitle(*entry);
-  }
-
-  // Add a fake history entry with a non-Instant search URL, so that search
-  // terms extraction (for autocomplete history matches) works.
-  HistoryService* history = HistoryServiceFactory::GetForProfile(
-      Profile::FromBrowserContext(overlay->GetBrowserContext()),
-      Profile::EXPLICIT_ACCESS);
-  if (history) {
-    history->AddPage(url_for_history_, base::Time::Now(), NULL, 0, GURL(),
-                     history::RedirectList(), last_transition_type_,
-                     history::SOURCE_BROWSED, false);
-  }
-
-  if (type == INSTANT_COMMIT_PRESSED_ALT_ENTER) {
-    overlay->GetController().PruneAllButVisible();
-  } else {
-    content::WebContents* active_tab = browser_->GetActiveWebContents();
-    AddSessionStorageHistogram(extended_enabled(), active_tab, overlay.get());
-    overlay->GetController().CopyStateFromAndPrune(
-        &active_tab->GetController());
-  }
-
-  if (extended_enabled()) {
-    // Adjust the search terms shown in the omnibox for this query. Hitting
-    // ENTER searches for what the user typed, so use last_omnibox_text_.
-    // Clicking on the overlay commits what is currently showing, so add in the
-    // gray text in that case.
-    if (type == INSTANT_COMMIT_FOCUS_LOST &&
-        last_suggestion_.behavior == INSTANT_COMPLETE_NEVER) {
-      // Update |last_omnibox_text_| so that the controller commits the proper
-      // query if the user focuses the omnibox and presses Enter.
-      last_omnibox_text_ += last_suggestion_.text;
-    }
-
-    EnsureSearchTermsAreSet(overlay.get(), last_omnibox_text_);
-  }
-
-  // Save notification source before we release the overlay.
-  content::Source<content::WebContents> notification_source(overlay.get());
-
-  browser_->CommitInstant(overlay.Pass(),
-                          type == INSTANT_COMMIT_PRESSED_ALT_ENTER);
-
-  content::NotificationService::current()->Notify(
-      chrome::NOTIFICATION_INSTANT_COMMITTED,
-      notification_source,
-      content::NotificationService::NoDetails());
-
-  // Hide explicitly. See comments in HideOverlay() for why.
-  model_.SetOverlayState(SearchMode(), 0, INSTANT_SIZE_PERCENT);
-
-  // Delay deletion as we could've gotten here from an InstantOverlay method.
-  DeletePageSoon(overlay_.Pass());
-
-  // Try to create another overlay immediately so that it is ready for the next
-  // user interaction.
-  ResetOverlay(GetInstantURL());
-
-  if (instant_tab_)
-    use_tab_for_suggestions_ = true;
-
-  LOG_INSTANT_DEBUG_EVENT(this, "Committed");
-  return true;
-}
-
 void InstantController::OmniboxFocusChanged(
     OmniboxFocusState state,
     OmniboxFocusChangeReason reason,
@@ -978,37 +243,21 @@
       "OmniboxFocusChanged: %d to %d for reason %d", omnibox_focus_state_,
       state, reason));
 
-  OmniboxFocusState old_focus_state = omnibox_focus_state_;
   omnibox_focus_state_ = state;
-  if (!extended_enabled() && !instant_enabled_)
+  if (!extended_enabled() || !instant_tab_)
     return;
 
-  if (extended_enabled()) {
-    if (overlay_)
-      overlay_->FocusChanged(omnibox_focus_state_, reason);
+  content::NotificationService::current()->Notify(
+      chrome::NOTIFICATION_OMNIBOX_FOCUS_CHANGED,
+      content::Source<InstantController>(this),
+      content::NotificationService::NoDetails());
 
-    if (instant_tab_) {
-      instant_tab_->FocusChanged(omnibox_focus_state_, reason);
-      // Don't send oninputstart/oninputend updates in response to focus changes
-      // if there's a navigation in progress. This prevents Chrome from sending
-      // a spurious oninputend when the user accepts a match in the omnibox.
-      if (instant_tab_->contents()->GetController().GetPendingEntry() == NULL)
-        instant_tab_->SetInputInProgress(IsInputInProgress());
-    }
-  }
-
-  if (state == OMNIBOX_FOCUS_VISIBLE && old_focus_state == OMNIBOX_FOCUS_NONE) {
-    // If the user explicitly focused the omnibox, then create the overlay if
-    // it doesn't exist. If we're using a fallback overlay, try loading the
-    // remote overlay again.
-    if (!overlay_ || (overlay_->IsLocal() && !use_local_page_only_))
-      ResetOverlay(GetInstantURL());
-  } else if (state == OMNIBOX_FOCUS_NONE &&
-             old_focus_state != OMNIBOX_FOCUS_NONE) {
-    // If the focus went from the omnibox to outside the omnibox, commit or
-    // discard the overlay.
-    OmniboxLostFocus(view_gaining_focus);
-  }
+  instant_tab_->sender()->FocusChanged(omnibox_focus_state_, reason);
+  // Don't send oninputstart/oninputend updates in response to focus changes
+  // if there's a navigation in progress. This prevents Chrome from sending
+  // a spurious oninputend when the user accepts a match in the omnibox.
+  if (instant_tab_->contents()->GetController().GetPendingEntry() == NULL)
+    instant_tab_->sender()->SetInputInProgress(IsInputInProgress());
 }
 
 void InstantController::SearchModeChanged(const SearchMode& old_mode,
@@ -1021,118 +270,32 @@
       old_mode.mode, new_mode.origin, new_mode.mode));
 
   search_mode_ = new_mode;
-  if (!new_mode.is_search_suggestions())
-    HideOverlay();
-
   ResetInstantTab();
 
   if (instant_tab_ && old_mode.is_ntp() != new_mode.is_ntp())
-    instant_tab_->SetInputInProgress(IsInputInProgress());
+    instant_tab_->sender()->SetInputInProgress(IsInputInProgress());
 }
 
 void InstantController::ActiveTabChanged() {
-  if (!extended_enabled() && !instant_enabled_)
-    return;
-
-  LOG_INSTANT_DEBUG_EVENT(this, "ActiveTabChanged");
-
-  // When switching tabs, always hide the overlay.
-  HideOverlay();
-
-  if (extended_enabled())
-    ResetInstantTab();
-}
-
-void InstantController::TabDeactivated(content::WebContents* contents) {
-  LOG_INSTANT_DEBUG_EVENT(this, "TabDeactivated");
-  if (extended_enabled() && !contents->IsBeingDestroyed())
-    CommitIfPossible(INSTANT_COMMIT_FOCUS_LOST);
-
-  if (GetOverlayContents())
-    HideOverlay();
-}
-
-void InstantController::SetInstantEnabled(bool instant_enabled,
-                                          bool use_local_page_only) {
-  LOG_INSTANT_DEBUG_EVENT(this, base::StringPrintf(
-      "SetInstantEnabled: instant_enabled=%d, use_local_page_only=%d",
-      instant_enabled, use_local_page_only));
-
-  // Non extended mode does not care about |use_local_page_only|.
-  if (instant_enabled == instant_enabled_ &&
-      (!extended_enabled() ||
-       use_local_page_only == use_local_page_only_)) {
-    return;
-  }
-
-  instant_enabled_ = instant_enabled;
-  use_local_page_only_ = use_local_page_only;
-  preload_ntp_ = !use_local_page_only_ || chrome::ShouldPreloadLocalOnlyNTP();
-
-  // Preload the overlay.
-  HideInternal();
-  overlay_.reset();
-  if (extended_enabled() || instant_enabled_)
-    ResetOverlay(GetInstantURL());
-
-  // Preload the Instant NTP.
-  ntp_.reset();
-  if (extended_enabled() && preload_ntp_)
-    ResetNTP(GetInstantURL());
-
-  if (instant_tab_)
-    instant_tab_->SetDisplayInstantResults(instant_enabled_);
-}
-
-void InstantController::ThemeChanged(const ThemeBackgroundInfo& theme_info) {
   if (!extended_enabled())
     return;
 
-  if (overlay_)
-    overlay_->SendThemeBackgroundInfo(theme_info);
+  LOG_INSTANT_DEBUG_EVENT(this, "ActiveTabChanged");
+  ResetInstantTab();
+}
+
+void InstantController::TabDeactivated(content::WebContents* contents) {
+}
+
+void InstantController::ThemeInfoChanged(
+    const ThemeBackgroundInfo& theme_info) {
+  if (!extended_enabled())
+    return;
+
   if (ntp_)
-    ntp_->SendThemeBackgroundInfo(theme_info);
+    ntp_->sender()->SendThemeBackgroundInfo(theme_info);
   if (instant_tab_)
-    instant_tab_->SendThemeBackgroundInfo(theme_info);
-}
-
-void InstantController::SwappedOverlayContents() {
-  model_.SetOverlayContents(GetOverlayContents());
-}
-
-void InstantController::FocusedOverlayContents() {
-#if defined(USE_AURA)
-  // On aura the omnibox only receives a focus lost if we initiate the focus
-  // change. This does that.
-  if (!model_.mode().is_default())
-    browser_->InstantOverlayFocused();
-#endif
-}
-
-void InstantController::ReloadOverlayIfStale() {
-  // The local overlay is never stale.
-  if (overlay_ && (overlay_->IsLocal() || !overlay_->is_stale()))
-    return;
-
-  // If the overlay is showing or the omnibox has focus, don't refresh the
-  // overlay. It will get refreshed the next time the overlay is hidden or the
-  // omnibox loses focus.
-  if (omnibox_focus_state_ == OMNIBOX_FOCUS_NONE && model_.mode().is_default())
-    ResetOverlay(GetInstantURL());
-}
-
-void InstantController::OverlayLoadCompletedMainFrame() {
-  if (overlay_->supports_instant())
-    return;
-  InstantService* instant_service =
-      InstantServiceFactory::GetForProfile(browser_->profile());
-  content::WebContents* contents = overlay_->contents();
-  DCHECK(contents);
-  if (instant_service->IsInstantProcess(
-      contents->GetRenderProcessHost()->GetID())) {
-    return;
-  }
-  InstantSupportDetermined(contents, false);
+    instant_tab_->sender()->SendThemeBackgroundInfo(theme_info);
 }
 
 void InstantController::LogDebugEvent(const std::string& info) const {
@@ -1149,32 +312,12 @@
   debug_events_.clear();
 }
 
-void InstantController::UpdateMostVisitedItems() {
-  InstantService* instant_service =
-      InstantServiceFactory::GetForProfile(profile());
-  if (!instant_service)
-    return;
-
-  std::vector<InstantMostVisitedItem> items;
-  instant_service->GetCurrentMostVisitedItems(&items);
-
-  if (overlay_ && GetOverlayContents() &&
-      SearchTabHelper::FromWebContents(overlay_->contents())->
-          UpdateLastKnownMostVisitedItems(items)) {
-    overlay_->SendMostVisitedItems(items);
-  }
-
-  if (ntp_ && ntp_->contents() &&
-      SearchTabHelper::FromWebContents(ntp_->contents())->
-          UpdateLastKnownMostVisitedItems(items)) {
-    ntp_->SendMostVisitedItems(items);
-  }
-
-  if (instant_tab_ && instant_tab_->contents() &&
-      SearchTabHelper::FromWebContents(instant_tab_->contents())->
-          UpdateLastKnownMostVisitedItems(items)) {
-    instant_tab_->SendMostVisitedItems(items);
-  }
+void InstantController::MostVisitedItemsChanged(
+    const std::vector<InstantMostVisitedItem>& items) {
+  if (ntp_)
+    ntp_->sender()->SendMostVisitedItems(items);
+  if (instant_tab_)
+    instant_tab_->sender()->SendMostVisitedItems(items);
 
   content::NotificationService::current()->Notify(
       chrome::NOTIFICATION_INSTANT_SENT_MOST_VISITED_ITEMS,
@@ -1184,8 +327,7 @@
 
 void InstantController::DeleteMostVisitedItem(const GURL& url) {
   DCHECK(!url.is_empty());
-  InstantService* instant_service =
-      InstantServiceFactory::GetForProfile(profile());
+  InstantService* instant_service = GetInstantService();
   if (!instant_service)
     return;
 
@@ -1194,8 +336,7 @@
 
 void InstantController::UndoMostVisitedDeletion(const GURL& url) {
   DCHECK(!url.is_empty());
-  InstantService* instant_service =
-      InstantServiceFactory::GetForProfile(profile());
+  InstantService* instant_service = GetInstantService();
   if (!instant_service)
     return;
 
@@ -1203,8 +344,7 @@
 }
 
 void InstantController::UndoAllMostVisitedDeletions() {
-  InstantService* instant_service =
-      InstantServiceFactory::GetForProfile(profile());
+  InstantService* instant_service = GetInstantService();
   if (!instant_service)
     return;
 
@@ -1215,10 +355,6 @@
   return browser_->profile();
 }
 
-InstantOverlay* InstantController::overlay() const {
-  return overlay_.get();
-}
-
 InstantTab* InstantController::instant_tab() const {
   return instant_tab_.get();
 }
@@ -1227,6 +363,17 @@
   return ntp_.get();
 }
 
+void InstantController::OnNetworkChanged(
+    net::NetworkChangeNotifier::ConnectionType type) {
+  // Not interested in events conveying change to offline
+  if (type == net::NetworkChangeNotifier::CONNECTION_NONE)
+    return;
+  if (!extended_enabled_)
+    return;
+  if (!ntp_ || ntp_->IsLocal())
+    ResetNTP(GetInstantURL());
+}
+
 // TODO(shishir): We assume that the WebContent's current RenderViewHost is the
 // RenderViewHost being created which is not always true. Fix this.
 void InstantController::InstantPageRenderViewCreated(
@@ -1235,22 +382,36 @@
     return;
 
   // Update theme info so that the page picks it up.
-  browser_->UpdateThemeInfo();
+  InstantService* instant_service = GetInstantService();
+  if (instant_service) {
+    instant_service->UpdateThemeInfo();
+    instant_service->UpdateMostVisitedItemsInfo();
+  }
 
   // Ensure the searchbox API has the correct initial state.
-  if (IsContentsFrom(overlay(), contents)) {
-    overlay_->SetDisplayInstantResults(instant_enabled_);
-    overlay_->FocusChanged(omnibox_focus_state_, omnibox_focus_change_reason_);
-    overlay_->SetOmniboxBounds(omnibox_bounds_);
-    overlay_->InitializeFonts();
-  } else if (IsContentsFrom(ntp(), contents)) {
-    ntp_->SetDisplayInstantResults(instant_enabled_);
-    ntp_->SetOmniboxBounds(omnibox_bounds_);
+  if (IsContentsFrom(ntp(), contents)) {
+    ntp_->sender()->SetOmniboxBounds(omnibox_bounds_);
     ntp_->InitializeFonts();
+    ntp_->InitializePromos();
   } else {
     NOTREACHED();
   }
-  UpdateMostVisitedItems();
+}
+
+void InstantController::InstantSupportChanged(
+    InstantSupportState instant_support) {
+  // Instant support determined. Update location bar contents to reflect the
+  // page Instant support state.
+  if (instant_support != INSTANT_SUPPORT_UNKNOWN)
+    browser_->UpdateLocationBar();
+
+  // Handle INSTANT_SUPPORT_YES here because InstantPage is not hooked up to the
+  // active tab. Search model changed listener in InstantPage will handle other
+  // cases.
+  if (instant_support != INSTANT_SUPPORT_YES)
+    return;
+
+  ResetInstantTab();
 }
 
 void InstantController::InstantSupportDetermined(
@@ -1279,29 +440,14 @@
         content::Source<InstantController>(this),
         content::NotificationService::NoDetails());
 
-  } else if (IsContentsFrom(overlay(), contents)) {
-    if (!supports_instant) {
-      HideInternal();
-      bool is_local = overlay_->IsLocal();
-      DeletePageSoon(overlay_.Pass());
-      // Preload a local overlay in place of the broken online one.
-      if (!is_local && extended_enabled())
-        ResetOverlay(GetLocalInstantURL());
-    }
-
-    content::NotificationService::current()->Notify(
-        chrome::NOTIFICATION_INSTANT_OVERLAY_SUPPORT_DETERMINED,
-        content::Source<InstantController>(this),
-        content::NotificationService::NoDetails());
+  } else {
+    NOTREACHED();
   }
 }
 
 void InstantController::InstantPageRenderViewGone(
     const content::WebContents* contents) {
-  if (IsContentsFrom(overlay(), contents)) {
-    HideInternal();
-    DeletePageSoon(overlay_.Pass());
-  } else if (IsContentsFrom(ntp(), contents)) {
+  if (IsContentsFrom(ntp(), contents)) {
     DeletePageSoon(ntp_.Pass());
   } else {
     NOTREACHED();
@@ -1311,31 +457,7 @@
 void InstantController::InstantPageAboutToNavigateMainFrame(
     const content::WebContents* contents,
     const GURL& url) {
-  if (IsContentsFrom(overlay(), contents)) {
-    // If the page does not yet support Instant, we allow redirects and other
-    // navigations to go through since the Instant URL can redirect - e.g. to
-    // country specific pages.
-    if (!overlay_->supports_instant())
-      return;
-
-    GURL instant_url(overlay_->instant_url());
-
-    // If we are navigating to the Instant URL, do nothing.
-    if (url == instant_url)
-      return;
-
-    // Commit the navigation if either:
-    //  - The page is in NTP mode (so it could only navigate on a user click) or
-    //  - The page is not in NTP mode and we are navigating to a URL with a
-    //    different host or path than the Instant URL. This enables the instant
-    //    page when it is showing search results to change the query parameters
-    //    and fragments of the URL without it navigating.
-    if (model_.mode().is_ntp() ||
-        (url.host() != instant_url.host() ||
-         url.path() != instant_url.path())) {
-      CommitIfPossible(INSTANT_COMMIT_NAVIGATED);
-    }
-  } else if (IsContentsFrom(instant_tab(), contents)) {
+  if (IsContentsFrom(instant_tab(), contents)) {
     // The Instant tab navigated.  Send it the data it needs to display
     // properly.
     UpdateInfoForInstantTab();
@@ -1344,118 +466,6 @@
   }
 }
 
-void InstantController::SetSuggestions(
-    const content::WebContents* contents,
-    const std::vector<InstantSuggestion>& suggestions) {
-  LOG_INSTANT_DEBUG_EVENT(this, "SetSuggestions");
-
-  // Ignore if the message is from an unexpected source.
-  if (IsContentsFrom(ntp(), contents))
-    return;
-  if (UseTabForSuggestions() && !IsContentsFrom(instant_tab(), contents))
-    return;
-  if (IsContentsFrom(overlay(), contents) &&
-      !allow_overlay_to_show_search_suggestions_)
-    return;
-
-  InstantSuggestion suggestion;
-  if (!suggestions.empty())
-    suggestion = suggestions[0];
-
-  // TODO(samarth): allow InstantTabs to call SetSuggestions() from the NTP once
-  // that is better supported.
-  bool can_use_instant_tab = UseTabForSuggestions() &&
-      search_mode_.is_search();
-  bool can_use_overlay = search_mode_.is_search_suggestions() &&
-      !last_omnibox_text_.empty();
-  if (!can_use_instant_tab && !can_use_overlay)
-    return;
-
-  if (suggestion.behavior == INSTANT_COMPLETE_REPLACE) {
-    if (omnibox_focus_state_ == OMNIBOX_FOCUS_NONE) {
-      // TODO(samarth,skanuj): setValue() needs to be handled differently when
-      // the omnibox doesn't have focus. Instead of setting temporary text, we
-      // should be setting search terms on the appropriate NavigationEntry.
-      // (Among other things, this ensures that URL-shaped values will get the
-      // additional security token.)
-      //
-      // Note that this also breaks clicking on a suggestion corresponding to
-      // gray-text completion: we can't distinguish between the user
-      // clicking on white space (where we don't accept the gray text) and the
-      // user clicking on the suggestion (when we do accept the gray text).
-      // This needs to be fixed before we can turn on Instant again.
-      return;
-    }
-
-    // We don't get an Update() when changing the omnibox due to a REPLACE
-    // suggestion (so that we don't inadvertently cause the overlay to change
-    // what it's showing, as the user arrows up/down through the page-provided
-    // suggestions). So, update these state variables here.
-    last_omnibox_text_ = suggestion.text;
-    last_user_text_.clear();
-    last_suggestion_ = InstantSuggestion();
-    last_match_was_search_ = suggestion.type == INSTANT_SUGGESTION_SEARCH;
-    LOG_INSTANT_DEBUG_EVENT(this, base::StringPrintf(
-        "ReplaceSuggestion text='%s' type=%d",
-        UTF16ToUTF8(suggestion.text).c_str(), suggestion.type));
-    browser_->SetInstantSuggestion(suggestion);
-  } else {
-    if (FixSuggestion(&suggestion)) {
-      last_suggestion_ = suggestion;
-      if (suggestion.type == INSTANT_SUGGESTION_SEARCH &&
-          suggestion.behavior == INSTANT_COMPLETE_NEVER)
-        last_omnibox_text_ = last_user_text_;
-      LOG_INSTANT_DEBUG_EVENT(this, base::StringPrintf(
-          "SetInstantSuggestion: text='%s' behavior=%d",
-          UTF16ToUTF8(suggestion.text).c_str(),
-          suggestion.behavior));
-      browser_->SetInstantSuggestion(suggestion);
-      content::NotificationService::current()->Notify(
-          chrome::NOTIFICATION_INSTANT_SET_SUGGESTION,
-          content::Source<InstantController>(this),
-          content::NotificationService::NoDetails());
-    } else {
-      last_suggestion_ = InstantSuggestion();
-    }
-  }
-
-  // Extended mode pages will call ShowOverlay() when they are ready.
-  if (!extended_enabled())
-    ShowOverlay(100, INSTANT_SIZE_PERCENT);
-}
-
-void InstantController::ShowInstantOverlay(const content::WebContents* contents,
-                                           int height,
-                                           InstantSizeUnits units) {
-  if (extended_enabled() && IsContentsFrom(overlay(), contents))
-    ShowOverlay(height, units);
-}
-
-void InstantController::LogDropdownShown() {
-  // If suggestions are being shown for the first time since the user started
-  // typing, record a histogram value.
-  if (!first_interaction_time_.is_null() && !first_interaction_time_recorded_) {
-    base::TimeDelta delta = base::Time::Now() - first_interaction_time_;
-    first_interaction_time_recorded_ = true;
-    if (search_mode_.is_origin_ntp()) {
-      UMA_HISTOGRAM_TIMES("Instant.TimeToFirstShowFromNTP", delta);
-      LOG_INSTANT_DEBUG_EVENT(this, base::StringPrintf(
-          "LogShowInstantOverlay: TimeToFirstShowFromNTP=%d",
-          static_cast<int>(delta.InMilliseconds())));
-    } else if (search_mode_.is_origin_search()) {
-      UMA_HISTOGRAM_TIMES("Instant.TimeToFirstShowFromSERP", delta);
-      LOG_INSTANT_DEBUG_EVENT(this, base::StringPrintf(
-          "LogShowInstantOverlay: TimeToFirstShowFromSERP=%d",
-          static_cast<int>(delta.InMilliseconds())));
-    } else {
-      UMA_HISTOGRAM_TIMES("Instant.TimeToFirstShowFromWeb", delta);
-      LOG_INSTANT_DEBUG_EVENT(this, base::StringPrintf(
-          "LogShowInstantOverlay: TimeToFirstShowFromWeb=%d",
-          static_cast<int>(delta.InMilliseconds())));
-    }
-  }
-}
-
 void InstantController::FocusOmnibox(const content::WebContents* contents,
                                      OmniboxFocusState state) {
   if (!extended_enabled())
@@ -1498,9 +508,6 @@
   // has switched tabs).
   if (!extended_enabled())
     return;
-  if (overlay_) {
-    HideOverlay();
-  }
 
   if (transition == content::PAGE_TRANSITION_AUTO_BOOKMARK) {
     content::RecordAction(
@@ -1513,43 +520,12 @@
   browser_->OpenURL(url, transition, disposition);
 }
 
-void InstantController::OmniboxLostFocus(gfx::NativeView view_gaining_focus) {
-  // If the overlay is showing custom NTP content, don't hide it, commit it
-  // (no matter where the user clicked) or try to recreate it.
-  if (model_.mode().is_ntp())
-    return;
-
-  if (model_.mode().is_default()) {
-    // If the overlay is not showing at all, recreate it if it's stale.
-    ReloadOverlayIfStale();
-    return;
-  }
-
-  // The overlay is showing search suggestions. If GetOverlayContents() is NULL,
-  // we are in the commit path. Don't do anything.
-  if (!GetOverlayContents())
-    return;
-
-#if defined(OS_MACOSX)
-  // TODO(sreeram): See if Mac really needs this special treatment.
-  if (!overlay_->is_pointer_down_from_activate())
-    HideOverlay();
-#else
-  if (IsFullHeight(model_))
-    CommitIfPossible(INSTANT_COMMIT_FOCUS_LOST);
-  else if (!IsViewInContents(GetViewGainingFocus(view_gaining_focus),
-                             overlay_->contents()))
-    HideOverlay();
-#endif
-}
-
 std::string InstantController::GetLocalInstantURL() const {
   return chrome::GetLocalInstantURL(profile()).spec();
 }
 
 std::string InstantController::GetInstantURL() const {
-  if (extended_enabled() &&
-      (use_local_page_only_ || net::NetworkChangeNotifier::IsOffline()))
+  if (extended_enabled() && net::NetworkChangeNotifier::IsOffline())
     return GetLocalInstantURL();
 
   const GURL instant_url = chrome::GetInstantURL(profile(),
@@ -1577,10 +553,15 @@
 }
 
 void InstantController::ResetNTP(const std::string& instant_url) {
+  // Never load the Instant NTP if it is disabled.
+  if (!chrome::ShouldShowInstantNTP())
+    return;
+
   // Instant NTP is only used in extended mode so we should always have a
   // non-empty URL to use.
   DCHECK(!instant_url.empty());
-  ntp_.reset(new InstantNTP(this, instant_url));
+  ntp_.reset(new InstantNTP(this, instant_url,
+                            browser_->profile()->IsOffTheRecord()));
   ntp_->InitContents(profile(), browser_->GetActiveWebContents(),
                      base::Bind(&InstantController::ReloadStaleNTP,
                                 base::Unretained(this)));
@@ -1589,7 +570,8 @@
 }
 
 void InstantController::ReloadStaleNTP() {
-  ResetNTP(GetInstantURL());
+  if (extended_enabled())
+    ResetNTP(GetInstantURL());
 }
 
 bool InstantController::ShouldSwitchToLocalNTP() const {
@@ -1614,57 +596,15 @@
   return !(InStartup() && chrome::ShouldPreferRemoteNTPOnStartup());
 }
 
-void InstantController::ResetOverlay(const std::string& instant_url) {
-  HideInternal();
-  // If there's no active tab, the browser is opening or closing.
-  const content::WebContents* active_tab = browser_->GetActiveWebContents();
-  if (!active_tab || instant_url.empty()) {
-    overlay_.reset();
-  } else {
-    overlay_.reset(new InstantOverlay(this, instant_url));
-    overlay_->InitContents(browser_->profile(), active_tab);
-  }
-  LOG_INSTANT_DEBUG_EVENT(this, base::StringPrintf(
-      "ResetOverlay: instant_url='%s'", instant_url.c_str()));
-}
-
-InstantController::InstantFallbackReason
-InstantController::ShouldSwitchToLocalOverlay() const {
-  if (!extended_enabled())
-    return INSTANT_FALLBACK_NONE;
-
-  if (!overlay())
-    return DetermineFallbackReason(NULL, std::string());
-
-  // Assume users with Javascript disabled do not want the online experience.
-  if (!IsJavascriptEnabled())
-    return INSTANT_FALLBACK_JAVASCRIPT_DISABLED;
-
-  if (overlay()->IsLocal())
-    return INSTANT_FALLBACK_NONE;
-
-  bool page_is_current = PageIsCurrent(overlay());
-  if (!page_is_current)
-    return DetermineFallbackReason(overlay(), GetInstantURL());
-
-  return INSTANT_FALLBACK_NONE;
-}
-
 void InstantController::ResetInstantTab() {
-  // Do not wire up the InstantTab in Incognito, to prevent it from sending data
-  // to the page.
-  if (!search_mode_.is_origin_default() &&
-      !browser_->profile()->IsOffTheRecord()) {
+  if (!search_mode_.is_origin_default()) {
     content::WebContents* active_tab = browser_->GetActiveWebContents();
     if (!instant_tab_ || active_tab != instant_tab_->contents()) {
-      instant_tab_.reset(new InstantTab(this));
+      instant_tab_.reset(
+          new InstantTab(this, browser_->profile()->IsOffTheRecord()));
       instant_tab_->Init(active_tab);
       UpdateInfoForInstantTab();
-      use_tab_for_suggestions_ = true;
     }
-
-    // Hide the |overlay_| since we are now using |instant_tab_| instead.
-    HideOverlay();
   } else {
     instant_tab_.reset();
   }
@@ -1672,14 +612,20 @@
 
 void InstantController::UpdateInfoForInstantTab() {
   if (instant_tab_) {
-    browser_->UpdateThemeInfo();
-    instant_tab_->SetDisplayInstantResults(instant_enabled_);
-    instant_tab_->SetOmniboxBounds(omnibox_bounds_);
+    instant_tab_->sender()->SetOmniboxBounds(omnibox_bounds_);
+
+    // Update theme details.
+    InstantService* instant_service = GetInstantService();
+    if (instant_service) {
+      instant_service->UpdateThemeInfo();
+      instant_service->UpdateMostVisitedItemsInfo();
+    }
+
     instant_tab_->InitializeFonts();
-    UpdateMostVisitedItems();
-    instant_tab_->FocusChanged(omnibox_focus_state_,
-                               omnibox_focus_change_reason_);
-    instant_tab_->SetInputInProgress(IsInputInProgress());
+    instant_tab_->InitializePromos();
+    instant_tab_->sender()->FocusChanged(omnibox_focus_state_,
+                                         omnibox_focus_change_reason_);
+    instant_tab_->sender()->SetInputInProgress(IsInputInProgress());
   }
 }
 
@@ -1688,164 +634,8 @@
       omnibox_focus_state_ == OMNIBOX_FOCUS_VISIBLE;
 }
 
-void InstantController::HideOverlay() {
-  HideInternal();
-  ReloadOverlayIfStale();
-}
-
-void InstantController::HideInternal() {
-  LOG_INSTANT_DEBUG_EVENT(this, "Hide");
-
-  // If GetOverlayContents() returns NULL, either we're already in the desired
-  // MODE_DEFAULT state, or we're in the commit path. For the latter, don't
-  // change the state just yet; else we may hide the overlay unnecessarily.
-  // Instead, the state will be set correctly after the commit is done.
-  if (GetOverlayContents()) {
-    model_.SetOverlayState(SearchMode(), 0, INSTANT_SIZE_PERCENT);
-    allow_overlay_to_show_search_suggestions_ = false;
-
-    // Send a message asking the overlay to clear out old results.
-    overlay_->Update(string16(), 0, 0, true);
-  }
-
-  // Clear the first interaction timestamp for later use.
-  first_interaction_time_ = base::Time();
-  first_interaction_time_recorded_ = false;
-
-  if (instant_tab_)
-    use_tab_for_suggestions_ = true;
-}
-
-void InstantController::ShowOverlay(int height, InstantSizeUnits units) {
-  // If we are on a committed search results page, the |overlay_| is not in use.
-  if (UseTabForSuggestions())
-    return;
-
-  LOG_INSTANT_DEBUG_EVENT(this, base::StringPrintf(
-      "Show: height=%d units=%d", height, units));
-
-  // Must have updated omnibox after the last HideOverlay() to show suggestions.
-  if (!allow_overlay_to_show_search_suggestions_)
-    return;
-
-  // The page is trying to hide itself. Hide explicitly (i.e., don't use
-  // HideOverlay()) so that it can change its mind.
-  if (height == 0) {
-    model_.SetOverlayState(SearchMode(), 0, INSTANT_SIZE_PERCENT);
-    if (instant_tab_)
-      use_tab_for_suggestions_ = true;
-    return;
-  }
-
-  // Show at 100% height except in the following cases:
-  // - The local overlay (omnibox popup) is being loaded.
-  // - Instant is disabled. The page needs to be able to show only a dropdown.
-  // - The page is over a website other than search or an NTP, and is not
-  //   already showing at 100% height.
-  if (overlay_->IsLocal() || !instant_enabled_ ||
-      (search_mode_.is_origin_default() && !IsFullHeight(model_)))
-    model_.SetOverlayState(search_mode_, height, units);
-  else
-    model_.SetOverlayState(search_mode_, 100, INSTANT_SIZE_PERCENT);
-
-  // If the overlay is being shown at full height and the omnibox is not
-  // focused, commit right away.
-  if (IsFullHeight(model_) && omnibox_focus_state_ == OMNIBOX_FOCUS_NONE)
-    CommitIfPossible(INSTANT_COMMIT_FOCUS_LOST);
-}
-
-void InstantController::SendPopupBoundsToPage() {
-  if (last_popup_bounds_ == popup_bounds_ || !overlay_ ||
-      overlay_->is_pointer_down_from_activate())
-    return;
-
-  last_popup_bounds_ = popup_bounds_;
-  gfx::Rect overlay_bounds = browser_->GetInstantBounds();
-  gfx::Rect intersection = gfx::IntersectRects(popup_bounds_, overlay_bounds);
-
-  // Translate into window coordinates.
-  if (!intersection.IsEmpty()) {
-    intersection.Offset(-overlay_bounds.origin().x(),
-                        -overlay_bounds.origin().y());
-  }
-
-  // In the current Chrome UI, these must always be true so they sanity check
-  // the above operations. In a future UI, these may be removed or adjusted.
-  // There is no point in sanity-checking |intersection.y()| because the omnibox
-  // can be placed anywhere vertically relative to the overlay (for example, in
-  // Mac fullscreen mode, the omnibox is fully enclosed by the overlay bounds).
-  DCHECK_LE(0, intersection.x());
-  DCHECK_LE(0, intersection.width());
-  DCHECK_LE(0, intersection.height());
-
-  overlay_->SetPopupBounds(intersection);
-}
-
-
-
-bool InstantController::FixSuggestion(InstantSuggestion* suggestion) const {
-  // We only accept suggestions if the user has typed text. If the user is
-  // arrowing up/down (|last_user_text_| is empty), we reject suggestions.
-  if (last_user_text_.empty())
-    return false;
-
-  // If the page is trying to set inline autocompletion in verbatim mode,
-  // instead try suggesting the exact omnibox text. This makes the omnibox
-  // interpret user text as an URL if possible while preventing unwanted
-  // autocompletion during backspacing.
-  if (suggestion->behavior == INSTANT_COMPLETE_NOW && last_verbatim_)
-    suggestion->text = last_omnibox_text_;
-
-  // Suggestion text should be a full URL for URL suggestions, or the
-  // completion of a query for query suggestions.
-  if (suggestion->type == INSTANT_SUGGESTION_URL) {
-    // If the suggestion is not a valid URL, perhaps it's something like
-    // "foo.com". Try prefixing "http://". If it still isn't valid, drop it.
-    if (!GURL(suggestion->text).is_valid()) {
-      suggestion->text.insert(0, ASCIIToUTF16("http://"));
-      if (!GURL(suggestion->text).is_valid())
-        return false;
-    }
-
-    // URL suggestions are only accepted if the query for which the suggestion
-    // was generated is the same as |last_user_text_|.
-    //
-    // Any other URL suggestions--in particular suggestions for old user_text
-    // lagging behind a slow IPC--are ignored. See crbug.com/181589.
-    //
-    // TODO(samarth): Accept stale suggestions if they would be accepted by
-    // SearchProvider as an inlinable suggestion. http://crbug.com/191656.
-    return suggestion->query == last_user_text_;
-  }
-
-  // We use |last_user_text_| because |last_omnibox_text| may contain text from
-  // a previous URL suggestion at this point.
-  if (suggestion->type == INSTANT_SUGGESTION_SEARCH) {
-    if (StartsWith(suggestion->text, last_user_text_, true)) {
-      // The user typed an exact prefix of the suggestion.
-      suggestion->text.erase(0, last_user_text_.size());
-      return true;
-    } else if (NormalizeAndStripPrefix(&suggestion->text, last_user_text_)) {
-      // Unicode normalize and case-fold the user text and suggestion. If the
-      // user text is a prefix, suggest the normalized, case-folded completion
-      // for instance, if the user types 'i' and the suggestion is 'INSTANT',
-      // suggest 'nstant'. Otherwise, the user text really isn't a prefix, so
-      // suggest nothing.
-      // TODO(samarth|jered): revisit this logic. http://crbug.com/196572.
-      return true;
-    }
-  }
-
-  return false;
-}
-
 bool InstantController::UsingLocalPage() const {
-  return (UseTabForSuggestions() && instant_tab_->IsLocal()) ||
-      (!UseTabForSuggestions() && overlay_ && overlay_->IsLocal());
-}
-
-bool InstantController::UseTabForSuggestions() const {
-  return instant_tab_ && use_tab_for_suggestions_;
+  return instant_tab_ && instant_tab_->IsLocal();
 }
 
 void InstantController::RedirectToLocalNTP(content::WebContents* contents) {
@@ -1859,31 +649,6 @@
   // entry.
 }
 
-void InstantController::PopulateInstantAutocompleteResultFromMatch(
-    const AutocompleteMatch& match, size_t autocomplete_match_index,
-    InstantAutocompleteResult* result) {
-  DCHECK(result);
-  result->provider = UTF8ToUTF16(match.provider->GetName());
-  result->type = match.type;
-  result->description = match.description;
-  result->destination_url = UTF8ToUTF16(match.destination_url.spec());
-
-  // Setting the search_query field tells the Instant page to treat the
-  // suggestion as a query.
-  if (AutocompleteMatch::IsSearchType(match.type))
-    result->search_query = match.contents;
-
-  result->transition = match.transition;
-  result->relevance = match.relevance;
-  result->autocomplete_match_index = autocomplete_match_index;
-
-  DVLOG(1) << "    " << result->relevance << " "
-      << UTF8ToUTF16(AutocompleteMatchType::ToString(result->type)) << " "
-      << result->provider << " " << result->destination_url << " '"
-      << result->description << "' '" << result->search_query << "' "
-      << result->transition <<  " " << result->autocomplete_match_index;
-}
-
 bool InstantController::IsJavascriptEnabled() const {
   GURL instant_url(GetInstantURL());
   GURL origin(instant_url.GetOrigin());
@@ -1907,3 +672,7 @@
   // startup time.
   return !browser_->GetActiveWebContents();
 }
+
+InstantService* InstantController::GetInstantService() const {
+  return InstantServiceFactory::GetForProfile(profile());
+}
diff --git a/chrome/browser/ui/search/instant_controller.h b/chrome/browser/ui/search/instant_controller.h
index 0a3d42e..8dd8bb9 100644
--- a/chrome/browser/ui/search/instant_controller.h
+++ b/chrome/browser/ui/search/instant_controller.h
@@ -14,31 +14,22 @@
 #include "base/gtest_prod_util.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/strings/string16.h"
-#include "base/time.h"
-#include "base/timer.h"
-#include "chrome/browser/ui/omnibox/omnibox_edit_model.h"
-#include "chrome/browser/ui/search/instant_commit_type.h"
-#include "chrome/browser/ui/search/instant_overlay_model.h"
+#include "chrome/browser/search/instant_service_observer.h"
 #include "chrome/browser/ui/search/instant_page.h"
 #include "chrome/common/instant_types.h"
 #include "chrome/common/omnibox_focus_state.h"
 #include "chrome/common/search_types.h"
-#include "content/public/common/page_transition_types.h"
 #include "googleurl/src/gurl.h"
+#include "net/base/network_change_notifier.h"
 #include "ui/base/window_open_disposition.h"
 #include "ui/gfx/native_widget_types.h"
 #include "ui/gfx/rect.h"
 
-struct AutocompleteMatch;
-struct InstantAutocompleteResult;
-
-class AutocompleteProvider;
-class AutocompleteResult;
 class BrowserInstantController;
 class InstantNTP;
-class InstantOverlay;
+class InstantService;
 class InstantTab;
-class TemplateURL;
+class Profile;
 
 namespace content {
 class WebContents;
@@ -51,123 +42,48 @@
 // InstantController drives Chrome Instant, i.e., the browser implementation of
 // the Embedded Search API (see http://dev.chromium.org/embeddedsearch).
 //
-// In extended mode, InstantController maintains and coordinates three
+// In extended mode, InstantController maintains and coordinates two
 // instances of InstantPage:
-//  (1) An InstantOverlay instance that is used to show search suggestions and
-//      results in an overlay over a non-search page.
-//  (2) An InstantNTP instance which is a preloaded search page that will be
+//  (1) An InstantNTP instance which is a preloaded search page that will be
 //      swapped-in the next time the user navigates to the New Tab Page. It is
 //      never shown to the user in an uncommitted state.
-//  (3) An InstantTab instance which points to the currently active tab, if it
+//  (2) An InstantTab instance which points to the currently active tab, if it
 //      supports the Embedded Search API.
 //
-// All three are backed by a WebContents. InstantOverlay and InstantNTP own
-// their corresponding WebContents; InstantTab does not. In non-extended mode,
-// only an InstantOverlay instance is kept.
+// Both are backed by a WebContents. InstantNTP owns its WebContents and
+// InstantTab does not.
 //
 // InstantController is owned by Browser via BrowserInstantController.
-class InstantController : public InstantPage::Delegate {
+class InstantController : public InstantPage::Delegate,
+                          public InstantServiceObserver {
  public:
-  // For reporting fallbacks to local overlay.
-  enum InstantFallbackReason {
-    INSTANT_FALLBACK_NONE = 0,
-    INSTANT_FALLBACK_UNKNOWN = 1,
-    INSTANT_FALLBACK_INSTANT_URL_EMPTY = 2,
-    INSTANT_FALLBACK_ORIGIN_PATH_MISMATCH = 3,
-    INSTANT_FALLBACK_INSTANT_NOT_SUPPORTED = 4,
-    INSTANT_FALLBACK_NO_OVERLAY = 5,
-    INSTANT_FALLBACK_JAVASCRIPT_DISABLED = 6,
-    INSTANT_FALLBACK_MAX = 7,
-  };
-
   InstantController(BrowserInstantController* browser,
                     bool extended_enabled);
   virtual ~InstantController();
 
-  // Called when the Autocomplete flow is about to start. Sets up the
-  // appropriate page to send user updates to.  May reset |instant_tab_| or
-  // switch to a local fallback |overlay_| as necessary.
-  void OnAutocompleteStart();
-
-  // Invoked as the user types into the omnibox. |user_text| is what the user
-  // has typed. |full_text| is what the omnibox is showing. These may differ if
-  // the user typed only some text, and the rest was inline autocompleted. If
-  // |verbatim| is true, search results are shown for the exact omnibox text,
-  // rather than the best guess as to what the user means. Returns true if the
-  // update is accepted (i.e., if |match| is a search rather than a URL).
-  // |is_keyword_search| is true if keyword searching is in effect.
-  bool Update(const AutocompleteMatch& match,
-              const string16& user_text,
-              const string16& full_text,
-              size_t selection_start,
-              size_t selection_end,
-              bool verbatim,
-              bool user_input_in_progress,
-              bool omnibox_popup_is_open,
-              bool escape_pressed,
-              bool is_keyword_search);
-
-  // Returns whether the Instant page currently being used will fetch its own
-  // completions. True for extended mode, unless using a local Instant page.
-  bool WillFetchCompletions() const;
-
   // Releases and returns the NTP WebContents. May be NULL. Loads a new
   // WebContents for the NTP.
   scoped_ptr<content::WebContents> ReleaseNTPContents() WARN_UNUSED_RESULT;
 
-  // Sets the bounds of the omnibox popup, in screen coordinates.
-  void SetPopupBounds(const gfx::Rect& bounds);
-
   // Sets the stored start-edge margin and width of the omnibox.
   void SetOmniboxBounds(const gfx::Rect& bounds);
 
-  // Send autocomplete results from |providers| to the overlay page.
-  void HandleAutocompleteResults(
-      const std::vector<AutocompleteProvider*>& providers,
-      const AutocompleteResult& result);
-
-  // Called when the default search provider changes. Resets InstantNTP and
-  // InstantOverlay.
+  // Called when the default search provider changes. Resets InstantNTP.
   void OnDefaultSearchProviderChanged();
 
-  // Called when the user presses up or down. |count| is a repeat count,
-  // negative for moving up, positive for moving down. Returns true if Instant
-  // handled the key press.
-  bool OnUpOrDownKeyPressed(int count);
-
-  // Called when the user has arrowed into the suggestions but wants to cancel,
-  // typically by pressing ESC. The omnibox text is expected to have been
-  // reverted to |full_text| by the OmniboxEditModel prior to calling this.
-  // |match| is the match reverted to.
-  void OnCancel(const AutocompleteMatch& match,
-                const string16& user_text,
-                const string16& full_text);
-
-  // Called when the user navigates to a URL from the omnibox. This will send
-  // an onsubmit notification to the instant page.
-  void OmniboxNavigateToURL();
-
   // Notifies |instant_Tab_| to toggle voice search.
   void ToggleVoiceSearch();
 
-  // The overlay WebContents. May be NULL. InstantController retains ownership.
-  content::WebContents* GetOverlayContents() const;
-
   // The ntp WebContents. May be NULL. InstantController retains ownership.
   content::WebContents* GetNTPContents() const;
 
-  // Returns true if Instant is showing a search results overlay. Returns false
-  // if the overlay is not showing, or if it's showing only suggestions.
-  bool IsOverlayingSearchResults() const;
-
   // Called if the browser is navigating to a search URL for |search_terms| with
   // search-term-replacement enabled. If |instant_tab_| can be used to process
   // the search, this does so and returns true. Else, returns false.
   bool SubmitQuery(const string16& search_terms);
 
-  // If the overlay is showing search results, commits the overlay, calling
-  // CommitInstant() on the browser, and returns true. Else, returns false.
-  bool CommitIfPossible(InstantCommitType type);
+  // If the network status changes, try to reset NTP and Overlay.
+  void OnNetworkChanged(net::NetworkChangeNotifier::ConnectionType type);
 
   // Called to indicate that the omnibox focus state changed with the given
   // |reason|. If |focus_state| is FOCUS_NONE, |view_gaining_focus| is set to
@@ -176,41 +92,18 @@
                            OmniboxFocusChangeReason reason,
                            gfx::NativeView view_gaining_focus);
 
-  // The search mode in the active tab has changed. Pass the message down to
-  // the overlay which will notify the renderer. Create |instant_tab_| if the
+  // The search mode in the active tab has changed. Bind |instant_tab_| if the
   // |new_mode| reflects an Instant search results page.
   void SearchModeChanged(const SearchMode& old_mode,
                          const SearchMode& new_mode);
 
-  // The user switched tabs. Hide the overlay. Create |instant_tab_| if the
-  // newly active tab is an Instant search results page.
+  // The user switched tabs. Bind |instant_tab_| if the newly active tab is an
+  // Instant search results page.
   void ActiveTabChanged();
 
-  // The user is about to switch tabs. Commit the overlay if needed.
+  // The user is about to switch tabs.
   void TabDeactivated(content::WebContents* contents);
 
-  // Sets whether Instant should show result overlays. |use_local_page_only|
-  // will force the use of baked-in page as the Instant URL and is only
-  // applicable if |extended_enabled_| is true.
-  void SetInstantEnabled(bool instant_enabled, bool use_local_page_only);
-
-  // The theme has changed. Pass the message to the overlay page.
-  void ThemeChanged(const ThemeBackgroundInfo& theme_info);
-
-  // Called when someone else swapped in a different contents in the |overlay_|.
-  void SwappedOverlayContents();
-
-  // Called when contents for |overlay_| received focus.
-  void FocusedOverlayContents();
-
-  // Called when the |overlay_| might be stale. If it's actually stale, and the
-  // omnibox doesn't have focus, and the overlay isn't showing, the |overlay_|
-  // is deleted and recreated. Else the refresh is skipped.
-  void ReloadOverlayIfStale();
-
-  // Called when the |overlay_|'s main frame has finished loading.
-  void OverlayLoadCompletedMainFrame();
-
   // Adds a new event to |debug_events_| and also DVLOG's it. Ensures that
   // |debug_events_| doesn't get too large.
   void LogDebugEvent(const std::string& info) const;
@@ -218,13 +111,11 @@
   // Resets list of debug events.
   void ClearDebugEvents();
 
-  // Gets the Most Visited items info from InstantService and forwards them to
-  // the Instant page renderer via the appropriate InstantPage subclass.
-  void UpdateMostVisitedItems();
+  // Loads a new NTP to replace |ntp_|.
+  void ReloadStaleNTP();
 
   // Returns the correct Instant URL to use from the following possibilities:
   //   o The default search engine's Instant URL
-  //   o The --instant-url command line switch
   //   o The local page (see GetLocalInstantURL())
   // Returns empty string if no valid Instant URL is available (this is only
   // possible in non-extended mode where we don't have a local page fall-back).
@@ -235,20 +126,14 @@
     return debug_events_;
   }
 
-  // Returns the transition type of the last AutocompleteMatch passed to Update.
-  content::PageTransition last_transition_type() const {
-    return last_transition_type_;
-  }
-
-  // Non-const for Add/RemoveObserver only.  Other model changes should only
-  // happen through the InstantController interface.
-  InstantOverlayModel* model() { return &model_; }
+  // Used by BrowserInstantController to notify InstantController about the
+  // instant support change event for the active web contents.
+  void InstantSupportChanged(InstantSupportState instant_support);
 
  protected:
   // Accessors are made protected for testing purposes.
   virtual bool extended_enabled() const;
 
-  virtual InstantOverlay* overlay() const;
   virtual InstantTab* instant_tab() const;
   virtual InstantNTP* ntp() const;
 
@@ -270,34 +155,13 @@
   UNIT_F(IsJavascriptEnabledChecksContentSettings);
   UNIT_F(IsJavascriptEnabledChecksPrefs);
   UNIT_F(PrefersRemoteNTPOnStartup);
-  UNIT_F(ShouldSwitchToLocalOverlay);
   UNIT_F(SwitchesToLocalNTPIfJSDisabled);
   UNIT_F(SwitchesToLocalNTPIfNoInstantSupport);
   UNIT_F(SwitchesToLocalNTPIfNoNTPReady);
   UNIT_F(SwitchesToLocalNTPIfPathBad);
 #undef UNIT_F
-  FRIEND_TEST_ALL_PREFIXES(InstantTest, OmniboxFocusLoadsInstant);
-  FRIEND_TEST_ALL_PREFIXES(InstantExtendedTest, UsesOverlayIfTabNotReady);
-  FRIEND_TEST_ALL_PREFIXES(InstantExtendedTest,
-                           SearchQueryNotDisplayedForNavsuggest);
-  FRIEND_TEST_ALL_PREFIXES(InstantTest, SetWithTemplateURL);
-  FRIEND_TEST_ALL_PREFIXES(InstantTest, NonInstantSearchProvider);
-  FRIEND_TEST_ALL_PREFIXES(InstantTest, InstantOverlayRefresh);
-  FRIEND_TEST_ALL_PREFIXES(InstantTest, InstantOverlayRefreshDifferentOrder);
-  FRIEND_TEST_ALL_PREFIXES(InstantTest, InstantRenderViewGone);
   FRIEND_TEST_ALL_PREFIXES(InstantExtendedTest, ExtendedModeIsOn);
   FRIEND_TEST_ALL_PREFIXES(InstantExtendedTest, MostVisited);
-  FRIEND_TEST_ALL_PREFIXES(InstantExtendedTest, RestrictedItemReadback);
-  FRIEND_TEST_ALL_PREFIXES(InstantExtendedTest, OmniboxFocusLoadsInstant);
-  FRIEND_TEST_ALL_PREFIXES(InstantExtendedTest,
-                           OmniboxTextUponFocusedCommittedSERP);
-  FRIEND_TEST_ALL_PREFIXES(InstantExtendedTest,
-                           NavigationSuggestionIsDiscardedUponSearchSuggestion);
-  FRIEND_TEST_ALL_PREFIXES(InstantExtendedTest,
-                           NavigateToURLSuggestionHitEnterAndLookForSubmit);
-  FRIEND_TEST_ALL_PREFIXES(InstantExtendedTest,
-                           MiddleClickOnSuggestionOpensInNewTab);
-  FRIEND_TEST_ALL_PREFIXES(InstantExtendedTest, SearchProviderRunsForFallback);
   FRIEND_TEST_ALL_PREFIXES(InstantExtendedTest, NTPIsPreloaded);
   FRIEND_TEST_ALL_PREFIXES(InstantExtendedTest, PreloadedNTPIsUsedInNewTab);
   FRIEND_TEST_ALL_PREFIXES(InstantExtendedTest, PreloadedNTPIsUsedInSameTab);
@@ -307,37 +171,25 @@
                            PreloadedNTPDoesntSupportInstant);
   FRIEND_TEST_ALL_PREFIXES(InstantExtendedTest, ProcessIsolation);
   FRIEND_TEST_ALL_PREFIXES(InstantExtendedTest, UnrelatedSiteInstance);
-  FRIEND_TEST_ALL_PREFIXES(InstantExtendedTest, ValidatesSuggestions);
-  FRIEND_TEST_ALL_PREFIXES(InstantExtendedTest,
-                           OmniboxCommitsWhenShownFullHeight);
-  FRIEND_TEST_ALL_PREFIXES(InstantExtendedTest, LocalOnlyNTPIsPreloaded);
-  FRIEND_TEST_ALL_PREFIXES(InstantExtendedTest, LocalOnlyNTPIsNotPreloaded);
-  FRIEND_TEST_ALL_PREFIXES(InstantExtendedTest, OverlayRenderViewGone);
-  FRIEND_TEST_ALL_PREFIXES(InstantExtendedTest, OverlayDoesntSupportInstant);
-  FRIEND_TEST_ALL_PREFIXES(InstantExtendedManualTest,
-                           MANUAL_OmniboxFocusLoadsInstant);
-  FRIEND_TEST_ALL_PREFIXES(InstantExtendedManualTest,
-                           MANUAL_BackspaceFromQueryToSelectedUrlAndNavigate);
   FRIEND_TEST_ALL_PREFIXES(InstantExtendedTest, OnDefaultSearchProviderChanged);
-  FRIEND_TEST_ALL_PREFIXES(InstantExtendedTest, SearchProviderForLocalNTP);
+  FRIEND_TEST_ALL_PREFIXES(InstantExtendedNetworkTest,
+                           NTPReactsToNetworkChanges);
   FRIEND_TEST_ALL_PREFIXES(InstantExtendedTest,
                            AcceptingURLSearchDoesNotNavigate);
   FRIEND_TEST_ALL_PREFIXES(InstantExtendedTest, AcceptingJSSearchDoesNotRunJS);
   FRIEND_TEST_ALL_PREFIXES(InstantExtendedTest,
                            ReloadSearchAfterBackReloadsCorrectQuery);
-  FRIEND_TEST_ALL_PREFIXES(
-      InstantExtendedFirstTabTest, RedirectToLocalOnLoadFailure);
-  FRIEND_TEST_ALL_PREFIXES(InstantExtendedTest, LogDropdownShown);
-  FRIEND_TEST_ALL_PREFIXES(InstantExtendedTest,
-                           OverlayDoesNotEchoSearchProviderNavsuggest);
+  FRIEND_TEST_ALL_PREFIXES(InstantExtendedFirstTabTest,
+                           RedirectToLocalOnLoadFailure);
   FRIEND_TEST_ALL_PREFIXES(InstantExtendedTest, KeyboardTogglesVoiceSearch);
-#if !defined(HTML_INSTANT_EXTENDED_POPUP)
+  FRIEND_TEST_ALL_PREFIXES(InstantExtendedTest, HomeButtonAffectsMargin);
   FRIEND_TEST_ALL_PREFIXES(InstantExtendedTest, SearchReusesInstantTab);
   FRIEND_TEST_ALL_PREFIXES(InstantExtendedTest,
                            SearchDoesntReuseInstantTabWithoutSupport);
   FRIEND_TEST_ALL_PREFIXES(InstantExtendedTest,
                            TypedSearchURLDoesntReuseInstantTab);
-#endif
+  FRIEND_TEST_ALL_PREFIXES(InstantExtendedTest,
+                           DispatchMVChangeEventWhileNavigatingBackToNTP);
 
   // Overridden from InstantPage::Delegate:
   // TODO(shishir): We assume that the WebContent's current RenderViewHost is
@@ -352,14 +204,6 @@
   virtual void InstantPageAboutToNavigateMainFrame(
       const content::WebContents* contents,
       const GURL& url) OVERRIDE;
-  virtual void SetSuggestions(
-      const content::WebContents* contents,
-      const std::vector<InstantSuggestion>& suggestions) OVERRIDE;
-  virtual void ShowInstantOverlay(
-      const content::WebContents* contents,
-      int height,
-      InstantSizeUnits units) OVERRIDE;
-  virtual void LogDropdownShown() OVERRIDE;
   virtual void FocusOmnibox(const content::WebContents* contents,
                             OmniboxFocusState state) OVERRIDE;
   virtual void NavigateToURL(
@@ -370,6 +214,11 @@
       bool is_search_type) OVERRIDE;
   virtual void InstantPageLoadFailed(content::WebContents* contents) OVERRIDE;
 
+  // Overridden from InstantServiceObserver:
+  virtual void ThemeInfoChanged(const ThemeBackgroundInfo& theme_info) OVERRIDE;
+  virtual void MostVisitedItemsChanged(
+      const std::vector<InstantMostVisitedItem>& items) OVERRIDE;
+
   // Invoked by the InstantLoader when the Instant page wants to delete a
   // Most Visited item.
   virtual void DeleteMostVisitedItem(const GURL& url) OVERRIDE;
@@ -400,19 +249,9 @@
   // Recreates |ntp_| using |instant_url|.
   void ResetNTP(const std::string& instant_url);
 
-  // Reloads a new InstantNTP.  Called when |ntp_| is stale.
-  void ReloadStaleNTP();
-
   // Returns true if we should switch to using the local NTP.
   bool ShouldSwitchToLocalNTP() const;
 
-  // Recreates |overlay_| using |instant_url|. |overlay_| will be NULL if
-  // |instant_url| is empty or if there is no active tab.
-  void ResetOverlay(const std::string& instant_url);
-
-  // Returns an enum value indicating the reason to fallback.
-  InstantFallbackReason ShouldSwitchToLocalOverlay() const;
-
   // If the active tab is an Instant search results page, sets |instant_tab_| to
   // point to it. Else, deletes any existing |instant_tab_|.
   void ResetInstantTab();
@@ -424,102 +263,22 @@
   // active tab is in mode SEARCH_SUGGESTIONS.
   bool IsInputInProgress() const;
 
-  // Hide the overlay. Also sends an onchange event (with blank query) to the
-  // overlay, telling it to clear out results for any old queries.
-  void HideOverlay();
-
-  // Like HideOverlay(), but doesn't call OnStaleOverlay(). Use HideOverlay()
-  // unless you are going to call overlay_.reset() yourself subsequently.
-  void HideInternal();
-
-  // Counterpart to HideOverlay(). Asks the |browser_| to display the overlay
-  // with the given |height| in |units|.
-  void ShowOverlay(int height, InstantSizeUnits units);
-
-  // Send the omnibox popup bounds to the page.
-  void SendPopupBoundsToPage();
-
-  // If possible, tries to mutate |suggestion| to a valid suggestion. Returns
-  // true if successful. (Note that |suggestion| may be modified even if this
-  // returns false.)
-  bool FixSuggestion(InstantSuggestion* suggestion) const;
-
   // Returns true if the local page is being used.
   bool UsingLocalPage() const;
 
-  // Returns true iff |use_tab_for_suggestions_| is true and |instant_tab_|
-  // exists.
-  bool UseTabForSuggestions() const;
-
-  // Populates InstantAutocompleteResult with AutocompleteMatch details.
-  // |autocomplete_match_index| specifies the index of |match| in the
-  // AutocompleteResult. If the |match| is obtained from auto complete
-  // providers, then the |autocomplete_match_index| is set to kNoMatchIndex.
-  void PopulateInstantAutocompleteResultFromMatch(
-      const AutocompleteMatch& match,
-      size_t autocomplete_match_index,
-      InstantAutocompleteResult* result);
+  // Returns the InstantService for the browser profile.
+  InstantService* GetInstantService() const;
 
   BrowserInstantController* const browser_;
 
   // Whether the extended API and regular API are enabled. If both are false,
   // Instant is effectively disabled.
   const bool extended_enabled_;
-  bool instant_enabled_;
 
-  // If true, the Instant URL is set to kChromeSearchLocalNtpUrl.
-  bool use_local_page_only_;
-
-  // If true, preload an NTP into |ntp_|.
-  bool preload_ntp_;
-
-  // The state of the overlay page, i.e., the page owned by |overlay_|. Ignored
-  // if |instant_tab_| is in use.
-  InstantOverlayModel model_;
-
-  // The three instances of InstantPage maintained by InstantController as
-  // described above. All three may be non-NULL in extended mode.  If
-  // |instant_tab_| is not NULL, then |overlay_| is guaranteed to be hidden and
-  // messages will be sent to |instant_tab_| instead.
-  //
-  // In non-extended mode, only |overlay_| is ever non-NULL.
-  scoped_ptr<InstantOverlay> overlay_;
+  // The instances of InstantPage maintained by InstantController.
   scoped_ptr<InstantNTP> ntp_;
   scoped_ptr<InstantTab> instant_tab_;
 
-  // If true, send suggestion-related events (such as user key strokes, auto
-  // complete results, etc.) to |instant_tab_| instead of |overlay_|. Once set
-  // to false, will stay false until the overlay is hidden or committed.
-  bool use_tab_for_suggestions_;
-
-  // The most recent full_text passed to Update(). If empty, we'll not accept
-  // search suggestions from |overlay_| or |instant_tab_|.
-  string16 last_omnibox_text_;
-
-  // The most recent user_text passed to Update(). Used to filter out-of-date
-  // URL suggestions from the Instant page. Set in Update() and cleared when
-  // the page sets temporary text (SetSuggestions() with REPLACE behavior).
-  string16 last_user_text_;
-
-  // True if the last Update() had an inline autocompletion. Used only to make
-  // sure that we don't accidentally suggest gray text suggestion in that case.
-  bool last_omnibox_text_has_inline_autocompletion_;
-
-  // The most recent verbatim passed to Update(). Used only to ensure that we
-  // don't accidentally suggest an inline autocompletion.
-  bool last_verbatim_;
-
-  // The most recent suggestion received from the page, minus any prefix that
-  // the user has typed.
-  InstantSuggestion last_suggestion_;
-
-  // See comments on the getter above.
-  content::PageTransition last_transition_type_;
-
-  // True if the last match passed to Update() was a search (versus a URL).
-  // Used to ensure that the overlay page is committable.
-  bool last_match_was_search_;
-
   // Omnibox focus state.
   OmniboxFocusState omnibox_focus_state_;
 
@@ -529,38 +288,10 @@
   // The search model mode for the active tab.
   SearchMode search_mode_;
 
-  // Current omnibox popup bounds.
-  gfx::Rect popup_bounds_;
-
-  // Last popup bounds passed to the page.
-  gfx::Rect last_popup_bounds_;
-
   // The start-edge margin and width of the omnibox, used by the page to align
   // its suggestions with the omnibox.
   gfx::Rect omnibox_bounds_;
 
-  // Timer used to update the bounds of the omnibox popup.
-  base::OneShotTimer<InstantController> update_bounds_timer_;
-
-  // Search terms extraction (for autocomplete history matches) doesn't work
-  // on Instant URLs. So, whenever the user commits an Instant search, we add
-  // an equivalent non-Instant search URL to history, so that the search shows
-  // up in autocomplete history matches.
-  // TODO(sreeram): Remove when http://crbug.com/155373 is fixed.
-  GURL url_for_history_;
-
-  // The timestamp at which query editing began. This value is used when the
-  // overlay is showed and cleared when the overlay is hidden.
-  base::Time first_interaction_time_;
-
-  // Indicates that the first interaction time has already been logged.
-  bool first_interaction_time_recorded_;
-
-  // Whether to allow the overlay to show search suggestions. In general, the
-  // overlay is allowed to show search suggestions whenever |search_mode_| is
-  // MODE_SEARCH_SUGGESTIONS, except in those cases where this is false.
-  bool allow_overlay_to_show_search_suggestions_;
-
   // List of events and their timestamps, useful in debugging Instant behaviour.
   mutable std::list<std::pair<int64, std::string> > debug_events_;
 
diff --git a/chrome/browser/ui/search/instant_controller_unittest.cc b/chrome/browser/ui/search/instant_controller_unittest.cc
index 3ed131e..b96540b 100644
--- a/chrome/browser/ui/search/instant_controller_unittest.cc
+++ b/chrome/browser/ui/search/instant_controller_unittest.cc
@@ -11,7 +11,6 @@
 #include "chrome/browser/search/search.h"
 #include "chrome/browser/ui/search/instant_controller.h"
 #include "chrome/browser/ui/search/instant_ntp.h"
-#include "chrome/browser/ui/search/instant_overlay.h"
 #include "chrome/common/content_settings.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/testing_profile.h"
@@ -22,41 +21,11 @@
 using base::HistogramSamples;
 using base::StatisticsRecorder;
 
-class TestableInstantOverlay : public InstantOverlay {
- public:
-  TestableInstantOverlay(InstantController* controller,
-                         const std::string& instant_url)
-      : InstantOverlay(controller, instant_url) {
-  }
-
-  // Overrides from InstantPage
-  virtual bool supports_instant() const OVERRIDE {
-    return test_supports_instant_;
-  }
-
-  virtual bool IsLocal() const OVERRIDE {
-    return test_is_local_;
-  };
-
-  void set_supports_instant(bool supports_instant) {
-    test_supports_instant_ = supports_instant;
-  }
-
-  void set_is_local(bool is_local) {
-    test_is_local_ = is_local;
-  }
-
- private:
-  std::string test_instant_url_;
-  bool test_supports_instant_;
-  bool test_is_local_;
-};
-
 class TestableInstantNTP : public InstantNTP {
  public:
   TestableInstantNTP(InstantController* controller,
                      const std::string& instant_url)
-      : InstantNTP(controller, instant_url) {
+      : InstantNTP(controller, instant_url, false) {
   }
 
   // Overrides from InstantPage
@@ -99,7 +68,6 @@
         override_javascript_enabled_(true),
         test_javascript_enabled_(true),
         test_in_startup_(false),
-        test_overlay_(NULL),
         test_ntp_(NULL) {}
 
   // Overrides from InstantController
@@ -115,10 +83,6 @@
     return test_extended_enabled_;
   }
 
-  virtual InstantOverlay* overlay() const OVERRIDE {
-    return test_overlay_;
-  }
-
   virtual InstantNTP* ntp() const OVERRIDE {
     return test_ntp_;
   }
@@ -131,10 +95,6 @@
     test_extended_enabled_ = extended_enabled;
   }
 
-  void set_overlay(InstantOverlay* overlay) {
-    test_overlay_ = overlay;
-  }
-
   void set_ntp(InstantNTP* ntp) {
     test_ntp_ = ntp;
   }
@@ -173,7 +133,6 @@
   bool override_javascript_enabled_;
   bool test_javascript_enabled_;
   bool test_in_startup_;
-  InstantOverlay* test_overlay_;
   InstantNTP* test_ntp_;
   mutable TestingProfile profile_;
 };
@@ -198,53 +157,6 @@
   scoped_ptr<TestableInstantController> instant_controller_;
 };
 
-TEST_F(InstantControllerTest, ShouldSwitchToLocalOverlay) {
-  InstantController::InstantFallbackReason fallback_reason;
-
-  instant_controller()->set_extended_enabled(false);
-  fallback_reason = instant_controller()->ShouldSwitchToLocalOverlay();
-  ASSERT_EQ(fallback_reason, InstantController::INSTANT_FALLBACK_NONE);
-
-  instant_controller()->set_extended_enabled(true);
-  fallback_reason = instant_controller()->ShouldSwitchToLocalOverlay();
-  ASSERT_EQ(fallback_reason, InstantController::INSTANT_FALLBACK_NO_OVERLAY);
-
-  std::string instant_url("http://test_url");
-  scoped_ptr<TestableInstantOverlay> test_overlay(
-      new TestableInstantOverlay(instant_controller(), instant_url));
-  test_overlay->set_is_local(true);
-  instant_controller()->set_overlay(test_overlay.get());
-  fallback_reason = instant_controller()->ShouldSwitchToLocalOverlay();
-  ASSERT_EQ(fallback_reason, InstantController::INSTANT_FALLBACK_NONE);
-
-  instant_controller()->set_javascript_enabled(false);
-  fallback_reason = instant_controller()->ShouldSwitchToLocalOverlay();
-  ASSERT_EQ(fallback_reason,
-            InstantController::INSTANT_FALLBACK_JAVASCRIPT_DISABLED);
-  instant_controller()->set_javascript_enabled(true);
-
-  test_overlay->set_is_local(false);
-  instant_controller()->set_instant_url("");
-  fallback_reason = instant_controller()->ShouldSwitchToLocalOverlay();
-  ASSERT_EQ(fallback_reason,
-            InstantController::INSTANT_FALLBACK_INSTANT_URL_EMPTY);
-
-  instant_controller()->set_instant_url("http://instant_url");
-  fallback_reason = instant_controller()->ShouldSwitchToLocalOverlay();
-  ASSERT_EQ(fallback_reason,
-            InstantController::INSTANT_FALLBACK_ORIGIN_PATH_MISMATCH);
-
-  instant_controller()->set_instant_url(instant_url);
-  test_overlay->set_supports_instant(false);
-  fallback_reason = instant_controller()->ShouldSwitchToLocalOverlay();
-  ASSERT_EQ(fallback_reason,
-            InstantController::INSTANT_FALLBACK_INSTANT_NOT_SUPPORTED);
-
-  test_overlay->set_supports_instant(true);
-  fallback_reason = instant_controller()->ShouldSwitchToLocalOverlay();
-  ASSERT_EQ(fallback_reason, InstantController::INSTANT_FALLBACK_NONE);
-}
-
 TEST_F(InstantControllerTest, PrefersRemoteNTPOnStartup) {
   std::string instant_url("http://instant_url");
   scoped_ptr<TestableInstantNTP> ntp(new TestableInstantNTP(
diff --git a/chrome/browser/ui/search/instant_extended_interactive_uitest.cc b/chrome/browser/ui/search/instant_extended_interactive_uitest.cc
index c9a6666..344b7e4 100644
--- a/chrome/browser/ui/search/instant_extended_interactive_uitest.cc
+++ b/chrome/browser/ui/search/instant_extended_interactive_uitest.cc
@@ -5,16 +5,16 @@
 #include <sstream>
 
 #include "base/command_line.h"
-#include "base/metrics/field_trial.h"
 #include "base/metrics/histogram_base.h"
 #include "base/metrics/histogram_samples.h"
 #include "base/metrics/statistics_recorder.h"
 #include "base/prefs/pref_service.h"
+#include "base/run_loop.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/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/autocomplete/autocomplete_controller.h"
 #include "chrome/browser/autocomplete/autocomplete_match.h"
 #include "chrome/browser/autocomplete/autocomplete_provider.h"
@@ -43,9 +43,7 @@
 #include "chrome/browser/ui/browser_list.h"
 #include "chrome/browser/ui/browser_tabstrip.h"
 #include "chrome/browser/ui/omnibox/omnibox_view.h"
-#include "chrome/browser/ui/search/instant_commit_type.h"
 #include "chrome/browser/ui/search/instant_ntp.h"
-#include "chrome/browser/ui/search/instant_overlay.h"
 #include "chrome/browser/ui/search/instant_tab.h"
 #include "chrome/browser/ui/search/instant_test_utils.h"
 #include "chrome/browser/ui/search/search_tab_helper.h"
@@ -75,6 +73,7 @@
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/test_utils.h"
 #include "grit/generated_resources.h"
+#include "net/base/network_change_notifier.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -113,6 +112,26 @@
   DISALLOW_COPY_AND_ASSIGN(QuittingHistoryDBTask);
 };
 
+class FakeNetworkChangeNotifier : public net::NetworkChangeNotifier {
+ public:
+  FakeNetworkChangeNotifier() : connection_type_(CONNECTION_NONE) {}
+
+  virtual ConnectionType GetCurrentConnectionType() const OVERRIDE {
+    return connection_type_;
+  }
+
+  void SetConnectionType(ConnectionType type) {
+    connection_type_ = type;
+    NotifyObserversOfNetworkChange(type);
+    base::RunLoop().RunUntilIdle();
+  }
+
+  virtual ~FakeNetworkChangeNotifier() {}
+
+ private:
+  ConnectionType connection_type_;
+  DISALLOW_COPY_AND_ASSIGN(FakeNetworkChangeNotifier);
+};
 }  // namespace
 
 class InstantExtendedTest : public InProcessBrowserTest,
@@ -150,10 +169,6 @@
     return histogram->SnapshotSamples()->TotalCount();
   }
 
-  std::string GetOmniboxText() {
-    return UTF16ToUTF8(omnibox()->GetText());
-  }
-
   void SendDownArrow() {
     omnibox()->model()->OnUpOrDownKeyPressed(1);
     // Wait for JavaScript to run the key handler by executing a blank script.
@@ -251,6 +266,29 @@
   int on_toggle_voice_search_calls_;
 };
 
+class InstantExtendedNetworkTest : public InstantExtendedTest {
+ protected:
+  virtual void SetUpOnMainThread() OVERRIDE {
+    disable_for_test_.reset(new net::NetworkChangeNotifier::DisableForTest);
+    fake_network_change_notifier_.reset(new FakeNetworkChangeNotifier);
+    InstantExtendedTest::SetUpOnMainThread();
+  }
+
+  virtual void CleanUpOnMainThread() OVERRIDE {
+    InstantExtendedTest::CleanUpOnMainThread();
+    fake_network_change_notifier_.reset();
+    disable_for_test_.reset();
+  }
+
+  void SetConnectionType(net::NetworkChangeNotifier::ConnectionType type) {
+    fake_network_change_notifier_->SetConnectionType(type);
+  }
+
+ private:
+  scoped_ptr<net::NetworkChangeNotifier::DisableForTest> disable_for_test_;
+  scoped_ptr<FakeNetworkChangeNotifier> fake_network_change_notifier_;
+};
+
 // Test class used to verify chrome-search: scheme and access policy from the
 // Instant overlay.  This is a subclass of |ExtensionBrowserTest| because it
 // loads a theme that provides a background image.
@@ -295,538 +333,45 @@
   EXPECT_TRUE(instant()->extended_enabled_);
 }
 
-// Test that Instant is preloaded when the omnibox is focused.
-IN_PROC_BROWSER_TEST_F(InstantExtendedTest, OmniboxFocusLoadsInstant) {
-  ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
-
-  // Explicitly unfocus the omnibox.
-  EXPECT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
-  ui_test_utils::ClickOnView(browser(), VIEW_ID_TAB_CONTAINER);
-
-  EXPECT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_TAB_CONTAINER));
-  EXPECT_FALSE(omnibox()->model()->has_focus());
-
-  // Delete any existing overlay.
-  instant()->overlay_.reset();
-  EXPECT_FALSE(instant()->GetOverlayContents());
-
-  // Refocus the omnibox. The InstantController should've preloaded Instant.
-  FocusOmniboxAndWaitForInstantOverlayAndNTPSupport();
-
-  EXPECT_FALSE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_TAB_CONTAINER));
-  EXPECT_TRUE(omnibox()->model()->has_focus());
-
-  content::WebContents* overlay = instant()->GetOverlayContents();
-  EXPECT_TRUE(overlay);
-
-  // Check that the page supports Instant, but it isn't showing.
-  EXPECT_TRUE(instant()->overlay_->supports_instant());
-  EXPECT_FALSE(instant()->IsOverlayingSearchResults());
-  EXPECT_TRUE(instant()->model()->mode().is_default());
-
-  // Adding a new tab shouldn't delete or recreate the overlay; otherwise,
-  // what's the point of preloading?
-  AddBlankTabAndShow(browser());
-  EXPECT_EQ(overlay, instant()->GetOverlayContents());
-
-  // Unfocusing and refocusing the omnibox should also preserve the overlay.
-  ui_test_utils::ClickOnView(browser(), VIEW_ID_TAB_CONTAINER);
-  EXPECT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_TAB_CONTAINER));
-
-  FocusOmnibox();
-  EXPECT_FALSE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_TAB_CONTAINER));
-  EXPECT_EQ(overlay, instant()->GetOverlayContents());
-}
-
-IN_PROC_BROWSER_TEST_F(InstantExtendedTest, InputShowsOverlay) {
-  ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
-
-  // Focus omnibox and confirm overlay isn't shown.
-  FocusOmniboxAndWaitForInstantOverlayAndNTPSupport();
-  content::WebContents* overlay = instant()->GetOverlayContents();
-  EXPECT_TRUE(overlay);
-  EXPECT_FALSE(instant()->IsOverlayingSearchResults());
-  EXPECT_TRUE(instant()->model()->mode().is_default());
-
-  // Typing in the omnibox should show the overlay.
-  ASSERT_TRUE(SetOmniboxTextAndWaitForOverlayToShow("query"));
-  EXPECT_TRUE(instant()->model()->mode().is_search_suggestions());
-  EXPECT_EQ(overlay, instant()->GetOverlayContents());
-}
-
-// Flaky on Linux Tests bot.
-#if defined(OS_LINUX)
-#define MAYBE_UsesOverlayIfTabNotReady DISABLED_UsesOverlayIfTabNotReady
-#else
-#define MAYBE_UsesOverlayIfTabNotReady UsesOverlayIfTabNotReady
-#endif
-
-IN_PROC_BROWSER_TEST_F(InstantExtendedTest, MAYBE_UsesOverlayIfTabNotReady) {
-  ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
-  FocusOmniboxAndWaitForInstantOverlayAndNTPSupport();
-
-  // Open a new tab and start typing before InstantTab is properly hooked up.
-  // Should use the overlay.
-  ui_test_utils::NavigateToURLWithDisposition(
-      browser(),
-      GURL(chrome::kChromeUINewTabURL),
-      NEW_FOREGROUND_TAB,
-      ui_test_utils::BROWSER_TEST_WAIT_FOR_TAB);
-  ASSERT_TRUE(SetOmniboxTextAndWaitForOverlayToShow("query"));
-
-  // But Instant tab should still exist.
-  ASSERT_NE(static_cast<InstantTab*>(NULL), instant()->instant_tab());
-  EXPECT_FALSE(instant()->UseTabForSuggestions());
-
-  // Wait for Instant Tab support if it still hasn't finished loading.
-  if (!instant()->instant_tab()->supports_instant()) {
-    content::WindowedNotificationObserver instant_tab_observer(
-        chrome::NOTIFICATION_INSTANT_TAB_SUPPORT_DETERMINED,
-        content::NotificationService::AllSources());
-    instant_tab_observer.Wait();
-  }
-
-  // Hide the overlay. Now, we should be using Instant tab for suggestions.
-  instant()->HideOverlay();
-  EXPECT_TRUE(instant()->UseTabForSuggestions());
-}
-
-// Flaky on Mac Tests bot. crbug.com/242415
-#if defined(OS_MACOSX)
-#define MAYBE_MiddleClickOnSuggestionOpensInNewTab DISABLED_MiddleClickOnSuggestionOpensInNewTab
-#else
-#define MAYBE_MiddleClickOnSuggestionOpensInNewTab MiddleClickOnSuggestionOpensInNewTab
-#endif
-
-// Test that middle clicking on a suggestion opens the result in a new tab.
-IN_PROC_BROWSER_TEST_F(InstantExtendedTest,
-                       MAYBE_MiddleClickOnSuggestionOpensInNewTab) {
-  ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
-  FocusOmniboxAndWaitForInstantOverlayAndNTPSupport();
-  EXPECT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
-
-  EXPECT_EQ(1, browser()->tab_strip_model()->count());
-
-  // Typing in the omnibox should show the overlay.
-  ASSERT_TRUE(SetOmniboxTextAndWaitForOverlayToShow("http://www.example.com/"));
-
-  // Create an event listener that opens the top suggestion in a new tab.
-  EXPECT_TRUE(ExecuteScript(
-      "var rid = getApiHandle().nativeSuggestions[0].rid;"
-      "document.body.addEventListener('click', function() {"
-        "chrome.embeddedSearch.navigateContentWindow(rid, 2);"
-      "});"
-      ));
-
-  content::WindowedNotificationObserver observer(
-        chrome::NOTIFICATION_TAB_ADDED,
-        content::NotificationService::AllSources());
-
-  // Click to trigger the event listener.
-  ui_test_utils::ClickOnView(browser(), VIEW_ID_TAB_CONTAINER);
-
-  // Wait for the new tab to be added.
-  observer.Wait();
-
-  // Check that the new tab URL is as expected.
-  content::WebContents* new_tab_contents =
-      browser()->tab_strip_model()->GetWebContentsAt(1);
-  EXPECT_EQ("http://www.example.com/", new_tab_contents->GetURL().spec());
-
-  // Check that there are now two tabs.
-  EXPECT_EQ(2, browser()->tab_strip_model()->count());
-}
-
-IN_PROC_BROWSER_TEST_F(InstantExtendedTest,
-                       UnfocusingOmniboxDoesNotChangeSuggestions) {
-  ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
-  FocusOmniboxAndWaitForInstantOverlayAndNTPSupport();
-  EXPECT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
-
-  // Get a committed tab to work with.
-  content::WebContents* instant_tab = instant()->GetOverlayContents();
-  ASSERT_TRUE(SetOmniboxTextAndWaitForOverlayToShow("committed"));
-  browser()->window()->GetLocationBar()->AcceptInput();
-
-  // Put focus back into the omnibox, type, and wait for some gray text.
-  EXPECT_TRUE(content::ExecuteScript(instant_tab,
-                                     "suggestion = 'santa claus';"));
-  SetOmniboxTextAndWaitForSuggestion("santa ");
-  EXPECT_EQ(ASCIIToUTF16("claus"), GetGrayText());
-  EXPECT_TRUE(content::ExecuteScript(instant_tab,
-      "onChangeCalls = onNativeSuggestionsCalls = 0;"));
-
-  // Now unfocus the omnibox.
-  ui_test_utils::ClickOnView(browser(), VIEW_ID_TAB_CONTAINER);
-  EXPECT_TRUE(UpdateSearchState(instant_tab));
-  EXPECT_EQ(0, on_change_calls_);
-  EXPECT_EQ(0, on_native_suggestions_calls_);
-}
-
-// Test that omnibox text is correctly set when overlay is committed with Enter.
-IN_PROC_BROWSER_TEST_F(InstantExtendedTest, OmniboxTextUponEnterCommit) {
-  ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
-  FocusOmniboxAndWaitForInstantOverlayAndNTPSupport();
-
-  // The page will autocomplete once we set the omnibox value.
-  EXPECT_TRUE(ExecuteScript("suggestion = 'santa claus';"));
-
-  // Set the text, and wait for suggestions to show up.
-  ASSERT_TRUE(SetOmniboxTextAndWaitForOverlayToShow("santa"));
-  EXPECT_EQ(ASCIIToUTF16("santa"), omnibox()->GetText());
-
-  // Test that the current suggestion is correctly set.
-  EXPECT_EQ(ASCIIToUTF16(" claus"), GetGrayText());
-
-  // Commit the search by pressing Enter.
-  browser()->window()->GetLocationBar()->AcceptInput();
-
-  // 'Enter' commits the query as it was typed.
-  EXPECT_EQ(ASCIIToUTF16("santa"), omnibox()->GetText());
-
-  // Suggestion should be cleared at this point.
-  EXPECT_EQ(ASCIIToUTF16(""), GetGrayText());
-}
-
-// Test that omnibox text is correctly set when committed with focus lost.
-IN_PROC_BROWSER_TEST_F(InstantExtendedTest, OmniboxTextUponFocusLostCommit) {
-  ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
-  FocusOmniboxAndWaitForInstantOverlayAndNTPSupport();
-
-  // Set autocomplete text (grey text).
-  EXPECT_TRUE(ExecuteScript("suggestion = 'johnny depp';"));
-
-  // Set the text, and wait for suggestions to show up.
-  ASSERT_TRUE(SetOmniboxTextAndWaitForOverlayToShow("johnny"));
-  EXPECT_EQ(ASCIIToUTF16("johnny"), omnibox()->GetText());
-
-  // Test that the current suggestion is correctly set.
-  EXPECT_EQ(ASCIIToUTF16(" depp"), GetGrayText());
-
-  // Commit the overlay by lost focus (e.g. clicking on the page).
-  instant()->CommitIfPossible(INSTANT_COMMIT_FOCUS_LOST);
-
-  // Omnibox text and suggestion should not be changed.
-  EXPECT_EQ(ASCIIToUTF16("johnny"), omnibox()->GetText());
-  EXPECT_EQ(ASCIIToUTF16(" depp"), GetGrayText());
-}
-
-// Test that omnibox text is correctly set when clicking on committed SERP.
-// Disabled on Mac because omnibox focus loss is not working correctly.
-IN_PROC_BROWSER_TEST_F(InstantExtendedTest,
-                       OmniboxTextUponFocusedCommittedSERP) {
-  // Setup Instant.
-  ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
-  FocusOmniboxAndWaitForInstantOverlayAndNTPSupport();
-
-  // Create an observer to wait for the instant tab to support Instant.
-  content::WindowedNotificationObserver observer(
-      chrome::NOTIFICATION_INSTANT_TAB_SUPPORT_DETERMINED,
-      content::NotificationService::AllSources());
-
-  // Do a search and commit it.
-  ASSERT_TRUE(SetOmniboxTextAndWaitForOverlayToShow("hello k"));
-  EXPECT_EQ(ASCIIToUTF16("hello k"), omnibox()->GetText());
-  browser()->window()->GetLocationBar()->AcceptInput();
-  observer.Wait();
-
-  // With a committed results page, do a search by unfocusing the omnibox and
-  // focusing the contents.
-  SetOmniboxText("hello");
-  // Calling handleOnChange manually to make sure it is called before the
-  // Focus() call below.
-  EXPECT_TRUE(content::ExecuteScript(instant()->instant_tab()->contents(),
-                                     "suggestion = 'hello kitty';"
-                                     "handleOnChange();"));
-  instant()->instant_tab()->contents()->GetView()->Focus();
-
-  // Omnibox text and suggestion should not be changed.
-  EXPECT_EQ(ASCIIToUTF16("hello"), omnibox()->GetText());
-  EXPECT_EQ(ASCIIToUTF16(" kitty"), GetGrayText());
-}
-
-// Checks that a previous Navigation suggestion is not re-used when a search
-// suggestion comes in.
-IN_PROC_BROWSER_TEST_F(InstantExtendedTest,
-                       NavigationSuggestionIsDiscardedUponSearchSuggestion) {
-  // Setup Instant.
-  ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
-  FocusOmniboxAndWaitForInstantOverlayAndNTPSupport();
-
-  // Tell the page to send a URL suggestion.
-  EXPECT_TRUE(ExecuteScript("suggestion = 'http://www.example.com';"
-                            "behavior = 1;"));
-  ASSERT_TRUE(SetOmniboxTextAndWaitForOverlayToShow("exa"));
-  EXPECT_EQ(ASCIIToUTF16("example.com"), omnibox()->GetText());
-
-  // Now send a search suggestion and see that Navigation suggestion is no
-  // longer kept.
-  EXPECT_TRUE(ExecuteScript("suggestion = 'exams are great';"
-                            "behavior = 2;"));
-  SetOmniboxText("exam");
-  // Wait for JavaScript to run handleOnChange by executing a blank script.
-  EXPECT_TRUE(ExecuteScript(std::string()));
-
-  instant()->overlay()->contents()->GetView()->Focus();
-  EXPECT_EQ(ASCIIToUTF16("exam"), omnibox()->GetText());
-  EXPECT_EQ(ASCIIToUTF16("s are great"), GetGrayText());
-
-  // TODO(jered): Remove this after fixing OnBlur().
-  omnibox()->RevertAll();
-}
-
-// This test simulates a search provider using the InstantExtended API to
-// navigate through the suggested results and back to the original user query.
-IN_PROC_BROWSER_TEST_F(InstantExtendedTest, NavigateSuggestionsWithArrowKeys) {
-  ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
-  FocusOmniboxAndWaitForInstantOverlayAndNTPSupport();
-
-  ASSERT_TRUE(SetOmniboxTextAndWaitForOverlayToShow("hello"));
-  EXPECT_EQ("hello", GetOmniboxText());
-
-  SendDownArrow();
-  EXPECT_EQ("result 1", GetOmniboxText());
-  SendDownArrow();
-  EXPECT_EQ("result 2", GetOmniboxText());
-  SendUpArrow();
-  EXPECT_EQ("result 1", GetOmniboxText());
-  SendUpArrow();
-  EXPECT_EQ("hello", GetOmniboxText());
-
-  // Ensure that the API's value is set correctly.
-  std::string result;
-  EXPECT_TRUE(GetStringFromJS(instant()->GetOverlayContents(),
-                              "window.chrome.searchBox.value",
-                              &result));
-  EXPECT_EQ("hello", result);
-
-  EXPECT_TRUE(HasUserInputInProgress());
-  // TODO(beaudoin): Figure out why this fails.
-  // EXPECT_FALSE(HasTemporaryText());
-
-  // Commit the search by pressing Enter.
-  browser()->window()->GetLocationBar()->AcceptInput();
-  EXPECT_EQ("hello", GetOmniboxText());
-}
-
-// Flaky on Linux Tests bot.  See http://crbug.com/233090.
-#if defined(OS_LINUX)
-#define MAYBE_NavigateToURLSuggestionHitEnterAndLookForSubmit DISABLED_NavigateToURLSuggestionHitEnterAndLookForSubmit
-#else
-#define MAYBE_NavigateToURLSuggestionHitEnterAndLookForSubmit NavigateToURLSuggestionHitEnterAndLookForSubmit
-#endif
-
-// This test simulates a search provider using the InstantExtended API to
-// navigate through the suggested results and back to the original user query.
-// If this test starts to flake, it may be that the second call to AcceptInput
-// below causes instant()->instant_tab() to no longer be valid due to e.g. a
-// navigation. In that case, see https://codereview.chromium.org/12895007/#msg28
-// and onwards for possible alternatives.
-IN_PROC_BROWSER_TEST_F(InstantExtendedTest,
-                       MAYBE_NavigateToURLSuggestionHitEnterAndLookForSubmit) {
-  ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
-  FocusOmniboxAndWaitForInstantOverlayAndNTPSupport();
-
-  // Create an observer to wait for the instant tab to support Instant.
-  content::WindowedNotificationObserver observer(
-      chrome::NOTIFICATION_INSTANT_TAB_SUPPORT_DETERMINED,
-      content::NotificationService::AllSources());
-
-  // Do a search and commit it.
-  ASSERT_TRUE(SetOmniboxTextAndWaitForOverlayToShow("hello k"));
-  EXPECT_EQ(ASCIIToUTF16("hello k"), omnibox()->GetText());
-  browser()->window()->GetLocationBar()->AcceptInput();
-  observer.Wait();
-
-  SetOmniboxText("http");
-  EXPECT_EQ("http", GetOmniboxText());
-
-  SendDownArrow();
-  EXPECT_EQ("result 1", GetOmniboxText());
-  SendDownArrow();
-  EXPECT_EQ("result 2", GetOmniboxText());
-
-  // Set the next suggestion to be of type INSTANT_SUGGESTION_URL.
-  EXPECT_TRUE(content::ExecuteScript(instant()->instant_tab()->contents(),
-                                     "suggestionType = 1;"));
-  SendDownArrow();
-  EXPECT_EQ("http://www.google.com", GetOmniboxText());
-
-  EXPECT_TRUE(HasUserInputInProgress());
-
-  EXPECT_TRUE(UpdateSearchState(instant()->instant_tab()->contents()));
-  // Note the commit count is initially 1 due to the AcceptInput() call above.
-  EXPECT_EQ(1, submit_count_);
-
-  std::string old_query_value(query_value_);
-
-  // Commit the search by pressing Enter.
-  browser()->window()->GetLocationBar()->AcceptInput();
-
-  // Make sure a submit message got sent.
-  EXPECT_TRUE(UpdateSearchState(instant()->instant_tab()->contents()));
-  EXPECT_EQ(2, submit_count_);
-  EXPECT_EQ(old_query_value, query_value_);
-}
-
-// This test simulates a search provider using the InstantExtended API to
-// navigate through the suggested results and hitting escape to get back to the
-// original user query.
-IN_PROC_BROWSER_TEST_F(InstantExtendedTest, NavigateSuggestionsAndHitEscape) {
-  ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
-  FocusOmniboxAndWaitForInstantOverlayAndNTPSupport();
-
-  ASSERT_TRUE(SetOmniboxTextAndWaitForOverlayToShow("hello"));
-  EXPECT_EQ("hello", GetOmniboxText());
-
-  SendDownArrow();
-  EXPECT_EQ("result 1", GetOmniboxText());
-  SendDownArrow();
-  EXPECT_EQ("result 2", GetOmniboxText());
-  SendEscape();
-  EXPECT_EQ("hello", GetOmniboxText());
-
-  // Ensure that the API's value is set correctly.
-  std::string result;
-  EXPECT_TRUE(GetStringFromJS(instant()->GetOverlayContents(),
-                              "window.chrome.searchBox.value",
-                              &result));
-  EXPECT_EQ("hello", result);
-
-  EXPECT_TRUE(HasUserInputInProgress());
-  EXPECT_FALSE(HasTemporaryText());
-
-  // Commit the search by pressing Enter.
-  browser()->window()->GetLocationBar()->AcceptInput();
-  EXPECT_EQ("hello", GetOmniboxText());
-}
-
-IN_PROC_BROWSER_TEST_F(InstantExtendedTest, PressEscapeWithBlueText) {
-  ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
-  FocusOmniboxAndWaitForInstantOverlayAndNTPSupport();
-
-  // Set blue text completion.
-  EXPECT_TRUE(ExecuteScript("suggestion = 'chimichanga.com';"
-                            "behavior = 1;"));
-
-  ASSERT_TRUE(SetOmniboxTextAndWaitForOverlayToShow("chimi"));
-
-  EXPECT_EQ(ASCIIToUTF16("chimichanga.com"), omnibox()->GetText());
-  EXPECT_EQ(ASCIIToUTF16("changa.com"), GetBlueText());
-  EXPECT_EQ(ASCIIToUTF16(""), GetGrayText());
-
-  EXPECT_TRUE(ExecuteScript("onChangeCalls = onNativeSuggestionsCalls = 0;"));
-
-  SendDownArrow();
-
-  EXPECT_EQ(ASCIIToUTF16("result 1"), omnibox()->GetText());
-  EXPECT_EQ(ASCIIToUTF16(""), GetBlueText());
-  EXPECT_EQ(ASCIIToUTF16(""), GetGrayText());
-
-  content::WindowedNotificationObserver observer(
-      chrome::NOTIFICATION_INSTANT_SET_SUGGESTION,
-      content::NotificationService::AllSources());
-  SendEscape();
-  observer.Wait();
-
-  EXPECT_EQ(ASCIIToUTF16("chimichanga.com"), omnibox()->GetText());
-  EXPECT_EQ(ASCIIToUTF16("changa.com"), GetBlueText());
-  EXPECT_EQ(ASCIIToUTF16(""), GetGrayText());
-
-  EXPECT_TRUE(UpdateSearchState(instant()->GetOverlayContents()));
-  EXPECT_EQ(0, on_native_suggestions_calls_);
-  EXPECT_EQ(0, on_change_calls_);
-}
-
-IN_PROC_BROWSER_TEST_F(InstantExtendedTest, PressEscapeWithGrayText) {
-  ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
-  FocusOmniboxAndWaitForInstantOverlayAndNTPSupport();
-
-  // Set gray text completion.
-  EXPECT_TRUE(ExecuteScript("suggestion = 'cowabunga';"
-                            "behavior = 2;"));
-
-  ASSERT_TRUE(SetOmniboxTextAndWaitForOverlayToShow("cowa"));
-
-  EXPECT_EQ(ASCIIToUTF16("cowa"), omnibox()->GetText());
-  EXPECT_EQ(ASCIIToUTF16(""), GetBlueText());
-  EXPECT_EQ(ASCIIToUTF16("bunga"), GetGrayText());
-
-  EXPECT_TRUE(ExecuteScript("onChangeCalls = onNativeSuggestionsCalls = 0;"));
-
-  SendDownArrow();
-
-  EXPECT_EQ(ASCIIToUTF16("result 1"), omnibox()->GetText());
-  EXPECT_EQ(ASCIIToUTF16(""), GetBlueText());
-  EXPECT_EQ(ASCIIToUTF16(""), GetGrayText());
-
-  content::WindowedNotificationObserver observer(
-      chrome::NOTIFICATION_INSTANT_SET_SUGGESTION,
-      content::NotificationService::AllSources());
-  SendEscape();
-  observer.Wait();
-
-  EXPECT_EQ(ASCIIToUTF16("cowa"), omnibox()->GetText());
-  EXPECT_EQ(ASCIIToUTF16(""), GetBlueText());
-  EXPECT_EQ(ASCIIToUTF16("bunga"), GetGrayText());
-
-  EXPECT_TRUE(UpdateSearchState(instant()->GetOverlayContents()));
-  EXPECT_EQ(0, on_native_suggestions_calls_);
-  EXPECT_EQ(0, on_change_calls_);
-}
-
 IN_PROC_BROWSER_TEST_F(InstantExtendedTest, NTPIsPreloaded) {
   // Setup Instant.
   ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
-  FocusOmniboxAndWaitForInstantOverlayAndNTPSupport();
+  FocusOmniboxAndWaitForInstantNTPSupport();
 
   // NTP contents should be preloaded.
   ASSERT_NE(static_cast<InstantNTP*>(NULL), instant()->ntp());
   content::WebContents* ntp_contents = instant()->ntp_->contents();
   EXPECT_TRUE(ntp_contents);
 }
+#endif  // HTML_INSTANT_EXTENDED_POPUP
 
-// Test that the local NTP is preloaded.
-IN_PROC_BROWSER_TEST_F(InstantExtendedTest, LocalOnlyNTPIsPreloaded) {
+IN_PROC_BROWSER_TEST_F(InstantExtendedNetworkTest, NTPReactsToNetworkChanges) {
   // Setup Instant.
   ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
+  FocusOmniboxAndWaitForInstantNTPSupport();
 
-  // The second argument says to use only the local overlay and NTP.
-  instant()->SetInstantEnabled(false, true);
-  FocusOmniboxAndWaitForInstantOverlayAndNTPSupport();
+  // The setup first initializes the platform specific NetworkChangeNotifier.
+  // The InstantExtendedNetworkTest replaces it with a fake, but by the time,
+  // instant controller has already registered itself. So the instant controller
+  // needs to register itself as NetworkChangeObserver again.
+  net::NetworkChangeNotifier::AddNetworkChangeObserver(browser_instant());
 
-  // NTP contents should be preloaded.
+  // The fake network change notifier will provide the network state to be
+  // offline, so the ntp will be local.
   ASSERT_NE(static_cast<InstantNTP*>(NULL), instant()->ntp());
-  content::WebContents* ntp_contents = instant()->ntp_->contents();
-  EXPECT_NE(static_cast<content::WebContents*>(NULL), ntp_contents);
   EXPECT_TRUE(instant()->ntp()->IsLocal());
-}
 
-// Test that the local NTP is not preloaded.
-IN_PROC_BROWSER_TEST_F(InstantExtendedTest, LocalOnlyNTPIsNotPreloaded) {
-  // Setup Instant.
-  ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
-  ASSERT_TRUE(base::FieldTrialList::CreateTrialsFromString(
-      "InstantExtended/Group1 local_only:1 preload_local_only_ntp:0/"));
+  // Change the connect state, and wait for the notifications to be run, and NTP
+  // support to be determined.
+  SetConnectionType(net::NetworkChangeNotifier::CONNECTION_ETHERNET);
+  FocusOmniboxAndWaitForInstantNTPSupport();
 
-  // The second argument says to use only the local overlay and NTP.
-  instant()->SetInstantEnabled(false, true);
+  // Verify the network state is fine, and instant controller doesn't want to
+  // switch to local NTP anymore.
+  EXPECT_FALSE(net::NetworkChangeNotifier::IsOffline());
+  EXPECT_FALSE(instant()->ShouldSwitchToLocalNTP());
 
-  // NTP contents should not be preloaded.
-  EXPECT_EQ(NULL, instant()->ntp());
-}
-
-IN_PROC_BROWSER_TEST_F(InstantExtendedTest, PreloadedNTPIsUsedInNewTab) {
-  // Setup Instant.
-  ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
-  FocusOmniboxAndWaitForInstantOverlayAndNTPSupport();
-
-  // NTP contents should be preloaded.
-  ASSERT_NE(static_cast<InstantNTP*>(NULL), instant()->ntp());
-  content::WebContents* ntp_contents = instant()->ntp_->contents();
-  EXPECT_TRUE(ntp_contents);
-
-  // Open new tab. Preloaded NTP contents should have been used.
+  // Open new tab.
   ui_test_utils::NavigateToURLWithDisposition(
       browser(),
       GURL(chrome::kChromeUINewTabURL),
@@ -834,14 +379,41 @@
       ui_test_utils::BROWSER_TEST_WAIT_FOR_TAB);
   content::WebContents* active_tab =
       browser()->tab_strip_model()->GetActiveWebContents();
-  EXPECT_EQ(ntp_contents, active_tab);
+
+  // Verify new NTP is not local.
   EXPECT_TRUE(chrome::IsInstantNTP(active_tab));
+  EXPECT_NE(instant()->GetLocalInstantURL(), active_tab->GetURL().spec());
+  ASSERT_NE(static_cast<InstantNTP*>(NULL), instant()->ntp());
+  EXPECT_FALSE(instant()->ntp()->IsLocal());
+
+  SetConnectionType(net::NetworkChangeNotifier::CONNECTION_NONE);
+  FocusOmniboxAndWaitForInstantNTPSupport();
+
+  // Verify the network state is fine, and instant controller doesn't want to
+  // switch to local NTP anymore.
+  EXPECT_TRUE(net::NetworkChangeNotifier::IsOffline());
+  EXPECT_TRUE(instant()->ShouldSwitchToLocalNTP());
+
+  // Open new tab. Preloaded NTP contents should have been used.
+  ui_test_utils::NavigateToURLWithDisposition(
+      browser(),
+      GURL(chrome::kChromeUINewTabURL),
+      NEW_FOREGROUND_TAB,
+      ui_test_utils::BROWSER_TEST_WAIT_FOR_TAB);
+  active_tab = browser()->tab_strip_model()->GetActiveWebContents();
+
+  // Verify new NTP is not local.
+  EXPECT_TRUE(chrome::IsInstantNTP(active_tab));
+  EXPECT_EQ(instant()->GetLocalInstantURL(), active_tab->GetURL().spec());
+  ASSERT_NE(static_cast<InstantNTP*>(NULL), instant()->ntp());
+  EXPECT_TRUE(instant()->ntp()->IsLocal());
 }
 
+#if defined(HTML_INSTANT_EXTENDED_POPUP)
 IN_PROC_BROWSER_TEST_F(InstantExtendedTest, PreloadedNTPIsUsedInSameTab) {
   // Setup Instant.
   ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
-  FocusOmniboxAndWaitForInstantOverlayAndNTPSupport();
+  FocusOmniboxAndWaitForInstantNTPSupport();
 
   // NTP contents should be preloaded.
   ASSERT_NE(static_cast<InstantNTP*>(NULL), instant()->ntp());
@@ -863,7 +435,7 @@
 IN_PROC_BROWSER_TEST_F(InstantExtendedTest, PreloadedNTPForWrongProvider) {
   // Setup Instant.
   ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
-  FocusOmniboxAndWaitForInstantOverlayAndNTPSupport();
+  FocusOmniboxAndWaitForInstantNTPSupport();
 
   // NTP contents should be preloaded.
   ASSERT_NE(static_cast<InstantNTP*>(NULL), instant()->ntp());
@@ -888,7 +460,7 @@
 IN_PROC_BROWSER_TEST_F(InstantExtendedTest, PreloadedNTPRenderViewGone) {
   // Setup Instant.
   ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
-  FocusOmniboxAndWaitForInstantOverlayAndNTPSupport();
+  FocusOmniboxAndWaitForInstantNTPSupport();
 
   // NTP contents should be preloaded.
   ASSERT_NE(static_cast<InstantNTP*>(NULL), instant()->ntp());
@@ -914,7 +486,7 @@
   GURL instant_url = test_server()->GetURL("files/empty.html?strk=1");
   InstantTestBase::Init(instant_url);
   ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
-  FocusOmniboxAndWaitForInstantOverlayAndNTPSupport();
+  FocusOmniboxAndWaitForInstantNTPSupport();
 
   // NTP contents should have fallen back to the local page.
   ASSERT_NE(static_cast<InstantNTP*>(NULL), instant()->ntp());
@@ -935,7 +507,7 @@
 IN_PROC_BROWSER_TEST_F(InstantExtendedTest, DISABLED_OmniboxHasFocusOnNewTab) {
   // Setup Instant.
   ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
-  FocusOmniboxAndWaitForInstantOverlayAndNTPSupport();
+  FocusOmniboxAndWaitForInstantNTPSupport();
 
   // Explicitly unfocus the omnibox.
   EXPECT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
@@ -956,7 +528,7 @@
 IN_PROC_BROWSER_TEST_F(InstantExtendedTest, OmniboxEmptyOnNewTabPage) {
   // Setup Instant.
   ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
-  FocusOmniboxAndWaitForInstantOverlayAndNTPSupport();
+  FocusOmniboxAndWaitForInstantNTPSupport();
 
   // Open new tab. Preloaded NTP contents should have been used.
   ui_test_utils::NavigateToURLWithDisposition(
@@ -972,7 +544,7 @@
 IN_PROC_BROWSER_TEST_F(InstantExtendedTest, NoFaviconOnNewTabPage) {
   // Setup Instant.
   ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
-  FocusOmniboxAndWaitForInstantOverlayAndNTPSupport();
+  FocusOmniboxAndWaitForInstantNTPSupport();
 
   // Open new tab. Preloaded NTP contents should have been used.
   ui_test_utils::NavigateToURLWithDisposition(
@@ -995,31 +567,8 @@
   EXPECT_TRUE(favicon_tab_helper->ShouldDisplayFavicon());
 }
 
-IN_PROC_BROWSER_TEST_F(InstantExtendedTest, InputOnNTPDoesntShowOverlay) {
-  ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
-
-  // Focus omnibox and confirm overlay isn't shown.
-  FocusOmniboxAndWaitForInstantOverlayAndNTPSupport();
-  content::WebContents* overlay = instant()->GetOverlayContents();
-  EXPECT_TRUE(overlay);
-  EXPECT_FALSE(instant()->IsOverlayingSearchResults());
-  EXPECT_TRUE(instant()->model()->mode().is_default());
-
-  // Navigate to the NTP. Should use preloaded contents.
-  ui_test_utils::NavigateToURLWithDisposition(
-      browser(),
-      GURL(chrome::kChromeUINewTabURL),
-      CURRENT_TAB,
-      ui_test_utils::BROWSER_TEST_NONE);
-
-  // Typing in the omnibox should not show the overlay.
-  SetOmniboxText("query");
-  EXPECT_FALSE(instant()->IsOverlayingSearchResults());
-  EXPECT_TRUE(instant()->model()->mode().is_default());
-}
-
 IN_PROC_BROWSER_TEST_F(InstantExtendedTest, ProcessIsolation) {
-  // Prior to setup, Instant has an overlay with a failed "google.com" load in
+  // Prior to setup, Instant has an ntp with a failed "google.com" load in
   // it, which is rendered in the dedicated Instant renderer process.
   //
   // TODO(sreeram): Fix this up when we stop doing crazy things on init.
@@ -1034,15 +583,11 @@
 
   // Setup Instant.
   ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
-  FocusOmniboxAndWaitForInstantOverlayAndNTPSupport();
+  FocusOmniboxAndWaitForInstantNTPSupport();
 
   // The registered Instant render process should still exist.
   EXPECT_EQ(1, instant_service->GetInstantProcessCount());
-
-  // And the Instant overlay and ntp should live inside it.
-  content::WebContents* overlay = instant()->GetOverlayContents();
-  EXPECT_TRUE(instant_service->IsInstantProcess(
-      overlay->GetRenderProcessHost()->GetID()));
+  // And the Instant ntp should live inside it.
   content::WebContents* ntp_contents = instant()->ntp_->contents();
   EXPECT_TRUE(instant_service->IsInstantProcess(
       ntp_contents->GetRenderProcessHost()->GetID()));
@@ -1064,235 +609,24 @@
       active_tab->GetRenderProcessHost()->GetID()));
 }
 
-// Test that a search query will not be displayed for navsuggest queries.
-IN_PROC_BROWSER_TEST_F(InstantExtendedTest,
-                       SearchQueryNotDisplayedForNavsuggest) {
-  ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
-
-  // The second argument indicates to use only the local overlay and NTP.
-  instant()->SetInstantEnabled(true, true);
-
-  // Focus omnibox and confirm overlay isn't shown.
-  FocusOmniboxAndWaitForInstantOverlaySupport();
-
-  // Typing in the omnibox should show the overlay.
-  SetOmniboxText("face");
-
-  content::WebContents* overlay = instant()->GetOverlayContents();
-
-  // Add a navsuggest suggestion.
-  instant()->SetSuggestions(
-      overlay,
-      std::vector<InstantSuggestion>(
-          1,
-          InstantSuggestion(ASCIIToUTF16("http://facemash.com/"),
-                            INSTANT_COMPLETE_NOW,
-                            INSTANT_SUGGESTION_URL,
-                            ASCIIToUTF16("face"),
-                            kNoMatchIndex)));
-
-  while (!omnibox()->model()->autocomplete_controller()->done()) {
-    content::WindowedNotificationObserver autocomplete_observer(
-        chrome::NOTIFICATION_AUTOCOMPLETE_CONTROLLER_RESULT_READY,
-        content::NotificationService::AllSources());
-    autocomplete_observer.Wait();
-  }
-
-  EXPECT_TRUE(ExecuteScript(
-      "var sorted = chrome.embeddedSearch.searchBox.nativeSuggestions.sort("
-          "function (a,b) {"
-            "return b.rankingData.relevance - a.rankingData.relevance;"
-          "});"));
-
-  int suggestions_count = -1;
-  EXPECT_TRUE(GetIntFromJS(
-      overlay, "sorted.length", &suggestions_count));
-  ASSERT_GT(suggestions_count, 0);
-
-  std::string type;
-  EXPECT_TRUE(
-      GetStringFromJS(overlay, "sorted[0].type", &type));
-  ASSERT_EQ("navsuggest", type);
-
-  bool is_search;
-  EXPECT_TRUE(GetBoolFromJS(
-      overlay, "!!sorted[0].is_search", &is_search));
-  EXPECT_FALSE(is_search);
-}
-
-// Verification of fix for BUG=176365.  Ensure that each Instant WebContents in
-// a tab uses a new BrowsingInstance, to avoid conflicts in the
-// NavigationController.
-// Flaky: http://crbug.com/177516
-IN_PROC_BROWSER_TEST_F(InstantExtendedTest, DISABLED_UnrelatedSiteInstance) {
-  // Setup Instant.
-  ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
-  FocusOmniboxAndWaitForInstantOverlayAndNTPSupport();
-
-  // Check that the uncommited ntp page and uncommited overlay have unrelated
-  // site instances.
-  // TODO(sreeram): |ntp_| is going away, so this check can be removed in the
-  // future.
-  content::WebContents* overlay = instant()->GetOverlayContents();
-  content::WebContents* ntp_contents = instant()->ntp_->contents();
-  EXPECT_FALSE(overlay->GetSiteInstance()->IsRelatedSiteInstance(
-      ntp_contents->GetSiteInstance()));
-
-  // Type a query and hit enter to get a results page.  The overlay becomes the
-  // active tab.
-  ASSERT_TRUE(SetOmniboxTextAndWaitForOverlayToShow("hello"));
-  EXPECT_EQ("hello", GetOmniboxText());
-  browser()->window()->GetLocationBar()->AcceptInput();
-  content::WebContents* first_active_tab =
-      browser()->tab_strip_model()->GetActiveWebContents();
-  EXPECT_EQ(first_active_tab, overlay);
-  scoped_refptr<content::SiteInstance> first_site_instance =
-      first_active_tab->GetSiteInstance();
-  EXPECT_FALSE(first_site_instance->IsRelatedSiteInstance(
-      ntp_contents->GetSiteInstance()));
-
-  // Navigating elsewhere gets us off of the commited page.  The next
-  // query will give us a new |overlay| which we will then commit.
-  ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUIAboutURL));
-
-  // Show and commit the new overlay.
-  ASSERT_TRUE(SetOmniboxTextAndWaitForOverlayToShow("hello again"));
-  EXPECT_EQ("hello again", GetOmniboxText());
-  browser()->window()->GetLocationBar()->AcceptInput();
-  content::WebContents* second_active_tab =
-      browser()->tab_strip_model()->GetActiveWebContents();
-  EXPECT_NE(first_active_tab, second_active_tab);
-  scoped_refptr<content::SiteInstance> second_site_instance =
-      second_active_tab->GetSiteInstance();
-  EXPECT_NE(first_site_instance, second_site_instance);
-  EXPECT_FALSE(
-      first_site_instance->IsRelatedSiteInstance(second_site_instance.get()));
-}
-
-// Tests that suggestions are sanity checked.
-IN_PROC_BROWSER_TEST_F(InstantExtendedTest, ValidatesSuggestions) {
-  ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
-  FocusOmniboxAndWaitForInstantOverlayAndNTPSupport();
-
-  // Do not set gray text that is not a suffix of the query.
-  EXPECT_TRUE(ExecuteScript("suggestion = 'potato';"
-                            "behavior = 2;"));
-  ASSERT_TRUE(SetOmniboxTextAndWaitForOverlayToShow("query"));
-  EXPECT_EQ(ASCIIToUTF16("query"), omnibox()->GetText());
-  EXPECT_EQ(ASCIIToUTF16(""), GetGrayText());
-
-  omnibox()->RevertAll();
-
-  // Do not set blue text that is not a valid URL completion.
-  EXPECT_TRUE(ExecuteScript("suggestion = 'this is not a url!';"
-                            "behavior = 1;"));
-  ASSERT_TRUE(SetOmniboxTextAndWaitForOverlayToShow("this is"));
-  EXPECT_EQ(ASCIIToUTF16("this is"), omnibox()->GetText());
-  EXPECT_EQ(ASCIIToUTF16(""), GetGrayText());
-
-  omnibox()->RevertAll();
-
-  // Do not set gray text when blue text is already set.
-  // First set up some blue text completion.
-  EXPECT_TRUE(ExecuteScript("suggestion = 'www.example.com';"
-                            "behavior = 1;"));
-  ASSERT_TRUE(SetOmniboxTextAndWaitForOverlayToShow("http://www.ex"));
-  EXPECT_EQ(ASCIIToUTF16("http://www.example.com"), omnibox()->GetText());
-  EXPECT_EQ(ASCIIToUTF16("ample.com"), GetBlueText());
-
-  // Now try to set gray text for the same query.
-  EXPECT_TRUE(ExecuteScript("suggestion = 'www.example.com rocks';"
-                            "behavior = 2;"));
-  SetOmniboxText("http://www.ex");
-  EXPECT_EQ(ASCIIToUTF16("http://www.example.com"), omnibox()->GetText());
-  EXPECT_EQ(ASCIIToUTF16(""), GetGrayText());
-
-  omnibox()->RevertAll();
-
-  // Ignore an out-of-date blue text suggestion. (Simulates a laggy
-  // SetSuggestion IPC by directly calling into InstantController.)
-  ASSERT_TRUE(SetOmniboxTextAndWaitForOverlayToShow("http://www.example.com/"));
-  instant()->SetSuggestions(
-      instant()->overlay()->contents(),
-      std::vector<InstantSuggestion>(
-          1,
-          InstantSuggestion(ASCIIToUTF16("www.exa"),
-                            INSTANT_COMPLETE_NOW,
-                            INSTANT_SUGGESTION_URL,
-                            ASCIIToUTF16("www.exa"),
-                            kNoMatchIndex)));
-  EXPECT_EQ(
-      "http://www.example.com/",
-      omnibox()->model()->result().default_match()->destination_url.spec());
-
-  omnibox()->RevertAll();
-
-  // TODO(samarth): uncomment after fixing crbug.com/191656.
-  // Use an out-of-date blue text suggestion, if the text typed by the user is
-  // contained in the suggestion.
-  // ASSERT_TRUE(SetOmniboxTextAndWaitForOverlayToShow("ex"));
-  // instant()->SetSuggestions(
-  //     instant()->overlay()->contents(),
-  //     std::vector<InstantSuggestion>(
-  //         1,
-  //         InstantSuggestion(ASCIIToUTF16("www.example.com"),
-  //                           INSTANT_COMPLETE_NOW,
-  //                           INSTANT_SUGGESTION_URL,
-  //                           ASCIIToUTF16("e"))));
-  // EXPECT_EQ(
-  //     "http://www.example.com/",
-  //     omnibox()->model()->result().default_match()->destination_url.spec());
-
-  // omnibox()->RevertAll();
-
-  // When asked to suggest blue text in verbatim mode, suggest the exact
-  // omnibox text rather than using the supplied suggestion text.
-  EXPECT_TRUE(ExecuteScript("suggestion = 'www.example.com/q';"
-                            "behavior = 1;"));
-  SetOmniboxText("www.example.com/q");
-  omnibox()->OnBeforePossibleChange();
-  SetOmniboxText("www.example.com/");
-  omnibox()->OnAfterPossibleChange();
-  EXPECT_EQ(ASCIIToUTF16("www.example.com/"), omnibox()->GetText());
-}
-
-// Tests that a previous navigation suggestion is not discarded if it's not
-// stale.
-IN_PROC_BROWSER_TEST_F(InstantExtendedTest,
-                       NavigationSuggestionIsNotDiscarded) {
-  ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
-  FocusOmniboxAndWaitForInstantOverlayAndNTPSupport();
-
-  // Tell the page to send a URL suggestion.
-  EXPECT_TRUE(ExecuteScript("suggestion = 'http://www.example.com';"
-                            "behavior = 1;"));
-  ASSERT_TRUE(SetOmniboxTextAndWaitForOverlayToShow("exa"));
-  EXPECT_EQ(ASCIIToUTF16("example.com"), omnibox()->GetText());
-  SetOmniboxText("exam");
-  EXPECT_EQ(ASCIIToUTF16("example.com"), omnibox()->GetText());
-
-  // TODO(jered): Remove this after fixing OnBlur().
-  omnibox()->RevertAll();
-}
-
-IN_PROC_BROWSER_TEST_F(InstantExtendedTest, MostVisited) {
+IN_PROC_BROWSER_TEST_F(InstantExtendedTest, DISABLED_MostVisited) {
   content::WindowedNotificationObserver observer(
       chrome::NOTIFICATION_INSTANT_SENT_MOST_VISITED_ITEMS,
       content::NotificationService::AllSources());
   // Initialize Instant.
   ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
-  FocusOmniboxAndWaitForInstantOverlayAndNTPSupport();
+  FocusOmniboxAndWaitForInstantNTPSupport();
 
   // Get a handle to the NTP and the current state of the JS.
   ASSERT_NE(static_cast<InstantNTP*>(NULL), instant()->ntp());
-  content::WebContents* overlay = instant()->ntp_->contents();
-  EXPECT_TRUE(overlay);
-  EXPECT_TRUE(UpdateSearchState(overlay));
+  content::WebContents* ntp = instant()->ntp_->contents();
+  EXPECT_TRUE(ntp);
+  EXPECT_TRUE(UpdateSearchState(ntp));
 
   // Wait for most visited data to be ready, if necessary.
   if (on_most_visited_change_calls_ == 0) {
     observer.Wait();
-    EXPECT_TRUE(UpdateSearchState(overlay));
+    EXPECT_TRUE(UpdateSearchState(ntp));
   }
 
   EXPECT_EQ(1, on_most_visited_change_calls_);
@@ -1308,11 +642,11 @@
   int rid = first_most_visited_item_id_;
   std::ostringstream stream;
   stream << "newTabPageHandle.deleteMostVisitedItem(" << rid << ");";
-  EXPECT_TRUE(ExecuteScript(stream.str()));
+  EXPECT_TRUE(content::ExecuteScript(ntp, stream.str()));
   observer.Wait();
 
   // Update Most Visited state.
-  EXPECT_TRUE(UpdateSearchState(overlay));
+  EXPECT_TRUE(UpdateSearchState(ntp));
 
   // Make sure we have one less item in there.
   EXPECT_EQ(most_visited_items_count_, old_most_visited_items_count - 1);
@@ -1320,11 +654,11 @@
   // Undo the deletion of the fist Most Visited Item.
   stream.str(std::string());
   stream << "newTabPageHandle.undoMostVisitedDeletion(" << rid << ");";
-  EXPECT_TRUE(ExecuteScript(stream.str()));
+  EXPECT_TRUE(content::ExecuteScript(ntp, stream.str()));
   observer.Wait();
 
   // Update Most Visited state.
-  EXPECT_TRUE(UpdateSearchState(overlay));
+  EXPECT_TRUE(UpdateSearchState(ntp));
 
   // Make sure we have the same number of items as before.
   EXPECT_EQ(most_visited_items_count_, old_most_visited_items_count);
@@ -1333,21 +667,21 @@
   rid = first_most_visited_item_id_;
   stream.str(std::string());
   stream << "newTabPageHandle.deleteMostVisitedItem(" << rid << ");";
-  EXPECT_TRUE(ExecuteScript(stream.str()));
+  EXPECT_TRUE(content::ExecuteScript(ntp, stream.str()));
   observer.Wait();
 
   // Update Most Visited state.
-  EXPECT_TRUE(UpdateSearchState(overlay));
+  EXPECT_TRUE(UpdateSearchState(ntp));
 
   // Delete the second Most Visited Item.
   rid = first_most_visited_item_id_;
   stream.str(std::string());
   stream << "newTabPageHandle.deleteMostVisitedItem(" << rid << ");";
-  EXPECT_TRUE(ExecuteScript(stream.str()));
+  EXPECT_TRUE(content::ExecuteScript(ntp, stream.str()));
   observer.Wait();
 
   // Update Most Visited state.
-  EXPECT_TRUE(UpdateSearchState(overlay));
+  EXPECT_TRUE(UpdateSearchState(ntp));
 
   // Make sure we have two less items in there.
   EXPECT_EQ(most_visited_items_count_, old_most_visited_items_count - 2);
@@ -1355,43 +689,16 @@
   // Delete the second Most Visited Item.
   stream.str(std::string());
   stream << "newTabPageHandle.undoAllMostVisitedDeletions();";
-  EXPECT_TRUE(ExecuteScript(stream.str()));
+  EXPECT_TRUE(content::ExecuteScript(ntp, stream.str()));
   observer.Wait();
 
   // Update Most Visited state.
-  EXPECT_TRUE(UpdateSearchState(overlay));
+  EXPECT_TRUE(UpdateSearchState(ntp));
 
   // Make sure we have the same number of items as before.
   EXPECT_EQ(most_visited_items_count_, old_most_visited_items_count);
 }
 
-IN_PROC_BROWSER_TEST_F(InstantPolicyTest, ThemeBackgroundAccess) {
-  InstallThemeSource();
-  ASSERT_NO_FATAL_FAILURE(InstallThemeAndVerify("theme", "camo theme"));
-  ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
-  FocusOmniboxAndWaitForInstantOverlayAndNTPSupport();
-
-  // The "Instant" New Tab should have access to chrome-search: scheme but not
-  // chrome: scheme.
-  ui_test_utils::NavigateToURLWithDisposition(
-      browser(),
-      GURL(chrome::kChromeUINewTabURL),
-      NEW_FOREGROUND_TAB,
-      ui_test_utils::BROWSER_TEST_NONE);
-
-  content::RenderViewHost* rvh =
-      browser()->tab_strip_model()->GetActiveWebContents()->GetRenderViewHost();
-
-  const std::string chrome_url("chrome://theme/IDR_THEME_NTP_BACKGROUND");
-  const std::string search_url(
-      "chrome-search://theme/IDR_THEME_NTP_BACKGROUND");
-  bool loaded = false;
-  ASSERT_TRUE(LoadImage(rvh, chrome_url, &loaded));
-  EXPECT_FALSE(loaded) << chrome_url;
-  ASSERT_TRUE(LoadImage(rvh, search_url, &loaded));
-  EXPECT_TRUE(loaded) << search_url;
-}
-
 // TODO(dhollowa): Fix flakes.  http://crbug.com/179930.
 IN_PROC_BROWSER_TEST_F(InstantExtendedTest, DISABLED_FaviconAccess) {
   // Create a favicon.
@@ -1402,7 +709,7 @@
   EXPECT_TRUE(top_sites->SetPageThumbnail(url, thumbnail, high_score));
 
   ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
-  FocusOmniboxAndWaitForInstantOverlayAndNTPSupport();
+  FocusOmniboxAndWaitForInstantNTPSupport();
 
   // The "Instant" New Tab should have access to chrome-search: scheme but not
   // chrome: scheme.
@@ -1427,10 +734,46 @@
   EXPECT_TRUE(loaded) << search_favicon_url;
 }
 
+// Only implemented in Views and Mac currently: http://crbug.com/164723
+#if defined(OS_WIN) || defined(OS_CHROMEOS) || defined(OS_MACOSX)
+#define MAYBE_HomeButtonAffectsMargin HomeButtonAffectsMargin
+#else
+#define MAYBE_HomeButtonAffectsMargin DISABLED_HomeButtonAffectsMargin
+#endif
+
+// Check that toggling the state of the home button changes the start-edge
+// margin and width.
+IN_PROC_BROWSER_TEST_F(InstantExtendedTest, MAYBE_HomeButtonAffectsMargin) {
+  ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
+  FocusOmniboxAndWaitForInstantNTPSupport();
+
+  // Get the current value of the start-edge margin and width.
+  int start_margin;
+  int width;
+  content::WebContents* ntp = instant()->ntp_->contents();
+  EXPECT_TRUE(GetIntFromJS(ntp, "chrome.searchBox.startMargin", &start_margin));
+  EXPECT_TRUE(GetIntFromJS(ntp, "chrome.searchBox.width", &width));
+
+  // Toggle the home button visibility pref.
+  PrefService* profile_prefs = browser()->profile()->GetPrefs();
+  bool show_home = profile_prefs->GetBoolean(prefs::kShowHomeButton);
+  profile_prefs->SetBoolean(prefs::kShowHomeButton, !show_home);
+
+  // Make sure the margin and width changed.
+  int new_start_margin;
+  int new_width;
+  EXPECT_TRUE(GetIntFromJS(ntp, "chrome.searchBox.startMargin",
+      &new_start_margin));
+  EXPECT_TRUE(GetIntFromJS(ntp, "chrome.searchBox.width", &new_width));
+  EXPECT_NE(start_margin, new_start_margin);
+  EXPECT_NE(width, new_width);
+  EXPECT_EQ(new_width - width, start_margin - new_start_margin);
+}
+
 // WebUIBindings should never be enabled on ANY Instant web contents.
 IN_PROC_BROWSER_TEST_F(InstantExtendedTest, NoWebUIBindingsOnNTP) {
   ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
-  FocusOmniboxAndWaitForInstantOverlayAndNTPSupport();
+  FocusOmniboxAndWaitForInstantNTPSupport();
 
   ui_test_utils::NavigateToURLWithDisposition(
       browser(),
@@ -1445,369 +788,22 @@
 }
 
 // WebUIBindings should never be enabled on ANY Instant web contents.
-IN_PROC_BROWSER_TEST_F(InstantExtendedTest, NoWebUIBindingsOnPreview) {
-  ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
-  FocusOmniboxAndWaitForInstantOverlayAndNTPSupport();
-
-  // Typing in the omnibox shows the overlay.
-  ASSERT_TRUE(SetOmniboxTextAndWaitForOverlayToShow("query"));
-  EXPECT_TRUE(instant()->model()->mode().is_search_suggestions());
-  content::WebContents* preview = instant()->GetOverlayContents();
-  ASSERT_NE(static_cast<content::WebContents*>(NULL), preview);
-
-  // Instant preview should not have any bindings enabled.
-  EXPECT_EQ(0, preview->GetRenderViewHost()->GetEnabledBindings());
-}
-
-// WebUIBindings should never be enabled on ANY Instant web contents.
 IN_PROC_BROWSER_TEST_F(InstantExtendedTest, NoWebUIBindingsOnResults) {
   ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
-  FocusOmniboxAndWaitForInstantOverlayAndNTPSupport();
+  FocusOmniboxAndWaitForInstantNTPSupport();
 
-  // Typing in the omnibox shows the overlay.
-  ASSERT_TRUE(SetOmniboxTextAndWaitForOverlayToShow("query"));
-  content::WebContents* preview = instant()->GetOverlayContents();
-  EXPECT_TRUE(instant()->model()->mode().is_search_suggestions());
+  // Type a query and press enter to get results.
+  SetOmniboxText("query");
   // Commit the search by pressing Enter.
   browser()->window()->GetLocationBar()->AcceptInput();
   EXPECT_TRUE(instant()->model()->mode().is_default());
   const content::WebContents* tab =
       browser()->tab_strip_model()->GetActiveWebContents();
-  EXPECT_EQ(preview, tab);
 
   // The commited Instant page should not have any bindings enabled.
   EXPECT_EQ(0, tab->GetRenderViewHost()->GetEnabledBindings());
 }
 
-// Only implemented in Views and Mac currently: http://crbug.com/164723
-#if defined(OS_WIN) || defined(OS_CHROMEOS) || defined(OS_MACOSX)
-#define MAYBE_HomeButtonAffectsMargin HomeButtonAffectsMargin
-#else
-#define MAYBE_HomeButtonAffectsMargin DISABLED_HomeButtonAffectsMargin
-#endif
-// Check that toggling the state of the home button changes the start-edge
-// margin and width.
-IN_PROC_BROWSER_TEST_F(InstantExtendedTest, MAYBE_HomeButtonAffectsMargin) {
-  ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
-  FocusOmniboxAndWaitForInstantOverlaySupport();
-
-  // Get the current value of the start-edge margin and width.
-  int start_margin;
-  int width;
-  content::WebContents* overlay = instant()->GetOverlayContents();
-  EXPECT_TRUE(GetIntFromJS(overlay, "chrome.searchBox.startMargin",
-      &start_margin));
-  EXPECT_TRUE(GetIntFromJS(overlay, "chrome.searchBox.width", &width));
-
-  // Toggle the home button visibility pref.
-  PrefService* profile_prefs = browser()->profile()->GetPrefs();
-  bool show_home = profile_prefs->GetBoolean(prefs::kShowHomeButton);
-  profile_prefs->SetBoolean(prefs::kShowHomeButton, !show_home);
-
-  // Make sure the margin and width changed.
-  int new_start_margin;
-  int new_width;
-  EXPECT_TRUE(GetIntFromJS(overlay, "chrome.searchBox.startMargin",
-      &new_start_margin));
-  EXPECT_TRUE(GetIntFromJS(overlay, "chrome.searchBox.width", &new_width));
-  EXPECT_NE(start_margin, new_start_margin);
-  EXPECT_NE(width, new_width);
-  EXPECT_EQ(new_width - width, start_margin - new_start_margin);
-}
-
-// Commit does not happen on Mac: http://crbug.com/178520
-#if defined(OS_MACOSX)
-#define MAYBE_CommitWhenFocusLostInFullHeight \
-        DISABLED_CommitWhenFocusLostInFullHeight
-#else
-#define MAYBE_CommitWhenFocusLostInFullHeight CommitWhenFocusLostInFullHeight
-#endif
-// Test that the overlay is committed when the omnibox loses focus when it is
-// shown at 100% height.
-IN_PROC_BROWSER_TEST_F(InstantExtendedTest,
-                       MAYBE_CommitWhenFocusLostInFullHeight) {
-  ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
-
-  // Focus omnibox and confirm overlay isn't shown.
-  FocusOmniboxAndWaitForInstantOverlayAndNTPSupport();
-  content::WebContents* overlay = instant()->GetOverlayContents();
-  EXPECT_TRUE(overlay);
-  EXPECT_TRUE(instant()->model()->mode().is_default());
-  EXPECT_FALSE(instant()->IsOverlayingSearchResults());
-
-  // Typing in the omnibox should show the overlay.
-  ASSERT_TRUE(SetOmniboxTextAndWaitForOverlayToShow("query"));
-  EXPECT_TRUE(instant()->IsOverlayingSearchResults());
-  EXPECT_EQ(overlay, instant()->GetOverlayContents());
-
-  // Explicitly unfocus the omnibox without triggering a click. Note that this
-  // doesn't actually change the focus state of the omnibox, only what the
-  // Instant controller sees it as.
-  omnibox()->model()->OnWillKillFocus(NULL);
-  omnibox()->model()->OnKillFocus();
-
-  // Confirm that the overlay has been committed.
-  content::WebContents* active_tab =
-      browser()->tab_strip_model()->GetActiveWebContents();
-  EXPECT_EQ(overlay, active_tab);
-}
-
-#if defined(OS_MACOSX)
-// http://crbug.com/227076
-#define MAYBE_CommitWhenShownInFullHeightWithoutFocus \
-        DISABLED_CommitWhenShownInFullHeightWithoutFocus
-#else
-#define MAYBE_CommitWhenShownInFullHeightWithoutFocus \
-        CommitWhenShownInFullHeightWithoutFocus
-#endif
-
-// Test that the overlay is committed when shown at 100% height without focus
-// in the omnibox.
-IN_PROC_BROWSER_TEST_F(InstantExtendedTest,
-                       MAYBE_CommitWhenShownInFullHeightWithoutFocus) {
-  ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
-
-  // Focus omnibox and confirm overlay isn't shown.
-  FocusOmniboxAndWaitForInstantOverlayAndNTPSupport();
-  content::WebContents* overlay = instant()->GetOverlayContents();
-  EXPECT_TRUE(overlay);
-  EXPECT_TRUE(instant()->model()->mode().is_default());
-  EXPECT_FALSE(instant()->IsOverlayingSearchResults());
-
-  // Create an observer to wait for the commit.
-  content::WindowedNotificationObserver commit_observer(
-      chrome::NOTIFICATION_INSTANT_COMMITTED,
-      content::NotificationService::AllSources());
-
-  // Create an observer to wait for the autocomplete.
-  content::WindowedNotificationObserver autocomplete_observer(
-      chrome::NOTIFICATION_INSTANT_SENT_AUTOCOMPLETE_RESULTS,
-      content::NotificationService::AllSources());
-
-  // Typing in the omnibox should show the overlay. Don't wait for the overlay
-  // to show however.
-  SetOmniboxText("query");
-
-  autocomplete_observer.Wait();
-
-  // Explicitly unfocus the omnibox without triggering a click. Note that this
-  // doesn't actually change the focus state of the omnibox, only what the
-  // Instant controller sees it as.
-  omnibox()->model()->OnWillKillFocus(NULL);
-  omnibox()->model()->OnKillFocus();
-
-  // Wait for the overlay to show.
-  commit_observer.Wait();
-
-  // Confirm that the overlay has been committed.
-  content::WebContents* active_tab =
-      browser()->tab_strip_model()->GetActiveWebContents();
-  EXPECT_EQ(overlay, active_tab);
-}
-
-// Test that a transient entry is set properly when the overlay is committed
-// without a navigation.
-IN_PROC_BROWSER_TEST_F(InstantExtendedTest, TransientEntrySet) {
-  ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
-
-  // Focus omnibox and confirm overlay isn't shown.
-  FocusOmniboxAndWaitForInstantOverlaySupport();
-  content::WebContents* overlay = instant()->GetOverlayContents();
-  EXPECT_TRUE(overlay);
-  EXPECT_TRUE(instant()->model()->mode().is_default());
-  EXPECT_FALSE(instant()->IsOverlayingSearchResults());
-
-  // Commit the overlay without triggering a navigation.
-  content::WindowedNotificationObserver observer(
-      chrome::NOTIFICATION_INSTANT_COMMITTED,
-      content::NotificationService::AllSources());
-  ASSERT_TRUE(SetOmniboxTextAndWaitForOverlayToShow("query"));
-  browser()->window()->GetLocationBar()->AcceptInput();
-  observer.Wait();
-
-  // Confirm that the overlay has been committed.
-  content::WebContents* active_tab =
-      browser()->tab_strip_model()->GetActiveWebContents();
-  EXPECT_EQ(overlay, active_tab);
-
-  // The page hasn't navigated so there should be a transient entry with the
-  // same URL but different page ID as the last committed entry.
-  const content::NavigationEntry* transient_entry =
-      active_tab->GetController().GetTransientEntry();
-  const content::NavigationEntry* committed_entry =
-      active_tab->GetController().GetLastCommittedEntry();
-  EXPECT_EQ(transient_entry->GetURL(), committed_entry->GetURL());
-  EXPECT_NE(transient_entry->GetPageID(), committed_entry->GetPageID());
-}
-
-// Test that the a transient entry is cleared when the overlay is committed
-// with a navigation.
-// TODO(samarth) : this test fails, http://crbug.com/181070.
-IN_PROC_BROWSER_TEST_F(InstantExtendedTest, DISABLED_TransientEntryRemoved) {
-  ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
-
-  // Focus omnibox and confirm overlay isn't shown.
-  FocusOmniboxAndWaitForInstantOverlaySupport();
-  content::WebContents* overlay = instant()->GetOverlayContents();
-  EXPECT_TRUE(overlay);
-  EXPECT_TRUE(instant()->model()->mode().is_default());
-  EXPECT_FALSE(instant()->IsOverlayingSearchResults());
-
-  // Create an observer to wait for the commit.
-  content::WindowedNotificationObserver observer(
-      chrome::NOTIFICATION_INSTANT_COMMITTED,
-      content::NotificationService::AllSources());
-
-  // Trigger a navigation on commit.
-  EXPECT_TRUE(ExecuteScript(
-      "getApiHandle().oncancel = function() {"
-      "  location.replace(location.href + '#q=query');"
-      "};"
-      ));
-
-  // Commit the overlay.
-  ASSERT_TRUE(SetOmniboxTextAndWaitForOverlayToShow("query"));
-  browser()->window()->GetLocationBar()->AcceptInput();
-  observer.Wait();
-
-  // Confirm that the overlay has been committed.
-  content::WebContents* active_tab =
-      browser()->tab_strip_model()->GetActiveWebContents();
-  EXPECT_EQ(overlay, active_tab);
-
-  // The page has navigated so there should be no transient entry.
-  const content::NavigationEntry* transient_entry =
-      active_tab->GetController().GetTransientEntry();
-  EXPECT_EQ(NULL, transient_entry);
-
-  // The last committed entry should be the URL the page navigated to.
-  const content::NavigationEntry* committed_entry =
-      active_tab->GetController().GetLastCommittedEntry();
-  EXPECT_TRUE(EndsWith(committed_entry->GetURL().spec(), "#q=query", true));
-}
-
-IN_PROC_BROWSER_TEST_F(InstantExtendedTest, RestrictedURLReading) {
-  std::string search_query;
-  bool is_undefined;
-  ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
-  FocusOmniboxAndWaitForInstantOverlaySupport();
-
-  // Verify we can read out something ok.
-  const char kOKQuery[] = "santa";
-  SetOmniboxText(kOKQuery);
-  EXPECT_EQ(ASCIIToUTF16(kOKQuery), omnibox()->GetText());
-  // Must always assert the value is defined before trying to read it, as trying
-  // to read undefined values causes the test to hang.
-  EXPECT_TRUE(GetBoolFromJS(instant()->GetOverlayContents(),
-                            "apiHandle.value === undefined",
-                            &is_undefined));
-  ASSERT_FALSE(is_undefined);
-  EXPECT_TRUE(GetStringFromJS(instant()->GetOverlayContents(),
-                              "apiHandle.value",
-                              &search_query));
-  EXPECT_EQ(kOKQuery, search_query);
-
-  // Verify we can't read out something that should be restricted, like a https
-  // url with a path.
-  const char kHTTPSUrlWithPath[] = "https://www.example.com/foobar";
-  SetOmniboxText(kHTTPSUrlWithPath);
-  EXPECT_EQ(ASCIIToUTF16(kHTTPSUrlWithPath), omnibox()->GetText());
-  EXPECT_TRUE(GetBoolFromJS(instant()->GetOverlayContents(),
-                            "apiHandle.value === undefined",
-                            &is_undefined));
-  EXPECT_TRUE(is_undefined);
-}
-
-IN_PROC_BROWSER_TEST_F(InstantExtendedTest, RestrictedItemReadback) {
-  // Initialize Instant.
-  ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
-  FocusOmniboxAndWaitForInstantOverlaySupport();
-
-  // Get a handle to the NTP and the current state of the JS.
-  ASSERT_NE(static_cast<InstantNTP*>(NULL), instant()->ntp());
-  content::WebContents* preview_tab = instant()->ntp()->contents();
-  EXPECT_TRUE(preview_tab);
-
-  // Manufacture a few autocomplete results and get them down to the page.
-  std::vector<InstantAutocompleteResult> autocomplete_results;
-  for (int i = 0; i < 3; ++i) {
-    std::string description(base::StringPrintf("Test Description %d", i));
-    std::string url(base::StringPrintf("http://www.testurl%d.com", i));
-
-    InstantAutocompleteResult res;
-    res.provider = ASCIIToUTF16(AutocompleteProvider::TypeToString(
-        AutocompleteProvider::TYPE_BUILTIN));
-    res.type = AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
-    res.description = ASCIIToUTF16(description);
-    res.destination_url = ASCIIToUTF16(url);
-    res.transition = content::PAGE_TRANSITION_TYPED;
-    res.relevance = 42 + i;
-
-    autocomplete_results.push_back(res);
-  }
-  instant()->overlay()->SendAutocompleteResults(autocomplete_results);
-
-  // Apparently, one needs to access nativeSuggestions before
-  // apiHandle.setRestrictedValue can work.
-  EXPECT_TRUE(ExecuteScript("var foo = apiHandle.nativeSuggestions;"));
-
-  const char kQueryString[] = "Hippos go berzerk!";
-
-  // First set the query text to a non restricted value and ensure it can be
-  // read back.
-  std::ostringstream stream;
-  stream << "apiHandle.setValue('" << kQueryString << "');";
-  EXPECT_TRUE(ExecuteScript(stream.str()));
-
-  std::string query_string;
-  bool is_undefined;
-  EXPECT_TRUE(GetStringFromJS(instant()->GetOverlayContents(),
-                              "apiHandle.value",
-                              &query_string));
-  EXPECT_EQ(kQueryString, query_string);
-
-  // Set the query text to the first restricted autocomplete item.
-  int rid = 1;
-  stream.str(std::string());
-  stream << "apiHandle.setRestrictedValue(" << rid << ");";
-  EXPECT_TRUE(ExecuteScript(stream.str()));
-
-  // Expect that we now receive undefined when reading the value back.
-  EXPECT_TRUE(GetBoolFromJS(
-      instant()->GetOverlayContents(),
-      "apiHandle.value === undefined",
-      &is_undefined));
-  EXPECT_TRUE(is_undefined);
-
-  // Now set the query text to a non restricted value and ensure that the
-  // visibility has been reset and the string can again be read back.
-  stream.str(std::string());
-  stream << "apiHandle.setValue('" << kQueryString << "');";
-  EXPECT_TRUE(ExecuteScript(stream.str()));
-
-  EXPECT_TRUE(GetStringFromJS(instant()->GetOverlayContents(),
-                              "apiHandle.value",
-                              &query_string));
-  EXPECT_EQ(kQueryString, query_string);
-}
-
-// Test that autocomplete results are sent to the page only when all the
-// providers are done.
-IN_PROC_BROWSER_TEST_F(InstantExtendedTest, AutocompleteProvidersDone) {
-  ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
-  FocusOmniboxAndWaitForInstantOverlayAndNTPSupport();
-
-  content::WebContents* overlay = instant()->GetOverlayContents();
-  EXPECT_TRUE(UpdateSearchState(overlay));
-  EXPECT_EQ(0, on_native_suggestions_calls_);
-
-  ASSERT_TRUE(SetOmniboxTextAndWaitForOverlayToShow("railroad"));
-
-  EXPECT_EQ(overlay, instant()->GetOverlayContents());
-  EXPECT_TRUE(UpdateSearchState(overlay));
-  EXPECT_EQ(1, on_native_suggestions_calls_);
-}
-
 // Test that the Bookmark provider is enabled, and returns results.
 // TODO(sreeram): Convert this to a unit test.
 IN_PROC_BROWSER_TEST_F(InstantExtendedTest, DISABLED_HasBookmarkProvider) {
@@ -1834,119 +830,10 @@
   EXPECT_TRUE(found_bookmark_match);
 }
 
-// Test that the omnibox's temporary text is reset when the popup is closed.
-IN_PROC_BROWSER_TEST_F(InstantExtendedTest, TemporaryTextResetWhenPopupClosed) {
-  ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
-  FocusOmniboxAndWaitForInstantOverlayAndNTPSupport();
-  EXPECT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
-
-  // Show the overlay and arrow-down to a suggestion (this sets temporary text).
-  ASSERT_TRUE(SetOmniboxTextAndWaitForOverlayToShow("juju"));
-  SendDownArrow();
-
-  EXPECT_TRUE(HasTemporaryText());
-  EXPECT_EQ("result 1", GetOmniboxText());
-
-  // Click outside the omnibox (but not on the overlay), to make the omnibox
-  // lose focus. Close the popup explicitly, to workaround test/toolkit issues.
-  ui_test_utils::ClickOnView(browser(), VIEW_ID_TOOLBAR);
-  omnibox()->CloseOmniboxPopup();
-
-  // The temporary text should've been accepted as the user text.
-  EXPECT_FALSE(HasTemporaryText());
-  EXPECT_EQ("result 1", GetOmniboxText());
-
-  // Now refocus the omnibox and hit Escape. This shouldn't crash.
-  FocusOmnibox();
-  SendEscape();
-
-  // The omnibox should've reverted to the underlying permanent URL.
-  EXPECT_FALSE(HasTemporaryText());
-  EXPECT_EQ(std::string(content::kAboutBlankURL), GetOmniboxText());
-}
-
-// Test that autocomplete results aren't sent when the popup is closed.
-IN_PROC_BROWSER_TEST_F(InstantExtendedTest,
-                       NoAutocompleteResultsWhenPopupClosed) {
-  ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
-  FocusOmniboxAndWaitForInstantOverlayAndNTPSupport();
-  EXPECT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
-
-  // Show the overlay and arrow-down to a suggestion (this sets temporary text).
-  ASSERT_TRUE(SetOmniboxTextAndWaitForOverlayToShow("thangam"));
-  SendDownArrow();
-  EXPECT_TRUE(HasTemporaryText());
-
-  EXPECT_TRUE(ExecuteScript("onChangeCalls = onNativeSuggestionsCalls = 0;"));
-
-  content::WebContents* overlay = instant()->GetOverlayContents();
-  EXPECT_TRUE(UpdateSearchState(overlay));
-  EXPECT_EQ(0, on_change_calls_);
-  EXPECT_EQ(0, on_native_suggestions_calls_);
-
-  // Click outside the omnibox (but not on the overlay), to make the omnibox
-  // lose focus. Close the popup explicitly, to workaround test/toolkit issues.
-  ui_test_utils::ClickOnView(browser(), VIEW_ID_TOOLBAR);
-  omnibox()->CloseOmniboxPopup();
-  EXPECT_FALSE(HasTemporaryText());
-
-  EXPECT_EQ(overlay, instant()->GetOverlayContents());
-  EXPECT_TRUE(UpdateSearchState(overlay));
-  EXPECT_EQ(0, on_change_calls_);
-  EXPECT_EQ(0, on_native_suggestions_calls_);
-}
-
-// Test that suggestions are not accepted when unexpected.
-IN_PROC_BROWSER_TEST_F(InstantExtendedTest, DeniesUnexpectedSuggestions) {
-  ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
-  FocusOmniboxAndWaitForInstantOverlayAndNTPSupport();
-  ASSERT_TRUE(SetOmniboxTextAndWaitForOverlayToShow("chip"));
-  SendDownArrow();
-
-  EXPECT_EQ("result 1", GetOmniboxText());
-  EXPECT_EQ(ASCIIToUTF16(""), GetGrayText());
-
-  // Make the page send an unexpected suggestion.
-  EXPECT_TRUE(ExecuteScript("suggestion = 'chippies';"
-                            "handleOnChange();"));
-
-  // Verify that the suggestion is ignored.
-  EXPECT_EQ("result 1", GetOmniboxText());
-  EXPECT_EQ(ASCIIToUTF16(""), GetGrayText());
-}
-
-// Test that autocomplete results are cleared when the query is cleared.
-IN_PROC_BROWSER_TEST_F(InstantExtendedTest, EmptyAutocompleteResults) {
-  ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
-  FocusOmniboxAndWaitForInstantOverlayAndNTPSupport();
-
-  // Type a URL, so that there's at least one autocomplete result (a "URL what
-  // you typed" match).
-  ASSERT_TRUE(SetOmniboxTextAndWaitForOverlayToShow("http://upsamina/"));
-
-  content::WebContents* overlay = instant()->GetOverlayContents();
-
-  int num_autocomplete_results = 0;
-  EXPECT_TRUE(GetIntFromJS(
-      overlay,
-      "chrome.embeddedSearch.searchBox.nativeSuggestions.length",
-      &num_autocomplete_results));
-  EXPECT_LT(0, num_autocomplete_results);
-
-  // Erase the query in the omnibox.
-  SetOmniboxText("");
-
-  EXPECT_TRUE(GetIntFromJS(
-      overlay,
-      "chrome.embeddedSearch.searchBox.nativeSuggestions.length",
-      &num_autocomplete_results));
-  EXPECT_EQ(0, num_autocomplete_results);
-}
-
 // Test that hitting Esc to clear the omnibox works. http://crbug.com/231744.
-IN_PROC_BROWSER_TEST_F(InstantExtendedTest, EscapeClearsOmnibox) {
+IN_PROC_BROWSER_TEST_F(InstantExtendedTest, DISABLED_EscapeClearsOmnibox) {
   ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
-  FocusOmniboxAndWaitForInstantOverlayAndNTPSupport();
+  FocusOmniboxAndWaitForInstantNTPSupport();
 
   // Navigate to the Instant NTP, and wait for it to be recognized.
   content::WindowedNotificationObserver instant_tab_observer(
@@ -1985,63 +872,6 @@
   EXPECT_LT(0, on_esc_key_press_event_calls_);
 }
 
-IN_PROC_BROWSER_TEST_F(InstantExtendedTest, FocusApiRespondsToFocusChange) {
-  ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
-  ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
-  EXPECT_FALSE(is_focused_);
-  EXPECT_EQ(0, on_focus_changed_calls_);
-
-  // Focus the omnibox.
-  FocusOmniboxAndWaitForInstantOverlaySupport();
-  ASSERT_TRUE(UpdateSearchState(instant()->GetOverlayContents()));
-  EXPECT_TRUE(is_focused_);
-  EXPECT_EQ(1, on_focus_changed_calls_);
-
-  // Now unfocus the omnibox.
-  ui_test_utils::ClickOnView(browser(), VIEW_ID_TAB_CONTAINER);
-  ASSERT_TRUE(UpdateSearchState(instant()->GetOverlayContents()));
-  EXPECT_FALSE(is_focused_);
-  EXPECT_EQ(2, on_focus_changed_calls_);
-
-  // Focus the omnibox again.
-  // The first focus may have worked only due to initial-state anomalies.
-  FocusOmnibox();
-  ASSERT_TRUE(UpdateSearchState(instant()->GetOverlayContents()));
-  EXPECT_TRUE(is_focused_);
-  EXPECT_EQ(3, on_focus_changed_calls_);
-}
-
-IN_PROC_BROWSER_TEST_F(InstantExtendedTest, FocusApiIgnoresRedundantFocus) {
-  ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
-  ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
-  EXPECT_FALSE(is_focused_);
-  EXPECT_EQ(0, on_focus_changed_calls_);
-
-  // Focus the Omnibox.
-  FocusOmniboxAndWaitForInstantOverlaySupport();
-  ASSERT_TRUE(UpdateSearchState(instant()->GetOverlayContents()));
-  EXPECT_TRUE(is_focused_);
-  EXPECT_EQ(1, on_focus_changed_calls_);
-
-  // When we focus the omnibox again, nothing should change.
-  FocusOmnibox();
-  ASSERT_TRUE(UpdateSearchState(instant()->GetOverlayContents()));
-  EXPECT_TRUE(is_focused_);
-  EXPECT_EQ(1, on_focus_changed_calls_);
-
-  // Now unfocus the omnibox.
-  ui_test_utils::ClickOnView(browser(), VIEW_ID_TAB_CONTAINER);
-  ASSERT_TRUE(UpdateSearchState(instant()->GetOverlayContents()));
-  EXPECT_FALSE(is_focused_);
-  EXPECT_EQ(2, on_focus_changed_calls_);
-
-  // When we unfocus again, nothing should change.
-  ui_test_utils::ClickOnView(browser(), VIEW_ID_TAB_CONTAINER);
-  ASSERT_TRUE(UpdateSearchState(instant()->GetOverlayContents()));
-  EXPECT_FALSE(is_focused_);
-  EXPECT_EQ(2, on_focus_changed_calls_);
-}
-
 IN_PROC_BROWSER_TEST_F(InstantExtendedTest, OnDefaultSearchProviderChanged) {
   InstantService* instant_service =
       InstantServiceFactory::GetForProfile(browser()->profile());
@@ -2049,7 +879,7 @@
 
   // Setup Instant.
   ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
-  FocusOmniboxAndWaitForInstantOverlayAndNTPSupport();
+  FocusOmniboxAndWaitForInstantNTPSupport();
   EXPECT_EQ(1, instant_service->GetInstantProcessCount());
 
   // Navigating to the NTP should use the Instant render process.
@@ -2102,109 +932,19 @@
   EXPECT_EQ(ntp_url, ntp_contents->GetURL());
 }
 
-IN_PROC_BROWSER_TEST_F(InstantExtendedTest, OverlayRenderViewGone) {
-  ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
-  FocusOmniboxAndWaitForInstantOverlayAndNTPSupport();
-  EXPECT_NE(static_cast<content::WebContents*>(NULL),
-            instant()->GetOverlayContents());
-
-  // Overlay is not reloaded after being killed.
-  EXPECT_FALSE(instant()->overlay()->IsLocal());
-  instant()->InstantPageRenderViewGone(instant()->GetOverlayContents());
-  EXPECT_EQ(NULL, instant()->GetOverlayContents());
-
-  // The local overlay is used on the next Update().
-  SetOmniboxText("query");
-  EXPECT_TRUE(instant()->overlay()->IsLocal());
-
-  // Switched back to the remote overlay when omnibox loses and regains focus.
-  instant()->HideOverlay();
-  browser()->tab_strip_model()->GetActiveWebContents()->GetView()->Focus();
-  FocusOmnibox();
-  EXPECT_FALSE(instant()->overlay()->IsLocal());
-}
-
-IN_PROC_BROWSER_TEST_F(InstantExtendedTest, OverlayDoesntSupportInstant) {
-  GURL instant_url = test_server()->GetURL("files/empty.html?strk=1");
-  InstantTestBase::Init(instant_url);
-  ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
-
-  // Focus the omnibox. When the support determination response comes back,
-  // Instant will destroy the non-Instant page and fall back to the local page.
-  FocusOmniboxAndWaitForInstantOverlayAndNTPSupport();
-  ASSERT_NE(static_cast<InstantOverlay*>(NULL), instant()->overlay());
-  EXPECT_TRUE(instant()->overlay()->IsLocal());
-
-  // The local overlay is used on the next Update().
-  SetOmniboxText("query");
-  EXPECT_TRUE(instant()->overlay()->IsLocal());
-
-  // Switched back to the remote overlay when omnibox loses and regains focus.
-  instant()->HideOverlay();
-  browser()->tab_strip_model()->GetActiveWebContents()->GetView()->Focus();
-  FocusOmnibox();
-  EXPECT_FALSE(instant()->overlay()->IsLocal());
-
-  // Overlay falls back to local again after determining support.
-  FocusOmniboxAndWaitForInstantOverlaySupport();
-  ASSERT_NE(static_cast<InstantOverlay*>(NULL), instant()->overlay());
-  EXPECT_TRUE(instant()->overlay()->IsLocal());
-}
-
-// Test that if Instant alters the input from URL to search, it's respected.
-IN_PROC_BROWSER_TEST_F(InstantExtendedTest, InputChangedFromURLToSearch) {
-  ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
-  FocusOmniboxAndWaitForInstantOverlayAndNTPSupport();
-
-  content::WebContents* overlay = instant()->GetOverlayContents();
-  EXPECT_TRUE(ExecuteScript("suggestions = ['mcqueen.com'];"));
-
-  SetOmniboxTextAndWaitForOverlayToShow("lightning");
-  EXPECT_EQ("lightning", GetOmniboxText());
-
-  SendDownArrow();
-  EXPECT_EQ("mcqueen.com", GetOmniboxText());
-
-  // Press Enter.
-  browser()->window()->GetLocationBar()->AcceptInput();
-
-  // Confirm that the Instant overlay was committed.
-  EXPECT_EQ(overlay, browser()->tab_strip_model()->GetActiveWebContents());
-}
-
-// Test that if Instant alters the input from search to URL, it's respected.
-IN_PROC_BROWSER_TEST_F(InstantExtendedTest, InputChangedFromSearchToURL) {
-  ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
-  FocusOmniboxAndWaitForInstantOverlayAndNTPSupport();
-
-  content::WebContents* overlay = instant()->GetOverlayContents();
-  EXPECT_TRUE(ExecuteScript("suggestionType = 1;"));  // INSTANT_SUGGESTION_URL
-
-  SetOmniboxTextAndWaitForOverlayToShow("mack.com");
-  EXPECT_EQ("mack.com", GetOmniboxText());
-
-  SendDownArrow();
-  EXPECT_EQ("result 1", GetOmniboxText());
-
-  // Press Enter.
-  browser()->window()->GetLocationBar()->AcceptInput();
-
-  // Confirm that the Instant overlay was NOT committed.
-  EXPECT_NE(overlay, browser()->tab_strip_model()->GetActiveWebContents());
-}
-
 // Test that renderer initiated navigations to an instant URL from a non
 // Instant page do not end up in an Instant process if they are bounced to the
 // browser.
-IN_PROC_BROWSER_TEST_F(InstantExtendedTest,
-                       RendererInitiatedNavigationNotInInstantProcess) {
+IN_PROC_BROWSER_TEST_F(
+    InstantExtendedTest,
+    DISABLED_RendererInitiatedNavigationNotInInstantProcess) {
   InstantService* instant_service =
       InstantServiceFactory::GetForProfile(browser()->profile());
   ASSERT_NE(static_cast<InstantService*>(NULL), instant_service);
 
   // Setup Instant.
   ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
-  FocusOmniboxAndWaitForInstantOverlayAndNTPSupport();
+  FocusOmniboxAndWaitForInstantNTPSupport();
 
   EXPECT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
   EXPECT_EQ(1, browser()->tab_strip_model()->count());
@@ -2269,7 +1009,7 @@
 
   // Setup Instant.
   ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
-  FocusOmniboxAndWaitForInstantOverlayAndNTPSupport();
+  FocusOmniboxAndWaitForInstantNTPSupport();
 
   EXPECT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
   EXPECT_EQ(1, browser()->tab_strip_model()->count());
@@ -2307,159 +1047,11 @@
   EXPECT_EQ(GURL(instant_url_with_query), contents->GetURL());
 }
 
-IN_PROC_BROWSER_TEST_F(InstantExtendedTest, SearchProviderDoesntRun) {
-  ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
-  FocusOmniboxAndWaitForInstantOverlaySupport();
-
-  // Add "query" to history.
-  ASSERT_TRUE(AddSearchToHistory(ASCIIToUTF16("query"), 10000));
-  BlockUntilHistoryProcessesPendingRequests();
-
-  SetOmniboxText("quer");
-
-  // Should get only SWYT from SearchProvider.
-  EXPECT_EQ(1, CountSearchProviderSuggestions());
-}
-
-IN_PROC_BROWSER_TEST_F(InstantExtendedTest, SearchProviderRunsForLocalOnly) {
-  // Force local-only Instant.
-  ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
-  instant()->SetInstantEnabled(true, true);
-  FocusOmniboxAndWaitForInstantOverlaySupport();
-
-  // Add "query" to history.
-  ASSERT_TRUE(AddSearchToHistory(ASCIIToUTF16("query"), 10000));
-  BlockUntilHistoryProcessesPendingRequests();
-
-  SetOmniboxText("quer");
-
-  // Should get 2 suggestions from SearchProvider:
-  //   - SWYT for "quer"
-  //   - Search history suggestion for "query"
-  EXPECT_EQ(2, CountSearchProviderSuggestions());
-}
-
-IN_PROC_BROWSER_TEST_F(InstantExtendedTest, SearchProviderRunsForFallback) {
-  // Use an Instant URL that won't support Instant.
-  GURL instant_url = test_server()->GetURL("files/empty.html?strk=1");
-  InstantTestBase::Init(instant_url);
-  ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
-  FocusOmniboxAndWaitForInstantOverlaySupport();
-  // Should fallback to the local overlay.
-  ASSERT_NE(static_cast<InstantOverlay*>(NULL), instant()->overlay());
-  EXPECT_TRUE(instant()->overlay()->IsLocal());
-
-  // Add "query" to history and wait for Instant support.
-  ASSERT_TRUE(AddSearchToHistory(ASCIIToUTF16("query"), 10000));
-  BlockUntilHistoryProcessesPendingRequests();
-
-  SetOmniboxText("quer");
-
-  // Should get 2 suggestions from SearchProvider:
-  //   - SWYT for "quer"
-  //   - Search history suggestion for "query"
-  EXPECT_EQ(2, CountSearchProviderSuggestions());
-}
-
-IN_PROC_BROWSER_TEST_F(InstantExtendedTest, SearchProviderForLocalNTP) {
-  // Force local-only Instant.
-  ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
-  FocusOmniboxAndWaitForInstantOverlayAndNTPSupport();
-  instant()->SetInstantEnabled(true, true);
-
-  // Add "google" to history.
-  ASSERT_TRUE(AddSearchToHistory(ASCIIToUTF16("google"), 10000));
-  BlockUntilHistoryProcessesPendingRequests();
-
-  // Create an observer to wait for the autocomplete.
-  content::WindowedNotificationObserver autocomplete_observer(
-      chrome::NOTIFICATION_INSTANT_SENT_AUTOCOMPLETE_RESULTS,
-      content::NotificationService::AllSources());
-
-  SetOmniboxText("http://www.example.com");
-
-  autocomplete_observer.Wait();
-  ASSERT_TRUE(omnibox()->model()->autocomplete_controller()->
-              search_provider()->IsNonInstantSearchDone());
-}
-
-IN_PROC_BROWSER_TEST_F(InstantExtendedTest, OverlaySendsSearchWhatYouTyped) {
-  ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
-  FocusOmniboxAndWaitForInstantOverlayAndNTPSupport();
-
-  // This input could be interpreted either as an URL or a query based on the
-  // relative ranking of search-what-you-typed or url-what-you-typed.
-  content::WindowedNotificationObserver autocomplete_observer(
-      chrome::NOTIFICATION_INSTANT_SENT_AUTOCOMPLETE_RESULTS,
-      content::NotificationService::AllSources());
-  SetOmniboxText("define:foo");
-  autocomplete_observer.Wait();
-
-  // In this case, we should treat [define:foo] as a query, so
-  // search-what-you-typed should be the top suggestion.
-  EXPECT_TRUE(ExecuteScript(
-      "var sorted = chrome.embeddedSearch.searchBox.nativeSuggestions.sort("
-          "function (a,b) {"
-            "return b.rankingData.relevance - a.rankingData.relevance;"
-          "});"));
-  std::string type;
-  EXPECT_TRUE(GetStringFromJS(instant()->GetOverlayContents(),
-                              "sorted[0].type", &type));
-  ASSERT_EQ("search-what-you-typed", type);
-}
-
-IN_PROC_BROWSER_TEST_F(InstantExtendedTest,
-                       OverlayDoesNotEchoSearchProviderNavsuggest) {
-  ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
-  FocusOmniboxAndWaitForInstantOverlayAndNTPSupport();
-
-  // Show the overlay so suggestions are allowed.
-  SetOmniboxTextAndWaitForOverlayToShow("www.");
-  content::WebContents* overlay = instant()->GetOverlayContents();
-
-  // Set a URL suggestion and wait for SearchProvider to echo it.
-  content::WindowedNotificationObserver autocomplete_observer(
-      chrome::NOTIFICATION_INSTANT_SENT_AUTOCOMPLETE_RESULTS,
-      content::NotificationService::AllSources());
-  instant()->SetSuggestions(
-      overlay,
-      std::vector<InstantSuggestion>(
-          1,
-          InstantSuggestion(ASCIIToUTF16("http://www.example.com/"),
-                            INSTANT_COMPLETE_NOW,
-                            INSTANT_SUGGESTION_URL,
-                            ASCIIToUTF16("www."),
-                            kNoMatchIndex)));
-  autocomplete_observer.Wait();
-
-  // Check that SearchProvider set a NAVSUGGEST match.
-  bool have_navsuggest_match = false;
-  SearchProvider* search_provider =
-      omnibox()->model()->autocomplete_controller()->search_provider();
-  for (ACMatches::const_iterator match = search_provider->matches().begin();
-       match != search_provider->matches().end(); ++match) {
-    if (match->type == AutocompleteMatchType::NAVSUGGEST) {
-      have_navsuggest_match = true;
-      break;
-    }
-  }
-  ASSERT_TRUE(have_navsuggest_match);
-
-  // Check that InstantController did not send the NAVSUGGEST match.
-  bool sent_navsuggest_match = true;
-  EXPECT_TRUE(GetBoolFromJS(overlay,
-      "chrome.embeddedSearch.searchBox.nativeSuggestions.some("
-          "function (s) {"
-            "return s.type == 'navsuggest';"
-          "})", &sent_navsuggest_match));
-  EXPECT_FALSE(sent_navsuggest_match);
-}
-
 IN_PROC_BROWSER_TEST_F(InstantExtendedTest, AcceptingURLSearchDoesNotNavigate) {
   // Get a committed Instant tab, which will be in the Instant process and thus
   // support chrome::GetSearchTerms().
   ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
-  FocusOmniboxAndWaitForInstantOverlaySupport();
+  FocusOmnibox();
 
   // Create an observer to wait for the instant tab to support Instant.
   content::WindowedNotificationObserver observer(
@@ -2467,7 +1059,7 @@
       content::NotificationService::AllSources());
 
   // Do a search and commit it.
-  ASSERT_TRUE(SetOmniboxTextAndWaitForOverlayToShow("foo"));
+  SetOmniboxText("foo");
   EXPECT_EQ(ASCIIToUTF16("foo"), omnibox()->GetText());
   browser()->window()->GetLocationBar()->AcceptInput();
   observer.Wait();
@@ -2491,11 +1083,13 @@
   EXPECT_EQ(instant_tab_url, instant_tab->GetURL());
 }
 
-IN_PROC_BROWSER_TEST_F(InstantExtendedTest, AcceptingJSSearchDoesNotRunJS) {
+// TODO(jered): Figure out why this test flakes and fix it.
+IN_PROC_BROWSER_TEST_F(InstantExtendedTest,
+                       DISABLED_AcceptingJSSearchDoesNotRunJS) {
   // Get a committed Instant tab, which will be in the Instant process and thus
   // support chrome::GetSearchTerms().
   ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
-  FocusOmniboxAndWaitForInstantOverlaySupport();
+  FocusOmnibox();
 
   // Create an observer to wait for the instant tab to support Instant.
   content::WindowedNotificationObserver observer(
@@ -2503,7 +1097,7 @@
       content::NotificationService::AllSources());
 
   // Do a search and commit it.
-  ASSERT_TRUE(SetOmniboxTextAndWaitForOverlayToShow("foo"));
+  SetOmniboxText("foo");
   EXPECT_EQ(ASCIIToUTF16("foo"), omnibox()->GetText());
   browser()->window()->GetLocationBar()->AcceptInput();
   observer.Wait();
@@ -2529,17 +1123,11 @@
   EXPECT_NE(ASCIIToUTF16("evil"), instant_tab->GetTitle());
 }
 
-// Flaky on mac: http://crbug.com/242164
-#if defined(OS_MACOSX)
-#define MAYBE_ReloadSearchAfterBackReloadsCorrectQuery DISABLED_ReloadSearchAfterBackReloadsCorrectQuery
-#else
-#define MAYBE_ReloadSearchAfterBackReloadsCorrectQuery ReloadSearchAfterBackReloadsCorrectQuery
-#endif
-
-IN_PROC_BROWSER_TEST_F(InstantExtendedTest,
-                       MAYBE_ReloadSearchAfterBackReloadsCorrectQuery) {
+IN_PROC_BROWSER_TEST_F(
+    InstantExtendedTest,
+    DISABLED_ReloadSearchAfterBackReloadsCorrectQuery) {
   ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
-  FocusOmniboxAndWaitForInstantOverlaySupport();
+  FocusOmnibox();
 
   // Create an observer to wait for the instant tab to support Instant.
   content::WindowedNotificationObserver observer(
@@ -2547,7 +1135,7 @@
       content::NotificationService::AllSources());
 
   // Search for [foo].
-  ASSERT_TRUE(SetOmniboxTextAndWaitForOverlayToShow("foo"));
+  SetOmniboxText("foo");
   EXPECT_EQ(ASCIIToUTF16("foo"), omnibox()->GetText());
   browser()->window()->GetLocationBar()->AcceptInput();
   observer.Wait();
@@ -2557,7 +1145,6 @@
   EXPECT_TRUE(content::ExecuteScript(instant_tab,
                                      "suggestion = 'bart';"));
   SetOmniboxTextAndWaitForSuggestion("bar");
-  EXPECT_EQ(ASCIIToUTF16("t"), GetGrayText());
 
   // Accept the new query and wait for the page to navigate.
   content::WindowedNotificationObserver nav_observer(
@@ -2604,12 +1191,12 @@
       NEW_WINDOW,
       ui_test_utils::BROWSER_TEST_WAIT_FOR_BROWSER);
 
-  const BrowserList* native_browser_list = BrowserList::GetInstance(
-      chrome::HOST_DESKTOP_TYPE_NATIVE);
-  ASSERT_EQ(2u, native_browser_list->size());
-  set_browser(native_browser_list->get(1));
+  const BrowserList* browser_list = BrowserList::GetInstance(
+      chrome::GetActiveDesktop());
+  ASSERT_EQ(2u, browser_list->size());
+  set_browser(browser_list->get(1));
 
-  FocusOmniboxAndWaitForInstantOverlayAndNTPSupport();
+  FocusOmniboxAndWaitForInstantNTPSupport();
 
   // Also make sure our instant_tab_ is loaded.
   if (!instant()->instant_tab_) {
@@ -2623,69 +1210,11 @@
   ASSERT_NE(static_cast<InstantNTP*>(NULL), instant()->ntp());
   EXPECT_TRUE(instant()->ntp()->IsLocal());
 
-  // Overlay contents should be preloaded.
-  ASSERT_NE(static_cast<InstantOverlay*>(NULL), instant()->overlay());
-  EXPECT_TRUE(instant()->overlay()->IsLocal());
-
   // Instant tab contents should be preloaded.
   ASSERT_NE(static_cast<InstantTab*>(NULL), instant()->instant_tab());
   EXPECT_TRUE(instant()->instant_tab()->IsLocal());
 }
 
-IN_PROC_BROWSER_TEST_F(InstantExtendedTest,
-                       PageVisibilityEventOnCommit) {
-  ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
-  FocusOmniboxAndWaitForInstantOverlayAndNTPSupport();
-
-  // Set the text, and wait for suggestions to show up.
-  ASSERT_TRUE(SetOmniboxTextAndWaitForOverlayToShow("search"));
-
-  content::WebContents* overlay = instant()->GetOverlayContents();
-
-  // Before commiting, verify visibility calls.
-  int on_visibility_calls = -1;
-  EXPECT_TRUE(GetIntFromJS(overlay, "onvisibilitycalls", &on_visibility_calls));
-  EXPECT_EQ(1, on_visibility_calls);
-
-  // Commit the search by pressing Enter.
-  browser()->window()->GetLocationBar()->AcceptInput();
-
-  // After commiting, verify visibility calls.
-  on_visibility_calls = -1;
-  EXPECT_TRUE(GetIntFromJS(overlay, "onvisibilitycalls", &on_visibility_calls));
-  EXPECT_EQ(1, on_visibility_calls);
-}
-
-// Test that if the LogDropdownShown() call records a histogram value.
-IN_PROC_BROWSER_TEST_F(InstantExtendedTest, LogDropdownShown) {
-  ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
-  FocusOmniboxAndWaitForInstantOverlayAndNTPSupport();
-  int64 histogramValue = GetHistogramCount("Instant.TimeToFirstShowFromWeb");
-  ASSERT_TRUE(SetOmniboxTextAndWaitForOverlayToShow("a"));
-  EXPECT_EQ(histogramValue + 1,
-            GetHistogramCount("Instant.TimeToFirstShowFromWeb"));
-}
-
-IN_PROC_BROWSER_TEST_F(InstantExtendedTest, TaskManagerPrefix) {
-  TaskManagerModel* task_manager = TaskManager::GetInstance()->model();
-  task_manager->StartUpdating();
-
-  // There should be three renderers, the second being the Instant overlay,
-  // and the third being the preloaded NTP.
-  TaskManagerBrowserTestUtil::WaitForWebResourceChange(3);
-
-  string16 prefix = l10n_util::GetStringFUTF16(
-      IDS_TASK_MANAGER_INSTANT_OVERLAY_PREFIX, string16());
-
-  int instant_overlays = 0;
-  for (int i = 0; i < task_manager->ResourceCount(); ++i) {
-    string16 title = task_manager->GetResourceTitle(i);
-    if (StartsWith(title, prefix, true))
-      ++instant_overlays;
-  }
-  EXPECT_EQ(2, instant_overlays);
-}
-
 // Broken on mac: http://crbug.com/247448
 #if defined(OS_MACOSX)
 #define MAYBE_KeyboardTogglesVoiceSearch DISABLED_KeyboardTogglesVoiceSearch
@@ -2694,23 +1223,19 @@
 #endif
 IN_PROC_BROWSER_TEST_F(InstantExtendedTest, MAYBE_KeyboardTogglesVoiceSearch) {
   ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
-  FocusOmniboxAndWaitForInstantOverlayAndNTPSupport();
-
-  // Test that toggle is not fired when no tab is open.
-  ASSERT_TRUE(ui_test_utils::SendKeyPressSync(browser(), ui::VKEY_OEM_PERIOD,
-                                              true, true, false, false));
-  EXPECT_TRUE(UpdateSearchState(instant()->GetOverlayContents()));
-  EXPECT_EQ(0, on_toggle_voice_search_calls_);
+  FocusOmniboxAndWaitForInstantNTPSupport();
 
   // Open new tab and test that toggle is fired.
   ui_test_utils::NavigateToURLWithDisposition(
       browser(),
       GURL(chrome::kChromeUINewTabURL),
-      NEW_FOREGROUND_TAB,
-      ui_test_utils::BROWSER_TEST_WAIT_FOR_TAB);
+      CURRENT_TAB,
+      ui_test_utils::BROWSER_TEST_NONE);
+  content::WebContents* active_tab =
+      browser()->tab_strip_model()->GetActiveWebContents();
   ASSERT_TRUE(ui_test_utils::SendKeyPressSync(browser(), ui::VKEY_OEM_PERIOD,
                                               true, true, false, false));
-  EXPECT_TRUE(UpdateSearchState(instant()->instant_tab()->contents()));
+  EXPECT_TRUE(UpdateSearchState(active_tab));
   EXPECT_EQ(1, on_toggle_voice_search_calls_);
 }
 
@@ -2719,17 +1244,9 @@
 IN_PROC_BROWSER_TEST_F(InstantExtendedTest, UpdateSearchQueryOnNavigation) {
   ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
 
-  // Focus omnibox and confirm overlay isn't shown.
-  FocusOmniboxAndWaitForInstantOverlayAndNTPSupport();
-  content::WebContents* overlay = instant()->GetOverlayContents();
-  EXPECT_TRUE(overlay);
-  EXPECT_TRUE(instant()->model()->mode().is_default());
-  EXPECT_FALSE(instant()->IsOverlayingSearchResults());
-
-  // Typing in the omnibox should show the overlay.
-  SetOmniboxTextAndWaitForOverlayToShow("flowers");
-  EXPECT_TRUE(instant()->IsOverlayingSearchResults());
-  EXPECT_EQ(overlay, instant()->GetOverlayContents());
+  // Focus omnibox.
+  FocusOmniboxAndWaitForInstantNTPSupport();
+  SetOmniboxText("flowers");
 
   // Commit the search by pressing 'Enter'.
   PressEnterAndWaitForNavigation();
@@ -2765,39 +1282,43 @@
 #if !defined(HTML_INSTANT_EXTENDED_POPUP)
 IN_PROC_BROWSER_TEST_F(InstantExtendedTest, SearchReusesInstantTab) {
   ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
-  FocusOmniboxAndWaitForInstantOverlayAndNTPSupport();
+  FocusOmniboxAndWaitForInstantNTPSupport();
 
-  // Create an observer to wait for the instant tab to support Instant.
+  // Open new tab. Preloaded NTP contents should have been used.
+  ui_test_utils::NavigateToURLWithDisposition(
+      browser(),
+      GURL(chrome::kChromeUINewTabURL),
+      NEW_FOREGROUND_TAB,
+      ui_test_utils::BROWSER_TEST_WAIT_FOR_TAB);
+
   content::WindowedNotificationObserver observer(
       chrome::NOTIFICATION_INSTANT_TAB_SUPPORT_DETERMINED,
       content::NotificationService::AllSources());
-
   SetOmniboxText("flowers");
-  browser()->window()->GetLocationBar()->AcceptInput();
+  PressEnterAndWaitForNavigation();
   observer.Wait();
 
   // Just did a regular search.
-  ASSERT_THAT(
-      browser()->tab_strip_model()->GetActiveWebContents()->GetURL().spec(),
-      HasSubstr("q=flowers"));
-  ASSERT_TRUE(UpdateSearchState(instant()->instant_tab()->contents()));
+  content::WebContents* active_tab =
+      browser()->tab_strip_model()->GetActiveWebContents();
+  ASSERT_THAT(active_tab->GetURL().spec(), HasSubstr("q=flowers"));
+  ASSERT_TRUE(UpdateSearchState(active_tab));
   ASSERT_EQ(0, submit_count_);
 
   SetOmniboxText("puppies");
-  browser()->window()->GetLocationBar()->AcceptInput();
+  PressEnterAndWaitForNavigation();
 
   // Should have reused the tab and sent an onsubmit message.
-  ASSERT_THAT(
-      browser()->tab_strip_model()->GetActiveWebContents()->GetURL().spec(),
-      HasSubstr("q=flowers"));
-  ASSERT_TRUE(UpdateSearchState(instant()->instant_tab()->contents()));
+  active_tab = browser()->tab_strip_model()->GetActiveWebContents();
+  ASSERT_THAT(active_tab->GetURL().spec(), HasSubstr("q=puppies"));
+  ASSERT_TRUE(UpdateSearchState(active_tab));
   EXPECT_EQ(1, submit_count_);
 }
 
 IN_PROC_BROWSER_TEST_F(InstantExtendedTest,
                        SearchDoesntReuseInstantTabWithoutSupport) {
   ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
-  FocusOmniboxAndWaitForInstantOverlayAndNTPSupport();
+  FocusOmniboxAndWaitForInstantNTPSupport();
 
   // Don't wait for the navigation to complete.
   SetOmniboxText("flowers");
@@ -2815,37 +1336,53 @@
 IN_PROC_BROWSER_TEST_F(InstantExtendedTest,
                        TypedSearchURLDoesntReuseInstantTab) {
   ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
-  FocusOmniboxAndWaitForInstantOverlayAndNTPSupport();
+  FocusOmniboxAndWaitForInstantNTPSupport();
+
+  // Open new tab. Preloaded NTP contents should have been used.
+  ui_test_utils::NavigateToURLWithDisposition(
+      browser(),
+      GURL(chrome::kChromeUINewTabURL),
+      NEW_FOREGROUND_TAB,
+      ui_test_utils::BROWSER_TEST_WAIT_FOR_TAB);
 
   // Create an observer to wait for the instant tab to support Instant.
-  content::WindowedNotificationObserver observer(
+  content::WindowedNotificationObserver observer_1(
       chrome::NOTIFICATION_INSTANT_TAB_SUPPORT_DETERMINED,
       content::NotificationService::AllSources());
-
   SetOmniboxText("flowers");
-  browser()->window()->GetLocationBar()->AcceptInput();
-  observer.Wait();
+  PressEnterAndWaitForNavigation();
+  observer_1.Wait();
 
   // Just did a regular search.
-  ASSERT_THAT(
-      browser()->tab_strip_model()->GetActiveWebContents()->GetURL().spec(),
-      HasSubstr("q=flowers"));
-  ASSERT_TRUE(UpdateSearchState(instant()->instant_tab()->contents()));
+  content::WebContents* active_tab =
+      browser()->tab_strip_model()->GetActiveWebContents();
+  ASSERT_THAT(active_tab->GetURL().spec(), HasSubstr("q=flowers"));
+  ASSERT_TRUE(UpdateSearchState(active_tab));
   ASSERT_EQ(0, submit_count_);
 
   // Typed in a search URL "by hand".
+  content::WindowedNotificationObserver observer_2(
+      chrome::NOTIFICATION_INSTANT_TAB_SUPPORT_DETERMINED,
+      content::NotificationService::AllSources());
   SetOmniboxText(instant_url().spec() + "#q=puppies");
-  browser()->window()->GetLocationBar()->AcceptInput();
+  PressEnterAndWaitForNavigation();
+  observer_2.Wait();
 
   // Should not have reused the tab.
-  ASSERT_THAT(
-      browser()->tab_strip_model()->GetActiveWebContents()->GetURL().spec(),
-      HasSubstr("q=puppies"));
+  active_tab = browser()->tab_strip_model()->GetActiveWebContents();
+  ASSERT_THAT(active_tab->GetURL().spec(), HasSubstr("q=puppies"));
 }
 
 IN_PROC_BROWSER_TEST_F(InstantExtendedTest, OmniboxMarginSetForSearchURLs) {
   ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
-  FocusOmniboxAndWaitForInstantOverlayAndNTPSupport();
+  FocusOmniboxAndWaitForInstantNTPSupport();
+
+  // Open new tab. Preloaded NTP contents should have been used.
+  ui_test_utils::NavigateToURLWithDisposition(
+      browser(),
+      GURL(chrome::kChromeUINewTabURL),
+      NEW_FOREGROUND_TAB,
+      ui_test_utils::BROWSER_TEST_WAIT_FOR_TAB);
 
   // Create an observer to wait for the instant tab to support Instant.
   content::WindowedNotificationObserver observer(
@@ -2870,7 +1407,7 @@
 IN_PROC_BROWSER_TEST_F(InstantExtendedTest, NoMostVisitedChangedOnTabSwitch) {
   // Initialize Instant.
   ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
-  FocusOmniboxAndWaitForInstantOverlayAndNTPSupport();
+  FocusOmniboxAndWaitForInstantNTPSupport();
 
   // Open new tab. Preloaded NTP contents should have been used.
   ui_test_utils::NavigateToURLWithDisposition(
@@ -2884,7 +1421,7 @@
   content::WebContents* active_tab =
       browser()->tab_strip_model()->GetActiveWebContents();
   EXPECT_TRUE(UpdateSearchState(active_tab));
-  EXPECT_EQ(2, on_most_visited_change_calls_);
+  EXPECT_EQ(1, on_most_visited_change_calls_);
 
   // Activate the previous tab.
   browser()->tab_strip_model()->ActivateTabAt(0, false);
@@ -2895,5 +1432,346 @@
   // Confirm that new tab got no onmostvisitedchanged event.
   active_tab = browser()->tab_strip_model()->GetActiveWebContents();
   EXPECT_TRUE(UpdateSearchState(active_tab));
-  EXPECT_EQ(2, on_most_visited_change_calls_);
+  EXPECT_EQ(1, on_most_visited_change_calls_);
+}
+
+IN_PROC_BROWSER_TEST_F(InstantPolicyTest, ThemeBackgroundAccess) {
+  InstallThemeSource();
+  ASSERT_NO_FATAL_FAILURE(InstallThemeAndVerify("theme", "camo theme"));
+  ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
+  FocusOmniboxAndWaitForInstantNTPSupport();
+
+  // The "Instant" New Tab should have access to chrome-search: scheme but not
+  // chrome: scheme.
+  ui_test_utils::NavigateToURLWithDisposition(
+      browser(),
+      GURL(chrome::kChromeUINewTabURL),
+      NEW_FOREGROUND_TAB,
+      ui_test_utils::BROWSER_TEST_NONE);
+
+  content::RenderViewHost* rvh =
+      browser()->tab_strip_model()->GetActiveWebContents()->GetRenderViewHost();
+
+  const std::string chrome_url("chrome://theme/IDR_THEME_NTP_BACKGROUND");
+  const std::string search_url(
+      "chrome-search://theme/IDR_THEME_NTP_BACKGROUND");
+  bool loaded = false;
+  ASSERT_TRUE(LoadImage(rvh, chrome_url, &loaded));
+  EXPECT_FALSE(loaded) << chrome_url;
+  ASSERT_TRUE(LoadImage(rvh, search_url, &loaded));
+  EXPECT_TRUE(loaded) << search_url;
+}
+
+IN_PROC_BROWSER_TEST_F(InstantPolicyTest,
+                       NoThemeBackgroundChangeEventOnTabSwitch) {
+  InstallThemeSource();
+  ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
+  FocusOmniboxAndWaitForInstantNTPSupport();
+
+  // Install a theme.
+  ASSERT_NO_FATAL_FAILURE(InstallThemeAndVerify("theme", "camo theme"));
+  EXPECT_EQ(1, browser()->tab_strip_model()->count());
+
+  // Open new tab. Preloaded NTP contents should have been used.
+  ui_test_utils::NavigateToURLWithDisposition(
+      browser(),
+      GURL(chrome::kChromeUINewTabURL),
+      NEW_FOREGROUND_TAB,
+      ui_test_utils::BROWSER_TEST_NONE);
+  EXPECT_EQ(2, browser()->tab_strip_model()->count());
+
+  content::WebContents* active_tab =
+      browser()->tab_strip_model()->GetActiveWebContents();
+  ASSERT_EQ(1, browser()->tab_strip_model()->active_index());
+  int on_theme_changed_calls = 0;
+  EXPECT_TRUE(GetIntFromJS(active_tab, "onThemeChangedCalls",
+                           &on_theme_changed_calls));
+  EXPECT_EQ(1, on_theme_changed_calls);
+
+  // Activate the previous tab.
+  browser()->tab_strip_model()->ActivateTabAt(0, false);
+  ASSERT_EQ(0, browser()->tab_strip_model()->active_index());
+
+  // Switch back to new tab.
+  browser()->tab_strip_model()->ActivateTabAt(1, false);
+  ASSERT_EQ(1, browser()->tab_strip_model()->active_index());
+
+  // Confirm that new tab got no onthemechanged event while switching tabs.
+  active_tab = browser()->tab_strip_model()->GetActiveWebContents();
+  on_theme_changed_calls = 0;
+  EXPECT_TRUE(GetIntFromJS(active_tab, "onThemeChangedCalls",
+                           &on_theme_changed_calls));
+  EXPECT_EQ(1, on_theme_changed_calls);
+}
+
+IN_PROC_BROWSER_TEST_F(InstantPolicyTest,
+                       SendThemeBackgroundChangedEvent) {
+  InstallThemeSource();
+  ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
+  FocusOmniboxAndWaitForInstantNTPSupport();
+
+  // Install a theme.
+  ASSERT_NO_FATAL_FAILURE(InstallThemeAndVerify("theme", "camo theme"));
+
+  // Open new tab. Preloaded NTP contents should have been used.
+  ui_test_utils::NavigateToURLWithDisposition(
+      browser(),
+      GURL(chrome::kChromeUINewTabURL),
+      NEW_FOREGROUND_TAB,
+      ui_test_utils::BROWSER_TEST_NONE);
+  EXPECT_EQ(2, browser()->tab_strip_model()->count());
+
+  // Make sure new tab received an onthemechanged event.
+  content::WebContents* active_tab =
+      browser()->tab_strip_model()->GetActiveWebContents();
+  ASSERT_EQ(1, browser()->tab_strip_model()->active_index());
+  int on_theme_changed_calls = 0;
+  EXPECT_TRUE(GetIntFromJS(active_tab, "onThemeChangedCalls",
+                           &on_theme_changed_calls));
+  EXPECT_EQ(1, on_theme_changed_calls);
+
+  // Install a new theme.
+  ASSERT_NO_FATAL_FAILURE(InstallThemeAndVerify("theme2", "snowflake theme"));
+
+  // Confirm that new tab is notified about the theme changed event.
+  on_theme_changed_calls = 0;
+  EXPECT_TRUE(GetIntFromJS(active_tab, "onThemeChangedCalls",
+                           &on_theme_changed_calls));
+  EXPECT_EQ(2, on_theme_changed_calls);
+}
+
+// Flaky on Mac and Linux Tests bots.
+#if defined(OS_MACOSX) || defined(OS_LINUX)
+#define MAYBE_UpdateSearchQueryOnBackNavigation DISABLED_UpdateSearchQueryOnBackNavigation
+#else
+#define MAYBE_UpdateSearchQueryOnBackNavigation UpdateSearchQueryOnBackNavigation
+#endif
+// Test to verify that the omnibox search query is updated on browser
+// back button press event.
+IN_PROC_BROWSER_TEST_F(InstantExtendedTest,
+                       MAYBE_UpdateSearchQueryOnBackNavigation) {
+  ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
+
+  // Focus omnibox and confirm overlay isn't shown.
+  FocusOmniboxAndWaitForInstantNTPSupport();
+
+  // Open new tab. Preloaded NTP contents should have been used.
+  ui_test_utils::NavigateToURLWithDisposition(
+      browser(),
+      GURL(chrome::kChromeUINewTabURL),
+      NEW_FOREGROUND_TAB,
+      ui_test_utils::BROWSER_TEST_WAIT_FOR_TAB);
+
+  // Create an observer to wait for the instant tab to support Instant.
+  content::WindowedNotificationObserver observer(
+      chrome::NOTIFICATION_INSTANT_TAB_SUPPORT_DETERMINED,
+      content::NotificationService::AllSources());
+
+  SetOmniboxText("flowers");
+  // Commit the search by pressing 'Enter'.
+  PressEnterAndWaitForNavigation();
+  observer.Wait();
+
+  EXPECT_EQ(ASCIIToUTF16("flowers"), omnibox()->GetText());
+
+  // Typing in the new search query in omnibox.
+  SetOmniboxText("cattles");
+  // Commit the search by pressing 'Enter'.
+  PressEnterAndWaitForNavigation();
+  // 'Enter' commits the query as it was typed. This creates a navigation entry
+  // in the history.
+  EXPECT_EQ(ASCIIToUTF16("cattles"), omnibox()->GetText());
+
+  content::WebContents* active_tab =
+      browser()->tab_strip_model()->GetActiveWebContents();
+  EXPECT_TRUE(active_tab->GetController().CanGoBack());
+  content::WindowedNotificationObserver load_stop_observer(
+      content::NOTIFICATION_LOAD_STOP,
+      content::Source<content::NavigationController>(
+          &active_tab->GetController()));
+  active_tab->GetController().GoBack();
+  load_stop_observer.Wait();
+
+  EXPECT_EQ(ASCIIToUTF16("flowers"), omnibox()->GetText());
+  // Commit the search by pressing 'Enter'.
+  FocusOmnibox();
+  PressEnterAndWaitForNavigation();
+  EXPECT_EQ(ASCIIToUTF16("flowers"), omnibox()->GetText());
+}
+
+// Flaky on Mac and Linux Tests bots.
+#if defined(OS_MACOSX) || defined(OS_LINUX)
+#define MAYBE_UpdateSearchQueryOnForwardNavigation DISABLED_UpdateSearchQueryOnForwardNavigation
+#else
+#define MAYBE_UpdateSearchQueryOnForwardNavigation UpdateSearchQueryOnForwardNavigation
+#endif
+// Test to verify that the omnibox search query is updated on browser
+// forward button press events.
+IN_PROC_BROWSER_TEST_F(InstantExtendedTest,
+                       MAYBE_UpdateSearchQueryOnForwardNavigation) {
+  ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
+
+  // Focus omnibox and confirm overlay isn't shown.
+  FocusOmniboxAndWaitForInstantNTPSupport();
+
+  // Open new tab. Preloaded NTP contents should have been used.
+  ui_test_utils::NavigateToURLWithDisposition(
+      browser(),
+      GURL(chrome::kChromeUINewTabURL),
+      NEW_FOREGROUND_TAB,
+      ui_test_utils::BROWSER_TEST_WAIT_FOR_TAB);
+
+  // Create an observer to wait for the instant tab to support Instant.
+  content::WindowedNotificationObserver observer(
+      chrome::NOTIFICATION_INSTANT_TAB_SUPPORT_DETERMINED,
+      content::NotificationService::AllSources());
+
+  SetOmniboxText("flowers");
+  // Commit the search by pressing 'Enter'.
+  PressEnterAndWaitForNavigation();
+  observer.Wait();
+
+  EXPECT_EQ(ASCIIToUTF16("flowers"), omnibox()->GetText());
+
+  // Typing in the new search query in omnibox.
+  SetOmniboxText("cattles");
+  // Commit the search by pressing 'Enter'.
+  PressEnterAndWaitForNavigation();
+  // 'Enter' commits the query as it was typed. This creates a navigation entry
+  // in the history.
+  EXPECT_EQ(ASCIIToUTF16("cattles"), omnibox()->GetText());
+
+  content::WebContents* active_tab =
+      browser()->tab_strip_model()->GetActiveWebContents();
+  EXPECT_TRUE(active_tab->GetController().CanGoBack());
+  content::WindowedNotificationObserver load_stop_observer(
+      content::NOTIFICATION_LOAD_STOP,
+      content::Source<content::NavigationController>(
+          &active_tab->GetController()));
+  active_tab->GetController().GoBack();
+  load_stop_observer.Wait();
+
+  EXPECT_EQ(ASCIIToUTF16("flowers"), omnibox()->GetText());
+
+  active_tab = browser()->tab_strip_model()->GetActiveWebContents();
+  EXPECT_TRUE(active_tab->GetController().CanGoForward());
+  content::WindowedNotificationObserver load_stop_observer_2(
+      content::NOTIFICATION_LOAD_STOP,
+      content::Source<content::NavigationController>(
+          &active_tab->GetController()));
+  active_tab->GetController().GoForward();
+  load_stop_observer_2.Wait();
+
+  // Commit the search by pressing 'Enter'.
+  FocusOmnibox();
+  EXPECT_EQ(ASCIIToUTF16("cattles"), omnibox()->GetText());
+  PressEnterAndWaitForNavigation();
+  EXPECT_EQ(ASCIIToUTF16("cattles"), omnibox()->GetText());
+}
+
+// Flaky on all bots since re-enabled in r208032, crbug.com/253092
+IN_PROC_BROWSER_TEST_F(InstantExtendedTest, DISABLED_NavigateBackToNTP) {
+  ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
+  FocusOmniboxAndWaitForInstantNTPSupport();
+
+  // Open a new tab page.
+  ui_test_utils::NavigateToURLWithDisposition(
+      browser(),
+      GURL(chrome::kChromeUINewTabURL),
+      NEW_FOREGROUND_TAB,
+      ui_test_utils::BROWSER_TEST_WAIT_FOR_TAB);
+  EXPECT_EQ(2, browser()->tab_strip_model()->count());
+
+  content::WindowedNotificationObserver observer(
+      chrome::NOTIFICATION_INSTANT_TAB_SUPPORT_DETERMINED,
+      content::NotificationService::AllSources());
+  SetOmniboxText("flowers");
+  PressEnterAndWaitForNavigation();
+  observer.Wait();
+
+  EXPECT_EQ(ASCIIToUTF16("flowers"), omnibox()->GetText());
+
+  // Typing in the new search query in omnibox.
+  // Commit the search by pressing 'Enter'.
+  SetOmniboxText("cattles");
+  PressEnterAndWaitForNavigation();
+
+  // 'Enter' commits the query as it was typed. This creates a navigation entry
+  // in the history.
+  EXPECT_EQ(ASCIIToUTF16("cattles"), omnibox()->GetText());
+
+  // Navigate back to "flowers" search result page.
+  content::WebContents* active_tab =
+      browser()->tab_strip_model()->GetActiveWebContents();
+  EXPECT_TRUE(active_tab->GetController().CanGoBack());
+  content::WindowedNotificationObserver load_stop_observer(
+      content::NOTIFICATION_LOAD_STOP,
+      content::Source<content::NavigationController>(
+          &active_tab->GetController()));
+  active_tab->GetController().GoBack();
+  load_stop_observer.Wait();
+
+  EXPECT_EQ(ASCIIToUTF16("flowers"), omnibox()->GetText());
+
+  // Navigate back to NTP.
+  active_tab = browser()->tab_strip_model()->GetActiveWebContents();
+  EXPECT_TRUE(active_tab->GetController().CanGoBack());
+  content::WindowedNotificationObserver load_stop_observer_2(
+      content::NOTIFICATION_LOAD_STOP,
+      content::Source<content::NavigationController>(
+          &active_tab->GetController()));
+  active_tab->GetController().GoBack();
+  load_stop_observer_2.Wait();
+
+  active_tab = browser()->tab_strip_model()->GetActiveWebContents();
+  EXPECT_TRUE(chrome::IsInstantNTP(active_tab));
+}
+
+// Flaky on Windows and Mac try bots.
+#if defined(OS_CHROMEOS)
+#define MAYBE_DispatchMVChangeEventWhileNavigatingBackToNTP DispatchMVChangeEventWhileNavigatingBackToNTP
+#else
+#define MAYBE_DispatchMVChangeEventWhileNavigatingBackToNTP DISABLED_DispatchMVChangeEventWhileNavigatingBackToNTP
+#endif
+IN_PROC_BROWSER_TEST_F(InstantExtendedTest,
+                       MAYBE_DispatchMVChangeEventWhileNavigatingBackToNTP) {
+  // Setup Instant.
+  ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
+  FocusOmniboxAndWaitForInstantNTPSupport();
+
+  // Open new tab. Preloaded NTP contents should have been used.
+  ui_test_utils::NavigateToURLWithDisposition(
+      browser(),
+      GURL(chrome::kChromeUINewTabURL),
+      NEW_FOREGROUND_TAB,
+      ui_test_utils::BROWSER_TEST_WAIT_FOR_TAB);
+
+  content::WebContents* active_tab =
+      browser()->tab_strip_model()->GetActiveWebContents();
+  EXPECT_TRUE(UpdateSearchState(active_tab));
+  EXPECT_EQ(1, on_most_visited_change_calls_);
+
+  content::WindowedNotificationObserver observer(
+      content::NOTIFICATION_LOAD_STOP,
+      content::NotificationService::AllSources());
+  // Set the text and press enter to navigate from NTP.
+  SetOmniboxText("Pen");
+  PressEnterAndWaitForNavigation();
+  EXPECT_EQ(ASCIIToUTF16("Pen"), omnibox()->GetText());
+  observer.Wait();
+
+  // Navigate back to NTP.
+  content::WindowedNotificationObserver back_observer(
+      content::NOTIFICATION_LOAD_STOP,
+      content::NotificationService::AllSources());
+  active_tab = browser()->tab_strip_model()->GetActiveWebContents();
+  EXPECT_TRUE(active_tab->GetController().CanGoBack());
+  active_tab->GetController().GoBack();
+  back_observer.Wait();
+
+  // Verify that onmostvisitedchange event is dispatched when we navigate from
+  // SRP to NTP.
+  active_tab = browser()->tab_strip_model()->GetActiveWebContents();
+  EXPECT_TRUE(UpdateSearchState(active_tab));
+  EXPECT_EQ(1, on_most_visited_change_calls_);
 }
diff --git a/chrome/browser/ui/search/instant_extended_manual_interactive_uitest.cc b/chrome/browser/ui/search/instant_extended_manual_interactive_uitest.cc
index ff81870..6ee7e94 100644
--- a/chrome/browser/ui/search/instant_extended_manual_interactive_uitest.cc
+++ b/chrome/browser/ui/search/instant_extended_manual_interactive_uitest.cc
@@ -11,10 +11,10 @@
 #include "chrome/browser/ui/host_desktop.h"
 #include "chrome/browser/ui/omnibox/omnibox_view.h"
 #include "chrome/browser/ui/search/instant_ntp.h"
-#include "chrome/browser/ui/search/instant_overlay.h"
 #include "chrome/browser/ui/search/instant_test_utils.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/common/chrome_notification_types.h"
+#include "chrome/common/omnibox_focus_state.h"
 #include "chrome/common/search_types.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/test/base/in_process_browser_test.h"
@@ -59,7 +59,7 @@
         testing::UnitTest::GetInstance()->current_test_info();
     ASSERT_TRUE(StartsWithASCII(test_info->name(), "MANUAL_", true) ||
                 StartsWithASCII(test_info->name(), "DISABLED_", true));
-    // Make IsOffline() return false so we don't try to use the local overlay.
+    // Make IsOffline() return false so we don't try to use the local NTP.
     disable_network_change_notifier_.reset(
         new net::NetworkChangeNotifier::DisableForTest());
   }
@@ -68,16 +68,6 @@
     disable_network_change_notifier_.reset();
   }
 
-  void ResetInstant() {
-    set_browser(browser());
-    instant()->SetInstantEnabled(false, true);
-    instant()->SetInstantEnabled(true, false);
-
-    FocusOmniboxAndWaitForInstantOverlayAndNTPSupport();
-    ASSERT_TRUE(IsGoogleOverlay());
-    ASSERT_TRUE(IsGoogleNTP());
-  }
-
  protected:
   virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
     chrome::EnableInstantExtendedAPIForTesting();
@@ -87,47 +77,6 @@
     return browser()->tab_strip_model()->GetActiveWebContents();
   }
 
-  bool PressBackspace() {
-    return ui_test_utils::SendKeyPressSync(browser(), ui::VKEY_BACK,
-                                           false, false, false, false);
-  }
-
-  bool PressBackspaceAndWaitForSuggestions() {
-    content::WindowedNotificationObserver observer(
-        chrome::NOTIFICATION_INSTANT_SET_SUGGESTION,
-        content::NotificationService::AllSources());
-    bool result = PressBackspace();
-    observer.Wait();
-    return result;
-  }
-
-  bool PressBackspaceAndWaitForOverlayToShow() {
-    InstantTestModelObserver observer(
-        instant()->model(), SearchMode::MODE_SEARCH_SUGGESTIONS);
-    return PressBackspace() && observer.WaitForExpectedOverlayState() ==
-        SearchMode::MODE_SEARCH_SUGGESTIONS;
-  }
-
-  bool PressEnterAndWaitForNavigationWithTitle(content::WebContents* contents,
-                                               const string16& title) {
-    content::TitleWatcher title_watcher(contents, title);
-    content::WindowedNotificationObserver nav_observer(
-        content::NOTIFICATION_NAV_ENTRY_COMMITTED,
-        content::NotificationService::AllSources());
-    browser()->window()->GetLocationBar()->AcceptInput();
-    nav_observer.Wait();
-    return title_watcher.WaitAndGetTitle() == title;
-  }
-
-  GURL GetActiveTabURL() {
-    return active_tab()->GetController().GetActiveEntry()->GetURL();
-  }
-
-  bool GetSelectionState(bool* selected) {
-    return GetBoolFromJS(instant()->GetOverlayContents(),
-                         "google.ac.gs().api.i()", selected);
-  }
-
   bool IsGooglePage(content::WebContents* contents) {
     bool is_google = false;
     if (!GetBoolFromJS(contents, "!!window.google", &is_google))
@@ -135,14 +84,6 @@
     return is_google;
   }
 
-  bool IsGoogleOverlay() {
-    return IsGooglePage(instant()->overlay()->contents());
-  }
-
-  bool IsGoogleNTP() {
-    return IsGooglePage(instant()->ntp()->contents());
-  }
-
  private:
   scoped_refptr<net::RuleBasedHostResolverProc> host_resolver_proc_;
   scoped_ptr<net::ScopedDefaultHostResolverProc> scoped_host_resolver_proc_;
@@ -150,31 +91,75 @@
       disable_network_change_notifier_;
 };
 
-IN_PROC_BROWSER_TEST_F(InstantExtendedManualTest,
-                       MANUAL_OmniboxFocusLoadsInstant) {
+IN_PROC_BROWSER_TEST_F(InstantExtendedManualTest, MANUAL_ShowsGoogleNTP) {
   set_browser(browser());
+  instant()->ReloadStaleNTP();
+  FocusOmniboxAndWaitForInstantNTPSupport();
 
-  // Explicitly unfocus the omnibox.
-  EXPECT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
+  content::WindowedNotificationObserver observer(
+      content::NOTIFICATION_NAV_ENTRY_COMMITTED,
+      content::NotificationService::AllSources());
+  ui_test_utils::NavigateToURLWithDisposition(
+      browser(),
+      GURL(chrome::kChromeUINewTabURL),
+      CURRENT_TAB,
+      ui_test_utils::BROWSER_TEST_NONE);
+  observer.Wait();
+  content::WebContents* active_tab =
+      browser()->tab_strip_model()->GetActiveWebContents();
+  EXPECT_TRUE(IsGooglePage(active_tab));
+}
+
+IN_PROC_BROWSER_TEST_F(InstantExtendedManualTest, MANUAL_SearchesFromFakebox) {
+  set_browser(browser());
+  instant()->ReloadStaleNTP();
+  FocusOmniboxAndWaitForInstantNTPSupport();
+
+  // Open a new tab page.
+  content::WindowedNotificationObserver observer(
+      content::NOTIFICATION_NAV_ENTRY_COMMITTED,
+      content::NotificationService::AllSources());
+  ui_test_utils::NavigateToURLWithDisposition(
+      browser(),
+      GURL(chrome::kChromeUINewTabURL),
+      CURRENT_TAB,
+      ui_test_utils::BROWSER_TEST_NONE);
+  observer.Wait();
+  content::WebContents* active_tab =
+      browser()->tab_strip_model()->GetActiveWebContents();
+  ASSERT_TRUE(IsGooglePage(active_tab));
+
+  // Click in the fakebox and expect invisible focus.
   ui_test_utils::ClickOnView(browser(), VIEW_ID_TAB_CONTAINER);
+  bool fakebox_is_present = false;
+  content::WindowedNotificationObserver focus_observer(
+      chrome::NOTIFICATION_OMNIBOX_FOCUS_CHANGED,
+      content::NotificationService::AllSources());
+  ASSERT_TRUE(GetBoolFromJS(active_tab, "!!document.querySelector('#fkbx')",
+                            &fakebox_is_present));
+  ASSERT_TRUE(fakebox_is_present);
+  ASSERT_TRUE(content::ExecuteScript(
+      active_tab, "document.querySelector('#fkbx').click()"));
+  focus_observer.Wait();
+  EXPECT_EQ(OMNIBOX_FOCUS_INVISIBLE, omnibox()->model()->focus_state());
 
-  EXPECT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_TAB_CONTAINER));
-  EXPECT_FALSE(omnibox()->model()->has_focus());
+  // Type "test".
+  const ui::KeyboardCode query[] = {
+    ui::VKEY_T, ui::VKEY_E, ui::VKEY_S, ui::VKEY_T,
+    ui::VKEY_UNKNOWN
+  };
+  for (size_t i = 0; query[i] != ui::VKEY_UNKNOWN; i++) {
+    ASSERT_TRUE(ui_test_utils::SendKeyPressSync(browser(), query[i],
+                                                false, false, false, false));
+  }
 
-  // Delete any existing overlay.
-  instant()->overlay_.reset();
-  EXPECT_FALSE(instant()->GetOverlayContents());
+  // The omnibox should say "test" and have visible focus.
+  EXPECT_EQ("test", GetOmniboxText());
+  EXPECT_EQ(OMNIBOX_FOCUS_VISIBLE, omnibox()->model()->focus_state());
 
-  // Refocus the omnibox. The InstantController should've preloaded Instant.
-  FocusOmniboxAndWaitForInstantOverlayAndNTPSupport();
-  ASSERT_TRUE(IsGoogleOverlay());
-
-  EXPECT_FALSE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_TAB_CONTAINER));
-  EXPECT_TRUE(omnibox()->model()->has_focus());
-
-  // Check that the page supports Instant, but it isn't showing.
-  ASSERT_TRUE(instant()->overlay());
-  EXPECT_TRUE(instant()->overlay()->supports_instant());
-  EXPECT_FALSE(instant()->IsOverlayingSearchResults());
-  EXPECT_TRUE(instant()->model()->mode().is_default());
+  // Pressing enter should search for [test].
+  const string16& search_title = ASCIIToUTF16("test - Google Search");
+  content::TitleWatcher title_watcher(active_tab, search_title);
+  PressEnterAndWaitForNavigation();
+  EXPECT_EQ(search_title, title_watcher.WaitAndGetTitle());
 }
diff --git a/chrome/browser/ui/search/instant_ipc_sender.cc b/chrome/browser/ui/search/instant_ipc_sender.cc
new file mode 100644
index 0000000..a457534
--- /dev/null
+++ b/chrome/browser/ui/search/instant_ipc_sender.cc
@@ -0,0 +1,98 @@
+// 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/ui/search/instant_ipc_sender.h"
+
+#include "chrome/common/render_messages.h"
+
+namespace {
+
+// Implementation for regular profiles.
+class InstantIPCSenderImpl : public InstantIPCSender {
+ public:
+  InstantIPCSenderImpl() {}
+  virtual ~InstantIPCSenderImpl() {}
+
+ private:
+  virtual void Submit(const string16& text) OVERRIDE {
+    Send(new ChromeViewMsg_SearchBoxSubmit(routing_id(), text));
+  }
+
+  virtual void SetOmniboxBounds(const gfx::Rect& bounds) OVERRIDE {
+    Send(new ChromeViewMsg_SearchBoxMarginChange(
+        routing_id(), bounds.x(), bounds.width()));
+  }
+
+  virtual void SetFontInformation(const string16& omnibox_font_name,
+                          size_t omnibox_font_size) OVERRIDE {
+    Send(new ChromeViewMsg_SearchBoxFontInformation(
+        routing_id(), omnibox_font_name, omnibox_font_size));
+  }
+
+  virtual void SetPromoInformation(bool is_app_launcher_enabled) OVERRIDE {
+    Send(new ChromeViewMsg_SearchBoxPromoInformation(
+        routing_id(), is_app_launcher_enabled));
+  }
+
+  virtual void SendThemeBackgroundInfo(
+      const ThemeBackgroundInfo& theme_info) OVERRIDE {
+    Send(new ChromeViewMsg_SearchBoxThemeChanged(routing_id(), theme_info));
+  }
+
+  virtual void FocusChanged(OmniboxFocusState state,
+                    OmniboxFocusChangeReason reason) OVERRIDE {
+    Send(new ChromeViewMsg_SearchBoxFocusChanged(routing_id(), state, reason));
+  }
+
+  virtual void SetInputInProgress(bool input_in_progress) OVERRIDE {
+    Send(new ChromeViewMsg_SearchBoxSetInputInProgress(
+        routing_id(), input_in_progress));
+  }
+
+  virtual void SendMostVisitedItems(
+      const std::vector<InstantMostVisitedItem>& items) OVERRIDE {
+    Send(new ChromeViewMsg_SearchBoxMostVisitedItemsChanged(
+        routing_id(), items));
+  }
+
+  virtual void ToggleVoiceSearch() OVERRIDE {
+    Send(new ChromeViewMsg_SearchBoxToggleVoiceSearch(routing_id()));
+  }
+
+  DISALLOW_COPY_AND_ASSIGN(InstantIPCSenderImpl);
+};
+
+// Implementation for incognito profiles.
+class IncognitoInstantIPCSenderImpl : public InstantIPCSender {
+ public:
+  IncognitoInstantIPCSenderImpl() {}
+  virtual ~IncognitoInstantIPCSenderImpl() {}
+
+ private:
+  virtual void Submit(const string16& text) OVERRIDE {
+    Send(new ChromeViewMsg_SearchBoxSubmit(routing_id(), text));
+  }
+
+  virtual void SetOmniboxBounds(const gfx::Rect& bounds) OVERRIDE {
+    Send(new ChromeViewMsg_SearchBoxMarginChange(
+        routing_id(), bounds.x(), bounds.width()));
+  }
+
+  DISALLOW_COPY_AND_ASSIGN(IncognitoInstantIPCSenderImpl);
+};
+
+}  // anonymous namespace
+
+// static
+scoped_ptr<InstantIPCSender> InstantIPCSender::Create(bool is_incognito) {
+  scoped_ptr<InstantIPCSender> sender(
+      is_incognito ?
+      static_cast<InstantIPCSender*>(new IncognitoInstantIPCSenderImpl()) :
+      static_cast<InstantIPCSender*>(new InstantIPCSenderImpl()));
+  return sender.Pass();
+}
+
+void InstantIPCSender::SetContents(content::WebContents* web_contents) {
+  Observe(web_contents);
+}
diff --git a/chrome/browser/ui/search/instant_ipc_sender.h b/chrome/browser/ui/search/instant_ipc_sender.h
new file mode 100644
index 0000000..8319f2c
--- /dev/null
+++ b/chrome/browser/ui/search/instant_ipc_sender.h
@@ -0,0 +1,73 @@
+// 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_UI_SEARCH_INSTANT_IPC_SENDER_H_
+#define CHROME_BROWSER_UI_SEARCH_INSTANT_IPC_SENDER_H_
+
+#include <vector>
+
+#include "base/memory/scoped_ptr.h"
+#include "chrome/common/instant_types.h"
+#include "chrome/common/omnibox_focus_state.h"
+#include "content/public/browser/web_contents_observer.h"
+
+namespace gfx {
+class Rect;
+}
+
+namespace IPC {
+class Sender;
+}
+
+class InstantIPCSender : public content::WebContentsObserver {
+ public:
+  // Creates a new instance of InstantIPCSender. If |is_incognito| is true,
+  // the instance will only send appropriate IPCs for incognito profiles.
+  static scoped_ptr<InstantIPCSender> Create(bool is_incognito);
+
+  virtual ~InstantIPCSender() {}
+
+  // Sets |web_contents| as the receiver of IPCs.
+  void SetContents(content::WebContents* web_contents);
+
+  // Tells the page that the user pressed Enter in the omnibox.
+  virtual void Submit(const string16& text) {}
+
+  // Tells the page the bounds of the omnibox (in screen coordinates). This is
+  // used by the page to align text or assets properly with the omnibox.
+  virtual void SetOmniboxBounds(const gfx::Rect& bounds) {}
+
+  // Tells the page about the font information.
+  virtual void SetFontInformation(const string16& omnibox_font_name,
+                                  size_t omnibox_font_size) {}
+
+  // Tells the page information it needs to display promos.
+  virtual void SetPromoInformation(bool is_app_launcher_enabled) {}
+
+  // Tells the page about the current theme background.
+  virtual void SendThemeBackgroundInfo(
+      const ThemeBackgroundInfo& theme_info) {}
+
+  // Tells the page that the omnibox focus has changed.
+  virtual void FocusChanged(OmniboxFocusState state,
+                            OmniboxFocusChangeReason reason) {}
+
+  // Tells the page that user input started or stopped.
+  virtual void SetInputInProgress(bool input_in_progress) {}
+
+  // Tells the page about new Most Visited data.
+  virtual void SendMostVisitedItems(
+      const std::vector<InstantMostVisitedItem>& items) {}
+
+  // Tells the page to toggle voice search.
+  virtual void ToggleVoiceSearch() {}
+
+ protected:
+  InstantIPCSender() {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(InstantIPCSender);
+};
+
+#endif  // CHROME_BROWSER_UI_SEARCH_INSTANT_IPC_SENDER_H_
diff --git a/chrome/browser/ui/search/instant_loader.cc b/chrome/browser/ui/search/instant_loader.cc
index 79d0031..c50b7fb 100644
--- a/chrome/browser/ui/search/instant_loader.cc
+++ b/chrome/browser/ui/search/instant_loader.cc
@@ -21,6 +21,8 @@
 #include "content/public/browser/render_widget_host_view.h"
 #include "content/public/browser/site_instance.h"
 #include "content/public/browser/web_contents_view.h"
+#include "grit/generated_resources.h"
+#include "ui/base/l10n/l10n_util.h"
 
 namespace {
 
@@ -56,6 +58,17 @@
   contents_->GetController().LoadURL(
       instant_url_, content::Referrer(),
       content::PAGE_TRANSITION_GENERATED, kInstantHeader);
+
+  // Explicitly set the new tab title and virtual URL.
+  //
+  // This ensures that the title is set even before we get a title from the
+  // page, preventing a potential flicker of the URL, and also ensures that
+  // (unless overridden by the page) the new tab title matches the browser UI
+  // locale.
+  content::NavigationEntry* entry = contents_->GetController().GetActiveEntry();
+  if (entry)
+    entry->SetTitle(l10n_util::GetStringUTF16(IDS_NEW_TAB_TITLE));
+
   contents_->WasHidden();
 
   int staleness_timeout_ms = chrome::GetInstantLoaderStalenessTimeoutSec() *
diff --git a/chrome/browser/ui/search/instant_loader.h b/chrome/browser/ui/search/instant_loader.h
index 6071cbd..e0ec012 100644
--- a/chrome/browser/ui/search/instant_loader.h
+++ b/chrome/browser/ui/search/instant_loader.h
@@ -9,7 +9,7 @@
 #include "base/callback.h"
 #include "base/compiler_specific.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/timer.h"
+#include "base/timer/timer.h"
 #include "chrome/browser/ui/tab_contents/core_tab_helper_delegate.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
diff --git a/chrome/browser/ui/search/instant_ntp.cc b/chrome/browser/ui/search/instant_ntp.cc
index bda523e..5813ae0 100644
--- a/chrome/browser/ui/search/instant_ntp.cc
+++ b/chrome/browser/ui/search/instant_ntp.cc
@@ -4,13 +4,16 @@
 
 #include "chrome/browser/ui/search/instant_ntp.h"
 
+#include "chrome/browser/ui/search/search_tab_helper.h"
 #include "content/public/browser/navigation_entry.h"
 #include "content/public/browser/web_contents.h"
 
 InstantNTP::InstantNTP(InstantPage::Delegate* delegate,
-                       const std::string& instant_url)
-    : InstantPage(delegate, instant_url),
+                       const std::string& instant_url,
+                       bool is_incognito)
+    : InstantPage(delegate, instant_url, is_incognito),
       loader_(this) {
+  DCHECK(delegate);
 }
 
 InstantNTP::~InstantNTP() {
@@ -21,6 +24,7 @@
                               const base::Closure& on_stale_callback) {
   loader_.Init(GURL(instant_url()), profile, active_tab, on_stale_callback);
   SetContents(loader_.contents());
+  SearchTabHelper::FromWebContents(contents())->InitForPreloadedNTP();
   loader_.Load();
 }
 
@@ -29,6 +33,14 @@
   return loader_.ReleaseContents();
 }
 
+void InstantNTP::RenderViewCreated(content::RenderViewHost* render_view_host) {
+  delegate()->InstantPageRenderViewCreated(contents());
+}
+
+void InstantNTP::RenderViewGone(base::TerminationStatus /* status */) {
+  delegate()->InstantPageRenderViewGone(contents());
+}
+
 void InstantNTP::OnSwappedContents() {
   SetContents(loader_.contents());
 }
@@ -53,11 +65,3 @@
 
 void InstantNTP::LoadCompletedMainFrame() {
 }
-
-bool InstantNTP::ShouldProcessRenderViewCreated() {
-  return true;
-}
-
-bool InstantNTP::ShouldProcessRenderViewGone() {
-  return true;
-}
diff --git a/chrome/browser/ui/search/instant_ntp.h b/chrome/browser/ui/search/instant_ntp.h
index eedc6e1..3000ee5 100644
--- a/chrome/browser/ui/search/instant_ntp.h
+++ b/chrome/browser/ui/search/instant_ntp.h
@@ -10,18 +10,24 @@
 #include "base/basictypes.h"
 #include "base/compiler_specific.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/process_util.h"
 #include "chrome/browser/ui/search/instant_loader.h"
 #include "chrome/browser/ui/search/instant_page.h"
 
 class Profile;
 
+namespace content {
+class RenderViewHost;
+}
+
 // InstantNTP is used to preload an Instant page that will be swapped in when a
 // user navigates to a New Tab Page (NTP). The InstantNTP contents are never
 // shown in an un-committed state.
 class InstantNTP : public InstantPage,
                    public InstantLoader::Delegate {
  public:
-  InstantNTP(InstantPage::Delegate* delegate, const std::string& instant_url);
+  InstantNTP(InstantPage::Delegate* delegate, const std::string& instant_url,
+             bool is_incognito);
   virtual ~InstantNTP();
 
   // Creates a new WebContents and loads |instant_url_| into it. Uses
@@ -37,6 +43,12 @@
   scoped_ptr<content::WebContents> ReleaseContents();
 
  private:
+  // Overridden from content::WebContentsObserver:
+  virtual void RenderViewCreated(
+      content::RenderViewHost* render_view_host) OVERRIDE;
+  virtual void RenderViewGone(
+      base::TerminationStatus status) OVERRIDE;
+
   // Overriden from InstantLoader::Delegate:
   virtual void OnSwappedContents() OVERRIDE;
   virtual void OnFocus() OVERRIDE;
@@ -47,10 +59,6 @@
       const content::OpenURLParams& params) OVERRIDE;
   virtual void LoadCompletedMainFrame() OVERRIDE;
 
-  // Overridden from InstantPage:
-  virtual bool ShouldProcessRenderViewCreated() OVERRIDE;
-  virtual bool ShouldProcessRenderViewGone() OVERRIDE;
-
   InstantLoader loader_;
 
   DISALLOW_COPY_AND_ASSIGN(InstantNTP);
diff --git a/chrome/browser/ui/search/instant_overlay.cc b/chrome/browser/ui/search/instant_overlay.cc
deleted file mode 100644
index 6656964..0000000
--- a/chrome/browser/ui/search/instant_overlay.cc
+++ /dev/null
@@ -1,171 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ui/search/instant_overlay.h"
-
-#include "base/auto_reset.h"
-#include "base/supports_user_data.h"
-#include "chrome/browser/search/search.h"
-#include "chrome/common/url_constants.h"
-#include "content/public/browser/web_contents.h"
-
-namespace {
-
-int kUserDataKey;
-
-class InstantOverlayUserData : public base::SupportsUserData::Data {
- public:
-  explicit InstantOverlayUserData(InstantOverlay* overlay)
-      : overlay_(overlay) {}
-
-  virtual InstantOverlay* overlay() const { return overlay_; }
-
- private:
-  virtual ~InstantOverlayUserData() {}
-
-  InstantOverlay* const overlay_;
-
-  DISALLOW_COPY_AND_ASSIGN(InstantOverlayUserData);
-};
-
-}  // namespace
-
-// static
-InstantOverlay* InstantOverlay::FromWebContents(
-    const content::WebContents* web_contents) {
-  InstantOverlayUserData* data = static_cast<InstantOverlayUserData*>(
-      web_contents->GetUserData(&kUserDataKey));
-  return data ? data->overlay() : NULL;
-}
-
-InstantOverlay::InstantOverlay(InstantController* controller,
-                               const std::string& instant_url)
-    : InstantPage(controller, instant_url),
-      loader_(this),
-      is_stale_(false),
-      is_pointer_down_from_activate_(false) {
-}
-
-InstantOverlay::~InstantOverlay() {
-}
-
-void InstantOverlay::InitContents(Profile* profile,
-                                  const content::WebContents* active_tab) {
-  loader_.Init(GURL(instant_url()), profile, active_tab,
-               base::Bind(&InstantOverlay::HandleStalePage,
-                           base::Unretained(this)));
-  SetContents(loader_.contents());
-  contents()->SetUserData(&kUserDataKey, new InstantOverlayUserData(this));
-  loader_.Load();
-}
-
-scoped_ptr<content::WebContents> InstantOverlay::ReleaseContents() {
-  contents()->RemoveUserData(&kUserDataKey);
-  SetContents(NULL);
-  return loader_.ReleaseContents();
-}
-
-void InstantOverlay::DidNavigate(
-    const history::HistoryAddPageArgs& add_page_args) {
-  last_navigation_ = add_page_args;
-}
-
-void InstantOverlay::Update(const string16& text,
-                            size_t selection_start,
-                            size_t selection_end,
-                            bool verbatim) {
-  last_navigation_ = history::HistoryAddPageArgs();
-  InstantPage::Update(text, selection_start, selection_end, verbatim);
-}
-
-bool InstantOverlay::ShouldProcessRenderViewCreated() {
-  return true;
-}
-
-bool InstantOverlay::ShouldProcessRenderViewGone() {
-  return true;
-}
-
-bool InstantOverlay::ShouldProcessAboutToNavigateMainFrame() {
-  return true;
-}
-
-bool InstantOverlay::ShouldProcessSetSuggestions() {
-  return true;
-}
-
-bool InstantOverlay::ShouldProcessShowInstantOverlay() {
-  return true;
-}
-
-bool InstantOverlay::ShouldProcessNavigateToURL() {
-  return true;
-}
-
-void InstantOverlay::OnSwappedContents() {
-  contents()->RemoveUserData(&kUserDataKey);
-  SetContents(loader_.contents());
-  contents()->SetUserData(&kUserDataKey, new InstantOverlayUserData(this));
-  instant_controller()->SwappedOverlayContents();
-}
-
-void InstantOverlay::OnFocus() {
-  // The overlay is getting focus. Equivalent to it being clicked.
-  base::AutoReset<bool> reset(&is_pointer_down_from_activate_, true);
-  instant_controller()->FocusedOverlayContents();
-}
-
-void InstantOverlay::OnMouseDown() {
-  is_pointer_down_from_activate_ = true;
-}
-
-void InstantOverlay::OnMouseUp() {
-  if (is_pointer_down_from_activate_) {
-    is_pointer_down_from_activate_ = false;
-    instant_controller()->CommitIfPossible(INSTANT_COMMIT_FOCUS_LOST);
-  }
-}
-
-content::WebContents* InstantOverlay::OpenURLFromTab(
-    content::WebContents* source,
-    const content::OpenURLParams& params) {
-  if (!supports_instant()) {
-    // If the page doesn't yet support Instant, it hasn't fully loaded.
-    // This is a redirect that we should allow. http://crbug.com/177948
-    content::NavigationController::LoadURLParams load_params(params.url);
-    load_params.transition_type = params.transition;
-    load_params.referrer = params.referrer;
-    load_params.extra_headers = params.extra_headers;
-    load_params.is_renderer_initiated = params.is_renderer_initiated;
-    load_params.transferred_global_request_id =
-        params.transferred_global_request_id;
-    load_params.is_cross_site_redirect = params.is_cross_site_redirect;
-
-    contents()->GetController().LoadURLWithParams(load_params);
-    return contents();
-  }
-
-  // We will allow the navigate to continue if we are able to commit the
-  // overlay.
-  //
-  // First, cache the overlay contents since committing it will cause the
-  // contents to be released (and be set to NULL).
-  content::WebContents* overlay = contents();
-  if (instant_controller()->CommitIfPossible(INSTANT_COMMIT_NAVIGATED)) {
-    // If the commit was successful, the overlay's delegate should be the tab
-    // strip, which will be able to handle the navigation.
-    DCHECK_NE(&loader_, overlay->GetDelegate());
-    return overlay->GetDelegate()->OpenURLFromTab(source, params);
-  }
-  return NULL;
-}
-
-void InstantOverlay::LoadCompletedMainFrame() {
-  instant_controller()->OverlayLoadCompletedMainFrame();
-}
-
-void InstantOverlay::HandleStalePage() {
-  is_stale_ = true;
-  instant_controller()->ReloadOverlayIfStale();
-}
diff --git a/chrome/browser/ui/search/instant_overlay.h b/chrome/browser/ui/search/instant_overlay.h
deleted file mode 100644
index beea995..0000000
--- a/chrome/browser/ui/search/instant_overlay.h
+++ /dev/null
@@ -1,111 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_SEARCH_INSTANT_OVERLAY_H_
-#define CHROME_BROWSER_UI_SEARCH_INSTANT_OVERLAY_H_
-
-#include <string>
-
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "base/gtest_prod_util.h"
-#include "base/memory/scoped_ptr.h"
-#include "chrome/browser/history/history_types.h"
-#include "chrome/browser/ui/search/instant_controller.h"
-#include "chrome/browser/ui/search/instant_loader.h"
-#include "chrome/browser/ui/search/instant_page.h"
-
-class Profile;
-
-namespace content {
-class WebContents;
-}
-
-// InstantOverlay is used to communicate with an overlay WebContents that it
-// owns and loads the "Instant URL" into. This overlay can appear and disappear
-// at will as the user types in the omnibox.
-class InstantOverlay : public InstantPage,
-                       public InstantLoader::Delegate {
- public:
-  // Returns the InstantOverlay for |contents| if it's used for Instant.
-  static InstantOverlay* FromWebContents(const content::WebContents* contents);
-
-  InstantOverlay(InstantController* controller,
-                 const std::string& instant_url);
-  virtual ~InstantOverlay();
-
-  // Creates a new WebContents and loads |instant_url_| into it. Uses
-  // |active_tab|, if non-NULL, to initialize the size of the WebContents.
-  void InitContents(Profile* profile,
-                    const content::WebContents* active_tab);
-
-  // Releases the overlay WebContents. This should be called when the overlay
-  // is committed.
-  scoped_ptr<content::WebContents> ReleaseContents();
-
-  // Returns whether the underlying contents is stale (i.e. was loaded too long
-  // ago).
-  bool is_stale() const { return is_stale_; }
-
-  // Returns true if the mouse or a touch pointer is down due to activating the
-  // overlay contents.
-  bool is_pointer_down_from_activate() const {
-    return is_pointer_down_from_activate_;
-  }
-
-  // Returns info about the last navigation by the Instant page. If the page
-  // hasn't navigated since the last Update(), the URL is empty.
-  const history::HistoryAddPageArgs& last_navigation() const {
-    return last_navigation_;
-  }
-
-  // Called by the history tab helper with information that it would have added
-  // to the history service had this WebContents not been used for Instant.
-  void DidNavigate(const history::HistoryAddPageArgs& add_page_args);
-
-  // Overridden from InstantPage:
-  virtual void Update(const string16& text,
-                      size_t selection_start,
-                      size_t selection_end,
-                      bool verbatim) OVERRIDE;
-
- private:
-  FRIEND_TEST_ALL_PREFIXES(InstantTest, InstantOverlayRefresh);
-  FRIEND_TEST_ALL_PREFIXES(InstantTest, InstantOverlayRefreshDifferentOrder);
-
-  // Helper to access delegate() as an InstantController object.
-  InstantController* instant_controller() const {
-    return static_cast<InstantController*>(delegate());
-  }
-
-  // Overridden from InstantPage:
-  virtual bool ShouldProcessRenderViewCreated() OVERRIDE;
-  virtual bool ShouldProcessRenderViewGone() OVERRIDE;
-  virtual bool ShouldProcessAboutToNavigateMainFrame() OVERRIDE;
-  virtual bool ShouldProcessSetSuggestions() OVERRIDE;
-  virtual bool ShouldProcessShowInstantOverlay() OVERRIDE;
-  virtual bool ShouldProcessNavigateToURL() OVERRIDE;
-
-  // Overriden from InstantLoader::Delegate:
-  virtual void OnSwappedContents() OVERRIDE;
-  virtual void OnFocus() OVERRIDE;
-  virtual void OnMouseDown() OVERRIDE;
-  virtual void OnMouseUp() OVERRIDE;
-  virtual content::WebContents* OpenURLFromTab(
-      content::WebContents* source,
-      const content::OpenURLParams& params) OVERRIDE;
-  virtual void LoadCompletedMainFrame() OVERRIDE;
-
-  // Called when the underlying page becomes stale.
-  void HandleStalePage();
-
-  InstantLoader loader_;
-  bool is_stale_;
-  bool is_pointer_down_from_activate_;
-  history::HistoryAddPageArgs last_navigation_;
-
-  DISALLOW_COPY_AND_ASSIGN(InstantOverlay);
-};
-
-#endif  // CHROME_BROWSER_UI_SEARCH_INSTANT_OVERLAY_H_
diff --git a/chrome/browser/ui/search/instant_overlay_controller.cc b/chrome/browser/ui/search/instant_overlay_controller.cc
index 547ccab..64fda78 100644
--- a/chrome/browser/ui/search/instant_overlay_controller.cc
+++ b/chrome/browser/ui/search/instant_overlay_controller.cc
@@ -9,11 +9,7 @@
 
 InstantOverlayController::InstantOverlayController(Browser* browser)
     : browser_(browser) {
-  if (browser_->instant_controller())
-    browser_->instant_controller()->instant()->model()->AddObserver(this);
 }
 
 InstantOverlayController::~InstantOverlayController() {
-  if (browser_->instant_controller())
-    browser_->instant_controller()->instant()->model()->RemoveObserver(this);
 }
diff --git a/chrome/browser/ui/search/instant_overlay_model.cc b/chrome/browser/ui/search/instant_overlay_model.cc
index 09a668b..bc6213b 100644
--- a/chrome/browser/ui/search/instant_overlay_model.cc
+++ b/chrome/browser/ui/search/instant_overlay_model.cc
@@ -50,9 +50,6 @@
 }
 
 content::WebContents* InstantOverlayModel::GetOverlayContents() const {
-  // |controller_| maybe NULL durning tests.
-  if (controller_)
-    return controller_->GetOverlayContents();
   return overlay_contents_;
 }
 
diff --git a/chrome/browser/ui/search/instant_page.cc b/chrome/browser/ui/search/instant_page.cc
index 356ecd0..121300a 100644
--- a/chrome/browser/ui/search/instant_page.cc
+++ b/chrome/browser/ui/search/instant_page.cc
@@ -4,7 +4,11 @@
 
 #include "chrome/browser/ui/search/instant_page.h"
 
+#include "apps/app_launcher.h"
 #include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/search/search.h"
+#include "chrome/browser/ui/search/search_model.h"
+#include "chrome/browser/ui/search/search_tab_helper.h"
 #include "chrome/common/render_messages.h"
 #include "chrome/common/url_constants.h"
 #include "content/public/browser/navigation_controller.h"
@@ -19,10 +23,13 @@
 }
 
 InstantPage::~InstantPage() {
+  if (contents())
+    SearchTabHelper::FromWebContents(contents())->model()->RemoveObserver(this);
 }
 
 bool InstantPage::supports_instant() const {
-  return supports_instant_;
+  return contents() ?
+      SearchTabHelper::FromWebContents(contents())->SupportsInstant() : false;
 }
 
 const std::string& InstantPage::instant_url() const {
@@ -35,137 +42,53 @@
        contents()->GetURL() == GURL(chrome::kChromeSearchLocalGoogleNtpUrl));
 }
 
-void InstantPage::Update(const string16& text,
-                         size_t selection_start,
-                         size_t selection_end,
-                         bool verbatim) {
-  Send(new ChromeViewMsg_SearchBoxChange(routing_id(), text, verbatim,
-                                         selection_start, selection_end));
-}
-
-void InstantPage::Submit(const string16& text) {
-  Send(new ChromeViewMsg_SearchBoxSubmit(routing_id(), text));
-}
-
-void InstantPage::Cancel(const string16& text) {
-  Send(new ChromeViewMsg_SearchBoxCancel(routing_id(), text));
-}
-
-void InstantPage::SetPopupBounds(const gfx::Rect& bounds) {
-  Send(new ChromeViewMsg_SearchBoxPopupResize(routing_id(), bounds));
-}
-
-void InstantPage::SetOmniboxBounds(const gfx::Rect& bounds) {
-  Send(new ChromeViewMsg_SearchBoxMarginChange(
-      routing_id(), bounds.x(), bounds.width()));
-}
-
 void InstantPage::InitializeFonts() {
 #if defined(OS_MACOSX)
   // This value should be kept in sync with OmniboxViewMac::GetFieldFont.
-  const gfx::Font omnibox_font("Helvetica Neue", 16);
+  const gfx::Font& omnibox_font =
+      ui::ResourceBundle::GetSharedInstance().GetFont(
+          ui::ResourceBundle::MediumFont).DeriveFont(1);
 #else
   const gfx::Font& omnibox_font =
       ui::ResourceBundle::GetSharedInstance().GetFont(
           ui::ResourceBundle::MediumFont);
 #endif
-  string16 omnibox_font_name = UTF8ToUTF16(omnibox_font.GetFontName());
-  size_t omnibox_font_size = omnibox_font.GetFontSize();
-  Send(new ChromeViewMsg_SearchBoxFontInformation(
-      routing_id(), omnibox_font_name, omnibox_font_size));
+  sender()->SetFontInformation(UTF8ToUTF16(omnibox_font.GetFontName()),
+                               omnibox_font.GetFontSize());
 }
 
-void InstantPage::DetermineIfPageSupportsInstant() {
-  if (IsLocal()) {
-    // Local pages always support Instant. That's why we keep them around.
-    int page_id = contents()->GetController().GetActiveEntry()->GetPageID();
-    OnInstantSupportDetermined(page_id, true);
-  } else {
-    Send(new ChromeViewMsg_DetermineIfPageSupportsInstant(routing_id()));
-  }
+void InstantPage::InitializePromos() {
+  sender()->SetPromoInformation(apps::IsAppLauncherEnabled());
 }
 
-void InstantPage::SendAutocompleteResults(
-    const std::vector<InstantAutocompleteResult>& results) {
-  Send(new ChromeViewMsg_SearchBoxAutocompleteResults(routing_id(), results));
-}
-
-void InstantPage::UpOrDownKeyPressed(int count) {
-  Send(new ChromeViewMsg_SearchBoxUpOrDownKeyPressed(routing_id(), count));
-}
-
-void InstantPage::EscKeyPressed() {
-  Send(new ChromeViewMsg_SearchBoxEscKeyPressed(routing_id()));
-}
-
-void InstantPage::CancelSelection(const string16& user_text,
-                                  size_t selection_start,
-                                  size_t selection_end,
-                                  bool verbatim) {
-  Send(new ChromeViewMsg_SearchBoxCancelSelection(
-      routing_id(), user_text, verbatim, selection_start, selection_end));
-}
-
-void InstantPage::SendThemeBackgroundInfo(
-    const ThemeBackgroundInfo& theme_info) {
-  Send(new ChromeViewMsg_SearchBoxThemeChanged(routing_id(), theme_info));
-}
-
-void InstantPage::SetDisplayInstantResults(bool display_instant_results) {
-  Send(new ChromeViewMsg_SearchBoxSetDisplayInstantResults(
-      routing_id(), display_instant_results));
-}
-
-void InstantPage::FocusChanged(OmniboxFocusState state,
-                               OmniboxFocusChangeReason reason) {
-  Send(new ChromeViewMsg_SearchBoxFocusChanged(routing_id(), state, reason));
-}
-
-void InstantPage::SetInputInProgress(bool input_in_progress) {
-  Send(new ChromeViewMsg_SearchBoxSetInputInProgress(
-      routing_id(), input_in_progress));
-}
-
-void InstantPage::SendMostVisitedItems(
-    const std::vector<InstantMostVisitedItem>& items) {
-  Send(new ChromeViewMsg_SearchBoxMostVisitedItemsChanged(routing_id(), items));
-}
-
-void InstantPage::ToggleVoiceSearch() {
-  Send(new ChromeViewMsg_SearchBoxToggleVoiceSearch(routing_id()));
-}
-
-InstantPage::InstantPage(Delegate* delegate, const std::string& instant_url)
+InstantPage::InstantPage(Delegate* delegate, const std::string& instant_url,
+                         bool is_incognito)
     : delegate_(delegate),
+      ipc_sender_(InstantIPCSender::Create(is_incognito)),
       instant_url_(instant_url),
-      supports_instant_(false),
-      instant_support_determined_(false) {
+      is_incognito_(is_incognito) {
 }
 
-void InstantPage::SetContents(content::WebContents* contents) {
-  Observe(contents);
-}
+void InstantPage::SetContents(content::WebContents* web_contents) {
+  ClearContents();
 
-bool InstantPage::ShouldProcessRenderViewCreated() {
-  return false;
-}
+  if (!web_contents)
+    return;
 
-bool InstantPage::ShouldProcessRenderViewGone() {
-  return false;
+  sender()->SetContents(web_contents);
+  Observe(web_contents);
+  SearchModel* model = SearchTabHelper::FromWebContents(contents())->model();
+  model->AddObserver(this);
+
+  // Already know whether the page supports instant.
+  if (model->instant_support() != INSTANT_SUPPORT_UNKNOWN)
+    InstantSupportDetermined(model->instant_support() == INSTANT_SUPPORT_YES);
 }
 
 bool InstantPage::ShouldProcessAboutToNavigateMainFrame() {
   return false;
 }
 
-bool InstantPage::ShouldProcessSetSuggestions() {
-  return false;
-}
-
-bool InstantPage::ShouldProcessShowInstantOverlay() {
-  return false;
-}
-
 bool InstantPage::ShouldProcessFocusOmnibox() {
   return false;
 }
@@ -186,28 +109,12 @@
   return false;
 }
 
-void InstantPage::RenderViewCreated(content::RenderViewHost* render_view_host) {
-  if (ShouldProcessRenderViewCreated())
-    delegate_->InstantPageRenderViewCreated(contents());
-}
-
-void InstantPage::DidFinishLoad(
-    int64 /* frame_id */,
-    const GURL& /* validated_url */,
-    bool is_main_frame,
-    content::RenderViewHost* /* render_view_host */) {
-  if (is_main_frame && !supports_instant_)
-    DetermineIfPageSupportsInstant();
-}
-
 bool InstantPage::OnMessageReceived(const IPC::Message& message) {
+  if (is_incognito_)
+    return false;
+
   bool handled = true;
   IPC_BEGIN_MESSAGE_MAP(InstantPage, message)
-    IPC_MESSAGE_HANDLER(ChromeViewHostMsg_SetSuggestions, OnSetSuggestions)
-    IPC_MESSAGE_HANDLER(ChromeViewHostMsg_InstantSupportDetermined,
-                        OnInstantSupportDetermined)
-    IPC_MESSAGE_HANDLER(ChromeViewHostMsg_ShowInstantOverlay,
-                        OnShowInstantOverlay)
     IPC_MESSAGE_HANDLER(ChromeViewHostMsg_FocusOmnibox, OnFocusOmnibox)
     IPC_MESSAGE_HANDLER(ChromeViewHostMsg_SearchBoxNavigate,
                         OnSearchBoxNavigate);
@@ -222,11 +129,6 @@
   return handled;
 }
 
-void InstantPage::RenderViewGone(base::TerminationStatus /* status */) {
-  if (ShouldProcessRenderViewGone())
-    delegate_->InstantPageRenderViewGone(contents());
-}
-
 void InstantPage::DidCommitProvisionalLoadForFrame(
     int64 /* frame_id */,
     bool is_main_frame,
@@ -258,54 +160,25 @@
     delegate_->InstantPageLoadFailed(contents());
 }
 
-void InstantPage::OnSetSuggestions(
-    int page_id,
-    const std::vector<InstantSuggestion>& suggestions) {
-  if (!contents()->IsActiveEntry(page_id))
-    return;
-
-  OnInstantSupportDetermined(page_id, true);
-  if (!ShouldProcessSetSuggestions())
-    return;
-
-  delegate_->SetSuggestions(contents(), suggestions);
+void InstantPage::ModelChanged(const SearchModel::State& old_state,
+                               const SearchModel::State& new_state) {
+  if (old_state.instant_support != new_state.instant_support)
+    InstantSupportDetermined(new_state.instant_support == INSTANT_SUPPORT_YES);
 }
 
-void InstantPage::OnInstantSupportDetermined(int page_id,
-                                             bool supports_instant) {
-  if (!contents()->IsActiveEntry(page_id) || supports_instant_) {
-    // Nothing to do if the page already supports Instant.
-    return;
-  }
-
-  instant_support_determined_ = true;
-  supports_instant_ = supports_instant;
+void InstantPage::InstantSupportDetermined(bool supports_instant) {
   delegate_->InstantSupportDetermined(contents(), supports_instant);
 
   // If the page doesn't support Instant, stop listening to it.
   if (!supports_instant)
-    Observe(NULL);
-}
-
-void InstantPage::OnShowInstantOverlay(int page_id,
-                                       int height,
-                                       InstantSizeUnits units) {
-  if (!contents()->IsActiveEntry(page_id))
-    return;
-
-  OnInstantSupportDetermined(page_id, true);
-  delegate_->LogDropdownShown();
-  if (!ShouldProcessShowInstantOverlay())
-    return;
-
-  delegate_->ShowInstantOverlay(contents(), height, units);
+    ClearContents();
 }
 
 void InstantPage::OnFocusOmnibox(int page_id, OmniboxFocusState state) {
   if (!contents()->IsActiveEntry(page_id))
     return;
 
-  OnInstantSupportDetermined(page_id, true);
+  SearchTabHelper::FromWebContents(contents())->InstantSupportChanged(true);
   if (!ShouldProcessFocusOmnibox())
     return;
 
@@ -320,7 +193,7 @@
   if (!contents()->IsActiveEntry(page_id))
     return;
 
-  OnInstantSupportDetermined(page_id, true);
+  SearchTabHelper::FromWebContents(contents())->InstantSupportChanged(true);
   if (!ShouldProcessNavigateToURL())
     return;
 
@@ -332,7 +205,7 @@
   if (!contents()->IsActiveEntry(page_id))
     return;
 
-  OnInstantSupportDetermined(page_id, true);
+  SearchTabHelper::FromWebContents(contents())->InstantSupportChanged(true);
   if (!ShouldProcessDeleteMostVisitedItem())
     return;
 
@@ -343,7 +216,7 @@
   if (!contents()->IsActiveEntry(page_id))
     return;
 
-  OnInstantSupportDetermined(page_id, true);
+  SearchTabHelper::FromWebContents(contents())->InstantSupportChanged(true);
   if (!ShouldProcessUndoMostVisitedDeletion())
     return;
 
@@ -354,9 +227,17 @@
   if (!contents()->IsActiveEntry(page_id))
     return;
 
-  OnInstantSupportDetermined(page_id, true);
+  SearchTabHelper::FromWebContents(contents())->InstantSupportChanged(true);
   if (!ShouldProcessUndoAllMostVisitedDeletions())
     return;
 
   delegate_->UndoAllMostVisitedDeletions();
 }
+
+void InstantPage::ClearContents() {
+  if (contents())
+    SearchTabHelper::FromWebContents(contents())->model()->RemoveObserver(this);
+
+  sender()->SetContents(NULL);
+  Observe(NULL);
+}
diff --git a/chrome/browser/ui/search/instant_page.h b/chrome/browser/ui/search/instant_page.h
index 341defc..bf60ccb 100644
--- a/chrome/browser/ui/search/instant_page.h
+++ b/chrome/browser/ui/search/instant_page.h
@@ -10,7 +10,10 @@
 #include "base/basictypes.h"
 #include "base/compiler_specific.h"
 #include "base/gtest_prod_util.h"
+#include "base/memory/scoped_ptr.h"
 #include "base/strings/string16.h"
+#include "chrome/browser/ui/search/instant_ipc_sender.h"
+#include "chrome/browser/ui/search/search_model_observer.h"
 #include "chrome/common/instant_types.h"
 #include "chrome/common/omnibox_focus_state.h"
 #include "content/public/browser/web_contents_observer.h"
@@ -30,9 +33,10 @@
 
 // InstantPage is used to exchange messages with a page that implements the
 // Instant/Embedded Search API (http://dev.chromium.org/embeddedsearch).
-// InstantPage is not used directly but via one of its derived classes:
-// InstantOverlay, InstantNTP and InstantTab.
-class InstantPage : public content::WebContentsObserver {
+// InstantPage is not used directly but via one of its derived classes,
+// InstantNTP and InstantTab.
+class InstantPage : public content::WebContentsObserver,
+                    public SearchModelObserver {
  public:
   // InstantPage calls its delegate in response to messages received from the
   // page. Each method is called with the |contents| corresponding to the page
@@ -57,22 +61,6 @@
         const content::WebContents* contents,
         const GURL& url) = 0;
 
-    // Called when the page has suggestions. Usually in response to Update(),
-    // SendAutocompleteResults() or UpOrDownKeyPressed().
-    virtual void SetSuggestions(
-        const content::WebContents* contents,
-        const std::vector<InstantSuggestion>& suggestions) = 0;
-
-    // Called when the page wants to be shown. Usually in response to Update()
-    // or SendAutocompleteResults().
-    virtual void ShowInstantOverlay(const content::WebContents* contents,
-                                    int height,
-                                    InstantSizeUnits units) = 0;
-
-    // Called when the page shows suggestions for logging purposes, regardless
-    // of whether the page is processing the call.
-    virtual void LogDropdownShown() = 0;
-
     // Called when the page wants the omnibox to be focused. |state| specifies
     // the omnibox focus state.
     virtual void FocusOmnibox(const content::WebContents* contents,
@@ -109,6 +97,9 @@
   // The WebContents corresponding to the page we're talking to. May be NULL.
   content::WebContents* contents() const { return web_contents(); }
 
+  // Used to send IPC messages to the page.
+  InstantIPCSender* sender() const { return ipc_sender_.get(); }
+
   // Returns the Instant URL that was loaded for this page. Returns the empty
   // string if no URL was explicitly loaded as is the case for InstantTab.
   virtual const std::string& instant_url() const;
@@ -119,94 +110,21 @@
   // support suddenly).
   virtual bool supports_instant() const;
 
-  // True if Instant support has been tested and determined for this page at
-  // least once. Note that Instant support may change in the future.
-  bool instant_support_determined() const {
-    return instant_support_determined_;
-  }
-
   // Returns true if the page is the local NTP (i.e. its URL is
   // chrome::kChromeSearchLocalNTPURL).
   virtual bool IsLocal() const;
 
-  // Tells the page that the user typed |text| into the omnibox. If |verbatim|
-  // is false, the page predicts the query the user means to type and fetches
-  // results for the prediction. If |verbatim| is true, |text| is taken as the
-  // exact query (no prediction is made). |selection_start| and |selection_end|
-  // mark the inline autocompleted portion (i.e., blue highlighted text). The
-  // omnibox caret (cursor) is at |selection_end|.
-  virtual void Update(const string16& text,
-                      size_t selection_start,
-                      size_t selection_end,
-                      bool verbatim);
-
-  // Tells the page that the user pressed Enter in the omnibox.
-  void Submit(const string16& text);
-
-  // Tells the page that the user clicked on it. Nothing is being cancelled; the
-  // poor choice of name merely reflects the IPC of the same (poor) name.
-  void Cancel(const string16& text);
-
-  // Tells the page the bounds of the omnibox dropdown (in screen coordinates).
-  // This is used by the page to offset the results to avoid them being covered
-  // by the omnibox dropdown.
-  void SetPopupBounds(const gfx::Rect& bounds);
-
-  // Tells the page the bounds of the omnibox (in screen coordinates). This is
-  // used by the page to align text or assets properly with the omnibox.
-  void SetOmniboxBounds(const gfx::Rect& bounds);
-
-  // Tells the page about the font information.
   void InitializeFonts();
 
-  // Tells the renderer to determine if the page supports the Instant API, which
-  // results in a call to InstantSupportDetermined() when the reply is received.
-  void DetermineIfPageSupportsInstant();
-
-  // Tells the page about the available autocomplete results.
-  void SendAutocompleteResults(
-      const std::vector<InstantAutocompleteResult>& results);
-
-  // Tells the page that the user pressed Up or Down in the omnibox. |count| is
-  // a repeat count, negative for moving up, positive for moving down.
-  void UpOrDownKeyPressed(int count);
-
-  // Tells the page that the user pressed Esc key in the omnibox.
-  void EscKeyPressed();
-
-  // Tells the page that the user pressed Esc in the omnibox after having
-  // arrowed down in the suggestions. The page should reset the selection to
-  // the first suggestion. Arguments are the same as those for Update().
-  void CancelSelection(const string16& user_text,
-                       size_t selection_start,
-                       size_t selection_end,
-                       bool verbatim);
-
-  // Tells the page about the current theme background.
-  void SendThemeBackgroundInfo(const ThemeBackgroundInfo& theme_info);
-
-  // Tells the page whether it is allowed to display Instant results.
-  void SetDisplayInstantResults(bool display_instant_results);
-
-  // Tells the page that the omnibox focus has changed.
-  void FocusChanged(OmniboxFocusState state, OmniboxFocusChangeReason reason);
-
-  // Tells the page that user input started or stopped.
-  void SetInputInProgress(bool input_in_progress);
-
-  // Tells the page about new Most Visited data.
-  void SendMostVisitedItems(
-      const std::vector<InstantMostVisitedItem>& items);
-
-  // Tells the page to toggle voice search.
-  void ToggleVoiceSearch();
+  void InitializePromos();
 
  protected:
-  InstantPage(Delegate* delegate, const std::string& instant_url);
+  InstantPage(Delegate* delegate, const std::string& instant_url,
+              bool is_incognito);
 
-  // Sets |contents| as the page to communicate with. |contents| may be NULL,
-  // which effectively stops all communication.
-  void SetContents(content::WebContents* contents);
+  // Sets |web_contents| as the page to communicate with. |web_contents| may be
+  // NULL, which effectively stops all communication.
+  void SetContents(content::WebContents* web_contents);
 
   Delegate* delegate() const { return delegate_; }
 
@@ -214,11 +132,7 @@
   // page. By default, all messages are handled, but any derived classes may
   // choose to ignore some or all of the received messages by overriding these
   // methods.
-  virtual bool ShouldProcessRenderViewCreated();
-  virtual bool ShouldProcessRenderViewGone();
   virtual bool ShouldProcessAboutToNavigateMainFrame();
-  virtual bool ShouldProcessSetSuggestions();
-  virtual bool ShouldProcessShowInstantOverlay();
   virtual bool ShouldProcessFocusOmnibox();
   virtual bool ShouldProcessNavigateToURL();
   virtual bool ShouldProcessDeleteMostVisitedItem();
@@ -236,17 +150,11 @@
                            IgnoreMessageIfThePageIsNotActive);
   FRIEND_TEST_ALL_PREFIXES(InstantPageTest,
                            IgnoreMessageReceivedFromThePage);
+  FRIEND_TEST_ALL_PREFIXES(InstantPageTest,
+                           IgnoreMessageReceivedFromIncognitoPage);
 
   // Overridden from content::WebContentsObserver:
-  virtual void RenderViewCreated(
-      content::RenderViewHost* render_view_host) OVERRIDE;
-  virtual void DidFinishLoad(
-      int64 frame_id,
-      const GURL& validated_url,
-      bool is_main_frame,
-      content::RenderViewHost* render_view_host) OVERRIDE;
   virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
-  virtual void RenderViewGone(base::TerminationStatus status) OVERRIDE;
   virtual void DidCommitProvisionalLoadForFrame(
       int64 frame_id,
       bool is_main_frame,
@@ -264,12 +172,13 @@
       const string16& error_description,
       content::RenderViewHost* render_view_host) OVERRIDE;
 
-  void OnSetSuggestions(int page_id,
-                        const std::vector<InstantSuggestion>& suggestions);
-  void OnInstantSupportDetermined(int page_id, bool supports_instant);
-  void OnShowInstantOverlay(int page_id,
-                            int height,
-                            InstantSizeUnits units);
+  // Overridden from SearchModelObserver:
+  virtual void ModelChanged(const SearchModel::State& old_state,
+                            const SearchModel::State& new_state) OVERRIDE;
+
+  // Update the status of Instant support.
+  void InstantSupportDetermined(bool supports_instant);
+
   void OnFocusOmnibox(int page_id, OmniboxFocusState state);
   void OnSearchBoxNavigate(int page_id,
                            const GURL& url,
@@ -280,10 +189,12 @@
   void OnUndoMostVisitedDeletion(int page_id, const GURL& url);
   void OnUndoAllMostVisitedDeletions(int page_id);
 
+  void ClearContents();
+
   Delegate* const delegate_;
+  scoped_ptr<InstantIPCSender> ipc_sender_;
   const std::string instant_url_;
-  bool supports_instant_;
-  bool instant_support_determined_;
+  const bool is_incognito_;
 
   DISALLOW_COPY_AND_ASSIGN(InstantPage);
 };
diff --git a/chrome/browser/ui/search/instant_page_unittest.cc b/chrome/browser/ui/search/instant_page_unittest.cc
index c9830ee..a73ffc9 100644
--- a/chrome/browser/ui/search/instant_page_unittest.cc
+++ b/chrome/browser/ui/search/instant_page_unittest.cc
@@ -4,7 +4,10 @@
 
 #include "chrome/browser/ui/search/instant_page.h"
 
+#include "base/command_line.h"
 #include "base/memory/scoped_ptr.h"
+#include "chrome/browser/ui/search/search_tab_helper.h"
+#include "chrome/common/chrome_switches.h"
 #include "chrome/common/render_messages.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
@@ -34,14 +37,6 @@
   MOCK_METHOD2(InstantPageAboutToNavigateMainFrame,
                void(const content::WebContents* contents,
                     const GURL& url));
-  MOCK_METHOD2(SetSuggestions,
-               void(const content::WebContents* contents,
-                    const std::vector<InstantSuggestion>& suggestions));
-  MOCK_METHOD3(ShowInstantOverlay,
-               void(const content::WebContents* contents,
-                    int height,
-                    InstantSizeUnits units));
-  MOCK_METHOD0(LogDropdownShown, void());
   MOCK_METHOD2(FocusOmnibox,
                void(const content::WebContents* contents,
                     OmniboxFocusState state));
@@ -59,7 +54,8 @@
 
 class FakePage : public InstantPage {
  public:
-  FakePage(Delegate* delegate, const std::string& instant_url);
+  FakePage(Delegate* delegate, const std::string& instant_url,
+           bool is_incognito);
   virtual ~FakePage();
 
   // InstantPage overrride.
@@ -78,8 +74,9 @@
   DISALLOW_COPY_AND_ASSIGN(FakePage);
 };
 
-FakePage::FakePage(Delegate* delegate, const std::string& instant_url)
-    : InstantPage(delegate, instant_url),
+FakePage::FakePage(Delegate* delegate, const std::string& instant_url,
+                   bool is_incognito)
+    : InstantPage(delegate, instant_url, is_incognito),
       should_handle_messages_(true) {
 }
 
@@ -106,12 +103,26 @@
 
 class InstantPageTest : public ChromeRenderViewHostTestHarness {
  public:
+  virtual void SetUp() OVERRIDE;
+
+  bool MessageWasSent(uint32 id) {
+    return process()->sink().GetFirstMessageMatching(id) != NULL;
+  }
+
   scoped_ptr<FakePage> page;
   FakePageDelegate delegate;
 };
 
+void InstantPageTest::SetUp() {
+  CommandLine::ForCurrentProcess()->AppendSwitch(
+      switches::kEnableInstantExtendedAPI);
+  ChromeRenderViewHostTestHarness::SetUp();
+  SearchTabHelper::CreateForWebContents(web_contents());
+}
+
 TEST_F(InstantPageTest, IsLocal) {
-  page.reset(new FakePage(&delegate, ""));
+  page.reset(new FakePage(&delegate, "", false));
+  EXPECT_FALSE(page->supports_instant());
   EXPECT_FALSE(page->IsLocal());
   page->SetContents(web_contents());
   NavigateAndCommit(GURL(chrome::kChromeSearchLocalNtpUrl));
@@ -123,25 +134,27 @@
 }
 
 TEST_F(InstantPageTest, DetermineIfPageSupportsInstant_Local) {
-  page.reset(new FakePage(&delegate, ""));
+  page.reset(new FakePage(&delegate, "", false));
   EXPECT_FALSE(page->supports_instant());
   page->SetContents(web_contents());
   NavigateAndCommit(GURL(chrome::kChromeSearchLocalNtpUrl));
   EXPECT_TRUE(page->IsLocal());
   EXPECT_CALL(delegate, InstantSupportDetermined(web_contents(), true))
       .Times(1);
-  page->DetermineIfPageSupportsInstant();
+  SearchTabHelper::FromWebContents(web_contents())->
+      DetermineIfPageSupportsInstant();
   EXPECT_TRUE(page->supports_instant());
 }
 
 TEST_F(InstantPageTest, DetermineIfPageSupportsInstant_NonLocal) {
-  page.reset(new FakePage(&delegate, ""));
+  page.reset(new FakePage(&delegate, "", false));
   EXPECT_FALSE(page->supports_instant());
   page->SetContents(web_contents());
-  NavigateAndCommit(GURL("http://example.com/"));
+  NavigateAndCommit(GURL("chrome-search://foo/bar"));
   EXPECT_FALSE(page->IsLocal());
   process()->sink().ClearMessages();
-  page->DetermineIfPageSupportsInstant();
+  SearchTabHelper::FromWebContents(web_contents())->
+      DetermineIfPageSupportsInstant();
   const IPC::Message* message = process()->sink().GetFirstMessageMatching(
       ChromeViewMsg_DetermineIfPageSupportsInstant::ID);
   ASSERT_TRUE(message != NULL);
@@ -149,7 +162,7 @@
 }
 
 TEST_F(InstantPageTest, DispatchRequestToDeleteMostVisitedItem) {
-  page.reset(new FakePage(&delegate, ""));
+  page.reset(new FakePage(&delegate, "", false));
   page->SetContents(web_contents());
   NavigateAndCommit(GURL(chrome::kChromeSearchLocalNtpUrl));
   GURL item_url("www.foo.com");
@@ -161,7 +174,7 @@
 }
 
 TEST_F(InstantPageTest, DispatchRequestToUndoMostVisitedDeletion) {
-  page.reset(new FakePage(&delegate, ""));
+  page.reset(new FakePage(&delegate, "", false));
   page->SetContents(web_contents());
   NavigateAndCommit(GURL(chrome::kChromeSearchLocalNtpUrl));
   GURL item_url("www.foo.com");
@@ -173,7 +186,7 @@
 }
 
 TEST_F(InstantPageTest, DispatchRequestToUndoAllMostVisitedDeletions) {
-  page.reset(new FakePage(&delegate, ""));
+  page.reset(new FakePage(&delegate, "", false));
   page->SetContents(web_contents());
   NavigateAndCommit(GURL(chrome::kChromeSearchLocalNtpUrl));
   int page_id = web_contents()->GetController().GetActiveEntry()->GetPageID();
@@ -183,8 +196,33 @@
           rvh()->GetRoutingID(), page_id)));
 }
 
+TEST_F(InstantPageTest, IgnoreMessageReceivedFromIncognitoPage) {
+  page.reset(new FakePage(&delegate, "", true));
+  page->SetContents(web_contents());
+  NavigateAndCommit(GURL(chrome::kChromeSearchLocalNtpUrl));
+  GURL item_url("www.foo.com");
+  int page_id = web_contents()->GetController().GetActiveEntry()->GetPageID();
+
+  EXPECT_CALL(delegate, DeleteMostVisitedItem(item_url)).Times(0);
+  EXPECT_FALSE(page->OnMessageReceived(
+      ChromeViewHostMsg_SearchBoxDeleteMostVisitedItem(rvh()->GetRoutingID(),
+                                                       page_id,
+                                                       item_url)));
+
+  EXPECT_CALL(delegate, UndoMostVisitedDeletion(item_url)).Times(0);
+  EXPECT_FALSE(page->OnMessageReceived(
+      ChromeViewHostMsg_SearchBoxUndoMostVisitedDeletion(rvh()->GetRoutingID(),
+                                                         page_id,
+                                                         item_url)));
+
+  EXPECT_CALL(delegate, UndoAllMostVisitedDeletions()).Times(0);
+  EXPECT_FALSE(page->OnMessageReceived(
+      ChromeViewHostMsg_SearchBoxUndoAllMostVisitedDeletions(
+          rvh()->GetRoutingID(), page_id)));
+}
+
 TEST_F(InstantPageTest, IgnoreMessageIfThePageIsNotActive) {
-  page.reset(new FakePage(&delegate, ""));
+  page.reset(new FakePage(&delegate, "", false));
   page->SetContents(web_contents());
   NavigateAndCommit(GURL(chrome::kChromeSearchLocalNtpUrl));
   GURL item_url("www.foo.com");
@@ -209,7 +247,7 @@
 }
 
 TEST_F(InstantPageTest, IgnoreMessageReceivedFromThePage) {
-  page.reset(new FakePage(&delegate, ""));
+  page.reset(new FakePage(&delegate, "", false));
   page->SetContents(web_contents());
 
   // Ignore the messages received from the page.
@@ -233,3 +271,88 @@
       ChromeViewHostMsg_SearchBoxUndoAllMostVisitedDeletions(
           rvh()->GetRoutingID(), page_id)));
 }
+
+TEST_F(InstantPageTest, PageURLDoesntBelongToInstantRenderer) {
+  page.reset(new FakePage(&delegate, "", false));
+  EXPECT_FALSE(page->supports_instant());
+  NavigateAndCommit(GURL(chrome::kChromeSearchLocalNtpUrl));
+  page->SetContents(web_contents());
+
+  // Navigate to a page URL that doesn't belong to Instant renderer.
+  // SearchTabHelper::DeterminerIfPageSupportsInstant() should return
+  // immediately without dispatching any message to the renderer.
+  NavigateAndCommit(GURL("http://www.example.com"));
+  EXPECT_FALSE(page->IsLocal());
+  process()->sink().ClearMessages();
+  EXPECT_CALL(delegate, InstantSupportDetermined(web_contents(), false))
+      .Times(1);
+
+  SearchTabHelper::FromWebContents(web_contents())->
+      DetermineIfPageSupportsInstant();
+  const IPC::Message* message = process()->sink().GetFirstMessageMatching(
+      ChromeViewMsg_DetermineIfPageSupportsInstant::ID);
+  ASSERT_TRUE(message == NULL);
+  EXPECT_FALSE(page->supports_instant());
+}
+
+// Test to verify that ChromeViewMsg_DetermineIfPageSupportsInstant message
+// reply handler updates the instant support state in InstantPage.
+TEST_F(InstantPageTest, PageSupportsInstant) {
+  page.reset(new FakePage(&delegate, "", false));
+  EXPECT_FALSE(page->supports_instant());
+  page->SetContents(web_contents());
+  NavigateAndCommit(GURL("chrome-search://foo/bar"));
+  process()->sink().ClearMessages();
+  SearchTabHelper::FromWebContents(web_contents())->
+      DetermineIfPageSupportsInstant();
+  const IPC::Message* message = process()->sink().GetFirstMessageMatching(
+      ChromeViewMsg_DetermineIfPageSupportsInstant::ID);
+  ASSERT_TRUE(message != NULL);
+  EXPECT_EQ(web_contents()->GetRoutingID(), message->routing_id());
+
+  EXPECT_CALL(delegate, InstantSupportDetermined(web_contents(), true))
+      .Times(1);
+
+  // Assume the page supports instant. Invoke the message reply handler to make
+  // sure the InstantPage is notified about the instant support state.
+  const content::NavigationEntry* entry =
+      web_contents()->GetController().GetActiveEntry();
+  EXPECT_TRUE(entry);
+  SearchTabHelper::FromWebContents(web_contents())->
+      OnInstantSupportDetermined(entry->GetPageID(), true);
+  EXPECT_TRUE(page->supports_instant());
+}
+
+TEST_F(InstantPageTest, AppropriateMessagesSentToIncognitoPages) {
+  page.reset(new FakePage(&delegate, "", true));
+  page->SetContents(web_contents());
+  NavigateAndCommit(GURL(chrome::kChromeSearchLocalNtpUrl));
+  process()->sink().ClearMessages();
+
+  // Incognito pages should get these messages.
+  page->sender()->Submit(string16());
+  EXPECT_TRUE(MessageWasSent(ChromeViewMsg_SearchBoxSubmit::ID));
+  page->sender()->SetOmniboxBounds(gfx::Rect());
+  EXPECT_TRUE(MessageWasSent(ChromeViewMsg_SearchBoxMarginChange::ID));
+
+  // Incognito pages should not get any others.
+  page->sender()->SetFontInformation(string16(), 0);
+  EXPECT_FALSE(MessageWasSent(ChromeViewMsg_SearchBoxFontInformation::ID));
+
+  page->sender()->SendThemeBackgroundInfo(ThemeBackgroundInfo());
+  EXPECT_FALSE(MessageWasSent(ChromeViewMsg_SearchBoxThemeChanged::ID));
+
+  page->sender()->FocusChanged(
+      OMNIBOX_FOCUS_NONE, OMNIBOX_FOCUS_CHANGE_EXPLICIT);
+  EXPECT_FALSE(MessageWasSent(ChromeViewMsg_SearchBoxFocusChanged::ID));
+
+  page->sender()->SetInputInProgress(false);
+  EXPECT_FALSE(MessageWasSent(ChromeViewMsg_SearchBoxSetInputInProgress::ID));
+
+  page->sender()->SendMostVisitedItems(std::vector<InstantMostVisitedItem>());
+  EXPECT_FALSE(MessageWasSent(
+      ChromeViewMsg_SearchBoxMostVisitedItemsChanged::ID));
+
+  page->sender()->ToggleVoiceSearch();
+  EXPECT_FALSE(MessageWasSent(ChromeViewMsg_SearchBoxToggleVoiceSearch::ID));
+}
diff --git a/chrome/browser/ui/search/instant_tab.cc b/chrome/browser/ui/search/instant_tab.cc
index e1c5b2a..fcda092 100644
--- a/chrome/browser/ui/search/instant_tab.cc
+++ b/chrome/browser/ui/search/instant_tab.cc
@@ -5,8 +5,9 @@
 #include "chrome/browser/ui/search/instant_tab.h"
 #include "content/public/browser/web_contents.h"
 
-InstantTab::InstantTab(InstantPage::Delegate* delegate)
-    : InstantPage(delegate, "") {
+InstantTab::InstantTab(InstantPage::Delegate* delegate,
+                       bool is_incognito)
+    : InstantPage(delegate, "", is_incognito) {
 }
 
 InstantTab::~InstantTab() {
@@ -14,18 +15,12 @@
 
 void InstantTab::Init(content::WebContents* contents) {
   SetContents(contents);
-  if (!contents->IsWaitingForResponse())
-    DetermineIfPageSupportsInstant();
 }
 
 bool InstantTab::ShouldProcessAboutToNavigateMainFrame() {
   return true;
 }
 
-bool InstantTab::ShouldProcessSetSuggestions() {
-  return true;
-}
-
 bool InstantTab::ShouldProcessFocusOmnibox() {
   return true;
 }
diff --git a/chrome/browser/ui/search/instant_tab.h b/chrome/browser/ui/search/instant_tab.h
index 6951c58..d1cdb67 100644
--- a/chrome/browser/ui/search/instant_tab.h
+++ b/chrome/browser/ui/search/instant_tab.h
@@ -13,7 +13,7 @@
 // that supports the Instant API.
 class InstantTab : public InstantPage {
  public:
-  explicit InstantTab(InstantPage::Delegate* delegate);
+  InstantTab(InstantPage::Delegate* delegate, bool is_incognito);
   virtual ~InstantTab();
 
   // Start observing |contents| for messages. Sends a message to determine if
@@ -23,7 +23,6 @@
  private:
   // Overridden from InstantPage:
   virtual bool ShouldProcessAboutToNavigateMainFrame() OVERRIDE;
-  virtual bool ShouldProcessSetSuggestions() OVERRIDE;
   virtual bool ShouldProcessFocusOmnibox() OVERRIDE;
   virtual bool ShouldProcessNavigateToURL() OVERRIDE;
   virtual bool ShouldProcessDeleteMostVisitedItem() OVERRIDE;
diff --git a/chrome/browser/ui/search/instant_test_utils.cc b/chrome/browser/ui/search/instant_test_utils.cc
index 29b460a..1ccbd03 100644
--- a/chrome/browser/ui/search/instant_test_utils.cc
+++ b/chrome/browser/ui/search/instant_test_utils.cc
@@ -6,12 +6,12 @@
 
 #include "base/command_line.h"
 #include "base/prefs/pref_service.h"
+#include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/search_engines/template_url_service.h"
 #include "chrome/browser/search_engines/template_url_service_factory.h"
 #include "chrome/browser/ui/omnibox/omnibox_view.h"
 #include "chrome/browser/ui/search/instant_ntp.h"
-#include "chrome/browser/ui/search/instant_overlay.h"
 #include "chrome/common/chrome_notification_types.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
@@ -31,32 +31,6 @@
 
 }  // namespace
 
-// InstantTestModelObserver --------------------------------------------------
-
-InstantTestModelObserver::InstantTestModelObserver(
-    InstantOverlayModel* model,
-    SearchMode::Type expected_mode_type)
-    : model_(model),
-      expected_mode_type_(expected_mode_type),
-      observed_mode_type_(static_cast<SearchMode::Type>(-1)) {
-  model_->AddObserver(this);
-}
-
-InstantTestModelObserver::~InstantTestModelObserver() {
-  model_->RemoveObserver(this);
-}
-
-SearchMode::Type InstantTestModelObserver::WaitForExpectedOverlayState() {
-  run_loop_.Run();
-  return observed_mode_type_;
-}
-
-void InstantTestModelObserver::OverlayStateChanged(
-    const InstantOverlayModel& model) {
-  observed_mode_type_ = model.mode().mode;
-  run_loop_.Quit();
-}
-
 // InstantTestBase -----------------------------------------------------------
 
 void InstantTestBase::SetupInstant(Browser* browser) {
@@ -78,9 +52,7 @@
   service->Add(template_url);  // Takes ownership of |template_url|.
   service->SetDefaultSearchProvider(template_url);
 
-  // TODO(shishir): Fix this ugly hack.
-  instant()->SetInstantEnabled(false, true);
-  instant()->SetInstantEnabled(true, false);
+  instant()->ReloadStaleNTP();
 }
 
 void InstantTestBase::SetInstantURL(const std::string& url) {
@@ -101,13 +73,6 @@
   instant_url_ = instant_url;
 }
 
-void InstantTestBase::KillInstantRenderView() {
-  base::KillProcess(
-      instant()->GetOverlayContents()->GetRenderProcessHost()->GetHandle(),
-      content::RESULT_CODE_KILLED,
-      false);
-}
-
 void InstantTestBase::FocusOmnibox() {
   // If the omnibox already has focus, just notify Instant.
   if (omnibox()->model()->has_focus()) {
@@ -118,33 +83,13 @@
   }
 }
 
-void InstantTestBase::FocusOmniboxAndWaitForInstantOverlaySupport() {
-  content::WindowedNotificationObserver observer(
-      chrome::NOTIFICATION_INSTANT_OVERLAY_SUPPORT_DETERMINED,
-      content::NotificationService::AllSources());
-  FocusOmnibox();
-  if (!instant()->overlay() ||
-      !instant()->overlay()->instant_support_determined()) {
-    observer.Wait();
-  }
-}
-
-void InstantTestBase::FocusOmniboxAndWaitForInstantOverlayAndNTPSupport() {
+void InstantTestBase::FocusOmniboxAndWaitForInstantNTPSupport() {
   content::WindowedNotificationObserver ntp_observer(
       chrome::NOTIFICATION_INSTANT_NTP_SUPPORT_DETERMINED,
       content::NotificationService::AllSources());
-  content::WindowedNotificationObserver overlay_observer(
-      chrome::NOTIFICATION_INSTANT_OVERLAY_SUPPORT_DETERMINED,
-      content::NotificationService::AllSources());
   FocusOmnibox();
-  if (!instant()->ntp() ||
-      !instant()->ntp()->instant_support_determined()) {
+  if (!instant()->ntp() || !instant()->ntp()->supports_instant())
     ntp_observer.Wait();
-  }
-  if (!instant()->overlay() ||
-      !instant()->overlay()->instant_support_determined()) {
-    overlay_observer.Wait();
-  }
 }
 
 void InstantTestBase::SetOmniboxText(const std::string& text) {
@@ -152,36 +97,6 @@
   omnibox()->SetUserText(UTF8ToUTF16(text));
 }
 
-bool InstantTestBase::SetOmniboxTextAndWaitForOverlayToShow(
-    const std::string& text) {
-  // The order of events may be:
-  //   { hide, show } or just { show } depending on the order things
-  // flow in from GWS and Chrome's response to hiding the infobar and/or
-  // bookmark bar.  Note, the GWS response is relevant because of the
-  // Instant "MANUAL_*" tests.
-  InstantTestModelObserver first_observer(
-      instant()->model(), SearchMode::MODE_DEFAULT);
-  SetOmniboxText(text);
-
-  SearchMode::Type observed = first_observer.WaitForExpectedOverlayState();
-  if (observed == SearchMode::MODE_DEFAULT) {
-    InstantTestModelObserver second_observer(
-        instant()->model(), SearchMode::MODE_SEARCH_SUGGESTIONS);
-    observed = second_observer.WaitForExpectedOverlayState();
-  }
-  EXPECT_EQ(SearchMode::MODE_SEARCH_SUGGESTIONS, observed);
-  return observed == SearchMode::MODE_SEARCH_SUGGESTIONS;
-}
-
-void InstantTestBase::SetOmniboxTextAndWaitForSuggestion(
-    const std::string& text) {
-  content::WindowedNotificationObserver observer(
-      chrome::NOTIFICATION_INSTANT_SET_SUGGESTION,
-      content::NotificationService::AllSources());
-  SetOmniboxText(text);
-  observer.Wait();
-}
-
 void InstantTestBase::PressEnterAndWaitForNavigation() {
   content::WindowedNotificationObserver nav_observer(
       content::NOTIFICATION_NAV_ENTRY_COMMITTED,
@@ -212,7 +127,7 @@
 }
 
 bool InstantTestBase::ExecuteScript(const std::string& script) {
-  return content::ExecuteScript(instant()->GetOverlayContents(), script);
+  return content::ExecuteScript(instant()->GetNTPContents(), script);
 }
 
 bool InstantTestBase::CheckVisibilityIs(content::WebContents* contents,
@@ -232,6 +147,10 @@
   return omnibox()->model()->has_temporary_text_;
 }
 
+std::string InstantTestBase::GetOmniboxText() {
+  return UTF16ToUTF8(omnibox()->GetText());
+}
+
 bool InstantTestBase::LoadImage(content::RenderViewHost* rvh,
                                 const std::string& image,
                                 bool* loaded) {
diff --git a/chrome/browser/ui/search/instant_test_utils.h b/chrome/browser/ui/search/instant_test_utils.h
index 647b8cd..5072443 100644
--- a/chrome/browser/ui/search/instant_test_utils.h
+++ b/chrome/browser/ui/search/instant_test_utils.h
@@ -16,11 +16,11 @@
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/omnibox/location_bar.h"
 #include "chrome/browser/ui/search/instant_controller.h"
-#include "chrome/browser/ui/search/instant_overlay_model_observer.h"
 #include "chrome/common/search_types.h"
 #include "googleurl/src/gurl.h"
 #include "net/test/spawned_test_server/spawned_test_server.h"
 
+class BrowserInstantController;
 class InstantController;
 class InstantModel;
 class OmniboxView;
@@ -29,28 +29,6 @@
 class WebContents;
 };
 
-class InstantTestModelObserver : public InstantOverlayModelObserver {
- public:
-  InstantTestModelObserver(InstantOverlayModel* model,
-                           SearchMode::Type expected_mode_type);
-  virtual ~InstantTestModelObserver();
-
-  // Returns the observed mode type, may be different than the
-  // |expected_mode_type_| that was observed in OverlayStateChanged.
-  SearchMode::Type WaitForExpectedOverlayState();
-
-  // Overridden from InstantOverlayModelObserver:
-  virtual void OverlayStateChanged(const InstantOverlayModel& model) OVERRIDE;
-
- private:
-  InstantOverlayModel* const model_;
-  const SearchMode::Type expected_mode_type_;
-  SearchMode::Type observed_mode_type_;
-  base::RunLoop run_loop_;
-
-  DISALLOW_COPY_AND_ASSIGN(InstantTestModelObserver);
-};
-
 // This utility class is meant to be used in a "mix-in" fashion, giving the
 // derived test class additional Instant-related functionality.
 class InstantTestBase {
@@ -73,6 +51,10 @@
     browser_ = browser;
   }
 
+  BrowserInstantController* browser_instant() {
+    return browser_->instant_controller();
+  }
+
   InstantController* instant() {
     return browser_->instant_controller()->instant();
   }
@@ -88,12 +70,9 @@
   void KillInstantRenderView();
 
   void FocusOmnibox();
-  void FocusOmniboxAndWaitForInstantOverlaySupport();
-  void FocusOmniboxAndWaitForInstantOverlayAndNTPSupport();
+  void FocusOmniboxAndWaitForInstantNTPSupport();
 
   void SetOmniboxText(const std::string& text);
-  bool SetOmniboxTextAndWaitForOverlayToShow(const std::string& text);
-  void SetOmniboxTextAndWaitForSuggestion(const std::string& text);
 
   void PressEnterAndWaitForNavigation();
 
@@ -112,6 +91,8 @@
   bool HasUserInputInProgress();
   bool HasTemporaryText();
 
+  std::string GetOmniboxText();
+
   // Loads a named image from url |image| from the given |rvh| host.  |loaded|
   // returns whether the image was able to load without error.
   // The method returns true if the JavaScript executed cleanly.
diff --git a/chrome/browser/ui/search/local_ntp_browsertest.cc b/chrome/browser/ui/search/local_ntp_browsertest.cc
index 8c2b63a..84decce 100644
--- a/chrome/browser/ui/search/local_ntp_browsertest.cc
+++ b/chrome/browser/ui/search/local_ntp_browsertest.cc
@@ -2,12 +2,18 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/prefs/pref_service.h"
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/browser_process.h"
 #include "chrome/browser/search/search.h"
 #include "chrome/browser/ui/search/instant_test_utils.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/common/url_constants.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "content/public/browser/web_contents.h"
+#include "ui/base/resource/resource_bundle.h"
 
 class LocalNTPTest : public InProcessBrowserTest,
                      public InstantTestBase {
@@ -26,7 +32,7 @@
 
 IN_PROC_BROWSER_TEST_F(LocalNTPTest, LocalNTPJavascriptTest) {
   ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
-  FocusOmniboxAndWaitForInstantOverlayAndNTPSupport();
+  FocusOmniboxAndWaitForInstantNTPSupport();
 
   ui_test_utils::NavigateToURLWithDisposition(
       browser(),
@@ -36,8 +42,46 @@
       ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
   content::WebContents* active_tab =
       browser()->tab_strip_model()->GetActiveWebContents();
-  ASSERT_TRUE(chrome::IsInstantNTP(active_tab));
+  EXPECT_TRUE(chrome::ShouldAssignURLToInstantRenderer(active_tab->GetURL(),
+                                                       browser()->profile()));
   bool success = false;
   ASSERT_TRUE(GetBoolFromJS(active_tab, "!!runTests()", &success));
   EXPECT_TRUE(success);
 }
+
+// Flaky on Linux Tests bot.
+#if defined(OS_LINUX)
+#define MAYBE_NTPRespectsBrowserLanguageSetting DISABLED_NTPRespectsBrowserLanguageSetting
+#else
+#define MAYBE_NTPRespectsBrowserLanguageSetting NTPRespectsBrowserLanguageSetting
+#endif
+IN_PROC_BROWSER_TEST_F(LocalNTPTest, MAYBE_NTPRespectsBrowserLanguageSetting) {
+  // Make sure the default language is not French.
+  std::string default_locale = g_browser_process->GetApplicationLocale();
+  EXPECT_NE("fr", default_locale);
+
+  // Switch browser language to French.
+  std::string loaded_locale =
+      ui::ResourceBundle::GetSharedInstance().ReloadLocaleResources("fr");
+  EXPECT_EQ("fr", loaded_locale);
+  g_browser_process->SetApplicationLocale(loaded_locale);
+  PrefService* prefs = g_browser_process->local_state();
+  prefs->SetString(prefs::kApplicationLocale, loaded_locale);
+
+  // Setup Instant.
+  ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
+  FocusOmniboxAndWaitForInstantNTPSupport();
+
+  // Open a new tab.
+  ui_test_utils::NavigateToURLWithDisposition(
+      browser(),
+      GURL(chrome::kChromeUINewTabURL),
+      NEW_FOREGROUND_TAB,
+      ui_test_utils::BROWSER_TEST_WAIT_FOR_TAB |
+      ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
+
+  // Verify that the NTP is in French.
+  content::WebContents* active_tab =
+      browser()->tab_strip_model()->GetActiveWebContents();
+  EXPECT_EQ(ASCIIToUTF16("Nouvel onglet"), active_tab->GetTitle());
+}
diff --git a/chrome/browser/ui/search/search_model.cc b/chrome/browser/ui/search/search_model.cc
index 53d0fcc..840fbfa 100644
--- a/chrome/browser/ui/search/search_model.cc
+++ b/chrome/browser/ui/search/search_model.cc
@@ -7,6 +7,28 @@
 #include "chrome/browser/search/search.h"
 #include "chrome/browser/ui/search/search_model_observer.h"
 
+SearchModel::State::State()
+    : top_bars_visible(true),
+      instant_support(INSTANT_SUPPORT_UNKNOWN),
+      voice_search_supported(false) {
+}
+
+SearchModel::State::State(const SearchMode& mode,
+                          bool top_bars_visible,
+                          InstantSupportState instant_support,
+                          bool voice_search_supported)
+    : mode(mode),
+      top_bars_visible(top_bars_visible),
+      instant_support(instant_support),
+      voice_search_supported(voice_search_supported) {
+}
+
+bool SearchModel::State::operator==(const State& rhs) const {
+  return mode == rhs.mode && top_bars_visible == rhs.top_bars_visible &&
+      instant_support == rhs.instant_support &&
+      voice_search_supported == rhs.voice_search_supported;
+}
+
 SearchModel::SearchModel() {
 }
 
@@ -64,7 +86,7 @@
 
 void SearchModel::SetTopBarsVisible(bool visible) {
   DCHECK(chrome::IsInstantExtendedAPIEnabled())
-      << "Please do not try to set the SearchModel mode without first "
+      << "Please do not try to set the SearchModel state without first "
       << "checking if Search is enabled.";
 
   if (state_.top_bars_visible == visible)
@@ -77,6 +99,35 @@
                     ModelChanged(old_state, state_));
 }
 
+void SearchModel::SetInstantSupportState(InstantSupportState instant_support) {
+  DCHECK(chrome::IsInstantExtendedAPIEnabled())
+      << "Please do not try to set the SearchModel state without first "
+      << "checking if Search is enabled.";
+
+  if (state_.instant_support == instant_support)
+    return;
+
+  const State old_state = state_;
+  state_.instant_support = instant_support;
+  FOR_EACH_OBSERVER(SearchModelObserver, observers_,
+                    ModelChanged(old_state, state_));
+}
+
+void SearchModel::SetVoiceSearchSupported(bool supported) {
+  DCHECK(chrome::IsInstantExtendedAPIEnabled())
+      << "Please do not try to set the SearchModel state without first "
+      << "checking if Search is enabled.";
+
+  if (state_.voice_search_supported == supported)
+    return;
+
+  const State old_state = state_;
+  state_.voice_search_supported = supported;
+
+  FOR_EACH_OBSERVER(SearchModelObserver, observers_,
+                    ModelChanged(old_state, state_));
+}
+
 void SearchModel::AddObserver(SearchModelObserver* observer) {
   observers_.AddObserver(observer);
 }
diff --git a/chrome/browser/ui/search/search_model.h b/chrome/browser/ui/search/search_model.h
index 3f77b87..b9a62fb 100644
--- a/chrome/browser/ui/search/search_model.h
+++ b/chrome/browser/ui/search/search_model.h
@@ -11,25 +11,37 @@
 
 class SearchModelObserver;
 
+// Represents whether a page supports Instant.
+enum InstantSupportState {
+  INSTANT_SUPPORT_NO,
+  INSTANT_SUPPORT_YES,
+  INSTANT_SUPPORT_UNKNOWN,
+};
+
 // An observable model for UI components that care about search model state
 // changes.
 class SearchModel {
  public:
   struct State {
-    State() : top_bars_visible(true) {}
-    State(const SearchMode& mode, bool top_bars_visible)
-        : mode(mode),
-          top_bars_visible(top_bars_visible) {}
+    State();
+    State(const SearchMode& mode,
+          bool top_bars_visible,
+          InstantSupportState instant_support,
+          bool voice_search_supported);
 
-    bool operator==(const State& rhs) const {
-      return mode == rhs.mode && top_bars_visible == rhs.top_bars_visible;
-    }
+    bool operator==(const State& rhs) const;
 
     // The display mode of UI elements such as the toolbar, the tab strip, etc.
     SearchMode mode;
 
     // The visibility of top bars such as bookmark and info bars.
     bool top_bars_visible;
+
+    // Does the current page support Instant?
+    InstantSupportState instant_support;
+
+    // Does the current page support voice search?
+    bool voice_search_supported;
   };
 
   SearchModel();
@@ -58,6 +70,22 @@
   // Get the visibility of top bars.
   bool top_bars_visible() const { return state_.top_bars_visible; }
 
+  // Sets the page instant support state. Change notifications are sent to
+  // observers.
+  void SetInstantSupportState(InstantSupportState instant_support);
+
+  // Gets the instant support state of the page.
+  InstantSupportState instant_support() const {
+    return state_.instant_support;
+  }
+
+  // Sets the page voice search support state.  Change notifications are sent to
+  // observers.
+  void SetVoiceSearchSupported(bool supported);
+
+  // Gets the voice search support state of the page.
+  bool voice_search_supported() const { return state_.voice_search_supported; }
+
   // Add and remove observers.
   void AddObserver(SearchModelObserver* observer);
   void RemoveObserver(SearchModelObserver* observer);
diff --git a/chrome/browser/ui/search/search_model_unittest.cc b/chrome/browser/ui/search/search_model_unittest.cc
new file mode 100644
index 0000000..762256b
--- /dev/null
+++ b/chrome/browser/ui/search/search_model_unittest.cc
@@ -0,0 +1,174 @@
+// 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/ui/search/search_model.h"
+
+#include "base/command_line.h"
+#include "chrome/browser/ui/search/search_model_observer.h"
+#include "chrome/browser/ui/search/search_tab_helper.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/search_types.h"
+#include "chrome/test/base/chrome_render_view_host_test_harness.h"
+
+namespace {
+
+class MockSearchModelObserver : public SearchModelObserver {
+ public:
+  MockSearchModelObserver();
+  virtual ~MockSearchModelObserver();
+
+  virtual void ModelChanged(const SearchModel::State& old_state,
+                            const SearchModel::State& new_state) OVERRIDE;
+
+  void VerifySearchModelStates(const SearchModel::State& expected_old_state,
+                               const SearchModel::State& expected_new_state);
+
+  void VerifyNotificationCount(int expected_count);
+
+ private:
+  // How many times we've seen search model changed notifications.
+  int modelchanged_notification_count_;
+
+  SearchModel::State actual_old_state_;
+  SearchModel::State actual_new_state_;
+
+  DISALLOW_COPY_AND_ASSIGN(MockSearchModelObserver);
+};
+
+MockSearchModelObserver::MockSearchModelObserver()
+    : modelchanged_notification_count_(0) {
+}
+
+MockSearchModelObserver::~MockSearchModelObserver() {
+}
+
+void MockSearchModelObserver::ModelChanged(
+    const SearchModel::State& old_state,
+    const SearchModel::State& new_state) {
+  actual_old_state_ = old_state;
+  actual_new_state_ = new_state;
+  modelchanged_notification_count_++;
+}
+
+void MockSearchModelObserver::VerifySearchModelStates(
+    const SearchModel::State& expected_old_state,
+    const SearchModel::State& expected_new_state) {
+  EXPECT_TRUE(actual_old_state_ == expected_old_state);
+  EXPECT_TRUE(actual_new_state_ == expected_new_state);
+}
+
+void MockSearchModelObserver::VerifyNotificationCount(int expected_count) {
+  EXPECT_EQ(modelchanged_notification_count_, expected_count);
+}
+
+}  // namespace
+
+class SearchModelTest : public ChromeRenderViewHostTestHarness {
+ public:
+  virtual void SetUp() OVERRIDE;
+  virtual void TearDown() OVERRIDE;
+
+  MockSearchModelObserver mock_observer;
+  SearchModel* model;
+};
+
+void SearchModelTest::SetUp() {
+  CommandLine::ForCurrentProcess()->AppendSwitch(
+      switches::kEnableInstantExtendedAPI);
+  ChromeRenderViewHostTestHarness::SetUp();
+  SearchTabHelper::CreateForWebContents(web_contents());
+  SearchTabHelper* search_tab_helper =
+      SearchTabHelper::FromWebContents(web_contents());
+  ASSERT_TRUE(search_tab_helper != NULL);
+  model = search_tab_helper->model();
+  model->AddObserver(&mock_observer);
+}
+
+void SearchModelTest::TearDown() {
+  model->RemoveObserver(&mock_observer);
+  ChromeRenderViewHostTestHarness::TearDown();
+}
+
+TEST_F(SearchModelTest, UpdateSearchModelInstantSupport) {
+  mock_observer.VerifyNotificationCount(0);
+  EXPECT_TRUE(model->instant_support() == INSTANT_SUPPORT_UNKNOWN);
+  SearchModel::State expected_old_state = model->state();
+  SearchModel::State expected_new_state(model->state());
+  expected_new_state.instant_support = INSTANT_SUPPORT_YES;
+
+  model->SetInstantSupportState(INSTANT_SUPPORT_YES);
+  mock_observer.VerifySearchModelStates(expected_old_state, expected_new_state);
+  mock_observer.VerifyNotificationCount(1);
+  EXPECT_TRUE(model->instant_support() == INSTANT_SUPPORT_YES);
+
+  expected_old_state = expected_new_state;
+  expected_new_state.instant_support = INSTANT_SUPPORT_NO;
+  model->SetInstantSupportState(INSTANT_SUPPORT_NO);
+  mock_observer.VerifySearchModelStates(expected_old_state, expected_new_state);
+  mock_observer.VerifyNotificationCount(2);
+
+  // Notify the observer only if the search model state is changed.
+  model->SetInstantSupportState(INSTANT_SUPPORT_NO);
+  EXPECT_TRUE(model->state() == expected_new_state);
+  EXPECT_TRUE(model->instant_support() == INSTANT_SUPPORT_NO);
+  mock_observer.VerifyNotificationCount(2);
+}
+
+TEST_F(SearchModelTest, UpdateSearchModelMode) {
+  mock_observer.VerifyNotificationCount(0);
+  SearchMode search_mode(SearchMode::MODE_NTP, SearchMode::ORIGIN_NTP);
+  SearchModel::State expected_old_state = model->state();
+  SearchModel::State expected_new_state(model->state());
+  expected_new_state.mode = search_mode;
+
+  model->SetMode(search_mode);
+  mock_observer.VerifySearchModelStates(expected_old_state, expected_new_state);
+  mock_observer.VerifyNotificationCount(1);
+
+  search_mode.mode = SearchMode::MODE_SEARCH_RESULTS;
+  expected_old_state = expected_new_state;
+  expected_new_state.mode = search_mode;
+  model->SetMode(search_mode);
+  mock_observer.VerifySearchModelStates(expected_old_state, expected_new_state);
+  mock_observer.VerifyNotificationCount(2);
+  EXPECT_TRUE(model->state() == expected_new_state);
+}
+
+TEST_F(SearchModelTest, UpdateTopBarVisibility) {
+  mock_observer.VerifyNotificationCount(0);
+  EXPECT_TRUE(model->top_bars_visible());
+
+  SearchModel::State expected_old_state = model->state();
+  SearchModel::State expected_new_state(model->state());
+  expected_new_state.top_bars_visible = false;
+
+  model->SetTopBarsVisible(false);
+  mock_observer.VerifySearchModelStates(expected_old_state, expected_new_state);
+  mock_observer.VerifyNotificationCount(1);
+  EXPECT_FALSE(model->top_bars_visible());
+}
+
+TEST_F(SearchModelTest, UpdateSearchModelState) {
+  SearchModel::State expected_new_state(model->state());
+  expected_new_state.top_bars_visible = false;
+  expected_new_state.instant_support = INSTANT_SUPPORT_NO;
+  EXPECT_FALSE(model->state() == expected_new_state);
+  model->SetState(expected_new_state);
+  mock_observer.VerifyNotificationCount(1);
+  EXPECT_TRUE(model->state() == expected_new_state);
+}
+
+TEST_F(SearchModelTest, UpdateVoiceSearchSupported) {
+  mock_observer.VerifyNotificationCount(0);
+  EXPECT_FALSE(model->voice_search_supported());
+
+  SearchModel::State expected_old_state = model->state();
+  SearchModel::State expected_new_state(model->state());
+  expected_new_state.voice_search_supported = true;
+
+  model->SetVoiceSearchSupported(true);
+  mock_observer.VerifySearchModelStates(expected_old_state, expected_new_state);
+  mock_observer.VerifyNotificationCount(1);
+  EXPECT_TRUE(model->voice_search_supported());
+}
diff --git a/chrome/browser/ui/search/search_tab_helper.cc b/chrome/browser/ui/search/search_tab_helper.cc
index 4cbbd8a..881b22e 100644
--- a/chrome/browser/ui/search/search_tab_helper.cc
+++ b/chrome/browser/ui/search/search_tab_helper.cc
@@ -4,12 +4,18 @@
 
 #include "chrome/browser/ui/search/search_tab_helper.h"
 
+#include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/search/search.h"
 #include "chrome/common/render_messages.h"
 #include "chrome/common/url_constants.h"
+#include "content/public/browser/navigation_controller.h"
+#include "content/public/browser/navigation_details.h"
 #include "content/public/browser/navigation_entry.h"
+#include "content/public/browser/navigation_type.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/notification_types.h"
+#include "grit/generated_resources.h"
+#include "ui/base/l10n/l10n_util.h"
 
 DEFINE_WEB_CONTENTS_USER_DATA_KEY(SearchTabHelper);
 
@@ -30,6 +36,14 @@
   return !chrome::GetSearchTerms(contents).empty();
 }
 
+// TODO(kmadhusu): Move this helper from anonymous namespace to chrome
+// namespace and remove InstantPage::IsLocal().
+bool IsLocal(const content::WebContents* contents) {
+  return contents &&
+      (contents->GetURL() == GURL(chrome::kChromeSearchLocalNtpUrl) ||
+       contents->GetURL() == GURL(chrome::kChromeSearchLocalGoogleNtpUrl));
+}
+
 }  // namespace
 
 SearchTabHelper::SearchTabHelper(content::WebContents* web_contents)
@@ -42,6 +56,9 @@
   if (!is_search_enabled_)
     return;
 
+  // Observe NOTIFICATION_NAV_ENTRY_COMMITTED events so we can reset state
+  // associated with the WebContents  (such as mode, last known most visited
+  // items, instant support state etc).
   registrar_.Add(
       this,
       content::NOTIFICATION_NAV_ENTRY_COMMITTED,
@@ -52,6 +69,10 @@
 SearchTabHelper::~SearchTabHelper() {
 }
 
+void SearchTabHelper::InitForPreloadedNTP() {
+  UpdateMode(true, true);
+}
+
 void SearchTabHelper::OmniboxEditModelChanged(bool user_input_in_progress,
                                               bool cancelling,
                                               bool popup_is_open,
@@ -65,23 +86,26 @@
   if (!user_input_in_progress && !cancelling)
     return;
 
-  UpdateMode();
+  UpdateMode(false, false);
 }
 
 void SearchTabHelper::NavigationEntryUpdated() {
   if (!is_search_enabled_)
     return;
 
-  UpdateMode();
+  UpdateMode(false, false);
 }
 
-bool SearchTabHelper::UpdateLastKnownMostVisitedItems(
-    const std::vector<InstantMostVisitedItem>& items) {
-  if (chrome::AreMostVisitedItemsEqual(items, last_known_most_visited_items_))
-    return false;
+void SearchTabHelper::InstantSupportChanged(bool instant_support) {
+  if (!is_search_enabled_)
+    return;
 
-  last_known_most_visited_items_ = items;
-  return true;
+  model_.SetInstantSupportState(instant_support ? INSTANT_SUPPORT_YES :
+                                                  INSTANT_SUPPORT_NO);
+}
+
+bool SearchTabHelper::SupportsInstant() const {
+  return model_.instant_support() == INSTANT_SUPPORT_YES;
 }
 
 void SearchTabHelper::Observe(
@@ -89,8 +113,52 @@
     const content::NotificationSource& source,
     const content::NotificationDetails& details) {
   DCHECK_EQ(content::NOTIFICATION_NAV_ENTRY_COMMITTED, type);
-  UpdateMode();
-  last_known_most_visited_items_.clear();
+  content::LoadCommittedDetails* load_details =
+      content::Details<content::LoadCommittedDetails>(details).ptr();
+  if (!load_details->is_main_frame)
+    return;
+
+  UpdateMode(true, false);
+
+  // Already determined the instant support state for this page, do not reset
+  // the instant support state.
+  //
+  // When we get a navigation entry committed event, there seem to be two ways
+  // to tell whether the navigation was "in-page". Ideally, when
+  // LoadCommittedDetails::is_in_page is true, we should have
+  // LoadCommittedDetails::type to be NAVIGATION_TYPE_IN_PAGE. Unfortunately,
+  // they are different in some cases. To workaround this bug, we are checking
+  // (is_in_page || type == NAVIGATION_TYPE_IN_PAGE). Please refer to
+  // crbug.com/251330 for more details.
+  if (load_details->is_in_page ||
+      load_details->type == content::NAVIGATION_TYPE_IN_PAGE) {
+    return;
+  }
+
+  model_.SetInstantSupportState(INSTANT_SUPPORT_UNKNOWN);
+  model_.SetVoiceSearchSupported(false);
+}
+
+void SearchTabHelper::DidNavigateMainFrame(
+    const content::LoadCommittedDetails& details,
+    const content::FrameNavigateParams& params) {
+  // Always set the title on the new tab page to be the one from our UI
+  // resources.  Normally, we set the title when we begin a NTP load, but it
+  // can get reset in several places (like when you press Reload). This check
+  // ensures that the title is properly set to the string defined by the Chrome
+  // UI language (rather than the server language) in all cases.
+  //
+  // We only override the title when it's nonempty to allow the page to set the
+  // title if it really wants. An empty title means to use the default. There's
+  // also a race condition between this code and the page's SetTitle call which
+  // this rule avoids.
+  content::NavigationEntry* entry =
+      web_contents_->GetController().GetActiveEntry();
+  if (entry && entry->GetTitle().empty() &&
+      (entry->GetVirtualURL() == GURL(chrome::kChromeUINewTabURL) ||
+       chrome::NavEntryIsInstantNTP(web_contents_, entry))) {
+    entry->SetTitle(l10n_util::GetStringUTF16(IDS_NEW_TAB_TITLE));
+  }
 }
 
 bool SearchTabHelper::OnMessageReceived(const IPC::Message& message) {
@@ -100,21 +168,36 @@
                         OnSearchBoxShowBars)
     IPC_MESSAGE_HANDLER(ChromeViewHostMsg_SearchBoxHideBars,
                         OnSearchBoxHideBars)
+    IPC_MESSAGE_HANDLER(ChromeViewHostMsg_InstantSupportDetermined,
+                        OnInstantSupportDetermined)
+    IPC_MESSAGE_HANDLER(ChromeViewHostMsg_SetVoiceSearchSupported,
+                        OnSetVoiceSearchSupported)
     IPC_MESSAGE_UNHANDLED(handled = false)
   IPC_END_MESSAGE_MAP()
   return handled;
 }
 
-void SearchTabHelper::UpdateMode() {
+void SearchTabHelper::DidFinishLoad(
+    int64 /* frame_id */,
+    const GURL&  /* validated_url */,
+    bool is_main_frame,
+    content::RenderViewHost* /* render_view_host */) {
+  if (is_main_frame)
+    DetermineIfPageSupportsInstant();
+}
+
+void SearchTabHelper::UpdateMode(bool update_origin, bool is_preloaded_ntp) {
   SearchMode::Type type = SearchMode::MODE_DEFAULT;
   SearchMode::Origin origin = SearchMode::ORIGIN_DEFAULT;
-  if (IsNTP(web_contents_)) {
+  if (IsNTP(web_contents_) || is_preloaded_ntp) {
     type = SearchMode::MODE_NTP;
     origin = SearchMode::ORIGIN_NTP;
   } else if (IsSearchResults(web_contents_)) {
     type = SearchMode::MODE_SEARCH_RESULTS;
     origin = SearchMode::ORIGIN_SEARCH;
   }
+  if (!update_origin)
+    origin = model_.mode().origin;
   if (user_input_in_progress_)
     type = SearchMode::MODE_SEARCH_SUGGESTIONS;
 
@@ -122,17 +205,45 @@
       !popup_is_open_ && !user_text_is_empty_) {
     // We're switching back (|popup_is_open_| is false) to an NTP (type and
     // mode are |NTP|) with suggestions (|user_text_is_empty_| is false), don't
-    // modify visibility of top bars.  This specific omnibox state is set when
-    // OmniboxEditModelChanged() is called from
+    // modify visibility of top bars or voice search support.  This specific
+    // omnibox state is set when OmniboxEditModelChanged() is called from
     // OmniboxEditModel::SetInputInProgress() which is called from
     // OmniboxEditModel::Revert().
     model_.SetState(SearchModel::State(SearchMode(type, origin),
-                                       model_.state().top_bars_visible));
+                                       model_.state().top_bars_visible,
+                                       model_.instant_support(),
+                                       model_.state().voice_search_supported));
   } else {
     model_.SetMode(SearchMode(type, origin));
   }
 }
 
+void SearchTabHelper::DetermineIfPageSupportsInstant() {
+  Profile* profile =
+      Profile::FromBrowserContext(web_contents_->GetBrowserContext());
+  if (!chrome::ShouldAssignURLToInstantRenderer(web_contents_->GetURL(),
+                                                profile)) {
+    // The page is not in the Instant process. This page does not support
+    // instant. If we send an IPC message to a page that is not in the Instant
+    // process, it will never receive it and will never respond. Therefore,
+    // return immediately.
+    InstantSupportChanged(false);
+  } else if (IsLocal(web_contents_)) {
+    // Local pages always support Instant.
+    InstantSupportChanged(true);
+  } else {
+    Send(new ChromeViewMsg_DetermineIfPageSupportsInstant(routing_id()));
+  }
+}
+
+void SearchTabHelper::OnInstantSupportDetermined(int page_id,
+                                                 bool instant_support) {
+  if (!web_contents()->IsActiveEntry(page_id))
+    return;
+
+  InstantSupportChanged(instant_support);
+}
+
 void SearchTabHelper::OnSearchBoxShowBars(int page_id) {
   if (web_contents()->IsActiveEntry(page_id))
     model_.SetTopBarsVisible(true);
@@ -144,3 +255,8 @@
     Send(new ChromeViewMsg_SearchBoxBarsHidden(routing_id()));
   }
 }
+
+void SearchTabHelper::OnSetVoiceSearchSupported(int page_id, bool supported) {
+  if (web_contents()->IsActiveEntry(page_id))
+    model_.SetVoiceSearchSupported(supported);
+}
diff --git a/chrome/browser/ui/search/search_tab_helper.h b/chrome/browser/ui/search/search_tab_helper.h
index 8dd7711..8d3ae48 100644
--- a/chrome/browser/ui/search/search_tab_helper.h
+++ b/chrome/browser/ui/search/search_tab_helper.h
@@ -5,12 +5,10 @@
 #ifndef CHROME_BROWSER_UI_SEARCH_SEARCH_TAB_HELPER_H_
 #define CHROME_BROWSER_UI_SEARCH_SEARCH_TAB_HELPER_H_
 
-#include <vector>
-
 #include "base/basictypes.h"
 #include "base/compiler_specific.h"
+#include "base/gtest_prod_util.h"
 #include "chrome/browser/ui/search/search_model.h"
-#include "chrome/common/instant_types.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
 #include "content/public/browser/web_contents_observer.h"
@@ -20,8 +18,15 @@
 class WebContents;
 }
 
+class InstantPageTest;
+
 // Per-tab search "helper".  Acts as the owner and controller of the tab's
 // search UI model.
+//
+// When the page is finished loading, SearchTabHelper determines the instant
+// support for the page. When a navigation entry is committed (except for
+// in-page navigations), SearchTabHelper resets the instant support state to
+// INSTANT_SUPPORT_UNKNOWN and cause support to be determined again.
 class SearchTabHelper : public content::NotificationObserver,
                         public content::WebContentsObserver,
                         public content::WebContentsUserData<SearchTabHelper> {
@@ -32,6 +37,13 @@
     return &model_;
   }
 
+  const SearchModel* model() const {
+    return &model_;
+  }
+
+  // Sets up the initial state correctly for a preloaded NTP.
+  void InitForPreloadedNTP();
+
   // Invoked when the OmniboxEditModel changes state in some way that might
   // affect the search mode.
   void OmniboxEditModelChanged(bool user_input_in_progress,
@@ -45,13 +57,23 @@
   // the notification system and shouldn't call this method.
   void NavigationEntryUpdated();
 
-  // Updates |last_known_most_visited_items_| with |items|.
-  // Returns false if |items| matches the |last_known_most_visited_items_|.
-  bool UpdateLastKnownMostVisitedItems(
-      const std::vector<InstantMostVisitedItem>& items);
+  // Invoked to update the instant support state.
+  void InstantSupportChanged(bool supports_instant);
+
+  // Returns true if the page supports instant. If the instant support state is
+  // not determined or if the page does not support instant returns false.
+  bool SupportsInstant() const;
 
  private:
   friend class content::WebContentsUserData<SearchTabHelper>;
+  friend class InstantPageTest;
+  FRIEND_TEST_ALL_PREFIXES(InstantPageTest,
+                           DetermineIfPageSupportsInstant_Local);
+  FRIEND_TEST_ALL_PREFIXES(InstantPageTest,
+                           DetermineIfPageSupportsInstant_NonLocal);
+  FRIEND_TEST_ALL_PREFIXES(InstantPageTest,
+                           PageURLDoesntBelongToInstantRenderer);
+  FRIEND_TEST_ALL_PREFIXES(InstantPageTest, PageSupportsInstant);
 
   explicit SearchTabHelper(content::WebContents* web_contents);
 
@@ -61,16 +83,39 @@
                        const content::NotificationDetails& details) OVERRIDE;
 
   // Overridden from contents::WebContentsObserver:
+  virtual void DidNavigateMainFrame(
+      const content::LoadCommittedDetails& details,
+      const content::FrameNavigateParams& params) OVERRIDE;
   virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
+  virtual void DidFinishLoad(
+      int64 frame_id,
+      const GURL& validated_url,
+      bool is_main_frame,
+      content::RenderViewHost* render_view_host) OVERRIDE;
 
   // Sets the mode of the model based on the current URL of web_contents().
-  void UpdateMode();
+  // Only updates the origin part of the mode if |update_origin| is true,
+  // otherwise keeps the current origin. If |is_preloaded_ntp| is true, the mode
+  // is set to NTP regardless of the current URL; this is used to ensure that
+  // InstantController can bind InstantTab to new tab pages immediately.
+  void UpdateMode(bool update_origin, bool is_preloaded_ntp);
+
+  // Tells the renderer to determine if the page supports the Instant API, which
+  // results in a call to OnInstantSupportDetermined() when the reply
+  // is received.
+  void DetermineIfPageSupportsInstant();
+
+  // Handler for when Instant support has been determined.
+  void OnInstantSupportDetermined(int page_id, bool supports_instant);
 
   // Handlers for SearchBox API to show and hide top bars (bookmark and info
   // bars).
   void OnSearchBoxShowBars(int page_id);
   void OnSearchBoxHideBars(int page_id);
 
+  // Sets whether the page supports voice search on the model.
+  void OnSetVoiceSearchSupported(int page_id, bool supported);
+
   const bool is_search_enabled_;
 
   // Tracks the last value passed to OmniboxEditModelChanged().
@@ -85,10 +130,6 @@
 
   content::WebContents* web_contents_;
 
-  // Tracks the last set of most visited items sent to the InstantPage renderer.
-  // Used to prevent sending duplicate IPC messages to the renderer.
-  std::vector<InstantMostVisitedItem> last_known_most_visited_items_;
-
   DISALLOW_COPY_AND_ASSIGN(SearchTabHelper);
 };
 
diff --git a/chrome/browser/ui/startup/startup_browser_creator.cc b/chrome/browser/ui/startup/startup_browser_creator.cc
index e64f900..f90004a 100644
--- a/chrome/browser/ui/startup/startup_browser_creator.cc
+++ b/chrome/browser/ui/startup/startup_browser_creator.cc
@@ -45,9 +45,7 @@
 #include "chrome/browser/printing/print_dialog_cloud.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
-#include "chrome/browser/search_engines/template_url.h"
-#include "chrome/browser/search_engines/template_url_service.h"
-#include "chrome/browser/search_engines/template_url_service_factory.h"
+#include "chrome/browser/search_engines/util.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/browser_window.h"
@@ -384,22 +382,17 @@
     const base::FilePath& cur_dir,
     Profile* profile) {
   std::vector<GURL> urls;
-  const CommandLine::StringVector& params = command_line.GetArgs();
 
+  const CommandLine::StringVector& params = command_line.GetArgs();
   for (size_t i = 0; i < params.size(); ++i) {
     base::FilePath param = base::FilePath(params[i]);
     // Handle Vista way of searching - "? <search-term>"
-    if (param.value().size() > 2 &&
-        param.value()[0] == '?' && param.value()[1] == ' ') {
-      const TemplateURL* default_provider =
-          TemplateURLServiceFactory::GetForProfile(profile)->
-          GetDefaultSearchProvider();
-      if (default_provider) {
-        const TemplateURLRef& search_url = default_provider->url_ref();
-        DCHECK(search_url.SupportsReplacement());
-        string16 search_term = param.LossyDisplayName().substr(2);
-        urls.push_back(GURL(search_url.ReplaceSearchTerms(
-            TemplateURLRef::SearchTermsArgs(search_term))));
+    if ((param.value().size() > 2) && (param.value()[0] == '?') &&
+        (param.value()[1] == ' ')) {
+      GURL url(GetDefaultSearchURLForSearchTerms(
+          profile, param.LossyDisplayName().substr(2)));
+      if (url.is_valid()) {
+        urls.push_back(url);
         continue;
       }
     }
@@ -436,9 +429,9 @@
     // If we are in Windows 8 metro mode and were launched as a result of the
     // search charm or via a url navigation in metro, then fetch the
     // corresponding url.
-    GURL url = chrome::GetURLToOpen(profile);
+    GURL url(chrome::GetURLToOpen(profile));
     if (url.is_valid())
-      urls.push_back(GURL(url));
+      urls.push_back(url);
   }
 #endif  // OS_WIN
   return urls;
diff --git a/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc b/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc
index 1af06b1..f761bf8 100644
--- a/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc
+++ b/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc
@@ -29,8 +29,8 @@
 #include "chrome/browser/ui/host_desktop.h"
 #include "chrome/browser/ui/startup/startup_browser_creator.h"
 #include "chrome/browser/ui/startup/startup_browser_creator_impl.h"
+#include "chrome/browser/ui/sync/sync_promo_ui.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
-#include "chrome/browser/ui/webui/sync_promo/sync_promo_ui.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/url_constants.h"
diff --git a/chrome/browser/ui/startup/startup_browser_creator_impl.cc b/chrome/browser/ui/startup/startup_browser_creator_impl.cc
index 2f29df6..fb78c6a 100644
--- a/chrome/browser/ui/startup/startup_browser_creator_impl.cc
+++ b/chrome/browser/ui/startup/startup_browser_creator_impl.cc
@@ -65,11 +65,11 @@
 #include "chrome/browser/ui/startup/obsolete_os_infobar_delegate.h"
 #include "chrome/browser/ui/startup/session_crashed_prompt.h"
 #include "chrome/browser/ui/startup/startup_browser_creator.h"
+#include "chrome/browser/ui/sync/sync_promo_ui.h"
 #include "chrome/browser/ui/tabs/pinned_tab_codec.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/webui/ntp/app_launcher_handler.h"
 #include "chrome/browser/ui/webui/sync_promo/sync_promo_trial.h"
-#include "chrome/browser/ui/webui/sync_promo/sync_promo_ui.h"
 #include "chrome/common/chrome_constants.h"
 #include "chrome/common/chrome_notification_types.h"
 #include "chrome/common/chrome_paths.h"
@@ -830,8 +830,7 @@
     params.extension_app_id = tabs[i].app_id;
 
 #if defined(ENABLE_RLZ)
-    if (process_startup &&
-        google_util::IsGoogleHomePageUrl(tabs[i].url.spec())) {
+    if (process_startup && google_util::IsGoogleHomePageUrl(tabs[i].url)) {
       params.extra_headers = RLZTracker::GetAccessPointHttpHeader(
           RLZTracker::CHROME_HOME_PAGE);
     }
diff --git a/chrome/browser/ui/startup/startup_browser_creator_win.cc b/chrome/browser/ui/startup/startup_browser_creator_win.cc
index 0544d90..a53e900 100644
--- a/chrome/browser/ui/startup/startup_browser_creator_win.cc
+++ b/chrome/browser/ui/startup/startup_browser_creator_win.cc
@@ -6,9 +6,7 @@
 
 #include "base/logging.h"
 #include "base/win/metro.h"
-#include "chrome/browser/search_engines/template_url.h"
-#include "chrome/browser/search_engines/template_url_service.h"
-#include "chrome/browser/search_engines/template_url_service_factory.h"
+#include "chrome/browser/search_engines/util.h"
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/startup/startup_browser_creator_impl.h"
@@ -21,22 +19,11 @@
   string16 params;
   base::win::MetroLaunchType launch_type =
       base::win::GetMetroLaunchParams(&params);
-
   if ((launch_type == base::win::METRO_PROTOCOL) ||
-      (launch_type == base::win::METRO_LAUNCH)) {
+      (launch_type == base::win::METRO_LAUNCH))
     return GURL(params);
-  } else if (launch_type == base::win::METRO_SEARCH) {
-    const TemplateURL* default_provider =
-        TemplateURLServiceFactory::GetForProfile(profile)->
-        GetDefaultSearchProvider();
-    if (default_provider) {
-      const TemplateURLRef& search_url = default_provider->url_ref();
-      DCHECK(search_url.SupportsReplacement());
-      return GURL(search_url.ReplaceSearchTerms(
-          TemplateURLRef::SearchTermsArgs(params)));
-    }
-  }
-  return GURL();
+  return (launch_type == base::win::METRO_SEARCH) ?
+      GetDefaultSearchURLForSearchTerms(profile, params) : GURL();
 }
 
 }  // namespace chrome
diff --git a/chrome/browser/ui/sync/one_click_signin_helper.cc b/chrome/browser/ui/sync/one_click_signin_helper.cc
index 8502d52..b614c93 100644
--- a/chrome/browser/ui/sync/one_click_signin_helper.cc
+++ b/chrome/browser/ui/sync/one_click_signin_helper.cc
@@ -229,20 +229,12 @@
     return;
   }
 
-  // If we are giving the user the option to configure sync, then that will
-  // suffice as a confirmation.
-  OneClickSigninSyncStarter::ConfirmationRequired confirmation =
-      args.confirmation_required;
-  if (start_mode == OneClickSigninSyncStarter::CONFIGURE_SYNC_FIRST &&
-      confirmation == OneClickSigninSyncStarter::CONFIRM_UNTRUSTED_SIGNIN) {
-    confirmation = OneClickSigninSyncStarter::CONFIRM_AFTER_SIGNIN;
-  }
-
   // The starter deletes itself once its done.
   new OneClickSigninSyncStarter(args.profile, args.browser, args.session_index,
                                 args.email, args.password, start_mode,
                                 args.force_same_tab_navigation,
-                                confirmation);
+                                args.confirmation_required,
+                                args.source);
 
   int action = one_click_signin::HISTOGRAM_MAX;
   switch (args.auto_accept) {
@@ -999,6 +991,22 @@
   }
 }
 
+void OneClickSigninHelper::DidNavigateMainFrame(
+    const content::LoadCommittedDetails& details,
+    const content::FrameNavigateParams& params) {
+  // If we navigate to a non-sign-in URL, make sure that the renderer process
+  // is no longer considered the trusted sign-in process.
+  if (!SigninManager::IsWebBasedSigninFlowURL(params.url)) {
+    Profile* profile =
+        Profile::FromBrowserContext(web_contents()->GetBrowserContext());
+    SigninManager* manager = profile ?
+        SigninManagerFactory::GetForProfile(profile) : NULL;
+    int process_id = web_contents()->GetRenderProcessHost()->GetID();
+    if (manager && manager->IsSigninProcess(process_id))
+      manager->ClearSigninProcess();
+  }
+}
+
 void OneClickSigninHelper::DidStopLoading(
     content::RenderViewHost* render_view_host) {
   // If the user left the sign in process, clear all members.
@@ -1150,12 +1158,12 @@
       LogOneClickHistogramValue(one_click_signin::HISTOGRAM_ACCEPTED);
       LogOneClickHistogramValue(one_click_signin::HISTOGRAM_WITH_ADVANCED);
       SigninManager::DisableOneClickSignIn(profile);
-      // Don't bother displaying an extra confirmation (even in the SAML case)
-      // since the user will get prompted to setup sync anyway.
+      // Display the extra confirmation (even in the SAML case) in case this
+      // was an untrusted renderer.
       StartSync(
           StartSyncArgs(profile, browser, auto_accept_, session_index_, email_,
                         password_, false /* force_same_tab_navigation */,
-                        false /* confirmation_required */, source_),
+                        true /* confirmation_required */, source_),
           OneClickSigninSyncStarter::CONFIGURE_SYNC_FIRST);
       break;
     case AUTO_ACCEPT_EXPLICIT: {
diff --git a/chrome/browser/ui/sync/one_click_signin_helper.h b/chrome/browser/ui/sync/one_click_signin_helper.h
index 1d17870..20c9954 100644
--- a/chrome/browser/ui/sync/one_click_signin_helper.h
+++ b/chrome/browser/ui/sync/one_click_signin_helper.h
@@ -9,7 +9,7 @@
 
 #include "base/gtest_prod_util.h"
 #include "chrome/browser/sync/profile_sync_service_observer.h"
-#include "chrome/browser/ui/webui/sync_promo/sync_promo_ui.h"
+#include "chrome/browser/ui/sync/sync_promo_ui.h"
 #include "content/public/browser/navigation_controller.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/browser/web_contents_user_data.h"
@@ -21,6 +21,8 @@
 
 namespace content {
 class WebContents;
+struct FrameNavigateParams;
+struct LoadCommittedDetails;
 struct PasswordForm;
 }
 
@@ -209,6 +211,9 @@
   virtual void NavigateToPendingEntry(
       const GURL& url,
       content::NavigationController::ReloadType reload_type) OVERRIDE;
+  virtual void DidNavigateMainFrame(
+      const content::LoadCommittedDetails& details,
+      const content::FrameNavigateParams& params) OVERRIDE;
   virtual void DidStopLoading(
       content::RenderViewHost* render_view_host) OVERRIDE;
 
diff --git a/chrome/browser/ui/sync/one_click_signin_sync_starter.cc b/chrome/browser/ui/sync/one_click_signin_sync_starter.cc
index b05a727..37001a4 100644
--- a/chrome/browser/ui/sync/one_click_signin_sync_starter.cc
+++ b/chrome/browser/ui/sync/one_click_signin_sync_starter.cc
@@ -48,10 +48,12 @@
     const std::string& password,
     StartSyncMode start_mode,
     bool force_same_tab_navigation,
-    ConfirmationRequired confirmation_required)
+    ConfirmationRequired confirmation_required,
+    SyncPromoUI::Source source)
     : start_mode_(start_mode),
       force_same_tab_navigation_(force_same_tab_navigation),
       confirmation_required_(confirmation_required),
+      source_(source),
       weak_pointer_factory_(this) {
   DCHECK(profile);
   BrowserList::AddObserver(this);
@@ -312,6 +314,16 @@
     StartSyncMode response) {
   if (response == UNDO_SYNC) {
     CancelSigninAndDelete();
+    // If this was not an interstitial signin, (i.e. it was a SAML signin)
+    // then the browser page is now blank and should redirect to the NTP.
+    if (source_ != SyncPromoUI::SOURCE_UNKNOWN) {
+      EnsureBrowser();
+      chrome::NavigateParams params(browser_, GURL(chrome::kChromeUINewTabURL),
+                                    content::PAGE_TRANSITION_AUTO_TOPLEVEL);
+      params.disposition = CURRENT_TAB;
+      params.window_action = chrome::NavigateParams::SHOW_WINDOW;
+      chrome::Navigate(&params);
+    }
   } else {
     // If the user clicked the "Advanced" link in the confirmation dialog, then
     // override the current start_mode_ to bring up the advanced sync settings.
diff --git a/chrome/browser/ui/sync/one_click_signin_sync_starter.h b/chrome/browser/ui/sync/one_click_signin_sync_starter.h
index 628d4f5..ce4ccda 100644
--- a/chrome/browser/ui/sync/one_click_signin_sync_starter.h
+++ b/chrome/browser/ui/sync/one_click_signin_sync_starter.h
@@ -13,6 +13,7 @@
 #include "chrome/browser/ui/browser_list_observer.h"
 #include "chrome/browser/ui/host_desktop.h"
 #include "chrome/browser/ui/sync/profile_signin_confirmation_helper.h"
+#include "chrome/browser/ui/sync/sync_promo_ui.h"
 
 class Browser;
 class ProfileSyncService;
@@ -65,7 +66,8 @@
                             const std::string& password,
                             StartSyncMode start_mode,
                             bool force_same_tab_navigation,
-                            ConfirmationRequired display_confirmation);
+                            ConfirmationRequired display_confirmation,
+                            SyncPromoUI::Source source);
 
   // chrome::BrowserListObserver override.
   virtual void OnBrowserRemoved(Browser* browser) OVERRIDE;
@@ -165,6 +167,7 @@
   chrome::HostDesktopType desktop_type_;
   bool force_same_tab_navigation_;
   ConfirmationRequired confirmation_required_;
+  SyncPromoUI::Source source_;
   base::WeakPtrFactory<OneClickSigninSyncStarter> weak_pointer_factory_;
 
 #if defined(ENABLE_CONFIGURATION_POLICY)
diff --git a/chrome/browser/ui/sync/profile_signin_confirmation_helper.cc b/chrome/browser/ui/sync/profile_signin_confirmation_helper.cc
index 38bc300..4d5dcda 100644
--- a/chrome/browser/ui/sync/profile_signin_confirmation_helper.cc
+++ b/chrome/browser/ui/sync/profile_signin_confirmation_helper.cc
@@ -68,27 +68,6 @@
   return has_bookmarks;
 }
 
-bool HasSyncedExtensions(Profile* profile) {
-  extensions::ExtensionSystem* system =
-      extensions::ExtensionSystem::Get(profile);
-  if (system && system->extension_service()) {
-    const ExtensionSet* extensions = system->extension_service()->extensions();
-    for (ExtensionSet::const_iterator iter = extensions->begin();
-         iter != extensions->end(); ++iter) {
-      // The webstore is synced so that it stays put on the new tab
-      // page, but since it's installed by default we don't want to
-      // consider it when determining if the profile is dirty.
-      if (extensions::sync_helper::IsSyncable(iter->get()) &&
-          (*iter)->id() != extension_misc::kWebStoreAppId) {
-        VLOG(1) << "ProfileSigninConfirmationHelper: "
-                << "profile contains a synced extension: " << (*iter)->id();
-        return true;
-      }
-    }
-  }
-  return false;
-}
-
 // Helper functions for Chrome profile signin.
 class ProfileSigninConfirmationHelper
     : public base::RefCounted<ProfileSigninConfirmationHelper> {
@@ -217,6 +196,28 @@
   return has_been_shutdown;
 }
 
+bool HasSyncedExtensions(Profile* profile) {
+  extensions::ExtensionSystem* system =
+      extensions::ExtensionSystem::Get(profile);
+  if (system && system->extension_service()) {
+    const ExtensionSet* extensions = system->extension_service()->extensions();
+    for (ExtensionSet::const_iterator iter = extensions->begin();
+         iter != extensions->end(); ++iter) {
+      // The webstore is synced so that it stays put on the new tab
+      // page, but since it's installed by default we don't want to
+      // consider it when determining if the profile is dirty.
+      if (extensions::sync_helper::IsSyncable(iter->get()) &&
+          (*iter)->id() != extension_misc::kWebStoreAppId &&
+          (*iter)->id() != extension_misc::kChromeAppId) {
+        VLOG(1) << "ProfileSigninConfirmationHelper: "
+                << "profile contains a synced extension: " << (*iter)->id();
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
 void CheckShouldPromptForNewProfile(
     Profile* profile,
     const base::Callback<void(bool)>& return_result) {
diff --git a/chrome/browser/ui/sync/profile_signin_confirmation_helper.h b/chrome/browser/ui/sync/profile_signin_confirmation_helper.h
index 073a579..d0d0c21 100644
--- a/chrome/browser/ui/sync/profile_signin_confirmation_helper.h
+++ b/chrome/browser/ui/sync/profile_signin_confirmation_helper.h
@@ -23,6 +23,10 @@
 // profile was created.
 bool HasBeenShutdown(Profile* profile);
 
+// Determines whether there are any synced extensions installed (that
+// shouldn't be ignored).
+bool HasSyncedExtensions(Profile* profile);
+
 // Determines whether the user should be prompted to create a new
 // profile before signin.
 void CheckShouldPromptForNewProfile(
diff --git a/chrome/browser/ui/sync/profile_signin_confirmation_helper_browsertest.cc b/chrome/browser/ui/sync/profile_signin_confirmation_helper_browsertest.cc
index c250511..41a9416 100644
--- a/chrome/browser/ui/sync/profile_signin_confirmation_helper_browsertest.cc
+++ b/chrome/browser/ui/sync/profile_signin_confirmation_helper_browsertest.cc
@@ -35,3 +35,8 @@
 #endif
   EXPECT_FALSE(ui::HasBeenShutdown(browser()->profile()));
 }
+
+IN_PROC_BROWSER_TEST_F(ProfileSigninConfirmationHelperBrowserTest,
+                       HasNoSyncedExtensions) {
+  EXPECT_FALSE(ui::HasSyncedExtensions(browser()->profile()));
+}
diff --git a/chrome/browser/ui/sync/sync_promo_ui.cc b/chrome/browser/ui/sync/sync_promo_ui.cc
new file mode 100644
index 0000000..83585b6
--- /dev/null
+++ b/chrome/browser/ui/sync/sync_promo_ui.cc
@@ -0,0 +1,275 @@
+// 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/ui/sync/sync_promo_ui.h"
+
+#include "base/command_line.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/strings/utf_string_conversions.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/first_run/first_run.h"
+#include "chrome/browser/google/google_util.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_info_cache.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/signin/signin_manager.h"
+#include "chrome/browser/signin/signin_manager_factory.h"
+#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"
+#include "chrome/common/pref_names.h"
+#include "chrome/common/url_constants.h"
+#include "components/user_prefs/pref_registry_syncable.h"
+#include "content/public/browser/url_data_source.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_ui.h"
+#include "content/public/browser/web_ui_data_source.h"
+#include "google_apis/gaia/gaia_urls.h"
+#include "grit/browser_resources.h"
+#include "grit/generated_resources.h"
+#include "grit/theme_resources.h"
+#include "net/base/escape.h"
+#include "net/base/network_change_notifier.h"
+#include "net/base/url_util.h"
+#include "ui/base/l10n/l10n_util.h"
+
+using content::WebContents;
+
+namespace {
+
+const char kStringsJsFile[] = "strings.js";
+const char kSyncPromoJsFile[] = "sync_promo.js";
+
+const char kSyncPromoQueryKeyAutoClose[] = "auto_close";
+const char kSyncPromoQueryKeyContinue[] = "continue";
+const char kSyncPromoQueryKeySource[] = "source";
+
+// Gaia cannot support about:blank as a continue URL, so using a hosted blank
+// page instead.
+const char kSyncLandingUrlPrefix[] =
+    "https://www.google.com/intl/%s/chrome/blank.html";
+
+// The maximum number of times we want to show the sync promo at startup.
+const int kSyncPromoShowAtStartupMaximum = 10;
+
+// Forces the web based signin flow when set.
+bool g_force_web_based_signin_flow = false;
+
+// Checks we want to show the sync promo for the given brand.
+bool AllowPromoAtStartupForCurrentBrand() {
+  std::string brand;
+  google_util::GetBrand(&brand);
+
+  if (brand.empty())
+    return true;
+
+  if (google_util::IsInternetCafeBrandCode(brand))
+    return false;
+
+  // Enable for both organic and distribution.
+  return true;
+}
+
+}  // namespace
+
+// static
+bool SyncPromoUI::HasShownPromoAtStartup(Profile* profile) {
+  return profile->GetPrefs()->HasPrefPath(prefs::kSyncPromoStartupCount);
+}
+
+// static
+bool SyncPromoUI::ShouldShowSyncPromo(Profile* profile) {
+#if defined(OS_CHROMEOS)
+  // There's no need to show the sync promo on cros since cros users are logged
+  // into sync already.
+  return false;
+#else
+
+  // Don't bother if we don't have any kind of network connection.
+  if (net::NetworkChangeNotifier::IsOffline())
+    return false;
+
+  // Don't show if the profile is an incognito.
+  if (profile->IsOffTheRecord())
+    return false;
+
+  // Don't show for managed profiles.
+  if (profile->GetPrefs()->GetBoolean(prefs::kProfileIsManaged))
+    return false;
+
+  // Display the signin promo if the user is not signed in.
+  SigninManager* signin = SigninManagerFactory::GetForProfile(
+      profile->GetOriginalProfile());
+  return !signin->AuthInProgress() && signin->IsSigninAllowed() &&
+      signin->GetAuthenticatedUsername().empty();
+#endif
+}
+
+// static
+void SyncPromoUI::RegisterUserPrefs(
+    user_prefs::PrefRegistrySyncable* registry) {
+  registry->RegisterIntegerPref(
+      prefs::kSyncPromoStartupCount,
+      0,
+      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
+  registry->RegisterBooleanPref(
+      prefs::kSyncPromoUserSkipped,
+      false,
+      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
+  registry->RegisterBooleanPref(
+      prefs::kSyncPromoShowOnFirstRunAllowed,
+      true,
+      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
+  registry->RegisterBooleanPref(
+      prefs::kSyncPromoShowNTPBubble,
+      false,
+      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
+  registry->RegisterStringPref(
+      prefs::kSyncPromoErrorMessage,
+      std::string(),
+      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
+}
+
+// static
+bool SyncPromoUI::ShouldShowSyncPromoAtStartup(Profile* profile,
+                                               bool is_new_profile) {
+  DCHECK(profile);
+
+  if (!ShouldShowSyncPromo(profile))
+    return false;
+
+  const CommandLine& command_line = *CommandLine::ForCurrentProcess();
+  if (command_line.HasSwitch(switches::kNoFirstRun))
+    is_new_profile = false;
+
+  if (!is_new_profile) {
+    if (!HasShownPromoAtStartup(profile))
+      return false;
+  }
+
+  if (HasUserSkippedSyncPromo(profile))
+    return false;
+
+  // For Chinese users skip the sync promo.
+  if (g_browser_process->GetApplicationLocale() == "zh-CN")
+    return false;
+
+  PrefService* prefs = profile->GetPrefs();
+  int show_count = prefs->GetInteger(prefs::kSyncPromoStartupCount);
+  if (show_count >= kSyncPromoShowAtStartupMaximum)
+    return false;
+
+  // This pref can be set in the master preferences file to allow or disallow
+  // showing the sync promo at startup.
+  if (prefs->HasPrefPath(prefs::kSyncPromoShowOnFirstRunAllowed))
+    return prefs->GetBoolean(prefs::kSyncPromoShowOnFirstRunAllowed);
+
+  // For now don't show the promo for some brands.
+  if (!AllowPromoAtStartupForCurrentBrand())
+    return false;
+
+  // Default to show the promo for Google Chrome builds.
+#if defined(GOOGLE_CHROME_BUILD)
+  return true;
+#else
+  return false;
+#endif
+}
+
+void SyncPromoUI::DidShowSyncPromoAtStartup(Profile* profile) {
+  int show_count = profile->GetPrefs()->GetInteger(
+      prefs::kSyncPromoStartupCount);
+  show_count++;
+  profile->GetPrefs()->SetInteger(prefs::kSyncPromoStartupCount, show_count);
+}
+
+bool SyncPromoUI::HasUserSkippedSyncPromo(Profile* profile) {
+  return profile->GetPrefs()->GetBoolean(prefs::kSyncPromoUserSkipped);
+}
+
+void SyncPromoUI::SetUserSkippedSyncPromo(Profile* profile) {
+  profile->GetPrefs()->SetBoolean(prefs::kSyncPromoUserSkipped, true);
+}
+
+// static
+std::string SyncPromoUI::GetSyncLandingURL(const char* option, int value) {
+  const std::string& locale = g_browser_process->GetApplicationLocale();
+  std::string url = base::StringPrintf(kSyncLandingUrlPrefix, locale.c_str());
+  base::StringAppendF(&url, "?%s=%d", option, value);
+  return url;
+}
+
+// static
+GURL SyncPromoUI::GetSyncPromoURL(Source source, bool auto_close) {
+  DCHECK_NE(SOURCE_UNKNOWN, source);
+
+  std::string url_string;
+
+  // Build a Gaia-based URL that can be used to sign the user into chrome.
+  // There are required request parameters:
+  //
+  //  - tell Gaia which service the user is signing into.  In this case,
+  //    a chrome sign in uses the service "chromiumsync"
+  //  - provide a continue URL.  This is the URL that Gaia will redirect to
+  //    once the sign is complete.
+  //
+  // The continue URL includes a source parameter that can be extracted using
+  // the function GetSourceForSyncPromoURL() below.  This is used to know
+  // which of the chrome sign in access points was used to sign the user in.
+  // See OneClickSigninHelper for details.
+  url_string = GaiaUrls::GetInstance()->service_login_url();
+  url_string.append("?service=chromiumsync&sarp=1");
+
+  std::string continue_url = GetSyncLandingURL(
+      kSyncPromoQueryKeySource, static_cast<int>(source));
+
+  base::StringAppendF(&url_string, "&%s=%s", kSyncPromoQueryKeyContinue,
+                      net::EscapeQueryParamValue(
+                          continue_url, false).c_str());
+
+  return GURL(url_string);
+}
+
+// static
+GURL SyncPromoUI::GetNextPageURLForSyncPromoURL(const GURL& url) {
+  std::string value;
+  if (net::GetValueForKeyInQuery(url, kSyncPromoQueryKeyContinue, &value))
+    return GURL(value);
+
+  return GURL();
+}
+
+// static
+SyncPromoUI::Source SyncPromoUI::GetSourceForSyncPromoURL(const GURL& url) {
+  std::string value;
+  if (net::GetValueForKeyInQuery(url, kSyncPromoQueryKeySource, &value)) {
+    int source = 0;
+    if (base::StringToInt(value, &source) && source >= SOURCE_START_PAGE &&
+        source < SOURCE_UNKNOWN) {
+      return static_cast<Source>(source);
+    }
+  }
+  return SOURCE_UNKNOWN;
+}
+
+// static
+bool SyncPromoUI::IsContinueUrlForWebBasedSigninFlow(const GURL& url) {
+  GURL::Replacements replacements;
+  replacements.ClearQuery();
+  const std::string& locale = g_browser_process->GetApplicationLocale();
+  return url.ReplaceComponents(replacements) ==
+      GURL(base::StringPrintf(kSyncLandingUrlPrefix, locale.c_str()));
+}
+
+// static
+void SyncPromoUI::ForceWebBasedSigninFlowForTesting(bool force) {
+  g_force_web_based_signin_flow = force;
+}
diff --git a/chrome/browser/ui/sync/sync_promo_ui.h b/chrome/browser/ui/sync/sync_promo_ui.h
new file mode 100644
index 0000000..48d2f1b
--- /dev/null
+++ b/chrome/browser/ui/sync/sync_promo_ui.h
@@ -0,0 +1,87 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_SYNC_SYNC_PROMO_UI_H_
+#define CHROME_BROWSER_UI_SYNC_SYNC_PROMO_UI_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+
+class GURL;
+class Profile;
+
+namespace user_prefs {
+class PrefRegistrySyncable;
+}
+
+// Static helper functions useful for chrome sign in.
+class SyncPromoUI {
+ public:
+  // 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,
+    SOURCE_MENU,
+    SOURCE_SETTINGS,
+    SOURCE_EXTENSION_INSTALL_BUBBLE,
+    SOURCE_WEBSTORE_INSTALL,
+    SOURCE_APP_LAUNCHER,
+    SOURCE_APPS_PAGE_LINK,
+    SOURCE_UNKNOWN, // This must be last.
+  };
+
+  // Returns true if the sync promo should be visible.
+  // |profile| is the profile of the tab the promo would be shown on.
+  static bool ShouldShowSyncPromo(Profile* profile);
+
+  // Returns true if we should show the sync promo at startup.
+  static bool ShouldShowSyncPromoAtStartup(Profile* profile,
+                                           bool is_new_profile);
+
+  // Called when the sync promo has been shown so that we can keep track
+  // of the number of times we've displayed it.
+  static void DidShowSyncPromoAtStartup(Profile* profile);
+
+  // Returns true if a user has seen the sync promo at startup previously.
+  static bool HasShownPromoAtStartup(Profile* profile);
+
+  // Returns true if the user has previously skipped the sync promo.
+  static bool HasUserSkippedSyncPromo(Profile* profile);
+
+  // Registers the fact that the user has skipped the sync promo.
+  static void SetUserSkippedSyncPromo(Profile* profile);
+
+  // Registers the preferences the Sync Promo UI needs.
+  static void RegisterUserPrefs(user_prefs::PrefRegistrySyncable* registry);
+
+  // Gets the sync landing page URL.
+  static std::string GetSyncLandingURL(const char* option, int value);
+
+  // Returns the sync promo URL wth the given arguments in the query.
+  // |source| identifies from where the sync promo is being called, and is used
+  // to record sync promo UMA stats in the context of the source.
+  // |auto_close| whether to close the sync promo automatically when done.
+  static GURL GetSyncPromoURL(Source source, bool auto_close);
+
+  // Gets the next page URL from the query portion of the sync promo URL.
+  static GURL GetNextPageURLForSyncPromoURL(const GURL& url);
+
+  // Gets the source from the query portion of the sync promo URL.
+  // The source identifies from where the sync promo was opened.
+  static Source GetSourceForSyncPromoURL(const GURL& url);
+
+  // Returns true if the given URL is the standard continue URL used with the
+  // sync promo when the web-based flow is enabled.  The query parameters
+  // of the URL are ignored for this comparison.
+  static bool IsContinueUrlForWebBasedSigninFlow(const GURL& url);
+
+  // Forces UseWebBasedSigninFlow() to return true when set; used in tests only.
+  static void ForceWebBasedSigninFlowForTesting(bool force);
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(SyncPromoUI);
+};
+
+#endif  // CHROME_BROWSER_UI_SYNC_SYNC_PROMO_UI_H_
diff --git a/chrome/browser/ui/tab_contents/core_tab_helper.cc b/chrome/browser/ui/tab_contents/core_tab_helper.cc
index f8dc42e..52106b8 100644
--- a/chrome/browser/ui/tab_contents/core_tab_helper.cc
+++ b/chrome/browser/ui/tab_contents/core_tab_helper.cc
@@ -4,8 +4,10 @@
 
 #include "chrome/browser/ui/tab_contents/core_tab_helper.h"
 
+#include "base/command_line.h"
 #include "base/metrics/histogram.h"
 #include "chrome/browser/renderer_host/web_cache_manager.h"
+#include "chrome/common/chrome_switches.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/web_contents.h"
@@ -116,20 +118,32 @@
 void CoreTabHelper::WebContentsDestroyed(WebContents* web_contents) {
   // OnCloseStarted isn't called in unit tests.
   if (!close_start_time_.is_null()) {
-    base::TimeTicks now = base::TimeTicks::Now();
-    base::TimeDelta close_time = now - close_start_time_;
-    UMA_HISTOGRAM_TIMES("Tab.Close", close_time);
+    bool fast_tab_close_enabled = CommandLine::ForCurrentProcess()->HasSwitch(
+        switches::kEnableFastUnload);
 
-    base::TimeTicks unload_start_time = close_start_time_;
-    base::TimeTicks unload_end_time = now;
-    if (!before_unload_end_time_.is_null())
-      unload_start_time = before_unload_end_time_;
-    if (!unload_detached_start_time_.is_null())
-      unload_end_time = unload_detached_start_time_;
-    base::TimeDelta unload_time = unload_end_time - unload_start_time;
-    UMA_HISTOGRAM_TIMES("Tab.Close.UnloadTime", unload_time);
+    if (fast_tab_close_enabled) {
+      base::TimeTicks now = base::TimeTicks::Now();
+      base::TimeDelta close_time = now - close_start_time_;
+      UMA_HISTOGRAM_TIMES("Tab.Close", close_time);
 
+      base::TimeTicks unload_start_time = close_start_time_;
+      base::TimeTicks unload_end_time = now;
+      if (!before_unload_end_time_.is_null())
+        unload_start_time = before_unload_end_time_;
+      if (!unload_detached_start_time_.is_null())
+        unload_end_time = unload_detached_start_time_;
+      base::TimeDelta unload_time = unload_end_time - unload_start_time;
+      UMA_HISTOGRAM_TIMES("Tab.Close.UnloadTime", unload_time);
+    } else {
+      base::TimeTicks now = base::TimeTicks::Now();
+      base::TimeTicks unload_start_time = close_start_time_;
+      if (!before_unload_end_time_.is_null())
+        unload_start_time = before_unload_end_time_;
+      UMA_HISTOGRAM_TIMES("Tab.Close", now - close_start_time_);
+      UMA_HISTOGRAM_TIMES("Tab.Close.UnloadTime", now - unload_start_time);
+    }
   }
+
 }
 
 void CoreTabHelper::BeforeUnloadFired(const base::TimeTicks& proceed_time) {
diff --git a/chrome/browser/ui/tab_contents/core_tab_helper.h b/chrome/browser/ui/tab_contents/core_tab_helper.h
index e5a37dd..c8e6782 100644
--- a/chrome/browser/ui/tab_contents/core_tab_helper.h
+++ b/chrome/browser/ui/tab_contents/core_tab_helper.h
@@ -5,7 +5,7 @@
 #ifndef CHROME_BROWSER_UI_TAB_CONTENTS_CORE_TAB_HELPER_H_
 #define CHROME_BROWSER_UI_TAB_CONTENTS_CORE_TAB_HELPER_H_
 
-#include "base/time.h"
+#include "base/time/time.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/browser/web_contents_user_data.h"
 
diff --git a/chrome/browser/ui/tests/ui_gfx_image_unittest.mm b/chrome/browser/ui/tests/ui_gfx_image_unittest.mm
index e025ccc..4e45cf2 100644
--- a/chrome/browser/ui/tests/ui_gfx_image_unittest.mm
+++ b/chrome/browser/ui/tests/ui_gfx_image_unittest.mm
@@ -5,7 +5,7 @@
 #import <AppKit/AppKit.h>
 
 #import "base/mac/mac_util.h"
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/skia/include/core/SkBitmap.h"
@@ -45,7 +45,7 @@
 }
 
 TEST_F(UiGfxImageTest, ImageView) {
-  scoped_nsobject<NSImageView> image_view(
+  base::scoped_nsobject<NSImageView> image_view(
       [[NSImageView alloc] initWithFrame:NSMakeRect(10, 10, 25, 25)]);
   [[test_window() contentView] addSubview:image_view];
   [test_window() orderFront:nil];
diff --git a/chrome/browser/ui/toolbar/back_forward_menu_model_unittest.cc b/chrome/browser/ui/toolbar/back_forward_menu_model_unittest.cc
index dee248b..4f2af32 100644
--- a/chrome/browser/ui/toolbar/back_forward_menu_model_unittest.cc
+++ b/chrome/browser/ui/toolbar/back_forward_menu_model_unittest.cc
@@ -8,7 +8,7 @@
 #include "base/strings/string16.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/favicon/favicon_service_factory.h"
 #include "chrome/browser/history/history_service.h"
 #include "chrome/browser/history/history_service_factory.h"
@@ -499,8 +499,7 @@
 TEST_F(BackFwdMenuModelTest, FaviconLoadTest) {
   profile()->CreateHistoryService(true, false);
   profile()->CreateFaviconService();
-  Browser::CreateParams native_params(profile(),
-                                      chrome::HOST_DESKTOP_TYPE_NATIVE);
+  Browser::CreateParams native_params(profile(), chrome::GetActiveDesktop());
   scoped_ptr<Browser> browser(
       chrome::CreateBrowserWithTestWindowForParams(&native_params));
   FaviconDelegate favicon_delegate;
diff --git a/chrome/browser/ui/toolbar/recent_tabs_builder_test_helper.h b/chrome/browser/ui/toolbar/recent_tabs_builder_test_helper.h
index 862f4b7..63f4761 100644
--- a/chrome/browser/ui/toolbar/recent_tabs_builder_test_helper.h
+++ b/chrome/browser/ui/toolbar/recent_tabs_builder_test_helper.h
@@ -8,7 +8,7 @@
 #include <vector>
 
 #include "base/strings/string16.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/sessions/session_id.h"
 
 namespace browser_sync {
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 aed88a7..d32cb3c 100644
--- a/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model.cc
+++ b/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/ui/toolbar/recent_tabs_sub_menu_model.h"
 
 #include "base/bind.h"
+#include "base/metrics/histogram.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/app/chrome_command_ids.h"
@@ -112,6 +113,14 @@
 
 }  // namespace
 
+enum RecentTabAction {
+  LOCAL_SESSION_TAB = 0,
+  OTHER_DEVICE_TAB,
+  RESTORE_WINDOW,
+  SHOW_MORE,
+  LIMIT_RECENT_TAB_ACTION
+};
+
 // An element in |RecentTabsSubMenuModel::tab_navigation_items_| that stores
 // the navigation information of a local or foreign tab required to restore the
 // tab.
@@ -120,9 +129,11 @@
 
   TabNavigationItem(const std::string& session_tag,
                     const SessionID::id_type& tab_id,
+                    const string16& title,
                     const GURL& url)
       : session_tag(session_tag),
         tab_id(tab_id),
+        title(title),
         url(url) {}
 
   // For use by std::set for sorting.
@@ -132,6 +143,7 @@
 
   std::string session_tag;  // Empty for local tabs, non-empty for foreign tabs.
   SessionID::id_type tab_id;  // -1 for invalid, >= 0 otherwise.
+  string16 title;
   GURL url;
 };
 
@@ -205,6 +217,8 @@
 
 void RecentTabsSubMenuModel::ExecuteCommand(int command_id, int event_flags) {
   if (command_id == IDC_SHOW_HISTORY) {
+    UMA_HISTOGRAM_ENUMERATION("WrenchMenu.RecentTabsSubMenu", SHOW_MORE,
+                              LIMIT_RECENT_TAB_ACTION);
     // We show all "other devices" on the history page.
     chrome::ExecuteCommandWithDisposition(browser_, IDC_SHOW_HISTORY,
         ui::DispositionFromEventFlags(event_flags));
@@ -233,6 +247,8 @@
 
     if (item.session_tag.empty()) {  // Restore tab of local session.
       if (service && delegate) {
+        UMA_HISTOGRAM_ENUMERATION("WrenchMenu.RecentTabsSubMenu",
+                                  LOCAL_SESSION_TAB, LIMIT_RECENT_TAB_ACTION);
         service->RestoreEntryById(delegate, item.tab_id,
                                   browser_->host_desktop_type(), disposition);
       }
@@ -245,6 +261,8 @@
         return;
       if (tab->navigations.empty())
         return;
+      UMA_HISTOGRAM_ENUMERATION("WrenchMenu.RecentTabsSubMenu",
+                                OTHER_DEVICE_TAB, LIMIT_RECENT_TAB_ACTION);
       SessionRestore::RestoreForeignSessionTab(
           browser_->tab_strip_model()->GetActiveWebContents(),
           *tab, disposition);
@@ -255,6 +273,8 @@
       int model_idx = CommandIdToWindowModelIndex(command_id);
       DCHECK(model_idx >= 0 &&
              model_idx < static_cast<int>(window_items_.size()));
+      UMA_HISTOGRAM_ENUMERATION("WrenchMenu.RecentTabsSubMenu", RESTORE_WINDOW,
+                                LIMIT_RECENT_TAB_ACTION);
       service->RestoreEntryById(delegate, window_items_[model_idx],
                                 browser_->host_desktop_type(), disposition);
     }
@@ -281,6 +301,22 @@
   return 320;
 }
 
+bool RecentTabsSubMenuModel::GetURLAndTitleForItemAtIndex(
+    int index,
+    std::string* url,
+    string16* title) const {
+  int command_id = GetCommandIdAt(index);
+  if (IsTabModelCommandId(command_id)) {
+    int model_idx = CommandIdToTabModelIndex(command_id);
+    DCHECK(model_idx >= 0 &&
+           model_idx < static_cast<int>(tab_navigation_items_.size()));
+    *url = tab_navigation_items_[model_idx].url.possibly_invalid_spec();
+    *title = tab_navigation_items_[model_idx].title;
+    return true;
+  }
+  return false;
+}
+
 void RecentTabsSubMenuModel::Build() {
   // The menu contains:
   // - Recently closed tabs header, then list of tabs, then separator
@@ -299,6 +335,12 @@
   ListValue recently_closed_list;
   TabRestoreService* service =
       TabRestoreServiceFactory::GetForProfile(browser_->profile());
+  if (service) {
+    // This does nothing if the tabs have already been loaded or they
+    // shouldn't be loaded.
+    service->LoadTabsFromLastSession();
+  }
+
   if (!service || service->entries().size() == 0) {
     // This is to show a disabled restore tab entry with the accelerator to
     // teach users about this command.
@@ -414,7 +456,7 @@
     int session_id,
     const string16& title,
     const GURL& url) {
-  TabNavigationItem item("", session_id, url);
+  TabNavigationItem item("", session_id, title, url);
   int command_id = TabModelIndexToCommandId(tab_navigation_items_.size());
   // There may be no tab title, in which case, use the url as tab title.
   AddItem(command_id, title.empty() ? UTF8ToUTF16(item.url.spec()) : title);
@@ -428,6 +470,7 @@
   const sessions::SerializedNavigationEntry& current_navigation =
       tab.navigations.at(tab.normalized_navigation_index());
   TabNavigationItem item(session_tag, tab.tab_id.id(),
+                         current_navigation.title(),
                          current_navigation.virtual_url());
   int command_id = TabModelIndexToCommandId(tab_navigation_items_.size());
   // There may be no tab title, in which case, use the url as tab title.
diff --git a/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model.h b/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model.h
index 2a455f0..62d9a07 100644
--- a/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model.h
+++ b/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model.h
@@ -56,6 +56,9 @@
   virtual const gfx::Font* GetLabelFontAt(int index) const OVERRIDE;
 
   int GetMaxWidthForItemAtIndex(int item_index) const;
+  bool GetURLAndTitleForItemAtIndex(int index,
+                                    std::string* url,
+                                    string16* title) const;
 
   // Command Id for recently closed items header or disabled item to which the
   // accelerator string will be appended.
diff --git a/chrome/browser/ui/toolbar/toolbar_model_impl.cc b/chrome/browser/ui/toolbar/toolbar_model_impl.cc
index 5c6d8bc..8ecf05c 100644
--- a/chrome/browser/ui/toolbar/toolbar_model_impl.cc
+++ b/chrome/browser/ui/toolbar/toolbar_model_impl.cc
@@ -270,6 +270,12 @@
       (entry->GetSSL().security_style == content::SECURITY_STYLE_UNKNOWN))
     return search_terms;
 
+  // If the URL is using a Google base URL specified via the command line, skip
+  // the security check below.
+  if (entry &&
+      google_util::StartsWithCommandLineGoogleBaseURL(entry->GetVirtualURL()))
+    return search_terms;
+
   // Otherwise, extract search terms for HTTPS pages that do not have a security
   // error.
   ToolbarModel::SecurityLevel security_level = GetSecurityLevel();
diff --git a/chrome/browser/ui/toolbar/toolbar_model_unittest.cc b/chrome/browser/ui/toolbar/toolbar_model_unittest.cc
index f8f8226..c3da77c 100644
--- a/chrome/browser/ui/toolbar/toolbar_model_unittest.cc
+++ b/chrome/browser/ui/toolbar/toolbar_model_unittest.cc
@@ -10,6 +10,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/autocomplete/autocomplete_classifier_factory.h"
 #include "chrome/browser/search/search.h"
+#include "chrome/browser/search_engines/search_terms_data.h"
 #include "chrome/browser/search_engines/template_url.h"
 #include "chrome/browser/search_engines/template_url_service.h"
 #include "chrome/browser/search_engines/template_url_service_factory.h"
@@ -182,6 +183,7 @@
       profile(), &TemplateURLServiceFactory::BuildInstanceFor);
   AutocompleteClassifierFactory::GetInstance()->SetTestingFactoryAndUse(
       profile(), &AutocompleteClassifierFactory::BuildInstanceFor);
+  UIThreadSearchTermsData::SetGoogleBaseURL("http://google.com/");
 }
 
 void ToolbarModelTest::ResetDefaultTemplateURL() {
@@ -203,7 +205,7 @@
 void ToolbarModelTest::ResetTemplateURLForInstant(const GURL& instant_url) {
   TemplateURLData data;
   data.short_name = ASCIIToUTF16("Google");
-  data.SetURL("http://google.com/search?q={searchTerms}");
+  data.SetURL("{google:baseURL}search?q={searchTerms}");
   data.instant_url = instant_url.spec();
   data.search_terms_replacement_key = "{google:instantExtendedEnabledKey}";
   TemplateURL* search_template_url = new TemplateURL(profile(), data);
@@ -254,16 +256,13 @@
 
 // Test that we don't replace any URLs when the query extraction is disabled.
 TEST_F(ToolbarModelTest, ShouldDisplayURLQueryExtractionDisabled) {
-  ASSERT_FALSE(chrome::IsQueryExtractionEnabled(profile()))
+  ASSERT_FALSE(chrome::IsQueryExtractionEnabled())
       << "This test expects query extraction to be disabled.";
-  ResetDefaultTemplateURL();
   AddTab(browser(), GURL(content::kAboutBlankURL));
   for (size_t i = 0; i < arraysize(test_items); ++i) {
     const TestItem& test_item = test_items[i];
-    NavigateAndCheckText(test_item.url,
-                         test_item.expected_text,
-                         test_item.expected_replace_text_inactive,
-                         false,
+    NavigateAndCheckText(test_item.url, test_item.expected_text,
+                         test_item.expected_replace_text_inactive, false,
                          test_item.should_display);
   }
 }
@@ -271,15 +270,12 @@
 // Test that we replace URLs when the query extraction API is enabled.
 TEST_F(ToolbarModelTest, ShouldDisplayURLQueryExtractionEnabled) {
   chrome::EnableInstantExtendedAPIForTesting();
-  ResetDefaultTemplateURL();
   AddTab(browser(), GURL(content::kAboutBlankURL));
   for (size_t i = 0; i < arraysize(test_items); ++i) {
     const TestItem& test_item = test_items[i];
-    NavigateAndCheckText(test_item.url,
-                         test_item.expected_text,
+    NavigateAndCheckText(test_item.url, test_item.expected_text,
                          test_item.expected_replace_text_active,
-                         test_item.would_replace,
-                         test_item.should_display);
+                         test_item.would_replace, test_item.should_display);
   }
 }
 
@@ -307,3 +303,30 @@
       content::SECURITY_STYLE_UNKNOWN;
   EXPECT_FALSE(toolbar_model->WouldReplaceSearchURLWithSearchTerms());
 }
+
+// When the Google base URL is overridden on the command line, we should extract
+// search terms from URLs that start with that base URL even when they're not
+// secure.
+TEST_F(ToolbarModelTest, GoogleBaseURL) {
+  chrome::EnableInstantExtendedAPIForTesting();
+  AddTab(browser(), GURL(content::kAboutBlankURL));
+
+  // If the Google base URL wasn't specified on the command line, then if it's
+  // HTTP, we should not extract search terms.
+  UIThreadSearchTermsData::SetGoogleBaseURL("http://www.foo.com/");
+  NavigateAndCheckText(
+      GURL("http://www.foo.com/search?q=tractor+supply&espv=1"),
+      ASCIIToUTF16("www.foo.com/search?q=tractor+supply&espv=1"),
+      ASCIIToUTF16("www.foo.com/search?q=tractor+supply&espv=1"), false,
+      true);
+
+  // The same URL, when specified on the command line, should allow search term
+  // extraction.
+  UIThreadSearchTermsData::SetGoogleBaseURL(std::string());
+  CommandLine::ForCurrentProcess()->AppendSwitchASCII(switches::kGoogleBaseURL,
+                                                      "http://www.foo.com/");
+  NavigateAndCheckText(
+      GURL("http://www.foo.com/search?q=tractor+supply&espv=1"),
+      ASCIIToUTF16("www.foo.com/search?q=tractor+supply&espv=1"),
+      ASCIIToUTF16("tractor supply"), true, true);
+}
diff --git a/chrome/browser/ui/toolbar/wrench_menu_model.cc b/chrome/browser/ui/toolbar/wrench_menu_model.cc
index f742d75..ab5998f 100644
--- a/chrome/browser/ui/toolbar/wrench_menu_model.cc
+++ b/chrome/browser/ui/toolbar/wrench_menu_model.cc
@@ -8,7 +8,6 @@
 #include <cmath>
 
 #include "base/command_line.h"
-#include "base/i18n/number_formatting.h"
 #include "base/prefs/pref_service.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
@@ -278,7 +277,6 @@
 #elif defined(OS_WIN)
          command_id == IDC_PIN_TO_START_SCREEN ||
 #endif
-         command_id == IDC_VIEW_BACKGROUND_PAGES ||
          command_id == IDC_UPGRADE_DIALOG ||
          command_id == IDC_SHOW_SIGNIN;
 }
@@ -308,12 +306,6 @@
       return l10n_util::GetStringUTF16(string_id);
     }
 #endif
-    case IDC_VIEW_BACKGROUND_PAGES: {
-      string16 num_background_pages = base::FormatNumber(
-          TaskManager::GetBackgroundPageCount());
-      return l10n_util::GetStringFUTF16(IDS_VIEW_BACKGROUND_PAGES,
-                                        num_background_pages);
-    }
     case IDC_UPGRADE_DIALOG:
       return GetUpgradeDialogMenuItemName();
     case IDC_SHOW_SIGNIN:
@@ -428,8 +420,6 @@
 #endif
   } else if (command_id == IDC_UPGRADE_DIALOG) {
     return UpgradeDetector::GetInstance()->notify_upgrade();
-  } else if (command_id == IDC_VIEW_BACKGROUND_PAGES) {
-    return TaskManager::GetBackgroundPageCount() > 0;
   }
   return true;
 }
@@ -601,19 +591,12 @@
                              IDS_TOGGLE_REQUEST_TABLET_SITE);
 #endif
 
-// On ChromeOS-Touch, we don't want the about/background pages menu options.
+// On ChromeOS-Touch, we don't want the about menu option.
 #if defined(OS_CHROMEOS)
   if (!is_new_menu)
 #endif
   {
     AddItem(IDC_ABOUT, l10n_util::GetStringUTF16(IDS_ABOUT));
-    // We use the task manager to show background pages.
-    if (chrome::CanOpenTaskManager()) {
-      string16 num_background_pages = base::FormatNumber(
-          TaskManager::GetBackgroundPageCount());
-      AddItem(IDC_VIEW_BACKGROUND_PAGES, l10n_util::GetStringFUTF16(
-          IDS_VIEW_BACKGROUND_PAGES, num_background_pages));
-    }
   }
 
   if (browser_defaults::kShowUpgradeMenuItem)
@@ -681,8 +664,10 @@
     if (error->HasMenuItem()) {
       // Don't add a signin error if it's already being displayed elsewhere.
 #if !defined(OS_CHROMEOS)
-      if (error == signin_ui_util::GetSignedInServiceError(
-                       browser_->profile()->GetOriginalProfile())) {
+      std::vector<GlobalError*> errors =
+          signin_ui_util::GetSignedInServiceErrors(
+              browser_->profile()->GetOriginalProfile());
+      if (std::find(errors.begin(), errors.end(), error) != errors.end()) {
         MenuModel* model = this;
         int index = 0;
         if (MenuModel::GetModelAndIndexForCommandId(
diff --git a/chrome/browser/ui/unload_controller.cc b/chrome/browser/ui/unload_controller.cc
index 19d6154..da61646 100644
--- a/chrome/browser/ui/unload_controller.cc
+++ b/chrome/browser/ui/unload_controller.cc
@@ -4,55 +4,25 @@
 
 #include "chrome/browser/ui/unload_controller.h"
 
-#include "base/logging.h"
 #include "base/message_loop.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_tabstrip.h"
-#include "chrome/browser/ui/tab_contents/core_tab_helper.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
-#include "chrome/browser/ui/tabs/tab_strip_model_delegate.h"
 #include "chrome/common/chrome_notification_types.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/notification_source.h"
 #include "content/public/browser/notification_types.h"
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/web_contents.h"
-#include "content/public/browser/web_contents_delegate.h"
 
 namespace chrome {
 
-
-////////////////////////////////////////////////////////////////////////////////
-// DetachedWebContentsDelegate will delete web contents when they close.
-class UnloadController::DetachedWebContentsDelegate
-    : public content::WebContentsDelegate {
- public:
-  DetachedWebContentsDelegate() { }
-  virtual ~DetachedWebContentsDelegate() { }
-
- private:
-  // WebContentsDelegate implementation.
-  virtual bool ShouldSuppressDialogs() OVERRIDE {
-    return true;  // Return true so dialogs are suppressed.
-  }
-
-  virtual void CloseContents(content::WebContents* source) OVERRIDE {
-    // Finished detached close.
-    // UnloadController will observe |NOTIFICATION_WEB_CONTENTS_DISCONNECTED|.
-    delete source;
-  }
-
-  DISALLOW_COPY_AND_ASSIGN(DetachedWebContentsDelegate);
-};
-
 ////////////////////////////////////////////////////////////////////////////////
 // UnloadController, public:
 
 UnloadController::UnloadController(Browser* browser)
     : browser_(browser),
-      tab_needing_before_unload_ack_(NULL),
       is_attempting_to_close_browser_(false),
-      detached_delegate_(new DetachedWebContentsDelegate()),
       weak_factory_(this) {
   browser_->tab_strip_model()->AddObserver(this);
 }
@@ -64,20 +34,16 @@
 bool UnloadController::CanCloseContents(content::WebContents* contents) {
   // Don't try to close the tab when the whole browser is being closed, since
   // that avoids the fast shutdown path where we just kill all the renderers.
+  if (is_attempting_to_close_browser_)
+    ClearUnloadState(contents, true);
   return !is_attempting_to_close_browser_;
 }
 
 bool UnloadController::BeforeUnloadFired(content::WebContents* contents,
                                          bool proceed) {
   if (!is_attempting_to_close_browser_) {
-    if (!proceed) {
+    if (!proceed)
       contents->SetClosedByUserGesture(false);
-    } else {
-      // No more dialogs are possible, so remove the tab and finish
-      // running unload listeners asynchrounously.
-      browser_->tab_strip_model()->delegate()->CreateHistoricalTab(contents);
-      DetachWebContents(contents);
-    }
     return proceed;
   }
 
@@ -87,10 +53,10 @@
     return false;
   }
 
-  if (tab_needing_before_unload_ack_ == contents) {
-    // Now that beforeunload has fired, queue the tab to fire unload.
-    tab_needing_before_unload_ack_ = NULL;
-    tabs_needing_unload_.insert(contents);
+  if (RemoveFromSet(&tabs_needing_before_unload_fired_, contents)) {
+    // Now that beforeunload has fired, put the tab on the queue to fire
+    // unload.
+    tabs_needing_unload_fired_.insert(contents);
     ProcessPendingTabs();
     // We want to handle firing the unload event ourselves since we want to
     // fire all the beforeunload events before attempting to fire the unload
@@ -115,20 +81,15 @@
 }
 
 bool UnloadController::TabsNeedBeforeUnloadFired() {
-  if (!tabs_needing_before_unload_.empty() ||
-      tab_needing_before_unload_ack_ != NULL)
-    return true;
-
-  if (!tabs_needing_unload_.empty())
-    return false;
-
-  for (int i = 0; i < browser_->tab_strip_model()->count(); ++i) {
-    content::WebContents* contents =
-        browser_->tab_strip_model()->GetWebContentsAt(i);
-    if (contents->NeedToFireBeforeUnload())
-      tabs_needing_before_unload_.insert(contents);
+  if (tabs_needing_before_unload_fired_.empty()) {
+    for (int i = 0; i < browser_->tab_strip_model()->count(); ++i) {
+      content::WebContents* contents =
+          browser_->tab_strip_model()->GetWebContentsAt(i);
+      if (contents->NeedToFireBeforeUnload())
+        tabs_needing_before_unload_fired_.insert(contents);
+    }
   }
-  return !tabs_needing_before_unload_.empty();
+  return !tabs_needing_before_unload_fired_.empty();
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -138,15 +99,12 @@
                                const content::NotificationSource& source,
                                const content::NotificationDetails& details) {
   switch (type) {
-    case content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED: {
-      registrar_.Remove(this,
-                        content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED,
-                        source);
-      content::WebContents* contents =
-          content::Source<content::WebContents>(source).ptr();
-      ClearUnloadState(contents);
+    case content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED:
+      if (is_attempting_to_close_browser_) {
+        ClearUnloadState(content::Source<content::WebContents>(source).ptr(),
+                         false);  // See comment for ClearUnloadState().
+      }
       break;
-    }
     default:
       NOTREACHED() << "Got a notification we didn't register for.";
   }
@@ -193,41 +151,11 @@
 }
 
 void UnloadController::TabDetachedImpl(content::WebContents* contents) {
-  if (tabs_needing_unload_ack_.find(contents) !=
-      tabs_needing_unload_ack_.end()) {
-    // Tab needs unload to complete.
-    // It will send |NOTIFICATION_WEB_CONTENTS_DISCONNECTED| when done.
-    return;
-  }
-
-  // If WEB_CONTENTS_DISCONNECTED was received then the notification may have
-  // already been unregistered.
-  const content::NotificationSource& source =
-      content::Source<content::WebContents>(contents);
-  if (registrar_.IsRegistered(this,
-                              content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED,
-                              source)) {
-    registrar_.Remove(this,
-                      content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED,
-                      source);
-  }
-
   if (is_attempting_to_close_browser_)
-    ClearUnloadState(contents);
-}
-
-bool UnloadController::DetachWebContents(content::WebContents* contents) {
-  int index = browser_->tab_strip_model()->GetIndexOfWebContents(contents);
-  if (index != TabStripModel::kNoTab &&
-      contents->NeedToFireBeforeUnload()) {
-    tabs_needing_unload_ack_.insert(contents);
-    browser_->tab_strip_model()->DetachWebContentsAt(index);
-    contents->SetDelegate(detached_delegate_.get());
-    CoreTabHelper* core_tab_helper = CoreTabHelper::FromWebContents(contents);
-    core_tab_helper->OnUnloadDetachedStarted();
-    return true;
-  }
-  return false;
+    ClearUnloadState(contents, false);
+  registrar_.Remove(this,
+                    content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED,
+                    content::Source<content::WebContents>(contents));
 }
 
 void UnloadController::ProcessPendingTabs() {
@@ -238,105 +166,58 @@
     return;
   }
 
-  if (tab_needing_before_unload_ack_ != NULL) {
-    // Wait for |BeforeUnloadFired| before proceeding.
+  if (HasCompletedUnloadProcessing()) {
+    // We've finished all the unload events and can proceed to close the
+    // browser.
+    browser_->OnWindowClosing();
     return;
   }
 
-  // Process a beforeunload handler.
-  if (!tabs_needing_before_unload_.empty()) {
-    WebContentsSet::iterator it = tabs_needing_before_unload_.begin();
-    content::WebContents* contents = *it;
-    tabs_needing_before_unload_.erase(it);
+  // Process beforeunload tabs first. When that queue is empty, process
+  // unload tabs.
+  if (!tabs_needing_before_unload_fired_.empty()) {
+    content::WebContents* web_contents =
+        *(tabs_needing_before_unload_fired_.begin());
     // Null check render_view_host here as this gets called on a PostTask and
     // the tab's render_view_host may have been nulled out.
-    if (contents->GetRenderViewHost()) {
-      tab_needing_before_unload_ack_ = contents;
-
-      CoreTabHelper* core_tab_helper = CoreTabHelper::FromWebContents(contents);
-      core_tab_helper->OnCloseStarted();
-
-      contents->GetRenderViewHost()->FirePageBeforeUnload(false);
+    if (web_contents->GetRenderViewHost()) {
+      web_contents->GetRenderViewHost()->FirePageBeforeUnload(false);
     } else {
-      ProcessPendingTabs();
+      ClearUnloadState(web_contents, true);
     }
-    return;
-  }
-
-  // Process all the unload handlers. (The beforeunload handlers have finished.)
-  if (!tabs_needing_unload_.empty()) {
-    browser_->OnWindowClosing();
-
-    // Run unload handlers detached since no more interaction is possible.
-    WebContentsSet::iterator it = tabs_needing_unload_.begin();
-    while (it != tabs_needing_unload_.end()) {
-      WebContentsSet::iterator current = it++;
-      content::WebContents* contents = *current;
-      tabs_needing_unload_.erase(current);
-      // Null check render_view_host here as this gets called on a PostTask
-      // and the tab's render_view_host may have been nulled out.
-      if (contents->GetRenderViewHost()) {
-        CoreTabHelper* core_tab_helper =
-            CoreTabHelper::FromWebContents(contents);
-        core_tab_helper->OnUnloadStarted();
-        DetachWebContents(contents);
-        contents->GetRenderViewHost()->ClosePage();
-      }
-    }
-
-    // Get the browser hidden.
-    if (browser_->tab_strip_model()->empty()) {
-      browser_->TabStripEmpty();
+  } else if (!tabs_needing_unload_fired_.empty()) {
+    // We've finished firing all beforeunload events and can proceed with unload
+    // events.
+    // TODO(ojan): We should add a call to browser_shutdown::OnShutdownStarting
+    // somewhere around here so that we have accurate measurements of shutdown
+    // time.
+    // TODO(ojan): We can probably fire all the unload events in parallel and
+    // get a perf benefit from that in the cases where the tab hangs in it's
+    // unload handler or takes a long time to page in.
+    content::WebContents* web_contents = *(tabs_needing_unload_fired_.begin());
+    // Null check render_view_host here as this gets called on a PostTask and
+    // the tab's render_view_host may have been nulled out.
+    if (web_contents->GetRenderViewHost()) {
+      web_contents->GetRenderViewHost()->ClosePage();
     } else {
-      browser_->tab_strip_model()->CloseAllTabs();  // tabs not needing unload
+      ClearUnloadState(web_contents, true);
     }
-    return;
-  }
-
-  if (HasCompletedUnloadProcessing()) {
-    browser_->OnWindowClosing();
-
-    // Get the browser closed.
-    if (browser_->tab_strip_model()->empty()) {
-      browser_->TabStripEmpty();
-    } else {
-      // There may be tabs if the last tab needing beforeunload crashed.
-      browser_->tab_strip_model()->CloseAllTabs();
-    }
-    return;
+  } else {
+    NOTREACHED();
   }
 }
 
 bool UnloadController::HasCompletedUnloadProcessing() const {
   return is_attempting_to_close_browser_ &&
-      tabs_needing_before_unload_.empty() &&
-      tab_needing_before_unload_ack_ == NULL &&
-      tabs_needing_unload_.empty() &&
-      tabs_needing_unload_ack_.empty();
+      tabs_needing_before_unload_fired_.empty() &&
+      tabs_needing_unload_fired_.empty();
 }
 
 void UnloadController::CancelWindowClose() {
   // Closing of window can be canceled from a beforeunload handler.
   DCHECK(is_attempting_to_close_browser_);
-  tabs_needing_before_unload_.clear();
-  if (tab_needing_before_unload_ack_ != NULL) {
-
-    CoreTabHelper* core_tab_helper =
-        CoreTabHelper::FromWebContents(tab_needing_before_unload_ack_);
-    core_tab_helper->OnCloseCanceled();
-    tab_needing_before_unload_ack_ = NULL;
-  }
-  for (WebContentsSet::iterator it = tabs_needing_unload_.begin();
-       it != tabs_needing_unload_.end(); it++) {
-    content::WebContents* contents = *it;
-
-    CoreTabHelper* core_tab_helper = CoreTabHelper::FromWebContents(contents);
-    core_tab_helper->OnCloseCanceled();
-  }
-  tabs_needing_unload_.clear();
-
-  // No need to clear tabs_needing_unload_ack_. Those tabs are already detached.
-
+  tabs_needing_before_unload_fired_.clear();
+  tabs_needing_unload_fired_.clear();
   is_attempting_to_close_browser_ = false;
 
   content::NotificationService::current()->Notify(
@@ -345,34 +226,33 @@
       content::NotificationService::NoDetails());
 }
 
-void UnloadController::ClearUnloadState(content::WebContents* contents) {
-  if (tabs_needing_unload_ack_.erase(contents) > 0) {
-    if (HasCompletedUnloadProcessing())
-      PostTaskForProcessPendingTabs();
-    return;
-  }
+bool UnloadController::RemoveFromSet(UnloadListenerSet* set,
+                                     content::WebContents* web_contents) {
+  DCHECK(is_attempting_to_close_browser_);
 
-  if (!is_attempting_to_close_browser_)
-    return;
-
-  if (tab_needing_before_unload_ack_ == contents) {
-    tab_needing_before_unload_ack_ = NULL;
-    PostTaskForProcessPendingTabs();
-    return;
+  UnloadListenerSet::iterator iter =
+      std::find(set->begin(), set->end(), web_contents);
+  if (iter != set->end()) {
+    set->erase(iter);
+    return true;
   }
-
-  if (tabs_needing_before_unload_.erase(contents) > 0 ||
-      tabs_needing_unload_.erase(contents) > 0) {
-    if (tab_needing_before_unload_ack_ == NULL)
-      PostTaskForProcessPendingTabs();
-  }
+  return false;
 }
 
-void UnloadController::PostTaskForProcessPendingTabs() {
-  base::MessageLoop::current()->PostTask(
-      FROM_HERE,
-      base::Bind(&UnloadController::ProcessPendingTabs,
-                 weak_factory_.GetWeakPtr()));
+void UnloadController::ClearUnloadState(content::WebContents* web_contents,
+                                        bool process_now) {
+  if (is_attempting_to_close_browser_) {
+    RemoveFromSet(&tabs_needing_before_unload_fired_, web_contents);
+    RemoveFromSet(&tabs_needing_unload_fired_, web_contents);
+    if (process_now) {
+      ProcessPendingTabs();
+    } else {
+      base::MessageLoop::current()->PostTask(
+          FROM_HERE,
+          base::Bind(&UnloadController::ProcessPendingTabs,
+                     weak_factory_.GetWeakPtr()));
+    }
+  }
 }
 
 }  // namespace chrome
diff --git a/chrome/browser/ui/unload_controller.h b/chrome/browser/ui/unload_controller.h
index 47e50b0..4c13c67 100644
--- a/chrome/browser/ui/unload_controller.h
+++ b/chrome/browser/ui/unload_controller.h
@@ -7,9 +7,7 @@
 
 #include <set>
 
-#include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
-#include "base/strings/string_piece.h"
 #include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
@@ -24,33 +22,7 @@
 }
 
 namespace chrome {
-// UnloadController manages closing tabs and windows -- especially in
-// regards to beforeunload handlers (have proceed/cancel dialogs) and
-// unload handlers (have no user interaction).
-//
-// Typical flow of closing a tab:
-//  1. Browser calls CanCloseContents().
-//     If true, browser calls contents::CloseWebContents().
-//  2. WebContents notifies us via its delegate and BeforeUnloadFired()
-//     that the beforeunload handler was run. If the user allowed the
-//     close to continue, we detached the tab and hold onto it while the
-//     close finishes.
-//
-// Typical flow of closing a window:
-//  1. BrowserView::CanClose() calls TabsNeedBeforeUnloadFired().
-//     If beforeunload/unload handlers need to run, UnloadController returns
-//     true and calls ProcessPendingTabs() (private method).
-//  2. For each tab with a beforeunload/unload handler, ProcessPendingTabs()
-//        calls |CoreTabHelper::OnCloseStarted()|
-//        and   |web_contents->GetRenderViewHost()->FirePageBeforeUnload()|.
-//  3. If the user allowed the close to continue, we detach all the tabs with
-//     unload handlers, remove them from the tab strip, and finish closing
-//     the tabs in the background.
-//  4. The browser gets notified that the tab strip is empty and calls
-//     CloseFrame where the empty tab strip causes the window to hide.
-//     Once the detached tabs finish, the browser calls CloseFrame again and
-//     the window is finally closed.
-//
+
 class UnloadController : public content::NotificationObserver,
                          public TabStripModelObserver {
  public:
@@ -77,7 +49,7 @@
   }
 
   // Called in response to a request to close |browser_|'s window. Returns true
-  // when there are no remaining beforeunload handlers to be run.
+  // when there are no remaining unload handlers to be run.
   bool ShouldCloseWindow();
 
   // Returns true if |browser_| has any tabs that have BeforeUnload handlers
@@ -89,10 +61,9 @@
   //             could be pursued.
   bool TabsNeedBeforeUnloadFired();
 
-  // Returns true if all tabs' beforeunload/unload events have fired.
-  bool HasCompletedUnloadProcessing() const;
-
  private:
+  typedef std::set<content::WebContents*> UnloadListenerSet;
+
   // Overridden from content::NotificationObserver:
   virtual void Observe(int type,
                        const content::NotificationSource& source,
@@ -113,52 +84,43 @@
   void TabAttachedImpl(content::WebContents* contents);
   void TabDetachedImpl(content::WebContents* contents);
 
-  // Detach |contents| and wait for it to finish closing.
-  // The close must be inititiated outside of this method.
-  // Returns true if it succeeds.
-  bool DetachWebContents(content::WebContents* contents);
-
   // Processes the next tab that needs it's beforeunload/unload event fired.
   void ProcessPendingTabs();
 
+  // Whether we've completed firing all the tabs' beforeunload/unload events.
+  bool HasCompletedUnloadProcessing() const;
+
   // Clears all the state associated with processing tabs' beforeunload/unload
   // events since the user cancelled closing the window.
   void CancelWindowClose();
 
-  // Cleans up state appropriately when we are trying to close the
-  // browser or close a tab in the background. We also use this in the
-  // cases where a tab crashes or hangs even if the
-  // beforeunload/unload haven't successfully fired.
-  void ClearUnloadState(content::WebContents* contents);
+  // Removes |web_contents| from the passed |set|.
+  // Returns whether the tab was in the set in the first place.
+  bool RemoveFromSet(UnloadListenerSet* set,
+                     content::WebContents* web_contents);
 
-  // Helper for |ClearUnloadState| to unwind stack before proceeding.
-  void PostTaskForProcessPendingTabs();
-
-  // Log a step of the unload processing.
-  void LogUnloadStep(const base::StringPiece& step_name,
-                     content::WebContents* contents) const;
+  // Cleans up state appropriately when we are trying to close the browser and
+  // the tab has finished firing its unload handler. We also use this in the
+  // cases where a tab crashes or hangs even if the beforeunload/unload haven't
+  // successfully fired. If |process_now| is true |ProcessPendingTabs| is
+  // invoked immediately, otherwise it is invoked after a delay (PostTask).
+  //
+  // Typically you'll want to pass in true for |process_now|. Passing in true
+  // may result in deleting |tab|. If you know that shouldn't happen (because of
+  // the state of the stack), pass in false.
+  void ClearUnloadState(content::WebContents* web_contents, bool process_now);
 
   Browser* browser_;
 
   content::NotificationRegistrar registrar_;
 
-  typedef std::set<content::WebContents*> WebContentsSet;
+  // Tracks tabs that need there beforeunload event fired before we can
+  // close the browser. Only gets populated when we try to close the browser.
+  UnloadListenerSet tabs_needing_before_unload_fired_;
 
-  // Tracks tabs that need their beforeunload event started.
-  // Only gets populated when we try to close the browser.
-  WebContentsSet tabs_needing_before_unload_;
-
-  // Tracks the tab that needs its beforeunload event result.
-  // Only gets populated when we try to close the browser.
-  content::WebContents* tab_needing_before_unload_ack_;
-
-  // Tracks tabs that need their unload event started.
-  // Only gets populated when we try to close the browser.
-  WebContentsSet tabs_needing_unload_;
-
-  // Tracks tabs that need to finish running their unload event.
-  // Populated both when closing individual tabs and when closing the browser.
-  WebContentsSet tabs_needing_unload_ack_;
+  // Tracks tabs that need there unload event fired before we can
+  // close the browser. Only gets populated when we try to close the browser.
+  UnloadListenerSet tabs_needing_unload_fired_;
 
   // Whether we are processing the beforeunload and unload events of each tab
   // in preparation for closing the browser. UnloadController owns this state
@@ -166,10 +128,6 @@
   // Browser window isn't just immediately closed.
   bool is_attempting_to_close_browser_;
 
-  // Manage tabs with beforeunload/unload handlers that close detached.
-  class DetachedWebContentsDelegate;
-  scoped_ptr<DetachedWebContentsDelegate> detached_delegate_;
-
   base::WeakPtrFactory<UnloadController> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(UnloadController);
diff --git a/chrome/browser/ui/views/about_ipc_dialog.cc b/chrome/browser/ui/views/about_ipc_dialog.cc
index cb09301..23c5821 100644
--- a/chrome/browser/ui/views/about_ipc_dialog.cc
+++ b/chrome/browser/ui/views/about_ipc_dialog.cc
@@ -26,7 +26,7 @@
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/thread.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/app/chrome_dll_resource.h"
 #include "chrome/browser/ui/browser_dialogs.h"
diff --git a/chrome/browser/ui/views/app_list/app_list_controller_win.cc b/chrome/browser/ui/views/app_list/app_list_controller_win.cc
index 20ff1b4..d459a01 100644
--- a/chrome/browser/ui/views/app_list/app_list_controller_win.cc
+++ b/chrome/browser/ui/views/app_list/app_list_controller_win.cc
@@ -15,13 +15,14 @@
 #include "base/prefs/pref_service.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/sequenced_worker_pool.h"
-#include "base/time.h"
-#include "base/timer.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
 #include "base/win/shortcut.h"
 #include "base/win/windows_version.h"
 #include "chrome/app/chrome_dll_resource.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/extensions/extension_system.h"
 #include "chrome/browser/lifetime/application_lifetime.h"
 #include "chrome/browser/platform_util.h"
 #include "chrome/browser/profiles/profile.h"
@@ -257,10 +258,9 @@
   virtual bool CanPin() OVERRIDE;
   virtual void OnShowExtensionPrompt() OVERRIDE;
   virtual void OnCloseExtensionPrompt() OVERRIDE;
-  virtual bool CanShowCreateShortcutsDialog() OVERRIDE;
-  virtual void ShowCreateShortcutsDialog(
-      Profile* profile,
-      const std::string& extension_id) OVERRIDE;
+  virtual bool CanDoCreateShortcutsFlow(bool is_platform_app) OVERRIDE;
+  virtual void DoCreateShortcutsFlow(Profile* profile,
+                                     const std::string& extension_id) OVERRIDE;
   virtual void CreateNewWindow(Profile* profile, bool incognito) OVERRIDE;
   virtual void ActivateApp(Profile* profile,
                            const extensions::Extension* extension,
@@ -431,14 +431,16 @@
   AppListController::GetInstance()->set_can_close(true);
 }
 
-bool AppListControllerDelegateWin::CanShowCreateShortcutsDialog() {
+bool AppListControllerDelegateWin::CanDoCreateShortcutsFlow(
+    bool is_platform_app) {
   return true;
 }
 
-void AppListControllerDelegateWin::ShowCreateShortcutsDialog(
+void AppListControllerDelegateWin::DoCreateShortcutsFlow(
     Profile* profile,
     const std::string& extension_id) {
-  ExtensionService* service = profile->GetExtensionService();
+  ExtensionService* service =
+      extensions::ExtensionSystem::Get(profile)->extension_service();
   DCHECK(service);
   const extensions::Extension* extension = service->GetInstalledExtension(
       extension_id);
@@ -863,6 +865,28 @@
         ShowAppListDuringModeSwitch(initial_profile);
   }
 
+  // Migrate from legacy app launcher if we are on a non-canary and non-chromium
+  // build.
+#if defined(GOOGLE_CHROME_BUILD)
+  if (!InstallUtil::IsChromeSxSProcess() &&
+      !chrome_launcher_support::GetAnyAppHostPath().empty()) {
+    chrome_launcher_support::InstallationState state =
+        chrome_launcher_support::GetAppLauncherInstallationState();
+    if (state == chrome_launcher_support::NOT_INSTALLED) {
+      // If app_host.exe is found but can't be located in the registry,
+      // skip the migration as this is likely a developer build.
+      return;
+    } else if (state == chrome_launcher_support::INSTALLED_AT_SYSTEM_LEVEL) {
+      chrome_launcher_support::UninstallLegacyAppLauncher(
+          chrome_launcher_support::SYSTEM_LEVEL_INSTALLATION);
+    } else if (state == chrome_launcher_support::INSTALLED_AT_USER_LEVEL) {
+      chrome_launcher_support::UninstallLegacyAppLauncher(
+          chrome_launcher_support::USER_LEVEL_INSTALLATION);
+    }
+    EnableAppList();
+  }
+#endif
+
   // Instantiate AppListController so it listens for profile deletions.
   AppListController::GetInstance();
 
@@ -887,25 +911,21 @@
   // shortcut, they can restore it by pinning the start menu or desktop
   // shortcut.
   PrefService* local_state = g_browser_process->local_state();
-  bool has_been_enabled = local_state->GetBoolean(
-      apps::prefs::kAppLauncherHasBeenEnabled);
-  if (!has_been_enabled) {
-    local_state->SetBoolean(apps::prefs::kAppLauncherHasBeenEnabled, true);
-    ShellIntegration::ShortcutLocations shortcut_locations;
-    shortcut_locations.on_desktop = true;
-    shortcut_locations.in_quick_launch_bar = true;
-    shortcut_locations.in_applications_menu = true;
-    BrowserDistribution* dist = BrowserDistribution::GetDistribution();
-    shortcut_locations.applications_menu_subdir = dist->GetAppShortCutName();
-    base::FilePath user_data_dir(
-        g_browser_process->profile_manager()->user_data_dir());
+  local_state->SetBoolean(apps::prefs::kAppLauncherHasBeenEnabled, true);
+  ShellIntegration::ShortcutLocations shortcut_locations;
+  shortcut_locations.on_desktop = true;
+  shortcut_locations.in_quick_launch_bar = true;
+  shortcut_locations.in_applications_menu = true;
+  BrowserDistribution* dist = BrowserDistribution::GetDistribution();
+  shortcut_locations.applications_menu_subdir = dist->GetAppShortCutName();
+  base::FilePath user_data_dir(
+      g_browser_process->profile_manager()->user_data_dir());
 
-    content::BrowserThread::PostTask(
-        content::BrowserThread::FILE,
-        FROM_HERE,
-        base::Bind(&CreateAppListShortcuts,
-                   user_data_dir, GetAppModelId(), shortcut_locations));
-  }
+  content::BrowserThread::PostTask(
+      content::BrowserThread::FILE,
+      FROM_HERE,
+      base::Bind(&CreateAppListShortcuts,
+                  user_data_dir, GetAppModelId(), shortcut_locations));
 }
 
 void AppListController::DisableAppList() {
@@ -937,7 +957,7 @@
 
   // We only need to initialize the view if there's no view already created and
   // there's no profile loading to be shown.
-  return !current_view_ && !profile_loader().AnyProfilesLoading();
+  return !current_view_ && !profile_loader().IsAnyProfileLoading();
 }
 
 void AppListController::LoadProfileForWarmup() {
diff --git a/chrome/browser/ui/views/ash/tab_scrubber.h b/chrome/browser/ui/views/ash/tab_scrubber.h
index f22fbe5..d0511ad 100644
--- a/chrome/browser/ui/views/ash/tab_scrubber.h
+++ b/chrome/browser/ui/views/ash/tab_scrubber.h
@@ -5,7 +5,7 @@
 #ifndef CHROME_BROWSER_UI_VIEWS_ASH_TAB_SCRUBBER_H_
 #define CHROME_BROWSER_UI_VIEWS_ASH_TAB_SCRUBBER_H_
 
-#include "base/timer.h"
+#include "base/timer/timer.h"
 #include "chrome/browser/ui/views/frame/immersive_mode_controller.h"
 #include "chrome/browser/ui/views/tabs/tab_strip_observer.h"
 #include "content/public/browser/notification_observer.h"
diff --git a/chrome/browser/ui/views/autofill/autofill_dialog_views.cc b/chrome/browser/ui/views/autofill/autofill_dialog_views.cc
index 32dff53..0bd2fd0 100644
--- a/chrome/browser/ui/views/autofill/autofill_dialog_views.cc
+++ b/chrome/browser/ui/views/autofill/autofill_dialog_views.cc
@@ -12,8 +12,8 @@
 #include "chrome/browser/ui/autofill/autofill_dialog_controller.h"
 #include "chrome/browser/ui/autofill/autofill_dialog_sign_in_delegate.h"
 #include "chrome/browser/ui/views/constrained_window_views.h"
-#include "components/autofill/browser/autofill_type.h"
 #include "components/autofill/content/browser/wallet/wallet_service_url.h"
+#include "components/autofill/core/browser/autofill_type.h"
 #include "components/web_modal/web_contents_modal_dialog_manager.h"
 #include "components/web_modal/web_contents_modal_dialog_manager_delegate.h"
 #include "content/public/browser/native_web_keyboard_event.h"
@@ -39,6 +39,7 @@
 #include "ui/views/controls/button/label_button.h"
 #include "ui/views/controls/button/label_button_border.h"
 #include "ui/views/controls/combobox/combobox.h"
+#include "ui/views/controls/focusable_border.h"
 #include "ui/views/controls/image_view.h"
 #include "ui/views/controls/label.h"
 #include "ui/views/controls/link.h"
@@ -66,6 +67,9 @@
 // Horizontal padding between text and other elements (in pixels).
 const int kAroundTextPadding = 4;
 
+// Padding around icons inside DecoratedTextfields.
+const size_t kTextfieldIconPadding = 3;
+
 // Size of the triangular mark that indicates an invalid textfield (in pixels).
 const size_t kDogEarSize = 10;
 
@@ -76,8 +80,11 @@
 // Vertical padding above and below each detail section (in pixels).
 const size_t kDetailSectionInset = 10;
 
-const size_t kAutocheckoutProgressBarWidth = 300;
-const size_t kAutocheckoutProgressBarHeight = 11;
+const size_t kAutocheckoutStepsAreaPadding = 28;
+const size_t kAutocheckoutStepInset = 20;
+
+const size_t kAutocheckoutProgressBarWidth = 375;
+const size_t kAutocheckoutProgressBarHeight = 15;
 
 const size_t kArrowHeight = 7;
 const size_t kArrowWidth = 2 * kArrowHeight;
@@ -311,57 +318,74 @@
   DISALLOW_COPY_AND_ASSIGN(DetailsContainerView);
 };
 
-// ButtonStripView wraps the Autocheckout progress bar and the "[X] Save details
-// in Chrome" checkbox and listens for visibility changes.
-class ButtonStripView : public views::View {
+// A view that propagates visibility and preferred size changes.
+class LayoutPropagationView : public views::View {
  public:
-  ButtonStripView() {}
-  virtual ~ButtonStripView() {}
+  LayoutPropagationView() {}
+  virtual ~LayoutPropagationView() {}
 
  protected:
   virtual void ChildVisibilityChanged(views::View* child) OVERRIDE {
     PreferredSizeChanged();
   }
+  virtual void ChildPreferredSizeChanged(views::View* child) OVERRIDE {
+    PreferredSizeChanged();
+  }
 
  private:
-  DISALLOW_COPY_AND_ASSIGN(ButtonStripView);
+  DISALLOW_COPY_AND_ASSIGN(LayoutPropagationView);
+};
+
+// A class which displays the status of an individual step in an
+// Autocheckout flow.
+class AutocheckoutStepProgressView : public views::View {
+ public:
+  AutocheckoutStepProgressView(const string16& description,
+                               const gfx::Font& font,
+                               const SkColor color,
+                               const bool is_icon_visible) {
+    views::GridLayout* layout = new views::GridLayout(this);
+    SetLayoutManager(layout);
+    const int kColumnSetId = 0;
+    views::ColumnSet* columns = layout->AddColumnSet(kColumnSetId);
+    columns->AddColumn(views::GridLayout::LEADING,
+                       views::GridLayout::LEADING,
+                       0,
+                       views::GridLayout::USE_PREF,
+                       0,
+                       0);
+    columns->AddPaddingColumn(0, 8);
+    columns->AddColumn(views::GridLayout::LEADING,
+                       views::GridLayout::LEADING,
+                       0,
+                       views::GridLayout::USE_PREF,
+                       0,
+                       0);
+    layout->StartRow(0, kColumnSetId);
+    views::Label* label = new views::Label();
+    label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
+    label->set_border(views::Border::CreateEmptyBorder(0, 0, 0, 0));
+    label->SetText(description);
+    label->SetFont(font);
+    label->SetEnabledColor(color);
+
+    views::ImageView* icon = new views::ImageView();
+    icon->SetVisible(is_icon_visible);
+    icon->SetImage(ui::ResourceBundle::GetSharedInstance().GetImageNamed(
+        IDR_WALLET_STEP_CHECK).ToImageSkia());
+
+    layout->AddView(icon);
+    layout->AddView(label);
+  }
+
+  virtual ~AutocheckoutStepProgressView() {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(AutocheckoutStepProgressView);
 };
 
 }  // namespace
 
-// AutofillDialogViews::SizeLimitedScrollView ----------------------------------
-
-AutofillDialogViews::SizeLimitedScrollView::SizeLimitedScrollView(
-    views::View* scroll_contents)
-    : max_height_(-1) {
-  set_hide_horizontal_scrollbar(true);
-  SetContents(scroll_contents);
-}
-
-AutofillDialogViews::SizeLimitedScrollView::~SizeLimitedScrollView() {}
-
-void AutofillDialogViews::SizeLimitedScrollView::Layout() {
-  contents()->SizeToPreferredSize();
-  ScrollView::Layout();
-}
-
-gfx::Size AutofillDialogViews::SizeLimitedScrollView::GetPreferredSize() {
-  gfx::Size size = contents()->GetPreferredSize();
-  if (max_height_ >= 0 && max_height_ < size.height())
-    size.set_height(max_height_);
-
-  return size;
-}
-
-void AutofillDialogViews::SizeLimitedScrollView::SetMaximumHeight(
-    int max_height) {
-  int old_max = max_height_;
-  max_height_ = max_height;
-
-  if (max_height_ < height() || old_max <= height())
-    PreferredSizeChanged();
-}
-
 // AutofillDialogViews::ErrorBubble --------------------------------------------
 
 AutofillDialogViews::ErrorBubble::ErrorBubble(views::View* anchor,
@@ -371,7 +395,7 @@
       observer_(this) {
   widget_ = new views::Widget;
   views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP);
-  params.transparent = true;
+  params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
   views::Widget* anchor_widget = anchor->GetWidget();
   DCHECK(anchor_widget);
   params.parent = anchor_widget->GetNativeView();
@@ -429,13 +453,19 @@
     const string16& default_value,
     const string16& placeholder,
     views::TextfieldController* controller)
-    : textfield_(new views::Textfield()),
+    : border_(new views::FocusableBorder()),
       invalid_(false) {
-  textfield_->set_placeholder_text(placeholder);
-  textfield_->SetText(default_value);
-  textfield_->SetController(controller);
-  SetLayoutManager(new views::FillLayout());
-  AddChildView(textfield_);
+  set_background(
+      views::Background::CreateSolidBackground(GetBackgroundColor()));
+
+  set_border(border_);
+  // Removes the border from |native_wrapper_|.
+  RemoveBorder();
+
+  set_placeholder_text(placeholder);
+  SetText(default_value);
+  SetController(controller);
+  SetHorizontalMargins(0, 0);
 }
 
 AutofillDialogViews::DecoratedTextfield::~DecoratedTextfield() {}
@@ -443,9 +473,21 @@
 void AutofillDialogViews::DecoratedTextfield::SetInvalid(bool invalid) {
   invalid_ = invalid;
   if (invalid)
-    textfield_->SetBorderColor(kWarningColor);
+    border_->SetColor(kWarningColor);
   else
-    textfield_->UseDefaultBorderColor();
+    border_->UseDefaultColor();
+  SchedulePaint();
+}
+
+void AutofillDialogViews::DecoratedTextfield::SetIcon(const gfx::Image& icon) {
+  int icon_space = icon.IsEmpty() ? 0 :
+                                    icon.Width() + 2 * kTextfieldIconPadding;
+  int left = base::i18n::IsRTL() ? icon_space : 0;
+  int right = base::i18n::IsRTL() ? 0 : icon_space;
+  SetHorizontalMargins(left, right);
+  icon_ = icon;
+
+  PreferredSizeChanged();
   SchedulePaint();
 }
 
@@ -457,17 +499,30 @@
     gfx::Canvas* canvas) {}
 
 void AutofillDialogViews::DecoratedTextfield::OnPaint(gfx::Canvas* canvas) {
-  // Draw the textfield first.
-  canvas->Save();
-  if (FlipCanvasOnPaintForRTLUI()) {
-    canvas->Translate(gfx::Vector2d(width(), 0));
-    canvas->Scale(-1, 1);
-  }
-  views::View::PaintChildren(canvas);
-  canvas->Restore();
+  // Draw the border and background.
+  border_->set_has_focus(HasFocus());
+  views::View::OnPaint(canvas);
 
-  // Then draw extra stuff on top.
+  // Then the textfield.
+  views::View::PaintChildren(canvas);
+
+  // Then the icon.
+  if (!icon_.IsEmpty()) {
+    gfx::Rect bounds = GetContentsBounds();
+    int x = base::i18n::IsRTL() ?
+        kTextfieldIconPadding :
+        bounds.right() - icon_.Width() - kTextfieldIconPadding;
+    canvas->DrawImageInt(icon_.AsImageSkia(), x,
+                         bounds.y() + (bounds.height() - icon_.Height()) / 2);
+  }
+
+  // Then the invalid indicator.
   if (invalid_) {
+    if (base::i18n::IsRTL()) {
+      canvas->Translate(gfx::Vector2d(width(), 0));
+      canvas->Scale(-1, 1);
+    }
+
     SkPath dog_ear;
     dog_ear.moveTo(width() - kDogEarSize, 0);
     dog_ear.lineTo(width(), 0);
@@ -478,10 +533,6 @@
   }
 }
 
-void AutofillDialogViews::DecoratedTextfield::RequestFocus() {
-  textfield()->RequestFocus();
-}
-
 // AutofillDialogViews::AccountChooser -----------------------------------------
 
 AutofillDialogViews::AccountChooser::AccountChooser(
@@ -508,6 +559,8 @@
 AutofillDialogViews::AccountChooser::~AccountChooser() {}
 
 void AutofillDialogViews::AccountChooser::Update() {
+  SetVisible(!controller_->ShouldShowSpinner());
+
   gfx::Image icon = controller_->AccountChooserImage();
   image_->SetImage(icon.AsImageSkia());
   label_->SetText(controller_->AccountChooserText());
@@ -656,13 +709,6 @@
 
 void AutofillDialogViews::OnWidgetBoundsChanged(views::Widget* widget,
                                                 const gfx::Rect& new_bounds) {
-  int non_scrollable_height = window_->GetContentsView()->bounds().height() -
-      scrollable_area_->bounds().height();
-  int browser_window_height = widget->GetContentsView()->bounds().height();
-
-  scrollable_area_->SetMaximumHeight(
-      std::max(kMinimumContentsHeight,
-               (browser_window_height - non_scrollable_height) * 8 / 10));
   ContentsPreferredSizeChanged();
 }
 
@@ -806,11 +852,12 @@
   label_container_->AddChildView(decorated_);
   decorated_->SetVisible(false);
   // TODO(estade): get the sizing and spacing right on this textfield.
-  decorated_->textfield()->set_default_width_in_chars(10);
+  decorated_->set_default_width_in_chars(10);
   AddChildView(label_container_);
 
   label_line_2_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
   label_line_2_->SetVisible(false);
+  label_line_2_->SetMultiLine(true);
   AddChildView(label_line_2_);
 
   SetLayoutManager(new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0));
@@ -845,16 +892,42 @@
 
 void AutofillDialogViews::SuggestionView::ShowTextfield(
     const string16& placeholder_text,
-    const gfx::ImageSkia& icon) {
-  decorated_->textfield()->set_placeholder_text(placeholder_text);
-  decorated_->textfield()->SetIcon(icon);
+    const gfx::Image& icon) {
+  decorated_->set_placeholder_text(placeholder_text);
+  decorated_->SetIcon(icon);
   decorated_->SetVisible(true);
   // The textfield will increase the height of the first row and cause the
   // label to be aligned properly, so the border is not necessary.
   label_->set_border(NULL);
 }
 
-// AutofilDialogViews::AutocheckoutProgressBar ---------------------------------
+// AutofillDialogViews::AutocheckoutStepsArea ---------------------------------
+
+AutofillDialogViews::AutocheckoutStepsArea::AutocheckoutStepsArea() {
+  SetLayoutManager(new views::BoxLayout(views::BoxLayout::kVertical,
+                                        kAutocheckoutStepsAreaPadding,
+                                        0,
+                                        kAutocheckoutStepInset));
+}
+
+void AutofillDialogViews::AutocheckoutStepsArea::SetSteps(
+    const std::vector<DialogAutocheckoutStep>& steps) {
+  RemoveAllChildViews(true);
+  for (size_t i = 0; i < steps.size(); ++i) {
+    const DialogAutocheckoutStep& step = steps[i];
+    AutocheckoutStepProgressView* progressView =
+        new AutocheckoutStepProgressView(step.GetDisplayText(),
+                                         step.GetTextFont(),
+                                         step.GetTextColor(),
+                                         step.IsIconVisible());
+
+    AddChildView(progressView);
+  }
+
+  PreferredSizeChanged();
+}
+
+// AutofillDialogViews::AutocheckoutProgressBar
 
 AutofillDialogViews::AutocheckoutProgressBar::AutocheckoutProgressBar() {}
 AutofillDialogViews::AutocheckoutProgressBar::~AutocheckoutProgressBar() {}
@@ -877,16 +950,16 @@
 AutofillDialogViews::AutofillDialogViews(AutofillDialogController* controller)
     : controller_(controller),
       window_(NULL),
-      contents_(NULL),
       notification_area_(NULL),
       account_chooser_(NULL),
       sign_in_webview_(NULL),
-      main_container_(NULL),
       scrollable_area_(NULL),
       details_container_(NULL),
+      loading_shield_(NULL),
       overlay_view_(NULL),
       button_strip_extra_view_(NULL),
       save_in_chrome_checkbox_(NULL),
+      autocheckout_steps_area_(NULL),
       autocheckout_progress_bar_view_(NULL),
       autocheckout_progress_bar_(NULL),
       footnote_view_(NULL),
@@ -945,7 +1018,6 @@
       views::Widget::GetTopLevelWidgetForNativeView(
           controller_->web_contents()->GetView()->GetNativeView());
   observer_.Add(browser_widget);
-  OnWidgetBoundsChanged(browser_widget, gfx::Rect());
 }
 
 void AutofillDialogViews::Hide() {
@@ -955,6 +1027,15 @@
 
 void AutofillDialogViews::UpdateAccountChooser() {
   account_chooser_->Update();
+  // TODO(estade): replace this with a better loading image/animation.
+  // See http://crbug.com/230932
+  string16 new_loading_message = (controller_->ShouldShowSpinner() ?
+      ASCIIToUTF16("Loading...") : base::string16());
+  if (new_loading_message != loading_shield_->text()) {
+    loading_shield_->SetText(new_loading_message);
+    loading_shield_->SetVisible(!new_loading_message.empty());
+    Layout();
+  }
 
   // Update legal documents for the account.
   if (footnote_view_) {
@@ -976,6 +1057,11 @@
   }
 }
 
+void AutofillDialogViews::UpdateAutocheckoutStepsArea() {
+  autocheckout_steps_area_->SetSteps(controller_->CurrentAutocheckoutSteps());
+  ContentsPreferredSizeChanged();
+}
+
 void AutofillDialogViews::UpdateButtonStrip() {
   button_strip_extra_view_->SetVisible(
       GetDialogButtons() != ui::DIALOG_BUTTON_NONE);
@@ -987,7 +1073,7 @@
 }
 
 void AutofillDialogViews::UpdateDetailArea() {
-  details_container_->SetVisible(controller_->ShouldShowDetailArea());
+  scrollable_area_->SetVisible(controller_->ShouldShowDetailArea());
   ContentsPreferredSizeChanged();
 }
 
@@ -1012,7 +1098,7 @@
   TextfieldMap::iterator text_mapping =
       group->textfields.find(&originating_input);
   if (text_mapping != group->textfields.end())
-    text_mapping->second->textfield()->SetText(string16());
+    text_mapping->second->SetText(string16());
 
   // If the Autofill data comes from a credit card, make sure to overwrite the
   // CC comboboxes (even if they already have something in them). If the
@@ -1035,7 +1121,7 @@
   DetailsGroup* group = GroupForSection(section);
   for (TextfieldMap::const_iterator it = group->textfields.begin();
        it != group->textfields.end(); ++it) {
-    output->insert(std::make_pair(it->first, it->second->textfield()->text()));
+    output->insert(std::make_pair(it->first, it->second->text()));
   }
   for (ComboboxMap::const_iterator it = group->comboboxes.begin();
        it != group->comboboxes.end(); ++it) {
@@ -1048,7 +1134,7 @@
   DialogSection billing_section = controller_->SectionIsActive(SECTION_CC) ?
       SECTION_CC : SECTION_CC_BILLING;
   return GroupForSection(billing_section)->suggested_info->
-      decorated_textfield()->textfield()->text();
+      decorated_textfield()->text();
 }
 
 bool AutofillDialogViews::SaveDetailsLocally() {
@@ -1062,7 +1148,6 @@
 
   sign_in_webview_->LoadInitialURL(wallet::GetSignInUrl());
 
-  main_container_->SetVisible(false);
   sign_in_webview_->SetVisible(true);
   UpdateButtonStrip();
   ContentsPreferredSizeChanged();
@@ -1071,7 +1156,6 @@
 
 void AutofillDialogViews::HideSignIn() {
   sign_in_webview_->SetVisible(false);
-  main_container_->SetVisible(true);
   UpdateButtonStrip();
   ContentsPreferredSizeChanged();
 }
@@ -1144,6 +1228,13 @@
   NOTREACHED();
 }
 
+void AutofillDialogViews::SetTextContentsOfSuggestionInput(
+    DialogSection section,
+    const base::string16& text) {
+  GroupForSection(section)->suggested_info->decorated_textfield()->
+      SetText(text);
+}
+
 void AutofillDialogViews::ActivateInput(const DetailInput& input) {
   TextfieldEditedOrActivated(TextfieldForInput(input), false);
 }
@@ -1164,6 +1255,93 @@
   return true;
 }
 
+gfx::Size AutofillDialogViews::GetPreferredSize() {
+  gfx::Insets insets = GetInsets();
+  gfx::Size scroll_size = scrollable_area_->contents()->GetPreferredSize();
+  int width = scroll_size.width() + insets.width();
+
+  if (sign_in_webview_->visible()) {
+    gfx::Size size = static_cast<views::View*>(sign_in_webview_)->
+        GetPreferredSize();
+    return gfx::Size(width, size.height() + insets.height());
+  }
+
+  int base_height = insets.height();
+  int notification_height = notification_area_->
+      GetHeightForWidth(scroll_size.width());
+  if (notification_height > 0)
+    base_height += notification_height + views::kRelatedControlVerticalSpacing;
+
+  int steps_height = autocheckout_steps_area_->
+      GetHeightForWidth(scroll_size.width());
+  if (steps_height > 0)
+    base_height += steps_height + views::kRelatedControlVerticalSpacing;
+
+  // When the scroll area isn't visible, it still sets the width but doesn't
+  // factor into height.
+  if (!scrollable_area_->visible())
+    return gfx::Size(width, base_height);
+
+  // Show as much of the scroll view as is possible without going past the
+  // bottom of the browser window.
+  views::Widget* widget =
+      views::Widget::GetTopLevelWidgetForNativeView(
+          controller_->web_contents()->GetView()->GetNativeView());
+  int browser_window_height =
+      widget ? widget->GetContentsView()->bounds().height() : INT_MAX;
+  const int kWindowDecorationHeight = 200;
+  int height = base_height + std::min(
+      scroll_size.height(),
+      std::max(kMinimumContentsHeight,
+               browser_window_height - base_height - kWindowDecorationHeight));
+
+  return gfx::Size(width, height);
+}
+
+void AutofillDialogViews::Layout() {
+  gfx::Rect content_bounds = GetContentsBounds();
+  if (sign_in_webview_->visible()) {
+    sign_in_webview_->SetBoundsRect(content_bounds);
+    return;
+  }
+
+  const int x = content_bounds.x();
+  const int y = content_bounds.y();
+  const int w = content_bounds.width();
+  // Layout notification area at top of dialog.
+  int notification_height = notification_area_->GetHeightForWidth(w);
+  notification_area_->SetBounds(x, y, w, notification_height);
+
+  // Layout Autocheckout steps at bottom of dialog.
+  int steps_height = autocheckout_steps_area_->GetHeightForWidth(w);
+  autocheckout_steps_area_->SetBounds(x, content_bounds.bottom() - steps_height,
+                                      w, steps_height);
+
+  // The rest (the |scrollable_area_|) takes up whatever's left.
+  if (scrollable_area_->visible()) {
+    int scroll_y = y;
+    if (notification_height > 0)
+      scroll_y += notification_height + views::kRelatedControlVerticalSpacing;
+
+    int scroll_bottom = content_bounds.bottom();
+    if (steps_height > 0)
+      scroll_bottom -= steps_height + views::kRelatedControlVerticalSpacing;
+
+    scrollable_area_->contents()->SizeToPreferredSize();
+    scrollable_area_->SetBounds(x, scroll_y, w, scroll_bottom - scroll_y);
+  }
+
+  if (loading_shield_->visible())
+    loading_shield_->SetBoundsRect(bounds());
+
+  if (error_bubble_)
+    error_bubble_->UpdatePosition();
+}
+
+void AutofillDialogViews::OnBoundsChanged(const gfx::Rect& previous_bounds) {
+  sign_in_delegate_->SetMinWidth(GetContentsBounds().width());
+}
+
 string16 AutofillDialogViews::GetWindowTitle() const {
   return controller_->DialogTitle();
 }
@@ -1178,18 +1356,6 @@
   controller_->ViewClosed();
 }
 
-views::Widget* AutofillDialogViews::GetWidget() {
-  return contents_->GetWidget();
-}
-
-const views::Widget* AutofillDialogViews::GetWidget() const {
-  return contents_->GetWidget();
-}
-
-views::View* AutofillDialogViews::GetContentsView() {
-  return contents_;
-}
-
 int AutofillDialogViews::GetDialogButtons() const {
   if (sign_in_webview_->visible())
     return ui::DIALOG_BUTTON_NONE;
@@ -1216,7 +1382,7 @@
 }
 
 views::View* AutofillDialogViews::CreateFootnoteView() {
-  footnote_view_ = new views::View();
+  footnote_view_ = new LayoutPropagationView();
   footnote_view_->SetLayoutManager(
       new views::BoxLayout(views::BoxLayout::kVertical,
                            kLegalDocPadding,
@@ -1368,7 +1534,7 @@
 }
 
 void AutofillDialogViews::InitChildViews() {
-  button_strip_extra_view_ = new ButtonStripView();
+  button_strip_extra_view_ = new LayoutPropagationView();
   button_strip_extra_view_->SetLayoutManager(
       new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, 0));
 
@@ -1379,12 +1545,7 @@
 
   autocheckout_progress_bar_view_ = new views::View();
   autocheckout_progress_bar_view_->SetLayoutManager(
-      new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0));
-
-  views::Label* progress_bar_label = new views::Label();
-  progress_bar_label->SetText(controller_->ProgressBarText());
-  progress_bar_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
-  autocheckout_progress_bar_view_->AddChildView(progress_bar_label);
+      new views::BoxLayout(views::BoxLayout::kVertical, 0, 15, 0));
 
   autocheckout_progress_bar_ = new AutocheckoutProgressBar();
   autocheckout_progress_bar_view_->AddChildView(autocheckout_progress_bar_);
@@ -1392,37 +1553,36 @@
   button_strip_extra_view_->AddChildView(autocheckout_progress_bar_view_);
   autocheckout_progress_bar_view_->SetVisible(false);
 
-  contents_ = new views::View();
-  contents_->SetLayoutManager(
-      new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, 0));
-  contents_->AddChildView(CreateMainContainer());
+  account_chooser_ = new AccountChooser(controller_);
+  notification_area_ = new NotificationArea(controller_);
+  notification_area_->set_arrow_centering_anchor(account_chooser_->AsWeakPtr());
+  AddChildView(notification_area_);
+
+  scrollable_area_ = new views::ScrollView();
+  scrollable_area_->set_hide_horizontal_scrollbar(true);
+  scrollable_area_->SetContents(CreateDetailsContainer());
+  AddChildView(scrollable_area_);
+
+  autocheckout_steps_area_ = new AutocheckoutStepsArea();
+  AddChildView(autocheckout_steps_area_);
+
+  loading_shield_ = new views::Label();
+  loading_shield_->SetVisible(false);
+  loading_shield_->set_background(views::Background::CreateSolidBackground(
+      GetNativeTheme()->GetSystemColor(
+          ui::NativeTheme::kColorId_DialogBackground)));
+  loading_shield_->SetFont(ui::ResourceBundle::GetSharedInstance().GetFont(
+      ui::ResourceBundle::BaseFont).DeriveFont(15));
+  AddChildView(loading_shield_);
+
   sign_in_webview_ = new views::WebView(controller_->profile());
   sign_in_webview_->SetVisible(false);
-  contents_->AddChildView(sign_in_webview_);
+  AddChildView(sign_in_webview_);
   sign_in_delegate_.reset(
       new AutofillDialogSignInDelegate(this,
                                        sign_in_webview_->GetWebContents()));
 }
 
-views::View* AutofillDialogViews::CreateMainContainer() {
-  main_container_ = new views::View();
-  main_container_->SetLayoutManager(
-      new views::BoxLayout(views::BoxLayout::kVertical, 0, 0,
-                           views::kRelatedControlVerticalSpacing));
-
-  account_chooser_ = new AccountChooser(controller_);
-  if (!views::DialogDelegate::UseNewStyle())
-    main_container_->AddChildView(account_chooser_);
-
-  notification_area_ = new NotificationArea(controller_);
-  notification_area_->set_arrow_centering_anchor(account_chooser_->AsWeakPtr());
-  main_container_->AddChildView(notification_area_);
-
-  scrollable_area_ = new SizeLimitedScrollView(CreateDetailsContainer());
-  main_container_->AddChildView(scrollable_area_);
-  return main_container_;
-}
-
 views::View* AutofillDialogViews::CreateDetailsContainer() {
   details_container_ = new DetailsContainerView(
       base::Bind(&AutofillDialogViews::DetailsContainerBoundsChanged,
@@ -1572,7 +1732,7 @@
 
       gfx::Image icon =
           controller_->IconForField(input.type, input.initial_value);
-      field->textfield()->SetIcon(icon.AsImageSkia());
+      field->SetIcon(icon);
 
       textfields->insert(std::make_pair(&input, field));
       view_to_add = field;
@@ -1602,12 +1762,12 @@
     TextfieldMap::iterator text_mapping = group->textfields.find(&input);
 
     if (text_mapping != group->textfields.end()) {
-      views::Textfield* textfield = text_mapping->second->textfield();
-      textfield->SetEnabled(input.editable);
-      if (textfield->text().empty() || clobber_inputs) {
-        textfield->SetText(iter->initial_value);
-        textfield->SetIcon(controller_->IconForField(
-            input.type, textfield->text()).AsImageSkia());
+      DecoratedTextfield* decorated = text_mapping->second;
+      decorated->SetEnabled(input.editable);
+      if (decorated->text().empty() || clobber_inputs) {
+        decorated->SetText(iter->initial_value);
+        decorated->SetIcon(
+            controller_->IconForField(input.type, decorated->text()));
       }
     }
 
@@ -1642,7 +1802,7 @@
   if (!suggestion_state.extra_text.empty()) {
     group.suggested_info->ShowTextfield(
         suggestion_state.extra_text,
-        suggestion_state.extra_icon.AsImageSkia());
+        suggestion_state.extra_icon);
   }
 
   group.manual_input->SetVisible(!show_suggestions);
@@ -1689,44 +1849,57 @@
   if (!view->GetWidget())
     return;
 
-  views::View* input =
-      view->GetAncestorWithClassName(kDecoratedTextfieldClassName);
-  if (!input)
-    input = view;
-
-  if (error_bubble_ && error_bubble_->anchor() == input)
+  if (error_bubble_ && error_bubble_->anchor() == view)
     return;
 
   std::map<views::View*, string16>::iterator error_message =
-      validity_map_.find(input);
+      validity_map_.find(view);
   if (error_message != validity_map_.end())
-    error_bubble_.reset(new ErrorBubble(input, error_message->second));
+    error_bubble_.reset(new ErrorBubble(view, error_message->second));
 }
 
 void AutofillDialogViews::MarkInputsInvalid(DialogSection section,
                                             const ValidityData& validity_data) {
-  DetailsGroup group = *GroupForSection(section);
-  DCHECK(group.container->visible());
+  DetailsGroup* group = GroupForSection(section);
+  DCHECK(group->container->visible());
 
   typedef std::map<AutofillFieldType,
       base::Callback<void(const base::string16&)> > FieldMap;
   FieldMap field_map;
 
-  if (group.manual_input->visible()) {
-    for (TextfieldMap::const_iterator iter = group.textfields.begin();
-         iter != group.textfields.end(); ++iter) {
+  if (group->manual_input->visible()) {
+    for (TextfieldMap::const_iterator iter = group->textfields.begin();
+         iter != group->textfields.end(); ++iter) {
       field_map[iter->first->type] = base::Bind(
           &AutofillDialogViews::SetValidityForInput<DecoratedTextfield>,
           base::Unretained(this),
           iter->second);
     }
-    for (ComboboxMap::const_iterator iter = group.comboboxes.begin();
-         iter != group.comboboxes.end(); ++iter) {
+    for (ComboboxMap::const_iterator iter = group->comboboxes.begin();
+         iter != group->comboboxes.end(); ++iter) {
       field_map[iter->first->type] = base::Bind(
           &AutofillDialogViews::SetValidityForInput<views::Combobox>,
           base::Unretained(this),
           iter->second);
     }
+  } else {
+    // Purge invisible views from |validity_map_|.
+    std::map<views::View*, base::string16>::iterator it;
+    for (it = validity_map_.begin(); it != validity_map_.end();) {
+      DCHECK(GroupForView(it->first));
+      if (GroupForView(it->first) == group)
+        validity_map_.erase(it++);
+      else
+        ++it;
+    }
+
+    if (section == SECTION_CC) {
+      // Special case CVC as it's not part of |group->manual_input|.
+      field_map[CREDIT_CARD_VERIFICATION_CODE] = base::Bind(
+          &AutofillDialogViews::SetValidityForInput<DecoratedTextfield>,
+          base::Unretained(this),
+          group->suggested_info->decorated_textfield());
+    }
   }
 
   // Flag invalid fields, removing them from |field_map|.
@@ -1757,7 +1930,7 @@
       if (!iter->first->editable)
         continue;
 
-      detail_outputs[iter->first] = iter->second->textfield()->text();
+      detail_outputs[iter->first] = iter->second->text();
     }
     for (ComboboxMap::const_iterator iter = group.comboboxes.begin();
          iter != group.comboboxes.end(); ++iter) {
@@ -1774,7 +1947,7 @@
         group.suggested_info->decorated_textfield();
     cvc_input.reset(new DetailInput);
     cvc_input->type = CREDIT_CARD_VERIFICATION_CODE;
-    detail_outputs[cvc_input.get()] = decorated_cvc->textfield()->text();
+    detail_outputs[cvc_input.get()] = decorated_cvc->text();
   }
 
   ValidityData invalid_inputs = controller_->InputsAreValid(
@@ -1786,6 +1959,8 @@
 
 bool AutofillDialogViews::ValidateForm() {
   bool all_valid = true;
+  validity_map_.clear();
+
   for (DetailGroupMap::iterator iter = detail_groups_.begin();
        iter != detail_groups_.end(); ++iter) {
     const DetailsGroup& group = iter->second;
@@ -1810,13 +1985,11 @@
   DecoratedTextfield* decorated = NULL;
 
   // Look for the input in the manual inputs.
-  views::View* ancestor =
-      textfield->GetAncestorWithClassName(kDecoratedTextfieldClassName);
   for (TextfieldMap::const_iterator iter = group->textfields.begin();
        iter != group->textfields.end();
        ++iter) {
     decorated = iter->second;
-    if (decorated == ancestor) {
+    if (decorated == textfield) {
       controller_->UserEditedOrActivatedInput(group->section,
                                               iter->first,
                                               GetWidget()->GetNativeView(),
@@ -1828,7 +2001,7 @@
     }
   }
 
-  if (ancestor == group->suggested_info->decorated_textfield()) {
+  if (textfield == group->suggested_info->decorated_textfield()) {
     decorated = group->suggested_info->decorated_textfield();
     type = CREDIT_CARD_VERIFICATION_CODE;
   }
@@ -1852,7 +2025,7 @@
   }
 
   gfx::Image icon = controller_->IconForField(type, textfield->text());
-  textfield->SetIcon(icon.AsImageSkia());
+  decorated->SetIcon(icon);
 }
 
 void AutofillDialogViews::UpdateSaveInChromeCheckbox() {
@@ -1865,10 +2038,7 @@
     GetWidget()->SetSize(GetWidget()->non_client_view()->GetPreferredSize());
     // If the above line does not cause the dialog's size to change, |contents_|
     // may not be laid out. This will trigger a layout only if it's needed.
-    contents_->SetBoundsRect(contents_->bounds());
-
-    if (error_bubble_)
-      error_bubble_->UpdatePosition();
+    SetBoundsRect(bounds());
   }
 }
 
@@ -1878,25 +2048,23 @@
 }
 
 AutofillDialogViews::DetailsGroup* AutofillDialogViews::GroupForView(
-  views::View* view) {
+    views::View* view) {
   DCHECK(view);
-  // Textfields are treated slightly differently. For them, inspect
-  // the DecoratedTextfield ancestor, not the actual control.
-  views::View* ancestor =
-      view->GetAncestorWithClassName(kDecoratedTextfieldClassName);
 
-  views::View* control = ancestor ? ancestor : view;
   for (DetailGroupMap::iterator iter = detail_groups_.begin();
        iter != detail_groups_.end(); ++iter) {
     DetailsGroup* group = &iter->second;
-    if (control->parent() == group->manual_input)
+    if (view->parent() == group->manual_input)
       return group;
 
+    views::View* decorated =
+        view->GetAncestorWithClassName(kDecoratedTextfieldClassName);
+
     // Textfields need to check a second case, since they can be
     // suggested inputs instead of directly editable inputs. Those are
     // accessed via |suggested_info|.
-    if (ancestor &&
-        ancestor == group->suggested_info->decorated_textfield()) {
+    if (decorated &&
+        decorated == group->suggested_info->decorated_textfield()) {
       return group;
     }
   }
@@ -1910,7 +2078,7 @@
     const DetailsGroup& group = iter->second;
     TextfieldMap::const_iterator text_mapping = group.textfields.find(&input);
     if (text_mapping != group.textfields.end())
-      return text_mapping->second->textfield();
+      return text_mapping->second;
   }
 
   return NULL;
diff --git a/chrome/browser/ui/views/autofill/autofill_dialog_views.h b/chrome/browser/ui/views/autofill/autofill_dialog_views.h
index cff27ea..ef7d115 100644
--- a/chrome/browser/ui/views/autofill/autofill_dialog_views.h
+++ b/chrome/browser/ui/views/autofill/autofill_dialog_views.h
@@ -20,6 +20,7 @@
 #include "ui/views/controls/progress_bar.h"
 #include "ui/views/controls/scroll_view.h"
 #include "ui/views/controls/styled_label_listener.h"
+#include "ui/views/controls/textfield/textfield.h"
 #include "ui/views/controls/textfield/textfield_controller.h"
 #include "ui/views/focus/focus_manager.h"
 #include "ui/views/widget/widget_observer.h"
@@ -36,6 +37,7 @@
 namespace views {
 class Checkbox;
 class Combobox;
+class FocusableBorder;
 class FocusManager;
 class ImageButton;
 class ImageView;
@@ -43,7 +45,6 @@
 class Link;
 class MenuRunner;
 class StyledLabel;
-class Textfield;
 class WebView;
 class Widget;
 }  // namespace views
@@ -62,14 +63,13 @@
 // imperative autocomplete API call.
 class AutofillDialogViews : public AutofillDialogView,
                             public TestableAutofillDialogView,
-                            public views::DialogDelegate,
+                            public views::DialogDelegateView,
                             public views::WidgetObserver,
                             public views::ButtonListener,
                             public views::TextfieldController,
                             public views::FocusChangeListener,
                             public views::ComboboxListener,
-                            public views::StyledLabelListener,
-                            public ui::AcceleratorTarget {
+                            public views::StyledLabelListener {
  public:
   explicit AutofillDialogViews(AutofillDialogController* controller);
   virtual ~AutofillDialogViews();
@@ -78,6 +78,7 @@
   virtual void Show() OVERRIDE;
   virtual void Hide() OVERRIDE;
   virtual void UpdateAccountChooser() OVERRIDE;
+  virtual void UpdateAutocheckoutStepsArea() OVERRIDE;
   virtual void UpdateButtonStrip() OVERRIDE;
   virtual void UpdateDetailArea() OVERRIDE;
   virtual void UpdateForErrors() OVERRIDE;
@@ -102,6 +103,9 @@
   virtual string16 GetTextContentsOfInput(const DetailInput& input) OVERRIDE;
   virtual void SetTextContentsOfInput(const DetailInput& input,
                                       const string16& contents) OVERRIDE;
+  virtual void SetTextContentsOfSuggestionInput(
+      DialogSection section,
+      const base::string16& text) OVERRIDE;
   virtual void ActivateInput(const DetailInput& input) OVERRIDE;
   virtual gfx::Size GetSize() const OVERRIDE;
 
@@ -109,13 +113,15 @@
   virtual bool AcceleratorPressed(const ui::Accelerator& accelerator) OVERRIDE;
   virtual bool CanHandleAccelerators() const OVERRIDE;
 
+  // views::View implementation.
+  virtual gfx::Size GetPreferredSize() OVERRIDE;
+  virtual void Layout() OVERRIDE;
+  virtual void OnBoundsChanged(const gfx::Rect& previous_bounds) OVERRIDE;
+
   // views::DialogDelegate implementation:
   virtual string16 GetWindowTitle() const OVERRIDE;
   virtual void WindowClosing() OVERRIDE;
   virtual void DeleteDelegate() OVERRIDE;
-  virtual views::Widget* GetWidget() OVERRIDE;
-  virtual const views::Widget* GetWidget() const OVERRIDE;
-  virtual views::View* GetContentsView() OVERRIDE;
   virtual views::View* CreateOverlayView() OVERRIDE;
   virtual int GetDialogButtons() const OVERRIDE;
   virtual string16 GetDialogButtonLabel(ui::DialogButton button) const OVERRIDE;
@@ -159,26 +165,6 @@
       OVERRIDE;
 
  private:
-  // A view that contains a single child view, and adds a vertical scrollbar
-  // after a certain maximum height is reached.
-  class SizeLimitedScrollView : public views::ScrollView {
-   public:
-    explicit SizeLimitedScrollView(views::View* scroll_contents);
-    virtual ~SizeLimitedScrollView();
-
-    // views::View implementation.
-    virtual void Layout() OVERRIDE;
-    virtual gfx::Size GetPreferredSize() OVERRIDE;
-
-    // Sets the maximum height for the viewport.
-    void SetMaximumHeight(int max_height);
-
-   private:
-    int max_height_;
-
-    DISALLOW_COPY_AND_ASSIGN(SizeLimitedScrollView);
-  };
-
   // A class that creates and manages a widget for error messages.
   class ErrorBubble : public views::WidgetObserver {
    public:
@@ -211,28 +197,35 @@
 
   // A class which holds a textfield and draws extra stuff on top, like
   // invalid content indications.
-  class DecoratedTextfield : public views::View {
+  class DecoratedTextfield : public views::Textfield {
    public:
     DecoratedTextfield(const string16& default_value,
                        const string16& placeholder,
                        views::TextfieldController* controller);
     virtual ~DecoratedTextfield();
 
-    // The wrapped text field.
-    views::Textfield* textfield() { return textfield_; }
-
     // Sets whether to indicate the textfield has invalid content.
     void SetInvalid(bool invalid);
     bool invalid() const { return invalid_; }
 
+    // Sets the icon to be displayed inside the textfield at the end of the
+    // text.
+    void SetIcon(const gfx::Image& icon);
+
     // views::View implementation.
     virtual const char* GetClassName() const OVERRIDE;
     virtual void PaintChildren(gfx::Canvas* canvas) OVERRIDE;
     virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
-    virtual void RequestFocus() OVERRIDE;
 
    private:
-    views::Textfield* textfield_;
+    // We draw the border.
+    views::FocusableBorder* border_;  // Weak.
+
+    // The icon that goes at the right side of the textfield.
+    gfx::Image icon_;
+
+    // Whether the text contents are "invalid" (i.e. should special markers be
+    // shown to indicate invalidness).
     bool invalid_;
 
     DISALLOW_COPY_AND_ASSIGN(DecoratedTextfield);
@@ -379,7 +372,7 @@
     // Shows an auxiliary textfield to the right of the suggestion icon and
     // text. This is currently only used to show a CVC field for the CC section.
     void ShowTextfield(const string16& placeholder_text,
-                       const gfx::ImageSkia& icon);
+                       const gfx::Image& icon);
 
     DecoratedTextfield* decorated_textfield() { return decorated_; }
 
@@ -423,13 +416,26 @@
     views::ImageButton* suggested_button;
   };
 
+  // Area for displaying that status of various steps in an Autocheckout flow.
+  class AutocheckoutStepsArea : public views::View {
+   public:
+    AutocheckoutStepsArea();
+    virtual ~AutocheckoutStepsArea() {}
+
+    // Display the given steps.
+    void SetSteps(const std::vector<DialogAutocheckoutStep>& steps);
+
+   private:
+    DISALLOW_COPY_AND_ASSIGN(AutocheckoutStepsArea);
+  };
+
   class AutocheckoutProgressBar : public views::ProgressBar {
    public:
     AutocheckoutProgressBar();
     virtual ~AutocheckoutProgressBar();
 
    private:
-    // Overidden from View:
+    // Overriden from View
     virtual gfx::Size GetPreferredSize() OVERRIDE;
 
     DISALLOW_COPY_AND_ASSIGN(AutocheckoutProgressBar);
@@ -533,9 +539,6 @@
   // dialog is closing.
   views::Widget* window_;
 
-  // The top-level View for the dialog. Owned by the constrained window.
-  views::View* contents_;
-
   // A DialogSection-keyed map of the DetailGroup structs.
   DetailGroupMap detail_groups_;
 
@@ -552,15 +555,15 @@
   // sign-in.
   views::WebView* sign_in_webview_;
 
-  // View to host everything that isn't related to sign-in.
-  views::View* main_container_;
-
   // View that wraps |details_container_| and makes it scroll vertically.
-  SizeLimitedScrollView* scrollable_area_;
+  views::ScrollView* scrollable_area_;
 
   // View to host details sections.
   views::View* details_container_;
 
+  // A view that overlays |this| (for "loading..." messages).
+  views::Label* loading_shield_;
+
   // The view that completely overlays the dialog (used for the splash page).
   views::View* overlay_view_;
 
@@ -571,6 +574,9 @@
   // database. It lives in |extra_view_|.
   views::Checkbox* save_in_chrome_checkbox_;
 
+  // View to host Autocheckout steps.
+  AutocheckoutStepsArea* autocheckout_steps_area_;
+
   // View to host |autocheckout_progress_bar_| and its label.
   views::View* autocheckout_progress_bar_view_;
 
diff --git a/chrome/browser/ui/views/autofill/autofill_popup_view_views.cc b/chrome/browser/ui/views/autofill/autofill_popup_view_views.cc
index 2b0723a..661ef09 100644
--- a/chrome/browser/ui/views/autofill/autofill_popup_view_views.cc
+++ b/chrome/browser/ui/views/autofill/autofill_popup_view_views.cc
@@ -164,8 +164,6 @@
 }
 
 void AutofillPopupViewViews::HideInternal() {
-  AutofillPopupView::Hide();
-
   observing_widget_->RemoveObserver(this);
 }
 
diff --git a/chrome/browser/ui/views/avatar_label.cc b/chrome/browser/ui/views/avatar_label.cc
new file mode 100644
index 0000000..11a7056
--- /dev/null
+++ b/chrome/browser/ui/views/avatar_label.cc
@@ -0,0 +1,91 @@
+// 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/ui/views/avatar_label.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "chrome/browser/themes/theme_properties.h"
+#include "chrome/browser/ui/views/avatar_menu_bubble_view.h"
+#include "chrome/browser/ui/views/frame/browser_view.h"
+#include "grit/generated_resources.h"
+#include "ui/base/events/event.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/base/theme_provider.h"
+#include "ui/gfx/canvas.h"
+#include "ui/gfx/color_utils.h"
+#include "ui/views/painter.h"
+
+namespace {
+
+// A special text button border for the managed user avatar label.
+class AvatarLabelBorder: public views::TextButtonBorder {
+ public:
+  explicit AvatarLabelBorder(ui::ThemeProvider* theme_provider);
+
+  virtual void Paint(const views::View& view, gfx::Canvas* canvas) OVERRIDE;
+
+ private:
+  scoped_ptr<views::Painter> hot_painter_;
+  scoped_ptr<views::Painter> painter_;
+
+  DISALLOW_COPY_AND_ASSIGN(AvatarLabelBorder);
+};
+
+AvatarLabelBorder::AvatarLabelBorder(ui::ThemeProvider* theme_provider) {
+  const int kHorizontalInset = 10;
+  const int kVerticalInset = 2;
+  SetInsets(gfx::Insets(
+      kVerticalInset, kHorizontalInset, kVerticalInset, kHorizontalInset));
+  SkColor color = theme_provider->GetColor(
+      ThemeProperties::COLOR_MANAGED_USER_LABEL_BACKGROUND);
+  SkColor color2 = color_utils::BlendTowardOppositeLuminance(color, 0x20);
+  painter_.reset(views::Painter::CreateVerticalGradient(color, color2));
+  hot_painter_.reset(views::Painter::CreateVerticalGradient(color2, color));
+}
+
+void AvatarLabelBorder::Paint(const views::View& view, gfx::Canvas* canvas) {
+  const views::TextButton* button =
+      static_cast<const views::TextButton*>(&view);
+  if (button->state() == views::TextButton::STATE_HOVERED ||
+      button->state() == views::TextButton::STATE_PRESSED)
+    hot_painter_->Paint(canvas, view.size());
+  else
+    painter_->Paint(canvas, view.size());
+}
+
+}  // namespace
+
+AvatarLabel::AvatarLabel(BrowserView* browser_view,
+                         ui::ThemeProvider* theme_provider)
+    : TextButton(NULL,
+                 l10n_util::GetStringUTF16(IDS_MANAGED_USER_AVATAR_LABEL)),
+      browser_view_(browser_view),
+      theme_provider_(theme_provider) {
+  SetFont(ui::ResourceBundle::GetSharedInstance().GetFont(
+      ui::ResourceBundle::SmallFont));
+  ClearMaxTextSize();
+  set_border(new AvatarLabelBorder(theme_provider));
+  UpdateLabelStyle();
+}
+
+AvatarLabel::~AvatarLabel() {}
+
+bool AvatarLabel::OnMousePressed(const ui::MouseEvent& event) {
+  if (!TextButton::OnMousePressed(event))
+    return false;
+
+  browser_view_->ShowAvatarBubbleFromAvatarButton();
+  return true;
+}
+
+void AvatarLabel::UpdateLabelStyle() {
+  SkColor color_label =
+      theme_provider_->GetColor(ThemeProperties::COLOR_MANAGED_USER_LABEL);
+  SetEnabledColor(color_label);
+  SetHighlightColor(color_label);
+  SetHoverColor(color_label);
+  SetDisabledColor(color_label);
+  SchedulePaint();
+}
diff --git a/chrome/browser/ui/views/avatar_label.h b/chrome/browser/ui/views/avatar_label.h
new file mode 100644
index 0000000..d2ad823
--- /dev/null
+++ b/chrome/browser/ui/views/avatar_label.h
@@ -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.
+
+#ifndef CHROME_BROWSER_UI_VIEWS_AVATAR_LABEL_H_
+#define CHROME_BROWSER_UI_VIEWS_AVATAR_LABEL_H_
+
+#include "base/compiler_specific.h"
+#include "ui/views/controls/button/text_button.h"
+
+class BrowserView;
+
+namespace ui {
+class MouseEvent;
+class ThemeProvider;
+}
+
+// AvatarLabel
+//
+// A label used to display a string indicating that the current profile belongs
+// to a managed user.
+class AvatarLabel : public views::TextButton {
+ public:
+  AvatarLabel(BrowserView* browser_view, ui::ThemeProvider* theme_provider);
+  virtual ~AvatarLabel();
+
+  // views::TextButton:
+  virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE;
+
+  // Update the style of the label according to the provided theme.
+  void UpdateLabelStyle();
+
+ private:
+  BrowserView* browser_view_;
+  ui::ThemeProvider* theme_provider_;
+
+  DISALLOW_COPY_AND_ASSIGN(AvatarLabel);
+};
+
+#endif  // CHROME_BROWSER_UI_VIEWS_AVATAR_LABEL_H_
diff --git a/chrome/browser/ui/views/avatar_menu_bubble_view.cc b/chrome/browser/ui/views/avatar_menu_bubble_view.cc
index 1049861..6119289 100644
--- a/chrome/browser/ui/views/avatar_menu_bubble_view.cc
+++ b/chrome/browser/ui/views/avatar_menu_bubble_view.cc
@@ -41,6 +41,7 @@
 #include "ui/views/controls/link.h"
 #include "ui/views/controls/separator.h"
 #include "ui/views/layout/grid_layout.h"
+#include "ui/views/layout/layout_constants.h"
 #include "ui/views/widget/widget.h"
 
 namespace {
@@ -553,7 +554,6 @@
     preferred_size.Enlarge(
         0,
         kSeparatorPaddingY * 4 + separator_->GetPreferredSize().height() * 2);
-
   }
 
   const int kBubbleViewMaxWidth = 800;
@@ -563,10 +563,12 @@
   // We have to do this after the final width is calculated, since the label
   // will wrap based on the width.
   if (managed_user_info_) {
+    int remaining_width =
+        preferred_size.width() - icon_view_->GetPreferredSize().width() -
+        views::kRelatedControlSmallHorizontalSpacing;
     preferred_size.Enlarge(
         0,
-        managed_user_info_->GetHeightForWidth(preferred_size.width()) +
-            kItemMarginY);
+        managed_user_info_->GetHeightForWidth(remaining_width) + kItemMarginY);
   }
 
   return preferred_size;
@@ -594,9 +596,15 @@
     buttons_view_->SetBounds(0, y,
         width(), buttons_view_->GetPreferredSize().height());
   } else if (managed_user_info_) {
-    managed_user_info_->SizeToFit(width());
-    int height = managed_user_info_->GetPreferredSize().height();
-    managed_user_info_->SetBounds(0, y, width(), height);
+    gfx::Size icon_size = icon_view_->GetPreferredSize();
+    gfx::Rect icon_bounds(0, y, icon_size.width(), icon_size.height());
+    icon_view_->SetBoundsRect(icon_bounds);
+    int info_width = width() - icon_bounds.right() -
+                     views::kRelatedControlSmallHorizontalSpacing;
+    int height = managed_user_info_->GetHeightForWidth(info_width);
+    managed_user_info_->SetBounds(
+        icon_bounds.right() + views::kRelatedControlSmallHorizontalSpacing,
+        y, info_width, height);
     y += height + kItemMarginY + kSeparatorPaddingY;
     separator_switch_users_->SetBounds(0, y, width(), separator_height);
     y += separator_height + kSeparatorPaddingY;
@@ -749,6 +757,11 @@
   managed_user_info_->SetBackgroundColor(color());
   AddChildView(managed_user_info_);
 
+  // Add the managed user icon.
+  icon_view_ = new views::ImageView();
+  icon_view_->SetImage(avatar_menu_model_->GetManagedUserIcon().ToImageSkia());
+  AddChildView(icon_view_);
+
   // Add a link for switching profiles.
   separator_switch_users_ = new views::Separator(views::Separator::HORIZONTAL);
   AddChildView(separator_switch_users_);
diff --git a/chrome/browser/ui/views/avatar_menu_bubble_view.h b/chrome/browser/ui/views/avatar_menu_bubble_view.h
index 63d9263..29597b1 100644
--- a/chrome/browser/ui/views/avatar_menu_bubble_view.h
+++ b/chrome/browser/ui/views/avatar_menu_bubble_view.h
@@ -25,6 +25,7 @@
 
 namespace views {
 class CustomButton;
+class ImageView;
 class Label;
 class Link;
 class Separator;
@@ -112,6 +113,7 @@
   // avatar_menu_model_->GetManagedUserInformation() returns a non-empty string.
   // See OnAvatarMenuModelChanged().
   views::Label* managed_user_info_;
+  views::ImageView* icon_view_;
   views::Separator* separator_switch_users_;
   views::Link* switch_profile_link_;
 
diff --git a/chrome/browser/ui/views/avatar_menu_button_browsertest.cc b/chrome/browser/ui/views/avatar_menu_button_browsertest.cc
index bd294f8..611995e 100644
--- a/chrome/browser/ui/views/avatar_menu_button_browsertest.cc
+++ b/chrome/browser/ui/views/avatar_menu_button_browsertest.cc
@@ -6,7 +6,7 @@
 
 #include "base/command_line.h"
 #include "base/path_service.h"
-#include "base/utf_string_conversions.h"
+#include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/profiles/avatar_menu_model.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/browser_list.h"
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc b/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc
index fce68ef..81b4a3b 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc
+++ b/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc
@@ -78,6 +78,7 @@
 #include "ui/views/view_constants.h"
 #include "ui/views/widget/tooltip_manager.h"
 #include "ui/views/widget/widget.h"
+#include "ui/views/window/non_client_view.h"
 
 using content::OpenURLParams;
 using content::PageNavigator;
@@ -134,18 +135,6 @@
 // Tag for the 'Other bookmarks' button.
 static const int kOtherFolderButtonTag = 1;
 
-// TODO(kuan): change chrome::kNTPBookmarkBarHeight to this new height when
-// search_ntp replaces ntp4; for now, while both versions exist, this new height
-// is only needed locally.
-static const int kSearchNewTabBookmarkBarHeight = 40;
-
-// TODO(kuan): change BookmarkBarView::kNewtabHorizontalPadding and
-// BookmarkBarView::kNewtabVerticalPadding to these new values when search_ntp
-// replaces ntp4; for now, while both versions exist, these new values are only
-// needed locally.
-static const int kSearchNewTabHorizontalPadding = 2;
-static const int kSearchNewTabVerticalPadding = 5;
-
 // Tag for the 'Apps Shortcut' button.
 static const int kAppsShortcutButtonTag = 2;
 
@@ -336,18 +325,6 @@
       extension->GetType());
 }
 
-int GetNewtabHorizontalPadding() {
-  return chrome::IsInstantExtendedAPIEnabled()
-         ? kSearchNewTabHorizontalPadding
-         : BookmarkBarView::kNewtabHorizontalPadding;
-}
-
-int GetNewtabVerticalPadding() {
-  return chrome::IsInstantExtendedAPIEnabled()
-         ? kSearchNewTabVerticalPadding
-         : BookmarkBarView::kNewtabVerticalPadding;
-}
-
 }  // namespace
 
 // DropLocation ---------------------------------------------------------------
@@ -440,8 +417,7 @@
 
 // static
 const int BookmarkBarView::kMaxButtonWidth = 150;
-const int BookmarkBarView::kNewtabHorizontalPadding = 8;
-const int BookmarkBarView::kNewtabVerticalPadding = 12;
+const int BookmarkBarView::kNewtabHorizontalPadding = 2;
 const int BookmarkBarView::kToolbarAttachedBookmarkBarOverlap = 3;
 
 static const gfx::ImageSkia& GetDefaultFavicon() {
@@ -529,19 +505,13 @@
   bookmark_bar_state_ = state;
 }
 
-int BookmarkBarView::GetToolbarOverlap(bool return_max) const {
-  // When not detached, always overlap by the full amount.
-  if (return_max || bookmark_bar_state_ != BookmarkBar::DETACHED)
-    return kToolbarAttachedBookmarkBarOverlap;
-  // When detached with an infobar, overlap by 0 whenever the infobar
-  // is above us (i.e. when we're detached), since drawing over the infobar
-  // looks weird.
-  if (IsDetached() && infobar_visible_)
+int BookmarkBarView::GetFullyDetachedToolbarOverlap() const {
+  if (!infobar_visible_ && browser_->window()->IsFullscreen()) {
+    // There is no client edge to overlap when detached in fullscreen with no
+    // infobars visible.
     return 0;
-  // When detached with no infobar, animate the overlap between the attached and
-  // detached states.
-  return static_cast<int>(
-      kToolbarAttachedBookmarkBarOverlap * size_animation_->GetCurrentValue());
+  }
+  return views::NonClientFrameView::kClientEdgeThickness;
 }
 
 bool BookmarkBarView::is_animating() {
@@ -676,7 +646,23 @@
 }
 
 int BookmarkBarView::GetToolbarOverlap() const {
-  return GetToolbarOverlap(false);
+  int attached_overlap = kToolbarAttachedBookmarkBarOverlap +
+      views::NonClientFrameView::kClientEdgeThickness;
+  if (!IsDetached())
+    return attached_overlap;
+
+  int detached_overlap = GetFullyDetachedToolbarOverlap();
+
+  // Do not animate the overlap when the infobar is above us (i.e. when we're
+  // detached), since drawing over the infobar looks weird.
+  if (infobar_visible_)
+    return detached_overlap;
+
+  // When detached with no infobar, animate the overlap between the attached and
+  // detached states.
+  return detached_overlap + static_cast<int>(
+      (attached_overlap - detached_overlap) *
+          size_animation_->GetCurrentValue());
 }
 
 gfx::Size BookmarkBarView::GetPreferredSize() {
@@ -689,9 +675,13 @@
   // Bookmarks" folder, along with appropriate margins and button padding.
   int width = kLeftMargin;
 
-  if (bookmark_bar_state_ == BookmarkBar::DETACHED) {
+  int height = browser_defaults::kBookmarkBarHeight;
+  if (IsDetached()) {
     double current_state = 1 - size_animation_->GetCurrentValue();
-    width += 2 * static_cast<int>(GetNewtabHorizontalPadding() * current_state);
+    width += 2 * static_cast<int>(kNewtabHorizontalPadding * current_state);
+    height += static_cast<int>(
+        (chrome::kNTPBookmarkBarHeight - browser_defaults::kBookmarkBarHeight) *
+            current_state);
   }
 
   gfx::Size other_bookmarked_pref;
@@ -712,7 +702,7 @@
       overflow_pref.width() + kButtonPadding +
       bookmarks_separator_pref.width();
 
-  return gfx::Size(width, browser_defaults::kBookmarkBarHeight);
+  return gfx::Size(width, height);
 }
 
 void BookmarkBarView::Layout() {
@@ -946,10 +936,10 @@
   int64 install_time =
       g_browser_process->local_state()->GetInt64(prefs::kInstallDate);
   int64 time_from_install = base::Time::Now().ToTimeT() - install_time;
-  if (bookmark_bar_state_ == BookmarkBar::SHOW)
+  if (bookmark_bar_state_ == BookmarkBar::SHOW) {
     UMA_HISTOGRAM_COUNTS("Import.ShowDialog.FromBookmarkBarView",
                          time_from_install);
-  else if (bookmark_bar_state_ == BookmarkBar::DETACHED) {
+  } else if (bookmark_bar_state_ == BookmarkBar::DETACHED) {
     UMA_HISTOGRAM_COUNTS("Import.ShowDialog.FromFloatingBookmarkBarView",
                          time_from_install);
   }
@@ -1724,9 +1714,9 @@
 
   if (IsDetached()) {
     double current_state = 1 - size_animation_->GetCurrentValue();
-    x += static_cast<int>(GetNewtabHorizontalPadding() * current_state);
+    x += static_cast<int>(kNewtabHorizontalPadding * current_state);
     y += (View::height() - browser_defaults::kBookmarkBarHeight) / 2;
-    width -= static_cast<int>(GetNewtabHorizontalPadding() * current_state);
+    width -= static_cast<int>(kNewtabHorizontalPadding * current_state);
     separator_margin -= static_cast<int>(kSeparatorMargin * current_state);
   } else {
     // For the attached appearance, pin the content to the bottom of the bar
@@ -1747,8 +1737,6 @@
       bookmarks_separator_pref.width();
   if (other_bookmarked_button_->visible())
     max_x -= other_bookmarked_pref.width() + kButtonPadding;
-  if (apps_page_shortcut_->visible())
-    max_x -= apps_page_shortcut_pref.width() + kButtonPadding;
 
   // Next, layout out the buttons. Any buttons that are placed beyond the
   // visible region and made invisible.
@@ -1833,15 +1821,12 @@
     x += kRightMargin;
     prefsize.set_width(x);
     if (IsDetached()) {
-      x += static_cast<int>(GetNewtabHorizontalPadding() *
+      x += static_cast<int>(kNewtabHorizontalPadding *
           (1 - size_animation_->GetCurrentValue()));
-      int ntp_bookmark_bar_height =
-          chrome::IsInstantExtendedAPIEnabled()
-          ? kSearchNewTabBookmarkBarHeight : chrome::kNTPBookmarkBarHeight;
       prefsize.set_height(
           browser_defaults::kBookmarkBarHeight +
           static_cast<int>(
-              (ntp_bookmark_bar_height -
+              (chrome::kNTPBookmarkBarHeight -
                browser_defaults::kBookmarkBarHeight) *
               (1 - size_animation_->GetCurrentValue())));
     } else {
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_bar_view.h b/chrome/browser/ui/views/bookmarks/bookmark_bar_view.h
index 5768fc0..72b0e2c 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_bar_view.h
+++ b/chrome/browser/ui/views/bookmarks/bookmark_bar_view.h
@@ -67,10 +67,9 @@
   // The internal view class name.
   static const char kViewClassName[];
 
-  // Constants used in Browser View, as well as here.
+  // Constant used in Browser View, as well as here.
   // How inset the bookmarks bar is when displayed on the new tab page.
   static const int kNewtabHorizontalPadding;
-  static const int kNewtabVerticalPadding;
 
   // Maximum size of buttons on the bookmark bar.
   static const int kMaxButtonWidth;
@@ -101,9 +100,8 @@
   void SetBookmarkBarState(BookmarkBar::State state,
                            BookmarkBar::AnimateChangeType animate_type);
 
-  // How much we want the bookmark bar to overlap the toolbar.  If |return_max|
-  // is true, we return the maximum overlap rather than the current overlap.
-  int GetToolbarOverlap(bool return_max) const;
+  // Returns the toolbar overlap when fully detached.
+  int GetFullyDetachedToolbarOverlap() const;
 
   // Whether or not we are animating.
   bool is_animating();
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_bar_view_test.cc b/chrome/browser/ui/views/bookmarks/bookmark_bar_view_test.cc
index dbeebea..d0b2ba8 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_bar_view_test.cc
+++ b/chrome/browser/ui/views/bookmarks/bookmark_bar_view_test.cc
@@ -127,7 +127,7 @@
     profile_->GetPrefs()->SetBoolean(prefs::kShowBookmarkBar, true);
 
     Browser::CreateParams native_params(profile_.get(),
-                                        chrome::HOST_DESKTOP_TYPE_NATIVE);
+                                        chrome::GetActiveDesktop());
     browser_.reset(
         chrome::CreateBrowserWithTestWindowForParams(&native_params));
 
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_bubble_view.cc b/chrome/browser/ui/views/bookmarks/bookmark_bubble_view.cc
index 3c2a170..ca52a45 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_bubble_view.cc
+++ b/chrome/browser/ui/views/bookmarks/bookmark_bubble_view.cc
@@ -8,11 +8,11 @@
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/app/chrome_command_ids.h"
-#include "chrome/browser/bookmarks/bookmark_editor.h"
 #include "chrome/browser/bookmarks/bookmark_model.h"
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
 #include "chrome/browser/bookmarks/bookmark_utils.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/bookmarks/bookmark_editor.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_list.h"
 #include "chrome/browser/ui/views/bookmarks/bookmark_bubble_view_observer.h"
@@ -22,6 +22,7 @@
 #include "ui/base/keycodes/keyboard_codes.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/resource/resource_bundle.h"
+#include "ui/views/bubble/bubble_frame_view.h"
 #include "ui/views/controls/button/label_button.h"
 #include "ui/views/controls/combobox/combobox.h"
 #include "ui/views/controls/label.h"
@@ -37,14 +38,8 @@
 
 namespace {
 
-// Padding between "Title:" and the actual title.
-const int kTitlePadding = 4;
-
-// Minimum width for the fields - they will push out the size of the bubble if
-// necessary. This should be big enough so that the field pushes the right side
-// of the bubble far enough so that the edit button's left edge is to the right
-// of the field's left edge.
-const int kMinimumFieldSize = 180;
+// Minimum width of the the bubble.
+const int kMinBubbleWidth = 350;
 
 }  // namespace
 
@@ -89,6 +84,7 @@
   views::BubbleDelegateView::CreateBubble(bookmark_bubble_)->Show();
   // Select the entire title textfield contents when the bubble is first shown.
   bookmark_bubble_->title_tf_->SelectAll(true);
+  bookmark_bubble_->SetArrowPaintType(views::BubbleBorder::PAINT_NONE);
 
   if (bookmark_bubble_->observer_)
     bookmark_bubble_->observer_->OnBookmarkBubbleShown(url);
@@ -146,9 +142,16 @@
 }
 
 void BookmarkBubbleView::Init() {
-  remove_link_ = new views::Link(l10n_util::GetStringUTF16(
+  views::Label* title_label = new views::Label(
+      l10n_util::GetStringUTF16(
+          newly_bookmarked_ ? IDS_BOOKMARK_BUBBLE_PAGE_BOOKMARKED :
+                              IDS_BOOKMARK_BUBBLE_PAGE_BOOKMARK));
+  ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
+  title_label->SetFont(rb.GetFont(ui::ResourceBundle::MediumFont));
+
+  remove_button_ = new views::LabelButton(this, l10n_util::GetStringUTF16(
       IDS_BOOKMARK_BUBBLE_REMOVE_BOOKMARK));
-  remove_link_->set_listener(this);
+  remove_button_->SetStyle(views::Button::STYLE_NATIVE_TEXTBUTTON);
 
   edit_button_ = new views::LabelButton(
       this, l10n_util::GetStringUTF16(IDS_BOOKMARK_BUBBLE_OPTIONS));
@@ -166,66 +169,54 @@
   parent_combobox_->set_listener(this);
   parent_combobox_->SetAccessibleName(combobox_label->text());
 
-  views::Label* title_label = new views::Label(
-      l10n_util::GetStringUTF16(
-          newly_bookmarked_ ? IDS_BOOKMARK_BUBBLE_PAGE_BOOKMARKED :
-                              IDS_BOOKMARK_BUBBLE_PAGE_BOOKMARK));
-  ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
-  title_label->SetFont(rb.GetFont(ui::ResourceBundle::MediumFont));
-
   GridLayout* layout = new GridLayout(this);
   SetLayoutManager(layout);
 
-  ColumnSet* cs = layout->AddColumnSet(0);
-
-  // Top (title) row.
-  cs->AddColumn(GridLayout::CENTER, GridLayout::CENTER, 0, GridLayout::USE_PREF,
-                0, 0);
-  cs->AddPaddingColumn(1, views::kUnrelatedControlHorizontalSpacing);
+  const int kTitleColumnSetID = 0;
+  ColumnSet* cs = layout->AddColumnSet(kTitleColumnSetID);
   cs->AddColumn(GridLayout::CENTER, GridLayout::CENTER, 0, GridLayout::USE_PREF,
                 0, 0);
 
-  // Middle (input field) rows.
-  cs = layout->AddColumnSet(2);
+  // The column layout used for middle and bottom rows.
+  const int kFirstColumnSetID = 1;
+  cs = layout->AddColumnSet(kFirstColumnSetID);
   cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 0,
                 GridLayout::USE_PREF, 0, 0);
-  cs->AddPaddingColumn(0, views::kRelatedControlHorizontalSpacing);
-  cs->AddColumn(GridLayout::FILL, GridLayout::CENTER, 1,
-                GridLayout::USE_PREF, 0, kMinimumFieldSize);
+  cs->AddPaddingColumn(0, views::kUnrelatedControlHorizontalSpacing);
 
-  // Bottom (buttons) row.
-  cs = layout->AddColumnSet(3);
-  cs->AddPaddingColumn(1, views::kRelatedControlHorizontalSpacing);
+  cs->AddColumn(GridLayout::FILL, GridLayout::CENTER, 0,
+                GridLayout::USE_PREF, 0, 0);
+  cs->AddPaddingColumn(1, views::kUnrelatedControlLargeHorizontalSpacing);
+
   cs->AddColumn(GridLayout::LEADING, GridLayout::TRAILING, 0,
                 GridLayout::USE_PREF, 0, 0);
-  // We subtract 2 to account for the natural button padding, and
-  // to bring the separation visually in line with the row separation
-  // height.
-  cs->AddPaddingColumn(0, views::kRelatedButtonHSpacing - 2);
+  cs->AddPaddingColumn(0, views::kRelatedButtonHSpacing);
   cs->AddColumn(GridLayout::LEADING, GridLayout::TRAILING, 0,
                 GridLayout::USE_PREF, 0, 0);
 
-  layout->StartRow(0, 0);
+  layout->StartRow(0, kTitleColumnSetID);
   layout->AddView(title_label);
-  layout->AddView(remove_link_);
+  layout->AddPaddingRow(0, views::kUnrelatedControlHorizontalSpacing);
 
-  layout->AddPaddingRow(0, views::kRelatedControlSmallVerticalSpacing);
-  layout->StartRow(0, 2);
+  layout->StartRow(0, kFirstColumnSetID);
   views::Label* label = new views::Label(
       l10n_util::GetStringUTF16(IDS_BOOKMARK_BUBBLE_TITLE_TEXT));
   layout->AddView(label);
   title_tf_ = new views::Textfield();
   title_tf_->SetText(GetTitle());
-  layout->AddView(title_tf_);
+  layout->AddView(title_tf_, 5, 1);
 
-  layout->AddPaddingRow(0, views::kRelatedControlSmallVerticalSpacing);
+  layout->AddPaddingRow(0, views::kUnrelatedControlHorizontalSpacing);
 
-  layout->StartRow(0, 2);
+  layout->StartRow(0, kFirstColumnSetID);
   layout->AddView(combobox_label);
-  layout->AddView(parent_combobox_);
-  layout->AddPaddingRow(0, views::kRelatedControlSmallVerticalSpacing);
+  layout->AddView(parent_combobox_, 5, 1);
 
-  layout->StartRow(0, 3);
+  layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
+
+  layout->StartRow(0, kFirstColumnSetID);
+  layout->SkipColumns(2);
+  layout->AddView(remove_button_);
   layout->AddView(edit_button_);
   layout->AddView(close_button_);
 
@@ -246,15 +237,20 @@
           BookmarkModelFactory::GetForProfile(profile_),
           BookmarkModelFactory::GetForProfile(profile_)->
               GetMostRecentlyAddedNodeForURL(url)),
-      remove_link_(NULL),
+      remove_button_(NULL),
       edit_button_(NULL),
       close_button_(NULL),
       title_tf_(NULL),
       parent_combobox_(NULL),
       remove_bookmark_(false),
       apply_edits_(true) {
+  const SkColor background_color = GetNativeTheme()->GetSystemColor(
+      ui::NativeTheme::kColorId_DialogBackground);
+  set_color(background_color);
+  set_background(views::Background::CreateSolidBackground(background_color));
+  set_margins(gfx::Insets(12, 19, 18, 18));
   // Compensate for built-in vertical padding in the anchor view's image.
-  set_anchor_view_insets(gfx::Insets(5, 0, 5, 0));
+  set_anchor_view_insets(gfx::Insets(7, 0, 7, 0));
 }
 
 string16 BookmarkBubbleView::GetTitle() {
@@ -269,21 +265,17 @@
   return string16();
 }
 
+gfx::Size BookmarkBubbleView::GetMinimumSize() {
+  gfx::Size size(views::BubbleDelegateView::GetPreferredSize());
+  size.SetToMax(gfx::Size(kMinBubbleWidth, 0));
+  return size;
+}
+
 void BookmarkBubbleView::ButtonPressed(views::Button* sender,
                                        const ui::Event& event) {
   HandleButtonPressed(sender);
 }
 
-void BookmarkBubbleView::LinkClicked(views::Link* source, int event_flags) {
-  DCHECK_EQ(remove_link_, source);
-  content::RecordAction(UserMetricsAction("BookmarkBubble_Unstar"));
-
-  // Set this so we remove the bookmark after the window closes.
-  remove_bookmark_ = true;
-  apply_edits_ = false;
-  StartFade(false);
-}
-
 void BookmarkBubbleView::OnSelectedIndexChanged(views::Combobox* combobox) {
   if (combobox->selected_index() + 1 == parent_model_.GetItemCount()) {
     content::RecordAction(UserMetricsAction("BookmarkBubble_EditFromCombobox"));
@@ -292,7 +284,13 @@
 }
 
 void BookmarkBubbleView::HandleButtonPressed(views::Button* sender) {
-  if (sender == edit_button_) {
+  if (sender == remove_button_) {
+    content::RecordAction(UserMetricsAction("BookmarkBubble_Unstar"));
+    // Set this so we remove the bookmark after the window closes.
+    remove_bookmark_ = true;
+    apply_edits_ = false;
+    StartFade(false);
+  } else if (sender == edit_button_) {
     content::RecordAction(UserMetricsAction("BookmarkBubble_Edit"));
     ShowEditor();
   } else {
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_bubble_view.h b/chrome/browser/ui/views/bookmarks/bookmark_bubble_view.h
index 5f4e739..83923ec 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_bubble_view.h
+++ b/chrome/browser/ui/views/bookmarks/bookmark_bubble_view.h
@@ -13,7 +13,6 @@
 #include "ui/views/bubble/bubble_delegate.h"
 #include "ui/views/controls/button/button.h"
 #include "ui/views/controls/combobox/combobox_listener.h"
-#include "ui/views/controls/link_listener.h"
 
 class BookmarkBubbleViewObserver;
 class Profile;
@@ -28,7 +27,6 @@
 // bookmark it is created with. Don't create a BookmarkBubbleView directly,
 // instead use the static Show method.
 class BookmarkBubbleView : public views::BubbleDelegateView,
-                           public views::LinkListener,
                            public views::ButtonListener,
                            public views::ComboboxListener {
  public:
@@ -68,10 +66,8 @@
   // Returns the title to display.
   string16 GetTitle();
 
-  // Overridden from views::LinkListener:
-  // Either unstars the item or shows the bookmark editor (depending upon which
-  // link was clicked).
-  virtual void LinkClicked(views::Link* source, int event_flags) OVERRIDE;
+  // Overridden from views::View:
+  virtual gfx::Size GetMinimumSize() OVERRIDE;
 
   // Overridden from views::ButtonListener:
   // Closes the bubble or opens the edit dialog.
@@ -107,8 +103,8 @@
 
   RecentlyUsedFoldersComboModel parent_model_;
 
-  // Link for removing/unstarring the bookmark.
-  views::Link* remove_link_;
+  // Button for removing the bookmark.
+  views::LabelButton* remove_button_;
 
   // Button to bring up the editor.
   views::LabelButton* edit_button_;
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_editor_view.cc b/chrome/browser/ui/views/bookmarks/bookmark_editor_view.cc
index 56be739..42c7d12 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_editor_view.cc
+++ b/chrome/browser/ui/views/bookmarks/bookmark_editor_view.cc
@@ -547,7 +547,7 @@
   string16 new_title(title_tf_->text());
 
   if (!show_tree_) {
-    bookmark_utils::ApplyEditsWithNoFolderChange(
+    BookmarkEditor::ApplyEditsWithNoFolderChange(
         bb_model_, parent_, details_, new_title, new_url);
     return;
   }
@@ -557,7 +557,7 @@
   ApplyNameChangesAndCreateNewFolders(
       bb_model_->root_node(), tree_model_->GetRoot(), parent, &new_parent);
 
-  bookmark_utils::ApplyEditsWithPossibleFolderChange(
+  BookmarkEditor::ApplyEditsWithPossibleFolderChange(
       bb_model_, new_parent, details_, new_title, new_url);
 
   BookmarkExpandedStateTracker::Nodes expanded_nodes;
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_editor_view.h b/chrome/browser/ui/views/bookmarks/bookmark_editor_view.h
index b11f00d..21f553d 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_editor_view.h
+++ b/chrome/browser/ui/views/bookmarks/bookmark_editor_view.h
@@ -10,9 +10,9 @@
 #include "base/compiler_specific.h"
 #include "base/gtest_prod_util.h"
 #include "base/strings/string16.h"
-#include "chrome/browser/bookmarks/bookmark_editor.h"
 #include "chrome/browser/bookmarks/bookmark_expanded_state_tracker.h"
 #include "chrome/browser/bookmarks/bookmark_model_observer.h"
+#include "chrome/browser/ui/bookmarks/bookmark_editor.h"
 #include "ui/base/models/simple_menu_model.h"
 #include "ui/base/models/tree_node_model.h"
 #include "ui/views/context_menu_controller.h"
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_menu_delegate.cc b/chrome/browser/ui/views/bookmarks/bookmark_menu_delegate.cc
index afd0b9f..5965de1 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_menu_delegate.cc
+++ b/chrome/browser/ui/views/bookmarks/bookmark_menu_delegate.cc
@@ -9,7 +9,6 @@
 #include "chrome/browser/bookmarks/bookmark_model.h"
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
 #include "chrome/browser/bookmarks/bookmark_node_data.h"
-#include "chrome/browser/bookmarks/bookmark_utils.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/bookmarks/bookmark_drag_drop.h"
 #include "chrome/browser/ui/bookmarks/bookmark_utils.h"
@@ -106,7 +105,12 @@
     int id,
     const gfx::Point& screen_loc) const {
   MenuIDToNodeMap::const_iterator i = menu_id_to_node_map_.find(id);
-  DCHECK(i != menu_id_to_node_map_.end());
+  // When removing bookmarks it may be possible to end up here without a node.
+  if (i == menu_id_to_node_map_.end()) {
+    DCHECK(is_mutating_model_);
+    return string16();
+  }
+
   const BookmarkNode* node = i->second;
   if (node->is_url()) {
     return BookmarkBarView::CreateToolTipForURLAndTitle(
@@ -369,10 +373,6 @@
   // is the DCHECK.
   DCHECK(changed_parent_menus.size() <= 1);
 
-  for (std::set<MenuItemView*>::const_iterator i(changed_parent_menus.begin());
-       i != changed_parent_menus.end(); ++i)
-    (*i)->ChildrenChanged();
-
   // Remove any descendants of the removed nodes in |node_to_menu_map_|.
   for (NodeToMenuMap::iterator i(node_to_menu_map_.begin());
        i != node_to_menu_map_.end(); ) {
@@ -391,6 +391,10 @@
       ++i;
     }
   }
+
+  for (std::set<MenuItemView*>::const_iterator i(changed_parent_menus.begin());
+       i != changed_parent_menus.end(); ++i)
+    (*i)->ChildrenChanged();
 }
 
 void BookmarkMenuDelegate::DidRemoveBookmarks() {
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_menu_delegate.h b/chrome/browser/ui/views/bookmarks/bookmark_menu_delegate.h
index 6e36d04..7a8a2cb 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_menu_delegate.h
+++ b/chrome/browser/ui/views/bookmarks/bookmark_menu_delegate.h
@@ -62,7 +62,7 @@
             const BookmarkNode* node,
             int start_child_index,
             ShowOptions show_options,
-            bookmark_utils::BookmarkLaunchLocation);
+            bookmark_utils::BookmarkLaunchLocation location);
 
   // Sets the PageNavigator.
   void SetPageNavigator(content::PageNavigator* navigator);
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_menu_delegate_unittest.cc b/chrome/browser/ui/views/bookmarks/bookmark_menu_delegate_unittest.cc
new file mode 100644
index 0000000..5564601
--- /dev/null
+++ b/chrome/browser/ui/views/bookmarks/bookmark_menu_delegate_unittest.cc
@@ -0,0 +1,97 @@
+// 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/ui/views/bookmarks/bookmark_menu_delegate.h"
+
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/bookmarks/bookmark_model.h"
+#include "chrome/browser/bookmarks/bookmark_model_factory.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/test/base/browser_with_test_window_test.h"
+#include "chrome/test/base/testing_profile.h"
+#include "chrome/test/base/ui_test_utils.h"
+#include "ui/views/controls/menu/menu_runner.h"
+
+class BookmarkMenuDelegateTest : public BrowserWithTestWindowTest {
+ public:
+  BookmarkMenuDelegateTest() : model_(NULL) {
+  }
+
+  virtual void SetUp() OVERRIDE {
+    BrowserWithTestWindowTest::SetUp();
+
+    profile()->CreateBookmarkModel(true);
+
+    model_ = BookmarkModelFactory::GetForProfile(profile());
+    ui_test_utils::WaitForBookmarkModelToLoad(model_);
+
+    AddTestData();
+
+    bookmark_menu_delegate_.reset(
+        new BookmarkMenuDelegate(browser(), NULL, NULL, 0));
+  }
+
+  virtual void TearDown() OVERRIDE {
+    // Since we never show the menu we need to pass the MenuItemView to
+    // MenuRunner so that the MenuItemView is destroyed.
+    views::MenuRunner menu_runner(bookmark_menu_delegate_->menu());
+    bookmark_menu_delegate_.reset();
+    BrowserWithTestWindowTest::TearDown();
+  }
+
+ protected:
+  BookmarkModel* model_;
+
+  scoped_ptr<BookmarkMenuDelegate> bookmark_menu_delegate_;
+
+ private:
+  std::string base_path() const { return "file:///c:/tmp/"; }
+
+  // Creates the following structure:
+  // bookmark bar node
+  //   a
+  //   F1
+  //    f1a
+  //    F11
+  //     f11a
+  //   F2
+  // other node
+  //   oa
+  //   OF1
+  //     of1a
+  void AddTestData() {
+    const BookmarkNode* bb_node = model_->bookmark_bar_node();
+    std::string test_base = base_path();
+    model_->AddURL(bb_node, 0, ASCIIToUTF16("a"), GURL(test_base + "a"));
+    const BookmarkNode* f1 = model_->AddFolder(bb_node, 1, ASCIIToUTF16("F1"));
+    model_->AddURL(f1, 0, ASCIIToUTF16("f1a"), GURL(test_base + "f1a"));
+    const BookmarkNode* f11 = model_->AddFolder(f1, 1, ASCIIToUTF16("F11"));
+    model_->AddURL(f11, 0, ASCIIToUTF16("f11a"), GURL(test_base + "f11a"));
+    model_->AddFolder(bb_node, 2, ASCIIToUTF16("F2"));
+
+    // Children of the other node.
+    model_->AddURL(model_->other_node(), 0, ASCIIToUTF16("oa"),
+                   GURL(test_base + "oa"));
+    const BookmarkNode* of1 =
+        model_->AddFolder(model_->other_node(), 1, ASCIIToUTF16("OF1"));
+    model_->AddURL(of1, 0, ASCIIToUTF16("of1a"), GURL(test_base + "of1a"));
+  }
+
+  DISALLOW_COPY_AND_ASSIGN(BookmarkMenuDelegateTest);
+};
+
+// Verifies WillRemoveBookmarks() doesn't attempt to access MenuItemViews that
+// have since been deleted.
+TEST_F(BookmarkMenuDelegateTest, RemoveBookmarks) {
+  views::MenuDelegate test_delegate;
+  const BookmarkNode* node = model_->bookmark_bar_node()->GetChild(1);
+  bookmark_menu_delegate_->Init(&test_delegate, NULL, node, 0,
+                                BookmarkMenuDelegate::HIDE_PERMANENT_FOLDERS,
+                                bookmark_utils::LAUNCH_NONE);
+  std::vector<const BookmarkNode*> nodes_to_remove;
+  nodes_to_remove.push_back(node->GetChild(1));
+  bookmark_menu_delegate_->WillRemoveBookmarks(nodes_to_remove);
+  nodes_to_remove.clear();
+  bookmark_menu_delegate_->DidRemoveBookmarks();
+}
diff --git a/chrome/browser/ui/views/chrome_views_delegate.cc b/chrome/browser/ui/views/chrome_views_delegate.cc
index a84c8f5..f25f15a 100644
--- a/chrome/browser/ui/views/chrome_views_delegate.cc
+++ b/chrome/browser/ui/views/chrome_views_delegate.cc
@@ -4,12 +4,11 @@
 
 #include "chrome/browser/ui/views/chrome_views_delegate.h"
 
-#include "base/command_line.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/prefs/pref_service.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/profiles/profile_manager.h"
@@ -25,6 +24,7 @@
 #include <dwmapi.h>
 #include "base/win/windows_version.h"
 #include "chrome/browser/app_icon_win.h"
+#include "ui/base/win/shell.h"
 #endif
 
 #if defined(USE_AURA)
@@ -204,28 +204,27 @@
       (!params->top_level ||
        chrome::GetHostDesktopTypeForNativeView(params->parent) !=
           chrome::HOST_DESKTOP_TYPE_NATIVE);
-#endif  // defined(OS_WIN)
 
-#if defined(OS_WIN)
-  // If we're on Vista+ with composition enabled, then we can use toplevel
-  // windows for most things (they get blended via WS_EX_COMPOSITED, which
-  // allows for animation effects, but also exceeding the bounds of the parent
-  // window).
-  if (base::win::GetVersion() >= base::win::VERSION_VISTA) {
-    BOOL composition_enabled = FALSE;
-    HRESULT hr = DwmIsCompositionEnabled(&composition_enabled);
-    if (CommandLine::ForCurrentProcess()->HasSwitch(
-            switches::kDisableDwmComposition))
-      composition_enabled = FALSE;
-    if (SUCCEEDED(hr) && composition_enabled) {
-      if (chrome::GetActiveDesktop() != chrome::HOST_DESKTOP_TYPE_ASH &&
-          params->parent &&
-          params->type != views::Widget::InitParams::TYPE_CONTROL &&
-          params->type != views::Widget::InitParams::TYPE_WINDOW) {
-        // When we set this to false, we get a DesktopNativeWidgetAura from the
-        // default case (not handled in this function).
-        use_non_toplevel_window = false;
-      }
+  if (!ui::win::IsAeroGlassEnabled()) {
+    // If we don't have composition (either because Glass is not enabled or
+    // because it was disabled at the command line), anything that requires
+    // transparency will be broken with a toplevel window, so force the use of
+    // a non toplevel window.
+    if (params->opacity == views::Widget::InitParams::TRANSLUCENT_WINDOW &&
+        params->type != views::Widget::InitParams::TYPE_MENU)
+      use_non_toplevel_window = true;
+  } else {
+    // If we're on Vista+ with composition enabled, then we can use toplevel
+    // windows for most things (they get blended via WS_EX_COMPOSITED, which
+    // allows for animation effects, but also exceeding the bounds of the parent
+    // window).
+    if (chrome::GetActiveDesktop() != chrome::HOST_DESKTOP_TYPE_ASH &&
+        params->parent &&
+        params->type != views::Widget::InitParams::TYPE_CONTROL &&
+        params->type != views::Widget::InitParams::TYPE_WINDOW) {
+      // When we set this to false, we get a DesktopNativeWidgetAura from the
+      // default case (not handled in this function).
+      use_non_toplevel_window = false;
     }
   }
 #endif  // OS_WIN
diff --git a/chrome/browser/ui/views/chrome_views_delegate_chromeos.cc b/chrome/browser/ui/views/chrome_views_delegate_chromeos.cc
index f387f08..e1bcf4a 100644
--- a/chrome/browser/ui/views/chrome_views_delegate_chromeos.cc
+++ b/chrome/browser/ui/views/chrome_views_delegate_chromeos.cc
@@ -4,21 +4,19 @@
 
 #include "chrome/browser/ui/views/chrome_views_delegate.h"
 
-#include "base/time.h"
-#include "chrome/browser/chromeos/login/startup_utils.h"
+#include "base/time/time.h"
 #include "chrome/browser/chromeos/login/user_manager.h"
 #include "chrome/browser/chromeos/system/statistics_provider.h"
 #include "chromeos/chromeos_constants.h"
 
 base::TimeDelta
 ChromeViewsDelegate::GetDefaultTextfieldObscuredRevealDuration() {
-  // Enable password echo during OOBE when keyboard driven flag is set.
+  // Enable password echo on login screen when the keyboard driven flag is set.
   if (chromeos::UserManager::IsInitialized() &&
-      !chromeos::UserManager::Get()->IsUserLoggedIn() &&
-      !chromeos::StartupUtils::IsOobeCompleted()) {
+      !chromeos::UserManager::Get()->IsUserLoggedIn()) {
     bool keyboard_driven_oobe = false;
     chromeos::system::StatisticsProvider::GetInstance()->GetMachineFlag(
-        chromeos::kOemKeyboardDrivenOobeKey, &keyboard_driven_oobe);
+        chromeos::system::kOemKeyboardDrivenOobeKey, &keyboard_driven_oobe);
     if (keyboard_driven_oobe)
       return base::TimeDelta::FromSeconds(1);
   }
diff --git a/chrome/browser/ui/views/collected_cookies_views.cc b/chrome/browser/ui/views/collected_cookies_views.cc
index c91af18..4f26860 100644
--- a/chrome/browser/ui/views/collected_cookies_views.cc
+++ b/chrome/browser/ui/views/collected_cookies_views.cc
@@ -45,6 +45,7 @@
 #include "ui/views/layout/grid_layout.h"
 #include "ui/views/layout/layout_constants.h"
 #include "ui/views/widget/widget.h"
+#include "ui/views/window/dialog_delegate.h"
 
 using web_modal::WebContentsModalDialogManager;
 
@@ -310,11 +311,13 @@
                         GridLayout::USE_PREF, 0, 0);
 
   layout->StartRow(0, single_column_layout_id);
-  views::TabbedPane* tabbed_pane = new views::TabbedPane();
-  // This color matches tabbed_pane.cc's kTabBorderColor.
-  const SkColor border_color = SkColorSetRGB(0xCC, 0xCC, 0xCC);
-  // TODO(msw): Remove border and expand bounds in new dialog style.
-  tabbed_pane->set_border(views::Border::CreateSolidBorder(1, border_color));
+  views::TabbedPane* tabbed_pane = NULL;
+  if (DialogDelegate::UseNewStyle()) {
+    tabbed_pane = new views::TabbedPane(false);
+    layout->SetInsets(gfx::Insets());
+  } else {
+    tabbed_pane = new views::TabbedPane(true);
+  }
 
   layout->AddView(tabbed_pane);
   // NOTE: Panes must be added after |tabbed_pane| has been added to its parent.
diff --git a/chrome/browser/ui/views/constrained_window_views.cc b/chrome/browser/ui/views/constrained_window_views.cc
index ffba423..bc7bb68 100644
--- a/chrome/browser/ui/views/constrained_window_views.cc
+++ b/chrome/browser/ui/views/constrained_window_views.cc
@@ -661,7 +661,7 @@
             dialog,
             kWebContentsModalDialogHostObserverViewsKey);
 #if defined(USE_AURA)
-    params.transparent = true;
+    params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
 #endif
   } else {
     params.parent = parent;
diff --git a/chrome/browser/ui/views/cookie_info_view.cc b/chrome/browser/ui/views/cookie_info_view.cc
index 6747cd5..d7e1657 100644
--- a/chrome/browser/ui/views/cookie_info_view.cc
+++ b/chrome/browser/ui/views/cookie_info_view.cc
@@ -25,6 +25,7 @@
 #include "ui/views/controls/textfield/textfield.h"
 #include "ui/views/layout/grid_layout.h"
 #include "ui/views/layout/layout_constants.h"
+#include "ui/views/window/dialog_delegate.h"
 
 namespace {
 
@@ -184,9 +185,6 @@
 #else
   SkColor border_color = color_utils::GetSysSkColor(COLOR_3DSHADOW);
 #endif
-  views::Border* border = views::Border::CreateSolidBorder(
-      kCookieInfoViewBorderSize, border_color);
-  set_border(border);
 
   name_label_ = new views::Label(
       l10n_util::GetStringUTF16(IDS_COOKIES_COOKIE_NAME_LABEL));
@@ -217,10 +215,17 @@
   using views::ColumnSet;
 
   GridLayout* layout = new GridLayout(this);
-  layout->SetInsets(kCookieInfoViewInsetSize,
-                    kCookieInfoViewInsetSize,
-                    kCookieInfoViewInsetSize,
-                    kCookieInfoViewInsetSize);
+  if (views::DialogDelegate::UseNewStyle()) {
+    layout->SetInsets(
+        0, views::kButtonHEdgeMarginNew, 0, views::kButtonHEdgeMarginNew);
+  } else {
+    set_border(views::Border::CreateSolidBorder(kCookieInfoViewBorderSize,
+                                                border_color));
+    layout->SetInsets(kCookieInfoViewInsetSize,
+                      kCookieInfoViewInsetSize,
+                      kCookieInfoViewInsetSize,
+                      kCookieInfoViewInsetSize);
+  }
   SetLayoutManager(layout);
 
   int three_column_layout_id = 0;
diff --git a/chrome/browser/ui/views/create_application_shortcut_view.cc b/chrome/browser/ui/views/create_application_shortcut_view.cc
index 8fd8b73..80e346f 100644
--- a/chrome/browser/ui/views/create_application_shortcut_view.cc
+++ b/chrome/browser/ui/views/create_application_shortcut_view.cc
@@ -382,7 +382,8 @@
   creation_locations.in_quick_launch_bar = false;
 #endif
 
-  web_app::CreateShortcuts(shortcut_info_, creation_locations);
+  web_app::CreateShortcuts(shortcut_info_, creation_locations,
+                           web_app::ALLOW_DUPLICATE_SHORTCUTS);
   return true;
 }
 
@@ -456,11 +457,13 @@
   if (unprocessed_icons_.empty())  // No icons to fetch.
     return;
 
+  int preferred_size = std::max(unprocessed_icons_.back().width,
+                                unprocessed_icons_.back().height);
   pending_download_id_ = web_contents_->DownloadImage(
       unprocessed_icons_.back().url,
-      true,
-      std::max(unprocessed_icons_.back().width,
-               unprocessed_icons_.back().height),
+      true,  // is a favicon
+      preferred_size,
+      0,  // no maximum size
       base::Bind(&CreateUrlApplicationShortcutView::DidDownloadFavicon,
                  base::Unretained(this)));
 
diff --git a/chrome/browser/ui/views/critical_notification_bubble_view.h b/chrome/browser/ui/views/critical_notification_bubble_view.h
index d4facfc..f387c29 100644
--- a/chrome/browser/ui/views/critical_notification_bubble_view.h
+++ b/chrome/browser/ui/views/critical_notification_bubble_view.h
@@ -5,7 +5,7 @@
 #ifndef CHROME_BROWSER_UI_VIEWS_CRITICAL_NOTIFICATION_BUBBLE_VIEW_H_
 #define CHROME_BROWSER_UI_VIEWS_CRITICAL_NOTIFICATION_BUBBLE_VIEW_H_
 
-#include "base/timer.h"
+#include "base/timer/timer.h"
 #include "ui/views/bubble/bubble_delegate.h"
 #include "ui/views/controls/button/button.h"
 
diff --git a/chrome/browser/ui/views/detachable_toolbar_view.cc b/chrome/browser/ui/views/detachable_toolbar_view.cc
index 4975158..b57e104 100644
--- a/chrome/browser/ui/views/detachable_toolbar_view.cc
+++ b/chrome/browser/ui/views/detachable_toolbar_view.cc
@@ -66,16 +66,6 @@
 }
 
 // static
-void DetachableToolbarView::PaintHorizontalBorderForState(
-    gfx::Canvas* canvas,
-    DetachableToolbarView* view) {
-  // Border can be at the top or at the bottom of the view depending on whether
-  // the view (bar/shelf) is attached or detached.
-  PaintHorizontalBorder(canvas, view, view->IsDetached(),
-                        ThemeProperties::GetDefaultColor(
-                            ThemeProperties::COLOR_TOOLBAR_SEPARATOR));
-}
-
 void DetachableToolbarView::PaintHorizontalBorder(
     gfx::Canvas* canvas,
     DetachableToolbarView* view,
diff --git a/chrome/browser/ui/views/detachable_toolbar_view.h b/chrome/browser/ui/views/detachable_toolbar_view.h
index 0fc784d..1148312 100644
--- a/chrome/browser/ui/views/detachable_toolbar_view.h
+++ b/chrome/browser/ui/views/detachable_toolbar_view.h
@@ -55,11 +55,6 @@
                                    views::View* view);
 
   // Paint the horizontal border separating the shelf/bar from the toolbar or
-  // page content according to view's detached/attached state.
-  static void PaintHorizontalBorderForState(gfx::Canvas* canvas,
-                                            DetachableToolbarView* view);
-
-  // Paint the horizontal border separating the shelf/bar from the toolbar or
   // page content according to |at_top| with |color|.
   static void PaintHorizontalBorder(gfx::Canvas* canvas,
                                     DetachableToolbarView* view,
diff --git a/chrome/browser/ui/views/download/download_item_view.h b/chrome/browser/ui/views/download/download_item_view.h
index ac672a5..61e7327 100644
--- a/chrome/browser/ui/views/download/download_item_view.h
+++ b/chrome/browser/ui/views/download/download_item_view.h
@@ -22,8 +22,8 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/strings/string_util.h"
-#include "base/time.h"
-#include "base/timer.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
 #include "chrome/browser/download/download_item_model.h"
 #include "chrome/browser/icon_manager.h"
 #include "chrome/common/cancelable_task_tracker.h"
diff --git a/chrome/browser/ui/views/download/download_started_animation_views.cc b/chrome/browser/ui/views/download/download_started_animation_views.cc
index 5b67f38..80252bd 100644
--- a/chrome/browser/ui/views/download/download_started_animation_views.cc
+++ b/chrome/browser/ui/views/download/download_started_animation_views.cc
@@ -109,7 +109,7 @@
   popup_ = new views::Widget;
 
   views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP);
-  params.transparent = true;
+  params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
   params.accept_events = false;
   params.parent = web_contents_->GetView()->GetNativeView();
   popup_->Init(params);
diff --git a/chrome/browser/ui/views/dropdown_bar_host.cc b/chrome/browser/ui/views/dropdown_bar_host.cc
index fb16b7c..1d150c8 100644
--- a/chrome/browser/ui/views/dropdown_bar_host.cc
+++ b/chrome/browser/ui/views/dropdown_bar_host.cc
@@ -67,7 +67,7 @@
   params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
   params.parent = browser_view_->GetWidget()->GetNativeView();
 #if defined(USE_AURA)
-  params.transparent = true;
+  params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
 #endif
   host_->Init(params);
   host_->SetContentsView(view_);
diff --git a/chrome/browser/ui/views/extensions/extension_installed_bubble.cc b/chrome/browser/ui/views/extensions/extension_installed_bubble.cc
index caa0369..7d43187 100644
--- a/chrome/browser/ui/views/extensions/extension_installed_bubble.cc
+++ b/chrome/browser/ui/views/extensions/extension_installed_bubble.cc
@@ -19,13 +19,14 @@
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/singleton_tabs.h"
+#include "chrome/browser/ui/sync/sync_promo_ui.h"
 #include "chrome/browser/ui/views/browser_action_view.h"
 #include "chrome/browser/ui/views/browser_actions_container.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
+#include "chrome/browser/ui/views/frame/immersive_mode_controller.h"
 #include "chrome/browser/ui/views/location_bar/location_bar_view.h"
 #include "chrome/browser/ui/views/tabs/tab_strip.h"
 #include "chrome/browser/ui/views/toolbar_view.h"
-#include "chrome/browser/ui/webui/sync_promo/sync_promo_ui.h"
 #include "chrome/common/chrome_notification_types.h"
 #include "chrome/common/extensions/api/extension_action/action_info.h"
 #include "chrome/common/extensions/api/omnibox/omnibox_handler.h"
@@ -653,6 +654,15 @@
   SetLayoutManager(new views::FillLayout());
   AddChildView(
       new InstalledBubbleContent(browser_, extension_, type_, &icon_, this));
+
+  // If we are in immersive fullscreen, reveal the top-of-window views
+  // (omnibox, toolbar) so that the view the bubble is anchored to is visible.
+  // We do not need to hold onto the lock because ImmersiveModeController will
+  // keep the top-of-window views revealed as long as the popup is active.
+  // TODO(pkotwicz): Move logic to ImmersiveModeController.
+  scoped_ptr<ImmersiveRevealedLock> immersive_reveal_lock(
+      browser_view->immersive_mode_controller()->GetRevealedLock(
+          ImmersiveModeController::ANIMATE_REVEAL_NO));
   views::BubbleDelegateView::CreateBubble(this);
 
   // The bubble widget is now the parent and owner of |this| and takes care of
diff --git a/chrome/browser/ui/views/extensions/extension_popup.cc b/chrome/browser/ui/views/extensions/extension_popup.cc
index d02e840..0c36f22 100644
--- a/chrome/browser/ui/views/extensions/extension_popup.cc
+++ b/chrome/browser/ui/views/extensions/extension_popup.cc
@@ -13,6 +13,9 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_window.h"
+#include "chrome/browser/ui/views/frame/browser_view.h"
+#include "chrome/browser/ui/views/frame/immersive_mode_controller.h"
+#include "chrome/browser/ui/views/frame/top_container_view.h"
 #include "chrome/common/chrome_notification_types.h"
 #include "content/public/browser/devtools_agent_host.h"
 #include "content/public/browser/devtools_manager.h"
@@ -67,6 +70,7 @@
                                views::BubbleBorder::Arrow arrow,
                                ShowAction show_action)
     : BubbleDelegateView(anchor_view, arrow),
+      browser_(browser),
       extension_host_(host),
       devtools_callback_(base::Bind(
           &ExtensionPopup::OnDevToolsStateChanged, base::Unretained(this))) {
@@ -193,6 +197,21 @@
 }
 
 void ExtensionPopup::ShowBubble() {
+  BrowserView* browser_view = browser_ ?
+      BrowserView::GetBrowserViewForBrowser(browser_) : NULL;
+  scoped_ptr<ImmersiveRevealedLock> immersive_reveal_lock;
+  if (browser_view &&
+      browser_view->top_container()->Contains(anchor_view())) {
+    // If we are in immersive fullscreen and we are anchored to a view in the
+    // top-of-window views (eg omnibox, toolbar), trigger an immersive reveal.
+    // We do not need to hold onto the lock because ImmersiveModeController will
+    // keep the top-of-window views revealed as long as the popup is active.
+    // TODO(pkotwicz): Move logic to ImmersiveModeController.
+    immersive_reveal_lock.reset(
+        browser_view->immersive_mode_controller()->GetRevealedLock(
+            ImmersiveModeController::ANIMATE_REVEAL_NO));
+    SizeToContents();
+  }
   GetWidget()->Show();
 
   // Focus on the host contents when the bubble is first shown.
diff --git a/chrome/browser/ui/views/extensions/extension_popup.h b/chrome/browser/ui/views/extensions/extension_popup.h
index f8b3237..b3b031a 100644
--- a/chrome/browser/ui/views/extensions/extension_popup.h
+++ b/chrome/browser/ui/views/extensions/extension_popup.h
@@ -84,6 +84,9 @@
 
   void OnDevToolsStateChanged(content::DevToolsAgentHost*, bool attached);
 
+  // The browser to which the popup is anchored. Not owned.
+  Browser* browser_;
+
   // The contained host for the view.
   scoped_ptr<extensions::ExtensionHost> extension_host_;
 
diff --git a/chrome/browser/ui/views/extensions/media_galleries_dialog_views.cc b/chrome/browser/ui/views/extensions/media_galleries_dialog_views.cc
index 7e80dd0..409b889 100644
--- a/chrome/browser/ui/views/extensions/media_galleries_dialog_views.cc
+++ b/chrome/browser/ui/views/extensions/media_galleries_dialog_views.cc
@@ -192,24 +192,6 @@
   layout->AddView(scroll_view, 1, 1,
                   views::GridLayout::FILL, views::GridLayout::FILL,
                   dialog_content_width, kScrollAreaHeight);
-
-  // Add location button.
-  add_gallery_button_ = new views::LabelButton(this,
-      l10n_util::GetStringUTF16(IDS_MEDIA_GALLERIES_DIALOG_ADD_GALLERY));
-  add_gallery_button_->SetStyle(views::Button::STYLE_NATIVE_TEXTBUTTON);
-  views::View* add_gallery_container = new views::View();
-  add_gallery_container->SetLayoutManager(
-      new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, 0));
-  add_gallery_container->set_border(views::Border::CreateEmptyBorder(
-      views::kRelatedControlVerticalSpacing,
-      0,
-      views::kRelatedControlVerticalSpacing,
-      0));
-  add_gallery_container->AddChildView(add_gallery_button_);
-
-  layout->StartRowWithPadding(0, column_set_id,
-                              0, views::kRelatedControlVerticalSpacing);
-  layout->AddView(add_gallery_container);
 }
 
 void MediaGalleriesDialogViews::UpdateGallery(
@@ -229,13 +211,9 @@
     bool permitted,
     views::View* container,
     int trailing_vertical_space) {
-  string16 label =
-      MediaGalleriesDialogController::GetGalleryDisplayNameNoAttachment(
-          gallery);
-  string16 tooltip_text =
-      MediaGalleriesDialogController::GetGalleryTooltip(gallery);
-  string16 details =
-      MediaGalleriesDialogController::GetGalleryAdditionalDetails(gallery);
+  string16 label = gallery.GetGalleryDisplayName();
+  string16 tooltip_text = gallery.GetGalleryTooltip();
+  string16 details = gallery.GetGalleryAdditionalDetails();
 
   CheckboxMap::iterator iter = checkbox_map_.find(gallery.pref_id);
   if (iter != checkbox_map_.end()) {
@@ -330,6 +308,14 @@
 #endif
 }
 
+views::View* MediaGalleriesDialogViews::CreateExtraView() {
+  DCHECK(!add_gallery_button_);
+  add_gallery_button_ = new views::LabelButton(this,
+      l10n_util::GetStringUTF16(IDS_MEDIA_GALLERIES_DIALOG_ADD_GALLERY));
+  add_gallery_button_->SetStyle(views::Button::STYLE_NATIVE_TEXTBUTTON);
+  return add_gallery_button_;
+}
+
 bool MediaGalleriesDialogViews::Cancel() {
   return true;
 }
diff --git a/chrome/browser/ui/views/extensions/media_galleries_dialog_views.h b/chrome/browser/ui/views/extensions/media_galleries_dialog_views.h
index cd043b9..a6944be 100644
--- a/chrome/browser/ui/views/extensions/media_galleries_dialog_views.h
+++ b/chrome/browser/ui/views/extensions/media_galleries_dialog_views.h
@@ -45,6 +45,7 @@
   virtual string16 GetDialogButtonLabel(ui::DialogButton button) const OVERRIDE;
   virtual bool IsDialogButtonEnabled(ui::DialogButton button) const OVERRIDE;
   virtual ui::ModalType GetModalType() const OVERRIDE;
+  virtual views::View* CreateExtraView() OVERRIDE;
   virtual bool Cancel() OVERRIDE;
   virtual bool Accept() OVERRIDE;
   virtual views::NonClientFrameView* CreateNonClientFrameView(
diff --git a/chrome/browser/ui/views/extensions/native_app_window_views.cc b/chrome/browser/ui/views/extensions/native_app_window_views.cc
index a030010..8d5433a 100644
--- a/chrome/browser/ui/views/extensions/native_app_window_views.cc
+++ b/chrome/browser/ui/views/extensions/native_app_window_views.cc
@@ -30,6 +30,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/ui/web_applications/web_app_ui.h"
 #include "chrome/browser/web_applications/web_app.h"
+#include "chrome/browser/web_applications/web_app_win.h"
 #include "ui/base/win/shell.h"
 #include "ui/views/win/hwnd_util.h"
 #endif
@@ -46,6 +47,8 @@
 #include "ui/aura/window.h"
 #endif
 
+using apps::ShellWindow;
+
 namespace {
 
 const int kMinPanelWidth = 100;
diff --git a/chrome/browser/ui/views/extensions/native_app_window_views.h b/chrome/browser/ui/views/extensions/native_app_window_views.h
index 0b66b57..138a9e0 100644
--- a/chrome/browser/ui/views/extensions/native_app_window_views.h
+++ b/chrome/browser/ui/views/extensions/native_app_window_views.h
@@ -5,9 +5,9 @@
 #ifndef CHROME_BROWSER_UI_VIEWS_EXTENSIONS_NATIVE_APP_WINDOW_VIEWS_H_
 #define CHROME_BROWSER_UI_VIEWS_EXTENSIONS_NATIVE_APP_WINDOW_VIEWS_H_
 
+#include "apps/shell_window.h"
 #include "base/observer_list.h"
 #include "chrome/browser/ui/extensions/native_app_window.h"
-#include "chrome/browser/ui/extensions/shell_window.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "third_party/skia/include/core/SkRegion.h"
 #include "ui/gfx/image/image_skia.h"
@@ -41,16 +41,18 @@
                              public views::WidgetObserver,
                              public content::WebContentsObserver {
  public:
-  NativeAppWindowViews(ShellWindow* shell_window,
-                       const ShellWindow::CreateParams& params);
+  NativeAppWindowViews(apps::ShellWindow* shell_window,
+                       const apps::ShellWindow::CreateParams& params);
   virtual ~NativeAppWindowViews();
 
   bool frameless() const { return frameless_; }
   SkRegion* draggable_region() { return draggable_region_.get(); }
 
  private:
-  void InitializeDefaultWindow(const ShellWindow::CreateParams& create_params);
-  void InitializePanelWindow(const ShellWindow::CreateParams& create_params);
+  void InitializeDefaultWindow(
+      const apps::ShellWindow::CreateParams& create_params);
+  void InitializePanelWindow(
+      const apps::ShellWindow::CreateParams& create_params);
   void OnViewWasResized();
 
   bool ShouldUseChromeStyleFrame() const;
@@ -154,7 +156,7 @@
     return shell_window_->extension();
   }
 
-  ShellWindow* shell_window_; // weak - ShellWindow owns NativeAppWindow.
+  apps::ShellWindow* shell_window_; // weak - ShellWindow owns NativeAppWindow.
   views::WebView* web_view_;
   views::Widget* window_;
   bool is_fullscreen_;
diff --git a/chrome/browser/ui/views/external_protocol_dialog.h b/chrome/browser/ui/views/external_protocol_dialog.h
index e16ec67..2f79103 100644
--- a/chrome/browser/ui/views/external_protocol_dialog.h
+++ b/chrome/browser/ui/views/external_protocol_dialog.h
@@ -7,7 +7,7 @@
 
 #include "base/basictypes.h"
 #include "base/compiler_specific.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "googleurl/src/gurl.h"
 #include "ui/views/window/dialog_delegate.h"
 
diff --git a/chrome/browser/ui/views/external_tab_container_win.cc b/chrome/browser/ui/views/external_tab_container_win.cc
index 4970de9..92c5834 100644
--- a/chrome/browser/ui/views/external_tab_container_win.cc
+++ b/chrome/browser/ui/views/external_tab_container_win.cc
@@ -19,7 +19,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/strings/string16.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "base/win/win_util.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/app/chrome_dll_resource.h"
@@ -342,6 +342,7 @@
   params.desktop_root_window_host =
       new ExternalTabRootWindowHost(widget_, native_widget, params.bounds);
   params.type = views::Widget::InitParams::TYPE_WINDOW_FRAMELESS;
+  params.opacity = views::Widget::InitParams::OPAQUE_WINDOW;
 #endif
   widget_->Init(params);
 
@@ -831,7 +832,12 @@
 void ExternalTabContainerWin::RegisterRenderViewHostForAutomation(
     bool pending_view,
     RenderViewHost* render_view_host) {
-  if (render_view_host) {
+  if (!GetTabHandle()) {
+    // This method is being called when it shouldn't be on the win_rel trybot;
+    // see http://crbug.com/250965. Don't crash release builds in that case
+    // until the root cause can be diagnosed and fixed. TODO(grt): fix this.
+    DLOG(FATAL) << "tab_handle_ unset";
+  } else if (render_view_host) {
     AutomationResourceMessageFilter::RegisterRenderView(
         render_view_host->GetProcess()->GetID(),
         render_view_host->GetRoutingID(),
diff --git a/chrome/browser/ui/views/frame/app_non_client_frame_view_ash.cc b/chrome/browser/ui/views/frame/app_non_client_frame_view_ash.cc
index c604457..fbdb190 100644
--- a/chrome/browser/ui/views/frame/app_non_client_frame_view_ash.cc
+++ b/chrome/browser/ui/views/frame/app_non_client_frame_view_ash.cc
@@ -214,7 +214,7 @@
   control_widget_ = new views::Widget;
   views::Widget::InitParams params(views::Widget::InitParams::TYPE_CONTROL);
   params.parent = browser_view->GetNativeWindow();
-  params.transparent = true;
+  params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
   control_widget_->Init(params);
   control_widget_->SetContentsView(control_view_);
   aura::Window* window = control_widget_->GetNativeView();
diff --git a/chrome/browser/ui/views/frame/browser_desktop_root_window_host_win.cc b/chrome/browser/ui/views/frame/browser_desktop_root_window_host_win.cc
index 07f888d..3e8e4d7 100644
--- a/chrome/browser/ui/views/frame/browser_desktop_root_window_host_win.cc
+++ b/chrome/browser/ui/views/frame/browser_desktop_root_window_host_win.cc
@@ -151,6 +151,10 @@
 }
 
 void BrowserDesktopRootWindowHostWin::HandleFrameChanged() {
+  // Reinitialize the status bubble, since it needs to be initialized
+  // differently depending on whether or not DWM composition is enabled
+  browser_view_->InitStatusBubble();
+
   // We need to update the glass region on or off before the base class adjusts
   // the window region.
   UpdateDWMFrame();
diff --git a/chrome/browser/ui/views/frame/browser_frame_win.cc b/chrome/browser/ui/views/frame/browser_frame_win.cc
index cc0f756..7234942 100644
--- a/chrome/browser/ui/views/frame/browser_frame_win.cc
+++ b/chrome/browser/ui/views/frame/browser_frame_win.cc
@@ -14,9 +14,7 @@
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/lifetime/application_lifetime.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/search_engines/template_url.h"
-#include "chrome/browser/search_engines/template_url_service.h"
-#include "chrome/browser/search_engines/template_url_service_factory.h"
+#include "chrome/browser/search_engines/util.h"
 #include "chrome/browser/ui/browser_commands.h"
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
@@ -466,22 +464,11 @@
   DCHECK(browser);
 
   GURL request_url;
-
   if (w_param) {
-    const wchar_t* url = reinterpret_cast<const wchar_t*>(w_param);
-    request_url = GURL(url);
+    request_url = GURL(reinterpret_cast<const wchar_t*>(w_param));
   } else if (l_param) {
-    const wchar_t* search_string =
-        reinterpret_cast<const wchar_t*>(l_param);
-    const TemplateURL* default_provider =
-        TemplateURLServiceFactory::GetForProfile(browser->profile())->
-        GetDefaultSearchProvider();
-    if (default_provider) {
-      const TemplateURLRef& search_url = default_provider->url_ref();
-      DCHECK(search_url.SupportsReplacement());
-      request_url = GURL(search_url.ReplaceSearchTerms(
-          TemplateURLRef::SearchTermsArgs(search_string)));
-    }
+    request_url = GetDefaultSearchURLForSearchTerms(
+        browser->profile(), reinterpret_cast<const wchar_t*>(l_param));
   }
   if (request_url.is_valid()) {
     browser->OpenURL(OpenURLParams(request_url, Referrer(), NEW_FOREGROUND_TAB,
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view.cc
index 049e266..d7e2f76 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view.cc
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view.cc
@@ -9,7 +9,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_info_cache.h"
 #include "chrome/browser/profiles/profile_manager.h"
-#include "chrome/browser/themes/theme_properties.h"
+#include "chrome/browser/ui/views/avatar_label.h"
 #include "chrome/browser/ui/views/avatar_menu_button.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/views/frame/taskbar_decorator.h"
@@ -21,7 +21,6 @@
 #include "ui/base/theme_provider.h"
 #include "ui/gfx/image/image.h"
 #include "ui/views/background.h"
-#include "ui/views/controls/label.h"
 
 #if defined(ENABLE_MANAGED_USERS)
 #include "chrome/browser/managed_mode/managed_user_service.h"
@@ -31,7 +30,9 @@
 BrowserNonClientFrameView::BrowserNonClientFrameView(BrowserFrame* frame,
                                                      BrowserView* browser_view)
     : frame_(frame),
-      browser_view_(browser_view) {
+      browser_view_(browser_view),
+      avatar_button_(NULL),
+      avatar_label_(NULL) {
 }
 
 BrowserNonClientFrameView::~BrowserNonClientFrameView() {
@@ -48,54 +49,38 @@
 }
 
 void BrowserNonClientFrameView::OnThemeChanged() {
-  UpdateAvatarLabelStyle();
-}
-
-void BrowserNonClientFrameView::UpdateAvatarLabelStyle() {
-  if (!avatar_label_.get())
-    return;
-
-  ui::ThemeProvider* tp = frame_->GetThemeProvider();
-  SkColor color_background = tp->GetColor(
-      ThemeProperties::COLOR_MANAGED_USER_LABEL_BACKGROUND);
-  avatar_label_->set_background(
-      views::Background::CreateSolidBackground(color_background));
-  avatar_label_->SetBackgroundColor(color_background);
-  SkColor color_label = tp->GetColor(
-      ThemeProperties::COLOR_MANAGED_USER_LABEL);
-  avatar_label_->SetEnabledColor(color_label);
+  if (avatar_label_)
+    avatar_label_->UpdateLabelStyle();
 }
 
 void BrowserNonClientFrameView::UpdateAvatarInfo() {
   if (browser_view_->ShouldShowAvatar()) {
-    if (!avatar_button_.get()) {
-      avatar_button_.reset(
-          new AvatarMenuButton(browser_view_->browser(),
-                               browser_view_->IsOffTheRecord()));
-      AddChildView(avatar_button_.get());
+    if (!avatar_button_) {
+      avatar_button_ = new AvatarMenuButton(browser_view_->browser(),
+                                            browser_view_->IsOffTheRecord());
+      AddChildView(avatar_button_);
 #if defined(ENABLE_MANAGED_USERS)
       Profile* profile = browser_view_->browser()->profile();
       ManagedUserService* service =
           ManagedUserServiceFactory::GetForProfile(profile);
-      if (service->ProfileIsManaged() && !avatar_label_.get()) {
-        ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
-        avatar_label_.reset(new views::Label(
-            l10n_util::GetStringUTF16(IDS_MANAGED_USER_AVATAR_LABEL),
-            rb.GetFont(ui::ResourceBundle::BoldFont)));
-        UpdateAvatarLabelStyle();
-        AddChildView(avatar_label_.get());
+      if (service->ProfileIsManaged() && !avatar_label_) {
+        avatar_label_ =
+            new AvatarLabel(browser_view_, frame_->GetThemeProvider());
+        AddChildView(avatar_label_);
       }
 #endif
       frame_->GetRootView()->Layout();
     }
-  } else if (avatar_button_.get()) {
+  } else if (avatar_button_) {
     // The avatar label can just be there if there is also an avatar button.
-    if (avatar_label_.get()) {
-      RemoveChildView(avatar_label_.get());
-      avatar_label_.reset();
+    if (avatar_label_) {
+      RemoveChildView(avatar_label_);
+      delete avatar_label_;
+      avatar_label_ = NULL;
     }
-    RemoveChildView(avatar_button_.get());
-    avatar_button_.reset();
+    RemoveChildView(avatar_button_);
+    delete avatar_button_;
+    avatar_button_ = NULL;
     frame_->GetRootView()->Layout();
   }
 
@@ -118,7 +103,7 @@
     avatar = cache.GetAvatarIconOfProfileAtIndex(index);
     text = cache.GetNameOfProfileAtIndex(index);
   }
-  if (avatar_button_.get()) {
+  if (avatar_button_) {
     avatar_button_->SetAvatarIcon(avatar, is_gaia_picture);
     if (!text.empty())
       avatar_button_->SetText(text);
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view.h b/chrome/browser/ui/views/frame/browser_non_client_frame_view.h
index 8f319a8..91a9b0d 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view.h
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view.h
@@ -5,17 +5,13 @@
 #ifndef CHROME_BROWSER_UI_VIEWS_FRAME_BROWSER_NON_CLIENT_FRAME_VIEW_H_
 #define CHROME_BROWSER_UI_VIEWS_FRAME_BROWSER_NON_CLIENT_FRAME_VIEW_H_
 
-#include "base/memory/scoped_ptr.h"
 #include "ui/views/window/non_client_view.h"
 
+class AvatarLabel;
 class AvatarMenuButton;
 class BrowserFrame;
 class BrowserView;
 
-namespace views {
-class Label;
-}
-
 // A specialization of the NonClientFrameView object that provides additional
 // Browser-specific methods.
 class BrowserNonClientFrameView : public views::NonClientFrameView {
@@ -36,9 +32,9 @@
   BrowserNonClientFrameView(BrowserFrame* frame, BrowserView* browser_view);
   virtual ~BrowserNonClientFrameView();
 
-  AvatarMenuButton* avatar_button() const { return avatar_button_.get(); }
+  AvatarMenuButton* avatar_button() const { return avatar_button_; }
 
-  views::Label* avatar_label() const { return avatar_label_.get(); }
+  AvatarLabel* avatar_label() const { return avatar_label_; }
 
   // Returns the bounds within which the TabStrip should be laid out.
   virtual gfx::Rect GetBoundsForTabStrip(views::View* tabstrip) const = 0;
@@ -63,9 +59,6 @@
   BrowserView* browser_view() const { return browser_view_; }
   BrowserFrame* frame() const { return frame_; }
 
-  // Determine the color of the label text and the label background.
-  void UpdateAvatarLabelStyle();
-
   // Updates the title and icon of the avatar button.
   void UpdateAvatarInfo();
 
@@ -78,10 +71,10 @@
 
   // Menu button that displays that either the incognito icon or the profile
   // icon.  May be NULL for some frame styles.
-  scoped_ptr<AvatarMenuButton> avatar_button_;
+  AvatarMenuButton* avatar_button_;
 
   // Avatar label that is used for a managed user.
-  scoped_ptr<views::Label> avatar_label_;
+  AvatarLabel* avatar_label_;
 };
 
 namespace chrome {
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc
index 28b2be3..523a456 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc
@@ -11,6 +11,7 @@
 #include "chrome/browser/ui/ash/chrome_shell_delegate.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/immersive_fullscreen_configuration.h"
+#include "chrome/browser/ui/views/avatar_label.h"
 #include "chrome/browser/ui/views/avatar_menu_button.h"
 #include "chrome/browser/ui/views/frame/browser_frame.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
diff --git a/chrome/browser/ui/views/frame/browser_root_view.cc b/chrome/browser/ui/views/frame/browser_root_view.cc
index 44cd1dc..88aea53 100644
--- a/chrome/browser/ui/views/frame/browser_root_view.cc
+++ b/chrome/browser/ui/views/frame/browser_root_view.cc
@@ -14,6 +14,7 @@
 #include "chrome/browser/ui/views/frame/browser_frame.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/views/tabs/tab_strip.h"
+#include "chrome/browser/ui/views/touch_uma/touch_uma.h"
 #include "chrome/common/chrome_notification_types.h"
 #include "grit/chromium_strings.h"
 #include "ui/base/accessibility/accessible_view_state.h"
@@ -119,6 +120,16 @@
   return kViewClassName;
 }
 
+void BrowserRootView::DispatchGestureEvent(ui::GestureEvent* event) {
+  if (event->type() == ui::ET_GESTURE_TAP &&
+      event->location().y() <= 0 &&
+      event->location().x() <= browser_view_->GetBounds().width()) {
+    TouchUMA::RecordGestureAction(TouchUMA::GESTURE_ROOTVIEWTOP_TAP);
+  }
+
+  RootView::DispatchGestureEvent(event);
+}
+
 bool BrowserRootView::ShouldForwardToTabStrip(
     const ui::DropTargetEvent& event) {
   if (!tabstrip()->visible())
diff --git a/chrome/browser/ui/views/frame/browser_root_view.h b/chrome/browser/ui/views/frame/browser_root_view.h
index 594b70c..6200f8b 100644
--- a/chrome/browser/ui/views/frame/browser_root_view.h
+++ b/chrome/browser/ui/views/frame/browser_root_view.h
@@ -39,6 +39,9 @@
   virtual int OnPerformDrop(const ui::DropTargetEvent& event) OVERRIDE;
   virtual const char* GetClassName() const OVERRIDE;
 
+  // Overridden from internal::RootView:
+  virtual void DispatchGestureEvent(ui::GestureEvent* event) OVERRIDE;
+
  private:
   // Returns true if the event should be forwarded to the tabstrip.
   bool ShouldForwardToTabStrip(const ui::DropTargetEvent& event);
diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc
index df661dc..e6fbbda 100644
--- a/chrome/browser/ui/views/frame/browser_view.cc
+++ b/chrome/browser/ui/views/frame/browser_view.cc
@@ -248,15 +248,6 @@
   return true;
 }
 
-// Returns whether immersive mode should replace fullscreen, which should only
-// occur for "browser-fullscreen" and not for "tab-fullscreen" (which has a URL
-// for the tab entering fullscreen).
-bool UseImmersiveFullscreenForUrl(const GURL& url) {
-  bool is_browser_fullscreen = url.is_empty();
-  return is_browser_fullscreen &&
-         ImmersiveFullscreenConfiguration::UseImmersiveFullscreen();
-}
-
 }  // namespace
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -341,97 +332,50 @@
 void BookmarkExtensionBackground::Paint(gfx::Canvas* canvas,
                                         views::View* view) const {
   int toolbar_overlap = host_view_->GetToolbarOverlap();
-  // The client edge is drawn below the toolbar bounds.
-  if (toolbar_overlap)
-    toolbar_overlap += views::NonClientFrameView::kClientEdgeThickness;
-  if (host_view_->IsDetached()) {
-    // As 'hidden' according to the animation is the full in-tab state,
-    // we invert the value - when current_state is at '0', we expect the
-    // bar to be docked.
-    double current_state = 1 - host_view_->GetAnimationValue();
-
-    // In Search NTP, the detached bookmark bar is different from regular NTP:
-    // - there's no padding around the bar
-    // - there's a separator below the bar
-    // - if animating between pinned and unpinned states:
-    //   - cross-fade the bar backgrounds
-    //   - fade in/out the separator between toolbar and bookmark bar.
-    if (chrome::IsInstantExtendedAPIEnabled()) {
-      ThemeService* ts =
-          ThemeServiceFactory::GetForProfile(browser_->profile());
-      if (current_state == 0.0 || current_state == 1.0) {
-        PaintDetachedBookmarkBar(canvas, host_view_, ts);
-        return;
-      }
-      // While animating, set opacity to cross-fade between attached and
-      // detached backgrounds including their respective separators.
-      int detached_alpha = static_cast<uint8>(current_state * 255);
-      int attached_alpha = 255 - detached_alpha;
-      if (browser_->bookmark_bar_state() == BookmarkBar::DETACHED) {
-        // To animate from attached to detached state:
-        // - fade out attached background
-        // - fade in detached background.
-        canvas->SaveLayerAlpha(attached_alpha);
-        PaintAttachedBookmarkBar(canvas, host_view_, browser_view_,
-                                 browser_->host_desktop_type(),
-                                 toolbar_overlap);
-        canvas->Restore();
-        canvas->SaveLayerAlpha(detached_alpha);
-        PaintDetachedBookmarkBar(canvas, host_view_, ts);
-      } else {
-        // To animate from detached to attached state:
-        // - fade out detached background
-        // - fade in attached background.
-        canvas->SaveLayerAlpha(detached_alpha);
-        PaintDetachedBookmarkBar(canvas, host_view_, ts);
-        canvas->Restore();
-        canvas->SaveLayerAlpha(attached_alpha);
-        PaintAttachedBookmarkBar(canvas, host_view_, browser_view_,
-                                 browser_->host_desktop_type(),
-                                 toolbar_overlap);
-      }
-      canvas->Restore();
-      return;
-    }
-
-    // Draw the background to match the new tab page.
-    ui::ThemeProvider* tp = host_view_->GetThemeProvider();
-    int height = 0;
-    WebContents* contents = browser_->tab_strip_model()->GetActiveWebContents();
-    if (contents && contents->GetView())
-      height = contents->GetView()->GetContainerSize().height();
-    NtpBackgroundUtil::PaintBackgroundDetachedMode(
-        tp, canvas,
-        gfx::Rect(0, toolbar_overlap, host_view_->width(),
-                  host_view_->height() - toolbar_overlap),
-        height);
-
-    double h_padding =
-        static_cast<double>(BookmarkBarView::kNewtabHorizontalPadding) *
-        current_state;
-    double v_padding =
-        static_cast<double>(BookmarkBarView::kNewtabVerticalPadding) *
-        current_state;
-
-    SkRect rect;
-    double roundness = 0;
-    DetachableToolbarView::CalculateContentArea(current_state, h_padding,
-        v_padding, &rect, &roundness, host_view_);
-    DetachableToolbarView::PaintContentAreaBackground(canvas, tp, rect,
-                                                      roundness);
-    DetachableToolbarView::PaintContentAreaBorder(canvas, tp, rect, roundness);
-    if (!toolbar_overlap)
-      DetachableToolbarView::PaintHorizontalBorderForState(canvas, host_view_);
-  } else {
-    gfx::Point background_image_offset =
-        browser_view_->OffsetPointForToolbarBackgroundImage(
-            gfx::Point(host_view_->GetMirroredX(), host_view_->y()));
-    DetachableToolbarView::PaintBackgroundAttachedMode(canvas,
-        host_view_->GetThemeProvider(), host_view_->GetLocalBounds(),
-        background_image_offset, browser_->host_desktop_type());
-    if (host_view_->height() >= toolbar_overlap)
-      DetachableToolbarView::PaintHorizontalBorderForState(canvas, host_view_);
+  if (!host_view_->IsDetached()) {
+    PaintAttachedBookmarkBar(canvas, host_view_, browser_view_,
+                             browser_->host_desktop_type(), toolbar_overlap);
+    return;
   }
+
+  // As 'hidden' according to the animation is the full in-tab state, we invert
+  // the value - when current_state is at '0', we expect the bar to be docked.
+  double current_state = 1 - host_view_->GetAnimationValue();
+
+  ThemeService* ts =
+      ThemeServiceFactory::GetForProfile(browser_->profile());
+  if (current_state == 0.0 || current_state == 1.0) {
+    PaintDetachedBookmarkBar(canvas, host_view_, ts);
+    return;
+  }
+  // While animating, set opacity to cross-fade between attached and detached
+  // backgrounds including their respective separators.
+  int detached_alpha = static_cast<uint8>(current_state * 255);
+  int attached_alpha = 255 - detached_alpha;
+  if (browser_->bookmark_bar_state() == BookmarkBar::DETACHED) {
+    // To animate from attached to detached state:
+    // - fade out attached background
+    // - fade in detached background.
+    canvas->SaveLayerAlpha(attached_alpha);
+    PaintAttachedBookmarkBar(canvas, host_view_, browser_view_,
+                             browser_->host_desktop_type(),
+                             toolbar_overlap);
+    canvas->Restore();
+    canvas->SaveLayerAlpha(detached_alpha);
+    PaintDetachedBookmarkBar(canvas, host_view_, ts);
+  } else {
+    // To animate from detached to attached state:
+    // - fade out detached background
+    // - fade in attached background.
+    canvas->SaveLayerAlpha(detached_alpha);
+    PaintDetachedBookmarkBar(canvas, host_view_, ts);
+    canvas->Restore();
+    canvas->SaveLayerAlpha(attached_alpha);
+    PaintAttachedBookmarkBar(canvas, host_view_, browser_view_,
+                             browser_->host_desktop_type(),
+                             toolbar_overlap);
+  }
+  canvas->Restore();
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -543,6 +487,10 @@
   return static_cast<BrowserView*>(browser->window());
 }
 
+void BrowserView::InitStatusBubble() {
+  status_bubble_.reset(new StatusBubbleViews(contents_container_));
+}
+
 gfx::Rect BrowserView::GetToolbarBounds() const {
   gfx::Rect toolbar_bounds(toolbar_->bounds());
   if (toolbar_bounds.IsEmpty())
@@ -886,7 +834,7 @@
   // Immersive mode has no exit bubble because it has a visible strip at the
   // top that gives the user a hover target.
   // TODO(jamescook): Figure out what to do with mouse-lock.
-  if (bubble_type == FEB_TYPE_NONE || UseImmersiveFullscreenForUrl(url)) {
+  if (bubble_type == FEB_TYPE_NONE || ShouldUseImmersiveFullscreenForUrl(url)) {
     fullscreen_bubble_.reset();
   } else if (fullscreen_bubble_.get()) {
     fullscreen_bubble_->UpdateContent(url, bubble_type);
@@ -1824,15 +1772,20 @@
   if (!browser_->ShouldCloseWindow())
     return false;
 
+  bool fast_tab_closing_enabled =
+    CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableFastUnload);
+
   if (!browser_->tab_strip_model()->empty()) {
     // Tab strip isn't empty.  Hide the frame (so it appears to have closed
     // immediately) and close all the tabs, allowing the renderers to shut
     // down. When the tab strip is empty we'll be called back again.
     frame_->Hide();
     browser_->OnWindowClosing();
-    browser_->tab_strip_model()->CloseAllTabs();
+    if (fast_tab_closing_enabled)
+      browser_->tab_strip_model()->CloseAllTabs();
     return false;
-  } else if (!browser_->HasCompletedUnloadProcessing()) {
+  } else if (fast_tab_closing_enabled &&
+        !browser_->HasCompletedUnloadProcessing()) {
     // The browser needs to finish running unload handlers.
     // Hide the frame (so it appears to have closed immediately), and
     // the browser will call us back again when it is ready to close.
@@ -2048,7 +2001,7 @@
   AddChildView(contents_split_);
   set_contents_view(contents_split_);
 
-  status_bubble_.reset(new StatusBubbleViews(contents_container_));
+  InitStatusBubble();
 
   // Top container holds tab strip and toolbar and lives at the front of the
   // view hierarchy.
@@ -2396,7 +2349,7 @@
   }
 
   // Enable immersive before the browser refreshes its list of enabled commands.
-  if (UseImmersiveFullscreenForUrl(url))
+  if (ShouldUseImmersiveFullscreenForUrl(url))
     immersive_mode_controller_->SetEnabled(fullscreen);
 
   browser_->WindowFullscreenStateChanged();
@@ -2404,7 +2357,7 @@
   if (fullscreen) {
     if (!chrome::IsRunningInAppMode() &&
         type != FOR_METRO &&
-        !UseImmersiveFullscreenForUrl(url)) {
+        !ShouldUseImmersiveFullscreenForUrl(url)) {
       fullscreen_bubble_.reset(new FullscreenExitBubbleViews(
           this, url, bubble_type));
     }
@@ -2427,6 +2380,12 @@
   ToolbarSizeChanged(false);
 }
 
+bool BrowserView::ShouldUseImmersiveFullscreenForUrl(const GURL& url) const {
+  bool is_browser_fullscreen = url.is_empty();
+  return ImmersiveFullscreenConfiguration::UseImmersiveFullscreen() &&
+      is_browser_fullscreen && IsBrowserTypeNormal();
+}
+
 void BrowserView::LoadAccelerators() {
 #if defined(OS_WIN) && !defined(USE_AURA)
   HACCEL accelerator_table = AtlLoadAccelerators(IDR_MAINFRAME);
diff --git a/chrome/browser/ui/views/frame/browser_view.h b/chrome/browser/ui/views/frame/browser_view.h
index bac93d8..6141f1a 100644
--- a/chrome/browser/ui/views/frame/browser_view.h
+++ b/chrome/browser/ui/views/frame/browser_view.h
@@ -11,7 +11,7 @@
 
 #include "base/compiler_specific.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/timer.h"
+#include "base/timer/timer.h"
 #include "build/build_config.h"
 #include "chrome/browser/devtools/devtools_window.h"
 #include "chrome/browser/infobars/infobar_container.h"
@@ -128,6 +128,12 @@
   // Returns a Browser instance of this view.
   Browser* browser() { return browser_.get(); }
 
+  // Initializes (or re-initializes) the status bubble.  We try to only create
+  // the bubble once and re-use it for the life of the browser, but certain
+  // events (such as changing enabling/disabling Aero on Win) can force a need
+  // to change some of the bubble's creation parameters.
+  void InitStatusBubble();
+
   // Returns the apparent bounds of the toolbar, in BrowserView coordinates.
   // These differ from |toolbar_.bounds()| in that they match where the toolbar
   // background image is drawn -- slightly outside the "true" bounds
@@ -551,6 +557,11 @@
                          const GURL& url,
                          FullscreenExitBubbleType bubble_type);
 
+  // Returns whether immmersive fullscreen should replace fullscreen. This
+  // should only occur for "browser-fullscreen" for tabbed-typed windows (not
+  // for tab-fullscreen and not for app/popup type windows).
+  bool ShouldUseImmersiveFullscreenForUrl(const GURL& url) const;
+
   // Copy the accelerator table from the app resources into something we can
   // use.
   void LoadAccelerators();
diff --git a/chrome/browser/ui/views/frame/browser_view_layout.cc b/chrome/browser/ui/views/frame/browser_view_layout.cc
index 8efb7e7..1262a3d 100644
--- a/chrome/browser/ui/views/frame/browser_view_layout.cc
+++ b/chrome/browser/ui/views/frame/browser_view_layout.cc
@@ -182,9 +182,7 @@
       bookmark_bar_->visible() &&
       browser()->SupportsWindowFeature(Browser::FEATURE_BOOKMARKBAR)) {
     bookmark_bar_size = bookmark_bar_->GetMinimumSize();
-    bookmark_bar_size.Enlarge(0,
-        -(views::NonClientFrameView::kClientEdgeThickness +
-            bookmark_bar_->GetToolbarOverlap(true)));
+    bookmark_bar_size.Enlarge(0, -bookmark_bar_->GetToolbarOverlap());
   }
   // TODO: Adjust the minimum height for the find bar.
 
@@ -485,8 +483,7 @@
 
   bookmark_bar_->set_infobar_visible(InfobarVisible());
   int bookmark_bar_height = bookmark_bar_->GetPreferredSize().height();
-  y -= views::NonClientFrameView::kClientEdgeThickness +
-      bookmark_bar_->GetToolbarOverlap(false);
+  y -= bookmark_bar_->GetToolbarOverlap();
   bookmark_bar_->SetBounds(vertical_layout_rect_.x(),
                            y,
                            vertical_layout_rect_.width(),
@@ -575,7 +572,7 @@
 
   // Offset for the detached bookmark bar.
   return bookmark_bar_->height() -
-      views::NonClientFrameView::kClientEdgeThickness;
+      bookmark_bar_->GetFullyDetachedToolbarOverlap();
 }
 
 int BrowserViewLayout::GetTopMarginForActiveContent() {
diff --git a/chrome/browser/ui/views/frame/glass_browser_frame_view.cc b/chrome/browser/ui/views/frame/glass_browser_frame_view.cc
index a744bc0..f1d8ba5 100644
--- a/chrome/browser/ui/views/frame/glass_browser_frame_view.cc
+++ b/chrome/browser/ui/views/frame/glass_browser_frame_view.cc
@@ -11,6 +11,7 @@
 #include "chrome/app/chrome_dll_resource.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/themes/theme_properties.h"
+#include "chrome/browser/ui/views/avatar_label.h"
 #include "chrome/browser/ui/views/avatar_menu_button.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/views/tabs/tab.h"
@@ -71,7 +72,7 @@
 // is no avatar icon.
 const int kTabStripIndent = -6;
 
-}
+}  // namespace
 
 ///////////////////////////////////////////////////////////////////////////////
 // GlassBrowserFrameView, public:
@@ -206,9 +207,11 @@
   if (!browser_view()->IsBrowserTypeNormal() || !bounds().Contains(point))
     return HTNOWHERE;
 
-  // See if the point is within the avatar menu button.
-  if (avatar_button() &&
-      avatar_button()->GetMirroredBounds().Contains(point))
+  // See if the point is within the avatar menu button or within the avatar
+  // label.
+  if ((avatar_button() &&
+       avatar_button()->GetMirroredBounds().Contains(point)) ||
+      (avatar_label() && avatar_label()->GetMirroredBounds().Contains(point)))
     return HTCLIENT;
 
   int frame_component = frame()->client_view()->NonClientHitTest(point);
diff --git a/chrome/browser/ui/views/frame/immersive_mode_controller.cc b/chrome/browser/ui/views/frame/immersive_mode_controller.cc
new file mode 100644
index 0000000..cebf6cb
--- /dev/null
+++ b/chrome/browser/ui/views/frame/immersive_mode_controller.cc
@@ -0,0 +1,20 @@
+// 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/ui/views/frame/immersive_mode_controller.h"
+
+ImmersiveModeController::ImmersiveModeController() {
+}
+
+ImmersiveModeController::~ImmersiveModeController() {
+  FOR_EACH_OBSERVER(Observer, observers_, OnImmersiveModeControllerDestroyed());
+}
+
+void ImmersiveModeController::AddObserver(Observer* observer) {
+  observers_.AddObserver(observer);
+}
+
+void ImmersiveModeController::RemoveObserver(Observer* observer) {
+  observers_.RemoveObserver(observer);
+}
diff --git a/chrome/browser/ui/views/frame/immersive_mode_controller.h b/chrome/browser/ui/views/frame/immersive_mode_controller.h
index ae8a0eb..81da8d8 100644
--- a/chrome/browser/ui/views/frame/immersive_mode_controller.h
+++ b/chrome/browser/ui/views/frame/immersive_mode_controller.h
@@ -6,6 +6,7 @@
 #define CHROME_BROWSER_UI_VIEWS_FRAME_IMMERSIVE_MODE_CONTROLLER_H_
 
 #include "base/compiler_specific.h"
+#include "base/observer_list.h"
 
 class BookmarkBarView;
 class FullscreenController;
@@ -40,6 +41,18 @@
     ANIMATE_REVEAL_NO
   };
 
+  class Observer {
+   public:
+    // Called when a reveal of the top-of-window views has been initiated.
+    virtual void OnImmersiveRevealStarted() {}
+
+    // Called when the immersive mode controller has been destroyed.
+    virtual void OnImmersiveModeControllerDestroyed() {}
+
+   protected:
+    virtual ~Observer() {}
+  };
+
   class Delegate {
    public:
     // Returns the bookmark bar, or NULL if the window does not support one.
@@ -58,7 +71,8 @@
     virtual ~Delegate() {}
   };
 
-  virtual ~ImmersiveModeController() {}
+  ImmersiveModeController();
+  virtual ~ImmersiveModeController();
 
   // Must initialize after browser view has a Widget and native window.
   virtual void Init(Delegate* delegate,
@@ -127,6 +141,15 @@
   // visible.
   virtual void OnFindBarVisibleBoundsChanged(
       const gfx::Rect& new_visible_bounds_in_screen) = 0;
+
+  virtual void AddObserver(Observer* observer);
+  virtual void RemoveObserver(Observer* observer);
+
+ protected:
+  ObserverList<Observer> observers_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ImmersiveModeController);
 };
 
 namespace chrome {
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 9b21a6f..a931f44 100644
--- a/chrome/browser/ui/views/frame/immersive_mode_controller_ash.cc
+++ b/chrome/browser/ui/views/frame/immersive_mode_controller_ash.cc
@@ -86,6 +86,16 @@
   return false;
 }
 
+// Returns the location of |event| in screen coordinates.
+gfx::Point GetEventLocationInScreen(const ui::LocatedEvent& event) {
+  gfx::Point location_in_screen = event.location();
+  aura::Window* target = static_cast<aura::Window*>(event.target());
+  aura::client::ScreenPositionClient* screen_position_client =
+      aura::client::GetScreenPositionClient(target->GetRootWindow());
+  screen_position_client->ConvertPointToScreen(target, &location_in_screen);
+  return location_in_screen;
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 
 class RevealedLockAsh : public ImmersiveRevealedLock {
@@ -288,11 +298,11 @@
       revealed_lock_count_(0),
       tab_indicator_visibility_(TAB_INDICATORS_HIDE),
       mouse_x_when_hit_top_(-1),
+      gesture_begun_(false),
       native_window_(NULL),
       animation_(new ui::SlideAnimation(this)),
       animations_disabled_for_test_(false),
-      weak_ptr_factory_(this),
-      gesture_begun_(false) {
+      weak_ptr_factory_(this) {
 }
 
 ImmersiveModeControllerAsh::~ImmersiveModeControllerAsh() {
@@ -350,10 +360,7 @@
     return;
   enabled_ = enabled;
 
-  // Delay the initialization of the window observers till the first call to
-  // SetEnabled(true) because FullscreenController is not yet initialized when
-  // Init() is called.
-  EnableWindowObservers(true);
+  EnableWindowObservers(enabled_);
 
   UpdateUseMinimalChrome(LAYOUT_NO);
 
@@ -505,7 +512,7 @@
 
   switch (event->type()) {
     case ui::ET_GESTURE_SCROLL_BEGIN:
-      if (ShouldHandleEvent(event->location())) {
+      if (ShouldHandleGestureEvent(GetEventLocationInScreen(*event))) {
         gesture_begun_ = true;
         event->SetHandled();
       }
@@ -585,6 +592,9 @@
 void ImmersiveModeControllerAsh::OnWindowPropertyChanged(aura::Window* window,
                                                          const void* key,
                                                          intptr_t old) {
+  if (!enabled_)
+    return;
+
   if (key == aura::client::kShowStateKey) {
     // Disable immersive mode when the user exits fullscreen without going
     // through FullscreenController::ToggleFullscreenMode(). This is the case
@@ -598,21 +608,18 @@
           base::Bind(&ImmersiveModeControllerAsh::MaybeExitImmersiveFullscreen,
                      weak_ptr_factory_.GetWeakPtr()));
     }
+
+    ui::WindowShowState show_state = native_window_->GetProperty(
+        aura::client::kShowStateKey);
+    if (show_state == ui::SHOW_STATE_FULLSCREEN &&
+        old == ui::SHOW_STATE_MINIMIZED) {
+      // Relayout in case there was a layout while the window show state was
+      // ui::SHOW_STATE_MINIMIZED.
+      LayoutBrowserRootView();
+    }
   }
 }
 
-void ImmersiveModeControllerAsh::OnWindowAddedToRootWindow(
-    aura::Window* window) {
-  DCHECK_EQ(window, native_window_);
-  UpdatePreTargetHandler();
-}
-
-void ImmersiveModeControllerAsh::OnWindowRemovingFromRootWindow(
-    aura::Window* window) {
-  DCHECK_EQ(window, native_window_);
-  UpdatePreTargetHandler();
-}
-
 ////////////////////////////////////////////////////////////////////////////////
 // Testing interface:
 
@@ -663,7 +670,10 @@
     focus_manager->RemoveFocusChangeListener(this);
   }
 
-  UpdatePreTargetHandler();
+  if (enable)
+    ash::Shell::GetInstance()->AddPreTargetHandler(this);
+  else
+    ash::Shell::GetInstance()->RemovePreTargetHandler(this);
 
   if (enable) {
     native_window_->AddObserver(this);
@@ -692,18 +702,29 @@
 void ImmersiveModeControllerAsh::UpdateTopEdgeHoverTimer(
     ui::MouseEvent* event) {
   DCHECK(enabled_);
-  // If the top-of-window views are already revealed or the cursor left the
-  // top edge we don't need to trigger based on a timer anymore.
-  if (reveal_state_ == SLIDING_OPEN ||
-      reveal_state_ == REVEALED ||
-      event->root_location().y() != 0) {
+  // Stop the timer if the top-of-window views are already revealed.
+  if (reveal_state_ == SLIDING_OPEN || reveal_state_ == REVEALED) {
     top_edge_hover_timer_.Stop();
     return;
   }
+
+  gfx::Point location_in_screen = GetEventLocationInScreen(*event);
+  gfx::Rect top_container_bounds_in_screen =
+      top_container_->GetBoundsInScreen();
+
+  // 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()) {
+    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 = event->root_location().x();
+  int mouse_x = location_in_screen.x() - top_container_bounds_in_screen.x();
   if (top_edge_hover_timer_.IsRunning() &&
       abs(mouse_x - mouse_x_when_hit_top_) <=
           ImmersiveFullscreenConfiguration::
@@ -749,11 +770,7 @@
 
   gfx::Point location_in_screen;
   if (event && event->type() != ui::ET_MOUSE_CAPTURE_CHANGED) {
-    location_in_screen = event->location();
-    aura::Window* target = static_cast<aura::Window*>(event->target());
-    aura::client::ScreenPositionClient* screen_position_client =
-        aura::client::GetScreenPositionClient(target->GetRootWindow());
-    screen_position_client->ConvertPointToScreen(target, &location_in_screen);
+    location_in_screen = GetEventLocationInScreen(*event);
   } else {
     aura::client::CursorClient* cursor_client = aura::client::GetCursorClient(
         native_window_->GetRootWindow());
@@ -932,8 +949,11 @@
 
     // Do not do any more processing if LayoutBrowserView() changed
     // |reveal_state_|.
-    if (reveal_state_ != SLIDING_OPEN)
+    if (reveal_state_ != SLIDING_OPEN) {
+      if (reveal_state_ == REVEALED)
+        FOR_EACH_OBSERVER(Observer, observers_, OnImmersiveRevealStarted());
       return;
+    }
   }
   // Slide in the reveal view.
   if (animate == ANIMATE_NO) {
@@ -943,6 +963,9 @@
     animation_->SetSlideDuration(GetAnimationDuration(animate));
     animation_->Show();
   }
+
+   if (previous_reveal_state == CLOSED)
+     FOR_EACH_OBSERVER(Observer, observers_, OnImmersiveRevealStarted());
 }
 
 void ImmersiveModeControllerAsh::EnablePaintToLayer(bool enable) {
@@ -1048,7 +1071,7 @@
   return SWIPE_NONE;
 }
 
-bool ImmersiveModeControllerAsh::ShouldHandleEvent(
+bool ImmersiveModeControllerAsh::ShouldHandleGestureEvent(
     const gfx::Point& location) const {
   // All of the gestures that are of interest start in a region with left &
   // right edges agreeing with |top_container_|. When CLOSED it is difficult to
@@ -1062,17 +1085,5 @@
   return near_bounds.Contains(location) ||
       ((location.y() < near_bounds.y()) &&
        (location.x() >= near_bounds.x()) &&
-       (location.x() <= near_bounds.right()));
-}
-
-void ImmersiveModeControllerAsh::UpdatePreTargetHandler() {
-  if (!native_window_)
-    return;
-  aura::RootWindow* root_window = native_window_->GetRootWindow();
-  if (!root_window)
-    return;
-  if (observers_enabled_)
-    root_window->AddPreTargetHandler(this);
-  else
-    root_window->RemovePreTargetHandler(this);
+       (location.x() < near_bounds.right()));
 }
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 c72c17d..ae7417a 100644
--- a/chrome/browser/ui/views/frame/immersive_mode_controller_ash.h
+++ b/chrome/browser/ui/views/frame/immersive_mode_controller_ash.h
@@ -7,7 +7,7 @@
 
 #include "chrome/browser/ui/views/frame/immersive_mode_controller.h"
 
-#include "base/timer.h"
+#include "base/timer/timer.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
 #include "ui/aura/window_observer.h"
@@ -108,8 +108,6 @@
   virtual void OnWindowPropertyChanged(aura::Window* window,
                                        const void* key,
                                        intptr_t old) OVERRIDE;
-  virtual void OnWindowAddedToRootWindow(aura::Window* window) OVERRIDE;
-  virtual void OnWindowRemovingFromRootWindow(aura::Window* window) OVERRIDE;
 
   // Testing interface.
   void SetForceHideTabIndicatorsForTest(bool force);
@@ -219,11 +217,7 @@
   // bounds, above it, or within a few pixels below it. This allow the container
   // to steal enough pixels to detect a swipe in and handles the case that there
   // is a bezel sensor above the top container.
-  bool ShouldHandleEvent(const gfx::Point& location) const;
-
-  // Call Add/RemovePreTargerHandler since either the RootWindow has changed or
-  // the enabled state of observing has changed.
-  void UpdatePreTargetHandler();
+  bool ShouldHandleGestureEvent(const gfx::Point& location) const;
 
   // Injected dependencies. Not owned.
   Delegate* delegate_;
@@ -252,6 +246,10 @@
   // the top edge of the screen.
   int mouse_x_when_hit_top_;
 
+  // Tracks if the controller has seen a ET_GESTURE_SCROLL_BEGIN, without the
+  // following events.
+  bool gesture_begun_;
+
   // The current visible bounds of the find bar, in screen coordinates. This is
   // an empty rect if the find bar is not visible.
   gfx::Rect find_bar_visible_bounds_in_screen_;
@@ -284,10 +282,6 @@
 
   base::WeakPtrFactory<ImmersiveModeControllerAsh> weak_ptr_factory_;
 
-  // Tracks if the controller has seen a ET_GESTURE_SCROLL_BEGIN, without the
-  // following events.
-  bool gesture_begun_;
-
   DISALLOW_COPY_AND_ASSIGN(ImmersiveModeControllerAsh);
 };
 
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 81192ff..f3125d7 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
@@ -230,12 +230,14 @@
 
   // Large move right restarts the timer (so it is still running) and considers
   // this a new hit at the top.
-  event_generator()->MoveMouseTo(150, 0);
+  event_generator()->MoveMouseTo(499, 0);
   EXPECT_TRUE(top_edge_hover_timer_running());
-  EXPECT_EQ(150, mouse_x_when_hit_top());
+  EXPECT_EQ(499, mouse_x_when_hit_top());
 
-  // Moving off the top edge stops the timer.
-  event_generator()->MoveMouseTo(150, 1);
+  // 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);
   EXPECT_FALSE(top_edge_hover_timer_running());
 
   // Once revealed, a move just a little below the top container doesn't end a
diff --git a/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc b/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc
index d77399c..c4bbf28 100644
--- a/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc
+++ b/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc
@@ -12,6 +12,7 @@
 #include "base/prefs/pref_service.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/themes/theme_properties.h"
+#include "chrome/browser/ui/views/avatar_label.h"
 #include "chrome/browser/ui/views/avatar_menu_button.h"
 #include "chrome/browser/ui/views/frame/browser_frame.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
@@ -321,9 +322,11 @@
   if (!bounds().Contains(point))
     return HTNOWHERE;
 
-  // See if the point is within the avatar menu button.
-  if (avatar_button() &&
-      avatar_button()->GetMirroredBounds().Contains(point))
+  // See if the point is within the avatar menu button or within the avatar
+  // label.
+  if ((avatar_button() &&
+       avatar_button()->GetMirroredBounds().Contains(point)) ||
+      (avatar_label() && avatar_label()->GetMirroredBounds().Contains(point)))
     return HTCLIENT;
 
   int frame_component = frame()->client_view()->NonClientHitTest(point);
diff --git a/chrome/browser/ui/views/fullscreen_exit_bubble_views.cc b/chrome/browser/ui/views/fullscreen_exit_bubble_views.cc
index cdd69ca..87bb1a3 100644
--- a/chrome/browser/ui/views/fullscreen_exit_bubble_views.cc
+++ b/chrome/browser/ui/views/fullscreen_exit_bubble_views.cc
@@ -277,7 +277,7 @@
   // Initialize the popup.
   popup_ = new views::Widget;
   views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP);
-  params.transparent = true;
+  params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
   params.can_activate = false;
   params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
   params.parent = browser_view_->GetWidget()->GetNativeView();
diff --git a/chrome/browser/ui/views/keyboard_access_browsertest.cc b/chrome/browser/ui/views/keyboard_access_browsertest.cc
index 2d78b89..3e69624 100644
--- a/chrome/browser/ui/views/keyboard_access_browsertest.cc
+++ b/chrome/browser/ui/views/keyboard_access_browsertest.cc
@@ -9,7 +9,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/message_loop.h"
 #include "base/strings/string_util.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
diff --git a/chrome/browser/ui/views/location_bar/content_setting_image_view.cc b/chrome/browser/ui/views/location_bar/content_setting_image_view.cc
index 38edd16..014c3da 100644
--- a/chrome/browser/ui/views/location_bar/content_setting_image_view.cc
+++ b/chrome/browser/ui/views/location_bar/content_setting_image_view.cc
@@ -99,8 +99,9 @@
 }
 
 void ContentSettingImageView::Update(content::WebContents* web_contents) {
-  if (web_contents)
-    content_setting_image_model_->UpdateFromWebContents(web_contents);
+  // Note: We explicitly want to call this even if |web_contents| is NULL, so we
+  // get hidden properly while the user is editing the omnibox.
+  content_setting_image_model_->UpdateFromWebContents(web_contents);
 
   if (!content_setting_image_model_->is_visible()) {
     SetVisible(false);
diff --git a/chrome/browser/ui/views/location_bar/zoom_bubble_view.cc b/chrome/browser/ui/views/location_bar/zoom_bubble_view.cc
index 7301f6d..76f1c7a 100644
--- a/chrome/browser/ui/views/location_bar/zoom_bubble_view.cc
+++ b/chrome/browser/ui/views/location_bar/zoom_bubble_view.cc
@@ -46,9 +46,11 @@
   DCHECK(browser && browser->window() && browser->fullscreen_controller());
 
   BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser);
-  bool is_fullscreen = browser->window()->IsFullscreen();
-  views::View* anchor_view = is_fullscreen ?
-      NULL : browser_view->GetLocationBarView()->zoom_view();
+  bool is_fullscreen = browser_view->IsFullscreen();
+  bool anchor_to_view = !is_fullscreen ||
+      browser_view->immersive_mode_controller()->IsRevealed();
+  views::View* anchor_view = anchor_to_view ?
+      browser_view->GetLocationBarView()->zoom_view() : NULL;
 
   // If the bubble is already showing in this window and its |auto_close_| value
   // is equal to |auto_close|, the bubble can be reused and only the label text
@@ -66,11 +68,11 @@
     zoom_bubble_ = new ZoomBubbleView(anchor_view,
                                       web_contents,
                                       auto_close,
+                                      browser_view->immersive_mode_controller(),
                                       browser->fullscreen_controller());
 
-    // If we're fullscreen, there is no anchor view, so parent the bubble to
-    // the content area.
-    if (is_fullscreen) {
+    // If we do not have an anchor view, parent the bubble to the content area.
+    if (!anchor_to_view) {
       zoom_bubble_->set_parent_window(
           web_contents->GetView()->GetTopLevelNativeWindow());
     }
@@ -93,33 +95,58 @@
 
 // static
 bool ZoomBubbleView::IsShowing() {
-  return zoom_bubble_ != NULL;
+  // The bubble may be in the process of closing.
+  return zoom_bubble_ != NULL && zoom_bubble_->GetWidget()->IsVisible();
 }
 
-ZoomBubbleView::ZoomBubbleView(views::View* anchor_view,
-                               content::WebContents* web_contents,
-                               bool auto_close,
-                               FullscreenController* fullscreen_controller)
+// static
+const ZoomBubbleView* ZoomBubbleView::GetZoomBubbleForTest() {
+  return zoom_bubble_;
+}
+
+ZoomBubbleView::ZoomBubbleView(
+    views::View* anchor_view,
+    content::WebContents* web_contents,
+    bool auto_close,
+    ImmersiveModeController* immersive_mode_controller,
+    FullscreenController* fullscreen_controller)
     : BubbleDelegateView(anchor_view, anchor_view ?
           views::BubbleBorder::TOP_RIGHT : views::BubbleBorder::NONE),
       label_(NULL),
       web_contents_(web_contents),
-      auto_close_(auto_close) {
+      auto_close_(auto_close),
+      immersive_mode_controller_(immersive_mode_controller) {
   // Compensate for built-in vertical padding in the anchor view's image.
   set_anchor_view_insets(gfx::Insets(5, 0, 5, 0));
   set_use_focusless(auto_close);
   set_notify_enter_exit_on_child(true);
 
+  if (anchor_view) {
+    // If we are in immersive fullscreen and the top-of-window views are
+    // already revealed, lock the top-of-window views in the revealed state
+    // as long as the zoom bubble is visible. ImmersiveModeController does
+    // not do this for us automatically because the zoom bubble is not
+    // activatable.
+    immersive_reveal_lock_.reset(immersive_mode_controller_->GetRevealedLock(
+        ImmersiveModeController::ANIMATE_REVEAL_NO));
+  }
+
+  // Add observers to close the bubble if the fullscreen state or immersive
+  // fullscreen revealed state changes.
   registrar_.Add(this,
                  chrome::NOTIFICATION_FULLSCREEN_CHANGED,
                  content::Source<FullscreenController>(fullscreen_controller));
+  immersive_mode_controller_->AddObserver(this);
 }
 
 ZoomBubbleView::~ZoomBubbleView() {
+  if (immersive_mode_controller_)
+    immersive_mode_controller_->RemoveObserver(this);
 }
 
 void ZoomBubbleView::AdjustForFullscreen(const gfx::Rect& screen_bounds) {
-  DCHECK(!anchor_view());
+  if (anchor_view())
+    return;
 
   // TODO(dbeam): should RTL logic be done in views::BubbleDelegateView?
   const size_t bubble_half_width = width() / 2;
@@ -218,6 +245,14 @@
   CloseBubble();
 }
 
+void ZoomBubbleView::OnImmersiveRevealStarted() {
+  CloseBubble();
+}
+
+void ZoomBubbleView::OnImmersiveModeControllerDestroyed() {
+  immersive_mode_controller_ = NULL;
+}
+
 void ZoomBubbleView::WindowClosing() {
   // |zoom_bubble_| can be a new bubble by this point (as Close(); doesn't
   // call this right away). Only set to NULL when it's this bubble.
diff --git a/chrome/browser/ui/views/location_bar/zoom_bubble_view.h b/chrome/browser/ui/views/location_bar/zoom_bubble_view.h
index 1bf4c8d..1b05401 100644
--- a/chrome/browser/ui/views/location_bar/zoom_bubble_view.h
+++ b/chrome/browser/ui/views/location_bar/zoom_bubble_view.h
@@ -6,7 +6,8 @@
 #define CHROME_BROWSER_UI_VIEWS_LOCATION_BAR_ZOOM_BUBBLE_VIEW_H_
 
 #include "base/basictypes.h"
-#include "base/timer.h"
+#include "base/timer/timer.h"
+#include "chrome/browser/ui/views/frame/immersive_mode_controller.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
 #include "ui/views/bubble/bubble_delegate.h"
@@ -24,7 +25,8 @@
 // View used to display the zoom percentage when it has changed.
 class ZoomBubbleView : public views::BubbleDelegateView,
                        public views::ButtonListener,
-                       public content::NotificationObserver {
+                       public content::NotificationObserver,
+                       public ImmersiveModeController::Observer {
  public:
   // Shows the bubble and automatically closes it after a short time period if
   // |auto_close| is true.
@@ -37,16 +39,22 @@
   // Whether the zoom bubble is currently showing.
   static bool IsShowing();
 
+  // Returns the zoom bubble if the zoom bubble is showing. Returns NULL
+  // otherwise.
+  static const ZoomBubbleView* GetZoomBubbleForTest();
+
  private:
   ZoomBubbleView(views::View* anchor_view,
                  content::WebContents* web_contents,
                  bool auto_close,
+                 ImmersiveModeController* immersive_mode_controller,
                  FullscreenController* fullscreen_controller);
   virtual ~ZoomBubbleView();
 
-  // Place the bubble in the top right (left in RTL) of the |screen_bounds| that
-  // contain |web_contents_|'s browser window. Because the positioning is based
-  // on the size of the bubble, this must be called after the bubble is created.
+  // If the bubble is not anchored to a view, places the bubble in the top
+  // right (left in RTL) of the |screen_bounds| that contain |web_contents_|'s
+  // browser window. Because the positioning is based on the size of the
+  // bubble, this must be called after the bubble is created.
   void AdjustForFullscreen(const gfx::Rect& screen_bounds);
 
   // Refreshes the bubble by changing the zoom percentage appropriately and
@@ -81,6 +89,10 @@
                        const content::NotificationSource& source,
                        const content::NotificationDetails& details) OVERRIDE;
 
+  // ImmersiveModeController::Observer methods.
+  virtual void OnImmersiveRevealStarted() OVERRIDE;
+  virtual void OnImmersiveModeControllerDestroyed() OVERRIDE;
+
   // Singleton instance of the zoom bubble. The zoom bubble can only be shown on
   // the active browser window, so there is no case in which it will be shown
   // twice at the same time.
@@ -98,6 +110,15 @@
   // Whether the currently displayed bubble will automatically close.
   bool auto_close_;
 
+  // The immersive mode controller for the BrowserView containing
+  // |web_contents_|.
+  // Not owned.
+  ImmersiveModeController* immersive_mode_controller_;
+
+  // Keeps the top-of-window views revealed (but does not initiate a reveal)
+  // when the bubble is visible in immersive fullscreen.
+  scoped_ptr<ImmersiveRevealedLock> immersive_reveal_lock_;
+
   // Used to register for fullscreen change notifications.
   content::NotificationRegistrar registrar_;
 
diff --git a/chrome/browser/ui/views/location_bar/zoom_bubble_view_browsertest.cc b/chrome/browser/ui/views/location_bar/zoom_bubble_view_browsertest.cc
new file mode 100644
index 0000000..d075227
--- /dev/null
+++ b/chrome/browser/ui/views/location_bar/zoom_bubble_view_browsertest.cc
@@ -0,0 +1,149 @@
+// 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/ui/views/location_bar/zoom_bubble_view.h"
+
+#include "chrome/browser/ui/browser_commands.h"
+#include "chrome/browser/ui/fullscreen/fullscreen_controller.h"
+#include "chrome/browser/ui/fullscreen/fullscreen_controller_test.h"
+#include "chrome/browser/ui/immersive_fullscreen_configuration.h"
+#include "chrome/browser/ui/views/frame/browser_view.h"
+#include "chrome/browser/ui/views/frame/immersive_mode_controller.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "chrome/test/base/ui_test_utils.h"
+
+#if defined(OS_CHROMEOS)
+#include "chrome/browser/ui/views/frame/immersive_mode_controller_ash.h"
+#endif
+
+class ZoomBubbleBrowserTest : public InProcessBrowserTest {
+ public:
+  ZoomBubbleBrowserTest() {}
+  virtual ~ZoomBubbleBrowserTest() {}
+
+  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
+    ImmersiveFullscreenConfiguration::EnableImmersiveFullscreenForTest();
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ZoomBubbleBrowserTest);
+};
+
+// TODO(linux_aura) http://crbug.com/163931
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(USE_AURA)
+#define MAYBE_NonImmersiveFullscreen DISABLED_NonImmersiveFullscreen
+#else
+#define MAYBE_NonImmersiveFullscreen NonImmersiveFullscreen
+#endif
+// Test whether the zoom bubble is anchored and whether it is visible when in
+// non-immersive fullscreen.
+IN_PROC_BROWSER_TEST_F(ZoomBubbleBrowserTest, MAYBE_NonImmersiveFullscreen) {
+  BrowserView* browser_view = static_cast<BrowserView*>(browser()->window());
+  content::WebContents* web_contents = browser_view->GetActiveWebContents();
+
+  // The zoom bubble should be anchored when not in fullscreen.
+  ZoomBubbleView::ShowBubble(web_contents, true);
+  ASSERT_TRUE(ZoomBubbleView::IsShowing());
+  const ZoomBubbleView* zoom_bubble = ZoomBubbleView::GetZoomBubbleForTest();
+  EXPECT_TRUE(zoom_bubble->anchor_view());
+
+  // Entering fullscreen should close the bubble. (We enter into tab fullscreen
+  // here because tab fullscreen is non-immersive even when
+  // ImmersiveFullscreenConfiguration::UseImmersiveFullscreen()) returns
+  // true.
+  {
+    // NOTIFICATION_FULLSCREEN_CHANGED is sent asynchronously. Wait for the
+    // notification before testing the zoom bubble visibility.
+    scoped_ptr<FullscreenNotificationObserver> waiter(
+        new FullscreenNotificationObserver());
+    browser()->fullscreen_controller()->ToggleFullscreenModeForTab(
+        web_contents, true);
+    waiter->Wait();
+  }
+  ASSERT_FALSE(browser_view->immersive_mode_controller()->IsEnabled());
+  EXPECT_FALSE(ZoomBubbleView::IsShowing());
+
+  // The bubble should not be anchored when it is shown in non-immersive
+  // fullscreen.
+  ZoomBubbleView::ShowBubble(web_contents, true);
+  ASSERT_TRUE(ZoomBubbleView::IsShowing());
+  zoom_bubble = ZoomBubbleView::GetZoomBubbleForTest();
+  EXPECT_FALSE(zoom_bubble->anchor_view());
+
+  // Exit fullscreen before ending the test for the sake of sanity.
+  {
+    scoped_ptr<FullscreenNotificationObserver> waiter(
+        new FullscreenNotificationObserver());
+    chrome::ToggleFullscreenMode(browser());
+    waiter->Wait();
+  }
+}
+
+// Immersive fullscreen is CrOS only for now.
+#if defined(OS_CHROMEOS)
+// Test whether the zoom bubble is anchored and whether it is visible when in
+// immersive fullscreen.
+IN_PROC_BROWSER_TEST_F(ZoomBubbleBrowserTest, ImmersiveFullscreen) {
+  BrowserView* browser_view = static_cast<BrowserView*>(browser()->window());
+  content::WebContents* web_contents = browser_view->GetActiveWebContents();
+
+  ASSERT_TRUE(ImmersiveFullscreenConfiguration::UseImmersiveFullscreen());
+  ImmersiveModeControllerAsh* immersive_controller =
+      static_cast<ImmersiveModeControllerAsh*>(
+          browser_view->immersive_mode_controller());
+  immersive_controller->DisableAnimationsForTest();
+
+  // Move the mouse out of the way.
+  immersive_controller->SetMouseHoveredForTest(false);
+
+  // Enter immersive fullscreen.
+  {
+    scoped_ptr<FullscreenNotificationObserver> waiter(
+        new FullscreenNotificationObserver());
+    chrome::ToggleFullscreenMode(browser());
+    waiter->Wait();
+  }
+  ASSERT_TRUE(immersive_controller->IsEnabled());
+  ASSERT_FALSE(immersive_controller->IsRevealed());
+
+  // The zoom bubble should not be anchored when it is shown in immersive
+  // fullscreen and the top-of-window views are not revealed.
+  ZoomBubbleView::ShowBubble(web_contents, false);
+  ASSERT_TRUE(ZoomBubbleView::IsShowing());
+  const ZoomBubbleView* zoom_bubble = ZoomBubbleView::GetZoomBubbleForTest();
+  EXPECT_FALSE(zoom_bubble->anchor_view());
+
+  // An immersive reveal should hide the zoom bubble.
+  scoped_ptr<ImmersiveRevealedLock> immersive_reveal_lock(
+      immersive_controller->GetRevealedLock(
+          ImmersiveModeController::ANIMATE_REVEAL_NO));
+  ASSERT_TRUE(immersive_controller->IsRevealed());
+  EXPECT_FALSE(ZoomBubbleView::IsShowing());
+
+  // The zoom bubble should be anchored when it is shown in immersive fullscreen
+  // and the top-of-window views are revealed.
+  ZoomBubbleView::ShowBubble(web_contents, true);
+  ASSERT_TRUE(ZoomBubbleView::IsShowing());
+  zoom_bubble = ZoomBubbleView::GetZoomBubbleForTest();
+  EXPECT_TRUE(zoom_bubble->anchor_view());
+
+  // The top-of-window views should not hide till the zoom bubble hides. (It
+  // would be weird if the view to which the zoom bubble is anchored hid while
+  // the zoom bubble was still visible.)
+  immersive_reveal_lock.reset();
+  EXPECT_TRUE(immersive_controller->IsRevealed());
+  ZoomBubbleView::CloseBubble();
+  // The zoom bubble is deleted on a task.
+  content::RunAllPendingInMessageLoop();
+  EXPECT_FALSE(immersive_controller->IsRevealed());
+
+  // Exit fullscreen before ending the test for the sake of sanity.
+  {
+    scoped_ptr<FullscreenNotificationObserver> waiter(
+        new FullscreenNotificationObserver());
+    chrome::ToggleFullscreenMode(browser());
+    waiter->Wait();
+  }
+}
+#endif  // OS_CHROMEOS
diff --git a/chrome/browser/ui/views/message_center/web_notification_tray.cc b/chrome/browser/ui/views/message_center/web_notification_tray.cc
index 77a79db..d8ae595 100644
--- a/chrome/browser/ui/views/message_center/web_notification_tray.cc
+++ b/chrome/browser/ui/views/message_center/web_notification_tray.cc
@@ -30,10 +30,6 @@
 #include "ui/message_center/views/message_popup_collection.h"
 #include "ui/views/widget/widget.h"
 
-#if defined(OS_WIN)
-#include "ui/base/win/hwnd_util.h"
-#endif
-
 namespace {
 
 // Tray constants
@@ -145,20 +141,21 @@
 }
 
 bool WebNotificationTray::ShowPopups() {
-  popup_collection_.reset(
-      new message_center::MessagePopupCollection(NULL, message_center()));
+  popup_collection_.reset(new message_center::MessagePopupCollection(
+      NULL, message_center(), message_center_tray_.get()));
   return true;
 }
 
 void WebNotificationTray::HidePopups() { popup_collection_.reset(); }
 
-bool WebNotificationTray::ShowMessageCenter() {
+bool WebNotificationTray::ShowMessageCenterInternal(bool show_settings) {
   content::RecordAction(UserMetricsAction("Notifications.ShowMessageCenter"));
 
   // Using MessageBubbleBase instead of MessageCenterBubble to
   // remove dependence on implicit type conversion
-  scoped_ptr<message_center::MessageBubbleBase> bubble(
-      new message_center::MessageCenterBubble(message_center()));
+  scoped_ptr<message_center::MessageCenterBubble> bubble(
+      new message_center::MessageCenterBubble(message_center(),
+                                              message_center_tray_.get()));
 
   gfx::Screen* screen = gfx::Screen::GetNativeScreen();
   gfx::Rect work_area = screen->GetPrimaryDisplay().work_area();
@@ -183,14 +180,20 @@
     }
   }
   bubble->SetMaxHeight(max_height);
+  if (show_settings)
+    bubble->SetSettingsVisible();
 
   message_center_bubble_.reset(new internal::NotificationBubbleWrapper(
       this,
-      bubble.Pass(),
+      bubble.PassAs<message_center::MessageBubbleBase>(),
       internal::NotificationBubbleWrapper::BUBBLE_TYPE_MESSAGE_CENTER));
   return true;
 }
 
+bool WebNotificationTray::ShowMessageCenter() {
+  return ShowMessageCenterInternal(false /* show_settings */);
+}
+
 void WebNotificationTray::HideMessageCenter() {
   message_center_bubble_.reset();
 }
@@ -202,6 +205,15 @@
   // non-rich-notifications in ChromeOS).
 };
 
+bool WebNotificationTray::ShowNotifierSettings() {
+  if (message_center_bubble_) {
+    static_cast<MessageCenterBubble*>(
+        message_center_bubble_->bubble())->SetSettingsVisible();
+    return true;
+  }
+  return ShowMessageCenterInternal(true /* show_settings */);
+}
+
 void WebNotificationTray::OnMessageCenterTrayChanged() {
   // See the comments in ash/system/web_notification/web_notification_tray.cc
   // for why PostTask.
diff --git a/chrome/browser/ui/views/message_center/web_notification_tray.h b/chrome/browser/ui/views/message_center/web_notification_tray.h
index 86b867e..67e2d4f 100644
--- a/chrome/browser/ui/views/message_center/web_notification_tray.h
+++ b/chrome/browser/ui/views/message_center/web_notification_tray.h
@@ -50,6 +50,7 @@
   virtual void HideMessageCenter() OVERRIDE;
   virtual void UpdatePopups() OVERRIDE;
   virtual void OnMessageCenterTrayChanged() OVERRIDE;
+  virtual bool ShowNotifierSettings() OVERRIDE;
 
   // These are forwarded to WebNotificationTray by
   // NotificationBubbleWrapper classes since they don't have enough
@@ -61,6 +62,13 @@
 
   // StatusIconObserver implementation.
   virtual void OnStatusIconClicked() OVERRIDE;
+#if defined(OS_WIN)
+  virtual void OnBalloonClicked() OVERRIDE;
+
+  // This shows a platform-specific balloon informing the user of the existence
+  // of the message center in the status tray area.
+  void DisplayFirstRunBalloon();
+#endif
 
   // Changes the icon and hovertext based on number of unread notifications.
   void UpdateStatusIcon();
@@ -73,6 +81,10 @@
                            ManyMessageCenterNotifications);
   FRIEND_TEST_ALL_PREFIXES(WebNotificationTrayTest, ManyPopupNotifications);
 
+  // The actual process to show the message center. Set |show_settings| to true
+  // if the message center should be initialized with the settings visible.
+  // Returns true if the center is successfully created.
+  bool ShowMessageCenterInternal(bool show_settings);
   StatusIcon* GetStatusIcon();
   void DestroyStatusIcon();
   void AddQuietModeMenu(StatusIcon* status_icon);
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
new file mode 100644
index 0000000..dcc6e25
--- /dev/null
+++ b/chrome/browser/ui/views/message_center/web_notification_tray_win.cc
@@ -0,0 +1,61 @@
+// 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/ui/views/message_center/web_notification_tray.h"
+
+#include <windows.h>
+
+#include "base/win/windows_version.h"
+#include "chrome/browser/app_icon_win.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/status_icons/status_icon.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_finder.h"
+#include "chrome/browser/ui/host_desktop.h"
+#include "chrome/browser/ui/singleton_tabs.h"
+#include "chrome/common/url_constants.h"
+#include "grit/chromium_strings.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/gfx/image/image_skia.h"
+
+namespace message_center {
+void WebNotificationTray::OnBalloonClicked() {
+  Browser* browser = chrome::FindOrCreateTabbedBrowser(
+      ProfileManager::GetLastUsedProfileAllowedByPolicy(),
+      chrome::GetActiveDesktop());
+  chrome::ShowSingletonTab(browser, GURL(chrome::kNotificationsHelpURL));
+}
+
+void WebNotificationTray::DisplayFirstRunBalloon() {
+  StatusIcon* status_icon = GetStatusIcon();
+  if (!status_icon)
+    return;
+
+  base::win::Version win_version = base::win::GetVersion();
+  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
+  // this flag is not set, the icon with dimensions SM_CXSMICON x SM_CYSMICON
+  // is used.
+  int icon_size = GetSystemMetrics(SM_CXICON);
+  if (win_version < base::win::VERSION_VISTA)
+    icon_size = GetSystemMetrics(SM_CXSMICON);
+
+  scoped_ptr<SkBitmap> sized_app_icon_bitmap = GetAppIconForSize(icon_size);
+  gfx::ImageSkia sized_app_icon_skia =
+      gfx::ImageSkia::CreateFrom1xBitmap(*sized_app_icon_bitmap);
+  string16 product_name(l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_NAME));
+  GetStatusIcon()->DisplayBalloon(
+      sized_app_icon_skia,
+      l10n_util::GetStringUTF16(IDS_MESSAGE_CENTER_BALLOON_TITLE),
+      l10n_util::GetStringUTF16(IDS_MESSAGE_CENTER_BALLOON_TEXT));
+}
+}  // namespace message_center
diff --git a/chrome/browser/ui/views/notifications/balloon_view_views.cc b/chrome/browser/ui/views/notifications/balloon_view_views.cc
index d6dc956..83884c7 100644
--- a/chrome/browser/ui/views/notifications/balloon_view_views.cc
+++ b/chrome/browser/ui/views/notifications/balloon_view_views.cc
@@ -336,7 +336,7 @@
 
   frame_container_ = new views::Widget;
   params.delegate = this;
-  params.transparent = true;
+  params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
   params.bounds = GetBoundsForFrameContainer();
   frame_container_->Init(params);
   frame_container_->SetContentsView(this);
diff --git a/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.cc b/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.cc
index 7fa6764..ec579dc 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.cc
@@ -216,7 +216,7 @@
     popup_ = (new AutocompletePopupWidget)->AsWeakPtr();
     views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP);
     params.can_activate = false;
-    params.transparent = true;
+    params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
     params.parent = popup_parent;
     params.bounds = GetPopupBounds();
     params.context = popup_parent;
diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_views.cc b/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
index 4abb228..3c39284 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
@@ -364,7 +364,6 @@
   bool changed_security_level = (security_level != security_level_);
   security_level_ = security_level;
 
-  // TODO(msw|oshima): Copied from GTK, determine correct Win/CrOS behavior.
   if (contents) {
     RevertAll();
     const OmniboxState* state = static_cast<OmniboxState*>(
@@ -377,7 +376,30 @@
       ClearEditHistory();
     }
   } else if (visibly_changed_permanent_text) {
+    // Not switching tabs, just updating the permanent text.  (In the case where
+    // we _were_ switching tabs, the RevertAll() above already drew the new
+    // permanent text.)
+
+    // Tweak: if the user had all the text selected, select all the new text.
+    // This makes one particular case better: the user clicks in the box to
+    // change it right before the permanent URL is changed.  Since the new URL
+    // is still fully selected, the user's typing will replace the edit contents
+    // as they'd intended.
+    const ui::Range range(GetSelectedRange());
+    const bool was_select_all = (range.length() == text().length());
+
     RevertAll();
+
+    // Only select all when we have focus.  If we don't have focus, selecting
+    // all is unnecessary since the selection will change on regaining focus,
+    // and can in fact cause artifacts, e.g. if the user is on the NTP and
+    // clicks a link to navigate, causing |was_select_all| to be vacuously true
+    // for the empty omnibox, and we then select all here, leading to the
+    // trailing portion of a long URL being scrolled into view.  We could try
+    // and address cases like this, but it seems better to just not muck with
+    // things when the omnibox isn't focused to begin with.
+    if (was_select_all && model()->has_focus())
+      SelectAll(range.is_reversed());
   } else if (changed_security_level) {
     EmphasizeURLComponents();
   }
@@ -585,10 +607,16 @@
 #if defined(OS_CHROMEOS)
   return ime_candidate_window_open_;
 #else
-  // TODO(yukishiino): Implement detection of candidate windows on Windows.
-  // We can detect whether any candidate window is open or not on Windows.
-  // Currently we simply fall back to IsImeComposing() as a second best way.
-  return IsImeComposing();
+  // We need const_cast here because there is no const version of
+  // View::GetInputMethod().  It's because Widget::GetInputMethod(), called from
+  // View::GetInputMethod(), creates a new views::InputMethod at the first-time
+  // call.  Except for this point, none of this method, View::GetInputMethod()
+  // or Widget::GetInputMethod() modifies the state of their instances.
+  // TODO(yukishiino): Make {View,Widget}::GetInputMethod() const and make the
+  // underlying input method object mutable.
+  const views::InputMethod* input_method =
+      const_cast<OmniboxViewViews*>(this)->GetInputMethod();
+  return input_method && input_method->IsCandidatePopupOpen();
 #endif
 }
 
@@ -741,7 +769,7 @@
   menu_contents->AddItemWithStringId(IDC_EDIT_SEARCH_ENGINES,
       IDS_EDIT_SEARCH_ENGINES);
 
-  if (chrome::IsQueryExtractionEnabled(model()->profile())) {
+  if (chrome::IsQueryExtractionEnabled()) {
     int copy_position = menu_contents->GetIndexOfCommandId(IDS_APP_COPY);
     DCHECK(copy_position >= 0);
     menu_contents->InsertItemWithStringIdAt(
diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_win.cc b/chrome/browser/ui/views/omnibox/omnibox_view_win.cc
index 3548e7f..db535a3 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_view_win.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_view_win.cc
@@ -639,26 +639,27 @@
     // we _were_ switching tabs, the RevertAll() above already drew the new
     // permanent text.)
 
-    // Tweak: if the edit was previously nonempty and had all the text selected,
-    // select all the new text.  This makes one particular case better: the
-    // user clicks in the box to change it right before the permanent URL is
-    // changed.  Since the new URL is still fully selected, the user's typing
-    // will replace the edit contents as they'd intended.
-    //
-    // NOTE: The selection can be longer than the text length if the edit is in
-    // in rich text mode and the user has selected the "phantom newline" at the
-    // end, so use ">=" instead of "==" to see if all the text is selected.  In
-    // theory we prevent this case from ever occurring, but this is still safe.
+    // Tweak: if the user had all the text selected, select all the new text.
+    // This makes one particular case better: the user clicks in the box to
+    // change it right before the permanent URL is changed.  Since the new URL
+    // is still fully selected, the user's typing will replace the edit contents
+    // as they'd intended.
     CHARRANGE sel;
     GetSelection(sel);
-    const bool was_reversed = (sel.cpMin > sel.cpMax);
-    const bool was_sel_all = (sel.cpMin != sel.cpMax) &&
-      IsSelectAllForRange(sel);
+    const bool was_select_all = IsSelectAllForRange(sel);
 
     RevertAll();
 
-    if (was_sel_all)
-      SelectAll(was_reversed);
+    // Only select all when we have focus.  If we don't have focus, selecting
+    // all is unnecessary since the selection will change on regaining focus,
+    // and can in fact cause artifacts, e.g. if the user is on the NTP and
+    // clicks a link to navigate, causing |was_select_all| to be vacuously true
+    // for the empty omnibox, and we then select all here, leading to the
+    // trailing portion of a long URL being scrolled into view.  We could try
+    // and address cases like this, but it seems better to just not muck with
+    // things when the omnibox isn't focused to begin with.
+    if (was_select_all && model()->has_focus())
+      SelectAll(sel.cpMin > sel.cpMax);
   } else if (changed_security_level) {
     // Only the security style changed, nothing else.  Redraw our text using it.
     EmphasizeURLComponents();
@@ -2784,7 +2785,7 @@
     context_menu_contents_->AddSeparator(ui::NORMAL_SEPARATOR);
     context_menu_contents_->AddItemWithStringId(IDC_CUT, IDS_CUT);
     context_menu_contents_->AddItemWithStringId(IDC_COPY, IDS_COPY);
-    if (chrome::IsQueryExtractionEnabled(model()->profile()))
+    if (chrome::IsQueryExtractionEnabled())
       context_menu_contents_->AddItemWithStringId(IDC_COPY_URL, IDS_COPY_URL);
     context_menu_contents_->AddItemWithStringId(IDC_PASTE, IDS_PASTE);
     // GetContextualLabel() will override this next label with the
diff --git a/chrome/browser/ui/views/panels/panel_stack_view.cc b/chrome/browser/ui/views/panels/panel_stack_view.cc
index b4c7df3..25843ed 100644
--- a/chrome/browser/ui/views/panels/panel_stack_view.cc
+++ b/chrome/browser/ui/views/panels/panel_stack_view.cc
@@ -218,6 +218,11 @@
     // To work around this problem, we recreate the underlying window.
     views::Widget* old_window = window_;
     window_ = CreateWindowWithBounds(GetStackWindowBounds());
+
+    // New background window should also be minimized if the old one is.
+    if (old_window->IsMinimized())
+      window_->Minimize();
+
     // Make sure the new background window stays at the same z-order as the old
     // one.
     ::SetWindowPos(views::HWNDForWidget(window_),
@@ -228,6 +233,11 @@
          iter != panels_.end(); ++iter) {
       MakeStackWindowOwnPanelWindow(*iter, this);
     }
+
+    // Serve the snapshot to the new backgroud window.
+    if (thumbnailer_.get())
+      thumbnailer_->ReplaceWindow(views::HWNDForWidget(window_));
+
     window_->UpdateWindowTitle();
     window_->UpdateWindowIcon();
     old_window->Close();
@@ -450,12 +460,6 @@
       ShellIntegration::GetAppModelIdForProfile(UTF8ToWide(panel->app_name()),
                                                 panel->profile()->GetPath()),
       views::HWNDForWidget(window));
-
-  if (base::win::GetVersion() >= base::win::VERSION_WIN7) {
-    HWND native_window = views::HWNDForWidget(window);
-    thumbnailer_.reset(new TaskbarWindowThumbnailerWin(native_window, this));
-    thumbnailer_->Start();
-  }
 #endif
 
   return window;
@@ -468,6 +472,14 @@
   // Empty size is not allowed so a temporary small size is passed. SetBounds
   // will be called later to update the bounds.
   window_ = CreateWindowWithBounds(gfx::Rect(0, 0, 1, 1));
+
+#if defined(OS_WIN)
+  if (base::win::GetVersion() >= base::win::VERSION_WIN7) {
+    HWND native_window = views::HWNDForWidget(window_);
+    thumbnailer_.reset(new TaskbarWindowThumbnailerWin(native_window, this));
+    thumbnailer_->Start();
+  }
+#endif
 }
 
 #if defined(OS_WIN)
@@ -484,7 +496,9 @@
 }
 
 void PanelStackView::RefreshLivePreviewThumbnail() {
-  if (!thumbnailer_.get())
+  // Don't refresh the thumbnail when the stack window is system minimized
+  // because the snapshot could not be retrieved.
+  if (!thumbnailer_.get() || IsMinimized())
     return;
   thumbnailer_->InvalidateSnapshot();
 }
diff --git a/chrome/browser/ui/views/panels/panel_view.cc b/chrome/browser/ui/views/panels/panel_view.cc
index a253fa4..bf81562 100644
--- a/chrome/browser/ui/views/panels/panel_view.cc
+++ b/chrome/browser/ui/views/panels/panel_view.cc
@@ -568,6 +568,16 @@
       window_->Hide();
   } else {
     ShowPanelInactive();
+
+#if defined(OS_WIN)
+    // When hiding and showing again a top-most window that belongs to a
+    // background application (i.e. the application is not a foreground one),
+    // the window may loose top-most placement even though its WS_EX_TOPMOST
+    // bit is still set. Re-issuing SetWindowsPos() returns the window to its
+    // top-most placement.
+    if (always_on_top_)
+      window_->SetAlwaysOnTop(true);
+#endif
   }
 }
 
diff --git a/chrome/browser/ui/views/panels/taskbar_window_thumbnailer_win.cc b/chrome/browser/ui/views/panels/taskbar_window_thumbnailer_win.cc
index 9a47e96..e6946bb 100644
--- a/chrome/browser/ui/views/panels/taskbar_window_thumbnailer_win.cc
+++ b/chrome/browser/ui/views/panels/taskbar_window_thumbnailer_win.cc
@@ -82,6 +82,18 @@
   ::DwmInvalidateIconicBitmaps(hwnd_);
 }
 
+void TaskbarWindowThumbnailerWin::ReplaceWindow(HWND new_hwnd) {
+  // Stop serving the custom thumbnail for the old window.
+  EnableCustomThumbnail(hwnd_, false);
+  ui::HWNDSubclass::RemoveFilterFromAllTargets(this);
+
+  hwnd_ = new_hwnd;
+
+  // Start serving the custom thumbnail to the new window.
+  ui::HWNDSubclass::AddFilterToTarget(hwnd_, this);
+  EnableCustomThumbnail(hwnd_, true);
+}
+
 bool TaskbarWindowThumbnailerWin::FilterMessage(HWND hwnd,
                                                 UINT message,
                                                 WPARAM w_param,
diff --git a/chrome/browser/ui/views/panels/taskbar_window_thumbnailer_win.h b/chrome/browser/ui/views/panels/taskbar_window_thumbnailer_win.h
index 6d13b00..8031599 100644
--- a/chrome/browser/ui/views/panels/taskbar_window_thumbnailer_win.h
+++ b/chrome/browser/ui/views/panels/taskbar_window_thumbnailer_win.h
@@ -42,6 +42,10 @@
   // when the system requests it.
   void InvalidateSnapshot();
 
+  // Provide the snapshot to the new window. If the snapshot is captured for the
+  // old window, it will also be used for the new window.
+  void ReplaceWindow(HWND new_hwnd);
+
  private:
   // Overridden from ui::HWNDMessageFilter:
   virtual bool FilterMessage(HWND hwnd,
diff --git a/chrome/browser/ui/views/password_generation_bubble_view.cc b/chrome/browser/ui/views/password_generation_bubble_view.cc
index 0c45d3f..cab4c79 100644
--- a/chrome/browser/ui/views/password_generation_bubble_view.cc
+++ b/chrome/browser/ui/views/password_generation_bubble_view.cc
@@ -9,7 +9,7 @@
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_list.h"
 #include "chrome/common/url_constants.h"
-#include "components/autofill/browser/password_generator.h"
+#include "components/autofill/core/browser/password_generator.h"
 #include "components/autofill/core/common/autofill_messages.h"
 #include "components/autofill/core/common/password_generation_util.h"
 #include "content/public/browser/page_navigator.h"
diff --git a/chrome/browser/ui/views/reload_button.h b/chrome/browser/ui/views/reload_button.h
index 31ebdc9..2611aef 100644
--- a/chrome/browser/ui/views/reload_button.h
+++ b/chrome/browser/ui/views/reload_button.h
@@ -7,7 +7,7 @@
 
 #include "base/basictypes.h"
 #include "base/gtest_prod_util.h"
-#include "base/timer.h"
+#include "base/timer/timer.h"
 #include "ui/base/models/simple_menu_model.h"
 #include "ui/views/controls/button/button_dropdown.h"
 
diff --git a/chrome/browser/ui/views/screen_capture_notification_ui_views.cc b/chrome/browser/ui/views/screen_capture_notification_ui_views.cc
new file mode 100644
index 0000000..227ef1c
--- /dev/null
+++ b/chrome/browser/ui/views/screen_capture_notification_ui_views.cc
@@ -0,0 +1,286 @@
+// 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/ui/screen_capture_notification_ui.h"
+
+#include "ash/shell.h"
+#include "chrome/app/chrome_dll_resource.h"
+#include "chrome/browser/ui/views/chrome_views_export.h"
+#include "grit/generated_resources.h"
+#include "grit/theme_resources.h"
+#include "ui/aura/root_window.h"
+#include "ui/base/hit_test.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/views/bubble/bubble_border.h"
+#include "ui/views/bubble/bubble_frame_view.h"
+#include "ui/views/controls/button/blue_button.h"
+#include "ui/views/controls/image_view.h"
+#include "ui/views/corewm/shadow_types.h"
+#include "ui/views/layout/box_layout.h"
+#include "ui/views/view.h"
+#include "ui/views/widget/widget.h"
+#include "ui/views/widget/widget_delegate.h"
+
+namespace {
+
+const int kMinimumWidth = 460;
+const int kMaximumWidth = 1000;
+const int kHorizontalMargin = 10;
+const int kPadding = 5;
+const int kPaddingLeft = 10;
+
+namespace {
+
+// A ClientView that overrides NonClientHitTest() so that the whole window area
+// acts as a window caption, except a rect specified using SetClientRect().
+// ScreenCaptureNotificationUIViews uses this class to make the notification bar
+// draggable.
+class NotificationBarClientView : public views::ClientView {
+ public:
+  NotificationBarClientView(views::Widget* widget, views::View* view)
+      : views::ClientView(widget, view) {
+  }
+  virtual ~NotificationBarClientView() {}
+
+  void SetClientRect(const gfx::Rect& rect) {
+    rect_ = rect;
+  }
+
+  // views::ClientView overrides.
+  virtual int NonClientHitTest(const gfx::Point& point) OVERRIDE  {
+    if (!bounds().Contains(point))
+      return HTNOWHERE;
+    // The whole window is HTCAPTION, except the |rect_|.
+    if (rect_.Contains(gfx::PointAtOffsetFromOrigin(point - bounds().origin())))
+      return HTCLIENT;
+
+    return HTCAPTION;
+  }
+
+ private:
+  gfx::Rect rect_;
+
+  DISALLOW_COPY_AND_ASSIGN(NotificationBarClientView);
+};
+
+}  // namespace
+
+// ScreenCaptureNotificationUI implementation using Views.
+class ScreenCaptureNotificationUIViews
+    : public ScreenCaptureNotificationUI,
+      public views::WidgetDelegateView,
+      public views::ButtonListener {
+ public:
+  ScreenCaptureNotificationUIViews();
+  virtual ~ScreenCaptureNotificationUIViews();
+
+  // ScreenCaptureNotificationUI interface.
+  virtual bool Show(const base::Closure& stop_callback,
+                    const string16& title) OVERRIDE;
+
+  // views::View overrides.
+  virtual gfx::Size GetPreferredSize() OVERRIDE;
+  virtual void Layout() OVERRIDE;
+
+  // views::WidgetDelegateView overrides.
+  virtual void DeleteDelegate() OVERRIDE;
+  virtual views::View* GetContentsView() OVERRIDE;
+  virtual views::ClientView* CreateClientView(views::Widget* widget) OVERRIDE;
+  virtual views::NonClientFrameView* CreateNonClientFrameView(
+      views::Widget* widget) OVERRIDE;
+  virtual string16 GetWindowTitle() const OVERRIDE;
+  virtual bool ShouldShowWindowTitle() const OVERRIDE;
+  virtual bool ShouldShowCloseButton() const OVERRIDE;
+
+  // views::ButtonListener interface.
+  virtual void ButtonPressed(views::Button* sender,
+                             const ui::Event& event) OVERRIDE;
+
+ private:
+  // Helper to call |stop_callback_|.
+  void NotifyStopped();
+
+  base::Closure stop_callback_;
+  string16 window_title_;
+  NotificationBarClientView* client_view_;
+  views::ImageView* gripper_;
+  views::Label* label_;
+  views::BlueButton* stop_button_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScreenCaptureNotificationUIViews);
+};
+
+ScreenCaptureNotificationUIViews::ScreenCaptureNotificationUIViews()
+    : client_view_(NULL),
+      gripper_(NULL),
+      label_(NULL),
+      stop_button_(NULL) {
+  set_owned_by_client();
+
+  set_background(views::Background::CreateSolidBackground(GetNativeTheme()->
+      GetSystemColor(ui::NativeTheme::kColorId_DialogBackground)));
+
+  gripper_ = new views::ImageView();
+  gripper_->SetImage(
+      ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
+          IDR_SCREEN_CAPTURE_NOTIFICATION_GRIP));
+  AddChildView(gripper_);
+
+  label_ = new views::Label();
+  AddChildView(label_);
+
+  string16 stop_text =
+      l10n_util::GetStringUTF16(IDS_MEDIA_SCREEN_CAPTURE_NOTIFICATION_STOP);
+  stop_button_ = new views::BlueButton(this, stop_text);
+  AddChildView(stop_button_);
+}
+
+ScreenCaptureNotificationUIViews::~ScreenCaptureNotificationUIViews() {
+  stop_callback_.Reset();
+  delete GetWidget();
+}
+
+bool ScreenCaptureNotificationUIViews::Show(
+    const base::Closure& stop_callback,
+    const string16& title) {
+  stop_callback_ = stop_callback;
+
+  label_->SetElideBehavior(views::Label::ELIDE_IN_MIDDLE);
+  label_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
+  string16 text = l10n_util::GetStringFUTF16(
+      IDS_MEDIA_SCREEN_CAPTURE_NOTIFICATION_TEXT, title);
+  label_->SetText(text);
+  window_title_ = l10n_util::GetStringFUTF16(
+      IDS_MEDIA_SCREEN_CAPTURE_NOTIFICATION_TITLE, title);
+
+  views::Widget* widget = new views::Widget;
+
+  views::Widget::InitParams params;
+  params.delegate = this;
+  params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+  params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
+  params.remove_standard_frame = true;
+  params.keep_on_top = true;
+  params.top_level = true;
+  params.can_activate = false;
+
+#if defined(USE_ASH)
+  // TODO(sergeyu): The notification bar must be shown on the monitor that's
+  // being captured. Make sure it's always the case. Currently we always capture
+  // the primary monitor.
+  if (ash::Shell::HasInstance())
+    params.context = ash::Shell::GetPrimaryRootWindow();
+#endif
+
+  widget->set_frame_type(views::Widget::FRAME_TYPE_FORCE_CUSTOM);
+  widget->Init(params);
+  widget->SetAlwaysOnTop(true);
+
+  gfx::Screen* screen = gfx::Screen::GetNativeScreen();
+  // TODO(sergeyu): Move the notification to the display being captured when
+  // per-display screen capture is supported.
+  gfx::Rect work_area = screen->GetPrimaryDisplay().work_area();
+
+  // Place the bar in the center of the bottom of the display.
+  gfx::Size size = widget->non_client_view()->GetPreferredSize();
+  gfx::Rect bounds(
+      work_area.x() + work_area.width() / 2 - size.width() / 2,
+      work_area.y() + work_area.height() - size.height(),
+      size.width(), size.height());
+  widget->SetBounds(bounds);
+
+  widget->Show();
+
+  return true;
+}
+
+gfx::Size ScreenCaptureNotificationUIViews::GetPreferredSize() {
+  gfx::Size grip_size = gripper_->GetPreferredSize();
+  gfx::Size label_size = child_at(1)->GetPreferredSize();
+  gfx::Size button_size = child_at(2)->GetPreferredSize();
+  int width = kHorizontalMargin * 2 + grip_size.width() + label_size.width() +
+      button_size.width();
+  width = std::max(width, kMinimumWidth);
+  width = std::min(width, kMaximumWidth);
+  return gfx::Size(width, std::max(label_size.height(), button_size.height()));
+}
+
+void ScreenCaptureNotificationUIViews::Layout() {
+  gfx::Rect grip_rect(gripper_->GetPreferredSize());
+  grip_rect.set_y(bounds().height() / 2 - grip_rect.height() / 2);
+  gripper_->SetBoundsRect(grip_rect);
+
+  gfx::Rect button_rect(stop_button_->GetPreferredSize());
+  button_rect.set_x(bounds().width() - button_rect.width());
+  stop_button_->SetBoundsRect(button_rect);
+
+  gfx::Rect label_rect;
+  label_rect.set_x(grip_rect.right() + kHorizontalMargin);
+  label_rect.set_width(button_rect.x() - kHorizontalMargin - label_rect.x());
+  label_rect.set_height(bounds().height());
+  label_->SetBoundsRect(label_rect);
+
+  client_view_->SetClientRect(button_rect);
+}
+
+void ScreenCaptureNotificationUIViews::DeleteDelegate() {
+  NotifyStopped();
+}
+
+views::View* ScreenCaptureNotificationUIViews::GetContentsView() {
+  return this;
+}
+
+views::ClientView* ScreenCaptureNotificationUIViews::CreateClientView(
+    views::Widget* widget) {
+  DCHECK(!client_view_);
+  client_view_ = new NotificationBarClientView(widget, this);
+  return client_view_;
+}
+
+views::NonClientFrameView*
+ScreenCaptureNotificationUIViews::CreateNonClientFrameView(
+    views::Widget* widget) {
+  views::BubbleFrameView* frame = new views::BubbleFrameView(
+      gfx::Insets(kPadding, kPaddingLeft, kPadding, kPadding));
+  SkColor color = widget->GetNativeTheme()->GetSystemColor(
+      ui::NativeTheme::kColorId_DialogBackground);
+  views::BubbleBorder* border = new views::BubbleBorder(
+      views::BubbleBorder::NONE, views::BubbleBorder::SMALL_SHADOW, color);
+  frame->SetBubbleBorder(border);
+  return frame;
+}
+
+string16 ScreenCaptureNotificationUIViews::GetWindowTitle() const {
+  return window_title_;
+}
+
+bool ScreenCaptureNotificationUIViews::ShouldShowWindowTitle() const {
+  return false;
+}
+
+bool ScreenCaptureNotificationUIViews::ShouldShowCloseButton() const {
+  return false;
+}
+
+void ScreenCaptureNotificationUIViews::ButtonPressed(views::Button* sender,
+                                                     const ui::Event& event) {
+  NotifyStopped();
+}
+
+void ScreenCaptureNotificationUIViews::NotifyStopped() {
+  if (!stop_callback_.is_null()) {
+    base::Closure callback = stop_callback_;
+    stop_callback_.Reset();
+    callback.Run();
+  }
+}
+
+}  // namespace
+
+scoped_ptr<ScreenCaptureNotificationUI> ScreenCaptureNotificationUI::Create() {
+  return scoped_ptr<ScreenCaptureNotificationUI>(
+      new ScreenCaptureNotificationUIViews());
+}
diff --git a/chrome/browser/ui/views/select_file_dialog_extension.cc b/chrome/browser/ui/views/select_file_dialog_extension.cc
index 3efc148..09e9ee5 100644
--- a/chrome/browser/ui/views/select_file_dialog_extension.cc
+++ b/chrome/browser/ui/views/select_file_dialog_extension.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/ui/views/select_file_dialog_extension.h"
 
+#include "apps/shell_window.h"
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/logging.h"
@@ -24,7 +25,6 @@
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/chrome_select_file_policy.h"
 #include "chrome/browser/ui/extensions/native_app_window.h"
-#include "chrome/browser/ui/extensions/shell_window.h"
 #include "chrome/browser/ui/host_desktop.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/views/extensions/extension_dialog.h"
@@ -33,16 +33,14 @@
 #include "ui/base/base_window.h"
 #include "ui/shell_dialogs/selected_file_info.h"
 
+using apps::ShellWindow;
 using content::BrowserThread;
 
 namespace {
 
-const int kFileManagerWidth = 954;  // pixels
+const int kFileManagerWidth = 972;  // pixels
 const int kFileManagerHeight = 640;  // pixels
 
-const int kFileManagerMinimumWidth = kFileManagerWidth * 2 / 3;  // pixels
-const int kFileManagerMinimumHeight = kFileManagerHeight * 2 / 3;  // pixels
-
 // Holds references to file manager dialogs that have callbacks pending
 // to their listeners.
 class PendingDialog {
@@ -354,8 +352,8 @@
   ExtensionDialog* dialog = ExtensionDialog::Show(file_browser_url,
       base_window, profile_, web_contents,
       kFileManagerWidth, kFileManagerHeight,
-      kFileManagerMinimumWidth,
-      kFileManagerMinimumHeight,
+      kFileManagerWidth,
+      kFileManagerHeight,
 #if defined(USE_AURA)
       file_manager_util::GetTitleFromType(type),
 #else
diff --git a/chrome/browser/ui/views/select_file_dialog_extension_browsertest.cc b/chrome/browser/ui/views/select_file_dialog_extension_browsertest.cc
index 92cf6eb..b77b366 100644
--- a/chrome/browser/ui/views/select_file_dialog_extension_browsertest.cc
+++ b/chrome/browser/ui/views/select_file_dialog_extension_browsertest.cc
@@ -200,7 +200,8 @@
     content::RenderViewHost* host = dialog_->GetRenderViewHost();
     string16 main_frame;
     std::string button_class =
-        (button_type == DIALOG_BTN_OK) ? ".ok" : ".cancel";
+        (button_type == DIALOG_BTN_OK) ? ".button-panel .ok" :
+                                         ".button-panel .cancel";
     string16 script = ASCIIToUTF16(
         "console.log(\'Test JavaScript injected.\');"
         "document.querySelector(\'" + button_class + "\').click();");
diff --git a/chrome/browser/ui/views/status_bubble_views.cc b/chrome/browser/ui/views/status_bubble_views.cc
index 3fbb520..48ed6eb 100644
--- a/chrome/browser/ui/views/status_bubble_views.cc
+++ b/chrome/browser/ui/views/status_bubble_views.cc
@@ -572,7 +572,7 @@
     if (!expand_view_.get())
       expand_view_.reset(new StatusViewExpander(this, view_));
     views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP);
-    params.transparent = true;
+    params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
     params.accept_events = false;
     params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
     params.parent = frame->GetNativeView();
diff --git a/chrome/browser/ui/views/status_icons/status_icon_win.cc b/chrome/browser/ui/views/status_icons/status_icon_win.cc
index ee23a68..a5af417 100644
--- a/chrome/browser/ui/views/status_icons/status_icon_win.cc
+++ b/chrome/browser/ui/views/status_icons/status_icon_win.cc
@@ -63,6 +63,11 @@
       ui::MENU_SOURCE_MOUSE, views::MenuRunner::HAS_MNEMONICS));
 }
 
+void StatusIconWin::HandleBalloonClickEvent() {
+  if (HasObservers())
+    DispatchBalloonClickEvent();
+}
+
 void StatusIconWin::ResetIcon() {
   NOTIFYICONDATA icon_data;
   InitIconData(&icon_data);
@@ -143,6 +148,9 @@
 // StatusIconWin, private:
 
 void StatusIconWin::UpdatePlatformContextMenu(ui::MenuModel* menu) {
+  // |menu_model_| is about to be destroyed. Destroy the menu (which closes it)
+  // so that it doesn't attempt to continue using |menu_model_|.
+  menu_runner_.reset();
   DCHECK(menu);
   menu_model_ = menu;
 }
diff --git a/chrome/browser/ui/views/status_icons/status_icon_win.h b/chrome/browser/ui/views/status_icons/status_icon_win.h
index b15a5e1..8f4cf1b 100644
--- a/chrome/browser/ui/views/status_icons/status_icon_win.h
+++ b/chrome/browser/ui/views/status_icons/status_icon_win.h
@@ -33,6 +33,9 @@
   // otherwise displays the context menu if there is one.
   void HandleClickEvent(const gfx::Point& cursor_pos, bool left_button_click);
 
+  // Handles a click on the balloon from the user.
+  void HandleBalloonClickEvent();
+
   // Re-creates the status tray icon now after the taskbar has been created.
   void ResetIcon();
 
diff --git a/chrome/browser/ui/views/status_icons/status_tray_win.cc b/chrome/browser/ui/views/status_icons/status_tray_win.cc
index 03797c0..97792f7 100644
--- a/chrome/browser/ui/views/status_icons/status_tray_win.cc
+++ b/chrome/browser/ui/views/status_icons/status_tray_win.cc
@@ -4,6 +4,8 @@
 
 #include "chrome/browser/ui/views/status_icons/status_tray_win.h"
 
+#include <commctrl.h>
+
 #include "base/win/wrapped_window_proc.h"
 #include "chrome/browser/ui/views/status_icons/status_icon_win.h"
 #include "chrome/common/chrome_constants.h"
@@ -68,22 +70,32 @@
     }
     return TRUE;
   } else if (message == kStatusIconMessage) {
+    StatusIconWin* win_icon = NULL;
+
+    // Find the selected status icon.
+    for (StatusIcons::const_iterator i(status_icons().begin());
+         i != status_icons().end();
+         ++i) {
+      StatusIconWin* current_win_icon = static_cast<StatusIconWin*>(*i);
+      if (current_win_icon->icon_id() == wparam) {
+        win_icon = current_win_icon;
+        break;
+      }
+    }
+
     switch (lparam) {
+      case TB_INDETERMINATE:
+        win_icon->HandleBalloonClickEvent();
+        return TRUE;
+
       case WM_LBUTTONDOWN:
       case WM_RBUTTONDOWN:
       case WM_CONTEXTMENU:
         // Walk our icons, find which one was clicked on, and invoke its
         // HandleClickEvent() method.
-        for (StatusIcons::const_iterator i(status_icons().begin());
-             i != status_icons().end(); ++i) {
-          StatusIconWin* win_icon = static_cast<StatusIconWin*>(*i);
-          if (win_icon->icon_id() == wparam) {
-            gfx::Point cursor_pos(
-                gfx::Screen::GetNativeScreen()->GetCursorScreenPoint());
-            win_icon->HandleClickEvent(cursor_pos, lparam == WM_LBUTTONDOWN);
-            break;
-          }
-        }
+        gfx::Point cursor_pos(
+            gfx::Screen::GetNativeScreen()->GetCursorScreenPoint());
+        win_icon->HandleClickEvent(cursor_pos, lparam == WM_LBUTTONDOWN);
         return TRUE;
     }
   }
diff --git a/chrome/browser/ui/views/status_icons/status_tray_win_unittest.cc b/chrome/browser/ui/views/status_icons/status_tray_win_unittest.cc
index 7ff8309..3968cdc 100644
--- a/chrome/browser/ui/views/status_icons/status_tray_win_unittest.cc
+++ b/chrome/browser/ui/views/status_icons/status_tray_win_unittest.cc
@@ -4,21 +4,34 @@
 
 #include "chrome/browser/ui/views/status_icons/status_tray_win.h"
 
+#include <commctrl.h>
+
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/status_icons/status_icon_observer.h"
 #include "chrome/browser/ui/views/status_icons/status_icon_win.h"
 #include "grit/chrome_unscaled_resources.h"
-#include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/models/simple_menu_model.h"
 #include "ui/base/resource/resource_bundle.h"
 
-class SkBitmap;
-
-class MockStatusIconObserver : public StatusIconObserver {
+class FakeStatusIconObserver : public StatusIconObserver {
  public:
-  MOCK_METHOD0(OnStatusIconClicked, void());
+  FakeStatusIconObserver()
+      : balloon_clicked_(false),
+        status_icon_click_count_(0) {}
+  virtual void OnStatusIconClicked() {
+    ++status_icon_click_count_;
+  }
+  virtual void OnBalloonClicked() { balloon_clicked_ = true; }
+  bool balloon_clicked() const { return balloon_clicked_; }
+  size_t status_icon_click_count() const {
+    return status_icon_click_count_;
+  }
+
+ private:
+  size_t status_icon_click_count_;
+  bool balloon_clicked_;
 };
 
 TEST(StatusTrayWinTest, CreateTray) {
@@ -46,13 +59,26 @@
   // Create an icon, send a fake click event, make sure observer is called.
   StatusTrayWin tray;
   StatusIconWin* icon = static_cast<StatusIconWin*>(tray.CreateStatusIcon());
-  MockStatusIconObserver observer;
+  FakeStatusIconObserver observer;
   icon->AddObserver(&observer);
-  EXPECT_CALL(observer, OnStatusIconClicked());
   // Mimic a click.
   tray.WndProc(NULL, icon->message_id(), icon->icon_id(), WM_LBUTTONDOWN);
   // Mimic a right-click - observer should not be called.
   tray.WndProc(NULL, icon->message_id(), icon->icon_id(), WM_RBUTTONDOWN);
+  EXPECT_EQ(1, observer.status_icon_click_count());
+  icon->RemoveObserver(&observer);
+}
+
+TEST(StatusTrayWinTest, ClickOnBalloon) {
+  // Create an icon, send a fake click event, make sure observer is called.
+  StatusTrayWin tray;
+  StatusIconWin* icon = static_cast<StatusIconWin*>(tray.CreateStatusIcon());
+  FakeStatusIconObserver observer;
+  icon->AddObserver(&observer);
+  // Mimic a click.
+  tray.WndProc(
+      NULL, icon->message_id(), icon->icon_id(), TB_INDETERMINATE);
+  EXPECT_TRUE(observer.balloon_clicked());
   icon->RemoveObserver(&observer);
 }
 #endif  // !defined(USE_AURA)
diff --git a/chrome/browser/ui/views/sync/profile_signin_confirmation_dialog_views.cc b/chrome/browser/ui/views/sync/profile_signin_confirmation_dialog_views.cc
index fff9132..a585367 100644
--- a/chrome/browser/ui/views/sync/profile_signin_confirmation_dialog_views.cc
+++ b/chrome/browser/ui/views/sync/profile_signin_confirmation_dialog_views.cc
@@ -4,6 +4,8 @@
 
 #include "chrome/browser/ui/views/sync/profile_signin_confirmation_dialog_views.h"
 
+#include <algorithm>
+
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_dialogs.h"
@@ -25,29 +27,12 @@
 #include "ui/gfx/native_widget_types.h"
 #include "ui/views/background.h"
 #include "ui/views/controls/label.h"
-#include "ui/views/controls/link.h"
 #include "ui/views/controls/styled_label.h"
 #include "ui/views/layout/box_layout.h"
 #include "ui/views/layout/grid_layout.h"
 #include "ui/views/layout/layout_constants.h"
 #include "ui/views/widget/widget.h"
-
-namespace {
-
-// Wrap a view in a fixed-width container.
-views::View* MakeFixedWidth(views::View* view, int width) {
-  views::View* container = new views::View;
-  views::GridLayout* layout = views::GridLayout::CreatePanel(container);
-  container->SetLayoutManager(layout);
-  layout->AddColumnSet(0)->AddColumn(
-      views::GridLayout::LEADING, views::GridLayout::CENTER, 0,
-      views::GridLayout::FIXED, width, false);
-  layout->StartRow(0, 0);
-  layout->AddView(view, 1, 1, views::GridLayout::FILL, views::GridLayout::FILL);
-  return container;
-}
-
-}  // namespace
+#include "ui/views/window/dialog_client_view.h"
 
 namespace chrome {
 // Declared in browser_dialogs.h
@@ -74,7 +59,7 @@
     username_(username),
     delegate_(delegate),
     prompt_for_new_profile_(true),
-    link_(NULL) {
+    continue_signin_button_(NULL) {
 }
 
 ProfileSigninConfirmationDialogViews::~ProfileSigninConfirmationDialogViews() {}
@@ -109,9 +94,15 @@
 
 string16 ProfileSigninConfirmationDialogViews::GetDialogButtonLabel(
     ui::DialogButton button) const {
-  return l10n_util::GetStringUTF16((button == ui::DIALOG_BUTTON_OK) ?
-      IDS_ENTERPRISE_SIGNIN_CONTINUE_NEW_STYLE :
-      IDS_ENTERPRISE_SIGNIN_CANCEL);
+  if (button == ui::DIALOG_BUTTON_OK) {
+    // If we're giving the option to create a new profile, then OK is
+    // "Create new profile".  Otherwise it is "Continue signin".
+    return l10n_util::GetStringUTF16(
+        prompt_for_new_profile_ ?
+            IDS_ENTERPRISE_SIGNIN_CREATE_NEW_PROFILE_NEW_STYLE :
+            IDS_ENTERPRISE_SIGNIN_CONTINUE_NEW_STYLE);
+  }
+  return l10n_util::GetStringUTF16(IDS_ENTERPRISE_SIGNIN_CANCEL);
 }
 
 int ProfileSigninConfirmationDialogViews::GetDefaultDialogButton() const {
@@ -120,20 +111,22 @@
 
 views::View* ProfileSigninConfirmationDialogViews::CreateExtraView() {
   if (prompt_for_new_profile_) {
-    const string16 create_profile_text =
-        l10n_util::GetStringUTF16(
-            IDS_ENTERPRISE_SIGNIN_CREATE_NEW_PROFILE_NEW_STYLE);
-    link_ = new views::Link(create_profile_text);
-    link_->SetUnderline(false);
-    link_->set_listener(this);
-    link_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
+    const string16 continue_signin_text =
+        l10n_util::GetStringUTF16(IDS_ENTERPRISE_SIGNIN_CONTINUE_NEW_STYLE);
+    continue_signin_button_ =
+        new views::LabelButton(this, continue_signin_text);
+    continue_signin_button_->SetStyle(views::Button::STYLE_NATIVE_TEXTBUTTON);
+    continue_signin_button_->set_focusable(true);
   }
-  return link_;
+  return continue_signin_button_;
 }
 
 bool ProfileSigninConfirmationDialogViews::Accept() {
   if (delegate_) {
-    delegate_->OnContinueSignin();
+    if (prompt_for_new_profile_)
+      delegate_->OnSigninWithNewProfile();
+    else
+      delegate_->OnContinueSignin();
     delegate_ = NULL;
   }
   return true;
@@ -160,39 +153,35 @@
   if (!details.is_add || details.child != this)
     return;
 
-  // Layout the labels in a single fixed-width column.
-  SetLayoutManager(new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0));
-
   // Create the prompt label.
-  std::vector<size_t> offsets;
+  size_t offset;
   const string16 domain = ASCIIToUTF16(gaia::ExtractDomainName(username_));
   const string16 username = ASCIIToUTF16(username_);
   const string16 prompt_text =
       l10n_util::GetStringFUTF16(
           IDS_ENTERPRISE_SIGNIN_ALERT_NEW_STYLE,
-          username, domain, &offsets);
+          domain, &offset);
   views::StyledLabel* prompt_label = new views::StyledLabel(prompt_text, this);
   views::StyledLabel::RangeStyleInfo bold_style;
   bold_style.font_style = gfx::Font::BOLD;
   prompt_label->AddStyleRange(
-      ui::Range(offsets[1], offsets[1] + domain.size()), bold_style);
+      ui::Range(offset, offset + domain.size()), bold_style);
 
-  // Add the prompt label with a darker background and border.
-  const int kDialogWidth = 440;
-  views::View* prompt_container = MakeFixedWidth(prompt_label, kDialogWidth);
-  prompt_container->set_border(
+  // Create the prompt bar.
+  views::View* prompt_bar = new views::View;
+  prompt_bar->set_border(
       views::Border::CreateSolidSidedBorder(
           1, 0, 1, 0,
           ui::GetSigninConfirmationPromptBarColor(
               ui::kSigninConfirmationPromptBarBorderAlpha)));
-  prompt_container->set_background(
+  // TODO(dconnelly): set the background color on the label (crbug.com/244630)
+  prompt_bar->set_background(
       views::Background::CreateSolidBackground(
           ui::GetSigninConfirmationPromptBarColor(
               ui::kSigninConfirmationPromptBarBackgroundAlpha)));
-  AddChildView(prompt_container);
 
-  // Create and add the explanation label.
-  offsets.clear();
+  // Create the explanation label.
+  std::vector<size_t> offsets;
   const string16 learn_more_text =
       l10n_util::GetStringUTF16(
           IDS_ENTERPRISE_SIGNIN_PROFILE_LINK_LEARN_MORE);
@@ -208,17 +197,42 @@
   explanation_label_->AddStyleRange(
       ui::Range(offsets[1], offsets[1] + learn_more_text.size()),
       link_style);
-  // TODO(dconnelly): set the background color on the label (crbug.com/244630)
-  AddChildView(MakeFixedWidth(explanation_label_, kDialogWidth));
-}
 
-void ProfileSigninConfirmationDialogViews::LinkClicked(views::Link* source,
-                                                       int event_flags) {
-  if (delegate_) {
-    delegate_->OnSigninWithNewProfile();
-    delegate_ = NULL;
-  }
-  GetWidget()->Close();
+  // Layout the components.
+  views::GridLayout* dialog_layout = new views::GridLayout(this);
+  SetLayoutManager(dialog_layout);
+
+  // Use GridLayout inside the prompt bar because StyledLabel requires it.
+  views::GridLayout* prompt_layout = views::GridLayout::CreatePanel(prompt_bar);
+  prompt_bar->SetLayoutManager(prompt_layout);
+  prompt_layout->AddColumnSet(0)->AddColumn(
+      views::GridLayout::FILL, views::GridLayout::CENTER, 100,
+      views::GridLayout::USE_PREF, 0, 0);
+  prompt_layout->StartRow(0, 0);
+  prompt_layout->AddView(prompt_label);
+  // Use a column set with no padding.
+  dialog_layout->AddColumnSet(0)->AddColumn(
+      views::GridLayout::FILL, views::GridLayout::FILL, 100,
+      views::GridLayout::USE_PREF, 0, 0);
+  dialog_layout->StartRow(0, 0);
+  dialog_layout->AddView(
+      prompt_bar, 1, 1,
+      views::GridLayout::FILL, views::GridLayout::FILL, 0, 0);
+
+  // Use a new column set for the explanation label so we can add padding.
+  dialog_layout->AddPaddingRow(0.0, views::kPanelVertMargin);
+  views::ColumnSet* explanation_columns = dialog_layout->AddColumnSet(1);
+  explanation_columns->AddPaddingColumn(0.0, views::kButtonHEdgeMarginNew);
+  explanation_columns->AddColumn(
+      views::GridLayout::FILL, views::GridLayout::FILL, 100,
+      views::GridLayout::USE_PREF, 0, 0);
+  explanation_columns->AddPaddingColumn(0.0, views::kButtonHEdgeMarginNew);
+  dialog_layout->StartRow(0, 1);
+  const int kPreferredWidth = 440;
+  dialog_layout->AddView(
+      explanation_label_, 1, 1,
+      views::GridLayout::FILL, views::GridLayout::FILL,
+      kPreferredWidth, explanation_label_->GetHeightForWidth(kPreferredWidth));
 }
 
 void ProfileSigninConfirmationDialogViews::StyledLabelLinkClicked(
@@ -232,3 +246,15 @@
   params.window_action = chrome::NavigateParams::SHOW_WINDOW;
   chrome::Navigate(&params);
 }
+
+void ProfileSigninConfirmationDialogViews::ButtonPressed(
+    views::Button* sender,
+    const ui::Event& event) {
+  DCHECK(prompt_for_new_profile_);
+  DCHECK_EQ(continue_signin_button_, sender);
+  if (delegate_) {
+    delegate_->OnContinueSignin();
+    delegate_ = NULL;
+  }
+  GetWidget()->Close();
+}
diff --git a/chrome/browser/ui/views/sync/profile_signin_confirmation_dialog_views.h b/chrome/browser/ui/views/sync/profile_signin_confirmation_dialog_views.h
index 69193c0..3499cf1 100644
--- a/chrome/browser/ui/views/sync/profile_signin_confirmation_dialog_views.h
+++ b/chrome/browser/ui/views/sync/profile_signin_confirmation_dialog_views.h
@@ -7,6 +7,8 @@
 
 #include "base/compiler_specific.h"
 #include "chrome/browser/ui/sync/profile_signin_confirmation_helper.h"
+#include "ui/views/controls/button/button.h"
+#include "ui/views/controls/button/label_button.h"
 #include "ui/views/controls/link_listener.h"
 #include "ui/views/controls/styled_label_listener.h"
 #include "ui/views/window/dialog_delegate.h"
@@ -25,8 +27,8 @@
 // A tab-modal dialog to allow a user signing in with a managed account
 // to create a new Chrome profile.
 class ProfileSigninConfirmationDialogViews : public views::DialogDelegateView,
-                                             public views::LinkListener,
-                                             public views::StyledLabelListener {
+                                             public views::StyledLabelListener,
+                                             public views::ButtonListener {
  public:
   // Create and show the dialog, which owns itself.
   static void ShowDialog(Browser* browser,
@@ -54,13 +56,13 @@
   virtual void ViewHierarchyChanged(
       const ViewHierarchyChangedDetails& details) OVERRIDE;
 
-  // views::LinkListener:
-  virtual void LinkClicked(views::Link* source, int event_flags) OVERRIDE;
-
   // views::StyledLabelListener:
   virtual void StyledLabelLinkClicked(const ui::Range& range,
                                       int event_flags) OVERRIDE;
 
+  // views::ButtonListener:
+  virtual void ButtonPressed(views::Button*, const ui::Event& event) OVERRIDE;
+
   // Shows the dialog and releases ownership of this object. It will
   // delete itself when the dialog is closed. If |prompt_for_new_profile|
   // is true, the dialog will offer to create a new profile before signin.
@@ -84,8 +86,8 @@
   // Whether the user should be prompted to create a new profile.
   bool prompt_for_new_profile_;
 
-  // The link to create a new profile.
-  views::Link* link_;
+  // The button to continue with signin, if an extra button is required.
+  views::LabelButton* continue_signin_button_;
 
   DISALLOW_COPY_AND_ASSIGN(ProfileSigninConfirmationDialogViews);
 };
diff --git a/chrome/browser/ui/views/tab_contents/render_view_context_menu_views.cc b/chrome/browser/ui/views/tab_contents/render_view_context_menu_views.cc
index 70d6c7b..3349064 100644
--- a/chrome/browser/ui/views/tab_contents/render_view_context_menu_views.cc
+++ b/chrome/browser/ui/views/tab_contents/render_view_context_menu_views.cc
@@ -40,33 +40,16 @@
 }
 #endif  // OS_WIN
 
-void RenderViewContextMenuViews::RunMenuAt(
-    views::Widget* parent,
-    const gfx::Point& point,
-    content::ContextMenuSourceType type) {
+void RenderViewContextMenuViews::RunMenuAt(views::Widget* parent,
+                                           const gfx::Point& point,
+                                           ui::MenuSourceType type) {
   views::MenuItemView::AnchorPosition anchor_position =
-      (type == content::CONTEXT_MENU_SOURCE_TOUCH ||
-          type == content::CONTEXT_MENU_SOURCE_TOUCH_EDIT_MENU) ?
+      (type == ui::MENU_SOURCE_TOUCH ||
+          type == ui::MENU_SOURCE_TOUCH_EDIT_MENU) ?
           views::MenuItemView::BOTTOMCENTER : views::MenuItemView::TOPLEFT;
 
-  // TODO(varunjain): remove this by consolidating ui::MenuSourceType and
-  // content::ContextMenuSourceType.
-  ui::MenuSourceType source_type = ui::MENU_SOURCE_NONE;
-  switch (type) {
-    case content::CONTEXT_MENU_SOURCE_MOUSE:
-      source_type = ui::MENU_SOURCE_MOUSE;
-      break;
-    case content::CONTEXT_MENU_SOURCE_KEYBOARD:
-      source_type = ui::MENU_SOURCE_KEYBOARD;
-      break;
-    case content::CONTEXT_MENU_SOURCE_TOUCH:
-      source_type = ui::MENU_SOURCE_TOUCH;
-      break;
-    default:
-      break;
-  }
   if (menu_runner_->RunMenuAt(parent, NULL, gfx::Rect(point, gfx::Size()),
-      anchor_position, source_type, views::MenuRunner::HAS_MNEMONICS |
+      anchor_position, type, views::MenuRunner::HAS_MNEMONICS |
           views::MenuRunner::CONTEXT_MENU) ==
       views::MenuRunner::MENU_DELETED)
     return;
diff --git a/chrome/browser/ui/views/tab_contents/render_view_context_menu_views.h b/chrome/browser/ui/views/tab_contents/render_view_context_menu_views.h
index 05b81e8..0b58ee1 100644
--- a/chrome/browser/ui/views/tab_contents/render_view_context_menu_views.h
+++ b/chrome/browser/ui/views/tab_contents/render_view_context_menu_views.h
@@ -9,7 +9,7 @@
 #include "base/memory/scoped_vector.h"
 #include "base/strings/string16.h"
 #include "chrome/browser/tab_contents/render_view_context_menu.h"
-#include "content/public/common/context_menu_source_type.h"
+#include "ui/base/ui_base_types.h"
 
 namespace gfx {
 class Point;
@@ -31,7 +31,7 @@
 
   void RunMenuAt(views::Widget* parent,
                  const gfx::Point& point,
-                 content::ContextMenuSourceType type);
+                 ui::MenuSourceType type);
 
   // RenderViewContextMenuDelegate implementation.
   virtual void UpdateMenuItem(int command_id,
diff --git a/chrome/browser/ui/views/tab_contents/web_drag_bookmark_handler_win.cc b/chrome/browser/ui/views/tab_contents/web_drag_bookmark_handler_win.cc
index d63d1b5..474235b 100644
--- a/chrome/browser/ui/views/tab_contents/web_drag_bookmark_handler_win.cc
+++ b/chrome/browser/ui/views/tab_contents/web_drag_bookmark_handler_win.cc
@@ -12,9 +12,9 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/url_constants.h"
 #include "content/public/browser/web_contents.h"
+#include "content/public/common/drop_data.h"
 #include "ui/base/dragdrop/os_exchange_data.h"
 #include "ui/base/dragdrop/os_exchange_data_provider_win.h"
-#include "webkit/common/webdropdata.h"
 
 using content::WebContents;
 
@@ -92,7 +92,7 @@
   }
 }
 
-bool WebDragBookmarkHandlerWin::AddDragData(const WebDropData& drop_data,
+bool WebDragBookmarkHandlerWin::AddDragData(const content::DropData& drop_data,
                                             ui::OSExchangeData* data) {
   if (!drop_data.url.SchemeIs(chrome::kJavaScriptScheme))
     return false;
diff --git a/chrome/browser/ui/views/tab_contents/web_drag_bookmark_handler_win.h b/chrome/browser/ui/views/tab_contents/web_drag_bookmark_handler_win.h
index 06460fd..404044a 100644
--- a/chrome/browser/ui/views/tab_contents/web_drag_bookmark_handler_win.h
+++ b/chrome/browser/ui/views/tab_contents/web_drag_bookmark_handler_win.h
@@ -28,7 +28,7 @@
   virtual void OnDragEnter(IDataObject* data_object) OVERRIDE;
   virtual void OnDrop(IDataObject* data_object) OVERRIDE;
   virtual void OnDragLeave(IDataObject* data_object) OVERRIDE;
-  virtual bool AddDragData(const WebDropData& drop_data,
+  virtual bool AddDragData(const content::DropData& drop_data,
                            ui::OSExchangeData* data) OVERRIDE;
 
  private:
diff --git a/chrome/browser/ui/views/tabs/dragged_tab_view.cc b/chrome/browser/ui/views/tabs/dragged_tab_view.cc
index d95d9da..9c5e19f 100644
--- a/chrome/browser/ui/views/tabs/dragged_tab_view.cc
+++ b/chrome/browser/ui/views/tabs/dragged_tab_view.cc
@@ -42,7 +42,7 @@
 
   container_.reset(new views::Widget);
   views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP);
-  params.transparent = true;
+  params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
   params.keep_on_top = true;
   params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
   params.bounds = gfx::Rect(PreferredContainerSize());
diff --git a/chrome/browser/ui/views/tabs/native_view_photobooth_win.cc b/chrome/browser/ui/views/tabs/native_view_photobooth_win.cc
index c9f8f77..132b895 100644
--- a/chrome/browser/ui/views/tabs/native_view_photobooth_win.cc
+++ b/chrome/browser/ui/views/tabs/native_view_photobooth_win.cc
@@ -36,7 +36,7 @@
   return gfx::Point(point.x() - 1, point.y() - 1);
 }
 
-}
+}  // namespace
 
 ///////////////////////////////////////////////////////////////////////////////
 // NativeViewPhotoboothWin, public:
@@ -152,7 +152,7 @@
                            contents_rect.bottom - contents_rect.top);
   capture_window_ = new views::Widget;
   views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP);
-  params.transparent = true;
+  params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
   params.bounds = capture_bounds;
   capture_window_->Init(params);
   // If the capture window isn't visible, blitting from the WebContents's
diff --git a/chrome/browser/ui/views/tabs/tab.cc b/chrome/browser/ui/views/tabs/tab.cc
index acfb5c5..3100357 100644
--- a/chrome/browser/ui/views/tabs/tab.cc
+++ b/chrome/browser/ui/views/tabs/tab.cc
@@ -17,6 +17,7 @@
 #include "chrome/browser/ui/view_ids.h"
 #include "chrome/browser/ui/views/tabs/tab_controller.h"
 #include "chrome/browser/ui/views/theme_image_mapper.h"
+#include "chrome/browser/ui/views/touch_uma/touch_uma.h"
 #include "chrome/common/chrome_switches.h"
 #include "grit/generated_resources.h"
 #include "grit/theme_resources.h"
@@ -457,6 +458,7 @@
       immersive_loading_step_(0),
       should_display_crashed_favicon_(false),
       theme_provider_(NULL),
+      tab_activated_with_last_gesture_begin_(false),
       hover_controller_(this),
       showing_icon_(false),
       showing_close_button_(false),
@@ -711,6 +713,8 @@
       CLOSE_TAB_FROM_TOUCH;
   DCHECK_EQ(close_button_, sender);
   controller()->CloseTab(this, source);
+  if (event.type() == ui::ET_GESTURE_TAP)
+    TouchUMA::RecordGestureAction(TouchUMA::GESTURE_TABCLOSE_TAP);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -1028,6 +1032,7 @@
                                        parent());
       ui::ListSelectionModel original_selection;
       original_selection.Copy(controller()->GetSelectionModel());
+      tab_activated_with_last_gesture_begin_ = !IsActive();
       if (!IsSelected())
         controller()->SelectTab(this);
       gfx::Point loc(event->location());
diff --git a/chrome/browser/ui/views/tabs/tab.h b/chrome/browser/ui/views/tabs/tab.h
index 91ddca8..534091f 100644
--- a/chrome/browser/ui/views/tabs/tab.h
+++ b/chrome/browser/ui/views/tabs/tab.h
@@ -100,6 +100,14 @@
     background_offset_ = offset;
   }
 
+  // Returns true if this tab became the active tab selected in
+  // response to the last ui::ET_GESTURE_BEGIN gesture dispatched to
+  // this tab. Only used for collecting UMA metrics.
+  // See ash/touch/touch_uma.cc.
+  bool tab_activated_with_last_gesture_begin() const {
+    return tab_activated_with_last_gesture_begin_;
+  }
+
   views::GlowHoverController* hover_controller() {
     return &hover_controller_;
   }
@@ -320,6 +328,8 @@
 
   ui::ThemeProvider* theme_provider_;
 
+  bool tab_activated_with_last_gesture_begin_;
+
   views::GlowHoverController hover_controller_;
 
   // The bounds of various sections of the display.
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller.cc b/chrome/browser/ui/views/tabs/tab_drag_controller.cc
index f36b867..3b432ce 100644
--- a/chrome/browser/ui/views/tabs/tab_drag_controller.cc
+++ b/chrome/browser/ui/views/tabs/tab_drag_controller.cc
@@ -254,7 +254,7 @@
         in_enable_area_(info.in_enable_area()) {
     popup_ = new views::Widget;
     views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP);
-    params.transparent = true;
+    params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
     params.keep_on_top = true;
     params.bounds = info.GetPopupRect();
     popup_->Init(params);
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller.h b/chrome/browser/ui/views/tabs/tab_drag_controller.h
index 7b6fbbc..7323976 100644
--- a/chrome/browser/ui/views/tabs/tab_drag_controller.h
+++ b/chrome/browser/ui/views/tabs/tab_drag_controller.h
@@ -9,7 +9,7 @@
 
 #include "base/memory/scoped_ptr.h"
 #include "base/message_loop.h"
-#include "base/timer.h"
+#include "base/timer/timer.h"
 #include "chrome/browser/ui/tabs/dock_info.h"
 #include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
 #include "chrome/browser/ui/views/tabs/tab_strip_types.h"
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
index da53034..f1e896a 100644
--- a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
+++ b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
@@ -1323,7 +1323,7 @@
       second_root).work_area();
   work_area.Inset(20,20,20,60);
   Browser::CreateParams params(browser()->profile(),
-                               chrome::HOST_DESKTOP_TYPE_NATIVE);
+                               browser()->host_desktop_type());
   params.initial_show_state = ui::SHOW_STATE_NORMAL;
   params.initial_bounds = work_area;
   Browser* browser2 = new Browser(params);
diff --git a/chrome/browser/ui/views/tabs/tab_strip.cc b/chrome/browser/ui/views/tabs/tab_strip.cc
index 68fede9..e0356c8 100644
--- a/chrome/browser/ui/views/tabs/tab_strip.cc
+++ b/chrome/browser/ui/views/tabs/tab_strip.cc
@@ -25,6 +25,7 @@
 #include "chrome/browser/ui/views/tabs/tab_drag_controller.h"
 #include "chrome/browser/ui/views/tabs/tab_strip_controller.h"
 #include "chrome/browser/ui/views/tabs/tab_strip_observer.h"
+#include "chrome/browser/ui/views/touch_uma/touch_uma.h"
 #include "content/public/browser/user_metrics.h"
 #include "grit/generated_resources.h"
 #include "grit/theme_resources.h"
@@ -1495,6 +1496,8 @@
     UMA_HISTOGRAM_ENUMERATION("Tab.NewTab", TabStripModel::NEW_TAB_BUTTON,
                               TabStripModel::NEW_TAB_ENUM_COUNT);
     controller()->CreateNewTab();
+    if (event.type() == ui::ET_GESTURE_TAP)
+      TouchUMA::RecordGestureAction(TouchUMA::GESTURE_NEWTAB_TAP);
   }
 }
 
@@ -1583,6 +1586,17 @@
       EndDrag(END_DRAG_CANCEL);
       break;
 
+    case ui::ET_GESTURE_TAP: {
+      const int active_index = controller_->GetActiveIndex();
+      DCHECK_NE(-1, active_index);
+      Tab* active_tab = tab_at(active_index);
+      TouchUMA::GestureActionType action = TouchUMA::GESTURE_TABNOSWITCH_TAP;
+      if (active_tab->tab_activated_with_last_gesture_begin())
+        action = TouchUMA::GESTURE_TABSWITCH_TAP;
+      TouchUMA::RecordGestureAction(action);
+      break;
+    }
+
     default:
       break;
   }
@@ -2401,7 +2415,7 @@
   arrow_window = new views::Widget;
   views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP);
   params.keep_on_top = true;
-  params.transparent = true;
+  params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
   params.accept_events = false;
   params.can_activate = false;
   params.bounds = gfx::Rect(drop_indicator_width, drop_indicator_height);
diff --git a/chrome/browser/ui/views/tabs/tab_strip.h b/chrome/browser/ui/views/tabs/tab_strip.h
index 8f44c6f..a78cff7 100644
--- a/chrome/browser/ui/views/tabs/tab_strip.h
+++ b/chrome/browser/ui/views/tabs/tab_strip.h
@@ -9,7 +9,7 @@
 
 #include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
-#include "base/timer.h"
+#include "base/timer/timer.h"
 #include "chrome/browser/ui/tabs/tab_strip_layout_type.h"
 #include "chrome/browser/ui/views/tabs/tab.h"
 #include "chrome/browser/ui/views/tabs/tab_controller.h"
diff --git a/chrome/browser/ui/views/task_manager_view.cc b/chrome/browser/ui/views/task_manager_view.cc
index 183a2b4..65195cd 100644
--- a/chrome/browser/ui/views/task_manager_view.cc
+++ b/chrome/browser/ui/views/task_manager_view.cc
@@ -29,7 +29,6 @@
 #include "ui/base/models/table_model.h"
 #include "ui/base/models/table_model_observer.h"
 #include "ui/gfx/canvas.h"
-#include "ui/views/background.h"
 #include "ui/views/context_menu_controller.h"
 #include "ui/views/controls/button/label_button.h"
 #include "ui/views/controls/link.h"
@@ -38,7 +37,6 @@
 #include "ui/views/controls/table/table_grouper.h"
 #include "ui/views/controls/table/table_view.h"
 #include "ui/views/controls/table/table_view_observer.h"
-#include "ui/views/controls/table/table_view_row_background_painter.h"
 #include "ui/views/layout/layout_constants.h"
 #include "ui/views/widget/widget.h"
 #include "ui/views/window/dialog_delegate.h"
@@ -51,10 +49,6 @@
 #include "win8/util/win8_util.h"
 #endif
 
-// Yellow highlight used when highlighting background resources.
-static const SkColor kBackgroundResourceHighlight =
-    SkColorSetRGB(0xff, 0xf1, 0xcd);
-
 namespace {
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -93,9 +87,6 @@
   virtual void OnItemsAdded(int start, int length) OVERRIDE;
   virtual void OnItemsRemoved(int start, int length) OVERRIDE;
 
-  // Returns true if resource corresponding to |row| is a background resource.
-  bool IsBackgroundResource(int row);
-
  private:
   TaskManagerModel* model_;
   ui::TableModelObserver* observer_;
@@ -170,28 +161,6 @@
   OnModelChanged();
 }
 
-bool TaskManagerTableModel::IsBackgroundResource(int row) {
-  return model_->IsBackgroundResource(row);
-}
-
-class BackgroundPainter : public views::TableViewRowBackgroundPainter {
- public:
-  explicit BackgroundPainter(TaskManagerTableModel* model) : model_(model) {}
-  virtual ~BackgroundPainter() {}
-
-  virtual void PaintRowBackground(int model_index,
-                                  const gfx::Rect& row_bounds,
-                                  gfx::Canvas* canvas) OVERRIDE {
-    if (model_->IsBackgroundResource(model_index))
-      canvas->FillRect(row_bounds, kBackgroundResourceHighlight);
-  }
-
- private:
-  TaskManagerTableModel* model_;
-
-  DISALLOW_COPY_AND_ASSIGN(BackgroundPainter);
-};
-
 // The Task manager UI container.
 class TaskManagerView : public views::ButtonListener,
                         public views::DialogDelegateView,
@@ -200,14 +169,11 @@
                         public views::ContextMenuController,
                         public ui::SimpleMenuModel::Delegate {
  public:
-  TaskManagerView(bool highlight_background_resources,
-                  chrome::HostDesktopType desktop_type);
+  explicit TaskManagerView(chrome::HostDesktopType desktop_type);
   virtual ~TaskManagerView();
 
-  // Shows the Task manager window, or re-activates an existing one. If
-  // |highlight_background_resources| is true, highlights the background
-  // resources in the resource display.
-  static void Show(bool highlight_background_resources, Browser* browser);
+  // Shows the Task manager window, or re-activates an existing one.
+  static void Show(Browser* browser);
 
   // views::View:
   virtual void Layout() OVERRIDE;
@@ -288,9 +254,6 @@
   // True when the Task Manager window should be shown on top of other windows.
   bool is_always_on_top_;
 
-  // True when the Task Manager should highlight background resources.
-  const bool highlight_background_resources_;
-
   // The host desktop type this task manager belongs to.
   const chrome::HostDesktopType desktop_type_;
 
@@ -310,8 +273,7 @@
 TaskManagerView* TaskManagerView::instance_ = NULL;
 
 
-TaskManagerView::TaskManagerView(bool highlight_background_resources,
-                                 chrome::HostDesktopType desktop_type)
+TaskManagerView::TaskManagerView(chrome::HostDesktopType desktop_type)
     : purge_memory_button_(NULL),
       kill_button_(NULL),
       about_memory_link_(NULL),
@@ -320,7 +282,6 @@
       task_manager_(TaskManager::GetInstance()),
       model_(TaskManager::GetInstance()->model()),
       is_always_on_top_(false),
-      highlight_background_resources_(highlight_background_resources),
       desktop_type_(desktop_type) {
   Init();
 }
@@ -394,12 +355,6 @@
   tab_table_ = new views::TableView(
       table_model_.get(), columns_, views::ICON_AND_TEXT, false);
   tab_table_->SetGrouper(table_model_.get());
-  if (highlight_background_resources_) {
-    scoped_ptr<BackgroundPainter> painter(
-        new BackgroundPainter(table_model_.get()));
-    tab_table_->SetRowBackgroundPainter(
-        painter.PassAs<views::TableViewRowBackgroundPainter>());
-  }
 
   // Hide some columns by default
   tab_table_->SetColumnVisibility(IDS_TASK_MANAGER_PROFILE_NAME_COLUMN, false);
@@ -529,8 +484,7 @@
 }
 
 // static
-void TaskManagerView::Show(bool highlight_background_resources,
-                           Browser* browser) {
+void TaskManagerView::Show(Browser* browser) {
 #if defined(OS_WIN)
   // In Windows Metro it's not good to open this native window.
   DCHECK(!win8::IsSingleWindowMetroMode());
@@ -541,17 +495,11 @@
       browser ? browser->host_desktop_type() : chrome::HOST_DESKTOP_TYPE_ASH;
 
   if (instance_) {
-    if (instance_->highlight_background_resources_ !=
-        highlight_background_resources ||
-        instance_->desktop_type_ != desktop_type) {
-      instance_->GetWidget()->Close();
-    } else {
-      // If there's a Task manager window open already, just activate it.
-      instance_->GetWidget()->Activate();
-      return;
-    }
+    // If there's a Task manager window open already, just activate it.
+    instance_->GetWidget()->Activate();
+    return;
   }
-  instance_ = new TaskManagerView(highlight_background_resources, desktop_type);
+  instance_ = new TaskManagerView(desktop_type);
   gfx::NativeWindow window =
       browser ? browser->window()->GetNativeWindow() : NULL;
 #if defined(USE_ASH)
@@ -779,8 +727,8 @@
 namespace chrome {
 
 // Declared in browser_dialogs.h so others don't need to depend on our header.
-void ShowTaskManager(Browser* browser, bool highlight_background_resources) {
-  TaskManagerView::Show(highlight_background_resources, browser);
+void ShowTaskManager(Browser* browser) {
+  TaskManagerView::Show(browser);
 }
 
 }  // namespace chrome
diff --git a/chrome/browser/ui/views/touch_uma/touch_uma.cc b/chrome/browser/ui/views/touch_uma/touch_uma.cc
new file mode 100644
index 0000000..d6dc3f8
--- /dev/null
+++ b/chrome/browser/ui/views/touch_uma/touch_uma.cc
@@ -0,0 +1,9 @@
+// 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/ui/views/touch_uma/touch_uma.h"
+
+// static
+void TouchUMA::RecordGestureAction(GestureActionType action) {
+}
diff --git a/chrome/browser/ui/views/touch_uma/touch_uma.h b/chrome/browser/ui/views/touch_uma/touch_uma.h
new file mode 100644
index 0000000..34e950b
--- /dev/null
+++ b/chrome/browser/ui/views/touch_uma/touch_uma.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 CHROME_BROWSER_UI_VIEWS_TOUCH_UMA_TOUCH_UMA_H_
+#define CHROME_BROWSER_UI_VIEWS_TOUCH_UMA_TOUCH_UMA_H_
+
+#include "base/basictypes.h"
+
+class TouchUMA {
+ public:
+  enum GestureActionType {
+    GESTURE_TABSWITCH_TAP,
+    GESTURE_TABNOSWITCH_TAP,
+    GESTURE_TABCLOSE_TAP,
+    GESTURE_NEWTAB_TAP,
+    GESTURE_ROOTVIEWTOP_TAP,
+  };
+
+  static void RecordGestureAction(GestureActionType action);
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(TouchUMA);
+};
+
+#endif  // CHROME_BROWSER_UI_VIEWS_TOUCH_UMA_TOUCH_UMA_H_
diff --git a/chrome/browser/ui/views/touch_uma/touch_uma_ash.cc b/chrome/browser/ui/views/touch_uma/touch_uma_ash.cc
new file mode 100644
index 0000000..14fc5d3
--- /dev/null
+++ b/chrome/browser/ui/views/touch_uma/touch_uma_ash.cc
@@ -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.
+
+#include "chrome/browser/ui/views/touch_uma/touch_uma.h"
+
+#include "ash/touch/touch_uma.h"
+
+// static
+void TouchUMA::RecordGestureAction(GestureActionType action) {
+  ash::TouchUMA::GestureActionType type = ash::TouchUMA::GESTURE_UNKNOWN;
+  switch (action) {
+    case GESTURE_TABSWITCH_TAP:
+      type = ash::TouchUMA::GESTURE_TABSWITCH_TAP;
+      break;
+    case GESTURE_TABNOSWITCH_TAP:
+      type = ash::TouchUMA::GESTURE_TABNOSWITCH_TAP;
+      break;
+    case GESTURE_TABCLOSE_TAP:
+      type = ash::TouchUMA::GESTURE_TABCLOSE_TAP;
+      break;
+    case GESTURE_NEWTAB_TAP:
+      type = ash::TouchUMA::GESTURE_NEWTAB_TAP;
+      break;
+    case GESTURE_ROOTVIEWTOP_TAP:
+      type = ash::TouchUMA::GESTURE_ROOTVIEWTOP_TAP;
+      break;
+  }
+  ash::TouchUMA::GetInstance()->RecordGestureAction(type);
+}
diff --git a/chrome/browser/ui/views/website_settings/website_settings_popup_view.cc b/chrome/browser/ui/views/website_settings/website_settings_popup_view.cc
index c17ed02..b2cc59f 100644
--- a/chrome/browser/ui/views/website_settings/website_settings_popup_view.cc
+++ b/chrome/browser/ui/views/website_settings/website_settings_popup_view.cc
@@ -310,7 +310,7 @@
   layout->AddView(header_);
 
   layout->AddPaddingRow(1, kHeaderMarginBottom);
-  tabbed_pane_ = new views::TabbedPane();
+  tabbed_pane_ = new views::TabbedPane(false);
   layout->StartRow(1, content_column);
   layout->AddView(tabbed_pane_);
   // Tabs must be added after the tabbed_pane_ was added to the views
diff --git a/chrome/browser/ui/web_applications/web_app_ui.cc b/chrome/browser/ui/web_applications/web_app_ui.cc
index edd4570..b83cbd5 100644
--- a/chrome/browser/ui/web_applications/web_app_ui.cc
+++ b/chrome/browser/ui/web_applications/web_app_ui.cc
@@ -43,6 +43,7 @@
 #if defined(OS_WIN)
 #include "base/win/shortcut.h"
 #include "base/win/windows_version.h"
+#include "chrome/browser/web_applications/web_app_win.h"
 #include "ui/gfx/icon_util.h"
 #endif
 
@@ -184,11 +185,13 @@
     return;
   }
 
+  int preferred_size = std::max(unprocessed_icons_.back().width,
+                                unprocessed_icons_.back().height);
   web_contents_->DownloadImage(
       unprocessed_icons_.back().url,
       true,  // favicon
-      std::max(unprocessed_icons_.back().width,
-               unprocessed_icons_.back().height),
+      preferred_size,
+      0,  // no maximum size
       base::Bind(&UpdateShortcutWorker::DidDownloadFavicon,
                  base::Unretained(this)));
   unprocessed_icons_.pop_back();
diff --git a/chrome/browser/ui/website_settings/website_settings.h b/chrome/browser/ui/website_settings/website_settings.h
index bb423dd..89712b4 100644
--- a/chrome/browser/ui/website_settings/website_settings.h
+++ b/chrome/browser/ui/website_settings/website_settings.h
@@ -7,7 +7,7 @@
 
 #include "base/memory/scoped_ptr.h"
 #include "base/strings/string16.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/common/cancelable_request.h"
 #include "chrome/browser/content_settings/tab_specific_content_settings.h"
 #include "chrome/browser/history/history_service.h"
diff --git a/chrome/browser/ui/webui/app_launcher_page_ui.cc b/chrome/browser/ui/webui/app_launcher_page_ui.cc
index f8cc98e..1a2b32e 100644
--- a/chrome/browser/ui/webui/app_launcher_page_ui.cc
+++ b/chrome/browser/ui/webui/app_launcher_page_ui.cc
@@ -4,7 +4,9 @@
 
 #include "chrome/browser/ui/webui/app_launcher_page_ui.h"
 
+#include "apps/app_launcher.h"
 #include "base/memory/ref_counted_memory.h"
+#include "base/metrics/histogram.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/webui/ntp/app_launcher_handler.h"
 #include "chrome/browser/ui/webui/ntp/app_resource_cache_factory.h"
@@ -109,6 +111,16 @@
   scoped_refptr<base::RefCountedMemory> html_bytes(
       resource->GetNewTabHTML(is_incognito));
 
+  if (!is_incognito) {
+    if (apps::IsAppLauncherEnabled()) {
+      AppLauncherHandler::RecordAppLauncherPromoHistogram(
+          apps::APP_LAUNCHER_PROMO_ALREADY_INSTALLED);
+    } else if (apps::ShouldShowAppLauncherPromo()){
+      AppLauncherHandler::RecordAppLauncherPromoHistogram(
+          apps::APP_LAUNCHER_PROMO_SHOWN);
+    }
+  }
+
   callback.Run(html_bytes.get());
 }
 
diff --git a/chrome/browser/ui/webui/bidi_checker_web_ui_test.cc b/chrome/browser/ui/webui/bidi_checker_web_ui_test.cc
index 09d7e16..18b2888 100644
--- a/chrome/browser/ui/webui/bidi_checker_web_ui_test.cc
+++ b/chrome/browser/ui/webui/bidi_checker_web_ui_test.cc
@@ -12,7 +12,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/threading/platform_thread.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "base/values.h"
 #include "chrome/browser/autofill/personal_data_manager_factory.h"
 #include "chrome/browser/history/history_service.h"
@@ -22,9 +22,9 @@
 #include "chrome/browser/ui/browser.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/test/base/ui_test_utils.h"
-#include "components/autofill/browser/autofill_common_test.h"
-#include "components/autofill/browser/autofill_profile.h"
-#include "components/autofill/browser/personal_data_manager.h"
+#include "components/autofill/core/browser/autofill_common_test.h"
+#include "components/autofill/core/browser/autofill_profile.h"
+#include "components/autofill/core/browser/personal_data_manager.h"
 #include "content/public/browser/browser_thread.h"
 #include "ui/base/resource/resource_bundle.h"
 
diff --git a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
index 68d4fcc..4bcecf7 100644
--- a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
+++ b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
@@ -72,6 +72,10 @@
 #include "chrome/browser/ui/webui/policy_ui.h"
 #endif
 
+#if defined(ENABLE_WEBRTC)
+#include "chrome/browser/ui/webui/media/webrtc_logs_ui.h"
+#endif
+
 #if defined(OS_ANDROID)
 #include "chrome/browser/ui/webui/welcome_ui_android.h"
 #else
@@ -96,6 +100,7 @@
 #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
 #include "chrome/browser/ui/webui/chromeos/mobile_setup_ui.h"
 #include "chrome/browser/ui/webui/chromeos/proxy_settings_ui.h"
+#include "chrome/browser/ui/webui/chromeos/salsa_ui.h"
 #include "chrome/browser/ui/webui/chromeos/sim_unlock_ui.h"
 #include "chrome/browser/ui/webui/chromeos/system_info_ui.h"
 #endif
@@ -107,7 +112,7 @@
 #endif
 
 #if !defined(OS_CHROMEOS) && !defined(OS_ANDROID)
-#include "chrome/browser/ui/webui/sync_promo/sync_promo_ui.h"
+#include "chrome/browser/ui/sync/sync_promo_ui.h"
 #endif
 
 #if defined(OS_WIN)
@@ -250,6 +255,10 @@
     return &NewWebUI<UserActionsUI>;
   if (url.host() == chrome::kChromeUIVersionHost)
     return &NewWebUI<VersionUI>;
+#if defined(ENABLE_WEBRTC)
+  if (url.host() == chrome::kChromeUIWebRtcLogsHost)
+    return &NewWebUI<WebRtcLogsUI>;
+#endif
 
   /****************************************************************************
    * OS Specific #defines
@@ -341,6 +350,8 @@
     return &NewWebUI<chromeos::OobeUI>;
   if (url.host() == chrome::kChromeUIProxySettingsHost)
     return &NewWebUI<chromeos::ProxySettingsUI>;
+  if (url.host() == chrome::kChromeUISalsaHost)
+    return &NewWebUI<SalsaUI>;
   if (url.host() == chrome::kChromeUISimUnlockHost)
     return &NewWebUI<chromeos::SimUnlockUI>;
   if (url.host() == chrome::kChromeUISystemInfoHost)
diff --git a/chrome/browser/ui/webui/chromeos/drive_internals_ui.cc b/chrome/browser/ui/webui/chromeos/drive_internals_ui.cc
index 0ef48ea..498ecf7 100644
--- a/chrome/browser/ui/webui/chromeos/drive_internals_ui.cc
+++ b/chrome/browser/ui/webui/chromeos/drive_internals_ui.cc
@@ -22,14 +22,14 @@
 #include "chrome/browser/chromeos/drive/file_system_util.h"
 #include "chrome/browser/chromeos/drive/job_list.h"
 #include "chrome/browser/chromeos/drive/logging.h"
+#include "chrome/browser/drive/drive_api_util.h"
 #include "chrome/browser/drive/drive_notification_manager.h"
 #include "chrome/browser/drive/drive_notification_manager_factory.h"
 #include "chrome/browser/drive/drive_service_interface.h"
+#include "chrome/browser/drive/drive_switches.h"
+#include "chrome/browser/drive/event_logger.h"
 #include "chrome/browser/google_apis/auth_service.h"
 #include "chrome/browser/google_apis/drive_api_parser.h"
-#include "chrome/browser/google_apis/drive_api_util.h"
-#include "chrome/browser/google_apis/drive_switches.h"
-#include "chrome/browser/google_apis/event_logger.h"
 #include "chrome/browser/google_apis/gdata_errorcode.h"
 #include "chrome/browser/google_apis/gdata_wapi_parser.h"
 #include "chrome/browser/google_apis/time_util.h"
@@ -209,11 +209,11 @@
   void UpdateDriveRelatedFlagsSection();
   void UpdateDriveRelatedPreferencesSection();
   void UpdateAuthStatusSection(
-      google_apis::DriveServiceInterface* drive_service);
+      drive::DriveServiceInterface* drive_service);
   void UpdateAboutResourceSection(
-      google_apis::DriveServiceInterface* drive_service);
+      drive::DriveServiceInterface* drive_service);
   void UpdateAppListSection(
-      google_apis::DriveServiceInterface* drive_service);
+      drive::DriveServiceInterface* drive_service);
   void UpdateLocalMetadataSection(
       drive::DebugInfoCollector* debug_info_collector);
   void UpdateDeltaUpdateStatusSection(
@@ -238,7 +238,6 @@
   // Called when ReadDirectoryByPath() is complete.
   void OnReadDirectoryByPath(const base::FilePath& parent_path,
                              drive::FileError error,
-                             bool hide_hosted_documents,
                              scoped_ptr<drive::ResourceEntryVector> entries);
 
   // Called as the iterator for DebugInfoCollector::IterateFileCache().
@@ -375,7 +374,7 @@
   if (!integration_service)
     return;
 
-  google_apis::DriveServiceInterface* drive_service =
+  drive::DriveServiceInterface* drive_service =
       integration_service->drive_service();
   DCHECK(drive_service);
   drive::DebugInfoCollector* debug_info_collector =
@@ -406,7 +405,7 @@
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
 
   const char* kDriveRelatedFlags[] = {
-    google_apis::switches::kEnableDriveV2Api,
+    drive::switches::kEnableDriveV2Api,
     chromeos::switches::kDisableDrive,
   };
 
@@ -454,7 +453,7 @@
 }
 
 void DriveInternalsWebUIHandler::UpdateAuthStatusSection(
-    google_apis::DriveServiceInterface* drive_service) {
+    drive::DriveServiceInterface* drive_service) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   DCHECK(drive_service);
 
@@ -467,7 +466,7 @@
 }
 
 void DriveInternalsWebUIHandler::UpdateAboutResourceSection(
-    google_apis::DriveServiceInterface* drive_service) {
+    drive::DriveServiceInterface* drive_service) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   DCHECK(drive_service);
 
@@ -477,7 +476,7 @@
 }
 
 void DriveInternalsWebUIHandler::UpdateAppListSection(
-    google_apis::DriveServiceInterface* drive_service) {
+    drive::DriveServiceInterface* drive_service) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   DCHECK(drive_service);
 
@@ -550,8 +549,8 @@
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
 
   Profile* profile = Profile::FromWebUI(web_ui());
-  google_apis::DriveNotificationManager* drive_notification_manager =
-      google_apis::DriveNotificationManagerFactory::GetForProfile(profile);
+  drive::DriveNotificationManager* drive_notification_manager =
+      drive::DriveNotificationManagerFactory::GetForProfile(profile);
   if (!drive_notification_manager)
     return;
 
@@ -674,7 +673,7 @@
 void DriveInternalsWebUIHandler::UpdateEventLogSection() {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
 
-  const std::vector<google_apis::EventLogger::Event> log =
+  const std::vector<drive::EventLogger::Event> log =
       drive::util::GetLogHistory();
 
   base::ListValue list;
@@ -722,7 +721,6 @@
 void DriveInternalsWebUIHandler::OnReadDirectoryByPath(
     const base::FilePath& parent_path,
     drive::FileError error,
-    bool hide_hosted_documents,
     scoped_ptr<drive::ResourceEntryVector> entries) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
 
diff --git a/chrome/browser/ui/webui/chromeos/keyboard_overlay_ui.cc b/chrome/browser/ui/webui/chromeos/keyboard_overlay_ui.cc
index 64cba4f..a768034 100644
--- a/chrome/browser/ui/webui/chromeos/keyboard_overlay_ui.cc
+++ b/chrome/browser/ui/webui/chromeos/keyboard_overlay_ui.cc
@@ -62,19 +62,6 @@
 } kI18nContentToMessage[] = {
   { "keyboardOverlayLearnMore", IDS_KEYBOARD_OVERLAY_LEARN_MORE },
   { "keyboardOverlayTitle", IDS_KEYBOARD_OVERLAY_TITLE },
-  { "keyboardOverlayF1", IDS_KEYBOARD_OVERLAY_F1 },
-  { "keyboardOverlayF2", IDS_KEYBOARD_OVERLAY_F2 },
-  { "keyboardOverlayF3", IDS_KEYBOARD_OVERLAY_F3 },
-  { "keyboardOverlayF4", IDS_KEYBOARD_OVERLAY_F4 },
-  { "keyboardOverlayF5", IDS_KEYBOARD_OVERLAY_F5 },
-  { "keyboardOverlayF6", IDS_KEYBOARD_OVERLAY_F6 },
-  { "keyboardOverlayF7", IDS_KEYBOARD_OVERLAY_F7 },
-  { "keyboardOverlayF8", IDS_KEYBOARD_OVERLAY_F8 },
-  { "keyboardOverlayF9", IDS_KEYBOARD_OVERLAY_F9 },
-  { "keyboardOverlayF10", IDS_KEYBOARD_OVERLAY_F10 },
-  { "keyboardOverlayF11", IDS_KEYBOARD_OVERLAY_F11 },
-  { "keyboardOverlayF12", IDS_KEYBOARD_OVERLAY_F12 },
-  { "keyboardOverlayInsert", IDS_KEYBOARD_OVERLAY_INSERT },
   { "keyboardOverlayInstructions", IDS_KEYBOARD_OVERLAY_INSTRUCTIONS },
   { "keyboardOverlayInstructionsHide", IDS_KEYBOARD_OVERLAY_INSTRUCTIONS_HIDE },
   { "keyboardOverlayActivateLastLauncherItem",
@@ -132,6 +119,18 @@
   { "keyboardOverlayDomInspector", IDS_KEYBOARD_OVERLAY_DOM_INSPECTOR },
   { "keyboardOverlayDownloads", IDS_KEYBOARD_OVERLAY_DOWNLOADS },
   { "keyboardOverlayEnd", IDS_KEYBOARD_OVERLAY_END },
+  { "keyboardOverlayF1", IDS_KEYBOARD_OVERLAY_F1 },
+  { "keyboardOverlayF10", IDS_KEYBOARD_OVERLAY_F10 },
+  { "keyboardOverlayF11", IDS_KEYBOARD_OVERLAY_F11 },
+  { "keyboardOverlayF12", IDS_KEYBOARD_OVERLAY_F12 },
+  { "keyboardOverlayF2", IDS_KEYBOARD_OVERLAY_F2 },
+  { "keyboardOverlayF3", IDS_KEYBOARD_OVERLAY_F3 },
+  { "keyboardOverlayF4", IDS_KEYBOARD_OVERLAY_F4 },
+  { "keyboardOverlayF5", IDS_KEYBOARD_OVERLAY_F5 },
+  { "keyboardOverlayF6", IDS_KEYBOARD_OVERLAY_F6 },
+  { "keyboardOverlayF7", IDS_KEYBOARD_OVERLAY_F7 },
+  { "keyboardOverlayF8", IDS_KEYBOARD_OVERLAY_F8 },
+  { "keyboardOverlayF9", IDS_KEYBOARD_OVERLAY_F9 },
   { "keyboardOverlayFindPreviousText",
     IDS_KEYBOARD_OVERLAY_FIND_PREVIOUS_TEXT },
   { "keyboardOverlayFindText", IDS_KEYBOARD_OVERLAY_FIND_TEXT },
@@ -155,6 +154,7 @@
     IDS_KEYBOARD_OVERLAY_INCREASE_KEY_BRIGHTNESS },
   { "keyboardOverlayInputUnicodeCharacters",
     IDS_KEYBOARD_OVERLAY_INPUT_UNICODE_CHARACTERS },
+  { "keyboardOverlayInsert", IDS_KEYBOARD_OVERLAY_INSERT },
   { "keyboardOverlayJavascriptConsole",
     IDS_KEYBOARD_OVERLAY_JAVASCRIPT_CONSOLE },
   { "keyboardOverlayLockScreen", IDS_KEYBOARD_OVERLAY_LOCK_SCREEN },
diff --git a/chrome/browser/ui/webui/chromeos/login/core_oobe_handler.cc b/chrome/browser/ui/webui/chromeos/login/core_oobe_handler.cc
index 185d124..259cdf6 100644
--- a/chrome/browser/ui/webui/chromeos/login/core_oobe_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/core_oobe_handler.cc
@@ -200,7 +200,7 @@
   bool enable_keyboard_flow = false;
   chromeos::system::StatisticsProvider* provider =
       chromeos::system::StatisticsProvider::GetInstance();
-  provider->GetMachineFlag(chromeos::kOemKeyboardDrivenOobeKey,
+  provider->GetMachineFlag(chromeos::system::kOemKeyboardDrivenOobeKey,
                            &enable_keyboard_flow);
   if (enable_keyboard_flow)
     CallJS("cr.ui.Oobe.enableKeyboardFlow", enable_keyboard_flow);
diff --git a/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.cc
index 847a807..e533193 100644
--- a/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.cc
@@ -182,6 +182,8 @@
     case GoogleServiceAuthError::HOSTED_NOT_ALLOWED:
     case GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS:
     case GoogleServiceAuthError::REQUEST_CANCELED:
+    case GoogleServiceAuthError::UNEXPECTED_SERVICE_RESPONSE:
+    case GoogleServiceAuthError::SERVICE_ERROR:
       ShowError(IDS_ENTERPRISE_ENROLLMENT_AUTH_FATAL_ERROR, false);
       return;
     case GoogleServiceAuthError::USER_NOT_SIGNED_UP:
@@ -275,14 +277,6 @@
   NOTREACHED();
 }
 
-void EnrollmentScreenHandler::SubmitTestCredentials(
-    const std::string& email,
-    const std::string& password) {
-  test_email_ = email;
-  test_password_ = password;
-  DoShow();
-}
-
 // EnrollmentScreenHandler BaseScreenHandler implementation -----
 
 void EnrollmentScreenHandler::Initialize() {
@@ -465,10 +459,6 @@
   screen_data.SetString("gaiaUrl", GaiaUrls::GetInstance()->gaia_url().spec());
   screen_data.SetBoolean("is_auto_enrollment", is_auto_enrollment_);
   screen_data.SetBoolean("prevent_cancellation", !can_exit_enrollment_);
-  if (!test_email_.empty()) {
-    screen_data.SetString("test_email", test_email_);
-    screen_data.SetString("test_password", test_password_);
-  }
 
   ShowScreen(OobeUI::kScreenOobeEnrollment, &screen_data);
 }
diff --git a/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.h
index 42e8f63..5183066 100644
--- a/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.h
@@ -51,8 +51,6 @@
   virtual void ShowAuthError(const GoogleServiceAuthError& error) OVERRIDE;
   virtual void ShowEnrollmentStatus(policy::EnrollmentStatus status) OVERRIDE;
   virtual void ShowUIError(UIError error_code) OVERRIDE;
-  virtual void SubmitTestCredentials(const std::string& email,
-                                     const std::string& password) OVERRIDE;
 
   // Implements BaseScreenHandler:
   virtual void Initialize() OVERRIDE;
@@ -123,10 +121,6 @@
   // Username of the user signing in.
   std::string user_;
 
-  // Credentials used for tests.
-  std::string test_email_;
-  std::string test_password_;
-
   // This intentionally lives here and not in the controller, since it needs to
   // execute requests in the context of the profile that displays the webui.
   scoped_ptr<GaiaOAuthFetcher> oauth_fetcher_;
diff --git a/chrome/browser/ui/webui/chromeos/login/error_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/error_screen_handler.cc
index f296b0c..cee9ea1 100644
--- a/chrome/browser/ui/webui/chromeos/login/error_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/error_screen_handler.cc
@@ -6,7 +6,7 @@
 
 #include "base/logging.h"
 #include "base/message_loop.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/chromeos/login/captive_portal_window_proxy.h"
 #include "chrome/browser/chromeos/net/network_portal_detector.h"
 #include "chrome/browser/ui/webui/chromeos/login/native_window_delegate.h"
diff --git a/chrome/browser/ui/webui/chromeos/login/kiosk_app_menu_handler.cc b/chrome/browser/ui/webui/chromeos/login/kiosk_app_menu_handler.cc
index fa23a06..1fdc155 100644
--- a/chrome/browser/ui/webui/chromeos/login/kiosk_app_menu_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/kiosk_app_menu_handler.cc
@@ -7,9 +7,11 @@
 #include "base/bind.h"
 #include "base/command_line.h"
 #include "base/values.h"
+#include "chrome/browser/browser_process.h"
 #include "chrome/browser/chromeos/app_mode/kiosk_app_launch_error.h"
 #include "chrome/browser/chromeos/app_mode/kiosk_app_launcher.h"
 #include "chrome/browser/chromeos/login/existing_user_controller.h"
+#include "chrome/browser/policy/browser_policy_connector.h"
 #include "chrome/common/chrome_notification_types.h"
 #include "chromeos/chromeos_switches.h"
 #include "content/public/browser/notification_details.h"
@@ -87,6 +89,12 @@
 
 void KioskAppMenuHandler::HandleInitializeKioskApps(
     const base::ListValue* args) {
+  if (g_browser_process->browser_policy_connector()->IsEnterpriseManaged()) {
+    initialized_ = true;
+    SendKioskApps();
+    return;
+  }
+
   KioskAppManager::Get()->GetConsumerKioskModeStatus(
       base::Bind(&KioskAppMenuHandler::OnGetConsumerKioskModeStatus,
                  weak_ptr_factory_.GetWeakPtr()));
diff --git a/chrome/browser/ui/webui/chromeos/login/locally_managed_user_creation_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/locally_managed_user_creation_screen_handler.cc
index e83226c..c2a594b 100644
--- a/chrome/browser/ui/webui/chromeos/login/locally_managed_user_creation_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/locally_managed_user_creation_screen_handler.cc
@@ -12,8 +12,10 @@
 #include "chrome/browser/chromeos/settings/cros_settings.h"
 #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
 #include "chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h"
+#include "chrome/common/url_constants.h"
 #include "google_apis/gaia/gaia_auth_util.h"
 #include "grit/generated_resources.h"
+#include "net/base/data_url.h"
 #include "ui/base/l10n/l10n_util.h"
 
 namespace {
@@ -22,15 +24,13 @@
 const char kLocallyManagedUserCreationScreen[] =
     "locally-managed-user-creation";
 
-const char kLocallyManagedWebURL[] =
-    "www.chrome.com/SomeTBDURL";
-
 }  // namespace
 
 namespace chromeos {
 
 LocallyManagedUserCreationScreenHandler::
-    LocallyManagedUserCreationScreenHandler() {}
+LocallyManagedUserCreationScreenHandler() : delegate_(NULL) {
+}
 
 LocallyManagedUserCreationScreenHandler::
     ~LocallyManagedUserCreationScreenHandler() {}
@@ -59,13 +59,13 @@
                IDS_CREATE_LOCALLY_MANAGED_INTRO_TEXT_2);
   builder->AddF("createManagedUserIntroText3",
                IDS_CREATE_LOCALLY_MANAGED_INTRO_TEXT_3,
-               UTF8ToUTF16(kLocallyManagedWebURL));
+               UTF8ToUTF16(chrome::kSupervisedUserManagementDisplayURL));
 
   builder->Add("createManagedUserPickManagerTitle",
                IDS_CREATE_LOCALLY_MANAGED_USER_CREATE_PICK_MANAGER_TITLE);
   builder->AddF("createManagedUserPickManagerTitleExplanation",
                IDS_CREATE_LOCALLY_MANAGED_USER_CREATE_PICK_MANAGER_EXPLANATION,
-               UTF8ToUTF16(kLocallyManagedWebURL));
+               UTF8ToUTF16(chrome::kSupervisedUserManagementDisplayURL));
   builder->Add("createManagedUserManagerPasswordHint",
                IDS_CREATE_LOCALLY_MANAGED_USER_CREATE_MANAGER_PASSWORD_HINT);
   builder->Add("createManagedUserWrongManagerPasswordText",
@@ -101,21 +101,15 @@
   builder->Add("createManagedUserCreated1Text2",
                IDS_CREATE_LOCALLY_MANAGED_USER_CREATED_1_TEXT_2);
   builder->Add("createManagedUserCreated1Text3",
-               IDS_CREATE_LOCALLY_MANAGED_USER_CREATED_3_TEXT_3);
+               IDS_CREATE_LOCALLY_MANAGED_USER_CREATED_1_TEXT_3);
 
-  builder->Add("createManagedUserCreated2Text1",
-               IDS_CREATE_LOCALLY_MANAGED_USER_CREATED_2_TEXT_1);
-  builder->Add("createManagedUserCreated2Text2",
-               IDS_CREATE_LOCALLY_MANAGED_USER_CREATED_2_TEXT_2);
+  builder->Add("managementURL", chrome::kSupervisedUserManagementDisplayURL);
 
-  builder->Add("createManagedUserCreated3Text1",
-               IDS_CREATE_LOCALLY_MANAGED_USER_CREATED_3_TEXT_1);
-  builder->Add("createManagedUserCreated3Text2",
-               IDS_CREATE_LOCALLY_MANAGED_USER_CREATED_3_TEXT_2);
-  builder->Add("createManagedUserCreated3Text3",
-               IDS_CREATE_LOCALLY_MANAGED_USER_CREATED_3_TEXT_3);
-
-  builder->Add("managementURL", kLocallyManagedWebURL);
+  // TODO(antrim) : this is an explicit code duplications with UserImageScreen.
+  // It should be removed by issue 251179.
+  builder->Add("takePhoto", IDS_OPTIONS_CHANGE_PICTURE_TAKE_PHOTO);
+  builder->Add("discardPhoto", IDS_OPTIONS_CHANGE_PICTURE_DISCARD_PHOTO);
+  builder->Add("flipPhoto", IDS_OPTIONS_CHANGE_PICTURE_FLIP_PHOTO);
 }
 
 void LocallyManagedUserCreationScreenHandler::Initialize() {}
@@ -139,6 +133,20 @@
   AddCallback("managerSelectedOnLocallyManagedUserCreationFlow",
               &LocallyManagedUserCreationScreenHandler::
                   HandleManagerSelected);
+
+  // TODO(antrim) : this is an explicit code duplications with UserImageScreen.
+  // It should be removed by issue 251179.
+  AddCallback("supervisedUserGetImages",
+              &LocallyManagedUserCreationScreenHandler::
+                  HandleGetImages);
+
+  AddCallback("supervisedUserPhotoTaken",
+              &LocallyManagedUserCreationScreenHandler::HandlePhotoTaken);
+  AddCallback("supervisedUserSelectImage",
+              &LocallyManagedUserCreationScreenHandler::HandleSelectImage);
+  AddCallback("supervisedUserCheckCameraPresence",
+              &LocallyManagedUserCreationScreenHandler::
+                  HandleCheckCameraPresence);
 }
 
 void LocallyManagedUserCreationScreenHandler::PrepareToShow() {}
@@ -160,6 +168,10 @@
   }
   data->Set("managers", users_list.release());
   ShowScreen(OobeUI::kScreenManagedUserCreationFlow, data.get());
+
+  if (!delegate_)
+    return;
+  delegate_->CheckCameraPresence();
 }
 
 void LocallyManagedUserCreationScreenHandler::Hide() {}
@@ -270,4 +282,49 @@
   delegate_->AuthenticateManager(manager_username, manager_password);
 }
 
+// TODO(antrim) : this is an explicit code duplications with UserImageScreen.
+// It should be removed by issue 251179.
+void LocallyManagedUserCreationScreenHandler::HandleGetImages() {
+  base::ListValue image_urls;
+  for (int i = kFirstDefaultImageIndex; i < kDefaultImagesCount; ++i) {
+    scoped_ptr<base::DictionaryValue> image_data(new base::DictionaryValue);
+    image_data->SetString("url", GetDefaultImageUrl(i));
+    image_data->SetString(
+        "author", l10n_util::GetStringUTF16(kDefaultImageAuthorIDs[i]));
+    image_data->SetString(
+        "website", l10n_util::GetStringUTF16(kDefaultImageWebsiteIDs[i]));
+    image_data->SetString("title", GetDefaultImageDescription(i));
+    image_urls.Append(image_data.release());
+  }
+  CallJS("login.LocallyManagedUserCreationScreen.setDefaultImages", image_urls);
+}
+
+void LocallyManagedUserCreationScreenHandler::HandlePhotoTaken
+    (const std::string& image_url) {
+  std::string mime_type, charset, raw_data;
+  if (!net::DataURL::Parse(GURL(image_url), &mime_type, &charset, &raw_data))
+    NOTREACHED();
+  DCHECK_EQ("image/png", mime_type);
+
+  if (delegate_)
+    delegate_->OnPhotoTaken(raw_data);
+}
+
+void LocallyManagedUserCreationScreenHandler::HandleCheckCameraPresence() {
+  if (!delegate_)
+    return;
+  delegate_->CheckCameraPresence();
+}
+
+void LocallyManagedUserCreationScreenHandler::HandleSelectImage(
+    const std::string& image_url,
+    const std::string& image_type) {
+  if (delegate_)
+    delegate_->OnImageSelected(image_type, image_url);
+}
+
+void LocallyManagedUserCreationScreenHandler::SetCameraPresent(bool present) {
+  CallJS("login.LocallyManagedUserCreationScreen.setCameraPresent", present);
+}
+
 }  // namespace chromeos
diff --git a/chrome/browser/ui/webui/chromeos/login/locally_managed_user_creation_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/locally_managed_user_creation_screen_handler.h
index d88faa3..1ec027a 100644
--- a/chrome/browser/ui/webui/chromeos/login/locally_managed_user_creation_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/locally_managed_user_creation_screen_handler.h
@@ -9,6 +9,7 @@
 
 #include "base/compiler_specific.h"
 #include "base/strings/string16.h"
+#include "chrome/browser/chromeos/login/default_user_images.h"
 #include "chrome/browser/ui/webui/chromeos/login/base_screen_handler.h"
 #include "content/public/browser/web_ui.h"
 
@@ -44,11 +45,14 @@
         const string16& display_name,
         const std::string& managed_user_password) = 0;
 
-    // Starts picture selection for created managed user.
-    virtual void SelectPicture() = 0;
-
     virtual void AbortFlow() = 0;
     virtual void FinishFlow() = 0;
+
+    virtual void CheckCameraPresence() = 0;
+    virtual void OnPhotoTaken(const std::string& raw_data) = 0;
+    virtual void OnImageSelected(const std::string& image_url,
+                                 const std::string& image_type) = 0;
+    virtual void OnImageAccepted() = 0;
   };
 
   LocallyManagedUserCreationScreenHandler();
@@ -74,6 +78,8 @@
                      const string16& message,
                      const string16& button_text);
 
+  void SetCameraPresent(bool enabled);
+
   // BaseScreenHandler implementation:
   virtual void DeclareLocalizedValues(LocalizedValuesBuilder* builder) OVERRIDE;
   virtual void Initialize() OVERRIDE;
@@ -96,6 +102,12 @@
   void HandleCreateManagedUser(const string16& new_raw_user_name,
                                const std::string& new_user_password);
 
+  void HandleGetImages();
+  void HandlePhotoTaken(const std::string& image_url);
+  void HandleCheckCameraPresence();
+  void HandleSelectImage(const std::string& image_url,
+                         const std::string& image_type);
+
   void UpdateText(const std::string& element_id, const string16& text);
 
   Delegate* delegate_;
diff --git a/chrome/browser/ui/webui/chromeos/login/network_dropdown.cc b/chrome/browser/ui/webui/chromeos/login/network_dropdown.cc
index c4b6a83..139092e 100644
--- a/chrome/browser/ui/webui/chromeos/login/network_dropdown.cc
+++ b/chrome/browser/ui/webui/chromeos/login/network_dropdown.cc
@@ -8,7 +8,7 @@
 
 #include "ash/system/chromeos/network/network_icon.h"
 #include "ash/system/chromeos/network/network_icon_animation.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "base/values.h"
 #include "chrome/browser/chromeos/login/login_display_host.h"
 #include "chrome/browser/chromeos/login/login_display_host_impl.h"
diff --git a/chrome/browser/ui/webui/chromeos/login/network_dropdown.h b/chrome/browser/ui/webui/chromeos/login/network_dropdown.h
index 6cf0fca..c92654b 100644
--- a/chrome/browser/ui/webui/chromeos/login/network_dropdown.h
+++ b/chrome/browser/ui/webui/chromeos/login/network_dropdown.h
@@ -7,7 +7,7 @@
 
 #include "ash/system/chromeos/network/network_icon_animation_observer.h"
 #include "base/basictypes.h"
-#include "base/timer.h"
+#include "base/timer/timer.h"
 #include "chrome/browser/chromeos/status/network_menu.h"
 #include "chromeos/network/network_state_handler_observer.h"
 #include "ui/gfx/native_widget_types.h"
diff --git a/chrome/browser/ui/webui/chromeos/login/network_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/network_screen_handler.cc
index 4044379..8d96641 100644
--- a/chrome/browser/ui/webui/chromeos/login/network_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/network_screen_handler.cc
@@ -89,7 +89,7 @@
 void NetworkScreenHandler::EnableContinue(bool enabled) {
   is_continue_enabled_ = enabled;
   if (page_is_ready())
-    CallJS("cr.ui.Oobe.enableContinueButton", enabled);
+    CallJS("login.NetworkScreen.enableContinueButton", enabled);
 }
 
 // NetworkScreenHandler, BaseScreenHandler implementation: --------------------
diff --git a/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc b/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc
index 81f0336..ef64deb 100644
--- a/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc
+++ b/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc
@@ -57,9 +57,6 @@
 // Path for a stripped down login page that does not have OOBE elements.
 const char kLoginPath[] = "login#login";
 
-// Path for the enterprise enrollment gaia page hosting.
-const char kEnterpriseEnrollmentGaiaLoginPath[] = "gaialogin";
-
 const char kStringsJSPath[] = "strings.js";
 const char kLoginJSPath[] = "login.js";
 const char kOobeJSPath[] = "oobe.js";
@@ -110,8 +107,6 @@
                           IDR_LOGIN_HTML);
   source->AddResourcePath(kLoginJSPath,
                           IDR_LOGIN_JS);
-  source->AddResourcePath(kEnterpriseEnrollmentGaiaLoginPath,
-                          IDR_GAIA_LOGIN_HTML);
   source->AddResourcePath(kKeyboardUtilsJSPath,
                           IDR_KEYBOARD_UTILS_JS);
   source->OverrideContentSecurityPolicyFrameSrc(
@@ -354,7 +349,7 @@
 
   bool keyboard_driven_oobe = false;
   system::StatisticsProvider::GetInstance()->GetMachineFlag(
-      chromeos::kOemKeyboardDrivenOobeKey, &keyboard_driven_oobe);
+      chromeos::system::kOemKeyboardDrivenOobeKey, &keyboard_driven_oobe);
   localized_strings->SetString("highlightStrength",
                                keyboard_driven_oobe ? "strong" : "normal");
 }
diff --git a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc
index e8cdd21..2388a61 100644
--- a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc
@@ -29,7 +29,6 @@
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/chromeos/settings/cros_settings.h"
 #include "chrome/browser/io_thread.h"
-#include "chrome/browser/managed_mode/managed_user_service.h"
 #include "chrome/browser/policy/browser_policy_connector.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/webui/chromeos/login/error_screen_handler.h"
@@ -329,6 +328,7 @@
       dns_clear_task_running_(false),
       cookies_cleared_(false),
       network_state_informer_(network_state_informer),
+      test_expects_complete_login_(false),
       weak_factory_(this),
       webui_visible_(false),
       preferences_changed_delayed_(false),
@@ -434,8 +434,9 @@
   builder->Add("publicAccountEnter", IDS_LOGIN_PUBLIC_ACCOUNT_ENTER);
   builder->Add("publicAccountEnterAccessibleName",
                IDS_LOGIN_PUBLIC_ACCOUNT_ENTER_ACCESSIBLE_NAME);
-  builder->Add("removeManagedUserWarningText",
-               IDS_USER_IS_LOCALLY_MANAGED_REMOVE_WARNING);
+  builder->AddF("removeManagedUserWarningText",
+               IDS_USER_IS_LOCALLY_MANAGED_REMOVE_WARNING,
+               UTF8ToUTF16(chrome::kSupervisedUserManagementDisplayURL));
   builder->Add("removeManagedUserWarningButtonTitle",
                IDS_USER_IS_LOCALLY_MANAGED_REMOVE_WARNING_BUTTON);
 
@@ -897,11 +898,20 @@
 void SigninScreenHandler::ShowSigninScreenForCreds(
     const std::string& username,
     const std::string& password) {
-  VLOG(2) << "ShowSigninScreenForCreds " << username << " " << password;
+  VLOG(2) << "ShowSigninScreenForCreds  for user " << username
+          << ", frame_state=" << frame_state_;
 
   test_user_ = username;
   test_pass_ = password;
-  HandleShowAddUser(NULL);
+  test_expects_complete_login_ = true;
+
+  // Submit login form for test if gaia is ready. If gaia is loading, login
+  // will be attempted in HandleLoginWebuiReady after gaia is ready. Otherwise,
+  // reload gaia then follow the loading case.
+  if (frame_state_ == FRAME_STATE_LOADED)
+    SubmitLoginFormForTest();
+  else if (frame_state_ != FRAME_STATE_LOADING)
+    HandleShowAddUser(NULL);
 }
 
 void SigninScreenHandler::OnCookiesCleared(base::Closure on_clear_callback) {
@@ -994,21 +1004,20 @@
 
 
 void SigninScreenHandler::UpdateAuthParams(DictionaryValue* params) {
+  if (!delegate_)
+    return;
+
   UpdateAuthParamsFromSettings(params, CrosSettings::Get());
 
-  // TODO(nkostylev): Allow locally managed user creation only if:
+  // Allow locally managed user creation only if:
   // 1. Enterprise managed device > is allowed by policy.
   // 2. Consumer device > owner exists.
-  // g_browser_process->browser_policy_connector()->IsEnterpriseManaged()
-  // const UserList& users = delegate_->GetUsers();
-  // bool single_user = users.size() == 1;
-  // chromeos::CrosSettings::Get()->GetString(chromeos::kDeviceOwner, &owner);
-
-  bool managed_users_enabled = ManagedUserService::AreManagedUsersEnabled();
+  bool managed_users_allowed =
+      UserManager::Get()->AreLocallyManagedUsersAllowed();
   bool managed_users_can_create = false;
-  if (managed_users_enabled)
+  if (managed_users_allowed)
     managed_users_can_create = delegate_->GetUsers().size() > 0;
-  params->SetBoolean("managedUsersEnabled", managed_users_enabled);
+  params->SetBoolean("managedUsersEnabled", managed_users_allowed);
   params->SetBoolean("managedUsersCanCreate", managed_users_can_create);
 }
 
@@ -1057,18 +1066,6 @@
           GaiaUrls::GetInstance()->gaia_url();
   params.SetString("gaiaUrl", gaia_url.spec());
 
-  // Test automation data:
-  const CommandLine* command_line = CommandLine::ForCurrentProcess();
-  if (command_line->HasSwitch(switches::kAuthExtensionPath)) {
-    if (!test_user_.empty()) {
-      params.SetString("test_email", test_user_);
-      test_user_.clear();
-    }
-    if (!test_pass_.empty()) {
-      params.SetString("test_password", test_pass_);
-      test_pass_.clear();
-    }
-  }
   frame_state_ = FRAME_STATE_LOADING;
   ignore_next_user_abort_frame_error_ = true;
   CallJS("login.GaiaSigninScreen.loadAuthExtension", params);
@@ -1094,6 +1091,15 @@
   delegate_->CompleteLogin(UserContext(sanitized_email,
                                        password,
                                        std::string()));  // auth_code
+
+  if (test_expects_complete_login_) {
+    VLOG(2) << "Complete test login for " << typed_email
+            << ", requested=" << test_user_;
+
+    test_expects_complete_login_ = false;
+    test_user_.clear();
+    test_pass_.clear();
+  }
 }
 
 void SigninScreenHandler::HandleCompleteAuthentication(
@@ -1127,9 +1133,10 @@
 }
 
 void SigninScreenHandler::HandleShowLocallyManagedUserCreationScreen() {
-  const CommandLine* command_line = CommandLine::ForCurrentProcess();
-  if (!command_line->HasSwitch(::switches::kEnableManagedUsers))
+  if (!UserManager::Get()->AreLocallyManagedUsersAllowed()) {
+    LOG(ERROR) << "Managed users not allowed.";
     return;
+  }
   scoped_ptr<DictionaryValue> params(new DictionaryValue());
   LoginDisplayHostImpl::default_host()->
       StartWizard(WizardController::kLocallyManagedUserCreationScreenName,
@@ -1386,6 +1393,9 @@
     RefocusCurrentPod();
   }
   HandleFrameLoadingCompleted(0);
+
+  if (test_expects_complete_login_)
+    SubmitLoginFormForTest();
 }
 
 void SigninScreenHandler::HandleDemoWebuiReady() {
@@ -1649,4 +1659,22 @@
   return !show_pods;
 }
 
+void SigninScreenHandler::SubmitLoginFormForTest() {
+  VLOG(2) << "Submit login form for test, user=" << test_user_;
+
+  std::string code;
+  code += "document.getElementById('Email').value = '" + test_user_ + "';";
+  code += "document.getElementById('Passwd').value = '" + test_pass_ + "';";
+  code += "document.getElementById('signIn').click();";
+
+  RenderViewHost* rvh = web_ui()->GetWebContents()->GetRenderViewHost();
+  rvh->ExecuteJavascriptInWebFrame(
+      ASCIIToUTF16("//iframe[@id='signin-frame']\n//iframe"),
+      ASCIIToUTF16(code));
+
+  // Test properties are cleared in HandleCompleteLogin because the form
+  // submission might fail and login will not be attempted after reloading
+  // if they are cleared here.
+}
+
 }  // namespace chromeos
diff --git a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h
index fe5e98a..1c17b8c 100644
--- a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h
@@ -376,6 +376,9 @@
   // Returns true if offline login is allowed.
   bool IsOfflineLoginAllowed() const;
 
+  // Attempts login for test.
+  void SubmitLoginFormForTest();
+
   // Current UI state of the signin screen.
   UIState ui_state_;
 
@@ -432,6 +435,7 @@
   // Test credentials.
   std::string test_user_;
   std::string test_pass_;
+  bool test_expects_complete_login_;
 
   base::WeakPtrFactory<SigninScreenHandler> weak_factory_;
 
diff --git a/chrome/browser/ui/webui/chromeos/login/user_image_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/user_image_screen_handler.h
index 9602558..9ac7c64 100644
--- a/chrome/browser/ui/webui/chromeos/login/user_image_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/user_image_screen_handler.h
@@ -8,7 +8,7 @@
 #include <string>
 
 #include "base/memory/weak_ptr.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/chromeos/login/screens/user_image_screen_actor.h"
 #include "chrome/browser/ui/webui/chromeos/login/base_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
diff --git a/chrome/browser/ui/webui/chromeos/proxy_settings_ui.cc b/chrome/browser/ui/webui/chromeos/proxy_settings_ui.cc
index 672bc83..c136db5 100644
--- a/chrome/browser/ui/webui/chromeos/proxy_settings_ui.cc
+++ b/chrome/browser/ui/webui/chromeos/proxy_settings_ui.cc
@@ -101,7 +101,7 @@
 
   bool keyboard_driven_oobe = false;
   system::StatisticsProvider::GetInstance()->GetMachineFlag(
-      chromeos::kOemKeyboardDrivenOobeKey, &keyboard_driven_oobe);
+      chromeos::system::kOemKeyboardDrivenOobeKey, &keyboard_driven_oobe);
   localized_strings->SetString("highlightStrength",
                                keyboard_driven_oobe ? "strong" : "normal");
 
diff --git a/chrome/browser/ui/webui/chromeos/salsa_ui.cc b/chrome/browser/ui/webui/chromeos/salsa_ui.cc
new file mode 100644
index 0000000..62ed671
--- /dev/null
+++ b/chrome/browser/ui/webui/chromeos/salsa_ui.cc
@@ -0,0 +1,193 @@
+// 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/ui/webui/chromeos/salsa_ui.h"
+
+#include "base/bind.h"
+#include "base/prefs/pref_service.h"
+#include "base/values.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/common/url_constants.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/web_ui.h"
+#include "content/public/browser/web_ui_data_source.h"
+#include "grit/browser_resources.h"
+
+// Whitelist of which preferences are possible targets for Salsa treatments.
+// If new preferences are added and they are to be used in an experiment, then
+// they must be added to this list as well to keep chrome://salsa from
+// changing arbitrary values.
+
+namespace {
+
+const char* kWhitelist[] = {
+  prefs::kFlingMaxCancelToDownTimeInMs,
+  prefs::kFlingMaxTapGapTimeInMs,
+  prefs::kLongPressTimeInSeconds,
+  prefs::kLongPressTimeInSeconds,
+  prefs::kMaxSecondsBetweenDoubleClick,
+  prefs::kMaxSeparationForGestureTouchesInPixels,
+  prefs::kMaxSwipeDeviationRatio,
+  prefs::kMaxTouchDownDurationInSecondsForClick,
+  prefs::kMaxTouchMoveInPixelsForClick,
+  prefs::kMaxDistanceBetweenTapsForDoubleTap,
+  prefs::kMaxDistanceForTwoFingerTapInPixels,
+  prefs::kMinDistanceForPinchScrollInPixels,
+  prefs::kMinFlickSpeedSquared,
+  prefs::kMinPinchUpdateDistanceInPixels,
+  prefs::kMinRailBreakVelocity,
+  prefs::kMinScrollDeltaSquared,
+  prefs::kMinSwipeSpeed,
+  prefs::kMinTouchDownDurationInSecondsForClick,
+  prefs::kPointsBufferedForVelocity,
+  prefs::kRailBreakProportion,
+  prefs::kRailStartProportion,
+  prefs::kFlingAccelerationCurveCoefficient0,
+  prefs::kFlingAccelerationCurveCoefficient1,
+  prefs::kFlingAccelerationCurveCoefficient2,
+  prefs::kFlingAccelerationCurveCoefficient3,
+  prefs::kFlingVelocityCap,
+  prefs::kTabScrubActivationDelayInMS,
+  prefs::kOverscrollHorizontalThresholdComplete,
+  prefs::kOverscrollVerticalThresholdComplete,
+  prefs::kOverscrollMinimumThresholdStart,
+  prefs::kOverscrollHorizontalResistThreshold,
+  prefs::kOverscrollVerticalResistThreshold,
+  prefs::kImmersiveModeRevealDelayMs,
+  prefs::kImmersiveModeRevealXThresholdPixels,
+  prefs::kWorkspaceCyclerSelectedScale,
+  prefs::kWorkspaceCyclerMinScale,
+  prefs::kWorkspaceCyclerMaxScale,
+  prefs::kWorkspaceCyclerMinBrightness,
+  prefs::kWorkspaceCyclerBackgroundOpacity,
+  prefs::kWorkspaceCyclerDesktopWorkspaceBrightness,
+  prefs::kWorkspaceCyclerDistanceToInitiateCycling,
+  prefs::kWorkspaceCyclerScrollDistanceToCycleToNextWorkspace,
+  prefs::kWorkspaceCyclerCyclerStepAnimationDurationRatio,
+  prefs::kWorkspaceCyclerStartCyclerAnimationDuration,
+  prefs::kWorkspaceCyclerStopCyclerAnimationDuration,
+  prefs::kFlingCurveTouchscreenAlpha,
+  prefs::kFlingCurveTouchscreenBeta,
+  prefs::kFlingCurveTouchscreenGamma,
+  prefs::kFlingCurveTouchpadAlpha,
+  prefs::kFlingCurveTouchpadBeta,
+  prefs::kFlingCurveTouchpadGamma,
+};
+
+void RevertPreferences(PrefService* prefs,
+                       std::map<int, const base::Value*>* vals) {
+  std::map<int, const base::Value*>::const_iterator it;
+  for (it = vals->begin(); it != vals->end(); ++it) {
+    if (!prefs->FindPreference(kWhitelist[it->first]))
+      continue;
+
+    if (!it->second) {
+      prefs->ClearPref(kWhitelist[it->first]);
+    } else {
+      prefs->Set(kWhitelist[it->first], *it->second);
+      delete it->second;
+    }
+  }
+}
+
+} // namespace
+
+SalsaUI::SalsaUI(content::WebUI* web_ui)
+    : content::WebUIController(web_ui) {
+  // Set up the chrome://salsa source.
+  content::WebUIDataSource* html_source =
+      content::WebUIDataSource::Create(chrome::kChromeUISalsaHost);
+
+  // Register callback handlers.
+  web_ui->RegisterMessageCallback(
+      "salsaSetPreferenceValue",
+      base::Bind(&SalsaUI::SetPreferenceValue,
+                 base::Unretained(this)));
+  web_ui->RegisterMessageCallback(
+      "salsaBackupPreferenceValue",
+      base::Bind(&SalsaUI::BackupPreferenceValue,
+                 base::Unretained(this)));
+
+  // Add required resources.
+  html_source->AddResourcePath("salsa.css", IDR_SALSA_CSS);
+  html_source->AddResourcePath("salsa.js", IDR_SALSA_JS);
+  html_source->SetDefaultResource(IDR_SALSA_HTML);
+
+  Profile* profile = Profile::FromWebUI(web_ui);
+  content::WebUIDataSource::Add(profile, html_source);
+}
+
+SalsaUI::~SalsaUI() {
+  std::map<int, const base::Value*>* values_to_revert =
+      new std::map<int, const base::Value*>;
+  values_to_revert->swap(orig_values_);
+
+  Profile* profile = Profile::FromWebUI(web_ui());
+  PrefService* prefs = profile->GetPrefs();
+
+  content::BrowserThread::PostTask(
+      content::BrowserThread::UI,
+      FROM_HERE,
+      base::Bind(&RevertPreferences, prefs, base::Owned(values_to_revert))
+    );
+}
+
+int SalsaUI::WhitelistIndex(const char* key) const {
+  if (!key)
+    return -1;
+
+  int len = arraysize(kWhitelist);
+  for (int i = 0; i < len; ++i) {
+    if (!strcmp(key, kWhitelist[i]))
+      return i;
+  }
+  return -1;
+}
+
+void SalsaUI::SetPreferenceValue(const base::ListValue* args) {
+  std::string pref_name;
+  const base::Value* value;
+  if (!args->GetString(0, &pref_name) || !args->Get(1, &value))
+    return;
+
+  int index = WhitelistIndex(pref_name.c_str());
+  if (index < 0)
+    return;
+
+  Profile* profile = Profile::FromWebUI(web_ui());
+  PrefService* prefs = profile->GetPrefs();
+  const PrefService::Preference* pref =
+      prefs->FindPreference(kWhitelist[index]);
+
+  if (pref->GetType() != value->GetType())
+    return;
+
+  prefs->Set(kWhitelist[index], *value);
+}
+
+void SalsaUI::BackupPreferenceValue(const base::ListValue* args) {
+  std::string pref_name;
+  if (!args->GetString(0, &pref_name))
+    return;
+
+  int index = WhitelistIndex(pref_name.c_str());
+  if (index < 0)
+    return;
+
+  Profile* profile = Profile::FromWebUI(web_ui());
+  PrefService* prefs = profile->GetPrefs();
+  const PrefService::Preference* pref =
+      prefs->FindPreference(kWhitelist[index]);
+
+  if (!pref)
+    return;
+
+  // Get our own copy of the user defined value or NULL if they are using the
+  // default. You have to make a copy since they'll be used in the destructor
+  // to restore the values and we need to make sure they're still around.
+  orig_values_[index] =
+      pref->IsDefaultValue() ? NULL : pref->GetValue()->DeepCopy();
+}
diff --git a/chrome/browser/ui/webui/chromeos/salsa_ui.h b/chrome/browser/ui/webui/chromeos/salsa_ui.h
new file mode 100644
index 0000000..130dd4b
--- /dev/null
+++ b/chrome/browser/ui/webui/chromeos/salsa_ui.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_UI_WEBUI_CHROMEOS_SALSA_UI_H_
+#define CHROME_BROWSER_UI_WEBUI_CHROMEOS_SALSA_UI_H_
+
+#include <map>
+
+#include "base/values.h"
+#include "chrome/browser/profiles/profile.h"
+#include "content/public/browser/web_ui_controller.h"
+
+namespace base {
+class ListValue;
+class Value;
+}  // namespace base
+
+// The WebUI for 'chrome://salsa' -- a user front end for the touch UI
+// blind user studies.  I does this by setting gesture preference values
+// without the user knowing which ones and having them try out various
+// settings to see which results in a better experience for them.
+class SalsaUI : public content::WebUIController {
+ public:
+  // Constructs a new GestureConfig for the specified |web_ui|.
+  explicit SalsaUI(content::WebUI* web_ui);
+  virtual ~SalsaUI();
+
+ private:
+  // Set a preference setting's value.
+  // Two parameters are provided in a JS list: prefName and value, the
+  // key of the preference value to be set, and the value it's to be set to.
+  void SetPreferenceValue(const base::ListValue* args);
+
+  // Record the current value for a preference key and store the key/value pair
+  // in the member variable orig_values_.
+  void BackupPreferenceValue(const base::ListValue* args);
+
+  // Check and see if a key is on the whitelist.  Returns the index into
+  // the whitelist on success and -1 on failure.
+  int WhitelistIndex(const char* key) const;
+
+  std::map<int, const base::Value*> orig_values_;
+
+  DISALLOW_COPY_AND_ASSIGN(SalsaUI);
+};
+
+#endif  // CHROME_BROWSER_UI_WEBUI_CHROMEOS_SALSA_UI_H_
+
diff --git a/chrome/browser/ui/webui/chromeos/system_info_ui.cc b/chrome/browser/ui/webui/chromeos/system_info_ui.cc
index c3d62e8..e60ca63 100644
--- a/chrome/browser/ui/webui/chromeos/system_info_ui.cc
+++ b/chrome/browser/ui/webui/chromeos/system_info_ui.cc
@@ -16,7 +16,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/threading/thread.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "base/values.h"
 #include "chrome/browser/chromeos/cros/cros_library.h"
 #include "chrome/browser/chromeos/system_logs/system_logs_fetcher.h"
diff --git a/chrome/browser/ui/webui/chromeos/ui_account_tweaks.cc b/chrome/browser/ui/webui/chromeos/ui_account_tweaks.cc
index 3d5a909..51d9540 100644
--- a/chrome/browser/ui/webui/chromeos/ui_account_tweaks.cc
+++ b/chrome/browser/ui/webui/chromeos/ui_account_tweaks.cc
@@ -29,6 +29,9 @@
 
   localized_strings->SetBoolean("loggedInAsGuest",
       UserManager::Get()->IsLoggedInAsGuest());
+
+  localized_strings->SetBoolean("loggedInAsLocallyManagedUser",
+      UserManager::Get()->IsLoggedInAsLocallyManagedUser());
 }
 
 void AddAccountUITweaksLocalizedValues(
diff --git a/chrome/browser/ui/webui/cookies_tree_model_util.cc b/chrome/browser/ui/webui/cookies_tree_model_util.cc
index eeb5eb2..109f0c7 100644
--- a/chrome/browser/ui/webui/cookies_tree_model_util.cc
+++ b/chrome/browser/ui/webui/cookies_tree_model_util.cc
@@ -8,6 +8,7 @@
 
 #include "base/i18n/time_formatting.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/stl_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
@@ -18,6 +19,7 @@
 #include "net/cookies/canonical_cookie.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/text/bytes_formatting.h"
+#include "webkit/common/fileapi/file_system_types.h"
 
 namespace {
 
@@ -197,18 +199,20 @@
 
       const BrowsingDataFileSystemHelper::FileSystemInfo& file_system_info =
           *node.GetDetailedInfo().file_system_info;
+      const fileapi::FileSystemType kPerm = fileapi::kFileSystemTypePersistent;
+      const fileapi::FileSystemType kTemp = fileapi::kFileSystemTypeTemporary;
 
       dict->SetString(kKeyOrigin, file_system_info.origin.spec());
       dict->SetString(kKeyPersistent,
-                      file_system_info.has_persistent ?
+                      ContainsKey(file_system_info.usage_map, kPerm) ?
                           UTF16ToUTF8(ui::FormatBytes(
-                              file_system_info.usage_persistent)) :
+                              file_system_info.usage_map.find(kPerm)->second)) :
                           l10n_util::GetStringUTF8(
                               IDS_COOKIES_FILE_SYSTEM_USAGE_NONE));
       dict->SetString(kKeyTemporary,
-                      file_system_info.has_temporary ?
+                      ContainsKey(file_system_info.usage_map, kTemp) ?
                           UTF16ToUTF8(ui::FormatBytes(
-                              file_system_info.usage_temporary)) :
+                              file_system_info.usage_map.find(kTemp)->second)) :
                           l10n_util::GetStringUTF8(
                               IDS_COOKIES_FILE_SYSTEM_USAGE_NONE));
       break;
diff --git a/chrome/browser/ui/webui/crashes_ui.cc b/chrome/browser/ui/webui/crashes_ui.cc
index 85743ba..b885b01 100644
--- a/chrome/browser/ui/webui/crashes_ui.cc
+++ b/chrome/browser/ui/webui/crashes_ui.cc
@@ -78,7 +78,7 @@
   virtual void RegisterMessages() OVERRIDE;
 
   // CrashUploadList::Delegate implemenation.
-  virtual void OnCrashListAvailable() OVERRIDE;
+  virtual void OnUploadListAvailable() OVERRIDE;
 
  private:
   // Asynchronously fetches the list of crashes. Called from JS.
@@ -104,7 +104,7 @@
 }
 
 void CrashesDOMHandler::RegisterMessages() {
-  upload_list_->LoadCrashListAsynchronously();
+  upload_list_->LoadUploadListAsynchronously();
 
   web_ui()->RegisterMessageCallback("requestCrashList",
       base::Bind(&CrashesDOMHandler::HandleRequestCrashes,
@@ -118,7 +118,7 @@
     js_request_pending_ = true;
 }
 
-void CrashesDOMHandler::OnCrashListAvailable() {
+void CrashesDOMHandler::OnUploadListAvailable() {
   list_available_ = true;
   if (js_request_pending_)
     UpdateUI();
@@ -129,15 +129,14 @@
   ListValue crash_list;
 
   if (crash_reporting_enabled) {
-    std::vector<CrashUploadList::CrashInfo> crashes;
-    upload_list_->GetUploadedCrashes(50, &crashes);
+    std::vector<CrashUploadList::UploadInfo> crashes;
+    upload_list_->GetUploads(50, &crashes);
 
-    for (std::vector<CrashUploadList::CrashInfo>::iterator i = crashes.begin();
+    for (std::vector<CrashUploadList::UploadInfo>::iterator i = crashes.begin();
          i != crashes.end(); ++i) {
       DictionaryValue* crash = new DictionaryValue();
-      crash->SetString("id", i->crash_id);
-      crash->SetString("time",
-                       base::TimeFormatFriendlyDateAndTime(i->crash_time));
+      crash->SetString("id", i->id);
+      crash->SetString("time", base::TimeFormatFriendlyDateAndTime(i->time));
       crash_list.Append(crash);
     }
   }
diff --git a/chrome/browser/ui/webui/devtools_ui.cc b/chrome/browser/ui/webui/devtools_ui.cc
index 34dbfb0..0d70e13 100644
--- a/chrome/browser/ui/webui/devtools_ui.cc
+++ b/chrome/browser/ui/webui/devtools_ui.cc
@@ -41,10 +41,6 @@
 #if defined(DEBUG_DEVTOOLS)
 // Local frontend url provided by InspectUI.
 const char kLocalFrontendURLPrefix[] = "https://localhost:9222/";
-// URL local frontend should be served from.
-const char kLocalFrontendBase[] = "http://localhost:9222/";
-// Local frontend path in DevToolsDataSource.
-const char kLocalFrontendDataSourcePath[] = "localhost";
 #endif  // defined(DEBUG_DEVTOOLS)
 
 class FetchRequest : public net::URLFetcherDelegate {
@@ -140,17 +136,6 @@
                               callback);
       return;
     }
-#if defined(DEBUG_DEVTOOLS)
-    std::string local_path_prefix(kLocalFrontendDataSourcePath);
-    local_path_prefix += "/";
-    if (StartsWithASCII(path, local_path_prefix, false)) {
-      StartLocalDataRequest(path.substr(local_path_prefix.length()),
-                              render_process_id,
-                              render_view_id,
-                              callback);
-      return;
-    }
-#endif  // defined(DEBUG_DEVTOOLS)
   }
 
   // Serves bundled DevTools frontend from ResourceBundle.
@@ -184,18 +169,6 @@
     new FetchRequest(request_context_.get(), url, callback);
   }
 
-  // Serves debug DevTools frontend from localhost:9222.
-#if defined(DEBUG_DEVTOOLS)
-  void StartLocalDataRequest(
-      const std::string& path,
-      int render_process_id,
-      int render_view_id,
-      const content::URLDataSource::GotDataCallback& callback) {
-    GURL url = GURL(kLocalFrontendBase + path);
-    new FetchRequest(request_context_.get(), url, callback);
-  }
-#endif  // defined(DEBUG_DEVTOOLS)
-
   virtual std::string GetMimeType(const std::string& path) const OVERRIDE {
     return GetMimeTypeForPath(path);
   }
@@ -219,12 +192,17 @@
 #if defined(DEBUG_DEVTOOLS)
   if (frontend_url.find(kLocalFrontendURLPrefix) == 0) {
     std::string path = url.path();
-    CHECK(path.find(chrome::kChromeUIDevToolsHost) == 1);
-    return GURL(base::StringPrintf("%s://%s/%s/%s",
-                                   chrome::kChromeDevToolsScheme,
-                                   chrome::kChromeUIDevToolsHost,
-                                   kLocalFrontendDataSourcePath,
-                                   path.substr(1).c_str()));
+    std::string local_path_prefix = "/";
+    local_path_prefix += chrome::kChromeUIDevToolsHost;
+    local_path_prefix += "/";
+    if (StartsWithASCII(path, local_path_prefix, false)) {
+      std::string local_path = path.substr(local_path_prefix.length());
+      return GURL(base::StringPrintf("%s://%s/%s/%s",
+                                     chrome::kChromeDevToolsScheme,
+                                     chrome::kChromeUIDevToolsHost,
+                                     chrome::kChromeUIDevToolsBundledPath,
+                                     local_path.c_str()));
+    }
   }
 #endif  // defined(DEBUG_DEVTOOLS)
   CHECK(url.is_valid());
diff --git a/chrome/browser/ui/webui/extensions/extension_icon_source.cc b/chrome/browser/ui/webui/extensions/extension_icon_source.cc
index edb0dbb..c9de20f 100644
--- a/chrome/browser/ui/webui/extensions/extension_icon_source.cc
+++ b/chrome/browser/ui/webui/extensions/extension_icon_source.cc
@@ -24,6 +24,7 @@
 #include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
 #include "chrome/common/extensions/manifest_handlers/icons_handler.h"
 #include "chrome/common/url_constants.h"
+#include "content/public/child/image_decoder_utils.h"
 #include "extensions/common/extension_resource.h"
 #include "googleurl/src/gurl.h"
 #include "grit/component_extension_resources_map.h"
@@ -34,8 +35,8 @@
 #include "ui/gfx/codec/png_codec.h"
 #include "ui/gfx/color_utils.h"
 #include "ui/gfx/favicon_size.h"
+#include "ui/gfx/size.h"
 #include "ui/gfx/skbitmap_operations.h"
-#include "webkit/glue/image_decoder.h"
 
 namespace {
 
@@ -51,9 +52,8 @@
 }
 
 SkBitmap* ToBitmap(const unsigned char* data, size_t size) {
-  webkit_glue::ImageDecoder decoder;
   SkBitmap* decoded = new SkBitmap();
-  *decoded = decoder.Decode(data, size);
+  *decoded = content::DecodeImage(data, gfx::Size(), size);
   return decoded;
 }
 
diff --git a/chrome/browser/ui/webui/extensions/extension_info_ui.cc b/chrome/browser/ui/webui/extensions/extension_info_ui.cc
index e364066..456cc78 100644
--- a/chrome/browser/ui/webui/extensions/extension_info_ui.cc
+++ b/chrome/browser/ui/webui/extensions/extension_info_ui.cc
@@ -7,7 +7,7 @@
 #include "base/i18n/time_formatting.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/extensions/extension_prefs.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/extension_system.h"
diff --git a/chrome/browser/ui/webui/extensions/extension_settings_browsertest.js b/chrome/browser/ui/webui/extensions/extension_settings_browsertest.js
index 966a833..ed1f622 100644
--- a/chrome/browser/ui/webui/extensions/extension_settings_browsertest.js
+++ b/chrome/browser/ui/webui/extensions/extension_settings_browsertest.js
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// TODO(dbeam): test for loading upacked extensions?
+
 /**
  * TestFixture for extension settings WebUI testing.
  * @extends {testing.Test}
@@ -12,10 +14,46 @@
 ExtensionSettingsWebUITest.prototype = {
   __proto__: testing.Test.prototype,
 
+  /**
+   * A URL to load before starting each test.
+   * @type {string}
+   * @const
+   */
   browsePreload: 'chrome://extensions-frame/',
 };
 
-// Test opening extension settings has correct location.
-TEST_F('ExtensionSettingsWebUITest', 'testOpenExtensionSettings', function() {
+TEST_F('ExtensionSettingsWebUITest', 'testChromeSendHandled', function() {
   assertEquals(this.browsePreload, document.location.href);
+
+  // This dialog should be hidden at first.
+  assertFalse($('packExtensionOverlay').classList.contains('showing'));
+
+  // Show the dialog, which triggers a chrome.send() for metrics purposes.
+  cr.dispatchSimpleEvent($('pack-extension'), 'click');
+  assertTrue($('packExtensionOverlay').classList.contains('showing'));
+});
+
+/**
+ * TestFixture for extension settings WebUI testing (commands config edition).
+ * @extends {testing.Test}
+ * @constructor
+ */
+function ExtensionSettingsCommandsConfigWebUITest() {}
+
+ExtensionSettingsCommandsConfigWebUITest.prototype = {
+  __proto__: testing.Test.prototype,
+
+  /**
+   * A URL to load before starting each test.
+   * @type {string}
+   * @const
+   */
+  browsePreload: 'chrome://extensions-frame/configureCommands',
+};
+
+TEST_F('ExtensionSettingsCommandsConfigWebUITest', 'testChromeSendHandler',
+    function() {
+  // Just navigating to the page should trigger the chrome.send().
+  assertEquals(this.browsePreload, document.location.href);
+  assertTrue($('extensionCommandsOverlay').classList.contains('showing'));
 });
diff --git a/chrome/browser/ui/webui/extensions/extension_settings_handler.cc b/chrome/browser/ui/webui/extensions/extension_settings_handler.cc
index 770d234..240cbca 100644
--- a/chrome/browser/ui/webui/extensions/extension_settings_handler.cc
+++ b/chrome/browser/ui/webui/extensions/extension_settings_handler.cc
@@ -7,6 +7,7 @@
 #include "apps/app_load_service.h"
 #include "apps/app_restore_service.h"
 #include "apps/saved_files_service.h"
+#include "apps/shell_window.h"
 #include "base/auto_reset.h"
 #include "base/base64.h"
 #include "base/bind.h"
@@ -43,7 +44,6 @@
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/chrome_select_file_policy.h"
 #include "chrome/browser/ui/extensions/application_launch.h"
-#include "chrome/browser/ui/extensions/shell_window.h"
 #include "chrome/browser/ui/webui/extensions/extension_basic_info.h"
 #include "chrome/browser/ui/webui/extensions/extension_icon_source.h"
 #include "chrome/common/chrome_notification_types.h"
@@ -65,6 +65,7 @@
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/site_instance.h"
+#include "content/public/browser/user_metrics.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_view.h"
 #include "content/public/browser/web_ui.h"
@@ -319,7 +320,7 @@
   source->AddString("extensionSettingsPolicyControlled",
      l10n_util::GetStringUTF16(IDS_EXTENSIONS_POLICY_CONTROLLED));
   source->AddString("extensionSettingsManagedMode",
-     l10n_util::GetStringUTF16(IDS_EXTENSIONS_LOCKED_MANAGED_MODE));
+     l10n_util::GetStringUTF16(IDS_EXTENSIONS_LOCKED_MANAGED_USER));
   source->AddString("sideloadWipeoutUrl",
       chrome::kSideloadWipeoutHelpURL);
   source->AddString("sideloadWipoutLearnMore",
@@ -885,6 +886,8 @@
       base::FilePath::StringType(),
       web_ui()->GetWebContents()->GetView()->GetTopLevelNativeWindow(),
       NULL);
+
+  content::RecordComputedAction("Options_LoadUnpackedExtension");
 }
 
 void ExtensionSettingsHandler::ShowAlert(const std::string& message) {
diff --git a/chrome/browser/ui/webui/extensions/extensions_ui.cc b/chrome/browser/ui/webui/extensions/extensions_ui.cc
index 7d1b9de..25ab454 100644
--- a/chrome/browser/ui/webui/extensions/extensions_ui.cc
+++ b/chrome/browser/ui/webui/extensions/extensions_ui.cc
@@ -9,6 +9,7 @@
 #include "chrome/browser/ui/webui/extensions/extension_settings_handler.h"
 #include "chrome/browser/ui/webui/extensions/install_extension_handler.h"
 #include "chrome/browser/ui/webui/extensions/pack_extension_handler.h"
+#include "chrome/browser/ui/webui/metrics_handler.h"
 #include "chrome/common/url_constants.h"
 #include "content/public/browser/web_ui.h"
 #include "content/public/browser/web_ui_data_source.h"
@@ -66,6 +67,8 @@
   web_ui->AddMessageHandler(kiosk_app_handler);
 #endif
 
+  web_ui->AddMessageHandler(new MetricsHandler());
+
   content::WebUIDataSource::Add(profile, source);
 }
 
diff --git a/chrome/browser/ui/webui/extensions/install_extension_handler.cc b/chrome/browser/ui/webui/extensions/install_extension_handler.cc
index cb640b9..6ccf455 100644
--- a/chrome/browser/ui/webui/extensions/install_extension_handler.cc
+++ b/chrome/browser/ui/webui/extensions/install_extension_handler.cc
@@ -17,10 +17,10 @@
 #include "content/public/browser/web_contents_view.h"
 #include "content/public/browser/web_ui.h"
 #include "content/public/browser/web_ui_data_source.h"
+#include "content/public/common/drop_data.h"
 #include "grit/generated_resources.h"
 #include "net/base/net_util.h"
 #include "ui/base/l10n/l10n_util.h"
-#include "webkit/common/webdropdata.h"
 
 InstallExtensionHandler::InstallExtensionHandler() {
 }
@@ -54,7 +54,8 @@
 }
 
 void InstallExtensionHandler::HandleStartDragMessage(const ListValue* args) {
-  WebDropData* drop_data = web_ui()->GetWebContents()->GetView()->GetDropData();
+  content::DropData* drop_data =
+      web_ui()->GetWebContents()->GetView()->GetDropData();
   if (!drop_data) {
     DLOG(ERROR) << "No current drop data.";
     return;
@@ -65,7 +66,7 @@
     return;
   }
 
-  const WebDropData::FileInfo& file_info = drop_data->filenames.front();
+  const content::DropData::FileInfo& file_info = drop_data->filenames.front();
 
   file_to_install_ = base::FilePath::FromWStringHack(
       UTF16ToWide(file_info.path));
diff --git a/chrome/browser/ui/webui/feedback_ui.cc b/chrome/browser/ui/webui/feedback_ui.cc
index 042b6fc..3da8d3a 100644
--- a/chrome/browser/ui/webui/feedback_ui.cc
+++ b/chrome/browser/ui/webui/feedback_ui.cc
@@ -18,7 +18,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/download/download_prefs.h"
@@ -117,7 +117,6 @@
                            std::vector<std::string>* saved_screenshots,
                            base::Closure callback,
                            drive::FileError error,
-                           bool hide_hosted_documents,
                            scoped_ptr<drive::ResourceEntryVector> entries) {
   if (error != drive::FILE_ERROR_OK) {
     callback.Run();
diff --git a/chrome/browser/ui/webui/flags_ui.cc b/chrome/browser/ui/webui/flags_ui.cc
index 6a31619..b02441ee 100644
--- a/chrome/browser/ui/webui/flags_ui.cc
+++ b/chrome/browser/ui/webui/flags_ui.cc
@@ -36,6 +36,7 @@
 #include "base/chromeos/chromeos_version.h"
 #include "chrome/browser/chromeos/login/user_manager.h"
 #include "chrome/browser/chromeos/settings/cros_settings.h"
+#include "chrome/browser/chromeos/settings/owner_flags_storage.h"
 #include "components/user_prefs/pref_registry_syncable.h"
 #endif
 
@@ -98,8 +99,9 @@
 // The handler for Javascript messages for the about:flags page.
 class FlagsDOMHandler : public WebUIMessageHandler {
  public:
-  explicit FlagsDOMHandler(PrefService* prefs, about_flags::FlagAccess access)
-      : flags_storage_(prefs), access_(access) {}
+  FlagsDOMHandler(about_flags::FlagsStorage* flags_storage,
+                  about_flags::FlagAccess access)
+      : flags_storage_(flags_storage), access_(access) {}
   virtual ~FlagsDOMHandler() {}
 
   // WebUIMessageHandler implementation.
@@ -118,7 +120,7 @@
   void HandleResetAllFlags(const ListValue* args);
 
  private:
-  about_flags::PrefServiceFlagsStorage flags_storage_;
+  scoped_ptr<about_flags::FlagsStorage> flags_storage_;
   about_flags::FlagAccess access_;
 
   DISALLOW_COPY_AND_ASSIGN(FlagsDOMHandler);
@@ -142,7 +144,7 @@
 void FlagsDOMHandler::HandleRequestFlagsExperiments(const ListValue* args) {
   scoped_ptr<ListValue> supported_experiments(new ListValue);
   scoped_ptr<ListValue> unsupported_experiments(new ListValue);
-  about_flags::GetFlagsExperimentsData(&flags_storage_,
+  about_flags::GetFlagsExperimentsData(flags_storage_.get(),
                                        access_,
                                        supported_experiments.get(),
                                        unsupported_experiments.get());
@@ -177,7 +179,7 @@
     return;
 
   about_flags::SetExperimentEnabled(
-      &flags_storage_,
+      flags_storage_.get(),
       experiment_internal_name,
       enable_str == "true");
 }
@@ -187,7 +189,7 @@
 }
 
 void FlagsDOMHandler::HandleResetAllFlags(const ListValue* args) {
-  about_flags::ResetAllFlags(&flags_storage_);
+  about_flags::ResetAllFlags(flags_storage_.get());
 }
 
 }  // namespace
@@ -209,7 +211,8 @@
                  weak_factory_.GetWeakPtr(), profile));
 #else
   web_ui->AddMessageHandler(
-      new FlagsDOMHandler(g_browser_process->local_state(),
+      new FlagsDOMHandler(new about_flags::PrefServiceFlagsStorage(
+                              g_browser_process->local_state()),
                           about_flags::kOwnerAccessToFlags));
 
   // Set up the about:flags source.
@@ -245,18 +248,17 @@
     bool current_user_is_owner) {
   // On Chrome OS the owner can set system wide flags and other users can only
   // set flags for their own session.
-  if (!current_user_is_owner) {
+  if (current_user_is_owner) {
     web_ui()->AddMessageHandler(
-        new FlagsDOMHandler(profile->GetPrefs(),
-                            about_flags::kGeneralAccessFlagsOnly));
+        new FlagsDOMHandler(new chromeos::about_flags::OwnerFlagsStorage(
+                                profile->GetPrefs(),
+                                chromeos::CrosSettings::Get()),
+                            about_flags::kOwnerAccessToFlags));
   } else {
     web_ui()->AddMessageHandler(
-        new FlagsDOMHandler(g_browser_process->local_state(),
-                            about_flags::kOwnerAccessToFlags));
-    // If the owner managed to set the flags pref on his own profile clear it
-    // because it will never be accessible anymore.
-    if (profile->GetPrefs()->HasPrefPath(prefs::kEnabledLabsExperiments))
-      profile->GetPrefs()->ClearPref(prefs::kEnabledLabsExperiments);
+        new FlagsDOMHandler(new about_flags::PrefServiceFlagsStorage(
+                                profile->GetPrefs()),
+                            about_flags::kGeneralAccessFlagsOnly));
   }
 
   // Set up the about:flags source.
diff --git a/chrome/browser/ui/webui/flash_ui.cc b/chrome/browser/ui/webui/flash_ui.cc
index 1ef49ac..84a5eba 100644
--- a/chrome/browser/ui/webui/flash_ui.cc
+++ b/chrome/browser/ui/webui/flash_ui.cc
@@ -17,7 +17,7 @@
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/thread_restrictions.h"
-#include "base/timer.h"
+#include "base/timer/timer.h"
 #include "base/values.h"
 #include "chrome/browser/crash_upload_list.h"
 #include "chrome/browser/plugins/plugin_prefs.h"
@@ -90,7 +90,7 @@
   virtual void RegisterMessages() OVERRIDE;
 
   // CrashUploadList::Delegate implementation.
-  virtual void OnCrashListAvailable() OVERRIDE;
+  virtual void OnUploadListAvailable() OVERRIDE;
 
   // GpuDataManager::Observer implementation.
   virtual void OnGpuInfoUpdate() OVERRIDE;
@@ -142,7 +142,7 @@
       has_plugin_info_(false) {
   // Request Crash data asynchronously.
   upload_list_ = CrashUploadList::Create(this);
-  upload_list_->LoadCrashListAsynchronously();
+  upload_list_->LoadUploadListAsynchronously();
 
   // Watch for changes in GPUInfo.
   GpuDataManager::GetInstance()->AddObserver(this);
@@ -167,6 +167,7 @@
 
 FlashDOMHandler::~FlashDOMHandler() {
   GpuDataManager::GetInstance()->RemoveObserver(this);
+  upload_list_->ClearDelegate();
 }
 
 void FlashDOMHandler::RegisterMessages() {
@@ -175,7 +176,7 @@
                  base::Unretained(this)));
 }
 
-void FlashDOMHandler::OnCrashListAvailable() {
+void FlashDOMHandler::OnUploadListAvailable() {
   crash_list_available_ = true;
   MaybeRespondToPage();
 }
@@ -295,14 +296,14 @@
   AddPair(list, string16(), "--- Crash data ---");
   bool crash_reporting_enabled = CrashesUI::CrashReportingUIEnabled();
   if (crash_reporting_enabled) {
-    std::vector<CrashUploadList::CrashInfo> crashes;
-    upload_list_->GetUploadedCrashes(10, &crashes);
+    std::vector<CrashUploadList::UploadInfo> crashes;
+    upload_list_->GetUploads(10, &crashes);
 
-    for (std::vector<CrashUploadList::CrashInfo>::iterator i = crashes.begin();
+    for (std::vector<CrashUploadList::UploadInfo>::iterator i = crashes.begin();
          i != crashes.end(); ++i) {
-      string16 crash_string(ASCIIToUTF16(i->crash_id));
+      string16 crash_string(ASCIIToUTF16(i->id));
       crash_string += ASCIIToUTF16(" ");
-      crash_string += base::TimeFormatFriendlyDateAndTime(i->crash_time);
+      crash_string += base::TimeFormatFriendlyDateAndTime(i->time);
       AddPair(list, ASCIIToUTF16("crash id"), crash_string);
     }
   } else {
diff --git a/chrome/browser/ui/webui/help/help_handler.cc b/chrome/browser/ui/webui/help/help_handler.cc
index 3da02fd..3ca356a 100644
--- a/chrome/browser/ui/webui/help/help_handler.cc
+++ b/chrome/browser/ui/webui/help/help_handler.cc
@@ -23,6 +23,7 @@
 #include "chrome/browser/ui/send_feedback_experiment.h"
 #include "chrome/common/chrome_notification_types.h"
 #include "chrome/common/chrome_version_info.h"
+#include "chrome/common/pref_names.h"
 #include "chrome/common/url_constants.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/notification_service.h"
@@ -46,6 +47,9 @@
 #include "chrome/browser/chromeos/settings/cros_settings.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/webui/help/help_utils_chromeos.h"
+#include "chromeos/chromeos_switches.h"
+#include "chromeos/dbus/dbus_thread_manager.h"
+#include "chromeos/dbus/power_manager_client.h"
 #include "content/public/browser/browser_thread.h"
 #endif
 
@@ -89,17 +93,21 @@
   }
 }
 
-bool CanChangeReleaseChannel() {
-  // On non managed machines we have local owner who is the only one to change
-  // anything.
-  if (chromeos::UserManager::Get()->IsCurrentUserOwner())
-    return true;
+// Returns true if the device is enterprise managed, false otherwise.
+bool IsEnterpriseManaged() {
+  return g_browser_process->browser_policy_connector()->IsEnterpriseManaged();
+}
+
+// Returns true if current user can change channel, false otherwise.
+bool CanChangeChannel() {
+  bool value = false;
+  chromeos::CrosSettings::Get()->GetBoolean(chromeos::kReleaseChannelDelegated,
+                                            &value);
+
   // On a managed machine we delegate this setting to the users of the same
   // domain only if the policy value is "domain".
-  if (g_browser_process->browser_policy_connector()->IsEnterpriseManaged()) {
-    bool value = false;
-    if (!chromeos::CrosSettings::Get()->GetBoolean(
-            chromeos::kReleaseChannelDelegated, &value) || !value)
+  if (IsEnterpriseManaged()) {
+    if (!value)
       return false;
     // Get the currently logged in user and strip the domain part only.
     std::string domain = "";
@@ -109,6 +117,10 @@
       domain = user.substr(user.find('@') + 1);
     return domain == g_browser_process->browser_policy_connector()->
         GetEnterpriseDomain();
+  } else if (chromeos::UserManager::Get()->IsCurrentUserOwner()) {
+    // On non managed machines we have local owner who is the only one to change
+    // anything. Ensure that ReleaseChannelDelegated is false.
+    return !value;
   }
   return false;
 }
@@ -146,12 +158,22 @@
 #endif
     { "aboutProductDescription", IDS_ABOUT_PRODUCT_DESCRIPTION },
     { "relaunch", IDS_RELAUNCH_BUTTON },
+    { "relaunch", IDS_RELAUNCH_BUTTON },
+#if defined(OS_CHROMEOS)
+    { "relaunchAndPowerwash", IDS_RELAUNCH_AND_POWERWASH_BUTTON },
+#endif
     { "productName", IDS_PRODUCT_NAME },
     { "productCopyright", IDS_ABOUT_VERSION_COPYRIGHT },
     { "updateCheckStarted", IDS_UPGRADE_CHECK_STARTED },
     { "upToDate", IDS_UPGRADE_UP_TO_DATE },
     { "updating", IDS_UPGRADE_UPDATING },
+#if defined(OS_CHROMEOS)
+    { "updatingChannelSwitch", IDS_UPGRADE_UPDATING_CHANNEL_SWITCH },
+#endif
     { "updateAlmostDone", IDS_UPGRADE_SUCCESSFUL_RELAUNCH },
+#if defined(OS_CHROMEOS)
+    { "successfulChannelSwitch", IDS_UPGRADE_SUCCESSFUL_CHANNEL_SWITCH },
+#endif
     { "getHelpWithChrome", IDS_GET_HELP_USING_CHROME },
     { kResourceReportIssue, IDS_REPORT_AN_ISSUE },
 #if defined(OS_CHROMEOS)
@@ -164,6 +186,28 @@
     { "beta", IDS_ABOUT_PAGE_CHANNEL_BETA },
     { "dev", IDS_ABOUT_PAGE_CHANNEL_DEVELOPMENT },
     { "channel-changed", IDS_ABOUT_PAGE_CHANNEL_CHANGED },
+    { "currentChannelStable", IDS_ABOUT_PAGE_CURRENT_CHANNEL_STABLE },
+    { "currentChannelBeta", IDS_ABOUT_PAGE_CURRENT_CHANNEL_BETA },
+    { "currentChannelDev", IDS_ABOUT_PAGE_CURRENT_CHANNEL_DEV },
+    { "currentChannel", IDS_ABOUT_PAGE_CURRENT_CHANNEL },
+    { "channelChangeButton", IDS_ABOUT_PAGE_CHANNEL_CHANGE_BUTTON },
+    { "channelChangeDisallowedMessage",
+      IDS_ABOUT_PAGE_CHANNEL_CHANGE_DISALLOWED_MESSAGE },
+    { "channelChangePageTitle", IDS_ABOUT_PAGE_CHANNEL_CHANGE_PAGE_TITLE },
+    { "channelChangePagePowerwashTitle",
+      IDS_ABOUT_PAGE_CHANNEL_CHANGE_PAGE_POWERWASH_TITLE },
+    { "channelChangePagePowerwashMessage",
+      IDS_ABOUT_PAGE_CHANNEL_CHANGE_PAGE_POWERWASH_MESSAGE },
+    { "channelChangePageDelayedChangeTitle",
+      IDS_ABOUT_PAGE_CHANNEL_CHANGE_PAGE_DELAYED_CHANGE_TITLE },
+    { "channelChangePageUnstableTitle",
+      IDS_ABOUT_PAGE_CHANNEL_CHANGE_PAGE_UNSTABLE_TITLE },
+    { "channelChangePagePowerwashButton",
+      IDS_ABOUT_PAGE_CHANNEL_CHANGE_PAGE_POWERWASH_BUTTON },
+    { "channelChangePageChangeButton",
+      IDS_ABOUT_PAGE_CHANNEL_CHANGE_PAGE_CHANGE_BUTTON },
+    { "channelChangePageCancelButton",
+      IDS_ABOUT_PAGE_CHANNEL_CHANGE_PAGE_CANCEL_BUTTON },
     { "webkit", IDS_WEBKIT },
     { "userAgent", IDS_ABOUT_VERSION_USER_AGENT },
     { "commandLine", IDS_ABOUT_VERSION_COMMAND_LINE },
@@ -206,6 +250,23 @@
       IDS_ABOUT_CROS_VERSION_LICENSE,
       ASCIIToUTF16(chrome::kChromeUIOSCreditsURL));
   source->AddString("productOsLicense", os_license);
+
+  string16 product_name = l10n_util::GetStringUTF16(IDS_PRODUCT_OS_NAME);
+  source->AddString(
+      "channelChangePageDelayedChangeMessage",
+      l10n_util::GetStringFUTF16(
+          IDS_ABOUT_PAGE_CHANNEL_CHANGE_PAGE_DELAYED_CHANGE_MESSAGE,
+          product_name));
+  source->AddString(
+      "channelChangePageUnstableMessage",
+      l10n_util::GetStringFUTF16(
+          IDS_ABOUT_PAGE_CHANNEL_CHANGE_PAGE_UNSTABLE_MESSAGE,
+          product_name));
+
+  if (CommandLine::ForCurrentProcess()->
+      HasSwitch(chromeos::switches::kDisableNewChannelSwitcherUI)) {
+    source->AddBoolean("disableNewChannelSwitcherUI", true);
+  }
 #endif
 
   string16 tos = l10n_util::GetStringFUTF16(
@@ -237,8 +298,10 @@
   web_ui()->RegisterMessageCallback("openHelpPage",
       base::Bind(&HelpHandler::OpenHelpPage, base::Unretained(this)));
 #if defined(OS_CHROMEOS)
-  web_ui()->RegisterMessageCallback("setReleaseTrack",
-      base::Bind(&HelpHandler::SetReleaseTrack, base::Unretained(this)));
+  web_ui()->RegisterMessageCallback("setChannel",
+      base::Bind(&HelpHandler::SetChannel, base::Unretained(this)));
+  web_ui()->RegisterMessageCallback("relaunchAndPowerwash",
+      base::Bind(&HelpHandler::RelaunchAndPowerwash, base::Unretained(this)));
 #endif
 #if defined(OS_MACOSX)
   web_ui()->RegisterMessageCallback("promoteUpdater",
@@ -278,7 +341,7 @@
 
   web_ui()->CallJavascriptFunction(
       "help.HelpPage.updateEnableReleaseChannel",
-      base::FundamentalValue(CanChangeReleaseChannel()));
+      base::FundamentalValue(CanChangeChannel()));
 
   if (g_build_date_string == NULL) {
     // If |g_build_date_string| is |NULL|, the date has not yet been assigned.
@@ -302,8 +365,16 @@
       );
 
 #if defined(OS_CHROMEOS)
-  version_updater_->GetReleaseChannel(
-      base::Bind(&HelpHandler::OnReleaseChannel, base::Unretained(this)));
+  web_ui()->CallJavascriptFunction(
+      "help.HelpPage.updateIsEnterpriseManaged",
+      base::FundamentalValue(IsEnterpriseManaged()));
+  // First argument to GetChannel() is a flag that indicates whether
+  // current channel should be returned (if true) or target channel
+  // (otherwise).
+  version_updater_->GetChannel(true,
+      base::Bind(&HelpHandler::OnCurrentChannel, weak_factory_.GetWeakPtr()));
+  version_updater_->GetChannel(false,
+      base::Bind(&HelpHandler::OnTargetChannel, weak_factory_.GetWeakPtr()));
 #endif
 }
 
@@ -334,27 +405,45 @@
 
 #if defined(OS_CHROMEOS)
 
-void HelpHandler::SetReleaseTrack(const ListValue* args) {
-  if (!CanChangeReleaseChannel()) {
+void HelpHandler::SetChannel(const ListValue* args) {
+  DCHECK(args->GetSize() == 2);
+
+  if (!CanChangeChannel()) {
     LOG(WARNING) << "Non-owner tried to change release track.";
     return;
   }
 
-  const std::string channel = UTF16ToUTF8(ExtractStringValue(args));
-  version_updater_->SetReleaseChannel(channel);
-  // On enterprise machines we can only use SetReleaseChannel to store the
-  // user choice in the lsb-release file but we can not modify the policy blob.
-  // Therefore we only call SetString if the device is locally owned and the
-  // currently logged in user is the owner.
+  base::string16 channel;
+  bool is_powerwash_allowed;
+  if (!args->GetString(0, &channel) ||
+      !args->GetBoolean(1, &is_powerwash_allowed)) {
+    LOG(ERROR) << "Can't parse SetReleaseTrack() args";
+    return;
+  }
+
+  version_updater_->SetChannel(UTF16ToUTF8(channel), is_powerwash_allowed);
   if (chromeos::UserManager::Get()->IsCurrentUserOwner()) {
-    chromeos::CrosSettings::Get()->SetString(chromeos::kReleaseChannel,
-                                             channel);
     // Check for update after switching release channel.
     version_updater_->CheckForUpdate(base::Bind(&HelpHandler::SetUpdateStatus,
                                                 base::Unretained(this)));
   }
 }
 
+void HelpHandler::RelaunchAndPowerwash(const ListValue* args) {
+  DCHECK(args->empty());
+
+  if (IsEnterpriseManaged())
+    return;
+
+  PrefService* prefs = g_browser_process->local_state();
+  prefs->SetBoolean(prefs::kFactoryResetRequested, true);
+  prefs->CommitPendingWrite();
+
+  // Perform sign out. Current chrome process will then terminate, new one will
+  // be launched (as if it was a restart).
+  chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->RequestRestart();
+}
+
 #endif  // defined(OS_CHROMEOS)
 
 void HelpHandler::SetUpdateStatus(VersionUpdater::Status status,
@@ -447,9 +536,14 @@
                                    base::StringValue(firmware));
 }
 
-void HelpHandler::OnReleaseChannel(const std::string& channel) {
+void HelpHandler::OnCurrentChannel(const std::string& channel) {
   web_ui()->CallJavascriptFunction(
-      "help.HelpPage.updateSelectedChannel", base::StringValue(channel));
+      "help.HelpPage.updateCurrentChannel", base::StringValue(channel));
+}
+
+void HelpHandler::OnTargetChannel(const std::string& channel) {
+  web_ui()->CallJavascriptFunction(
+      "help.HelpPage.updateTargetChannel", base::StringValue(channel));
 }
 
 void HelpHandler::ProcessLsbFileInfo(
diff --git a/chrome/browser/ui/webui/help/help_handler.h b/chrome/browser/ui/webui/help/help_handler.h
index 397c023..0f25dab 100644
--- a/chrome/browser/ui/webui/help/help_handler.h
+++ b/chrome/browser/ui/webui/help/help_handler.h
@@ -60,7 +60,10 @@
 
 #if defined(OS_CHROMEOS)
   // Sets the release track version.
-  void SetReleaseTrack(const base::ListValue* args);
+  void SetChannel(const base::ListValue* args);
+
+  // Performs relaunch and powerwash.
+  void RelaunchAndPowerwash(const base::ListValue* args);
 #endif
 
   // Callback method which forwards status updates to the page.
@@ -76,7 +79,8 @@
   // Callbacks from VersionLoader.
   void OnOSVersion(const std::string& version);
   void OnOSFirmware(const std::string& firmware);
-  void OnReleaseChannel(const std::string& channel);
+  void OnCurrentChannel(const std::string& channel);
+  void OnTargetChannel(const std::string& channel);
 
   void ProcessLsbFileInfo(
       base::PlatformFileError rv, const base::PlatformFileInfo& file_info);
diff --git a/chrome/browser/ui/webui/help/help_ui.cc b/chrome/browser/ui/webui/help/help_ui.cc
index f7694ba..0d48728 100644
--- a/chrome/browser/ui/webui/help/help_ui.cc
+++ b/chrome/browser/ui/webui/help/help_ui.cc
@@ -21,6 +21,7 @@
   source->SetJsonPath("strings.js");
   source->SetUseJsonJSFormatV2();
   source->AddResourcePath("help.js", IDR_HELP_JS);
+  source->AddResourcePath("channel_change_page.js", IDR_CHANNEL_CHANGE_PAGE_JS);
   source->SetDefaultResource(IDR_HELP_HTML);
   source->DisableDenyXFrameOptions();
   return source;
diff --git a/chrome/browser/ui/webui/help/version_updater.h b/chrome/browser/ui/webui/help/version_updater.h
index 76e381f..a78444d 100644
--- a/chrome/browser/ui/webui/help/version_updater.h
+++ b/chrome/browser/ui/webui/help/version_updater.h
@@ -75,8 +75,10 @@
   virtual void RelaunchBrowser() const = 0;
 
 #if defined(OS_CHROMEOS)
-  virtual void SetReleaseChannel(const std::string& channel) = 0;
-  virtual void GetReleaseChannel(const ChannelCallback& callback) = 0;
+  virtual void SetChannel(const std::string& channel,
+                          bool is_powerwash_allowed) = 0;
+  virtual void GetChannel(bool get_current_channel,
+                          const ChannelCallback& callback) = 0;
 #endif
 };
 
diff --git a/chrome/browser/ui/webui/help/version_updater_chromeos.cc b/chrome/browser/ui/webui/help/version_updater_chromeos.cc
index 1ea7be5..9532bc4 100644
--- a/chrome/browser/ui/webui/help/version_updater_chromeos.cc
+++ b/chrome/browser/ui/webui/help/version_updater_chromeos.cc
@@ -8,11 +8,13 @@
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
+#include "chrome/browser/browser_process.h"
 #include "chrome/browser/chromeos/login/startup_utils.h"
 #include "chrome/browser/chromeos/login/user_manager.h"
 #include "chrome/browser/chromeos/login/wizard_controller.h"
 #include "chrome/browser/chromeos/settings/cros_settings.h"
 #include "chrome/browser/chromeos/settings/cros_settings_names.h"
+#include "chrome/browser/policy/browser_policy_connector.h"
 #include "chrome/browser/ui/webui/help/help_utils_chromeos.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/power_manager_client.h"
@@ -125,25 +127,28 @@
   DBusThreadManager::Get()->GetPowerManagerClient()->RequestRestart();
 }
 
-void VersionUpdaterCros::SetReleaseChannel(const std::string& channel) {
-  DBusThreadManager::Get()->GetUpdateEngineClient()->SetReleaseTrack(channel);
-  // For local owner set the field in the policy blob too.
-  if (UserManager::Get()->IsCurrentUserOwner())
+void VersionUpdaterCros::SetChannel(const std::string& channel,
+                                    bool is_powerwash_allowed) {
+  // On enterprise machines we can only use SetChannel to store the
+  // user choice in the lsb-release file but we can not modify the
+  // policy blob.  Therefore we only call SetString if the device is
+  // locally owned and the currently logged in user is the owner.
+  if (g_browser_process->browser_policy_connector()->IsEnterpriseManaged()) {
+    DBusThreadManager::Get()->GetUpdateEngineClient()->
+        SetChannel(channel, is_powerwash_allowed);
+  } else if (UserManager::Get()->IsCurrentUserOwner()) {
+    // For local owner set the field in the policy blob.
     CrosSettings::Get()->SetString(chromeos::kReleaseChannel, channel);
+  }
 }
 
-void VersionUpdaterCros::GetReleaseChannel(const ChannelCallback& cb) {
-  channel_callback_ = cb;
-
-  // TODO(jhawkins): Store on this object.
+void VersionUpdaterCros::GetChannel(bool get_current_channel,
+                                    const ChannelCallback& cb) {
   UpdateEngineClient* update_engine_client =
       DBusThreadManager::Get()->GetUpdateEngineClient();
 
-  // Request the channel information. Use the observer to track the help page
-  // handler and ensure it does not get deleted before the callback.
-  update_engine_client->GetReleaseTrack(
-      base::Bind(&VersionUpdaterCros::UpdateSelectedChannel,
-                 weak_ptr_factory_.GetWeakPtr()));
+  // Request the channel information.
+  update_engine_client->GetChannel(get_current_channel, cb);
 }
 
 VersionUpdaterCros::VersionUpdaterCros()
@@ -215,7 +220,3 @@
   if (result == UpdateEngineClient::UPDATE_RESULT_NOTIMPLEMENTED)
     callback_.Run(UPDATED, 0, string16());
 }
-
-void VersionUpdaterCros::UpdateSelectedChannel(const std::string& channel) {
-  channel_callback_.Run(channel);
-}
diff --git a/chrome/browser/ui/webui/help/version_updater_chromeos.h b/chrome/browser/ui/webui/help/version_updater_chromeos.h
index ffd4782..59bbecd 100644
--- a/chrome/browser/ui/webui/help/version_updater_chromeos.h
+++ b/chrome/browser/ui/webui/help/version_updater_chromeos.h
@@ -16,8 +16,10 @@
   // VersionUpdater implementation.
   virtual void CheckForUpdate(const StatusCallback& callback) OVERRIDE;
   virtual void RelaunchBrowser() const OVERRIDE;
-  virtual void SetReleaseChannel(const std::string& channel) OVERRIDE;
-  virtual void GetReleaseChannel(const ChannelCallback& callback) OVERRIDE;
+  virtual void SetChannel(const std::string& channel,
+                          bool is_powerwash_allowed) OVERRIDE;
+  virtual void GetChannel(bool get_current_channel,
+                          const ChannelCallback& callback) OVERRIDE;
 
  protected:
   friend class VersionUpdater;
@@ -34,15 +36,9 @@
   // Callback from UpdateEngineClient::RequestUpdateCheck().
   void OnUpdateCheck(chromeos::UpdateEngineClient::UpdateCheckResult result);
 
-  // Callback from UpdateEngineClient::GetReleaseTrack().
-  void UpdateSelectedChannel(const std::string& channel);
-
   // Callback used to communicate update status to the client.
   StatusCallback callback_;
 
-  // Callback used to communicate current channel to the client.
-  ChannelCallback channel_callback_;
-
   // Last state received via UpdateStatusChanged().
   chromeos::UpdateEngineClient::UpdateStatusOperation last_operation_;
 
diff --git a/chrome/browser/ui/webui/help/version_updater_mac.h b/chrome/browser/ui/webui/help/version_updater_mac.h
index 2b705d7..f2a82bc 100644
--- a/chrome/browser/ui/webui/help/version_updater_mac.h
+++ b/chrome/browser/ui/webui/help/version_updater_mac.h
@@ -8,7 +8,7 @@
 #import <AppKit/AppKit.h>
 
 #include "base/compiler_specific.h"
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "chrome/browser/ui/webui/help/version_updater.h"
 
 @class KeystoneObserver;
@@ -50,7 +50,7 @@
   bool show_promote_button_;
 
   // The observer that will receive keystone status updates.
-  scoped_nsobject<KeystoneObserver> keystone_observer_;
+  base::scoped_nsobject<KeystoneObserver> keystone_observer_;
 
   DISALLOW_COPY_AND_ASSIGN(VersionUpdaterMac);
 };
diff --git a/chrome/browser/ui/webui/help/version_updater_win.cc b/chrome/browser/ui/webui/help/version_updater_win.cc
index 59482d2..3d1a7ad 100644
--- a/chrome/browser/ui/webui/help/version_updater_win.cc
+++ b/chrome/browser/ui/webui/help/version_updater_win.cc
@@ -214,13 +214,17 @@
     case UPGRADE_ERROR: {
       content::RecordAction(UserMetricsAction("UpgradeCheck_Error"));
       status = FAILED;
-      if (error_code != GOOGLE_UPDATE_DISABLED_BY_POLICY) {
-        message =
-            l10n_util::GetStringFUTF16Int(IDS_UPGRADE_ERROR, error_code);
-      } else {
+      if (error_code == GOOGLE_UPDATE_DISABLED_BY_POLICY) {
         message =
             l10n_util::GetStringUTF16(IDS_UPGRADE_DISABLED_BY_POLICY);
+      } else if (error_code == GOOGLE_UPDATE_DISABLED_BY_POLICY_AUTO_ONLY) {
+        message =
+            l10n_util::GetStringUTF16(IDS_UPGRADE_DISABLED_BY_POLICY_MANUAL);
+      } else {
+        message =
+            l10n_util::GetStringFUTF16Int(IDS_UPGRADE_ERROR, error_code);
       }
+
       if (!error_message.empty()) {
         message +=
             l10n_util::GetStringFUTF16(IDS_ABOUT_BOX_ERROR_DURING_UPDATE_CHECK,
diff --git a/chrome/browser/ui/webui/history_ui.cc b/chrome/browser/ui/webui/history_ui.cc
index 0b93651..ddcc5bb 100644
--- a/chrome/browser/ui/webui/history_ui.cc
+++ b/chrome/browser/ui/webui/history_ui.cc
@@ -18,7 +18,7 @@
 #include "base/strings/string16.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "base/values.h"
 #include "chrome/browser/bookmarks/bookmark_model.h"
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
@@ -40,6 +40,7 @@
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/chrome_pages.h"
 #include "chrome/browser/ui/webui/favicon_source.h"
+#include "chrome/browser/ui/webui/metrics_handler.h"
 #include "chrome/common/chrome_notification_types.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
@@ -962,6 +963,7 @@
 
 HistoryUI::HistoryUI(content::WebUI* web_ui) : WebUIController(web_ui) {
   web_ui->AddMessageHandler(new BrowsingHistoryHandler());
+  web_ui->AddMessageHandler(new MetricsHandler());
 
 // On mobile we deal with foreign sessions differently.
 #if !defined(OS_ANDROID) && !defined(OS_IOS)
diff --git a/chrome/browser/ui/webui/history_ui.h b/chrome/browser/ui/webui/history_ui.h
index 2d67292..318db25 100644
--- a/chrome/browser/ui/webui/history_ui.h
+++ b/chrome/browser/ui/webui/history_ui.h
@@ -6,7 +6,7 @@
 #define CHROME_BROWSER_UI_WEBUI_HISTORY_UI_H_
 
 #include "base/strings/string16.h"
-#include "base/timer.h"
+#include "base/timer/timer.h"
 #include "base/values.h"
 #include "chrome/browser/common/cancelable_request.h"
 #include "chrome/browser/history/history_service.h"
diff --git a/chrome/browser/ui/webui/identity_internals_ui.cc b/chrome/browser/ui/webui/identity_internals_ui.cc
index 00e03df..e575e49 100644
--- a/chrome/browser/ui/webui/identity_internals_ui.cc
+++ b/chrome/browser/ui/webui/identity_internals_ui.cc
@@ -32,7 +32,7 @@
 const char kScopes[] = "scopes";
 const char kStatus[] = "status";
 const char kTokenExpirationTime[] = "expirationTime";
-const char kTokenId[] = "tokenId";
+const char kAccessToken[] = "accessToken";
 
 // RevokeToken message parameter offsets.
 const int kRevokeTokenExtensionOffset = 0;
@@ -40,6 +40,7 @@
 
 class IdentityInternalsTokenRevoker;
 
+// Class acting as a controller of the chrome://identity-internals WebUI.
 class IdentityInternalsUIMessageHandler : public content::WebUIMessageHandler {
  public:
   IdentityInternalsUIMessageHandler();
@@ -54,26 +55,41 @@
   virtual void RegisterMessages() OVERRIDE;
 
  private:
+  // Gets the name of an extension referred to by |token_cache_key| as a string.
   const std::string GetExtensionName(
       const extensions::IdentityAPI::TokenCacheKey& token_cache_key);
 
+  // Gets a list of scopes specified in |token_cache_key| and returns a pointer
+  // to a ListValue containing the scopes. The caller gets ownership of the
+  // returned object.
   ListValue* GetScopes(
       const extensions::IdentityAPI::TokenCacheKey& token_cache_key);
 
+  // Gets a localized status of the access token in |token_cache_value|.
   const base::string16 GetStatus(
       const extensions::IdentityTokenCacheValue& token_cache_value);
 
+  // Gets a string representation of an expiration time of the access token in
+  // |token_cache_value|.
   const std::string GetExpirationTime(
       const extensions::IdentityTokenCacheValue& token_cache_value);
 
+  // Converts a pair of |token_cache_key| and |token_cache_value| to a
+  // DictionaryValue object with corresponding information in a localized and
+  // readable form and returns a pointer to created object. Caller gets the
+  // ownership of the returned object.
   DictionaryValue* GetInfoForToken(
       const extensions::IdentityAPI::TokenCacheKey& token_cache_key,
       const extensions::IdentityTokenCacheValue& token_cache_value);
 
+  // Gets all of the tokens stored in IdentityAPI token cache and returns them
+  // to the caller using Javascript callback function
+  // |identity_internals.returnTokens()|.
   void GetInfoForAllTokens(const ListValue* args);
 
   // Initiates revoking of the token, based on the extension ID and token
-  // passed as entries in the args list.
+  // passed as entries in the |args| list. Updates the caller of completion
+  // using Javascript callback function |identity_internals.tokenRevokeDone()|.
   void RevokeToken(const ListValue* args);
 
   // A vector of token revokers that are currently revoking tokens.
@@ -192,7 +208,7 @@
   token_data->SetString(kExtensionName, GetExtensionName(token_cache_key));
   token_data->Set(kScopes, GetScopes(token_cache_key));
   token_data->SetString(kStatus, GetStatus(token_cache_value));
-  token_data->SetString(kTokenId, token_cache_value.token());
+  token_data->SetString(kAccessToken, token_cache_value.token());
   token_data->SetString(kTokenExpirationTime,
                         GetExpirationTime(token_cache_value));
   return token_data;
@@ -262,8 +278,8 @@
   // Localized strings
   html_source->AddLocalizedString("tokenCacheHeader",
       IDS_IDENTITY_INTERNALS_TOKEN_CACHE_TEXT);
-  html_source->AddLocalizedString("tokenId",
-      IDS_IDENTITY_INTERNALS_TOKEN_ID);
+  html_source->AddLocalizedString("accessToken",
+      IDS_IDENTITY_INTERNALS_ACCESS_TOKEN);
   html_source->AddLocalizedString("extensionName",
       IDS_IDENTITY_INTERNALS_EXTENSION_NAME);
   html_source->AddLocalizedString("extensionId",
diff --git a/chrome/browser/ui/webui/identity_internals_ui_browsertest.cc b/chrome/browser/ui/webui/identity_internals_ui_browsertest.cc
index ec45499..aba132d 100644
--- a/chrome/browser/ui/webui/identity_internals_ui_browsertest.cc
+++ b/chrome/browser/ui/webui/identity_internals_ui_browsertest.cc
@@ -5,7 +5,7 @@
 #include "chrome/browser/ui/webui/identity_internals_ui_browsertest.h"
 
 #include "base/strings/string_number_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/extensions/api/identity/identity_api.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
diff --git a/chrome/browser/ui/webui/identity_internals_ui_browsertest.js b/chrome/browser/ui/webui/identity_internals_ui_browsertest.js
index 09163b3..67a6cb6 100644
--- a/chrome/browser/ui/webui/identity_internals_ui_browsertest.js
+++ b/chrome/browser/ui/webui/identity_internals_ui_browsertest.js
@@ -79,8 +79,8 @@
    * @param {Element} tokenEntry Display element holding token information.
    * @return {string} Token ID of the token.
    */
-  getTokenId: function(tokenEntry) {
-    return tokenEntry.querySelector('.token-id').innerText;
+  getAccessToken: function(tokenEntry) {
+    return tokenEntry.querySelector('.access-token').innerText;
   },
 
   /**
@@ -135,7 +135,7 @@
   expectEquals('Store', this.getExtensionName(tokenListEntries[0]));
   expectEquals('ahfgeienlihckogmohjhadlkjgocpleb',
                this.getExtensionId(tokenListEntries[0]));
-  expectEquals('store_token', this.getTokenId(tokenListEntries[0]));
+  expectEquals('store_token', this.getAccessToken(tokenListEntries[0]));
   expectEquals('Token Present', this.getTokenStatus(tokenListEntries[0]));
   expectLT(this.getExpirationTime(tokenListEntries[0]) - new Date(),
            3600 * 1000);
@@ -158,8 +158,8 @@
       tokenListEntries[0].querySelector('.extension-name').innerText);
   expectEquals(this.getExtensionId(tokenListEntries[0]),
       tokenListEntries[0].querySelector('.extension-id').innerText);
-  expectEquals(this.getTokenId(tokenListEntries[0]),
-      tokenListEntries[0].querySelector('.token-id').innerText);
+  expectEquals(this.getAccessToken(tokenListEntries[0]),
+      tokenListEntries[0].querySelector('.access-token').innerText);
   expectEquals(this.getTokenStatus(tokenListEntries[0]),
       tokenListEntries[0].querySelector('.token-status').innerText);
   expectEquals(this.getExpirationTime(tokenListEntries[0]),
@@ -200,7 +200,7 @@
   expectEquals('', this.getExtensionName(tokenListEntries[0]));
   expectEquals('extension0',
                this.getExtensionId(tokenListEntries[0]));
-  expectEquals('token0', this.getTokenId(tokenListEntries[0]));
+  expectEquals('token0', this.getAccessToken(tokenListEntries[0]));
   expectEquals('Token Present', this.getTokenStatus(tokenListEntries[0]));
   expectLT(this.getExpirationTime(tokenListEntries[0]) - new Date(),
            3600 * 1000);
@@ -212,7 +212,7 @@
   expectEquals('', this.getExtensionName(tokenListEntries[1]));
   expectEquals('extension1',
                this.getExtensionId(tokenListEntries[1]));
-  expectEquals('token1', this.getTokenId(tokenListEntries[1]));
+  expectEquals('token1', this.getAccessToken(tokenListEntries[1]));
   expectEquals('Token Present', this.getTokenStatus(tokenListEntries[1]));
   expectLT(this.getExpirationTime(tokenListEntries[1]) - new Date(),
            3600 * 1000);
@@ -243,13 +243,13 @@
   expectEquals(2, tokenListBefore.length);
   var tokenRevokeDone = identity_internals.tokenRevokeDone;
   identity_internals.tokenRevokeDone = this.continueTest(
-      WhenTestDone.ALWAYS, function (tokenIds) {
-        tokenRevokeDone.call(identity_internals, tokenIds);
+      WhenTestDone.ALWAYS, function (accessTokens) {
+        tokenRevokeDone.call(identity_internals, accessTokens);
         identity_internals.tokenRevokeDone = tokenRevokeDone;
         var tokenListAfter = this.getTokens();
         expectEquals(1, tokenListAfter.length);
-        expectEquals(this.getTokenId(tokenListBefore[0]),
-                     this.getTokenId(tokenListAfter[0]));
+        expectEquals(this.getAccessToken(tokenListBefore[0]),
+                     this.getAccessToken(tokenListAfter[0]));
       }.bind(this));
   this.getRevokeButton(tokenListBefore[1]).click();
 });
diff --git a/chrome/browser/ui/webui/inline_login_ui.cc b/chrome/browser/ui/webui/inline_login_ui.cc
index 55f3a1b..8683184 100644
--- a/chrome/browser/ui/webui/inline_login_ui.cc
+++ b/chrome/browser/ui/webui/inline_login_ui.cc
@@ -13,6 +13,7 @@
 #include "chrome/browser/signin/token_service.h"
 #include "chrome/browser/signin/token_service_factory.h"
 #include "chrome/browser/ui/sync/one_click_signin_sync_starter.h"
+#include "chrome/browser/ui/sync/sync_promo_ui.h"
 #include "chrome/common/url_constants.h"
 #include "content/public/browser/web_ui.h"
 #include "content/public/browser/web_ui_data_source.h"
@@ -131,7 +132,8 @@
         UTF16ToASCII(email), UTF16ToASCII(password),
         OneClickSigninSyncStarter::SYNC_WITH_DEFAULT_SETTINGS,
         true /* force_same_tab_navigation */,
-        OneClickSigninSyncStarter::NO_CONFIRMATION);
+        OneClickSigninSyncStarter::NO_CONFIRMATION,
+        SyncPromoUI::SOURCE_UNKNOWN);
     web_ui()->CallJavascriptFunction("inline.login.closeDialog");
 #endif
   }
diff --git a/chrome/browser/ui/webui/instant_ui.cc b/chrome/browser/ui/webui/instant_ui.cc
index 289e83d..d399753 100644
--- a/chrome/browser/ui/webui/instant_ui.cc
+++ b/chrome/browser/ui/webui/instant_ui.cc
@@ -7,7 +7,7 @@
 #include "base/bind.h"
 #include "base/prefs/pref_service.h"
 #include "base/strings/stringprintf.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_finder.h"
diff --git a/chrome/browser/ui/webui/media/webrtc_logs_ui.cc b/chrome/browser/ui/webui/media/webrtc_logs_ui.cc
new file mode 100644
index 0000000..54de606
--- /dev/null
+++ b/chrome/browser/ui/webui/media/webrtc_logs_ui.cc
@@ -0,0 +1,196 @@
+// 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/ui/webui/media/webrtc_logs_ui.h"
+
+#include <vector>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/i18n/time_formatting.h"
+#include "base/memory/ref_counted_memory.h"
+#include "base/prefs/pref_service.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/values.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/media/webrtc_log_upload_list.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/common/chrome_version_info.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/common/url_constants.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_ui.h"
+#include "content/public/browser/web_ui_data_source.h"
+#include "content/public/browser/web_ui_message_handler.h"
+#include "grit/browser_resources.h"
+#include "grit/chromium_strings.h"
+#include "grit/generated_resources.h"
+#include "grit/theme_resources.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/resource/resource_bundle.h"
+
+#if defined(OS_CHROMEOS)
+#include "chrome/browser/chromeos/settings/cros_settings.h"
+#endif
+
+using content::WebContents;
+using content::WebUIMessageHandler;
+
+namespace {
+
+content::WebUIDataSource* CreateWebRtcLogsUIHTMLSource() {
+  content::WebUIDataSource* source =
+      content::WebUIDataSource::Create(chrome::kChromeUIWebRtcLogsHost);
+  source->SetUseJsonJSFormatV2();
+
+  source->AddLocalizedString("webrtcLogsTitle", IDS_WEBRTC_LOGS_TITLE);
+  source->AddLocalizedString("webrtcLogCountFormat",
+                             IDS_WEBRTC_LOGS_LOG_COUNT_BANNER_FORMAT);
+  source->AddLocalizedString("webrtcLogHeaderFormat",
+                             IDS_WEBRTC_LOGS_LOG_HEADER_FORMAT);
+  source->AddLocalizedString("webrtcLogTimeFormat",
+                             IDS_WEBRTC_LOGS_LOG_TIME_FORMAT);
+  source->AddLocalizedString("bugLinkText", IDS_WEBRTC_LOGS_BUG_LINK_LABEL);
+  source->AddLocalizedString("noLogsMessage",
+                             IDS_WEBRTC_LOGS_NO_LOGS_MESSAGE);
+  source->AddLocalizedString("disabledHeader", IDS_WEBRTC_LOGS_DISABLED_HEADER);
+  source->AddLocalizedString("disabledMessage",
+                             IDS_WEBRTC_LOGS_DISABLED_MESSAGE);
+  source->SetJsonPath("strings.js");
+  source->AddResourcePath("webrtc_logs.js", IDR_WEBRTC_LOGS_JS);
+  source->SetDefaultResource(IDR_WEBRTC_LOGS_HTML);
+  return source;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// WebRtcLogsDOMHandler
+//
+////////////////////////////////////////////////////////////////////////////////
+
+// The handler for Javascript messages for the chrome://webrtc-logs/ page.
+class WebRtcLogsDOMHandler : public WebUIMessageHandler,
+                             public WebRtcLogUploadList::Delegate {
+ public:
+  explicit WebRtcLogsDOMHandler();
+  virtual ~WebRtcLogsDOMHandler();
+
+  // WebUIMessageHandler implementation.
+  virtual void RegisterMessages() OVERRIDE;
+
+  // WebRtcLogUploadList::Delegate implemenation.
+  virtual void OnUploadListAvailable() OVERRIDE;
+
+ private:
+  // Asynchronously fetches the list of upload WebRTC logs. Called from JS.
+  void HandleRequestWebRtcLogs(const ListValue* args);
+
+  // Sends the recently uploaded logs list JS.
+  void UpdateUI();
+
+  // Loads, parses and stores the list of uploaded WebRTC logs.
+  scoped_refptr<WebRtcLogUploadList> upload_list_;
+
+  // Set when |upload_list_| has finished populating the list of logs.
+  bool list_available_;
+
+  // Set when the webpage wants to update the list (on the webpage) but
+  // |upload_list_| hasn't finished populating the list of logs yet.
+  bool js_request_pending_;
+
+  DISALLOW_COPY_AND_ASSIGN(WebRtcLogsDOMHandler);
+};
+
+WebRtcLogsDOMHandler::WebRtcLogsDOMHandler()
+    : list_available_(false), js_request_pending_(false) {
+  upload_list_ = WebRtcLogUploadList::Create(this);
+}
+
+WebRtcLogsDOMHandler::~WebRtcLogsDOMHandler() {
+  upload_list_->ClearDelegate();
+}
+
+void WebRtcLogsDOMHandler::RegisterMessages() {
+  upload_list_->LoadUploadListAsynchronously();
+
+  web_ui()->RegisterMessageCallback("requestWebRtcLogsList",
+      base::Bind(&WebRtcLogsDOMHandler::HandleRequestWebRtcLogs,
+                 base::Unretained(this)));
+}
+
+void WebRtcLogsDOMHandler::HandleRequestWebRtcLogs(const ListValue* args) {
+  if (!WebRtcLogsUI::WebRtcLogsUIEnabled() || list_available_)
+    UpdateUI();
+  else
+    js_request_pending_ = true;
+}
+
+void WebRtcLogsDOMHandler::OnUploadListAvailable() {
+  list_available_ = true;
+  if (js_request_pending_)
+    UpdateUI();
+}
+
+void WebRtcLogsDOMHandler::UpdateUI() {
+  bool webrtc_logs_enabled = WebRtcLogsUI::WebRtcLogsUIEnabled();
+  ListValue upload_list;
+
+  if (webrtc_logs_enabled) {
+    std::vector<WebRtcLogUploadList::UploadInfo> uploads;
+    upload_list_->GetUploads(50, &uploads);
+
+    for (std::vector<WebRtcLogUploadList::UploadInfo>::iterator i =
+         uploads.begin(); i != uploads.end(); ++i) {
+      DictionaryValue* upload = new DictionaryValue();
+      upload->SetString("id", i->id);
+      upload->SetString("time", base::TimeFormatFriendlyDateAndTime(i->time));
+      upload_list.Append(upload);
+    }
+  }
+
+  base::FundamentalValue enabled(webrtc_logs_enabled);
+
+  const chrome::VersionInfo version_info;
+  base::StringValue version(version_info.Version());
+
+  web_ui()->CallJavascriptFunction("updateWebRtcLogsList", enabled, upload_list,
+                                   version);
+}
+
+}  // namespace
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// WebRtcLogsUI
+//
+///////////////////////////////////////////////////////////////////////////////
+
+WebRtcLogsUI::WebRtcLogsUI(content::WebUI* web_ui) : WebUIController(web_ui) {
+  web_ui->AddMessageHandler(new WebRtcLogsDOMHandler());
+
+  // Set up the chrome://webrtc-logs/ source.
+  Profile* profile = Profile::FromWebUI(web_ui);
+  content::WebUIDataSource::Add(profile, CreateWebRtcLogsUIHTMLSource());
+}
+
+// static
+bool WebRtcLogsUI::WebRtcLogsUIEnabled() {
+#if defined(GOOGLE_CHROME_BUILD)
+#if defined(OS_CHROMEOS)
+  bool reporting_enabled = false;
+  chromeos::CrosSettings::Get()->GetBoolean(chromeos::kStatsReportingPref,
+                                            &reporting_enabled);
+  return reporting_enabled;
+#elif defined(OS_ANDROID)
+  // Android has it's own setings for metrics / crash uploading.
+  PrefService* prefs = g_browser_process->local_state();
+  return prefs->GetBoolean(prefs::kCrashReportingEnabled);
+#else
+  PrefService* prefs = g_browser_process->local_state();
+  return prefs->GetBoolean(prefs::kMetricsReportingEnabled);
+#endif
+#else
+  return false;
+#endif
+}
diff --git a/chrome/browser/ui/webui/media/webrtc_logs_ui.h b/chrome/browser/ui/webui/media/webrtc_logs_ui.h
new file mode 100644
index 0000000..3c37548
--- /dev/null
+++ b/chrome/browser/ui/webui/media/webrtc_logs_ui.h
@@ -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.
+
+#ifndef CHROME_BROWSER_UI_WEBUI_MEDIA_WEBRTC_LOGS_UI_H_
+#define CHROME_BROWSER_UI_WEBUI_MEDIA_WEBRTC_LOGS_UI_H_
+
+#include "content/public/browser/web_ui_controller.h"
+#include "ui/base/layout.h"
+
+namespace base {
+class RefCountedMemory;
+}
+
+// The WebUI handler for chrome://webrtc-logs.
+class WebRtcLogsUI : public content::WebUIController {
+ public:
+  explicit WebRtcLogsUI(content::WebUI* web_ui);
+
+  // Whether WebRTC logs UI has been enabled.
+  static bool WebRtcLogsUIEnabled();
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(WebRtcLogsUI);
+};
+
+#endif  // CHROME_BROWSER_UI_WEBUI_MEDIA_WEBRTC_LOGS_UI_H_
diff --git a/chrome/browser/ui/webui/memory_internals/memory_internals_proxy.cc b/chrome/browser/ui/webui/memory_internals/memory_internals_proxy.cc
index 3c0e244..accb3a5 100644
--- a/chrome/browser/ui/webui/memory_internals/memory_internals_proxy.cc
+++ b/chrome/browser/ui/webui/memory_internals/memory_internals_proxy.cc
@@ -4,42 +4,38 @@
 
 #include "chrome/browser/ui/webui/memory_internals/memory_internals_proxy.h"
 
+#include <set>
 #include <string>
 #include <vector>
 
 #include "base/bind.h"
 #include "base/strings/string16.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/stringprintf.h"
-#include "base/strings/utf_string_conversions.h"
 #include "base/sys_info.h"
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
-#include "chrome/browser/defaults.h"
-#include "chrome/browser/extensions/extension_service.h"
-#include "chrome/browser/extensions/extension_system.h"
 #include "chrome/browser/memory_details.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/renderer_host/chrome_render_message_filter.h"
+#include "chrome/browser/ui/tab_contents/tab_contents_iterator.h"
 #include "chrome/browser/ui/webui/memory_internals/memory_internals_handler.h"
-#include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/extension_set.h"
-#include "content/public/browser/url_data_source.h"
+#include "chrome/common/chrome_notification_types.h"
+#include "chrome/common/render_messages.h"
+#include "content/public/browser/notification_observer.h"
+#include "content/public/browser/notification_registrar.h"
+#include "content/public/browser/notification_service.h"
+#include "content/public/browser/render_view_host.h"
+#include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_ui.h"
-#include "grit/chromium_strings.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "ui/webui/jstemplate_builder.h"
-#include "ui/webui/web_ui_util.h"
 
 using content::BrowserThread;
 
 namespace {
 
-class BrowserProcessDetails : public MemoryDetails {
+class ProcessDetails : public MemoryDetails {
  public:
   typedef base::Callback<void(const ProcessData&)> DataCallback;
-  explicit BrowserProcessDetails(const DataCallback& callback)
+  explicit ProcessDetails(const DataCallback& callback)
       : callback_(callback) {}
+  // MemoryDetails:
   virtual void OnDetailsAvailable() OVERRIDE {
     const std::vector<ProcessData>& browser_processes = processes();
     // [0] means Chrome.
@@ -47,16 +43,75 @@
   }
 
  private:
-  virtual ~BrowserProcessDetails() {}
+  virtual ~ProcessDetails() {}
 
   DataCallback callback_;
 
-  DISALLOW_COPY_AND_ASSIGN(BrowserProcessDetails);
+  DISALLOW_COPY_AND_ASSIGN(ProcessDetails);
 };
 
 }  // namespace
 
-MemoryInternalsProxy::MemoryInternalsProxy() {}
+class RendererDetails : public content::NotificationObserver {
+ public:
+  typedef base::Callback<void(const base::ProcessId pid,
+                              const size_t v8_allocated,
+                              const size_t v8_used)> V8DataCallback;
+
+  explicit RendererDetails(const V8DataCallback& callback)
+      : callback_(callback) {
+    registrar_.Add(this, chrome::NOTIFICATION_RENDERER_V8_HEAP_STATS_COMPUTED,
+                   content::NotificationService::AllSources());
+  }
+  virtual ~RendererDetails() {}
+
+  void Request() {
+    for (std::set<content::WebContents*>::iterator iter = web_contents_.begin();
+         iter != web_contents_.end(); ++iter)
+      (*iter)->GetRenderViewHost()->Send(new ChromeViewMsg_GetV8HeapStats);
+  }
+  void AddWebContents(content::WebContents* content) {
+    web_contents_.insert(content);
+  }
+  void Clear() {
+    web_contents_.clear();
+  }
+  void RemoveWebContents() {
+    // We don't have to detect which content is the caller of this method.
+    if (!web_contents_.empty())
+      web_contents_.erase(web_contents_.begin());
+  }
+  int IsClean() {
+    return web_contents_.empty();
+  }
+
+ private:
+  // NotificationObserver:
+  virtual void Observe(int type,
+                       const content::NotificationSource& source,
+                       const content::NotificationDetails& details) OVERRIDE {
+    const base::ProcessId* pid =
+        content::Source<const base::ProcessId>(source).ptr();
+    const ChromeRenderMessageFilter::V8HeapStatsDetails* v8_heap =
+        content::Details<const ChromeRenderMessageFilter::V8HeapStatsDetails>(
+            details).ptr();
+    callback_.Run(*pid,
+                  v8_heap->v8_memory_allocated(),
+                  v8_heap->v8_memory_used());
+  }
+
+  V8DataCallback callback_;
+  content::NotificationRegistrar registrar_;
+  std::set<content::WebContents*> web_contents_;  // This class does not own
+
+  DISALLOW_COPY_AND_ASSIGN(RendererDetails);
+};
+
+MemoryInternalsProxy::MemoryInternalsProxy()
+    : information_(new base::DictionaryValue()),
+      renderer_details_(new RendererDetails(
+          base::Bind(&MemoryInternalsProxy::OnV8MemoryUpdate, this))) {
+}
 
 void MemoryInternalsProxy::Attach(MemoryInternalsHandler* handler) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
@@ -71,7 +126,7 @@
 void MemoryInternalsProxy::GetInfo(const base::ListValue* list) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
 
-  scoped_refptr<BrowserProcessDetails> browsers(new BrowserProcessDetails(
+  scoped_refptr<ProcessDetails> browsers(new ProcessDetails(
       base::Bind(&MemoryInternalsProxy::OnDetailsAvailable, this)));
   browsers->StartFetch(MemoryDetails::SKIP_USER_METRICS);
 }
@@ -86,43 +141,80 @@
     handler_->OnUpdate(update);
 }
 
+void MemoryInternalsProxy::OnV8MemoryUpdate(const base::ProcessId pid,
+                                            const size_t v8_allocated,
+                                            const size_t v8_used) {
+  base::ListValue* processes;
+  if (!information_->GetList("processes", &processes))
+    return;
+
+  const size_t size = processes->GetSize();
+  for (size_t i = 0; i < size; ++i) {
+    base::DictionaryValue* process;
+    processes->GetDictionary(i, &process);
+    int id;
+    if (!process->GetInteger("pid", &id) || id != static_cast<int>(pid))
+      continue;
+    process->SetInteger("v8_alloc", v8_allocated);
+    process->SetInteger("v8_used", v8_used);
+    break;
+  }
+
+  renderer_details_->RemoveWebContents();
+  if (renderer_details_->IsClean())
+    CallJavaScriptFunctionOnUIThread("g_main_view.onSetSnapshot", information_);
+}
+
+void MemoryInternalsProxy::RequestV8MemoryUpdate() {
+  renderer_details_->Clear();
+#if !defined(OS_ANDROID)
+  for (TabContentsIterator iter; !iter.done(); iter.Next())
+    renderer_details_->AddWebContents(*iter);
+#endif
+
+  // if no contents are shown, update UI.
+  if (renderer_details_->IsClean())
+    CallJavaScriptFunctionOnUIThread("g_main_view.onSetSnapshot", information_);
+
+  renderer_details_->Request();
+}
+
 void MemoryInternalsProxy::OnDetailsAvailable(const ProcessData& browser) {
-  base::DictionaryValue details;
+  information_->Clear();
 
   // System information, which is independent from processes.
-  details.SetInteger("uptime", base::SysInfo::Uptime());
-  details.SetString("os", base::SysInfo::OperatingSystemName());
-  details.SetString("os_version", base::SysInfo::OperatingSystemVersion());
+  information_->SetInteger("uptime", base::SysInfo::Uptime());
+  information_->SetString("os", base::SysInfo::OperatingSystemName());
+  information_->SetString("os_version",
+                          base::SysInfo::OperatingSystemVersion());
 
   base::ListValue* processes = new ListValue();
   base::ListValue* extensions = new ListValue();
-  details.Set("processes", processes);
-  details.Set("extensions", extensions);
+  information_->Set("processes", processes);
+  information_->Set("extensions", extensions);
   for (ProcessMemoryInformationList::const_iterator
            iter = browser.processes.begin();
        iter != browser.processes.end(); ++iter) {
-    base::DictionaryValue* info = new DictionaryValue();
-
-    // Information from MemoryDetails.
-    info->SetInteger("pid", iter->pid);
-    info->SetString("type",
-                    ProcessMemoryInformation::GetFullTypeNameInEnglish(
-                        iter->process_type, iter->renderer_type));
-    info->SetInteger("memory_private",
-                     iter->working_set.priv + iter->committed.priv);
-    base::ListValue* titles = new ListValue();
-    info->Set("titles", titles);
-    for (size_t i = 0; i < iter->titles.size(); ++i)
-      titles->AppendString(iter->titles[i]);
-
+    base::DictionaryValue* process = new DictionaryValue();
     if (iter->process_type == content::PROCESS_TYPE_RENDERER &&
         iter->renderer_type == ProcessMemoryInformation::RENDERER_EXTENSION)
-      extensions->Append(info);
+      extensions->Append(process);
     else
-      processes->Append(info);
+      processes->Append(process);
+
+    // Information from MemoryDetails.
+    process->SetInteger("pid", iter->pid);
+    process->SetString("type",
+                    ProcessMemoryInformation::GetFullTypeNameInEnglish(
+                        iter->process_type, iter->renderer_type));
+    process->SetInteger("memory_private", iter->working_set.priv);
+    base::ListValue* titles = new ListValue();
+    process->Set("titles", titles);
+    for (size_t i = 0; i < iter->titles.size(); ++i)
+      titles->AppendString(iter->titles[i]);
   }
 
-  CallJavaScriptFunctionOnUIThread("g_main_view.onSetSnapshot", &details);
+  RequestV8MemoryUpdate();
 }
 
 void MemoryInternalsProxy::CallJavaScriptFunctionOnUIThread(
diff --git a/chrome/browser/ui/webui/memory_internals/memory_internals_proxy.h b/chrome/browser/ui/webui/memory_internals/memory_internals_proxy.h
index f3e4b84..5c5ee78 100644
--- a/chrome/browser/ui/webui/memory_internals/memory_internals_proxy.h
+++ b/chrome/browser/ui/webui/memory_internals/memory_internals_proxy.h
@@ -9,10 +9,12 @@
 
 #include "base/memory/ref_counted.h"
 #include "base/strings/string16.h"
+#include "base/values.h"
 #include "chrome/browser/memory_details.h"
 #include "content/public/browser/browser_thread.h"
 
 class MemoryInternalsHandler;
+class RendererDetails;
 
 namespace base {
 class ListValue;
@@ -21,7 +23,7 @@
 
 class MemoryInternalsProxy
     : public base::RefCountedThreadSafe<
-        MemoryInternalsProxy, content::BrowserThread::DeleteOnUIThread> {
+          MemoryInternalsProxy, content::BrowserThread::DeleteOnUIThread> {
  public:
   MemoryInternalsProxy();
 
@@ -43,6 +45,12 @@
   // Sends a message from IO thread to update UI on UI thread.
   void UpdateUIOnUIThread(const string16& update);
 
+  // Measure memory usage of V8.
+  void OnV8MemoryUpdate(const base::ProcessId pid,
+                        const size_t v8_allocated,
+                        const size_t v8_used);
+  void RequestV8MemoryUpdate();
+
   // Convert memory information into DictionaryValue format.
   void OnDetailsAvailable(const ProcessData& browser);
 
@@ -51,6 +59,8 @@
                                         base::Value* args);
 
   MemoryInternalsHandler* handler_;
+  base::DictionaryValue* information_;
+  RendererDetails* renderer_details_;
 
   DISALLOW_COPY_AND_ASSIGN(MemoryInternalsProxy);
 };
diff --git a/chrome/browser/ui/webui/net_internals/net_internals_ui.cc b/chrome/browser/ui/webui/net_internals/net_internals_ui.cc
index 96b3f22..7b65a8e 100644
--- a/chrome/browser/ui/webui/net_internals/net_internals_ui.cc
+++ b/chrome/browser/ui/webui/net_internals/net_internals_ui.cc
@@ -61,6 +61,7 @@
 #include "grit/generated_resources.h"
 #include "grit/net_internals_resources.h"
 #include "net/base/net_errors.h"
+#include "net/base/net_log_logger.h"
 #include "net/base/net_util.h"
 #include "net/disk_cache/disk_cache.h"
 #include "net/dns/host_cache.h"
@@ -104,11 +105,6 @@
 // sent to the page at once, which reduces context switching and CPU usage.
 const int kNetLogEventDelayMilliseconds = 100;
 
-// about:net-internals will not even attempt to load a log dump when it
-// encounters a new version.  This should be incremented when significant
-// changes are made that will invalidate the old loading code.
-const int kLogFormatVersion = 1;
-
 // Returns the HostCache for |context|'s primary HostResolver, or NULL if
 // there is none.
 net::HostCache* GetHostResolverCache(net::URLRequestContext* context) {
@@ -327,7 +323,7 @@
 void CloseAndDeleteDebugLogFile(PassPlatformFile pass_platform_file,
                                 const base::FilePath& file_path) {
   CloseDebugLogFile(pass_platform_file);
-  file_util::Delete(file_path, false);
+  base::Delete(file_path, false);
 }
 
 // Called upon completion of |WriteDebugLogToFile|. Closes file
@@ -1572,23 +1568,32 @@
   std::string error;
   if (!chromeos::onc::ParseAndValidateOncForImport(
           onc_blob, onc_source, passcode, &network_configs, &certificates)) {
-    error = "Errors occurred during the ONC parsing.";
+    error = "Errors occurred during the ONC parsing. ";
+    LOG(ERROR) << error;
+  }
+
+  chromeos::CertificateHandler::CertsByGUID imported_server_and_ca_certs;
+  chromeos::CertificateHandler certificate_handler;
+  if (!certificate_handler.ImportCertificates(certificates, onc_source, NULL,
+                                              &imported_server_and_ca_certs)) {
+    error += "Some certificates couldn't be imported. ";
+    LOG(ERROR) << error;
+  }
+
+  if (!chromeos::onc::ResolveServerCertRefsInNetworks(
+          imported_server_and_ca_certs, &network_configs)) {
+    error += "Some certificate references could not be resolved. ";
     LOG(ERROR) << error;
   }
 
   chromeos::NetworkLibrary* network_library =
       chromeos::CrosLibrary::Get()->GetNetworkLibrary();
   network_library->LoadOncNetworks(network_configs, onc_source);
+
   // Now that we've added the networks, we need to rescan them so they'll be
   // available from the menu more immediately.
   network_library->RequestNetworkScan();
 
-  chromeos::CertificateHandler certificate_handler;
-  if (!certificate_handler.ImportCertificates(certificates, onc_source, NULL)) {
-    error += "Some certificates couldn't be imported.";
-    LOG(ERROR) << error;
-  }
-
   SendJavascriptCommand("receivedONCFileParse",
                         Value::CreateStringValue(error));
 }
@@ -1854,14 +1859,8 @@
 
 // static
 Value* NetInternalsUI::GetConstants() {
-  DictionaryValue* constants_dict = new DictionaryValue();
-
-  // Version of the file format.
-  constants_dict->SetInteger("logFormatVersion", kLogFormatVersion);
-
-  // Add a dictionary with information on the relationship between event type
-  // enums and their symbolic names.
-  constants_dict->Set("logEventTypes", net::NetLog::GetEventTypesAsValue());
+  DictionaryValue* constants_dict = net::NetLogLogger::GetConstants();
+  DCHECK(constants_dict);
 
   // Add a dictionary with the version of the client and its command line
   // arguments.
@@ -1890,111 +1889,6 @@
     constants_dict->Set("clientInfo", dict);
   }
 
-  // Add a dictionary with information about the relationship between load flag
-  // enums and their symbolic names.
-  {
-    DictionaryValue* dict = new DictionaryValue();
-
-#define LOAD_FLAG(label, value) \
-    dict->SetInteger(# label, static_cast<int>(value));
-#include "net/base/load_flags_list.h"
-#undef LOAD_FLAG
-
-    constants_dict->Set("loadFlag", dict);
-  }
-
-  // Add a dictionary with information about the relationship between load state
-  // enums and their symbolic names.
-  {
-    DictionaryValue* dict = new DictionaryValue();
-
-#define LOAD_STATE(label) \
-    dict->SetInteger(# label, net::LOAD_STATE_ ## label);
-#include "net/base/load_states_list.h"
-#undef LOAD_STATE
-
-    constants_dict->Set("loadState", dict);
-  }
-
-  // Add information on the relationship between net error codes and their
-  // symbolic names.
-  {
-    DictionaryValue* dict = new DictionaryValue();
-
-#define NET_ERROR(label, value) \
-    dict->SetInteger(# label, static_cast<int>(value));
-#include "net/base/net_error_list.h"
-#undef NET_ERROR
-
-    constants_dict->Set("netError", dict);
-  }
-
-  // Information about the relationship between event phase enums and their
-  // symbolic names.
-  {
-    DictionaryValue* dict = new DictionaryValue();
-
-    dict->SetInteger("PHASE_BEGIN", net::NetLog::PHASE_BEGIN);
-    dict->SetInteger("PHASE_END", net::NetLog::PHASE_END);
-    dict->SetInteger("PHASE_NONE", net::NetLog::PHASE_NONE);
-
-    constants_dict->Set("logEventPhase", dict);
-  }
-
-  // Information about the relationship between source type enums and
-  // their symbolic names.
-  constants_dict->Set("logSourceType", net::NetLog::GetSourceTypesAsValue());
-
-  // Information about the relationship between LogLevel enums and their
-  // symbolic names.
-  {
-    DictionaryValue* dict = new DictionaryValue();
-
-    dict->SetInteger("LOG_ALL", net::NetLog::LOG_ALL);
-    dict->SetInteger("LOG_ALL_BUT_BYTES", net::NetLog::LOG_ALL_BUT_BYTES);
-    dict->SetInteger("LOG_BASIC", net::NetLog::LOG_BASIC);
-
-    constants_dict->Set("logLevelType", dict);
-  }
-
-  // Information about the relationship between address family enums and
-  // their symbolic names.
-  {
-    DictionaryValue* dict = new DictionaryValue();
-
-    dict->SetInteger("ADDRESS_FAMILY_UNSPECIFIED",
-                     net::ADDRESS_FAMILY_UNSPECIFIED);
-    dict->SetInteger("ADDRESS_FAMILY_IPV4",
-                     net::ADDRESS_FAMILY_IPV4);
-    dict->SetInteger("ADDRESS_FAMILY_IPV6",
-                     net::ADDRESS_FAMILY_IPV6);
-
-    constants_dict->Set("addressFamily", dict);
-  }
-
-  // Information about how the "time ticks" values we have given it relate to
-  // actual system times. (We used time ticks throughout since they are stable
-  // across system clock changes).
-  {
-    int64 cur_time_ms = (base::Time::Now() - base::Time()).InMilliseconds();
-
-    int64 cur_time_ticks_ms =
-        (base::TimeTicks::Now() - base::TimeTicks()).InMilliseconds();
-
-    // If we add this number to a time tick value, it gives the timestamp.
-    int64 tick_to_time_ms = cur_time_ms - cur_time_ticks_ms;
-
-    // Chrome on all platforms stores times using the Windows epoch
-    // (Jan 1 1601), but the javascript wants a unix epoch.
-    // TODO(eroman): Getting the timestamp relative to the unix epoch should
-    //               be part of the time library.
-    const int64 kUnixEpochMs = 11644473600000LL;
-    int64 tick_to_unix_time_ms = tick_to_time_ms - kUnixEpochMs;
-
-    // Pass it as a string, since it may be too large to fit in an integer.
-    constants_dict->SetString("timeTickOffset",
-                              base::Int64ToString(tick_to_unix_time_ms));
-  }
   return constants_dict;
 }
 
diff --git a/chrome/browser/ui/webui/net_internals/net_internals_ui_browsertest.cc b/chrome/browser/ui/webui/net_internals/net_internals_ui_browsertest.cc
index 06f809a..486e28e 100644
--- a/chrome/browser/ui/webui/net_internals/net_internals_ui_browsertest.cc
+++ b/chrome/browser/ui/webui/net_internals/net_internals_ui_browsertest.cc
@@ -14,12 +14,12 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/io_thread.h"
 #include "chrome/browser/net/chrome_net_log.h"
-#include "chrome/browser/net/net_log_logger.h"
 #include "chrome/browser/prerender/prerender_manager.h"
 #include "chrome/browser/prerender/prerender_manager_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/browser/ui/webui/net_internals/net_internals_ui.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "content/public/browser/render_view_host.h"
@@ -29,6 +29,7 @@
 #include "net/base/address_list.h"
 #include "net/base/net_errors.h"
 #include "net/base/net_log.h"
+#include "net/base/net_log_logger.h"
 #include "net/dns/host_cache.h"
 #include "net/dns/host_resolver.h"
 #include "net/dns/mock_host_resolver.h"
@@ -344,7 +345,9 @@
   FILE* temp_file_handle = file_util::OpenFile(temp_file, "w");
   ASSERT_TRUE(temp_file_handle);
 
-  scoped_ptr<NetLogLogger> net_log_logger(new NetLogLogger(temp_file_handle));
+  scoped_ptr<base::Value> constants(NetInternalsUI::GetConstants());
+  scoped_ptr<net::NetLogLogger> net_log_logger(new net::NetLogLogger(
+      temp_file_handle, *constants));
   net_log_logger->StartObserving(g_browser_process->net_log());
   g_browser_process->net_log()->AddGlobalEntry(
       net::NetLog::TYPE_NETWORK_IP_ADDRESSES_CHANGED);
diff --git a/chrome/browser/ui/webui/ntp/android/OWNERS b/chrome/browser/ui/webui/ntp/android/OWNERS
index 9549e8c..0d259ac 100644
--- a/chrome/browser/ui/webui/ntp/android/OWNERS
+++ b/chrome/browser/ui/webui/ntp/android/OWNERS
@@ -1,4 +1,3 @@
-jcivelli@chromium.org
 newt@chromium.org
 tedchoc@chromium.org
 yfriedman@chromium.org
diff --git a/chrome/browser/ui/webui/ntp/app_launcher_handler.cc b/chrome/browser/ui/webui/ntp/app_launcher_handler.cc
index 88bff10..82c0078 100644
--- a/chrome/browser/ui/webui/ntp/app_launcher_handler.cc
+++ b/chrome/browser/ui/webui/ntp/app_launcher_handler.cc
@@ -6,6 +6,7 @@
 
 #include <vector>
 
+#include "apps/metrics_names.h"
 #include "apps/pref_names.h"
 #include "base/auto_reset.h"
 #include "base/bind.h"
@@ -212,6 +213,9 @@
   web_ui()->RegisterMessageCallback("stopShowingAppLauncherPromo",
       base::Bind(&AppLauncherHandler::StopShowingAppLauncherPromo,
                  base::Unretained(this)));
+  web_ui()->RegisterMessageCallback("onLearnMore",
+      base::Bind(&AppLauncherHandler::OnLearnMore,
+                 base::Unretained(this)));
 }
 
 void AppLauncherHandler::Observe(int type,
@@ -694,6 +698,11 @@
     const base::ListValue* args) {
   g_browser_process->local_state()->SetBoolean(
       apps::prefs::kShowAppLauncherPromo, false);
+  RecordAppLauncherPromoHistogram(apps::APP_LAUNCHER_PROMO_DISMISSED);
+}
+
+void AppLauncherHandler::OnLearnMore(const base::ListValue* args) {
+  RecordAppLauncherPromoHistogram(apps::APP_LAUNCHER_PROMO_LEARN_MORE);
 }
 
 void AppLauncherHandler::OnFaviconForApp(
@@ -758,6 +767,7 @@
 void AppLauncherHandler::RecordAppLaunchType(
     extension_misc::AppLaunchBucket bucket,
     extensions::Manifest::Type app_type) {
+  DCHECK_LT(bucket, extension_misc::APP_LAUNCH_BUCKET_BOUNDARY);
   if (app_type == extensions::Manifest::TYPE_PLATFORM_APP) {
     UMA_HISTOGRAM_ENUMERATION(extension_misc::kPlatformAppLaunchHistogram,
         bucket, extension_misc::APP_LAUNCH_BUCKET_BOUNDARY);
@@ -790,6 +800,14 @@
 }
 
 // static
+void AppLauncherHandler::RecordAppLauncherPromoHistogram(
+      apps::AppLauncherPromoHistogramValues value) {
+  DCHECK_LT(value, apps::APP_LAUNCHER_PROMO_MAX);
+  UMA_HISTOGRAM_ENUMERATION(
+      "Apps.AppLauncherPromo", value, apps::APP_LAUNCHER_PROMO_MAX);
+}
+
+// static
 void AppLauncherHandler::RecordWebStoreLaunch() {
   RecordAppLaunchType(extension_misc::APP_LAUNCH_NTP_WEBSTORE,
       extensions::Manifest::TYPE_HOSTED_APP);
diff --git a/chrome/browser/ui/webui/ntp/app_launcher_handler.h b/chrome/browser/ui/webui/ntp/app_launcher_handler.h
index 986d055..7a5dc0f 100644
--- a/chrome/browser/ui/webui/ntp/app_launcher_handler.h
+++ b/chrome/browser/ui/webui/ntp/app_launcher_handler.h
@@ -8,6 +8,7 @@
 #include <set>
 #include <string>
 
+#include "apps/metrics_names.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/prefs/pref_change_registrar.h"
 #include "chrome/browser/extensions/extension_uninstall_dialog.h"
@@ -68,31 +69,41 @@
   // Populate the given dictionary with the web store promo content.
   void FillPromoDictionary(base::DictionaryValue* value);
 
-  // Callback for the "getApps" message.
+  // Handles the "launchApp" message with unused |args|.
   void HandleGetApps(const base::ListValue* args);
 
-  // Callback for the "launchApp" message.
+  // Handles the "launchApp" message with |args| containing [extension_id,
+  // source] with optional [url, disposition], |disposition| defaulting to
+  // CURRENT_TAB.
   void HandleLaunchApp(const base::ListValue* args);
 
-  // Callback for the "setLaunchType" message.
+  // Handles the "setLaunchType" message with args containing [extension_id,
+  // launch_type].
   void HandleSetLaunchType(const base::ListValue* args);
 
-  // Callback for the "uninstallApp" message.
+  // Handles the "uninstallApp" message with |args| containing [extension_id]
+  // and an optional bool to not confirm the uninstall when true, defaults to
+  // false.
   void HandleUninstallApp(const base::ListValue* args);
 
-  // Callback for the "createAppShortcut" message.
+  // Handles the "createAppShortcut" message with |args| containing
+  // [extension_id].
   void HandleCreateAppShortcut(const base::ListValue* args);
 
-  // Callback for the "reorderApps" message.
+  // Handles the "reorderApps" message with |args| containing [dragged_app_id,
+  // app_order].
   void HandleReorderApps(const base::ListValue* args);
 
-  // Callback for the "setPageIndex" message.
+  // Handles the "setPageIndex" message with |args| containing [extension_id,
+  // page_index].
   void HandleSetPageIndex(const base::ListValue* args);
 
-  // Callback for the "saveAppPageName" message.
+  // Handles "saveAppPageName" message with |args| containing [name,
+  // page_index].
   void HandleSaveAppPageName(const base::ListValue* args);
 
-  // Callback for the "generateAppForLink" message.
+  // Handles "generateAppForLink" message with |args| containing [url, title,
+  // page_index].
   void HandleGenerateAppForLink(const base::ListValue* args);
 
   // Callback for the "recordAppLaunchByURL" message. Takes an escaped URL and a
@@ -100,14 +111,9 @@
   // action for UMA.
   void HandleRecordAppLaunchByUrl(const base::ListValue* args);
 
-  // Callback for "stopShowingAppLauncherPromo" message.
+  // Other registered message callbacks with unused |args|.
   void StopShowingAppLauncherPromo(const base::ListValue* args);
-
-  // Callback for "closeNotification" message.
-  void HandleNotificationClose(const base::ListValue* args);
-
-  // Callback for "setNotificationsDisabled" message.
-  void HandleSetNotificationsDisabled(const base::ListValue* args);
+  void OnLearnMore(const base::ListValue* args);
 
   // Register app launcher preferences.
   static void RegisterUserPrefs(user_prefs::PrefRegistrySyncable* registry);
@@ -122,6 +128,10 @@
   // Records an app launch from the main view of the app list.
   static void RecordAppListMainLaunch(const extensions::Extension* extension);
 
+  // Records the given |value| in the apps::kAppLauncherPromoHistogram.
+  static void RecordAppLauncherPromoHistogram(
+      apps::AppLauncherPromoHistogramValues value);
+
  private:
   struct AppInstallInfo {
     AppInstallInfo();
diff --git a/chrome/browser/ui/webui/ntp/foreign_session_handler.h b/chrome/browser/ui/webui/ntp/foreign_session_handler.h
index 4e466f0..fd470ca 100644
--- a/chrome/browser/ui/webui/ntp/foreign_session_handler.h
+++ b/chrome/browser/ui/webui/ntp/foreign_session_handler.h
@@ -7,7 +7,7 @@
 
 #include <vector>
 
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/sessions/session_service.h"
 #include "chrome/browser/sync/glue/session_model_associator.h"
 #include "content/public/browser/notification_observer.h"
diff --git a/chrome/browser/ui/webui/ntp/new_tab_ui.h b/chrome/browser/ui/webui/ntp/new_tab_ui.h
index 644430a..bbc4ff8 100644
--- a/chrome/browser/ui/webui/ntp/new_tab_ui.h
+++ b/chrome/browser/ui/webui/ntp/new_tab_ui.h
@@ -9,8 +9,8 @@
 
 #include "base/gtest_prod_util.h"
 #include "base/prefs/pref_change_registrar.h"
-#include "base/time.h"
-#include "base/timer.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
 #include "content/public/browser/url_data_source.h"
diff --git a/chrome/browser/ui/webui/ntp/ntp_login_handler.cc b/chrome/browser/ui/webui/ntp/ntp_login_handler.cc
index 7be787e..cfafc72 100644
--- a/chrome/browser/ui/webui/ntp/ntp_login_handler.cc
+++ b/chrome/browser/ui/webui/ntp/ntp_login_handler.cc
@@ -28,8 +28,8 @@
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/chrome_pages.h"
+#include "chrome/browser/ui/sync/sync_promo_ui.h"
 #include "chrome/browser/ui/webui/ntp/new_tab_ui.h"
-#include "chrome/browser/ui/webui/sync_promo/sync_promo_ui.h"
 #include "chrome/browser/web_resource/promo_resource_service.h"
 #include "chrome/common/chrome_notification_types.h"
 #include "chrome/common/pref_names.h"
diff --git a/chrome/browser/ui/webui/ntp/ntp_resource_cache.cc b/chrome/browser/ui/webui/ntp/ntp_resource_cache.cc
index e19ad8a..15d0f19 100644
--- a/chrome/browser/ui/webui/ntp/ntp_resource_cache.cc
+++ b/chrome/browser/ui/webui/ntp/ntp_resource_cache.cc
@@ -8,11 +8,9 @@
 #include <vector>
 
 #include "apps/app_launcher.h"
-#include "apps/field_trial_names.h"
 #include "apps/pref_names.h"
 #include "base/command_line.h"
 #include "base/memory/ref_counted_memory.h"
-#include "base/metrics/field_trial.h"
 #include "base/prefs/pref_service.h"
 #include "base/strings/string16.h"
 #include "base/strings/string_number_conversions.h"
@@ -31,10 +29,10 @@
 #include "chrome/browser/themes/theme_service.h"
 #include "chrome/browser/themes/theme_service_factory.h"
 #include "chrome/browser/ui/bookmarks/bookmark_bar_constants.h"
+#include "chrome/browser/ui/sync/sync_promo_ui.h"
 #include "chrome/browser/ui/webui/ntp/new_tab_page_handler.h"
 #include "chrome/browser/ui/webui/ntp/new_tab_ui.h"
 #include "chrome/browser/ui/webui/ntp/ntp_login_handler.h"
-#include "chrome/browser/ui/webui/sync_promo/sync_promo_ui.h"
 #include "chrome/browser/ui/webui/sync_setup_handler.h"
 #include "chrome/browser/web_resource/notification_promo.h"
 #include "chrome/common/chrome_notification_types.h"
@@ -338,7 +336,6 @@
   // Show the profile name in the title and most visited labels if the current
   // profile is not the default.
   PrefService* prefs = profile_->GetPrefs();
-  PrefService* local_state = g_browser_process->local_state();
   DictionaryValue load_time_data;
   load_time_data.SetBoolean("bookmarkbarattached",
       prefs->GetBoolean(prefs::kShowBookmarkBar));
@@ -346,15 +343,8 @@
       ThemeServiceFactory::GetForProfile(profile_)->HasCustomImage(
           IDR_THEME_NTP_ATTRIBUTION));
   load_time_data.SetBoolean("showMostvisited", should_show_most_visited_page_);
-  std::string app_launcher_promo_group_name =
-      base::FieldTrialList::FindFullName(apps::kLauncherPromoTrialName);
-  bool show_app_launcher_promo =
-      !apps::IsAppLauncherEnabled() &&
-      local_state->GetBoolean(apps::prefs::kShowAppLauncherPromo) &&
-      (app_launcher_promo_group_name == apps::kShowLauncherPromoOnceGroupName ||
-       app_launcher_promo_group_name ==
-          apps::kResetShowLauncherPromoPrefGroupName);
-  load_time_data.SetBoolean("showAppLauncherPromo", show_app_launcher_promo);
+  load_time_data.SetBoolean("showAppLauncherPromo",
+      apps::ShouldShowAppLauncherPromo());
   load_time_data.SetBoolean("showRecentlyClosed",
       should_show_recently_closed_menu_);
   load_time_data.SetString("title",
@@ -405,6 +395,8 @@
       l10n_util::GetStringUTF16(IDS_SYNC_START_SYNC_BUTTON_LABEL));
   load_time_data.SetString("syncLinkText",
       l10n_util::GetStringUTF16(IDS_SYNC_ADVANCED_OPTIONS));
+  load_time_data.SetBoolean("shouldShowSyncLogin",
+                            NTPLoginHandler::ShouldShow(profile_));
   load_time_data.SetString("otherSessions",
       l10n_util::GetStringUTF16(IDS_NEW_TAB_OTHER_SESSIONS_LABEL));
   load_time_data.SetString("otherSessionsEmpty",
diff --git a/chrome/browser/ui/webui/omnibox/omnibox_ui_handler.cc b/chrome/browser/ui/webui/omnibox/omnibox_ui_handler.cc
index 3856684..3b62f03 100644
--- a/chrome/browser/ui/webui/omnibox/omnibox_ui_handler.cc
+++ b/chrome/browser/ui/webui/omnibox/omnibox_ui_handler.cc
@@ -11,7 +11,7 @@
 #include "base/strings/string16.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "base/values.h"
 #include "chrome/browser/autocomplete/autocomplete_classifier.h"
 #include "chrome/browser/autocomplete/autocomplete_controller.h"
diff --git a/chrome/browser/ui/webui/omnibox/omnibox_ui_handler.h b/chrome/browser/ui/webui/omnibox/omnibox_ui_handler.h
index 292d4de..8c18792 100644
--- a/chrome/browser/ui/webui/omnibox/omnibox_ui_handler.h
+++ b/chrome/browser/ui/webui/omnibox/omnibox_ui_handler.h
@@ -8,7 +8,7 @@
 #include "base/basictypes.h"
 #include "base/compiler_specific.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/autocomplete/autocomplete_controller_delegate.h"
 #include "chrome/browser/autocomplete/autocomplete_match.h"
 #include "content/public/browser/web_ui_message_handler.h"
diff --git a/chrome/browser/ui/webui/options/autofill_options_handler.cc b/chrome/browser/ui/webui/options/autofill_options_handler.cc
index 4fcbb41..e00af5c 100644
--- a/chrome/browser/ui/webui/options/autofill_options_handler.cc
+++ b/chrome/browser/ui/webui/options/autofill_options_handler.cc
@@ -19,11 +19,11 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/autofill/country_combobox_model.h"
 #include "chrome/common/url_constants.h"
-#include "components/autofill/browser/autofill_country.h"
-#include "components/autofill/browser/autofill_profile.h"
-#include "components/autofill/browser/credit_card.h"
-#include "components/autofill/browser/personal_data_manager.h"
-#include "components/autofill/browser/phone_number_i18n.h"
+#include "components/autofill/core/browser/autofill_country.h"
+#include "components/autofill/core/browser/autofill_profile.h"
+#include "components/autofill/core/browser/credit_card.h"
+#include "components/autofill/core/browser/personal_data_manager.h"
+#include "components/autofill/core/browser/phone_number_i18n.h"
 #include "components/autofill/core/common/autofill_constants.h"
 #include "content/public/browser/web_ui.h"
 #include "grit/component_strings.h"
diff --git a/chrome/browser/ui/webui/options/autofill_options_handler.h b/chrome/browser/ui/webui/options/autofill_options_handler.h
index a9b90a8..5d58d21 100644
--- a/chrome/browser/ui/webui/options/autofill_options_handler.h
+++ b/chrome/browser/ui/webui/options/autofill_options_handler.h
@@ -9,7 +9,7 @@
 
 #include "base/compiler_specific.h"
 #include "chrome/browser/ui/webui/options/options_ui.h"
-#include "components/autofill/browser/personal_data_manager_observer.h"
+#include "components/autofill/core/browser/personal_data_manager_observer.h"
 
 namespace autofill {
 class PersonalDataManager;
diff --git a/chrome/browser/ui/webui/options/browser_options_handler.cc b/chrome/browser/ui/webui/options/browser_options_handler.cc
index da0e12d..04f7ceb 100644
--- a/chrome/browser/ui/webui/options/browser_options_handler.cc
+++ b/chrome/browser/ui/webui/options/browser_options_handler.cc
@@ -31,7 +31,6 @@
 #include "chrome/browser/prefs/session_startup_pref.h"
 #include "chrome/browser/printing/cloud_print/cloud_print_proxy_service.h"
 #include "chrome/browser/printing/cloud_print/cloud_print_proxy_service_factory.h"
-#include "chrome/browser/printing/cloud_print/cloud_print_setup_flow.h"
 #include "chrome/browser/printing/cloud_print/cloud_print_url.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_info_cache.h"
@@ -92,7 +91,6 @@
 #endif
 
 #if !defined(OS_CHROMEOS)
-#include "chrome/browser/printing/cloud_print/cloud_print_setup_handler.h"
 #include "chrome/browser/ui/webui/options/advanced_options_utils.h"
 #include "chromeos/chromeos_switches.h"
 #endif
@@ -116,10 +114,6 @@
 #include "chrome/installer/util/auto_launch_util.h"
 #endif  // defined(OS_WIN)
 
-#if defined(TOOLKIT_GTK)
-#include "chrome/browser/ui/gtk/gtk_theme_service.h"
-#endif  // defined(TOOLKIT_GTK)
-
 using content::BrowserContext;
 using content::BrowserThread;
 using content::DownloadManager;
@@ -131,11 +125,13 @@
 
 namespace {
 
-bool ShouldShowMultiProfilesUserList() {
+bool ShouldShowMultiProfilesUserList(chrome::HostDesktopType desktop_type) {
 #if defined(OS_CHROMEOS)
   // On Chrome OS we use different UI for multi-profiles.
   return false;
 #else
+  if (desktop_type != chrome::HOST_DESKTOP_TYPE_NATIVE)
+    return false;
   return ProfileManager::IsMultipleProfilesEnabled();
 #endif
 }
@@ -338,9 +334,9 @@
     { "toolbarShowHomeButton", IDS_OPTIONS_TOOLBAR_SHOW_HOME_BUTTON },
     { "translateEnableTranslate",
       IDS_OPTIONS_TRANSLATE_ENABLE_TRANSLATE },
-#if defined(TOOLKIT_GTK)
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
     { "showWindowDecorations", IDS_SHOW_WINDOW_DECORATIONS },
-    { "themesGTKButton", IDS_THEMES_GTK_BUTTON },
+    { "themesNativeButton", IDS_THEMES_GTK_BUTTON },
     { "themesSetClassic", IDS_THEMES_SET_CLASSIC },
 #else
     { "themes", IDS_THEMES_GROUP_NAME },
@@ -512,7 +508,7 @@
       g_browser_process->profile_manager()->GetNumberOfProfiles() > 1);
 #endif
 
-  if (ShouldShowMultiProfilesUserList())
+  if (ShouldShowMultiProfilesUserList(GetDesktopType()))
     values->Set("profilesInfo", GetProfilesInfoList().release());
 
 #if defined(ENABLE_MANAGED_USERS)
@@ -580,10 +576,10 @@
       "themesReset",
       base::Bind(&BrowserOptionsHandler::ThemesReset,
                  base::Unretained(this)));
-#if defined(TOOLKIT_GTK)
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
   web_ui()->RegisterMessageCallback(
-      "themesSetGTK",
-      base::Bind(&BrowserOptionsHandler::ThemesSetGTK,
+      "themesSetNative",
+      base::Bind(&BrowserOptionsHandler::ThemesSetNative,
                  base::Unretained(this)));
 #endif
   web_ui()->RegisterMessageCallback(
@@ -1091,7 +1087,7 @@
 }
 
 void BrowserOptionsHandler::SendProfilesInfo() {
-  if (!ShouldShowMultiProfilesUserList())
+  if (!ShouldShowMultiProfilesUserList(GetDesktopType()))
     return;
   web_ui()->CallJavascriptFunction("BrowserOptions.setProfilesInfo",
                                    *GetProfilesInfoList());
@@ -1320,31 +1316,35 @@
 
 void BrowserOptionsHandler::ObserveThemeChanged() {
   Profile* profile = Profile::FromWebUI(web_ui());
-#if defined(TOOLKIT_GTK)
-  GtkThemeService* theme_service = GtkThemeService::GetFrom(profile);
-  bool is_gtk_theme = theme_service->UsingNativeTheme();
-  base::FundamentalValue gtk_enabled(!is_gtk_theme);
-  web_ui()->CallJavascriptFunction("BrowserOptions.setGtkThemeButtonEnabled",
-                                   gtk_enabled);
-#else
+  bool profile_is_managed = ManagedUserService::ProfileIsManaged(profile);
   ThemeService* theme_service = ThemeServiceFactory::GetForProfile(profile);
-  bool is_gtk_theme = false;
+  bool is_native_theme = false;
+
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+  is_native_theme = theme_service->UsingNativeTheme();
+  base::FundamentalValue native_theme_enabled(!is_native_theme &&
+                                              !profile_is_managed);
+  web_ui()->CallJavascriptFunction("BrowserOptions.setNativeThemeButtonEnabled",
+                                   native_theme_enabled);
 #endif
 
-  bool is_classic_theme = !is_gtk_theme && theme_service->UsingDefaultTheme();
-  base::FundamentalValue enabled(!is_classic_theme);
+  bool is_classic_theme = !is_native_theme &&
+                          theme_service->UsingDefaultTheme();
+  base::FundamentalValue enabled(!is_classic_theme && !profile_is_managed);
   web_ui()->CallJavascriptFunction("BrowserOptions.setThemesResetButtonEnabled",
                                    enabled);
 }
 
 void BrowserOptionsHandler::ThemesReset(const ListValue* args) {
-  content::RecordAction(UserMetricsAction("Options_ThemesReset"));
   Profile* profile = Profile::FromWebUI(web_ui());
+  if (ManagedUserService::ProfileIsManaged(profile))
+    return;
+  content::RecordAction(UserMetricsAction("Options_ThemesReset"));
   ThemeServiceFactory::GetForProfile(profile)->UseDefaultTheme();
 }
 
-#if defined(TOOLKIT_GTK)
-void BrowserOptionsHandler::ThemesSetGTK(const ListValue* args) {
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+void BrowserOptionsHandler::ThemesSetNative(const ListValue* args) {
   content::RecordAction(UserMetricsAction("Options_GtkThemeSet"));
   Profile* profile = Profile::FromWebUI(web_ui());
   ThemeServiceFactory::GetForProfile(profile)->SetNativeTheme();
@@ -1441,13 +1441,6 @@
   pref_service->SetFilePath(prefs::kSaveFileDefaultDirectory, path);
 }
 
-void BrowserOptionsHandler::OnCloudPrintSetupClosed() {
-#if !defined(OS_CHROMEOS)
-  if (cloud_print_connector_ui_enabled_)
-    SetupCloudPrintConnectorSection();
-#endif
-}
-
 #if defined(OS_CHROMEOS)
 void BrowserOptionsHandler::TouchpadExists(bool exists) {
   base::FundamentalValue val(exists);
@@ -1737,8 +1730,8 @@
   bool is_extension_controlled = (proxy_config &&
                                   proxy_config->IsExtensionControlled());
 
-  base::FundamentalValue disabled(profile_pref_registrar_.IsManaged() ||
-                                  is_extension_controlled);
+  base::FundamentalValue disabled(proxy_config &&
+                                  !proxy_config->IsUserModifiable());
   base::FundamentalValue extension_controlled(is_extension_controlled);
   web_ui()->CallJavascriptFunction("BrowserOptions.setupProxySettingsSection",
                                    disabled, extension_controlled);
diff --git a/chrome/browser/ui/webui/options/browser_options_handler.h b/chrome/browser/ui/webui/options/browser_options_handler.h
index acc81cf..6acf28f 100644
--- a/chrome/browser/ui/webui/options/browser_options_handler.h
+++ b/chrome/browser/ui/webui/options/browser_options_handler.h
@@ -11,8 +11,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/prefs/pref_member.h"
-#include "base/time.h"
-#include "chrome/browser/printing/cloud_print/cloud_print_setup_handler.h"
+#include "base/time/time.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/search_engines/template_url_service_observer.h"
@@ -38,7 +37,6 @@
 // Chrome browser options page UI handler.
 class BrowserOptionsHandler
     : public OptionsPageUIHandler,
-      public CloudPrintSetupHandlerDelegate,
       public ProfileSyncServiceObserver,
       public ui::SelectFileDialog::Listener,
       public ShellIntegration::DefaultWebClientObserver,
@@ -88,9 +86,6 @@
                             int index,
                             void* params) OVERRIDE;
 
-  // CloudPrintSetupHandler::Delegate implementation.
-  virtual void OnCloudPrintSetupClosed() OVERRIDE;
-
 #if defined(OS_CHROMEOS)
   // PointerDeviceObserver::Observer implementation.
   virtual void TouchpadExists(bool exists) OVERRIDE;
@@ -199,8 +194,8 @@
 
   void ObserveThemeChanged();
   void ThemesReset(const base::ListValue* args);
-#if defined(TOOLKIT_GTK)
-  void ThemesSetGTK(const base::ListValue* args);
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+  void ThemesSetNative(const base::ListValue* args);
 #endif
 
 #if defined(OS_CHROMEOS)
@@ -343,7 +338,6 @@
   StringPrefMember cloud_print_connector_email_;
   BooleanPrefMember cloud_print_connector_enabled_;
   bool cloud_print_connector_ui_enabled_;
-  scoped_ptr<CloudPrintSetupHandler> cloud_print_setup_handler_;
 #endif
 
   StringPrefMember auto_open_files_;
diff --git a/chrome/browser/ui/webui/options/certificate_manager_browsertest.cc b/chrome/browser/ui/webui/options/certificate_manager_browsertest.cc
index f45624c..d18f733 100644
--- a/chrome/browser/ui/webui/options/certificate_manager_browsertest.cc
+++ b/chrome/browser/ui/webui/options/certificate_manager_browsertest.cc
@@ -51,10 +51,9 @@
 
     // Enable web trust certs from policy.
     g_browser_process->browser_policy_connector()->
-        GetNetworkConfigurationUpdater()->SetUserPolicyService(
+        network_configuration_updater()->SetUserPolicyService(
             true, "", connector->policy_service());
 #endif
-    content::RunAllPendingInMessageLoop();
   }
 
 #if defined(OS_CHROMEOS)
diff --git a/chrome/browser/ui/webui/options/certificate_manager_handler.cc b/chrome/browser/ui/webui/options/certificate_manager_handler.cc
index 6a97f84..f77cc8b 100644
--- a/chrome/browser/ui/webui/options/certificate_manager_handler.cc
+++ b/chrome/browser/ui/webui/options/certificate_manager_handler.cc
@@ -114,8 +114,8 @@
 // Struct to bind the Equals member function to an object for use in find_if.
 struct CertEquals {
   explicit CertEquals(const net::X509Certificate* cert) : cert_(cert) {}
-  bool operator()(const net::X509Certificate* cert) const {
-    return cert_->Equals(cert);
+  bool operator()(const scoped_refptr<net::X509Certificate> cert) const {
+    return cert_->Equals(cert.get());
   }
   const net::X509Certificate* cert_;
 };
diff --git a/chrome/browser/ui/webui/options/chromeos/accounts_options_browsertest.js b/chrome/browser/ui/webui/options/chromeos/accounts_options_browsertest.js
new file mode 100644
index 0000000..4dd58bd
--- /dev/null
+++ b/chrome/browser/ui/webui/options/chromeos/accounts_options_browsertest.js
@@ -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.
+
+function AccountsOptionsWebUITest() {}
+
+AccountsOptionsWebUITest.prototype = {
+  __proto__: testing.Test.prototype,
+
+  /**
+   * Browse to accounts options.
+   **/
+  browsePreload: 'chrome://settings-frame/accounts',
+};
+
+function createEnterKeyboardEvent(type) {
+  return new KeyboardEvent(type, {
+    'bubbles': true,
+    'cancelable': true,
+    'keyIdentifier': 'Enter'
+  });
+}
+
+TEST_F('AccountsOptionsWebUITest', 'testNoCloseOnEnter', function() {
+  assertEquals(this.browsePreload, document.location.href);
+
+  var inputField = $('userNameEdit');
+  var overlay = $('accountsPage').parentNode;
+
+  // Overlay is visible.
+  assertFalse(overlay.classList.contains('transparent'));
+
+  // Simulate pressing the enter key in the edit field.
+  inputField.dispatchEvent(createEnterKeyboardEvent('keydown'));
+  inputField.dispatchEvent(createEnterKeyboardEvent('keypress'));
+  inputField.dispatchEvent(createEnterKeyboardEvent('keyup'));
+
+  // Verify the overlay is still visible.
+  assertFalse(overlay.classList.contains('transparent'));
+});
diff --git a/chrome/browser/ui/webui/options/chromeos/display_options_handler.cc b/chrome/browser/ui/webui/options/chromeos/display_options_handler.cc
index 1b9c086..9d1f9e1 100644
--- a/chrome/browser/ui/webui/options/chromeos/display_options_handler.cc
+++ b/chrome/browser/ui/webui/options/chromeos/display_options_handler.cc
@@ -227,7 +227,7 @@
 
 void DisplayOptionsHandler::OnFadeOutForDisplayLayoutFinished(
     int position, int offset) {
-  SetCurrentAndDefaultDisplayLayout(
+  SetCurrentDisplayLayout(
       ash::DisplayLayout::FromInts(position, offset));
   ash::Shell::GetInstance()->output_configurator_animation()->
       StartFadeInAnimation();
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 d39d0af..a49dd5c 100644
--- a/chrome/browser/ui/webui/options/chromeos/internet_options_handler.cc
+++ b/chrome/browser/ui/webui/options/chromeos/internet_options_handler.cc
@@ -23,7 +23,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chromeos/choose_mobile_network_dialog.h"
@@ -1194,21 +1194,29 @@
   chromeos::Network* network = cros_->FindNetworkByPath(service_path);
   if (!network)
     return;
-  // Have to copy the properties because the object will go out of scope when
-  // this function call completes (it's owned by the calling function).
-  base::DictionaryValue* shill_props_copy = shill_properties->DeepCopy();
-  cros_->GetIPConfigs(
-      network->device_path(),
-      chromeos::NetworkLibrary::FORMAT_COLON_SEPARATED_HEX,
-      base::Bind(&InternetOptionsHandler::PopulateIPConfigsCallback,
-                 weak_factory_.GetWeakPtr(),
-                 service_path,
-                 base::Owned(shill_props_copy)));
+
+  if (network->device_path().empty()) {
+    PopulateIPConfigsCallback(service_path,
+                              shill_properties,
+                              chromeos::NetworkIPConfigVector(),
+                              std::string());
+  } else {
+    // Have to copy the properties because the object will go out of scope when
+    // this function call completes (it's owned by the calling function).
+    base::DictionaryValue* shill_props_copy = shill_properties->DeepCopy();
+    cros_->GetIPConfigs(
+        network->device_path(),
+        chromeos::NetworkLibrary::FORMAT_COLON_SEPARATED_HEX,
+        base::Bind(&InternetOptionsHandler::PopulateIPConfigsCallback,
+                   weak_factory_.GetWeakPtr(),
+                   service_path,
+                   base::Owned(shill_props_copy)));
+  }
 }
 
 void InternetOptionsHandler::PopulateIPConfigsCallback(
     const std::string& service_path,
-    base::DictionaryValue* shill_properties,
+    const base::DictionaryValue* shill_properties,
     const chromeos::NetworkIPConfigVector& ipconfigs,
     const std::string& hardware_address) {
   if (!shill_properties)
diff --git a/chrome/browser/ui/webui/options/chromeos/internet_options_handler.h b/chrome/browser/ui/webui/options/chromeos/internet_options_handler.h
index 9d19ad3..59ef335 100644
--- a/chrome/browser/ui/webui/options/chromeos/internet_options_handler.h
+++ b/chrome/browser/ui/webui/options/chromeos/internet_options_handler.h
@@ -109,7 +109,7 @@
       const base::DictionaryValue* shill_properties);
   void PopulateIPConfigsCallback(
       const std::string& service_path,
-      base::DictionaryValue* shill_properties,
+      const base::DictionaryValue* shill_properties,
       const chromeos::NetworkIPConfigVector& ipconfigs,
       const std::string& hardware_address);
   void PopulateConnectionDetails(const chromeos::Network* network,
diff --git a/chrome/browser/ui/webui/options/chromeos/proxy_handler.cc b/chrome/browser/ui/webui/options/chromeos/proxy_handler.cc
index 92bab43..4ed2345 100644
--- a/chrome/browser/ui/webui/options/chromeos/proxy_handler.cc
+++ b/chrome/browser/ui/webui/options/chromeos/proxy_handler.cc
@@ -8,7 +8,7 @@
 #include "base/callback.h"
 #include "base/stl_util.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "base/values.h"
 #include "chrome/browser/chromeos/system/statistics_provider.h"
 #include "chrome/common/chrome_constants.h"
@@ -70,7 +70,7 @@
 
   bool keyboard_driven_oobe = false;
   system::StatisticsProvider::GetInstance()->GetMachineFlag(
-      chromeos::kOemKeyboardDrivenOobeKey, &keyboard_driven_oobe);
+      chromeos::system::kOemKeyboardDrivenOobeKey, &keyboard_driven_oobe);
   if (keyboard_driven_oobe) {
     web_ui()->CallJavascriptFunction(
         "DetailsInternetPage.initializeKeyboardFlow");
diff --git a/chrome/browser/ui/webui/options/core_options_handler.cc b/chrome/browser/ui/webui/options/core_options_handler.cc
index 4241edb..e063533 100644
--- a/chrome/browser/ui/webui/options/core_options_handler.cc
+++ b/chrome/browser/ui/webui/options/core_options_handler.cc
@@ -472,26 +472,41 @@
 
   switch (type) {
     case TYPE_BOOLEAN:
-      CHECK_EQ(base::Value::TYPE_BOOLEAN, value->GetType());
+      if (!value->IsType(base::Value::TYPE_BOOLEAN)) {
+        NOTREACHED();
+        return;
+      }
       break;
     case TYPE_INTEGER: {
       // In JS all numbers are doubles.
       double double_value;
-      CHECK(value->GetAsDouble(&double_value));
+      if (!value->GetAsDouble(&double_value)) {
+        NOTREACHED();
+        return;
+      }
       int int_value = static_cast<int>(double_value);
       temp_value.reset(new base::FundamentalValue(int_value));
       value = temp_value.get();
       break;
     }
     case TYPE_DOUBLE:
-      CHECK_EQ(base::Value::TYPE_DOUBLE, value->GetType());
+      if (!value->IsType(base::Value::TYPE_DOUBLE)) {
+        NOTREACHED();
+        return;
+      }
       break;
     case TYPE_STRING:
-      CHECK_EQ(base::Value::TYPE_STRING, value->GetType());
+      if (!value->IsType(base::Value::TYPE_STRING)) {
+        NOTREACHED();
+        return;
+      }
       break;
     case TYPE_URL: {
       std::string original;
-      CHECK(value->GetAsString(&original));
+      if (!value->GetAsString(&original)) {
+        NOTREACHED();
+        return;
+      }
       GURL fixed = URLFixerUpper::FixupURL(original, std::string());
       temp_value.reset(new base::StringValue(fixed.spec()));
       value = temp_value.get();
@@ -500,11 +515,17 @@
     case TYPE_LIST: {
       // In case we have a List pref we got a JSON string.
       std::string json_string;
-      CHECK(value->GetAsString(&json_string));
+      if (!value->GetAsString(&json_string)) {
+        NOTREACHED();
+        return;
+      }
       temp_value.reset(
           base::JSONReader::Read(json_string));
       value = temp_value.get();
-      CHECK_EQ(base::Value::TYPE_LIST, value->GetType());
+      if (!value->IsType(base::Value::TYPE_LIST)) {
+        NOTREACHED();
+        return;
+      }
       break;
     }
     default:
diff --git a/chrome/browser/ui/webui/options/import_data_handler.cc b/chrome/browser/ui/webui/options/import_data_handler.cc
index 2bb576b..ccb0165 100644
--- a/chrome/browser/ui/webui/options/import_data_handler.cc
+++ b/chrome/browser/ui/webui/options/import_data_handler.cc
@@ -16,10 +16,10 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/thread_restrictions.h"
 #include "base/values.h"
+#include "chrome/browser/browser_process.h"
 #include "chrome/browser/importer/external_process_importer_host.h"
-#include "chrome/browser/importer/importer_host.h"
+#include "chrome/browser/importer/importer_creator.h"
 #include "chrome/browser/importer/importer_list.h"
-#include "chrome/browser/importer/importer_type.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser_finder.h"
 #include "content/public/browser/web_ui.h"
@@ -35,10 +35,10 @@
 
 ImportDataHandler::~ImportDataHandler() {
   if (importer_list_.get())
-    importer_list_->SetObserver(NULL);
+    importer_list_->set_observer(NULL);
 
   if (importer_host_)
-    importer_host_->SetObserver(NULL);
+    importer_host_->set_observer(NULL);
 }
 
 void ImportDataHandler::GetLocalizedValues(DictionaryValue* localized_strings) {
@@ -64,9 +64,9 @@
 }
 
 void ImportDataHandler::InitializeHandler() {
-  Profile* profile = Profile::FromWebUI(web_ui());
-  importer_list_ = new ImporterList(profile->GetRequestContext());
-  importer_list_->DetectSourceProfiles(this);
+  importer_list_ = new ImporterList();
+  importer_list_->DetectSourceProfiles(
+      g_browser_process->GetApplicationLocale(), this);
 }
 
 void ImportDataHandler::RegisterMessages() {
@@ -109,22 +109,8 @@
                                      state);
     import_did_succeed_ = false;
 
-    // TODO(gab): Make Linux use OOP import as well (http://crbug.com/56816) and
-    // get rid of these ugly ifdefs.
-#if defined(OS_MACOSX) || defined(OS_WIN)
-    // The Google Toolbar importer doesn't work for the out-of-process import.
-    // This is the only entry point for this importer (it is never used on first
-    // run). See discussion on http://crbug.com/219419 for details.
-    if (source_profile.importer_type == importer::TYPE_GOOGLE_TOOLBAR5)
-      importer_host_ = new ImporterHost;
-    else
-      importer_host_ = new ExternalProcessImporterHost;
-#else
-    importer_host_ = new ImporterHost;
-#endif
-    importer_host_->SetObserver(this);
-    importer_host_->set_browser(
-        chrome::FindBrowserWithWebContents(web_ui()->GetWebContents()));
+    importer_host_ = new ExternalProcessImporterHost();
+    importer_host_->set_observer(this);
     Profile* profile = Profile::FromWebUI(web_ui());
     importer_host_->StartImportSettings(source_profile, profile,
                                         import_services,
@@ -184,7 +170,7 @@
 }
 
 void ImportDataHandler::ImportEnded() {
-  importer_host_->SetObserver(NULL);
+  importer_host_->set_observer(NULL);
   importer_host_ = NULL;
 
   if (import_did_succeed_) {
diff --git a/chrome/browser/ui/webui/options/import_data_handler.h b/chrome/browser/ui/webui/options/import_data_handler.h
index d22ff82..79bd035 100644
--- a/chrome/browser/ui/webui/options/import_data_handler.h
+++ b/chrome/browser/ui/webui/options/import_data_handler.h
@@ -8,12 +8,12 @@
 #include "base/basictypes.h"
 #include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
-#include "chrome/browser/importer/importer_data_types.h"
 #include "chrome/browser/importer/importer_list_observer.h"
 #include "chrome/browser/importer/importer_progress_observer.h"
 #include "chrome/browser/ui/webui/options/options_ui.h"
+#include "chrome/common/importer/importer_data_types.h"
 
-class ImporterHost;
+class ExternalProcessImporterHost;
 class ImporterList;
 
 namespace options {
@@ -51,7 +51,7 @@
 
   // If non-null it means importing is in progress. ImporterHost takes care
   // of deleting itself when import is complete.
-  ImporterHost* importer_host_;  // weak
+  ExternalProcessImporterHost* importer_host_;  // weak
 
   bool import_did_succeed_;
 
diff --git a/chrome/browser/ui/webui/options/language_options_handler_common.cc b/chrome/browser/ui/webui/options/language_options_handler_common.cc
index 5517541..9493a06 100644
--- a/chrome/browser/ui/webui/options/language_options_handler_common.cc
+++ b/chrome/browser/ui/webui/options/language_options_handler_common.cc
@@ -13,7 +13,7 @@
 #include "base/bind.h"
 #include "base/command_line.h"
 #include "base/prefs/pref_service.h"
-#include "base/string_util.h"
+#include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
@@ -125,6 +125,13 @@
   localized_strings->SetBoolean("enableTranslateSettings",
                                 enable_translate_settings);
 
+  Profile* profile = Profile::FromWebUI(web_ui());
+  PrefService* prefs = profile->GetPrefs();
+  std::string default_target_language =
+      TranslateManager::GetTargetLanguage(prefs);
+  localized_strings->SetString("defaultTargetLanguage",
+                               default_target_language);
+
   std::vector<std::string> languages;
   TranslateManager::GetSupportedLanguages(&languages);
 
diff --git a/chrome/browser/ui/webui/options/manage_profile_handler.cc b/chrome/browser/ui/webui/options/manage_profile_handler.cc
index ad252ff..94a0929 100644
--- a/chrome/browser/ui/webui/options/manage_profile_handler.cc
+++ b/chrome/browser/ui/webui/options/manage_profile_handler.cc
@@ -92,13 +92,16 @@
     { "manageProfilesDuplicateNameError",
         IDS_PROFILES_MANAGE_DUPLICATE_NAME_ERROR },
     { "manageProfilesIconLabel", IDS_PROFILES_MANAGE_ICON_LABEL },
-    { "manageProfilesLimitedNotSignedInLabel",
-        IDS_PROFILES_CREATE_LIMITED_NOT_SIGNED_IN_LABEL },
-    { "manageProfilesLimitedNotSignedInLink",
-        IDS_PROFILES_CREATE_LIMITED_NOT_SIGNED_IN_LINK },
+    { "manageProfilesManagedSignedInLabel",
+    IDS_PROFILES_CREATE_MANAGED_SIGNED_IN_LABEL },
+    { "manageProfilesManagedNotSignedInLabel",
+        IDS_PROFILES_CREATE_MANAGED_NOT_SIGNED_IN_LABEL },
+    { "manageProfilesManagedNotSignedInLink",
+        IDS_PROFILES_CREATE_MANAGED_NOT_SIGNED_IN_LINK },
     { "deleteProfileTitle", IDS_PROFILES_DELETE_TITLE },
     { "deleteProfileOK", IDS_PROFILES_DELETE_OK_BUTTON_LABEL },
     { "deleteProfileMessage", IDS_PROFILES_DELETE_MESSAGE },
+    { "deleteManagedProfileAddendum", IDS_PROFILES_DELETE_MANAGED_ADDENDUM },
     { "createProfileTitle", IDS_PROFILES_CREATE_TITLE },
     { "createProfileInstructions", IDS_PROFILES_CREATE_INSTRUCTIONS },
     { "createProfileConfirm", IDS_PROFILES_CREATE_CONFIRM },
@@ -124,10 +127,17 @@
 void ManageProfileHandler::InitializeHandler() {
   registrar_.Add(this, chrome::NOTIFICATION_PROFILE_CACHED_INFO_CHANGED,
                  content::NotificationService::AllSources());
+
+  pref_change_registrar_.Init(Profile::FromWebUI(web_ui())->GetPrefs());
+  pref_change_registrar_.Add(
+      prefs::kManagedUserCreationAllowed,
+      base::Bind(&ManageProfileHandler::OnCreateManagedUserPrefChange,
+                 base::Unretained(this)));
 }
 
 void ManageProfileHandler::InitializePage() {
   SendProfileNames();
+  OnCreateManagedUserPrefChange();
 }
 
 void ManageProfileHandler::RegisterMessages() {
@@ -143,8 +153,8 @@
   web_ui()->RegisterMessageCallback("requestHasProfileShortcuts",
       base::Bind(&ManageProfileHandler::RequestHasProfileShortcuts,
                  base::Unretained(this)));
-  web_ui()->RegisterMessageCallback("requestSignedInText",
-      base::Bind(&ManageProfileHandler::RequestSignedInText,
+  web_ui()->RegisterMessageCallback("requestCreateProfileUpdate",
+      base::Bind(&ManageProfileHandler::RequestCreateProfileUpdate,
                  base::Unretained(this)));
   web_ui()->RegisterMessageCallback("profileIconSelectionChanged",
       base::Bind(&ManageProfileHandler::ProfileIconSelectionChanged,
@@ -389,18 +399,24 @@
                                weak_factory_.GetWeakPtr()));
 }
 
-void ManageProfileHandler::RequestSignedInText(const base::ListValue* args) {
+void ManageProfileHandler::RequestCreateProfileUpdate(
+    const base::ListValue* args) {
   SigninManagerBase* manager =
       SigninManagerFactory::GetForProfile(Profile::FromWebUI(web_ui()));
   string16 username = UTF8ToUTF16(manager->GetAuthenticatedUsername());
-  string16 text = string16();
-  if (!username.empty()) {
-     text = l10n_util::GetStringFUTF16(
-         IDS_PROFILES_CREATE_LIMITED_SIGNED_IN_LABEL, username);
-  }
-  StringValue text_value(text);
+  StringValue username_value(username);
   web_ui()->CallJavascriptFunction("CreateProfileOverlay.updateSignedInStatus",
-                                   text_value);
+                                   username_value);
+
+  OnCreateManagedUserPrefChange();
+}
+
+void ManageProfileHandler::OnCreateManagedUserPrefChange() {
+  PrefService* prefs = Profile::FromWebUI(web_ui())->GetPrefs();
+  base::FundamentalValue allowed(
+      prefs->GetBoolean(prefs::kManagedUserCreationAllowed));
+  web_ui()->CallJavascriptFunction(
+      "CreateProfileOverlay.updateManagedUsersAllowed", allowed);
 }
 
 void ManageProfileHandler::OnHasProfileShortcuts(bool has_shortcuts) {
diff --git a/chrome/browser/ui/webui/options/manage_profile_handler.h b/chrome/browser/ui/webui/options/manage_profile_handler.h
index 6872cf5..4723b67 100644
--- a/chrome/browser/ui/webui/options/manage_profile_handler.h
+++ b/chrome/browser/ui/webui/options/manage_profile_handler.h
@@ -8,6 +8,7 @@
 #include <string>
 
 #include "base/memory/weak_ptr.h"
+#include "base/prefs/pref_change_registrar.h"
 #include "chrome/browser/ui/webui/options/options_ui.h"
 
 namespace base {
@@ -87,10 +88,15 @@
   // |args| is of the form: [ {string} profileFilePath ]
   void RequestHasProfileShortcuts(const base::ListValue* args);
 
-  // Callback for the "requestSignedInText" message.
-  // Sends the text to be shown if the user is signed in, or an empty string
-  // if not. |args| is not used.
-  void RequestSignedInText(const base::ListValue* args);
+  // Callback for the "RequestCreateProfileUpdate" message.
+  // Sends the email address of the signed-in user, or an empty string if the
+  // user is not signed in. Also sends information about whether managed users
+  // may be created.
+  void RequestCreateProfileUpdate(const base::ListValue* args);
+
+  // When the pref allowing managed-user creation changes, sends the new value
+  // to the UI.
+  void OnCreateManagedUserPrefChange();
 
   // Callback invoked from the profile manager indicating whether the profile
   // being edited has any desktop shortcuts.
@@ -112,6 +118,10 @@
   // For generating weak pointers to itself for callbacks.
   base::WeakPtrFactory<ManageProfileHandler> weak_factory_;
 
+  // Used to observe the preference that allows creating managed users, which
+  // can be changed by policy.
+  PrefChangeRegistrar pref_change_registrar_;
+
   DISALLOW_COPY_AND_ASSIGN(ManageProfileHandler);
 };
 
diff --git a/chrome/browser/ui/webui/options/managed_user_create_confirm_handler.cc b/chrome/browser/ui/webui/options/managed_user_create_confirm_handler.cc
index 04ad4cd..92d6524 100644
--- a/chrome/browser/ui/webui/options/managed_user_create_confirm_handler.cc
+++ b/chrome/browser/ui/webui/options/managed_user_create_confirm_handler.cc
@@ -11,6 +11,9 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/signin/signin_manager.h"
+#include "chrome/browser/signin/signin_manager_base.h"
+#include "chrome/browser/signin/signin_manager_factory.h"
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/host_desktop.h"
 #include "chrome/browser/ui/startup/startup_types.h"
@@ -31,18 +34,21 @@
   DCHECK(localized_strings);
 
   static OptionsStringResource resources[] = {
-    {"managedUserCreateConfirmTitle", IDS_NEW_LIMITED_USER_SUCCESS_TITLE},
-    {"managedUserCreateConfirmTextSlide1",
-     IDS_NEW_LIMITED_USER_SUCCESS_TEXT_SLIDE_1},
-    {"managedUserCreateConfirmTextSlide2",
-     IDS_NEW_LIMITED_USER_SUCCESS_TEXT_SLIDE_2},
-    {"managedUserCreateConfirmTextSlide3",
-     IDS_NEW_LIMITED_USER_SUCCESS_TEXT_SLIDE_3},
-    {"managedUserCreateConfirmDone", IDS_NEW_LIMITED_USER_SUCCESS_DONE_BUTTON},
-    {"managedUserCreateConfirmSwitch",
-     IDS_NEW_LIMITED_USER_SUCCESS_SWITCH_BUTTON},
+    { "managedUserCreatedTitle", IDS_NEW_MANAGED_USER_CREATED_TITLE },
+    { "managedUserCreatedText", IDS_NEW_MANAGED_USER_CREATED_TEXT },
+    { "managedUserCreatedDone", IDS_NEW_MANAGED_USER_CREATED_DONE_BUTTON },
+    { "managedUserCreatedSwitch", IDS_NEW_MANAGED_USER_CREATED_SWITCH_BUTTON },
   };
 
+  SigninManagerBase* signin =
+      SigninManagerFactory::GetForProfile(Profile::FromWebUI(web_ui()));
+  if (signin) {
+    localized_strings->SetString("custodianEmail",
+                                 signin->GetAuthenticatedUsername());
+  } else {
+    localized_strings->SetString("custodianEmail", std::string());
+  }
+
   RegisterStrings(localized_strings, resources, arraysize(resources));
 }
 
diff --git a/chrome/browser/ui/webui/options/managed_user_learn_more_handler.cc b/chrome/browser/ui/webui/options/managed_user_learn_more_handler.cc
index a1a77fd..177def7 100644
--- a/chrome/browser/ui/webui/options/managed_user_learn_more_handler.cc
+++ b/chrome/browser/ui/webui/options/managed_user_learn_more_handler.cc
@@ -20,9 +20,9 @@
   DCHECK(localized_strings);
 
   static OptionsStringResource resources[] = {
-    { "managedUserLearnMoreTitle", IDS_NEW_LIMITED_USER_LEARN_MORE_TITLE },
-    { "managedUserLearnMoreText", IDS_NEW_LIMITED_USER_LEARN_MORE_TEXT },
-    { "managedUserLearnMoreDone", IDS_NEW_LIMITED_USER_LEARN_MORE_DONE_BUTTON },
+    { "managedUserLearnMoreTitle", IDS_NEW_MANAGED_USER_LEARN_MORE_TITLE },
+    { "managedUserLearnMoreText", IDS_NEW_MANAGED_USER_LEARN_MORE_TEXT },
+    { "managedUserLearnMoreDone", IDS_NEW_MANAGED_USER_LEARN_MORE_DONE_BUTTON },
   };
 
   RegisterStrings(localized_strings, resources, arraysize(resources));
diff --git a/chrome/browser/ui/webui/options/media_galleries_handler.cc b/chrome/browser/ui/webui/options/media_galleries_handler.cc
index 90a9362..c157a1b 100644
--- a/chrome/browser/ui/webui/options/media_galleries_handler.cc
+++ b/chrome/browser/ui/webui/options/media_galleries_handler.cc
@@ -9,7 +9,6 @@
 #include "base/strings/string_number_conversions.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/media_galleries/media_file_system_registry.h"
-#include "chrome/browser/media_galleries/media_galleries_dialog_controller.h"
 #include "chrome/browser/media_galleries/media_galleries_preferences.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/storage_monitor/storage_monitor.h"
@@ -24,7 +23,6 @@
 
 namespace options {
 
-using chrome::MediaGalleriesDialogController;
 using chrome::MediaGalleriesPreferences;
 using chrome::MediaGalleriesPrefInfoMap;
 using chrome::MediaGalleryPrefInfo;
@@ -53,7 +51,7 @@
 }
 
 void MediaGalleriesHandler::InitializePage() {
-  chrome::StorageMonitor::GetInstance()->Initialize(
+  chrome::StorageMonitor::GetInstance()->EnsureInitialized(
       base::Bind(&MediaGalleriesHandler::InitializeOnStorageMonitorInit,
                  weak_ptr_factory_.GetWeakPtr()));
 }
@@ -75,7 +73,7 @@
 }
 
 void MediaGalleriesHandler::RegisterMessages() {
-  chrome::StorageMonitor::GetInstance()->Initialize(
+  chrome::StorageMonitor::GetInstance()->EnsureInitialized(
       base::Bind(&MediaGalleriesHandler::RegisterOnStorageMonitorInit,
                  weak_ptr_factory_.GetWeakPtr()));
 }
@@ -106,9 +104,7 @@
       continue;
 
     DictionaryValue* dict = new DictionaryValue();
-    dict->SetString("displayName",
-        MediaGalleriesDialogController::GetGalleryDisplayNameNoAttachment(
-            gallery));
+    dict->SetString("displayName", gallery.GetGalleryDisplayName());
     dict->SetString("path", gallery.AbsolutePath().LossyDisplayName());
     dict->SetString("id", base::Uint64ToString(gallery.pref_id));
     list.Append(dict);
diff --git a/chrome/browser/ui/webui/options/options_ui.cc b/chrome/browser/ui/webui/options/options_ui.cc
index f4567d9..11a58b1 100644
--- a/chrome/browser/ui/webui/options/options_ui.cc
+++ b/chrome/browser/ui/webui/options/options_ui.cc
@@ -15,7 +15,7 @@
 #include "base/strings/string_piece.h"
 #include "base/strings/string_util.h"
 #include "base/threading/thread.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "base/values.h"
 #include "chrome/browser/autocomplete/autocomplete_match.h"
 #include "chrome/browser/autocomplete/autocomplete_result.h"
@@ -59,6 +59,7 @@
 #include "grit/options_resources.h"
 #include "grit/theme_resources.h"
 #include "net/base/escape.h"
+#include "ui/base/l10n/l10n_util.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/webui/jstemplate_builder.h"
 #include "ui/webui/web_ui_util.h"
diff --git a/chrome/browser/ui/webui/options/preferences_browsertest.cc b/chrome/browser/ui/webui/options/preferences_browsertest.cc
index dab5306..da6b08d 100644
--- a/chrome/browser/ui/webui/options/preferences_browsertest.cc
+++ b/chrome/browser/ui/webui/options/preferences_browsertest.cc
@@ -33,7 +33,7 @@
 #include "testing/gtest/include/gtest/gtest.h"
 
 #if defined(OS_CHROMEOS)
-#include "base/stringprintf.h"
+#include "base/strings/stringprintf.h"
 #include "chrome/browser/chromeos/net/proxy_config_handler.h"
 #include "chrome/browser/chromeos/proxy_cros_settings_parser.h"
 #include "chrome/browser/chromeos/settings/cros_settings.h"
diff --git a/chrome/browser/ui/webui/options/settings_app_browsertest.js b/chrome/browser/ui/webui/options/settings_app_browsertest.js
new file mode 100644
index 0000000..7de3546
--- /dev/null
+++ b/chrome/browser/ui/webui/options/settings_app_browsertest.js
@@ -0,0 +1,57 @@
+// 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.
+
+/**
+ * TestFixture for App Launcher's Settings App testing.
+ * @extends {testing.Test}
+ * @constructor
+ */
+function SettingsAppWebUITest() {}
+
+SettingsAppWebUITest.prototype = {
+  __proto__: testing.Test.prototype,
+
+  /**
+   * Browse to Settings App page, in a browser.
+   */
+  browsePreload: 'chrome://settings-frame/options_settings_app.html',
+};
+
+GEN('#if defined(ENABLE_SETTINGS_APP)');
+
+// Test opening Settings App, and do some checks on section visibility.
+TEST_F('SettingsAppWebUITest', 'testOpenSettingsApp', function() {
+  // Note there is no location bar in the Settings App.
+
+  // Some things are hidden via a parent, so make a helper function.
+  function isVisible(elementId) {
+    var elem = $(elementId);
+    return elem.offsetWidth > 0 || elem.offsetHeight > 0;
+  }
+  assertTrue(OptionsPage.isSettingsApp());
+  assertTrue(isVisible('sync-users-section'));
+  assertTrue(isVisible('sync-section'));
+
+  // Spot-check some regular settings items that should be hidden.
+  assertFalse(isVisible('change-home-page-section'));
+  assertFalse(isVisible('default-search-engine'));
+  assertFalse(isVisible('privacy-section'));
+  assertFalse(isVisible('startup-section'));
+});
+
+// Check functionality of LoadTimeData.overrideValues(), which the Settings App
+// uses. Do spot checks, so the test is not too fragile. Some of the content
+// strings rely on waiting for sync sign-in status, or platform-specifics.
+TEST_F('SettingsAppWebUITest', 'testStrings', function() {
+  // Ensure we check against the override values.
+  assertTrue(!!loadTimeData.getValue('settingsApp'));
+
+  // Check a product-specific label, to ensure it uses "App Launcher", and not
+  // Chrome / Chromium.
+  var languagesLabelElement =
+      document.querySelector('[i18n-content="languageSectionLabel"]');
+  assertNotEquals(-1, languagesLabelElement.innerHTML.indexOf('App Launcher'));
+});
+
+GEN('#endif  // defined(ENABLE_SETTINGS_APP)');
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 af7fbce..118452f 100644
--- a/chrome/browser/ui/webui/performance_monitor/performance_monitor_handler.cc
+++ b/chrome/browser/ui/webui/performance_monitor/performance_monitor_handler.cc
@@ -7,7 +7,7 @@
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/command_line.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "base/values.h"
 #include "chrome/browser/performance_monitor/database.h"
 #include "chrome/browser/performance_monitor/event.h"
diff --git a/chrome/browser/ui/webui/performance_monitor/performance_monitor_ui_constants.cc b/chrome/browser/ui/webui/performance_monitor/performance_monitor_ui_constants.cc
index 07ffb35..a510e24 100644
--- a/chrome/browser/ui/webui/performance_monitor/performance_monitor_ui_constants.cc
+++ b/chrome/browser/ui/webui/performance_monitor/performance_monitor_ui_constants.cc
@@ -5,7 +5,7 @@
 #include "chrome/browser/ui/webui/performance_monitor/performance_monitor_ui_constants.h"
 
 #include "base/logging.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/performance_monitor/constants.h"
 
 namespace performance_monitor {
diff --git a/chrome/browser/ui/webui/performance_monitor/performance_monitor_ui_util.cc b/chrome/browser/ui/webui/performance_monitor/performance_monitor_ui_util.cc
index 2e8a9c1..5bf736b 100644
--- a/chrome/browser/ui/webui/performance_monitor/performance_monitor_ui_util.cc
+++ b/chrome/browser/ui/webui/performance_monitor/performance_monitor_ui_util.cc
@@ -6,7 +6,7 @@
 
 #include <algorithm>
 
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/performance_monitor/metric.h"
 
 namespace performance_monitor {
diff --git a/chrome/browser/ui/webui/performance_monitor/performance_monitor_ui_util_unittest.cc b/chrome/browser/ui/webui/performance_monitor/performance_monitor_ui_util_unittest.cc
index d120f38..6841ea8 100644
--- a/chrome/browser/ui/webui/performance_monitor/performance_monitor_ui_util_unittest.cc
+++ b/chrome/browser/ui/webui/performance_monitor/performance_monitor_ui_util_unittest.cc
@@ -5,7 +5,7 @@
 #include <string>
 
 #include "base/strings/string_number_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/performance_monitor/metric.h"
 #include "chrome/browser/ui/webui/performance_monitor/performance_monitor_ui_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/chrome/browser/ui/webui/policy_ui.cc b/chrome/browser/ui/webui/policy_ui.cc
index 2ee0e85..3b3f1ea 100644
--- a/chrome/browser/ui/webui/policy_ui.cc
+++ b/chrome/browser/ui/webui/policy_ui.cc
@@ -12,7 +12,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/strings/string16.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/policy/browser_policy_connector.h"
@@ -32,8 +32,12 @@
 #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/chrome_notification_types.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"
+#include "content/public/browser/notification_service.h"
 #include "content/public/browser/web_ui.h"
 #include "content/public/browser/web_ui_data_source.h"
 #include "content/public/browser/web_ui_message_handler.h"
@@ -54,6 +58,17 @@
 #include "chrome/browser/policy/cloud/user_cloud_policy_manager_factory.h"
 #endif
 
+#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/extensions/extension_system.h"
+#include "chrome/browser/policy/policy_domain_descriptor.h"
+#include "chrome/browser/policy/policy_schema.h"
+#include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/extension_manifest_constants.h"
+#include "chrome/common/extensions/extension_set.h"
+#include "chrome/common/extensions/manifest.h"
+#endif
+
 namespace em = enterprise_management;
 
 namespace {
@@ -258,12 +273,18 @@
 #endif
 
 // The JavaScript message handler for the chrome://policy page.
-class PolicyUIHandler : public content::WebUIMessageHandler,
+class PolicyUIHandler : public content::NotificationObserver,
+                        public content::WebUIMessageHandler,
                         public policy::PolicyService::Observer {
  public:
   PolicyUIHandler();
   virtual ~PolicyUIHandler();
 
+  // content::NotificationObserver implementation.
+  virtual void Observe(int type,
+                       const content::NotificationSource& source,
+                       const content::NotificationDetails& details) OVERRIDE;
+
   // content::WebUIMessageHandler implementation.
   virtual void RegisterMessages() OVERRIDE;
 
@@ -286,6 +307,14 @@
   // information is sent.
   void SendStatus() const;
 
+  // Inserts a description of each policy in |policy_map| into |values|, using
+  // the optional errors in |errors| to determine the status of each policy.
+  void GetPolicyValues(const policy::PolicyMap& policy_map,
+                       policy::PolicyErrorMap* errors,
+                       base::DictionaryValue* values) const;
+
+  void GetChromePolicyValues(base::DictionaryValue* values) const;
+
   void HandleInitialized(const base::ListValue* args);
   void HandleReloadPolicies(const base::ListValue* args);
 
@@ -303,6 +332,8 @@
   scoped_ptr<CloudPolicyStatusProvider> user_status_provider_;
   scoped_ptr<CloudPolicyStatusProvider> device_status_provider_;
 
+  content::NotificationRegistrar registrar_;
+
   DISALLOW_COPY_AND_ASSIGN(PolicyUIHandler);
 };
 
@@ -425,6 +456,7 @@
 
 PolicyUIHandler::~PolicyUIHandler() {
   GetPolicyService()->RemoveObserver(policy::POLICY_DOMAIN_CHROME, this);
+  GetPolicyService()->RemoveObserver(policy::POLICY_DOMAIN_EXTENSIONS, this);
 }
 
 void PolicyUIHandler::RegisterMessages() {
@@ -472,6 +504,14 @@
   user_status_provider_->SetStatusChangeCallback(update_callback);
   device_status_provider_->SetStatusChangeCallback(update_callback);
   GetPolicyService()->AddObserver(policy::POLICY_DOMAIN_CHROME, this);
+  GetPolicyService()->AddObserver(policy::POLICY_DOMAIN_EXTENSIONS, this);
+
+  registrar_.Add(this,
+                 chrome::NOTIFICATION_EXTENSION_LOADED,
+                 content::NotificationService::AllSources());
+  registrar_.Add(this,
+                 chrome::NOTIFICATION_EXTENSION_UNLOADED,
+                 content::NotificationService::AllSources());
 
   web_ui()->RegisterMessageCallback(
       "initialized",
@@ -482,44 +522,119 @@
                  base::Unretained(this)));
 }
 
+void PolicyUIHandler::Observe(int type,
+                              const content::NotificationSource& source,
+                              const content::NotificationDetails& details) {
+  DCHECK(type == chrome::NOTIFICATION_EXTENSION_LOADED ||
+         type == chrome::NOTIFICATION_EXTENSION_UNLOADED);
+  SendPolicyNames();
+  SendPolicyValues();
+}
+
 void PolicyUIHandler::OnPolicyUpdated(const policy::PolicyNamespace& ns,
                                       const policy::PolicyMap& previous,
                                       const policy::PolicyMap& current) {
-  DCHECK_EQ(policy::POLICY_DOMAIN_CHROME, ns.domain);
-  DCHECK(ns.component_id.empty());
   SendPolicyValues();
 }
 
 void PolicyUIHandler::SendPolicyNames() const {
   base::DictionaryValue names;
+
+  // Add Chrome policy names.
+  base::DictionaryValue* chrome_policy_names = new base::DictionaryValue;
   const policy::PolicyDefinitionList* list =
       policy::GetChromePolicyDefinitionList();
   for (const policy::PolicyDefinitionList::Entry* entry = list->begin;
        entry != list->end; ++entry) {
-    names.SetBoolean(entry->name, true);
+    chrome_policy_names->SetBoolean(entry->name, true);
   }
+  names.Set("chromePolicyNames", chrome_policy_names);
+
+#if !defined(OS_ANDROID) && !defined(OS_IOS)
+  // Add extension policy names.
+  base::DictionaryValue* extension_policy_names = new base::DictionaryValue;
+  extensions::ExtensionSystem* extension_system =
+      extensions::ExtensionSystem::Get(Profile::FromWebUI(web_ui()));
+  const ExtensionSet* extensions =
+      extension_system->extension_service()->extensions();
+  scoped_refptr<const policy::PolicyDomainDescriptor> policy_domain_descriptor;
+  policy_domain_descriptor = GetPolicyService()->
+      GetPolicyDomainDescriptor(policy::POLICY_DOMAIN_EXTENSIONS);
+  const policy::PolicyDomainDescriptor::SchemaMap& schema_map =
+      policy_domain_descriptor->components();
+
+  for (ExtensionSet::const_iterator it = extensions->begin();
+       it != extensions->end(); ++it) {
+    const extensions::Extension* extension = it->get();
+    // Skip this extension if it's not an enterprise extension.
+    if (!extension->manifest()->HasPath(
+        extension_manifest_keys::kStorageManagedSchema))
+      continue;
+    base::DictionaryValue* extension_value = new base::DictionaryValue;
+    extension_value->SetString("name", extension->name());
+    policy::PolicyDomainDescriptor::SchemaMap::const_iterator schema =
+        schema_map.find(extension->id());
+    base::DictionaryValue* policy_names = new base::DictionaryValue;
+    if (schema != schema_map.end()) {
+      // Get policy names from the extension's policy schema.
+      // Store in a map, not an array, for faster lookup on JS side.
+      const policy::PolicySchemaMap* policies = schema->second->GetProperties();
+      policy::PolicySchemaMap::const_iterator it_policies;
+      for (it_policies = policies->begin(); it_policies != policies->end();
+           it_policies++) {
+        policy_names->SetBoolean(it_policies->first, true);
+      }
+    }
+    extension_value->Set("policyNames", policy_names);
+    extension_policy_names->Set(extension->id(), extension_value);
+  }
+  names.Set("extensionPolicyNames", extension_policy_names);
+#endif
+
   web_ui()->CallJavascriptFunction("policy.Page.setPolicyNames", names);
 }
 
 void PolicyUIHandler::SendPolicyValues() const {
-  // Make a copy that can be modified, since some policy values are modified
-  // before being displayed.
-  policy::PolicyMap map;
-  map.CopyFrom(GetPolicyService()->GetPolicies(policy::PolicyNamespace(
-      policy::POLICY_DOMAIN_CHROME, std::string())));
+  base::DictionaryValue all_policies;
 
-  // Get a list of all the errors in the policy values.
-  const policy::ConfigurationPolicyHandlerList* handler_list =
-      g_browser_process->browser_policy_connector()->GetHandlerList();
-  policy::PolicyErrorMap errors;
-  handler_list->ApplyPolicySettings(map, NULL, &errors);
+  // Add Chrome policy values.
+  base::DictionaryValue* chrome_policies = new base::DictionaryValue;
+  GetChromePolicyValues(chrome_policies);
+  all_policies.Set("chromePolicies", chrome_policies);
 
-  // Convert dictionary values to strings for display.
-  handler_list->PrepareForDisplaying(&map);
+#if !defined(OS_ANDROID) && !defined(OS_IOS)
+  // Add extension policy values.
+  extensions::ExtensionSystem* extension_system =
+      extensions::ExtensionSystem::Get(Profile::FromWebUI(web_ui()));
+  const ExtensionSet* extensions =
+      extension_system->extension_service()->extensions();
+  base::DictionaryValue* extension_values = new base::DictionaryValue;
 
-  base::DictionaryValue values;
+  for (ExtensionSet::const_iterator it = extensions->begin();
+       it != extensions->end(); ++it) {
+    const extensions::Extension* extension = it->get();
+    // Skip this extension if it's not an enterprise extension.
+    if (!extension->manifest()->HasPath(
+        extension_manifest_keys::kStorageManagedSchema))
+      continue;
+    base::DictionaryValue* extension_policies = new base::DictionaryValue;
+    policy::PolicyNamespace policy_namespace = policy::PolicyNamespace(
+        policy::POLICY_DOMAIN_EXTENSIONS, extension->id());
+    policy::PolicyErrorMap empty_error_map;
+    GetPolicyValues(GetPolicyService()->GetPolicies(policy_namespace),
+                    &empty_error_map, extension_policies);
+    extension_values->Set(extension->id(), extension_policies);
+  }
+  all_policies.Set("extensionPolicies", extension_values);
+#endif
+  web_ui()->CallJavascriptFunction("policy.Page.setPolicyValues", all_policies);
+}
+
+void PolicyUIHandler::GetPolicyValues(const policy::PolicyMap& map,
+                                      policy::PolicyErrorMap* errors,
+                                      base::DictionaryValue* values) const {
   for (policy::PolicyMap::const_iterator entry = map.begin();
-      entry != map.end(); ++entry) {
+       entry != map.end(); ++entry) {
     base::DictionaryValue* value = new base::DictionaryValue;
     value->Set("value", entry->second.value->DeepCopy());
     if (entry->second.scope == policy::POLICY_SCOPE_USER)
@@ -530,13 +645,33 @@
       value->SetString("level", "recommended");
     else
       value->SetString("level", "mandatory");
-    string16 error = errors.GetErrors(entry->first);
+    string16 error = errors->GetErrors(entry->first);
     if (!error.empty())
       value->SetString("error", error);
-    values.Set(entry->first, value);
+    values->Set(entry->first, value);
   }
+}
 
-  web_ui()->CallJavascriptFunction("policy.Page.setPolicyValues", values);
+void PolicyUIHandler::GetChromePolicyValues(
+    base::DictionaryValue* values) const {
+  policy::PolicyService* policy_service = GetPolicyService();
+  policy::PolicyMap map;
+
+  // Make a copy that can be modified, since some policy values are modified
+  // before being displayed.
+  map.CopyFrom(policy_service->GetPolicies(
+      policy::PolicyNamespace(policy::POLICY_DOMAIN_CHROME, std::string())));
+
+  // Get a list of all the errors in the policy values.
+  const policy::ConfigurationPolicyHandlerList* handler_list =
+      g_browser_process->browser_policy_connector()->GetHandlerList();
+  policy::PolicyErrorMap errors;
+  handler_list->ApplyPolicySettings(map, NULL, &errors);
+
+  // Convert dictionary values to strings for display.
+  handler_list->PrepareForDisplaying(&map);
+
+  GetPolicyValues(map, &errors, values);
 }
 
 void PolicyUIHandler::SendStatus() const {
diff --git a/chrome/browser/ui/webui/policy_ui_browsertest.cc b/chrome/browser/ui/webui/policy_ui_browsertest.cc
index 13fc4ff..2d8193f 100644
--- a/chrome/browser/ui/webui/policy_ui_browsertest.cc
+++ b/chrome/browser/ui/webui/policy_ui_browsertest.cc
@@ -122,7 +122,7 @@
   // Retrieve the text contents of the policy table cells for all policies.
   const std::string javascript =
       "var entries = document.querySelectorAll("
-      "    'table#policy-table > tbody');"
+      "    'section.policy-table-section > * > tbody');"
       "var policies = [];"
       "for (var i = 0; i < entries.length; ++i) {"
       "  var items = entries[i].querySelectorAll('tr > td');"
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_ui.h b/chrome/browser/ui/webui/print_preview/print_preview_ui.h
index 4cfd242..51fdd02 100644
--- a/chrome/browser/ui/webui/print_preview/print_preview_ui.h
+++ b/chrome/browser/ui/webui/print_preview/print_preview_ui.h
@@ -9,7 +9,7 @@
 
 #include "base/gtest_prod_util.h"
 #include "base/memory/ref_counted.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/ui/webui/constrained_web_dialog_ui.h"
 
 class PrintPreviewDataService;
diff --git a/chrome/browser/ui/webui/quota_internals/quota_internals_types.h b/chrome/browser/ui/webui/quota_internals/quota_internals_types.h
index 0291567..a559782 100644
--- a/chrome/browser/ui/webui/quota_internals/quota_internals_types.h
+++ b/chrome/browser/ui/webui/quota_internals/quota_internals_types.h
@@ -8,7 +8,7 @@
 #include <map>
 #include <string>
 
-#include "base/time.h"
+#include "base/time/time.h"
 #include "googleurl/src/gurl.h"
 #include "webkit/common/quota/quota_types.h"
 
diff --git a/chrome/browser/ui/webui/set_as_default_browser_ui.cc b/chrome/browser/ui/webui/set_as_default_browser_ui.cc
index d939033..89184e2 100644
--- a/chrome/browser/ui/webui/set_as_default_browser_ui.cc
+++ b/chrome/browser/ui/webui/set_as_default_browser_ui.cc
@@ -23,8 +23,8 @@
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/chrome_pages.h"
 #include "chrome/browser/ui/singleton_tabs.h"
+#include "chrome/browser/ui/sync/sync_promo_ui.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
-#include "chrome/browser/ui/webui/sync_promo/sync_promo_ui.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/installer/util/install_util.h"
diff --git a/chrome/browser/ui/webui/signin/login_ui_service.cc b/chrome/browser/ui/webui/signin/login_ui_service.cc
index baa07f7..cae530f 100644
--- a/chrome/browser/ui/webui/signin/login_ui_service.cc
+++ b/chrome/browser/ui/webui/signin/login_ui_service.cc
@@ -11,8 +11,8 @@
 #include "chrome/browser/ui/chrome_pages.h"
 #include "chrome/browser/ui/host_desktop.h"
 #include "chrome/browser/ui/sync/inline_login_dialog.h"
+#include "chrome/browser/ui/sync/sync_promo_ui.h"
 #include "chrome/browser/ui/webui/signin/login_ui_service_factory.h"
-#include "chrome/browser/ui/webui/sync_promo/sync_promo_ui.h"
 #include "chrome/common/url_constants.h"
 
 #if defined(OS_CHROMEOS)
diff --git a/chrome/browser/ui/webui/sync_file_system_internals/extension_statuses_handler.cc b/chrome/browser/ui/webui/sync_file_system_internals/extension_statuses_handler.cc
index 15aa2f4..9e35e1e 100644
--- a/chrome/browser/ui/webui/sync_file_system_internals/extension_statuses_handler.cc
+++ b/chrome/browser/ui/webui/sync_file_system_internals/extension_statuses_handler.cc
@@ -9,9 +9,12 @@
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/values.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/extensions/extension_system.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/sync_file_system/sync_file_system_service.h"
 #include "chrome/browser/sync_file_system/sync_file_system_service_factory.h"
+#include "chrome/common/extensions/extension.h"
 #include "content/public/browser/web_ui.h"
 #include "content/public/browser/web_ui_data_source.h"
 #include "grit/sync_file_system_internals_resources.h"
@@ -33,23 +36,42 @@
                  base::Unretained(this)));
 }
 
-void ExtensionStatusesHandler::GetExtensionStatuses(
-    const base::ListValue* args) {
-  DCHECK(args);
+//static
+void ExtensionStatusesHandler::GetExtensionStatusesAsDictionary(
+    Profile* profile,
+    base::ListValue* values) {
+  DCHECK(profile);
+  DCHECK(values);
   std::map<GURL, std::string> status_map;
-  SyncFileSystemServiceFactory::GetForProfile(profile_)->GetExtensionStatusMap(
+  SyncFileSystemServiceFactory::GetForProfile(profile)->GetExtensionStatusMap(
       &status_map);
 
-  base::ListValue list;
+  ExtensionService* extension_service =
+      extensions::ExtensionSystem::Get(profile)->extension_service();
+  DCHECK(extension_service);
   for (std::map<GURL, std::string>::const_iterator itr = status_map.begin();
        itr != status_map.end();
        ++itr) {
-    base::DictionaryValue* dict = new DictionaryValue;
-    dict->SetString("extensionID", itr->first.spec());
-    dict->SetString("status", itr->second);
-    list.Append(dict);
-  }
+    std::string extension_id = itr->first.HostNoBrackets();
 
+    // Join with human readable extension name.
+    const extensions::Extension* extension =
+        extension_service->GetExtensionById(extension_id, true);
+    DCHECK(extension);
+
+    base::DictionaryValue* dict = new DictionaryValue;
+    dict->SetString("extensionID", extension_id);
+    dict->SetString("extensionName", extension->name());
+    dict->SetString("status", itr->second);
+    values->Append(dict);
+  }
+}
+
+void ExtensionStatusesHandler::GetExtensionStatuses(
+    const base::ListValue* args) {
+  DCHECK(args);
+  base::ListValue list;
+  GetExtensionStatusesAsDictionary(profile_, &list);
   web_ui()->CallJavascriptFunction("ExtensionStatuses.onGetExtensionStatuses",
                                    list);
 }
diff --git a/chrome/browser/ui/webui/sync_file_system_internals/extension_statuses_handler.h b/chrome/browser/ui/webui/sync_file_system_internals/extension_statuses_handler.h
index 74b1cbb..94e9442 100644
--- a/chrome/browser/ui/webui/sync_file_system_internals/extension_statuses_handler.h
+++ b/chrome/browser/ui/webui/sync_file_system_internals/extension_statuses_handler.h
@@ -21,6 +21,11 @@
   explicit ExtensionStatusesHandler(Profile* profile);
   virtual ~ExtensionStatusesHandler();
 
+  // Shared by Extension Statuses Tab and also File Metadata Tab to generate the
+  // extension drop down.
+  static void GetExtensionStatusesAsDictionary(Profile* profile,
+                                               base::ListValue* values);
+
   // WebUIMessageHandler implementation.
   virtual void RegisterMessages() OVERRIDE;
 
diff --git a/chrome/browser/ui/webui/sync_file_system_internals/file_metadata_handler.cc b/chrome/browser/ui/webui/sync_file_system_internals/file_metadata_handler.cc
index 6b508ad..42025bf 100644
--- a/chrome/browser/ui/webui/sync_file_system_internals/file_metadata_handler.cc
+++ b/chrome/browser/ui/webui/sync_file_system_internals/file_metadata_handler.cc
@@ -14,6 +14,8 @@
 #include "chrome/browser/sync_file_system/file_metadata.h"
 #include "chrome/browser/sync_file_system/sync_file_system_service.h"
 #include "chrome/browser/sync_file_system/sync_file_system_service_factory.h"
+#include "chrome/browser/ui/webui/sync_file_system_internals/extension_statuses_handler.h"
+#include "chrome/common/extensions/extension.h"
 #include "content/public/browser/web_ui.h"
 #include "content/public/browser/web_ui_data_source.h"
 #include "grit/sync_file_system_internals_resources.h"
@@ -49,6 +51,10 @@
 
 void FileMetadataHandler::RegisterMessages() {
   web_ui()->RegisterMessageCallback(
+      "getExtensions",
+      base::Bind(&FileMetadataHandler::GetExtensions,
+                 base::Unretained(this)));
+  web_ui()->RegisterMessageCallback(
       "getFileMetadata",
       base::Bind(&FileMetadataHandler::GetFileMetadata,
                  base::Unretained(this)));
@@ -56,9 +62,22 @@
 
 void FileMetadataHandler::GetFileMetadata(
     const base::ListValue* args) {
-  OriginFileMetadataMap* metadata_map = new OriginFileMetadataMap;
+  std::string extension_id;
+  if (!args->GetString(0, &extension_id) || extension_id.empty()) {
+    LOG(WARNING) << "GetFileMetadata() Extension ID wasn't given";
+    return;
+  }
+
+  // Extension ID from JS is just the host. Need to reformat it to chrome
+  // extension type GURL.
+  const GURL origin = extensions::Extension::GetBaseURLFromExtensionId(
+      extension_id);
+
+  // Get all metadata for the one specific origin.
+  FileMetadataMap* metadata_map = new FileMetadataMap;
   size_t* num_results = new size_t(0);
   SyncFileSystemServiceFactory::GetForProfile(profile_)->GetFileMetadataMap(
+      origin,
       metadata_map,
       num_results,
       base::Bind(&FileMetadataHandler::DidGetFileMetadata,
@@ -67,11 +86,18 @@
                  base::Owned(num_results)));
 }
 
+void FileMetadataHandler::GetExtensions(const base::ListValue* args) {
+  DCHECK(args);
+  base::ListValue list;
+  ExtensionStatusesHandler::GetExtensionStatusesAsDictionary(profile_, &list);
+  web_ui()->CallJavascriptFunction("FileMetadata.onGetExtensions", list);
+}
+
 // TODO(calvinlo): This would probably be better if there was a drop down UI
 // box to pick one origin at a time. Then this function would only print
 // files for one origin.
 void FileMetadataHandler::DidGetFileMetadata(
-    OriginFileMetadataMap* metadata_map,
+    FileMetadataMap* metadata_map,
     size_t* num_results,
     sync_file_system::SyncStatusCode status) {
   DCHECK(metadata_map);
@@ -79,30 +105,24 @@
 
   // Flatten map hierarchy in initial version.
   base::ListValue list;
-  RemoteFileSyncService::OriginFileMetadataMap::const_iterator origin_itr;
-  for (origin_itr = metadata_map->begin();
-       origin_itr != metadata_map->end();
-       ++origin_itr) {
-    RemoteFileSyncService::FileMetadataMap::const_iterator file_path_itr;
-    for (file_path_itr = origin_itr->second.begin();
-         file_path_itr != origin_itr->second.end();
-         ++file_path_itr) {
-      const GURL& origin = origin_itr->first;
-      const FileMetadata& metadata_object = file_path_itr->second;
-      std::string status_string = extensions::api::sync_file_system::ToString(
-            extensions::SyncFileStatusToExtensionEnum(
-                metadata_object.sync_status));
+  RemoteFileSyncService::FileMetadataMap::const_iterator file_path_itr;
+  for (file_path_itr = metadata_map->begin();
+       file_path_itr != metadata_map->end();
+       ++file_path_itr) {
+    const FileMetadata& metadata_object = file_path_itr->second;
+    std::string status_string = extensions::api::sync_file_system::ToString(
+          extensions::SyncFileStatusToExtensionEnum(
+              metadata_object.sync_status));
 
-      // Convert each file metadata object into primitives for rendering.
-      base::DictionaryValue* dict = new DictionaryValue;
-      dict->SetString("origin", origin.spec());
-      dict->SetString("status", status_string);
-      dict->SetString("type", FileTypeToString(metadata_object.type));
-      dict->SetString("title", metadata_object.title);
-      dict->SetString("details", metadata_object.service_specific_metadata);
-      list.Append(dict);
-    }
+    // Convert each file metadata object into primitives for rendering.
+    base::DictionaryValue* dict = new DictionaryValue;
+    dict->SetString("status", status_string);
+    dict->SetString("type", FileTypeToString(metadata_object.type));
+    dict->SetString("title", metadata_object.title);
+    dict->SetString("details", metadata_object.service_specific_metadata);
+    list.Append(dict);
   }
+
   web_ui()->CallJavascriptFunction("FileMetadata.onGetFileMetadata", list);
 }
 
diff --git a/chrome/browser/ui/webui/sync_file_system_internals/file_metadata_handler.h b/chrome/browser/ui/webui/sync_file_system_internals/file_metadata_handler.h
index b7e2e22..64a8152 100644
--- a/chrome/browser/ui/webui/sync_file_system_internals/file_metadata_handler.h
+++ b/chrome/browser/ui/webui/sync_file_system_internals/file_metadata_handler.h
@@ -29,11 +29,13 @@
   virtual void RegisterMessages() OVERRIDE;
 
  private:
-  typedef sync_file_system::RemoteFileSyncService::OriginFileMetadataMap
-      OriginFileMetadataMap;
+  void GetExtensions(const base::ListValue* args);
+
+  typedef sync_file_system::RemoteFileSyncService::FileMetadataMap
+      FileMetadataMap;
   void GetFileMetadata(const base::ListValue* args);
   void DidGetFileMetadata(
-      OriginFileMetadataMap* metadata_map,
+      FileMetadataMap* metadata_map,
       size_t* num_results,
       sync_file_system::SyncStatusCode status);
 
diff --git a/chrome/browser/ui/webui/sync_file_system_internals/sync_file_system_internals_handler.cc b/chrome/browser/ui/webui/sync_file_system_internals/sync_file_system_internals_handler.cc
index 200d88c..1890731 100644
--- a/chrome/browser/ui/webui/sync_file_system_internals/sync_file_system_internals_handler.cc
+++ b/chrome/browser/ui/webui/sync_file_system_internals/sync_file_system_internals_handler.cc
@@ -20,7 +20,7 @@
 #include "content/public/browser/storage_partition.h"
 #include "content/public/browser/web_ui.h"
 
-using google_apis::EventLogger;
+using drive::EventLogger;
 using sync_file_system::SyncFileSystemServiceFactory;
 using sync_file_system::SyncServiceState;
 
@@ -90,8 +90,8 @@
 
 void SyncFileSystemInternalsHandler::GetNotificationSource(
     const base::ListValue* args) {
-  google_apis::DriveNotificationManager* drive_notification_manager =
-      google_apis::DriveNotificationManagerFactory::GetForProfile(profile_);
+  drive::DriveNotificationManager* drive_notification_manager =
+      drive::DriveNotificationManagerFactory::GetForProfile(profile_);
   bool xmpp_enabled = drive_notification_manager->push_notification_enabled();
   std::string notification_source = xmpp_enabled ? "XMPP" : "Polling";
   web_ui()->CallJavascriptFunction("SyncService.onGetNotificationSource",
diff --git a/chrome/browser/ui/webui/sync_promo/sync_promo_trial.cc b/chrome/browser/ui/webui/sync_promo/sync_promo_trial.cc
index 14517a7..a410d2b 100644
--- a/chrome/browser/ui/webui/sync_promo/sync_promo_trial.cc
+++ b/chrome/browser/ui/webui/sync_promo/sync_promo_trial.cc
@@ -6,7 +6,7 @@
 
 #include "base/logging.h"
 #include "chrome/browser/metrics/metrics_service.h"
-#include "chrome/browser/ui/webui/sync_promo/sync_promo_ui.h"
+#include "chrome/browser/ui/sync/sync_promo_ui.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_ui.h"
 
diff --git a/chrome/browser/ui/webui/sync_promo/sync_promo_trial.h b/chrome/browser/ui/webui/sync_promo/sync_promo_trial.h
index c4510ea..f522ba9 100644
--- a/chrome/browser/ui/webui/sync_promo/sync_promo_trial.h
+++ b/chrome/browser/ui/webui/sync_promo/sync_promo_trial.h
@@ -6,7 +6,7 @@
 #define CHROME_BROWSER_UI_WEBUI_SYNC_PROMO_SYNC_PROMO_TRIAL_H_
 
 #include "base/basictypes.h"
-#include "chrome/browser/ui/webui/sync_promo/sync_promo_ui.h"
+#include "chrome/browser/ui/sync/sync_promo_ui.h"
 
 class Profile;
 namespace content {
diff --git a/chrome/browser/ui/webui/sync_promo/sync_promo_ui.cc b/chrome/browser/ui/webui/sync_promo/sync_promo_ui.cc
deleted file mode 100644
index b63325d..0000000
--- a/chrome/browser/ui/webui/sync_promo/sync_promo_ui.cc
+++ /dev/null
@@ -1,275 +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_ui.h"
-
-#include "base/command_line.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/strings/utf_string_conversions.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/first_run/first_run.h"
-#include "chrome/browser/google/google_util.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/profiles/profile_info_cache.h"
-#include "chrome/browser/profiles/profile_manager.h"
-#include "chrome/browser/signin/signin_manager.h"
-#include "chrome/browser/signin/signin_manager_factory.h"
-#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"
-#include "chrome/common/pref_names.h"
-#include "chrome/common/url_constants.h"
-#include "components/user_prefs/pref_registry_syncable.h"
-#include "content/public/browser/url_data_source.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/browser/web_ui.h"
-#include "content/public/browser/web_ui_data_source.h"
-#include "google_apis/gaia/gaia_urls.h"
-#include "grit/browser_resources.h"
-#include "grit/generated_resources.h"
-#include "grit/theme_resources.h"
-#include "net/base/escape.h"
-#include "net/base/network_change_notifier.h"
-#include "net/base/url_util.h"
-#include "ui/base/l10n/l10n_util.h"
-
-using content::WebContents;
-
-namespace {
-
-const char kStringsJsFile[] = "strings.js";
-const char kSyncPromoJsFile[] = "sync_promo.js";
-
-const char kSyncPromoQueryKeyAutoClose[] = "auto_close";
-const char kSyncPromoQueryKeyContinue[] = "continue";
-const char kSyncPromoQueryKeySource[] = "source";
-
-// Gaia cannot support about:blank as a continue URL, so using a hosted blank
-// page instead.
-const char kSyncLandingUrlPrefix[] =
-    "https://www.google.com/intl/%s/chrome/blank.html";
-
-// The maximum number of times we want to show the sync promo at startup.
-const int kSyncPromoShowAtStartupMaximum = 10;
-
-// Forces the web based signin flow when set.
-bool g_force_web_based_signin_flow = false;
-
-// Checks we want to show the sync promo for the given brand.
-bool AllowPromoAtStartupForCurrentBrand() {
-  std::string brand;
-  google_util::GetBrand(&brand);
-
-  if (brand.empty())
-    return true;
-
-  if (google_util::IsInternetCafeBrandCode(brand))
-    return false;
-
-  // Enable for both organic and distribution.
-  return true;
-}
-
-}  // namespace
-
-// static
-bool SyncPromoUI::HasShownPromoAtStartup(Profile* profile) {
-  return profile->GetPrefs()->HasPrefPath(prefs::kSyncPromoStartupCount);
-}
-
-// static
-bool SyncPromoUI::ShouldShowSyncPromo(Profile* profile) {
-#if defined(OS_CHROMEOS)
-  // There's no need to show the sync promo on cros since cros users are logged
-  // into sync already.
-  return false;
-#else
-
-  // Don't bother if we don't have any kind of network connection.
-  if (net::NetworkChangeNotifier::IsOffline())
-    return false;
-
-  // Don't show if the profile is an incognito.
-  if (profile->IsOffTheRecord())
-    return false;
-
-  // Don't show for managed profiles.
-  if (profile->GetPrefs()->GetBoolean(prefs::kProfileIsManaged))
-    return false;
-
-  // Display the signin promo if the user is not signed in.
-  SigninManager* signin = SigninManagerFactory::GetForProfile(
-      profile->GetOriginalProfile());
-  return !signin->AuthInProgress() && signin->IsSigninAllowed() &&
-      signin->GetAuthenticatedUsername().empty();
-#endif
-}
-
-// static
-void SyncPromoUI::RegisterUserPrefs(
-    user_prefs::PrefRegistrySyncable* registry) {
-  registry->RegisterIntegerPref(
-      prefs::kSyncPromoStartupCount,
-      0,
-      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
-  registry->RegisterBooleanPref(
-      prefs::kSyncPromoUserSkipped,
-      false,
-      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
-  registry->RegisterBooleanPref(
-      prefs::kSyncPromoShowOnFirstRunAllowed,
-      true,
-      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
-  registry->RegisterBooleanPref(
-      prefs::kSyncPromoShowNTPBubble,
-      false,
-      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
-  registry->RegisterStringPref(
-      prefs::kSyncPromoErrorMessage,
-      std::string(),
-      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
-}
-
-// static
-bool SyncPromoUI::ShouldShowSyncPromoAtStartup(Profile* profile,
-                                               bool is_new_profile) {
-  DCHECK(profile);
-
-  if (!ShouldShowSyncPromo(profile))
-    return false;
-
-  const CommandLine& command_line = *CommandLine::ForCurrentProcess();
-  if (command_line.HasSwitch(switches::kNoFirstRun))
-    is_new_profile = false;
-
-  if (!is_new_profile) {
-    if (!HasShownPromoAtStartup(profile))
-      return false;
-  }
-
-  if (HasUserSkippedSyncPromo(profile))
-    return false;
-
-  // For Chinese users skip the sync promo.
-  if (g_browser_process->GetApplicationLocale() == "zh-CN")
-    return false;
-
-  PrefService* prefs = profile->GetPrefs();
-  int show_count = prefs->GetInteger(prefs::kSyncPromoStartupCount);
-  if (show_count >= kSyncPromoShowAtStartupMaximum)
-    return false;
-
-  // This pref can be set in the master preferences file to allow or disallow
-  // showing the sync promo at startup.
-  if (prefs->HasPrefPath(prefs::kSyncPromoShowOnFirstRunAllowed))
-    return prefs->GetBoolean(prefs::kSyncPromoShowOnFirstRunAllowed);
-
-  // For now don't show the promo for some brands.
-  if (!AllowPromoAtStartupForCurrentBrand())
-    return false;
-
-  // Default to show the promo for Google Chrome builds.
-#if defined(GOOGLE_CHROME_BUILD)
-  return true;
-#else
-  return false;
-#endif
-}
-
-void SyncPromoUI::DidShowSyncPromoAtStartup(Profile* profile) {
-  int show_count = profile->GetPrefs()->GetInteger(
-      prefs::kSyncPromoStartupCount);
-  show_count++;
-  profile->GetPrefs()->SetInteger(prefs::kSyncPromoStartupCount, show_count);
-}
-
-bool SyncPromoUI::HasUserSkippedSyncPromo(Profile* profile) {
-  return profile->GetPrefs()->GetBoolean(prefs::kSyncPromoUserSkipped);
-}
-
-void SyncPromoUI::SetUserSkippedSyncPromo(Profile* profile) {
-  profile->GetPrefs()->SetBoolean(prefs::kSyncPromoUserSkipped, true);
-}
-
-// static
-std::string SyncPromoUI::GetSyncLandingURL(const char* option, int value) {
-  const std::string& locale = g_browser_process->GetApplicationLocale();
-  std::string url = base::StringPrintf(kSyncLandingUrlPrefix, locale.c_str());
-  base::StringAppendF(&url, "?%s=%d", option, value);
-  return url;
-}
-
-// static
-GURL SyncPromoUI::GetSyncPromoURL(Source source, bool auto_close) {
-  DCHECK_NE(SOURCE_UNKNOWN, source);
-
-  std::string url_string;
-
-  // Build a Gaia-based URL that can be used to sign the user into chrome.
-  // There are required request parameters:
-  //
-  //  - tell Gaia which service the user is signing into.  In this case,
-  //    a chrome sign in uses the service "chromiumsync"
-  //  - provide a continue URL.  This is the URL that Gaia will redirect to
-  //    once the sign is complete.
-  //
-  // The continue URL includes a source parameter that can be extracted using
-  // the function GetSourceForSyncPromoURL() below.  This is used to know
-  // which of the chrome sign in access points was used to sign the user in.
-  // See OneClickSigninHelper for details.
-  url_string = GaiaUrls::GetInstance()->service_login_url();
-  url_string.append("?service=chromiumsync&sarp=1");
-
-  std::string continue_url = GetSyncLandingURL(
-      kSyncPromoQueryKeySource, static_cast<int>(source));
-
-  base::StringAppendF(&url_string, "&%s=%s", kSyncPromoQueryKeyContinue,
-                      net::EscapeQueryParamValue(
-                          continue_url, false).c_str());
-
-  return GURL(url_string);
-}
-
-// static
-GURL SyncPromoUI::GetNextPageURLForSyncPromoURL(const GURL& url) {
-  std::string value;
-  if (net::GetValueForKeyInQuery(url, kSyncPromoQueryKeyContinue, &value))
-    return GURL(value);
-
-  return GURL();
-}
-
-// static
-SyncPromoUI::Source SyncPromoUI::GetSourceForSyncPromoURL(const GURL& url) {
-  std::string value;
-  if (net::GetValueForKeyInQuery(url, kSyncPromoQueryKeySource, &value)) {
-    int source = 0;
-    if (base::StringToInt(value, &source) && source >= SOURCE_START_PAGE &&
-        source < SOURCE_UNKNOWN) {
-      return static_cast<Source>(source);
-    }
-  }
-  return SOURCE_UNKNOWN;
-}
-
-// static
-bool SyncPromoUI::IsContinueUrlForWebBasedSigninFlow(const GURL& url) {
-  GURL::Replacements replacements;
-  replacements.ClearQuery();
-  const std::string& locale = g_browser_process->GetApplicationLocale();
-  return url.ReplaceComponents(replacements) ==
-      GURL(base::StringPrintf(kSyncLandingUrlPrefix, locale.c_str()));
-}
-
-// static
-void SyncPromoUI::ForceWebBasedSigninFlowForTesting(bool force) {
-  g_force_web_based_signin_flow = force;
-}
diff --git a/chrome/browser/ui/webui/sync_promo/sync_promo_ui.h b/chrome/browser/ui/webui/sync_promo/sync_promo_ui.h
deleted file mode 100644
index ae67031..0000000
--- a/chrome/browser/ui/webui/sync_promo/sync_promo_ui.h
+++ /dev/null
@@ -1,87 +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_UI_H_
-#define CHROME_BROWSER_UI_WEBUI_SYNC_PROMO_SYNC_PROMO_UI_H_
-
-#include <string>
-
-#include "base/basictypes.h"
-
-class GURL;
-class Profile;
-
-namespace user_prefs {
-class PrefRegistrySyncable;
-}
-
-// Static helper functions useful for chrome sign in.
-class SyncPromoUI {
- public:
-  // 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,
-    SOURCE_MENU,
-    SOURCE_SETTINGS,
-    SOURCE_EXTENSION_INSTALL_BUBBLE,
-    SOURCE_WEBSTORE_INSTALL,
-    SOURCE_APP_LAUNCHER,
-    SOURCE_APPS_PAGE_LINK,
-    SOURCE_UNKNOWN, // This must be last.
-  };
-
-  // Returns true if the sync promo should be visible.
-  // |profile| is the profile of the tab the promo would be shown on.
-  static bool ShouldShowSyncPromo(Profile* profile);
-
-  // Returns true if we should show the sync promo at startup.
-  static bool ShouldShowSyncPromoAtStartup(Profile* profile,
-                                           bool is_new_profile);
-
-  // Called when the sync promo has been shown so that we can keep track
-  // of the number of times we've displayed it.
-  static void DidShowSyncPromoAtStartup(Profile* profile);
-
-  // Returns true if a user has seen the sync promo at startup previously.
-  static bool HasShownPromoAtStartup(Profile* profile);
-
-  // Returns true if the user has previously skipped the sync promo.
-  static bool HasUserSkippedSyncPromo(Profile* profile);
-
-  // Registers the fact that the user has skipped the sync promo.
-  static void SetUserSkippedSyncPromo(Profile* profile);
-
-  // Registers the preferences the Sync Promo UI needs.
-  static void RegisterUserPrefs(user_prefs::PrefRegistrySyncable* registry);
-
-  // Gets the sync landing page URL.
-  static std::string GetSyncLandingURL(const char* option, int value);
-
-  // Returns the sync promo URL wth the given arguments in the query.
-  // |source| identifies from where the sync promo is being called, and is used
-  // to record sync promo UMA stats in the context of the source.
-  // |auto_close| whether to close the sync promo automatically when done.
-  static GURL GetSyncPromoURL(Source source, bool auto_close);
-
-  // Gets the next page URL from the query portion of the sync promo URL.
-  static GURL GetNextPageURLForSyncPromoURL(const GURL& url);
-
-  // Gets the source from the query portion of the sync promo URL.
-  // The source identifies from where the sync promo was opened.
-  static Source GetSourceForSyncPromoURL(const GURL& url);
-
-  // Returns true if the given URL is the standard continue URL used with the
-  // sync promo when the web-based flow is enabled.  The query parameters
-  // of the URL are ignored for this comparison.
-  static bool IsContinueUrlForWebBasedSigninFlow(const GURL& url);
-
-  // Forces UseWebBasedSigninFlow() to return true when set; used in tests only.
-  static void ForceWebBasedSigninFlowForTesting(bool force);
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(SyncPromoUI);
-};
-
-#endif  // CHROME_BROWSER_UI_WEBUI_SYNC_PROMO_SYNC_PROMO_UI_H_
diff --git a/chrome/browser/ui/webui/sync_setup_handler.cc b/chrome/browser/ui/webui/sync_setup_handler.cc
index 03a82fe..11085ea 100644
--- a/chrome/browser/ui/webui/sync_setup_handler.cc
+++ b/chrome/browser/ui/webui/sync_setup_handler.cc
@@ -29,10 +29,10 @@
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/browser_navigator.h"
 #include "chrome/browser/ui/sync/signin_histogram.h"
+#include "chrome/browser/ui/sync/sync_promo_ui.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/webui/signin/login_ui_service.h"
 #include "chrome/browser/ui/webui/signin/login_ui_service_factory.h"
-#include "chrome/browser/ui/webui/sync_promo/sync_promo_ui.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/url_constants.h"
@@ -652,7 +652,7 @@
 }
 
 void SyncSetupHandler::OnDidClosePage(const ListValue* args) {
-  CloseSyncSetup();
+  CloseOverlay();
 }
 
 void SyncSetupHandler::SyncStartupFailed() {
@@ -932,6 +932,13 @@
       if (sync_service) {
         DVLOG(1) << "Sync setup aborted by user action";
         sync_service->OnStopSyncingPermanently();
+#if !defined(OS_CHROMEOS)
+        // Sign out the user on desktop Chrome if they click cancel during
+        // initial setup.
+        // TODO(rsimha): Revisit this for M30. See http://crbug.com/252049.
+        if (sync_service->FirstSetupInProgress())
+          SigninManagerFactory::GetForProfile(GetProfile())->SignOut();
+#endif
       }
     }
 
@@ -1094,9 +1101,6 @@
 }
 
 void SyncSetupHandler::CloseOverlay() {
-  // Stop a timer to handle timeout in waiting for sync setup.
-  backend_start_timer_.reset();
-
   CloseSyncSetup();
   web_ui()->CallJavascriptFunction("OptionsPage.closeOverlay");
 }
diff --git a/chrome/browser/ui/webui/sync_setup_handler.h b/chrome/browser/ui/webui/sync_setup_handler.h
index 9dedce6..4285beb 100644
--- a/chrome/browser/ui/webui/sync_setup_handler.h
+++ b/chrome/browser/ui/webui/sync_setup_handler.h
@@ -7,7 +7,7 @@
 
 #include "base/gtest_prod_util.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/timer.h"
+#include "base/timer/timer.h"
 #include "chrome/browser/signin/signin_tracker.h"
 #include "chrome/browser/sync/sync_startup_tracker.h"
 #include "chrome/browser/ui/webui/options/options_ui.h"
diff --git a/chrome/browser/ui/webui/task_manager/task_manager_handler.cc b/chrome/browser/ui/webui/task_manager/task_manager_handler.cc
index afb3960..42a74a4 100644
--- a/chrome/browser/ui/webui/task_manager/task_manager_handler.cc
+++ b/chrome/browser/ui/webui/task_manager/task_manager_handler.cc
@@ -264,10 +264,8 @@
   int index = model_->GetResourceIndexForGroup(group_index, 0);
   int length = model_->GetGroupRangeForResource(index).second;
 
-  // Forces to set following 3 columns regardless of |enable_columns|.
+  // Forces to set following column regardless of |enable_columns|.
   val->SetInteger("index", index);
-  val->SetBoolean("isBackgroundResource",
-                  model_->IsBackgroundResource(index));
   CreateGroupColumnList("processId", index, 1, val);
   CreateGroupColumnList("type", index, length, val);
   CreateGroupColumnList("uniqueId", index, length, val);
diff --git a/chrome/browser/ui/webui/translate_internals/translate_internals_handler.cc b/chrome/browser/ui/webui/translate_internals/translate_internals_handler.cc
index 09d7ede..9b44249 100644
--- a/chrome/browser/ui/webui/translate_internals/translate_internals_handler.cc
+++ b/chrome/browser/ui/webui/translate_internals/translate_internals_handler.cc
@@ -9,12 +9,14 @@
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
+#include "base/command_line.h"
 #include "base/prefs/pref_service.h"
 #include "base/values.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/translate/translate_error_details.h"
 #include "chrome/browser/translate/translate_event_details.h"
 #include "chrome/browser/translate/translate_prefs.h"
+#include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/translate/language_detection_details.h"
 #include "content/public/browser/web_contents.h"
@@ -89,11 +91,16 @@
   if (!args->GetString(0, &pref_name))
     return;
 
-  if (pref_name == "language_blacklist") {
+  if (pref_name == "blocked_languages") {
     std::string language;
     if (!args->GetString(1, &language))
       return;
-    translate_prefs.RemoveLanguageFromBlacklist(language);
+    translate_prefs.UnblockLanguage(language);
+  } else if (pref_name == "language_blacklist") {
+    std::string language;
+    if (!args->GetString(1, &language))
+      return;
+    translate_prefs.RemoveLanguageFromLegacyBlacklist(language);
   } else if (pref_name == "site_blacklist") {
     std::string site;
     if (!args->GetString(1, &site))
@@ -133,18 +140,25 @@
 
   base::DictionaryValue dict;
 
-  static const char* keys[] = {
-    prefs::kEnableTranslate,
-    TranslatePrefs::kPrefTranslateLanguageBlacklist,
-    TranslatePrefs::kPrefTranslateSiteBlacklist,
-    TranslatePrefs::kPrefTranslateWhitelists,
-    TranslatePrefs::kPrefTranslateDeniedCount,
-    TranslatePrefs::kPrefTranslateAcceptedCount,
-  };
+  std::vector<std::string> keys;
+  keys.push_back(prefs::kEnableTranslate);
 
-  for (size_t i = 0; i < arraysize(keys); ++i) {
-    const char* key = keys[i];
-    const PrefService::Preference* pref = prefs->FindPreference(key);
+  const CommandLine& command_line = *CommandLine::ForCurrentProcess();
+  bool enable_translate_settings =
+      command_line.HasSwitch(switches::kEnableTranslateSettings);
+  if (enable_translate_settings)
+    keys.push_back(TranslatePrefs::kPrefTranslateBlockedLanguages);
+
+  keys.push_back(TranslatePrefs::kPrefTranslateLanguageBlacklist);
+  keys.push_back(TranslatePrefs::kPrefTranslateSiteBlacklist);
+  keys.push_back(TranslatePrefs::kPrefTranslateWhitelists);
+  keys.push_back(TranslatePrefs::kPrefTranslateDeniedCount);
+  keys.push_back(TranslatePrefs::kPrefTranslateAcceptedCount);
+
+  for (std::vector<std::string>::const_iterator it = keys.begin();
+       it != keys.end(); ++it) {
+    const std::string& key = *it;
+    const PrefService::Preference* pref = prefs->FindPreference(key.c_str());
     if (pref)
       dict.Set(key, pref->GetValue()->DeepCopy());
   }
diff --git a/chrome/browser/ui/webui/translate_internals/translate_internals_ui.cc b/chrome/browser/ui/webui/translate_internals/translate_internals_ui.cc
index 0c7570c..6f5b606 100644
--- a/chrome/browser/ui/webui/translate_internals/translate_internals_ui.cc
+++ b/chrome/browser/ui/webui/translate_internals/translate_internals_ui.cc
@@ -7,11 +7,13 @@
 #include <string>
 #include <vector>
 
+#include "base/command_line.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/webui/translate_internals/translate_internals_handler.h"
+#include "chrome/common/chrome_switches.h"
 #include "chrome/common/url_constants.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_ui.h"
@@ -58,6 +60,11 @@
     source->AddString(key, value);
   }
 
+  const CommandLine& command_line = *CommandLine::ForCurrentProcess();
+  bool enable_translate_settings =
+      command_line.HasSwitch(switches::kEnableTranslateSettings);
+  source->AddBoolean("enable-translate-settings", enable_translate_settings);
+
   return source;
 }
 
diff --git a/chrome/browser/unload_browsertest.cc b/chrome/browser/unload_browsertest.cc
index 331b23c..b39cb8e 100644
--- a/chrome/browser/unload_browsertest.cc
+++ b/chrome/browser/unload_browsertest.cc
@@ -411,9 +411,13 @@
   CheckTitle("only_one_unload");
 }
 
-
 class FastUnloadTest : public UnloadTest {
  public:
+  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
+    UnloadTest::SetUpCommandLine(command_line);
+    command_line->AppendSwitch(switches::kEnableFastUnload);
+  }
+
   virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
     ASSERT_TRUE(test_server()->Start());
   }
diff --git a/chrome/browser/upgrade_detector.h b/chrome/browser/upgrade_detector.h
index 86f2c44..9c1826e 100644
--- a/chrome/browser/upgrade_detector.h
+++ b/chrome/browser/upgrade_detector.h
@@ -5,7 +5,7 @@
 #ifndef CHROME_BROWSER_UPGRADE_DETECTOR_H_
 #define CHROME_BROWSER_UPGRADE_DETECTOR_H_
 
-#include "base/timer.h"
+#include "base/timer/timer.h"
 #include "chrome/browser/idle.h"
 #include "ui/gfx/image/image.h"
 
diff --git a/chrome/browser/upgrade_detector_impl.cc b/chrome/browser/upgrade_detector_impl.cc
index d56f33f..436d05e 100644
--- a/chrome/browser/upgrade_detector_impl.cc
+++ b/chrome/browser/upgrade_detector_impl.cc
@@ -17,7 +17,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "base/version.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/google/google_util.h"
diff --git a/chrome/browser/upgrade_detector_impl.h b/chrome/browser/upgrade_detector_impl.h
index 95597cd..e8a1d82 100644
--- a/chrome/browser/upgrade_detector_impl.h
+++ b/chrome/browser/upgrade_detector_impl.h
@@ -6,7 +6,7 @@
 #define CHROME_BROWSER_UPGRADE_DETECTOR_IMPL_H_
 
 #include "base/memory/weak_ptr.h"
-#include "base/timer.h"
+#include "base/timer/timer.h"
 #include "chrome/browser/net/network_time_tracker.h"
 #include "chrome/browser/upgrade_detector.h"
 
diff --git a/chrome/browser/upload_list.cc b/chrome/browser/upload_list.cc
new file mode 100644
index 0000000..52c42a7
--- /dev/null
+++ b/chrome/browser/upload_list.cc
@@ -0,0 +1,95 @@
+// 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/upload_list.h"
+
+#include <algorithm>
+#include <iterator>
+
+#include "base/bind.h"
+#include "base/file_util.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
+#include "content/public/browser/browser_thread.h"
+
+using content::BrowserThread;
+
+UploadList::UploadInfo::UploadInfo(const std::string& c, const base::Time& t)
+    : id(c), time(t) {}
+
+UploadList::UploadInfo::~UploadInfo() {}
+
+UploadList::UploadList(Delegate* delegate,
+                       const base::FilePath& upload_log_path)
+    : delegate_(delegate),
+      upload_log_path_(upload_log_path) {}
+
+UploadList::~UploadList() {}
+
+void UploadList::LoadUploadListAsynchronously() {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  BrowserThread::PostBlockingPoolTask(
+      FROM_HERE,
+      base::Bind(&UploadList::LoadUploadListAndInformDelegateOfCompletion,
+                 this));
+}
+
+void UploadList::ClearDelegate() {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  delegate_ = NULL;
+}
+
+void UploadList::LoadUploadListAndInformDelegateOfCompletion() {
+  LoadUploadList();
+  BrowserThread::PostTask(
+      BrowserThread::UI,
+      FROM_HERE,
+      base::Bind(&UploadList::InformDelegateOfCompletion, this));
+}
+
+void UploadList::LoadUploadList() {
+  if (file_util::PathExists(upload_log_path_)) {
+    std::string contents;
+    file_util::ReadFileToString(upload_log_path_, &contents);
+    std::vector<std::string> log_entries;
+    base::SplitStringAlongWhitespace(contents, &log_entries);
+    ParseLogEntries(log_entries);
+  }
+}
+
+void UploadList::AppendUploadInfo(const UploadInfo& info) {
+  uploads_.push_back(info);
+}
+
+void UploadList::ParseLogEntries(
+    const std::vector<std::string>& log_entries) {
+  std::vector<std::string>::const_reverse_iterator i;
+  for (i = log_entries.rbegin(); i != log_entries.rend(); ++i) {
+    std::vector<std::string> components;
+    base::SplitString(*i, ',', &components);
+    // Skip any blank (or corrupted) lines.
+    if (components.size() != 2)
+      continue;
+    double seconds_since_epoch;
+    if (!base::StringToDouble(components[0], &seconds_since_epoch))
+      continue;
+    UploadInfo info(components[1],
+                    base::Time::FromDoubleT(seconds_since_epoch));
+    uploads_.push_back(info);
+  }
+}
+
+void UploadList::InformDelegateOfCompletion() {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  if (delegate_)
+    delegate_->OnUploadListAvailable();
+}
+
+void UploadList::GetUploads(unsigned int max_count,
+                            std::vector<UploadInfo>* uploads) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  std::copy(uploads_.begin(),
+            uploads_.begin() + std::min<size_t>(uploads_.size(), max_count),
+            std::back_inserter(*uploads));
+}
diff --git a/chrome/browser/upload_list.h b/chrome/browser/upload_list.h
new file mode 100644
index 0000000..23c4ff5
--- /dev/null
+++ b/chrome/browser/upload_list.h
@@ -0,0 +1,88 @@
+// 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_UPLOAD_LIST_H_
+#define CHROME_BROWSER_UPLOAD_LIST_H_
+
+#include <string>
+#include <vector>
+
+#include "base/files/file_path.h"
+#include "base/gtest_prod_util.h"
+#include "base/memory/ref_counted.h"
+#include "base/time/time.h"
+
+// Loads and parses an upload list text file of the format
+// time,id
+// time,id
+// etc.
+// where each line represents an upload and "time" is Unix time. Must be used
+// from the UI thread. The loading and parsing is done on a blocking pool task
+// runner.
+class UploadList : public base::RefCountedThreadSafe<UploadList> {
+ public:
+  struct UploadInfo {
+    UploadInfo(const std::string& c, const base::Time& t);
+    ~UploadInfo();
+
+    std::string id;
+    base::Time time;
+  };
+
+  class Delegate {
+   public:
+    // Invoked when the upload list has been loaded. Will be called on the
+    // UI thread.
+    virtual void OnUploadListAvailable() = 0;
+
+   protected:
+    virtual ~Delegate() {}
+  };
+
+  // Creates a new upload list with the given callback delegate.
+  UploadList(Delegate* delegate, const base::FilePath& upload_log_path);
+
+  // Starts loading the upload list. OnUploadListAvailable will be called when
+  // loading is complete.
+  void LoadUploadListAsynchronously();
+
+  // Clears the delegate, so that any outstanding asynchronous load will not
+  // call the delegate on completion.
+  void ClearDelegate();
+
+  // Populates |uploads| with the |max_count| most recent uploads,
+  // in reverse chronological order.
+  // Must be called only after OnUploadListAvailable has been called.
+  void GetUploads(unsigned int max_count, std::vector<UploadInfo>* uploads);
+
+ protected:
+  virtual ~UploadList();
+
+  // Reads the upload log and stores the entries in |uploads_|.
+  virtual void LoadUploadList();
+
+  // Adds |info| to |uploads_|.
+  void AppendUploadInfo(const UploadInfo& info);
+
+ private:
+  friend class base::RefCountedThreadSafe<UploadList>;
+  FRIEND_TEST_ALL_PREFIXES(UploadListTest, ParseLogEntries);
+
+  // Manages the background thread work for LoadUploadListAsynchronously().
+  void LoadUploadListAndInformDelegateOfCompletion();
+
+  // Calls the delegate's callback method, if there is a delegate.
+  void InformDelegateOfCompletion();
+
+  // Parses upload log lines, converting them to UploadInfo entries.
+  void ParseLogEntries(const std::vector<std::string>& log_entries);
+
+  std::vector<UploadInfo> uploads_;
+  Delegate* delegate_;
+  const base::FilePath upload_log_path_;
+
+  DISALLOW_COPY_AND_ASSIGN(UploadList);
+};
+
+#endif  // CHROME_BROWSER_UPLOAD_LIST_H_
diff --git a/chrome/browser/upload_list_unittest.cc b/chrome/browser/upload_list_unittest.cc
new file mode 100644
index 0000000..153f9db
--- /dev/null
+++ b/chrome/browser/upload_list_unittest.cc
@@ -0,0 +1,44 @@
+// 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/files/file_path.h"
+#include "base/memory/ref_counted.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/time/time.h"
+#include "chrome/browser/upload_list.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+// Test that UploadList can parse a vector of log entry strings to a vector of
+// UploadInfo objects. See the UploadList declaration for a description of the
+// log entry string format.
+TEST(UploadListTest, ParseLogEntries) {
+  const char kTestTime[] = "1234567890";
+  const char kTestID[] = "0123456789abcdef";
+  std::string test_entry = kTestTime;
+  test_entry += ",";
+  test_entry.append(kTestID, sizeof(kTestID));
+
+  scoped_refptr<UploadList> upload_list =
+      new UploadList(NULL, base::FilePath());
+
+  // 1 entry.
+  std::vector<std::string> log_entries;
+  log_entries.push_back(test_entry);
+  upload_list->ParseLogEntries(log_entries);
+  EXPECT_EQ(1u, upload_list->uploads_.size());
+  double time_double = upload_list->uploads_[0].time.ToDoubleT();
+  EXPECT_STREQ(kTestTime, base::DoubleToString(time_double).c_str());
+  EXPECT_STREQ(kTestID, upload_list->uploads_[0].id.c_str());
+
+  // Add 3 more entries.
+  log_entries.push_back(test_entry);
+  log_entries.push_back(test_entry);
+  upload_list->ParseLogEntries(log_entries);
+  EXPECT_EQ(4u, upload_list->uploads_.size());
+  time_double = upload_list->uploads_[3].time.ToDoubleT();
+  EXPECT_STREQ(kTestTime, base::DoubleToString(time_double).c_str());
+  EXPECT_STREQ(kTestID, upload_list->uploads_[3].id.c_str());
+}
diff --git a/chrome/browser/usb/usb_service.cc b/chrome/browser/usb/usb_service.cc
index 038786d..e44c8aa 100644
--- a/chrome/browser/usb/usb_service.cc
+++ b/chrome/browser/usb/usb_service.cc
@@ -104,6 +104,22 @@
 #endif  // defined(OS_CHROMEOS)
 }
 
+void UsbService::EnumerateDevices(
+    std::vector<scoped_refptr<UsbDevice> >* devices) {
+  devices->clear();
+
+  DeviceVector enumerated_devices;
+  EnumerateDevicesImpl(&enumerated_devices);
+
+  for (DeviceVector::iterator it = enumerated_devices.begin();
+       it != enumerated_devices.end(); ++it) {
+    PlatformUsbDevice device = it->device();
+    UsbDevice* const wrapper = LookupOrCreateDevice(device);
+    if (wrapper)
+      devices->push_back(wrapper);
+  }
+}
+
 void UsbService::FindDevicesImpl(const uint16 vendor_id,
                                  const uint16 product_id,
                                  vector<scoped_refptr<UsbDevice> >* devices,
@@ -120,12 +136,11 @@
     return;
 
   DeviceVector enumerated_devices;
-  EnumerateDevices(&enumerated_devices);
-  if (enumerated_devices.empty())
-    return;
+  EnumerateDevicesImpl(&enumerated_devices);
 
-  for (unsigned int i = 0; i < enumerated_devices.size(); ++i) {
-    PlatformUsbDevice device = enumerated_devices[i].device();
+  for (DeviceVector::iterator it = enumerated_devices.begin();
+       it != enumerated_devices.end(); ++it) {
+    PlatformUsbDevice device = it->device();
     if (DeviceMatches(device, vendor_id, product_id)) {
       UsbDevice* const wrapper = LookupOrCreateDevice(device);
       if (wrapper)
@@ -165,7 +180,7 @@
   return device_;
 }
 
-void UsbService::EnumerateDevices(DeviceVector* output) {
+void UsbService::EnumerateDevicesImpl(DeviceVector* output) {
   STLClearObject(output);
 
   libusb_device** devices = NULL;
diff --git a/chrome/browser/usb/usb_service.h b/chrome/browser/usb/usb_service.h
index 8e04ce2..f2cfd3c 100644
--- a/chrome/browser/usb/usb_service.h
+++ b/chrome/browser/usb/usb_service.h
@@ -40,6 +40,10 @@
                    std::vector<scoped_refptr<UsbDevice> >* devices,
                    const base::Callback<void()>& callback);
 
+  // Find all of the devices attached to the system, inserting them into
+  // |devices|. Clears |devices| before use.
+  void EnumerateDevices(std::vector<scoped_refptr<UsbDevice> >* devices);
+
   // This function should not be called by normal code. It is invoked by a
   // UsbDevice's Close function and disposes of the associated platform handle.
   void CloseDevice(scoped_refptr<UsbDevice> device);
@@ -79,7 +83,7 @@
                        bool success);
 
   // Populates |output| with the result of enumerating all attached USB devices.
-  void EnumerateDevices(DeviceVector* output);
+  void EnumerateDevicesImpl(DeviceVector* output);
 
   // If a UsbDevice wrapper corresponding to |device| has already been created,
   // returns it. Otherwise, opens the device, creates a wrapper, and associates
diff --git a/chrome/browser/user_style_sheet_watcher.h b/chrome/browser/user_style_sheet_watcher.h
index 72b002c..9ab8482 100644
--- a/chrome/browser/user_style_sheet_watcher.h
+++ b/chrome/browser/user_style_sheet_watcher.h
@@ -13,7 +13,7 @@
 #include "components/browser_context_keyed_service/refcounted_browser_context_keyed_service.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 class Profile;
 class UserStyleSheetLoader;
diff --git a/chrome/browser/validation_message_message_filter.cc b/chrome/browser/validation_message_message_filter.cc
index 1d48232..ef2366b 100644
--- a/chrome/browser/validation_message_message_filter.cc
+++ b/chrome/browser/validation_message_message_filter.cc
@@ -62,8 +62,8 @@
 void ValidationMessageMessageFilter::OnShowValidationMessage(
     int route_id, const gfx::Rect& anchor_in_root_view,
     const string16& main_text, const string16& sub_text) {
-  RenderProcessHost* process = RenderProcessHost::FromID(renderer_id_);
-  RenderWidgetHost* widget_host = process->GetRenderWidgetHostByID(route_id);
+  RenderWidgetHost* widget_host =
+      RenderWidgetHost::FromID(renderer_id_, route_id);
   validation_message_bubble_ = chrome::ValidationMessageBubble::CreateAndShow(
       widget_host, anchor_in_root_view, main_text, sub_text);
 }
@@ -76,8 +76,8 @@
     int route_id, const gfx::Rect& anchor_in_root_view) {
   if (!validation_message_bubble_)
       return;
-  RenderProcessHost* process = RenderProcessHost::FromID(renderer_id_);
-  RenderWidgetHost* widget_host = process->GetRenderWidgetHostByID(route_id);
+  RenderWidgetHost* widget_host =
+      RenderWidgetHost::FromID(renderer_id_, route_id);
   validation_message_bubble_->SetPositionRelativeToAnchor(
       widget_host, anchor_in_root_view);
 }
diff --git a/chrome/browser/value_store/leveldb_value_store.cc b/chrome/browser/value_store/leveldb_value_store.cc
index 54fc3c2..d192399 100644
--- a/chrome/browser/value_store/leveldb_value_store.cc
+++ b/chrome/browser/value_store/leveldb_value_store.cc
@@ -94,7 +94,7 @@
   if (db_ && IsEmpty()) {
     // Close |db_| now to release any lock on the directory.
     db_.reset();
-    if (!file_util::Delete(db_path_, true)) {
+    if (!base::Delete(db_path_, true)) {
       LOG(WARNING) << "Failed to delete LeveldbValueStore database " <<
           db_path_.value();
     }
diff --git a/chrome/browser/value_store/value_store.h b/chrome/browser/value_store/value_store.h
index c57140f..4a25786 100644
--- a/chrome/browser/value_store/value_store.h
+++ b/chrome/browser/value_store/value_store.h
@@ -19,7 +19,7 @@
   class ReadResultType {
    public:
     // Ownership of |settings| taken.
-    explicit ReadResultType(DictionaryValue* settings);
+    explicit ReadResultType(base::DictionaryValue* settings);
     explicit ReadResultType(const std::string& error);
     ~ReadResultType();
 
@@ -27,7 +27,7 @@
     // the root object. If you request the value for key "foo", that value will
     // be in |settings.foo|.
     // Must only be called if HasError() is false.
-    scoped_ptr<DictionaryValue>& settings();
+    scoped_ptr<base::DictionaryValue>& settings();
 
     // Gets whether the operation failed.
     bool HasError() const;
@@ -37,7 +37,7 @@
     const std::string& error() const;
 
    private:
-    scoped_ptr<DictionaryValue> settings_;
+    scoped_ptr<base::DictionaryValue> settings_;
     const std::string error_;
 
     DISALLOW_COPY_AND_ASSIGN(ReadResultType);
@@ -124,12 +124,13 @@
   virtual ReadResult Get() = 0;
 
   // Sets a single key to a new value.
-  virtual WriteResult Set(
-      WriteOptions options, const std::string& key, const Value& value) = 0;
+  virtual WriteResult Set(WriteOptions options,
+                          const std::string& key,
+                          const base::Value& value) = 0;
 
   // Sets multiple keys to new values.
   virtual WriteResult Set(
-      WriteOptions options, const DictionaryValue& values) = 0;
+      WriteOptions options, const base::DictionaryValue& values) = 0;
 
   // Removes a key from the storage.
   virtual WriteResult Remove(const std::string& key) = 0;
diff --git a/chrome/browser/web_applications/web_app.cc b/chrome/browser/web_applications/web_app.cc
index de8e048..06a12f7 100644
--- a/chrome/browser/web_applications/web_app.cc
+++ b/chrome/browser/web_applications/web_app.cc
@@ -149,14 +149,15 @@
 
 void CreateShortcuts(
     const ShellIntegration::ShortcutInfo& shortcut_info,
-    const ShellIntegration::ShortcutLocations& creation_locations) {
+    const ShellIntegration::ShortcutLocations& creation_locations,
+    ShortcutCreationPolicy creation_policy) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
 
   BrowserThread::PostTask(
       BrowserThread::FILE,
       FROM_HERE,
       base::Bind(base::IgnoreResult(&CreateShortcutsOnFileThread),
-                 shortcut_info, creation_locations));
+                 shortcut_info, creation_locations, creation_policy));
 }
 
 void DeleteAllShortcuts(const ShellIntegration::ShortcutInfo& shortcut_info) {
@@ -180,14 +181,16 @@
 
 bool CreateShortcutsOnFileThread(
     const ShellIntegration::ShortcutInfo& shortcut_info,
-    const ShellIntegration::ShortcutLocations& creation_locations) {
+    const ShellIntegration::ShortcutLocations& creation_locations,
+    ShortcutCreationPolicy creation_policy) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
 
   base::FilePath shortcut_data_dir = GetWebAppDataDirectory(
       shortcut_info.profile_path, shortcut_info.extension_id,
       shortcut_info.url);
   return internals::CreatePlatformShortcuts(shortcut_data_dir, shortcut_info,
-                                            creation_locations);
+                                            creation_locations,
+                                            creation_policy);
 }
 
 bool IsValidUrl(const GURL& url) {
diff --git a/chrome/browser/web_applications/web_app.h b/chrome/browser/web_applications/web_app.h
index f4c647c..1fc5a5a 100644
--- a/chrome/browser/web_applications/web_app.h
+++ b/chrome/browser/web_applications/web_app.h
@@ -24,6 +24,14 @@
 
 namespace web_app {
 
+// Policy on whether to create duplicate shortcuts.
+enum ShortcutCreationPolicy {
+  // Duplicate shortcuts may be created, at the discretion of the
+  // implementation.
+  ALLOW_DUPLICATE_SHORTCUTS,
+  DONT_CREATE_DUPLICATE_SHORTCUTS
+};
+
 // Gets the user data directory for given web app. The path for the directory is
 // based on |extension_id|. If |extension_id| is empty then |url| is used
 // to construct a unique ID.
@@ -56,7 +64,8 @@
 // |creation_locations| contains information about where to create them.
 void CreateShortcuts(
     const ShellIntegration::ShortcutInfo& shortcut_info,
-    const ShellIntegration::ShortcutLocations& creation_locations);
+    const ShellIntegration::ShortcutLocations& creation_locations,
+    ShortcutCreationPolicy creation_policy);
 
 // Delete all the shortcuts that have been created for the given
 // |shortcut_data| in the profile with |profile_path|.
@@ -75,7 +84,8 @@
 // |creation_locations| contains information about where to create them.
 bool CreateShortcutsOnFileThread(
     const ShellIntegration::ShortcutInfo& shortcut_info,
-    const ShellIntegration::ShortcutLocations& creation_locations);
+    const ShellIntegration::ShortcutLocations& creation_locations,
+    ShortcutCreationPolicy creation_policy);
 
 // Returns true if given url is a valid web app url.
 bool IsValidUrl(const GURL& url);
@@ -101,9 +111,6 @@
 namespace internals {
 
 #if defined(OS_WIN)
-bool CheckAndSaveIcon(const base::FilePath& icon_file,
-                      const gfx::ImageFamily& image);
-
 std::vector<base::FilePath> GetShortcutPaths(
     const ShellIntegration::ShortcutLocations& creation_locations);
 #endif
@@ -117,7 +124,8 @@
 bool CreatePlatformShortcuts(
     const base::FilePath& shortcut_data_path,
     const ShellIntegration::ShortcutInfo& shortcut_info,
-    const ShellIntegration::ShortcutLocations& creation_locations);
+    const ShellIntegration::ShortcutLocations& creation_locations,
+    ShortcutCreationPolicy creation_policy);
 
 // Delete all the shortcuts we have added for this extension. This is the
 // platform specific implementation of the DeleteAllShortcuts function, and
@@ -134,6 +142,10 @@
     const string16& old_app_title,
     const ShellIntegration::ShortcutInfo& shortcut_info);
 
+// Delete all the shortcuts for an entire profile.
+// This is executed on the FILE thread.
+void DeleteAllShortcutsForProfile(const base::FilePath& profile_path);
+
 // Sanitizes |name| and returns a version of it that is safe to use as an
 // on-disk file name .
 base::FilePath GetSanitizedFileName(const string16& name);
diff --git a/chrome/browser/web_applications/web_app_android.cc b/chrome/browser/web_applications/web_app_android.cc
index ece27a1..bce8a52 100644
--- a/chrome/browser/web_applications/web_app_android.cc
+++ b/chrome/browser/web_applications/web_app_android.cc
@@ -10,7 +10,8 @@
 bool CreatePlatformShortcuts(
     const base::FilePath& web_app_path,
     const ShellIntegration::ShortcutInfo& shortcut_info,
-    const ShellIntegration::ShortcutLocations& creation_locations) {
+    const ShellIntegration::ShortcutLocations& creation_locations,
+    ShortcutCreationPolicy creation_policy) {
   return true;
 }
 
@@ -23,5 +24,7 @@
     const string16& old_app_title,
     const ShellIntegration::ShortcutInfo& shortcut_info) {}
 
+void DeleteAllShortcutsForProfile(const base::FilePath& profile_path) {}
+
 }  // namespace internals
 }  // namespace web_app
diff --git a/chrome/browser/web_applications/web_app_linux.cc b/chrome/browser/web_applications/web_app_linux.cc
index f3139ba..09aaf91 100644
--- a/chrome/browser/web_applications/web_app_linux.cc
+++ b/chrome/browser/web_applications/web_app_linux.cc
@@ -16,7 +16,8 @@
 bool CreatePlatformShortcuts(
     const base::FilePath& web_app_path,
     const ShellIntegration::ShortcutInfo& shortcut_info,
-    const ShellIntegration::ShortcutLocations& creation_locations) {
+    const ShellIntegration::ShortcutLocations& creation_locations,
+    ShortcutCreationPolicy /*creation_policy*/) {
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
   return ShellIntegrationLinux::CreateDesktopShortcut(
       shortcut_info, creation_locations);
@@ -50,7 +51,12 @@
   // currently in a different location).
   creation_locations.applications_menu_subdir = GetAppShortcutsSubdirName();
 
-  CreatePlatformShortcuts(web_app_path, shortcut_info, creation_locations);
+  CreatePlatformShortcuts(web_app_path, shortcut_info, creation_locations,
+                          ALLOW_DUPLICATE_SHORTCUTS);
+}
+
+void DeleteAllShortcutsForProfile(const base::FilePath& profile_path) {
+  // TODO(mgiuca): Implement this on Linux.
 }
 
 }  // namespace internals
diff --git a/chrome/browser/web_applications/web_app_mac.h b/chrome/browser/web_applications/web_app_mac.h
index e0ba9ab..fed1b1e 100644
--- a/chrome/browser/web_applications/web_app_mac.h
+++ b/chrome/browser/web_applications/web_app_mac.h
@@ -5,6 +5,8 @@
 #ifndef CHROME_BROWSER_WEB_APPLICATIONS_WEB_APP_MAC_H_
 #define CHROME_BROWSER_WEB_APPLICATIONS_WEB_APP_MAC_H_
 
+#include <vector>
+
 #include "base/files/file_path.h"
 #include "base/gtest_prod_util.h"
 #include "base/strings/string16.h"
@@ -38,45 +40,63 @@
   WebAppShortcutCreator(
       const base::FilePath& app_data_path,
       const ShellIntegration::ShortcutInfo& shortcut_info,
-      const string16& chrome_bundle_id);
+      const std::string& chrome_bundle_id);
 
   virtual ~WebAppShortcutCreator();
 
-  // Returns a path to the destination where the app should be written to.
-  base::FilePath GetShortcutPath() const;
+  // Returns the base name for the shortcut.
+  base::FilePath GetShortcutName() const;
 
-  // Copies the app launcher template into place and fills in all relevant
-  // information.
-  bool CreateShortcut();
+  // Returns a path to the Chrome Apps folder in the relevant applications
+  // folder. E.g. ~/Applications or /Applications.
+  virtual base::FilePath GetDestinationPath() const;
+
+  bool CreateShortcuts();
+  void DeleteShortcuts();
+  bool UpdateShortcuts();
 
  protected:
   // Returns a path to the app loader.
   base::FilePath GetAppLoaderPath() const;
 
-  // Returns a path to the destination where the app should be written to.
-  virtual base::FilePath GetDestinationPath() const;
-
   // Updates the plist inside |app_path| with information about the app.
   bool UpdatePlist(const base::FilePath& app_path) const;
 
   // Updates the icon for the shortcut.
   bool UpdateIcon(const base::FilePath& app_path) const;
 
+  // Returns a path to an app bundle with the given id. Or an empty path if no
+  // matching bundle was found.
+  // Protected and virtual so it can be mocked out for testing.
+  virtual base::FilePath GetAppBundleById(const std::string& bundle_id) const;
+
  private:
   FRIEND_TEST_ALL_PREFIXES(WebAppShortcutCreatorTest, UpdateIcon);
+  FRIEND_TEST_ALL_PREFIXES(WebAppShortcutCreatorTest, UpdateShortcuts);
+
+  // Copies the app loader template into a temporary directory and fills in all
+  // relevant information.
+  bool BuildShortcut(const base::FilePath& staging_path) const;
+
+  // Builds a shortcut and copies it into the given destination folders.
+  // Returns with the number of successful copies. Returns on the first failure.
+  size_t CreateShortcutsIn(const std::vector<base::FilePath>& folders) const;
 
   // Updates the InfoPlist.string inside |app_path| with the display name for
   // the app.
   bool UpdateDisplayName(const base::FilePath& app_path) const;
 
+  // Updates the bundle id of the internal copy of the app shim bundle.
+  bool UpdateInternalBundleIdentifier() const;
+
   // Returns the bundle identifier to use for this app bundle.
-  // |plist| is a dictionary containg a copy of the template plist file to
-  // be used for creating the app bundle.
-  NSString* GetBundleIdentifier(NSDictionary* plist) const;
+  std::string GetBundleIdentifier() const;
+
+  // Returns the bundle identifier for the internal copy of the bundle.
+  std::string GetInternalBundleIdentifier() const;
 
   // Show the bundle we just generated in the Finder.
-  virtual void RevealGeneratedBundleInFinder(
-      const base::FilePath& generated_bundle) const;
+  virtual void RevealAppShimInFinder() const;
 
   // Path to the data directory for this app. For example:
   // ~/Library/Application Support/Chromium/Default/Web Applications/_crx_abc/
@@ -86,7 +106,7 @@
   ShellIntegration::ShortcutInfo info_;
 
   // The CFBundleIdentifier of the Chrome browser bundle.
-  string16 chrome_bundle_id_;
+  std::string chrome_bundle_id_;
 };
 
 }  // namespace web_app
diff --git a/chrome/browser/web_applications/web_app_mac.mm b/chrome/browser/web_applications/web_app_mac.mm
index 224c798..2743f32 100644
--- a/chrome/browser/web_applications/web_app_mac.mm
+++ b/chrome/browser/web_applications/web_app_mac.mm
@@ -17,7 +17,6 @@
 #include "base/mac/mac_logging.h"
 #include "base/mac/mac_util.h"
 #include "base/mac/scoped_cftyperef.h"
-#include "base/memory/scoped_nsobject.h"
 #include "base/strings/string_util.h"
 #include "base/strings/sys_string_conversions.h"
 #include "base/strings/utf_string_conversions.h"
@@ -166,7 +165,16 @@
     const ShellIntegration::ShortcutInfo& shortcut_info) {
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
   base::FilePath shim_path = web_app::GetAppInstallPath(shortcut_info);
-  if (shim_path.empty())
+
+  if (shim_path.empty() || !file_util::PathExists(shim_path)) {
+    // The user may have deleted the copy in the Applications folder, use the
+    // one in the web app's app_data_path.
+    base::FilePath app_data_path = web_app::GetWebAppDataDirectory(
+        shortcut_info.profile_path, shortcut_info.extension_id, GURL());
+    shim_path = app_data_path.Append(shim_path.BaseName());
+  }
+
+  if (!file_util::PathExists(shim_path))
     return;
 
   CommandLine command_line(CommandLine::NO_PROGRAM);
@@ -219,6 +227,14 @@
                  atomically:YES];
 }
 
+void DeletePathAndParentIfEmpty(const base::FilePath& app_path) {
+  DCHECK(!app_path.empty());
+  base::Delete(app_path, true);
+  base::FilePath apps_folder = app_path.DirName();
+  if (file_util::IsDirectoryEmpty(apps_folder))
+    base::Delete(apps_folder, false);
+}
+
 }  // namespace
 
 namespace web_app {
@@ -227,7 +243,7 @@
 WebAppShortcutCreator::WebAppShortcutCreator(
     const base::FilePath& app_data_path,
     const ShellIntegration::ShortcutInfo& shortcut_info,
-    const string16& chrome_bundle_id)
+    const std::string& chrome_bundle_id)
     : app_data_path_(app_data_path),
       info_(shortcut_info),
       chrome_bundle_id_(chrome_bundle_id) {
@@ -236,40 +252,21 @@
 WebAppShortcutCreator::~WebAppShortcutCreator() {
 }
 
-base::FilePath WebAppShortcutCreator::GetShortcutPath() const {
-  base::FilePath dst_path = GetDestinationPath();
-  if (dst_path.empty())
-    return dst_path;
-
-  base::FilePath app_name = internals::GetSanitizedFileName(UTF8ToUTF16(
-      info_.profile_path.BaseName().value() + " " + info_.extension_id));
-  return dst_path.Append(app_name.ReplaceExtension("app"));
+base::FilePath WebAppShortcutCreator::GetShortcutName() const {
+  std::string app_name;
+  // Check if there should be a separate shortcut made for different profiles.
+  // Such shortcuts will have a |profile_name| set on the ShortcutInfo,
+  // otherwise it will be empty.
+  if (!info_.profile_name.empty()) {
+    app_name += info_.profile_path.BaseName().value();
+    app_name += ' ';
+  }
+  app_name += info_.extension_id;
+  return base::FilePath(app_name).ReplaceExtension("app");
 }
 
-bool WebAppShortcutCreator::CreateShortcut() {
-  base::FilePath app_path = GetShortcutPath();
-  base::FilePath app_name = app_path.BaseName();
-  base::FilePath dst_path = app_path.DirName();
-  if (app_path.empty() || !file_util::DirectoryExists(dst_path.DirName())) {
-    LOG(ERROR) << "Couldn't find an Applications directory to copy app to.";
-    return false;
-  }
-  if (!file_util::CreateDirectory(app_data_path_)) {
-    LOG(ERROR) << "Creating app_data_path " << app_data_path_.value()
-               << " failed.";
-    return false;
-  }
-  if (!file_util::CreateDirectory(dst_path)) {
-    LOG(ERROR) << "Creating directory " << dst_path.value() << " failed.";
-    return false;
-  }
-  UpdateAppShortcutsSubdirLocalizedName(dst_path);
-
-  base::ScopedTempDir scoped_temp_dir;
-  if (!scoped_temp_dir.CreateUniqueTempDir())
-    return false;
-  base::FilePath staging_path = scoped_temp_dir.path().Append(app_name);
-
+bool WebAppShortcutCreator::BuildShortcut(
+    const base::FilePath& staging_path) const {
   // Update the app's plist and icon in a temp directory. This works around
   // a Finder bug where the app's icon doesn't properly update.
   if (!file_util::CopyDirectory(GetAppLoaderPath(), staging_path, true)) {
@@ -287,23 +284,115 @@
   if (!UpdateIcon(staging_path))
     return false;
 
-  // Put one copy in the app's app_data_path so we can still run it if the user
-  // deletes the one in the applications folder.
-  if (!file_util::CopyDirectory(staging_path, app_data_path_, true)) {
-    NOTREACHED();
+  return true;
+}
+
+size_t WebAppShortcutCreator::CreateShortcutsIn(
+    const std::vector<base::FilePath>& folders) const {
+  size_t succeeded = 0;
+
+  base::ScopedTempDir scoped_temp_dir;
+  if (!scoped_temp_dir.CreateUniqueTempDir())
+    return 0;
+
+  base::FilePath app_name = GetShortcutName();
+  base::FilePath staging_path =
+      scoped_temp_dir.path().Append(app_name);
+  if (!BuildShortcut(staging_path))
+    return 0;
+
+  for (std::vector<base::FilePath>::const_iterator it = folders.begin();
+       it != folders.end(); ++it) {
+    const base::FilePath& dst_path = *it;
+    if (!file_util::CopyDirectory(staging_path, dst_path, true)) {
+      LOG(ERROR) << "Copying app to dst path: " << dst_path.value()
+                 << " failed";
+      return succeeded;
+    }
+
+    base::mac::RemoveQuarantineAttribute(dst_path.Append(app_name));
+    ++succeeded;
+  }
+
+  return succeeded;
+}
+
+bool WebAppShortcutCreator::CreateShortcuts() {
+  base::FilePath dst_path = GetDestinationPath();
+  if (dst_path.empty() || !file_util::DirectoryExists(dst_path.DirName())) {
+    LOG(ERROR) << "Couldn't find an Applications directory to copy app to.";
     return false;
   }
-  base::mac::RemoveQuarantineAttribute(app_data_path_.Append(app_name));
 
-  if (!file_util::CopyDirectory(staging_path, dst_path, true))
+  if (!file_util::CreateDirectory(app_data_path_)) {
+    LOG(ERROR) << "Creating app_data_path " << app_data_path_.value()
+               << " failed.";
+    return false;
+  }
+
+  if (!file_util::CreateDirectory(dst_path)) {
+    LOG(ERROR) << "Creating directory " << dst_path.value() << " failed.";
+    return false;
+  }
+
+  UpdateAppShortcutsSubdirLocalizedName(dst_path);
+
+  std::vector<base::FilePath> paths;
+  paths.push_back(app_data_path_);
+  paths.push_back(dst_path);
+  size_t success_count = CreateShortcutsIn(paths);
+  if (success_count == 0)
     return false;
 
-  base::mac::RemoveQuarantineAttribute(app_path);
-  RevealGeneratedBundleInFinder(app_path);
+  UpdateInternalBundleIdentifier();
 
+  if (success_count != paths.size())
+    return false;
+
+  RevealAppShimInFinder();
   return true;
 }
 
+void WebAppShortcutCreator::DeleteShortcuts() {
+  base::FilePath dst_path = GetDestinationPath();
+  if (!dst_path.empty())
+    DeletePathAndParentIfEmpty(dst_path.Append(GetShortcutName()));
+
+  // In case the user has moved/renamed/copied the app bundle.
+  base::FilePath bundle_path = GetAppBundleById(GetBundleIdentifier());
+  if (!bundle_path.empty())
+    base::Delete(bundle_path, true);
+
+  // Delete the internal one.
+  DeletePathAndParentIfEmpty(app_data_path_.Append(GetShortcutName()));
+}
+
+bool WebAppShortcutCreator::UpdateShortcuts() {
+  std::vector<base::FilePath> paths;
+  base::Delete(app_data_path_.Append(GetShortcutName()), true);
+  paths.push_back(app_data_path_);
+
+  base::FilePath dst_path = GetDestinationPath();
+  base::FilePath app_path = dst_path.Append(GetShortcutName());
+
+  // If the path does not exist, check if a matching bundle can be found
+  // elsewhere.
+  if (dst_path.empty() || !file_util::PathExists(app_path))
+    app_path = GetAppBundleById(GetBundleIdentifier());
+
+  if (!app_path.empty()) {
+    base::Delete(app_path, true);
+    paths.push_back(app_path.DirName());
+  }
+
+  size_t success_count = CreateShortcutsIn(paths);
+  if (success_count == 0)
+    return false;
+
+  UpdateInternalBundleIdentifier();
+  return success_count == paths.size() && !app_path.empty();
+}
+
 base::FilePath WebAppShortcutCreator::GetAppLoaderPath() const {
   return base::mac::PathForFrameworkBundleResource(
       base::mac::NSToCFCast(@"app_mode_loader.app"));
@@ -320,7 +409,7 @@
   NSString* extension_id = base::SysUTF8ToNSString(info_.extension_id);
   NSString* extension_title = base::SysUTF16ToNSString(info_.title);
   NSString* extension_url = base::SysUTF8ToNSString(info_.url.spec());
-  NSString* chrome_bundle_id = base::SysUTF16ToNSString(chrome_bundle_id_);
+  NSString* chrome_bundle_id = base::SysUTF8ToNSString(chrome_bundle_id_);
   NSDictionary* replacement_dict =
       [NSDictionary dictionaryWithObjectsAndKeys:
           extension_id, app_mode::kShortcutIdPlaceholder,
@@ -351,7 +440,7 @@
   }
 
   // 2. Fill in other values.
-  [plist setObject:GetBundleIdentifier(plist)
+  [plist setObject:base::SysUTF8ToNSString(GetBundleIdentifier())
             forKey:base::mac::CFToNSCast(kCFBundleIdentifierKey)];
   [plist setObject:base::mac::FilePathToNSString(app_data_path_)
             forKey:app_mode::kCrAppModeUserDataDirKey];
@@ -366,7 +455,8 @@
   [plist setObject:base::mac::FilePathToNSString(app_name)
             forKey:base::mac::CFToNSCast(kCFBundleNameKey)];
 
-  return [plist writeToFile:plist_path atomically:YES];
+  return [plist writeToFile:plist_path
+                 atomically:YES];
 }
 
 bool WebAppShortcutCreator::UpdateDisplayName(
@@ -427,25 +517,60 @@
   return icon_family.WriteDataToFile(resources_path.Append("app.icns"));
 }
 
-NSString* WebAppShortcutCreator::GetBundleIdentifier(NSDictionary* plist) const
-{
-  NSString* bundle_id_template =
-    base::mac::ObjCCast<NSString>(
-        [plist objectForKey:base::mac::CFToNSCast(kCFBundleIdentifierKey)]);
-  NSString* extension_id = base::SysUTF8ToNSString(info_.extension_id);
-  NSString* placeholder =
-      [NSString stringWithFormat:@"@%@@", app_mode::kShortcutIdPlaceholder];
-  NSString* bundle_id =
-      [bundle_id_template
-          stringByReplacingOccurrencesOfString:placeholder
-                                    withString:extension_id];
+bool WebAppShortcutCreator::UpdateInternalBundleIdentifier() const {
+  NSString* plist_path = base::mac::FilePathToNSString(
+      app_data_path_.Append(GetShortcutName())
+          .Append("Contents").Append("Info.plist"));
+  NSMutableDictionary* plist =
+      [NSMutableDictionary dictionaryWithContentsOfFile:plist_path];
+
+  [plist setObject:base::SysUTF8ToNSString(GetInternalBundleIdentifier())
+            forKey:base::mac::CFToNSCast(kCFBundleIdentifierKey)];
+  return [plist writeToFile:plist_path
+                 atomically:YES];
+}
+
+base::FilePath WebAppShortcutCreator::GetAppBundleById(
+    const std::string& bundle_id) const {
+  base::ScopedCFTypeRef<CFStringRef> bundle_id_cf(
+      base::SysUTF8ToCFStringRef(bundle_id));
+  CFURLRef url_ref = NULL;
+  OSStatus status = LSFindApplicationForInfo(
+      kLSUnknownCreator, bundle_id_cf.get(), NULL, NULL, &url_ref);
+  if (status != noErr)
+    return base::FilePath();
+
+  base::ScopedCFTypeRef<CFURLRef> url(url_ref);
+  NSString* path_string = [base::mac::CFToNSCast(url.get()) path];
+  return base::FilePath([path_string fileSystemRepresentation]);
+}
+
+std::string WebAppShortcutCreator::GetBundleIdentifier() const {
+  // Replace spaces in the profile path with hyphen.
+  std::string normalized_profile_path;
+  ReplaceChars(info_.profile_path.BaseName().value(),
+               " ", "-", &normalized_profile_path);
+
+  // This matches APP_MODE_APP_BUNDLE_ID in chrome/chrome.gyp.
+  std::string bundle_id =
+      chrome_bundle_id_ + std::string(".app.") +
+      normalized_profile_path + "-" + info_.extension_id;
+
   return bundle_id;
 }
 
-void WebAppShortcutCreator::RevealGeneratedBundleInFinder(
-    const base::FilePath& generated_bundle) const {
+std::string WebAppShortcutCreator::GetInternalBundleIdentifier() const {
+  return GetBundleIdentifier() + "-internal";
+}
+
+void WebAppShortcutCreator::RevealAppShimInFinder() const {
+  base::FilePath dst_path = GetDestinationPath();
+  if (dst_path.empty())
+    return;
+
+  base::FilePath app_path = dst_path.Append(GetShortcutName());
   [[NSWorkspace sharedWorkspace]
-                    selectFile:base::mac::FilePathToNSString(generated_bundle)
+                    selectFile:base::mac::FilePathToNSString(app_path)
       inFileViewerRootedAtPath:nil];
 }
 
@@ -453,8 +578,10 @@
     const ShellIntegration::ShortcutInfo& shortcut_info) {
   WebAppShortcutCreator shortcut_creator(base::FilePath(),
                                          shortcut_info,
-                                         string16());
-  return shortcut_creator.GetShortcutPath();
+                                         std::string());
+  base::FilePath dst_path = shortcut_creator.GetDestinationPath();
+  return dst_path.empty() ?
+      base::FilePath() : dst_path.Append(shortcut_creator.GetShortcutName());
 }
 
 void MaybeLaunchShortcut(const ShellIntegration::ShortcutInfo& shortcut_info) {
@@ -468,51 +595,38 @@
 
 namespace internals {
 
-base::FilePath GetAppBundleByExtensionId(std::string extension_id) {
-  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
-  // This matches APP_MODE_APP_BUNDLE_ID in chrome/chrome.gyp.
-  std::string bundle_id =
-      base::mac::BaseBundleID() + std::string(".app.") + extension_id;
-  base::mac::ScopedCFTypeRef<CFStringRef> bundle_id_cf(
-      base::SysUTF8ToCFStringRef(bundle_id));
-  CFURLRef url_ref = NULL;
-  OSStatus status = LSFindApplicationForInfo(
-      kLSUnknownCreator, bundle_id_cf.get(), NULL, NULL, &url_ref);
-  base::mac::ScopedCFTypeRef<CFURLRef> url(url_ref);
-
-  if (status != noErr)
-    return base::FilePath();
-
-  NSString* path_string = [base::mac::CFToNSCast(url.get()) path];
-  return base::FilePath([path_string fileSystemRepresentation]);
-}
-
 bool CreatePlatformShortcuts(
     const base::FilePath& app_data_path,
     const ShellIntegration::ShortcutInfo& shortcut_info,
-    const ShellIntegration::ShortcutLocations& creation_locations) {
+    const ShellIntegration::ShortcutLocations& creation_locations,
+    ShortcutCreationPolicy /*creation_policy*/) {
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
-  string16 bundle_id = UTF8ToUTF16(base::mac::BaseBundleID());
-  WebAppShortcutCreator shortcut_creator(app_data_path, shortcut_info,
-                            bundle_id);
-  return shortcut_creator.CreateShortcut();
+  WebAppShortcutCreator shortcut_creator(
+      app_data_path, shortcut_info, base::mac::BaseBundleID());
+  return shortcut_creator.CreateShortcuts();
 }
 
 void DeletePlatformShortcuts(
     const base::FilePath& app_data_path,
-    const ShellIntegration::ShortcutInfo& info) {
+    const ShellIntegration::ShortcutInfo& shortcut_info) {
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
-
-  base::FilePath bundle_path = GetAppBundleByExtensionId(info.extension_id);
-  file_util::Delete(bundle_path, true);
+  WebAppShortcutCreator shortcut_creator(
+      app_data_path, shortcut_info, base::mac::BaseBundleID());
+  shortcut_creator.DeleteShortcuts();
 }
 
 void UpdatePlatformShortcuts(
     const base::FilePath& app_data_path,
     const string16& old_app_title,
     const ShellIntegration::ShortcutInfo& shortcut_info) {
-  // TODO(benwells): Implement this when shortcuts / weblings are enabled on
-  // mac.
+  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
+  WebAppShortcutCreator shortcut_creator(
+      app_data_path, shortcut_info, base::mac::BaseBundleID());
+  shortcut_creator.UpdateShortcuts();
+}
+
+void DeleteAllShortcutsForProfile(const base::FilePath& profile_path) {
+  // TODO(mgiuca): Implement this on Mac.
 }
 
 }  // namespace internals
diff --git a/chrome/browser/web_applications/web_app_mac_unittest.mm b/chrome/browser/web_applications/web_app_mac_unittest.mm
index b82a0d5..a96ff4c 100644
--- a/chrome/browser/web_applications/web_app_mac_unittest.mm
+++ b/chrome/browser/web_applications/web_app_mac_unittest.mm
@@ -6,13 +6,13 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include <sys/xattr.h>
 #include <errno.h>
+#include <sys/xattr.h>
 
 #include "base/file_util.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/mac/foundation_util.h"
-#include "base/memory/scoped_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
 #include "base/strings/sys_string_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/common/mac/app_mode_common.h"
@@ -30,27 +30,31 @@
 
 namespace {
 
+const char kFakeChromeBundleId[] = "fake.cfbundleidentifier";
+
 class WebAppShortcutCreatorMock : public web_app::WebAppShortcutCreator {
  public:
   explicit WebAppShortcutCreatorMock(
       const base::FilePath& app_data_path,
       const ShellIntegration::ShortcutInfo& shortcut_info)
-      : WebAppShortcutCreator(app_data_path, shortcut_info,
-            UTF8ToUTF16("fake.cfbundleidentifier")) {
+      : WebAppShortcutCreator(app_data_path,
+                              shortcut_info,
+                              kFakeChromeBundleId) {
   }
 
   MOCK_CONST_METHOD0(GetDestinationPath, base::FilePath());
-  MOCK_CONST_METHOD1(RevealGeneratedBundleInFinder,
-                     void (const base::FilePath&));
+  MOCK_CONST_METHOD1(GetAppBundleById,
+                     base::FilePath(const std::string& bundle_id));
+  MOCK_CONST_METHOD0(RevealAppShimInFinder, void());
 };
 
 ShellIntegration::ShortcutInfo GetShortcutInfo() {
   ShellIntegration::ShortcutInfo info;
-  info.extension_id = "extension_id";
+  info.extension_id = "extensionid";
   info.extension_path = base::FilePath("/fake/extension/path");
   info.title = ASCIIToUTF16("Shortcut Title");
   info.url = GURL("http://example.com/");
-  info.profile_path = base::FilePath("Default");
+  info.profile_path = base::FilePath("Profile 1");
   info.profile_name = "profile name";
   return info;
 }
@@ -59,7 +63,7 @@
 
 namespace web_app {
 
-TEST(WebAppShortcutCreatorTest, CreateShortcut) {
+TEST(WebAppShortcutCreatorTest, CreateShortcuts) {
   base::ScopedTempDir temp_app_data_path;
   EXPECT_TRUE(temp_app_data_path.CreateUniqueTempDir());
   base::ScopedTempDir temp_dst_dir;
@@ -67,7 +71,6 @@
 
   ShellIntegration::ShortcutInfo info = GetShortcutInfo();
 
-
   base::FilePath app_name(
       info.profile_path.value() + " " + info.extension_id + ".app");
   base::FilePath app_in_app_data_path_path =
@@ -79,12 +82,12 @@
       temp_app_data_path.path(), info);
   EXPECT_CALL(shortcut_creator, GetDestinationPath())
       .WillRepeatedly(Return(dst_folder));
-  EXPECT_CALL(shortcut_creator, RevealGeneratedBundleInFinder(dst_path));
+  EXPECT_CALL(shortcut_creator, RevealAppShimInFinder());
 
-  EXPECT_TRUE(shortcut_creator.CreateShortcut());
+  EXPECT_TRUE(shortcut_creator.CreateShortcuts());
   EXPECT_TRUE(file_util::PathExists(app_in_app_data_path_path));
   EXPECT_TRUE(file_util::PathExists(dst_path));
-  EXPECT_EQ(dst_path.value(), shortcut_creator.GetShortcutPath().value());
+  EXPECT_EQ(dst_path.BaseName(), shortcut_creator.GetShortcutName());
 
   base::FilePath plist_path = dst_path.Append("Contents").Append("Info.plist");
   NSDictionary* plist = [NSDictionary dictionaryWithContentsOfFile:
@@ -107,6 +110,77 @@
   }
 }
 
+TEST(WebAppShortcutCreatorTest, UpdateShortcuts) {
+  base::ScopedTempDir temp_app_data_path;
+  EXPECT_TRUE(temp_app_data_path.CreateUniqueTempDir());
+  base::ScopedTempDir temp_dst_dir;
+  EXPECT_TRUE(temp_dst_dir.CreateUniqueTempDir());
+  base::ScopedTempDir temp_dst_dir_other;
+  EXPECT_TRUE(temp_dst_dir_other.CreateUniqueTempDir());
+
+  ShellIntegration::ShortcutInfo info = GetShortcutInfo();
+
+  base::FilePath app_name(
+      info.profile_path.value() + " " + info.extension_id + ".app");
+  base::FilePath app_in_app_data_path_path =
+      temp_app_data_path.path().Append(app_name);
+  base::FilePath dst_folder = temp_dst_dir.path();
+  base::FilePath other_folder = temp_dst_dir_other.path();
+
+  NiceMock<WebAppShortcutCreatorMock> shortcut_creator(
+      temp_app_data_path.path(), info);
+  EXPECT_CALL(shortcut_creator, GetDestinationPath())
+      .WillRepeatedly(Return(dst_folder));
+
+  std::string expected_bundle_id = kFakeChromeBundleId;
+  expected_bundle_id += ".app.Profile-1-" + info.extension_id;
+  EXPECT_CALL(shortcut_creator, GetAppBundleById(expected_bundle_id))
+      .WillOnce(Return(other_folder.Append(app_name)));
+
+  shortcut_creator.BuildShortcut(other_folder.Append(app_name));
+
+  EXPECT_TRUE(base::Delete(
+      other_folder.Append(app_name).Append("Contents"), true));
+
+  EXPECT_TRUE(shortcut_creator.UpdateShortcuts());
+  EXPECT_FALSE(file_util::PathExists(dst_folder.Append(app_name)));
+  EXPECT_TRUE(file_util::PathExists(
+      other_folder.Append(app_name).Append("Contents")));
+
+  // Also test case where GetAppBundleById fails.
+  EXPECT_CALL(shortcut_creator, GetAppBundleById(expected_bundle_id))
+      .WillOnce(Return(base::FilePath()));
+
+  shortcut_creator.BuildShortcut(other_folder.Append(app_name));
+
+  EXPECT_TRUE(base::Delete(
+      other_folder.Append(app_name).Append("Contents"), true));
+
+  EXPECT_FALSE(shortcut_creator.UpdateShortcuts());
+  EXPECT_FALSE(file_util::PathExists(dst_folder.Append(app_name)));
+  EXPECT_FALSE(file_util::PathExists(
+      other_folder.Append(app_name).Append("Contents")));
+}
+
+TEST(WebAppShortcutCreatorTest, CreateAppListShortcut) {
+  base::ScopedTempDir temp_dst_dir;
+  EXPECT_TRUE(temp_dst_dir.CreateUniqueTempDir());
+
+  ShellIntegration::ShortcutInfo info = GetShortcutInfo();
+
+  base::FilePath dst_folder = temp_dst_dir.path();
+
+  // With an empty |profile_name|, the shortcut path should not have the profile
+  // directory prepended to the extension id on the app bundle name.
+  info.profile_name.clear();
+  base::FilePath dst_path = dst_folder.Append(info.extension_id + ".app");
+
+  NiceMock<WebAppShortcutCreatorMock> shortcut_creator(base::FilePath(), info);
+  EXPECT_CALL(shortcut_creator, GetDestinationPath())
+      .WillRepeatedly(Return(dst_folder));
+  EXPECT_EQ(dst_path.BaseName(), shortcut_creator.GetShortcutName());
+}
+
 TEST(WebAppShortcutCreatorTest, RunShortcut) {
   base::ScopedTempDir temp_app_data_path;
   EXPECT_TRUE(temp_app_data_path.CreateUniqueTempDir());
@@ -123,9 +197,9 @@
       temp_app_data_path.path(), info);
   EXPECT_CALL(shortcut_creator, GetDestinationPath())
       .WillRepeatedly(Return(dst_folder));
-  EXPECT_CALL(shortcut_creator, RevealGeneratedBundleInFinder(dst_path));
+  EXPECT_CALL(shortcut_creator, RevealAppShimInFinder());
 
-  EXPECT_TRUE(shortcut_creator.CreateShortcut());
+  EXPECT_TRUE(shortcut_creator.CreateShortcuts());
   EXPECT_TRUE(file_util::PathExists(dst_path));
 
   ssize_t status = getxattr(
@@ -147,7 +221,7 @@
       temp_app_data_path.path(), GetShortcutInfo());
   EXPECT_CALL(shortcut_creator, GetDestinationPath())
       .WillRepeatedly(Return(non_existent_path));
-  EXPECT_FALSE(shortcut_creator.CreateShortcut());
+  EXPECT_FALSE(shortcut_creator.CreateShortcuts());
 }
 
 TEST(WebAppShortcutCreatorTest, UpdateIcon) {
@@ -168,8 +242,8 @@
   base::FilePath icon_path =
       dst_path.Append("Contents").Append("Resources").Append("app.icns");
 
-  scoped_nsobject<NSImage> image([[NSImage alloc] initWithContentsOfFile:
-      base::mac::FilePathToNSString(icon_path)]);
+  base::scoped_nsobject<NSImage> image([[NSImage alloc]
+      initWithContentsOfFile:base::mac::FilePathToNSString(icon_path)]);
   EXPECT_TRUE(image);
   EXPECT_EQ(product_logo.Width(), [image size].width);
   EXPECT_EQ(product_logo.Height(), [image size].height);
diff --git a/chrome/browser/web_applications/web_app_win.cc b/chrome/browser/web_applications/web_app_win.cc
index 9e3c5ee..6e19753 100644
--- a/chrome/browser/web_applications/web_app_win.cc
+++ b/chrome/browser/web_applications/web_app_win.cc
@@ -2,12 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/web_applications/web_app.h"
+#include "chrome/browser/web_applications/web_app_win.h"
 
 #include <shlobj.h>
 
 #include "base/command_line.h"
 #include "base/file_util.h"
+#include "base/files/file_enumerator.h"
 #include "base/logging.h"
 #include "base/md5.h"
 #include "base/path_service.h"
@@ -16,6 +17,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/win/shortcut.h"
 #include "base/win/windows_version.h"
+#include "chrome/browser/web_applications/web_app.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/installer/launcher_support/chrome_launcher_support.h"
 #include "chrome/installer/util/util_constants.h"
@@ -91,53 +93,78 @@
                 sizeof(base::MD5Digest)) != 0;
 }
 
-bool ShortcutIsForProfile(const base::FilePath& shortcut_file_name,
-                          const base::FilePath& profile_path) {
+// Returns true if |shortcut_file_name| matches profile |profile_path|, and has
+// an --app-id flag.
+bool IsAppShortcutForProfile(const base::FilePath& shortcut_file_name,
+                             const base::FilePath& profile_path) {
   string16 cmd_line_string;
   if (base::win::ResolveShortcut(shortcut_file_name, NULL, &cmd_line_string)) {
     cmd_line_string = L"program " + cmd_line_string;
     CommandLine shortcut_cmd_line = CommandLine::FromString(cmd_line_string);
     return shortcut_cmd_line.HasSwitch(switches::kProfileDirectory) &&
            shortcut_cmd_line.GetSwitchValuePath(switches::kProfileDirectory) ==
-               profile_path.BaseName();
+               profile_path.BaseName() &&
+           shortcut_cmd_line.HasSwitch(switches::kAppId);
   }
 
   return false;
 }
 
-std::vector<base::FilePath> MatchingShortcutsForProfileAndExtension(
+// Finds shortcuts in |shortcut_path| that match profile for |profile_path| and
+// extension with title |shortcut_name|.
+// If |shortcut_name| is empty, finds all shortcuts matching |profile_path|.
+std::vector<base::FilePath> FindAppShortcutsByProfileAndTitle(
     const base::FilePath& shortcut_path,
     const base::FilePath& profile_path,
     const string16& shortcut_name) {
   std::vector<base::FilePath> shortcut_paths;
-  base::FilePath base_path = shortcut_path.
-      Append(web_app::internals::GetSanitizedFileName(shortcut_name)).
-      AddExtension(FILE_PATH_LITERAL(".lnk"));
 
-  const int fileNamesToCheck = 10;
-  for (int i = 0; i < fileNamesToCheck; ++i) {
-    base::FilePath shortcut_file = base_path;
-    if (i) {
-      shortcut_file = shortcut_file.InsertBeforeExtensionASCII(
-          base::StringPrintf(" (%d)", i));
+  if (shortcut_name.empty()) {
+    // Find all shortcuts for this profile.
+    base::FileEnumerator files(shortcut_path, false,
+                               base::FileEnumerator::FILES,
+                               FILE_PATH_LITERAL("*.lnk"));
+    base::FilePath shortcut_file = files.Next();
+    while (!shortcut_file.empty()) {
+      if (IsAppShortcutForProfile(shortcut_file, profile_path))
+        shortcut_paths.push_back(shortcut_file);
+      shortcut_file = files.Next();
     }
-    if (file_util::PathExists(shortcut_file) &&
-        ShortcutIsForProfile(shortcut_file, profile_path)) {
-      shortcut_paths.push_back(shortcut_file);
+  } else {
+    // Find all shortcuts matching |shortcut_name|.
+    base::FilePath base_path = shortcut_path.
+        Append(web_app::internals::GetSanitizedFileName(shortcut_name)).
+        AddExtension(FILE_PATH_LITERAL(".lnk"));
+
+    const int fileNamesToCheck = 10;
+    for (int i = 0; i < fileNamesToCheck; ++i) {
+      base::FilePath shortcut_file = base_path;
+      if (i > 0) {
+        shortcut_file = shortcut_file.InsertBeforeExtensionASCII(
+            base::StringPrintf(" (%d)", i));
+      }
+      if (file_util::PathExists(shortcut_file) &&
+          IsAppShortcutForProfile(shortcut_file, profile_path)) {
+        shortcut_paths.push_back(shortcut_file);
+      }
     }
   }
+
   return shortcut_paths;
 }
 
 // Creates application shortcuts in a given set of paths.
 // |shortcut_paths| is a list of directories in which shortcuts should be
-// created.
+// created. If |creation_policy| is DONT_CREATE_DUPLICATE_SHORTCUTS and there is
+// an existing shortcut to this app for this profile, does nothing (succeeding).
 // Returns true on success, false on failure.
 // Must be called on the FILE thread.
 bool CreateShortcutsInPaths(
     const base::FilePath& web_app_path,
     const ShellIntegration::ShortcutInfo& shortcut_info,
-    const std::vector<base::FilePath>& shortcut_paths) {
+    const std::vector<base::FilePath>& shortcut_paths,
+    web_app::ShortcutCreationPolicy creation_policy,
+    std::vector<base::FilePath>* out_filenames) {
   // Ensure web_app_path exists.
   if (!file_util::PathExists(web_app_path) &&
       !file_util::CreateDirectory(web_app_path)) {
@@ -188,6 +215,15 @@
   for (size_t i = 0; i < shortcut_paths.size(); ++i) {
     base::FilePath shortcut_file = shortcut_paths[i].Append(file_name).
         AddExtension(installer::kLnkExt);
+    if (creation_policy == web_app::DONT_CREATE_DUPLICATE_SHORTCUTS) {
+      // Check whether there is an existing shortcut to this app.
+      std::vector<base::FilePath> shortcut_files =
+          FindAppShortcutsByProfileAndTitle(shortcut_paths[i],
+                                            shortcut_info.profile_path,
+                                            shortcut_info.title);
+      if (!shortcut_files.empty())
+        continue;
+    }
     if (shortcut_paths[i] != web_app_path) {
       int unique_number =
           file_util::GetUniquePathNumber(shortcut_file, FILE_PATH_LITERAL(""));
@@ -215,6 +251,8 @@
     success = base::win::CreateOrUpdateShortcutLink(
         shortcut_file, shortcut_properties,
         base::win::SHORTCUT_CREATE_ALWAYS) && success;
+    if (out_filenames)
+      out_filenames->push_back(shortcut_file);
   }
 
   return success;
@@ -225,6 +263,9 @@
 // in the profile with |profile_path|.
 // |was_pinned_to_taskbar| will be set to true if there was previously a
 // shortcut pinned to the taskbar for this app; false otherwise.
+// If |web_app_path| is empty, this will not delete shortcuts from the web app
+// directory. If |title| is empty, all shortcuts for this profile will be
+// deleted.
 // |shortcut_paths| will be populated with a list of directories where shortcuts
 // for this app were found (and deleted). This will delete duplicate shortcuts,
 // but only return each path once, even if it contained multiple deleted
@@ -249,16 +290,18 @@
       web_app::GetAppShortcutsSubdirName();
   std::vector<base::FilePath> all_paths = web_app::internals::GetShortcutPaths(
       all_shortcut_locations);
-  if (base::win::GetVersion() >= base::win::VERSION_WIN7)
+  if (base::win::GetVersion() >= base::win::VERSION_WIN7 &&
+      !web_app_path.empty()) {
     all_paths.push_back(web_app_path);
+  }
 
   if (was_pinned_to_taskbar) {
     // Determine if there is a link to this app in the TaskBar pin directory.
     base::FilePath taskbar_pin_path;
     if (PathService::Get(base::DIR_TASKBAR_PINS, &taskbar_pin_path)) {
       std::vector<base::FilePath> taskbar_pin_files =
-          MatchingShortcutsForProfileAndExtension(taskbar_pin_path,
-                                                  profile_path, title);
+          FindAppShortcutsByProfileAndTitle(taskbar_pin_path, profile_path,
+                                            title);
       *was_pinned_to_taskbar = !taskbar_pin_files.empty();
     } else {
       *was_pinned_to_taskbar = false;
@@ -268,7 +311,7 @@
   for (std::vector<base::FilePath>::const_iterator i = all_paths.begin();
        i != all_paths.end(); ++i) {
     std::vector<base::FilePath> shortcut_files =
-        MatchingShortcutsForProfileAndExtension(*i, profile_path, title);
+        FindAppShortcutsByProfileAndTitle(*i, profile_path, title);
     if (shortcut_paths && !shortcut_files.empty()) {
       shortcut_paths->push_back(*i);
     }
@@ -277,7 +320,7 @@
       // Any shortcut could have been pinned, either by chrome or the user, so
       // they are all unpinned.
       base::win::TaskbarUnpinShortcutLink(j->value().c_str());
-      file_util::Delete(*j, false);
+      base::Delete(*j, false);
     }
   }
 }
@@ -286,6 +329,18 @@
 
 namespace web_app {
 
+base::FilePath CreateShortcutInWebAppDir(
+    const base::FilePath& web_app_dir,
+    const ShellIntegration::ShortcutInfo& shortcut_info) {
+  std::vector<base::FilePath> paths;
+  paths.push_back(web_app_dir);
+  std::vector<base::FilePath> out_filenames;
+  CreateShortcutsInPaths(web_app_dir, shortcut_info, paths,
+                         ALLOW_DUPLICATE_SHORTCUTS, &out_filenames);
+  DCHECK_EQ(out_filenames.size(), 1u);
+  return out_filenames[0];
+}
+
 namespace internals {
 
 // Saves |image| to |icon_file| if the file is outdated and refresh shell's
@@ -311,7 +366,8 @@
 bool CreatePlatformShortcuts(
     const base::FilePath& web_app_path,
     const ShellIntegration::ShortcutInfo& shortcut_info,
-    const ShellIntegration::ShortcutLocations& creation_locations) {
+    const ShellIntegration::ShortcutLocations& creation_locations,
+    ShortcutCreationPolicy creation_policy) {
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
 
   // Shortcut paths under which to create shortcuts.
@@ -331,7 +387,8 @@
   if (shortcut_paths.empty())
     return false;
 
-  if (!CreateShortcutsInPaths(web_app_path, shortcut_info, shortcut_paths))
+  if (!CreateShortcutsInPaths(web_app_path, shortcut_info, shortcut_paths,
+                              creation_policy, NULL))
     return false;
 
   if (pin_to_taskbar) {
@@ -367,7 +424,8 @@
     GetShortcutLocationsAndDeleteShortcuts(
         web_app_path, shortcut_info.profile_path, old_app_title,
         &was_pinned_to_taskbar, &shortcut_paths);
-    CreateShortcutsInPaths(web_app_path, shortcut_info, shortcut_paths);
+    CreateShortcutsInPaths(web_app_path, shortcut_info, shortcut_paths,
+                           ALLOW_DUPLICATE_SHORTCUTS, NULL);
     // If the shortcut was pinned to the taskbar,
     // GetShortcutLocationsAndDeleteShortcuts will have deleted it. In that
     // case, re-pin it.
@@ -403,7 +461,20 @@
   if (PathService::Get(base::DIR_START_MENU, &chrome_apps_dir)) {
     chrome_apps_dir = chrome_apps_dir.Append(GetAppShortcutsSubdirName());
     if (file_util::IsDirectoryEmpty(chrome_apps_dir))
-      file_util::Delete(chrome_apps_dir, false);
+      base::Delete(chrome_apps_dir, false);
+  }
+}
+
+void DeleteAllShortcutsForProfile(const base::FilePath& profile_path) {
+  GetShortcutLocationsAndDeleteShortcuts(base::FilePath(), profile_path, L"",
+                                         NULL, NULL);
+
+  // If there are no more shortcuts in the Chrome Apps subdirectory, remove it.
+  base::FilePath chrome_apps_dir;
+  if (PathService::Get(base::DIR_START_MENU, &chrome_apps_dir)) {
+    chrome_apps_dir = chrome_apps_dir.Append(GetAppShortcutsSubdirName());
+    if (file_util::IsDirectoryEmpty(chrome_apps_dir))
+      base::Delete(chrome_apps_dir, false);
   }
 }
 
diff --git a/chrome/browser/web_applications/web_app_win.h b/chrome/browser/web_applications/web_app_win.h
new file mode 100644
index 0000000..6b2cf5b
--- /dev/null
+++ b/chrome/browser/web_applications/web_app_win.h
@@ -0,0 +1,32 @@
+// 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_WEB_APPLICATIONS_WEB_APP_WIN_H_
+#define CHROME_BROWSER_WEB_APPLICATIONS_WEB_APP_WIN_H_
+
+#include "base/files/file_path.h"
+#include "chrome/browser/shell_integration.h"
+
+namespace gfx {
+class ImageFamily;
+}
+
+namespace web_app {
+
+// Create a shortcut in the given web app data dir, returning the name of the
+// created shortcut.
+base::FilePath CreateShortcutInWebAppDir(
+    const base::FilePath& web_app_path,
+    const ShellIntegration::ShortcutInfo& shortcut_info);
+
+namespace internals {
+
+bool CheckAndSaveIcon(const base::FilePath& icon_file,
+                      const gfx::ImageFamily& image);
+
+}  // namespace internals
+
+}  // namespace web_app
+
+#endif  // CHROME_BROWSER_WEB_APPLICATIONS_WEB_APP_WIN_H_
diff --git a/chrome/browser/web_resource/notification_promo.cc b/chrome/browser/web_resource/notification_promo.cc
index f0869e4..222f4f5 100644
--- a/chrome/browser/web_resource/notification_promo.cc
+++ b/chrome/browser/web_resource/notification_promo.cc
@@ -16,7 +16,7 @@
 #include "base/strings/string_util.h"
 #include "base/sys_info.h"
 #include "base/threading/thread_restrictions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/web_resource/promo_resource_service.h"
@@ -24,8 +24,8 @@
 #include "chrome/common/pref_names.h"
 #include "components/user_prefs/pref_registry_syncable.h"
 #include "content/public/browser/user_metrics.h"
-#include "googleurl/src/gurl.h"
 #include "net/base/url_util.h"
+#include "url/gurl.h"
 
 #if defined(OS_ANDROID)
 #include "base/command_line.h"
diff --git a/chrome/browser/web_resource/notification_promo.h b/chrome/browser/web_resource/notification_promo.h
index bde22d6..0cc8ace 100644
--- a/chrome/browser/web_resource/notification_promo.h
+++ b/chrome/browser/web_resource/notification_promo.h
@@ -11,7 +11,7 @@
 #include "base/gtest_prod_util.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 class PrefRegistrySimple;
 class PrefService;
diff --git a/chrome/browser/web_resource/promo_resource_service.cc b/chrome/browser/web_resource/promo_resource_service.cc
index 02c1655..2c02f63 100644
--- a/chrome/browser/web_resource/promo_resource_service.cc
+++ b/chrome/browser/web_resource/promo_resource_service.cc
@@ -18,7 +18,7 @@
 #include "chrome/common/pref_names.h"
 #include "components/user_prefs/pref_registry_syncable.h"
 #include "content/public/browser/notification_service.h"
-#include "googleurl/src/gurl.h"
+#include "url/gurl.h"
 
 namespace {
 
diff --git a/chrome/browser/web_resource/promo_resource_service_mobile_ntp_unittest.cc b/chrome/browser/web_resource/promo_resource_service_mobile_ntp_unittest.cc
index 389ebe0..fd98b20 100644
--- a/chrome/browser/web_resource/promo_resource_service_mobile_ntp_unittest.cc
+++ b/chrome/browser/web_resource/promo_resource_service_mobile_ntp_unittest.cc
@@ -8,7 +8,7 @@
 #include "base/message_loop.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/web_resource/notification_promo.h"
diff --git a/chrome/browser/web_resource/promo_resource_service_unittest.cc b/chrome/browser/web_resource/promo_resource_service_unittest.cc
index 8c7c98f..bea1751 100644
--- a/chrome/browser/web_resource/promo_resource_service_unittest.cc
+++ b/chrome/browser/web_resource/promo_resource_service_unittest.cc
@@ -12,7 +12,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/prefs/browser_prefs.h"
diff --git a/chrome/browser/web_resource/web_resource_service.cc b/chrome/browser/web_resource/web_resource_service.cc
index 94f00b3..b483a6e 100644
--- a/chrome/browser/web_resource/web_resource_service.cc
+++ b/chrome/browser/web_resource/web_resource_service.cc
@@ -10,14 +10,14 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/google/google_util.h"
-#include "googleurl/src/gurl.h"
 #include "net/base/load_flags.h"
 #include "net/url_request/url_fetcher.h"
 #include "net/url_request/url_request_status.h"
+#include "url/gurl.h"
 
 WebResourceService::WebResourceService(
     PrefService* prefs,
diff --git a/chrome/browser/web_resource/web_resource_service.h b/chrome/browser/web_resource/web_resource_service.h
index 9cc4d3c..7acc63a 100644
--- a/chrome/browser/web_resource/web_resource_service.h
+++ b/chrome/browser/web_resource/web_resource_service.h
@@ -12,8 +12,8 @@
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/web_resource/json_asynchronous_unpacker.h"
 #include "chrome/browser/web_resource/resource_request_allowed_notifier.h"
-#include "googleurl/src/gurl.h"
 #include "net/url_request/url_fetcher_delegate.h"
+#include "url/gurl.h"
 
 class PrefService;
 
diff --git a/chrome/browser/webdata/autocomplete_syncable_service.cc b/chrome/browser/webdata/autocomplete_syncable_service.cc
index 2a95887..a57994a 100644
--- a/chrome/browser/webdata/autocomplete_syncable_service.cc
+++ b/chrome/browser/webdata/autocomplete_syncable_service.cc
@@ -7,8 +7,8 @@
 #include "base/location.h"
 #include "base/logging.h"
 #include "base/strings/utf_string_conversions.h"
-#include "components/autofill/browser/webdata/autofill_table.h"
-#include "components/autofill/browser/webdata/autofill_webdata_service.h"
+#include "components/autofill/core/browser/webdata/autofill_table.h"
+#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
 #include "components/webdata/common/web_database.h"
 #include "content/public/browser/browser_thread.h"
 #include "net/base/escape.h"
@@ -238,8 +238,10 @@
   DCHECK(sync_processor_.get());
 
   if (!sync_processor_.get()) {
-    syncer::SyncError error(FROM_HERE, "Models not yet associated.",
-                    syncer::AUTOFILL);
+    syncer::SyncError error(FROM_HERE,
+                            syncer::SyncError::DATATYPE_ERROR,
+                            "Models not yet associated.",
+                            syncer::AUTOFILL);
     return error;
   }
 
diff --git a/chrome/browser/webdata/autocomplete_syncable_service.h b/chrome/browser/webdata/autocomplete_syncable_service.h
index 3deb86b..fb254dc 100644
--- a/chrome/browser/webdata/autocomplete_syncable_service.h
+++ b/chrome/browser/webdata/autocomplete_syncable_service.h
@@ -15,11 +15,11 @@
 #include "base/scoped_observer.h"
 #include "base/supports_user_data.h"
 #include "base/threading/non_thread_safe.h"
-#include "components/autofill/browser/webdata/autofill_change.h"
-#include "components/autofill/browser/webdata/autofill_entry.h"
-#include "components/autofill/browser/webdata/autofill_webdata_backend.h"
-#include "components/autofill/browser/webdata/autofill_webdata_service.h"
-#include "components/autofill/browser/webdata/autofill_webdata_service_observer.h"
+#include "components/autofill/core/browser/webdata/autofill_change.h"
+#include "components/autofill/core/browser/webdata/autofill_entry.h"
+#include "components/autofill/core/browser/webdata/autofill_webdata_backend.h"
+#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
+#include "components/autofill/core/browser/webdata/autofill_webdata_service_observer.h"
 #include "sync/api/sync_change.h"
 #include "sync/api/sync_data.h"
 #include "sync/api/sync_error.h"
diff --git a/chrome/browser/webdata/autofill_profile_syncable_service.cc b/chrome/browser/webdata/autofill_profile_syncable_service.cc
index 60b73b5..530f390 100644
--- a/chrome/browser/webdata/autofill_profile_syncable_service.cc
+++ b/chrome/browser/webdata/autofill_profile_syncable_service.cc
@@ -8,11 +8,11 @@
 #include "base/location.h"
 #include "base/logging.h"
 #include "base/strings/utf_string_conversions.h"
-#include "components/autofill/browser/autofill_country.h"
-#include "components/autofill/browser/autofill_profile.h"
-#include "components/autofill/browser/form_group.h"
-#include "components/autofill/browser/webdata/autofill_table.h"
-#include "components/autofill/browser/webdata/autofill_webdata_service.h"
+#include "components/autofill/core/browser/autofill_country.h"
+#include "components/autofill/core/browser/autofill_profile.h"
+#include "components/autofill/core/browser/form_group.h"
+#include "components/autofill/core/browser/webdata/autofill_table.h"
+#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
 #include "components/webdata/common/web_database.h"
 #include "content/public/browser/browser_thread.h"
 #include "sync/api/sync_error.h"
@@ -228,8 +228,10 @@
     const syncer::SyncChangeList& change_list) {
   DCHECK(CalledOnValidThread());
   if (!sync_processor_.get()) {
-    syncer::SyncError error(FROM_HERE, "Models not yet associated.",
-                    syncer::AUTOFILL_PROFILE);
+    syncer::SyncError error(FROM_HERE,
+                            syncer::SyncError::DATATYPE_ERROR,
+                            "Models not yet associated.",
+                            syncer::AUTOFILL_PROFILE);
     return error;
   }
 
@@ -319,6 +321,15 @@
     AutofillProfile* profile,
     const std::string& app_locale) {
   bool diff = false;
+  if (profile->origin() != specifics.origin()) {
+    bool was_verified = profile->IsVerified();
+    profile->set_origin(specifics.origin());
+    diff = true;
+
+    // Verified profiles should never be overwritten by unverified ones.
+    DCHECK(!was_verified || profile->IsVerified());
+  }
+
   diff = UpdateMultivaluedField(autofill::NAME_FIRST,
                                 specifics.name_first(), profile) || diff;
   diff = UpdateMultivaluedField(autofill::NAME_MIDDLE,
@@ -368,6 +379,8 @@
   specifics->clear_phone_home_whole_number();
 
   specifics->set_guid(profile.guid());
+  specifics->set_origin(profile.origin());
+
   std::vector<string16> values;
   profile.GetRawMultiInfo(autofill::NAME_FIRST, &values);
   for (size_t i = 0; i < values.size(); ++i) {
@@ -435,49 +448,59 @@
   const sync_pb::AutofillProfileSpecifics& autofill_specifics(
       specifics.autofill_profile());
 
-  GUIDToProfileMap::iterator it = profile_map->find(
+  GUIDToProfileMap::iterator existing_profile = profile_map->find(
         autofill_specifics.guid());
-  if (it != profile_map->end()) {
-    // Some profile that already present is synced.
+  if (existing_profile != profile_map->end()) {
+    // The synced profile already exists locally.  It might need to be updated.
     if (OverwriteProfileWithServerData(
-            autofill_specifics, it->second, app_locale_)) {
-      bundle->profiles_to_update.push_back(it->second);
+            autofill_specifics, existing_profile->second, app_locale_)) {
+      bundle->profiles_to_update.push_back(existing_profile->second);
     }
-  } else {
-    // New profile synced.
-    // TODO(isherman): Read the origin from |autofill_specifics|.
-    AutofillProfile* new_profile(
-        new AutofillProfile(autofill_specifics.guid(), std::string()));
-    OverwriteProfileWithServerData(
-        autofill_specifics, new_profile, app_locale_);
-
-    // Check if profile appears under a different guid.
-    for (GUIDToProfileMap::iterator i = profile_map->begin();
-         i != profile_map->end(); ++i) {
-      if (i->second->Compare(*new_profile) == 0) {
-        bundle->profiles_to_delete.push_back(i->second->guid());
-        DVLOG(2) << "[AUTOFILL SYNC]"
-                 << "Found in sync db but with a different guid: "
-                 << UTF16ToUTF8(i->second->GetRawInfo(autofill::NAME_FIRST))
-                 << UTF16ToUTF8(i->second->GetRawInfo(autofill::NAME_LAST))
-                 << "New guid " << new_profile->guid()
-                 << ". Profile to be deleted " << i->second->guid();
-        profile_map->erase(i);
-        break;
-      } else if (!i->second->PrimaryValue().empty() &&
-                 i->second->PrimaryValue() == new_profile->PrimaryValue()) {
-        // Add it to candidates for merge - if there is no profile with this
-        // guid we will merge them.
-        bundle->candidates_to_merge.insert(std::make_pair(i->second->guid(),
-                                                          new_profile));
-      }
-    }
-    profiles_.push_back(new_profile);
-    it = profile_map->insert(std::make_pair(new_profile->guid(),
-                                            new_profile)).first;
-    bundle->profiles_to_add.push_back(new_profile);
+    return existing_profile;
   }
-  return it;
+
+
+  // New profile synced.
+  AutofillProfile* new_profile = new AutofillProfile(
+      autofill_specifics.guid(), autofill_specifics.origin());
+  OverwriteProfileWithServerData(autofill_specifics, new_profile, app_locale_);
+
+  // Check if profile appears under a different guid.
+  // Unverified profiles should never overwrite verified ones.
+  for (GUIDToProfileMap::iterator it = profile_map->begin();
+       it != profile_map->end(); ++it) {
+    AutofillProfile* local_profile = it->second;
+    if (local_profile->Compare(*new_profile) == 0) {
+      // Ensure that a verified profile can never revert back to an unverified
+      // one.
+      if (local_profile->IsVerified() && !new_profile->IsVerified()) {
+        new_profile->set_origin(local_profile->origin());
+        bundle->profiles_to_sync_back.push_back(new_profile);
+      }
+
+      bundle->profiles_to_delete.push_back(local_profile->guid());
+      DVLOG(2) << "[AUTOFILL SYNC]"
+               << "Found in sync db but with a different guid: "
+               << UTF16ToUTF8(local_profile->GetRawInfo(autofill::NAME_FIRST))
+               << UTF16ToUTF8(local_profile->GetRawInfo(autofill::NAME_LAST))
+               << "New guid " << new_profile->guid()
+               << ". Profile to be deleted " << local_profile->guid();
+      profile_map->erase(it);
+      break;
+    } else if (!local_profile->IsVerified() &&
+               !new_profile->IsVerified() &&
+               !local_profile->PrimaryValue().empty() &&
+               local_profile->PrimaryValue() == new_profile->PrimaryValue()) {
+      // Add it to candidates for merge - if there is no profile with this
+      // guid we will merge them.
+      bundle->candidates_to_merge.insert(
+          std::make_pair(local_profile->guid(), new_profile));
+    }
+  }
+  profiles_.push_back(new_profile);
+  bundle->profiles_to_add.push_back(new_profile);
+  return profile_map->insert(std::make_pair(new_profile->guid(),
+                                            new_profile)).first;
 }
 
 void AutofillProfileSyncableService::ActOnChange(
@@ -582,7 +605,8 @@
     AutofillProfile* merge_into,
     const std::string& app_locale) {
   merge_into->OverwriteWithOrAddTo(merge_from, app_locale);
-  return (merge_into->Compare(merge_from) != 0);
+  return (merge_into->Compare(merge_from) != 0 ||
+          merge_into->origin() != merge_from.origin());
 }
 
 AutofillTable* AutofillProfileSyncableService::GetAutofillTable() const {
diff --git a/chrome/browser/webdata/autofill_profile_syncable_service.h b/chrome/browser/webdata/autofill_profile_syncable_service.h
index 6f0a831..498d3aa 100644
--- a/chrome/browser/webdata/autofill_profile_syncable_service.h
+++ b/chrome/browser/webdata/autofill_profile_syncable_service.h
@@ -14,11 +14,11 @@
 #include "base/supports_user_data.h"
 #include "base/synchronization/lock.h"
 #include "base/threading/non_thread_safe.h"
-#include "components/autofill/browser/autofill_type.h"
-#include "components/autofill/browser/webdata/autofill_change.h"
-#include "components/autofill/browser/webdata/autofill_entry.h"
-#include "components/autofill/browser/webdata/autofill_webdata_backend.h"
-#include "components/autofill/browser/webdata/autofill_webdata_service_observer.h"
+#include "components/autofill/core/browser/autofill_type.h"
+#include "components/autofill/core/browser/webdata/autofill_change.h"
+#include "components/autofill/core/browser/webdata/autofill_entry.h"
+#include "components/autofill/core/browser/webdata/autofill_webdata_backend.h"
+#include "components/autofill/core/browser/webdata/autofill_webdata_service_observer.h"
 #include "sync/api/sync_change.h"
 #include "sync/api/sync_data.h"
 #include "sync/api/sync_error.h"
@@ -96,26 +96,28 @@
   struct DataBundle;
 
   // Helper to query WebDatabase for the current autofill state.
-  // Made virtual for ease of mocking in the unit-test.
+  // Made virtual for ease of mocking in unit tests.
   // Caller owns returned |profiles|.
   virtual bool LoadAutofillData(
       std::vector<autofill::AutofillProfile*>* profiles);
 
   // Helper to persist any changes that occured during model association to
   // the WebDatabase.
-  // Made virtual for ease of mocking in the unit-test.
+  // Made virtual for ease of mocking in unit tests.
   virtual bool SaveChangesToWebData(const DataBundle& bundle);
 
+  // For unit tests.
+  AutofillProfileSyncableService();
+  void set_sync_processor(syncer::SyncChangeProcessor* sync_processor) {
+    sync_processor_.reset(sync_processor);
+  }
+
+  // Creates syncer::SyncData based on supplied |profile|.
+  // Exposed for unit tests.
+  static syncer::SyncData CreateData(const autofill::AutofillProfile& profile);
+
  private:
   friend class ProfileSyncServiceAutofillTest;
-  friend class MockAutofillProfileSyncableService;
-  FRIEND_TEST_ALL_PREFIXES(AutofillProfileSyncableServiceTest,
-                           MergeDataAndStartSyncing);
-  FRIEND_TEST_ALL_PREFIXES(AutofillProfileSyncableServiceTest, GetAllSyncData);
-  FRIEND_TEST_ALL_PREFIXES(AutofillProfileSyncableServiceTest,
-                           ProcessSyncChanges);
-  FRIEND_TEST_ALL_PREFIXES(AutofillProfileSyncableServiceTest,
-                           ActOnChange);
   FRIEND_TEST_ALL_PREFIXES(AutofillProfileSyncableServiceTest,
                            UpdateField);
   FRIEND_TEST_ALL_PREFIXES(AutofillProfileSyncableServiceTest,
@@ -156,9 +158,6 @@
   // Syncs |change| to the cloud.
   void ActOnChange(const autofill::AutofillProfileChange& change);
 
-  // Creates syncer::SyncData based on supplied |profile|.
-  static syncer::SyncData CreateData(const autofill::AutofillProfile& profile);
-
   autofill::AutofillTable* GetAutofillTable() const;
 
   // Helper to compare the local value and cloud value of a field, copy into
@@ -174,17 +173,14 @@
 
   // Calls merge_into->OverwriteWithOrAddTo() and then checks if the
   // |merge_into| has extra data. Returns |true| if |merge_into| posseses some
-  // multi-valued field values that are not in |merge_from|, false otherwise.
+  // multi-valued field values that are not in |merge_from| or if the origins
+  // of the two profiles differ, false otherwise.
+  // TODO(isherman): Seems like this should return |true| if |merge_into| was
+  // modified at all: http://crbug.com/248440
   static bool MergeProfile(const autofill::AutofillProfile& merge_from,
                            autofill::AutofillProfile* merge_into,
                            const std::string& app_locale);
 
-  // For unit-tests.
-  AutofillProfileSyncableService();
-  void set_sync_processor(syncer::SyncChangeProcessor* sync_processor) {
-    sync_processor_.reset(sync_processor);
-  }
-
   autofill::AutofillWebDataBackend* webdata_backend_;  // WEAK
   std::string app_locale_;
   ScopedObserver<autofill::AutofillWebDataBackend,
@@ -204,7 +200,7 @@
   DISALLOW_COPY_AND_ASSIGN(AutofillProfileSyncableService);
 };
 
-// This object is used in unit-tests as well, so it defined here.
+// This object is used in unit tests as well, so it defined here.
 struct AutofillProfileSyncableService::DataBundle {
   DataBundle();
   ~DataBundle();
diff --git a/chrome/browser/webdata/autofill_profile_syncable_service_unittest.cc b/chrome/browser/webdata/autofill_profile_syncable_service_unittest.cc
index bc51614..f5265a2 100644
--- a/chrome/browser/webdata/autofill_profile_syncable_service_unittest.cc
+++ b/chrome/browser/webdata/autofill_profile_syncable_service_unittest.cc
@@ -6,8 +6,8 @@
 #include "base/message_loop.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/webdata/autofill_profile_syncable_service.h"
-#include "components/autofill/browser/autofill_profile.h"
-#include "components/autofill/browser/webdata/autofill_change.h"
+#include "components/autofill/core/browser/autofill_profile.h"
+#include "components/autofill/core/browser/webdata/autofill_change.h"
 #include "content/public/test/test_browser_thread.h"
 #include "sync/api/sync_error_factory.h"
 #include "sync/api/sync_error_factory_mock.h"
@@ -36,10 +36,13 @@
 class MockAutofillProfileSyncableService
     : public AutofillProfileSyncableService {
  public:
-  MockAutofillProfileSyncableService() {
-  }
+  MockAutofillProfileSyncableService() {}
   virtual ~MockAutofillProfileSyncableService() {}
 
+  using AutofillProfileSyncableService::DataBundle;
+  using AutofillProfileSyncableService::set_sync_processor;
+  using AutofillProfileSyncableService::CreateData;
+
   MOCK_METHOD1(LoadAutofillData, bool(std::vector<AutofillProfile*>*));
   MOCK_METHOD1(SaveChangesToWebData,
                bool(const AutofillProfileSyncableService::DataBundle&));
@@ -71,21 +74,18 @@
 MATCHER_P(DataBundleCheck, n_bundle, "") {
   if ((arg.profiles_to_delete.size() != n_bundle.profiles_to_delete.size()) ||
       (arg.profiles_to_update.size() != n_bundle.profiles_to_update.size()) ||
-      (arg.profiles_to_add.size() != n_bundle.profiles_to_add.size())) {
+      (arg.profiles_to_add.size() != n_bundle.profiles_to_add.size()))
     return false;
-  }
   for (size_t i = 0; i < arg.profiles_to_delete.size(); ++i) {
     if (arg.profiles_to_delete[i] != n_bundle.profiles_to_delete[i])
       return false;
   }
   for (size_t i = 0; i < arg.profiles_to_update.size(); ++i) {
-    if (arg.profiles_to_update[i]->guid() !=
-        n_bundle.profiles_to_update[i]->guid()) {
+    if (*arg.profiles_to_update[i] != *n_bundle.profiles_to_update[i])
       return false;
-    }
   }
   for (size_t i = 0; i < arg.profiles_to_add.size(); ++i) {
-    if (arg.profiles_to_add[i]->Compare(*n_bundle.profiles_to_add[i]))
+    if (*arg.profiles_to_add[i] != *n_bundle.profiles_to_add[i])
       return false;
   }
   return true;
@@ -98,7 +98,25 @@
 
   MOCK_METHOD2(ProcessSyncChanges,
                syncer::SyncError(const tracked_objects::Location&,
-                         const syncer::SyncChangeList&));
+                                 const syncer::SyncChangeList&));
+};
+
+class TestSyncChangeProcessor : public syncer::SyncChangeProcessor {
+ public:
+  TestSyncChangeProcessor() {}
+  virtual ~TestSyncChangeProcessor() {}
+
+  virtual syncer::SyncError ProcessSyncChanges(
+      const tracked_objects::Location& location,
+      const syncer::SyncChangeList& changes) OVERRIDE {
+    changes_ = changes;
+    return syncer::SyncError();
+  }
+
+  const syncer::SyncChangeList& changes() { return changes_; }
+
+ private:
+  syncer::SyncChangeList changes_;
 };
 
 class AutofillProfileSyncableServiceTest : public testing::Test {
@@ -111,6 +129,35 @@
     sync_processor_.reset(new MockSyncChangeProcessor);
   }
 
+  // Wrapper around AutofillProfileSyncableService::MergeDataAndStartSyncing()
+  // that also verifies expectations.
+  void MergeDataAndStartSyncing(
+      const std::vector<AutofillProfile*>& profiles_from_web_db,
+      const syncer::SyncDataList& data_list,
+      const MockAutofillProfileSyncableService::DataBundle& expected_bundle,
+      const syncer::SyncChangeList& expected_change_list) {
+    EXPECT_CALL(autofill_syncable_service_, LoadAutofillData(_))
+        .Times(1)
+        .WillOnce(DoAll(CopyData(&profiles_from_web_db), Return(true)));
+    EXPECT_CALL(autofill_syncable_service_,
+                SaveChangesToWebData(DataBundleCheck(expected_bundle)))
+        .Times(1)
+        .WillOnce(Return(true));
+    ON_CALL(*sync_processor_, ProcessSyncChanges(_, _))
+        .WillByDefault(Return(syncer::SyncError()));
+    EXPECT_CALL(*sync_processor_,
+                ProcessSyncChanges(_, CheckSyncChanges(expected_change_list)))
+        .Times(1)
+        .WillOnce(Return(syncer::SyncError()));
+
+    // Takes ownership of sync_processor_.
+    autofill_syncable_service_.MergeDataAndStartSyncing(
+        syncer::AUTOFILL_PROFILE, data_list,
+        sync_processor_.PassAs<syncer::SyncChangeProcessor>(),
+        scoped_ptr<syncer::SyncErrorFactory>(
+            new syncer::SyncErrorFactoryMock()));
+  }
+
  protected:
   base::MessageLoop message_loop_;
   content::TestBrowserThread ui_thread_;
@@ -120,7 +167,7 @@
 };
 
 TEST_F(AutofillProfileSyncableServiceTest, MergeDataAndStartSyncing) {
-  std::vector<AutofillProfile *> profiles_from_web_db;
+  std::vector<AutofillProfile*> profiles_from_web_db;
   std::string guid_present1 = kGuid1;
   std::string guid_present2 = kGuid2;
   std::string guid_synced1 = kGuid3;
@@ -150,7 +197,7 @@
   AutofillProfile profile2(guid_synced2, origin_synced2);
   profile2.SetRawInfo(autofill::NAME_FIRST, UTF8ToUTF16("Harry"));
   data_list.push_back(autofill_syncable_service_.CreateData(profile2));
-  // This one will have the name updated.
+  // This one will have the name and origin updated.
   AutofillProfile profile3(guid_present2, origin_synced2);
   profile3.SetRawInfo(autofill::NAME_FIRST, UTF8ToUTF16("Tom Doe"));
   data_list.push_back(autofill_syncable_service_.CreateData(profile3));
@@ -159,14 +206,172 @@
   expected_change_list.push_back(
       syncer::SyncChange(FROM_HERE,
                          syncer::SyncChange::ACTION_ADD,
-                         AutofillProfileSyncableService::CreateData(
-                             (*profiles_from_web_db.front()))));
+                         MockAutofillProfileSyncableService::CreateData(
+                             *profiles_from_web_db.front())));
 
-  AutofillProfileSyncableService::DataBundle expected_bundle;
+  MockAutofillProfileSyncableService::DataBundle expected_bundle;
   expected_bundle.profiles_to_add.push_back(&profile1);
   expected_bundle.profiles_to_add.push_back(&profile2);
   expected_bundle.profiles_to_update.push_back(&profile3);
 
+  MergeDataAndStartSyncing(
+      profiles_from_web_db, data_list, expected_bundle, expected_change_list);
+  autofill_syncable_service_.StopSyncing(syncer::AUTOFILL_PROFILE);
+}
+
+TEST_F(AutofillProfileSyncableServiceTest, MergeIdenticalProfiles) {
+  std::vector<AutofillProfile*> profiles_from_web_db;
+  std::string guid_present1 = kGuid1;
+  std::string guid_present2 = kGuid2;
+  std::string guid_synced1 = kGuid3;
+  std::string guid_synced2 = kGuid4;
+  std::string origin_present1 = kHttpOrigin;
+  std::string origin_present2 = kSettingsOrigin;
+  std::string origin_synced1 = kHttpsOrigin;
+  std::string origin_synced2 = kHttpsOrigin;
+
+  profiles_from_web_db.push_back(
+      new AutofillProfile(guid_present1, origin_present1));
+  profiles_from_web_db.back()->SetRawInfo(
+      autofill::NAME_FIRST, UTF8ToUTF16("John"));
+  profiles_from_web_db.back()->SetRawInfo(
+      autofill::ADDRESS_HOME_LINE1, UTF8ToUTF16("1 1st st"));
+  profiles_from_web_db.push_back(
+      new AutofillProfile(guid_present2, origin_present2));
+  profiles_from_web_db.back()->SetRawInfo(
+      autofill::NAME_FIRST, UTF8ToUTF16("Tom"));
+  profiles_from_web_db.back()->SetRawInfo(
+      autofill::ADDRESS_HOME_LINE1, UTF8ToUTF16("2 2nd st"));
+
+  // The synced profiles are identical to the local ones, except that the guids
+  // are different.
+  syncer::SyncDataList data_list;
+  AutofillProfile profile1(guid_synced1, origin_synced1);
+  profile1.SetRawInfo(autofill::NAME_FIRST, UTF8ToUTF16("John"));
+  profile1.SetRawInfo(autofill::ADDRESS_HOME_LINE1, UTF8ToUTF16("1 1st st"));
+  data_list.push_back(autofill_syncable_service_.CreateData(profile1));
+  AutofillProfile profile2(guid_synced2, origin_synced2);
+  profile2.SetRawInfo(autofill::NAME_FIRST, UTF8ToUTF16("Tom"));
+  profile2.SetRawInfo(autofill::ADDRESS_HOME_LINE1, UTF8ToUTF16("2 2nd st"));
+  data_list.push_back(autofill_syncable_service_.CreateData(profile2));
+
+  AutofillProfile expected_profile(profile2);
+  expected_profile.set_origin(kSettingsOrigin);
+  syncer::SyncChangeList expected_change_list;
+  expected_change_list.push_back(
+      syncer::SyncChange(FROM_HERE,
+                         syncer::SyncChange::ACTION_UPDATE,
+                         MockAutofillProfileSyncableService::CreateData(
+                             expected_profile)));
+
+  MockAutofillProfileSyncableService::DataBundle expected_bundle;
+  expected_bundle.profiles_to_delete.push_back(guid_present1);
+  expected_bundle.profiles_to_delete.push_back(guid_present2);
+  expected_bundle.profiles_to_add.push_back(&profile1);
+  expected_bundle.profiles_to_add.push_back(&expected_profile);
+
+  MergeDataAndStartSyncing(
+      profiles_from_web_db, data_list, expected_bundle, expected_change_list);
+  autofill_syncable_service_.StopSyncing(syncer::AUTOFILL_PROFILE);
+}
+
+TEST_F(AutofillProfileSyncableServiceTest, MergeSimilarProfiles) {
+  std::vector<AutofillProfile*> profiles_from_web_db;
+  std::string guid_present1 = kGuid1;
+  std::string guid_present2 = kGuid2;
+  std::string guid_synced1 = kGuid3;
+  std::string guid_synced2 = kGuid4;
+  std::string origin_present1 = kHttpOrigin;
+  std::string origin_present2 = kSettingsOrigin;
+  std::string origin_synced1 = kHttpsOrigin;
+  std::string origin_synced2 = kHttpsOrigin;
+
+  profiles_from_web_db.push_back(
+      new AutofillProfile(guid_present1, origin_present1));
+  profiles_from_web_db.back()->SetRawInfo(
+      autofill::NAME_FIRST, UTF8ToUTF16("John"));
+  profiles_from_web_db.back()->SetRawInfo(
+      autofill::ADDRESS_HOME_LINE1, UTF8ToUTF16("1 1st st"));
+  profiles_from_web_db.push_back(
+      new AutofillProfile(guid_present2, origin_present2));
+  profiles_from_web_db.back()->SetRawInfo(
+      autofill::NAME_FIRST, UTF8ToUTF16("Tom"));
+  profiles_from_web_db.back()->SetRawInfo(
+      autofill::ADDRESS_HOME_LINE1, UTF8ToUTF16("2 2nd st"));
+
+  // The synced profiles are identical to the local ones, except that the guids
+  // are different.
+  syncer::SyncDataList data_list;
+  AutofillProfile profile1(guid_synced1, origin_synced1);
+  profile1.SetRawInfo(autofill::NAME_FIRST, UTF8ToUTF16("John"));
+  profile1.SetRawInfo(autofill::ADDRESS_HOME_LINE1, UTF8ToUTF16("1 1st st"));
+  profile1.SetRawInfo(autofill::COMPANY_NAME, UTF8ToUTF16("Frobbers, Inc."));
+  data_list.push_back(autofill_syncable_service_.CreateData(profile1));
+  AutofillProfile profile2(guid_synced2, origin_synced2);
+  profile2.SetRawInfo(autofill::NAME_FIRST, UTF8ToUTF16("Tom"));
+  profile2.SetRawInfo(autofill::ADDRESS_HOME_LINE1, UTF8ToUTF16("2 2nd st"));
+  profile2.SetRawInfo(autofill::COMPANY_NAME, UTF8ToUTF16("Fizzbang, LLC."));
+  data_list.push_back(autofill_syncable_service_.CreateData(profile2));
+
+  // The first profile should have its origin updated.
+  // The second profile should remain as-is, because an unverified profile
+  // should never overwrite a verified one.
+  AutofillProfile expected_profile(profile1);
+  expected_profile.set_origin(origin_present1);
+  syncer::SyncChangeList expected_change_list;
+  expected_change_list.push_back(
+      syncer::SyncChange(FROM_HERE,
+                         syncer::SyncChange::ACTION_ADD,
+                         MockAutofillProfileSyncableService::CreateData(
+                             *profiles_from_web_db.back())));
+  expected_change_list.push_back(
+      syncer::SyncChange(FROM_HERE,
+                         syncer::SyncChange::ACTION_UPDATE,
+                         MockAutofillProfileSyncableService::CreateData(
+                             expected_profile)));
+
+  MockAutofillProfileSyncableService::DataBundle expected_bundle;
+  expected_bundle.profiles_to_delete.push_back(guid_present1);
+  expected_bundle.profiles_to_add.push_back(&expected_profile);
+  expected_bundle.profiles_to_add.push_back(&profile2);
+
+  MergeDataAndStartSyncing(
+      profiles_from_web_db, data_list, expected_bundle, expected_change_list);
+  autofill_syncable_service_.StopSyncing(syncer::AUTOFILL_PROFILE);
+}
+
+// Ensure that no Sync events are generated to fill in missing origins from Sync
+// with explicitly present empty ones.  This ensures that the migration to add
+// origins to profiles does not generate lots of needless Sync updates.
+TEST_F(AutofillProfileSyncableServiceTest, MergeDataEmptyOrigins) {
+  std::vector<AutofillProfile*> profiles_from_web_db;
+
+  // Create a profile with an empty origin.
+  AutofillProfile profile(kGuid1, std::string());
+  profile.SetRawInfo(autofill::NAME_FIRST, UTF8ToUTF16("John"));
+  profile.SetRawInfo(autofill::ADDRESS_HOME_LINE1, UTF8ToUTF16("1 1st st"));
+
+  profiles_from_web_db.push_back(new AutofillProfile(profile));
+
+  // Create a Sync profile identical to |profile|, except with no origin set.
+  sync_pb::EntitySpecifics specifics;
+  sync_pb::AutofillProfileSpecifics* autofill_specifics =
+      specifics.mutable_autofill_profile();
+  autofill_specifics->set_guid(profile.guid());
+  autofill_specifics->add_name_first("John");
+  autofill_specifics->add_name_middle(std::string());
+  autofill_specifics->add_name_last(std::string());
+  autofill_specifics->add_email_address(std::string());
+  autofill_specifics->add_phone_home_whole_number(std::string());
+  autofill_specifics->set_address_home_line1("1 1st st");
+  EXPECT_FALSE(autofill_specifics->has_origin());
+
+  syncer::SyncDataList data_list;
+  data_list.push_back(
+      syncer::SyncData::CreateLocalData(
+          profile.guid(), profile.guid(), specifics));
+
+  MockAutofillProfileSyncableService::DataBundle expected_bundle;
   EXPECT_CALL(autofill_syncable_service_, LoadAutofillData(_))
       .Times(1)
       .WillOnce(DoAll(CopyData(&profiles_from_web_db), Return(true)));
@@ -174,23 +379,19 @@
               SaveChangesToWebData(DataBundleCheck(expected_bundle)))
       .Times(1)
       .WillOnce(Return(true));
-  ON_CALL(*sync_processor_, ProcessSyncChanges(_, _))
-      .WillByDefault(Return(syncer::SyncError()));
-  EXPECT_CALL(*sync_processor_,
-              ProcessSyncChanges(_, CheckSyncChanges(expected_change_list)))
-      .Times(1)
-      .WillOnce(Return(syncer::SyncError()));
+  EXPECT_CALL(*sync_processor_, ProcessSyncChanges(_, _)).Times(0);
 
   // Takes ownership of sync_processor_.
   autofill_syncable_service_.MergeDataAndStartSyncing(
       syncer::AUTOFILL_PROFILE, data_list,
       sync_processor_.PassAs<syncer::SyncChangeProcessor>(),
       scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock()));
+
   autofill_syncable_service_.StopSyncing(syncer::AUTOFILL_PROFILE);
 }
 
 TEST_F(AutofillProfileSyncableServiceTest, GetAllSyncData) {
-  std::vector<AutofillProfile *> profiles_from_web_db;
+  std::vector<AutofillProfile*> profiles_from_web_db;
   std::string guid_present1 = kGuid1;
   std::string guid_present2 = kGuid2;
 
@@ -203,27 +404,22 @@
   profiles_from_web_db.back()->SetRawInfo(
       autofill::NAME_FIRST, UTF8ToUTF16("Jane"));
 
-  EXPECT_CALL(autofill_syncable_service_, LoadAutofillData(_))
-      .Times(1)
-      .WillOnce(DoAll(CopyData(&profiles_from_web_db), Return(true)));
-  EXPECT_CALL(autofill_syncable_service_, SaveChangesToWebData(_))
-      .Times(1)
-      .WillOnce(Return(true));
-  ON_CALL(*sync_processor_, ProcessSyncChanges(_, _))
-      .WillByDefault(Return(syncer::SyncError()));
-  EXPECT_CALL(*sync_processor_,
-              ProcessSyncChanges(
-                  _,
-                  Property(&syncer::SyncChangeList::size, Eq(2U))))
-      .Times(1)
-      .WillOnce(Return(syncer::SyncError()));
+  syncer::SyncChangeList expected_change_list;
+  expected_change_list.push_back(
+      syncer::SyncChange(FROM_HERE,
+                         syncer::SyncChange::ACTION_ADD,
+                         MockAutofillProfileSyncableService::CreateData(
+                             *profiles_from_web_db.front())));
+  expected_change_list.push_back(
+      syncer::SyncChange(FROM_HERE,
+                         syncer::SyncChange::ACTION_ADD,
+                         MockAutofillProfileSyncableService::CreateData(
+                             *profiles_from_web_db.back())));
 
+  MockAutofillProfileSyncableService::DataBundle expected_bundle;
   syncer::SyncDataList data_list;
-  // Takes ownership of sync_processor_.
-  autofill_syncable_service_.MergeDataAndStartSyncing(
-      syncer::AUTOFILL_PROFILE, data_list,
-      sync_processor_.PassAs<syncer::SyncChangeProcessor>(),
-      scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock()));
+  MergeDataAndStartSyncing(
+      profiles_from_web_db, data_list, expected_bundle, expected_change_list);
 
   syncer::SyncDataList data =
       autofill_syncable_service_.GetAllSyncData(syncer::AUTOFILL_PROFILE);
@@ -231,12 +427,10 @@
   ASSERT_EQ(2U, data.size());
   EXPECT_EQ(guid_present1, data[0].GetSpecifics().autofill_profile().guid());
   EXPECT_EQ(guid_present2, data[1].GetSpecifics().autofill_profile().guid());
-  // TODO(isherman): Verify that the origins match once they are saved and read
-  // from the database and included in the Sync protocol buffers.
-  // http://crbug.com/170401
-  // EXPECT_EQ(kHttpOrigin, data[0].GetSpecifics().autofill_profile().origin());
-  // EXPECT_EQ(kHttpsOrigin,
-  //           data[1].GetSpecifics().autofill_profile().origin());
+  EXPECT_EQ(kHttpOrigin, data[0].GetSpecifics().autofill_profile().origin());
+  EXPECT_EQ(kHttpsOrigin, data[1].GetSpecifics().autofill_profile().origin());
+
+  autofill_syncable_service_.StopSyncing(syncer::AUTOFILL_PROFILE);
 }
 
 TEST_F(AutofillProfileSyncableServiceTest, ProcessSyncChanges) {
@@ -248,17 +442,18 @@
   AutofillProfile profile(guid_synced, kHttpOrigin);
   profile.SetRawInfo(autofill::NAME_FIRST, UTF8ToUTF16("Jane"));
   change_list.push_back(
-      syncer::SyncChange(FROM_HERE,
-                         syncer::SyncChange::ACTION_ADD,
-                         AutofillProfileSyncableService::CreateData(profile)));
+      syncer::SyncChange(
+          FROM_HERE,
+          syncer::SyncChange::ACTION_ADD,
+          MockAutofillProfileSyncableService::CreateData(profile)));
   AutofillProfile empty_profile(guid_present, kHttpsOrigin);
   change_list.push_back(
       syncer::SyncChange(
           FROM_HERE,
           syncer::SyncChange::ACTION_DELETE,
-          AutofillProfileSyncableService::CreateData(empty_profile)));
+          MockAutofillProfileSyncableService::CreateData(empty_profile)));
 
-  AutofillProfileSyncableService::DataBundle expected_bundle;
+  MockAutofillProfileSyncableService::DataBundle expected_bundle;
   expected_bundle.profiles_to_delete.push_back(guid_present);
   expected_bundle.profiles_to_add.push_back(&profile);
 
@@ -274,20 +469,43 @@
   EXPECT_FALSE(error.IsSet());
 }
 
-TEST_F(AutofillProfileSyncableServiceTest, ActOnChange) {
-  AutofillProfile profile(kGuid1, std::string());
-  profile.SetRawInfo(autofill::NAME_FIRST, UTF8ToUTF16("Jane"));
-  AutofillProfileChange change1(AutofillProfileChange::ADD, kGuid1, &profile);
-  AutofillProfileChange change2(AutofillProfileChange::REMOVE, kGuid2, NULL);
-  ON_CALL(*sync_processor_, ProcessSyncChanges(_, _))
-      .WillByDefault(
-          Return(syncer::SyncError(FROM_HERE, std::string("an error"),
-                                   syncer::AUTOFILL_PROFILE)));
-  EXPECT_CALL(*sync_processor_, ProcessSyncChanges(_, _)).Times(2);
+TEST_F(AutofillProfileSyncableServiceTest, AutofillProfileAdded) {
+  // Will be owned by the syncable service.  Keep a reference available here for
+  // verifying test expectations.
+  TestSyncChangeProcessor* sync_change_processor = new TestSyncChangeProcessor;
+  autofill_syncable_service_.set_sync_processor(sync_change_processor);
 
-  autofill_syncable_service_.set_sync_processor(sync_processor_.release());
-  autofill_syncable_service_.ActOnChange(change1);
-  autofill_syncable_service_.ActOnChange(change2);
+  AutofillProfile profile(kGuid1, kHttpsOrigin);
+  profile.SetRawInfo(autofill::NAME_FIRST, UTF8ToUTF16("Jane"));
+  AutofillProfileChange change(AutofillProfileChange::ADD, kGuid1, &profile);
+  autofill_syncable_service_.AutofillProfileChanged(change);
+
+  ASSERT_EQ(1U, sync_change_processor->changes().size());
+  syncer::SyncChange result = sync_change_processor->changes()[0];
+  EXPECT_EQ(syncer::SyncChange::ACTION_ADD, result.change_type());
+
+  sync_pb::AutofillProfileSpecifics specifics =
+      result.sync_data().GetSpecifics().autofill_profile();
+  EXPECT_EQ(kGuid1, specifics.guid());
+  EXPECT_EQ(kHttpsOrigin, specifics.origin());
+  EXPECT_THAT(specifics.name_first(), testing::ElementsAre("Jane"));
+}
+
+TEST_F(AutofillProfileSyncableServiceTest, AutofillProfileDeleted) {
+  // Will be owned by the syncable service.  Keep a reference available here for
+  // verifying test expectations.
+  TestSyncChangeProcessor* sync_change_processor = new TestSyncChangeProcessor;
+  autofill_syncable_service_.set_sync_processor(sync_change_processor);
+
+  AutofillProfileChange change(AutofillProfileChange::REMOVE, kGuid2, NULL);
+  autofill_syncable_service_.AutofillProfileChanged(change);
+
+  ASSERT_EQ(1U, sync_change_processor->changes().size());
+  syncer::SyncChange result = sync_change_processor->changes()[0];
+  EXPECT_EQ(syncer::SyncChange::ACTION_DELETE, result.change_type());
+  sync_pb::AutofillProfileSpecifics specifics =
+      result.sync_data().GetSpecifics().autofill_profile();
+  EXPECT_EQ(kGuid2, specifics.guid());
 }
 
 TEST_F(AutofillProfileSyncableServiceTest, UpdateField) {
@@ -350,7 +568,7 @@
   values.push_back(UTF8ToUTF16("2@1.com"));
   profile1.SetRawMultiInfo(autofill::EMAIL_ADDRESS, values);
 
-  AutofillProfile profile2(kGuid2, std::string());
+  AutofillProfile profile2(kGuid2, kHttpsOrigin);
   profile2.SetRawInfo(
       autofill::ADDRESS_HOME_LINE1, UTF8ToUTF16("111 First St."));
 
@@ -398,6 +616,8 @@
   ASSERT_EQ(values.size(), 1U);
   EXPECT_EQ(values[0], UTF8ToUTF16("650234567"));
 
+  EXPECT_EQ(profile2.origin(), profile1.origin());
+
   AutofillProfile profile3(kGuid3, kHttpOrigin);
   profile3.SetRawInfo(
       autofill::ADDRESS_HOME_LINE1, UTF8ToUTF16("111 First St."));
diff --git a/chrome/browser/webdata/keyword_table.cc b/chrome/browser/webdata/keyword_table.cc
index 3560bb3..640985e 100644
--- a/chrome/browser/webdata/keyword_table.cc
+++ b/chrome/browser/webdata/keyword_table.cc
@@ -20,9 +20,9 @@
 #include "chrome/browser/search_engines/template_url.h"
 #include "chrome/browser/search_engines/template_url_service.h"
 #include "components/webdata/common/web_database.h"
-#include "googleurl/src/gurl.h"
 #include "sql/statement.h"
 #include "sql/transaction.h"
+#include "url/gurl.h"
 
 using base::Time;
 
diff --git a/chrome/browser/webdata/keyword_table_unittest.cc b/chrome/browser/webdata/keyword_table_unittest.cc
index 48fe297..7f15aa1 100644
--- a/chrome/browser/webdata/keyword_table_unittest.cc
+++ b/chrome/browser/webdata/keyword_table_unittest.cc
@@ -10,7 +10,7 @@
 #include "base/stl_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/search_engines/template_url.h"
 #include "chrome/browser/webdata/keyword_table.h"
 #include "components/webdata/common/web_database.h"
diff --git a/chrome/browser/webdata/logins_table_win.cc b/chrome/browser/webdata/logins_table_win.cc
index 0e3ae5a..2a959e9 100644
--- a/chrome/browser/webdata/logins_table_win.cc
+++ b/chrome/browser/webdata/logins_table_win.cc
@@ -6,7 +6,7 @@
 
 #include "base/logging.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "components/webdata/encryptor/ie7_password.h"
 #include "sql/statement.h"
 
diff --git a/chrome/browser/webdata/token_service_table_unittest.cc b/chrome/browser/webdata/token_service_table_unittest.cc
index 20c1827..d291a5a 100644
--- a/chrome/browser/webdata/token_service_table_unittest.cc
+++ b/chrome/browser/webdata/token_service_table_unittest.cc
@@ -5,7 +5,7 @@
 #include "base/files/scoped_temp_dir.h"
 #include "base/path_service.h"
 #include "base/strings/string_number_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/webdata/token_service_table.h"
 #include "components/webdata/common/web_database.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/chrome/browser/webdata/web_apps_table.cc b/chrome/browser/webdata/web_apps_table.cc
index ac1e305..16d498b 100644
--- a/chrome/browser/webdata/web_apps_table.cc
+++ b/chrome/browser/webdata/web_apps_table.cc
@@ -7,10 +7,10 @@
 #include "base/logging.h"
 #include "chrome/browser/history/history_database.h"
 #include "components/webdata/common/web_database.h"
-#include "googleurl/src/gurl.h"
 #include "sql/statement.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/gfx/codec/png_codec.h"
+#include "url/gurl.h"
 
 namespace {
 
diff --git a/chrome/browser/webdata/web_apps_table_unittest.cc b/chrome/browser/webdata/web_apps_table_unittest.cc
index 86fbade..3ca084a 100644
--- a/chrome/browser/webdata/web_apps_table_unittest.cc
+++ b/chrome/browser/webdata/web_apps_table_unittest.cc
@@ -5,12 +5,12 @@
 #include "base/files/scoped_temp_dir.h"
 #include "base/path_service.h"
 #include "base/strings/string_number_conversions.h"
-#include "base/time.h"
+#include "base/time/time.h"
 #include "chrome/browser/webdata/web_apps_table.h"
 #include "components/webdata/common/web_database.h"
-#include "googleurl/src/gurl.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/skia/include/core/SkBitmap.h"
+#include "url/gurl.h"
 
 using base::Time;
 
diff --git a/chrome/browser/webdata/web_data_service_factory.cc b/chrome/browser/webdata/web_data_service_factory.cc
index e63220b..1838713 100644
--- a/chrome/browser/webdata/web_data_service_factory.cc
+++ b/chrome/browser/webdata/web_data_service_factory.cc
@@ -19,9 +19,9 @@
 #include "chrome/browser/webdata/web_apps_table.h"
 #include "chrome/browser/webdata/web_data_service.h"
 #include "chrome/browser/webdata/web_intents_table.h"
-#include "components/autofill/browser/autofill_country.h"
-#include "components/autofill/browser/webdata/autofill_table.h"
-#include "components/autofill/browser/webdata/autofill_webdata_service.h"
+#include "components/autofill/core/browser/autofill_country.h"
+#include "components/autofill/core/browser/webdata/autofill_table.h"
+#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
 #include "components/browser_context_keyed_service/browser_context_dependency_manager.h"
 #include "components/webdata/common/webdata_constants.h"
 #include "content/public/browser/browser_thread.h"
diff --git a/chrome/browser/webdata/web_intents_table.cc b/chrome/browser/webdata/web_intents_table.cc
index cdd9472..bb57097 100644
--- a/chrome/browser/webdata/web_intents_table.cc
+++ b/chrome/browser/webdata/web_intents_table.cc
@@ -11,10 +11,10 @@
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "components/webdata/common/web_database.h"
-#include "googleurl/src/gurl.h"
 #include "net/base/mime_util.h"
 #include "sql/statement.h"
 #include "third_party/sqlite/sqlite3.h"
+#include "url/gurl.h"
 
 namespace {
 
diff --git a/chrome/browser/webview/webview_guest.cc b/chrome/browser/webview/webview_guest.cc
deleted file mode 100644
index 958b0e2..0000000
--- a/chrome/browser/webview/webview_guest.cc
+++ /dev/null
@@ -1,115 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/webview/webview_guest.h"
-
-#include "base/lazy_instance.h"
-#include "chrome/browser/extensions/api/web_request/web_request_api.h"
-#include "chrome/browser/extensions/extension_renderer_state.h"
-#include "chrome/browser/extensions/script_executor.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/render_process_host.h"
-#include "content/public/browser/site_instance.h"
-#include "content/public/browser/web_contents.h"
-
-using content::WebContents;
-
-namespace chrome {
-
-namespace {
-
-typedef std::map<std::pair<int, int>, WebViewGuest*> WebViewGuestMap;
-static base::LazyInstance<WebViewGuestMap> webview_guest_map =
-    LAZY_INSTANCE_INITIALIZER;
-
-void RemoveWebViewEventListenersOnIOThread(
-    void* profile,
-    const std::string& extension_id,
-    int embedder_process_id,
-    int guest_instance_id) {
-  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
-  ExtensionWebRequestEventRouter::GetInstance()->RemoveWebViewEventListeners(
-      profile, extension_id, embedder_process_id, guest_instance_id);
-}
-
-}  // namespace
-
-WebViewGuest::WebViewGuest(WebContents* guest_web_contents,
-                           WebContents* embedder_web_contents,
-                           const std::string& extension_id,
-                           int webview_instance_id)
-    : WebContentsObserver(guest_web_contents),
-      embedder_web_contents_(embedder_web_contents),
-      extension_id_(extension_id),
-      embedder_render_process_id_(
-          embedder_web_contents->GetRenderProcessHost()->GetID()),
-      profile_(guest_web_contents->GetBrowserContext()),
-      guest_instance_id_(guest_web_contents->GetEmbeddedInstanceID()),
-      webview_instance_id_(webview_instance_id),
-      script_executor_(new extensions::ScriptExecutor(guest_web_contents,
-                                                      &script_observers_)) {
-  std::pair<int, int> key(embedder_render_process_id_, guest_instance_id_);
-  webview_guest_map.Get().insert(std::make_pair(key, this));
-
-  AddWebViewToExtensionRendererState();
-}
-
-// static
-WebViewGuest* WebViewGuest::From(int embedder_process_id,
-                                 int guest_instance_id) {
-  WebViewGuestMap* guest_map = webview_guest_map.Pointer();
-  WebViewGuestMap::iterator it = guest_map->find(
-      std::make_pair(embedder_process_id, guest_instance_id));
-  return it == guest_map->end() ? NULL : it->second;
-}
-
-WebViewGuest::~WebViewGuest() {
-  std::pair<int, int> key(embedder_render_process_id_, guest_instance_id_);
-  webview_guest_map.Get().erase(key);
-}
-
-void WebViewGuest::WebContentsDestroyed(WebContents* web_contents) {
-  RemoveWebViewFromExtensionRendererState(web_contents);
-  content::BrowserThread::PostTask(
-      content::BrowserThread::IO,
-      FROM_HERE,
-      base::Bind(
-          &RemoveWebViewEventListenersOnIOThread,
-          profile_, extension_id_,
-          embedder_render_process_id_,
-          webview_instance_id_));
-  delete this;
-}
-
-void WebViewGuest::AddWebViewToExtensionRendererState() {
-  ExtensionRendererState::WebViewInfo webview_info;
-  webview_info.embedder_process_id =
-      embedder_web_contents()->GetRenderProcessHost()->GetID();
-  webview_info.embedder_routing_id = embedder_web_contents()->GetRoutingID();
-  webview_info.guest_instance_id = guest_instance_id_;
-  webview_info.instance_id = webview_instance_id_;
-
-  content::BrowserThread::PostTask(
-      content::BrowserThread::IO, FROM_HERE,
-      base::Bind(
-          &ExtensionRendererState::AddWebView,
-          base::Unretained(ExtensionRendererState::GetInstance()),
-          web_contents()->GetRenderProcessHost()->GetID(),
-          web_contents()->GetRoutingID(),
-          webview_info));
-}
-
-// static
-void WebViewGuest::RemoveWebViewFromExtensionRendererState(
-    WebContents* web_contents) {
-  content::BrowserThread::PostTask(
-      content::BrowserThread::IO, FROM_HERE,
-      base::Bind(
-          &ExtensionRendererState::RemoveWebView,
-          base::Unretained(ExtensionRendererState::GetInstance()),
-          web_contents->GetRenderProcessHost()->GetID(),
-          web_contents->GetRoutingID()));
-}
-
-}  // namespace chrome
diff --git a/chrome/browser/webview/webview_guest.h b/chrome/browser/webview/webview_guest.h
deleted file mode 100644
index ff68d60..0000000
--- a/chrome/browser/webview/webview_guest.h
+++ /dev/null
@@ -1,80 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_WEBVIEW_WEBVIEW_GUEST_H_
-#define CHROME_BROWSER_WEBVIEW_WEBVIEW_GUEST_H_
-
-#include "base/observer_list.h"
-#include "chrome/browser/extensions/tab_helper.h"
-#include "content/public/browser/web_contents_observer.h"
-
-namespace extensions {
-class ScriptExecutor;
-}  // namespace extensions
-
-namespace chrome {
-
-// A WebViewGuest is a WebContentsObserver on the guest WebContents of a
-// <webview> tag. It provides the browser-side implementation of the <webview>
-// API and manages the lifetime of <webview> extension events. WebViewGuest is
-// created on attachment. That is, when a guest WebContents is associated with
-// a particular embedder WebContents. This happens on either initial navigation
-// or through the use of the New Window API, when a new window is attached to
-// a particular <webview>.
-class WebViewGuest : public content::WebContentsObserver {
- public:
-  WebViewGuest(content::WebContents* guest_web_contents,
-               content::WebContents* embedder_web_contents,
-               const std::string& extension_id,
-               int webview_instance_id);
-
-  static WebViewGuest* From(int embedder_process_id, int instance_id);
-
-  content::WebContents* embedder_web_contents() const {
-    return embedder_web_contents_;
-  }
-
-  content::WebContents* web_contents() const {
-    return WebContentsObserver::web_contents();
-  }
-
-  int instance_id() const { return webview_instance_id_; }
-
-  extensions::ScriptExecutor* script_executor() {
-    return script_executor_.get();
-  }
-
- private:
-  virtual ~WebViewGuest();
-  virtual void WebContentsDestroyed(
-      content::WebContents* web_contents) OVERRIDE;
-
-  void AddWebViewToExtensionRendererState();
-  static void RemoveWebViewFromExtensionRendererState(
-      content::WebContents* web_contents);
-
-  content::WebContents* embedder_web_contents_;
-  const std::string extension_id_;
-  const int embedder_render_process_id_;
-  // Profile and instance ID are cached here because |web_contents()| is
-  // null on destruction.
-  void* profile_;
-  // |guest_instance_id_| is a profile-wide unique identifier for a guest
-  // WebContents.
-  const int guest_instance_id_;
-  // |webview_instance_id_| is an identifier that's unique within a particular
-  // embedder RenderView for a particular <webview> instance.
-  const int webview_instance_id_;
-
-  ObserverList<extensions::TabHelper::ScriptExecutionObserver>
-      script_observers_;
-  scoped_ptr<extensions::ScriptExecutor> script_executor_;
-
-
-  DISALLOW_COPY_AND_ASSIGN(WebViewGuest);
-};
-
-}  // namespace chrome
-
-#endif  // CHROME_BROWSER_WEBVIEW_WEBVIEW_GUEST_H_